added crypt32 (still not complete, from wine 0.91)
[reactos.git] / reactos / lib / crypt32 / encode.c
1 /*
2 * Copyright 2002 Mike McCormack for CodeWeavers
3 * Copyright 2005 Juan Lang
4 *
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.
9 *
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.
14 *
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
18 *
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.
23 *
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.)
28 *
29 * RFC3280, http://www.faqs.org/rfcs/rfc3280.html
30 *
31 * MSDN, especially:
32 * http://msdn.microsoft.com/library/en-us/seccrypto/security/constants_for_cryptencodeobject_and_cryptdecodeobject.asp
33 */
34
35 #include "precomp.h"
36
37 /* This is a bit arbitrary, but to set some limit: */
38 #define MAX_ENCODED_LEN 0x02000000
39
40 /* a few asn.1 tags we need */
41 #define ASN_BOOL (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x01)
42 #define ASN_BITSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x03)
43 #define ASN_OCTETSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x04)
44 #define ASN_ENUMERATED (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x0a)
45 #define ASN_SETOF (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x11)
46 #define ASN_NUMERICSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x12)
47 #define ASN_PRINTABLESTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x13)
48 #define ASN_IA5STRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x16)
49 #define ASN_UTCTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x17)
50 #define ASN_GENERALTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x18)
51
52 #define ASN_FLAGS_MASK 0xf0
53 #define ASN_TYPE_MASK 0x0f
54
55 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
56
57 static const WCHAR szDllName[] = { 'D','l','l',0 };
58
59 typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
60 BYTE *, DWORD *);
61 typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *,
62 DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *);
63 typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
64 DWORD, DWORD, void *, DWORD *);
65 typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *,
66 DWORD, DWORD, PCRYPT_DECODE_PARA, void *, DWORD *);
67
68 /* Prototypes for built-in encoders/decoders. They follow the Ex style
69 * prototypes. The dwCertEncodingType and lpszStructType are ignored by the
70 * built-in functions, but the parameters are retained to simplify
71 * CryptEncodeObjectEx/CryptDecodeObjectEx, since they must call functions in
72 * external DLLs that follow these signatures.
73 * FIXME: some built-in functions are suitable to be called directly by
74 * CryptEncodeObjectEx/CryptDecodeObjectEx (they implement exception handling
75 * and memory allocation if requested), others are only suitable to be called
76 * internally. Comment which are which.
77 */
78 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
79 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
80 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
81 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
82 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
83 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
84 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
85 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
86 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
87 static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
88 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
89 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
90 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
91 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
92 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
93 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
94 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
95 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
96 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
97 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
98 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
99 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
100 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
101 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
102 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
103 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
104 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
105 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
106 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
107 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
108 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
109 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
110 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
111
112 static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
113 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
114 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
115 static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType,
116 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
117 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
118 /* Like CRYPT_AsnDecodeExtensions, except assumes rgExtension is set ahead of
119 * time, doesn't do memory allocation, and doesn't do exception handling.
120 * (This isn't intended to be the externally-called one.)
121 */
122 static BOOL WINAPI CRYPT_AsnDecodeExtensionsInternal(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_AsnDecodeOid(const BYTE *pbEncoded, DWORD cbEncoded,
126 DWORD dwFlags, LPSTR pszObjId, DWORD *pcbObjId);
127 /* Assumes algo->Parameters.pbData is set ahead of time */
128 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
129 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
130 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
131 static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
132 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
133 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
134 /* Assumes the CRYPT_DATA_BLOB's pbData member has been initialized */
135 static BOOL WINAPI CRYPT_AsnDecodeOctetsInternal(DWORD dwCertEncodingType,
136 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
137 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
138 /* Like CRYPT_AsnDecodeBits, but assumes the CRYPT_INTEGER_BLOB's pbData
139 * member has been initialized, doesn't do exception handling, and doesn't do
140 * memory allocation.
141 */
142 static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
143 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
144 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
145 static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType,
146 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
147 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
148 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
149 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
150 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
151 /* Like CRYPT_AsnDecodeInteger, but assumes the CRYPT_INTEGER_BLOB's pbData
152 * member has been initialized, doesn't do exception handling, and doesn't do
153 * memory allocation.
154 */
155 static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType,
156 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
157 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
158 /* Like CRYPT_AsnDecodeInteger, but unsigned. */
159 static BOOL WINAPI CRYPT_AsnDecodeUnsignedIntegerInternal(
160 DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded,
161 DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
162 void *pvStructInfo, DWORD *pcbStructInfo);
163
164 /* filter for page-fault exceptions */
165 static WINE_EXCEPTION_FILTER(page_fault)
166 {
167 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
168 return EXCEPTION_EXECUTE_HANDLER;
169 return EXCEPTION_CONTINUE_SEARCH;
170 }
171
172 static char *CRYPT_GetKeyName(DWORD dwEncodingType, LPCSTR pszFuncName,
173 LPCSTR pszOID)
174 {
175 static const char szEncodingTypeFmt[] =
176 "Software\\Microsoft\\Cryptography\\OID\\EncodingType %ld\\%s\\%s";
177 UINT len;
178 char numericOID[7]; /* enough for "#65535" */
179 const char *oid;
180 LPSTR szKey;
181
182 /* MSDN says the encoding type is a mask, but it isn't treated that way.
183 * (E.g., if dwEncodingType were 3, the key names "EncodingType 1" and
184 * "EncodingType 2" would be expected if it were a mask. Instead native
185 * stores values in "EncodingType 3".
186 */
187 if (!HIWORD(pszOID))
188 {
189 snprintf(numericOID, sizeof(numericOID), "#%d", LOWORD(pszOID));
190 oid = numericOID;
191 }
192 else
193 oid = pszOID;
194
195 /* This is enough: the lengths of the two string parameters are explicitly
196 * counted, and we need up to five additional characters for the encoding
197 * type. These are covered by the "%d", "%s", and "%s" characters in the
198 * format specifier that are removed by sprintf.
199 */
200 len = sizeof(szEncodingTypeFmt) + lstrlenA(pszFuncName) + lstrlenA(oid);
201 szKey = CryptMemAlloc(len);
202 if (szKey)
203 sprintf(szKey, szEncodingTypeFmt, dwEncodingType, pszFuncName, oid);
204 return szKey;
205 }
206
207 BOOL WINAPI CryptRegisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
208 LPCSTR pszOID, LPCWSTR pwszDll, LPCSTR pszOverrideFuncName)
209 {
210 LONG r;
211 HKEY hKey;
212 LPSTR szKey;
213
214 TRACE("%lx %s %s %s %s\n", dwEncodingType, pszFuncName, pszOID,
215 debugstr_w(pwszDll), pszOverrideFuncName);
216
217 /* This only registers functions for encoding certs, not messages */
218 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
219 return TRUE;
220
221 /* Native does nothing pwszDll is NULL */
222 if (!pwszDll)
223 return TRUE;
224
225 /* I'm not matching MS bug for bug here, because I doubt any app depends on
226 * it:
227 * - native "succeeds" if pszFuncName is NULL, but the nonsensical entry
228 * it creates would never be used
229 * - native returns an HRESULT rather than a Win32 error if pszOID is NULL.
230 * Instead I disallow both of these with ERROR_INVALID_PARAMETER.
231 */
232 if (!pszFuncName || !pszOID)
233 {
234 SetLastError(ERROR_INVALID_PARAMETER);
235 return FALSE;
236 }
237
238 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
239 TRACE("Key name is %s\n", debugstr_a(szKey));
240
241 if (!szKey)
242 return FALSE;
243
244 r = RegCreateKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
245 CryptMemFree(szKey);
246 if(r != ERROR_SUCCESS)
247 return FALSE;
248
249 /* write the values */
250 if (pszOverrideFuncName)
251 RegSetValueExA(hKey, "FuncName", 0, REG_SZ, (const BYTE*)pszOverrideFuncName,
252 lstrlenA(pszOverrideFuncName) + 1);
253 RegSetValueExW(hKey, szDllName, 0, REG_SZ, (const BYTE*) pwszDll,
254 (lstrlenW(pwszDll) + 1) * sizeof (WCHAR));
255
256 RegCloseKey(hKey);
257 return TRUE;
258 }
259
260 BOOL WINAPI CryptUnregisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
261 LPCSTR pszOID)
262 {
263 LPSTR szKey;
264 LONG rc;
265
266 TRACE("%lx %s %s\n", dwEncodingType, pszFuncName, pszOID);
267
268 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
269 return TRUE;
270
271 if (!pszFuncName || !pszOID)
272 {
273 SetLastError(ERROR_INVALID_PARAMETER);
274 return FALSE;
275 }
276
277 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
278 rc = RegDeleteKeyA(HKEY_LOCAL_MACHINE, szKey);
279 CryptMemFree(szKey);
280 if (rc)
281 SetLastError(rc);
282 return rc ? FALSE : TRUE;
283 }
284
285 BOOL WINAPI CryptGetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
286 LPCSTR pszOID, LPCWSTR pwszValueName, DWORD *pdwValueType, BYTE *pbValueData,
287 DWORD *pcbValueData)
288 {
289 LPSTR szKey;
290 LONG rc;
291 HKEY hKey;
292
293 TRACE("%lx %s %s %s %p %p %p\n", dwEncodingType, debugstr_a(pszFuncName),
294 debugstr_a(pszOID), debugstr_w(pwszValueName), pdwValueType, pbValueData,
295 pcbValueData);
296
297 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
298 return TRUE;
299
300 if (!pszFuncName || !pszOID || !pwszValueName)
301 {
302 SetLastError(ERROR_INVALID_PARAMETER);
303 return FALSE;
304 }
305
306 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
307 rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
308 CryptMemFree(szKey);
309 if (rc)
310 SetLastError(rc);
311 else
312 {
313 rc = RegQueryValueExW(hKey, pwszValueName, NULL, pdwValueType,
314 pbValueData, pcbValueData);
315 if (rc)
316 SetLastError(rc);
317 RegCloseKey(hKey);
318 }
319 return rc ? FALSE : TRUE;
320 }
321
322 BOOL WINAPI CryptSetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
323 LPCSTR pszOID, LPCWSTR pwszValueName, DWORD dwValueType,
324 const BYTE *pbValueData, DWORD cbValueData)
325 {
326 LPSTR szKey;
327 LONG rc;
328 HKEY hKey;
329
330 TRACE("%lx %s %s %s %ld %p %ld\n", dwEncodingType, debugstr_a(pszFuncName),
331 debugstr_a(pszOID), debugstr_w(pwszValueName), dwValueType, pbValueData,
332 cbValueData);
333
334 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
335 return TRUE;
336
337 if (!pszFuncName || !pszOID || !pwszValueName)
338 {
339 SetLastError(ERROR_INVALID_PARAMETER);
340 return FALSE;
341 }
342
343 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
344 rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
345 CryptMemFree(szKey);
346 if (rc)
347 SetLastError(rc);
348 else
349 {
350 rc = RegSetValueExW(hKey, pwszValueName, 0, dwValueType, pbValueData,
351 cbValueData);
352 if (rc)
353 SetLastError(rc);
354 RegCloseKey(hKey);
355 }
356 return rc ? FALSE : TRUE;
357 }
358
359 /* Gets the registered function named szFuncName for dwCertEncodingType and
360 * lpszStructType, or NULL if one could not be found. *lib will be set to the
361 * handle of the module it's in, or NULL if no module was loaded. If the
362 * return value is NULL, *lib will also be NULL, to simplify error handling.
363 */
364 static void *CRYPT_GetFunc(DWORD dwCertEncodingType, LPCSTR lpszStructType,
365 LPCSTR szFuncName, HMODULE *lib)
366 {
367 void *ret = NULL;
368 char *szKey = CRYPT_GetKeyName(dwCertEncodingType, szFuncName,
369 lpszStructType);
370 const char *funcName;
371 long r;
372 HKEY hKey;
373 DWORD type, size = 0;
374
375 TRACE("(%08lx %s %s %p)\n", dwCertEncodingType, debugstr_a(lpszStructType),
376 debugstr_a(szFuncName), lib);
377
378 *lib = NULL;
379 r = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
380 CryptMemFree(szKey);
381 if(r != ERROR_SUCCESS)
382 return NULL;
383
384 RegQueryValueExA(hKey, "FuncName", NULL, &type, NULL, &size);
385 if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
386 {
387 funcName = CryptMemAlloc(size);
388 RegQueryValueExA(hKey, "FuncName", NULL, &type, (LPBYTE)funcName,
389 &size);
390 }
391 else
392 funcName = szFuncName;
393 RegQueryValueExW(hKey, szDllName, NULL, &type, NULL, &size);
394 if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
395 {
396 LPWSTR dllName = CryptMemAlloc(size);
397
398 RegQueryValueExW(hKey, szDllName, NULL, &type, (LPBYTE)dllName,
399 &size);
400 *lib = LoadLibraryW(dllName);
401 if (*lib)
402 {
403 ret = GetProcAddress(*lib, funcName);
404 if (!ret)
405 {
406 /* Unload the library, the caller doesn't want to unload it
407 * when the return value is NULL.
408 */
409 FreeLibrary(*lib);
410 *lib = NULL;
411 }
412 }
413 CryptMemFree(dllName);
414 }
415 if (funcName != szFuncName)
416 CryptMemFree((char *)funcName);
417 TRACE("returning %p\n", ret);
418 return ret;
419 }
420
421 BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
422 const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
423 {
424 BOOL ret = FALSE;
425 HMODULE lib;
426 CryptEncodeObjectFunc pCryptEncodeObject;
427
428 TRACE("(0x%08lx, %s, %p, %p, %p)\n", dwCertEncodingType,
429 debugstr_a(lpszStructType), pvStructInfo, pbEncoded,
430 pcbEncoded);
431
432 if (!pbEncoded && !pcbEncoded)
433 {
434 SetLastError(ERROR_INVALID_PARAMETER);
435 return FALSE;
436 }
437
438 /* Try registered DLL first.. */
439 pCryptEncodeObject =
440 (CryptEncodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
441 lpszStructType, CRYPT_OID_ENCODE_OBJECT_FUNC, &lib);
442 if (pCryptEncodeObject)
443 {
444 ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
445 pvStructInfo, pbEncoded, pcbEncoded);
446 FreeLibrary(lib);
447 }
448 else
449 {
450 /* If not, use CryptEncodeObjectEx */
451 ret = CryptEncodeObjectEx(dwCertEncodingType, lpszStructType,
452 pvStructInfo, 0, NULL, pbEncoded, pcbEncoded);
453 }
454 return ret;
455 }
456
457 /* Helper function to check *pcbEncoded, set it to the required size, and
458 * optionally to allocate memory. Assumes pbEncoded is not NULL.
459 * If CRYPT_ENCODE_ALLOC_FLAG is set in dwFlags, *pbEncoded will be set to a
460 * pointer to the newly allocated memory.
461 */
462 static BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags,
463 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded,
464 DWORD bytesNeeded)
465 {
466 BOOL ret = TRUE;
467
468 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
469 {
470 if (pEncodePara && pEncodePara->pfnAlloc)
471 *(BYTE **)pbEncoded = pEncodePara->pfnAlloc(bytesNeeded);
472 else
473 *(BYTE **)pbEncoded = LocalAlloc(0, bytesNeeded);
474 if (!*(BYTE **)pbEncoded)
475 ret = FALSE;
476 else
477 *pcbEncoded = bytesNeeded;
478 }
479 else if (bytesNeeded > *pcbEncoded)
480 {
481 *pcbEncoded = bytesNeeded;
482 SetLastError(ERROR_MORE_DATA);
483 ret = FALSE;
484 }
485 return ret;
486 }
487
488 static BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded)
489 {
490 DWORD bytesNeeded, significantBytes = 0;
491
492 if (len <= 0x7f)
493 bytesNeeded = 1;
494 else
495 {
496 DWORD temp;
497
498 for (temp = len, significantBytes = sizeof(temp); !(temp & 0xff000000);
499 temp <<= 8, significantBytes--)
500 ;
501 bytesNeeded = significantBytes + 1;
502 }
503 if (!pbEncoded)
504 {
505 *pcbEncoded = bytesNeeded;
506 return TRUE;
507 }
508 if (*pcbEncoded < bytesNeeded)
509 {
510 SetLastError(ERROR_MORE_DATA);
511 return FALSE;
512 }
513 if (len <= 0x7f)
514 *pbEncoded = (BYTE)len;
515 else
516 {
517 DWORD i;
518
519 *pbEncoded++ = significantBytes | 0x80;
520 for (i = 0; i < significantBytes; i++)
521 {
522 *(pbEncoded + significantBytes - i - 1) = (BYTE)(len & 0xff);
523 len >>= 8;
524 }
525 }
526 *pcbEncoded = bytesNeeded;
527 return TRUE;
528 }
529
530 struct AsnEncodeSequenceItem
531 {
532 const void *pvStructInfo;
533 CryptEncodeObjectExFunc encodeFunc;
534 DWORD size; /* used during encoding, not for your use */
535 };
536
537 static BOOL WINAPI CRYPT_AsnEncodeSequence(DWORD dwCertEncodingType,
538 struct AsnEncodeSequenceItem items[], DWORD cItem, DWORD dwFlags,
539 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
540 {
541 BOOL ret;
542 DWORD i, dataLen = 0;
543
544 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", items, cItem, dwFlags, pEncodePara,
545 pbEncoded, *pcbEncoded);
546 for (i = 0, ret = TRUE; ret && i < cItem; i++)
547 {
548 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
549 items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
550 NULL, &items[i].size);
551 dataLen += items[i].size;
552 }
553 if (ret)
554 {
555 DWORD lenBytes, bytesNeeded;
556
557 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
558 bytesNeeded = 1 + lenBytes + dataLen;
559 if (!pbEncoded)
560 *pcbEncoded = bytesNeeded;
561 else
562 {
563 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
564 pcbEncoded, bytesNeeded)))
565 {
566 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
567 pbEncoded = *(BYTE **)pbEncoded;
568 *pbEncoded++ = ASN_SEQUENCE;
569 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
570 pbEncoded += lenBytes;
571 for (i = 0; ret && i < cItem; i++)
572 {
573 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
574 items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG,
575 NULL, pbEncoded, &items[i].size);
576 pbEncoded += items[i].size;
577 }
578 }
579 }
580 }
581 TRACE("returning %d (%08lx)\n", ret, GetLastError());
582 return ret;
583 }
584
585 struct AsnConstructedItem
586 {
587 BYTE tag;
588 const void *pvStructInfo;
589 CryptEncodeObjectExFunc encodeFunc;
590 };
591
592 static BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType,
593 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
594 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
595 {
596 BOOL ret;
597 const struct AsnConstructedItem *item =
598 (const struct AsnConstructedItem *)pvStructInfo;
599 DWORD len;
600
601 if ((ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
602 item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &len)))
603 {
604 DWORD dataLen, bytesNeeded;
605
606 CRYPT_EncodeLen(len, NULL, &dataLen);
607 bytesNeeded = 1 + dataLen + len;
608 if (!pbEncoded)
609 *pcbEncoded = bytesNeeded;
610 else if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
611 pbEncoded, pcbEncoded, bytesNeeded)))
612 {
613 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
614 pbEncoded = *(BYTE **)pbEncoded;
615 *pbEncoded++ = ASN_CONTEXT | ASN_CONSTRUCTOR | item->tag;
616 CRYPT_EncodeLen(len, pbEncoded, &dataLen);
617 pbEncoded += dataLen;
618 ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
619 item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
620 pbEncoded, &len);
621 }
622 }
623 return ret;
624 }
625
626 static BOOL WINAPI CRYPT_AsnEncodeCertVersion(DWORD dwCertEncodingType,
627 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
628 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
629 {
630 const DWORD *ver = (const DWORD *)pvStructInfo;
631 BOOL ret;
632
633 /* CERT_V1 is not encoded */
634 if (*ver == CERT_V1)
635 {
636 *pcbEncoded = 0;
637 ret = TRUE;
638 }
639 else
640 {
641 struct AsnConstructedItem item = { 0, ver, CRYPT_AsnEncodeInt };
642
643 ret = CRYPT_AsnEncodeConstructed(dwCertEncodingType, X509_INTEGER,
644 &item, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
645 }
646 return ret;
647 }
648
649 static BOOL WINAPI CRYPT_CopyEncodedBlob(DWORD dwCertEncodingType,
650 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
651 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
652 {
653 const CRYPT_DER_BLOB *blob = (const CRYPT_DER_BLOB *)pvStructInfo;
654 BOOL ret;
655
656 if (!pbEncoded)
657 {
658 *pcbEncoded = blob->cbData;
659 ret = TRUE;
660 }
661 else if (*pcbEncoded < blob->cbData)
662 {
663 *pcbEncoded = blob->cbData;
664 SetLastError(ERROR_MORE_DATA);
665 ret = FALSE;
666 }
667 else
668 {
669 if (blob->cbData)
670 memcpy(pbEncoded, blob->pbData, blob->cbData);
671 *pcbEncoded = blob->cbData;
672 ret = TRUE;
673 }
674 return ret;
675 }
676
677 static BOOL WINAPI CRYPT_AsnEncodeValidity(DWORD dwCertEncodingType,
678 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
679 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
680 {
681 BOOL ret;
682 /* This has two filetimes in a row, a NotBefore and a NotAfter */
683 const FILETIME *timePtr = (const FILETIME *)pvStructInfo;
684 struct AsnEncodeSequenceItem items[] = {
685 { timePtr++, CRYPT_AsnEncodeChoiceOfTime, 0 },
686 { timePtr, CRYPT_AsnEncodeChoiceOfTime, 0 },
687 };
688
689 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
690 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
691 pcbEncoded);
692 return ret;
693 }
694
695 static BOOL WINAPI CRYPT_AsnEncodeAlgorithmId(
696 DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
697 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
698 DWORD *pcbEncoded)
699 {
700 const CRYPT_ALGORITHM_IDENTIFIER *algo =
701 (const CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
702 BOOL ret;
703 struct AsnEncodeSequenceItem items[] = {
704 { algo->pszObjId, CRYPT_AsnEncodeOid, 0 },
705 { &algo->Parameters, CRYPT_CopyEncodedBlob, 0 },
706 };
707
708 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
709 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
710 pcbEncoded);
711 return ret;
712 }
713
714 static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
715 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
716 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
717 {
718 BOOL ret;
719
720 _SEH_TRY
721 {
722 const CERT_PUBLIC_KEY_INFO *info =
723 (const CERT_PUBLIC_KEY_INFO *)pvStructInfo;
724 struct AsnEncodeSequenceItem items[] = {
725 { &info->Algorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
726 { &info->PublicKey, CRYPT_AsnEncodeBits, 0 },
727 };
728
729 TRACE("Encoding public key with OID %s\n",
730 debugstr_a(info->Algorithm.pszObjId));
731 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
732 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
733 pcbEncoded);
734 }
735 _SEH_EXCEPT(page_fault)
736 {
737 SetLastError(STATUS_ACCESS_VIOLATION);
738 ret = FALSE;
739 }
740 _SEH_END
741 return ret;
742 }
743
744 static BOOL WINAPI CRYPT_AsnEncodeCert(DWORD dwCertEncodingType,
745 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
746 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
747 {
748 BOOL ret;
749
750 _SEH_TRY
751 {
752 const CERT_SIGNED_CONTENT_INFO *info =
753 (const CERT_SIGNED_CONTENT_INFO *)pvStructInfo;
754 struct AsnEncodeSequenceItem items[] = {
755 { &info->ToBeSigned, CRYPT_CopyEncodedBlob, 0 },
756 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
757 { &info->Signature, CRYPT_AsnEncodeBitsSwapBytes, 0 },
758 };
759
760 if (dwFlags & CRYPT_ENCODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG)
761 items[2].encodeFunc = CRYPT_AsnEncodeBits;
762 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
763 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
764 pcbEncoded);
765 }
766 _SEH_EXCEPT(page_fault)
767 {
768 SetLastError(STATUS_ACCESS_VIOLATION);
769 ret = FALSE;
770 }
771 _SEH_END
772 return ret;
773 }
774
775 /* Like in Windows, this blithely ignores the validity of the passed-in
776 * CERT_INFO, and just encodes it as-is. The resulting encoded data may not
777 * decode properly, see CRYPT_AsnDecodeCertInfo.
778 */
779 static BOOL WINAPI CRYPT_AsnEncodeCertInfo(DWORD dwCertEncodingType,
780 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
781 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
782 {
783 BOOL ret;
784
785 _SEH_TRY
786 {
787 const CERT_INFO *info = (const CERT_INFO *)pvStructInfo;
788 struct AsnEncodeSequenceItem items[10] = {
789 { &info->dwVersion, CRYPT_AsnEncodeCertVersion, 0 },
790 { &info->SerialNumber, CRYPT_AsnEncodeInteger, 0 },
791 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
792 { &info->Issuer, CRYPT_CopyEncodedBlob, 0 },
793 { &info->NotBefore, CRYPT_AsnEncodeValidity, 0 },
794 { &info->Subject, CRYPT_CopyEncodedBlob, 0 },
795 { &info->SubjectPublicKeyInfo, CRYPT_AsnEncodePubKeyInfo, 0 },
796 { 0 }
797 };
798 struct AsnConstructedItem constructed[3] = { { 0 } };
799 DWORD cItem = 7, cConstructed = 0;
800
801 if (info->IssuerUniqueId.cbData)
802 {
803 constructed[cConstructed].tag = 1;
804 constructed[cConstructed].pvStructInfo = &info->IssuerUniqueId;
805 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
806 items[cItem].pvStructInfo = &constructed[cConstructed];
807 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
808 cConstructed++;
809 cItem++;
810 }
811 if (info->SubjectUniqueId.cbData)
812 {
813 constructed[cConstructed].tag = 2;
814 constructed[cConstructed].pvStructInfo = &info->SubjectUniqueId;
815 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
816 items[cItem].pvStructInfo = &constructed[cConstructed];
817 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
818 cConstructed++;
819 cItem++;
820 }
821 if (info->cExtension)
822 {
823 constructed[cConstructed].tag = 3;
824 constructed[cConstructed].pvStructInfo = &info->cExtension;
825 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeExtensions;
826 items[cItem].pvStructInfo = &constructed[cConstructed];
827 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
828 cConstructed++;
829 cItem++;
830 }
831
832 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
833 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
834 }
835 _SEH_EXCEPT(page_fault)
836 {
837 SetLastError(STATUS_ACCESS_VIOLATION);
838 ret = FALSE;
839 }
840 _SEH_END
841 return ret;
842 }
843
844 static BOOL WINAPI CRYPT_AsnEncodeCRLEntry(const CRL_ENTRY *entry,
845 BYTE *pbEncoded, DWORD *pcbEncoded)
846 {
847 struct AsnEncodeSequenceItem items[3] = {
848 { &entry->SerialNumber, CRYPT_AsnEncodeInteger, 0 },
849 { &entry->RevocationDate, CRYPT_AsnEncodeChoiceOfTime, 0 },
850 { 0 }
851 };
852 DWORD cItem = 2;
853 BOOL ret;
854
855 TRACE("%p, %p, %p\n", entry, pbEncoded, pcbEncoded);
856
857 if (entry->cExtension)
858 {
859 items[cItem].pvStructInfo = &entry->cExtension;
860 items[cItem].encodeFunc = CRYPT_AsnEncodeExtensions;
861 cItem++;
862 }
863
864 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
865 pbEncoded, pcbEncoded);
866
867 TRACE("returning %d (%08lx)\n", ret, GetLastError());
868 return ret;
869 }
870
871 static BOOL WINAPI CRYPT_AsnEncodeCRLEntries(DWORD dwCertEncodingType,
872 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
873 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
874 {
875 DWORD cCRLEntry = *(const DWORD *)pvStructInfo;
876 DWORD bytesNeeded, dataLen, lenBytes, i;
877 const CRL_ENTRY *rgCRLEntry = *(const CRL_ENTRY **)
878 ((const BYTE *)pvStructInfo + sizeof(DWORD));
879 BOOL ret = TRUE;
880
881 for (i = 0, dataLen = 0; ret && i < cCRLEntry; i++)
882 {
883 DWORD size;
884
885 ret = CRYPT_AsnEncodeCRLEntry(&rgCRLEntry[i], NULL, &size);
886 if (ret)
887 dataLen += size;
888 }
889 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
890 bytesNeeded = 1 + lenBytes + dataLen;
891 if (!pbEncoded)
892 *pcbEncoded = bytesNeeded;
893 else
894 {
895 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
896 pcbEncoded, bytesNeeded)))
897 {
898 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
899 pbEncoded = *(BYTE **)pbEncoded;
900 *pbEncoded++ = ASN_SEQUENCEOF;
901 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
902 pbEncoded += lenBytes;
903 for (i = 0; i < cCRLEntry; i++)
904 {
905 DWORD size = dataLen;
906
907 ret = CRYPT_AsnEncodeCRLEntry(&rgCRLEntry[i], pbEncoded, &size);
908 pbEncoded += size;
909 dataLen -= size;
910 }
911 }
912 }
913 return ret;
914 }
915
916 static BOOL WINAPI CRYPT_AsnEncodeCRLVersion(DWORD dwCertEncodingType,
917 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
918 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
919 {
920 const DWORD *ver = (const DWORD *)pvStructInfo;
921 BOOL ret;
922
923 /* CRL_V1 is not encoded */
924 if (*ver == CRL_V1)
925 {
926 *pcbEncoded = 0;
927 ret = TRUE;
928 }
929 else
930 ret = CRYPT_AsnEncodeInt(dwCertEncodingType, X509_INTEGER, ver,
931 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
932 return ret;
933 }
934
935 /* Like in Windows, this blithely ignores the validity of the passed-in
936 * CRL_INFO, and just encodes it as-is. The resulting encoded data may not
937 * decode properly, see CRYPT_AsnDecodeCRLInfo.
938 */
939 static BOOL WINAPI CRYPT_AsnEncodeCRLInfo(DWORD dwCertEncodingType,
940 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
941 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
942 {
943 BOOL ret;
944
945 _SEH_TRY
946 {
947 const CRL_INFO *info = (const CRL_INFO *)pvStructInfo;
948 struct AsnEncodeSequenceItem items[7] = {
949 { &info->dwVersion, CRYPT_AsnEncodeCRLVersion, 0 },
950 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
951 { &info->Issuer, CRYPT_CopyEncodedBlob, 0 },
952 { &info->ThisUpdate, CRYPT_AsnEncodeChoiceOfTime, 0 },
953 { 0 }
954 };
955 DWORD cItem = 4;
956
957 if (info->NextUpdate.dwLowDateTime || info->NextUpdate.dwHighDateTime)
958 {
959 items[cItem].pvStructInfo = &info->NextUpdate;
960 items[cItem].encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
961 cItem++;
962 }
963 if (info->cCRLEntry)
964 {
965 items[cItem].pvStructInfo = &info->cCRLEntry;
966 items[cItem].encodeFunc = CRYPT_AsnEncodeCRLEntries;
967 cItem++;
968 }
969 if (info->cExtension)
970 {
971 items[cItem].pvStructInfo = &info->cExtension;
972 items[cItem].encodeFunc = CRYPT_AsnEncodeExtensions;
973 cItem++;
974 }
975
976 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
977 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
978 }
979 _SEH_EXCEPT(page_fault)
980 {
981 SetLastError(STATUS_ACCESS_VIOLATION);
982 ret = FALSE;
983 }
984 _SEH_END
985 return ret;
986 }
987
988 static BOOL CRYPT_AsnEncodeExtension(CERT_EXTENSION *ext, BYTE *pbEncoded,
989 DWORD *pcbEncoded)
990 {
991 BOOL ret;
992 struct AsnEncodeSequenceItem items[3] = {
993 { ext->pszObjId, CRYPT_AsnEncodeOid, 0 },
994 { NULL, NULL, 0 },
995 { NULL, NULL, 0 },
996 };
997 DWORD cItem = 1;
998
999 TRACE("%p, %p, %ld\n", ext, pbEncoded, *pcbEncoded);
1000
1001 if (ext->fCritical)
1002 {
1003 items[cItem].pvStructInfo = &ext->fCritical;
1004 items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
1005 cItem++;
1006 }
1007 items[cItem].pvStructInfo = &ext->Value;
1008 items[cItem].encodeFunc = CRYPT_AsnEncodeOctets;
1009 cItem++;
1010
1011 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
1012 pbEncoded, pcbEncoded);
1013 TRACE("returning %d (%08lx)\n", ret, GetLastError());
1014 return ret;
1015 }
1016
1017 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
1018 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1019 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1020 {
1021 BOOL ret;
1022
1023 _SEH_TRY
1024 {
1025 DWORD bytesNeeded, dataLen, lenBytes, i;
1026 const CERT_EXTENSIONS *exts = (const CERT_EXTENSIONS *)pvStructInfo;
1027
1028 ret = TRUE;
1029 for (i = 0, dataLen = 0; ret && i < exts->cExtension; i++)
1030 {
1031 DWORD size;
1032
1033 ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i], NULL, &size);
1034 if (ret)
1035 dataLen += size;
1036 }
1037 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1038 bytesNeeded = 1 + lenBytes + dataLen;
1039 if (!pbEncoded)
1040 *pcbEncoded = bytesNeeded;
1041 else
1042 {
1043 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1044 pcbEncoded, bytesNeeded)))
1045 {
1046 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1047 pbEncoded = *(BYTE **)pbEncoded;
1048 *pbEncoded++ = ASN_SEQUENCEOF;
1049 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1050 pbEncoded += lenBytes;
1051 for (i = 0; i < exts->cExtension; i++)
1052 {
1053 DWORD size = dataLen;
1054
1055 ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i],
1056 pbEncoded, &size);
1057 pbEncoded += size;
1058 dataLen -= size;
1059 }
1060 }
1061 }
1062 }
1063 _SEH_EXCEPT(page_fault)
1064 {
1065 SetLastError(STATUS_ACCESS_VIOLATION);
1066 ret = FALSE;
1067 }
1068 _SEH_END
1069 return ret;
1070 }
1071
1072 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
1073 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1074 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1075 {
1076 LPCSTR pszObjId = (LPCSTR)pvStructInfo;
1077 DWORD bytesNeeded = 0, lenBytes;
1078 BOOL ret = TRUE;
1079 int firstPos = 0;
1080 BYTE firstByte = 0;
1081
1082 TRACE("%s\n", debugstr_a(pszObjId));
1083
1084 if (pszObjId)
1085 {
1086 const char *ptr;
1087 int val1, val2;
1088
1089 if (sscanf(pszObjId, "%d.%d.%n", &val1, &val2, &firstPos) != 2)
1090 {
1091 SetLastError(CRYPT_E_ASN1_ERROR);
1092 return FALSE;
1093 }
1094 bytesNeeded++;
1095 firstByte = val1 * 40 + val2;
1096 ptr = pszObjId + firstPos;
1097 while (ret && *ptr)
1098 {
1099 int pos;
1100
1101 /* note I assume each component is at most 32-bits long in base 2 */
1102 if (sscanf(ptr, "%d%n", &val1, &pos) == 1)
1103 {
1104 if (val1 >= 0x10000000)
1105 bytesNeeded += 5;
1106 else if (val1 >= 0x200000)
1107 bytesNeeded += 4;
1108 else if (val1 >= 0x4000)
1109 bytesNeeded += 3;
1110 else if (val1 >= 0x80)
1111 bytesNeeded += 2;
1112 else
1113 bytesNeeded += 1;
1114 ptr += pos;
1115 if (*ptr == '.')
1116 ptr++;
1117 }
1118 else
1119 {
1120 SetLastError(CRYPT_E_ASN1_ERROR);
1121 return FALSE;
1122 }
1123 }
1124 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1125 }
1126 else
1127 lenBytes = 1;
1128 bytesNeeded += 1 + lenBytes;
1129 if (pbEncoded)
1130 {
1131 if (*pcbEncoded < bytesNeeded)
1132 {
1133 SetLastError(ERROR_MORE_DATA);
1134 ret = FALSE;
1135 }
1136 else
1137 {
1138 *pbEncoded++ = ASN_OBJECTIDENTIFIER;
1139 CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded, &lenBytes);
1140 pbEncoded += lenBytes;
1141 if (pszObjId)
1142 {
1143 const char *ptr;
1144 int val, pos;
1145
1146 *pbEncoded++ = firstByte;
1147 ptr = pszObjId + firstPos;
1148 while (ret && *ptr)
1149 {
1150 sscanf(ptr, "%d%n", &val, &pos);
1151 {
1152 unsigned char outBytes[5];
1153 int numBytes, i;
1154
1155 if (val >= 0x10000000)
1156 numBytes = 5;
1157 else if (val >= 0x200000)
1158 numBytes = 4;
1159 else if (val >= 0x4000)
1160 numBytes = 3;
1161 else if (val >= 0x80)
1162 numBytes = 2;
1163 else
1164 numBytes = 1;
1165 for (i = numBytes; i > 0; i--)
1166 {
1167 outBytes[i - 1] = val & 0x7f;
1168 val >>= 7;
1169 }
1170 for (i = 0; i < numBytes - 1; i++)
1171 *pbEncoded++ = outBytes[i] | 0x80;
1172 *pbEncoded++ = outBytes[i];
1173 ptr += pos;
1174 if (*ptr == '.')
1175 ptr++;
1176 }
1177 }
1178 }
1179 }
1180 }
1181 *pcbEncoded = bytesNeeded;
1182 return ret;
1183 }
1184
1185 static BOOL WINAPI CRYPT_AsnEncodeNameValue(DWORD dwCertEncodingType,
1186 CERT_NAME_VALUE *value, BYTE *pbEncoded, DWORD *pcbEncoded)
1187 {
1188 BYTE tag;
1189 DWORD bytesNeeded, lenBytes, encodedLen;
1190 BOOL ret = TRUE;
1191
1192 switch (value->dwValueType)
1193 {
1194 case CERT_RDN_NUMERIC_STRING:
1195 tag = ASN_NUMERICSTRING;
1196 encodedLen = value->Value.cbData;
1197 break;
1198 case CERT_RDN_PRINTABLE_STRING:
1199 tag = ASN_PRINTABLESTRING;
1200 encodedLen = value->Value.cbData;
1201 break;
1202 case CERT_RDN_IA5_STRING:
1203 tag = ASN_IA5STRING;
1204 encodedLen = value->Value.cbData;
1205 break;
1206 case CERT_RDN_ANY_TYPE:
1207 /* explicitly disallowed */
1208 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1209 return FALSE;
1210 default:
1211 FIXME("String type %ld unimplemented\n", value->dwValueType);
1212 return FALSE;
1213 }
1214 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1215 bytesNeeded = 1 + lenBytes + encodedLen;
1216 if (pbEncoded)
1217 {
1218 if (*pcbEncoded < bytesNeeded)
1219 {
1220 SetLastError(ERROR_MORE_DATA);
1221 ret = FALSE;
1222 }
1223 else
1224 {
1225 *pbEncoded++ = tag;
1226 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1227 pbEncoded += lenBytes;
1228 switch (value->dwValueType)
1229 {
1230 case CERT_RDN_NUMERIC_STRING:
1231 case CERT_RDN_PRINTABLE_STRING:
1232 case CERT_RDN_IA5_STRING:
1233 memcpy(pbEncoded, value->Value.pbData, value->Value.cbData);
1234 }
1235 }
1236 }
1237 *pcbEncoded = bytesNeeded;
1238 return ret;
1239 }
1240
1241 static BOOL WINAPI CRYPT_AsnEncodeRdnAttr(DWORD dwCertEncodingType,
1242 CERT_RDN_ATTR *attr, BYTE *pbEncoded, DWORD *pcbEncoded)
1243 {
1244 DWORD bytesNeeded = 0, lenBytes, size;
1245 BOOL ret;
1246
1247 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL, attr->pszObjId,
1248 0, NULL, NULL, &size);
1249 if (ret)
1250 {
1251 bytesNeeded += size;
1252 /* hack: a CERT_RDN_ATTR is identical to a CERT_NAME_VALUE beginning
1253 * with dwValueType, so "cast" it to get its encoded size
1254 */
1255 ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
1256 (CERT_NAME_VALUE *)&attr->dwValueType, NULL, &size);
1257 if (ret)
1258 {
1259 bytesNeeded += size;
1260 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1261 bytesNeeded += 1 + lenBytes;
1262 if (pbEncoded)
1263 {
1264 if (*pcbEncoded < bytesNeeded)
1265 {
1266 SetLastError(ERROR_MORE_DATA);
1267 ret = FALSE;
1268 }
1269 else
1270 {
1271 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SEQUENCE;
1272 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1273 &lenBytes);
1274 pbEncoded += lenBytes;
1275 size = bytesNeeded - 1 - lenBytes;
1276 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
1277 attr->pszObjId, 0, NULL, pbEncoded, &size);
1278 if (ret)
1279 {
1280 pbEncoded += size;
1281 size = bytesNeeded - 1 - lenBytes - size;
1282 ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
1283 (CERT_NAME_VALUE *)&attr->dwValueType, pbEncoded,
1284 &size);
1285 }
1286 }
1287 }
1288 *pcbEncoded = bytesNeeded;
1289 }
1290 }
1291 return ret;
1292 }
1293
1294 static int BLOBComp(const void *l, const void *r)
1295 {
1296 CRYPT_DER_BLOB *a = (CRYPT_DER_BLOB *)l, *b = (CRYPT_DER_BLOB *)r;
1297 int ret;
1298
1299 if (!(ret = memcmp(a->pbData, b->pbData, min(a->cbData, b->cbData))))
1300 ret = a->cbData - b->cbData;
1301 return ret;
1302 }
1303
1304 /* This encodes as a SET OF, which in DER must be lexicographically sorted.
1305 */
1306 static BOOL WINAPI CRYPT_AsnEncodeRdn(DWORD dwCertEncodingType, CERT_RDN *rdn,
1307 BYTE *pbEncoded, DWORD *pcbEncoded)
1308 {
1309 BOOL ret;
1310 CRYPT_DER_BLOB *blobs = NULL;
1311
1312 _SEH_TRY
1313 {
1314 DWORD bytesNeeded = 0, lenBytes, i;
1315
1316 blobs = NULL;
1317 ret = TRUE;
1318 if (rdn->cRDNAttr)
1319 {
1320 blobs = CryptMemAlloc(rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
1321 if (!blobs)
1322 ret = FALSE;
1323 else
1324 memset(blobs, 0, rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
1325 }
1326 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1327 {
1328 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType, &rdn->rgRDNAttr[i],
1329 NULL, &blobs[i].cbData);
1330 if (ret)
1331 bytesNeeded += blobs[i].cbData;
1332 }
1333 if (ret)
1334 {
1335 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1336 bytesNeeded += 1 + lenBytes;
1337 if (pbEncoded)
1338 {
1339 if (*pcbEncoded < bytesNeeded)
1340 {
1341 SetLastError(ERROR_MORE_DATA);
1342 ret = FALSE;
1343 }
1344 else
1345 {
1346 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1347 {
1348 blobs[i].pbData = CryptMemAlloc(blobs[i].cbData);
1349 if (!blobs[i].pbData)
1350 ret = FALSE;
1351 else
1352 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType,
1353 &rdn->rgRDNAttr[i], blobs[i].pbData,
1354 &blobs[i].cbData);
1355 }
1356 if (ret)
1357 {
1358 qsort(blobs, rdn->cRDNAttr, sizeof(CRYPT_DER_BLOB),
1359 BLOBComp);
1360 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF;
1361 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1362 &lenBytes);
1363 pbEncoded += lenBytes;
1364 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1365 {
1366 memcpy(pbEncoded, blobs[i].pbData, blobs[i].cbData);
1367 pbEncoded += blobs[i].cbData;
1368 }
1369 }
1370 }
1371 }
1372 *pcbEncoded = bytesNeeded;
1373 }
1374 if (blobs)
1375 {
1376 for (i = 0; i < rdn->cRDNAttr; i++)
1377 CryptMemFree(blobs[i].pbData);
1378 }
1379 }
1380 _SEH_EXCEPT(page_fault)
1381 {
1382 SetLastError(STATUS_ACCESS_VIOLATION);
1383 return FALSE;
1384 }
1385 _SEH_END
1386 CryptMemFree(blobs);
1387 return ret;
1388 }
1389
1390 static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
1391 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1392 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1393 {
1394 BOOL ret;
1395
1396 _SEH_TRY
1397 {
1398 const CERT_NAME_INFO *info = (const CERT_NAME_INFO *)pvStructInfo;
1399 DWORD bytesNeeded = 0, lenBytes, size, i;
1400
1401 TRACE("encoding name with %ld RDNs\n", info->cRDN);
1402 ret = TRUE;
1403 for (i = 0; ret && i < info->cRDN; i++)
1404 {
1405 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i], NULL,
1406 &size);
1407 if (ret)
1408 bytesNeeded += size;
1409 }
1410 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1411 bytesNeeded += 1 + lenBytes;
1412 if (ret)
1413 {
1414 if (!pbEncoded)
1415 *pcbEncoded = bytesNeeded;
1416 else
1417 {
1418 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1419 pbEncoded, pcbEncoded, bytesNeeded)))
1420 {
1421 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1422 pbEncoded = *(BYTE **)pbEncoded;
1423 *pbEncoded++ = ASN_SEQUENCEOF;
1424 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1425 &lenBytes);
1426 pbEncoded += lenBytes;
1427 for (i = 0; ret && i < info->cRDN; i++)
1428 {
1429 size = bytesNeeded;
1430 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType,
1431 &info->rgRDN[i], pbEncoded, &size);
1432 if (ret)
1433 {
1434 pbEncoded += size;
1435 bytesNeeded -= size;
1436 }
1437 }
1438 }
1439 }
1440 }
1441 }
1442 _SEH_EXCEPT(page_fault)
1443 {
1444 SetLastError(STATUS_ACCESS_VIOLATION);
1445 ret = FALSE;
1446 }
1447 _SEH_END
1448 return ret;
1449 }
1450
1451 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
1452 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1453 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1454 {
1455 BOOL val = *(const BOOL *)pvStructInfo, ret;
1456
1457 TRACE("%d\n", val);
1458
1459 if (!pbEncoded)
1460 {
1461 *pcbEncoded = 3;
1462 ret = TRUE;
1463 }
1464 else if (*pcbEncoded < 3)
1465 {
1466 *pcbEncoded = 3;
1467 SetLastError(ERROR_MORE_DATA);
1468 ret = FALSE;
1469 }
1470 else
1471 {
1472 *pcbEncoded = 3;
1473 *pbEncoded++ = ASN_BOOL;
1474 *pbEncoded++ = 1;
1475 *pbEncoded++ = val ? 0xff : 0;
1476 ret = TRUE;
1477 }
1478 TRACE("returning %d (%08lx)\n", ret, GetLastError());
1479 return ret;
1480 }
1481
1482 static BOOL CRYPT_AsnEncodeAltNameEntry(const CERT_ALT_NAME_ENTRY *entry,
1483 BYTE *pbEncoded, DWORD *pcbEncoded)
1484 {
1485 BOOL ret;
1486 DWORD dataLen;
1487
1488 ret = TRUE;
1489 switch (entry->dwAltNameChoice)
1490 {
1491 case CERT_ALT_NAME_RFC822_NAME:
1492 case CERT_ALT_NAME_DNS_NAME:
1493 case CERT_ALT_NAME_URL:
1494 if (entry->u.pwszURL)
1495 {
1496 DWORD i;
1497
1498 /* Not + 1: don't encode the NULL-terminator */
1499 dataLen = lstrlenW(entry->u.pwszURL);
1500 for (i = 0; ret && i < dataLen; i++)
1501 {
1502 if (entry->u.pwszURL[i] > 0x7f)
1503 {
1504 SetLastError(CRYPT_E_INVALID_IA5_STRING);
1505 ret = FALSE;
1506 *pcbEncoded = i;
1507 }
1508 }
1509 }
1510 else
1511 dataLen = 0;
1512 break;
1513 case CERT_ALT_NAME_IP_ADDRESS:
1514 dataLen = entry->u.IPAddress.cbData;
1515 break;
1516 case CERT_ALT_NAME_REGISTERED_ID:
1517 /* FIXME: encode OID */
1518 case CERT_ALT_NAME_OTHER_NAME:
1519 case CERT_ALT_NAME_DIRECTORY_NAME:
1520 FIXME("name type %ld unimplemented\n", entry->dwAltNameChoice);
1521 return FALSE;
1522 default:
1523 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1524 return FALSE;
1525 }
1526 if (ret)
1527 {
1528 DWORD bytesNeeded, lenBytes;
1529
1530 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1531 bytesNeeded = 1 + dataLen + lenBytes;
1532 if (!pbEncoded)
1533 *pcbEncoded = bytesNeeded;
1534 else if (*pcbEncoded < bytesNeeded)
1535 {
1536 SetLastError(ERROR_MORE_DATA);
1537 *pcbEncoded = bytesNeeded;
1538 ret = FALSE;
1539 }
1540 else
1541 {
1542 *pbEncoded++ = ASN_CONTEXT | (entry->dwAltNameChoice - 1);
1543 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1544 pbEncoded += lenBytes;
1545 switch (entry->dwAltNameChoice)
1546 {
1547 case CERT_ALT_NAME_RFC822_NAME:
1548 case CERT_ALT_NAME_DNS_NAME:
1549 case CERT_ALT_NAME_URL:
1550 {
1551 DWORD i;
1552
1553 for (i = 0; i < dataLen; i++)
1554 *pbEncoded++ = (BYTE)entry->u.pwszURL[i];
1555 break;
1556 }
1557 case CERT_ALT_NAME_IP_ADDRESS:
1558 memcpy(pbEncoded, entry->u.IPAddress.pbData, dataLen);
1559 break;
1560 }
1561 if (ret)
1562 *pcbEncoded = bytesNeeded;
1563 }
1564 }
1565 TRACE("returning %d (%08lx)\n", ret, GetLastError());
1566 return ret;
1567 }
1568
1569 static BOOL WINAPI CRYPT_AsnEncodeAltName(DWORD dwCertEncodingType,
1570 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1571 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1572 {
1573 BOOL ret;
1574
1575 _SEH_TRY
1576 {
1577 const CERT_ALT_NAME_INFO *info =
1578 (const CERT_ALT_NAME_INFO *)pvStructInfo;
1579
1580 DWORD bytesNeeded, dataLen, lenBytes, i;
1581
1582 ret = TRUE;
1583 /* FIXME: should check that cAltEntry is not bigger than 0xff, since we
1584 * can't encode an erroneous entry index if it's bigger than this.
1585 */
1586 for (i = 0, dataLen = 0; ret && i < info->cAltEntry; i++)
1587 {
1588 DWORD len;
1589
1590 ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i], NULL,
1591 &len);
1592 if (ret)
1593 dataLen += len;
1594 else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
1595 {
1596 /* CRYPT_AsnEncodeAltNameEntry encoded the index of
1597 * the bad character, now set the index of the bad
1598 * entry
1599 */
1600 *pcbEncoded = (BYTE)i <<
1601 CERT_ALT_NAME_ENTRY_ERR_INDEX_SHIFT | len;
1602 }
1603 }
1604 if (ret)
1605 {
1606 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1607 bytesNeeded = 1 + lenBytes + dataLen;
1608 if (!pbEncoded)
1609 {
1610 *pcbEncoded = bytesNeeded;
1611 ret = TRUE;
1612 }
1613 else
1614 {
1615 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1616 pbEncoded, pcbEncoded, bytesNeeded)))
1617 {
1618 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1619 pbEncoded = *(BYTE **)pbEncoded;
1620 *pbEncoded++ = ASN_SEQUENCEOF;
1621 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1622 pbEncoded += lenBytes;
1623 for (i = 0; ret && i < info->cAltEntry; i++)
1624 {
1625 DWORD len = dataLen;
1626
1627 ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i],
1628 pbEncoded, &len);
1629 if (ret)
1630 {
1631 pbEncoded += len;
1632 dataLen -= len;
1633 }
1634 }
1635 }
1636 }
1637 }
1638 }
1639 _SEH_EXCEPT(page_fault)
1640 {
1641 SetLastError(STATUS_ACCESS_VIOLATION);
1642 ret = FALSE;
1643 }
1644 _SEH_END
1645 return ret;
1646 }
1647
1648 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
1649 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1650 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1651 {
1652 BOOL ret;
1653
1654 _SEH_TRY
1655 {
1656 const CERT_BASIC_CONSTRAINTS2_INFO *info =
1657 (const CERT_BASIC_CONSTRAINTS2_INFO *)pvStructInfo;
1658 struct AsnEncodeSequenceItem items[2] = { { 0 } };
1659 DWORD cItem = 0;
1660
1661 if (info->fCA)
1662 {
1663 items[cItem].pvStructInfo = &info->fCA;
1664 items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
1665 cItem++;
1666 }
1667 if (info->fPathLenConstraint)
1668 {
1669 items[cItem].pvStructInfo = &info->dwPathLenConstraint;
1670 items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
1671 cItem++;
1672 }
1673 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
1674 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1675 }
1676 _SEH_EXCEPT(page_fault)
1677 {
1678 SetLastError(STATUS_ACCESS_VIOLATION);
1679 ret = FALSE;
1680 }
1681 _SEH_END
1682 return ret;
1683 }
1684
1685 static BOOL WINAPI CRYPT_AsnEncodeRsaPubKey(DWORD dwCertEncodingType,
1686 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1687 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1688 {
1689 BOOL ret;
1690
1691 _SEH_TRY
1692 {
1693 const BLOBHEADER *hdr =
1694 (const BLOBHEADER *)pvStructInfo;
1695
1696 if (hdr->bType != PUBLICKEYBLOB)
1697 {
1698 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1699 ret = FALSE;
1700 }
1701 else
1702 {
1703 const RSAPUBKEY *rsaPubKey = (const RSAPUBKEY *)
1704 ((const BYTE *)pvStructInfo + sizeof(BLOBHEADER));
1705 CRYPT_INTEGER_BLOB blob = { rsaPubKey->bitlen / 8,
1706 (BYTE *)pvStructInfo + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) };
1707 struct AsnEncodeSequenceItem items[] = {
1708 { &blob, CRYPT_AsnEncodeUnsignedInteger, 0 },
1709 { &rsaPubKey->pubexp, CRYPT_AsnEncodeInt, 0 },
1710 };
1711
1712 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
1713 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
1714 pcbEncoded);
1715 }
1716 }
1717 _SEH_EXCEPT(page_fault)
1718 {
1719 SetLastError(STATUS_ACCESS_VIOLATION);
1720 ret = FALSE;
1721 }
1722 _SEH_END
1723 return ret;
1724 }
1725
1726 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
1727 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1728 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1729 {
1730 BOOL ret;
1731
1732 _SEH_TRY
1733 {
1734 const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo;
1735 DWORD bytesNeeded, lenBytes;
1736
1737 TRACE("(%ld, %p), %08lx, %p, %p, %ld\n", blob->cbData, blob->pbData,
1738 dwFlags, pEncodePara, pbEncoded, *pcbEncoded);
1739
1740 CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
1741 bytesNeeded = 1 + lenBytes + blob->cbData;
1742 if (!pbEncoded)
1743 {
1744 *pcbEncoded = bytesNeeded;
1745 ret = TRUE;
1746 }
1747 else
1748 {
1749 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1750 pcbEncoded, bytesNeeded)))
1751 {
1752 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1753 pbEncoded = *(BYTE **)pbEncoded;
1754 *pbEncoded++ = ASN_OCTETSTRING;
1755 CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
1756 pbEncoded += lenBytes;
1757 if (blob->cbData)
1758 memcpy(pbEncoded, blob->pbData, blob->cbData);
1759 }
1760 }
1761 }
1762 _SEH_EXCEPT(page_fault)
1763 {
1764 SetLastError(STATUS_ACCESS_VIOLATION);
1765 ret = FALSE;
1766 }
1767 _SEH_END
1768 TRACE("returning %d (%08lx)\n", ret, GetLastError());
1769 return ret;
1770 }
1771
1772 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
1773 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1774 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1775 {
1776 BOOL ret;
1777
1778 _SEH_TRY
1779 {
1780 const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
1781 DWORD bytesNeeded, lenBytes, dataBytes;
1782 BYTE unusedBits;
1783
1784 /* yep, MS allows cUnusedBits to be >= 8 */
1785 if (!blob->cUnusedBits)
1786 {
1787 dataBytes = blob->cbData;
1788 unusedBits = 0;
1789 }
1790 else if (blob->cbData * 8 > blob->cUnusedBits)
1791 {
1792 dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
1793 unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
1794 blob->cUnusedBits;
1795 }
1796 else
1797 {
1798 dataBytes = 0;
1799 unusedBits = 0;
1800 }
1801 CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
1802 bytesNeeded = 1 + lenBytes + dataBytes + 1;
1803 if (!pbEncoded)
1804 {
1805 *pcbEncoded = bytesNeeded;
1806 ret = TRUE;
1807 }
1808 else
1809 {
1810 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1811 pcbEncoded, bytesNeeded)))
1812 {
1813 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1814 pbEncoded = *(BYTE **)pbEncoded;
1815 *pbEncoded++ = ASN_BITSTRING;
1816 CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
1817 pbEncoded += lenBytes;
1818 *pbEncoded++ = unusedBits;
1819 if (dataBytes)
1820 {
1821 BYTE mask = 0xff << unusedBits;
1822
1823 if (dataBytes > 1)
1824 {
1825 memcpy(pbEncoded, blob->pbData, dataBytes - 1);
1826 pbEncoded += dataBytes - 1;
1827 }
1828 *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
1829 }
1830 }
1831 }
1832 }
1833 _SEH_EXCEPT(page_fault)
1834 {
1835 SetLastError(STATUS_ACCESS_VIOLATION);
1836 ret = FALSE;
1837 }
1838 _SEH_END
1839 return ret;
1840 }
1841
1842 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
1843 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1844 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1845 {
1846 BOOL ret;
1847
1848 _SEH_TRY
1849 {
1850 const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
1851 CRYPT_BIT_BLOB newBlob = { blob->cbData, NULL, blob->cUnusedBits };
1852
1853 ret = TRUE;
1854 if (newBlob.cbData)
1855 {
1856 newBlob.pbData = CryptMemAlloc(newBlob.cbData);
1857 if (newBlob.pbData)
1858 {
1859 DWORD i;
1860
1861 for (i = 0; i < newBlob.cbData; i++)
1862 newBlob.pbData[newBlob.cbData - i - 1] = blob->pbData[i];
1863 }
1864 else
1865 ret = FALSE;
1866 }
1867 if (ret)
1868 ret = CRYPT_AsnEncodeBits(dwCertEncodingType, lpszStructType,
1869 &newBlob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1870 CryptMemFree(newBlob.pbData);
1871 }
1872 _SEH_EXCEPT(page_fault)
1873 {
1874 SetLastError(STATUS_ACCESS_VIOLATION);
1875 ret = FALSE;
1876 }
1877 _SEH_END
1878 return ret;
1879 }
1880
1881 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
1882 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1883 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1884 {
1885 CRYPT_INTEGER_BLOB blob = { sizeof(INT), (BYTE *)pvStructInfo };
1886
1887 return CRYPT_AsnEncodeInteger(dwCertEncodingType, X509_MULTI_BYTE_INTEGER,
1888 &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1889 }
1890
1891 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
1892 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1893 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1894 {
1895 BOOL ret;
1896
1897 _SEH_TRY
1898 {
1899 DWORD significantBytes, lenBytes;
1900 BYTE padByte = 0, bytesNeeded;
1901 BOOL pad = FALSE;
1902 const CRYPT_INTEGER_BLOB *blob =
1903 (const CRYPT_INTEGER_BLOB *)pvStructInfo;
1904
1905 significantBytes = blob->cbData;
1906 if (significantBytes)
1907 {
1908 if (blob->pbData[significantBytes - 1] & 0x80)
1909 {
1910 /* negative, lop off leading (little-endian) 0xffs */
1911 for (; significantBytes > 0 &&
1912 blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
1913 ;
1914 if (blob->pbData[significantBytes - 1] < 0x80)
1915 {
1916 padByte = 0xff;
1917 pad = TRUE;
1918 }
1919 }
1920 else
1921 {
1922 /* positive, lop off leading (little-endian) zeroes */
1923 for (; significantBytes > 0 &&
1924 !blob->pbData[significantBytes - 1]; significantBytes--)
1925 ;
1926 if (significantBytes == 0)
1927 significantBytes = 1;
1928 if (blob->pbData[significantBytes - 1] > 0x7f)
1929 {
1930 padByte = 0;
1931 pad = TRUE;
1932 }
1933 }
1934 }
1935 if (pad)
1936 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
1937 else
1938 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
1939 bytesNeeded = 1 + lenBytes + significantBytes;
1940 if (pad)
1941 bytesNeeded++;
1942 if (!pbEncoded)
1943 {
1944 *pcbEncoded = bytesNeeded;
1945 ret = TRUE;
1946 }
1947 else
1948 {
1949 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1950 pcbEncoded, bytesNeeded)))
1951 {
1952 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1953 pbEncoded = *(BYTE **)pbEncoded;
1954 *pbEncoded++ = ASN_INTEGER;
1955 if (pad)
1956 {
1957 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
1958 pbEncoded += lenBytes;
1959 *pbEncoded++ = padByte;
1960 }
1961 else
1962 {
1963 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
1964 pbEncoded += lenBytes;
1965 }
1966 for (; significantBytes > 0; significantBytes--)
1967 *(pbEncoded++) = blob->pbData[significantBytes - 1];
1968 }
1969 }
1970 }
1971 _SEH_EXCEPT(page_fault)
1972 {
1973 SetLastError(STATUS_ACCESS_VIOLATION);
1974 ret = FALSE;
1975 }
1976 _SEH_END
1977 return ret;
1978 }
1979
1980 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
1981 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1982 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1983 {
1984 BOOL ret;
1985
1986 _SEH_TRY
1987 {
1988 DWORD significantBytes, lenBytes;
1989 BYTE bytesNeeded;
1990 BOOL pad = FALSE;
1991 const CRYPT_INTEGER_BLOB *blob =
1992 (const CRYPT_INTEGER_BLOB *)pvStructInfo;
1993
1994 significantBytes = blob->cbData;
1995 if (significantBytes)
1996 {
1997 /* positive, lop off leading (little-endian) zeroes */
1998 for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
1999 significantBytes--)
2000 ;
2001 if (significantBytes == 0)
2002 significantBytes = 1;
2003 if (blob->pbData[significantBytes - 1] > 0x7f)
2004 pad = TRUE;
2005 }
2006 if (pad)
2007 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
2008 else
2009 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
2010 bytesNeeded = 1 + lenBytes + significantBytes;
2011 if (pad)
2012 bytesNeeded++;
2013 if (!pbEncoded)
2014 {
2015 *pcbEncoded = bytesNeeded;
2016 ret = TRUE;
2017 }
2018 else
2019 {
2020 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2021 pcbEncoded, bytesNeeded)))
2022 {
2023 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2024 pbEncoded = *(BYTE **)pbEncoded;
2025 *pbEncoded++ = ASN_INTEGER;
2026 if (pad)
2027 {
2028 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
2029 pbEncoded += lenBytes;
2030 *pbEncoded++ = 0;
2031 }
2032 else
2033 {
2034 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
2035 pbEncoded += lenBytes;
2036 }
2037 for (; significantBytes > 0; significantBytes--)
2038 *(pbEncoded++) = blob->pbData[significantBytes - 1];
2039 }
2040 }
2041 }
2042 _SEH_EXCEPT(page_fault)
2043 {
2044 SetLastError(STATUS_ACCESS_VIOLATION);
2045 ret = FALSE;
2046 }
2047 _SEH_END
2048 return ret;
2049 }
2050
2051 static BOOL WINAPI CRYPT_AsnEncodeEnumerated(DWORD dwCertEncodingType,
2052 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2053 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2054 {
2055 CRYPT_INTEGER_BLOB blob;
2056 BOOL ret;
2057
2058 /* Encode as an unsigned integer, then change the tag to enumerated */
2059 blob.cbData = sizeof(DWORD);
2060 blob.pbData = (BYTE *)pvStructInfo;
2061 ret = CRYPT_AsnEncodeUnsignedInteger(dwCertEncodingType,
2062 X509_MULTI_BYTE_UINT, &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2063 if (ret && pbEncoded)
2064 {
2065 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2066 pbEncoded = *(BYTE **)pbEncoded;
2067 pbEncoded[0] = ASN_ENUMERATED;
2068 }
2069 return ret;
2070 }
2071
2072 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
2073 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2074 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2075 {
2076 BOOL ret;
2077
2078 _SEH_TRY
2079 {
2080 SYSTEMTIME sysTime;
2081 /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0. I use a
2082 * temporary buffer because the output buffer is not NULL-terminated.
2083 */
2084 char buf[16];
2085 static const DWORD bytesNeeded = sizeof(buf) - 1;
2086
2087 if (!pbEncoded)
2088 {
2089 *pcbEncoded = bytesNeeded;
2090 ret = TRUE;
2091 }
2092 else
2093 {
2094 /* Sanity check the year, this is a two-digit year format */
2095 ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
2096 &sysTime);
2097 if (ret && (sysTime.wYear < 1950 || sysTime.wYear > 2050))
2098 {
2099 SetLastError(CRYPT_E_BAD_ENCODE);
2100 ret = FALSE;
2101 }
2102 if (ret)
2103 {
2104 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2105 pbEncoded, pcbEncoded, bytesNeeded)))
2106 {
2107 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2108 pbEncoded = *(BYTE **)pbEncoded;
2109 buf[0] = ASN_UTCTIME;
2110 buf[1] = bytesNeeded - 2;
2111 snprintf(buf + 2, sizeof(buf) - 2,
2112 "%02d%02d%02d%02d%02d%02dZ", sysTime.wYear >= 2000 ?
2113 sysTime.wYear - 2000 : sysTime.wYear - 1900,
2114 sysTime.wDay, sysTime.wMonth, sysTime.wHour,
2115 sysTime.wMinute, sysTime.wSecond);
2116 memcpy(pbEncoded, buf, bytesNeeded);
2117 }
2118 }
2119 }
2120 }
2121 _SEH_EXCEPT(page_fault)
2122 {
2123 SetLastError(STATUS_ACCESS_VIOLATION);
2124 ret = FALSE;
2125 }
2126 _SEH_END
2127 return ret;
2128 }
2129
2130 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
2131 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2132 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2133 {
2134 BOOL ret;
2135
2136 _SEH_TRY
2137 {
2138 SYSTEMTIME sysTime;
2139 /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0. I use a
2140 * temporary buffer because the output buffer is not NULL-terminated.
2141 */
2142 char buf[18];
2143 static const DWORD bytesNeeded = sizeof(buf) - 1;
2144
2145 if (!pbEncoded)
2146 {
2147 *pcbEncoded = bytesNeeded;
2148 ret = TRUE;
2149 }
2150 else
2151 {
2152 ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
2153 &sysTime);
2154 if (ret)
2155 ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2156 pcbEncoded, bytesNeeded);
2157 if (ret)
2158 {
2159 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2160 pbEncoded = *(BYTE **)pbEncoded;
2161 buf[0] = ASN_GENERALTIME;
2162 buf[1] = bytesNeeded - 2;
2163 snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
2164 sysTime.wYear, sysTime.wDay, sysTime.wMonth, sysTime.wHour,
2165 sysTime.wMinute, sysTime.wSecond);
2166 memcpy(pbEncoded, buf, bytesNeeded);
2167 }
2168 }
2169 }
2170 _SEH_EXCEPT(page_fault)
2171 {
2172 SetLastError(STATUS_ACCESS_VIOLATION);
2173 ret = FALSE;
2174 }
2175 _SEH_END
2176 return ret;
2177 }
2178
2179 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
2180 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2181 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2182 {
2183 BOOL ret;
2184
2185 _SEH_TRY
2186 {
2187 SYSTEMTIME sysTime;
2188
2189 /* Check the year, if it's in the UTCTime range call that encode func */
2190 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
2191 return FALSE;
2192 if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
2193 ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
2194 pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2195 else
2196 ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
2197 lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
2198 pcbEncoded);
2199 }
2200 _SEH_EXCEPT(page_fault)
2201 {
2202 SetLastError(STATUS_ACCESS_VIOLATION);
2203 ret = FALSE;
2204 }
2205 _SEH_END
2206 return ret;
2207 }
2208
2209 static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
2210 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2211 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2212 {
2213 BOOL ret;
2214
2215 _SEH_TRY
2216 {
2217 DWORD bytesNeeded, dataLen, lenBytes, i;
2218 const CRYPT_SEQUENCE_OF_ANY *seq =
2219 (const CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
2220
2221 for (i = 0, dataLen = 0; i < seq->cValue; i++)
2222 dataLen += seq->rgValue[i].cbData;
2223 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2224 bytesNeeded = 1 + lenBytes + dataLen;
2225 if (!pbEncoded)
2226 {
2227 *pcbEncoded = bytesNeeded;
2228 ret = TRUE;
2229 }
2230 else
2231 {
2232 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2233 pcbEncoded, bytesNeeded)))
2234 {
2235 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2236 pbEncoded = *(BYTE **)pbEncoded;
2237 *pbEncoded++ = ASN_SEQUENCEOF;
2238 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2239 pbEncoded += lenBytes;
2240 for (i = 0; i < seq->cValue; i++)
2241 {
2242 memcpy(pbEncoded, seq->rgValue[i].pbData,
2243 seq->rgValue[i].cbData);
2244 pbEncoded += seq->rgValue[i].cbData;
2245 }
2246 }
2247 }
2248 }
2249 _SEH_EXCEPT(page_fault)
2250 {
2251 SetLastError(STATUS_ACCESS_VIOLATION);
2252 ret = FALSE;
2253 }
2254 _SEH_END
2255 return ret;
2256 }
2257
2258 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
2259 const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
2260 void *pvEncoded, DWORD *pcbEncoded)
2261 {
2262 BOOL ret = FALSE;
2263 HMODULE lib = NULL;
2264 CryptEncodeObjectExFunc encodeFunc = NULL;
2265
2266 TRACE("(0x%08lx, %s, %p, 0x%08lx, %p, %p, %p)\n", dwCertEncodingType,
2267 debugstr_a(lpszStructType), pvStructInfo, dwFlags, pEncodePara,
2268 pvEncoded, pcbEncoded);
2269
2270 if (!pvEncoded && !pcbEncoded)
2271 {
2272 SetLastError(ERROR_INVALID_PARAMETER);
2273 return FALSE;
2274 }
2275 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
2276 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
2277 {
2278 SetLastError(ERROR_FILE_NOT_FOUND);
2279 return FALSE;
2280 }
2281
2282 SetLastError(NOERROR);
2283 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG && pvEncoded)
2284 *(BYTE **)pvEncoded = NULL;
2285 if (!HIWORD(lpszStructType))
2286 {
2287 switch (LOWORD(lpszStructType))
2288 {
2289 case (WORD)X509_CERT:
2290 encodeFunc = CRYPT_AsnEncodeCert;
2291 break;
2292 case (WORD)X509_CERT_TO_BE_SIGNED:
2293 encodeFunc = CRYPT_AsnEncodeCertInfo;
2294 break;
2295 case (WORD)X509_CERT_CRL_TO_BE_SIGNED:
2296 encodeFunc = CRYPT_AsnEncodeCRLInfo;
2297 break;
2298 case (WORD)X509_EXTENSIONS:
2299 encodeFunc = CRYPT_AsnEncodeExtensions;
2300 break;
2301 case (WORD)X509_NAME:
2302 encodeFunc = CRYPT_AsnEncodeName;
2303 break;
2304 case (WORD)X509_PUBLIC_KEY_INFO:
2305 encodeFunc = CRYPT_AsnEncodePubKeyInfo;
2306 break;
2307 case (WORD)X509_ALTERNATE_NAME:
2308 encodeFunc = CRYPT_AsnEncodeAltName;
2309 break;
2310 case (WORD)X509_BASIC_CONSTRAINTS2:
2311 encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
2312 break;
2313 case (WORD)RSA_CSP_PUBLICKEYBLOB:
2314 encodeFunc = CRYPT_AsnEncodeRsaPubKey;
2315 break;
2316 case (WORD)X509_OCTET_STRING:
2317 encodeFunc = CRYPT_AsnEncodeOctets;
2318 break;
2319 case (WORD)X509_BITS:
2320 case (WORD)X509_KEY_USAGE:
2321 encodeFunc = CRYPT_AsnEncodeBits;
2322 break;
2323 case (WORD)X509_INTEGER:
2324 encodeFunc = CRYPT_AsnEncodeInt;
2325 break;
2326 case (WORD)X509_MULTI_BYTE_INTEGER:
2327 encodeFunc = CRYPT_AsnEncodeInteger;
2328 break;
2329 case (WORD)X509_MULTI_BYTE_UINT:
2330 encodeFunc = CRYPT_AsnEncodeUnsignedInteger;
2331 break;
2332 case (WORD)X509_ENUMERATED:
2333 encodeFunc = CRYPT_AsnEncodeEnumerated;
2334 break;
2335 case (WORD)X509_CHOICE_OF_TIME:
2336 encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
2337 break;
2338 case (WORD)X509_SEQUENCE_OF_ANY:
2339 encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
2340 break;
2341 case (WORD)PKCS_UTC_TIME:
2342 encodeFunc = CRYPT_AsnEncodeUtcTime;
2343 break;
2344 default:
2345 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
2346 }
2347 }
2348 else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
2349 encodeFunc = CRYPT_AsnEncodeExtensions;
2350 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
2351 encodeFunc = CRYPT_AsnEncodeUtcTime;
2352 else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
2353 encodeFunc = CRYPT_AsnEncodeEnumerated;
2354 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
2355 encodeFunc = CRYPT_AsnEncodeBits;
2356 else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
2357 encodeFunc = CRYPT_AsnEncodeOctets;
2358 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
2359 encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
2360 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
2361 encodeFunc = CRYPT_AsnEncodeAltName;
2362 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
2363 encodeFunc = CRYPT_AsnEncodeAltName;
2364 else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION))
2365 encodeFunc = CRYPT_AsnEncodeAltName;
2366 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
2367 encodeFunc = CRYPT_AsnEncodeAltName;
2368 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
2369 encodeFunc = CRYPT_AsnEncodeAltName;
2370 else
2371 TRACE("OID %s not found or unimplemented, looking for DLL\n",
2372 debugstr_a(lpszStructType));
2373 if (!encodeFunc)
2374 encodeFunc = (CryptEncodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
2375 lpszStructType, CRYPT_OID_ENCODE_OBJECT_EX_FUNC, &lib);
2376 if (encodeFunc)
2377 ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
2378 dwFlags, pEncodePara, pvEncoded, pcbEncoded);
2379 else
2380 SetLastError(ERROR_FILE_NOT_FOUND);
2381 if (lib)
2382 FreeLibrary(lib);
2383 return ret;
2384 }
2385
2386 BOOL WINAPI CryptDecodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
2387 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo,
2388 DWORD *pcbStructInfo)
2389 {
2390 BOOL ret = FALSE;
2391 HMODULE lib;
2392 CryptDecodeObjectFunc pCryptDecodeObject;
2393
2394 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p)\n", dwCertEncodingType,
2395 debugstr_a(lpszStructType), pbEncoded, cbEncoded, dwFlags,
2396 pvStructInfo, pcbStructInfo);
2397
2398 if (!pvStructInfo && !pcbStructInfo)
2399 {
2400 SetLastError(ERROR_INVALID_PARAMETER);
2401 return FALSE;
2402 }
2403
2404 /* Try registered DLL first.. */
2405 pCryptDecodeObject =
2406 (CryptDecodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
2407 lpszStructType, CRYPT_OID_DECODE_OBJECT_FUNC, &lib);
2408 if (pCryptDecodeObject)
2409 {
2410 ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType,
2411 pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
2412 FreeLibrary(lib);
2413 }
2414 else
2415 {
2416 /* If not, use CryptDecodeObjectEx */
2417 ret = CryptDecodeObjectEx(dwCertEncodingType, lpszStructType, pbEncoded,
2418 cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo);
2419 }
2420 return ret;
2421 }
2422
2423 /* Gets the number of length bytes from the given (leading) length byte */
2424 #define GET_LEN_BYTES(b) ((b) <= 0x7f ? 1 : 1 + ((b) & 0x7f))
2425
2426 /* Helper function to get the encoded length of the data starting at pbEncoded,
2427 * where pbEncoded[0] is the tag. If the data are too short to contain a
2428 * length or if the length is too large for cbEncoded, sets an appropriate
2429 * error code and returns FALSE.
2430 */
2431 static BOOL WINAPI CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded,
2432 DWORD *len)
2433 {
2434 BOOL ret;
2435
2436 if (cbEncoded <= 1)
2437 {
2438 SetLastError(CRYPT_E_ASN1_CORRUPT);
2439 ret = FALSE;
2440 }
2441 else if (pbEncoded[1] <= 0x7f)
2442 {
2443 if (pbEncoded[1] + 1 > cbEncoded)
2444 {
2445 SetLastError(CRYPT_E_ASN1_EOD);
2446 ret = FALSE;
2447 }
2448 else
2449 {
2450 *len = pbEncoded[1];
2451 ret = TRUE;
2452 }
2453 }
2454 else
2455 {
2456 BYTE lenLen = GET_LEN_BYTES(pbEncoded[1]);
2457
2458 if (lenLen > sizeof(DWORD) + 1)
2459 {
2460 SetLastError(CRYPT_E_ASN1_LARGE);
2461 ret = FALSE;
2462 }
2463 else if (lenLen + 2 > cbEncoded)
2464 {
2465 SetLastError(CRYPT_E_ASN1_CORRUPT);
2466 ret = FALSE;
2467 }
2468 else
2469 {
2470 DWORD out = 0;
2471
2472 pbEncoded += 2;
2473 while (--lenLen)
2474 {
2475 out <<= 8;
2476 out |= *pbEncoded++;
2477 }
2478 if (out + lenLen + 1 > cbEncoded)
2479 {
2480 SetLastError(CRYPT_E_ASN1_EOD);
2481 ret = FALSE;
2482 }
2483 else
2484 {
2485 *len = out;
2486 ret = TRUE;
2487 }
2488 }
2489 }
2490 return ret;
2491 }
2492
2493 /* Helper function to check *pcbStructInfo, set it to the required size, and
2494 * optionally to allocate memory. Assumes pvStructInfo is not NULL.
2495 * If CRYPT_DECODE_ALLOC_FLAG is set in dwFlags, *pvStructInfo will be set to a
2496 * pointer to the newly allocated memory.
2497 */
2498 static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags,
2499 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo,
2500 DWORD bytesNeeded)
2501 {
2502 BOOL ret = TRUE;
2503
2504 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2505 {
2506 if (pDecodePara && pDecodePara->pfnAlloc)
2507 *(BYTE **)pvStructInfo = pDecodePara->pfnAlloc(bytesNeeded);
2508 else
2509 *(BYTE **)pvStructInfo = LocalAlloc(0, bytesNeeded);
2510 if (!*(BYTE **)pvStructInfo)
2511 ret = FALSE;
2512 else
2513 *pcbStructInfo = bytesNeeded;
2514 }
2515 else if (*pcbStructInfo < bytesNeeded)
2516 {
2517 *pcbStructInfo = bytesNeeded;
2518 SetLastError(ERROR_MORE_DATA);
2519 ret = FALSE;
2520 }
2521 return ret;
2522 }
2523
2524 /* A few of the members need explanation:
2525 * offset:
2526 * A sequence is decoded into a struct. The offset member is the
2527 * offset of this item within that struct.
2528 * decodeFunc:
2529 * The decoder function to use. If this is NULL, then the member isn't
2530 * decoded, but minSize space is reserved for it.
2531 * minSize:
2532 * The minimum amount of space occupied after decoding. You must set this.
2533 * optional:
2534 * If true, and a decoding function fails with CRYPT_E_ASN1_BADTAG, then
2535 * minSize space is filled with 0 for this member. (Any other failure
2536 * results in CRYPT_AsnDecodeSequence failing.)
2537 * hasPointer, pointerOffset, minSize:
2538 * If the item has dynamic data, set hasPointer to TRUE, pointerOffset to
2539 * the offset within the (outer) struct of the data pointer (or to the
2540 * first data pointer, if more than one exist).
2541 * size:
2542 * Used by CRYPT_AsnDecodeSequence, not for your use.
2543 */
2544 struct AsnDecodeSequenceItem
2545 {
2546 DWORD offset;
2547 CryptDecodeObjectExFunc decodeFunc;
2548 DWORD minSize;
2549 BOOL optional;
2550 BOOL hasPointer;
2551 DWORD pointerOffset;
2552 DWORD size;
2553 };
2554
2555 /* This decodes an arbitrary sequence into a contiguous block of memory
2556 * (basically, a struct.) Each element being decoded is described by a struct
2557 * AsnDecodeSequenceItem, see above.
2558 * startingPointer is an optional pointer to the first place where dynamic
2559 * data will be stored. If you know the starting offset, you may pass it
2560 * here. Otherwise, pass NULL, and one will be inferred from the items.
2561 * Each item decoder is never called with CRYPT_DECODE_ALLOC_FLAG set.
2562 * If any undecoded data are left over, fails with CRYPT_E_ASN1_CORRUPT.
2563 */
2564 static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType,
2565 struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
2566 DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
2567 void *pvStructInfo, DWORD *pcbStructInfo, void *startingPointer)
2568 {
2569 BOOL ret;
2570
2571 TRACE("%p, %ld, %p, %ld, %08lx, %p, %p, %ld, %p\n", items, cItem, pbEncoded,
2572 cbEncoded, dwFlags, pDecodePara, pvStructInfo, *pcbStructInfo,
2573 startingPointer);
2574
2575 if (pbEncoded[0] == ASN_SEQUENCE)
2576 {
2577 DWORD dataLen;
2578
2579 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2580 {
2581 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2582 DWORD i, bytesNeeded = 0, minSize = 0;
2583 const BYTE *ptr;
2584
2585 ptr = pbEncoded + 1 + lenBytes;
2586 for (i = 0; ret && i < cItem; i++)
2587 {
2588 DWORD nextItemLen;
2589
2590 minSize += items[i].minSize;
2591 if (cbEncoded - (ptr - pbEncoded) != 0)
2592 {
2593 if ((ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
2594 &nextItemLen)))
2595 {
2596 BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
2597
2598 if (items[i].decodeFunc)
2599 {
2600 TRACE("sizing item %ld\n", i);
2601 ret = items[i].decodeFunc(dwCertEncodingType, NULL,
2602 ptr, 1 + nextItemLenBytes + nextItemLen,
2603 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL,
2604 &items[i].size);
2605 if (ret)
2606 {
2607 /* Account for alignment padding */
2608 bytesNeeded += items[i].size;
2609 if (items[i].size % sizeof(DWORD))
2610 bytesNeeded += sizeof(DWORD) -
2611 items[i].size % sizeof(DWORD);
2612 ptr += 1 + nextItemLenBytes + nextItemLen;
2613 }
2614 else if (items[i].optional &&
2615 GetLastError() == CRYPT_E_ASN1_BADTAG)
2616 {
2617 TRACE("skipping optional item %ld\n", i);
2618 bytesNeeded += items[i].minSize;
2619 SetLastError(NOERROR);
2620 ret = TRUE;
2621 }
2622 else
2623 TRACE("item %ld failed: %08lx\n", i,
2624 GetLastError());
2625 }
2626 else
2627 bytesNeeded += items[i].minSize;
2628 }
2629 }
2630 else if (items[i].optional)
2631 bytesNeeded += items[i].minSize;
2632 else
2633 {
2634 SetLastError(CRYPT_E_ASN1_CORRUPT);
2635 ret = FALSE;
2636 }
2637 }
2638 if (cbEncoded - (ptr - pbEncoded) != 0)
2639 {
2640 TRACE("%ld remaining bytes, failing\n", cbEncoded -
2641 (ptr - pbEncoded));
2642 SetLastError(CRYPT_E_ASN1_CORRUPT);
2643 ret = FALSE;
2644 }
2645 if (ret)
2646 {
2647 if (!pvStructInfo)
2648 *pcbStructInfo = bytesNeeded;
2649 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
2650 pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
2651 {
2652 BYTE *nextData;
2653
2654 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2655 pvStructInfo = *(BYTE **)pvStructInfo;
2656 if (startingPointer)
2657 nextData = (BYTE *)startingPointer;
2658 else
2659 nextData = (BYTE *)pvStructInfo + minSize;
2660 memset(pvStructInfo, 0, minSize);
2661 ptr = pbEncoded + 1 + lenBytes;
2662 for (i = 0; ret && i < cItem; i++)
2663 {
2664 if (cbEncoded - (ptr - pbEncoded) != 0)
2665 {
2666 DWORD nextItemLen;
2667 BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
2668
2669 CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
2670 &nextItemLen);
2671 if (items[i].hasPointer)
2672 {
2673 *(BYTE **)((BYTE *)pvStructInfo +
2674 items[i].pointerOffset) = nextData;
2675 }
2676 if (items[i].decodeFunc)
2677 {
2678 TRACE("decoding item %ld\n", i);
2679 ret = items[i].decodeFunc(dwCertEncodingType,
2680 NULL, ptr, 1 + nextItemLenBytes + nextItemLen,
2681 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
2682 (BYTE *)pvStructInfo + items[i].offset,
2683 &items[i].size);
2684 if (!ret)
2685 TRACE("item %ld failed: %08lx\n", i,
2686 GetLastError());
2687 }
2688 else
2689 items[i].size = items[i].minSize;
2690 if (ret)
2691 {
2692 if (items[i].hasPointer &&
2693 items[i].size > items[i].minSize)
2694 {
2695 nextData += items[i].size -
2696 items[i].minSize;
2697 /* align nextData to DWORD boundaries */
2698 if (items[i].size % sizeof(DWORD))
2699 {
2700 nextData += sizeof(DWORD) -
2701 items[i].size % sizeof(DWORD);
2702 }
2703 }
2704 ptr += 1 + nextItemLenBytes + nextItemLen;
2705 }
2706 else if (items[i].optional &&
2707 GetLastError() == CRYPT_E_ASN1_BADTAG)
2708 {
2709 SetLastError(NOERROR);
2710 ret = TRUE;
2711 }
2712 }
2713 else if (!items[i].optional)
2714 {
2715 SetLastError(CRYPT_E_ASN1_CORRUPT);
2716 ret = FALSE;
2717 }
2718 }
2719 }
2720 }
2721 }
2722 }
2723 else
2724 {
2725 SetLastError(CRYPT_E_ASN1_BADTAG);
2726 ret = FALSE;
2727 }
2728 TRACE("returning %d (%08lx)\n", ret, GetLastError());
2729 return ret;
2730 }
2731
2732 /* Decodes a DER-encoded BLOB into a CRYPT_DER_BLOB struct pointed to by
2733 * pvStructInfo. The BLOB must be non-empty, otherwise the last error is set
2734 * to CRYPT_E_ASN1_CORRUPT.
2735 * Warning: assumes the CRYPT_DER_BLOB pointed to by pvStructInfo has pbData
2736 * set!
2737 */
2738 static BOOL WINAPI CRYPT_AsnDecodeDerBlob(DWORD dwCertEncodingType,
2739 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2740 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2741 {
2742 BOOL ret;
2743 DWORD dataLen;
2744
2745 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2746 {
2747 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2748 DWORD bytesNeeded = sizeof(CRYPT_DER_BLOB);
2749
2750 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
2751 bytesNeeded += 1 + lenBytes + dataLen;
2752
2753 if (!pvStructInfo)
2754 *pcbStructInfo = bytesNeeded;
2755 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
2756 pvStructInfo, pcbStructInfo, bytesNeeded)))
2757 {
2758 CRYPT_DER_BLOB *blob = (CRYPT_DER_BLOB *)pvStructInfo;
2759
2760 blob->cbData = 1 + lenBytes + dataLen;
2761 if (blob->cbData)
2762 {
2763 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
2764 blob->pbData = (BYTE *)pbEncoded;
2765 else
2766 {
2767 assert(blob->pbData);
2768 memcpy(blob->pbData, pbEncoded, blob->cbData);
2769 }
2770 }
2771 else
2772 {
2773 SetLastError(CRYPT_E_ASN1_CORRUPT);
2774 ret = FALSE;
2775 }
2776 }
2777 }
2778 return ret;
2779 }
2780
2781 /* Like CRYPT_AsnDecodeBitsInternal, but swaps the bytes */
2782 static BOOL WINAPI CRYPT_AsnDecodeBitsSwapBytes(DWORD dwCertEncodingType,
2783 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2784 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2785 {
2786 BOOL ret;
2787
2788 TRACE("(%p, %ld, 0x%08lx, %p, %p, %ld)\n", pbEncoded, cbEncoded, dwFlags,
2789 pDecodePara, pvStructInfo, *pcbStructInfo);
2790
2791 /* Can't use the CRYPT_DECODE_NOCOPY_FLAG, because we modify the bytes in-
2792 * place.
2793 */
2794 ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType, lpszStructType,
2795 pbEncoded, cbEncoded, dwFlags & ~CRYPT_DECODE_NOCOPY_FLAG, pDecodePara,
2796 pvStructInfo, pcbStructInfo);
2797 if (ret && pvStructInfo)
2798 {
2799 CRYPT_BIT_BLOB *blob = (CRYPT_BIT_BLOB *)pvStructInfo;
2800
2801 if (blob->cbData)
2802 {
2803 DWORD i;
2804 BYTE temp;
2805
2806 for (i = 0; i < blob->cbData / 2; i++)
2807 {
2808 temp = blob->pbData[i];
2809 blob->pbData[i] = blob->pbData[blob->cbData - i - 1];
2810 blob->pbData[blob->cbData - i - 1] = temp;
2811 }
2812 }
2813 }
2814 TRACE("returning %d (%08lx)\n", ret, GetLastError());
2815 return ret;
2816 }
2817
2818 static BOOL WINAPI CRYPT_AsnDecodeCert(DWORD dwCertEncodingType,
2819 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2820 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2821 {
2822 BOOL ret = TRUE;
2823
2824 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
2825 pDecodePara, pvStructInfo, *pcbStructInfo);
2826
2827 _SEH_TRY
2828 {
2829 struct AsnDecodeSequenceItem items[] = {
2830 { offsetof(CERT_SIGNED_CONTENT_INFO, ToBeSigned),
2831 CRYPT_AsnDecodeDerBlob, sizeof(CRYPT_DER_BLOB), FALSE, TRUE,
2832 offsetof(CERT_SIGNED_CONTENT_INFO, ToBeSigned.pbData), 0 },
2833 { offsetof(CERT_SIGNED_CONTENT_INFO, SignatureAlgorithm),
2834 CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
2835 FALSE, TRUE, offsetof(CERT_SIGNED_CONTENT_INFO,
2836 SignatureAlgorithm.pszObjId), 0 },
2837 { offsetof(CERT_SIGNED_CONTENT_INFO, Signature),
2838 CRYPT_AsnDecodeBitsSwapBytes, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE,
2839 offsetof(CERT_SIGNED_CONTENT_INFO, Signature.pbData), 0 },
2840 };
2841
2842 if (dwFlags & CRYPT_DECODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG)
2843 items[2].decodeFunc = CRYPT_AsnDecodeBitsInternal;
2844 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2845 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2846 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
2847 }
2848 _SEH_EXCEPT(page_fault)
2849 {
2850 SetLastError(STATUS_ACCESS_VIOLATION);
2851 ret = FALSE;
2852 }
2853 _SEH_END
2854 return ret;
2855 }
2856
2857 static BOOL WINAPI CRYPT_AsnDecodeCertVersion(DWORD dwCertEncodingType,
2858 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2859 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2860 {
2861 BOOL ret;
2862
2863 if (pbEncoded[0] == (ASN_CONTEXT | ASN_CONSTRUCTOR))
2864 {
2865 DWORD dataLen;
2866
2867 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2868 {
2869 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2870
2871 ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER,
2872 pbEncoded + 1 + lenBytes, dataLen, dwFlags, pDecodePara,
2873 pvStructInfo, pcbStructInfo);
2874 }
2875 }
2876 else
2877 {
2878 SetLastError(CRYPT_E_ASN1_BADTAG);
2879 ret = FALSE;
2880 }
2881 return ret;
2882 }
2883
2884 static BOOL WINAPI CRYPT_AsnDecodeValidity(DWORD dwCertEncodingType,
2885 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2886 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2887 {
2888 BOOL ret;
2889
2890 struct AsnDecodeSequenceItem items[] = {
2891 { offsetof(CERT_PRIVATE_KEY_VALIDITY, NotBefore),
2892 CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 },
2893 { offsetof(CERT_PRIVATE_KEY_VALIDITY, NotAfter),
2894 CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 },
2895 };
2896
2897 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2898 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2899 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
2900 return ret;
2901 }
2902
2903 static BOOL WINAPI CRYPT_AsnDecodeCertExtensions(DWORD dwCertEncodingType,
2904 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2905 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2906 {
2907 BOOL ret;
2908
2909 if (pbEncoded[0] == (ASN_CONTEXT | ASN_CONSTRUCTOR | 3))
2910 {
2911 DWORD dataLen;
2912
2913 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2914 {
2915 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2916
2917 ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType,
2918 X509_EXTENSIONS, pbEncoded + 1 + lenBytes, dataLen, dwFlags,
2919 pDecodePara, pvStructInfo, pcbStructInfo);
2920 }
2921 }
2922 else
2923 {
2924 SetLastError(CRYPT_E_ASN1_BADTAG);
2925 ret = FALSE;
2926 }
2927 return ret;
2928 }
2929
2930 static BOOL WINAPI CRYPT_AsnDecodeCertInfo(DWORD dwCertEncodingType,
2931 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2932 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2933 {
2934 BOOL ret = TRUE;
2935
2936 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
2937 pDecodePara, pvStructInfo, *pcbStructInfo);
2938
2939 _SEH_TRY
2940 {
2941 struct AsnDecodeSequenceItem items[] = {
2942 { offsetof(CERT_INFO, dwVersion), CRYPT_AsnDecodeCertVersion,
2943 sizeof(DWORD), TRUE, FALSE, 0, 0 },
2944 { offsetof(CERT_INFO, SerialNumber), CRYPT_AsnDecodeIntegerInternal,
2945 sizeof(CRYPT_INTEGER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
2946 SerialNumber.pbData), 0 },
2947 { offsetof(CERT_INFO, SignatureAlgorithm), CRYPT_AsnDecodeAlgorithmId,
2948 sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE, offsetof(CERT_INFO,
2949 SignatureAlgorithm.pszObjId), 0 },
2950 { offsetof(CERT_INFO, Issuer), CRYPT_AsnDecodeDerBlob,
2951 sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
2952 Issuer.pbData) },
2953 { offsetof(CERT_INFO, NotBefore), CRYPT_AsnDecodeValidity,
2954 sizeof(CERT_PRIVATE_KEY_VALIDITY), FALSE, FALSE, 0 },
2955 { offsetof(CERT_INFO, Subject), CRYPT_AsnDecodeDerBlob,
2956 sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
2957 Subject.pbData) },
2958 { offsetof(CERT_INFO, SubjectPublicKeyInfo), CRYPT_AsnDecodePubKeyInfo,
2959 sizeof(CERT_PUBLIC_KEY_INFO), FALSE, TRUE, offsetof(CERT_INFO,
2960 SubjectPublicKeyInfo.Algorithm.Parameters.pbData), 0 },
2961 { offsetof(CERT_INFO, IssuerUniqueId), CRYPT_AsnDecodeBitsInternal,
2962 sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, offsetof(CERT_INFO,
2963 IssuerUniqueId.pbData), 0 },
2964 { offsetof(CERT_INFO, SubjectUniqueId), CRYPT_AsnDecodeBitsInternal,
2965 sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, offsetof(CERT_INFO,
2966 SubjectUniqueId.pbData), 0 },
2967 { offsetof(CERT_INFO, cExtension), CRYPT_AsnDecodeCertExtensions,
2968 sizeof(CERT_EXTENSIONS), TRUE, TRUE, offsetof(CERT_INFO,
2969 rgExtension), 0 },
2970 };
2971
2972 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2973 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2974 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
2975 }
2976 _SEH_EXCEPT(page_fault)
2977 {
2978 SetLastError(STATUS_ACCESS_VIOLATION);
2979 ret = FALSE;
2980 }
2981 _SEH_END
2982 return ret;
2983 }
2984
2985 static BOOL CRYPT_AsnDecodeCRLEntry(const BYTE *pbEncoded, DWORD cbEncoded,
2986 DWORD dwFlags, PCRL_ENTRY entry, DWORD *pcbEntry)
2987 {
2988 BOOL ret;
2989 struct AsnDecodeSequenceItem items[] = {
2990 { offsetof(CRL_ENTRY, SerialNumber), CRYPT_AsnDecodeIntegerInternal,
2991 sizeof(CRYPT_INTEGER_BLOB), FALSE, TRUE, offsetof(CRL_ENTRY,
2992 SerialNumber.pbData), 0 },
2993 { offsetof(CRL_ENTRY, RevocationDate), CRYPT_AsnDecodeChoiceOfTime,
2994 sizeof(FILETIME), FALSE, FALSE, 0 },
2995 { offsetof(CRL_ENTRY, cExtension), CRYPT_AsnDecodeExtensionsInternal,
2996 sizeof(CERT_EXTENSIONS), TRUE, TRUE, offsetof(CRL_ENTRY,
2997 rgExtension), 0 },
2998 };
2999
3000 TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, entry,
3001 *pcbEntry);
3002
3003 ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items,
3004 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3005 NULL, entry, pcbEntry, entry ? entry->SerialNumber.pbData : NULL);
3006 TRACE("Returning %d (%08lx)\n", ret, GetLastError());
3007 return ret;
3008 }
3009
3010 typedef struct _WINE_CRL_ENTRIES {
3011 DWORD cCRLEntry;
3012 PCRL_ENTRY rgCRLEntry;
3013 } WINE_CRL_ENTRIES, *PWINE_CRL_ENTRIES;
3014
3015 /* Warning: assumes pvStructInfo is a WINE_CRL_ENTRIES whose rgCRLEntry has
3016 * been set prior to calling.
3017 */
3018 static BOOL WINAPI CRYPT_AsnDecodeCRLEntries(DWORD dwCertEncodingType,
3019 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3020 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3021 {
3022 BOOL ret;
3023
3024 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3025 pDecodePara, pvStructInfo, *pcbStructInfo);
3026
3027 if (pbEncoded[0] == ASN_SEQUENCEOF)
3028 {
3029 DWORD dataLen, bytesNeeded;
3030
3031 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3032 {
3033 DWORD cCRLEntry = 0;
3034 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3035
3036 bytesNeeded = sizeof(WINE_CRL_ENTRIES);
3037 if (dataLen)
3038 {
3039 const BYTE *ptr;
3040 DWORD size;
3041
3042 for (ptr = pbEncoded + 1 + lenBytes; ret &&
3043 ptr - pbEncoded - 1 - lenBytes < dataLen; )
3044 {
3045 size = 0;
3046 ret = CRYPT_AsnDecodeCRLEntry(ptr,
3047 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
3048 if (ret)
3049 {
3050 DWORD nextLen;
3051
3052 cCRLEntry++;
3053 bytesNeeded += size;
3054 ret = CRYPT_GetLen(ptr,
3055 cbEncoded - (ptr - pbEncoded), &nextLen);
3056 if (ret)
3057 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3058 }
3059 }
3060 }
3061 if (ret)
3062 {
3063 if (!pvStructInfo)
3064 *pcbStructInfo = bytesNeeded;
3065 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
3066 pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
3067 {
3068 DWORD size, i;
3069 BYTE *nextData;
3070 const BYTE *ptr;
3071 PWINE_CRL_ENTRIES entries;
3072
3073 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3074 pvStructInfo = *(BYTE **)pvStructInfo;
3075 *pcbStructInfo = bytesNeeded;
3076 entries = (PWINE_CRL_ENTRIES)pvStructInfo;
3077 entries->cCRLEntry = cCRLEntry;
3078 assert(entries->rgCRLEntry);
3079 nextData = (BYTE *)entries->rgCRLEntry +
3080 entries->cCRLEntry * sizeof(CRL_ENTRY);
3081 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
3082 i < cCRLEntry && ptr - pbEncoded - 1 - lenBytes <
3083 dataLen; i++)
3084 {
3085 entries->rgCRLEntry[i].SerialNumber.pbData = nextData;
3086 size = bytesNeeded;
3087 ret = CRYPT_AsnDecodeCRLEntry(ptr,
3088 cbEncoded - (ptr - pbEncoded), dwFlags,
3089 &entries->rgCRLEntry[i], &size);
3090 if (ret)
3091 {
3092 DWORD nextLen;
3093
3094 bytesNeeded -= size;
3095 /* Increment nextData by the difference of the
3096 * minimum size and the actual size.
3097 */
3098 if (size > sizeof(CRL_ENTRY))
3099 nextData += size - sizeof(CRL_ENTRY);
3100 ret = CRYPT_GetLen(ptr,
3101 cbEncoded - (ptr - pbEncoded), &nextLen);
3102 if (ret)
3103 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3104 }
3105 }
3106 }
3107 }
3108 }
3109 }
3110 else
3111 {
3112 SetLastError(CRYPT_E_ASN1_BADTAG);
3113 ret = FALSE;
3114 }
3115 TRACE("Returning %d (%08lx)\n", ret, GetLastError());
3116 return ret;
3117 }
3118
3119 static BOOL WINAPI CRYPT_AsnDecodeCRLInfo(DWORD dwCertEncodingType,
3120 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3121 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3122 {
3123 BOOL ret = TRUE;
3124
3125 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3126 pDecodePara, pvStructInfo, *pcbStructInfo);
3127
3128 _SEH_TRY
3129 {
3130 struct AsnDecodeSequenceItem items[] = {
3131 { offsetof(CRL_INFO, dwVersion), CRYPT_AsnDecodeCertVersion,
3132 sizeof(DWORD), TRUE, FALSE, 0, 0 },
3133 { offsetof(CRL_INFO, SignatureAlgorithm), CRYPT_AsnDecodeAlgorithmId,
3134 sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE, offsetof(CRL_INFO,
3135 SignatureAlgorithm.pszObjId), 0 },
3136 { offsetof(CRL_INFO, Issuer), CRYPT_AsnDecodeDerBlob,
3137 sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CRL_INFO,
3138 Issuer.pbData) },
3139 { offsetof(CRL_INFO, ThisUpdate), CRYPT_AsnDecodeChoiceOfTime,
3140 sizeof(FILETIME), FALSE, FALSE, 0 },
3141 { offsetof(CRL_INFO, NextUpdate), CRYPT_AsnDecodeChoiceOfTime,
3142 sizeof(FILETIME), TRUE, FALSE, 0 },
3143 { offsetof(CRL_INFO, cCRLEntry), CRYPT_AsnDecodeCRLEntries,
3144 sizeof(WINE_CRL_ENTRIES), TRUE, TRUE, offsetof(CRL_INFO,
3145 rgCRLEntry), 0 },
3146 /* Note that the extensions are ignored by MS, so I'll ignore them too
3147 */
3148 { offsetof(CRL_INFO, cExtension), NULL,
3149 sizeof(CERT_EXTENSIONS), TRUE, FALSE, 0 },
3150 };
3151
3152 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
3153 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3154 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
3155 }
3156 _SEH_EXCEPT(page_fault)
3157 {
3158 SetLastError(STATUS_ACCESS_VIOLATION);
3159 ret = FALSE;
3160 }
3161 _SEH_END
3162
3163 TRACE("Returning %d (%08lx)\n", ret, GetLastError());
3164 return ret;
3165 }
3166
3167 /* Differences between this and CRYPT_AsnDecodeOid:
3168 * - pvStructInfo is a LPSTR *, not an LPSTR
3169 * - CRYPT_AsnDecodeOid doesn't account for the size of an LPSTR in its byte
3170 * count, whereas our callers (typically CRYPT_AsnDecodeSequence) expect this
3171 * to
3172 */
3173 static BOOL WINAPI CRYPT_AsnDecodeOidWrapper(DWORD dwCertEncodingType,
3174 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3175 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3176 {
3177 BOOL ret;
3178
3179 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3180 pDecodePara, pvStructInfo, *pcbStructInfo);
3181
3182