server: Added access rights mapping to token objects.
[wine/multimedia.git] / dlls / crypt32 / encode.c
blobbea24dd26892b625a49b5e885879854908938028
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
33 #include <assert.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <stdlib.h>
38 #define NONAMELESSUNION
40 #include "windef.h"
41 #include "winbase.h"
42 #include "excpt.h"
43 #include "wincrypt.h"
44 #include "winreg.h"
45 #include "snmp.h"
46 #include "wine/debug.h"
47 #include "wine/exception.h"
48 #include "crypt32_private.h"
50 /* This is a bit arbitrary, but to set some limit: */
51 #define MAX_ENCODED_LEN 0x02000000
53 /* a few asn.1 tags we need */
54 #define ASN_BOOL (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x01)
55 #define ASN_BITSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x03)
56 #define ASN_ENUMERATED (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x0a)
57 #define ASN_SETOF (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x11)
58 #define ASN_NUMERICSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x12)
59 #define ASN_PRINTABLESTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x13)
60 #define ASN_IA5STRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x16)
61 #define ASN_UTCTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x17)
62 #define ASN_GENERALTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x18)
64 #define ASN_FLAGS_MASK 0xf0
65 #define ASN_TYPE_MASK 0x0f
67 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
69 typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
70 BYTE *, DWORD *);
71 typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *,
72 DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *);
73 typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
74 DWORD, DWORD, void *, DWORD *);
75 typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *,
76 DWORD, DWORD, PCRYPT_DECODE_PARA, void *, DWORD *);
78 /* Prototypes for built-in encoders/decoders. They follow the Ex style
79 * prototypes. The dwCertEncodingType and lpszStructType are ignored by the
80 * built-in functions, but the parameters are retained to simplify
81 * CryptEncodeObjectEx/CryptDecodeObjectEx, since they must call functions in
82 * external DLLs that follow these signatures.
83 * FIXME: some built-in functions are suitable to be called directly by
84 * CryptEncodeObjectEx/CryptDecodeObjectEx (they implement exception handling
85 * and memory allocation if requested), others are only suitable to be called
86 * internally. Comment which are which.
88 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
89 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
90 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
91 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
92 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
93 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
94 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
95 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
96 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
97 static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
98 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
99 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
100 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
101 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
102 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
103 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
104 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
105 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
106 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
107 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
108 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
109 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
110 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
111 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
112 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
113 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
114 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
115 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
116 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
117 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
118 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
119 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
120 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
122 static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
123 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
124 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
125 static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType,
126 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
127 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
128 /* Like CRYPT_AsnDecodeExtensions, except assumes rgExtension is set ahead of
129 * time, doesn't do memory allocation, and doesn't do exception handling.
130 * (This isn't intended to be the externally-called one.)
132 static BOOL WINAPI CRYPT_AsnDecodeExtensionsInternal(DWORD dwCertEncodingType,
133 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
134 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
135 static BOOL WINAPI CRYPT_AsnDecodeOid(const BYTE *pbEncoded, DWORD cbEncoded,
136 DWORD dwFlags, LPSTR pszObjId, DWORD *pcbObjId);
137 /* Assumes algo->Parameters.pbData is set ahead of time */
138 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
139 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
140 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
141 static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
142 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
143 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
144 /* Assumes the CRYPT_DATA_BLOB's pbData member has been initialized */
145 static BOOL WINAPI CRYPT_AsnDecodeOctetsInternal(DWORD dwCertEncodingType,
146 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
147 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
148 /* Like CRYPT_AsnDecodeBits, but assumes the CRYPT_INTEGER_BLOB's pbData
149 * member has been initialized, doesn't do exception handling, and doesn't do
150 * memory allocation.
152 static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
153 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
154 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
155 static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType,
156 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
157 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
158 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
159 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
160 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
161 /* Like CRYPT_AsnDecodeInteger, but assumes the CRYPT_INTEGER_BLOB's pbData
162 * member has been initialized, doesn't do exception handling, and doesn't do
163 * memory allocation.
165 static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType,
166 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
167 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
168 /* Like CRYPT_AsnDecodeInteger, but unsigned. */
169 static BOOL WINAPI CRYPT_AsnDecodeUnsignedIntegerInternal(
170 DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded,
171 DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
172 void *pvStructInfo, DWORD *pcbStructInfo);
174 /* filter for page-fault exceptions */
175 static WINE_EXCEPTION_FILTER(page_fault)
177 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
178 return EXCEPTION_EXECUTE_HANDLER;
179 return EXCEPTION_CONTINUE_SEARCH;
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 dataLen += items[i].size;
316 if (ret)
318 DWORD lenBytes, bytesNeeded;
320 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
321 bytesNeeded = 1 + lenBytes + dataLen;
322 if (!pbEncoded)
323 *pcbEncoded = bytesNeeded;
324 else
326 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
327 pcbEncoded, bytesNeeded)))
329 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
330 pbEncoded = *(BYTE **)pbEncoded;
331 *pbEncoded++ = ASN_SEQUENCE;
332 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
333 pbEncoded += lenBytes;
334 for (i = 0; ret && i < cItem; i++)
336 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
337 items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG,
338 NULL, pbEncoded, &items[i].size);
339 pbEncoded += items[i].size;
344 TRACE("returning %d (%08lx)\n", ret, GetLastError());
345 return ret;
348 struct AsnConstructedItem
350 BYTE tag;
351 const void *pvStructInfo;
352 CryptEncodeObjectExFunc encodeFunc;
355 static BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType,
356 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
357 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
359 BOOL ret;
360 const struct AsnConstructedItem *item =
361 (const struct AsnConstructedItem *)pvStructInfo;
362 DWORD len;
364 if ((ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
365 item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &len)))
367 DWORD dataLen, bytesNeeded;
369 CRYPT_EncodeLen(len, NULL, &dataLen);
370 bytesNeeded = 1 + dataLen + len;
371 if (!pbEncoded)
372 *pcbEncoded = bytesNeeded;
373 else if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
374 pbEncoded, pcbEncoded, bytesNeeded)))
376 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
377 pbEncoded = *(BYTE **)pbEncoded;
378 *pbEncoded++ = ASN_CONTEXT | ASN_CONSTRUCTOR | item->tag;
379 CRYPT_EncodeLen(len, pbEncoded, &dataLen);
380 pbEncoded += dataLen;
381 ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
382 item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
383 pbEncoded, &len);
386 return ret;
389 static BOOL WINAPI CRYPT_AsnEncodeCertVersion(DWORD dwCertEncodingType,
390 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
391 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
393 const DWORD *ver = (const DWORD *)pvStructInfo;
394 BOOL ret;
396 /* CERT_V1 is not encoded */
397 if (*ver == CERT_V1)
399 *pcbEncoded = 0;
400 ret = TRUE;
402 else
404 struct AsnConstructedItem item = { 0, ver, CRYPT_AsnEncodeInt };
406 ret = CRYPT_AsnEncodeConstructed(dwCertEncodingType, X509_INTEGER,
407 &item, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
409 return ret;
412 static BOOL WINAPI CRYPT_CopyEncodedBlob(DWORD dwCertEncodingType,
413 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
414 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
416 const CRYPT_DER_BLOB *blob = (const CRYPT_DER_BLOB *)pvStructInfo;
417 BOOL ret;
419 if (!pbEncoded)
421 *pcbEncoded = blob->cbData;
422 ret = TRUE;
424 else if (*pcbEncoded < blob->cbData)
426 *pcbEncoded = blob->cbData;
427 SetLastError(ERROR_MORE_DATA);
428 ret = FALSE;
430 else
432 if (blob->cbData)
433 memcpy(pbEncoded, blob->pbData, blob->cbData);
434 *pcbEncoded = blob->cbData;
435 ret = TRUE;
437 return ret;
440 static BOOL WINAPI CRYPT_AsnEncodeValidity(DWORD dwCertEncodingType,
441 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
442 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
444 BOOL ret;
445 /* This has two filetimes in a row, a NotBefore and a NotAfter */
446 const FILETIME *timePtr = (const FILETIME *)pvStructInfo;
447 struct AsnEncodeSequenceItem items[] = {
448 { timePtr++, CRYPT_AsnEncodeChoiceOfTime, 0 },
449 { timePtr, CRYPT_AsnEncodeChoiceOfTime, 0 },
452 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
453 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
454 pcbEncoded);
455 return ret;
458 static BOOL WINAPI CRYPT_AsnEncodeAlgorithmId(
459 DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
460 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
461 DWORD *pcbEncoded)
463 const CRYPT_ALGORITHM_IDENTIFIER *algo =
464 (const CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
465 BOOL ret;
466 struct AsnEncodeSequenceItem items[] = {
467 { algo->pszObjId, CRYPT_AsnEncodeOid, 0 },
468 { &algo->Parameters, CRYPT_CopyEncodedBlob, 0 },
471 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
472 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
473 pcbEncoded);
474 return ret;
477 static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
478 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
479 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
481 BOOL ret;
483 __TRY
485 const CERT_PUBLIC_KEY_INFO *info =
486 (const CERT_PUBLIC_KEY_INFO *)pvStructInfo;
487 struct AsnEncodeSequenceItem items[] = {
488 { &info->Algorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
489 { &info->PublicKey, CRYPT_AsnEncodeBits, 0 },
492 TRACE("Encoding public key with OID %s\n",
493 debugstr_a(info->Algorithm.pszObjId));
494 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
495 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
496 pcbEncoded);
498 __EXCEPT(page_fault)
500 SetLastError(STATUS_ACCESS_VIOLATION);
501 ret = FALSE;
503 __ENDTRY
504 return ret;
507 static BOOL WINAPI CRYPT_AsnEncodeCert(DWORD dwCertEncodingType,
508 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
509 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
511 BOOL ret;
513 __TRY
515 const CERT_SIGNED_CONTENT_INFO *info =
516 (const CERT_SIGNED_CONTENT_INFO *)pvStructInfo;
517 struct AsnEncodeSequenceItem items[] = {
518 { &info->ToBeSigned, CRYPT_CopyEncodedBlob, 0 },
519 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
520 { &info->Signature, CRYPT_AsnEncodeBitsSwapBytes, 0 },
523 if (dwFlags & CRYPT_ENCODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG)
524 items[2].encodeFunc = CRYPT_AsnEncodeBits;
525 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
526 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
527 pcbEncoded);
529 __EXCEPT(page_fault)
531 SetLastError(STATUS_ACCESS_VIOLATION);
532 ret = FALSE;
534 __ENDTRY
535 return ret;
538 /* Like in Windows, this blithely ignores the validity of the passed-in
539 * CERT_INFO, and just encodes it as-is. The resulting encoded data may not
540 * decode properly, see CRYPT_AsnDecodeCertInfo.
542 static BOOL WINAPI CRYPT_AsnEncodeCertInfo(DWORD dwCertEncodingType,
543 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
544 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
546 BOOL ret;
548 __TRY
550 const CERT_INFO *info = (const CERT_INFO *)pvStructInfo;
551 struct AsnEncodeSequenceItem items[10] = {
552 { &info->dwVersion, CRYPT_AsnEncodeCertVersion, 0 },
553 { &info->SerialNumber, CRYPT_AsnEncodeInteger, 0 },
554 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
555 { &info->Issuer, CRYPT_CopyEncodedBlob, 0 },
556 { &info->NotBefore, CRYPT_AsnEncodeValidity, 0 },
557 { &info->Subject, CRYPT_CopyEncodedBlob, 0 },
558 { &info->SubjectPublicKeyInfo, CRYPT_AsnEncodePubKeyInfo, 0 },
559 { 0 }
561 struct AsnConstructedItem constructed[3] = { { 0 } };
562 DWORD cItem = 7, cConstructed = 0;
564 if (info->IssuerUniqueId.cbData)
566 constructed[cConstructed].tag = 1;
567 constructed[cConstructed].pvStructInfo = &info->IssuerUniqueId;
568 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
569 items[cItem].pvStructInfo = &constructed[cConstructed];
570 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
571 cConstructed++;
572 cItem++;
574 if (info->SubjectUniqueId.cbData)
576 constructed[cConstructed].tag = 2;
577 constructed[cConstructed].pvStructInfo = &info->SubjectUniqueId;
578 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
579 items[cItem].pvStructInfo = &constructed[cConstructed];
580 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
581 cConstructed++;
582 cItem++;
584 if (info->cExtension)
586 constructed[cConstructed].tag = 3;
587 constructed[cConstructed].pvStructInfo = &info->cExtension;
588 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeExtensions;
589 items[cItem].pvStructInfo = &constructed[cConstructed];
590 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
591 cConstructed++;
592 cItem++;
595 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
596 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
598 __EXCEPT(page_fault)
600 SetLastError(STATUS_ACCESS_VIOLATION);
601 ret = FALSE;
603 __ENDTRY
604 return ret;
607 static BOOL WINAPI CRYPT_AsnEncodeCRLEntry(const CRL_ENTRY *entry,
608 BYTE *pbEncoded, DWORD *pcbEncoded)
610 struct AsnEncodeSequenceItem items[3] = {
611 { &entry->SerialNumber, CRYPT_AsnEncodeInteger, 0 },
612 { &entry->RevocationDate, CRYPT_AsnEncodeChoiceOfTime, 0 },
613 { 0 }
615 DWORD cItem = 2;
616 BOOL ret;
618 TRACE("%p, %p, %p\n", entry, pbEncoded, pcbEncoded);
620 if (entry->cExtension)
622 items[cItem].pvStructInfo = &entry->cExtension;
623 items[cItem].encodeFunc = CRYPT_AsnEncodeExtensions;
624 cItem++;
627 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
628 pbEncoded, pcbEncoded);
630 TRACE("returning %d (%08lx)\n", ret, GetLastError());
631 return ret;
634 static BOOL WINAPI CRYPT_AsnEncodeCRLEntries(DWORD dwCertEncodingType,
635 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
636 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
638 DWORD cCRLEntry = *(const DWORD *)pvStructInfo;
639 DWORD bytesNeeded, dataLen, lenBytes, i;
640 const CRL_ENTRY *rgCRLEntry = *(const CRL_ENTRY **)
641 ((const BYTE *)pvStructInfo + sizeof(DWORD));
642 BOOL ret = TRUE;
644 for (i = 0, dataLen = 0; ret && i < cCRLEntry; i++)
646 DWORD size;
648 ret = CRYPT_AsnEncodeCRLEntry(&rgCRLEntry[i], NULL, &size);
649 if (ret)
650 dataLen += size;
652 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
653 bytesNeeded = 1 + lenBytes + dataLen;
654 if (!pbEncoded)
655 *pcbEncoded = bytesNeeded;
656 else
658 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
659 pcbEncoded, bytesNeeded)))
661 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
662 pbEncoded = *(BYTE **)pbEncoded;
663 *pbEncoded++ = ASN_SEQUENCEOF;
664 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
665 pbEncoded += lenBytes;
666 for (i = 0; i < cCRLEntry; i++)
668 DWORD size = dataLen;
670 ret = CRYPT_AsnEncodeCRLEntry(&rgCRLEntry[i], pbEncoded, &size);
671 pbEncoded += size;
672 dataLen -= size;
676 return ret;
679 static BOOL WINAPI CRYPT_AsnEncodeCRLVersion(DWORD dwCertEncodingType,
680 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
681 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
683 const DWORD *ver = (const DWORD *)pvStructInfo;
684 BOOL ret;
686 /* CRL_V1 is not encoded */
687 if (*ver == CRL_V1)
689 *pcbEncoded = 0;
690 ret = TRUE;
692 else
693 ret = CRYPT_AsnEncodeInt(dwCertEncodingType, X509_INTEGER, ver,
694 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
695 return ret;
698 /* Like in Windows, this blithely ignores the validity of the passed-in
699 * CRL_INFO, and just encodes it as-is. The resulting encoded data may not
700 * decode properly, see CRYPT_AsnDecodeCRLInfo.
702 static BOOL WINAPI CRYPT_AsnEncodeCRLInfo(DWORD dwCertEncodingType,
703 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
704 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
706 BOOL ret;
708 __TRY
710 const CRL_INFO *info = (const CRL_INFO *)pvStructInfo;
711 struct AsnEncodeSequenceItem items[7] = {
712 { &info->dwVersion, CRYPT_AsnEncodeCRLVersion, 0 },
713 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
714 { &info->Issuer, CRYPT_CopyEncodedBlob, 0 },
715 { &info->ThisUpdate, CRYPT_AsnEncodeChoiceOfTime, 0 },
716 { 0 }
718 DWORD cItem = 4;
720 if (info->NextUpdate.dwLowDateTime || info->NextUpdate.dwHighDateTime)
722 items[cItem].pvStructInfo = &info->NextUpdate;
723 items[cItem].encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
724 cItem++;
726 if (info->cCRLEntry)
728 items[cItem].pvStructInfo = &info->cCRLEntry;
729 items[cItem].encodeFunc = CRYPT_AsnEncodeCRLEntries;
730 cItem++;
732 if (info->cExtension)
734 items[cItem].pvStructInfo = &info->cExtension;
735 items[cItem].encodeFunc = CRYPT_AsnEncodeExtensions;
736 cItem++;
739 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
740 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
742 __EXCEPT(page_fault)
744 SetLastError(STATUS_ACCESS_VIOLATION);
745 ret = FALSE;
747 __ENDTRY
748 return ret;
751 static BOOL CRYPT_AsnEncodeExtension(CERT_EXTENSION *ext, BYTE *pbEncoded,
752 DWORD *pcbEncoded)
754 BOOL ret;
755 struct AsnEncodeSequenceItem items[3] = {
756 { ext->pszObjId, CRYPT_AsnEncodeOid, 0 },
757 { NULL, NULL, 0 },
758 { NULL, NULL, 0 },
760 DWORD cItem = 1;
762 TRACE("%p, %p, %ld\n", ext, pbEncoded, *pcbEncoded);
764 if (ext->fCritical)
766 items[cItem].pvStructInfo = &ext->fCritical;
767 items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
768 cItem++;
770 items[cItem].pvStructInfo = &ext->Value;
771 items[cItem].encodeFunc = CRYPT_AsnEncodeOctets;
772 cItem++;
774 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
775 pbEncoded, pcbEncoded);
776 TRACE("returning %d (%08lx)\n", ret, GetLastError());
777 return ret;
780 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
781 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
782 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
784 BOOL ret;
786 __TRY
788 DWORD bytesNeeded, dataLen, lenBytes, i;
789 const CERT_EXTENSIONS *exts = (const CERT_EXTENSIONS *)pvStructInfo;
791 ret = TRUE;
792 for (i = 0, dataLen = 0; ret && i < exts->cExtension; i++)
794 DWORD size;
796 ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i], NULL, &size);
797 if (ret)
798 dataLen += size;
800 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
801 bytesNeeded = 1 + lenBytes + dataLen;
802 if (!pbEncoded)
803 *pcbEncoded = bytesNeeded;
804 else
806 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
807 pcbEncoded, bytesNeeded)))
809 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
810 pbEncoded = *(BYTE **)pbEncoded;
811 *pbEncoded++ = ASN_SEQUENCEOF;
812 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
813 pbEncoded += lenBytes;
814 for (i = 0; i < exts->cExtension; i++)
816 DWORD size = dataLen;
818 ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i],
819 pbEncoded, &size);
820 pbEncoded += size;
821 dataLen -= size;
826 __EXCEPT(page_fault)
828 SetLastError(STATUS_ACCESS_VIOLATION);
829 ret = FALSE;
831 __ENDTRY
832 return ret;
835 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
836 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
837 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
839 LPCSTR pszObjId = (LPCSTR)pvStructInfo;
840 DWORD bytesNeeded = 0, lenBytes;
841 BOOL ret = TRUE;
842 int firstPos = 0;
843 BYTE firstByte = 0;
845 TRACE("%s\n", debugstr_a(pszObjId));
847 if (pszObjId)
849 const char *ptr;
850 int val1, val2;
852 if (sscanf(pszObjId, "%d.%d.%n", &val1, &val2, &firstPos) != 2)
854 SetLastError(CRYPT_E_ASN1_ERROR);
855 return FALSE;
857 bytesNeeded++;
858 firstByte = val1 * 40 + val2;
859 ptr = pszObjId + firstPos;
860 while (ret && *ptr)
862 int pos;
864 /* note I assume each component is at most 32-bits long in base 2 */
865 if (sscanf(ptr, "%d%n", &val1, &pos) == 1)
867 if (val1 >= 0x10000000)
868 bytesNeeded += 5;
869 else if (val1 >= 0x200000)
870 bytesNeeded += 4;
871 else if (val1 >= 0x4000)
872 bytesNeeded += 3;
873 else if (val1 >= 0x80)
874 bytesNeeded += 2;
875 else
876 bytesNeeded += 1;
877 ptr += pos;
878 if (*ptr == '.')
879 ptr++;
881 else
883 SetLastError(CRYPT_E_ASN1_ERROR);
884 return FALSE;
887 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
889 else
890 lenBytes = 1;
891 bytesNeeded += 1 + lenBytes;
892 if (pbEncoded)
894 if (*pcbEncoded < bytesNeeded)
896 SetLastError(ERROR_MORE_DATA);
897 ret = FALSE;
899 else
901 *pbEncoded++ = ASN_OBJECTIDENTIFIER;
902 CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded, &lenBytes);
903 pbEncoded += lenBytes;
904 if (pszObjId)
906 const char *ptr;
907 int val, pos;
909 *pbEncoded++ = firstByte;
910 ptr = pszObjId + firstPos;
911 while (ret && *ptr)
913 sscanf(ptr, "%d%n", &val, &pos);
915 unsigned char outBytes[5];
916 int numBytes, i;
918 if (val >= 0x10000000)
919 numBytes = 5;
920 else if (val >= 0x200000)
921 numBytes = 4;
922 else if (val >= 0x4000)
923 numBytes = 3;
924 else if (val >= 0x80)
925 numBytes = 2;
926 else
927 numBytes = 1;
928 for (i = numBytes; i > 0; i--)
930 outBytes[i - 1] = val & 0x7f;
931 val >>= 7;
933 for (i = 0; i < numBytes - 1; i++)
934 *pbEncoded++ = outBytes[i] | 0x80;
935 *pbEncoded++ = outBytes[i];
936 ptr += pos;
937 if (*ptr == '.')
938 ptr++;
944 *pcbEncoded = bytesNeeded;
945 return ret;
948 static BOOL WINAPI CRYPT_AsnEncodeNameValue(DWORD dwCertEncodingType,
949 CERT_NAME_VALUE *value, BYTE *pbEncoded, DWORD *pcbEncoded)
951 BYTE tag;
952 DWORD bytesNeeded, lenBytes, encodedLen;
953 BOOL ret = TRUE;
955 switch (value->dwValueType)
957 case CERT_RDN_NUMERIC_STRING:
958 tag = ASN_NUMERICSTRING;
959 encodedLen = value->Value.cbData;
960 break;
961 case CERT_RDN_PRINTABLE_STRING:
962 tag = ASN_PRINTABLESTRING;
963 encodedLen = value->Value.cbData;
964 break;
965 case CERT_RDN_IA5_STRING:
966 tag = ASN_IA5STRING;
967 encodedLen = value->Value.cbData;
968 break;
969 case CERT_RDN_ANY_TYPE:
970 /* explicitly disallowed */
971 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
972 return FALSE;
973 default:
974 FIXME("String type %ld unimplemented\n", value->dwValueType);
975 return FALSE;
977 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
978 bytesNeeded = 1 + lenBytes + encodedLen;
979 if (pbEncoded)
981 if (*pcbEncoded < bytesNeeded)
983 SetLastError(ERROR_MORE_DATA);
984 ret = FALSE;
986 else
988 *pbEncoded++ = tag;
989 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
990 pbEncoded += lenBytes;
991 switch (value->dwValueType)
993 case CERT_RDN_NUMERIC_STRING:
994 case CERT_RDN_PRINTABLE_STRING:
995 case CERT_RDN_IA5_STRING:
996 memcpy(pbEncoded, value->Value.pbData, value->Value.cbData);
1000 *pcbEncoded = bytesNeeded;
1001 return ret;
1004 static BOOL WINAPI CRYPT_AsnEncodeRdnAttr(DWORD dwCertEncodingType,
1005 CERT_RDN_ATTR *attr, BYTE *pbEncoded, DWORD *pcbEncoded)
1007 DWORD bytesNeeded = 0, lenBytes, size;
1008 BOOL ret;
1010 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL, attr->pszObjId,
1011 0, NULL, NULL, &size);
1012 if (ret)
1014 bytesNeeded += size;
1015 /* hack: a CERT_RDN_ATTR is identical to a CERT_NAME_VALUE beginning
1016 * with dwValueType, so "cast" it to get its encoded size
1018 ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
1019 (CERT_NAME_VALUE *)&attr->dwValueType, NULL, &size);
1020 if (ret)
1022 bytesNeeded += size;
1023 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1024 bytesNeeded += 1 + lenBytes;
1025 if (pbEncoded)
1027 if (*pcbEncoded < bytesNeeded)
1029 SetLastError(ERROR_MORE_DATA);
1030 ret = FALSE;
1032 else
1034 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SEQUENCE;
1035 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1036 &lenBytes);
1037 pbEncoded += lenBytes;
1038 size = bytesNeeded - 1 - lenBytes;
1039 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
1040 attr->pszObjId, 0, NULL, pbEncoded, &size);
1041 if (ret)
1043 pbEncoded += size;
1044 size = bytesNeeded - 1 - lenBytes - size;
1045 ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
1046 (CERT_NAME_VALUE *)&attr->dwValueType, pbEncoded,
1047 &size);
1051 *pcbEncoded = bytesNeeded;
1054 return ret;
1057 static int BLOBComp(const void *l, const void *r)
1059 CRYPT_DER_BLOB *a = (CRYPT_DER_BLOB *)l, *b = (CRYPT_DER_BLOB *)r;
1060 int ret;
1062 if (!(ret = memcmp(a->pbData, b->pbData, min(a->cbData, b->cbData))))
1063 ret = a->cbData - b->cbData;
1064 return ret;
1067 /* This encodes as a SET OF, which in DER must be lexicographically sorted.
1069 static BOOL WINAPI CRYPT_AsnEncodeRdn(DWORD dwCertEncodingType, CERT_RDN *rdn,
1070 BYTE *pbEncoded, DWORD *pcbEncoded)
1072 BOOL ret;
1073 CRYPT_DER_BLOB *blobs = NULL;
1075 __TRY
1077 DWORD bytesNeeded = 0, lenBytes, i;
1079 blobs = NULL;
1080 ret = TRUE;
1081 if (rdn->cRDNAttr)
1083 blobs = CryptMemAlloc(rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
1084 if (!blobs)
1085 ret = FALSE;
1086 else
1087 memset(blobs, 0, rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
1089 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1091 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType, &rdn->rgRDNAttr[i],
1092 NULL, &blobs[i].cbData);
1093 if (ret)
1094 bytesNeeded += blobs[i].cbData;
1096 if (ret)
1098 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1099 bytesNeeded += 1 + lenBytes;
1100 if (pbEncoded)
1102 if (*pcbEncoded < bytesNeeded)
1104 SetLastError(ERROR_MORE_DATA);
1105 ret = FALSE;
1107 else
1109 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1111 blobs[i].pbData = CryptMemAlloc(blobs[i].cbData);
1112 if (!blobs[i].pbData)
1113 ret = FALSE;
1114 else
1115 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType,
1116 &rdn->rgRDNAttr[i], blobs[i].pbData,
1117 &blobs[i].cbData);
1119 if (ret)
1121 qsort(blobs, rdn->cRDNAttr, sizeof(CRYPT_DER_BLOB),
1122 BLOBComp);
1123 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF;
1124 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1125 &lenBytes);
1126 pbEncoded += lenBytes;
1127 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1129 memcpy(pbEncoded, blobs[i].pbData, blobs[i].cbData);
1130 pbEncoded += blobs[i].cbData;
1135 *pcbEncoded = bytesNeeded;
1137 if (blobs)
1139 for (i = 0; i < rdn->cRDNAttr; i++)
1140 CryptMemFree(blobs[i].pbData);
1143 __EXCEPT(page_fault)
1145 SetLastError(STATUS_ACCESS_VIOLATION);
1146 ret = FALSE;
1148 __ENDTRY
1149 CryptMemFree(blobs);
1150 return ret;
1153 static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
1154 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1155 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1157 BOOL ret;
1159 __TRY
1161 const CERT_NAME_INFO *info = (const CERT_NAME_INFO *)pvStructInfo;
1162 DWORD bytesNeeded = 0, lenBytes, size, i;
1164 TRACE("encoding name with %ld RDNs\n", info->cRDN);
1165 ret = TRUE;
1166 for (i = 0; ret && i < info->cRDN; i++)
1168 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i], NULL,
1169 &size);
1170 if (ret)
1171 bytesNeeded += size;
1173 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1174 bytesNeeded += 1 + lenBytes;
1175 if (ret)
1177 if (!pbEncoded)
1178 *pcbEncoded = bytesNeeded;
1179 else
1181 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1182 pbEncoded, pcbEncoded, bytesNeeded)))
1184 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1185 pbEncoded = *(BYTE **)pbEncoded;
1186 *pbEncoded++ = ASN_SEQUENCEOF;
1187 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1188 &lenBytes);
1189 pbEncoded += lenBytes;
1190 for (i = 0; ret && i < info->cRDN; i++)
1192 size = bytesNeeded;
1193 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType,
1194 &info->rgRDN[i], pbEncoded, &size);
1195 if (ret)
1197 pbEncoded += size;
1198 bytesNeeded -= size;
1205 __EXCEPT(page_fault)
1207 SetLastError(STATUS_ACCESS_VIOLATION);
1208 ret = FALSE;
1210 __ENDTRY
1211 return ret;
1214 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
1215 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1216 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1218 BOOL val = *(const BOOL *)pvStructInfo, ret;
1220 TRACE("%d\n", val);
1222 if (!pbEncoded)
1224 *pcbEncoded = 3;
1225 ret = TRUE;
1227 else if (*pcbEncoded < 3)
1229 *pcbEncoded = 3;
1230 SetLastError(ERROR_MORE_DATA);
1231 ret = FALSE;
1233 else
1235 *pcbEncoded = 3;
1236 *pbEncoded++ = ASN_BOOL;
1237 *pbEncoded++ = 1;
1238 *pbEncoded++ = val ? 0xff : 0;
1239 ret = TRUE;
1241 TRACE("returning %d (%08lx)\n", ret, GetLastError());
1242 return ret;
1245 static BOOL CRYPT_AsnEncodeAltNameEntry(const CERT_ALT_NAME_ENTRY *entry,
1246 BYTE *pbEncoded, DWORD *pcbEncoded)
1248 BOOL ret;
1249 DWORD dataLen;
1251 ret = TRUE;
1252 switch (entry->dwAltNameChoice)
1254 case CERT_ALT_NAME_RFC822_NAME:
1255 case CERT_ALT_NAME_DNS_NAME:
1256 case CERT_ALT_NAME_URL:
1257 if (entry->u.pwszURL)
1259 DWORD i;
1261 /* Not + 1: don't encode the NULL-terminator */
1262 dataLen = lstrlenW(entry->u.pwszURL);
1263 for (i = 0; ret && i < dataLen; i++)
1265 if (entry->u.pwszURL[i] > 0x7f)
1267 SetLastError(CRYPT_E_INVALID_IA5_STRING);
1268 ret = FALSE;
1269 *pcbEncoded = i;
1273 else
1274 dataLen = 0;
1275 break;
1276 case CERT_ALT_NAME_IP_ADDRESS:
1277 dataLen = entry->u.IPAddress.cbData;
1278 break;
1279 case CERT_ALT_NAME_REGISTERED_ID:
1280 /* FIXME: encode OID */
1281 case CERT_ALT_NAME_OTHER_NAME:
1282 case CERT_ALT_NAME_DIRECTORY_NAME:
1283 FIXME("name type %ld unimplemented\n", entry->dwAltNameChoice);
1284 return FALSE;
1285 default:
1286 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1287 return FALSE;
1289 if (ret)
1291 DWORD bytesNeeded, lenBytes;
1293 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1294 bytesNeeded = 1 + dataLen + lenBytes;
1295 if (!pbEncoded)
1296 *pcbEncoded = bytesNeeded;
1297 else if (*pcbEncoded < bytesNeeded)
1299 SetLastError(ERROR_MORE_DATA);
1300 *pcbEncoded = bytesNeeded;
1301 ret = FALSE;
1303 else
1305 *pbEncoded++ = ASN_CONTEXT | (entry->dwAltNameChoice - 1);
1306 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1307 pbEncoded += lenBytes;
1308 switch (entry->dwAltNameChoice)
1310 case CERT_ALT_NAME_RFC822_NAME:
1311 case CERT_ALT_NAME_DNS_NAME:
1312 case CERT_ALT_NAME_URL:
1314 DWORD i;
1316 for (i = 0; i < dataLen; i++)
1317 *pbEncoded++ = (BYTE)entry->u.pwszURL[i];
1318 break;
1320 case CERT_ALT_NAME_IP_ADDRESS:
1321 memcpy(pbEncoded, entry->u.IPAddress.pbData, dataLen);
1322 break;
1324 if (ret)
1325 *pcbEncoded = bytesNeeded;
1328 TRACE("returning %d (%08lx)\n", ret, GetLastError());
1329 return ret;
1332 static BOOL WINAPI CRYPT_AsnEncodeAltName(DWORD dwCertEncodingType,
1333 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1334 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1336 BOOL ret;
1338 __TRY
1340 const CERT_ALT_NAME_INFO *info =
1341 (const CERT_ALT_NAME_INFO *)pvStructInfo;
1343 DWORD bytesNeeded, dataLen, lenBytes, i;
1345 ret = TRUE;
1346 /* FIXME: should check that cAltEntry is not bigger than 0xff, since we
1347 * can't encode an erroneous entry index if it's bigger than this.
1349 for (i = 0, dataLen = 0; ret && i < info->cAltEntry; i++)
1351 DWORD len;
1353 ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i], NULL,
1354 &len);
1355 if (ret)
1356 dataLen += len;
1357 else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
1359 /* CRYPT_AsnEncodeAltNameEntry encoded the index of
1360 * the bad character, now set the index of the bad
1361 * entry
1363 *pcbEncoded = (BYTE)i <<
1364 CERT_ALT_NAME_ENTRY_ERR_INDEX_SHIFT | len;
1367 if (ret)
1369 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1370 bytesNeeded = 1 + lenBytes + dataLen;
1371 if (!pbEncoded)
1373 *pcbEncoded = bytesNeeded;
1374 ret = TRUE;
1376 else
1378 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1379 pbEncoded, pcbEncoded, bytesNeeded)))
1381 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1382 pbEncoded = *(BYTE **)pbEncoded;
1383 *pbEncoded++ = ASN_SEQUENCEOF;
1384 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1385 pbEncoded += lenBytes;
1386 for (i = 0; ret && i < info->cAltEntry; i++)
1388 DWORD len = dataLen;
1390 ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i],
1391 pbEncoded, &len);
1392 if (ret)
1394 pbEncoded += len;
1395 dataLen -= len;
1402 __EXCEPT(page_fault)
1404 SetLastError(STATUS_ACCESS_VIOLATION);
1405 ret = FALSE;
1407 __ENDTRY
1408 return ret;
1411 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
1412 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1413 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1415 BOOL ret;
1417 __TRY
1419 const CERT_BASIC_CONSTRAINTS2_INFO *info =
1420 (const CERT_BASIC_CONSTRAINTS2_INFO *)pvStructInfo;
1421 struct AsnEncodeSequenceItem items[2] = { { 0 } };
1422 DWORD cItem = 0;
1424 if (info->fCA)
1426 items[cItem].pvStructInfo = &info->fCA;
1427 items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
1428 cItem++;
1430 if (info->fPathLenConstraint)
1432 items[cItem].pvStructInfo = &info->dwPathLenConstraint;
1433 items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
1434 cItem++;
1436 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
1437 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1439 __EXCEPT(page_fault)
1441 SetLastError(STATUS_ACCESS_VIOLATION);
1442 ret = FALSE;
1444 __ENDTRY
1445 return ret;
1448 static BOOL WINAPI CRYPT_AsnEncodeRsaPubKey(DWORD dwCertEncodingType,
1449 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1450 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1452 BOOL ret;
1454 __TRY
1456 const BLOBHEADER *hdr =
1457 (const BLOBHEADER *)pvStructInfo;
1459 if (hdr->bType != PUBLICKEYBLOB)
1461 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1462 ret = FALSE;
1464 else
1466 const RSAPUBKEY *rsaPubKey = (const RSAPUBKEY *)
1467 ((const BYTE *)pvStructInfo + sizeof(BLOBHEADER));
1468 CRYPT_INTEGER_BLOB blob = { rsaPubKey->bitlen / 8,
1469 (BYTE *)pvStructInfo + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) };
1470 struct AsnEncodeSequenceItem items[] = {
1471 { &blob, CRYPT_AsnEncodeUnsignedInteger, 0 },
1472 { &rsaPubKey->pubexp, CRYPT_AsnEncodeInt, 0 },
1475 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
1476 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
1477 pcbEncoded);
1480 __EXCEPT(page_fault)
1482 SetLastError(STATUS_ACCESS_VIOLATION);
1483 ret = FALSE;
1485 __ENDTRY
1486 return ret;
1489 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
1490 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1491 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1493 BOOL ret;
1495 __TRY
1497 const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo;
1498 DWORD bytesNeeded, lenBytes;
1500 TRACE("(%ld, %p), %08lx, %p, %p, %ld\n", blob->cbData, blob->pbData,
1501 dwFlags, pEncodePara, pbEncoded, *pcbEncoded);
1503 CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
1504 bytesNeeded = 1 + lenBytes + blob->cbData;
1505 if (!pbEncoded)
1507 *pcbEncoded = bytesNeeded;
1508 ret = TRUE;
1510 else
1512 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1513 pcbEncoded, bytesNeeded)))
1515 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1516 pbEncoded = *(BYTE **)pbEncoded;
1517 *pbEncoded++ = ASN_OCTETSTRING;
1518 CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
1519 pbEncoded += lenBytes;
1520 if (blob->cbData)
1521 memcpy(pbEncoded, blob->pbData, blob->cbData);
1525 __EXCEPT(page_fault)
1527 SetLastError(STATUS_ACCESS_VIOLATION);
1528 ret = FALSE;
1530 __ENDTRY
1531 TRACE("returning %d (%08lx)\n", ret, GetLastError());
1532 return ret;
1535 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
1536 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1537 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1539 BOOL ret;
1541 __TRY
1543 const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
1544 DWORD bytesNeeded, lenBytes, dataBytes;
1545 BYTE unusedBits;
1547 /* yep, MS allows cUnusedBits to be >= 8 */
1548 if (!blob->cUnusedBits)
1550 dataBytes = blob->cbData;
1551 unusedBits = 0;
1553 else if (blob->cbData * 8 > blob->cUnusedBits)
1555 dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
1556 unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
1557 blob->cUnusedBits;
1559 else
1561 dataBytes = 0;
1562 unusedBits = 0;
1564 CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
1565 bytesNeeded = 1 + lenBytes + dataBytes + 1;
1566 if (!pbEncoded)
1568 *pcbEncoded = bytesNeeded;
1569 ret = TRUE;
1571 else
1573 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1574 pcbEncoded, bytesNeeded)))
1576 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1577 pbEncoded = *(BYTE **)pbEncoded;
1578 *pbEncoded++ = ASN_BITSTRING;
1579 CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
1580 pbEncoded += lenBytes;
1581 *pbEncoded++ = unusedBits;
1582 if (dataBytes)
1584 BYTE mask = 0xff << unusedBits;
1586 if (dataBytes > 1)
1588 memcpy(pbEncoded, blob->pbData, dataBytes - 1);
1589 pbEncoded += dataBytes - 1;
1591 *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
1596 __EXCEPT(page_fault)
1598 SetLastError(STATUS_ACCESS_VIOLATION);
1599 ret = FALSE;
1601 __ENDTRY
1602 return ret;
1605 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
1606 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1607 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1609 BOOL ret;
1611 __TRY
1613 const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
1614 CRYPT_BIT_BLOB newBlob = { blob->cbData, NULL, blob->cUnusedBits };
1616 ret = TRUE;
1617 if (newBlob.cbData)
1619 newBlob.pbData = CryptMemAlloc(newBlob.cbData);
1620 if (newBlob.pbData)
1622 DWORD i;
1624 for (i = 0; i < newBlob.cbData; i++)
1625 newBlob.pbData[newBlob.cbData - i - 1] = blob->pbData[i];
1627 else
1628 ret = FALSE;
1630 if (ret)
1631 ret = CRYPT_AsnEncodeBits(dwCertEncodingType, lpszStructType,
1632 &newBlob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1633 CryptMemFree(newBlob.pbData);
1635 __EXCEPT(page_fault)
1637 SetLastError(STATUS_ACCESS_VIOLATION);
1638 ret = FALSE;
1640 __ENDTRY
1641 return ret;
1644 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
1645 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1646 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1648 CRYPT_INTEGER_BLOB blob = { sizeof(INT), (BYTE *)pvStructInfo };
1650 return CRYPT_AsnEncodeInteger(dwCertEncodingType, X509_MULTI_BYTE_INTEGER,
1651 &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1654 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
1655 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1656 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1658 BOOL ret;
1660 __TRY
1662 DWORD significantBytes, lenBytes;
1663 BYTE padByte = 0, bytesNeeded;
1664 BOOL pad = FALSE;
1665 const CRYPT_INTEGER_BLOB *blob =
1666 (const CRYPT_INTEGER_BLOB *)pvStructInfo;
1668 significantBytes = blob->cbData;
1669 if (significantBytes)
1671 if (blob->pbData[significantBytes - 1] & 0x80)
1673 /* negative, lop off leading (little-endian) 0xffs */
1674 for (; significantBytes > 0 &&
1675 blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
1677 if (blob->pbData[significantBytes - 1] < 0x80)
1679 padByte = 0xff;
1680 pad = TRUE;
1683 else
1685 /* positive, lop off leading (little-endian) zeroes */
1686 for (; significantBytes > 0 &&
1687 !blob->pbData[significantBytes - 1]; significantBytes--)
1689 if (significantBytes == 0)
1690 significantBytes = 1;
1691 if (blob->pbData[significantBytes - 1] > 0x7f)
1693 padByte = 0;
1694 pad = TRUE;
1698 if (pad)
1699 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
1700 else
1701 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
1702 bytesNeeded = 1 + lenBytes + significantBytes;
1703 if (pad)
1704 bytesNeeded++;
1705 if (!pbEncoded)
1707 *pcbEncoded = bytesNeeded;
1708 ret = TRUE;
1710 else
1712 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1713 pcbEncoded, bytesNeeded)))
1715 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1716 pbEncoded = *(BYTE **)pbEncoded;
1717 *pbEncoded++ = ASN_INTEGER;
1718 if (pad)
1720 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
1721 pbEncoded += lenBytes;
1722 *pbEncoded++ = padByte;
1724 else
1726 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
1727 pbEncoded += lenBytes;
1729 for (; significantBytes > 0; significantBytes--)
1730 *(pbEncoded++) = blob->pbData[significantBytes - 1];
1734 __EXCEPT(page_fault)
1736 SetLastError(STATUS_ACCESS_VIOLATION);
1737 ret = FALSE;
1739 __ENDTRY
1740 return ret;
1743 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
1744 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1745 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1747 BOOL ret;
1749 __TRY
1751 DWORD significantBytes, lenBytes;
1752 BYTE bytesNeeded;
1753 BOOL pad = FALSE;
1754 const CRYPT_INTEGER_BLOB *blob =
1755 (const CRYPT_INTEGER_BLOB *)pvStructInfo;
1757 significantBytes = blob->cbData;
1758 if (significantBytes)
1760 /* positive, lop off leading (little-endian) zeroes */
1761 for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
1762 significantBytes--)
1764 if (significantBytes == 0)
1765 significantBytes = 1;
1766 if (blob->pbData[significantBytes - 1] > 0x7f)
1767 pad = TRUE;
1769 if (pad)
1770 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
1771 else
1772 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
1773 bytesNeeded = 1 + lenBytes + significantBytes;
1774 if (pad)
1775 bytesNeeded++;
1776 if (!pbEncoded)
1778 *pcbEncoded = bytesNeeded;
1779 ret = TRUE;
1781 else
1783 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1784 pcbEncoded, bytesNeeded)))
1786 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1787 pbEncoded = *(BYTE **)pbEncoded;
1788 *pbEncoded++ = ASN_INTEGER;
1789 if (pad)
1791 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
1792 pbEncoded += lenBytes;
1793 *pbEncoded++ = 0;
1795 else
1797 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
1798 pbEncoded += lenBytes;
1800 for (; significantBytes > 0; significantBytes--)
1801 *(pbEncoded++) = blob->pbData[significantBytes - 1];
1805 __EXCEPT(page_fault)
1807 SetLastError(STATUS_ACCESS_VIOLATION);
1808 ret = FALSE;
1810 __ENDTRY
1811 return ret;
1814 static BOOL WINAPI CRYPT_AsnEncodeEnumerated(DWORD dwCertEncodingType,
1815 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1816 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1818 CRYPT_INTEGER_BLOB blob;
1819 BOOL ret;
1821 /* Encode as an unsigned integer, then change the tag to enumerated */
1822 blob.cbData = sizeof(DWORD);
1823 blob.pbData = (BYTE *)pvStructInfo;
1824 ret = CRYPT_AsnEncodeUnsignedInteger(dwCertEncodingType,
1825 X509_MULTI_BYTE_UINT, &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1826 if (ret && pbEncoded)
1828 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1829 pbEncoded = *(BYTE **)pbEncoded;
1830 pbEncoded[0] = ASN_ENUMERATED;
1832 return ret;
1835 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
1836 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1837 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1839 BOOL ret;
1841 __TRY
1843 SYSTEMTIME sysTime;
1844 /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0. I use a
1845 * temporary buffer because the output buffer is not NULL-terminated.
1847 char buf[16];
1848 static const DWORD bytesNeeded = sizeof(buf) - 1;
1850 if (!pbEncoded)
1852 *pcbEncoded = bytesNeeded;
1853 ret = TRUE;
1855 else
1857 /* Sanity check the year, this is a two-digit year format */
1858 ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
1859 &sysTime);
1860 if (ret && (sysTime.wYear < 1950 || sysTime.wYear > 2050))
1862 SetLastError(CRYPT_E_BAD_ENCODE);
1863 ret = FALSE;
1865 if (ret)
1867 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1868 pbEncoded, pcbEncoded, bytesNeeded)))
1870 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1871 pbEncoded = *(BYTE **)pbEncoded;
1872 buf[0] = ASN_UTCTIME;
1873 buf[1] = bytesNeeded - 2;
1874 snprintf(buf + 2, sizeof(buf) - 2,
1875 "%02d%02d%02d%02d%02d%02dZ", sysTime.wYear >= 2000 ?
1876 sysTime.wYear - 2000 : sysTime.wYear - 1900,
1877 sysTime.wDay, sysTime.wMonth, sysTime.wHour,
1878 sysTime.wMinute, sysTime.wSecond);
1879 memcpy(pbEncoded, buf, bytesNeeded);
1884 __EXCEPT(page_fault)
1886 SetLastError(STATUS_ACCESS_VIOLATION);
1887 ret = FALSE;
1889 __ENDTRY
1890 return ret;
1893 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
1894 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1895 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1897 BOOL ret;
1899 __TRY
1901 SYSTEMTIME sysTime;
1902 /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0. I use a
1903 * temporary buffer because the output buffer is not NULL-terminated.
1905 char buf[18];
1906 static const DWORD bytesNeeded = sizeof(buf) - 1;
1908 if (!pbEncoded)
1910 *pcbEncoded = bytesNeeded;
1911 ret = TRUE;
1913 else
1915 ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
1916 &sysTime);
1917 if (ret)
1918 ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1919 pcbEncoded, bytesNeeded);
1920 if (ret)
1922 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1923 pbEncoded = *(BYTE **)pbEncoded;
1924 buf[0] = ASN_GENERALTIME;
1925 buf[1] = bytesNeeded - 2;
1926 snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
1927 sysTime.wYear, sysTime.wDay, sysTime.wMonth, sysTime.wHour,
1928 sysTime.wMinute, sysTime.wSecond);
1929 memcpy(pbEncoded, buf, bytesNeeded);
1933 __EXCEPT(page_fault)
1935 SetLastError(STATUS_ACCESS_VIOLATION);
1936 ret = FALSE;
1938 __ENDTRY
1939 return ret;
1942 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
1943 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1944 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1946 BOOL ret;
1948 __TRY
1950 SYSTEMTIME sysTime;
1952 /* Check the year, if it's in the UTCTime range call that encode func */
1953 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
1954 return FALSE;
1955 if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
1956 ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
1957 pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1958 else
1959 ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
1960 lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
1961 pcbEncoded);
1963 __EXCEPT(page_fault)
1965 SetLastError(STATUS_ACCESS_VIOLATION);
1966 ret = FALSE;
1968 __ENDTRY
1969 return ret;
1972 static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
1973 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1974 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1976 BOOL ret;
1978 __TRY
1980 DWORD bytesNeeded, dataLen, lenBytes, i;
1981 const CRYPT_SEQUENCE_OF_ANY *seq =
1982 (const CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
1984 for (i = 0, dataLen = 0; i < seq->cValue; i++)
1985 dataLen += seq->rgValue[i].cbData;
1986 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1987 bytesNeeded = 1 + lenBytes + dataLen;
1988 if (!pbEncoded)
1990 *pcbEncoded = bytesNeeded;
1991 ret = TRUE;
1993 else
1995 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1996 pcbEncoded, bytesNeeded)))
1998 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1999 pbEncoded = *(BYTE **)pbEncoded;
2000 *pbEncoded++ = ASN_SEQUENCEOF;
2001 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2002 pbEncoded += lenBytes;
2003 for (i = 0; i < seq->cValue; i++)
2005 memcpy(pbEncoded, seq->rgValue[i].pbData,
2006 seq->rgValue[i].cbData);
2007 pbEncoded += seq->rgValue[i].cbData;
2012 __EXCEPT(page_fault)
2014 SetLastError(STATUS_ACCESS_VIOLATION);
2015 ret = FALSE;
2017 __ENDTRY
2018 return ret;
2021 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
2022 const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
2023 void *pvEncoded, DWORD *pcbEncoded)
2025 static HCRYPTOIDFUNCSET set = NULL;
2026 BOOL ret = FALSE;
2027 CryptEncodeObjectExFunc encodeFunc = NULL;
2028 HCRYPTOIDFUNCADDR hFunc = NULL;
2030 TRACE("(0x%08lx, %s, %p, 0x%08lx, %p, %p, %p)\n", dwCertEncodingType,
2031 debugstr_a(lpszStructType), pvStructInfo, dwFlags, pEncodePara,
2032 pvEncoded, pcbEncoded);
2034 if (!pvEncoded && !pcbEncoded)
2036 SetLastError(ERROR_INVALID_PARAMETER);
2037 return FALSE;
2039 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
2040 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
2042 SetLastError(ERROR_FILE_NOT_FOUND);
2043 return FALSE;
2046 SetLastError(NOERROR);
2047 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG && pvEncoded)
2048 *(BYTE **)pvEncoded = NULL;
2049 if (!HIWORD(lpszStructType))
2051 switch (LOWORD(lpszStructType))
2053 case (WORD)X509_CERT:
2054 encodeFunc = CRYPT_AsnEncodeCert;
2055 break;
2056 case (WORD)X509_CERT_TO_BE_SIGNED:
2057 encodeFunc = CRYPT_AsnEncodeCertInfo;
2058 break;
2059 case (WORD)X509_CERT_CRL_TO_BE_SIGNED:
2060 encodeFunc = CRYPT_AsnEncodeCRLInfo;
2061 break;
2062 case (WORD)X509_EXTENSIONS:
2063 encodeFunc = CRYPT_AsnEncodeExtensions;
2064 break;
2065 case (WORD)X509_NAME:
2066 encodeFunc = CRYPT_AsnEncodeName;
2067 break;
2068 case (WORD)X509_PUBLIC_KEY_INFO:
2069 encodeFunc = CRYPT_AsnEncodePubKeyInfo;
2070 break;
2071 case (WORD)X509_ALTERNATE_NAME:
2072 encodeFunc = CRYPT_AsnEncodeAltName;
2073 break;
2074 case (WORD)X509_BASIC_CONSTRAINTS2:
2075 encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
2076 break;
2077 case (WORD)RSA_CSP_PUBLICKEYBLOB:
2078 encodeFunc = CRYPT_AsnEncodeRsaPubKey;
2079 break;
2080 case (WORD)X509_OCTET_STRING:
2081 encodeFunc = CRYPT_AsnEncodeOctets;
2082 break;
2083 case (WORD)X509_BITS:
2084 case (WORD)X509_KEY_USAGE:
2085 encodeFunc = CRYPT_AsnEncodeBits;
2086 break;
2087 case (WORD)X509_INTEGER:
2088 encodeFunc = CRYPT_AsnEncodeInt;
2089 break;
2090 case (WORD)X509_MULTI_BYTE_INTEGER:
2091 encodeFunc = CRYPT_AsnEncodeInteger;
2092 break;
2093 case (WORD)X509_MULTI_BYTE_UINT:
2094 encodeFunc = CRYPT_AsnEncodeUnsignedInteger;
2095 break;
2096 case (WORD)X509_ENUMERATED:
2097 encodeFunc = CRYPT_AsnEncodeEnumerated;
2098 break;
2099 case (WORD)X509_CHOICE_OF_TIME:
2100 encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
2101 break;
2102 case (WORD)X509_SEQUENCE_OF_ANY:
2103 encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
2104 break;
2105 case (WORD)PKCS_UTC_TIME:
2106 encodeFunc = CRYPT_AsnEncodeUtcTime;
2107 break;
2108 default:
2109 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
2112 else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
2113 encodeFunc = CRYPT_AsnEncodeExtensions;
2114 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
2115 encodeFunc = CRYPT_AsnEncodeUtcTime;
2116 else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
2117 encodeFunc = CRYPT_AsnEncodeEnumerated;
2118 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
2119 encodeFunc = CRYPT_AsnEncodeBits;
2120 else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
2121 encodeFunc = CRYPT_AsnEncodeOctets;
2122 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
2123 encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
2124 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
2125 encodeFunc = CRYPT_AsnEncodeAltName;
2126 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
2127 encodeFunc = CRYPT_AsnEncodeAltName;
2128 else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION))
2129 encodeFunc = CRYPT_AsnEncodeAltName;
2130 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
2131 encodeFunc = CRYPT_AsnEncodeAltName;
2132 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
2133 encodeFunc = CRYPT_AsnEncodeAltName;
2134 else
2135 TRACE("OID %s not found or unimplemented, looking for DLL\n",
2136 debugstr_a(lpszStructType));
2137 if (!encodeFunc)
2139 if (!set)
2140 set = CryptInitOIDFunctionSet(CRYPT_OID_ENCODE_OBJECT_EX_FUNC, 0);
2141 CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
2142 (void **)&encodeFunc, &hFunc);
2144 if (encodeFunc)
2145 ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
2146 dwFlags, pEncodePara, pvEncoded, pcbEncoded);
2147 else
2148 SetLastError(ERROR_FILE_NOT_FOUND);
2149 if (hFunc)
2150 CryptFreeOIDFunctionAddress(hFunc, 0);
2151 return ret;
2154 BOOL WINAPI CryptDecodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
2155 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo,
2156 DWORD *pcbStructInfo)
2158 static HCRYPTOIDFUNCSET set = NULL;
2159 BOOL ret = FALSE;
2160 CryptDecodeObjectFunc pCryptDecodeObject;
2161 HCRYPTOIDFUNCADDR hFunc;
2163 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p)\n", dwCertEncodingType,
2164 debugstr_a(lpszStructType), pbEncoded, cbEncoded, dwFlags,
2165 pvStructInfo, pcbStructInfo);
2167 if (!pvStructInfo && !pcbStructInfo)
2169 SetLastError(ERROR_INVALID_PARAMETER);
2170 return FALSE;
2173 /* Try registered DLL first.. */
2174 if (!set)
2175 set = CryptInitOIDFunctionSet(CRYPT_OID_DECODE_OBJECT_FUNC, 0);
2176 CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
2177 (void **)&pCryptDecodeObject, &hFunc);
2178 if (pCryptDecodeObject)
2180 ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType,
2181 pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
2182 CryptFreeOIDFunctionAddress(hFunc, 0);
2184 else
2186 /* If not, use CryptDecodeObjectEx */
2187 ret = CryptDecodeObjectEx(dwCertEncodingType, lpszStructType, pbEncoded,
2188 cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo);
2190 return ret;
2193 /* Gets the number of length bytes from the given (leading) length byte */
2194 #define GET_LEN_BYTES(b) ((b) <= 0x7f ? 1 : 1 + ((b) & 0x7f))
2196 /* Helper function to get the encoded length of the data starting at pbEncoded,
2197 * where pbEncoded[0] is the tag. If the data are too short to contain a
2198 * length or if the length is too large for cbEncoded, sets an appropriate
2199 * error code and returns FALSE.
2201 static BOOL WINAPI CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded,
2202 DWORD *len)
2204 BOOL ret;
2206 if (cbEncoded <= 1)
2208 SetLastError(CRYPT_E_ASN1_CORRUPT);
2209 ret = FALSE;
2211 else if (pbEncoded[1] <= 0x7f)
2213 if (pbEncoded[1] + 1 > cbEncoded)
2215 SetLastError(CRYPT_E_ASN1_EOD);
2216 ret = FALSE;
2218 else
2220 *len = pbEncoded[1];
2221 ret = TRUE;
2224 else
2226 BYTE lenLen = GET_LEN_BYTES(pbEncoded[1]);
2228 if (lenLen > sizeof(DWORD) + 1)
2230 SetLastError(CRYPT_E_ASN1_LARGE);
2231 ret = FALSE;
2233 else if (lenLen + 2 > cbEncoded)
2235 SetLastError(CRYPT_E_ASN1_CORRUPT);
2236 ret = FALSE;
2238 else
2240 DWORD out = 0;
2242 pbEncoded += 2;
2243 while (--lenLen)
2245 out <<= 8;
2246 out |= *pbEncoded++;
2248 if (out + lenLen + 1 > cbEncoded)
2250 SetLastError(CRYPT_E_ASN1_EOD);
2251 ret = FALSE;
2253 else
2255 *len = out;
2256 ret = TRUE;
2260 return ret;
2263 /* Helper function to check *pcbStructInfo, set it to the required size, and
2264 * optionally to allocate memory. Assumes pvStructInfo is not NULL.
2265 * If CRYPT_DECODE_ALLOC_FLAG is set in dwFlags, *pvStructInfo will be set to a
2266 * pointer to the newly allocated memory.
2268 static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags,
2269 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo,
2270 DWORD bytesNeeded)
2272 BOOL ret = TRUE;
2274 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2276 if (pDecodePara && pDecodePara->pfnAlloc)
2277 *(BYTE **)pvStructInfo = pDecodePara->pfnAlloc(bytesNeeded);
2278 else
2279 *(BYTE **)pvStructInfo = LocalAlloc(0, bytesNeeded);
2280 if (!*(BYTE **)pvStructInfo)
2281 ret = FALSE;
2282 else
2283 *pcbStructInfo = bytesNeeded;
2285 else if (*pcbStructInfo < bytesNeeded)
2287 *pcbStructInfo = bytesNeeded;
2288 SetLastError(ERROR_MORE_DATA);
2289 ret = FALSE;
2291 return ret;
2294 /* A few of the members need explanation:
2295 * offset:
2296 * A sequence is decoded into a struct. The offset member is the
2297 * offset of this item within that struct.
2298 * decodeFunc:
2299 * The decoder function to use. If this is NULL, then the member isn't
2300 * decoded, but minSize space is reserved for it.
2301 * minSize:
2302 * The minimum amount of space occupied after decoding. You must set this.
2303 * optional:
2304 * If true, and a decoding function fails with CRYPT_E_ASN1_BADTAG, then
2305 * minSize space is filled with 0 for this member. (Any other failure
2306 * results in CRYPT_AsnDecodeSequence failing.)
2307 * hasPointer, pointerOffset, minSize:
2308 * If the item has dynamic data, set hasPointer to TRUE, pointerOffset to
2309 * the offset within the (outer) struct of the data pointer (or to the
2310 * first data pointer, if more than one exist).
2311 * size:
2312 * Used by CRYPT_AsnDecodeSequence, not for your use.
2314 struct AsnDecodeSequenceItem
2316 DWORD offset;
2317 CryptDecodeObjectExFunc decodeFunc;
2318 DWORD minSize;
2319 BOOL optional;
2320 BOOL hasPointer;
2321 DWORD pointerOffset;
2322 DWORD size;
2325 /* This decodes an arbitrary sequence into a contiguous block of memory
2326 * (basically, a struct.) Each element being decoded is described by a struct
2327 * AsnDecodeSequenceItem, see above.
2328 * startingPointer is an optional pointer to the first place where dynamic
2329 * data will be stored. If you know the starting offset, you may pass it
2330 * here. Otherwise, pass NULL, and one will be inferred from the items.
2331 * Each item decoder is never called with CRYPT_DECODE_ALLOC_FLAG set.
2332 * If any undecoded data are left over, fails with CRYPT_E_ASN1_CORRUPT.
2334 static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType,
2335 struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
2336 DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
2337 void *pvStructInfo, DWORD *pcbStructInfo, void *startingPointer)
2339 BOOL ret;
2341 TRACE("%p, %ld, %p, %ld, %08lx, %p, %p, %ld, %p\n", items, cItem, pbEncoded,
2342 cbEncoded, dwFlags, pDecodePara, pvStructInfo, *pcbStructInfo,
2343 startingPointer);
2345 if (pbEncoded[0] == ASN_SEQUENCE)
2347 DWORD dataLen;
2349 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2351 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2352 DWORD i, bytesNeeded = 0, minSize = 0;
2353 const BYTE *ptr;
2355 ptr = pbEncoded + 1 + lenBytes;
2356 for (i = 0; ret && i < cItem; i++)
2358 DWORD nextItemLen;
2360 minSize += items[i].minSize;
2361 if (cbEncoded - (ptr - pbEncoded) != 0)
2363 if ((ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
2364 &nextItemLen)))
2366 BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
2368 if (items[i].decodeFunc)
2370 TRACE("sizing item %ld\n", i);
2371 ret = items[i].decodeFunc(dwCertEncodingType, NULL,
2372 ptr, 1 + nextItemLenBytes + nextItemLen,
2373 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL,
2374 &items[i].size);
2375 if (ret)
2377 /* Account for alignment padding */
2378 bytesNeeded += items[i].size;
2379 if (items[i].size % sizeof(DWORD))
2380 bytesNeeded += sizeof(DWORD) -
2381 items[i].size % sizeof(DWORD);
2382 ptr += 1 + nextItemLenBytes + nextItemLen;
2384 else if (items[i].optional &&
2385 GetLastError() == CRYPT_E_ASN1_BADTAG)
2387 TRACE("skipping optional item %ld\n", i);
2388 bytesNeeded += items[i].minSize;
2389 SetLastError(NOERROR);
2390 ret = TRUE;
2392 else
2393 TRACE("item %ld failed: %08lx\n", i,
2394 GetLastError());
2396 else
2397 bytesNeeded += items[i].minSize;
2400 else if (items[i].optional)
2401 bytesNeeded += items[i].minSize;
2402 else
2404 SetLastError(CRYPT_E_ASN1_CORRUPT);
2405 ret = FALSE;
2408 if (cbEncoded - (ptr - pbEncoded) != 0)
2410 TRACE("%ld remaining bytes, failing\n", cbEncoded -
2411 (ptr - pbEncoded));
2412 SetLastError(CRYPT_E_ASN1_CORRUPT);
2413 ret = FALSE;
2415 if (ret)
2417 if (!pvStructInfo)
2418 *pcbStructInfo = bytesNeeded;
2419 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
2420 pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
2422 BYTE *nextData;
2424 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2425 pvStructInfo = *(BYTE **)pvStructInfo;
2426 if (startingPointer)
2427 nextData = (BYTE *)startingPointer;
2428 else
2429 nextData = (BYTE *)pvStructInfo + minSize;
2430 memset(pvStructInfo, 0, minSize);
2431 ptr = pbEncoded + 1 + lenBytes;
2432 for (i = 0; ret && i < cItem; i++)
2434 if (cbEncoded - (ptr - pbEncoded) != 0)
2436 DWORD nextItemLen;
2437 BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
2439 CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
2440 &nextItemLen);
2441 if (items[i].hasPointer)
2443 *(BYTE **)((BYTE *)pvStructInfo +
2444 items[i].pointerOffset) = nextData;
2446 if (items[i].decodeFunc)
2448 TRACE("decoding item %ld\n", i);
2449 ret = items[i].decodeFunc(dwCertEncodingType,
2450 NULL, ptr, 1 + nextItemLenBytes + nextItemLen,
2451 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
2452 (BYTE *)pvStructInfo + items[i].offset,
2453 &items[i].size);
2454 if (!ret)
2455 TRACE("item %ld failed: %08lx\n", i,
2456 GetLastError());
2458 else
2459 items[i].size = items[i].minSize;
2460 if (ret)
2462 if (items[i].hasPointer &&
2463 items[i].size > items[i].minSize)
2465 nextData += items[i].size -
2466 items[i].minSize;
2467 /* align nextData to DWORD boundaries */
2468 if (items[i].size % sizeof(DWORD))
2470 nextData += sizeof(DWORD) -
2471 items[i].size % sizeof(DWORD);
2474 ptr += 1 + nextItemLenBytes + nextItemLen;
2476 else if (items[i].optional &&
2477 GetLastError() == CRYPT_E_ASN1_BADTAG)
2479 SetLastError(NOERROR);
2480 ret = TRUE;
2483 else if (!items[i].optional)
2485 SetLastError(CRYPT_E_ASN1_CORRUPT);
2486 ret = FALSE;
2493 else
2495 SetLastError(CRYPT_E_ASN1_BADTAG);
2496 ret = FALSE;
2498 TRACE("returning %d (%08lx)\n", ret, GetLastError());
2499 return ret;
2502 /* Decodes a DER-encoded BLOB into a CRYPT_DER_BLOB struct pointed to by
2503 * pvStructInfo. The BLOB must be non-empty, otherwise the last error is set
2504 * to CRYPT_E_ASN1_CORRUPT.
2505 * Warning: assumes the CRYPT_DER_BLOB pointed to by pvStructInfo has pbData
2506 * set!
2508 static BOOL WINAPI CRYPT_AsnDecodeDerBlob(DWORD dwCertEncodingType,
2509 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2510 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2512 BOOL ret;
2513 DWORD dataLen;
2515 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2517 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2518 DWORD bytesNeeded = sizeof(CRYPT_DER_BLOB);
2520 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
2521 bytesNeeded += 1 + lenBytes + dataLen;
2523 if (!pvStructInfo)
2524 *pcbStructInfo = bytesNeeded;
2525 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
2526 pvStructInfo, pcbStructInfo, bytesNeeded)))
2528 CRYPT_DER_BLOB *blob = (CRYPT_DER_BLOB *)pvStructInfo;
2530 blob->cbData = 1 + lenBytes + dataLen;
2531 if (blob->cbData)
2533 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
2534 blob->pbData = (BYTE *)pbEncoded;
2535 else
2537 assert(blob->pbData);
2538 memcpy(blob->pbData, pbEncoded, blob->cbData);
2541 else
2543 SetLastError(CRYPT_E_ASN1_CORRUPT);
2544 ret = FALSE;
2548 return ret;
2551 /* Like CRYPT_AsnDecodeBitsInternal, but swaps the bytes */
2552 static BOOL WINAPI CRYPT_AsnDecodeBitsSwapBytes(DWORD dwCertEncodingType,
2553 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2554 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2556 BOOL ret;
2558 TRACE("(%p, %ld, 0x%08lx, %p, %p, %ld)\n", pbEncoded, cbEncoded, dwFlags,
2559 pDecodePara, pvStructInfo, *pcbStructInfo);
2561 /* Can't use the CRYPT_DECODE_NOCOPY_FLAG, because we modify the bytes in-
2562 * place.
2564 ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType, lpszStructType,
2565 pbEncoded, cbEncoded, dwFlags & ~CRYPT_DECODE_NOCOPY_FLAG, pDecodePara,
2566 pvStructInfo, pcbStructInfo);
2567 if (ret && pvStructInfo)
2569 CRYPT_BIT_BLOB *blob = (CRYPT_BIT_BLOB *)pvStructInfo;
2571 if (blob->cbData)
2573 DWORD i;
2574 BYTE temp;
2576 for (i = 0; i < blob->cbData / 2; i++)
2578 temp = blob->pbData[i];
2579 blob->pbData[i] = blob->pbData[blob->cbData - i - 1];
2580 blob->pbData[blob->cbData - i - 1] = temp;
2584 TRACE("returning %d (%08lx)\n", ret, GetLastError());
2585 return ret;
2588 static BOOL WINAPI CRYPT_AsnDecodeCert(DWORD dwCertEncodingType,
2589 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2590 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2592 BOOL ret = TRUE;
2594 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
2595 pDecodePara, pvStructInfo, *pcbStructInfo);
2597 __TRY
2599 struct AsnDecodeSequenceItem items[] = {
2600 { offsetof(CERT_SIGNED_CONTENT_INFO, ToBeSigned),
2601 CRYPT_AsnDecodeDerBlob, sizeof(CRYPT_DER_BLOB), FALSE, TRUE,
2602 offsetof(CERT_SIGNED_CONTENT_INFO, ToBeSigned.pbData), 0 },
2603 { offsetof(CERT_SIGNED_CONTENT_INFO, SignatureAlgorithm),
2604 CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
2605 FALSE, TRUE, offsetof(CERT_SIGNED_CONTENT_INFO,
2606 SignatureAlgorithm.pszObjId), 0 },
2607 { offsetof(CERT_SIGNED_CONTENT_INFO, Signature),
2608 CRYPT_AsnDecodeBitsSwapBytes, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE,
2609 offsetof(CERT_SIGNED_CONTENT_INFO, Signature.pbData), 0 },
2612 if (dwFlags & CRYPT_DECODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG)
2613 items[2].decodeFunc = CRYPT_AsnDecodeBitsInternal;
2614 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2615 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2616 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
2618 __EXCEPT(page_fault)
2620 SetLastError(STATUS_ACCESS_VIOLATION);
2621 ret = FALSE;
2623 __ENDTRY
2624 return ret;
2627 static BOOL WINAPI CRYPT_AsnDecodeCertVersion(DWORD dwCertEncodingType,
2628 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2629 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2631 BOOL ret;
2633 if (pbEncoded[0] == (ASN_CONTEXT | ASN_CONSTRUCTOR))
2635 DWORD dataLen;
2637 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2639 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2641 ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER,
2642 pbEncoded + 1 + lenBytes, dataLen, dwFlags, pDecodePara,
2643 pvStructInfo, pcbStructInfo);
2646 else
2648 SetLastError(CRYPT_E_ASN1_BADTAG);
2649 ret = FALSE;
2651 return ret;
2654 static BOOL WINAPI CRYPT_AsnDecodeValidity(DWORD dwCertEncodingType,
2655 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2656 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2658 BOOL ret;
2660 struct AsnDecodeSequenceItem items[] = {
2661 { offsetof(CERT_PRIVATE_KEY_VALIDITY, NotBefore),
2662 CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 },
2663 { offsetof(CERT_PRIVATE_KEY_VALIDITY, NotAfter),
2664 CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 },
2667 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2668 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2669 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
2670 return ret;
2673 static BOOL WINAPI CRYPT_AsnDecodeCertExtensions(DWORD dwCertEncodingType,
2674 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2675 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2677 BOOL ret;
2679 if (pbEncoded[0] == (ASN_CONTEXT | ASN_CONSTRUCTOR | 3))
2681 DWORD dataLen;
2683 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2685 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2687 ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType,
2688 X509_EXTENSIONS, pbEncoded + 1 + lenBytes, dataLen, dwFlags,
2689 pDecodePara, pvStructInfo, pcbStructInfo);
2692 else
2694 SetLastError(CRYPT_E_ASN1_BADTAG);
2695 ret = FALSE;
2697 return ret;
2700 static BOOL WINAPI CRYPT_AsnDecodeCertInfo(DWORD dwCertEncodingType,
2701 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2702 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2704 BOOL ret = TRUE;
2706 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
2707 pDecodePara, pvStructInfo, *pcbStructInfo);
2709 __TRY
2711 struct AsnDecodeSequenceItem items[] = {
2712 { offsetof(CERT_INFO, dwVersion), CRYPT_AsnDecodeCertVersion,
2713 sizeof(DWORD), TRUE, FALSE, 0, 0 },
2714 { offsetof(CERT_INFO, SerialNumber), CRYPT_AsnDecodeIntegerInternal,
2715 sizeof(CRYPT_INTEGER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
2716 SerialNumber.pbData), 0 },
2717 { offsetof(CERT_INFO, SignatureAlgorithm), CRYPT_AsnDecodeAlgorithmId,
2718 sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE, offsetof(CERT_INFO,
2719 SignatureAlgorithm.pszObjId), 0 },
2720 { offsetof(CERT_INFO, Issuer), CRYPT_AsnDecodeDerBlob,
2721 sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
2722 Issuer.pbData) },
2723 { offsetof(CERT_INFO, NotBefore), CRYPT_AsnDecodeValidity,
2724 sizeof(CERT_PRIVATE_KEY_VALIDITY), FALSE, FALSE, 0 },
2725 { offsetof(CERT_INFO, Subject), CRYPT_AsnDecodeDerBlob,
2726 sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
2727 Subject.pbData) },
2728 { offsetof(CERT_INFO, SubjectPublicKeyInfo), CRYPT_AsnDecodePubKeyInfo,
2729 sizeof(CERT_PUBLIC_KEY_INFO), FALSE, TRUE, offsetof(CERT_INFO,
2730 SubjectPublicKeyInfo.Algorithm.Parameters.pbData), 0 },
2731 { offsetof(CERT_INFO, IssuerUniqueId), CRYPT_AsnDecodeBitsInternal,
2732 sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, offsetof(CERT_INFO,
2733 IssuerUniqueId.pbData), 0 },
2734 { offsetof(CERT_INFO, SubjectUniqueId), CRYPT_AsnDecodeBitsInternal,
2735 sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, offsetof(CERT_INFO,
2736 SubjectUniqueId.pbData), 0 },
2737 { offsetof(CERT_INFO, cExtension), CRYPT_AsnDecodeCertExtensions,
2738 sizeof(CERT_EXTENSIONS), TRUE, TRUE, offsetof(CERT_INFO,
2739 rgExtension), 0 },
2742 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2743 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2744 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
2746 __EXCEPT(page_fault)
2748 SetLastError(STATUS_ACCESS_VIOLATION);
2749 ret = FALSE;
2751 __ENDTRY
2752 return ret;
2755 static BOOL CRYPT_AsnDecodeCRLEntry(const BYTE *pbEncoded, DWORD cbEncoded,
2756 DWORD dwFlags, PCRL_ENTRY entry, DWORD *pcbEntry)
2758 BOOL ret;
2759 struct AsnDecodeSequenceItem items[] = {
2760 { offsetof(CRL_ENTRY, SerialNumber), CRYPT_AsnDecodeIntegerInternal,
2761 sizeof(CRYPT_INTEGER_BLOB), FALSE, TRUE, offsetof(CRL_ENTRY,
2762 SerialNumber.pbData), 0 },
2763 { offsetof(CRL_ENTRY, RevocationDate), CRYPT_AsnDecodeChoiceOfTime,
2764 sizeof(FILETIME), FALSE, FALSE, 0 },
2765 { offsetof(CRL_ENTRY, cExtension), CRYPT_AsnDecodeExtensionsInternal,
2766 sizeof(CERT_EXTENSIONS), TRUE, TRUE, offsetof(CRL_ENTRY,
2767 rgExtension), 0 },
2770 TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, entry,
2771 *pcbEntry);
2773 ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items,
2774 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2775 NULL, entry, pcbEntry, entry ? entry->SerialNumber.pbData : NULL);
2776 TRACE("Returning %d (%08lx)\n", ret, GetLastError());
2777 return ret;
2780 typedef struct _WINE_CRL_ENTRIES {
2781 DWORD cCRLEntry;
2782 PCRL_ENTRY rgCRLEntry;
2783 } WINE_CRL_ENTRIES, *PWINE_CRL_ENTRIES;
2785 /* Warning: assumes pvStructInfo is a WINE_CRL_ENTRIES whose rgCRLEntry has
2786 * been set prior to calling.
2788 static BOOL WINAPI CRYPT_AsnDecodeCRLEntries(DWORD dwCertEncodingType,
2789 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2790 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2792 BOOL ret;
2794 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
2795 pDecodePara, pvStructInfo, *pcbStructInfo);
2797 if (pbEncoded[0] == ASN_SEQUENCEOF)
2799 DWORD dataLen, bytesNeeded;
2801 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2803 DWORD cCRLEntry = 0;
2804 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2806 bytesNeeded = sizeof(WINE_CRL_ENTRIES);
2807 if (dataLen)
2809 const BYTE *ptr;
2810 DWORD size;
2812 for (ptr = pbEncoded + 1 + lenBytes; ret &&
2813 ptr - pbEncoded - 1 - lenBytes < dataLen; )
2815 size = 0;
2816 ret = CRYPT_AsnDecodeCRLEntry(ptr,
2817 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
2818 if (ret)
2820 DWORD nextLen;
2822 cCRLEntry++;
2823 bytesNeeded += size;
2824 ret = CRYPT_GetLen(ptr,
2825 cbEncoded - (ptr - pbEncoded), &nextLen);
2826 if (ret)
2827 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
2831 if (ret)
2833 if (!pvStructInfo)
2834 *pcbStructInfo = bytesNeeded;
2835 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
2836 pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
2838 DWORD size, i;
2839 BYTE *nextData;
2840 const BYTE *ptr;
2841 PWINE_CRL_ENTRIES entries;
2843 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2844 pvStructInfo = *(BYTE **)pvStructInfo;
2845 *pcbStructInfo = bytesNeeded;
2846 entries = (PWINE_CRL_ENTRIES)pvStructInfo;
2847 entries->cCRLEntry = cCRLEntry;
2848 assert(entries->rgCRLEntry);
2849 nextData = (BYTE *)entries->rgCRLEntry +
2850 entries->cCRLEntry * sizeof(CRL_ENTRY);
2851 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
2852 i < cCRLEntry && ptr - pbEncoded - 1 - lenBytes <
2853 dataLen; i++)
2855 entries->rgCRLEntry[i].SerialNumber.pbData = nextData;
2856 size = bytesNeeded;
2857 ret = CRYPT_AsnDecodeCRLEntry(ptr,
2858 cbEncoded - (ptr - pbEncoded), dwFlags,
2859 &entries->rgCRLEntry[i], &size);
2860 if (ret)
2862 DWORD nextLen;
2864 bytesNeeded -= size;
2865 /* Increment nextData by the difference of the
2866 * minimum size and the actual size.
2868 if (size > sizeof(CRL_ENTRY))
2869 nextData += size - sizeof(CRL_ENTRY);
2870 ret = CRYPT_GetLen(ptr,
2871 cbEncoded - (ptr - pbEncoded), &nextLen);
2872 if (ret)
2873 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
2880 else
2882 SetLastError(CRYPT_E_ASN1_BADTAG);
2883 ret = FALSE;
2885 TRACE("Returning %d (%08lx)\n", ret, GetLastError());
2886 return ret;
2889 static BOOL WINAPI CRYPT_AsnDecodeCRLInfo(DWORD dwCertEncodingType,
2890 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2891 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2893 BOOL ret = TRUE;
2895 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
2896 pDecodePara, pvStructInfo, *pcbStructInfo);
2898 __TRY
2900 struct AsnDecodeSequenceItem items[] = {
2901 { offsetof(CRL_INFO, dwVersion), CRYPT_AsnDecodeCertVersion,
2902 sizeof(DWORD), TRUE, FALSE, 0, 0 },
2903 { offsetof(CRL_INFO, SignatureAlgorithm), CRYPT_AsnDecodeAlgorithmId,
2904 sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE, offsetof(CRL_INFO,
2905 SignatureAlgorithm.pszObjId), 0 },
2906 { offsetof(CRL_INFO, Issuer), CRYPT_AsnDecodeDerBlob,
2907 sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CRL_INFO,
2908 Issuer.pbData) },
2909 { offsetof(CRL_INFO, ThisUpdate), CRYPT_AsnDecodeChoiceOfTime,
2910 sizeof(FILETIME), FALSE, FALSE, 0 },
2911 { offsetof(CRL_INFO, NextUpdate), CRYPT_AsnDecodeChoiceOfTime,
2912 sizeof(FILETIME), TRUE, FALSE, 0 },
2913 { offsetof(CRL_INFO, cCRLEntry), CRYPT_AsnDecodeCRLEntries,
2914 sizeof(WINE_CRL_ENTRIES), TRUE, TRUE, offsetof(CRL_INFO,
2915 rgCRLEntry), 0 },
2916 /* Note that the extensions are ignored by MS, so I'll ignore them too
2918 { offsetof(CRL_INFO, cExtension), NULL,
2919 sizeof(CERT_EXTENSIONS), TRUE, FALSE, 0 },
2922 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2923 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2924 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
2926 __EXCEPT(page_fault)
2928 SetLastError(STATUS_ACCESS_VIOLATION);
2929 ret = FALSE;
2931 __ENDTRY
2933 TRACE("Returning %d (%08lx)\n", ret, GetLastError());
2934 return ret;
2937 /* Differences between this and CRYPT_AsnDecodeOid:
2938 * - pvStructInfo is a LPSTR *, not an LPSTR
2939 * - CRYPT_AsnDecodeOid doesn't account for the size of an LPSTR in its byte
2940 * count, whereas our callers (typically CRYPT_AsnDecodeSequence) expect this
2941 * to
2943 static BOOL WINAPI CRYPT_AsnDecodeOidWrapper(DWORD dwCertEncodingType,
2944 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2945 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2947 BOOL ret;
2949 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
2950 pDecodePara, pvStructInfo, *pcbStructInfo);
2952 ret = CRYPT_AsnDecodeOid(pbEncoded, cbEncoded, dwFlags,
2953 pvStructInfo ? *(LPSTR *)pvStructInfo : NULL, pcbStructInfo);
2954 if (ret || GetLastError() == ERROR_MORE_DATA)
2955 *pcbStructInfo += sizeof(LPSTR);
2956 if (ret && pvStructInfo)
2957 TRACE("returning %s\n", debugstr_a(*(LPSTR *)pvStructInfo));
2958 return ret;
2961 /* Warning: assumes ext->pszObjId is set ahead of time! */
2962 static BOOL CRYPT_AsnDecodeExtension(const BYTE *pbEncoded, DWORD cbEncoded,
2963 DWORD dwFlags, CERT_EXTENSION *ext, DWORD *pcbExt)
2965 struct AsnDecodeSequenceItem items[] = {
2966 { offsetof(CERT_EXTENSION, pszObjId), CRYPT_AsnDecodeOidWrapper,
2967 sizeof(LPSTR), FALSE, TRUE, offsetof(CERT_EXTENSION, pszObjId), 0 },
2968 { offsetof(CERT_EXTENSION, fCritical), CRYPT_AsnDecodeBool,
2969 sizeof(BOOL), TRUE, FALSE, 0, 0 },
2970 { offsetof(CERT_EXTENSION, Value), CRYPT_AsnDecodeOctetsInternal,
2971 sizeof(CRYPT_OBJID_BLOB), FALSE, TRUE, offsetof(CERT_EXTENSION,
2972 Value.pbData) },
2974 BOOL ret = TRUE;
2976 TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, ext,
2977 *pcbExt);
2979 if (ext)
2980 TRACE("ext->pszObjId is %p\n", ext->pszObjId);
2981 ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items,
2982 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, NULL,
2983 ext, pcbExt, ext ? ext->pszObjId : NULL);
2984 if (ext)
2985 TRACE("ext->pszObjId is %p (%s)\n", ext->pszObjId,
2986 debugstr_a(ext->pszObjId));
2987 TRACE("returning %d (%08lx)\n", ret, GetLastError());
2988 return ret;
2991 static BOOL WINAPI CRYPT_AsnDecodeExtensionsInternal(DWORD dwCertEncodingType,
2992 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2993 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2995 BOOL ret = TRUE;
2997 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
2998 pDecodePara, pvStructInfo, *pcbStructInfo);
3000 if (pbEncoded[0] == ASN_SEQUENCEOF)
3002 DWORD dataLen, bytesNeeded;
3004 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3006 DWORD cExtension = 0;
3007 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3009 bytesNeeded = sizeof(CERT_EXTENSIONS);
3010 if (dataLen)
3012 const BYTE *ptr;
3013 DWORD size;
3015 for (ptr = pbEncoded + 1 + lenBytes; ret &&
3016 ptr - pbEncoded - 1 - lenBytes < dataLen; )
3018 size = 0;
3019 ret = CRYPT_AsnDecodeExtension(ptr,
3020 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
3021 if (ret)
3023 DWORD nextLen;
3025 cExtension++;
3026 bytesNeeded += size;
3027 ret = CRYPT_GetLen(ptr,
3028 cbEncoded - (ptr - pbEncoded), &nextLen);
3029 if (ret)
3030 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3034 if (ret)
3036 if (!pvStructInfo)
3037 *pcbStructInfo = bytesNeeded;
3038 else if (*pcbStructInfo < bytesNeeded)
3040 SetLastError(ERROR_MORE_DATA);
3041 *pcbStructInfo = bytesNeeded;
3042 ret = FALSE;
3044 else
3046 DWORD size, i;
3047 BYTE *nextData;
3048 const BYTE *ptr;
3049 CERT_EXTENSIONS *exts;
3051 *pcbStructInfo = bytesNeeded;
3052 exts = (CERT_EXTENSIONS *)pvStructInfo;
3053 exts->cExtension = cExtension;
3054 assert(exts->rgExtension);
3055 nextData = (BYTE *)exts->rgExtension +
3056 exts->cExtension * sizeof(CERT_EXTENSION);
3057 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
3058 i < cExtension && ptr - pbEncoded - 1 - lenBytes <
3059 dataLen; i++)
3061 exts->rgExtension[i].pszObjId = (LPSTR)nextData;
3062 size = bytesNeeded;
3063 ret = CRYPT_AsnDecodeExtension(ptr,
3064 cbEncoded - (ptr - pbEncoded), dwFlags,
3065 &exts->rgExtension[i], &size);
3066 if (ret)
3068 DWORD nextLen;
3070 bytesNeeded -= size;
3071 if (size > sizeof(CERT_EXTENSION))
3072 nextData += size - sizeof(CERT_EXTENSION);
3073 ret = CRYPT_GetLen(ptr,
3074 cbEncoded - (ptr - pbEncoded), &nextLen);
3075 if (ret)
3076 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3083 else
3085 SetLastError(CRYPT_E_ASN1_BADTAG);
3086 ret = FALSE;
3088 return ret;
3091 static BOOL WINAPI CRYPT_AsnDecodeExtensions(DWORD dwCertEncodingType,
3092 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3093 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3095 BOOL ret = TRUE;
3097 __TRY
3099 ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType,
3100 lpszStructType, pbEncoded, cbEncoded,
3101 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, pcbStructInfo);
3102 if (ret && pvStructInfo)
3104 ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
3105 pcbStructInfo, *pcbStructInfo);
3106 if (ret)
3108 CERT_EXTENSIONS *exts;
3110 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3111 pvStructInfo = *(BYTE **)pvStructInfo;
3112 exts = (CERT_EXTENSIONS *)pvStructInfo;
3113 exts->rgExtension = (CERT_EXTENSION *)((BYTE *)exts +
3114 sizeof(CERT_EXTENSIONS));
3115 ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType,
3116 lpszStructType, pbEncoded, cbEncoded,
3117 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
3118 pcbStructInfo);
3122 __EXCEPT(page_fault)
3124 SetLastError(STATUS_ACCESS_VIOLATION);
3125 ret = FALSE;
3127 __ENDTRY
3128 return ret;
3131 /* FIXME: honor the CRYPT_DECODE_SHARE_OID_STRING_FLAG. */
3132 static BOOL WINAPI CRYPT_AsnDecodeOid(const BYTE *pbEncoded, DWORD cbEncoded,
3133 DWORD dwFlags, LPSTR pszObjId, DWORD *pcbObjId)
3135 BOOL ret = TRUE;
3137 TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, pszObjId,
3138 *pcbObjId);
3140 __TRY
3142 if (pbEncoded[0] == ASN_OBJECTIDENTIFIER)
3144 DWORD dataLen;
3146 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3148 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3149 DWORD bytesNeeded;
3151 if (dataLen)
3153 /* The largest possible string for the first two components
3154 * is 2.175 (= 2 * 40 + 175 = 255), so this is big enough.
3156 char firstTwo[6];
3157 const BYTE *ptr;
3159 snprintf(firstTwo, sizeof(firstTwo), "%d.%d",
3160 pbEncoded[1 + lenBytes] / 40,
3161 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40)
3162 * 40);
3163 bytesNeeded = strlen(firstTwo) + 1;
3164 for (ptr = pbEncoded + 2 + lenBytes; ret &&
3165 ptr - pbEncoded - 1 - lenBytes < dataLen; )
3167 /* large enough for ".4000000" */
3168 char str[9];
3169 int val = 0;
3171 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
3172 (*ptr & 0x80))
3174 val <<= 7;
3175 val |= *ptr & 0x7f;
3176 ptr++;
3178 if (ptr - pbEncoded - 1 - lenBytes >= dataLen ||
3179 (*ptr & 0x80))
3181 SetLastError(CRYPT_E_ASN1_CORRUPT);
3182 ret = FALSE;
3184 else
3186 val <<= 7;
3187 val |= *ptr++;
3188 snprintf(str, sizeof(str), ".%d", val);
3189 bytesNeeded += strlen(str);
3192 if (!pszObjId)
3193 *pcbObjId = bytesNeeded;
3194 else if (*pcbObjId < bytesNeeded)
3196 *pcbObjId = bytesNeeded;
3197 SetLastError(ERROR_MORE_DATA);
3198 ret = FALSE;
3200 else
3202 *pszObjId = 0;
3203 sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40,
3204 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] /
3205 40) * 40);
3206 pszObjId += strlen(pszObjId);
3207 for (ptr = pbEncoded + 2 + lenBytes; ret &&
3208 ptr - pbEncoded - 1 - lenBytes < dataLen; )
3210 int val = 0;
3212 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
3213 (*ptr & 0x80))
3215 val <<= 7;
3216 val |= *ptr & 0x7f;
3217 ptr++;
3219 val <<= 7;
3220 val |= *ptr++;
3221 sprintf(pszObjId, ".%d", val);
3222 pszObjId += strlen(pszObjId);
3226 else
3227 bytesNeeded = 0;
3228 *pcbObjId = bytesNeeded;
3231 else
3233 SetLastError(CRYPT_E_ASN1_BADTAG);
3234 ret = FALSE;
3237 __EXCEPT(page_fault)
3239 SetLastError(STATUS_ACCESS_VIOLATION);
3240 ret = FALSE;
3242 __ENDTRY
3243 return ret;
3246 /* Warning: this assumes the address of value->Value.pbData is already set, in
3247 * order to avoid overwriting memory. (In some cases, it may change it, if it
3248 * doesn't copy anything to memory.) Be sure to set it correctly!
3250 static BOOL WINAPI CRYPT_AsnDecodeNameValue(const BYTE *pbEncoded,
3251 DWORD cbEncoded, DWORD dwFlags, CERT_NAME_VALUE *value, DWORD *pcbValue)
3253 BOOL ret = TRUE;
3255 __TRY
3257 DWORD dataLen;
3259 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3261 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3263 switch (pbEncoded[0])
3265 case ASN_NUMERICSTRING:
3266 case ASN_PRINTABLESTRING:
3267 case ASN_IA5STRING:
3268 break;
3269 default:
3270 FIXME("Unimplemented string type %02x\n", pbEncoded[0]);
3271 SetLastError(OSS_UNIMPLEMENTED);
3272 ret = FALSE;
3274 if (ret)
3276 DWORD bytesNeeded = sizeof(CERT_NAME_VALUE);
3278 switch (pbEncoded[0])
3280 case ASN_NUMERICSTRING:
3281 case ASN_PRINTABLESTRING:
3282 case ASN_IA5STRING:
3283 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
3284 bytesNeeded += dataLen;
3285 break;
3287 if (!value)
3288 *pcbValue = bytesNeeded;
3289 else if (*pcbValue < bytesNeeded)
3291 *pcbValue = bytesNeeded;
3292 SetLastError(ERROR_MORE_DATA);
3293 ret = FALSE;
3295 else
3297 *pcbValue = bytesNeeded;
3298 switch (pbEncoded[0])
3300 case ASN_NUMERICSTRING:
3301 value->dwValueType = CERT_RDN_NUMERIC_STRING;
3302 break;
3303 case ASN_PRINTABLESTRING:
3304 value->dwValueType = CERT_RDN_PRINTABLE_STRING;
3305 break;
3306 case ASN_IA5STRING:
3307 value->dwValueType = CERT_RDN_IA5_STRING;
3308 break;
3310 if (dataLen)
3312 switch (pbEncoded[0])
3314 case ASN_NUMERICSTRING:
3315 case ASN_PRINTABLESTRING:
3316 case ASN_IA5STRING:
3317 value->Value.cbData = dataLen;
3318 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
3319 value->Value.pbData = (BYTE *)pbEncoded + 1 +
3320 lenBytes;
3321 else
3323 assert(value->Value.pbData);
3324 memcpy(value->Value.pbData,
3325 pbEncoded + 1 + lenBytes, dataLen);
3327 break;
3330 else
3332 value->Value.cbData = 0;
3333 value->Value.pbData = NULL;
3339 __EXCEPT(page_fault)
3341 SetLastError(STATUS_ACCESS_VIOLATION);
3342 ret = FALSE;
3344 __ENDTRY
3345 return ret;
3348 /* FIXME: this should use CRYPT_AsnDecodeSequence (though that won't accept it
3349 * at the moment because of the ASN_CONSTRUCTOR tag.)
3351 static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(const BYTE *pbEncoded,
3352 DWORD cbEncoded, DWORD dwFlags, CERT_RDN_ATTR *attr, DWORD *pcbAttr)
3354 BOOL ret;
3356 __TRY
3358 if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SEQUENCE))
3360 DWORD bytesNeeded, dataLen, size;
3361 BYTE lenBytes;
3363 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3365 /* The data length must be at least 4, two for the tag and
3366 * length for the OID, and two for the string (assuming both
3367 * have short-form lengths.)
3369 if (dataLen < 4)
3371 SetLastError(CRYPT_E_ASN1_EOD);
3372 ret = FALSE;
3374 else
3376 bytesNeeded = sizeof(CERT_RDN_ATTR);
3377 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3378 ret = CRYPT_AsnDecodeOid(pbEncoded + 1 + lenBytes,
3379 cbEncoded - 1 - lenBytes, dwFlags, NULL, &size);
3380 if (ret)
3382 /* ugly: need to know the size of the next element of
3383 * the sequence, so get it directly
3385 DWORD objIdOfset = 1 + lenBytes, objIdLen,
3386 nameValueOffset = 0;
3388 ret = CRYPT_GetLen(pbEncoded + objIdOfset,
3389 cbEncoded - objIdOfset, &objIdLen);
3390 bytesNeeded += size;
3391 /* hack: like encoding, this takes advantage of the
3392 * fact that the rest of the structure is identical to
3393 * a CERT_NAME_VALUE.
3395 if (ret)
3397 nameValueOffset = objIdOfset + objIdLen + 1 +
3398 GET_LEN_BYTES(pbEncoded[objIdOfset]);
3399 ret = CRYPT_AsnDecodeNameValue(
3400 pbEncoded + nameValueOffset,
3401 cbEncoded - nameValueOffset, dwFlags, NULL, &size);
3403 if (ret)
3405 bytesNeeded += size;
3406 if (!attr)
3407 *pcbAttr = bytesNeeded;
3408 else if (*pcbAttr < bytesNeeded)
3410 *pcbAttr = bytesNeeded;
3411 SetLastError(ERROR_MORE_DATA);
3412 ret = FALSE;
3414 else
3416 BYTE *originalData = attr->Value.pbData;
3418 *pcbAttr = bytesNeeded;
3419 /* strange: decode the value first, because it
3420 * has a counted size, and we can store the OID
3421 * after it. Keep track of the original data
3422 * pointer, we'll need to know whether it was
3423 * changed.
3425 size = bytesNeeded;
3426 ret = CRYPT_AsnDecodeNameValue(
3427 pbEncoded + nameValueOffset,
3428 cbEncoded - nameValueOffset, dwFlags,
3429 (CERT_NAME_VALUE *)&attr->dwValueType, &size);
3430 if (ret)
3432 if (objIdLen)
3434 /* if the data were copied to the
3435 * original location, the OID goes
3436 * after. Otherwise it goes in the
3437 * spot originally reserved for the
3438 * data.
3440 if (attr->Value.pbData == originalData)
3441 attr->pszObjId =
3442 (LPSTR)(attr->Value.pbData +
3443 attr->Value.cbData);
3444 else
3445 attr->pszObjId =
3446 (LPSTR)originalData;
3447 size = bytesNeeded - size;
3448 ret = CRYPT_AsnDecodeOid(
3449 pbEncoded + objIdOfset,
3450 cbEncoded - objIdOfset,
3451 dwFlags, attr->pszObjId, &size);
3453 else
3454 attr->pszObjId = NULL;
3462 else
3464 SetLastError(CRYPT_E_ASN1_BADTAG);
3465 ret = FALSE;
3468 __EXCEPT(page_fault)
3470 SetLastError(STATUS_ACCESS_VIOLATION);
3471 ret = FALSE;
3473 __ENDTRY
3474 return ret;
3477 static BOOL WINAPI CRYPT_AsnDecodeRdn(const BYTE *pbEncoded, DWORD cbEncoded,
3478 DWORD dwFlags, CERT_RDN *rdn, DWORD *pcbRdn)
3480 BOOL ret = TRUE;
3482 __TRY
3484 if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SETOF))
3486 DWORD dataLen;
3488 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3490 DWORD bytesNeeded, cRDNAttr = 0;
3491 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3493 bytesNeeded = sizeof(CERT_RDN);
3494 if (dataLen)
3496 const BYTE *ptr;
3497 DWORD size;
3499 for (ptr = pbEncoded + 1 + lenBytes; ret &&
3500 ptr - pbEncoded - 1 - lenBytes < dataLen; )
3502 ret = CRYPT_AsnDecodeRdnAttr(ptr,
3503 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
3504 if (ret)
3506 DWORD nextLen;
3508 cRDNAttr++;
3509 bytesNeeded += size;
3510 ret = CRYPT_GetLen(ptr,
3511 cbEncoded - (ptr - pbEncoded), &nextLen);
3512 if (ret)
3513 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3517 if (ret)
3519 if (!rdn)
3520 *pcbRdn = bytesNeeded;
3521 else if (*pcbRdn < bytesNeeded)
3523 *pcbRdn = bytesNeeded;
3524 SetLastError(ERROR_MORE_DATA);
3525 ret = FALSE;
3527 else
3529 DWORD size, i;
3530 BYTE *nextData;
3531 const BYTE *ptr;
3533 *pcbRdn = bytesNeeded;
3534 rdn->cRDNAttr = cRDNAttr;
3535 rdn->rgRDNAttr = (CERT_RDN_ATTR *)((BYTE *)rdn +
3536 sizeof(CERT_RDN));
3537 nextData = (BYTE *)rdn->rgRDNAttr +
3538 rdn->cRDNAttr * sizeof(CERT_RDN_ATTR);
3539 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
3540 i < cRDNAttr && ptr - pbEncoded - 1 - lenBytes <
3541 dataLen; i++)
3543 rdn->rgRDNAttr[i].Value.pbData = nextData;
3544 size = bytesNeeded;
3545 ret = CRYPT_AsnDecodeRdnAttr(ptr,
3546 cbEncoded - (ptr - pbEncoded), dwFlags,
3547 &rdn->rgRDNAttr[i], &size);
3548 if (ret)
3550 DWORD nextLen;
3552 bytesNeeded -= size;
3553 /* If dwFlags & CRYPT_DECODE_NOCOPY_FLAG, the
3554 * data may not have been copied.
3556 if (rdn->rgRDNAttr[i].Value.pbData == nextData)
3557 nextData +=
3558 rdn->rgRDNAttr[i].Value.cbData;
3559 /* Ugly: the OID, if copied, is stored in
3560 * memory after the value, so increment by its
3561 * string length if it's set and points here.
3563 if ((const BYTE *)rdn->rgRDNAttr[i].pszObjId
3564 == nextData)
3565 nextData += strlen(
3566 rdn->rgRDNAttr[i].pszObjId) + 1;
3567 ret = CRYPT_GetLen(ptr,
3568 cbEncoded - (ptr - pbEncoded), &nextLen);
3569 if (ret)
3570 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3577 else
3579 SetLastError(CRYPT_E_ASN1_BADTAG);
3580 ret = FALSE;
3583 __EXCEPT(page_fault)
3585 SetLastError(STATUS_ACCESS_VIOLATION);
3586 ret = FALSE;
3588 __ENDTRY
3589 return ret;
3592 static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType,
3593 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3594 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3596 BOOL ret = TRUE;
3598 __TRY
3600 if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SEQUENCEOF))
3602 DWORD dataLen;
3604 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3606 DWORD bytesNeeded, cRDN = 0;
3607 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3609 bytesNeeded = sizeof(CERT_NAME_INFO);
3610 if (dataLen)
3612 const BYTE *ptr;
3614 for (ptr = pbEncoded + 1 + lenBytes; ret &&
3615 ptr - pbEncoded - 1 - lenBytes < dataLen; )
3617 DWORD size;
3619 ret = CRYPT_AsnDecodeRdn(ptr,
3620 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
3621 if (ret)
3623 DWORD nextLen;
3625 cRDN++;
3626 bytesNeeded += size;
3627 ret = CRYPT_GetLen(ptr,
3628 cbEncoded - (ptr - pbEncoded), &nextLen);
3629 if (ret)
3630 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3634 if (ret)
3636 if (!pvStructInfo)
3637 *pcbStructInfo = bytesNeeded;
3638 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
3639 pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
3641 CERT_NAME_INFO *info;
3643 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3644 pvStructInfo = *(BYTE **)pvStructInfo;
3645 info = (CERT_NAME_INFO *)pvStructInfo;
3646 info->cRDN = cRDN;
3647 if (info->cRDN == 0)
3648 info->rgRDN = NULL;
3649 else
3651 DWORD size, i;
3652 BYTE *nextData;
3653 const BYTE *ptr;
3655 info->rgRDN = (CERT_RDN *)((BYTE *)pvStructInfo +
3656 sizeof(CERT_NAME_INFO));
3657 nextData = (BYTE *)info->rgRDN +
3658 info->cRDN * sizeof(CERT_RDN);
3659 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
3660 i < cRDN && ptr - pbEncoded - 1 - lenBytes <
3661 dataLen; i++)
3663 info->rgRDN[i].rgRDNAttr =
3664 (CERT_RDN_ATTR *)nextData;
3665 size = bytesNeeded;
3666 ret = CRYPT_AsnDecodeRdn(ptr,
3667 cbEncoded - (ptr - pbEncoded), dwFlags,
3668 &info->rgRDN[i], &size);
3669 if (ret)
3671 DWORD nextLen;
3673 nextData += size;
3674 bytesNeeded -= size;
3675 ret = CRYPT_GetLen(ptr,
3676 cbEncoded - (ptr - pbEncoded), &nextLen);
3677 if (ret)
3678 ptr += nextLen + 1 +
3679 GET_LEN_BYTES(ptr[1]);
3687 else
3689 SetLastError(CRYPT_E_ASN1_BADTAG);
3690 ret = FALSE;
3693 __EXCEPT(page_fault)
3695 SetLastError(STATUS_ACCESS_VIOLATION);
3696 ret = FALSE;
3698 __ENDTRY
3699 return ret;
3702 static BOOL WINAPI CRYPT_AsnDecodeCopyBytes(DWORD dwCertEncodingType,
3703 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3704 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3706 BOOL ret = TRUE;
3707 DWORD bytesNeeded = sizeof(CRYPT_OBJID_BLOB);
3709 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3710 pDecodePara, pvStructInfo, *pcbStructInfo);
3712 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
3713 bytesNeeded += cbEncoded;
3714 if (!pvStructInfo)
3715 *pcbStructInfo = bytesNeeded;
3716 else if (*pcbStructInfo < bytesNeeded)
3718 SetLastError(ERROR_MORE_DATA);
3719 *pcbStructInfo = bytesNeeded;
3720 ret = FALSE;
3722 else
3724 PCRYPT_OBJID_BLOB blob = (PCRYPT_OBJID_BLOB)pvStructInfo;
3726 *pcbStructInfo = bytesNeeded;
3727 blob->cbData = cbEncoded;
3728 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
3729 blob->pbData = (LPBYTE)pbEncoded;
3730 else
3732 assert(blob->pbData);
3733 memcpy(blob->pbData, pbEncoded, blob->cbData);
3736 return ret;
3739 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
3740 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3741 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3743 CRYPT_ALGORITHM_IDENTIFIER *algo =
3744 (CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
3745 BOOL ret = TRUE;
3746 struct AsnDecodeSequenceItem items[] = {
3747 { offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId),
3748 CRYPT_AsnDecodeOidWrapper, sizeof(LPSTR), FALSE, TRUE,
3749 offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId), 0 },
3750 { offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters),
3751 CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_OBJID_BLOB), TRUE, TRUE,
3752 offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters.pbData), 0 },
3755 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3756 pDecodePara, pvStructInfo, *pcbStructInfo);
3758 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
3759 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3760 pDecodePara, pvStructInfo, pcbStructInfo, algo ? algo->pszObjId : NULL);
3761 if (ret && pvStructInfo)
3763 TRACE("pszObjId is %p (%s)\n", algo->pszObjId,
3764 debugstr_a(algo->pszObjId));
3766 return ret;
3769 static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType,
3770 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3771 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3773 BOOL ret = TRUE;
3775 __TRY
3777 struct AsnDecodeSequenceItem items[] = {
3778 { offsetof(CERT_PUBLIC_KEY_INFO, Algorithm),
3779 CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
3780 FALSE, TRUE, offsetof(CERT_PUBLIC_KEY_INFO,
3781 Algorithm.pszObjId) },
3782 { offsetof(CERT_PUBLIC_KEY_INFO, PublicKey),
3783 CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE,
3784 offsetof(CERT_PUBLIC_KEY_INFO, PublicKey.pbData) },
3787 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
3788 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3789 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
3791 __EXCEPT(page_fault)
3793 SetLastError(STATUS_ACCESS_VIOLATION);
3794 ret = FALSE;
3796 __ENDTRY
3797 return ret;
3800 static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
3801 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3802 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3804 BOOL ret;
3806 if (cbEncoded < 3)
3808 SetLastError(CRYPT_E_ASN1_CORRUPT);
3809 return FALSE;
3811 if (pbEncoded[0] != ASN_BOOL)
3813 SetLastError(CRYPT_E_ASN1_BADTAG);
3814 return FALSE;
3816 if (GET_LEN_BYTES(pbEncoded[1]) > 1)
3818 SetLastError(CRYPT_E_ASN1_CORRUPT);
3819 return FALSE;
3821 if (pbEncoded[1] > 1)
3823 SetLastError(CRYPT_E_ASN1_CORRUPT);
3824 return FALSE;
3826 if (!pvStructInfo)
3828 *pcbStructInfo = sizeof(BOOL);
3829 ret = TRUE;
3831 else if (*pcbStructInfo < sizeof(BOOL))
3833 *pcbStructInfo = sizeof(BOOL);
3834 SetLastError(ERROR_MORE_DATA);
3835 ret = FALSE;
3837 else
3839 *(BOOL *)pvStructInfo = pbEncoded[2] ? TRUE : FALSE;
3840 ret = TRUE;
3842 TRACE("returning %d (%08lx)\n", ret, GetLastError());
3843 return ret;
3846 static BOOL CRYPT_AsnDecodeAltNameEntry(const BYTE *pbEncoded, DWORD cbEncoded,
3847 DWORD dwFlags, CERT_ALT_NAME_ENTRY *entry, DWORD *pcbEntry)
3849 DWORD dataLen, lenBytes, bytesNeeded = sizeof(CERT_ALT_NAME_ENTRY);
3850 BOOL ret;
3852 if (cbEncoded < 2)
3854 SetLastError(CRYPT_E_ASN1_CORRUPT);
3855 return FALSE;
3857 if ((pbEncoded[0] & ASN_FLAGS_MASK) != ASN_CONTEXT)
3859 SetLastError(CRYPT_E_ASN1_BADTAG);
3860 return FALSE;
3862 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3863 if (1 + lenBytes > cbEncoded)
3865 SetLastError(CRYPT_E_ASN1_CORRUPT);
3866 return FALSE;
3868 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3870 switch (pbEncoded[0] & ASN_TYPE_MASK)
3872 case 1: /* rfc822Name */
3873 case 2: /* dNSName */
3874 case 6: /* uniformResourceIdentifier */
3875 bytesNeeded += (dataLen + 1) * sizeof(WCHAR);
3876 break;
3877 case 7: /* iPAddress */
3878 bytesNeeded += dataLen;
3879 break;
3880 case 8: /* registeredID */
3881 /* FIXME: decode as OID */
3882 case 0: /* otherName */
3883 case 4: /* directoryName */
3884 FIXME("stub\n");
3885 SetLastError(CRYPT_E_ASN1_BADTAG);
3886 ret = FALSE;
3887 break;
3888 case 3: /* x400Address, unimplemented */
3889 case 5: /* ediPartyName, unimplemented */
3890 SetLastError(CRYPT_E_ASN1_BADTAG);
3891 ret = FALSE;
3892 break;
3893 default:
3894 SetLastError(CRYPT_E_ASN1_CORRUPT);
3895 ret = FALSE;
3897 if (ret)
3899 if (!entry)
3900 *pcbEntry = bytesNeeded;
3901 else if (*pcbEntry < bytesNeeded)
3903 SetLastError(ERROR_MORE_DATA);
3904 ret = FALSE;
3906 else
3908 /* MS used values one greater than the asn1 ones.. sigh */
3909 entry->dwAltNameChoice = (pbEncoded[0] & 0x7f) + 1;
3910 switch (pbEncoded[0] & ASN_TYPE_MASK)
3912 case 1: /* rfc822Name */
3913 case 2: /* dNSName */
3914 case 6: /* uniformResourceIdentifier */
3916 DWORD i;
3918 for (i = 0; i < dataLen; i++)
3919 entry->u.pwszURL[i] =
3920 (WCHAR)pbEncoded[1 + lenBytes + i];
3921 entry->u.pwszURL[i] = 0;
3922 break;
3924 case 7: /* iPAddress */
3925 /* The next data pointer is in the pwszURL spot, that is,
3926 * the first 4 bytes. Need to move it to the next spot.
3928 entry->u.IPAddress.pbData = (LPBYTE)entry->u.pwszURL;
3929 entry->u.IPAddress.cbData = dataLen;
3930 memcpy(entry->u.IPAddress.pbData, pbEncoded + 1 + lenBytes,
3931 dataLen);
3932 break;
3937 return ret;
3940 static BOOL WINAPI CRYPT_AsnDecodeAltName(DWORD dwCertEncodingType,
3941 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3942 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3944 BOOL ret = TRUE;
3946 __TRY
3948 if (pbEncoded[0] == ASN_SEQUENCEOF)
3950 DWORD dataLen;
3952 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3954 DWORD bytesNeeded, cEntry = 0;
3955 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3957 bytesNeeded = sizeof(CERT_ALT_NAME_INFO);
3958 if (dataLen)
3960 const BYTE *ptr;
3962 for (ptr = pbEncoded + 1 + lenBytes; ret &&
3963 ptr - pbEncoded - 1 - lenBytes < dataLen; )
3965 DWORD size;
3967 ret = CRYPT_AsnDecodeAltNameEntry(ptr,
3968 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
3969 if (ret)
3971 DWORD nextLen;
3973 cEntry++;
3974 bytesNeeded += size;
3975 ret = CRYPT_GetLen(ptr,
3976 cbEncoded - (ptr - pbEncoded), &nextLen);
3977 if (ret)
3978 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3982 if (ret)
3984 if (!pvStructInfo)
3985 *pcbStructInfo = bytesNeeded;
3986 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
3987 pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
3989 CERT_ALT_NAME_INFO *info;
3991 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3992 pvStructInfo = *(BYTE **)pvStructInfo;
3993 info = (CERT_ALT_NAME_INFO *)pvStructInfo;
3994 info->cAltEntry = 0;
3995 if (cEntry == 0)
3996 info->rgAltEntry = NULL;
3997 else
3999 DWORD size, i;
4000 BYTE *nextData;
4001 const BYTE *ptr;
4003 info->rgAltEntry =
4004 (CERT_ALT_NAME_ENTRY *)((BYTE *)pvStructInfo +
4005 sizeof(CERT_ALT_NAME_INFO));
4006 nextData = (BYTE *)info->rgAltEntry +
4007 cEntry * sizeof(CERT_ALT_NAME_ENTRY);
4008 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
4009 i < cEntry && ptr - pbEncoded - 1 - lenBytes <
4010 dataLen; i++)
4012 info->rgAltEntry[i].u.pwszURL =
4013 (LPWSTR)nextData;
4014 size = bytesNeeded;
4015 ret = CRYPT_AsnDecodeAltNameEntry(ptr,
4016 cbEncoded - (ptr - pbEncoded), dwFlags,
4017 &info->rgAltEntry[i], &size);
4018 if (ret)
4020 DWORD nextLen;
4022 info->cAltEntry++;
4023 nextData += size -
4024 sizeof(CERT_ALT_NAME_ENTRY);
4025 bytesNeeded -= size;
4026 ret = CRYPT_GetLen(ptr,
4027 cbEncoded - (ptr - pbEncoded), &nextLen);
4028 if (ret)
4029 ptr += nextLen + 1 +
4030 GET_LEN_BYTES(ptr[1]);
4038 else
4040 SetLastError(CRYPT_E_ASN1_BADTAG);
4041 ret = FALSE;
4044 __EXCEPT(page_fault)
4046 SetLastError(STATUS_ACCESS_VIOLATION);
4047 ret = FALSE;
4049 __ENDTRY
4050 return ret;
4053 struct PATH_LEN_CONSTRAINT
4055 BOOL fPathLenConstraint;
4056 DWORD dwPathLenConstraint;
4059 static BOOL WINAPI CRYPT_AsnDecodePathLenConstraint(DWORD dwCertEncodingType,
4060 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4061 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4063 BOOL ret = TRUE;
4065 if (cbEncoded)
4067 if (pbEncoded[0] == ASN_INTEGER)
4069 DWORD bytesNeeded = sizeof(struct PATH_LEN_CONSTRAINT);
4071 if (!pvStructInfo)
4072 *pcbStructInfo = bytesNeeded;
4073 else if (*pcbStructInfo < bytesNeeded)
4075 SetLastError(ERROR_MORE_DATA);
4076 *pcbStructInfo = bytesNeeded;
4077 ret = FALSE;
4079 else
4081 struct PATH_LEN_CONSTRAINT *constraint =
4082 (struct PATH_LEN_CONSTRAINT *)pvStructInfo;
4083 DWORD size = sizeof(constraint->dwPathLenConstraint);
4085 ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER,
4086 pbEncoded, cbEncoded, 0, NULL,
4087 &constraint->dwPathLenConstraint, &size);
4088 if (ret)
4089 constraint->fPathLenConstraint = TRUE;
4090 TRACE("got an int, dwPathLenConstraint is %ld\n",
4091 constraint->dwPathLenConstraint);
4094 else
4096 SetLastError(CRYPT_E_ASN1_CORRUPT);
4097 ret = FALSE;
4100 TRACE("returning %d (%08lx)\n", ret, GetLastError());
4101 return ret;
4104 static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints2(DWORD dwCertEncodingType,
4105 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4106 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4108 BOOL ret;
4110 __TRY
4112 struct AsnDecodeSequenceItem items[] = {
4113 { offsetof(CERT_BASIC_CONSTRAINTS2_INFO, fCA), CRYPT_AsnDecodeBool,
4114 sizeof(BOOL), TRUE, FALSE, 0, 0 },
4115 { offsetof(CERT_BASIC_CONSTRAINTS2_INFO, fPathLenConstraint),
4116 CRYPT_AsnDecodePathLenConstraint, sizeof(struct PATH_LEN_CONSTRAINT),
4117 TRUE, FALSE, 0, 0 },
4120 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
4121 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
4122 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
4124 __EXCEPT(page_fault)
4126 SetLastError(STATUS_ACCESS_VIOLATION);
4127 ret = FALSE;
4129 __ENDTRY
4130 return ret;
4133 #define RSA1_MAGIC 0x31415352
4135 struct DECODED_RSA_PUB_KEY
4137 DWORD pubexp;
4138 CRYPT_INTEGER_BLOB modulus;
4141 static BOOL WINAPI CRYPT_AsnDecodeRsaPubKey(DWORD dwCertEncodingType,
4142 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4143 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4145 BOOL ret;
4147 __TRY
4149 struct AsnDecodeSequenceItem items[] = {
4150 { offsetof(struct DECODED_RSA_PUB_KEY, modulus),
4151 CRYPT_AsnDecodeUnsignedIntegerInternal, sizeof(CRYPT_INTEGER_BLOB),
4152 FALSE, TRUE, offsetof(struct DECODED_RSA_PUB_KEY, modulus.pbData),
4153 0 },
4154 { offsetof(struct DECODED_RSA_PUB_KEY, pubexp),
4155 CRYPT_AsnDecodeInt, sizeof(DWORD), FALSE, FALSE, 0, 0 },
4157 struct DECODED_RSA_PUB_KEY *decodedKey = NULL;
4158 DWORD size = 0;
4160 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
4161 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded,
4162 CRYPT_DECODE_ALLOC_FLAG, NULL, &decodedKey, &size, NULL);
4163 if (ret)
4165 DWORD bytesNeeded = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
4166 decodedKey->modulus.cbData;
4168 if (!pvStructInfo)
4170 *pcbStructInfo = bytesNeeded;
4171 ret = TRUE;
4173 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4174 pvStructInfo, pcbStructInfo, bytesNeeded)))
4176 BLOBHEADER *hdr;
4177 RSAPUBKEY *rsaPubKey;
4179 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4180 pvStructInfo = *(BYTE **)pvStructInfo;
4181 hdr = (BLOBHEADER *)pvStructInfo;
4182 hdr->bType = PUBLICKEYBLOB;
4183 hdr->bVersion = CUR_BLOB_VERSION;
4184 hdr->reserved = 0;
4185 hdr->aiKeyAlg = CALG_RSA_KEYX;
4186 rsaPubKey = (RSAPUBKEY *)((BYTE *)pvStructInfo +
4187 sizeof(BLOBHEADER));
4188 rsaPubKey->magic = RSA1_MAGIC;
4189 rsaPubKey->pubexp = decodedKey->pubexp;
4190 rsaPubKey->bitlen = decodedKey->modulus.cbData * 8;
4191 memcpy((BYTE *)pvStructInfo + sizeof(BLOBHEADER) +
4192 sizeof(RSAPUBKEY), decodedKey->modulus.pbData,
4193 decodedKey->modulus.cbData);
4195 LocalFree(decodedKey);
4198 __EXCEPT(page_fault)
4200 SetLastError(STATUS_ACCESS_VIOLATION);
4201 ret = FALSE;
4203 __ENDTRY
4204 return ret;
4207 static BOOL WINAPI CRYPT_AsnDecodeOctetsInternal(DWORD dwCertEncodingType,
4208 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4209 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4211 BOOL ret;
4213 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
4214 pDecodePara, pvStructInfo, *pcbStructInfo);
4216 if (pbEncoded[0] == ASN_OCTETSTRING)
4218 DWORD bytesNeeded, dataLen;
4220 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4222 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4223 bytesNeeded = sizeof(CRYPT_DATA_BLOB);
4224 else
4225 bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB);
4226 if (!pvStructInfo)
4227 *pcbStructInfo = bytesNeeded;
4228 else if (*pcbStructInfo < bytesNeeded)
4230 SetLastError(ERROR_MORE_DATA);
4231 *pcbStructInfo = bytesNeeded;
4232 ret = FALSE;
4234 else
4236 CRYPT_DATA_BLOB *blob;
4237 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4239 blob = (CRYPT_DATA_BLOB *)pvStructInfo;
4240 blob->cbData = dataLen;
4241 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4242 blob->pbData = (BYTE *)pbEncoded + 1 + lenBytes;
4243 else
4245 assert(blob->pbData);
4246 if (blob->cbData)
4247 memcpy(blob->pbData, pbEncoded + 1 + lenBytes,
4248 blob->cbData);
4253 else
4255 SetLastError(CRYPT_E_ASN1_BADTAG);
4256 ret = FALSE;
4258 return ret;
4261 static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
4262 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4263 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4265 BOOL ret;
4267 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
4268 pDecodePara, pvStructInfo, *pcbStructInfo);
4270 __TRY
4272 DWORD bytesNeeded;
4274 if ((ret = CRYPT_AsnDecodeOctetsInternal(dwCertEncodingType,
4275 lpszStructType, pbEncoded, cbEncoded,
4276 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
4278 if (!pvStructInfo)
4279 *pcbStructInfo = bytesNeeded;
4280 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4281 pvStructInfo, pcbStructInfo, bytesNeeded)))
4283 CRYPT_DATA_BLOB *blob;
4285 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4286 pvStructInfo = *(BYTE **)pvStructInfo;
4287 blob = (CRYPT_DATA_BLOB *)pvStructInfo;
4288 blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_DATA_BLOB);
4289 ret = CRYPT_AsnDecodeOctetsInternal(dwCertEncodingType,
4290 lpszStructType, pbEncoded, cbEncoded,
4291 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
4292 &bytesNeeded);
4295 else
4297 SetLastError(CRYPT_E_ASN1_BADTAG);
4298 ret = FALSE;
4301 __EXCEPT(page_fault)
4303 SetLastError(STATUS_ACCESS_VIOLATION);
4304 ret = FALSE;
4306 __ENDTRY
4307 return ret;
4310 static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
4311 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4312 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4314 BOOL ret;
4316 TRACE("(%p, %ld, 0x%08lx, %p, %p, %ld)\n", pbEncoded, cbEncoded, dwFlags,
4317 pDecodePara, pvStructInfo, *pcbStructInfo);
4319 if (pbEncoded[0] == ASN_BITSTRING)
4321 DWORD bytesNeeded, dataLen;
4323 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4325 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4326 bytesNeeded = sizeof(CRYPT_BIT_BLOB);
4327 else
4328 bytesNeeded = dataLen - 1 + sizeof(CRYPT_BIT_BLOB);
4329 if (!pvStructInfo)
4330 *pcbStructInfo = bytesNeeded;
4331 else if (*pcbStructInfo < bytesNeeded)
4333 *pcbStructInfo = bytesNeeded;
4334 SetLastError(ERROR_MORE_DATA);
4335 ret = FALSE;
4337 else
4339 CRYPT_BIT_BLOB *blob;
4341 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
4342 blob->cbData = dataLen - 1;
4343 blob->cUnusedBits = *(pbEncoded + 1 +
4344 GET_LEN_BYTES(pbEncoded[1]));
4345 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4347 blob->pbData = (BYTE *)pbEncoded + 2 +
4348 GET_LEN_BYTES(pbEncoded[1]);
4350 else
4352 assert(blob->pbData);
4353 if (blob->cbData)
4355 BYTE mask = 0xff << blob->cUnusedBits;
4357 memcpy(blob->pbData, pbEncoded + 2 +
4358 GET_LEN_BYTES(pbEncoded[1]), blob->cbData);
4359 blob->pbData[blob->cbData - 1] &= mask;
4365 else
4367 SetLastError(CRYPT_E_ASN1_BADTAG);
4368 ret = FALSE;
4370 TRACE("returning %d (%08lx)\n", ret, GetLastError());
4371 return ret;
4374 static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType,
4375 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4376 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4378 BOOL ret;
4380 TRACE("(%p, %ld, 0x%08lx, %p, %p, %p)\n", pbEncoded, cbEncoded, dwFlags,
4381 pDecodePara, pvStructInfo, pcbStructInfo);
4383 __TRY
4385 DWORD bytesNeeded;
4387 if ((ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType,
4388 lpszStructType, pbEncoded, cbEncoded,
4389 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
4391 if (!pvStructInfo)
4392 *pcbStructInfo = bytesNeeded;
4393 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4394 pvStructInfo, pcbStructInfo, bytesNeeded)))
4396 CRYPT_BIT_BLOB *blob;
4398 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4399 pvStructInfo = *(BYTE **)pvStructInfo;
4400 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
4401 blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_BIT_BLOB);
4402 ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType,
4403 lpszStructType, pbEncoded, cbEncoded,
4404 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
4405 &bytesNeeded);
4409 __EXCEPT(page_fault)
4411 SetLastError(STATUS_ACCESS_VIOLATION);
4412 ret = FALSE;
4414 __ENDTRY
4415 TRACE("returning %d (%08lx)\n", ret, GetLastError());
4416 return ret;
4419 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
4420 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4421 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4423 BOOL ret;
4425 if (!pvStructInfo)
4427 *pcbStructInfo = sizeof(int);
4428 return TRUE;
4430 __TRY
4432 BYTE buf[sizeof(CRYPT_INTEGER_BLOB) + sizeof(int)];
4433 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
4434 DWORD size = sizeof(buf);
4436 blob->pbData = buf + sizeof(CRYPT_INTEGER_BLOB);
4437 ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
4438 X509_MULTI_BYTE_INTEGER, pbEncoded, cbEncoded, 0, NULL, &buf, &size);
4439 if (ret)
4441 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4442 pvStructInfo, pcbStructInfo, sizeof(int))))
4444 int val, i;
4446 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4447 pvStructInfo = *(BYTE **)pvStructInfo;
4448 if (blob->pbData[blob->cbData - 1] & 0x80)
4450 /* initialize to a negative value to sign-extend */
4451 val = -1;
4453 else
4454 val = 0;
4455 for (i = 0; i < blob->cbData; i++)
4457 val <<= 8;
4458 val |= blob->pbData[blob->cbData - i - 1];
4460 memcpy(pvStructInfo, &val, sizeof(int));
4463 else if (GetLastError() == ERROR_MORE_DATA)
4464 SetLastError(CRYPT_E_ASN1_LARGE);
4466 __EXCEPT(page_fault)
4468 SetLastError(STATUS_ACCESS_VIOLATION);
4469 ret = FALSE;
4471 __ENDTRY
4472 return ret;
4475 static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType,
4476 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4477 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4479 BOOL ret;
4481 if (pbEncoded[0] == ASN_INTEGER)
4483 DWORD bytesNeeded, dataLen;
4485 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4487 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4489 bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
4490 if (!pvStructInfo)
4491 *pcbStructInfo = bytesNeeded;
4492 else if (*pcbStructInfo < bytesNeeded)
4494 *pcbStructInfo = bytesNeeded;
4495 SetLastError(ERROR_MORE_DATA);
4496 ret = FALSE;
4498 else
4500 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
4502 blob->cbData = dataLen;
4503 assert(blob->pbData);
4504 if (blob->cbData)
4506 DWORD i;
4508 for (i = 0; i < blob->cbData; i++)
4510 blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
4511 dataLen - i - 1);
4517 else
4519 SetLastError(CRYPT_E_ASN1_BADTAG);
4520 ret = FALSE;
4522 return ret;
4525 static BOOL WINAPI CRYPT_AsnDecodeInteger(DWORD dwCertEncodingType,
4526 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4527 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4529 BOOL ret;
4531 __TRY
4533 DWORD bytesNeeded;
4535 if ((ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
4536 lpszStructType, pbEncoded, cbEncoded,
4537 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
4539 if (!pvStructInfo)
4540 *pcbStructInfo = bytesNeeded;
4541 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4542 pvStructInfo, pcbStructInfo, bytesNeeded)))
4544 CRYPT_INTEGER_BLOB *blob;
4546 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4547 pvStructInfo = *(BYTE **)pvStructInfo;
4548 blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
4549 blob->pbData = (BYTE *)pvStructInfo +
4550 sizeof(CRYPT_INTEGER_BLOB);
4551 ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
4552 lpszStructType, pbEncoded, cbEncoded,
4553 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pvStructInfo,
4554 &bytesNeeded);
4558 __EXCEPT(page_fault)
4560 SetLastError(STATUS_ACCESS_VIOLATION);
4561 ret = FALSE;
4563 __ENDTRY
4564 return ret;
4567 static BOOL WINAPI CRYPT_AsnDecodeUnsignedIntegerInternal(
4568 DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded,
4569 DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
4570 void *pvStructInfo, DWORD *pcbStructInfo)
4572 BOOL ret;
4574 if (pbEncoded[0] == ASN_INTEGER)
4576 DWORD bytesNeeded, dataLen;
4578 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4580 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4582 bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
4583 if (!pvStructInfo)
4584 *pcbStructInfo = bytesNeeded;
4585 else if (*pcbStructInfo < bytesNeeded)
4587 *pcbStructInfo = bytesNeeded;
4588 SetLastError(ERROR_MORE_DATA);
4589 ret = FALSE;
4591 else
4593 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
4595 blob->cbData = dataLen;
4596 assert(blob->pbData);
4597 /* remove leading zero byte if it exists */
4598 if (blob->cbData && *(pbEncoded + 1 + lenBytes) == 0)
4600 blob->cbData--;
4601 blob->pbData++;
4603 if (blob->cbData)
4605 DWORD i;
4607 for (i = 0; i < blob->cbData; i++)
4609 blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
4610 dataLen - i - 1);
4616 else
4618 SetLastError(CRYPT_E_ASN1_BADTAG);
4619 ret = FALSE;
4621 return ret;
4624 static BOOL WINAPI CRYPT_AsnDecodeUnsignedInteger(DWORD dwCertEncodingType,
4625 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4626 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4628 BOOL ret;
4630 __TRY
4632 DWORD bytesNeeded;
4634 if ((ret = CRYPT_AsnDecodeUnsignedIntegerInternal(dwCertEncodingType,
4635 lpszStructType, pbEncoded, cbEncoded,
4636 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
4638 if (!pvStructInfo)
4639 *pcbStructInfo = bytesNeeded;
4640 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4641 pvStructInfo, pcbStructInfo, bytesNeeded)))
4643 CRYPT_INTEGER_BLOB *blob;
4645 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4646 pvStructInfo = *(BYTE **)pvStructInfo;
4647 blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
4648 blob->pbData = (BYTE *)pvStructInfo +
4649 sizeof(CRYPT_INTEGER_BLOB);
4650 ret = CRYPT_AsnDecodeUnsignedIntegerInternal(dwCertEncodingType,
4651 lpszStructType, pbEncoded, cbEncoded,
4652 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pvStructInfo,
4653 &bytesNeeded);
4657 __EXCEPT(page_fault)
4659 SetLastError(STATUS_ACCESS_VIOLATION);
4660 ret = FALSE;
4662 __ENDTRY
4663 return ret;
4666 static BOOL WINAPI CRYPT_AsnDecodeEnumerated(DWORD dwCertEncodingType,
4667 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4668 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4670 BOOL ret;
4672 if (!pvStructInfo)
4674 *pcbStructInfo = sizeof(int);
4675 return TRUE;
4677 __TRY
4679 if (pbEncoded[0] == ASN_ENUMERATED)
4681 unsigned int val = 0, i;
4683 if (cbEncoded <= 1)
4685 SetLastError(CRYPT_E_ASN1_EOD);
4686 ret = FALSE;
4688 else if (pbEncoded[1] == 0)
4690 SetLastError(CRYPT_E_ASN1_CORRUPT);
4691 ret = FALSE;
4693 else
4695 /* A little strange looking, but we have to accept a sign byte:
4696 * 0xffffffff gets encoded as 0a 05 00 ff ff ff ff. Also,
4697 * assuming a small length is okay here, it has to be in short
4698 * form.
4700 if (pbEncoded[1] > sizeof(unsigned int) + 1)
4702 SetLastError(CRYPT_E_ASN1_LARGE);
4703 return FALSE;
4705 for (i = 0; i < pbEncoded[1]; i++)
4707 val <<= 8;
4708 val |= pbEncoded[2 + i];
4710 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4711 pvStructInfo, pcbStructInfo, sizeof(unsigned int))))
4713 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4714 pvStructInfo = *(BYTE **)pvStructInfo;
4715 memcpy(pvStructInfo, &val, sizeof(unsigned int));
4719 else
4721 SetLastError(CRYPT_E_ASN1_BADTAG);
4722 ret = FALSE;
4725 __EXCEPT(page_fault)
4727 SetLastError(STATUS_ACCESS_VIOLATION);
4728 ret = FALSE;
4730 __ENDTRY
4731 return ret;
4734 /* Modifies word, pbEncoded, and len, and magically sets a value ret to FALSE
4735 * if it fails.
4737 #define CRYPT_TIME_GET_DIGITS(pbEncoded, len, numDigits, word) \
4738 do { \
4739 BYTE i; \
4741 (word) = 0; \
4742 for (i = 0; (len) > 0 && i < (numDigits); i++, (len)--) \
4744 if (!isdigit(*(pbEncoded))) \
4746 SetLastError(CRYPT_E_ASN1_CORRUPT); \
4747 ret = FALSE; \
4749 else \
4751 (word) *= 10; \
4752 (word) += *(pbEncoded)++ - '0'; \
4755 } while (0)
4757 static BOOL CRYPT_AsnDecodeTimeZone(const BYTE *pbEncoded, DWORD len,
4758 SYSTEMTIME *sysTime)
4760 BOOL ret;
4762 __TRY
4764 ret = TRUE;
4765 if (len >= 3 && (*pbEncoded == '+' || *pbEncoded == '-'))
4767 WORD hours, minutes = 0;
4768 BYTE sign = *pbEncoded++;
4770 len--;
4771 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, hours);
4772 if (ret && hours >= 24)
4774 SetLastError(CRYPT_E_ASN1_CORRUPT);
4775 ret = FALSE;
4777 else if (len >= 2)
4779 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, minutes);
4780 if (ret && minutes >= 60)
4782 SetLastError(CRYPT_E_ASN1_CORRUPT);
4783 ret = FALSE;
4786 if (ret)
4788 if (sign == '+')
4790 sysTime->wHour += hours;
4791 sysTime->wMinute += minutes;
4793 else
4795 if (hours > sysTime->wHour)
4797 sysTime->wDay--;
4798 sysTime->wHour = 24 - (hours - sysTime->wHour);
4800 else
4801 sysTime->wHour -= hours;
4802 if (minutes > sysTime->wMinute)
4804 sysTime->wHour--;
4805 sysTime->wMinute = 60 - (minutes - sysTime->wMinute);
4807 else
4808 sysTime->wMinute -= minutes;
4813 __EXCEPT(page_fault)
4815 SetLastError(STATUS_ACCESS_VIOLATION);
4816 ret = FALSE;
4818 __ENDTRY
4819 return ret;
4822 #define MIN_ENCODED_TIME_LENGTH 10
4824 static BOOL WINAPI CRYPT_AsnDecodeUtcTime(DWORD dwCertEncodingType,
4825 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4826 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4828 BOOL ret;
4830 if (!pvStructInfo)
4832 *pcbStructInfo = sizeof(FILETIME);
4833 return TRUE;
4835 __TRY
4837 ret = TRUE;
4838 if (pbEncoded[0] == ASN_UTCTIME)
4840 if (cbEncoded <= 1)
4842 SetLastError(CRYPT_E_ASN1_EOD);
4843 ret = FALSE;
4845 else if (pbEncoded[1] > 0x7f)
4847 /* long-form date strings really can't be valid */
4848 SetLastError(CRYPT_E_ASN1_CORRUPT);
4849 ret = FALSE;
4851 else
4853 SYSTEMTIME sysTime = { 0 };
4854 BYTE len = pbEncoded[1];
4856 if (len < MIN_ENCODED_TIME_LENGTH)
4858 SetLastError(CRYPT_E_ASN1_CORRUPT);
4859 ret = FALSE;
4861 else
4863 pbEncoded += 2;
4864 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wYear);
4865 if (sysTime.wYear >= 50)
4866 sysTime.wYear += 1900;
4867 else
4868 sysTime.wYear += 2000;
4869 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
4870 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
4871 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
4872 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
4873 if (ret && len > 0)
4875 if (len >= 2 && isdigit(*pbEncoded) &&
4876 isdigit(*(pbEncoded + 1)))
4877 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
4878 sysTime.wSecond);
4879 else if (isdigit(*pbEncoded))
4880 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 1,
4881 sysTime.wSecond);
4882 if (ret)
4883 ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len,
4884 &sysTime);
4886 if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags,
4887 pDecodePara, pvStructInfo, pcbStructInfo,
4888 sizeof(FILETIME))))
4890 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4891 pvStructInfo = *(BYTE **)pvStructInfo;
4892 ret = SystemTimeToFileTime(&sysTime,
4893 (FILETIME *)pvStructInfo);
4898 else
4900 SetLastError(CRYPT_E_ASN1_BADTAG);
4901 ret = FALSE;
4904 __EXCEPT(page_fault)
4906 SetLastError(STATUS_ACCESS_VIOLATION);
4907 ret = FALSE;
4909 __ENDTRY
4910 return ret;
4913 static BOOL WINAPI CRYPT_AsnDecodeGeneralizedTime(DWORD dwCertEncodingType,
4914 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4915 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4917 BOOL ret;
4919 if (!pvStructInfo)
4921 *pcbStructInfo = sizeof(FILETIME);
4922 return TRUE;
4924 __TRY
4926 ret = TRUE;
4927 if (pbEncoded[0] == ASN_GENERALTIME)
4929 if (cbEncoded <= 1)
4931 SetLastError(CRYPT_E_ASN1_EOD);
4932 ret = FALSE;
4934 else if (pbEncoded[1] > 0x7f)
4936 /* long-form date strings really can't be valid */
4937 SetLastError(CRYPT_E_ASN1_CORRUPT);
4938 ret = FALSE;
4940 else
4942 BYTE len = pbEncoded[1];
4944 if (len < MIN_ENCODED_TIME_LENGTH)
4946 SetLastError(CRYPT_E_ASN1_CORRUPT);
4947 ret = FALSE;
4949 else
4951 SYSTEMTIME sysTime = { 0 };
4953 pbEncoded += 2;
4954 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 4, sysTime.wYear);
4955 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
4956 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
4957 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
4958 if (ret && len > 0)
4960 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
4961 sysTime.wMinute);
4962 if (ret && len > 0)
4963 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
4964 sysTime.wSecond);
4965 if (ret && len > 0 && (*pbEncoded == '.' ||
4966 *pbEncoded == ','))
4968 BYTE digits;
4970 pbEncoded++;
4971 len--;
4972 /* workaround macro weirdness */
4973 digits = min(len, 3);
4974 CRYPT_TIME_GET_DIGITS(pbEncoded, len, digits,
4975 sysTime.wMilliseconds);
4977 if (ret)
4978 ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len,
4979 &sysTime);
4981 if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags,
4982 pDecodePara, pvStructInfo, pcbStructInfo,
4983 sizeof(FILETIME))))
4985 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4986 pvStructInfo = *(BYTE **)pvStructInfo;
4987 ret = SystemTimeToFileTime(&sysTime,
4988 (FILETIME *)pvStructInfo);
4993 else
4995 SetLastError(CRYPT_E_ASN1_BADTAG);
4996 ret = FALSE;
4999 __EXCEPT(page_fault)
5001 SetLastError(STATUS_ACCESS_VIOLATION);
5002 ret = FALSE;
5004 __ENDTRY
5005 return ret;
5008 static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
5009 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5010 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5012 BOOL ret;
5014 __TRY
5016 if (pbEncoded[0] == ASN_UTCTIME)
5017 ret = CRYPT_AsnDecodeUtcTime(dwCertEncodingType, lpszStructType,
5018 pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
5019 pcbStructInfo);
5020 else if (pbEncoded[0] == ASN_GENERALTIME)
5021 ret = CRYPT_AsnDecodeGeneralizedTime(dwCertEncodingType,
5022 lpszStructType, pbEncoded, cbEncoded, dwFlags, pDecodePara,
5023 pvStructInfo, pcbStructInfo);
5024 else
5026 SetLastError(CRYPT_E_ASN1_BADTAG);
5027 ret = FALSE;
5030 __EXCEPT(page_fault)
5032 SetLastError(STATUS_ACCESS_VIOLATION);
5033 ret = FALSE;
5035 __ENDTRY
5036 return ret;
5039 static BOOL WINAPI CRYPT_AsnDecodeSequenceOfAny(DWORD dwCertEncodingType,
5040 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5041 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5043 BOOL ret = TRUE;
5045 __TRY
5047 if (pbEncoded[0] == ASN_SEQUENCEOF)
5049 DWORD bytesNeeded, dataLen, remainingLen, cValue;
5051 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
5053 BYTE lenBytes;
5054 const BYTE *ptr;
5056 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
5057 bytesNeeded = sizeof(CRYPT_SEQUENCE_OF_ANY);
5058 cValue = 0;
5059 ptr = pbEncoded + 1 + lenBytes;
5060 remainingLen = dataLen;
5061 while (ret && remainingLen)
5063 DWORD nextLen;
5065 ret = CRYPT_GetLen(ptr, remainingLen, &nextLen);
5066 if (ret)
5068 DWORD nextLenBytes = GET_LEN_BYTES(ptr[1]);
5070 remainingLen -= 1 + nextLenBytes + nextLen;
5071 ptr += 1 + nextLenBytes + nextLen;
5072 bytesNeeded += sizeof(CRYPT_DER_BLOB);
5073 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
5074 bytesNeeded += 1 + nextLenBytes + nextLen;
5075 cValue++;
5078 if (ret)
5080 CRYPT_SEQUENCE_OF_ANY *seq;
5081 BYTE *nextPtr;
5082 DWORD i;
5084 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
5085 pvStructInfo, pcbStructInfo, bytesNeeded)))
5087 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
5088 pvStructInfo = *(BYTE **)pvStructInfo;
5089 seq = (CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
5090 seq->cValue = cValue;
5091 seq->rgValue = (CRYPT_DER_BLOB *)((BYTE *)seq +
5092 sizeof(*seq));
5093 nextPtr = (BYTE *)seq->rgValue +
5094 cValue * sizeof(CRYPT_DER_BLOB);
5095 ptr = pbEncoded + 1 + lenBytes;
5096 remainingLen = dataLen;
5097 i = 0;
5098 while (ret && remainingLen)
5100 DWORD nextLen;
5102 ret = CRYPT_GetLen(ptr, remainingLen, &nextLen);
5103 if (ret)
5105 DWORD nextLenBytes = GET_LEN_BYTES(ptr[1]);
5107 seq->rgValue[i].cbData = 1 + nextLenBytes +
5108 nextLen;
5109 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
5110 seq->rgValue[i].pbData = (BYTE *)ptr;
5111 else
5113 seq->rgValue[i].pbData = nextPtr;
5114 memcpy(nextPtr, ptr, 1 + nextLenBytes +
5115 nextLen);
5116 nextPtr += 1 + nextLenBytes + nextLen;
5118 remainingLen -= 1 + nextLenBytes + nextLen;
5119 ptr += 1 + nextLenBytes + nextLen;
5120 i++;
5127 else
5129 SetLastError(CRYPT_E_ASN1_BADTAG);
5130 return FALSE;
5133 __EXCEPT(page_fault)
5135 SetLastError(STATUS_ACCESS_VIOLATION);
5136 ret = FALSE;
5138 __ENDTRY
5139 return ret;
5142 BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
5143 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5144 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5146 static HCRYPTOIDFUNCSET set = NULL;
5147 BOOL ret = FALSE;
5148 CryptDecodeObjectExFunc decodeFunc = NULL;
5149 HCRYPTOIDFUNCADDR hFunc = NULL;
5151 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p, %p)\n",
5152 dwCertEncodingType, debugstr_a(lpszStructType), pbEncoded,
5153 cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
5155 if (!pvStructInfo && !pcbStructInfo)
5157 SetLastError(ERROR_INVALID_PARAMETER);
5158 return FALSE;
5160 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
5161 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
5163 SetLastError(ERROR_FILE_NOT_FOUND);
5164 return FALSE;
5166 if (!cbEncoded)
5168 SetLastError(CRYPT_E_ASN1_EOD);
5169 return FALSE;
5171 if (cbEncoded > MAX_ENCODED_LEN)
5173 SetLastError(CRYPT_E_ASN1_LARGE);
5174 return FALSE;
5177 SetLastError(NOERROR);
5178 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG && pvStructInfo)
5179 *(BYTE **)pvStructInfo = NULL;
5180 if (!HIWORD(lpszStructType))
5182 switch (LOWORD(lpszStructType))
5184 case (WORD)X509_CERT:
5185 decodeFunc = CRYPT_AsnDecodeCert;
5186 break;
5187 case (WORD)X509_CERT_TO_BE_SIGNED:
5188 decodeFunc = CRYPT_AsnDecodeCertInfo;
5189 break;
5190 case (WORD)X509_CERT_CRL_TO_BE_SIGNED:
5191 decodeFunc = CRYPT_AsnDecodeCRLInfo;
5192 break;
5193 case (WORD)X509_EXTENSIONS:
5194 decodeFunc = CRYPT_AsnDecodeExtensions;
5195 break;
5196 case (WORD)X509_NAME:
5197 decodeFunc = CRYPT_AsnDecodeName;
5198 break;
5199 case (WORD)X509_PUBLIC_KEY_INFO:
5200 decodeFunc = CRYPT_AsnDecodePubKeyInfo;
5201 break;
5202 case (WORD)X509_ALTERNATE_NAME:
5203 decodeFunc = CRYPT_AsnDecodeAltName;
5204 break;
5205 case (WORD)X509_BASIC_CONSTRAINTS2:
5206 decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
5207 break;
5208 case (WORD)RSA_CSP_PUBLICKEYBLOB:
5209 decodeFunc = CRYPT_AsnDecodeRsaPubKey;
5210 break;
5211 case (WORD)X509_OCTET_STRING:
5212 decodeFunc = CRYPT_AsnDecodeOctets;
5213 break;
5214 case (WORD)X509_BITS:
5215 case (WORD)X509_KEY_USAGE:
5216 decodeFunc = CRYPT_AsnDecodeBits;
5217 break;
5218 case (WORD)X509_INTEGER:
5219 decodeFunc = CRYPT_AsnDecodeInt;
5220 break;
5221 case (WORD)X509_MULTI_BYTE_INTEGER:
5222 decodeFunc = CRYPT_AsnDecodeInteger;
5223 break;
5224 case (WORD)X509_MULTI_BYTE_UINT:
5225 decodeFunc = CRYPT_AsnDecodeUnsignedInteger;
5226 break;
5227 case (WORD)X509_ENUMERATED:
5228 decodeFunc = CRYPT_AsnDecodeEnumerated;
5229 break;
5230 case (WORD)X509_CHOICE_OF_TIME:
5231 decodeFunc = CRYPT_AsnDecodeChoiceOfTime;
5232 break;
5233 case (WORD)X509_SEQUENCE_OF_ANY:
5234 decodeFunc = CRYPT_AsnDecodeSequenceOfAny;
5235 break;
5236 case (WORD)PKCS_UTC_TIME:
5237 decodeFunc = CRYPT_AsnDecodeUtcTime;
5238 break;
5239 default:
5240 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
5243 else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
5244 decodeFunc = CRYPT_AsnDecodeExtensions;
5245 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
5246 decodeFunc = CRYPT_AsnDecodeUtcTime;
5247 else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
5248 decodeFunc = CRYPT_AsnDecodeEnumerated;
5249 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
5250 decodeFunc = CRYPT_AsnDecodeBits;
5251 else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
5252 decodeFunc = CRYPT_AsnDecodeOctets;
5253 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
5254 decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
5255 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
5256 decodeFunc = CRYPT_AsnDecodeAltName;
5257 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
5258 decodeFunc = CRYPT_AsnDecodeAltName;
5259 else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION))
5260 decodeFunc = CRYPT_AsnDecodeAltName;
5261 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
5262 decodeFunc = CRYPT_AsnDecodeAltName;
5263 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
5264 decodeFunc = CRYPT_AsnDecodeAltName;
5265 else
5266 TRACE("OID %s not found or unimplemented, looking for DLL\n",
5267 debugstr_a(lpszStructType));
5268 if (!decodeFunc)
5270 if (!set)
5271 set = CryptInitOIDFunctionSet(CRYPT_OID_DECODE_OBJECT_EX_FUNC, 0);
5272 CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
5273 (void **)&decodeFunc, &hFunc);
5275 if (decodeFunc)
5276 ret = decodeFunc(dwCertEncodingType, lpszStructType, pbEncoded,
5277 cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
5278 else
5279 SetLastError(ERROR_FILE_NOT_FOUND);
5280 if (hFunc)
5281 CryptFreeOIDFunctionAddress(hFunc, 0);
5282 return ret;
5285 BOOL WINAPI CryptExportPublicKeyInfo(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
5286 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
5288 return CryptExportPublicKeyInfoEx(hCryptProv, dwKeySpec, dwCertEncodingType,
5289 NULL, 0, NULL, pInfo, pcbInfo);
5292 static BOOL WINAPI CRYPT_ExportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv,
5293 DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
5294 DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
5296 BOOL ret;
5297 HCRYPTKEY key;
5299 TRACE("(%ld, %ld, %08lx, %s, %08lx, %p, %p, %p)\n", hCryptProv, dwKeySpec,
5300 dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo,
5301 pInfo, pcbInfo);
5303 if (!pszPublicKeyObjId)
5304 pszPublicKeyObjId = szOID_RSA_RSA;
5305 if ((ret = CryptGetUserKey(hCryptProv, dwKeySpec, &key)))
5307 DWORD keySize = 0;
5309 ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, NULL, &keySize);
5310 if (ret)
5312 LPBYTE pubKey = CryptMemAlloc(keySize);
5314 if (pubKey)
5316 ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, pubKey,
5317 &keySize);
5318 if (ret)
5320 DWORD encodedLen = 0;
5322 ret = CryptEncodeObject(dwCertEncodingType,
5323 RSA_CSP_PUBLICKEYBLOB, pubKey, NULL, &encodedLen);
5324 if (ret)
5326 DWORD sizeNeeded = sizeof(CERT_PUBLIC_KEY_INFO) +
5327 strlen(pszPublicKeyObjId) + 1 + encodedLen;
5329 if (!pInfo)
5330 *pcbInfo = sizeNeeded;
5331 else if (*pcbInfo < sizeNeeded)
5333 SetLastError(ERROR_MORE_DATA);
5334 *pcbInfo = sizeNeeded;
5335 ret = FALSE;
5337 else
5339 pInfo->Algorithm.pszObjId = (char *)pInfo +
5340 sizeof(CERT_PUBLIC_KEY_INFO);
5341 lstrcpyA(pInfo->Algorithm.pszObjId,
5342 pszPublicKeyObjId);
5343 pInfo->Algorithm.Parameters.cbData = 0;
5344 pInfo->Algorithm.Parameters.pbData = NULL;
5345 pInfo->PublicKey.pbData =
5346 (BYTE *)pInfo->Algorithm.pszObjId
5347 + lstrlenA(pInfo->Algorithm.pszObjId) + 1;
5348 pInfo->PublicKey.cbData = encodedLen;
5349 pInfo->PublicKey.cUnusedBits = 0;
5350 ret = CryptEncodeObject(dwCertEncodingType,
5351 RSA_CSP_PUBLICKEYBLOB, pubKey,
5352 pInfo->PublicKey.pbData, &pInfo->PublicKey.cbData);
5356 CryptMemFree(pubKey);
5358 else
5359 ret = FALSE;
5361 CryptDestroyKey(key);
5363 return ret;
5366 typedef BOOL (WINAPI *ExportPublicKeyInfoExFunc)(HCRYPTPROV hCryptProv,
5367 DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
5368 DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo);
5370 BOOL WINAPI CryptExportPublicKeyInfoEx(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
5371 DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId, DWORD dwFlags,
5372 void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
5374 static HCRYPTOIDFUNCSET set = NULL;
5375 BOOL ret;
5376 ExportPublicKeyInfoExFunc exportFunc = NULL;
5377 HCRYPTOIDFUNCADDR hFunc = NULL;
5379 TRACE("(%ld, %ld, %08lx, %s, %08lx, %p, %p, %p)\n", hCryptProv, dwKeySpec,
5380 dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo,
5381 pInfo, pcbInfo);
5383 if (!hCryptProv)
5385 SetLastError(ERROR_INVALID_PARAMETER);
5386 return FALSE;
5389 if (pszPublicKeyObjId)
5391 if (!set)
5392 set = CryptInitOIDFunctionSet(CRYPT_OID_EXPORT_PUBLIC_KEY_INFO_FUNC,
5394 CryptGetOIDFunctionAddress(set, dwCertEncodingType, pszPublicKeyObjId,
5395 0, (void **)&exportFunc, &hFunc);
5397 if (!exportFunc)
5398 exportFunc = CRYPT_ExportRsaPublicKeyInfoEx;
5399 ret = exportFunc(hCryptProv, dwKeySpec, dwCertEncodingType,
5400 pszPublicKeyObjId, dwFlags, pvAuxInfo, pInfo, pcbInfo);
5401 if (hFunc)
5402 CryptFreeOIDFunctionAddress(hFunc, 0);
5403 return ret;
5406 BOOL WINAPI CryptImportPublicKeyInfo(HCRYPTPROV hCryptProv,
5407 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
5409 return CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType, pInfo,
5410 0, 0, NULL, phKey);
5413 static BOOL WINAPI CRYPT_ImportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv,
5414 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
5415 DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
5417 BOOL ret;
5418 DWORD pubKeySize = 0;
5420 TRACE("(%ld, %ld, %p, %d, %08lx, %p, %p)\n", hCryptProv,
5421 dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
5423 ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
5424 pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, NULL, &pubKeySize);
5425 if (ret)
5427 LPBYTE pubKey = CryptMemAlloc(pubKeySize);
5429 if (pubKey)
5431 ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
5432 pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, pubKey,
5433 &pubKeySize);
5434 if (ret)
5435 ret = CryptImportKey(hCryptProv, pubKey, pubKeySize, 0, 0,
5436 phKey);
5437 CryptMemFree(pubKey);
5439 else
5440 ret = FALSE;
5442 return ret;
5445 typedef BOOL (WINAPI *ImportPublicKeyInfoExFunc)(HCRYPTPROV hCryptProv,
5446 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
5447 DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey);
5449 BOOL WINAPI CryptImportPublicKeyInfoEx(HCRYPTPROV hCryptProv,
5450 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
5451 DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
5453 static HCRYPTOIDFUNCSET set = NULL;
5454 BOOL ret;
5455 ImportPublicKeyInfoExFunc importFunc = NULL;
5456 HCRYPTOIDFUNCADDR hFunc = NULL;
5458 TRACE("(%ld, %ld, %p, %d, %08lx, %p, %p)\n", hCryptProv,
5459 dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
5461 if (!set)
5462 set = CryptInitOIDFunctionSet(CRYPT_OID_IMPORT_PUBLIC_KEY_INFO_FUNC, 0);
5463 CryptGetOIDFunctionAddress(set, dwCertEncodingType,
5464 pInfo->Algorithm.pszObjId, 0, (void **)&importFunc, &hFunc);
5465 if (!importFunc)
5466 importFunc = CRYPT_ImportRsaPublicKeyInfoEx;
5467 ret = importFunc(hCryptProv, dwCertEncodingType, pInfo, aiKeyAlg, dwFlags,
5468 pvAuxInfo, phKey);
5469 if (hFunc)
5470 CryptFreeOIDFunctionAddress(hFunc, 0);
5471 return ret;