Fix some memory leaks.
[wine/multimedia.git] / dlls / crypt32 / encode.c
blobc65941f4b3f4cf7cf609efefad8a6138f126fdf0
1 /*
2 * Copyright 2002 Mike McCormack for CodeWeavers
3 * Copyright 2005 Juan Lang
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 * This file implements ASN.1 DER encoding and decoding of a limited set of
20 * types. It isn't a full ASN.1 implementation. Microsoft implements BER
21 * encoding of many of the basic types in msasn1.dll, but that interface is
22 * undocumented, so I implement them here.
24 * References:
25 * "A Layman's Guide to a Subset of ASN.1, BER, and DER", by Burton Kaliski
26 * (available online, look for a PDF copy as the HTML versions tend to have
27 * translation errors.)
29 * RFC3280, http://www.faqs.org/rfcs/rfc3280.html
31 * MSDN, especially:
32 * http://msdn.microsoft.com/library/en-us/seccrypto/security/constants_for_cryptencodeobject_and_cryptdecodeobject.asp
34 #include <assert.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <stdlib.h>
39 #define NONAMELESSUNION
41 #include "windef.h"
42 #include "winbase.h"
43 #include "excpt.h"
44 #include "wincrypt.h"
45 #include "winreg.h"
46 #include "snmp.h"
47 #include "wine/debug.h"
48 #include "wine/exception.h"
49 #include "crypt32_private.h"
51 /* This is a bit arbitrary, but to set some limit: */
52 #define MAX_ENCODED_LEN 0x02000000
54 /* a few asn.1 tags we need */
55 #define ASN_BOOL (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x01)
56 #define ASN_BITSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x03)
57 #define ASN_ENUMERATED (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x0a)
58 #define ASN_SETOF (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x11)
59 #define ASN_NUMERICSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x12)
60 #define ASN_PRINTABLESTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x13)
61 #define ASN_IA5STRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x16)
62 #define ASN_UTCTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x17)
63 #define ASN_GENERALTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x18)
65 #define ASN_FLAGS_MASK 0xf0
66 #define ASN_TYPE_MASK 0x0f
68 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
70 static const WCHAR szDllName[] = { 'D','l','l',0 };
72 typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
73 BYTE *, DWORD *);
74 typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *,
75 DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *);
76 typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
77 DWORD, DWORD, void *, DWORD *);
78 typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *,
79 DWORD, DWORD, PCRYPT_DECODE_PARA, void *, DWORD *);
81 /* Prototypes for built-in encoders/decoders. They follow the Ex style
82 * prototypes. The dwCertEncodingType and lpszStructType are ignored by the
83 * built-in functions, but the parameters are retained to simplify
84 * CryptEncodeObjectEx/CryptDecodeObjectEx, since they must call functions in
85 * external DLLs that follow these signatures.
86 * FIXME: some built-in functions are suitable to be called directly by
87 * CryptEncodeObjectEx/CryptDecodeObjectEx (they implement exception handling
88 * and memory allocation if requested), others are only suitable to be called
89 * internally. Comment which are which.
91 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
92 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
93 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
94 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
95 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
96 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
97 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
98 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
99 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
100 static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
101 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
102 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
103 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
104 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
105 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
106 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
107 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
108 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
109 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
110 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
111 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
112 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
113 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
114 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
115 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
116 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
117 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
118 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
119 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
120 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
121 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
122 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
123 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
125 static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
126 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
127 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
128 static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType,
129 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
130 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
131 /* Like CRYPT_AsnDecodeExtensions, except assumes rgExtension is set ahead of
132 * time, doesn't do memory allocation, and doesn't do exception handling.
133 * (This isn't intended to be the externally-called one.)
135 static BOOL WINAPI CRYPT_AsnDecodeExtensionsInternal(DWORD dwCertEncodingType,
136 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
137 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
138 static BOOL WINAPI CRYPT_AsnDecodeOid(const BYTE *pbEncoded, DWORD cbEncoded,
139 DWORD dwFlags, LPSTR pszObjId, DWORD *pcbObjId);
140 /* Assumes algo->Parameters.pbData is set ahead of time */
141 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
142 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
143 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
144 static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
145 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
146 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
147 /* Assumes the CRYPT_DATA_BLOB's pbData member has been initialized */
148 static BOOL WINAPI CRYPT_AsnDecodeOctetsInternal(DWORD dwCertEncodingType,
149 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
150 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
151 /* Like CRYPT_AsnDecodeBits, but assumes the CRYPT_INTEGER_BLOB's pbData
152 * member has been initialized, doesn't do exception handling, and doesn't do
153 * memory allocation.
155 static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(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_AsnDecodeBits(DWORD dwCertEncodingType,
159 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
160 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
161 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
162 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
163 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
164 /* Like CRYPT_AsnDecodeInteger, but assumes the CRYPT_INTEGER_BLOB's pbData
165 * member has been initialized, doesn't do exception handling, and doesn't do
166 * memory allocation.
168 static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType,
169 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
170 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
171 /* Like CRYPT_AsnDecodeInteger, but unsigned. */
172 static BOOL WINAPI CRYPT_AsnDecodeUnsignedIntegerInternal(
173 DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded,
174 DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
175 void *pvStructInfo, DWORD *pcbStructInfo);
177 /* filter for page-fault exceptions */
178 static WINE_EXCEPTION_FILTER(page_fault)
180 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
181 return EXCEPTION_EXECUTE_HANDLER;
182 return EXCEPTION_CONTINUE_SEARCH;
185 static char *CRYPT_GetKeyName(DWORD dwEncodingType, LPCSTR pszFuncName,
186 LPCSTR pszOID)
188 static const char szEncodingTypeFmt[] =
189 "Software\\Microsoft\\Cryptography\\OID\\EncodingType %ld\\%s\\%s";
190 UINT len;
191 char numericOID[7]; /* enough for "#65535" */
192 const char *oid;
193 LPSTR szKey;
195 /* MSDN says the encoding type is a mask, but it isn't treated that way.
196 * (E.g., if dwEncodingType were 3, the key names "EncodingType 1" and
197 * "EncodingType 2" would be expected if it were a mask. Instead native
198 * stores values in "EncodingType 3".
200 if (!HIWORD(pszOID))
202 snprintf(numericOID, sizeof(numericOID), "#%d", LOWORD(pszOID));
203 oid = numericOID;
205 else
206 oid = pszOID;
208 /* This is enough: the lengths of the two string parameters are explicitly
209 * counted, and we need up to five additional characters for the encoding
210 * type. These are covered by the "%d", "%s", and "%s" characters in the
211 * format specifier that are removed by sprintf.
213 len = sizeof(szEncodingTypeFmt) + lstrlenA(pszFuncName) + lstrlenA(oid);
214 szKey = CryptMemAlloc(len);
215 if (szKey)
216 sprintf(szKey, szEncodingTypeFmt, dwEncodingType, pszFuncName, oid);
217 return szKey;
220 BOOL WINAPI CryptRegisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
221 LPCSTR pszOID, LPCWSTR pwszDll, LPCSTR pszOverrideFuncName)
223 LONG r;
224 HKEY hKey;
225 LPSTR szKey;
227 TRACE("%lx %s %s %s %s\n", dwEncodingType, pszFuncName, pszOID,
228 debugstr_w(pwszDll), pszOverrideFuncName);
230 /* This only registers functions for encoding certs, not messages */
231 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
232 return TRUE;
234 /* Native does nothing pwszDll is NULL */
235 if (!pwszDll)
236 return TRUE;
238 /* I'm not matching MS bug for bug here, because I doubt any app depends on
239 * it:
240 * - native "succeeds" if pszFuncName is NULL, but the nonsensical entry
241 * it creates would never be used
242 * - native returns an HRESULT rather than a Win32 error if pszOID is NULL.
243 * Instead I disallow both of these with ERROR_INVALID_PARAMETER.
245 if (!pszFuncName || !pszOID)
247 SetLastError(ERROR_INVALID_PARAMETER);
248 return FALSE;
251 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
252 TRACE("Key name is %s\n", debugstr_a(szKey));
254 if (!szKey)
255 return FALSE;
257 r = RegCreateKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
258 CryptMemFree(szKey);
259 if(r != ERROR_SUCCESS)
260 return FALSE;
262 /* write the values */
263 if (pszOverrideFuncName)
264 RegSetValueExA(hKey, "FuncName", 0, REG_SZ, (const BYTE*)pszOverrideFuncName,
265 lstrlenA(pszOverrideFuncName) + 1);
266 RegSetValueExW(hKey, szDllName, 0, REG_SZ, (const BYTE*) pwszDll,
267 (lstrlenW(pwszDll) + 1) * sizeof (WCHAR));
269 RegCloseKey(hKey);
270 return TRUE;
273 BOOL WINAPI CryptUnregisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
274 LPCSTR pszOID)
276 LPSTR szKey;
277 LONG rc;
279 TRACE("%lx %s %s\n", dwEncodingType, pszFuncName, pszOID);
281 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
282 return TRUE;
284 if (!pszFuncName || !pszOID)
286 SetLastError(ERROR_INVALID_PARAMETER);
287 return FALSE;
290 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
291 rc = RegDeleteKeyA(HKEY_LOCAL_MACHINE, szKey);
292 CryptMemFree(szKey);
293 if (rc)
294 SetLastError(rc);
295 return rc ? FALSE : TRUE;
298 BOOL WINAPI CryptGetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
299 LPCSTR pszOID, LPCWSTR pwszValueName, DWORD *pdwValueType, BYTE *pbValueData,
300 DWORD *pcbValueData)
302 LPSTR szKey;
303 LONG rc;
304 HKEY hKey;
306 TRACE("%lx %s %s %s %p %p %p\n", dwEncodingType, debugstr_a(pszFuncName),
307 debugstr_a(pszOID), debugstr_w(pwszValueName), pdwValueType, pbValueData,
308 pcbValueData);
310 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
311 return TRUE;
313 if (!pszFuncName || !pszOID || !pwszValueName)
315 SetLastError(ERROR_INVALID_PARAMETER);
316 return FALSE;
319 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
320 rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
321 CryptMemFree(szKey);
322 if (rc)
323 SetLastError(rc);
324 else
326 rc = RegQueryValueExW(hKey, pwszValueName, NULL, pdwValueType,
327 pbValueData, pcbValueData);
328 if (rc)
329 SetLastError(rc);
330 RegCloseKey(hKey);
332 return rc ? FALSE : TRUE;
335 BOOL WINAPI CryptSetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
336 LPCSTR pszOID, LPCWSTR pwszValueName, DWORD dwValueType,
337 const BYTE *pbValueData, DWORD cbValueData)
339 LPSTR szKey;
340 LONG rc;
341 HKEY hKey;
343 TRACE("%lx %s %s %s %ld %p %ld\n", dwEncodingType, debugstr_a(pszFuncName),
344 debugstr_a(pszOID), debugstr_w(pwszValueName), dwValueType, pbValueData,
345 cbValueData);
347 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
348 return TRUE;
350 if (!pszFuncName || !pszOID || !pwszValueName)
352 SetLastError(ERROR_INVALID_PARAMETER);
353 return FALSE;
356 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
357 rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
358 CryptMemFree(szKey);
359 if (rc)
360 SetLastError(rc);
361 else
363 rc = RegSetValueExW(hKey, pwszValueName, 0, dwValueType, pbValueData,
364 cbValueData);
365 if (rc)
366 SetLastError(rc);
367 RegCloseKey(hKey);
369 return rc ? FALSE : TRUE;
372 /* Gets the registered function named szFuncName for dwCertEncodingType and
373 * lpszStructType, or NULL if one could not be found. *lib will be set to the
374 * handle of the module it's in, or NULL if no module was loaded. If the
375 * return value is NULL, *lib will also be NULL, to simplify error handling.
377 static void *CRYPT_GetFunc(DWORD dwCertEncodingType, LPCSTR lpszStructType,
378 LPCSTR szFuncName, HMODULE *lib)
380 void *ret = NULL;
381 char *szKey = CRYPT_GetKeyName(dwCertEncodingType, szFuncName,
382 lpszStructType);
383 const char *funcName;
384 long r;
385 HKEY hKey;
386 DWORD type, size = 0;
388 TRACE("(%08lx %s %s %p)\n", dwCertEncodingType, debugstr_a(lpszStructType),
389 debugstr_a(szFuncName), lib);
391 *lib = NULL;
392 r = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
393 CryptMemFree(szKey);
394 if(r != ERROR_SUCCESS)
395 return NULL;
397 RegQueryValueExA(hKey, "FuncName", NULL, &type, NULL, &size);
398 if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
400 funcName = CryptMemAlloc(size);
401 RegQueryValueExA(hKey, "FuncName", NULL, &type, (LPBYTE)funcName,
402 &size);
404 else
405 funcName = szFuncName;
406 RegQueryValueExW(hKey, szDllName, NULL, &type, NULL, &size);
407 if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
409 LPWSTR dllName = CryptMemAlloc(size);
411 RegQueryValueExW(hKey, szDllName, NULL, &type, (LPBYTE)dllName,
412 &size);
413 *lib = LoadLibraryW(dllName);
414 if (*lib)
416 ret = GetProcAddress(*lib, funcName);
417 if (!ret)
419 /* Unload the library, the caller doesn't want to unload it
420 * when the return value is NULL.
422 FreeLibrary(*lib);
423 *lib = NULL;
426 CryptMemFree(dllName);
428 if (funcName != szFuncName)
429 CryptMemFree((char *)funcName);
430 TRACE("returning %p\n", ret);
431 return ret;
434 BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
435 const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
437 BOOL ret = FALSE;
438 HMODULE lib;
439 CryptEncodeObjectFunc pCryptEncodeObject;
441 TRACE("(0x%08lx, %s, %p, %p, %p)\n", dwCertEncodingType,
442 debugstr_a(lpszStructType), pvStructInfo, pbEncoded,
443 pcbEncoded);
445 if (!pbEncoded && !pcbEncoded)
447 SetLastError(ERROR_INVALID_PARAMETER);
448 return FALSE;
451 /* Try registered DLL first.. */
452 pCryptEncodeObject =
453 (CryptEncodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
454 lpszStructType, CRYPT_OID_ENCODE_OBJECT_FUNC, &lib);
455 if (pCryptEncodeObject)
457 ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
458 pvStructInfo, pbEncoded, pcbEncoded);
459 FreeLibrary(lib);
461 else
463 /* If not, use CryptEncodeObjectEx */
464 ret = CryptEncodeObjectEx(dwCertEncodingType, lpszStructType,
465 pvStructInfo, 0, NULL, pbEncoded, pcbEncoded);
467 return ret;
470 /* Helper function to check *pcbEncoded, set it to the required size, and
471 * optionally to allocate memory. Assumes pbEncoded is not NULL.
472 * If CRYPT_ENCODE_ALLOC_FLAG is set in dwFlags, *pbEncoded will be set to a
473 * pointer to the newly allocated memory.
475 static BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags,
476 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded,
477 DWORD bytesNeeded)
479 BOOL ret = TRUE;
481 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
483 if (pEncodePara && pEncodePara->pfnAlloc)
484 *(BYTE **)pbEncoded = pEncodePara->pfnAlloc(bytesNeeded);
485 else
486 *(BYTE **)pbEncoded = LocalAlloc(0, bytesNeeded);
487 if (!*(BYTE **)pbEncoded)
488 ret = FALSE;
489 else
490 *pcbEncoded = bytesNeeded;
492 else if (bytesNeeded > *pcbEncoded)
494 *pcbEncoded = bytesNeeded;
495 SetLastError(ERROR_MORE_DATA);
496 ret = FALSE;
498 return ret;
501 static BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded)
503 DWORD bytesNeeded, significantBytes = 0;
505 if (len <= 0x7f)
506 bytesNeeded = 1;
507 else
509 DWORD temp;
511 for (temp = len, significantBytes = sizeof(temp); !(temp & 0xff000000);
512 temp <<= 8, significantBytes--)
514 bytesNeeded = significantBytes + 1;
516 if (!pbEncoded)
518 *pcbEncoded = bytesNeeded;
519 return TRUE;
521 if (*pcbEncoded < bytesNeeded)
523 SetLastError(ERROR_MORE_DATA);
524 return FALSE;
526 if (len <= 0x7f)
527 *pbEncoded = (BYTE)len;
528 else
530 DWORD i;
532 *pbEncoded++ = significantBytes | 0x80;
533 for (i = 0; i < significantBytes; i++)
535 *(pbEncoded + significantBytes - i - 1) = (BYTE)(len & 0xff);
536 len >>= 8;
539 *pcbEncoded = bytesNeeded;
540 return TRUE;
543 struct AsnEncodeSequenceItem
545 const void *pvStructInfo;
546 CryptEncodeObjectExFunc encodeFunc;
547 DWORD size; /* used during encoding, not for your use */
550 static BOOL WINAPI CRYPT_AsnEncodeSequence(DWORD dwCertEncodingType,
551 struct AsnEncodeSequenceItem items[], DWORD cItem, DWORD dwFlags,
552 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
554 BOOL ret;
555 DWORD i, dataLen = 0;
557 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", items, cItem, dwFlags, pEncodePara,
558 pbEncoded, *pcbEncoded);
559 for (i = 0, ret = TRUE; ret && i < cItem; i++)
561 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
562 items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
563 NULL, &items[i].size);
564 dataLen += items[i].size;
566 if (ret)
568 DWORD lenBytes, bytesNeeded;
570 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
571 bytesNeeded = 1 + lenBytes + dataLen;
572 if (!pbEncoded)
573 *pcbEncoded = bytesNeeded;
574 else
576 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
577 pcbEncoded, bytesNeeded)))
579 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
580 pbEncoded = *(BYTE **)pbEncoded;
581 *pbEncoded++ = ASN_SEQUENCE;
582 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
583 pbEncoded += lenBytes;
584 for (i = 0; ret && i < cItem; i++)
586 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
587 items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG,
588 NULL, pbEncoded, &items[i].size);
589 pbEncoded += items[i].size;
594 TRACE("returning %d (%08lx)\n", ret, GetLastError());
595 return ret;
598 struct AsnConstructedItem
600 BYTE tag;
601 const void *pvStructInfo;
602 CryptEncodeObjectExFunc encodeFunc;
605 static BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType,
606 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
607 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
609 BOOL ret;
610 const struct AsnConstructedItem *item =
611 (const struct AsnConstructedItem *)pvStructInfo;
612 DWORD len;
614 if ((ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
615 item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &len)))
617 DWORD dataLen, bytesNeeded;
619 CRYPT_EncodeLen(len, NULL, &dataLen);
620 bytesNeeded = 1 + dataLen + len;
621 if (!pbEncoded)
622 *pcbEncoded = bytesNeeded;
623 else if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
624 pbEncoded, pcbEncoded, bytesNeeded)))
626 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
627 pbEncoded = *(BYTE **)pbEncoded;
628 *pbEncoded++ = ASN_CONTEXT | ASN_CONSTRUCTOR | item->tag;
629 CRYPT_EncodeLen(len, pbEncoded, &dataLen);
630 pbEncoded += dataLen;
631 ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
632 item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
633 pbEncoded, &len);
636 return ret;
639 static BOOL WINAPI CRYPT_AsnEncodeCertVersion(DWORD dwCertEncodingType,
640 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
641 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
643 const DWORD *ver = (const DWORD *)pvStructInfo;
644 BOOL ret;
646 /* CERT_V1 is not encoded */
647 if (*ver == CERT_V1)
649 *pcbEncoded = 0;
650 ret = TRUE;
652 else
654 struct AsnConstructedItem item = { 0, ver, CRYPT_AsnEncodeInt };
656 ret = CRYPT_AsnEncodeConstructed(dwCertEncodingType, X509_INTEGER,
657 &item, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
659 return ret;
662 static BOOL WINAPI CRYPT_CopyEncodedBlob(DWORD dwCertEncodingType,
663 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
664 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
666 const CRYPT_DER_BLOB *blob = (const CRYPT_DER_BLOB *)pvStructInfo;
667 BOOL ret;
669 if (!pbEncoded)
671 *pcbEncoded = blob->cbData;
672 ret = TRUE;
674 else if (*pcbEncoded < blob->cbData)
676 *pcbEncoded = blob->cbData;
677 SetLastError(ERROR_MORE_DATA);
678 ret = FALSE;
680 else
682 if (blob->cbData)
683 memcpy(pbEncoded, blob->pbData, blob->cbData);
684 *pcbEncoded = blob->cbData;
685 ret = TRUE;
687 return ret;
690 static BOOL WINAPI CRYPT_AsnEncodeValidity(DWORD dwCertEncodingType,
691 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
692 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
694 BOOL ret;
695 /* This has two filetimes in a row, a NotBefore and a NotAfter */
696 const FILETIME *timePtr = (const FILETIME *)pvStructInfo;
697 struct AsnEncodeSequenceItem items[] = {
698 { timePtr++, CRYPT_AsnEncodeChoiceOfTime, 0 },
699 { timePtr, CRYPT_AsnEncodeChoiceOfTime, 0 },
702 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
703 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
704 pcbEncoded);
705 return ret;
708 static BOOL WINAPI CRYPT_AsnEncodeAlgorithmId(
709 DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
710 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
711 DWORD *pcbEncoded)
713 const CRYPT_ALGORITHM_IDENTIFIER *algo =
714 (const CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
715 BOOL ret;
716 struct AsnEncodeSequenceItem items[] = {
717 { algo->pszObjId, CRYPT_AsnEncodeOid, 0 },
718 { &algo->Parameters, CRYPT_CopyEncodedBlob, 0 },
721 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
722 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
723 pcbEncoded);
724 return ret;
727 static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
728 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
729 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
731 BOOL ret;
733 __TRY
735 const CERT_PUBLIC_KEY_INFO *info =
736 (const CERT_PUBLIC_KEY_INFO *)pvStructInfo;
737 struct AsnEncodeSequenceItem items[] = {
738 { &info->Algorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
739 { &info->PublicKey, CRYPT_AsnEncodeBits, 0 },
742 TRACE("Encoding public key with OID %s\n",
743 debugstr_a(info->Algorithm.pszObjId));
744 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
745 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
746 pcbEncoded);
748 __EXCEPT(page_fault)
750 SetLastError(STATUS_ACCESS_VIOLATION);
751 ret = FALSE;
753 __ENDTRY
754 return ret;
757 static BOOL WINAPI CRYPT_AsnEncodeCert(DWORD dwCertEncodingType,
758 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
759 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
761 BOOL ret;
763 __TRY
765 const CERT_SIGNED_CONTENT_INFO *info =
766 (const CERT_SIGNED_CONTENT_INFO *)pvStructInfo;
767 struct AsnEncodeSequenceItem items[] = {
768 { &info->ToBeSigned, CRYPT_CopyEncodedBlob, 0 },
769 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
770 { &info->Signature, CRYPT_AsnEncodeBitsSwapBytes, 0 },
773 if (dwFlags & CRYPT_ENCODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG)
774 items[2].encodeFunc = CRYPT_AsnEncodeBits;
775 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
776 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
777 pcbEncoded);
779 __EXCEPT(page_fault)
781 SetLastError(STATUS_ACCESS_VIOLATION);
782 ret = FALSE;
784 __ENDTRY
785 return ret;
788 /* Like in Windows, this blithely ignores the validity of the passed-in
789 * CERT_INFO, and just encodes it as-is. The resulting encoded data may not
790 * decode properly, see CRYPT_AsnDecodeCertInfo.
792 static BOOL WINAPI CRYPT_AsnEncodeCertInfo(DWORD dwCertEncodingType,
793 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
794 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
796 BOOL ret;
798 __TRY
800 const CERT_INFO *info = (const CERT_INFO *)pvStructInfo;
801 struct AsnEncodeSequenceItem items[10] = {
802 { &info->dwVersion, CRYPT_AsnEncodeCertVersion, 0 },
803 { &info->SerialNumber, CRYPT_AsnEncodeInteger, 0 },
804 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
805 { &info->Issuer, CRYPT_CopyEncodedBlob, 0 },
806 { &info->NotBefore, CRYPT_AsnEncodeValidity, 0 },
807 { &info->Subject, CRYPT_CopyEncodedBlob, 0 },
808 { &info->SubjectPublicKeyInfo, CRYPT_AsnEncodePubKeyInfo, 0 },
809 { 0 }
811 struct AsnConstructedItem constructed[3] = { { 0 } };
812 DWORD cItem = 7, cConstructed = 0;
814 if (info->IssuerUniqueId.cbData)
816 constructed[cConstructed].tag = 1;
817 constructed[cConstructed].pvStructInfo = &info->IssuerUniqueId;
818 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
819 items[cItem].pvStructInfo = &constructed[cConstructed];
820 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
821 cConstructed++;
822 cItem++;
824 if (info->SubjectUniqueId.cbData)
826 constructed[cConstructed].tag = 2;
827 constructed[cConstructed].pvStructInfo = &info->SubjectUniqueId;
828 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
829 items[cItem].pvStructInfo = &constructed[cConstructed];
830 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
831 cConstructed++;
832 cItem++;
834 if (info->cExtension)
836 constructed[cConstructed].tag = 3;
837 constructed[cConstructed].pvStructInfo = &info->cExtension;
838 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeExtensions;
839 items[cItem].pvStructInfo = &constructed[cConstructed];
840 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
841 cConstructed++;
842 cItem++;
845 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
846 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
848 __EXCEPT(page_fault)
850 SetLastError(STATUS_ACCESS_VIOLATION);
851 ret = FALSE;
853 __ENDTRY
854 return ret;
857 static BOOL WINAPI CRYPT_AsnEncodeCRLEntry(const CRL_ENTRY *entry,
858 BYTE *pbEncoded, DWORD *pcbEncoded)
860 struct AsnEncodeSequenceItem items[3] = {
861 { &entry->SerialNumber, CRYPT_AsnEncodeInteger, 0 },
862 { &entry->RevocationDate, CRYPT_AsnEncodeChoiceOfTime, 0 },
863 { 0 }
865 DWORD cItem = 2;
866 BOOL ret;
868 TRACE("%p, %p, %p\n", entry, pbEncoded, pcbEncoded);
870 if (entry->cExtension)
872 items[cItem].pvStructInfo = &entry->cExtension;
873 items[cItem].encodeFunc = CRYPT_AsnEncodeExtensions;
874 cItem++;
877 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
878 pbEncoded, pcbEncoded);
880 TRACE("returning %d (%08lx)\n", ret, GetLastError());
881 return ret;
884 static BOOL WINAPI CRYPT_AsnEncodeCRLEntries(DWORD dwCertEncodingType,
885 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
886 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
888 DWORD cCRLEntry = *(const DWORD *)pvStructInfo;
889 DWORD bytesNeeded, dataLen, lenBytes, i;
890 const CRL_ENTRY *rgCRLEntry = *(const CRL_ENTRY **)
891 ((const BYTE *)pvStructInfo + sizeof(DWORD));
892 BOOL ret = TRUE;
894 for (i = 0, dataLen = 0; ret && i < cCRLEntry; i++)
896 DWORD size;
898 ret = CRYPT_AsnEncodeCRLEntry(&rgCRLEntry[i], NULL, &size);
899 if (ret)
900 dataLen += size;
902 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
903 bytesNeeded = 1 + lenBytes + dataLen;
904 if (!pbEncoded)
905 *pcbEncoded = bytesNeeded;
906 else
908 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
909 pcbEncoded, bytesNeeded)))
911 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
912 pbEncoded = *(BYTE **)pbEncoded;
913 *pbEncoded++ = ASN_SEQUENCEOF;
914 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
915 pbEncoded += lenBytes;
916 for (i = 0; i < cCRLEntry; i++)
918 DWORD size = dataLen;
920 ret = CRYPT_AsnEncodeCRLEntry(&rgCRLEntry[i], pbEncoded, &size);
921 pbEncoded += size;
922 dataLen -= size;
926 return ret;
929 static BOOL WINAPI CRYPT_AsnEncodeCRLVersion(DWORD dwCertEncodingType,
930 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
931 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
933 const DWORD *ver = (const DWORD *)pvStructInfo;
934 BOOL ret;
936 /* CRL_V1 is not encoded */
937 if (*ver == CRL_V1)
939 *pcbEncoded = 0;
940 ret = TRUE;
942 else
943 ret = CRYPT_AsnEncodeInt(dwCertEncodingType, X509_INTEGER, ver,
944 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
945 return ret;
948 /* Like in Windows, this blithely ignores the validity of the passed-in
949 * CRL_INFO, and just encodes it as-is. The resulting encoded data may not
950 * decode properly, see CRYPT_AsnDecodeCRLInfo.
952 static BOOL WINAPI CRYPT_AsnEncodeCRLInfo(DWORD dwCertEncodingType,
953 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
954 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
956 BOOL ret;
958 __TRY
960 const CRL_INFO *info = (const CRL_INFO *)pvStructInfo;
961 struct AsnEncodeSequenceItem items[7] = {
962 { &info->dwVersion, CRYPT_AsnEncodeCRLVersion, 0 },
963 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
964 { &info->Issuer, CRYPT_CopyEncodedBlob, 0 },
965 { &info->ThisUpdate, CRYPT_AsnEncodeChoiceOfTime, 0 },
966 { 0 }
968 DWORD cItem = 4;
970 if (info->NextUpdate.dwLowDateTime || info->NextUpdate.dwHighDateTime)
972 items[cItem].pvStructInfo = &info->NextUpdate;
973 items[cItem].encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
974 cItem++;
976 if (info->cCRLEntry)
978 items[cItem].pvStructInfo = &info->cCRLEntry;
979 items[cItem].encodeFunc = CRYPT_AsnEncodeCRLEntries;
980 cItem++;
982 if (info->cExtension)
984 items[cItem].pvStructInfo = &info->cExtension;
985 items[cItem].encodeFunc = CRYPT_AsnEncodeExtensions;
986 cItem++;
989 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
990 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
992 __EXCEPT(page_fault)
994 SetLastError(STATUS_ACCESS_VIOLATION);
995 ret = FALSE;
997 __ENDTRY
998 return ret;
1001 static BOOL CRYPT_AsnEncodeExtension(CERT_EXTENSION *ext, BYTE *pbEncoded,
1002 DWORD *pcbEncoded)
1004 BOOL ret;
1005 struct AsnEncodeSequenceItem items[3] = {
1006 { ext->pszObjId, CRYPT_AsnEncodeOid, 0 },
1007 { NULL, NULL, 0 },
1008 { NULL, NULL, 0 },
1010 DWORD cItem = 1;
1012 TRACE("%p, %p, %ld\n", ext, pbEncoded, *pcbEncoded);
1014 if (ext->fCritical)
1016 items[cItem].pvStructInfo = &ext->fCritical;
1017 items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
1018 cItem++;
1020 items[cItem].pvStructInfo = &ext->Value;
1021 items[cItem].encodeFunc = CRYPT_AsnEncodeOctets;
1022 cItem++;
1024 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
1025 pbEncoded, pcbEncoded);
1026 TRACE("returning %d (%08lx)\n", ret, GetLastError());
1027 return ret;
1030 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
1031 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1032 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1034 BOOL ret;
1036 __TRY
1038 DWORD bytesNeeded, dataLen, lenBytes, i;
1039 const CERT_EXTENSIONS *exts = (const CERT_EXTENSIONS *)pvStructInfo;
1041 ret = TRUE;
1042 for (i = 0, dataLen = 0; ret && i < exts->cExtension; i++)
1044 DWORD size;
1046 ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i], NULL, &size);
1047 if (ret)
1048 dataLen += size;
1050 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1051 bytesNeeded = 1 + lenBytes + dataLen;
1052 if (!pbEncoded)
1053 *pcbEncoded = bytesNeeded;
1054 else
1056 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1057 pcbEncoded, bytesNeeded)))
1059 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1060 pbEncoded = *(BYTE **)pbEncoded;
1061 *pbEncoded++ = ASN_SEQUENCEOF;
1062 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1063 pbEncoded += lenBytes;
1064 for (i = 0; i < exts->cExtension; i++)
1066 DWORD size = dataLen;
1068 ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i],
1069 pbEncoded, &size);
1070 pbEncoded += size;
1071 dataLen -= size;
1076 __EXCEPT(page_fault)
1078 SetLastError(STATUS_ACCESS_VIOLATION);
1079 ret = FALSE;
1081 __ENDTRY
1082 return ret;
1085 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
1086 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1087 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1089 LPCSTR pszObjId = (LPCSTR)pvStructInfo;
1090 DWORD bytesNeeded = 0, lenBytes;
1091 BOOL ret = TRUE;
1092 int firstPos = 0;
1093 BYTE firstByte = 0;
1095 TRACE("%s\n", debugstr_a(pszObjId));
1097 if (pszObjId)
1099 const char *ptr;
1100 int val1, val2;
1102 if (sscanf(pszObjId, "%d.%d.%n", &val1, &val2, &firstPos) != 2)
1104 SetLastError(CRYPT_E_ASN1_ERROR);
1105 return FALSE;
1107 bytesNeeded++;
1108 firstByte = val1 * 40 + val2;
1109 ptr = pszObjId + firstPos;
1110 while (ret && *ptr)
1112 int pos;
1114 /* note I assume each component is at most 32-bits long in base 2 */
1115 if (sscanf(ptr, "%d%n", &val1, &pos) == 1)
1117 if (val1 >= 0x10000000)
1118 bytesNeeded += 5;
1119 else if (val1 >= 0x200000)
1120 bytesNeeded += 4;
1121 else if (val1 >= 0x4000)
1122 bytesNeeded += 3;
1123 else if (val1 >= 0x80)
1124 bytesNeeded += 2;
1125 else
1126 bytesNeeded += 1;
1127 ptr += pos;
1128 if (*ptr == '.')
1129 ptr++;
1131 else
1133 SetLastError(CRYPT_E_ASN1_ERROR);
1134 return FALSE;
1137 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1139 else
1140 lenBytes = 1;
1141 bytesNeeded += 1 + lenBytes;
1142 if (pbEncoded)
1144 if (*pcbEncoded < bytesNeeded)
1146 SetLastError(ERROR_MORE_DATA);
1147 ret = FALSE;
1149 else
1151 *pbEncoded++ = ASN_OBJECTIDENTIFIER;
1152 CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded, &lenBytes);
1153 pbEncoded += lenBytes;
1154 if (pszObjId)
1156 const char *ptr;
1157 int val, pos;
1159 *pbEncoded++ = firstByte;
1160 ptr = pszObjId + firstPos;
1161 while (ret && *ptr)
1163 sscanf(ptr, "%d%n", &val, &pos);
1165 unsigned char outBytes[5];
1166 int numBytes, i;
1168 if (val >= 0x10000000)
1169 numBytes = 5;
1170 else if (val >= 0x200000)
1171 numBytes = 4;
1172 else if (val >= 0x4000)
1173 numBytes = 3;
1174 else if (val >= 0x80)
1175 numBytes = 2;
1176 else
1177 numBytes = 1;
1178 for (i = numBytes; i > 0; i--)
1180 outBytes[i - 1] = val & 0x7f;
1181 val >>= 7;
1183 for (i = 0; i < numBytes - 1; i++)
1184 *pbEncoded++ = outBytes[i] | 0x80;
1185 *pbEncoded++ = outBytes[i];
1186 ptr += pos;
1187 if (*ptr == '.')
1188 ptr++;
1194 *pcbEncoded = bytesNeeded;
1195 return ret;
1198 static BOOL WINAPI CRYPT_AsnEncodeNameValue(DWORD dwCertEncodingType,
1199 CERT_NAME_VALUE *value, BYTE *pbEncoded, DWORD *pcbEncoded)
1201 BYTE tag;
1202 DWORD bytesNeeded, lenBytes, encodedLen;
1203 BOOL ret = TRUE;
1205 switch (value->dwValueType)
1207 case CERT_RDN_NUMERIC_STRING:
1208 tag = ASN_NUMERICSTRING;
1209 encodedLen = value->Value.cbData;
1210 break;
1211 case CERT_RDN_PRINTABLE_STRING:
1212 tag = ASN_PRINTABLESTRING;
1213 encodedLen = value->Value.cbData;
1214 break;
1215 case CERT_RDN_IA5_STRING:
1216 tag = ASN_IA5STRING;
1217 encodedLen = value->Value.cbData;
1218 break;
1219 case CERT_RDN_ANY_TYPE:
1220 /* explicitly disallowed */
1221 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1222 return FALSE;
1223 default:
1224 FIXME("String type %ld unimplemented\n", value->dwValueType);
1225 return FALSE;
1227 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1228 bytesNeeded = 1 + lenBytes + encodedLen;
1229 if (pbEncoded)
1231 if (*pcbEncoded < bytesNeeded)
1233 SetLastError(ERROR_MORE_DATA);
1234 ret = FALSE;
1236 else
1238 *pbEncoded++ = tag;
1239 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1240 pbEncoded += lenBytes;
1241 switch (value->dwValueType)
1243 case CERT_RDN_NUMERIC_STRING:
1244 case CERT_RDN_PRINTABLE_STRING:
1245 case CERT_RDN_IA5_STRING:
1246 memcpy(pbEncoded, value->Value.pbData, value->Value.cbData);
1250 *pcbEncoded = bytesNeeded;
1251 return ret;
1254 static BOOL WINAPI CRYPT_AsnEncodeRdnAttr(DWORD dwCertEncodingType,
1255 CERT_RDN_ATTR *attr, BYTE *pbEncoded, DWORD *pcbEncoded)
1257 DWORD bytesNeeded = 0, lenBytes, size;
1258 BOOL ret;
1260 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL, attr->pszObjId,
1261 0, NULL, NULL, &size);
1262 if (ret)
1264 bytesNeeded += size;
1265 /* hack: a CERT_RDN_ATTR is identical to a CERT_NAME_VALUE beginning
1266 * with dwValueType, so "cast" it to get its encoded size
1268 ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
1269 (CERT_NAME_VALUE *)&attr->dwValueType, NULL, &size);
1270 if (ret)
1272 bytesNeeded += size;
1273 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1274 bytesNeeded += 1 + lenBytes;
1275 if (pbEncoded)
1277 if (*pcbEncoded < bytesNeeded)
1279 SetLastError(ERROR_MORE_DATA);
1280 ret = FALSE;
1282 else
1284 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SEQUENCE;
1285 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1286 &lenBytes);
1287 pbEncoded += lenBytes;
1288 size = bytesNeeded - 1 - lenBytes;
1289 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
1290 attr->pszObjId, 0, NULL, pbEncoded, &size);
1291 if (ret)
1293 pbEncoded += size;
1294 size = bytesNeeded - 1 - lenBytes - size;
1295 ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
1296 (CERT_NAME_VALUE *)&attr->dwValueType, pbEncoded,
1297 &size);
1301 *pcbEncoded = bytesNeeded;
1304 return ret;
1307 static int BLOBComp(const void *l, const void *r)
1309 CRYPT_DER_BLOB *a = (CRYPT_DER_BLOB *)l, *b = (CRYPT_DER_BLOB *)r;
1310 int ret;
1312 if (!(ret = memcmp(a->pbData, b->pbData, min(a->cbData, b->cbData))))
1313 ret = a->cbData - b->cbData;
1314 return ret;
1317 /* This encodes as a SET OF, which in DER must be lexicographically sorted.
1319 static BOOL WINAPI CRYPT_AsnEncodeRdn(DWORD dwCertEncodingType, CERT_RDN *rdn,
1320 BYTE *pbEncoded, DWORD *pcbEncoded)
1322 BOOL ret;
1323 CRYPT_DER_BLOB *blobs = NULL;
1325 __TRY
1327 DWORD bytesNeeded = 0, lenBytes, i;
1329 blobs = NULL;
1330 ret = TRUE;
1331 if (rdn->cRDNAttr)
1333 blobs = CryptMemAlloc(rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
1334 if (!blobs)
1335 ret = FALSE;
1336 else
1337 memset(blobs, 0, rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
1339 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1341 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType, &rdn->rgRDNAttr[i],
1342 NULL, &blobs[i].cbData);
1343 if (ret)
1344 bytesNeeded += blobs[i].cbData;
1346 if (ret)
1348 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1349 bytesNeeded += 1 + lenBytes;
1350 if (pbEncoded)
1352 if (*pcbEncoded < bytesNeeded)
1354 SetLastError(ERROR_MORE_DATA);
1355 ret = FALSE;
1357 else
1359 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1361 blobs[i].pbData = CryptMemAlloc(blobs[i].cbData);
1362 if (!blobs[i].pbData)
1363 ret = FALSE;
1364 else
1365 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType,
1366 &rdn->rgRDNAttr[i], blobs[i].pbData,
1367 &blobs[i].cbData);
1369 if (ret)
1371 qsort(blobs, rdn->cRDNAttr, sizeof(CRYPT_DER_BLOB),
1372 BLOBComp);
1373 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF;
1374 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1375 &lenBytes);
1376 pbEncoded += lenBytes;
1377 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1379 memcpy(pbEncoded, blobs[i].pbData, blobs[i].cbData);
1380 pbEncoded += blobs[i].cbData;
1385 *pcbEncoded = bytesNeeded;
1387 if (blobs)
1389 for (i = 0; i < rdn->cRDNAttr; i++)
1390 CryptMemFree(blobs[i].pbData);
1393 __EXCEPT(page_fault)
1395 SetLastError(STATUS_ACCESS_VIOLATION);
1396 ret = FALSE;
1398 __ENDTRY
1399 CryptMemFree(blobs);
1400 return ret;
1403 static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
1404 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1405 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1407 BOOL ret;
1409 __TRY
1411 const CERT_NAME_INFO *info = (const CERT_NAME_INFO *)pvStructInfo;
1412 DWORD bytesNeeded = 0, lenBytes, size, i;
1414 TRACE("encoding name with %ld RDNs\n", info->cRDN);
1415 ret = TRUE;
1416 for (i = 0; ret && i < info->cRDN; i++)
1418 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i], NULL,
1419 &size);
1420 if (ret)
1421 bytesNeeded += size;
1423 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1424 bytesNeeded += 1 + lenBytes;
1425 if (ret)
1427 if (!pbEncoded)
1428 *pcbEncoded = bytesNeeded;
1429 else
1431 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1432 pbEncoded, pcbEncoded, bytesNeeded)))
1434 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1435 pbEncoded = *(BYTE **)pbEncoded;
1436 *pbEncoded++ = ASN_SEQUENCEOF;
1437 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1438 &lenBytes);
1439 pbEncoded += lenBytes;
1440 for (i = 0; ret && i < info->cRDN; i++)
1442 size = bytesNeeded;
1443 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType,
1444 &info->rgRDN[i], pbEncoded, &size);
1445 if (ret)
1447 pbEncoded += size;
1448 bytesNeeded -= size;
1455 __EXCEPT(page_fault)
1457 SetLastError(STATUS_ACCESS_VIOLATION);
1458 ret = FALSE;
1460 __ENDTRY
1461 return ret;
1464 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
1465 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1466 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1468 BOOL val = *(const BOOL *)pvStructInfo, ret;
1470 TRACE("%d\n", val);
1472 if (!pbEncoded)
1474 *pcbEncoded = 3;
1475 ret = TRUE;
1477 else if (*pcbEncoded < 3)
1479 *pcbEncoded = 3;
1480 SetLastError(ERROR_MORE_DATA);
1481 ret = FALSE;
1483 else
1485 *pcbEncoded = 3;
1486 *pbEncoded++ = ASN_BOOL;
1487 *pbEncoded++ = 1;
1488 *pbEncoded++ = val ? 0xff : 0;
1489 ret = TRUE;
1491 TRACE("returning %d (%08lx)\n", ret, GetLastError());
1492 return ret;
1495 static BOOL CRYPT_AsnEncodeAltNameEntry(const CERT_ALT_NAME_ENTRY *entry,
1496 BYTE *pbEncoded, DWORD *pcbEncoded)
1498 BOOL ret;
1499 DWORD dataLen;
1501 ret = TRUE;
1502 switch (entry->dwAltNameChoice)
1504 case CERT_ALT_NAME_RFC822_NAME:
1505 case CERT_ALT_NAME_DNS_NAME:
1506 case CERT_ALT_NAME_URL:
1507 if (entry->u.pwszURL)
1509 DWORD i;
1511 /* Not + 1: don't encode the NULL-terminator */
1512 dataLen = lstrlenW(entry->u.pwszURL);
1513 for (i = 0; ret && i < dataLen; i++)
1515 if (entry->u.pwszURL[i] > 0x7f)
1517 SetLastError(CRYPT_E_INVALID_IA5_STRING);
1518 ret = FALSE;
1519 *pcbEncoded = i;
1523 else
1524 dataLen = 0;
1525 break;
1526 case CERT_ALT_NAME_IP_ADDRESS:
1527 dataLen = entry->u.IPAddress.cbData;
1528 break;
1529 case CERT_ALT_NAME_REGISTERED_ID:
1530 /* FIXME: encode OID */
1531 case CERT_ALT_NAME_OTHER_NAME:
1532 case CERT_ALT_NAME_DIRECTORY_NAME:
1533 FIXME("name type %ld unimplemented\n", entry->dwAltNameChoice);
1534 return FALSE;
1535 default:
1536 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1537 return FALSE;
1539 if (ret)
1541 DWORD bytesNeeded, lenBytes;
1543 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1544 bytesNeeded = 1 + dataLen + lenBytes;
1545 if (!pbEncoded)
1546 *pcbEncoded = bytesNeeded;
1547 else if (*pcbEncoded < bytesNeeded)
1549 SetLastError(ERROR_MORE_DATA);
1550 *pcbEncoded = bytesNeeded;
1551 ret = FALSE;
1553 else
1555 *pbEncoded++ = ASN_CONTEXT | (entry->dwAltNameChoice - 1);
1556 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1557 pbEncoded += lenBytes;
1558 switch (entry->dwAltNameChoice)
1560 case CERT_ALT_NAME_RFC822_NAME:
1561 case CERT_ALT_NAME_DNS_NAME:
1562 case CERT_ALT_NAME_URL:
1564 DWORD i;
1566 for (i = 0; i < dataLen; i++)
1567 *pbEncoded++ = (BYTE)entry->u.pwszURL[i];
1568 break;
1570 case CERT_ALT_NAME_IP_ADDRESS:
1571 memcpy(pbEncoded, entry->u.IPAddress.pbData, dataLen);
1572 break;
1574 if (ret)
1575 *pcbEncoded = bytesNeeded;
1578 TRACE("returning %d (%08lx)\n", ret, GetLastError());
1579 return ret;
1582 static BOOL WINAPI CRYPT_AsnEncodeAltName(DWORD dwCertEncodingType,
1583 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1584 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1586 BOOL ret;
1588 __TRY
1590 const CERT_ALT_NAME_INFO *info =
1591 (const CERT_ALT_NAME_INFO *)pvStructInfo;
1593 DWORD bytesNeeded, dataLen, lenBytes, i;
1595 ret = TRUE;
1596 /* FIXME: should check that cAltEntry is not bigger than 0xff, since we
1597 * can't encode an erroneous entry index if it's bigger than this.
1599 for (i = 0, dataLen = 0; ret && i < info->cAltEntry; i++)
1601 DWORD len;
1603 ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i], NULL,
1604 &len);
1605 if (ret)
1606 dataLen += len;
1607 else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
1609 /* CRYPT_AsnEncodeAltNameEntry encoded the index of
1610 * the bad character, now set the index of the bad
1611 * entry
1613 *pcbEncoded = (BYTE)i <<
1614 CERT_ALT_NAME_ENTRY_ERR_INDEX_SHIFT | len;
1617 if (ret)
1619 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1620 bytesNeeded = 1 + lenBytes + dataLen;
1621 if (!pbEncoded)
1623 *pcbEncoded = bytesNeeded;
1624 ret = TRUE;
1626 else
1628 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1629 pbEncoded, pcbEncoded, bytesNeeded)))
1631 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1632 pbEncoded = *(BYTE **)pbEncoded;
1633 *pbEncoded++ = ASN_SEQUENCEOF;
1634 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1635 pbEncoded += lenBytes;
1636 for (i = 0; ret && i < info->cAltEntry; i++)
1638 DWORD len = dataLen;
1640 ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i],
1641 pbEncoded, &len);
1642 if (ret)
1644 pbEncoded += len;
1645 dataLen -= len;
1652 __EXCEPT(page_fault)
1654 SetLastError(STATUS_ACCESS_VIOLATION);
1655 ret = FALSE;
1657 __ENDTRY
1658 return ret;
1661 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
1662 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1663 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1665 BOOL ret;
1667 __TRY
1669 const CERT_BASIC_CONSTRAINTS2_INFO *info =
1670 (const CERT_BASIC_CONSTRAINTS2_INFO *)pvStructInfo;
1671 struct AsnEncodeSequenceItem items[2] = { { 0 } };
1672 DWORD cItem = 0;
1674 if (info->fCA)
1676 items[cItem].pvStructInfo = &info->fCA;
1677 items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
1678 cItem++;
1680 if (info->fPathLenConstraint)
1682 items[cItem].pvStructInfo = &info->dwPathLenConstraint;
1683 items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
1684 cItem++;
1686 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
1687 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1689 __EXCEPT(page_fault)
1691 SetLastError(STATUS_ACCESS_VIOLATION);
1692 ret = FALSE;
1694 __ENDTRY
1695 return ret;
1698 static BOOL WINAPI CRYPT_AsnEncodeRsaPubKey(DWORD dwCertEncodingType,
1699 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1700 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1702 BOOL ret;
1704 __TRY
1706 const BLOBHEADER *hdr =
1707 (const BLOBHEADER *)pvStructInfo;
1709 if (hdr->bType != PUBLICKEYBLOB)
1711 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1712 ret = FALSE;
1714 else
1716 const RSAPUBKEY *rsaPubKey = (const RSAPUBKEY *)
1717 ((const BYTE *)pvStructInfo + sizeof(BLOBHEADER));
1718 CRYPT_INTEGER_BLOB blob = { rsaPubKey->bitlen / 8,
1719 (BYTE *)pvStructInfo + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) };
1720 struct AsnEncodeSequenceItem items[] = {
1721 { &blob, CRYPT_AsnEncodeUnsignedInteger, 0 },
1722 { &rsaPubKey->pubexp, CRYPT_AsnEncodeInt, 0 },
1725 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
1726 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
1727 pcbEncoded);
1730 __EXCEPT(page_fault)
1732 SetLastError(STATUS_ACCESS_VIOLATION);
1733 ret = FALSE;
1735 __ENDTRY
1736 return ret;
1739 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
1740 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1741 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1743 BOOL ret;
1745 __TRY
1747 const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo;
1748 DWORD bytesNeeded, lenBytes;
1750 TRACE("(%ld, %p), %08lx, %p, %p, %ld\n", blob->cbData, blob->pbData,
1751 dwFlags, pEncodePara, pbEncoded, *pcbEncoded);
1753 CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
1754 bytesNeeded = 1 + lenBytes + blob->cbData;
1755 if (!pbEncoded)
1757 *pcbEncoded = bytesNeeded;
1758 ret = TRUE;
1760 else
1762 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1763 pcbEncoded, bytesNeeded)))
1765 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1766 pbEncoded = *(BYTE **)pbEncoded;
1767 *pbEncoded++ = ASN_OCTETSTRING;
1768 CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
1769 pbEncoded += lenBytes;
1770 if (blob->cbData)
1771 memcpy(pbEncoded, blob->pbData, blob->cbData);
1775 __EXCEPT(page_fault)
1777 SetLastError(STATUS_ACCESS_VIOLATION);
1778 ret = FALSE;
1780 __ENDTRY
1781 TRACE("returning %d (%08lx)\n", ret, GetLastError());
1782 return ret;
1785 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
1786 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1787 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1789 BOOL ret;
1791 __TRY
1793 const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
1794 DWORD bytesNeeded, lenBytes, dataBytes;
1795 BYTE unusedBits;
1797 /* yep, MS allows cUnusedBits to be >= 8 */
1798 if (!blob->cUnusedBits)
1800 dataBytes = blob->cbData;
1801 unusedBits = 0;
1803 else if (blob->cbData * 8 > blob->cUnusedBits)
1805 dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
1806 unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
1807 blob->cUnusedBits;
1809 else
1811 dataBytes = 0;
1812 unusedBits = 0;
1814 CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
1815 bytesNeeded = 1 + lenBytes + dataBytes + 1;
1816 if (!pbEncoded)
1818 *pcbEncoded = bytesNeeded;
1819 ret = TRUE;
1821 else
1823 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1824 pcbEncoded, bytesNeeded)))
1826 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1827 pbEncoded = *(BYTE **)pbEncoded;
1828 *pbEncoded++ = ASN_BITSTRING;
1829 CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
1830 pbEncoded += lenBytes;
1831 *pbEncoded++ = unusedBits;
1832 if (dataBytes)
1834 BYTE mask = 0xff << unusedBits;
1836 if (dataBytes > 1)
1838 memcpy(pbEncoded, blob->pbData, dataBytes - 1);
1839 pbEncoded += dataBytes - 1;
1841 *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
1846 __EXCEPT(page_fault)
1848 SetLastError(STATUS_ACCESS_VIOLATION);
1849 ret = FALSE;
1851 __ENDTRY
1852 return ret;
1855 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
1856 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1857 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1859 BOOL ret;
1861 __TRY
1863 const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
1864 CRYPT_BIT_BLOB newBlob = { blob->cbData, NULL, blob->cUnusedBits };
1866 ret = TRUE;
1867 if (newBlob.cbData)
1869 newBlob.pbData = CryptMemAlloc(newBlob.cbData);
1870 if (newBlob.pbData)
1872 DWORD i;
1874 for (i = 0; i < newBlob.cbData; i++)
1875 newBlob.pbData[newBlob.cbData - i - 1] = blob->pbData[i];
1877 else
1878 ret = FALSE;
1880 if (ret)
1881 ret = CRYPT_AsnEncodeBits(dwCertEncodingType, lpszStructType,
1882 &newBlob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1883 CryptMemFree(newBlob.pbData);
1885 __EXCEPT(page_fault)
1887 SetLastError(STATUS_ACCESS_VIOLATION);
1888 ret = FALSE;
1890 __ENDTRY
1891 return ret;
1894 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
1895 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1896 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1898 CRYPT_INTEGER_BLOB blob = { sizeof(INT), (BYTE *)pvStructInfo };
1900 return CRYPT_AsnEncodeInteger(dwCertEncodingType, X509_MULTI_BYTE_INTEGER,
1901 &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1904 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
1905 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1906 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1908 BOOL ret;
1910 __TRY
1912 DWORD significantBytes, lenBytes;
1913 BYTE padByte = 0, bytesNeeded;
1914 BOOL pad = FALSE;
1915 const CRYPT_INTEGER_BLOB *blob =
1916 (const CRYPT_INTEGER_BLOB *)pvStructInfo;
1918 significantBytes = blob->cbData;
1919 if (significantBytes)
1921 if (blob->pbData[significantBytes - 1] & 0x80)
1923 /* negative, lop off leading (little-endian) 0xffs */
1924 for (; significantBytes > 0 &&
1925 blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
1927 if (blob->pbData[significantBytes - 1] < 0x80)
1929 padByte = 0xff;
1930 pad = TRUE;
1933 else
1935 /* positive, lop off leading (little-endian) zeroes */
1936 for (; significantBytes > 0 &&
1937 !blob->pbData[significantBytes - 1]; significantBytes--)
1939 if (significantBytes == 0)
1940 significantBytes = 1;
1941 if (blob->pbData[significantBytes - 1] > 0x7f)
1943 padByte = 0;
1944 pad = TRUE;
1948 if (pad)
1949 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
1950 else
1951 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
1952 bytesNeeded = 1 + lenBytes + significantBytes;
1953 if (pad)
1954 bytesNeeded++;
1955 if (!pbEncoded)
1957 *pcbEncoded = bytesNeeded;
1958 ret = TRUE;
1960 else
1962 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1963 pcbEncoded, bytesNeeded)))
1965 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1966 pbEncoded = *(BYTE **)pbEncoded;
1967 *pbEncoded++ = ASN_INTEGER;
1968 if (pad)
1970 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
1971 pbEncoded += lenBytes;
1972 *pbEncoded++ = padByte;
1974 else
1976 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
1977 pbEncoded += lenBytes;
1979 for (; significantBytes > 0; significantBytes--)
1980 *(pbEncoded++) = blob->pbData[significantBytes - 1];
1984 __EXCEPT(page_fault)
1986 SetLastError(STATUS_ACCESS_VIOLATION);
1987 ret = FALSE;
1989 __ENDTRY
1990 return ret;
1993 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
1994 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1995 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1997 BOOL ret;
1999 __TRY
2001 DWORD significantBytes, lenBytes;
2002 BYTE bytesNeeded;
2003 BOOL pad = FALSE;
2004 const CRYPT_INTEGER_BLOB *blob =
2005 (const CRYPT_INTEGER_BLOB *)pvStructInfo;
2007 significantBytes = blob->cbData;
2008 if (significantBytes)
2010 /* positive, lop off leading (little-endian) zeroes */
2011 for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
2012 significantBytes--)
2014 if (significantBytes == 0)
2015 significantBytes = 1;
2016 if (blob->pbData[significantBytes - 1] > 0x7f)
2017 pad = TRUE;
2019 if (pad)
2020 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
2021 else
2022 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
2023 bytesNeeded = 1 + lenBytes + significantBytes;
2024 if (pad)
2025 bytesNeeded++;
2026 if (!pbEncoded)
2028 *pcbEncoded = bytesNeeded;
2029 ret = TRUE;
2031 else
2033 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2034 pcbEncoded, bytesNeeded)))
2036 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2037 pbEncoded = *(BYTE **)pbEncoded;
2038 *pbEncoded++ = ASN_INTEGER;
2039 if (pad)
2041 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
2042 pbEncoded += lenBytes;
2043 *pbEncoded++ = 0;
2045 else
2047 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
2048 pbEncoded += lenBytes;
2050 for (; significantBytes > 0; significantBytes--)
2051 *(pbEncoded++) = blob->pbData[significantBytes - 1];
2055 __EXCEPT(page_fault)
2057 SetLastError(STATUS_ACCESS_VIOLATION);
2058 ret = FALSE;
2060 __ENDTRY
2061 return ret;
2064 static BOOL WINAPI CRYPT_AsnEncodeEnumerated(DWORD dwCertEncodingType,
2065 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2066 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2068 CRYPT_INTEGER_BLOB blob;
2069 BOOL ret;
2071 /* Encode as an unsigned integer, then change the tag to enumerated */
2072 blob.cbData = sizeof(DWORD);
2073 blob.pbData = (BYTE *)pvStructInfo;
2074 ret = CRYPT_AsnEncodeUnsignedInteger(dwCertEncodingType,
2075 X509_MULTI_BYTE_UINT, &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2076 if (ret && pbEncoded)
2078 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2079 pbEncoded = *(BYTE **)pbEncoded;
2080 pbEncoded[0] = ASN_ENUMERATED;
2082 return ret;
2085 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
2086 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2087 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2089 BOOL ret;
2091 __TRY
2093 SYSTEMTIME sysTime;
2094 /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0. I use a
2095 * temporary buffer because the output buffer is not NULL-terminated.
2097 char buf[16];
2098 static const DWORD bytesNeeded = sizeof(buf) - 1;
2100 if (!pbEncoded)
2102 *pcbEncoded = bytesNeeded;
2103 ret = TRUE;
2105 else
2107 /* Sanity check the year, this is a two-digit year format */
2108 ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
2109 &sysTime);
2110 if (ret && (sysTime.wYear < 1950 || sysTime.wYear > 2050))
2112 SetLastError(CRYPT_E_BAD_ENCODE);
2113 ret = FALSE;
2115 if (ret)
2117 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2118 pbEncoded, pcbEncoded, bytesNeeded)))
2120 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2121 pbEncoded = *(BYTE **)pbEncoded;
2122 buf[0] = ASN_UTCTIME;
2123 buf[1] = bytesNeeded - 2;
2124 snprintf(buf + 2, sizeof(buf) - 2,
2125 "%02d%02d%02d%02d%02d%02dZ", sysTime.wYear >= 2000 ?
2126 sysTime.wYear - 2000 : sysTime.wYear - 1900,
2127 sysTime.wDay, sysTime.wMonth, sysTime.wHour,
2128 sysTime.wMinute, sysTime.wSecond);
2129 memcpy(pbEncoded, buf, bytesNeeded);
2134 __EXCEPT(page_fault)
2136 SetLastError(STATUS_ACCESS_VIOLATION);
2137 ret = FALSE;
2139 __ENDTRY
2140 return ret;
2143 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
2144 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2145 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2147 BOOL ret;
2149 __TRY
2151 SYSTEMTIME sysTime;
2152 /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0. I use a
2153 * temporary buffer because the output buffer is not NULL-terminated.
2155 char buf[18];
2156 static const DWORD bytesNeeded = sizeof(buf) - 1;
2158 if (!pbEncoded)
2160 *pcbEncoded = bytesNeeded;
2161 ret = TRUE;
2163 else
2165 ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
2166 &sysTime);
2167 if (ret)
2168 ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2169 pcbEncoded, bytesNeeded);
2170 if (ret)
2172 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2173 pbEncoded = *(BYTE **)pbEncoded;
2174 buf[0] = ASN_GENERALTIME;
2175 buf[1] = bytesNeeded - 2;
2176 snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
2177 sysTime.wYear, sysTime.wDay, sysTime.wMonth, sysTime.wHour,
2178 sysTime.wMinute, sysTime.wSecond);
2179 memcpy(pbEncoded, buf, bytesNeeded);
2183 __EXCEPT(page_fault)
2185 SetLastError(STATUS_ACCESS_VIOLATION);
2186 ret = FALSE;
2188 __ENDTRY
2189 return ret;
2192 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
2193 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2194 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2196 BOOL ret;
2198 __TRY
2200 SYSTEMTIME sysTime;
2202 /* Check the year, if it's in the UTCTime range call that encode func */
2203 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
2204 return FALSE;
2205 if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
2206 ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
2207 pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2208 else
2209 ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
2210 lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
2211 pcbEncoded);
2213 __EXCEPT(page_fault)
2215 SetLastError(STATUS_ACCESS_VIOLATION);
2216 ret = FALSE;
2218 __ENDTRY
2219 return ret;
2222 static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
2223 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2224 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2226 BOOL ret;
2228 __TRY
2230 DWORD bytesNeeded, dataLen, lenBytes, i;
2231 const CRYPT_SEQUENCE_OF_ANY *seq =
2232 (const CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
2234 for (i = 0, dataLen = 0; i < seq->cValue; i++)
2235 dataLen += seq->rgValue[i].cbData;
2236 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2237 bytesNeeded = 1 + lenBytes + dataLen;
2238 if (!pbEncoded)
2240 *pcbEncoded = bytesNeeded;
2241 ret = TRUE;
2243 else
2245 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2246 pcbEncoded, bytesNeeded)))
2248 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2249 pbEncoded = *(BYTE **)pbEncoded;
2250 *pbEncoded++ = ASN_SEQUENCEOF;
2251 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2252 pbEncoded += lenBytes;
2253 for (i = 0; i < seq->cValue; i++)
2255 memcpy(pbEncoded, seq->rgValue[i].pbData,
2256 seq->rgValue[i].cbData);
2257 pbEncoded += seq->rgValue[i].cbData;
2262 __EXCEPT(page_fault)
2264 SetLastError(STATUS_ACCESS_VIOLATION);
2265 ret = FALSE;
2267 __ENDTRY
2268 return ret;
2271 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
2272 const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
2273 void *pvEncoded, DWORD *pcbEncoded)
2275 BOOL ret = FALSE;
2276 HMODULE lib = NULL;
2277 CryptEncodeObjectExFunc encodeFunc = NULL;
2279 TRACE("(0x%08lx, %s, %p, 0x%08lx, %p, %p, %p)\n", dwCertEncodingType,
2280 debugstr_a(lpszStructType), pvStructInfo, dwFlags, pEncodePara,
2281 pvEncoded, pcbEncoded);
2283 if (!pvEncoded && !pcbEncoded)
2285 SetLastError(ERROR_INVALID_PARAMETER);
2286 return FALSE;
2288 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
2289 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
2291 SetLastError(ERROR_FILE_NOT_FOUND);
2292 return FALSE;
2295 SetLastError(NOERROR);
2296 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG && pvEncoded)
2297 *(BYTE **)pvEncoded = NULL;
2298 if (!HIWORD(lpszStructType))
2300 switch (LOWORD(lpszStructType))
2302 case (WORD)X509_CERT:
2303 encodeFunc = CRYPT_AsnEncodeCert;
2304 break;
2305 case (WORD)X509_CERT_TO_BE_SIGNED:
2306 encodeFunc = CRYPT_AsnEncodeCertInfo;
2307 break;
2308 case (WORD)X509_CERT_CRL_TO_BE_SIGNED:
2309 encodeFunc = CRYPT_AsnEncodeCRLInfo;
2310 break;
2311 case (WORD)X509_EXTENSIONS:
2312 encodeFunc = CRYPT_AsnEncodeExtensions;
2313 break;
2314 case (WORD)X509_NAME:
2315 encodeFunc = CRYPT_AsnEncodeName;
2316 break;
2317 case (WORD)X509_PUBLIC_KEY_INFO:
2318 encodeFunc = CRYPT_AsnEncodePubKeyInfo;
2319 break;
2320 case (WORD)X509_ALTERNATE_NAME:
2321 encodeFunc = CRYPT_AsnEncodeAltName;
2322 break;
2323 case (WORD)X509_BASIC_CONSTRAINTS2:
2324 encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
2325 break;
2326 case (WORD)RSA_CSP_PUBLICKEYBLOB:
2327 encodeFunc = CRYPT_AsnEncodeRsaPubKey;
2328 break;
2329 case (WORD)X509_OCTET_STRING:
2330 encodeFunc = CRYPT_AsnEncodeOctets;
2331 break;
2332 case (WORD)X509_BITS:
2333 case (WORD)X509_KEY_USAGE:
2334 encodeFunc = CRYPT_AsnEncodeBits;
2335 break;
2336 case (WORD)X509_INTEGER:
2337 encodeFunc = CRYPT_AsnEncodeInt;
2338 break;
2339 case (WORD)X509_MULTI_BYTE_INTEGER:
2340 encodeFunc = CRYPT_AsnEncodeInteger;
2341 break;
2342 case (WORD)X509_MULTI_BYTE_UINT:
2343 encodeFunc = CRYPT_AsnEncodeUnsignedInteger;
2344 break;
2345 case (WORD)X509_ENUMERATED:
2346 encodeFunc = CRYPT_AsnEncodeEnumerated;
2347 break;
2348 case (WORD)X509_CHOICE_OF_TIME:
2349 encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
2350 break;
2351 case (WORD)X509_SEQUENCE_OF_ANY:
2352 encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
2353 break;
2354 case (WORD)PKCS_UTC_TIME:
2355 encodeFunc = CRYPT_AsnEncodeUtcTime;
2356 break;
2357 default:
2358 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
2361 else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
2362 encodeFunc = CRYPT_AsnEncodeExtensions;
2363 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
2364 encodeFunc = CRYPT_AsnEncodeUtcTime;
2365 else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
2366 encodeFunc = CRYPT_AsnEncodeEnumerated;
2367 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
2368 encodeFunc = CRYPT_AsnEncodeBits;
2369 else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
2370 encodeFunc = CRYPT_AsnEncodeOctets;
2371 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
2372 encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
2373 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
2374 encodeFunc = CRYPT_AsnEncodeAltName;
2375 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
2376 encodeFunc = CRYPT_AsnEncodeAltName;
2377 else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION))
2378 encodeFunc = CRYPT_AsnEncodeAltName;
2379 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
2380 encodeFunc = CRYPT_AsnEncodeAltName;
2381 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
2382 encodeFunc = CRYPT_AsnEncodeAltName;
2383 else
2384 TRACE("OID %s not found or unimplemented, looking for DLL\n",
2385 debugstr_a(lpszStructType));
2386 if (!encodeFunc)
2387 encodeFunc = (CryptEncodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
2388 lpszStructType, CRYPT_OID_ENCODE_OBJECT_EX_FUNC, &lib);
2389 if (encodeFunc)
2390 ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
2391 dwFlags, pEncodePara, pvEncoded, pcbEncoded);
2392 else
2393 SetLastError(ERROR_FILE_NOT_FOUND);
2394 if (lib)
2395 FreeLibrary(lib);
2396 return ret;
2399 BOOL WINAPI CryptDecodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
2400 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo,
2401 DWORD *pcbStructInfo)
2403 BOOL ret = FALSE;
2404 HMODULE lib;
2405 CryptDecodeObjectFunc pCryptDecodeObject;
2407 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p)\n", dwCertEncodingType,
2408 debugstr_a(lpszStructType), pbEncoded, cbEncoded, dwFlags,
2409 pvStructInfo, pcbStructInfo);
2411 if (!pvStructInfo && !pcbStructInfo)
2413 SetLastError(ERROR_INVALID_PARAMETER);
2414 return FALSE;
2417 /* Try registered DLL first.. */
2418 pCryptDecodeObject =
2419 (CryptDecodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
2420 lpszStructType, CRYPT_OID_DECODE_OBJECT_FUNC, &lib);
2421 if (pCryptDecodeObject)
2423 ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType,
2424 pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
2425 FreeLibrary(lib);
2427 else
2429 /* If not, use CryptDecodeObjectEx */
2430 ret = CryptDecodeObjectEx(dwCertEncodingType, lpszStructType, pbEncoded,
2431 cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo);
2433 return ret;
2436 /* Gets the number of length bytes from the given (leading) length byte */
2437 #define GET_LEN_BYTES(b) ((b) <= 0x7f ? 1 : 1 + ((b) & 0x7f))
2439 /* Helper function to get the encoded length of the data starting at pbEncoded,
2440 * where pbEncoded[0] is the tag. If the data are too short to contain a
2441 * length or if the length is too large for cbEncoded, sets an appropriate
2442 * error code and returns FALSE.
2444 static BOOL WINAPI CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded,
2445 DWORD *len)
2447 BOOL ret;
2449 if (cbEncoded <= 1)
2451 SetLastError(CRYPT_E_ASN1_CORRUPT);
2452 ret = FALSE;
2454 else if (pbEncoded[1] <= 0x7f)
2456 if (pbEncoded[1] + 1 > cbEncoded)
2458 SetLastError(CRYPT_E_ASN1_EOD);
2459 ret = FALSE;
2461 else
2463 *len = pbEncoded[1];
2464 ret = TRUE;
2467 else
2469 BYTE lenLen = GET_LEN_BYTES(pbEncoded[1]);
2471 if (lenLen > sizeof(DWORD) + 1)
2473 SetLastError(CRYPT_E_ASN1_LARGE);
2474 ret = FALSE;
2476 else if (lenLen + 2 > cbEncoded)
2478 SetLastError(CRYPT_E_ASN1_CORRUPT);
2479 ret = FALSE;
2481 else
2483 DWORD out = 0;
2485 pbEncoded += 2;
2486 while (--lenLen)
2488 out <<= 8;
2489 out |= *pbEncoded++;
2491 if (out + lenLen + 1 > cbEncoded)
2493 SetLastError(CRYPT_E_ASN1_EOD);
2494 ret = FALSE;
2496 else
2498 *len = out;
2499 ret = TRUE;
2503 return ret;
2506 /* Helper function to check *pcbStructInfo, set it to the required size, and
2507 * optionally to allocate memory. Assumes pvStructInfo is not NULL.
2508 * If CRYPT_DECODE_ALLOC_FLAG is set in dwFlags, *pvStructInfo will be set to a
2509 * pointer to the newly allocated memory.
2511 static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags,
2512 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo,
2513 DWORD bytesNeeded)
2515 BOOL ret = TRUE;
2517 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2519 if (pDecodePara && pDecodePara->pfnAlloc)
2520 *(BYTE **)pvStructInfo = pDecodePara->pfnAlloc(bytesNeeded);
2521 else
2522 *(BYTE **)pvStructInfo = LocalAlloc(0, bytesNeeded);
2523 if (!*(BYTE **)pvStructInfo)
2524 ret = FALSE;
2525 else
2526 *pcbStructInfo = bytesNeeded;
2528 else if (*pcbStructInfo < bytesNeeded)
2530 *pcbStructInfo = bytesNeeded;
2531 SetLastError(ERROR_MORE_DATA);
2532 ret = FALSE;
2534 return ret;
2537 /* A few of the members need explanation:
2538 * offset:
2539 * A sequence is decoded into a struct. The offset member is the
2540 * offset of this item within that struct.
2541 * decodeFunc:
2542 * The decoder function to use. If this is NULL, then the member isn't
2543 * decoded, but minSize space is reserved for it.
2544 * minSize:
2545 * The minimum amount of space occupied after decoding. You must set this.
2546 * optional:
2547 * If true, and a decoding function fails with CRYPT_E_ASN1_BADTAG, then
2548 * minSize space is filled with 0 for this member. (Any other failure
2549 * results in CRYPT_AsnDecodeSequence failing.)
2550 * hasPointer, pointerOffset, minSize:
2551 * If the item has dynamic data, set hasPointer to TRUE, pointerOffset to
2552 * the offset within the (outer) struct of the data pointer (or to the
2553 * first data pointer, if more than one exist).
2554 * size:
2555 * Used by CRYPT_AsnDecodeSequence, not for your use.
2557 struct AsnDecodeSequenceItem
2559 DWORD offset;
2560 CryptDecodeObjectExFunc decodeFunc;
2561 DWORD minSize;
2562 BOOL optional;
2563 BOOL hasPointer;
2564 DWORD pointerOffset;
2565 DWORD size;
2568 /* This decodes an arbitrary sequence into a contiguous block of memory
2569 * (basically, a struct.) Each element being decoded is described by a struct
2570 * AsnDecodeSequenceItem, see above.
2571 * startingPointer is an optional pointer to the first place where dynamic
2572 * data will be stored. If you know the starting offset, you may pass it
2573 * here. Otherwise, pass NULL, and one will be inferred from the items.
2574 * Each item decoder is never called with CRYPT_DECODE_ALLOC_FLAG set.
2575 * If any undecoded data are left over, fails with CRYPT_E_ASN1_CORRUPT.
2577 static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType,
2578 struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
2579 DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
2580 void *pvStructInfo, DWORD *pcbStructInfo, void *startingPointer)
2582 BOOL ret;
2584 TRACE("%p, %ld, %p, %ld, %08lx, %p, %p, %ld, %p\n", items, cItem, pbEncoded,
2585 cbEncoded, dwFlags, pDecodePara, pvStructInfo, *pcbStructInfo,
2586 startingPointer);
2588 if (pbEncoded[0] == ASN_SEQUENCE)
2590 DWORD dataLen;
2592 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2594 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2595 DWORD i, bytesNeeded = 0, minSize = 0;
2596 const BYTE *ptr;
2598 ptr = pbEncoded + 1 + lenBytes;
2599 for (i = 0; ret && i < cItem; i++)
2601 DWORD nextItemLen;
2603 minSize += items[i].minSize;
2604 if (cbEncoded - (ptr - pbEncoded) != 0)
2606 if ((ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
2607 &nextItemLen)))
2609 BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
2611 if (items[i].decodeFunc)
2613 TRACE("sizing item %ld\n", i);
2614 ret = items[i].decodeFunc(dwCertEncodingType, NULL,
2615 ptr, 1 + nextItemLenBytes + nextItemLen,
2616 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL,
2617 &items[i].size);
2618 if (ret)
2620 /* Account for alignment padding */
2621 bytesNeeded += items[i].size;
2622 if (items[i].size % sizeof(DWORD))
2623 bytesNeeded += sizeof(DWORD) -
2624 items[i].size % sizeof(DWORD);
2625 ptr += 1 + nextItemLenBytes + nextItemLen;
2627 else if (items[i].optional &&
2628 GetLastError() == CRYPT_E_ASN1_BADTAG)
2630 TRACE("skipping optional item %ld\n", i);
2631 bytesNeeded += items[i].minSize;
2632 SetLastError(NOERROR);
2633 ret = TRUE;
2635 else
2636 TRACE("item %ld failed: %08lx\n", i,
2637 GetLastError());
2639 else
2640 bytesNeeded += items[i].minSize;
2643 else if (items[i].optional)
2644 bytesNeeded += items[i].minSize;
2645 else
2647 SetLastError(CRYPT_E_ASN1_CORRUPT);
2648 ret = FALSE;
2651 if (cbEncoded - (ptr - pbEncoded) != 0)
2653 TRACE("%ld remaining bytes, failing\n", cbEncoded -
2654 (ptr - pbEncoded));
2655 SetLastError(CRYPT_E_ASN1_CORRUPT);
2656 ret = FALSE;
2658 if (ret)
2660 if (!pvStructInfo)
2661 *pcbStructInfo = bytesNeeded;
2662 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
2663 pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
2665 BYTE *nextData;
2667 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2668 pvStructInfo = *(BYTE **)pvStructInfo;
2669 if (startingPointer)
2670 nextData = (BYTE *)startingPointer;
2671 else
2672 nextData = (BYTE *)pvStructInfo + minSize;
2673 memset(pvStructInfo, 0, minSize);
2674 ptr = pbEncoded + 1 + lenBytes;
2675 for (i = 0; ret && i < cItem; i++)
2677 if (cbEncoded - (ptr - pbEncoded) != 0)
2679 DWORD nextItemLen;
2680 BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
2682 CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
2683 &nextItemLen);
2684 if (items[i].hasPointer)
2686 *(BYTE **)((BYTE *)pvStructInfo +
2687 items[i].pointerOffset) = nextData;
2689 if (items[i].decodeFunc)
2691 TRACE("decoding item %ld\n", i);
2692 ret = items[i].decodeFunc(dwCertEncodingType,
2693 NULL, ptr, 1 + nextItemLenBytes + nextItemLen,
2694 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
2695 (BYTE *)pvStructInfo + items[i].offset,
2696 &items[i].size);
2697 if (!ret)
2698 TRACE("item %ld failed: %08lx\n", i,
2699 GetLastError());
2701 else
2702 items[i].size = items[i].minSize;
2703 if (ret)
2705 if (items[i].hasPointer &&
2706 items[i].size > items[i].minSize)
2708 nextData += items[i].size -
2709 items[i].minSize;
2710 /* align nextData to DWORD boundaries */
2711 if (items[i].size % sizeof(DWORD))
2713 nextData += sizeof(DWORD) -
2714 items[i].size % sizeof(DWORD);
2717 ptr += 1 + nextItemLenBytes + nextItemLen;
2719 else if (items[i].optional &&
2720 GetLastError() == CRYPT_E_ASN1_BADTAG)
2722 SetLastError(NOERROR);
2723 ret = TRUE;
2726 else if (!items[i].optional)
2728 SetLastError(CRYPT_E_ASN1_CORRUPT);
2729 ret = FALSE;
2736 else
2738 SetLastError(CRYPT_E_ASN1_BADTAG);
2739 ret = FALSE;
2741 TRACE("returning %d (%08lx)\n", ret, GetLastError());
2742 return ret;
2745 /* Decodes a DER-encoded BLOB into a CRYPT_DER_BLOB struct pointed to by
2746 * pvStructInfo. The BLOB must be non-empty, otherwise the last error is set
2747 * to CRYPT_E_ASN1_CORRUPT.
2748 * Warning: assumes the CRYPT_DER_BLOB pointed to by pvStructInfo has pbData
2749 * set!
2751 static BOOL WINAPI CRYPT_AsnDecodeDerBlob(DWORD dwCertEncodingType,
2752 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2753 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2755 BOOL ret;
2756 DWORD dataLen;
2758 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2760 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2761 DWORD bytesNeeded = sizeof(CRYPT_DER_BLOB);
2763 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
2764 bytesNeeded += 1 + lenBytes + dataLen;
2766 if (!pvStructInfo)
2767 *pcbStructInfo = bytesNeeded;
2768 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
2769 pvStructInfo, pcbStructInfo, bytesNeeded)))
2771 CRYPT_DER_BLOB *blob = (CRYPT_DER_BLOB *)pvStructInfo;
2773 blob->cbData = 1 + lenBytes + dataLen;
2774 if (blob->cbData)
2776 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
2777 blob->pbData = (BYTE *)pbEncoded;
2778 else
2780 assert(blob->pbData);
2781 memcpy(blob->pbData, pbEncoded, blob->cbData);
2784 else
2786 SetLastError(CRYPT_E_ASN1_CORRUPT);
2787 ret = FALSE;
2791 return ret;
2794 /* Like CRYPT_AsnDecodeBitsInternal, but swaps the bytes */
2795 static BOOL WINAPI CRYPT_AsnDecodeBitsSwapBytes(DWORD dwCertEncodingType,
2796 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2797 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2799 BOOL ret;
2801 TRACE("(%p, %ld, 0x%08lx, %p, %p, %ld)\n", pbEncoded, cbEncoded, dwFlags,
2802 pDecodePara, pvStructInfo, *pcbStructInfo);
2804 /* Can't use the CRYPT_DECODE_NOCOPY_FLAG, because we modify the bytes in-
2805 * place.
2807 ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType, lpszStructType,
2808 pbEncoded, cbEncoded, dwFlags & ~CRYPT_DECODE_NOCOPY_FLAG, pDecodePara,
2809 pvStructInfo, pcbStructInfo);
2810 if (ret && pvStructInfo)
2812 CRYPT_BIT_BLOB *blob = (CRYPT_BIT_BLOB *)pvStructInfo;
2814 if (blob->cbData)
2816 DWORD i;
2817 BYTE temp;
2819 for (i = 0; i < blob->cbData / 2; i++)
2821 temp = blob->pbData[i];
2822 blob->pbData[i] = blob->pbData[blob->cbData - i - 1];
2823 blob->pbData[blob->cbData - i - 1] = temp;
2827 TRACE("returning %d (%08lx)\n", ret, GetLastError());
2828 return ret;
2831 static BOOL WINAPI CRYPT_AsnDecodeCert(DWORD dwCertEncodingType,
2832 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2833 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2835 BOOL ret = TRUE;
2837 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
2838 pDecodePara, pvStructInfo, *pcbStructInfo);
2840 __TRY
2842 struct AsnDecodeSequenceItem items[] = {
2843 { offsetof(CERT_SIGNED_CONTENT_INFO, ToBeSigned),
2844 CRYPT_AsnDecodeDerBlob, sizeof(CRYPT_DER_BLOB), FALSE, TRUE,
2845 offsetof(CERT_SIGNED_CONTENT_INFO, ToBeSigned.pbData), 0 },
2846 { offsetof(CERT_SIGNED_CONTENT_INFO, SignatureAlgorithm),
2847 CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
2848 FALSE, TRUE, offsetof(CERT_SIGNED_CONTENT_INFO,
2849 SignatureAlgorithm.pszObjId), 0 },
2850 { offsetof(CERT_SIGNED_CONTENT_INFO, Signature),
2851 CRYPT_AsnDecodeBitsSwapBytes, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE,
2852 offsetof(CERT_SIGNED_CONTENT_INFO, Signature.pbData), 0 },
2855 if (dwFlags & CRYPT_DECODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG)
2856 items[2].decodeFunc = CRYPT_AsnDecodeBitsInternal;
2857 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2858 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2859 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
2861 __EXCEPT(page_fault)
2863 SetLastError(STATUS_ACCESS_VIOLATION);
2864 ret = FALSE;
2866 __ENDTRY
2867 return ret;
2870 static BOOL WINAPI CRYPT_AsnDecodeCertVersion(DWORD dwCertEncodingType,
2871 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2872 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2874 BOOL ret;
2876 if (pbEncoded[0] == (ASN_CONTEXT | ASN_CONSTRUCTOR))
2878 DWORD dataLen;
2880 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2882 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2884 ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER,
2885 pbEncoded + 1 + lenBytes, dataLen, dwFlags, pDecodePara,
2886 pvStructInfo, pcbStructInfo);
2889 else
2891 SetLastError(CRYPT_E_ASN1_BADTAG);
2892 ret = FALSE;
2894 return ret;
2897 static BOOL WINAPI CRYPT_AsnDecodeValidity(DWORD dwCertEncodingType,
2898 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2899 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2901 BOOL ret;
2903 struct AsnDecodeSequenceItem items[] = {
2904 { offsetof(CERT_PRIVATE_KEY_VALIDITY, NotBefore),
2905 CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 },
2906 { offsetof(CERT_PRIVATE_KEY_VALIDITY, NotAfter),
2907 CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 },
2910 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2911 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2912 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
2913 return ret;
2916 static BOOL WINAPI CRYPT_AsnDecodeCertExtensions(DWORD dwCertEncodingType,
2917 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2918 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2920 BOOL ret;
2922 if (pbEncoded[0] == (ASN_CONTEXT | ASN_CONSTRUCTOR | 3))
2924 DWORD dataLen;
2926 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2928 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2930 ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType,
2931 X509_EXTENSIONS, pbEncoded + 1 + lenBytes, dataLen, dwFlags,
2932 pDecodePara, pvStructInfo, pcbStructInfo);
2935 else
2937 SetLastError(CRYPT_E_ASN1_BADTAG);
2938 ret = FALSE;
2940 return ret;
2943 static BOOL WINAPI CRYPT_AsnDecodeCertInfo(DWORD dwCertEncodingType,
2944 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2945 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2947 BOOL ret = TRUE;
2949 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
2950 pDecodePara, pvStructInfo, *pcbStructInfo);
2952 __TRY
2954 struct AsnDecodeSequenceItem items[] = {
2955 { offsetof(CERT_INFO, dwVersion), CRYPT_AsnDecodeCertVersion,
2956 sizeof(DWORD), TRUE, FALSE, 0, 0 },
2957 { offsetof(CERT_INFO, SerialNumber), CRYPT_AsnDecodeIntegerInternal,
2958 sizeof(CRYPT_INTEGER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
2959 SerialNumber.pbData), 0 },
2960 { offsetof(CERT_INFO, SignatureAlgorithm), CRYPT_AsnDecodeAlgorithmId,
2961 sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE, offsetof(CERT_INFO,
2962 SignatureAlgorithm.pszObjId), 0 },
2963 { offsetof(CERT_INFO, Issuer), CRYPT_AsnDecodeDerBlob,
2964 sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
2965 Issuer.pbData) },
2966 { offsetof(CERT_INFO, NotBefore), CRYPT_AsnDecodeValidity,
2967 sizeof(CERT_PRIVATE_KEY_VALIDITY), FALSE, FALSE, 0 },
2968 { offsetof(CERT_INFO, Subject), CRYPT_AsnDecodeDerBlob,
2969 sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
2970 Subject.pbData) },
2971 { offsetof(CERT_INFO, SubjectPublicKeyInfo), CRYPT_AsnDecodePubKeyInfo,
2972 sizeof(CERT_PUBLIC_KEY_INFO), FALSE, TRUE, offsetof(CERT_INFO,
2973 SubjectPublicKeyInfo.Algorithm.Parameters.pbData), 0 },
2974 { offsetof(CERT_INFO, IssuerUniqueId), CRYPT_AsnDecodeBitsInternal,
2975 sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, offsetof(CERT_INFO,
2976 IssuerUniqueId.pbData), 0 },
2977 { offsetof(CERT_INFO, SubjectUniqueId), CRYPT_AsnDecodeBitsInternal,
2978 sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, offsetof(CERT_INFO,
2979 SubjectUniqueId.pbData), 0 },
2980 { offsetof(CERT_INFO, cExtension), CRYPT_AsnDecodeCertExtensions,
2981 sizeof(CERT_EXTENSIONS), TRUE, TRUE, offsetof(CERT_INFO,
2982 rgExtension), 0 },
2985 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2986 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2987 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
2989 __EXCEPT(page_fault)
2991 SetLastError(STATUS_ACCESS_VIOLATION);
2992 ret = FALSE;
2994 __ENDTRY
2995 return ret;
2998 static BOOL CRYPT_AsnDecodeCRLEntry(const BYTE *pbEncoded, DWORD cbEncoded,
2999 DWORD dwFlags, PCRL_ENTRY entry, DWORD *pcbEntry)
3001 BOOL ret;
3002 struct AsnDecodeSequenceItem items[] = {
3003 { offsetof(CRL_ENTRY, SerialNumber), CRYPT_AsnDecodeIntegerInternal,
3004 sizeof(CRYPT_INTEGER_BLOB), FALSE, TRUE, offsetof(CRL_ENTRY,
3005 SerialNumber.pbData), 0 },
3006 { offsetof(CRL_ENTRY, RevocationDate), CRYPT_AsnDecodeChoiceOfTime,
3007 sizeof(FILETIME), FALSE, FALSE, 0 },
3008 { offsetof(CRL_ENTRY, cExtension), CRYPT_AsnDecodeExtensionsInternal,
3009 sizeof(CERT_EXTENSIONS), TRUE, TRUE, offsetof(CRL_ENTRY,
3010 rgExtension), 0 },
3013 TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, entry,
3014 *pcbEntry);
3016 ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items,
3017 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3018 NULL, entry, pcbEntry, entry ? entry->SerialNumber.pbData : NULL);
3019 TRACE("Returning %d (%08lx)\n", ret, GetLastError());
3020 return ret;
3023 typedef struct _WINE_CRL_ENTRIES {
3024 DWORD cCRLEntry;
3025 PCRL_ENTRY rgCRLEntry;
3026 } WINE_CRL_ENTRIES, *PWINE_CRL_ENTRIES;
3028 /* Warning: assumes pvStructInfo is a WINE_CRL_ENTRIES whose rgCRLEntry has
3029 * been set prior to calling.
3031 static BOOL WINAPI CRYPT_AsnDecodeCRLEntries(DWORD dwCertEncodingType,
3032 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3033 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3035 BOOL ret;
3037 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3038 pDecodePara, pvStructInfo, *pcbStructInfo);
3040 if (pbEncoded[0] == ASN_SEQUENCEOF)
3042 DWORD dataLen, bytesNeeded;
3044 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3046 DWORD cCRLEntry = 0;
3047 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3049 bytesNeeded = sizeof(WINE_CRL_ENTRIES);
3050 if (dataLen)
3052 const BYTE *ptr;
3053 DWORD size;
3055 for (ptr = pbEncoded + 1 + lenBytes; ret &&
3056 ptr - pbEncoded - 1 - lenBytes < dataLen; )
3058 size = 0;
3059 ret = CRYPT_AsnDecodeCRLEntry(ptr,
3060 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
3061 if (ret)
3063 DWORD nextLen;
3065 cCRLEntry++;
3066 bytesNeeded += size;
3067 ret = CRYPT_GetLen(ptr,
3068 cbEncoded - (ptr - pbEncoded), &nextLen);
3069 if (ret)
3070 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3074 if (ret)
3076 if (!pvStructInfo)
3077 *pcbStructInfo = bytesNeeded;
3078 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
3079 pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
3081 DWORD size, i;
3082 BYTE *nextData;
3083 const BYTE *ptr;
3084 PWINE_CRL_ENTRIES entries;
3086 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3087 pvStructInfo = *(BYTE **)pvStructInfo;
3088 *pcbStructInfo = bytesNeeded;
3089 entries = (PWINE_CRL_ENTRIES)pvStructInfo;
3090 entries->cCRLEntry = cCRLEntry;
3091 assert(entries->rgCRLEntry);
3092 nextData = (BYTE *)entries->rgCRLEntry +
3093 entries->cCRLEntry * sizeof(CRL_ENTRY);
3094 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
3095 i < cCRLEntry && ptr - pbEncoded - 1 - lenBytes <
3096 dataLen; i++)
3098 entries->rgCRLEntry[i].SerialNumber.pbData = nextData;
3099 size = bytesNeeded;
3100 ret = CRYPT_AsnDecodeCRLEntry(ptr,
3101 cbEncoded - (ptr - pbEncoded), dwFlags,
3102 &entries->rgCRLEntry[i], &size);
3103 if (ret)
3105 DWORD nextLen;
3107 bytesNeeded -= size;
3108 /* Increment nextData by the difference of the
3109 * minimum size and the actual size.
3111 if (size > sizeof(CRL_ENTRY))
3112 nextData += size - sizeof(CRL_ENTRY);
3113 ret = CRYPT_GetLen(ptr,
3114 cbEncoded - (ptr - pbEncoded), &nextLen);
3115 if (ret)
3116 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3123 else
3125 SetLastError(CRYPT_E_ASN1_BADTAG);
3126 ret = FALSE;
3128 TRACE("Returning %d (%08lx)\n", ret, GetLastError());
3129 return ret;
3132 static BOOL WINAPI CRYPT_AsnDecodeCRLInfo(DWORD dwCertEncodingType,
3133 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3134 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3136 BOOL ret = TRUE;
3138 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3139 pDecodePara, pvStructInfo, *pcbStructInfo);
3141 __TRY
3143 struct AsnDecodeSequenceItem items[] = {
3144 { offsetof(CRL_INFO, dwVersion), CRYPT_AsnDecodeCertVersion,
3145 sizeof(DWORD), TRUE, FALSE, 0, 0 },
3146 { offsetof(CRL_INFO, SignatureAlgorithm), CRYPT_AsnDecodeAlgorithmId,
3147 sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE, offsetof(CRL_INFO,
3148 SignatureAlgorithm.pszObjId), 0 },
3149 { offsetof(CRL_INFO, Issuer), CRYPT_AsnDecodeDerBlob,
3150 sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CRL_INFO,
3151 Issuer.pbData) },
3152 { offsetof(CRL_INFO, ThisUpdate), CRYPT_AsnDecodeChoiceOfTime,
3153 sizeof(FILETIME), FALSE, FALSE, 0 },
3154 { offsetof(CRL_INFO, NextUpdate), CRYPT_AsnDecodeChoiceOfTime,
3155 sizeof(FILETIME), TRUE, FALSE, 0 },
3156 { offsetof(CRL_INFO, cCRLEntry), CRYPT_AsnDecodeCRLEntries,
3157 sizeof(WINE_CRL_ENTRIES), TRUE, TRUE, offsetof(CRL_INFO,
3158 rgCRLEntry), 0 },
3159 /* Note that the extensions are ignored by MS, so I'll ignore them too
3161 { offsetof(CRL_INFO, cExtension), NULL,
3162 sizeof(CERT_EXTENSIONS), TRUE, FALSE, 0 },
3165 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
3166 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3167 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
3169 __EXCEPT(page_fault)
3171 SetLastError(STATUS_ACCESS_VIOLATION);
3172 ret = FALSE;
3174 __ENDTRY
3176 TRACE("Returning %d (%08lx)\n", ret, GetLastError());
3177 return ret;
3180 /* Differences between this and CRYPT_AsnDecodeOid:
3181 * - pvStructInfo is a LPSTR *, not an LPSTR
3182 * - CRYPT_AsnDecodeOid doesn't account for the size of an LPSTR in its byte
3183 * count, whereas our callers (typically CRYPT_AsnDecodeSequence) expect this
3184 * to
3186 static BOOL WINAPI CRYPT_AsnDecodeOidWrapper(DWORD dwCertEncodingType,
3187 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3188 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3190 BOOL ret;
3192 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3193 pDecodePara, pvStructInfo, *pcbStructInfo);
3195 ret = CRYPT_AsnDecodeOid(pbEncoded, cbEncoded, dwFlags,
3196 pvStructInfo ? *(LPSTR *)pvStructInfo : NULL, pcbStructInfo);
3197 if (ret || GetLastError() == ERROR_MORE_DATA)
3198 *pcbStructInfo += sizeof(LPSTR);
3199 if (ret && pvStructInfo)
3200 TRACE("returning %s\n", debugstr_a(*(LPSTR *)pvStructInfo));
3201 return ret;
3204 /* Warning: assumes ext->pszObjId is set ahead of time! */
3205 static BOOL CRYPT_AsnDecodeExtension(const BYTE *pbEncoded, DWORD cbEncoded,
3206 DWORD dwFlags, CERT_EXTENSION *ext, DWORD *pcbExt)
3208 struct AsnDecodeSequenceItem items[] = {
3209 { offsetof(CERT_EXTENSION, pszObjId), CRYPT_AsnDecodeOidWrapper,
3210 sizeof(LPSTR), FALSE, TRUE, offsetof(CERT_EXTENSION, pszObjId), 0 },
3211 { offsetof(CERT_EXTENSION, fCritical), CRYPT_AsnDecodeBool,
3212 sizeof(BOOL), TRUE, FALSE, 0, 0 },
3213 { offsetof(CERT_EXTENSION, Value), CRYPT_AsnDecodeOctetsInternal,
3214 sizeof(CRYPT_OBJID_BLOB), FALSE, TRUE, offsetof(CERT_EXTENSION,
3215 Value.pbData) },
3217 BOOL ret = TRUE;
3219 TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, ext,
3220 *pcbExt);
3222 if (ext)
3223 TRACE("ext->pszObjId is %p\n", ext->pszObjId);
3224 ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items,
3225 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, NULL,
3226 ext, pcbExt, ext ? ext->pszObjId : NULL);
3227 if (ext)
3228 TRACE("ext->pszObjId is %p (%s)\n", ext->pszObjId,
3229 debugstr_a(ext->pszObjId));
3230 TRACE("returning %d (%08lx)\n", ret, GetLastError());
3231 return ret;
3234 static BOOL WINAPI CRYPT_AsnDecodeExtensionsInternal(DWORD dwCertEncodingType,
3235 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3236 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3238 BOOL ret = TRUE;
3240 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3241 pDecodePara, pvStructInfo, *pcbStructInfo);
3243 if (pbEncoded[0] == ASN_SEQUENCEOF)
3245 DWORD dataLen, bytesNeeded;
3247 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3249 DWORD cExtension = 0;
3250 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3252 bytesNeeded = sizeof(CERT_EXTENSIONS);
3253 if (dataLen)
3255 const BYTE *ptr;
3256 DWORD size;
3258 for (ptr = pbEncoded + 1 + lenBytes; ret &&
3259 ptr - pbEncoded - 1 - lenBytes < dataLen; )
3261 size = 0;
3262 ret = CRYPT_AsnDecodeExtension(ptr,
3263 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
3264 if (ret)
3266 DWORD nextLen;
3268 cExtension++;
3269 bytesNeeded += size;
3270 ret = CRYPT_GetLen(ptr,
3271 cbEncoded - (ptr - pbEncoded), &nextLen);
3272 if (ret)
3273 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3277 if (ret)
3279 if (!pvStructInfo)
3280 *pcbStructInfo = bytesNeeded;
3281 else if (*pcbStructInfo < bytesNeeded)
3283 SetLastError(ERROR_MORE_DATA);
3284 *pcbStructInfo = bytesNeeded;
3285 ret = FALSE;
3287 else
3289 DWORD size, i;
3290 BYTE *nextData;
3291 const BYTE *ptr;
3292 CERT_EXTENSIONS *exts;
3294 *pcbStructInfo = bytesNeeded;
3295 exts = (CERT_EXTENSIONS *)pvStructInfo;
3296 exts->cExtension = cExtension;
3297 assert(exts->rgExtension);
3298 nextData = (BYTE *)exts->rgExtension +
3299 exts->cExtension * sizeof(CERT_EXTENSION);
3300 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
3301 i < cExtension && ptr - pbEncoded - 1 - lenBytes <
3302 dataLen; i++)
3304 exts->rgExtension[i].pszObjId = (LPSTR)nextData;
3305 size = bytesNeeded;
3306 ret = CRYPT_AsnDecodeExtension(ptr,
3307 cbEncoded - (ptr - pbEncoded), dwFlags,
3308 &exts->rgExtension[i], &size);
3309 if (ret)
3311 DWORD nextLen;
3313 bytesNeeded -= size;
3314 if (size > sizeof(CERT_EXTENSION))
3315 nextData += size - sizeof(CERT_EXTENSION);
3316 ret = CRYPT_GetLen(ptr,
3317 cbEncoded - (ptr - pbEncoded), &nextLen);
3318 if (ret)
3319 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3326 else
3328 SetLastError(CRYPT_E_ASN1_BADTAG);
3329 ret = FALSE;
3331 return ret;
3334 static BOOL WINAPI CRYPT_AsnDecodeExtensions(DWORD dwCertEncodingType,
3335 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3336 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3338 BOOL ret = TRUE;
3340 __TRY
3342 ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType,
3343 lpszStructType, pbEncoded, cbEncoded,
3344 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, pcbStructInfo);
3345 if (ret && pvStructInfo)
3347 ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
3348 pcbStructInfo, *pcbStructInfo);
3349 if (ret)
3351 CERT_EXTENSIONS *exts;
3353 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3354 pvStructInfo = *(BYTE **)pvStructInfo;
3355 exts = (CERT_EXTENSIONS *)pvStructInfo;
3356 exts->rgExtension = (CERT_EXTENSION *)((BYTE *)exts +
3357 sizeof(CERT_EXTENSIONS));
3358 ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType,
3359 lpszStructType, pbEncoded, cbEncoded,
3360 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
3361 pcbStructInfo);
3365 __EXCEPT(page_fault)
3367 SetLastError(STATUS_ACCESS_VIOLATION);
3368 ret = FALSE;
3370 __ENDTRY
3371 return ret;
3374 /* FIXME: honor the CRYPT_DECODE_SHARE_OID_STRING_FLAG. */
3375 static BOOL WINAPI CRYPT_AsnDecodeOid(const BYTE *pbEncoded, DWORD cbEncoded,
3376 DWORD dwFlags, LPSTR pszObjId, DWORD *pcbObjId)
3378 BOOL ret = TRUE;
3380 TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, pszObjId,
3381 *pcbObjId);
3383 __TRY
3385 if (pbEncoded[0] == ASN_OBJECTIDENTIFIER)
3387 DWORD dataLen;
3389 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3391 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3392 DWORD bytesNeeded;
3394 if (dataLen)
3396 /* The largest possible string for the first two components
3397 * is 2.175 (= 2 * 40 + 175 = 255), so this is big enough.
3399 char firstTwo[6];
3400 const BYTE *ptr;
3402 snprintf(firstTwo, sizeof(firstTwo), "%d.%d",
3403 pbEncoded[1 + lenBytes] / 40,
3404 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40)
3405 * 40);
3406 bytesNeeded = strlen(firstTwo) + 1;
3407 for (ptr = pbEncoded + 2 + lenBytes; ret &&
3408 ptr - pbEncoded - 1 - lenBytes < dataLen; )
3410 /* large enough for ".4000000" */
3411 char str[9];
3412 int val = 0;
3414 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
3415 (*ptr & 0x80))
3417 val <<= 7;
3418 val |= *ptr & 0x7f;
3419 ptr++;
3421 if (ptr - pbEncoded - 1 - lenBytes >= dataLen ||
3422 (*ptr & 0x80))
3424 SetLastError(CRYPT_E_ASN1_CORRUPT);
3425 ret = FALSE;
3427 else
3429 val <<= 7;
3430 val |= *ptr++;
3431 snprintf(str, sizeof(str), ".%d", val);
3432 bytesNeeded += strlen(str);
3435 if (!pszObjId)
3436 *pcbObjId = bytesNeeded;
3437 else if (*pcbObjId < bytesNeeded)
3439 *pcbObjId = bytesNeeded;
3440 SetLastError(ERROR_MORE_DATA);
3441 ret = FALSE;
3443 else
3445 *pszObjId = 0;
3446 sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40,
3447 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] /
3448 40) * 40);
3449 pszObjId += strlen(pszObjId);
3450 for (ptr = pbEncoded + 2 + lenBytes; ret &&
3451 ptr - pbEncoded - 1 - lenBytes < dataLen; )
3453 int val = 0;
3455 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
3456 (*ptr & 0x80))
3458 val <<= 7;
3459 val |= *ptr & 0x7f;
3460 ptr++;
3462 val <<= 7;
3463 val |= *ptr++;
3464 sprintf(pszObjId, ".%d", val);
3465 pszObjId += strlen(pszObjId);
3469 else
3470 bytesNeeded = 0;
3471 *pcbObjId = bytesNeeded;
3474 else
3476 SetLastError(CRYPT_E_ASN1_BADTAG);
3477 ret = FALSE;
3480 __EXCEPT(page_fault)
3482 SetLastError(STATUS_ACCESS_VIOLATION);
3483 ret = FALSE;
3485 __ENDTRY
3486 return ret;
3489 /* Warning: this assumes the address of value->Value.pbData is already set, in
3490 * order to avoid overwriting memory. (In some cases, it may change it, if it
3491 * doesn't copy anything to memory.) Be sure to set it correctly!
3493 static BOOL WINAPI CRYPT_AsnDecodeNameValue(const BYTE *pbEncoded,
3494 DWORD cbEncoded, DWORD dwFlags, CERT_NAME_VALUE *value, DWORD *pcbValue)
3496 BOOL ret = TRUE;
3498 __TRY
3500 DWORD dataLen;
3502 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3504 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3506 switch (pbEncoded[0])
3508 case ASN_NUMERICSTRING:
3509 case ASN_PRINTABLESTRING:
3510 case ASN_IA5STRING:
3511 break;
3512 default:
3513 FIXME("Unimplemented string type %02x\n", pbEncoded[0]);
3514 SetLastError(OSS_UNIMPLEMENTED);
3515 ret = FALSE;
3517 if (ret)
3519 DWORD bytesNeeded = sizeof(CERT_NAME_VALUE);
3521 switch (pbEncoded[0])
3523 case ASN_NUMERICSTRING:
3524 case ASN_PRINTABLESTRING:
3525 case ASN_IA5STRING:
3526 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
3527 bytesNeeded += dataLen;
3528 break;
3530 if (!value)
3531 *pcbValue = bytesNeeded;
3532 else if (*pcbValue < bytesNeeded)
3534 *pcbValue = bytesNeeded;
3535 SetLastError(ERROR_MORE_DATA);
3536 ret = FALSE;
3538 else
3540 *pcbValue = bytesNeeded;
3541 switch (pbEncoded[0])
3543 case ASN_NUMERICSTRING:
3544 value->dwValueType = CERT_RDN_NUMERIC_STRING;
3545 break;
3546 case ASN_PRINTABLESTRING:
3547 value->dwValueType = CERT_RDN_PRINTABLE_STRING;
3548 break;
3549 case ASN_IA5STRING:
3550 value->dwValueType = CERT_RDN_IA5_STRING;
3551 break;
3553 if (dataLen)
3555 switch (pbEncoded[0])
3557 case ASN_NUMERICSTRING:
3558 case ASN_PRINTABLESTRING:
3559 case ASN_IA5STRING:
3560 value->Value.cbData = dataLen;
3561 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
3562 value->Value.pbData = (BYTE *)pbEncoded + 1 +
3563 lenBytes;
3564 else
3566 assert(value->Value.pbData);
3567 memcpy(value->Value.pbData,
3568 pbEncoded + 1 + lenBytes, dataLen);
3570 break;
3573 else
3575 value->Value.cbData = 0;
3576 value->Value.pbData = NULL;
3582 __EXCEPT(page_fault)
3584 SetLastError(STATUS_ACCESS_VIOLATION);
3585 ret = FALSE;
3587 __ENDTRY
3588 return ret;
3591 /* FIXME: this should use CRYPT_AsnDecodeSequence (though that won't accept it
3592 * at the moment because of the ASN_CONSTRUCTOR tag.)
3594 static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(const BYTE *pbEncoded,
3595 DWORD cbEncoded, DWORD dwFlags, CERT_RDN_ATTR *attr, DWORD *pcbAttr)
3597 BOOL ret;
3599 __TRY
3601 if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SEQUENCE))
3603 DWORD bytesNeeded, dataLen, size;
3604 BYTE lenBytes;
3606 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3608 /* The data length must be at least 4, two for the tag and
3609 * length for the OID, and two for the string (assuming both
3610 * have short-form lengths.)
3612 if (dataLen < 4)
3614 SetLastError(CRYPT_E_ASN1_EOD);
3615 ret = FALSE;
3617 else
3619 bytesNeeded = sizeof(CERT_RDN_ATTR);
3620 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3621 ret = CRYPT_AsnDecodeOid(pbEncoded + 1 + lenBytes,
3622 cbEncoded - 1 - lenBytes, dwFlags, NULL, &size);
3623 if (ret)
3625 /* ugly: need to know the size of the next element of
3626 * the sequence, so get it directly
3628 DWORD objIdOfset = 1 + lenBytes, objIdLen,
3629 nameValueOffset = 0;
3631 ret = CRYPT_GetLen(pbEncoded + objIdOfset,
3632 cbEncoded - objIdOfset, &objIdLen);
3633 bytesNeeded += size;
3634 /* hack: like encoding, this takes advantage of the
3635 * fact that the rest of the structure is identical to
3636 * a CERT_NAME_VALUE.
3638 if (ret)
3640 nameValueOffset = objIdOfset + objIdLen + 1 +
3641 GET_LEN_BYTES(pbEncoded[objIdOfset]);
3642 ret = CRYPT_AsnDecodeNameValue(
3643 pbEncoded + nameValueOffset,
3644 cbEncoded - nameValueOffset, dwFlags, NULL, &size);
3646 if (ret)
3648 bytesNeeded += size;
3649 if (!attr)
3650 *pcbAttr = bytesNeeded;
3651 else if (*pcbAttr < bytesNeeded)
3653 *pcbAttr = bytesNeeded;
3654 SetLastError(ERROR_MORE_DATA);
3655 ret = FALSE;
3657 else
3659 BYTE *originalData = attr->Value.pbData;
3661 *pcbAttr = bytesNeeded;
3662 /* strange: decode the value first, because it
3663 * has a counted size, and we can store the OID
3664 * after it. Keep track of the original data
3665 * pointer, we'll need to know whether it was
3666 * changed.
3668 size = bytesNeeded;
3669 ret = CRYPT_AsnDecodeNameValue(
3670 pbEncoded + nameValueOffset,
3671 cbEncoded - nameValueOffset, dwFlags,
3672 (CERT_NAME_VALUE *)&attr->dwValueType, &size);
3673 if (ret)
3675 if (objIdLen)
3677 /* if the data were copied to the
3678 * original location, the OID goes
3679 * after. Otherwise it goes in the
3680 * spot originally reserved for the
3681 * data.
3683 if (attr->Value.pbData == originalData)
3684 attr->pszObjId =
3685 (LPSTR)(attr->Value.pbData +
3686 attr->Value.cbData);
3687 else
3688 attr->pszObjId =
3689 (LPSTR)originalData;
3690 size = bytesNeeded - size;
3691 ret = CRYPT_AsnDecodeOid(
3692 pbEncoded + objIdOfset,
3693 cbEncoded - objIdOfset,
3694 dwFlags, attr->pszObjId, &size);
3696 else
3697 attr->pszObjId = NULL;
3705 else
3707 SetLastError(CRYPT_E_ASN1_BADTAG);
3708 ret = FALSE;
3711 __EXCEPT(page_fault)
3713 SetLastError(STATUS_ACCESS_VIOLATION);
3714 ret = FALSE;
3716 __ENDTRY
3717 return ret;
3720 static BOOL WINAPI CRYPT_AsnDecodeRdn(const BYTE *pbEncoded, DWORD cbEncoded,
3721 DWORD dwFlags, CERT_RDN *rdn, DWORD *pcbRdn)
3723 BOOL ret = TRUE;
3725 __TRY
3727 if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SETOF))
3729 DWORD dataLen;
3731 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3733 DWORD bytesNeeded, cRDNAttr = 0;
3734 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3736 bytesNeeded = sizeof(CERT_RDN);
3737 if (dataLen)
3739 const BYTE *ptr;
3740 DWORD size;
3742 for (ptr = pbEncoded + 1 + lenBytes; ret &&
3743 ptr - pbEncoded - 1 - lenBytes < dataLen; )
3745 ret = CRYPT_AsnDecodeRdnAttr(ptr,
3746 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
3747 if (ret)
3749 DWORD nextLen;
3751 cRDNAttr++;
3752 bytesNeeded += size;
3753 ret = CRYPT_GetLen(ptr,
3754 cbEncoded - (ptr - pbEncoded), &nextLen);
3755 if (ret)
3756 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3760 if (ret)
3762 if (!rdn)
3763 *pcbRdn = bytesNeeded;
3764 else if (*pcbRdn < bytesNeeded)
3766 *pcbRdn = bytesNeeded;
3767 SetLastError(ERROR_MORE_DATA);
3768 ret = FALSE;
3770 else
3772 DWORD size, i;
3773 BYTE *nextData;
3774 const BYTE *ptr;
3776 *pcbRdn = bytesNeeded;
3777 rdn->cRDNAttr = cRDNAttr;
3778 rdn->rgRDNAttr = (CERT_RDN_ATTR *)((BYTE *)rdn +
3779 sizeof(CERT_RDN));
3780 nextData = (BYTE *)rdn->rgRDNAttr +
3781 rdn->cRDNAttr * sizeof(CERT_RDN_ATTR);
3782 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
3783 i < cRDNAttr && ptr - pbEncoded - 1 - lenBytes <
3784 dataLen; i++)
3786 rdn->rgRDNAttr[i].Value.pbData = nextData;
3787 size = bytesNeeded;
3788 ret = CRYPT_AsnDecodeRdnAttr(ptr,
3789 cbEncoded - (ptr - pbEncoded), dwFlags,
3790 &rdn->rgRDNAttr[i], &size);
3791 if (ret)
3793 DWORD nextLen;
3795 bytesNeeded -= size;
3796 /* If dwFlags & CRYPT_DECODE_NOCOPY_FLAG, the
3797 * data may not have been copied.
3799 if (rdn->rgRDNAttr[i].Value.pbData == nextData)
3800 nextData +=
3801 rdn->rgRDNAttr[i].Value.cbData;
3802 /* Ugly: the OID, if copied, is stored in
3803 * memory after the value, so increment by its
3804 * string length if it's set and points here.
3806 if ((const BYTE *)rdn->rgRDNAttr[i].pszObjId
3807 == nextData)
3808 nextData += strlen(
3809 rdn->rgRDNAttr[i].pszObjId) + 1;
3810 ret = CRYPT_GetLen(ptr,
3811 cbEncoded - (ptr - pbEncoded), &nextLen);
3812 if (ret)
3813 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3820 else
3822 SetLastError(CRYPT_E_ASN1_BADTAG);
3823 ret = FALSE;
3826 __EXCEPT(page_fault)
3828 SetLastError(STATUS_ACCESS_VIOLATION);
3829 ret = FALSE;
3831 __ENDTRY
3832 return ret;
3835 static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType,
3836 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3837 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3839 BOOL ret = TRUE;
3841 __TRY
3843 if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SEQUENCEOF))
3845 DWORD dataLen;
3847 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3849 DWORD bytesNeeded, cRDN = 0;
3850 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3852 bytesNeeded = sizeof(CERT_NAME_INFO);
3853 if (dataLen)
3855 const BYTE *ptr;
3857 for (ptr = pbEncoded + 1 + lenBytes; ret &&
3858 ptr - pbEncoded - 1 - lenBytes < dataLen; )
3860 DWORD size;
3862 ret = CRYPT_AsnDecodeRdn(ptr,
3863 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
3864 if (ret)
3866 DWORD nextLen;
3868 cRDN++;
3869 bytesNeeded += size;
3870 ret = CRYPT_GetLen(ptr,
3871 cbEncoded - (ptr - pbEncoded), &nextLen);
3872 if (ret)
3873 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3877 if (ret)
3879 if (!pvStructInfo)
3880 *pcbStructInfo = bytesNeeded;
3881 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
3882 pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
3884 CERT_NAME_INFO *info;
3886 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3887 pvStructInfo = *(BYTE **)pvStructInfo;
3888 info = (CERT_NAME_INFO *)pvStructInfo;
3889 info->cRDN = cRDN;
3890 if (info->cRDN == 0)
3891 info->rgRDN = NULL;
3892 else
3894 DWORD size, i;
3895 BYTE *nextData;
3896 const BYTE *ptr;
3898 info->rgRDN = (CERT_RDN *)((BYTE *)pvStructInfo +
3899 sizeof(CERT_NAME_INFO));
3900 nextData = (BYTE *)info->rgRDN +
3901 info->cRDN * sizeof(CERT_RDN);
3902 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
3903 i < cRDN && ptr - pbEncoded - 1 - lenBytes <
3904 dataLen; i++)
3906 info->rgRDN[i].rgRDNAttr =
3907 (CERT_RDN_ATTR *)nextData;
3908 size = bytesNeeded;
3909 ret = CRYPT_AsnDecodeRdn(ptr,
3910 cbEncoded - (ptr - pbEncoded), dwFlags,
3911 &info->rgRDN[i], &size);
3912 if (ret)
3914 DWORD nextLen;
3916 nextData += size;
3917 bytesNeeded -= size;
3918 ret = CRYPT_GetLen(ptr,
3919 cbEncoded - (ptr - pbEncoded), &nextLen);
3920 if (ret)
3921 ptr += nextLen + 1 +
3922 GET_LEN_BYTES(ptr[1]);
3930 else
3932 SetLastError(CRYPT_E_ASN1_BADTAG);
3933 ret = FALSE;
3936 __EXCEPT(page_fault)
3938 SetLastError(STATUS_ACCESS_VIOLATION);
3939 ret = FALSE;
3941 __ENDTRY
3942 return ret;
3945 static BOOL WINAPI CRYPT_AsnDecodeCopyBytes(DWORD dwCertEncodingType,
3946 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3947 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3949 BOOL ret = TRUE;
3950 DWORD bytesNeeded = sizeof(CRYPT_OBJID_BLOB);
3952 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3953 pDecodePara, pvStructInfo, *pcbStructInfo);
3955 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
3956 bytesNeeded += cbEncoded;
3957 if (!pvStructInfo)
3958 *pcbStructInfo = bytesNeeded;
3959 else if (*pcbStructInfo < bytesNeeded)
3961 SetLastError(ERROR_MORE_DATA);
3962 *pcbStructInfo = bytesNeeded;
3963 ret = FALSE;
3965 else
3967 PCRYPT_OBJID_BLOB blob = (PCRYPT_OBJID_BLOB)pvStructInfo;
3969 *pcbStructInfo = bytesNeeded;
3970 blob->cbData = cbEncoded;
3971 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
3972 blob->pbData = (LPBYTE)pbEncoded;
3973 else
3975 assert(blob->pbData);
3976 memcpy(blob->pbData, pbEncoded, blob->cbData);
3979 return ret;
3982 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
3983 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3984 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3986 CRYPT_ALGORITHM_IDENTIFIER *algo =
3987 (CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
3988 BOOL ret = TRUE;
3989 struct AsnDecodeSequenceItem items[] = {
3990 { offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId),
3991 CRYPT_AsnDecodeOidWrapper, sizeof(LPSTR), FALSE, TRUE,
3992 offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId), 0 },
3993 { offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters),
3994 CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_OBJID_BLOB), TRUE, TRUE,
3995 offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters.pbData), 0 },
3998 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3999 pDecodePara, pvStructInfo, *pcbStructInfo);
4001 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
4002 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
4003 pDecodePara, pvStructInfo, pcbStructInfo, algo ? algo->pszObjId : NULL);
4004 if (ret && pvStructInfo)
4006 TRACE("pszObjId is %p (%s)\n", algo->pszObjId,
4007 debugstr_a(algo->pszObjId));
4009 return ret;
4012 static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType,
4013 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4014 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4016 BOOL ret = TRUE;
4018 __TRY
4020 struct AsnDecodeSequenceItem items[] = {
4021 { offsetof(CERT_PUBLIC_KEY_INFO, Algorithm),
4022 CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
4023 FALSE, TRUE, offsetof(CERT_PUBLIC_KEY_INFO,
4024 Algorithm.pszObjId) },
4025 { offsetof(CERT_PUBLIC_KEY_INFO, PublicKey),
4026 CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE,
4027 offsetof(CERT_PUBLIC_KEY_INFO, PublicKey.pbData) },
4030 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
4031 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
4032 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
4034 __EXCEPT(page_fault)
4036 SetLastError(STATUS_ACCESS_VIOLATION);
4037 ret = FALSE;
4039 __ENDTRY
4040 return ret;
4043 static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
4044 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4045 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4047 BOOL ret;
4049 if (cbEncoded < 3)
4051 SetLastError(CRYPT_E_ASN1_CORRUPT);
4052 return FALSE;
4054 if (pbEncoded[0] != ASN_BOOL)
4056 SetLastError(CRYPT_E_ASN1_BADTAG);
4057 return FALSE;
4059 if (GET_LEN_BYTES(pbEncoded[1]) > 1)
4061 SetLastError(CRYPT_E_ASN1_CORRUPT);
4062 return FALSE;
4064 if (pbEncoded[1] > 1)
4066 SetLastError(CRYPT_E_ASN1_CORRUPT);
4067 return FALSE;
4069 if (!pvStructInfo)
4071 *pcbStructInfo = sizeof(BOOL);
4072 ret = TRUE;
4074 else if (*pcbStructInfo < sizeof(BOOL))
4076 *pcbStructInfo = sizeof(BOOL);
4077 SetLastError(ERROR_MORE_DATA);
4078 ret = FALSE;
4080 else
4082 *(BOOL *)pvStructInfo = pbEncoded[2] ? TRUE : FALSE;
4083 ret = TRUE;
4085 TRACE("returning %d (%08lx)\n", ret, GetLastError());
4086 return ret;
4089 static BOOL CRYPT_AsnDecodeAltNameEntry(const BYTE *pbEncoded, DWORD cbEncoded,
4090 DWORD dwFlags, CERT_ALT_NAME_ENTRY *entry, DWORD *pcbEntry)
4092 DWORD dataLen, lenBytes, bytesNeeded = sizeof(CERT_ALT_NAME_ENTRY);
4093 BOOL ret;
4095 if (cbEncoded < 2)
4097 SetLastError(CRYPT_E_ASN1_CORRUPT);
4098 return FALSE;
4100 if ((pbEncoded[0] & ASN_FLAGS_MASK) != ASN_CONTEXT)
4102 SetLastError(CRYPT_E_ASN1_BADTAG);
4103 return FALSE;
4105 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4106 if (1 + lenBytes > cbEncoded)
4108 SetLastError(CRYPT_E_ASN1_CORRUPT);
4109 return FALSE;
4111 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4113 switch (pbEncoded[0] & ASN_TYPE_MASK)
4115 case 1: /* rfc822Name */
4116 case 2: /* dNSName */
4117 case 6: /* uniformResourceIdentifier */
4118 bytesNeeded += (dataLen + 1) * sizeof(WCHAR);
4119 break;
4120 case 7: /* iPAddress */
4121 bytesNeeded += dataLen;
4122 break;
4123 case 8: /* registeredID */
4124 /* FIXME: decode as OID */
4125 case 0: /* otherName */
4126 case 4: /* directoryName */
4127 FIXME("stub\n");
4128 SetLastError(CRYPT_E_ASN1_BADTAG);
4129 ret = FALSE;
4130 break;
4131 case 3: /* x400Address, unimplemented */
4132 case 5: /* ediPartyName, unimplemented */
4133 SetLastError(CRYPT_E_ASN1_BADTAG);
4134 ret = FALSE;
4135 break;
4136 default:
4137 SetLastError(CRYPT_E_ASN1_CORRUPT);
4138 ret = FALSE;
4140 if (ret)
4142 if (!entry)
4143 *pcbEntry = bytesNeeded;
4144 else if (*pcbEntry < bytesNeeded)
4146 SetLastError(ERROR_MORE_DATA);
4147 ret = FALSE;
4149 else
4151 /* MS used values one greater than the asn1 ones.. sigh */
4152 entry->dwAltNameChoice = (pbEncoded[0] & 0x7f) + 1;
4153 switch (pbEncoded[0] & ASN_TYPE_MASK)
4155 case 1: /* rfc822Name */
4156 case 2: /* dNSName */
4157 case 6: /* uniformResourceIdentifier */
4159 DWORD i;
4161 for (i = 0; i < dataLen; i++)
4162 entry->u.pwszURL[i] =
4163 (WCHAR)pbEncoded[1 + lenBytes + i];
4164 entry->u.pwszURL[i] = 0;
4165 break;
4167 case 7: /* iPAddress */
4168 /* The next data pointer is in the pwszURL spot, that is,
4169 * the first 4 bytes. Need to move it to the next spot.
4171 entry->u.IPAddress.pbData = (LPBYTE)entry->u.pwszURL;
4172 entry->u.IPAddress.cbData = dataLen;
4173 memcpy(entry->u.IPAddress.pbData, pbEncoded + 1 + lenBytes,
4174 dataLen);
4175 break;
4180 return ret;
4183 static BOOL WINAPI CRYPT_AsnDecodeAltName(DWORD dwCertEncodingType,
4184 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4185 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4187 BOOL ret = TRUE;
4189 __TRY
4191 if (pbEncoded[0] == ASN_SEQUENCEOF)
4193 DWORD dataLen;
4195 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4197 DWORD bytesNeeded, cEntry = 0;
4198 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4200 bytesNeeded = sizeof(CERT_ALT_NAME_INFO);
4201 if (dataLen)
4203 const BYTE *ptr;
4205 for (ptr = pbEncoded + 1 + lenBytes; ret &&
4206 ptr - pbEncoded - 1 - lenBytes < dataLen; )
4208 DWORD size;
4210 ret = CRYPT_AsnDecodeAltNameEntry(ptr,
4211 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
4212 if (ret)
4214 DWORD nextLen;
4216 cEntry++;
4217 bytesNeeded += size;
4218 ret = CRYPT_GetLen(ptr,
4219 cbEncoded - (ptr - pbEncoded), &nextLen);
4220 if (ret)
4221 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
4225 if (ret)
4227 if (!pvStructInfo)
4228 *pcbStructInfo = bytesNeeded;
4229 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
4230 pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
4232 CERT_ALT_NAME_INFO *info;
4234 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4235 pvStructInfo = *(BYTE **)pvStructInfo;
4236 info = (CERT_ALT_NAME_INFO *)pvStructInfo;
4237 info->cAltEntry = 0;
4238 if (cEntry == 0)
4239 info->rgAltEntry = NULL;
4240 else
4242 DWORD size, i;
4243 BYTE *nextData;
4244 const BYTE *ptr;
4246 info->rgAltEntry =
4247 (CERT_ALT_NAME_ENTRY *)((BYTE *)pvStructInfo +
4248 sizeof(CERT_ALT_NAME_INFO));
4249 nextData = (BYTE *)info->rgAltEntry +
4250 cEntry * sizeof(CERT_ALT_NAME_ENTRY);
4251 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
4252 i < cEntry && ptr - pbEncoded - 1 - lenBytes <
4253 dataLen; i++)
4255 info->rgAltEntry[i].u.pwszURL =
4256 (LPWSTR)nextData;
4257 size = bytesNeeded;
4258 ret = CRYPT_AsnDecodeAltNameEntry(ptr,
4259 cbEncoded - (ptr - pbEncoded), dwFlags,
4260 &info->rgAltEntry[i], &size);
4261 if (ret)
4263 DWORD nextLen;
4265 info->cAltEntry++;
4266 nextData += size -
4267 sizeof(CERT_ALT_NAME_ENTRY);
4268 bytesNeeded -= size;
4269 ret = CRYPT_GetLen(ptr,
4270 cbEncoded - (ptr - pbEncoded), &nextLen);
4271 if (ret)
4272 ptr += nextLen + 1 +
4273 GET_LEN_BYTES(ptr[1]);
4281 else
4283 SetLastError(CRYPT_E_ASN1_BADTAG);
4284 ret = FALSE;
4287 __EXCEPT(page_fault)
4289 SetLastError(STATUS_ACCESS_VIOLATION);
4290 ret = FALSE;
4292 __ENDTRY
4293 return ret;
4296 struct PATH_LEN_CONSTRAINT
4298 BOOL fPathLenConstraint;
4299 DWORD dwPathLenConstraint;
4302 static BOOL WINAPI CRYPT_AsnDecodePathLenConstraint(DWORD dwCertEncodingType,
4303 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4304 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4306 BOOL ret = TRUE;
4308 if (cbEncoded)
4310 if (pbEncoded[0] == ASN_INTEGER)
4312 DWORD bytesNeeded = sizeof(struct PATH_LEN_CONSTRAINT);
4314 if (!pvStructInfo)
4315 *pcbStructInfo = bytesNeeded;
4316 else if (*pcbStructInfo < bytesNeeded)
4318 SetLastError(ERROR_MORE_DATA);
4319 *pcbStructInfo = bytesNeeded;
4320 ret = FALSE;
4322 else
4324 struct PATH_LEN_CONSTRAINT *constraint =
4325 (struct PATH_LEN_CONSTRAINT *)pvStructInfo;
4326 DWORD size = sizeof(constraint->dwPathLenConstraint);
4328 ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER,
4329 pbEncoded, cbEncoded, 0, NULL,
4330 &constraint->dwPathLenConstraint, &size);
4331 if (ret)
4332 constraint->fPathLenConstraint = TRUE;
4333 TRACE("got an int, dwPathLenConstraint is %ld\n",
4334 constraint->dwPathLenConstraint);
4337 else
4339 SetLastError(CRYPT_E_ASN1_CORRUPT);
4340 ret = FALSE;
4343 TRACE("returning %d (%08lx)\n", ret, GetLastError());
4344 return ret;
4347 static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints2(DWORD dwCertEncodingType,
4348 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4349 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4351 BOOL ret;
4353 __TRY
4355 struct AsnDecodeSequenceItem items[] = {
4356 { offsetof(CERT_BASIC_CONSTRAINTS2_INFO, fCA), CRYPT_AsnDecodeBool,
4357 sizeof(BOOL), TRUE, FALSE, 0, 0 },
4358 { offsetof(CERT_BASIC_CONSTRAINTS2_INFO, fPathLenConstraint),
4359 CRYPT_AsnDecodePathLenConstraint, sizeof(struct PATH_LEN_CONSTRAINT),
4360 TRUE, FALSE, 0, 0 },
4363 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
4364 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
4365 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
4367 __EXCEPT(page_fault)
4369 SetLastError(STATUS_ACCESS_VIOLATION);
4370 ret = FALSE;
4372 __ENDTRY
4373 return ret;
4376 #define RSA1_MAGIC 0x31415352
4378 struct DECODED_RSA_PUB_KEY
4380 DWORD pubexp;
4381 CRYPT_INTEGER_BLOB modulus;
4384 static BOOL WINAPI CRYPT_AsnDecodeRsaPubKey(DWORD dwCertEncodingType,
4385 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4386 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4388 BOOL ret;
4390 __TRY
4392 struct AsnDecodeSequenceItem items[] = {
4393 { offsetof(struct DECODED_RSA_PUB_KEY, modulus),
4394 CRYPT_AsnDecodeUnsignedIntegerInternal, sizeof(CRYPT_INTEGER_BLOB),
4395 FALSE, TRUE, offsetof(struct DECODED_RSA_PUB_KEY, modulus.pbData),
4396 0 },
4397 { offsetof(struct DECODED_RSA_PUB_KEY, pubexp),
4398 CRYPT_AsnDecodeInt, sizeof(DWORD), FALSE, FALSE, 0, 0 },
4400 struct DECODED_RSA_PUB_KEY *decodedKey = NULL;
4401 DWORD size = 0;
4403 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
4404 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded,
4405 CRYPT_DECODE_ALLOC_FLAG, NULL, &decodedKey, &size, NULL);
4406 if (ret)
4408 DWORD bytesNeeded = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
4409 decodedKey->modulus.cbData;
4411 if (!pvStructInfo)
4413 *pcbStructInfo = bytesNeeded;
4414 ret = TRUE;
4416 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4417 pvStructInfo, pcbStructInfo, bytesNeeded)))
4419 BLOBHEADER *hdr;
4420 RSAPUBKEY *rsaPubKey;
4422 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4423 pvStructInfo = *(BYTE **)pvStructInfo;
4424 hdr = (BLOBHEADER *)pvStructInfo;
4425 hdr->bType = PUBLICKEYBLOB;
4426 hdr->bVersion = CUR_BLOB_VERSION;
4427 hdr->reserved = 0;
4428 hdr->aiKeyAlg = CALG_RSA_KEYX;
4429 rsaPubKey = (RSAPUBKEY *)((BYTE *)pvStructInfo +
4430 sizeof(BLOBHEADER));
4431 rsaPubKey->magic = RSA1_MAGIC;
4432 rsaPubKey->pubexp = decodedKey->pubexp;
4433 rsaPubKey->bitlen = decodedKey->modulus.cbData * 8;
4434 memcpy((BYTE *)pvStructInfo + sizeof(BLOBHEADER) +
4435 sizeof(RSAPUBKEY), decodedKey->modulus.pbData,
4436 decodedKey->modulus.cbData);
4438 LocalFree(decodedKey);
4441 __EXCEPT(page_fault)
4443 SetLastError(STATUS_ACCESS_VIOLATION);
4444 ret = FALSE;
4446 __ENDTRY
4447 return ret;
4450 static BOOL WINAPI CRYPT_AsnDecodeOctetsInternal(DWORD dwCertEncodingType,
4451 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4452 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4454 BOOL ret;
4456 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
4457 pDecodePara, pvStructInfo, *pcbStructInfo);
4459 if (pbEncoded[0] == ASN_OCTETSTRING)
4461 DWORD bytesNeeded, dataLen;
4463 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4465 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4466 bytesNeeded = sizeof(CRYPT_DATA_BLOB);
4467 else
4468 bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB);
4469 if (!pvStructInfo)
4470 *pcbStructInfo = bytesNeeded;
4471 else if (*pcbStructInfo < bytesNeeded)
4473 SetLastError(ERROR_MORE_DATA);
4474 *pcbStructInfo = bytesNeeded;
4475 ret = FALSE;
4477 else
4479 CRYPT_DATA_BLOB *blob;
4480 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4482 blob = (CRYPT_DATA_BLOB *)pvStructInfo;
4483 blob->cbData = dataLen;
4484 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4485 blob->pbData = (BYTE *)pbEncoded + 1 + lenBytes;
4486 else
4488 assert(blob->pbData);
4489 if (blob->cbData)
4490 memcpy(blob->pbData, pbEncoded + 1 + lenBytes,
4491 blob->cbData);
4496 else
4498 SetLastError(CRYPT_E_ASN1_BADTAG);
4499 ret = FALSE;
4501 return ret;
4504 static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
4505 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4506 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4508 BOOL ret;
4510 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
4511 pDecodePara, pvStructInfo, *pcbStructInfo);
4513 __TRY
4515 DWORD bytesNeeded;
4517 if ((ret = CRYPT_AsnDecodeOctetsInternal(dwCertEncodingType,
4518 lpszStructType, pbEncoded, cbEncoded,
4519 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
4521 if (!pvStructInfo)
4522 *pcbStructInfo = bytesNeeded;
4523 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4524 pvStructInfo, pcbStructInfo, bytesNeeded)))
4526 CRYPT_DATA_BLOB *blob;
4528 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4529 pvStructInfo = *(BYTE **)pvStructInfo;
4530 blob = (CRYPT_DATA_BLOB *)pvStructInfo;
4531 blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_DATA_BLOB);
4532 ret = CRYPT_AsnDecodeOctetsInternal(dwCertEncodingType,
4533 lpszStructType, pbEncoded, cbEncoded,
4534 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
4535 &bytesNeeded);
4538 else
4540 SetLastError(CRYPT_E_ASN1_BADTAG);
4541 ret = FALSE;
4544 __EXCEPT(page_fault)
4546 SetLastError(STATUS_ACCESS_VIOLATION);
4547 ret = FALSE;
4549 __ENDTRY
4550 return ret;
4553 static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
4554 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4555 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4557 BOOL ret;
4559 TRACE("(%p, %ld, 0x%08lx, %p, %p, %ld)\n", pbEncoded, cbEncoded, dwFlags,
4560 pDecodePara, pvStructInfo, *pcbStructInfo);
4562 if (pbEncoded[0] == ASN_BITSTRING)
4564 DWORD bytesNeeded, dataLen;
4566 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4568 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4569 bytesNeeded = sizeof(CRYPT_BIT_BLOB);
4570 else
4571 bytesNeeded = dataLen - 1 + sizeof(CRYPT_BIT_BLOB);
4572 if (!pvStructInfo)
4573 *pcbStructInfo = bytesNeeded;
4574 else if (*pcbStructInfo < bytesNeeded)
4576 *pcbStructInfo = bytesNeeded;
4577 SetLastError(ERROR_MORE_DATA);
4578 ret = FALSE;
4580 else
4582 CRYPT_BIT_BLOB *blob;
4584 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
4585 blob->cbData = dataLen - 1;
4586 blob->cUnusedBits = *(pbEncoded + 1 +
4587 GET_LEN_BYTES(pbEncoded[1]));
4588 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4590 blob->pbData = (BYTE *)pbEncoded + 2 +
4591 GET_LEN_BYTES(pbEncoded[1]);
4593 else
4595 assert(blob->pbData);
4596 if (blob->cbData)
4598 BYTE mask = 0xff << blob->cUnusedBits;
4600 memcpy(blob->pbData, pbEncoded + 2 +
4601 GET_LEN_BYTES(pbEncoded[1]), blob->cbData);
4602 blob->pbData[blob->cbData - 1] &= mask;
4608 else
4610 SetLastError(CRYPT_E_ASN1_BADTAG);
4611 ret = FALSE;
4613 TRACE("returning %d (%08lx)\n", ret, GetLastError());
4614 return ret;
4617 static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType,
4618 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4619 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4621 BOOL ret;
4623 TRACE("(%p, %ld, 0x%08lx, %p, %p, %p)\n", pbEncoded, cbEncoded, dwFlags,
4624 pDecodePara, pvStructInfo, pcbStructInfo);
4626 __TRY
4628 DWORD bytesNeeded;
4630 if ((ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType,
4631 lpszStructType, pbEncoded, cbEncoded,
4632 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
4634 if (!pvStructInfo)
4635 *pcbStructInfo = bytesNeeded;
4636 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4637 pvStructInfo, pcbStructInfo, bytesNeeded)))
4639 CRYPT_BIT_BLOB *blob;
4641 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4642 pvStructInfo = *(BYTE **)pvStructInfo;
4643 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
4644 blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_BIT_BLOB);
4645 ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType,
4646 lpszStructType, pbEncoded, cbEncoded,
4647 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
4648 &bytesNeeded);
4652 __EXCEPT(page_fault)
4654 SetLastError(STATUS_ACCESS_VIOLATION);
4655 ret = FALSE;
4657 __ENDTRY
4658 TRACE("returning %d (%08lx)\n", ret, GetLastError());
4659 return ret;
4662 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
4663 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4664 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4666 BOOL ret;
4668 if (!pvStructInfo)
4670 *pcbStructInfo = sizeof(int);
4671 return TRUE;
4673 __TRY
4675 BYTE buf[sizeof(CRYPT_INTEGER_BLOB) + sizeof(int)];
4676 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
4677 DWORD size = sizeof(buf);
4679 blob->pbData = buf + sizeof(CRYPT_INTEGER_BLOB);
4680 ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
4681 X509_MULTI_BYTE_INTEGER, pbEncoded, cbEncoded, 0, NULL, &buf, &size);
4682 if (ret)
4684 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4685 pvStructInfo, pcbStructInfo, sizeof(int))))
4687 int val, i;
4689 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4690 pvStructInfo = *(BYTE **)pvStructInfo;
4691 if (blob->pbData[blob->cbData - 1] & 0x80)
4693 /* initialize to a negative value to sign-extend */
4694 val = -1;
4696 else
4697 val = 0;
4698 for (i = 0; i < blob->cbData; i++)
4700 val <<= 8;
4701 val |= blob->pbData[blob->cbData - i - 1];
4703 memcpy(pvStructInfo, &val, sizeof(int));
4706 else if (GetLastError() == ERROR_MORE_DATA)
4707 SetLastError(CRYPT_E_ASN1_LARGE);
4709 __EXCEPT(page_fault)
4711 SetLastError(STATUS_ACCESS_VIOLATION);
4712 ret = FALSE;
4714 __ENDTRY
4715 return ret;
4718 static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType,
4719 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4720 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4722 BOOL ret;
4724 if (pbEncoded[0] == ASN_INTEGER)
4726 DWORD bytesNeeded, dataLen;
4728 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4730 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4732 bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
4733 if (!pvStructInfo)
4734 *pcbStructInfo = bytesNeeded;
4735 else if (*pcbStructInfo < bytesNeeded)
4737 *pcbStructInfo = bytesNeeded;
4738 SetLastError(ERROR_MORE_DATA);
4739 ret = FALSE;
4741 else
4743 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
4745 blob->cbData = dataLen;
4746 assert(blob->pbData);
4747 if (blob->cbData)
4749 DWORD i;
4751 for (i = 0; i < blob->cbData; i++)
4753 blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
4754 dataLen - i - 1);
4760 else
4762 SetLastError(CRYPT_E_ASN1_BADTAG);
4763 ret = FALSE;
4765 return ret;
4768 static BOOL WINAPI CRYPT_AsnDecodeInteger(DWORD dwCertEncodingType,
4769 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4770 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4772 BOOL ret;
4774 __TRY
4776 DWORD bytesNeeded;
4778 if ((ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
4779 lpszStructType, pbEncoded, cbEncoded,
4780 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
4782 if (!pvStructInfo)
4783 *pcbStructInfo = bytesNeeded;
4784 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4785 pvStructInfo, pcbStructInfo, bytesNeeded)))
4787 CRYPT_INTEGER_BLOB *blob;
4789 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4790 pvStructInfo = *(BYTE **)pvStructInfo;
4791 blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
4792 blob->pbData = (BYTE *)pvStructInfo +
4793 sizeof(CRYPT_INTEGER_BLOB);
4794 ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
4795 lpszStructType, pbEncoded, cbEncoded,
4796 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pvStructInfo,
4797 &bytesNeeded);
4801 __EXCEPT(page_fault)
4803 SetLastError(STATUS_ACCESS_VIOLATION);
4804 ret = FALSE;
4806 __ENDTRY
4807 return ret;
4810 static BOOL WINAPI CRYPT_AsnDecodeUnsignedIntegerInternal(
4811 DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded,
4812 DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
4813 void *pvStructInfo, DWORD *pcbStructInfo)
4815 BOOL ret;
4817 if (pbEncoded[0] == ASN_INTEGER)
4819 DWORD bytesNeeded, dataLen;
4821 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4823 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4825 bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
4826 if (!pvStructInfo)
4827 *pcbStructInfo = bytesNeeded;
4828 else if (*pcbStructInfo < bytesNeeded)
4830 *pcbStructInfo = bytesNeeded;
4831 SetLastError(ERROR_MORE_DATA);
4832 ret = FALSE;
4834 else
4836 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
4838 blob->cbData = dataLen;
4839 assert(blob->pbData);
4840 /* remove leading zero byte if it exists */
4841 if (blob->cbData && *(pbEncoded + 1 + lenBytes) == 0)
4843 blob->cbData--;
4844 blob->pbData++;
4846 if (blob->cbData)
4848 DWORD i;
4850 for (i = 0; i < blob->cbData; i++)
4852 blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
4853 dataLen - i - 1);
4859 else
4861 SetLastError(CRYPT_E_ASN1_BADTAG);
4862 ret = FALSE;
4864 return ret;
4867 static BOOL WINAPI CRYPT_AsnDecodeUnsignedInteger(DWORD dwCertEncodingType,
4868 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4869 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4871 BOOL ret;
4873 __TRY
4875 DWORD bytesNeeded;
4877 if ((ret = CRYPT_AsnDecodeUnsignedIntegerInternal(dwCertEncodingType,
4878 lpszStructType, pbEncoded, cbEncoded,
4879 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
4881 if (!pvStructInfo)
4882 *pcbStructInfo = bytesNeeded;
4883 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4884 pvStructInfo, pcbStructInfo, bytesNeeded)))
4886 CRYPT_INTEGER_BLOB *blob;
4888 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4889 pvStructInfo = *(BYTE **)pvStructInfo;
4890 blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
4891 blob->pbData = (BYTE *)pvStructInfo +
4892 sizeof(CRYPT_INTEGER_BLOB);
4893 ret = CRYPT_AsnDecodeUnsignedIntegerInternal(dwCertEncodingType,
4894 lpszStructType, pbEncoded, cbEncoded,
4895 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pvStructInfo,
4896 &bytesNeeded);
4900 __EXCEPT(page_fault)
4902 SetLastError(STATUS_ACCESS_VIOLATION);
4903 ret = FALSE;
4905 __ENDTRY
4906 return ret;
4909 static BOOL WINAPI CRYPT_AsnDecodeEnumerated(DWORD dwCertEncodingType,
4910 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4911 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4913 BOOL ret;
4915 if (!pvStructInfo)
4917 *pcbStructInfo = sizeof(int);
4918 return TRUE;
4920 __TRY
4922 if (pbEncoded[0] == ASN_ENUMERATED)
4924 unsigned int val = 0, i;
4926 if (cbEncoded <= 1)
4928 SetLastError(CRYPT_E_ASN1_EOD);
4929 ret = FALSE;
4931 else if (pbEncoded[1] == 0)
4933 SetLastError(CRYPT_E_ASN1_CORRUPT);
4934 ret = FALSE;
4936 else
4938 /* A little strange looking, but we have to accept a sign byte:
4939 * 0xffffffff gets encoded as 0a 05 00 ff ff ff ff. Also,
4940 * assuming a small length is okay here, it has to be in short
4941 * form.
4943 if (pbEncoded[1] > sizeof(unsigned int) + 1)
4945 SetLastError(CRYPT_E_ASN1_LARGE);
4946 return FALSE;
4948 for (i = 0; i < pbEncoded[1]; i++)
4950 val <<= 8;
4951 val |= pbEncoded[2 + i];
4953 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4954 pvStructInfo, pcbStructInfo, sizeof(unsigned int))))
4956 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4957 pvStructInfo = *(BYTE **)pvStructInfo;
4958 memcpy(pvStructInfo, &val, sizeof(unsigned int));
4962 else
4964 SetLastError(CRYPT_E_ASN1_BADTAG);
4965 ret = FALSE;
4968 __EXCEPT(page_fault)
4970 SetLastError(STATUS_ACCESS_VIOLATION);
4971 ret = FALSE;
4973 __ENDTRY
4974 return ret;
4977 /* Modifies word, pbEncoded, and len, and magically sets a value ret to FALSE
4978 * if it fails.
4980 #define CRYPT_TIME_GET_DIGITS(pbEncoded, len, numDigits, word) \
4981 do { \
4982 BYTE i; \
4984 (word) = 0; \
4985 for (i = 0; (len) > 0 && i < (numDigits); i++, (len)--) \
4987 if (!isdigit(*(pbEncoded))) \
4989 SetLastError(CRYPT_E_ASN1_CORRUPT); \
4990 ret = FALSE; \
4992 else \
4994 (word) *= 10; \
4995 (word) += *(pbEncoded)++ - '0'; \
4998 } while (0)
5000 static BOOL CRYPT_AsnDecodeTimeZone(const BYTE *pbEncoded, DWORD len,
5001 SYSTEMTIME *sysTime)
5003 BOOL ret;
5005 __TRY
5007 ret = TRUE;
5008 if (len >= 3 && (*pbEncoded == '+' || *pbEncoded == '-'))
5010 WORD hours, minutes = 0;
5011 BYTE sign = *pbEncoded++;
5013 len--;
5014 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, hours);
5015 if (ret && hours >= 24)
5017 SetLastError(CRYPT_E_ASN1_CORRUPT);
5018 ret = FALSE;
5020 else if (len >= 2)
5022 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, minutes);
5023 if (ret && minutes >= 60)
5025 SetLastError(CRYPT_E_ASN1_CORRUPT);
5026 ret = FALSE;
5029 if (ret)
5031 if (sign == '+')
5033 sysTime->wHour += hours;
5034 sysTime->wMinute += minutes;
5036 else
5038 if (hours > sysTime->wHour)
5040 sysTime->wDay--;
5041 sysTime->wHour = 24 - (hours - sysTime->wHour);
5043 else
5044 sysTime->wHour -= hours;
5045 if (minutes > sysTime->wMinute)
5047 sysTime->wHour--;
5048 sysTime->wMinute = 60 - (minutes - sysTime->wMinute);
5050 else
5051 sysTime->wMinute -= minutes;
5056 __EXCEPT(page_fault)
5058 SetLastError(STATUS_ACCESS_VIOLATION);
5059 ret = FALSE;
5061 __ENDTRY
5062 return ret;
5065 #define MIN_ENCODED_TIME_LENGTH 10
5067 static BOOL WINAPI CRYPT_AsnDecodeUtcTime(DWORD dwCertEncodingType,
5068 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5069 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5071 BOOL ret;
5073 if (!pvStructInfo)
5075 *pcbStructInfo = sizeof(FILETIME);
5076 return TRUE;
5078 __TRY
5080 ret = TRUE;
5081 if (pbEncoded[0] == ASN_UTCTIME)
5083 if (cbEncoded <= 1)
5085 SetLastError(CRYPT_E_ASN1_EOD);
5086 ret = FALSE;
5088 else if (pbEncoded[1] > 0x7f)
5090 /* long-form date strings really can't be valid */
5091 SetLastError(CRYPT_E_ASN1_CORRUPT);
5092 ret = FALSE;
5094 else
5096 SYSTEMTIME sysTime = { 0 };
5097 BYTE len = pbEncoded[1];
5099 if (len < MIN_ENCODED_TIME_LENGTH)
5101 SetLastError(CRYPT_E_ASN1_CORRUPT);
5102 ret = FALSE;
5104 else
5106 pbEncoded += 2;
5107 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wYear);
5108 if (sysTime.wYear >= 50)
5109 sysTime.wYear += 1900;
5110 else
5111 sysTime.wYear += 2000;
5112 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
5113 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
5114 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
5115 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
5116 if (ret && len > 0)
5118 if (len >= 2 && isdigit(*pbEncoded) &&
5119 isdigit(*(pbEncoded + 1)))
5120 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
5121 sysTime.wSecond);
5122 else if (isdigit(*pbEncoded))
5123 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 1,
5124 sysTime.wSecond);
5125 if (ret)
5126 ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len,
5127 &sysTime);
5129 if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags,
5130 pDecodePara, pvStructInfo, pcbStructInfo,
5131 sizeof(FILETIME))))
5133 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
5134 pvStructInfo = *(BYTE **)pvStructInfo;
5135 ret = SystemTimeToFileTime(&sysTime,
5136 (FILETIME *)pvStructInfo);
5141 else
5143 SetLastError(CRYPT_E_ASN1_BADTAG);
5144 ret = FALSE;
5147 __EXCEPT(page_fault)
5149 SetLastError(STATUS_ACCESS_VIOLATION);
5150 ret = FALSE;
5152 __ENDTRY
5153 return ret;
5156 static BOOL WINAPI CRYPT_AsnDecodeGeneralizedTime(DWORD dwCertEncodingType,
5157 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5158 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5160 BOOL ret;
5162 if (!pvStructInfo)
5164 *pcbStructInfo = sizeof(FILETIME);
5165 return TRUE;
5167 __TRY
5169 ret = TRUE;
5170 if (pbEncoded[0] == ASN_GENERALTIME)
5172 if (cbEncoded <= 1)
5174 SetLastError(CRYPT_E_ASN1_EOD);
5175 ret = FALSE;
5177 else if (pbEncoded[1] > 0x7f)
5179 /* long-form date strings really can't be valid */
5180 SetLastError(CRYPT_E_ASN1_CORRUPT);
5181 ret = FALSE;
5183 else
5185 BYTE len = pbEncoded[1];
5187 if (len < MIN_ENCODED_TIME_LENGTH)
5189 SetLastError(CRYPT_E_ASN1_CORRUPT);
5190 ret = FALSE;
5192 else
5194 SYSTEMTIME sysTime = { 0 };
5196 pbEncoded += 2;
5197 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 4, sysTime.wYear);
5198 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
5199 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
5200 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
5201 if (ret && len > 0)
5203 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
5204 sysTime.wMinute);
5205 if (ret && len > 0)
5206 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
5207 sysTime.wSecond);
5208 if (ret && len > 0 && (*pbEncoded == '.' ||
5209 *pbEncoded == ','))
5211 BYTE digits;
5213 pbEncoded++;
5214 len--;
5215 /* workaround macro weirdness */
5216 digits = min(len, 3);
5217 CRYPT_TIME_GET_DIGITS(pbEncoded, len, digits,
5218 sysTime.wMilliseconds);
5220 if (ret)
5221 ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len,
5222 &sysTime);
5224 if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags,
5225 pDecodePara, pvStructInfo, pcbStructInfo,
5226 sizeof(FILETIME))))
5228 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
5229 pvStructInfo = *(BYTE **)pvStructInfo;
5230 ret = SystemTimeToFileTime(&sysTime,
5231 (FILETIME *)pvStructInfo);
5236 else
5238 SetLastError(CRYPT_E_ASN1_BADTAG);
5239 ret = FALSE;
5242 __EXCEPT(page_fault)
5244 SetLastError(STATUS_ACCESS_VIOLATION);
5245 ret = FALSE;
5247 __ENDTRY
5248 return ret;
5251 static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
5252 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5253 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5255 BOOL ret;
5257 __TRY
5259 if (pbEncoded[0] == ASN_UTCTIME)
5260 ret = CRYPT_AsnDecodeUtcTime(dwCertEncodingType, lpszStructType,
5261 pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
5262 pcbStructInfo);
5263 else if (pbEncoded[0] == ASN_GENERALTIME)
5264 ret = CRYPT_AsnDecodeGeneralizedTime(dwCertEncodingType,
5265 lpszStructType, pbEncoded, cbEncoded, dwFlags, pDecodePara,
5266 pvStructInfo, pcbStructInfo);
5267 else
5269 SetLastError(CRYPT_E_ASN1_BADTAG);
5270 ret = FALSE;
5273 __EXCEPT(page_fault)
5275 SetLastError(STATUS_ACCESS_VIOLATION);
5276 ret = FALSE;
5278 __ENDTRY
5279 return ret;
5282 static BOOL WINAPI CRYPT_AsnDecodeSequenceOfAny(DWORD dwCertEncodingType,
5283 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5284 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5286 BOOL ret = TRUE;
5288 __TRY
5290 if (pbEncoded[0] == ASN_SEQUENCEOF)
5292 DWORD bytesNeeded, dataLen, remainingLen, cValue;
5294 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
5296 BYTE lenBytes;
5297 const BYTE *ptr;
5299 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
5300 bytesNeeded = sizeof(CRYPT_SEQUENCE_OF_ANY);
5301 cValue = 0;
5302 ptr = pbEncoded + 1 + lenBytes;
5303 remainingLen = dataLen;
5304 while (ret && remainingLen)
5306 DWORD nextLen;
5308 ret = CRYPT_GetLen(ptr, remainingLen, &nextLen);
5309 if (ret)
5311 DWORD nextLenBytes = GET_LEN_BYTES(ptr[1]);
5313 remainingLen -= 1 + nextLenBytes + nextLen;
5314 ptr += 1 + nextLenBytes + nextLen;
5315 bytesNeeded += sizeof(CRYPT_DER_BLOB);
5316 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
5317 bytesNeeded += 1 + nextLenBytes + nextLen;
5318 cValue++;
5321 if (ret)
5323 CRYPT_SEQUENCE_OF_ANY *seq;
5324 BYTE *nextPtr;
5325 DWORD i;
5327 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
5328 pvStructInfo, pcbStructInfo, bytesNeeded)))
5330 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
5331 pvStructInfo = *(BYTE **)pvStructInfo;
5332 seq = (CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
5333 seq->cValue = cValue;
5334 seq->rgValue = (CRYPT_DER_BLOB *)((BYTE *)seq +
5335 sizeof(*seq));
5336 nextPtr = (BYTE *)seq->rgValue +
5337 cValue * sizeof(CRYPT_DER_BLOB);
5338 ptr = pbEncoded + 1 + lenBytes;
5339 remainingLen = dataLen;
5340 i = 0;
5341 while (ret && remainingLen)
5343 DWORD nextLen;
5345 ret = CRYPT_GetLen(ptr, remainingLen, &nextLen);
5346 if (ret)
5348 DWORD nextLenBytes = GET_LEN_BYTES(ptr[1]);
5350 seq->rgValue[i].cbData = 1 + nextLenBytes +
5351 nextLen;
5352 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
5353 seq->rgValue[i].pbData = (BYTE *)ptr;
5354 else
5356 seq->rgValue[i].pbData = nextPtr;
5357 memcpy(nextPtr, ptr, 1 + nextLenBytes +
5358 nextLen);
5359 nextPtr += 1 + nextLenBytes + nextLen;
5361 remainingLen -= 1 + nextLenBytes + nextLen;
5362 ptr += 1 + nextLenBytes + nextLen;
5363 i++;
5370 else
5372 SetLastError(CRYPT_E_ASN1_BADTAG);
5373 return FALSE;
5376 __EXCEPT(page_fault)
5378 SetLastError(STATUS_ACCESS_VIOLATION);
5379 ret = FALSE;
5381 __ENDTRY
5382 return ret;
5385 BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
5386 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5387 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5389 BOOL ret = FALSE;
5390 HMODULE lib = NULL;
5391 CryptDecodeObjectExFunc decodeFunc = NULL;
5393 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p, %p)\n",
5394 dwCertEncodingType, debugstr_a(lpszStructType), pbEncoded,
5395 cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
5397 if (!pvStructInfo && !pcbStructInfo)
5399 SetLastError(ERROR_INVALID_PARAMETER);
5400 return FALSE;
5402 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
5403 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
5405 SetLastError(ERROR_FILE_NOT_FOUND);
5406 return FALSE;
5408 if (!cbEncoded)
5410 SetLastError(CRYPT_E_ASN1_EOD);
5411 return FALSE;
5413 if (cbEncoded > MAX_ENCODED_LEN)
5415 SetLastError(CRYPT_E_ASN1_LARGE);
5416 return FALSE;
5419 SetLastError(NOERROR);
5420 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG && pvStructInfo)
5421 *(BYTE **)pvStructInfo = NULL;
5422 if (!HIWORD(lpszStructType))
5424 switch (LOWORD(lpszStructType))
5426 case (WORD)X509_CERT:
5427 decodeFunc = CRYPT_AsnDecodeCert;
5428 break;
5429 case (WORD)X509_CERT_TO_BE_SIGNED:
5430 decodeFunc = CRYPT_AsnDecodeCertInfo;
5431 break;
5432 case (WORD)X509_CERT_CRL_TO_BE_SIGNED:
5433 decodeFunc = CRYPT_AsnDecodeCRLInfo;
5434 break;
5435 case (WORD)X509_EXTENSIONS:
5436 decodeFunc = CRYPT_AsnDecodeExtensions;
5437 break;
5438 case (WORD)X509_NAME:
5439 decodeFunc = CRYPT_AsnDecodeName;
5440 break;
5441 case (WORD)X509_PUBLIC_KEY_INFO:
5442 decodeFunc = CRYPT_AsnDecodePubKeyInfo;
5443 break;
5444 case (WORD)X509_ALTERNATE_NAME:
5445 decodeFunc = CRYPT_AsnDecodeAltName;
5446 break;
5447 case (WORD)X509_BASIC_CONSTRAINTS2:
5448 decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
5449 break;
5450 case (WORD)RSA_CSP_PUBLICKEYBLOB:
5451 decodeFunc = CRYPT_AsnDecodeRsaPubKey;
5452 break;
5453 case (WORD)X509_OCTET_STRING:
5454 decodeFunc = CRYPT_AsnDecodeOctets;
5455 break;
5456 case (WORD)X509_BITS:
5457 case (WORD)X509_KEY_USAGE:
5458 decodeFunc = CRYPT_AsnDecodeBits;
5459 break;
5460 case (WORD)X509_INTEGER:
5461 decodeFunc = CRYPT_AsnDecodeInt;
5462 break;
5463 case (WORD)X509_MULTI_BYTE_INTEGER:
5464 decodeFunc = CRYPT_AsnDecodeInteger;
5465 break;
5466 case (WORD)X509_MULTI_BYTE_UINT:
5467 decodeFunc = CRYPT_AsnDecodeUnsignedInteger;
5468 break;
5469 case (WORD)X509_ENUMERATED:
5470 decodeFunc = CRYPT_AsnDecodeEnumerated;
5471 break;
5472 case (WORD)X509_CHOICE_OF_TIME:
5473 decodeFunc = CRYPT_AsnDecodeChoiceOfTime;
5474 break;
5475 case (WORD)X509_SEQUENCE_OF_ANY:
5476 decodeFunc = CRYPT_AsnDecodeSequenceOfAny;
5477 break;
5478 case (WORD)PKCS_UTC_TIME:
5479 decodeFunc = CRYPT_AsnDecodeUtcTime;
5480 break;
5481 default:
5482 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
5485 else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
5486 decodeFunc = CRYPT_AsnDecodeExtensions;
5487 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
5488 decodeFunc = CRYPT_AsnDecodeUtcTime;
5489 else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
5490 decodeFunc = CRYPT_AsnDecodeEnumerated;
5491 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
5492 decodeFunc = CRYPT_AsnDecodeBits;
5493 else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
5494 decodeFunc = CRYPT_AsnDecodeOctets;
5495 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
5496 decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
5497 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
5498 decodeFunc = CRYPT_AsnDecodeAltName;
5499 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
5500 decodeFunc = CRYPT_AsnDecodeAltName;
5501 else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION))
5502 decodeFunc = CRYPT_AsnDecodeAltName;
5503 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
5504 decodeFunc = CRYPT_AsnDecodeAltName;
5505 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
5506 decodeFunc = CRYPT_AsnDecodeAltName;
5507 else
5508 TRACE("OID %s not found or unimplemented, looking for DLL\n",
5509 debugstr_a(lpszStructType));
5510 if (!decodeFunc)
5511 decodeFunc = (CryptDecodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
5512 lpszStructType, CRYPT_OID_DECODE_OBJECT_EX_FUNC, &lib);
5513 if (decodeFunc)
5514 ret = decodeFunc(dwCertEncodingType, lpszStructType, pbEncoded,
5515 cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
5516 else
5517 SetLastError(ERROR_FILE_NOT_FOUND);
5518 if (lib)
5519 FreeLibrary(lib);
5520 return ret;
5523 BOOL WINAPI CryptExportPublicKeyInfo(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
5524 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
5526 return CryptExportPublicKeyInfoEx(hCryptProv, dwKeySpec, dwCertEncodingType,
5527 NULL, 0, NULL, pInfo, pcbInfo);
5530 static BOOL WINAPI CRYPT_ExportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv,
5531 DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
5532 DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
5534 BOOL ret;
5535 HCRYPTKEY key;
5537 TRACE("(%ld, %ld, %08lx, %s, %08lx, %p, %p, %p)\n", hCryptProv, dwKeySpec,
5538 dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo,
5539 pInfo, pcbInfo);
5541 if (!pszPublicKeyObjId)
5542 pszPublicKeyObjId = szOID_RSA_RSA;
5543 if ((ret = CryptGetUserKey(hCryptProv, dwKeySpec, &key)))
5545 DWORD keySize = 0;
5547 ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, NULL, &keySize);
5548 if (ret)
5550 LPBYTE pubKey = CryptMemAlloc(keySize);
5552 if (pubKey)
5554 ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, pubKey,
5555 &keySize);
5556 if (ret)
5558 DWORD encodedLen = 0;
5560 ret = CryptEncodeObject(dwCertEncodingType,
5561 RSA_CSP_PUBLICKEYBLOB, pubKey, NULL, &encodedLen);
5562 if (ret)
5564 DWORD sizeNeeded = sizeof(CERT_PUBLIC_KEY_INFO) +
5565 strlen(pszPublicKeyObjId) + 1 + encodedLen;
5567 if (!pInfo)
5568 *pcbInfo = sizeNeeded;
5569 else if (*pcbInfo < sizeNeeded)
5571 SetLastError(ERROR_MORE_DATA);
5572 *pcbInfo = sizeNeeded;
5573 ret = FALSE;
5575 else
5577 pInfo->Algorithm.pszObjId = (char *)pInfo +
5578 sizeof(CERT_PUBLIC_KEY_INFO);
5579 lstrcpyA(pInfo->Algorithm.pszObjId,
5580 pszPublicKeyObjId);
5581 pInfo->Algorithm.Parameters.cbData = 0;
5582 pInfo->Algorithm.Parameters.pbData = NULL;
5583 pInfo->PublicKey.pbData =
5584 (BYTE *)pInfo->Algorithm.pszObjId
5585 + lstrlenA(pInfo->Algorithm.pszObjId) + 1;
5586 pInfo->PublicKey.cbData = encodedLen;
5587 pInfo->PublicKey.cUnusedBits = 0;
5588 ret = CryptEncodeObject(dwCertEncodingType,
5589 RSA_CSP_PUBLICKEYBLOB, pubKey,
5590 pInfo->PublicKey.pbData, &pInfo->PublicKey.cbData);
5594 CryptMemFree(pubKey);
5596 else
5597 ret = FALSE;
5599 CryptDestroyKey(key);
5601 return ret;
5604 typedef BOOL (WINAPI *ExportPublicKeyInfoExFunc)(HCRYPTPROV hCryptProv,
5605 DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
5606 DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo);
5608 BOOL WINAPI CryptExportPublicKeyInfoEx(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
5609 DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId, DWORD dwFlags,
5610 void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
5612 BOOL ret;
5613 ExportPublicKeyInfoExFunc exportFunc = NULL;
5614 HMODULE lib = NULL;
5616 TRACE("(%ld, %ld, %08lx, %s, %08lx, %p, %p, %p)\n", hCryptProv, dwKeySpec,
5617 dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo,
5618 pInfo, pcbInfo);
5620 if (!hCryptProv)
5622 SetLastError(ERROR_INVALID_PARAMETER);
5623 return FALSE;
5626 if (pszPublicKeyObjId)
5627 exportFunc = CRYPT_GetFunc(dwCertEncodingType, pszPublicKeyObjId,
5628 CRYPT_OID_EXPORT_PUBLIC_KEY_INFO_FUNC, &lib);
5629 if (!exportFunc)
5630 exportFunc = CRYPT_ExportRsaPublicKeyInfoEx;
5631 ret = exportFunc(hCryptProv, dwKeySpec, dwCertEncodingType,
5632 pszPublicKeyObjId, dwFlags, pvAuxInfo, pInfo, pcbInfo);
5633 if (lib)
5634 FreeLibrary(lib);
5635 return ret;
5638 BOOL WINAPI CryptImportPublicKeyInfo(HCRYPTPROV hCryptProv,
5639 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
5641 return CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType, pInfo,
5642 0, 0, NULL, phKey);
5645 static BOOL WINAPI CRYPT_ImportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv,
5646 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
5647 DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
5649 BOOL ret;
5650 DWORD pubKeySize = 0;
5652 TRACE("(%ld, %ld, %p, %d, %08lx, %p, %p)\n", hCryptProv,
5653 dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
5655 ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
5656 pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, NULL, &pubKeySize);
5657 if (ret)
5659 LPBYTE pubKey = CryptMemAlloc(pubKeySize);
5661 if (pubKey)
5663 ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
5664 pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, pubKey,
5665 &pubKeySize);
5666 if (ret)
5667 ret = CryptImportKey(hCryptProv, pubKey, pubKeySize, 0, 0,
5668 phKey);
5669 CryptMemFree(pubKey);
5671 else
5672 ret = FALSE;
5674 return ret;
5677 typedef BOOL (WINAPI *ImportPublicKeyInfoExFunc)(HCRYPTPROV hCryptProv,
5678 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
5679 DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey);
5681 BOOL WINAPI CryptImportPublicKeyInfoEx(HCRYPTPROV hCryptProv,
5682 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
5683 DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
5685 BOOL ret;
5686 ImportPublicKeyInfoExFunc importFunc = NULL;
5687 HMODULE lib = NULL;
5689 TRACE("(%ld, %ld, %p, %d, %08lx, %p, %p)\n", hCryptProv,
5690 dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
5692 importFunc = CRYPT_GetFunc(dwCertEncodingType, pInfo->Algorithm.pszObjId,
5693 CRYPT_OID_IMPORT_PUBLIC_KEY_INFO_FUNC, &lib);
5694 if (!importFunc)
5695 importFunc = CRYPT_ImportRsaPublicKeyInfoEx;
5696 ret = importFunc(hCryptProv, dwCertEncodingType, pInfo, aiKeyAlg, dwFlags,
5697 pvAuxInfo, phKey);
5698 if (lib)
5699 FreeLibrary(lib);
5700 return ret;