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