Implement encoding/decoding RSA public keys.
[wine/wine64.git] / dlls / crypt32 / encode.c
blobaeb2bc82f3e1b9d1695f6eddd97cac2343f8ce68
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"
50 /* This is a bit arbitrary, but to set some limit: */
51 #define MAX_ENCODED_LEN 0x02000000
53 /* a few asn.1 tags we need */
54 #define ASN_BOOL (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x01)
55 #define ASN_BITSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x03)
56 #define ASN_OCTETSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x04)
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_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
119 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
120 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
122 static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
123 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
124 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
125 static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType,
126 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
127 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
128 /* Like CRYPT_AsnDecodeExtensions, except assumes rgExtension is set ahead of
129 * time, doesn't do memory allocation, and doesn't do exception handling.
130 * (This isn't intended to be the externally-called one.)
132 static BOOL WINAPI CRYPT_AsnDecodeExtensionsInternal(DWORD dwCertEncodingType,
133 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
134 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
135 static BOOL WINAPI CRYPT_AsnDecodeOid(const BYTE *pbEncoded, DWORD cbEncoded,
136 DWORD dwFlags, LPSTR pszObjId, DWORD *pcbObjId);
137 /* Assumes algo->Parameters.pbData is set ahead of time */
138 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
139 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
140 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
141 static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
142 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
143 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
144 static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
145 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
146 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
147 /* Like CRYPT_AsnDecodeBits, but assumes the CRYPT_INTEGER_BLOB's pbData
148 * member has been initialized, doesn't do exception handling, and doesn't do
149 * memory allocation.
151 static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
152 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
153 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
154 static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType,
155 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
156 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
157 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
158 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
159 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
160 /* Like CRYPT_AsnDecodeInteger, but assumes the CRYPT_INTEGER_BLOB's pbData
161 * member has been initialized, doesn't do exception handling, and doesn't do
162 * memory allocation.
164 static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType,
165 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
166 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
168 /* filter for page-fault exceptions */
169 static WINE_EXCEPTION_FILTER(page_fault)
171 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
172 return EXCEPTION_EXECUTE_HANDLER;
173 return EXCEPTION_CONTINUE_SEARCH;
176 static char *CRYPT_GetKeyName(DWORD dwEncodingType, LPCSTR pszFuncName,
177 LPCSTR pszOID)
179 static const char szEncodingTypeFmt[] =
180 "Software\\Microsoft\\Cryptography\\OID\\EncodingType %ld\\%s\\%s";
181 UINT len;
182 char numericOID[7]; /* enough for "#65535" */
183 const char *oid;
184 LPSTR szKey;
186 /* MSDN says the encoding type is a mask, but it isn't treated that way.
187 * (E.g., if dwEncodingType were 3, the key names "EncodingType 1" and
188 * "EncodingType 2" would be expected if it were a mask. Instead native
189 * stores values in "EncodingType 3".
191 if (!HIWORD(pszOID))
193 snprintf(numericOID, sizeof(numericOID), "#%d", LOWORD(pszOID));
194 oid = numericOID;
196 else
197 oid = pszOID;
199 /* This is enough: the lengths of the two string parameters are explicitly
200 * counted, and we need up to five additional characters for the encoding
201 * type. These are covered by the "%d", "%s", and "%s" characters in the
202 * format specifier that are removed by sprintf.
204 len = sizeof(szEncodingTypeFmt) + lstrlenA(pszFuncName) + lstrlenA(oid);
205 szKey = HeapAlloc(GetProcessHeap(), 0, len);
206 if (szKey)
207 sprintf(szKey, szEncodingTypeFmt, dwEncodingType, pszFuncName, oid);
208 return szKey;
211 BOOL WINAPI CryptRegisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
212 LPCSTR pszOID, LPCWSTR pwszDll, LPCSTR pszOverrideFuncName)
214 LONG r;
215 HKEY hKey;
216 LPSTR szKey;
218 TRACE("%lx %s %s %s %s\n", dwEncodingType, pszFuncName, pszOID,
219 debugstr_w(pwszDll), pszOverrideFuncName);
221 /* This only registers functions for encoding certs, not messages */
222 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
223 return TRUE;
225 /* Native does nothing pwszDll is NULL */
226 if (!pwszDll)
227 return TRUE;
229 /* I'm not matching MS bug for bug here, because I doubt any app depends on
230 * it:
231 * - native "succeeds" if pszFuncName is NULL, but the nonsensical entry
232 * it creates would never be used
233 * - native returns an HRESULT rather than a Win32 error if pszOID is NULL.
234 * Instead I disallow both of these with ERROR_INVALID_PARAMETER.
236 if (!pszFuncName || !pszOID)
238 SetLastError(ERROR_INVALID_PARAMETER);
239 return FALSE;
242 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
243 TRACE("Key name is %s\n", debugstr_a(szKey));
245 if (!szKey)
246 return FALSE;
248 r = RegCreateKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
249 HeapFree(GetProcessHeap(), 0, szKey);
250 if(r != ERROR_SUCCESS)
251 return FALSE;
253 /* write the values */
254 if (pszOverrideFuncName)
255 RegSetValueExA(hKey, "FuncName", 0, REG_SZ, (const BYTE*)pszOverrideFuncName,
256 lstrlenA(pszOverrideFuncName) + 1);
257 RegSetValueExW(hKey, szDllName, 0, REG_SZ, (const BYTE*) pwszDll,
258 (lstrlenW(pwszDll) + 1) * sizeof (WCHAR));
260 RegCloseKey(hKey);
261 return TRUE;
264 BOOL WINAPI CryptUnregisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
265 LPCSTR pszOID)
267 LPSTR szKey;
268 LONG rc;
270 TRACE("%lx %s %s\n", dwEncodingType, pszFuncName, pszOID);
272 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
273 return TRUE;
275 if (!pszFuncName || !pszOID)
277 SetLastError(ERROR_INVALID_PARAMETER);
278 return FALSE;
281 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
282 rc = RegDeleteKeyA(HKEY_LOCAL_MACHINE, szKey);
283 HeapFree(GetProcessHeap(), 0, szKey);
284 if (rc)
285 SetLastError(rc);
286 return rc ? FALSE : TRUE;
289 BOOL WINAPI CryptGetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
290 LPCSTR pszOID, LPCWSTR pwszValueName, DWORD *pdwValueType, BYTE *pbValueData,
291 DWORD *pcbValueData)
293 LPSTR szKey;
294 LONG rc;
295 HKEY hKey;
297 TRACE("%lx %s %s %s %p %p %p\n", dwEncodingType, debugstr_a(pszFuncName),
298 debugstr_a(pszOID), debugstr_w(pwszValueName), pdwValueType, pbValueData,
299 pcbValueData);
301 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
302 return TRUE;
304 if (!pszFuncName || !pszOID || !pwszValueName)
306 SetLastError(ERROR_INVALID_PARAMETER);
307 return FALSE;
310 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
311 rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
312 HeapFree(GetProcessHeap(), 0, szKey);
313 if (rc)
314 SetLastError(rc);
315 else
317 rc = RegQueryValueExW(hKey, pwszValueName, NULL, pdwValueType,
318 pbValueData, pcbValueData);
319 if (rc)
320 SetLastError(rc);
321 RegCloseKey(hKey);
323 return rc ? FALSE : TRUE;
326 BOOL WINAPI CryptSetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
327 LPCSTR pszOID, LPCWSTR pwszValueName, DWORD dwValueType,
328 const BYTE *pbValueData, DWORD cbValueData)
330 LPSTR szKey;
331 LONG rc;
332 HKEY hKey;
334 TRACE("%lx %s %s %s %ld %p %ld\n", dwEncodingType, debugstr_a(pszFuncName),
335 debugstr_a(pszOID), debugstr_w(pwszValueName), dwValueType, pbValueData,
336 cbValueData);
338 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
339 return TRUE;
341 if (!pszFuncName || !pszOID || !pwszValueName)
343 SetLastError(ERROR_INVALID_PARAMETER);
344 return FALSE;
347 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
348 rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
349 HeapFree(GetProcessHeap(), 0, szKey);
350 if (rc)
351 SetLastError(rc);
352 else
354 rc = RegSetValueExW(hKey, pwszValueName, 0, dwValueType, pbValueData,
355 cbValueData);
356 if (rc)
357 SetLastError(rc);
358 RegCloseKey(hKey);
360 return rc ? FALSE : TRUE;
363 /* Gets the registered function named szFuncName for dwCertEncodingType and
364 * lpszStructType, or NULL if one could not be found. *lib will be set to the
365 * handle of the module it's in, or NULL if no module was loaded. If the
366 * return value is NULL, *lib will also be NULL, to simplify error handling.
368 static void *CRYPT_GetFunc(DWORD dwCertEncodingType, LPCSTR lpszStructType,
369 LPCSTR szFuncName, HMODULE *lib)
371 void *ret = NULL;
372 char *szKey = CRYPT_GetKeyName(dwCertEncodingType, szFuncName,
373 lpszStructType);
374 const char *funcName;
375 long r;
376 HKEY hKey;
377 DWORD type, size = 0;
379 TRACE("(%08lx %s %s %p)\n", dwCertEncodingType, debugstr_a(lpszStructType),
380 debugstr_a(szFuncName), lib);
382 *lib = NULL;
383 r = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
384 HeapFree(GetProcessHeap(), 0, szKey);
385 if(r != ERROR_SUCCESS)
386 return NULL;
388 RegQueryValueExA(hKey, "FuncName", NULL, &type, NULL, &size);
389 if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
391 funcName = HeapAlloc(GetProcessHeap(), 0, size);
392 RegQueryValueExA(hKey, "FuncName", NULL, &type, (LPBYTE)funcName,
393 &size);
395 else
396 funcName = szFuncName;
397 RegQueryValueExW(hKey, szDllName, NULL, &type, NULL, &size);
398 if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
400 LPWSTR dllName = HeapAlloc(GetProcessHeap(), 0, size);
402 RegQueryValueExW(hKey, szDllName, NULL, &type, (LPBYTE)dllName,
403 &size);
404 *lib = LoadLibraryW(dllName);
405 if (*lib)
407 ret = GetProcAddress(*lib, funcName);
408 if (!ret)
410 /* Unload the library, the caller doesn't want to unload it
411 * when the return value is NULL.
413 FreeLibrary(*lib);
414 *lib = NULL;
417 HeapFree(GetProcessHeap(), 0, dllName);
419 if (funcName != szFuncName)
420 HeapFree(GetProcessHeap(), 0, (char *)funcName);
421 TRACE("returning %p\n", ret);
422 return ret;
425 BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
426 const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
428 BOOL ret = FALSE;
429 HMODULE lib;
430 CryptEncodeObjectFunc pCryptEncodeObject;
432 TRACE("(0x%08lx, %s, %p, %p, %p)\n", dwCertEncodingType,
433 debugstr_a(lpszStructType), pvStructInfo, pbEncoded,
434 pcbEncoded);
436 if (!pbEncoded && !pcbEncoded)
438 SetLastError(ERROR_INVALID_PARAMETER);
439 return FALSE;
442 /* Try registered DLL first.. */
443 pCryptEncodeObject =
444 (CryptEncodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
445 lpszStructType, "CryptEncodeObject", &lib);
446 if (pCryptEncodeObject)
448 ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
449 pvStructInfo, pbEncoded, pcbEncoded);
450 FreeLibrary(lib);
452 else
454 /* If not, use CryptEncodeObjectEx */
455 ret = CryptEncodeObjectEx(dwCertEncodingType, lpszStructType,
456 pvStructInfo, 0, NULL, pbEncoded, pcbEncoded);
458 return ret;
461 /* Helper function to check *pcbEncoded, set it to the required size, and
462 * optionally to allocate memory. Assumes pbEncoded is not NULL.
463 * If CRYPT_ENCODE_ALLOC_FLAG is set in dwFlags, *pbEncoded will be set to a
464 * pointer to the newly allocated memory.
466 static BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags,
467 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded,
468 DWORD bytesNeeded)
470 BOOL ret = TRUE;
472 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
474 if (pEncodePara && pEncodePara->pfnAlloc)
475 *(BYTE **)pbEncoded = pEncodePara->pfnAlloc(bytesNeeded);
476 else
477 *(BYTE **)pbEncoded = LocalAlloc(0, bytesNeeded);
478 if (!*(BYTE **)pbEncoded)
479 ret = FALSE;
480 else
481 *pcbEncoded = bytesNeeded;
483 else if (bytesNeeded > *pcbEncoded)
485 *pcbEncoded = bytesNeeded;
486 SetLastError(ERROR_MORE_DATA);
487 ret = FALSE;
489 return ret;
492 static BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded)
494 DWORD bytesNeeded, significantBytes = 0;
496 if (len <= 0x7f)
497 bytesNeeded = 1;
498 else
500 DWORD temp;
502 for (temp = len, significantBytes = sizeof(temp); !(temp & 0xff000000);
503 temp <<= 8, significantBytes--)
505 bytesNeeded = significantBytes + 1;
507 if (!pbEncoded)
509 *pcbEncoded = bytesNeeded;
510 return TRUE;
512 if (*pcbEncoded < bytesNeeded)
514 SetLastError(ERROR_MORE_DATA);
515 return FALSE;
517 if (len <= 0x7f)
518 *pbEncoded = (BYTE)len;
519 else
521 DWORD i;
523 *pbEncoded++ = significantBytes | 0x80;
524 for (i = 0; i < significantBytes; i++)
526 *(pbEncoded + significantBytes - i - 1) = (BYTE)(len & 0xff);
527 len >>= 8;
530 *pcbEncoded = bytesNeeded;
531 return TRUE;
534 struct AsnEncodeSequenceItem
536 const void *pvStructInfo;
537 CryptEncodeObjectExFunc encodeFunc;
538 DWORD size; /* used during encoding, not for your use */
541 static BOOL WINAPI CRYPT_AsnEncodeSequence(DWORD dwCertEncodingType,
542 struct AsnEncodeSequenceItem items[], DWORD cItem, DWORD dwFlags,
543 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
545 BOOL ret;
546 DWORD i, dataLen = 0;
548 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", items, cItem, dwFlags, pEncodePara,
549 pbEncoded, *pcbEncoded);
550 for (i = 0, ret = TRUE; ret && i < cItem; i++)
552 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
553 items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
554 NULL, &items[i].size);
555 dataLen += items[i].size;
557 if (ret)
559 DWORD lenBytes, bytesNeeded;
561 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
562 bytesNeeded = 1 + lenBytes + dataLen;
563 if (!pbEncoded)
564 *pcbEncoded = bytesNeeded;
565 else
567 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
568 pcbEncoded, bytesNeeded)))
570 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
571 pbEncoded = *(BYTE **)pbEncoded;
572 *pbEncoded++ = ASN_SEQUENCE;
573 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
574 pbEncoded += lenBytes;
575 for (i = 0; ret && i < cItem; i++)
577 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
578 items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG,
579 NULL, pbEncoded, &items[i].size);
580 pbEncoded += items[i].size;
585 TRACE("returning %d (%08lx)\n", ret, GetLastError());
586 return ret;
589 struct AsnConstructedItem
591 BYTE tag;
592 const void *pvStructInfo;
593 CryptEncodeObjectExFunc encodeFunc;
596 static BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType,
597 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
598 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
600 BOOL ret;
601 const struct AsnConstructedItem *item =
602 (const struct AsnConstructedItem *)pvStructInfo;
603 DWORD len;
605 if ((ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
606 item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &len)))
608 DWORD dataLen, bytesNeeded;
610 CRYPT_EncodeLen(len, NULL, &dataLen);
611 bytesNeeded = 1 + dataLen + len;
612 if (!pbEncoded)
613 *pcbEncoded = bytesNeeded;
614 else if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
615 pbEncoded, pcbEncoded, bytesNeeded)))
617 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
618 pbEncoded = *(BYTE **)pbEncoded;
619 *pbEncoded++ = ASN_CONTEXT | ASN_CONSTRUCTOR | item->tag;
620 CRYPT_EncodeLen(len, pbEncoded, &dataLen);
621 pbEncoded += dataLen;
622 ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
623 item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
624 pbEncoded, &len);
627 return ret;
630 static BOOL WINAPI CRYPT_AsnEncodeCertVersion(DWORD dwCertEncodingType,
631 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
632 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
634 const DWORD *ver = (const DWORD *)pvStructInfo;
635 BOOL ret;
637 /* CERT_V1 is not encoded */
638 if (*ver == CERT_V1)
640 *pcbEncoded = 0;
641 ret = TRUE;
643 else
645 struct AsnConstructedItem item = { 0, ver, CRYPT_AsnEncodeInt };
647 ret = CRYPT_AsnEncodeConstructed(dwCertEncodingType, X509_INTEGER,
648 &item, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
650 return ret;
653 static BOOL WINAPI CRYPT_CopyEncodedBlob(DWORD dwCertEncodingType,
654 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
655 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
657 const CRYPT_DER_BLOB *blob = (const CRYPT_DER_BLOB *)pvStructInfo;
658 BOOL ret;
660 if (!pbEncoded)
662 *pcbEncoded = blob->cbData;
663 ret = TRUE;
665 else if (*pcbEncoded < blob->cbData)
667 *pcbEncoded = blob->cbData;
668 SetLastError(ERROR_MORE_DATA);
669 ret = FALSE;
671 else
673 if (blob->cbData)
674 memcpy(pbEncoded, blob->pbData, blob->cbData);
675 *pcbEncoded = blob->cbData;
676 ret = TRUE;
678 return ret;
681 static BOOL WINAPI CRYPT_AsnEncodeValidity(DWORD dwCertEncodingType,
682 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
683 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
685 BOOL ret;
686 /* This has two filetimes in a row, a NotBefore and a NotAfter */
687 const FILETIME *timePtr = (const FILETIME *)pvStructInfo;
688 struct AsnEncodeSequenceItem items[] = {
689 { timePtr++, CRYPT_AsnEncodeChoiceOfTime, 0 },
690 { timePtr, CRYPT_AsnEncodeChoiceOfTime, 0 },
693 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
694 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
695 pcbEncoded);
696 return ret;
699 static BOOL WINAPI CRYPT_AsnEncodeAlgorithmId(
700 DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
701 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
702 DWORD *pcbEncoded)
704 const CRYPT_ALGORITHM_IDENTIFIER *algo =
705 (const CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
706 BOOL ret;
707 struct AsnEncodeSequenceItem items[] = {
708 { algo->pszObjId, CRYPT_AsnEncodeOid, 0 },
709 { &algo->Parameters, CRYPT_CopyEncodedBlob, 0 },
712 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
713 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
714 pcbEncoded);
715 return ret;
718 static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
719 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
720 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
722 BOOL ret;
724 __TRY
726 const CERT_PUBLIC_KEY_INFO *info =
727 (const CERT_PUBLIC_KEY_INFO *)pvStructInfo;
728 struct AsnEncodeSequenceItem items[] = {
729 { &info->Algorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
730 { &info->PublicKey, CRYPT_AsnEncodeBits, 0 },
733 TRACE("Encoding public key with OID %s\n",
734 debugstr_a(info->Algorithm.pszObjId));
735 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
736 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
737 pcbEncoded);
739 __EXCEPT(page_fault)
741 SetLastError(STATUS_ACCESS_VIOLATION);
742 ret = FALSE;
744 __ENDTRY
745 return ret;
748 static BOOL WINAPI CRYPT_AsnEncodeCert(DWORD dwCertEncodingType,
749 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
750 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
752 BOOL ret;
754 __TRY
756 const CERT_SIGNED_CONTENT_INFO *info =
757 (const CERT_SIGNED_CONTENT_INFO *)pvStructInfo;
758 struct AsnEncodeSequenceItem items[] = {
759 { &info->ToBeSigned, CRYPT_CopyEncodedBlob, 0 },
760 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
761 { &info->Signature, CRYPT_AsnEncodeBitsSwapBytes, 0 },
764 if (dwFlags & CRYPT_ENCODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG)
765 items[2].encodeFunc = CRYPT_AsnEncodeBits;
766 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
767 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
768 pcbEncoded);
770 __EXCEPT(page_fault)
772 SetLastError(STATUS_ACCESS_VIOLATION);
773 ret = FALSE;
775 __ENDTRY
776 return ret;
779 /* Like in Windows, this blithely ignores the validity of the passed-in
780 * CERT_INFO, and just encodes it as-is. The resulting encoded data may not
781 * decode properly, see CRYPT_AsnDecodeCertInfo.
783 static BOOL WINAPI CRYPT_AsnEncodeCertInfo(DWORD dwCertEncodingType,
784 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
785 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
787 BOOL ret;
789 __TRY
791 const CERT_INFO *info = (const CERT_INFO *)pvStructInfo;
792 struct AsnEncodeSequenceItem items[10] = {
793 { &info->dwVersion, CRYPT_AsnEncodeCertVersion, 0 },
794 { &info->SerialNumber, CRYPT_AsnEncodeInteger, 0 },
795 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
796 { &info->Issuer, CRYPT_CopyEncodedBlob, 0 },
797 { &info->NotBefore, CRYPT_AsnEncodeValidity, 0 },
798 { &info->Subject, CRYPT_CopyEncodedBlob, 0 },
799 { &info->SubjectPublicKeyInfo, CRYPT_AsnEncodePubKeyInfo, 0 },
800 { 0 }
802 struct AsnConstructedItem constructed[3] = { { 0 } };
803 DWORD cItem = 7, cConstructed = 0;
805 if (info->IssuerUniqueId.cbData)
807 constructed[cConstructed].tag = 1;
808 constructed[cConstructed].pvStructInfo = &info->IssuerUniqueId;
809 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
810 items[cItem].pvStructInfo = &constructed[cConstructed];
811 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
812 cConstructed++;
813 cItem++;
815 if (info->SubjectUniqueId.cbData)
817 constructed[cConstructed].tag = 2;
818 constructed[cConstructed].pvStructInfo = &info->SubjectUniqueId;
819 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
820 items[cItem].pvStructInfo = &constructed[cConstructed];
821 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
822 cConstructed++;
823 cItem++;
825 if (info->cExtension)
827 constructed[cConstructed].tag = 3;
828 constructed[cConstructed].pvStructInfo = &info->cExtension;
829 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeExtensions;
830 items[cItem].pvStructInfo = &constructed[cConstructed];
831 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
832 cConstructed++;
833 cItem++;
836 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
837 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
839 __EXCEPT(page_fault)
841 SetLastError(STATUS_ACCESS_VIOLATION);
842 ret = FALSE;
844 __ENDTRY
845 return ret;
848 static BOOL WINAPI CRYPT_AsnEncodeCRLEntry(const CRL_ENTRY *entry,
849 BYTE *pbEncoded, DWORD *pcbEncoded)
851 struct AsnEncodeSequenceItem items[3] = {
852 { &entry->SerialNumber, CRYPT_AsnEncodeInteger, 0 },
853 { &entry->RevocationDate, CRYPT_AsnEncodeChoiceOfTime, 0 },
854 { 0 }
856 DWORD cItem = 2;
857 BOOL ret;
859 TRACE("%p, %p, %p\n", entry, pbEncoded, pcbEncoded);
861 if (entry->cExtension)
863 items[cItem].pvStructInfo = &entry->cExtension;
864 items[cItem].encodeFunc = CRYPT_AsnEncodeExtensions;
865 cItem++;
868 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
869 pbEncoded, pcbEncoded);
871 TRACE("returning %d (%08lx)\n", ret, GetLastError());
872 return ret;
875 static BOOL WINAPI CRYPT_AsnEncodeCRLEntries(DWORD dwCertEncodingType,
876 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
877 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
879 DWORD cCRLEntry = *(const DWORD *)pvStructInfo;
880 DWORD bytesNeeded, dataLen, lenBytes, i;
881 const CRL_ENTRY *rgCRLEntry = *(const CRL_ENTRY **)
882 ((const BYTE *)pvStructInfo + sizeof(DWORD));
883 BOOL ret = TRUE;
885 for (i = 0, dataLen = 0; ret && i < cCRLEntry; i++)
887 DWORD size;
889 ret = CRYPT_AsnEncodeCRLEntry(&rgCRLEntry[i], NULL, &size);
890 if (ret)
891 dataLen += size;
893 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
894 bytesNeeded = 1 + lenBytes + dataLen;
895 if (!pbEncoded)
896 *pcbEncoded = bytesNeeded;
897 else
899 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
900 pcbEncoded, bytesNeeded)))
902 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
903 pbEncoded = *(BYTE **)pbEncoded;
904 *pbEncoded++ = ASN_SEQUENCEOF;
905 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
906 pbEncoded += lenBytes;
907 for (i = 0; i < cCRLEntry; i++)
909 DWORD size = dataLen;
911 ret = CRYPT_AsnEncodeCRLEntry(&rgCRLEntry[i], pbEncoded, &size);
912 pbEncoded += size;
913 dataLen -= size;
917 return ret;
920 static BOOL WINAPI CRYPT_AsnEncodeCRLVersion(DWORD dwCertEncodingType,
921 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
922 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
924 const DWORD *ver = (const DWORD *)pvStructInfo;
925 BOOL ret;
927 /* CRL_V1 is not encoded */
928 if (*ver == CRL_V1)
930 *pcbEncoded = 0;
931 ret = TRUE;
933 else
934 ret = CRYPT_AsnEncodeInt(dwCertEncodingType, X509_INTEGER, ver,
935 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
936 return ret;
939 /* Like in Windows, this blithely ignores the validity of the passed-in
940 * CRL_INFO, and just encodes it as-is. The resulting encoded data may not
941 * decode properly, see CRYPT_AsnDecodeCRLInfo.
943 static BOOL WINAPI CRYPT_AsnEncodeCRLInfo(DWORD dwCertEncodingType,
944 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
945 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
947 BOOL ret;
949 __TRY
951 const CRL_INFO *info = (const CRL_INFO *)pvStructInfo;
952 struct AsnEncodeSequenceItem items[7] = {
953 { &info->dwVersion, CRYPT_AsnEncodeCRLVersion, 0 },
954 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
955 { &info->Issuer, CRYPT_CopyEncodedBlob, 0 },
956 { &info->ThisUpdate, CRYPT_AsnEncodeChoiceOfTime, 0 },
957 { 0 }
959 struct AsnConstructedItem constructed = { 0 };
960 DWORD cItem = 4;
962 if (info->NextUpdate.dwLowDateTime || info->NextUpdate.dwHighDateTime)
964 items[cItem].pvStructInfo = &info->NextUpdate;
965 items[cItem].encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
966 cItem++;
968 if (info->cCRLEntry)
970 items[cItem].pvStructInfo = &info->cCRLEntry;
971 items[cItem].encodeFunc = CRYPT_AsnEncodeCRLEntries;
972 cItem++;
974 if (info->cExtension)
976 /* FIXME: is this really constructed? if so, is this the right tag?
978 constructed.tag = 3;
979 constructed.pvStructInfo = &info->cExtension;
980 constructed.encodeFunc = CRYPT_AsnEncodeExtensions;
981 items[cItem].pvStructInfo = &constructed;
982 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
983 cItem++;
986 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
987 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
989 __EXCEPT(page_fault)
991 SetLastError(STATUS_ACCESS_VIOLATION);
992 ret = FALSE;
994 __ENDTRY
995 return ret;
998 static BOOL CRYPT_AsnEncodeExtension(CERT_EXTENSION *ext, BYTE *pbEncoded,
999 DWORD *pcbEncoded)
1001 BOOL ret;
1002 struct AsnEncodeSequenceItem items[3] = {
1003 { ext->pszObjId, CRYPT_AsnEncodeOid, 0 },
1004 { NULL, NULL, 0 },
1005 { NULL, NULL, 0 },
1007 DWORD cItem = 1;
1009 TRACE("%p, %p, %ld\n", ext, pbEncoded, *pcbEncoded);
1011 if (ext->fCritical)
1013 items[cItem].pvStructInfo = &ext->fCritical;
1014 items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
1015 cItem++;
1017 items[cItem].pvStructInfo = &ext->Value;
1018 items[cItem].encodeFunc = CRYPT_AsnEncodeOctets;
1019 cItem++;
1021 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
1022 pbEncoded, pcbEncoded);
1023 TRACE("returning %d (%08lx)\n", ret, GetLastError());
1024 return ret;
1027 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
1028 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1029 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1031 BOOL ret;
1033 __TRY
1035 DWORD bytesNeeded, dataLen, lenBytes, i;
1036 const CERT_EXTENSIONS *exts = (const CERT_EXTENSIONS *)pvStructInfo;
1038 ret = TRUE;
1039 for (i = 0, dataLen = 0; ret && i < exts->cExtension; i++)
1041 DWORD size;
1043 ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i], NULL, &size);
1044 if (ret)
1045 dataLen += size;
1047 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1048 bytesNeeded = 1 + lenBytes + dataLen;
1049 if (!pbEncoded)
1050 *pcbEncoded = bytesNeeded;
1051 else
1053 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1054 pcbEncoded, bytesNeeded)))
1056 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1057 pbEncoded = *(BYTE **)pbEncoded;
1058 *pbEncoded++ = ASN_SEQUENCEOF;
1059 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1060 pbEncoded += lenBytes;
1061 for (i = 0; i < exts->cExtension; i++)
1063 DWORD size = dataLen;
1065 ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i],
1066 pbEncoded, &size);
1067 pbEncoded += size;
1068 dataLen -= size;
1073 __EXCEPT(page_fault)
1075 SetLastError(STATUS_ACCESS_VIOLATION);
1076 ret = FALSE;
1078 __ENDTRY
1079 return ret;
1082 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
1083 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1084 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1086 LPCSTR pszObjId = (LPCSTR)pvStructInfo;
1087 DWORD bytesNeeded = 0, lenBytes;
1088 BOOL ret = TRUE;
1089 int firstPos = 0;
1090 BYTE firstByte = 0;
1092 TRACE("%s\n", debugstr_a(pszObjId));
1094 if (pszObjId)
1096 const char *ptr;
1097 int val1, val2;
1099 if (sscanf(pszObjId, "%d.%d.%n", &val1, &val2, &firstPos) != 2)
1101 SetLastError(CRYPT_E_ASN1_ERROR);
1102 return FALSE;
1104 bytesNeeded++;
1105 firstByte = val1 * 40 + val2;
1106 ptr = pszObjId + firstPos;
1107 while (ret && *ptr)
1109 int pos;
1111 /* note I assume each component is at most 32-bits long in base 2 */
1112 if (sscanf(ptr, "%d%n", &val1, &pos) == 1)
1114 if (val1 >= 0x10000000)
1115 bytesNeeded += 5;
1116 else if (val1 >= 0x200000)
1117 bytesNeeded += 4;
1118 else if (val1 >= 0x4000)
1119 bytesNeeded += 3;
1120 else if (val1 >= 0x80)
1121 bytesNeeded += 2;
1122 else
1123 bytesNeeded += 1;
1124 ptr += pos;
1125 if (*ptr == '.')
1126 ptr++;
1128 else
1130 SetLastError(CRYPT_E_ASN1_ERROR);
1131 return FALSE;
1134 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1136 else
1137 lenBytes = 1;
1138 bytesNeeded += 1 + lenBytes;
1139 if (pbEncoded)
1141 if (*pcbEncoded < bytesNeeded)
1143 SetLastError(ERROR_MORE_DATA);
1144 ret = FALSE;
1146 else
1148 *pbEncoded++ = ASN_OBJECTIDENTIFIER;
1149 CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded, &lenBytes);
1150 pbEncoded += lenBytes;
1151 if (pszObjId)
1153 const char *ptr;
1154 int val, pos;
1156 *pbEncoded++ = firstByte;
1157 ptr = pszObjId + firstPos;
1158 while (ret && *ptr)
1160 sscanf(ptr, "%d%n", &val, &pos);
1162 unsigned char outBytes[5];
1163 int numBytes, i;
1165 if (val >= 0x10000000)
1166 numBytes = 5;
1167 else if (val >= 0x200000)
1168 numBytes = 4;
1169 else if (val >= 0x4000)
1170 numBytes = 3;
1171 else if (val >= 0x80)
1172 numBytes = 2;
1173 else
1174 numBytes = 1;
1175 for (i = numBytes; i > 0; i--)
1177 outBytes[i - 1] = val & 0x7f;
1178 val >>= 7;
1180 for (i = 0; i < numBytes - 1; i++)
1181 *pbEncoded++ = outBytes[i] | 0x80;
1182 *pbEncoded++ = outBytes[i];
1183 ptr += pos;
1184 if (*ptr == '.')
1185 ptr++;
1191 *pcbEncoded = bytesNeeded;
1192 return ret;
1195 static BOOL WINAPI CRYPT_AsnEncodeNameValue(DWORD dwCertEncodingType,
1196 CERT_NAME_VALUE *value, BYTE *pbEncoded, DWORD *pcbEncoded)
1198 BYTE tag;
1199 DWORD bytesNeeded, lenBytes, encodedLen;
1200 BOOL ret = TRUE;
1202 switch (value->dwValueType)
1204 case CERT_RDN_NUMERIC_STRING:
1205 tag = ASN_NUMERICSTRING;
1206 encodedLen = value->Value.cbData;
1207 break;
1208 case CERT_RDN_PRINTABLE_STRING:
1209 tag = ASN_PRINTABLESTRING;
1210 encodedLen = value->Value.cbData;
1211 break;
1212 case CERT_RDN_IA5_STRING:
1213 tag = ASN_IA5STRING;
1214 encodedLen = value->Value.cbData;
1215 break;
1216 case CERT_RDN_ANY_TYPE:
1217 /* explicitly disallowed */
1218 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1219 return FALSE;
1220 default:
1221 FIXME("String type %ld unimplemented\n", value->dwValueType);
1222 return FALSE;
1224 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1225 bytesNeeded = 1 + lenBytes + encodedLen;
1226 if (pbEncoded)
1228 if (*pcbEncoded < bytesNeeded)
1230 SetLastError(ERROR_MORE_DATA);
1231 ret = FALSE;
1233 else
1235 *pbEncoded++ = tag;
1236 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1237 pbEncoded += lenBytes;
1238 switch (value->dwValueType)
1240 case CERT_RDN_NUMERIC_STRING:
1241 case CERT_RDN_PRINTABLE_STRING:
1242 case CERT_RDN_IA5_STRING:
1243 memcpy(pbEncoded, value->Value.pbData, value->Value.cbData);
1247 *pcbEncoded = bytesNeeded;
1248 return ret;
1251 static BOOL WINAPI CRYPT_AsnEncodeRdnAttr(DWORD dwCertEncodingType,
1252 CERT_RDN_ATTR *attr, BYTE *pbEncoded, DWORD *pcbEncoded)
1254 DWORD bytesNeeded = 0, lenBytes, size;
1255 BOOL ret;
1257 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL, attr->pszObjId,
1258 0, NULL, NULL, &size);
1259 if (ret)
1261 bytesNeeded += size;
1262 /* hack: a CERT_RDN_ATTR is identical to a CERT_NAME_VALUE beginning
1263 * with dwValueType, so "cast" it to get its encoded size
1265 ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
1266 (CERT_NAME_VALUE *)&attr->dwValueType, NULL, &size);
1267 if (ret)
1269 bytesNeeded += size;
1270 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1271 bytesNeeded += 1 + lenBytes;
1272 if (pbEncoded)
1274 if (*pcbEncoded < bytesNeeded)
1276 SetLastError(ERROR_MORE_DATA);
1277 ret = FALSE;
1279 else
1281 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SEQUENCE;
1282 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1283 &lenBytes);
1284 pbEncoded += lenBytes;
1285 size = bytesNeeded - 1 - lenBytes;
1286 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
1287 attr->pszObjId, 0, NULL, pbEncoded, &size);
1288 if (ret)
1290 pbEncoded += size;
1291 size = bytesNeeded - 1 - lenBytes - size;
1292 ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
1293 (CERT_NAME_VALUE *)&attr->dwValueType, pbEncoded,
1294 &size);
1298 *pcbEncoded = bytesNeeded;
1301 return ret;
1304 static int BLOBComp(const void *l, const void *r)
1306 CRYPT_DER_BLOB *a = (CRYPT_DER_BLOB *)l, *b = (CRYPT_DER_BLOB *)r;
1307 int ret;
1309 if (!(ret = memcmp(a->pbData, b->pbData, min(a->cbData, b->cbData))))
1310 ret = a->cbData - b->cbData;
1311 return ret;
1314 /* This encodes as a SET OF, which in DER must be lexicographically sorted.
1316 static BOOL WINAPI CRYPT_AsnEncodeRdn(DWORD dwCertEncodingType, CERT_RDN *rdn,
1317 BYTE *pbEncoded, DWORD *pcbEncoded)
1319 BOOL ret;
1320 CRYPT_DER_BLOB *blobs = NULL;
1322 __TRY
1324 DWORD bytesNeeded = 0, lenBytes, i;
1326 ret = TRUE;
1327 if (rdn->cRDNAttr)
1329 blobs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1330 rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
1331 if (!blobs)
1332 ret = FALSE;
1334 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1336 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType, &rdn->rgRDNAttr[i],
1337 NULL, &blobs[i].cbData);
1338 if (ret)
1339 bytesNeeded += blobs[i].cbData;
1341 if (ret)
1343 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1344 bytesNeeded += 1 + lenBytes;
1345 if (pbEncoded)
1347 if (*pcbEncoded < bytesNeeded)
1349 SetLastError(ERROR_MORE_DATA);
1350 ret = FALSE;
1352 else
1354 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1356 blobs[i].pbData = HeapAlloc(GetProcessHeap(), 0,
1357 blobs[i].cbData);
1358 if (!blobs[i].pbData)
1359 ret = FALSE;
1360 else
1361 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType,
1362 &rdn->rgRDNAttr[i], blobs[i].pbData,
1363 &blobs[i].cbData);
1365 if (ret)
1367 qsort(blobs, rdn->cRDNAttr, sizeof(CRYPT_DER_BLOB),
1368 BLOBComp);
1369 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF;
1370 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1371 &lenBytes);
1372 pbEncoded += lenBytes;
1373 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1375 memcpy(pbEncoded, blobs[i].pbData, blobs[i].cbData);
1376 pbEncoded += blobs[i].cbData;
1381 *pcbEncoded = bytesNeeded;
1383 if (blobs)
1385 for (i = 0; i < rdn->cRDNAttr; i++)
1386 HeapFree(GetProcessHeap(), 0, blobs[i].pbData);
1389 __EXCEPT(page_fault)
1391 SetLastError(STATUS_ACCESS_VIOLATION);
1392 ret = FALSE;
1394 __ENDTRY
1395 HeapFree(GetProcessHeap(), 0, blobs);
1396 return ret;
1399 static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
1400 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1401 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1403 BOOL ret;
1405 __TRY
1407 const CERT_NAME_INFO *info = (const CERT_NAME_INFO *)pvStructInfo;
1408 DWORD bytesNeeded = 0, lenBytes, size, i;
1410 TRACE("encoding name with %ld RDNs\n", info->cRDN);
1411 ret = TRUE;
1412 for (i = 0; ret && i < info->cRDN; i++)
1414 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i], NULL,
1415 &size);
1416 if (ret)
1417 bytesNeeded += size;
1419 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1420 bytesNeeded += 1 + lenBytes;
1421 if (ret)
1423 if (!pbEncoded)
1424 *pcbEncoded = bytesNeeded;
1425 else
1427 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1428 pbEncoded, pcbEncoded, bytesNeeded)))
1430 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1431 pbEncoded = *(BYTE **)pbEncoded;
1432 *pbEncoded++ = ASN_SEQUENCEOF;
1433 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1434 &lenBytes);
1435 pbEncoded += lenBytes;
1436 for (i = 0; ret && i < info->cRDN; i++)
1438 size = bytesNeeded;
1439 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType,
1440 &info->rgRDN[i], pbEncoded, &size);
1441 if (ret)
1443 pbEncoded += size;
1444 bytesNeeded -= size;
1451 __EXCEPT(page_fault)
1453 SetLastError(STATUS_ACCESS_VIOLATION);
1454 ret = FALSE;
1456 __ENDTRY
1457 return ret;
1460 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
1461 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1462 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1464 BOOL val = *(const BOOL *)pvStructInfo, ret;
1466 TRACE("%d\n", val);
1468 if (!pbEncoded)
1470 *pcbEncoded = 3;
1471 ret = TRUE;
1473 else if (*pcbEncoded < 3)
1475 *pcbEncoded = 3;
1476 SetLastError(ERROR_MORE_DATA);
1477 ret = FALSE;
1479 else
1481 *pcbEncoded = 3;
1482 *pbEncoded++ = ASN_BOOL;
1483 *pbEncoded++ = 1;
1484 *pbEncoded++ = val ? 0xff : 0;
1485 ret = TRUE;
1487 TRACE("returning %d (%08lx)\n", ret, GetLastError());
1488 return ret;
1491 static BOOL CRYPT_AsnEncodeAltNameEntry(const CERT_ALT_NAME_ENTRY *entry,
1492 BYTE *pbEncoded, DWORD *pcbEncoded)
1494 BOOL ret;
1495 DWORD dataLen;
1497 ret = TRUE;
1498 switch (entry->dwAltNameChoice)
1500 case CERT_ALT_NAME_RFC822_NAME:
1501 case CERT_ALT_NAME_DNS_NAME:
1502 case CERT_ALT_NAME_URL:
1503 if (entry->u.pwszURL)
1505 DWORD i;
1507 /* Not + 1: don't encode the NULL-terminator */
1508 dataLen = lstrlenW(entry->u.pwszURL);
1509 for (i = 0; ret && i < dataLen; i++)
1511 if (entry->u.pwszURL[i] > 0x7f)
1513 SetLastError(CRYPT_E_INVALID_IA5_STRING);
1514 ret = FALSE;
1515 *pcbEncoded = i;
1519 else
1520 dataLen = 0;
1521 break;
1522 case CERT_ALT_NAME_IP_ADDRESS:
1523 dataLen = entry->u.IPAddress.cbData;
1524 break;
1525 case CERT_ALT_NAME_REGISTERED_ID:
1526 /* FIXME: encode OID */
1527 case CERT_ALT_NAME_OTHER_NAME:
1528 case CERT_ALT_NAME_DIRECTORY_NAME:
1529 FIXME("name type %ld unimplemented\n", entry->dwAltNameChoice);
1530 return FALSE;
1531 default:
1532 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1533 return FALSE;
1535 if (ret)
1537 DWORD bytesNeeded, lenBytes;
1539 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1540 bytesNeeded = 1 + dataLen + lenBytes;
1541 if (!pbEncoded)
1542 *pcbEncoded = bytesNeeded;
1543 else if (*pcbEncoded < bytesNeeded)
1545 SetLastError(ERROR_MORE_DATA);
1546 *pcbEncoded = bytesNeeded;
1547 ret = FALSE;
1549 else
1551 *pbEncoded++ = ASN_CONTEXT | (entry->dwAltNameChoice - 1);
1552 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1553 pbEncoded += lenBytes;
1554 switch (entry->dwAltNameChoice)
1556 case CERT_ALT_NAME_RFC822_NAME:
1557 case CERT_ALT_NAME_DNS_NAME:
1558 case CERT_ALT_NAME_URL:
1560 DWORD i;
1562 for (i = 0; i < dataLen; i++)
1563 *pbEncoded++ = (BYTE)entry->u.pwszURL[i];
1564 break;
1566 case CERT_ALT_NAME_IP_ADDRESS:
1567 memcpy(pbEncoded, entry->u.IPAddress.pbData, dataLen);
1568 break;
1570 if (ret)
1571 *pcbEncoded = bytesNeeded;
1574 return ret;
1577 static BOOL WINAPI CRYPT_AsnEncodeAltName(DWORD dwCertEncodingType,
1578 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1579 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1581 BOOL ret;
1583 __TRY
1585 const CERT_ALT_NAME_INFO *info =
1586 (const CERT_ALT_NAME_INFO *)pvStructInfo;
1588 DWORD bytesNeeded, dataLen, lenBytes, i;
1590 ret = TRUE;
1591 /* FIXME: should check that cAltEntry is not bigger than 0xff, since we
1592 * can't encode an erroneous entry index if it's bigger than this.
1594 for (i = 0, dataLen = 0; ret && i < info->cAltEntry; i++)
1596 DWORD len;
1598 ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i], NULL,
1599 &len);
1600 if (ret)
1601 dataLen += len;
1603 if (ret)
1605 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1606 bytesNeeded = 1 + lenBytes + dataLen;
1607 if (!pbEncoded)
1609 *pcbEncoded = bytesNeeded;
1610 ret = TRUE;
1612 else
1614 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1615 pbEncoded, pcbEncoded, bytesNeeded)))
1617 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1618 pbEncoded = *(BYTE **)pbEncoded;
1619 *pbEncoded++ = ASN_SEQUENCEOF;
1620 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1621 pbEncoded += lenBytes;
1622 for (i = 0; ret && i < info->cAltEntry; i++)
1624 DWORD len = dataLen;
1626 ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i],
1627 pbEncoded, &len);
1628 if (ret)
1630 pbEncoded += len;
1631 dataLen -= len;
1633 else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
1635 /* CRYPT_AsnEncodeAltNameEntry encoded the index of
1636 * the bad character, now set the index of the bad
1637 * entry
1639 *pcbEncoded |= (BYTE)i <<
1640 CERT_ALT_NAME_ENTRY_ERR_INDEX_SHIFT;
1647 __EXCEPT(page_fault)
1649 SetLastError(STATUS_ACCESS_VIOLATION);
1650 ret = FALSE;
1652 __ENDTRY
1653 return ret;
1656 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
1657 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1658 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1660 BOOL ret;
1662 __TRY
1664 const CERT_BASIC_CONSTRAINTS2_INFO *info =
1665 (const CERT_BASIC_CONSTRAINTS2_INFO *)pvStructInfo;
1666 struct AsnEncodeSequenceItem items[2] = { { 0 } };
1667 DWORD cItem = 0;
1669 if (info->fCA)
1671 items[cItem].pvStructInfo = &info->fCA;
1672 items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
1673 cItem++;
1675 if (info->fPathLenConstraint)
1677 items[cItem].pvStructInfo = &info->dwPathLenConstraint;
1678 items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
1679 cItem++;
1681 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
1682 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1684 __EXCEPT(page_fault)
1686 SetLastError(STATUS_ACCESS_VIOLATION);
1687 ret = FALSE;
1689 __ENDTRY
1690 return ret;
1693 static BOOL WINAPI CRYPT_AsnEncodeRsaPubKey(DWORD dwCertEncodingType,
1694 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1695 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1697 BOOL ret;
1699 __TRY
1701 const BLOBHEADER *hdr =
1702 (const BLOBHEADER *)pvStructInfo;
1704 if (hdr->bType != PUBLICKEYBLOB)
1706 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1707 ret = FALSE;
1709 else
1711 const RSAPUBKEY *rsaPubKey = (const RSAPUBKEY *)
1712 ((const BYTE *)pvStructInfo + sizeof(BLOBHEADER));
1713 CRYPT_INTEGER_BLOB blob = { rsaPubKey->bitlen / 8,
1714 (BYTE *)pvStructInfo + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) };
1715 struct AsnEncodeSequenceItem items[] = {
1716 { &blob, CRYPT_AsnEncodeInteger, 0 },
1717 { &rsaPubKey->pubexp, CRYPT_AsnEncodeInt, 0 },
1720 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
1721 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
1722 pcbEncoded);
1725 __EXCEPT(page_fault)
1727 SetLastError(STATUS_ACCESS_VIOLATION);
1728 ret = FALSE;
1730 __ENDTRY
1731 return ret;
1734 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
1735 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1736 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1738 BOOL ret;
1740 __TRY
1742 const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo;
1743 DWORD bytesNeeded, lenBytes;
1745 TRACE("(%ld, %p), %08lx, %p, %p, %ld\n", blob->cbData, blob->pbData,
1746 dwFlags, pEncodePara, pbEncoded, *pcbEncoded);
1748 CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
1749 bytesNeeded = 1 + lenBytes + blob->cbData;
1750 if (!pbEncoded)
1752 *pcbEncoded = bytesNeeded;
1753 ret = TRUE;
1755 else
1757 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1758 pcbEncoded, bytesNeeded)))
1760 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1761 pbEncoded = *(BYTE **)pbEncoded;
1762 *pbEncoded++ = ASN_OCTETSTRING;
1763 CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
1764 pbEncoded += lenBytes;
1765 if (blob->cbData)
1766 memcpy(pbEncoded, blob->pbData, blob->cbData);
1770 __EXCEPT(page_fault)
1772 SetLastError(STATUS_ACCESS_VIOLATION);
1773 ret = FALSE;
1775 __ENDTRY
1776 TRACE("returning %d (%08lx)\n", ret, GetLastError());
1777 return ret;
1780 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
1781 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1782 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1784 BOOL ret;
1786 __TRY
1788 const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
1789 DWORD bytesNeeded, lenBytes, dataBytes;
1790 BYTE unusedBits;
1792 /* yep, MS allows cUnusedBits to be >= 8 */
1793 if (!blob->cUnusedBits)
1795 dataBytes = blob->cbData;
1796 unusedBits = 0;
1798 else if (blob->cbData * 8 > blob->cUnusedBits)
1800 dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
1801 unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
1802 blob->cUnusedBits;
1804 else
1806 dataBytes = 0;
1807 unusedBits = 0;
1809 CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
1810 bytesNeeded = 1 + lenBytes + dataBytes + 1;
1811 if (!pbEncoded)
1813 *pcbEncoded = bytesNeeded;
1814 ret = TRUE;
1816 else
1818 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1819 pcbEncoded, bytesNeeded)))
1821 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1822 pbEncoded = *(BYTE **)pbEncoded;
1823 *pbEncoded++ = ASN_BITSTRING;
1824 CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
1825 pbEncoded += lenBytes;
1826 *pbEncoded++ = unusedBits;
1827 if (dataBytes)
1829 BYTE mask = 0xff << unusedBits;
1831 if (dataBytes > 1)
1833 memcpy(pbEncoded, blob->pbData, dataBytes - 1);
1834 pbEncoded += dataBytes - 1;
1836 *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
1841 __EXCEPT(page_fault)
1843 SetLastError(STATUS_ACCESS_VIOLATION);
1844 ret = FALSE;
1846 __ENDTRY
1847 return ret;
1850 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
1851 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1852 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1854 BOOL ret;
1856 __TRY
1858 const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
1859 CRYPT_BIT_BLOB newBlob = { blob->cbData, NULL, blob->cUnusedBits };
1861 ret = TRUE;
1862 if (newBlob.cbData)
1864 newBlob.pbData = HeapAlloc(GetProcessHeap(), 0, newBlob.cbData);
1865 if (newBlob.pbData)
1867 DWORD i;
1869 for (i = 0; i < newBlob.cbData; i++)
1870 newBlob.pbData[newBlob.cbData - i - 1] = blob->pbData[i];
1872 else
1873 ret = FALSE;
1875 if (ret)
1876 ret = CRYPT_AsnEncodeBits(dwCertEncodingType, lpszStructType,
1877 &newBlob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1878 HeapFree(GetProcessHeap(), 0, newBlob.pbData);
1880 __EXCEPT(page_fault)
1882 SetLastError(STATUS_ACCESS_VIOLATION);
1883 ret = FALSE;
1885 __ENDTRY
1886 return ret;
1889 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
1890 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1891 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1893 CRYPT_INTEGER_BLOB blob = { sizeof(INT), (BYTE *)pvStructInfo };
1895 return CRYPT_AsnEncodeInteger(dwCertEncodingType, X509_MULTI_BYTE_INTEGER,
1896 &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1899 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
1900 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1901 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1903 BOOL ret;
1905 __TRY
1907 DWORD significantBytes, lenBytes;
1908 BYTE padByte = 0, bytesNeeded;
1909 BOOL pad = FALSE;
1910 const CRYPT_INTEGER_BLOB *blob =
1911 (const CRYPT_INTEGER_BLOB *)pvStructInfo;
1913 significantBytes = blob->cbData;
1914 if (significantBytes)
1916 if (blob->pbData[significantBytes - 1] & 0x80)
1918 /* negative, lop off leading (little-endian) 0xffs */
1919 for (; significantBytes > 0 &&
1920 blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
1922 if (blob->pbData[significantBytes - 1] < 0x80)
1924 padByte = 0xff;
1925 pad = TRUE;
1928 else
1930 /* positive, lop off leading (little-endian) zeroes */
1931 for (; significantBytes > 0 &&
1932 !blob->pbData[significantBytes - 1]; significantBytes--)
1934 if (significantBytes == 0)
1935 significantBytes = 1;
1936 if (blob->pbData[significantBytes - 1] > 0x7f)
1938 padByte = 0;
1939 pad = TRUE;
1943 if (pad)
1944 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
1945 else
1946 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
1947 bytesNeeded = 1 + lenBytes + significantBytes;
1948 if (pad)
1949 bytesNeeded++;
1950 if (!pbEncoded)
1952 *pcbEncoded = bytesNeeded;
1953 ret = TRUE;
1955 else
1957 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1958 pcbEncoded, bytesNeeded)))
1960 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1961 pbEncoded = *(BYTE **)pbEncoded;
1962 *pbEncoded++ = ASN_INTEGER;
1963 if (pad)
1965 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
1966 pbEncoded += lenBytes;
1967 *pbEncoded++ = padByte;
1969 else
1971 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
1972 pbEncoded += lenBytes;
1974 for (; significantBytes > 0; significantBytes--)
1975 *(pbEncoded++) = blob->pbData[significantBytes - 1];
1979 __EXCEPT(page_fault)
1981 SetLastError(STATUS_ACCESS_VIOLATION);
1982 ret = FALSE;
1984 __ENDTRY
1985 return ret;
1988 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
1989 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1990 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1992 BOOL ret;
1994 __TRY
1996 DWORD significantBytes, lenBytes;
1997 BYTE bytesNeeded;
1998 BOOL pad = FALSE;
1999 const CRYPT_INTEGER_BLOB *blob =
2000 (const CRYPT_INTEGER_BLOB *)pvStructInfo;
2002 significantBytes = blob->cbData;
2003 if (significantBytes)
2005 /* positive, lop off leading (little-endian) zeroes */
2006 for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
2007 significantBytes--)
2009 if (significantBytes == 0)
2010 significantBytes = 1;
2011 if (blob->pbData[significantBytes - 1] > 0x7f)
2012 pad = TRUE;
2014 if (pad)
2015 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
2016 else
2017 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
2018 bytesNeeded = 1 + lenBytes + significantBytes;
2019 if (pad)
2020 bytesNeeded++;
2021 if (!pbEncoded)
2023 *pcbEncoded = bytesNeeded;
2024 ret = TRUE;
2026 else
2028 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2029 pcbEncoded, bytesNeeded)))
2031 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2032 pbEncoded = *(BYTE **)pbEncoded;
2033 *pbEncoded++ = ASN_INTEGER;
2034 if (pad)
2036 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
2037 pbEncoded += lenBytes;
2038 *pbEncoded++ = 0;
2040 else
2042 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
2043 pbEncoded += lenBytes;
2045 for (; significantBytes > 0; significantBytes--)
2046 *(pbEncoded++) = blob->pbData[significantBytes - 1];
2050 __EXCEPT(page_fault)
2052 SetLastError(STATUS_ACCESS_VIOLATION);
2053 ret = FALSE;
2055 __ENDTRY
2056 return ret;
2059 static BOOL WINAPI CRYPT_AsnEncodeEnumerated(DWORD dwCertEncodingType,
2060 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2061 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2063 CRYPT_INTEGER_BLOB blob;
2064 BOOL ret;
2066 /* Encode as an unsigned integer, then change the tag to enumerated */
2067 blob.cbData = sizeof(DWORD);
2068 blob.pbData = (BYTE *)pvStructInfo;
2069 ret = CRYPT_AsnEncodeUnsignedInteger(dwCertEncodingType,
2070 X509_MULTI_BYTE_UINT, &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2071 if (ret && pbEncoded)
2073 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2074 pbEncoded = *(BYTE **)pbEncoded;
2075 pbEncoded[0] = ASN_ENUMERATED;
2077 return ret;
2080 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
2081 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2082 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2084 BOOL ret;
2086 __TRY
2088 SYSTEMTIME sysTime;
2089 /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0. I use a
2090 * temporary buffer because the output buffer is not NULL-terminated.
2092 char buf[16];
2093 static const DWORD bytesNeeded = sizeof(buf) - 1;
2095 if (!pbEncoded)
2097 *pcbEncoded = bytesNeeded;
2098 ret = TRUE;
2100 else
2102 /* Sanity check the year, this is a two-digit year format */
2103 ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
2104 &sysTime);
2105 if (ret && (sysTime.wYear < 1950 || sysTime.wYear > 2050))
2107 SetLastError(CRYPT_E_BAD_ENCODE);
2108 ret = FALSE;
2110 if (ret)
2112 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2113 pbEncoded, pcbEncoded, bytesNeeded)))
2115 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2116 pbEncoded = *(BYTE **)pbEncoded;
2117 buf[0] = ASN_UTCTIME;
2118 buf[1] = bytesNeeded - 2;
2119 snprintf(buf + 2, sizeof(buf) - 2,
2120 "%02d%02d%02d%02d%02d%02dZ", sysTime.wYear >= 2000 ?
2121 sysTime.wYear - 2000 : sysTime.wYear - 1900,
2122 sysTime.wDay, sysTime.wMonth, sysTime.wHour,
2123 sysTime.wMinute, sysTime.wSecond);
2124 memcpy(pbEncoded, buf, bytesNeeded);
2129 __EXCEPT(page_fault)
2131 SetLastError(STATUS_ACCESS_VIOLATION);
2132 ret = FALSE;
2134 __ENDTRY
2135 return ret;
2138 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
2139 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2140 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2142 BOOL ret;
2144 __TRY
2146 SYSTEMTIME sysTime;
2147 /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0. I use a
2148 * temporary buffer because the output buffer is not NULL-terminated.
2150 char buf[18];
2151 static const DWORD bytesNeeded = sizeof(buf) - 1;
2153 if (!pbEncoded)
2155 *pcbEncoded = bytesNeeded;
2156 ret = TRUE;
2158 else
2160 ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
2161 &sysTime);
2162 if (ret)
2163 ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2164 pcbEncoded, bytesNeeded);
2165 if (ret)
2167 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2168 pbEncoded = *(BYTE **)pbEncoded;
2169 buf[0] = ASN_GENERALTIME;
2170 buf[1] = bytesNeeded - 2;
2171 snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
2172 sysTime.wYear, sysTime.wDay, sysTime.wMonth, sysTime.wHour,
2173 sysTime.wMinute, sysTime.wSecond);
2174 memcpy(pbEncoded, buf, bytesNeeded);
2178 __EXCEPT(page_fault)
2180 SetLastError(STATUS_ACCESS_VIOLATION);
2181 ret = FALSE;
2183 __ENDTRY
2184 return ret;
2187 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
2188 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2189 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2191 BOOL ret;
2193 __TRY
2195 SYSTEMTIME sysTime;
2197 /* Check the year, if it's in the UTCTime range call that encode func */
2198 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
2199 return FALSE;
2200 if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
2201 ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
2202 pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2203 else
2204 ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
2205 lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
2206 pcbEncoded);
2208 __EXCEPT(page_fault)
2210 SetLastError(STATUS_ACCESS_VIOLATION);
2211 ret = FALSE;
2213 __ENDTRY
2214 return ret;
2217 static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
2218 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2219 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2221 BOOL ret;
2223 __TRY
2225 DWORD bytesNeeded, dataLen, lenBytes, i;
2226 const CRYPT_SEQUENCE_OF_ANY *seq =
2227 (const CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
2229 for (i = 0, dataLen = 0; i < seq->cValue; i++)
2230 dataLen += seq->rgValue[i].cbData;
2231 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2232 bytesNeeded = 1 + lenBytes + dataLen;
2233 if (!pbEncoded)
2235 *pcbEncoded = bytesNeeded;
2236 ret = TRUE;
2238 else
2240 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2241 pcbEncoded, bytesNeeded)))
2243 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2244 pbEncoded = *(BYTE **)pbEncoded;
2245 *pbEncoded++ = ASN_SEQUENCEOF;
2246 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2247 pbEncoded += lenBytes;
2248 for (i = 0; i < seq->cValue; i++)
2250 memcpy(pbEncoded, seq->rgValue[i].pbData,
2251 seq->rgValue[i].cbData);
2252 pbEncoded += seq->rgValue[i].cbData;
2257 __EXCEPT(page_fault)
2259 SetLastError(STATUS_ACCESS_VIOLATION);
2260 ret = FALSE;
2262 __ENDTRY
2263 return ret;
2266 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
2267 const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
2268 void *pvEncoded, DWORD *pcbEncoded)
2270 BOOL ret = FALSE;
2271 HMODULE lib = NULL;
2272 CryptEncodeObjectExFunc encodeFunc = NULL;
2274 TRACE("(0x%08lx, %s, %p, 0x%08lx, %p, %p, %p)\n", dwCertEncodingType,
2275 debugstr_a(lpszStructType), pvStructInfo, dwFlags, pEncodePara,
2276 pvEncoded, pcbEncoded);
2278 if (!pvEncoded && !pcbEncoded)
2280 SetLastError(ERROR_INVALID_PARAMETER);
2281 return FALSE;
2283 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
2284 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
2286 SetLastError(ERROR_FILE_NOT_FOUND);
2287 return FALSE;
2290 SetLastError(NOERROR);
2291 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG && pvEncoded)
2292 *(BYTE **)pvEncoded = NULL;
2293 if (!HIWORD(lpszStructType))
2295 switch (LOWORD(lpszStructType))
2297 case (WORD)X509_CERT:
2298 encodeFunc = CRYPT_AsnEncodeCert;
2299 break;
2300 case (WORD)X509_CERT_TO_BE_SIGNED:
2301 encodeFunc = CRYPT_AsnEncodeCertInfo;
2302 break;
2303 case (WORD)X509_CERT_CRL_TO_BE_SIGNED:
2304 encodeFunc = CRYPT_AsnEncodeCRLInfo;
2305 break;
2306 case (WORD)X509_EXTENSIONS:
2307 encodeFunc = CRYPT_AsnEncodeExtensions;
2308 break;
2309 case (WORD)X509_NAME:
2310 encodeFunc = CRYPT_AsnEncodeName;
2311 break;
2312 case (WORD)X509_PUBLIC_KEY_INFO:
2313 encodeFunc = CRYPT_AsnEncodePubKeyInfo;
2314 break;
2315 case (WORD)X509_ALTERNATE_NAME:
2316 encodeFunc = CRYPT_AsnEncodeAltName;
2317 break;
2318 case (WORD)X509_BASIC_CONSTRAINTS2:
2319 encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
2320 break;
2321 case (WORD)RSA_CSP_PUBLICKEYBLOB:
2322 encodeFunc = CRYPT_AsnEncodeRsaPubKey;
2323 break;
2324 case (WORD)X509_OCTET_STRING:
2325 encodeFunc = CRYPT_AsnEncodeOctets;
2326 break;
2327 case (WORD)X509_BITS:
2328 case (WORD)X509_KEY_USAGE:
2329 encodeFunc = CRYPT_AsnEncodeBits;
2330 break;
2331 case (WORD)X509_INTEGER:
2332 encodeFunc = CRYPT_AsnEncodeInt;
2333 break;
2334 case (WORD)X509_MULTI_BYTE_INTEGER:
2335 encodeFunc = CRYPT_AsnEncodeInteger;
2336 break;
2337 case (WORD)X509_MULTI_BYTE_UINT:
2338 encodeFunc = CRYPT_AsnEncodeUnsignedInteger;
2339 break;
2340 case (WORD)X509_ENUMERATED:
2341 encodeFunc = CRYPT_AsnEncodeEnumerated;
2342 break;
2343 case (WORD)X509_CHOICE_OF_TIME:
2344 encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
2345 break;
2346 case (WORD)X509_SEQUENCE_OF_ANY:
2347 encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
2348 break;
2349 case (WORD)PKCS_UTC_TIME:
2350 encodeFunc = CRYPT_AsnEncodeUtcTime;
2351 break;
2352 default:
2353 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
2356 else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
2357 encodeFunc = CRYPT_AsnEncodeExtensions;
2358 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
2359 encodeFunc = CRYPT_AsnEncodeUtcTime;
2360 else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
2361 encodeFunc = CRYPT_AsnEncodeEnumerated;
2362 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
2363 encodeFunc = CRYPT_AsnEncodeBits;
2364 else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
2365 encodeFunc = CRYPT_AsnEncodeOctets;
2366 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
2367 encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
2368 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
2369 encodeFunc = CRYPT_AsnEncodeAltName;
2370 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
2371 encodeFunc = CRYPT_AsnEncodeAltName;
2372 else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION))
2373 encodeFunc = CRYPT_AsnEncodeAltName;
2374 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
2375 encodeFunc = CRYPT_AsnEncodeAltName;
2376 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
2377 encodeFunc = CRYPT_AsnEncodeAltName;
2378 else
2379 TRACE("OID %s not found or unimplemented, looking for DLL\n",
2380 debugstr_a(lpszStructType));
2381 if (!encodeFunc)
2382 encodeFunc = (CryptEncodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
2383 lpszStructType, "CryptEncodeObjectEx", &lib);
2384 if (encodeFunc)
2385 ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
2386 dwFlags, pEncodePara, pvEncoded, pcbEncoded);
2387 else
2388 SetLastError(ERROR_FILE_NOT_FOUND);
2389 if (lib)
2390 FreeLibrary(lib);
2391 return ret;
2394 BOOL WINAPI CryptDecodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
2395 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo,
2396 DWORD *pcbStructInfo)
2398 BOOL ret = FALSE;
2399 HMODULE lib;
2400 CryptDecodeObjectFunc pCryptDecodeObject;
2402 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p)\n", dwCertEncodingType,
2403 debugstr_a(lpszStructType), pbEncoded, cbEncoded, dwFlags,
2404 pvStructInfo, pcbStructInfo);
2406 if (!pvStructInfo && !pcbStructInfo)
2408 SetLastError(ERROR_INVALID_PARAMETER);
2409 return FALSE;
2412 /* Try registered DLL first.. */
2413 pCryptDecodeObject =
2414 (CryptDecodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
2415 lpszStructType, "CryptDecodeObject", &lib);
2416 if (pCryptDecodeObject)
2418 ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType,
2419 pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
2420 FreeLibrary(lib);
2422 else
2424 /* If not, use CryptDecodeObjectEx */
2425 ret = CryptDecodeObjectEx(dwCertEncodingType, lpszStructType, pbEncoded,
2426 cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo);
2428 return ret;
2431 /* Gets the number of length bytes from the given (leading) length byte */
2432 #define GET_LEN_BYTES(b) ((b) <= 0x7f ? 1 : 1 + ((b) & 0x7f))
2434 /* Helper function to get the encoded length of the data starting at pbEncoded,
2435 * where pbEncoded[0] is the tag. If the data are too short to contain a
2436 * length or if the length is too large for cbEncoded, sets an appropriate
2437 * error code and returns FALSE.
2439 static BOOL WINAPI CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded,
2440 DWORD *len)
2442 BOOL ret;
2444 if (cbEncoded <= 1)
2446 SetLastError(CRYPT_E_ASN1_CORRUPT);
2447 ret = FALSE;
2449 else if (pbEncoded[1] <= 0x7f)
2451 if (pbEncoded[1] + 1 > cbEncoded)
2453 SetLastError(CRYPT_E_ASN1_EOD);
2454 ret = FALSE;
2456 else
2458 *len = pbEncoded[1];
2459 ret = TRUE;
2462 else
2464 BYTE lenLen = GET_LEN_BYTES(pbEncoded[1]);
2466 if (lenLen > sizeof(DWORD) + 1)
2468 SetLastError(CRYPT_E_ASN1_LARGE);
2469 ret = FALSE;
2471 else if (lenLen + 2 > cbEncoded)
2473 SetLastError(CRYPT_E_ASN1_CORRUPT);
2474 ret = FALSE;
2476 else
2478 DWORD out = 0;
2480 pbEncoded += 2;
2481 while (--lenLen)
2483 out <<= 8;
2484 out |= *pbEncoded++;
2486 if (out + lenLen + 1 > cbEncoded)
2488 SetLastError(CRYPT_E_ASN1_EOD);
2489 ret = FALSE;
2491 else
2493 *len = out;
2494 ret = TRUE;
2498 return ret;
2501 /* Helper function to check *pcbStructInfo, set it to the required size, and
2502 * optionally to allocate memory. Assumes pvStructInfo is not NULL.
2503 * If CRYPT_DECODE_ALLOC_FLAG is set in dwFlags, *pvStructInfo will be set to a
2504 * pointer to the newly allocated memory.
2506 static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags,
2507 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo,
2508 DWORD bytesNeeded)
2510 BOOL ret = TRUE;
2512 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2514 if (pDecodePara && pDecodePara->pfnAlloc)
2515 *(BYTE **)pvStructInfo = pDecodePara->pfnAlloc(bytesNeeded);
2516 else
2517 *(BYTE **)pvStructInfo = LocalAlloc(0, bytesNeeded);
2518 if (!*(BYTE **)pvStructInfo)
2519 ret = FALSE;
2520 else
2521 *pcbStructInfo = bytesNeeded;
2523 else if (*pcbStructInfo < bytesNeeded)
2525 *pcbStructInfo = bytesNeeded;
2526 SetLastError(ERROR_MORE_DATA);
2527 ret = FALSE;
2529 return ret;
2532 /* A few of the members need explanation:
2533 * offset:
2534 * A sequence is decoded into a struct. The offset member is the
2535 * offset of this item within that struct.
2536 * decodeFunc:
2537 * The decoder function to use. If this is NULL, then the member isn't
2538 * decoded, but minSize space is reserved for it.
2539 * minSize:
2540 * The minimum amount of space occupied after decoding. You must set this.
2541 * hasPointer, pointerOffset, minSize:
2542 * If the item has dynamic data, set hasPointer to TRUE, pointerOffset to
2543 * the offset within the (outer) struct of the data pointer (or to the
2544 * first data pointer, if more than one exist).
2545 * size:
2546 * Used by CRYPT_AsnDecodeSequence, not for your use.
2548 struct AsnDecodeSequenceItem
2550 DWORD offset;
2551 CryptDecodeObjectExFunc decodeFunc;
2552 DWORD minSize;
2553 BOOL optional;
2554 BOOL hasPointer;
2555 DWORD pointerOffset;
2556 DWORD size;
2559 /* This decodes an arbitrary sequence into a contiguous block of memory
2560 * (basically, a struct.) Each element being decoded is described by a struct
2561 * AsnDecodeSequenceItem, see above.
2562 * startingPointer is an optional pointer to the first place where dynamic
2563 * data will be stored. If you know the starting offset, you may pass it
2564 * here. Otherwise, pass NULL, and one will be inferred from the items.
2565 * Each item decoder is never called with CRYPT_DECODE_ALLOC_FLAG set.
2566 * If any undecoded data are left over, fails with CRYPT_E_ASN1_CORRUPT.
2567 * FIXME: use to decode more sequences.
2569 static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType,
2570 struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
2571 DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
2572 void *pvStructInfo, DWORD *pcbStructInfo, void *startingPointer)
2574 BOOL ret;
2576 TRACE("%p, %ld, %p, %ld, %08lx, %p, %p, %ld\n", items, cItem, pbEncoded,
2577 cbEncoded, dwFlags, pDecodePara, pvStructInfo, *pcbStructInfo);
2579 if (pbEncoded[0] == ASN_SEQUENCE)
2581 DWORD dataLen;
2583 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2585 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2586 DWORD i, bytesNeeded = 0, minSize = 0;
2587 const BYTE *ptr;
2589 ptr = pbEncoded + 1 + lenBytes;
2590 for (i = 0; ret && i < cItem; i++)
2592 DWORD nextItemLen;
2594 minSize += items[i].minSize;
2595 if (cbEncoded - (ptr - pbEncoded) != 0)
2597 if ((ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
2598 &nextItemLen)))
2600 BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
2602 if (items[i].decodeFunc)
2604 ret = items[i].decodeFunc(dwCertEncodingType, NULL,
2605 ptr, 1 + nextItemLenBytes + nextItemLen,
2606 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL,
2607 &items[i].size);
2608 if (ret)
2610 /* Account for alignment padding */
2611 bytesNeeded += items[i].size;
2612 if (items[i].size % sizeof(DWORD))
2613 bytesNeeded += sizeof(DWORD) -
2614 items[i].size % sizeof(DWORD);
2615 ptr += 1 + nextItemLenBytes + nextItemLen;
2617 else if (items[i].optional &&
2618 GetLastError() == CRYPT_E_ASN1_BADTAG)
2620 bytesNeeded += items[i].minSize;
2621 SetLastError(NOERROR);
2622 ret = TRUE;
2625 else
2626 bytesNeeded += items[i].minSize;
2629 else if (items[i].optional)
2630 bytesNeeded += items[i].minSize;
2631 else
2633 SetLastError(CRYPT_E_ASN1_CORRUPT);
2634 ret = FALSE;
2637 if (ret)
2639 if (!pvStructInfo)
2640 *pcbStructInfo = bytesNeeded;
2641 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
2642 pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
2644 BYTE *nextData;
2646 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2647 pvStructInfo = *(BYTE **)pvStructInfo;
2648 if (startingPointer)
2649 nextData = (BYTE *)startingPointer;
2650 else
2651 nextData = (BYTE *)pvStructInfo + minSize;
2652 memset(pvStructInfo, 0, minSize);
2653 ptr = pbEncoded + 1 + lenBytes;
2654 for (i = 0; ret && i < cItem; i++)
2656 if (cbEncoded - (ptr - pbEncoded) != 0)
2658 DWORD nextItemLen;
2659 BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
2661 CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
2662 &nextItemLen);
2663 if (items[i].hasPointer)
2664 *(BYTE **)((BYTE *)pvStructInfo +
2665 items[i].pointerOffset) = nextData;
2666 if (items[i].decodeFunc)
2667 ret = items[i].decodeFunc(dwCertEncodingType,
2668 NULL, ptr, 1 + nextItemLenBytes + nextItemLen,
2669 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
2670 (BYTE *)pvStructInfo + items[i].offset,
2671 &items[i].size);
2672 else
2673 items[i].size = items[i].minSize;
2674 if (ret)
2676 if (items[i].hasPointer &&
2677 items[i].size > items[i].minSize)
2679 nextData += items[i].size -
2680 items[i].minSize;
2681 /* align nextData to DWORD boundaries */
2682 if (items[i].size % sizeof(DWORD))
2683 nextData += sizeof(DWORD) -
2684 items[i].size % sizeof(DWORD);
2686 ptr += 1 + nextItemLenBytes + nextItemLen;
2688 else if (items[i].optional &&
2689 GetLastError() == CRYPT_E_ASN1_BADTAG)
2691 SetLastError(NOERROR);
2692 ret = TRUE;
2695 else if (!items[i].optional)
2697 SetLastError(CRYPT_E_ASN1_CORRUPT);
2698 ret = FALSE;
2705 else
2707 SetLastError(CRYPT_E_ASN1_BADTAG);
2708 ret = FALSE;
2710 TRACE("returning %d (%08lx)\n", ret, GetLastError());
2711 return ret;
2714 /* Decodes a DER-encoded BLOB into a CRYPT_DER_BLOB struct pointed to by
2715 * pvStructInfo. The BLOB must be non-empty, otherwise the last error is set
2716 * to CRYPT_E_ASN1_CORRUPT.
2717 * Warning: assumes the CRYPT_DER_BLOB pointed to by pvStructInfo has pbData
2718 * set!
2720 static BOOL WINAPI CRYPT_AsnDecodeDerBlob(DWORD dwCertEncodingType,
2721 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2722 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2724 BOOL ret;
2725 DWORD dataLen;
2727 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2729 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2730 DWORD bytesNeeded = sizeof(CRYPT_DER_BLOB);
2732 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
2733 bytesNeeded += 1 + lenBytes + dataLen;
2735 if (!pvStructInfo)
2736 *pcbStructInfo = bytesNeeded;
2737 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
2738 pvStructInfo, pcbStructInfo, bytesNeeded)))
2740 CRYPT_DER_BLOB *blob = (CRYPT_DER_BLOB *)pvStructInfo;
2742 blob->cbData = 1 + lenBytes + dataLen;
2743 if (blob->cbData)
2745 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
2746 blob->pbData = (BYTE *)pbEncoded;
2747 else
2749 assert(blob->pbData);
2750 memcpy(blob->pbData, pbEncoded, blob->cbData);
2753 else
2755 SetLastError(CRYPT_E_ASN1_CORRUPT);
2756 ret = FALSE;
2760 return ret;
2763 /* Like CRYPT_AsnDecodeBitsInternal, but swaps the bytes */
2764 static BOOL WINAPI CRYPT_AsnDecodeBitsSwapBytes(DWORD dwCertEncodingType,
2765 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2766 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2768 BOOL ret;
2770 ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType, lpszStructType,
2771 pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
2772 if (ret && pvStructInfo)
2774 CRYPT_BIT_BLOB *blob = (CRYPT_BIT_BLOB *)pvStructInfo;
2775 DWORD i;
2776 BYTE temp;
2778 for (i = 0; i < blob->cbData / 2; i++)
2780 temp = blob->pbData[i];
2781 blob->pbData[i] = blob->pbData[blob->cbData - i - 1];
2782 blob->pbData[blob->cbData - i - 1] = temp;
2785 return ret;
2788 static BOOL WINAPI CRYPT_AsnDecodeCert(DWORD dwCertEncodingType,
2789 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2790 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2792 BOOL ret = TRUE;
2794 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
2795 pDecodePara, pvStructInfo, *pcbStructInfo);
2797 __TRY
2799 struct AsnDecodeSequenceItem items[] = {
2800 { offsetof(CERT_SIGNED_CONTENT_INFO, ToBeSigned),
2801 CRYPT_AsnDecodeDerBlob, sizeof(CRYPT_DER_BLOB), FALSE, TRUE,
2802 offsetof(CERT_SIGNED_CONTENT_INFO, ToBeSigned.pbData), 0 },
2803 { offsetof(CERT_SIGNED_CONTENT_INFO, SignatureAlgorithm),
2804 CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
2805 FALSE, TRUE, offsetof(CERT_SIGNED_CONTENT_INFO,
2806 SignatureAlgorithm.Parameters.pbData), 0 },
2807 { offsetof(CERT_SIGNED_CONTENT_INFO, Signature),
2808 CRYPT_AsnDecodeBitsSwapBytes, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE,
2809 offsetof(CERT_SIGNED_CONTENT_INFO, Signature.pbData), 0 },
2812 if (dwFlags & CRYPT_DECODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG)
2813 items[2].decodeFunc = CRYPT_AsnDecodeBitsInternal;
2814 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2815 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2816 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
2818 __EXCEPT(page_fault)
2820 SetLastError(STATUS_ACCESS_VIOLATION);
2821 ret = FALSE;
2823 __ENDTRY
2824 return ret;
2827 static BOOL WINAPI CRYPT_AsnDecodeCertVersion(DWORD dwCertEncodingType,
2828 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2829 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2831 BOOL ret;
2833 if (pbEncoded[0] == (ASN_CONTEXT | ASN_CONSTRUCTOR))
2835 DWORD dataLen;
2837 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2839 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2841 ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER,
2842 pbEncoded + 1 + lenBytes, dataLen, dwFlags, pDecodePara,
2843 pvStructInfo, pcbStructInfo);
2846 else
2848 SetLastError(CRYPT_E_ASN1_BADTAG);
2849 ret = FALSE;
2851 return ret;
2854 static BOOL WINAPI CRYPT_AsnDecodeValidity(DWORD dwCertEncodingType,
2855 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2856 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2858 BOOL ret;
2860 struct AsnDecodeSequenceItem items[] = {
2861 { offsetof(CERT_PRIVATE_KEY_VALIDITY, NotBefore),
2862 CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 },
2863 { offsetof(CERT_PRIVATE_KEY_VALIDITY, NotAfter),
2864 CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 },
2867 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2868 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2869 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
2870 return ret;
2873 static BOOL WINAPI CRYPT_AsnDecodeCertInfo(DWORD dwCertEncodingType,
2874 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2875 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2877 BOOL ret = TRUE;
2879 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
2880 pDecodePara, pvStructInfo, *pcbStructInfo);
2882 __TRY
2884 struct AsnDecodeSequenceItem items[] = {
2885 { offsetof(CERT_INFO, dwVersion), CRYPT_AsnDecodeCertVersion,
2886 sizeof(DWORD), TRUE, FALSE, 0, 0 },
2887 { offsetof(CERT_INFO, SerialNumber), CRYPT_AsnDecodeIntegerInternal,
2888 sizeof(CRYPT_INTEGER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
2889 SerialNumber.pbData), 0 },
2890 { offsetof(CERT_INFO, SignatureAlgorithm), CRYPT_AsnDecodeAlgorithmId,
2891 sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE, offsetof(CERT_INFO,
2892 SignatureAlgorithm.Parameters.pbData), 0 },
2893 { offsetof(CERT_INFO, Issuer), CRYPT_AsnDecodeDerBlob,
2894 sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
2895 Issuer.pbData) },
2896 { offsetof(CERT_INFO, NotBefore), CRYPT_AsnDecodeValidity,
2897 sizeof(CERT_PRIVATE_KEY_VALIDITY), FALSE, FALSE, 0 },
2898 { offsetof(CERT_INFO, Subject), CRYPT_AsnDecodeDerBlob,
2899 sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
2900 Subject.pbData) },
2901 { offsetof(CERT_INFO, SubjectPublicKeyInfo), CRYPT_AsnDecodePubKeyInfo,
2902 sizeof(CERT_PUBLIC_KEY_INFO), FALSE, TRUE, offsetof(CERT_INFO,
2903 SubjectPublicKeyInfo.Algorithm.Parameters.pbData), 0 },
2904 { offsetof(CERT_INFO, IssuerUniqueId), CRYPT_AsnDecodeBitsInternal,
2905 sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, offsetof(CERT_INFO,
2906 IssuerUniqueId.pbData), 0 },
2907 { offsetof(CERT_INFO, SubjectUniqueId), CRYPT_AsnDecodeBitsInternal,
2908 sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, offsetof(CERT_INFO,
2909 SubjectUniqueId.pbData), 0 },
2910 { offsetof(CERT_INFO, cExtension), CRYPT_AsnDecodeExtensionsInternal,
2911 sizeof(CERT_EXTENSIONS), TRUE, TRUE, offsetof(CERT_INFO,
2912 rgExtension), 0 },
2915 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2916 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2917 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
2919 __EXCEPT(page_fault)
2921 SetLastError(STATUS_ACCESS_VIOLATION);
2922 ret = FALSE;
2924 __ENDTRY
2925 return ret;
2928 static BOOL CRYPT_AsnDecodeCRLEntry(const BYTE *pbEncoded, DWORD cbEncoded,
2929 DWORD dwFlags, PCRL_ENTRY entry, DWORD *pcbEntry)
2931 BOOL ret;
2932 struct AsnDecodeSequenceItem items[] = {
2933 { offsetof(CRL_ENTRY, SerialNumber), CRYPT_AsnDecodeIntegerInternal,
2934 sizeof(CRYPT_INTEGER_BLOB), FALSE, TRUE, offsetof(CRL_ENTRY,
2935 SerialNumber.pbData), 0 },
2936 { offsetof(CRL_ENTRY, RevocationDate), CRYPT_AsnDecodeChoiceOfTime,
2937 sizeof(FILETIME), FALSE, FALSE, 0 },
2938 { offsetof(CRL_ENTRY, cExtension), CRYPT_AsnDecodeExtensionsInternal,
2939 sizeof(CERT_EXTENSIONS), TRUE, TRUE, offsetof(CRL_ENTRY,
2940 rgExtension), 0 },
2943 TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, entry,
2944 *pcbEntry);
2946 ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items,
2947 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2948 NULL, entry, pcbEntry, entry ? entry->SerialNumber.pbData : NULL);
2949 TRACE("Returning %d (%08lx)\n", ret, GetLastError());
2950 return ret;
2953 typedef struct _WINE_CRL_ENTRIES {
2954 DWORD cCRLEntry;
2955 PCRL_ENTRY rgCRLEntry;
2956 } WINE_CRL_ENTRIES, *PWINE_CRL_ENTRIES;
2958 /* Warning: assumes pvStructInfo is a WINE_CRL_ENTRIES whose rgCRLEntry has
2959 * been set prior to calling.
2961 static BOOL WINAPI CRYPT_AsnDecodeCRLEntries(DWORD dwCertEncodingType,
2962 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2963 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2965 BOOL ret;
2967 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
2968 pDecodePara, pvStructInfo, *pcbStructInfo);
2970 if (pbEncoded[0] == ASN_SEQUENCEOF)
2972 DWORD dataLen, bytesNeeded;
2974 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2976 DWORD cCRLEntry = 0;
2977 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2979 bytesNeeded = sizeof(WINE_CRL_ENTRIES);
2980 if (dataLen)
2982 const BYTE *ptr;
2983 DWORD size;
2985 for (ptr = pbEncoded + 1 + lenBytes; ret &&
2986 ptr - pbEncoded - 1 - lenBytes < dataLen; )
2988 size = 0;
2989 ret = CRYPT_AsnDecodeCRLEntry(ptr,
2990 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
2991 if (ret)
2993 DWORD nextLen;
2995 cCRLEntry++;
2996 bytesNeeded += size;
2997 ret = CRYPT_GetLen(ptr,
2998 cbEncoded - (ptr - pbEncoded), &nextLen);
2999 if (ret)
3000 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3004 if (ret)
3006 if (!pvStructInfo)
3007 *pcbStructInfo = bytesNeeded;
3008 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
3009 pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
3011 DWORD size, i;
3012 BYTE *nextData;
3013 const BYTE *ptr;
3014 PWINE_CRL_ENTRIES entries;
3016 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3017 pvStructInfo = *(BYTE **)pvStructInfo;
3018 *pcbStructInfo = bytesNeeded;
3019 entries = (PWINE_CRL_ENTRIES)pvStructInfo;
3020 entries->cCRLEntry = cCRLEntry;
3021 assert(entries->rgCRLEntry);
3022 nextData = (BYTE *)entries->rgCRLEntry +
3023 entries->cCRLEntry * sizeof(CRL_ENTRY);
3024 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
3025 i < cCRLEntry && ptr - pbEncoded - 1 - lenBytes <
3026 dataLen; i++)
3028 entries->rgCRLEntry[i].SerialNumber.pbData = nextData;
3029 size = bytesNeeded;
3030 ret = CRYPT_AsnDecodeCRLEntry(ptr,
3031 cbEncoded - (ptr - pbEncoded), dwFlags,
3032 &entries->rgCRLEntry[i], &size);
3033 if (ret)
3035 DWORD nextLen;
3037 bytesNeeded -= size;
3038 /* Increment nextData by the difference of the
3039 * minimum size and the actual size.
3041 if (size > sizeof(CRL_ENTRY))
3042 nextData += size - sizeof(CRL_ENTRY);
3043 ret = CRYPT_GetLen(ptr,
3044 cbEncoded - (ptr - pbEncoded), &nextLen);
3045 if (ret)
3046 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3053 else
3055 SetLastError(CRYPT_E_ASN1_BADTAG);
3056 ret = FALSE;
3058 TRACE("Returning %d (%08lx)\n", ret, GetLastError());
3059 return ret;
3062 static BOOL WINAPI CRYPT_AsnDecodeCRLInfo(DWORD dwCertEncodingType,
3063 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3064 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3066 BOOL ret = TRUE;
3068 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3069 pDecodePara, pvStructInfo, *pcbStructInfo);
3071 __TRY
3073 struct AsnDecodeSequenceItem items[] = {
3074 { offsetof(CRL_INFO, dwVersion), CRYPT_AsnDecodeCertVersion,
3075 sizeof(DWORD), TRUE, FALSE, 0, 0 },
3076 { offsetof(CRL_INFO, SignatureAlgorithm), CRYPT_AsnDecodeAlgorithmId,
3077 sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE, offsetof(CRL_INFO,
3078 SignatureAlgorithm.Parameters.pbData), 0 },
3079 { offsetof(CRL_INFO, Issuer), CRYPT_AsnDecodeDerBlob,
3080 sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CRL_INFO,
3081 Issuer.pbData) },
3082 { offsetof(CRL_INFO, ThisUpdate), CRYPT_AsnDecodeChoiceOfTime,
3083 sizeof(FILETIME), FALSE, FALSE, 0 },
3084 { offsetof(CRL_INFO, NextUpdate), CRYPT_AsnDecodeChoiceOfTime,
3085 sizeof(FILETIME), TRUE, FALSE, 0 },
3086 { offsetof(CRL_INFO, cCRLEntry), CRYPT_AsnDecodeCRLEntries,
3087 sizeof(WINE_CRL_ENTRIES), TRUE, TRUE, offsetof(CRL_INFO,
3088 rgCRLEntry), 0 },
3089 /* Note that the extensions are ignored by MS, so I'll ignore them too
3091 { offsetof(CRL_INFO, cExtension), NULL,
3092 sizeof(CERT_EXTENSIONS), TRUE, FALSE, 0 },
3095 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
3096 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3097 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
3099 __EXCEPT(page_fault)
3101 SetLastError(STATUS_ACCESS_VIOLATION);
3102 ret = FALSE;
3104 __ENDTRY
3106 TRACE("Returning %d (%08lx)\n", ret, GetLastError());
3107 return ret;
3110 /* Warning: assumes ext->Value.pbData is set ahead of time! */
3111 static BOOL CRYPT_AsnDecodeExtension(const BYTE *pbEncoded, DWORD cbEncoded,
3112 DWORD dwFlags, CERT_EXTENSION *ext, DWORD *pcbExt)
3114 BOOL ret = TRUE;
3116 if (pbEncoded[0] == ASN_SEQUENCE)
3118 DWORD dataLen, bytesNeeded;
3120 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3122 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]), oidLenBytes = 0;
3124 bytesNeeded = sizeof(CERT_EXTENSION);
3125 if (dataLen)
3127 const BYTE *ptr = pbEncoded + 1 + lenBytes;
3128 DWORD encodedOidLen, oidLen;
3130 CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
3131 &encodedOidLen);
3132 oidLenBytes = GET_LEN_BYTES(ptr[1]);
3133 ret = CRYPT_AsnDecodeOid(ptr, cbEncoded - (ptr - pbEncoded),
3134 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, &oidLen);
3135 if (ret)
3137 bytesNeeded += oidLen;
3138 ptr += 1 + encodedOidLen + oidLenBytes;
3139 if (*ptr == ASN_BOOL)
3140 ptr += 3;
3141 ret = CRYPT_AsnDecodeOctets(X509_ASN_ENCODING,
3142 X509_OCTET_STRING, ptr, cbEncoded - (ptr - pbEncoded),
3143 0, NULL, NULL, &dataLen);
3144 bytesNeeded += dataLen;
3145 if (ret)
3147 if (!ext)
3148 *pcbExt = bytesNeeded;
3149 else if (*pcbExt < bytesNeeded)
3151 SetLastError(ERROR_MORE_DATA);
3152 ret = FALSE;
3154 else
3156 ptr = pbEncoded + 2 + lenBytes + encodedOidLen +
3157 oidLenBytes;
3158 if (*ptr == ASN_BOOL)
3160 DWORD size = sizeof(BOOL);
3162 CRYPT_AsnDecodeBool(X509_ASN_ENCODING, NULL,
3163 ptr, cbEncoded - (ptr - pbEncoded),
3164 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
3165 &ext->fCritical, &size);
3166 ptr += 3;
3168 else
3169 ext->fCritical = FALSE;
3170 ret = CRYPT_AsnDecodeOctets(X509_ASN_ENCODING,
3171 X509_OCTET_STRING, ptr,
3172 cbEncoded - (ptr - pbEncoded),
3173 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
3174 &ext->Value, &dataLen);
3175 if (ret)
3177 ext->pszObjId = (LPSTR)ext->Value.pbData +
3178 ext->Value.cbData;
3179 ptr = pbEncoded + 1 + lenBytes;
3180 ret = CRYPT_AsnDecodeOid(ptr,
3181 cbEncoded - (ptr - pbEncoded),
3182 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG,
3183 ext->pszObjId, &oidLen);
3189 else
3191 SetLastError(CRYPT_E_ASN1_EOD);
3192 ret = FALSE;
3196 else
3198 SetLastError(CRYPT_E_ASN1_BADTAG);
3199 ret = FALSE;
3201 return ret;
3204 static BOOL WINAPI CRYPT_AsnDecodeExtensionsInternal(DWORD dwCertEncodingType,
3205 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3206 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3208 BOOL ret = TRUE;
3210 if (pbEncoded[0] == ASN_SEQUENCEOF)
3212 DWORD dataLen, bytesNeeded;
3214 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3216 DWORD cExtension = 0;
3217 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3219 bytesNeeded = sizeof(CERT_EXTENSIONS);
3220 if (dataLen)
3222 const BYTE *ptr;
3223 DWORD size;
3225 for (ptr = pbEncoded + 1 + lenBytes; ret &&
3226 ptr - pbEncoded - 1 - lenBytes < dataLen; )
3228 ret = CRYPT_AsnDecodeExtension(ptr,
3229 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
3230 if (ret)
3232 DWORD nextLen;
3234 cExtension++;
3235 bytesNeeded += size;
3236 ret = CRYPT_GetLen(ptr,
3237 cbEncoded - (ptr - pbEncoded), &nextLen);
3238 if (ret)
3239 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3243 if (ret)
3245 if (!pvStructInfo)
3246 *pcbStructInfo = bytesNeeded;
3247 else if (*pcbStructInfo < bytesNeeded)
3249 SetLastError(ERROR_MORE_DATA);
3250 *pcbStructInfo = bytesNeeded;
3251 ret = FALSE;
3253 else
3255 DWORD size, i;
3256 BYTE *nextData;
3257 const BYTE *ptr;
3258 CERT_EXTENSIONS *exts;
3260 *pcbStructInfo = bytesNeeded;
3261 exts = (CERT_EXTENSIONS *)pvStructInfo;
3262 exts->cExtension = cExtension;
3263 assert(exts->rgExtension);
3264 nextData = (BYTE *)exts->rgExtension +
3265 exts->cExtension * sizeof(CERT_EXTENSION);
3266 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
3267 i < cExtension && ptr - pbEncoded - 1 - lenBytes <
3268 dataLen; i++)
3270 exts->rgExtension[i].Value.pbData = nextData;
3271 size = bytesNeeded;
3272 ret = CRYPT_AsnDecodeExtension(ptr,
3273 cbEncoded - (ptr - pbEncoded), dwFlags,
3274 &exts->rgExtension[i], &size);
3275 if (ret)
3277 DWORD nextLen;
3279 bytesNeeded -= size;
3280 /* If dwFlags & CRYPT_DECODE_NOCOPY_FLAG, the
3281 * data may not have been copied.
3283 if (exts->rgExtension[i].Value.pbData ==
3284 nextData)
3285 nextData +=
3286 exts->rgExtension[i].Value.cbData;
3287 /* Ugly: the OID, if copied, is stored in
3288 * memory after the value, so increment by its
3289 * string length if it's set and points here.
3291 if ((const BYTE *)exts->rgExtension[i].pszObjId
3292 == nextData)
3293 nextData += strlen(
3294 exts->rgExtension[i].pszObjId) + 1;
3295 ret = CRYPT_GetLen(ptr,
3296 cbEncoded - (ptr - pbEncoded), &nextLen);
3297 if (ret)
3298 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3305 else
3307 SetLastError(CRYPT_E_ASN1_BADTAG);
3308 ret = FALSE;
3310 return ret;
3313 static BOOL WINAPI CRYPT_AsnDecodeExtensions(DWORD dwCertEncodingType,
3314 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3315 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3317 BOOL ret = TRUE;
3319 __TRY
3321 ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType,
3322 lpszStructType, pbEncoded, cbEncoded,
3323 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, pcbStructInfo);
3324 if (ret && pvStructInfo)
3326 ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
3327 pcbStructInfo, *pcbStructInfo);
3328 if (ret)
3330 CERT_EXTENSIONS *exts;
3332 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3333 pvStructInfo = *(BYTE **)pvStructInfo;
3334 exts = (CERT_EXTENSIONS *)pvStructInfo;
3335 exts->rgExtension = (CERT_EXTENSION *)((BYTE *)exts +
3336 sizeof(CERT_EXTENSIONS));
3337 ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType,
3338 lpszStructType, pbEncoded, cbEncoded,
3339 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
3340 pcbStructInfo);
3344 __EXCEPT(page_fault)
3346 SetLastError(STATUS_ACCESS_VIOLATION);
3347 ret = FALSE;
3349 __ENDTRY
3350 return ret;
3353 /* FIXME: honor the CRYPT_DECODE_SHARE_OID_STRING_FLAG. */
3354 static BOOL WINAPI CRYPT_AsnDecodeOid(const BYTE *pbEncoded, DWORD cbEncoded,
3355 DWORD dwFlags, LPSTR pszObjId, DWORD *pcbObjId)
3357 BOOL ret = TRUE;
3359 __TRY
3361 if (pbEncoded[0] == ASN_OBJECTIDENTIFIER)
3363 DWORD dataLen;
3365 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3367 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3368 DWORD bytesNeeded;
3370 if (dataLen)
3372 /* The largest possible string for the first two components
3373 * is 2.175 (= 2 * 40 + 175 = 255), so this is big enough.
3375 char firstTwo[6];
3376 const BYTE *ptr;
3378 snprintf(firstTwo, sizeof(firstTwo), "%d.%d",
3379 pbEncoded[1 + lenBytes] / 40,
3380 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40)
3381 * 40);
3382 bytesNeeded = strlen(firstTwo) + 1;
3383 for (ptr = pbEncoded + 2 + lenBytes; ret &&
3384 ptr - pbEncoded - 1 - lenBytes < dataLen; )
3386 /* large enough for ".4000000" */
3387 char str[9];
3388 int val = 0;
3390 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
3391 (*ptr & 0x80))
3393 val <<= 7;
3394 val |= *ptr & 0x7f;
3395 ptr++;
3397 if (ptr - pbEncoded - 1 - lenBytes >= dataLen ||
3398 (*ptr & 0x80))
3400 SetLastError(CRYPT_E_ASN1_CORRUPT);
3401 ret = FALSE;
3403 else
3405 val <<= 7;
3406 val |= *ptr++;
3407 snprintf(str, sizeof(str), ".%d", val);
3408 bytesNeeded += strlen(str);
3411 if (!pszObjId)
3412 *pcbObjId = bytesNeeded;
3413 else if (*pcbObjId < bytesNeeded)
3415 *pcbObjId = bytesNeeded;
3416 SetLastError(ERROR_MORE_DATA);
3417 ret = FALSE;
3419 else
3421 sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40,
3422 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] /
3423 40) * 40);
3424 pszObjId += strlen(pszObjId);
3425 for (ptr = pbEncoded + 2 + lenBytes; ret &&
3426 ptr - pbEncoded - 1 - lenBytes < dataLen; )
3428 int val = 0;
3430 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
3431 (*ptr & 0x80))
3433 val <<= 7;
3434 val |= *ptr & 0x7f;
3435 ptr++;
3437 val <<= 7;
3438 val |= *ptr++;
3439 sprintf(pszObjId, ".%d", val);
3440 pszObjId += strlen(pszObjId);
3444 else
3445 bytesNeeded = 0;
3446 *pcbObjId = bytesNeeded;
3449 else
3451 SetLastError(CRYPT_E_ASN1_BADTAG);
3452 ret = FALSE;
3455 __EXCEPT(page_fault)
3457 SetLastError(STATUS_ACCESS_VIOLATION);
3458 ret = FALSE;
3460 __ENDTRY
3461 return ret;
3464 /* Warning: this assumes the address of value->Value.pbData is already set, in
3465 * order to avoid overwriting memory. (In some cases, it may change it, if it
3466 * doesn't copy anything to memory.) Be sure to set it correctly!
3468 static BOOL WINAPI CRYPT_AsnDecodeNameValue(const BYTE *pbEncoded,
3469 DWORD cbEncoded, DWORD dwFlags, CERT_NAME_VALUE *value, DWORD *pcbValue)
3471 BOOL ret = TRUE;
3473 __TRY
3475 DWORD dataLen;
3477 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3479 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3481 switch (pbEncoded[0])
3483 case ASN_NUMERICSTRING:
3484 case ASN_PRINTABLESTRING:
3485 case ASN_IA5STRING:
3486 break;
3487 default:
3488 FIXME("Unimplemented string type %02x\n", pbEncoded[0]);
3489 SetLastError(OSS_UNIMPLEMENTED);
3490 ret = FALSE;
3492 if (ret)
3494 DWORD bytesNeeded = sizeof(CERT_NAME_VALUE);
3496 switch (pbEncoded[0])
3498 case ASN_NUMERICSTRING:
3499 case ASN_PRINTABLESTRING:
3500 case ASN_IA5STRING:
3501 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
3502 bytesNeeded += dataLen;
3503 break;
3505 if (!value)
3506 *pcbValue = bytesNeeded;
3507 else if (*pcbValue < bytesNeeded)
3509 *pcbValue = bytesNeeded;
3510 SetLastError(ERROR_MORE_DATA);
3511 ret = FALSE;
3513 else
3515 *pcbValue = bytesNeeded;
3516 switch (pbEncoded[0])
3518 case ASN_NUMERICSTRING:
3519 value->dwValueType = CERT_RDN_NUMERIC_STRING;
3520 break;
3521 case ASN_PRINTABLESTRING:
3522 value->dwValueType = CERT_RDN_PRINTABLE_STRING;
3523 break;
3524 case ASN_IA5STRING:
3525 value->dwValueType = CERT_RDN_IA5_STRING;
3526 break;
3528 if (dataLen)
3530 switch (pbEncoded[0])
3532 case ASN_NUMERICSTRING:
3533 case ASN_PRINTABLESTRING:
3534 case ASN_IA5STRING:
3535 value->Value.cbData = dataLen;
3536 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
3537 value->Value.pbData = (BYTE *)pbEncoded + 1 +
3538 lenBytes;
3539 else
3541 assert(value->Value.pbData);
3542 memcpy(value->Value.pbData,
3543 pbEncoded + 1 + lenBytes, dataLen);
3545 break;
3548 else
3550 value->Value.cbData = 0;
3551 value->Value.pbData = NULL;
3557 __EXCEPT(page_fault)
3559 SetLastError(STATUS_ACCESS_VIOLATION);
3560 ret = FALSE;
3562 __ENDTRY
3563 return ret;
3566 static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(const BYTE *pbEncoded,
3567 DWORD cbEncoded, DWORD dwFlags, CERT_RDN_ATTR *attr, DWORD *pcbAttr)
3569 BOOL ret;
3571 __TRY
3573 if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SEQUENCE))
3575 DWORD bytesNeeded, dataLen, size;
3576 BYTE lenBytes;
3578 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3580 /* The data length must be at least 4, two for the tag and
3581 * length for the OID, and two for the string (assuming both
3582 * have short-form lengths.)
3584 if (dataLen < 4)
3586 SetLastError(CRYPT_E_ASN1_EOD);
3587 ret = FALSE;
3589 else
3591 bytesNeeded = sizeof(CERT_RDN_ATTR);
3592 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3593 ret = CRYPT_AsnDecodeOid(pbEncoded + 1 + lenBytes,
3594 cbEncoded - 1 - lenBytes, dwFlags, NULL, &size);
3595 if (ret)
3597 /* ugly: need to know the size of the next element of
3598 * the sequence, so get it directly
3600 DWORD objIdOfset = 1 + lenBytes, objIdLen,
3601 nameValueOffset = 0;
3603 ret = CRYPT_GetLen(pbEncoded + objIdOfset,
3604 cbEncoded - objIdOfset, &objIdLen);
3605 bytesNeeded += size;
3606 /* hack: like encoding, this takes advantage of the
3607 * fact that the rest of the structure is identical to
3608 * a CERT_NAME_VALUE.
3610 if (ret)
3612 nameValueOffset = objIdOfset + objIdLen + 1 +
3613 GET_LEN_BYTES(pbEncoded[objIdOfset]);
3614 ret = CRYPT_AsnDecodeNameValue(
3615 pbEncoded + nameValueOffset,
3616 cbEncoded - nameValueOffset, dwFlags, NULL, &size);
3618 if (ret)
3620 bytesNeeded += size;
3621 if (!attr)
3622 *pcbAttr = bytesNeeded;
3623 else if (*pcbAttr < bytesNeeded)
3625 *pcbAttr = bytesNeeded;
3626 SetLastError(ERROR_MORE_DATA);
3627 ret = FALSE;
3629 else
3631 BYTE *originalData = attr->Value.pbData;
3633 *pcbAttr = bytesNeeded;
3634 /* strange: decode the value first, because it
3635 * has a counted size, and we can store the OID
3636 * after it. Keep track of the original data
3637 * pointer, we'll need to know whether it was
3638 * changed.
3640 size = bytesNeeded;
3641 ret = CRYPT_AsnDecodeNameValue(
3642 pbEncoded + nameValueOffset,
3643 cbEncoded - nameValueOffset, dwFlags,
3644 (CERT_NAME_VALUE *)&attr->dwValueType, &size);
3645 if (ret)
3647 if (objIdLen)
3649 /* if the data were copied to the
3650 * original location, the OID goes
3651 * after. Otherwise it goes in the
3652 * spot originally reserved for the
3653 * data.
3655 if (attr->Value.pbData == originalData)
3656 attr->pszObjId =
3657 (LPSTR)(attr->Value.pbData +
3658 attr->Value.cbData);
3659 else
3660 attr->pszObjId = (LPSTR)originalData;
3661 size = bytesNeeded - size;
3662 ret = CRYPT_AsnDecodeOid(
3663 pbEncoded + objIdOfset,
3664 cbEncoded - objIdOfset,
3665 dwFlags, attr->pszObjId, &size);
3667 else
3668 attr->pszObjId = NULL;
3676 else
3678 SetLastError(CRYPT_E_ASN1_BADTAG);
3679 ret = FALSE;
3682 __EXCEPT(page_fault)
3684 SetLastError(STATUS_ACCESS_VIOLATION);
3685 ret = FALSE;
3687 __ENDTRY
3688 return ret;
3691 static BOOL WINAPI CRYPT_AsnDecodeRdn(const BYTE *pbEncoded, DWORD cbEncoded,
3692 DWORD dwFlags, CERT_RDN *rdn, DWORD *pcbRdn)
3694 BOOL ret = TRUE;
3696 __TRY
3698 if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SETOF))
3700 DWORD dataLen;
3702 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3704 DWORD bytesNeeded, cRDNAttr = 0;
3705 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3707 bytesNeeded = sizeof(CERT_RDN);
3708 if (dataLen)
3710 const BYTE *ptr;
3711 DWORD size;
3713 for (ptr = pbEncoded + 1 + lenBytes; ret &&
3714 ptr - pbEncoded - 1 - lenBytes < dataLen; )
3716 ret = CRYPT_AsnDecodeRdnAttr(ptr,
3717 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
3718 if (ret)
3720 DWORD nextLen;
3722 cRDNAttr++;
3723 bytesNeeded += size;
3724 ret = CRYPT_GetLen(ptr,
3725 cbEncoded - (ptr - pbEncoded), &nextLen);
3726 if (ret)
3727 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3731 if (ret)
3733 if (!rdn)
3734 *pcbRdn = bytesNeeded;
3735 else if (*pcbRdn < bytesNeeded)
3737 *pcbRdn = bytesNeeded;
3738 SetLastError(ERROR_MORE_DATA);
3739 ret = FALSE;
3741 else
3743 DWORD size, i;
3744 BYTE *nextData;
3745 const BYTE *ptr;
3747 *pcbRdn = bytesNeeded;
3748 rdn->cRDNAttr = cRDNAttr;
3749 rdn->rgRDNAttr = (CERT_RDN_ATTR *)((BYTE *)rdn +
3750 sizeof(CERT_RDN));
3751 nextData = (BYTE *)rdn->rgRDNAttr +
3752 rdn->cRDNAttr * sizeof(CERT_RDN_ATTR);
3753 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
3754 i < cRDNAttr && ptr - pbEncoded - 1 - lenBytes <
3755 dataLen; i++)
3757 rdn->rgRDNAttr[i].Value.pbData = nextData;
3758 size = bytesNeeded;
3759 ret = CRYPT_AsnDecodeRdnAttr(ptr,
3760 cbEncoded - (ptr - pbEncoded), dwFlags,
3761 &rdn->rgRDNAttr[i], &size);
3762 if (ret)
3764 DWORD nextLen;
3766 bytesNeeded -= size;
3767 /* If dwFlags & CRYPT_DECODE_NOCOPY_FLAG, the
3768 * data may not have been copied.
3770 if (rdn->rgRDNAttr[i].Value.pbData == nextData)
3771 nextData +=
3772 rdn->rgRDNAttr[i].Value.cbData;
3773 /* Ugly: the OID, if copied, is stored in
3774 * memory after the value, so increment by its
3775 * string length if it's set and points here.
3777 if ((const BYTE *)rdn->rgRDNAttr[i].pszObjId
3778 == nextData)
3779 nextData += strlen(
3780 rdn->rgRDNAttr[i].pszObjId) + 1;
3781 ret = CRYPT_GetLen(ptr,
3782 cbEncoded - (ptr - pbEncoded), &nextLen);
3783 if (ret)
3784 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3791 else
3793 SetLastError(CRYPT_E_ASN1_BADTAG);
3794 ret = FALSE;
3797 __EXCEPT(page_fault)
3799 SetLastError(STATUS_ACCESS_VIOLATION);
3800 ret = FALSE;
3802 __ENDTRY
3803 return ret;
3806 static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType,
3807 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3808 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3810 BOOL ret = TRUE;
3812 __TRY
3814 if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SEQUENCEOF))
3816 DWORD dataLen;
3818 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3820 DWORD bytesNeeded, cRDN = 0;
3821 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3823 bytesNeeded = sizeof(CERT_NAME_INFO);
3824 if (dataLen)
3826 const BYTE *ptr;
3828 for (ptr = pbEncoded + 1 + lenBytes; ret &&
3829 ptr - pbEncoded - 1 - lenBytes < dataLen; )
3831 DWORD size;
3833 ret = CRYPT_AsnDecodeRdn(ptr,
3834 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
3835 if (ret)
3837 DWORD nextLen;
3839 cRDN++;
3840 bytesNeeded += size;
3841 ret = CRYPT_GetLen(ptr,
3842 cbEncoded - (ptr - pbEncoded), &nextLen);
3843 if (ret)
3844 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3848 if (ret)
3850 if (!pvStructInfo)
3851 *pcbStructInfo = bytesNeeded;
3852 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
3853 pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
3855 CERT_NAME_INFO *info;
3857 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3858 pvStructInfo = *(BYTE **)pvStructInfo;
3859 info = (CERT_NAME_INFO *)pvStructInfo;
3860 info->cRDN = cRDN;
3861 if (info->cRDN == 0)
3862 info->rgRDN = NULL;
3863 else
3865 DWORD size, i;
3866 BYTE *nextData;
3867 const BYTE *ptr;
3869 info->rgRDN = (CERT_RDN *)((BYTE *)pvStructInfo +
3870 sizeof(CERT_NAME_INFO));
3871 nextData = (BYTE *)info->rgRDN +
3872 info->cRDN * sizeof(CERT_RDN);
3873 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
3874 i < cRDN && ptr - pbEncoded - 1 - lenBytes <
3875 dataLen; i++)
3877 info->rgRDN[i].rgRDNAttr =
3878 (CERT_RDN_ATTR *)nextData;
3879 size = bytesNeeded;
3880 ret = CRYPT_AsnDecodeRdn(ptr,
3881 cbEncoded - (ptr - pbEncoded), dwFlags,
3882 &info->rgRDN[i], &size);
3883 if (ret)
3885 DWORD nextLen;
3887 nextData += size;
3888 bytesNeeded -= size;
3889 ret = CRYPT_GetLen(ptr,
3890 cbEncoded - (ptr - pbEncoded), &nextLen);
3891 if (ret)
3892 ptr += nextLen + 1 +
3893 GET_LEN_BYTES(ptr[1]);
3901 else
3903 SetLastError(CRYPT_E_ASN1_BADTAG);
3904 ret = FALSE;
3907 __EXCEPT(page_fault)
3909 SetLastError(STATUS_ACCESS_VIOLATION);
3910 ret = FALSE;
3912 __ENDTRY
3913 return ret;
3916 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
3917 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3918 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3920 CRYPT_ALGORITHM_IDENTIFIER *algo =
3921 (CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
3922 BOOL ret = TRUE;
3924 if (pbEncoded[0] == ASN_SEQUENCE)
3926 DWORD dataLen, bytesNeeded;
3928 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3930 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3932 bytesNeeded = sizeof(CRYPT_ALGORITHM_IDENTIFIER);
3933 if (dataLen)
3935 const BYTE *ptr = pbEncoded + 1 + lenBytes;
3936 BYTE oidLenBytes;
3937 DWORD encodedOidLen, oidLen;
3939 CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
3940 &encodedOidLen);
3941 oidLenBytes = GET_LEN_BYTES(ptr[1]);
3942 ret = CRYPT_AsnDecodeOid(ptr, cbEncoded - (ptr - pbEncoded),
3943 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, &oidLen);
3944 if (ret)
3946 bytesNeeded += oidLen;
3947 ptr += 1 + encodedOidLen + oidLenBytes;
3948 /* The remaining bytes are just copied as-is, no decoding
3949 * is done.
3951 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
3952 bytesNeeded += cbEncoded - (ptr - pbEncoded);
3953 if (!algo)
3954 *pcbStructInfo = bytesNeeded;
3955 else if (*pcbStructInfo < bytesNeeded)
3957 SetLastError(ERROR_MORE_DATA);
3958 ret = FALSE;
3960 else
3962 /* Get and sanity-check parameter length first */
3963 if (dataLen - 1 - oidLenBytes - encodedOidLen != 0)
3965 DWORD paramsLen;
3967 if ((ret = CRYPT_GetLen(ptr, cbEncoded -
3968 (ptr - pbEncoded), &paramsLen)))
3970 BYTE paramsLenBytes = GET_LEN_BYTES(ptr[1]);
3972 if (paramsLen != dataLen - encodedOidLen - 1 -
3973 oidLenBytes - 1 - paramsLenBytes)
3975 SetLastError(CRYPT_E_ASN1_CORRUPT);
3976 ret = FALSE;
3980 if (ret)
3982 *pcbStructInfo = bytesNeeded;
3983 algo->Parameters.cbData = dataLen - 1 -
3984 oidLenBytes - encodedOidLen;
3985 if (algo->Parameters.cbData)
3987 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
3989 memcpy(algo->Parameters.pbData, ptr,
3990 algo->Parameters.cbData);
3991 algo->pszObjId = (LPSTR)algo->Parameters.pbData +
3992 algo->Parameters.cbData;
3994 else
3996 algo->Parameters.pbData = (BYTE *)ptr;
3997 algo->pszObjId = (LPSTR)algo->Parameters.pbData;
4000 else
4001 algo->pszObjId = (LPSTR)algo->Parameters.pbData;
4002 ptr = pbEncoded + 1 + lenBytes;
4003 ret = CRYPT_AsnDecodeOid(ptr,
4004 cbEncoded - (ptr - pbEncoded),
4005 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG,
4006 algo->pszObjId, &oidLen);
4011 else
4013 SetLastError(CRYPT_E_ASN1_EOD);
4014 ret = FALSE;
4018 else
4020 SetLastError(CRYPT_E_ASN1_BADTAG);
4021 ret = FALSE;
4023 return ret;
4026 static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType,
4027 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4028 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4030 BOOL ret = TRUE;
4032 __TRY
4034 struct AsnDecodeSequenceItem items[] = {
4035 { offsetof(CERT_PUBLIC_KEY_INFO, Algorithm),
4036 CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
4037 FALSE, TRUE, offsetof(CERT_PUBLIC_KEY_INFO,
4038 Algorithm.Parameters.pbData) },
4039 { offsetof(CERT_PUBLIC_KEY_INFO, PublicKey),
4040 CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE,
4041 offsetof(CERT_PUBLIC_KEY_INFO, PublicKey.pbData) },
4044 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
4045 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
4046 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
4048 __EXCEPT(page_fault)
4050 SetLastError(STATUS_ACCESS_VIOLATION);
4051 ret = FALSE;
4053 __ENDTRY
4054 return ret;
4057 static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
4058 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4059 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4061 BOOL ret;
4063 if (cbEncoded < 3)
4065 SetLastError(CRYPT_E_ASN1_CORRUPT);
4066 return FALSE;
4068 if (pbEncoded[0] != ASN_BOOL)
4070 SetLastError(CRYPT_E_ASN1_BADTAG);
4071 return FALSE;
4073 if (GET_LEN_BYTES(pbEncoded[1]) > 1)
4075 SetLastError(CRYPT_E_ASN1_CORRUPT);
4076 return FALSE;
4078 if (pbEncoded[1] > 1)
4080 SetLastError(CRYPT_E_ASN1_CORRUPT);
4081 return FALSE;
4083 if (!pvStructInfo)
4085 *pcbStructInfo = sizeof(BOOL);
4086 ret = TRUE;
4088 else if (*pcbStructInfo < sizeof(BOOL))
4090 *pcbStructInfo = sizeof(BOOL);
4091 SetLastError(ERROR_MORE_DATA);
4092 ret = FALSE;
4094 else
4096 *(BOOL *)pvStructInfo = pbEncoded[2] ? TRUE : FALSE;
4097 ret = TRUE;
4099 return ret;
4102 static BOOL CRYPT_AsnDecodeAltNameEntry(const BYTE *pbEncoded, DWORD cbEncoded,
4103 DWORD dwFlags, CERT_ALT_NAME_ENTRY *entry, DWORD *pcbEntry)
4105 DWORD dataLen, lenBytes, bytesNeeded = sizeof(CERT_ALT_NAME_ENTRY);
4106 BOOL ret;
4108 if (cbEncoded < 2)
4110 SetLastError(CRYPT_E_ASN1_CORRUPT);
4111 return FALSE;
4113 if ((pbEncoded[0] & ASN_FLAGS_MASK) != ASN_CONTEXT)
4115 SetLastError(CRYPT_E_ASN1_BADTAG);
4116 return FALSE;
4118 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4119 if (1 + lenBytes > cbEncoded)
4121 SetLastError(CRYPT_E_ASN1_CORRUPT);
4122 return FALSE;
4124 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4126 switch (pbEncoded[0] & ASN_TYPE_MASK)
4128 case 1: /* rfc822Name */
4129 case 2: /* dNSName */
4130 case 6: /* uniformResourceIdentifier */
4131 bytesNeeded += (dataLen + 1) * sizeof(WCHAR);
4132 break;
4133 case 7: /* iPAddress */
4134 bytesNeeded += dataLen;
4135 break;
4136 case 8: /* registeredID */
4137 /* FIXME: decode as OID */
4138 case 0: /* otherName */
4139 case 4: /* directoryName */
4140 FIXME("stub\n");
4141 SetLastError(CRYPT_E_ASN1_BADTAG);
4142 ret = FALSE;
4143 break;
4144 case 3: /* x400Address, unimplemented */
4145 case 5: /* ediPartyName, unimplemented */
4146 SetLastError(CRYPT_E_ASN1_BADTAG);
4147 ret = FALSE;
4148 break;
4149 default:
4150 SetLastError(CRYPT_E_ASN1_CORRUPT);
4151 ret = FALSE;
4153 if (ret)
4155 if (!entry)
4156 *pcbEntry = bytesNeeded;
4157 else if (*pcbEntry < bytesNeeded)
4159 SetLastError(ERROR_MORE_DATA);
4160 ret = FALSE;
4162 else
4164 /* MS used values one greater than the asn1 ones.. sigh */
4165 entry->dwAltNameChoice = (pbEncoded[0] & 0x7f) + 1;
4166 switch (pbEncoded[0] & ASN_TYPE_MASK)
4168 case 1: /* rfc822Name */
4169 case 2: /* dNSName */
4170 case 6: /* uniformResourceIdentifier */
4172 DWORD i;
4174 for (i = 0; i < dataLen; i++)
4175 entry->u.pwszURL[i] = (WCHAR)pbEncoded[1 + lenBytes + i];
4176 entry->u.pwszURL[i] = 0;
4177 break;
4179 case 7: /* iPAddress */
4180 /* The next data pointer is in the pwszURL spot, that is,
4181 * the first 4 bytes. Need to move it to the next spot.
4183 entry->u.IPAddress.pbData = (LPBYTE)entry->u.pwszURL;
4184 entry->u.IPAddress.cbData = dataLen;
4185 memcpy(entry->u.IPAddress.pbData, pbEncoded + 1 + lenBytes,
4186 dataLen);
4187 break;
4192 return ret;
4195 static BOOL WINAPI CRYPT_AsnDecodeAltName(DWORD dwCertEncodingType,
4196 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4197 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4199 BOOL ret = TRUE;
4201 __TRY
4203 if (pbEncoded[0] == ASN_SEQUENCEOF)
4205 DWORD dataLen;
4207 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4209 DWORD bytesNeeded, cEntry = 0;
4210 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4212 bytesNeeded = sizeof(CERT_ALT_NAME_INFO);
4213 if (dataLen)
4215 const BYTE *ptr;
4217 for (ptr = pbEncoded + 1 + lenBytes; ret &&
4218 ptr - pbEncoded - 1 - lenBytes < dataLen; )
4220 DWORD size;
4222 ret = CRYPT_AsnDecodeAltNameEntry(ptr,
4223 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
4224 if (ret)
4226 DWORD nextLen;
4228 cEntry++;
4229 bytesNeeded += size;
4230 ret = CRYPT_GetLen(ptr,
4231 cbEncoded - (ptr - pbEncoded), &nextLen);
4232 if (ret)
4233 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
4237 if (ret)
4239 if (!pvStructInfo)
4240 *pcbStructInfo = bytesNeeded;
4241 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
4242 pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
4244 CERT_ALT_NAME_INFO *info;
4246 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4247 pvStructInfo = *(BYTE **)pvStructInfo;
4248 info = (CERT_ALT_NAME_INFO *)pvStructInfo;
4249 info->cAltEntry = 0;
4250 if (cEntry == 0)
4251 info->rgAltEntry = NULL;
4252 else
4254 DWORD size, i;
4255 BYTE *nextData;
4256 const BYTE *ptr;
4258 info->rgAltEntry =
4259 (CERT_ALT_NAME_ENTRY *)((BYTE *)pvStructInfo +
4260 sizeof(CERT_ALT_NAME_INFO));
4261 nextData = (BYTE *)info->rgAltEntry +
4262 cEntry * sizeof(CERT_ALT_NAME_ENTRY);
4263 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
4264 i < cEntry && ptr - pbEncoded - 1 - lenBytes <
4265 dataLen; i++)
4267 info->rgAltEntry[i].u.pwszURL = (LPWSTR)nextData;
4268 size = bytesNeeded;
4269 ret = CRYPT_AsnDecodeAltNameEntry(ptr,
4270 cbEncoded - (ptr - pbEncoded), dwFlags,
4271 &info->rgAltEntry[i], &size);
4272 if (ret)
4274 DWORD nextLen;
4276 info->cAltEntry++;
4277 nextData += size -
4278 sizeof(CERT_ALT_NAME_ENTRY);
4279 bytesNeeded -= size;
4280 ret = CRYPT_GetLen(ptr,
4281 cbEncoded - (ptr - pbEncoded), &nextLen);
4282 if (ret)
4283 ptr += nextLen + 1 +
4284 GET_LEN_BYTES(ptr[1]);
4292 else
4294 SetLastError(CRYPT_E_ASN1_BADTAG);
4295 ret = FALSE;
4298 __EXCEPT(page_fault)
4300 SetLastError(STATUS_ACCESS_VIOLATION);
4301 ret = FALSE;
4303 __ENDTRY
4304 return ret;
4307 static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints2(DWORD dwCertEncodingType,
4308 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4309 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4311 BOOL ret;
4313 __TRY
4315 if (pbEncoded[0] == ASN_SEQUENCE)
4317 DWORD dataLen;
4319 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4321 /* sanity-check length, space enough for 7 bytes of integer and
4322 * 3 bytes of bool
4324 if (dataLen > 10)
4326 SetLastError(CRYPT_E_ASN1_CORRUPT);
4327 ret = FALSE;
4329 else
4331 DWORD bytesNeeded = sizeof(CERT_BASIC_CONSTRAINTS2_INFO);
4333 if (!pvStructInfo)
4334 *pcbStructInfo = bytesNeeded;
4335 else
4337 BYTE lenBytes;
4338 CERT_BASIC_CONSTRAINTS2_INFO info = { 0 };
4340 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4341 pbEncoded += 1 + lenBytes;
4342 cbEncoded -= 1 + lenBytes;
4343 if (cbEncoded)
4345 DWORD size;
4347 if (pbEncoded[0] == ASN_BOOL)
4349 size = sizeof(BOOL);
4350 ret = CRYPT_AsnDecodeBool(dwCertEncodingType,
4351 NULL, pbEncoded, cbEncoded,
4352 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
4353 &info.fCA, &size);
4354 if (ret)
4356 cbEncoded -= 2 + pbEncoded[1];
4357 pbEncoded += 2 + pbEncoded[1];
4360 if (ret && cbEncoded && pbEncoded[0] == ASN_INTEGER)
4362 size = sizeof(info.dwPathLenConstraint);
4363 ret = CRYPT_AsnDecodeInt(dwCertEncodingType,
4364 X509_INTEGER, pbEncoded, cbEncoded, 0, NULL,
4365 &info.dwPathLenConstraint, &size);
4366 if (ret)
4368 cbEncoded -= 2 + pbEncoded[1];
4369 pbEncoded += 2 + pbEncoded[1];
4370 if (cbEncoded)
4372 SetLastError(CRYPT_E_ASN1_CORRUPT);
4373 ret = FALSE;
4375 else
4376 info.fPathLenConstraint = TRUE;
4380 if (ret)
4382 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
4383 pDecodePara, pvStructInfo, pcbStructInfo,
4384 bytesNeeded)))
4386 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4387 pvStructInfo = *(BYTE **)pvStructInfo;
4388 memcpy(pvStructInfo, &info,
4389 sizeof(CERT_BASIC_CONSTRAINTS2_INFO));
4396 else
4398 SetLastError(CRYPT_E_ASN1_BADTAG);
4399 ret = FALSE;
4402 __EXCEPT(page_fault)
4404 SetLastError(STATUS_ACCESS_VIOLATION);
4405 ret = FALSE;
4407 __ENDTRY
4408 return ret;
4411 #define RSA1_MAGIC 0x31415352
4413 struct DECODED_RSA_PUB_KEY
4415 DWORD pubexp;
4416 CRYPT_INTEGER_BLOB modulus;
4419 static BOOL WINAPI CRYPT_AsnDecodeRsaPubKey(DWORD dwCertEncodingType,
4420 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4421 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4423 BOOL ret;
4425 __TRY
4427 struct AsnDecodeSequenceItem items[] = {
4428 { offsetof(struct DECODED_RSA_PUB_KEY, modulus),
4429 CRYPT_AsnDecodeIntegerInternal, sizeof(CRYPT_INTEGER_BLOB),
4430 FALSE, TRUE, offsetof(struct DECODED_RSA_PUB_KEY, modulus.pbData),
4431 0 },
4432 { offsetof(struct DECODED_RSA_PUB_KEY, pubexp),
4433 CRYPT_AsnDecodeInt, sizeof(DWORD), FALSE, FALSE, 0, 0 },
4435 struct DECODED_RSA_PUB_KEY *decodedKey = NULL;
4436 DWORD size = 0;
4438 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
4439 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded,
4440 CRYPT_DECODE_ALLOC_FLAG, NULL, &decodedKey, &size, NULL);
4441 if (ret)
4443 DWORD bytesNeeded = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
4444 decodedKey->modulus.cbData;
4446 if (!pvStructInfo)
4448 *pcbStructInfo = bytesNeeded;
4449 ret = TRUE;
4451 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4452 pvStructInfo, pcbStructInfo, bytesNeeded)))
4454 BLOBHEADER *hdr;
4455 RSAPUBKEY *rsaPubKey;
4457 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4458 pvStructInfo = *(BYTE **)pvStructInfo;
4459 hdr = (BLOBHEADER *)pvStructInfo;
4460 hdr->bType = PUBLICKEYBLOB;
4461 hdr->bVersion = CUR_BLOB_VERSION;
4462 hdr->reserved = 0;
4463 hdr->aiKeyAlg = CALG_RSA_KEYX;
4464 rsaPubKey = (RSAPUBKEY *)((BYTE *)pvStructInfo +
4465 sizeof(BLOBHEADER));
4466 rsaPubKey->magic = RSA1_MAGIC;
4467 rsaPubKey->pubexp = decodedKey->pubexp;
4468 rsaPubKey->bitlen = decodedKey->modulus.cbData * 8;
4469 memcpy((BYTE *)pvStructInfo + sizeof(BLOBHEADER) +
4470 sizeof(RSAPUBKEY), decodedKey->modulus.pbData,
4471 decodedKey->modulus.cbData);
4473 LocalFree(decodedKey);
4476 __EXCEPT(page_fault)
4478 SetLastError(STATUS_ACCESS_VIOLATION);
4479 ret = FALSE;
4481 __ENDTRY
4482 return ret;
4485 static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
4486 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4487 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4489 BOOL ret;
4491 __TRY
4493 if (pbEncoded[0] == ASN_OCTETSTRING)
4495 DWORD bytesNeeded, dataLen;
4497 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4499 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4500 bytesNeeded = sizeof(CRYPT_DATA_BLOB);
4501 else
4502 bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB);
4503 if (!pvStructInfo)
4504 *pcbStructInfo = bytesNeeded;
4505 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4506 pvStructInfo, pcbStructInfo, bytesNeeded)))
4508 CRYPT_DATA_BLOB *blob;
4509 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4511 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4512 pvStructInfo = *(BYTE **)pvStructInfo;
4513 blob = (CRYPT_DATA_BLOB *)pvStructInfo;
4514 blob->cbData = dataLen;
4515 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4516 blob->pbData = (BYTE *)pbEncoded + 1 + lenBytes;
4517 else
4519 blob->pbData = (BYTE *)pvStructInfo +
4520 sizeof(CRYPT_DATA_BLOB);
4521 if (blob->cbData)
4522 memcpy(blob->pbData, pbEncoded + 1 + lenBytes,
4523 blob->cbData);
4528 else
4530 SetLastError(CRYPT_E_ASN1_BADTAG);
4531 ret = FALSE;
4534 __EXCEPT(page_fault)
4536 SetLastError(STATUS_ACCESS_VIOLATION);
4537 ret = FALSE;
4539 __ENDTRY
4540 return ret;
4543 static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
4544 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4545 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4547 BOOL ret;
4549 TRACE("(%p, %ld, 0x%08lx, %p, %p, %ld)\n", pbEncoded, cbEncoded, dwFlags,
4550 pDecodePara, pvStructInfo, *pcbStructInfo);
4552 if (pbEncoded[0] == ASN_BITSTRING)
4554 DWORD bytesNeeded, dataLen;
4556 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4558 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4559 bytesNeeded = sizeof(CRYPT_BIT_BLOB);
4560 else
4561 bytesNeeded = dataLen - 1 + sizeof(CRYPT_BIT_BLOB);
4562 if (!pvStructInfo)
4563 *pcbStructInfo = bytesNeeded;
4564 else if (*pcbStructInfo < bytesNeeded)
4566 *pcbStructInfo = bytesNeeded;
4567 SetLastError(ERROR_MORE_DATA);
4568 ret = FALSE;
4570 else
4572 CRYPT_BIT_BLOB *blob;
4574 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
4575 blob->cbData = dataLen - 1;
4576 blob->cUnusedBits = *(pbEncoded + 1 +
4577 GET_LEN_BYTES(pbEncoded[1]));
4578 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4580 blob->pbData = (BYTE *)pbEncoded + 2 +
4581 GET_LEN_BYTES(pbEncoded[1]);
4583 else
4585 assert(blob->pbData);
4586 if (blob->cbData)
4588 BYTE mask = 0xff << blob->cUnusedBits;
4590 memcpy(blob->pbData, pbEncoded + 2 +
4591 GET_LEN_BYTES(pbEncoded[1]), blob->cbData);
4592 blob->pbData[blob->cbData - 1] &= mask;
4598 else
4600 SetLastError(CRYPT_E_ASN1_BADTAG);
4601 ret = FALSE;
4603 return ret;
4606 static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType,
4607 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4608 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4610 BOOL ret;
4612 TRACE("(%p, %ld, 0x%08lx, %p, %p, %p)\n", pbEncoded, cbEncoded, dwFlags,
4613 pDecodePara, pvStructInfo, pcbStructInfo);
4615 __TRY
4617 DWORD bytesNeeded;
4619 if ((ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType,
4620 lpszStructType, pbEncoded, cbEncoded,
4621 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
4623 if (!pvStructInfo)
4624 *pcbStructInfo = bytesNeeded;
4625 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4626 pvStructInfo, pcbStructInfo, bytesNeeded)))
4628 CRYPT_BIT_BLOB *blob;
4630 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4631 pvStructInfo = *(BYTE **)pvStructInfo;
4632 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
4633 blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_BIT_BLOB);
4634 ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType,
4635 lpszStructType, pbEncoded, cbEncoded,
4636 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
4637 &bytesNeeded);
4641 __EXCEPT(page_fault)
4643 SetLastError(STATUS_ACCESS_VIOLATION);
4644 ret = FALSE;
4646 __ENDTRY
4647 return ret;
4650 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
4651 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4652 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4654 BOOL ret;
4656 if (!pvStructInfo)
4658 *pcbStructInfo = sizeof(int);
4659 return TRUE;
4661 __TRY
4663 BYTE buf[sizeof(CRYPT_INTEGER_BLOB) + sizeof(int)];
4664 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
4665 DWORD size = sizeof(buf);
4667 blob->pbData = buf + sizeof(CRYPT_INTEGER_BLOB);
4668 ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
4669 X509_MULTI_BYTE_INTEGER, pbEncoded, cbEncoded, 0, NULL, &buf, &size);
4670 if (ret)
4672 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4673 pvStructInfo, pcbStructInfo, sizeof(int))))
4675 int val, i;
4677 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4678 pvStructInfo = *(BYTE **)pvStructInfo;
4679 if (blob->pbData[blob->cbData - 1] & 0x80)
4681 /* initialize to a negative value to sign-extend */
4682 val = -1;
4684 else
4685 val = 0;
4686 for (i = 0; i < blob->cbData; i++)
4688 val <<= 8;
4689 val |= blob->pbData[blob->cbData - i - 1];
4691 memcpy(pvStructInfo, &val, sizeof(int));
4694 else if (GetLastError() == ERROR_MORE_DATA)
4695 SetLastError(CRYPT_E_ASN1_LARGE);
4697 __EXCEPT(page_fault)
4699 SetLastError(STATUS_ACCESS_VIOLATION);
4700 ret = FALSE;
4702 __ENDTRY
4703 return ret;
4706 static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType,
4707 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4708 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4710 BOOL ret;
4712 if (pbEncoded[0] == ASN_INTEGER)
4714 DWORD bytesNeeded, dataLen;
4716 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4718 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4720 bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
4721 if (!pvStructInfo)
4722 *pcbStructInfo = bytesNeeded;
4723 else if (*pcbStructInfo < bytesNeeded)
4725 *pcbStructInfo = bytesNeeded;
4726 SetLastError(ERROR_MORE_DATA);
4727 ret = FALSE;
4729 else
4731 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
4733 blob->cbData = dataLen;
4734 assert(blob->pbData);
4735 if (blob->cbData)
4737 DWORD i;
4739 for (i = 0; i < blob->cbData; i++)
4741 blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
4742 dataLen - i - 1);
4748 else
4750 SetLastError(CRYPT_E_ASN1_BADTAG);
4751 ret = FALSE;
4753 return ret;
4756 static BOOL WINAPI CRYPT_AsnDecodeInteger(DWORD dwCertEncodingType,
4757 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4758 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4760 BOOL ret;
4762 __TRY
4764 DWORD bytesNeeded;
4766 if ((ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
4767 lpszStructType, pbEncoded, cbEncoded,
4768 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
4770 if (!pvStructInfo)
4771 *pcbStructInfo = bytesNeeded;
4772 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4773 pvStructInfo, pcbStructInfo, bytesNeeded)))
4775 CRYPT_INTEGER_BLOB *blob;
4777 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4778 pvStructInfo = *(BYTE **)pvStructInfo;
4779 blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
4780 blob->pbData = (BYTE *)pvStructInfo +
4781 sizeof(CRYPT_INTEGER_BLOB);
4782 ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
4783 lpszStructType, pbEncoded, cbEncoded,
4784 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pvStructInfo,
4785 &bytesNeeded);
4789 __EXCEPT(page_fault)
4791 SetLastError(STATUS_ACCESS_VIOLATION);
4792 ret = FALSE;
4794 __ENDTRY
4795 return ret;
4798 static BOOL WINAPI CRYPT_AsnDecodeUnsignedInteger(DWORD dwCertEncodingType,
4799 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4800 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4802 BOOL ret;
4804 __TRY
4806 if (pbEncoded[0] == ASN_INTEGER)
4808 DWORD bytesNeeded, dataLen;
4809 CRYPT_INTEGER_BLOB *blob;
4811 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4813 bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
4814 if (!pvStructInfo)
4815 *pcbStructInfo = bytesNeeded;
4816 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4817 pvStructInfo, pcbStructInfo, bytesNeeded)))
4819 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4821 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4822 pvStructInfo = *(BYTE **)pvStructInfo;
4823 blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
4824 blob->cbData = dataLen;
4825 blob->pbData = (BYTE *)pvStructInfo +
4826 sizeof(CRYPT_INTEGER_BLOB);
4827 /* remove leading zero byte if it exists */
4828 if (blob->cbData && *(pbEncoded + 1 + lenBytes) == 0)
4830 blob->cbData--;
4831 blob->pbData++;
4833 if (blob->cbData)
4835 DWORD i;
4837 for (i = 0; i < blob->cbData; i++)
4838 blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
4839 pbEncoded[1] - i - 1);
4844 else
4846 SetLastError(CRYPT_E_ASN1_BADTAG);
4847 ret = FALSE;
4850 __EXCEPT(page_fault)
4852 SetLastError(STATUS_ACCESS_VIOLATION);
4853 ret = FALSE;
4855 __ENDTRY
4856 return ret;
4859 static BOOL WINAPI CRYPT_AsnDecodeEnumerated(DWORD dwCertEncodingType,
4860 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4861 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4863 BOOL ret;
4865 if (!pvStructInfo)
4867 *pcbStructInfo = sizeof(int);
4868 return TRUE;
4870 __TRY
4872 if (pbEncoded[0] == ASN_ENUMERATED)
4874 unsigned int val = 0, i;
4876 if (cbEncoded <= 1)
4878 SetLastError(CRYPT_E_ASN1_EOD);
4879 ret = FALSE;
4881 else if (pbEncoded[1] == 0)
4883 SetLastError(CRYPT_E_ASN1_CORRUPT);
4884 ret = FALSE;
4886 else
4888 /* A little strange looking, but we have to accept a sign byte:
4889 * 0xffffffff gets encoded as 0a 05 00 ff ff ff ff. Also,
4890 * assuming a small length is okay here, it has to be in short
4891 * form.
4893 if (pbEncoded[1] > sizeof(unsigned int) + 1)
4895 SetLastError(CRYPT_E_ASN1_LARGE);
4896 return FALSE;
4898 for (i = 0; i < pbEncoded[1]; i++)
4900 val <<= 8;
4901 val |= pbEncoded[2 + i];
4903 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4904 pvStructInfo, pcbStructInfo, sizeof(unsigned int))))
4906 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4907 pvStructInfo = *(BYTE **)pvStructInfo;
4908 memcpy(pvStructInfo, &val, sizeof(unsigned int));
4912 else
4914 SetLastError(CRYPT_E_ASN1_BADTAG);
4915 ret = FALSE;
4918 __EXCEPT(page_fault)
4920 SetLastError(STATUS_ACCESS_VIOLATION);
4921 ret = FALSE;
4923 __ENDTRY
4924 return ret;
4927 /* Modifies word, pbEncoded, and len, and magically sets a value ret to FALSE
4928 * if it fails.
4930 #define CRYPT_TIME_GET_DIGITS(pbEncoded, len, numDigits, word) \
4931 do { \
4932 BYTE i; \
4934 (word) = 0; \
4935 for (i = 0; (len) > 0 && i < (numDigits); i++, (len)--) \
4937 if (!isdigit(*(pbEncoded))) \
4939 SetLastError(CRYPT_E_ASN1_CORRUPT); \
4940 ret = FALSE; \
4942 else \
4944 (word) *= 10; \
4945 (word) += *(pbEncoded)++ - '0'; \
4948 } while (0)
4950 static BOOL CRYPT_AsnDecodeTimeZone(const BYTE *pbEncoded, DWORD len,
4951 SYSTEMTIME *sysTime)
4953 BOOL ret = TRUE;
4955 __TRY
4957 if (len >= 3 && (*pbEncoded == '+' || *pbEncoded == '-'))
4959 WORD hours, minutes = 0;
4960 BYTE sign = *pbEncoded++;
4962 len--;
4963 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, hours);
4964 if (ret && hours >= 24)
4966 SetLastError(CRYPT_E_ASN1_CORRUPT);
4967 ret = FALSE;
4969 else if (len >= 2)
4971 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, minutes);
4972 if (ret && minutes >= 60)
4974 SetLastError(CRYPT_E_ASN1_CORRUPT);
4975 ret = FALSE;
4978 if (ret)
4980 if (sign == '+')
4982 sysTime->wHour += hours;
4983 sysTime->wMinute += minutes;
4985 else
4987 if (hours > sysTime->wHour)
4989 sysTime->wDay--;
4990 sysTime->wHour = 24 - (hours - sysTime->wHour);
4992 else
4993 sysTime->wHour -= hours;
4994 if (minutes > sysTime->wMinute)
4996 sysTime->wHour--;
4997 sysTime->wMinute = 60 - (minutes - sysTime->wMinute);
4999 else
5000 sysTime->wMinute -= minutes;
5005 __EXCEPT(page_fault)
5007 SetLastError(STATUS_ACCESS_VIOLATION);
5008 ret = FALSE;
5010 __ENDTRY
5011 return ret;
5014 #define MIN_ENCODED_TIME_LENGTH 10
5016 static BOOL WINAPI CRYPT_AsnDecodeUtcTime(DWORD dwCertEncodingType,
5017 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5018 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5020 BOOL ret = TRUE;
5022 if (!pvStructInfo)
5024 *pcbStructInfo = sizeof(FILETIME);
5025 return TRUE;
5027 __TRY
5029 if (pbEncoded[0] == ASN_UTCTIME)
5031 if (cbEncoded <= 1)
5033 SetLastError(CRYPT_E_ASN1_EOD);
5034 ret = FALSE;
5036 else if (pbEncoded[1] > 0x7f)
5038 /* long-form date strings really can't be valid */
5039 SetLastError(CRYPT_E_ASN1_CORRUPT);
5040 ret = FALSE;
5042 else
5044 SYSTEMTIME sysTime = { 0 };
5045 BYTE len = pbEncoded[1];
5047 if (len < MIN_ENCODED_TIME_LENGTH)
5049 SetLastError(CRYPT_E_ASN1_CORRUPT);
5050 ret = FALSE;
5052 else
5054 pbEncoded += 2;
5055 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wYear);
5056 if (sysTime.wYear >= 50)
5057 sysTime.wYear += 1900;
5058 else
5059 sysTime.wYear += 2000;
5060 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
5061 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
5062 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
5063 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
5064 if (ret && len > 0)
5066 if (len >= 2 && isdigit(*pbEncoded) &&
5067 isdigit(*(pbEncoded + 1)))
5068 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
5069 sysTime.wSecond);
5070 else if (isdigit(*pbEncoded))
5071 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 1,
5072 sysTime.wSecond);
5073 if (ret)
5074 ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len,
5075 &sysTime);
5077 if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags,
5078 pDecodePara, pvStructInfo, pcbStructInfo,
5079 sizeof(FILETIME))))
5081 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
5082 pvStructInfo = *(BYTE **)pvStructInfo;
5083 ret = SystemTimeToFileTime(&sysTime,
5084 (FILETIME *)pvStructInfo);
5089 else
5091 SetLastError(CRYPT_E_ASN1_BADTAG);
5092 ret = FALSE;
5095 __EXCEPT(page_fault)
5097 SetLastError(STATUS_ACCESS_VIOLATION);
5098 ret = FALSE;
5100 __ENDTRY
5101 return ret;
5104 static BOOL WINAPI CRYPT_AsnDecodeGeneralizedTime(DWORD dwCertEncodingType,
5105 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5106 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5108 BOOL ret = TRUE;
5110 if (!pvStructInfo)
5112 *pcbStructInfo = sizeof(FILETIME);
5113 return TRUE;
5115 __TRY
5117 if (pbEncoded[0] == ASN_GENERALTIME)
5119 if (cbEncoded <= 1)
5121 SetLastError(CRYPT_E_ASN1_EOD);
5122 ret = FALSE;
5124 else if (pbEncoded[1] > 0x7f)
5126 /* long-form date strings really can't be valid */
5127 SetLastError(CRYPT_E_ASN1_CORRUPT);
5128 ret = FALSE;
5130 else
5132 BYTE len = pbEncoded[1];
5134 if (len < MIN_ENCODED_TIME_LENGTH)
5136 SetLastError(CRYPT_E_ASN1_CORRUPT);
5137 ret = FALSE;
5139 else
5141 SYSTEMTIME sysTime = { 0 };
5143 pbEncoded += 2;
5144 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 4, sysTime.wYear);
5145 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
5146 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
5147 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
5148 if (ret && len > 0)
5150 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
5151 sysTime.wMinute);
5152 if (ret && len > 0)
5153 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
5154 sysTime.wSecond);
5155 if (ret && len > 0 && (*pbEncoded == '.' ||
5156 *pbEncoded == ','))
5158 BYTE digits;
5160 pbEncoded++;
5161 len--;
5162 /* workaround macro weirdness */
5163 digits = min(len, 3);
5164 CRYPT_TIME_GET_DIGITS(pbEncoded, len, digits,
5165 sysTime.wMilliseconds);
5167 if (ret)
5168 ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len,
5169 &sysTime);
5171 if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags,
5172 pDecodePara, pvStructInfo, pcbStructInfo,
5173 sizeof(FILETIME))))
5175 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
5176 pvStructInfo = *(BYTE **)pvStructInfo;
5177 ret = SystemTimeToFileTime(&sysTime,
5178 (FILETIME *)pvStructInfo);
5183 else
5185 SetLastError(CRYPT_E_ASN1_BADTAG);
5186 ret = FALSE;
5189 __EXCEPT(page_fault)
5191 SetLastError(STATUS_ACCESS_VIOLATION);
5192 ret = FALSE;
5194 __ENDTRY
5195 return ret;
5198 static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
5199 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5200 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5202 BOOL ret;
5204 __TRY
5206 if (pbEncoded[0] == ASN_UTCTIME)
5207 ret = CRYPT_AsnDecodeUtcTime(dwCertEncodingType, lpszStructType,
5208 pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
5209 pcbStructInfo);
5210 else if (pbEncoded[0] == ASN_GENERALTIME)
5211 ret = CRYPT_AsnDecodeGeneralizedTime(dwCertEncodingType,
5212 lpszStructType, pbEncoded, cbEncoded, dwFlags, pDecodePara,
5213 pvStructInfo, pcbStructInfo);
5214 else
5216 SetLastError(CRYPT_E_ASN1_BADTAG);
5217 ret = FALSE;
5220 __EXCEPT(page_fault)
5222 SetLastError(STATUS_ACCESS_VIOLATION);
5223 ret = FALSE;
5225 __ENDTRY
5226 return ret;
5229 static BOOL WINAPI CRYPT_AsnDecodeSequenceOfAny(DWORD dwCertEncodingType,
5230 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5231 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5233 BOOL ret = TRUE;
5235 __TRY
5237 if (pbEncoded[0] == ASN_SEQUENCEOF)
5239 DWORD bytesNeeded, dataLen, remainingLen, cValue;
5241 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
5243 BYTE lenBytes;
5244 const BYTE *ptr;
5246 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
5247 bytesNeeded = sizeof(CRYPT_SEQUENCE_OF_ANY);
5248 cValue = 0;
5249 ptr = pbEncoded + 1 + lenBytes;
5250 remainingLen = dataLen;
5251 while (ret && remainingLen)
5253 DWORD nextLen;
5255 ret = CRYPT_GetLen(ptr, remainingLen, &nextLen);
5256 if (ret)
5258 DWORD nextLenBytes = GET_LEN_BYTES(ptr[1]);
5260 remainingLen -= 1 + nextLenBytes + nextLen;
5261 ptr += 1 + nextLenBytes + nextLen;
5262 bytesNeeded += sizeof(CRYPT_DER_BLOB);
5263 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
5264 bytesNeeded += 1 + nextLenBytes + nextLen;
5265 cValue++;
5268 if (ret)
5270 CRYPT_SEQUENCE_OF_ANY *seq;
5271 BYTE *nextPtr;
5272 DWORD i;
5274 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
5275 pvStructInfo, pcbStructInfo, bytesNeeded)))
5277 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
5278 pvStructInfo = *(BYTE **)pvStructInfo;
5279 seq = (CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
5280 seq->cValue = cValue;
5281 seq->rgValue = (CRYPT_DER_BLOB *)((BYTE *)seq +
5282 sizeof(*seq));
5283 nextPtr = (BYTE *)seq->rgValue +
5284 cValue * sizeof(CRYPT_DER_BLOB);
5285 ptr = pbEncoded + 1 + lenBytes;
5286 remainingLen = dataLen;
5287 i = 0;
5288 while (ret && remainingLen)
5290 DWORD nextLen;
5292 ret = CRYPT_GetLen(ptr, remainingLen, &nextLen);
5293 if (ret)
5295 DWORD nextLenBytes = GET_LEN_BYTES(ptr[1]);
5297 seq->rgValue[i].cbData = 1 + nextLenBytes +
5298 nextLen;
5299 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
5300 seq->rgValue[i].pbData = (BYTE *)ptr;
5301 else
5303 seq->rgValue[i].pbData = nextPtr;
5304 memcpy(nextPtr, ptr, 1 + nextLenBytes +
5305 nextLen);
5306 nextPtr += 1 + nextLenBytes + nextLen;
5308 remainingLen -= 1 + nextLenBytes + nextLen;
5309 ptr += 1 + nextLenBytes + nextLen;
5310 i++;
5317 else
5319 SetLastError(CRYPT_E_ASN1_BADTAG);
5320 return FALSE;
5323 __EXCEPT(page_fault)
5325 SetLastError(STATUS_ACCESS_VIOLATION);
5326 ret = FALSE;
5328 __ENDTRY
5329 return ret;
5332 BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
5333 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5334 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5336 BOOL ret = FALSE;
5337 HMODULE lib = NULL;
5338 CryptDecodeObjectExFunc decodeFunc = NULL;
5340 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p, %p)\n",
5341 dwCertEncodingType, debugstr_a(lpszStructType), pbEncoded,
5342 cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
5344 if (!pvStructInfo && !pcbStructInfo)
5346 SetLastError(ERROR_INVALID_PARAMETER);
5347 return FALSE;
5349 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
5350 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
5352 SetLastError(ERROR_FILE_NOT_FOUND);
5353 return FALSE;
5355 if (!cbEncoded)
5357 SetLastError(CRYPT_E_ASN1_EOD);
5358 return FALSE;
5360 if (cbEncoded > MAX_ENCODED_LEN)
5362 SetLastError(CRYPT_E_ASN1_LARGE);
5363 return FALSE;
5366 SetLastError(NOERROR);
5367 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG && pvStructInfo)
5368 *(BYTE **)pvStructInfo = NULL;
5369 if (!HIWORD(lpszStructType))
5371 switch (LOWORD(lpszStructType))
5373 case (WORD)X509_CERT:
5374 decodeFunc = CRYPT_AsnDecodeCert;
5375 break;
5376 case (WORD)X509_CERT_TO_BE_SIGNED:
5377 decodeFunc = CRYPT_AsnDecodeCertInfo;
5378 break;
5379 case (WORD)X509_CERT_CRL_TO_BE_SIGNED:
5380 decodeFunc = CRYPT_AsnDecodeCRLInfo;
5381 break;
5382 case (WORD)X509_EXTENSIONS:
5383 decodeFunc = CRYPT_AsnDecodeExtensions;
5384 break;
5385 case (WORD)X509_NAME:
5386 decodeFunc = CRYPT_AsnDecodeName;
5387 break;
5388 case (WORD)X509_PUBLIC_KEY_INFO:
5389 decodeFunc = CRYPT_AsnDecodePubKeyInfo;
5390 break;
5391 case (WORD)X509_ALTERNATE_NAME:
5392 decodeFunc = CRYPT_AsnDecodeAltName;
5393 break;
5394 case (WORD)X509_BASIC_CONSTRAINTS2:
5395 decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
5396 break;
5397 case (WORD)RSA_CSP_PUBLICKEYBLOB:
5398 decodeFunc = CRYPT_AsnDecodeRsaPubKey;
5399 break;
5400 case (WORD)X509_OCTET_STRING:
5401 decodeFunc = CRYPT_AsnDecodeOctets;
5402 break;
5403 case (WORD)X509_BITS:
5404 case (WORD)X509_KEY_USAGE:
5405 decodeFunc = CRYPT_AsnDecodeBits;
5406 break;
5407 case (WORD)X509_INTEGER:
5408 decodeFunc = CRYPT_AsnDecodeInt;
5409 break;
5410 case (WORD)X509_MULTI_BYTE_INTEGER:
5411 decodeFunc = CRYPT_AsnDecodeInteger;
5412 break;
5413 case (WORD)X509_MULTI_BYTE_UINT:
5414 decodeFunc = CRYPT_AsnDecodeUnsignedInteger;
5415 break;
5416 case (WORD)X509_ENUMERATED:
5417 decodeFunc = CRYPT_AsnDecodeEnumerated;
5418 break;
5419 case (WORD)X509_CHOICE_OF_TIME:
5420 decodeFunc = CRYPT_AsnDecodeChoiceOfTime;
5421 break;
5422 case (WORD)X509_SEQUENCE_OF_ANY:
5423 decodeFunc = CRYPT_AsnDecodeSequenceOfAny;
5424 break;
5425 case (WORD)PKCS_UTC_TIME:
5426 decodeFunc = CRYPT_AsnDecodeUtcTime;
5427 break;
5428 default:
5429 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
5432 else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
5433 decodeFunc = CRYPT_AsnDecodeExtensions;
5434 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
5435 decodeFunc = CRYPT_AsnDecodeUtcTime;
5436 else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
5437 decodeFunc = CRYPT_AsnDecodeEnumerated;
5438 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
5439 decodeFunc = CRYPT_AsnDecodeBits;
5440 else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
5441 decodeFunc = CRYPT_AsnDecodeOctets;
5442 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
5443 decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
5444 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
5445 decodeFunc = CRYPT_AsnDecodeAltName;
5446 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
5447 decodeFunc = CRYPT_AsnDecodeAltName;
5448 else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION))
5449 decodeFunc = CRYPT_AsnDecodeAltName;
5450 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
5451 decodeFunc = CRYPT_AsnDecodeAltName;
5452 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
5453 decodeFunc = CRYPT_AsnDecodeAltName;
5454 else
5455 TRACE("OID %s not found or unimplemented, looking for DLL\n",
5456 debugstr_a(lpszStructType));
5457 if (!decodeFunc)
5458 decodeFunc = (CryptDecodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
5459 lpszStructType, "CryptDecodeObjectEx", &lib);
5460 if (decodeFunc)
5461 ret = decodeFunc(dwCertEncodingType, lpszStructType, pbEncoded,
5462 cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
5463 else
5464 SetLastError(ERROR_FILE_NOT_FOUND);
5465 if (lib)
5466 FreeLibrary(lib);
5467 return ret;