Fail loading when compiled without lcms support.
[wine/dcerpc.git] / dlls / crypt32 / encode.c
blob9a6695204afc8d45fe0b7e246d940c43e4cf5fdb
1 /*
2 * Copyright 2002 Mike McCormack for CodeWeavers
3 * Copyright 2005 Juan Lang
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 * This file implements ASN.1 DER encoding and decoding of a limited set of
20 * types. It isn't a full ASN.1 implementation. Microsoft implements BER
21 * encoding of many of the basic types in msasn1.dll, but that interface is
22 * undocumented, so I implement them here.
24 * References:
25 * "A Layman's Guide to a Subset of ASN.1, BER, and DER", by Burton Kaliski
26 * (available online, look for a PDF copy as the HTML versions tend to have
27 * translation errors.)
29 * RFC3280, http://www.faqs.org/rfcs/rfc3280.html
31 * MSDN, especially:
32 * http://msdn.microsoft.com/library/en-us/seccrypto/security/constants_for_cryptencodeobject_and_cryptdecodeobject.asp
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include "windef.h"
38 #include "winbase.h"
39 #include "excpt.h"
40 #include "wincrypt.h"
41 #include "winreg.h"
42 #include "snmp.h"
43 #include "wine/debug.h"
44 #include "wine/exception.h"
46 /* This is a bit arbitrary, but to set some limit: */
47 #define MAX_ENCODED_LEN 0x02000000
49 /* a few asn.1 tags we need */
50 #define ASN_BOOL (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x01)
51 #define ASN_BITSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x03)
52 #define ASN_OCTETSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x04)
53 #define ASN_ENUMERATED (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x0a)
54 #define ASN_SETOF (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x11)
55 #define ASN_NUMERICSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x12)
56 #define ASN_PRINTABLESTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x13)
57 #define ASN_IA5STRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x16)
58 #define ASN_UTCTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x17)
59 #define ASN_GENERALTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x18)
61 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
63 static const WCHAR szDllName[] = { 'D','l','l',0 };
65 static BOOL WINAPI CRYPT_AsnEncodeOid(LPCSTR pszObjId, BYTE *pbEncoded,
66 DWORD *pcbEncoded);
67 static BOOL CRYPT_EncodeBool(BOOL val, BYTE *pbEncoded, DWORD *pcbEncoded);
68 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
69 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
70 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
71 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
72 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
73 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
74 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
75 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
76 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
77 static BOOL WINAPI CRYPT_AsnDecodeOid(const BYTE *pbEncoded, DWORD cbEncoded,
78 DWORD dwFlags, LPSTR pszObjId, DWORD *pcbObjId);
79 static BOOL WINAPI CRYPT_DecodeBool(const BYTE *pbEncoded, DWORD cbEncoded,
80 BOOL *val);
81 static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
82 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
83 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
84 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
85 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
86 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
87 static BOOL WINAPI CRYPT_AsnDecodeInteger(DWORD dwCertEncodingType,
88 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
89 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
91 /* filter for page-fault exceptions */
92 static WINE_EXCEPTION_FILTER(page_fault)
94 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
95 return EXCEPTION_EXECUTE_HANDLER;
96 return EXCEPTION_CONTINUE_SEARCH;
99 static char *CRYPT_GetKeyName(DWORD dwEncodingType, LPCSTR pszFuncName,
100 LPCSTR pszOID)
102 static const char szEncodingTypeFmt[] =
103 "Software\\Microsoft\\Cryptography\\OID\\EncodingType %ld\\%s\\%s";
104 UINT len;
105 char numericOID[7]; /* enough for "#65535" */
106 const char *oid;
107 LPSTR szKey;
109 /* MSDN says the encoding type is a mask, but it isn't treated that way.
110 * (E.g., if dwEncodingType were 3, the key names "EncodingType 1" and
111 * "EncodingType 2" would be expected if it were a mask. Instead native
112 * stores values in "EncodingType 3".
114 if (!HIWORD(pszOID))
116 snprintf(numericOID, sizeof(numericOID), "#%d", (int)pszOID);
117 oid = numericOID;
119 else
120 oid = pszOID;
122 /* This is enough: the lengths of the two string parameters are explicitly
123 * counted, and we need up to five additional characters for the encoding
124 * type. These are covered by the "%d", "%s", and "%s" characters in the
125 * format specifier that are removed by sprintf.
127 len = sizeof(szEncodingTypeFmt) + lstrlenA(pszFuncName) + lstrlenA(oid);
128 szKey = HeapAlloc(GetProcessHeap(), 0, len);
129 if (szKey)
130 sprintf(szKey, szEncodingTypeFmt, dwEncodingType, pszFuncName, oid);
131 return szKey;
134 BOOL WINAPI CryptRegisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
135 LPCSTR pszOID, LPCWSTR pwszDll, LPCSTR pszOverrideFuncName)
137 LONG r;
138 HKEY hKey;
139 LPSTR szKey;
141 TRACE("%lx %s %s %s %s\n", dwEncodingType, pszFuncName, pszOID,
142 debugstr_w(pwszDll), pszOverrideFuncName);
144 /* This only registers functions for encoding certs, not messages */
145 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
146 return TRUE;
148 /* Native does nothing pwszDll is NULL */
149 if (!pwszDll)
150 return TRUE;
152 /* I'm not matching MS bug for bug here, because I doubt any app depends on
153 * it:
154 * - native "succeeds" if pszFuncName is NULL, but the nonsensical entry
155 * it creates would never be used
156 * - native returns an HRESULT rather than a Win32 error if pszOID is NULL.
157 * Instead I disallow both of these with ERROR_INVALID_PARAMETER.
159 if (!pszFuncName || !pszOID)
161 SetLastError(ERROR_INVALID_PARAMETER);
162 return FALSE;
165 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
166 TRACE("Key name is %s\n", debugstr_a(szKey));
168 if (!szKey)
169 return FALSE;
171 r = RegCreateKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
172 HeapFree(GetProcessHeap(), 0, szKey);
173 if(r != ERROR_SUCCESS)
174 return FALSE;
176 /* write the values */
177 if (pszOverrideFuncName)
178 RegSetValueExA(hKey, "FuncName", 0, REG_SZ, pszOverrideFuncName,
179 lstrlenA(pszOverrideFuncName) + 1);
180 RegSetValueExW(hKey, szDllName, 0, REG_SZ, (const BYTE*) pwszDll,
181 (lstrlenW(pwszDll) + 1) * sizeof (WCHAR));
183 RegCloseKey(hKey);
184 return TRUE;
187 BOOL WINAPI CryptUnregisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
188 LPCSTR pszOID)
190 LPSTR szKey;
191 LONG rc;
193 TRACE("%lx %s %s\n", dwEncodingType, pszFuncName, pszOID);
195 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
196 return TRUE;
198 if (!pszFuncName || !pszOID)
200 SetLastError(ERROR_INVALID_PARAMETER);
201 return FALSE;
204 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
205 rc = RegDeleteKeyA(HKEY_LOCAL_MACHINE, szKey);
206 HeapFree(GetProcessHeap(), 0, szKey);
207 if (rc)
208 SetLastError(rc);
209 return rc ? FALSE : TRUE;
212 BOOL WINAPI CryptGetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
213 LPCSTR pszOID, LPCWSTR pwszValueName, DWORD *pdwValueType, BYTE *pbValueData,
214 DWORD *pcbValueData)
216 LPSTR szKey;
217 LONG rc;
218 HKEY hKey;
220 TRACE("%lx %s %s %s %p %p %p\n", dwEncodingType, debugstr_a(pszFuncName),
221 debugstr_a(pszOID), debugstr_w(pwszValueName), pdwValueType, pbValueData,
222 pcbValueData);
224 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
225 return TRUE;
227 if (!pszFuncName || !pszOID || !pwszValueName)
229 SetLastError(ERROR_INVALID_PARAMETER);
230 return FALSE;
233 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
234 rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
235 HeapFree(GetProcessHeap(), 0, szKey);
236 if (rc)
237 SetLastError(rc);
238 else
240 rc = RegQueryValueExW(hKey, pwszValueName, NULL, pdwValueType,
241 pbValueData, pcbValueData);
242 if (rc)
243 SetLastError(rc);
244 RegCloseKey(hKey);
246 return rc ? FALSE : TRUE;
249 BOOL WINAPI CryptSetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
250 LPCSTR pszOID, LPCWSTR pwszValueName, DWORD dwValueType,
251 const BYTE *pbValueData, DWORD cbValueData)
253 LPSTR szKey;
254 LONG rc;
255 HKEY hKey;
257 TRACE("%lx %s %s %s %ld %p %ld\n", dwEncodingType, debugstr_a(pszFuncName),
258 debugstr_a(pszOID), debugstr_w(pwszValueName), dwValueType, pbValueData,
259 cbValueData);
261 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
262 return TRUE;
264 if (!pszFuncName || !pszOID || !pwszValueName)
266 SetLastError(ERROR_INVALID_PARAMETER);
267 return FALSE;
270 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
271 rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
272 HeapFree(GetProcessHeap(), 0, szKey);
273 if (rc)
274 SetLastError(rc);
275 else
277 rc = RegSetValueExW(hKey, pwszValueName, 0, dwValueType, pbValueData,
278 cbValueData);
279 if (rc)
280 SetLastError(rc);
281 RegCloseKey(hKey);
283 return rc ? FALSE : TRUE;
286 /* Gets the registered function named szFuncName for dwCertEncodingType and
287 * lpszStructType, or NULL if one could not be found. *lib will be set to the
288 * handle of the module it's in, or NULL if no module was loaded. If the
289 * return value is NULL, *lib will also be NULL, to simplify error handling.
291 static void *CRYPT_GetFunc(DWORD dwCertEncodingType, LPCSTR lpszStructType,
292 LPCSTR szFuncName, HMODULE *lib)
294 void *ret = NULL;
295 char *szKey = CRYPT_GetKeyName(dwCertEncodingType, szFuncName,
296 lpszStructType);
297 const char *funcName;
298 long r;
299 HKEY hKey;
300 DWORD type, size = 0;
302 TRACE("(%08lx %s %s %p)\n", dwCertEncodingType, debugstr_a(lpszStructType),
303 debugstr_a(szFuncName), lib);
305 *lib = NULL;
306 r = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
307 HeapFree(GetProcessHeap(), 0, szKey);
308 if(r != ERROR_SUCCESS)
309 return NULL;
311 RegQueryValueExA(hKey, "FuncName", NULL, &type, NULL, &size);
312 if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
314 funcName = HeapAlloc(GetProcessHeap(), 0, size);
315 RegQueryValueExA(hKey, "FuncName", NULL, &type, (LPBYTE)funcName,
316 &size);
318 else
319 funcName = szFuncName;
320 RegQueryValueExW(hKey, szDllName, NULL, &type, NULL, &size);
321 if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
323 LPWSTR dllName = HeapAlloc(GetProcessHeap(), 0, size);
325 RegQueryValueExW(hKey, szDllName, NULL, &type, (LPBYTE)dllName,
326 &size);
327 *lib = LoadLibraryW(dllName);
328 if (*lib)
330 ret = GetProcAddress(*lib, funcName);
331 if (!ret)
333 /* Unload the library, the caller doesn't want to unload it
334 * when the return value is NULL.
336 FreeLibrary(*lib);
337 *lib = NULL;
340 HeapFree(GetProcessHeap(), 0, dllName);
342 if (funcName != szFuncName)
343 HeapFree(GetProcessHeap(), 0, (char *)funcName);
344 TRACE("returning %p\n", ret);
345 return ret;
348 typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
349 BYTE *, DWORD *);
351 BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
352 const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
354 BOOL ret = FALSE;
355 HMODULE lib;
356 CryptEncodeObjectFunc pCryptEncodeObject;
358 TRACE("(0x%08lx, %s, %p, %p, %p)\n",
359 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
360 "(integer value)", pvStructInfo, pbEncoded, pcbEncoded);
362 if (!pbEncoded && !pcbEncoded)
364 SetLastError(ERROR_INVALID_PARAMETER);
365 return FALSE;
368 /* Try registered DLL first.. */
369 pCryptEncodeObject =
370 (CryptEncodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
371 lpszStructType, "CryptEncodeObject", &lib);
372 if (pCryptEncodeObject)
374 ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
375 pvStructInfo, pbEncoded, pcbEncoded);
376 FreeLibrary(lib);
378 else
380 /* If not, use CryptEncodeObjectEx */
381 ret = CryptEncodeObjectEx(dwCertEncodingType, lpszStructType,
382 pvStructInfo, 0, NULL, pbEncoded, pcbEncoded);
384 return ret;
387 /* Helper function to check *pcbEncoded, set it to the required size, and
388 * optionally to allocate memory. Assumes pbEncoded is not NULL.
389 * If CRYPT_ENCODE_ALLOC_FLAG is set in dwFlags, *pbEncoded will be set to a
390 * pointer to the newly allocated memory.
392 static BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags,
393 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded,
394 DWORD bytesNeeded)
396 BOOL ret = TRUE;
398 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
400 if (pEncodePara && pEncodePara->pfnAlloc)
401 *(BYTE **)pbEncoded = pEncodePara->pfnAlloc(bytesNeeded);
402 else
403 *(BYTE **)pbEncoded = LocalAlloc(0, bytesNeeded);
404 if (!*(BYTE **)pbEncoded)
405 ret = FALSE;
406 else
407 *pcbEncoded = bytesNeeded;
409 else if (bytesNeeded > *pcbEncoded)
411 *pcbEncoded = bytesNeeded;
412 SetLastError(ERROR_MORE_DATA);
413 ret = FALSE;
415 return ret;
418 static BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded)
420 DWORD bytesNeeded, significantBytes = 0;
422 if (len <= 0x7f)
423 bytesNeeded = 1;
424 else
426 DWORD temp;
428 for (temp = len, significantBytes = sizeof(temp); !(temp & 0xff000000);
429 temp <<= 8, significantBytes--)
431 bytesNeeded = significantBytes + 1;
433 if (!pbEncoded)
435 *pcbEncoded = bytesNeeded;
436 return TRUE;
438 if (*pcbEncoded < bytesNeeded)
440 SetLastError(ERROR_MORE_DATA);
441 return FALSE;
443 if (len <= 0x7f)
444 *pbEncoded = (BYTE)len;
445 else
447 DWORD i;
449 *pbEncoded++ = significantBytes | 0x80;
450 for (i = 0; i < significantBytes; i++)
452 *(pbEncoded + significantBytes - i - 1) = (BYTE)(len & 0xff);
453 len >>= 8;
456 *pcbEncoded = bytesNeeded;
457 return TRUE;
460 static BOOL CRYPT_AsnEncodeExtension(CERT_EXTENSION *ext, BYTE *pbEncoded,
461 DWORD *pcbEncoded)
463 BOOL ret;
464 DWORD dataLen, octetsLen, lenBytes, size;
466 ret = CRYPT_AsnEncodeOid(ext->pszObjId, NULL, &size);
467 if (ret)
469 dataLen = size;
470 if (ext->fCritical)
472 ret = CRYPT_EncodeBool(TRUE, NULL, &size);
473 dataLen += size;
475 if (ret)
477 ret = CRYPT_AsnEncodeOctets(X509_ASN_ENCODING, X509_OCTET_STRING,
478 &ext->Value, 0, NULL, NULL, &octetsLen);
479 dataLen += octetsLen;
481 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
482 *pcbEncoded = 1 + lenBytes + dataLen;
484 if (ret && pbEncoded)
486 *pbEncoded++ = ASN_SEQUENCE;
487 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
488 pbEncoded += lenBytes;
489 ret = CRYPT_AsnEncodeOid(ext->pszObjId, pbEncoded, &size);
490 if (ret)
492 pbEncoded += size;
493 if (ext->fCritical)
495 ret = CRYPT_EncodeBool(TRUE, pbEncoded, &size);
496 pbEncoded += size;
498 if (ret)
500 ret = CRYPT_AsnEncodeOctets(X509_ASN_ENCODING,
501 X509_OCTET_STRING, &ext->Value, 0, NULL, pbEncoded,
502 &octetsLen);
503 pbEncoded += octetsLen;
507 return ret;
510 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
511 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
512 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
514 BOOL ret;
516 __TRY
518 DWORD bytesNeeded, dataLen, lenBytes, i;
519 CERT_EXTENSIONS *exts = (CERT_EXTENSIONS *)pvStructInfo;
521 ret = TRUE;
522 for (i = 0, dataLen = 0; ret && i < exts->cExtension; i++)
524 DWORD size;
526 ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i], NULL, &size);
527 if (ret)
528 dataLen += size;
530 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
531 bytesNeeded = 1 + lenBytes + dataLen;
532 if (!pbEncoded)
533 *pcbEncoded = bytesNeeded;
534 else
536 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
537 pcbEncoded, bytesNeeded)))
539 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
540 pbEncoded = *(BYTE **)pbEncoded;
541 *pbEncoded++ = ASN_SEQUENCEOF;
542 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
543 pbEncoded += lenBytes;
544 for (i = 0; i < exts->cExtension; i++)
546 DWORD size;
548 ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i],
549 pbEncoded, &size);
550 if (ret)
551 pbEncoded += size;
556 __EXCEPT(page_fault)
558 SetLastError(STATUS_ACCESS_VIOLATION);
559 ret = FALSE;
561 __ENDTRY
562 return ret;
565 static BOOL WINAPI CRYPT_AsnEncodeOid(LPCSTR pszObjId, BYTE *pbEncoded,
566 DWORD *pcbEncoded)
568 DWORD bytesNeeded = 0, lenBytes;
569 BOOL ret = TRUE;
570 int firstPos = 0;
571 BYTE firstByte = 0;
573 if (pszObjId)
575 const char *ptr;
576 int val1, val2;
578 if (sscanf(pszObjId, "%d.%d.%n", &val1, &val2, &firstPos) != 2)
580 SetLastError(CRYPT_E_ASN1_ERROR);
581 return FALSE;
583 bytesNeeded++;
584 firstByte = val1 * 40 + val2;
585 ptr = pszObjId + firstPos;
586 while (ret && *ptr)
588 int pos;
590 /* note I assume each component is at most 32-bits long in base 2 */
591 if (sscanf(ptr, "%d%n", &val1, &pos) == 1)
593 if (val1 >= 0x10000000)
594 bytesNeeded += 5;
595 else if (val1 >= 0x200000)
596 bytesNeeded += 4;
597 else if (val1 >= 0x4000)
598 bytesNeeded += 3;
599 else if (val1 >= 0x80)
600 bytesNeeded += 2;
601 else
602 bytesNeeded += 1;
603 ptr += pos;
604 if (*ptr == '.')
605 ptr++;
607 else
609 SetLastError(CRYPT_E_ASN1_ERROR);
610 return FALSE;
613 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
615 else
616 lenBytes = 1;
617 bytesNeeded += 1 + lenBytes;
618 if (pbEncoded)
620 if (*pbEncoded < bytesNeeded)
622 SetLastError(ERROR_MORE_DATA);
623 ret = FALSE;
625 else
627 *pbEncoded++ = ASN_OBJECTIDENTIFIER;
628 CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded, &lenBytes);
629 pbEncoded += lenBytes;
630 if (pszObjId)
632 const char *ptr;
633 int val, pos;
635 *pbEncoded++ = firstByte;
636 ptr = pszObjId + firstPos;
637 while (ret && *ptr)
639 sscanf(ptr, "%d%n", &val, &pos);
641 unsigned char outBytes[5];
642 int numBytes, i;
644 if (val >= 0x10000000)
645 numBytes = 5;
646 else if (val >= 0x200000)
647 numBytes = 4;
648 else if (val >= 0x4000)
649 numBytes = 3;
650 else if (val >= 0x80)
651 numBytes = 2;
652 else
653 numBytes = 1;
654 for (i = numBytes; i > 0; i--)
656 outBytes[i - 1] = val & 0x7f;
657 val >>= 7;
659 for (i = 0; i < numBytes - 1; i++)
660 *pbEncoded++ = outBytes[i] | 0x80;
661 *pbEncoded++ = outBytes[i];
662 ptr += pos;
663 if (*ptr == '.')
664 ptr++;
670 *pcbEncoded = bytesNeeded;
671 return ret;
674 static BOOL WINAPI CRYPT_AsnEncodeNameValue(DWORD dwCertEncodingType,
675 CERT_NAME_VALUE *value, BYTE *pbEncoded, DWORD *pcbEncoded)
677 BYTE tag;
678 DWORD bytesNeeded, lenBytes, encodedLen;
679 BOOL ret = TRUE;
681 switch (value->dwValueType)
683 case CERT_RDN_NUMERIC_STRING:
684 tag = ASN_NUMERICSTRING;
685 encodedLen = value->Value.cbData;
686 break;
687 case CERT_RDN_PRINTABLE_STRING:
688 tag = ASN_PRINTABLESTRING;
689 encodedLen = value->Value.cbData;
690 break;
691 case CERT_RDN_IA5_STRING:
692 tag = ASN_IA5STRING;
693 encodedLen = value->Value.cbData;
694 break;
695 case CERT_RDN_ANY_TYPE:
696 /* explicitly disallowed */
697 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
698 return FALSE;
699 default:
700 FIXME("String type %ld unimplemented\n", value->dwValueType);
701 return FALSE;
703 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
704 bytesNeeded = 1 + lenBytes + encodedLen;
705 if (pbEncoded)
707 if (*pcbEncoded < bytesNeeded)
709 SetLastError(ERROR_MORE_DATA);
710 ret = FALSE;
712 else
714 *pbEncoded++ = tag;
715 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
716 pbEncoded += lenBytes;
717 switch (value->dwValueType)
719 case CERT_RDN_NUMERIC_STRING:
720 case CERT_RDN_PRINTABLE_STRING:
721 case CERT_RDN_IA5_STRING:
722 memcpy(pbEncoded, value->Value.pbData, value->Value.cbData);
726 *pcbEncoded = bytesNeeded;
727 return ret;
730 static BOOL WINAPI CRYPT_AsnEncodeRdnAttr(DWORD dwCertEncodingType,
731 CERT_RDN_ATTR *attr, BYTE *pbEncoded, DWORD *pcbEncoded)
733 DWORD bytesNeeded = 0, lenBytes, size;
734 BOOL ret;
736 ret = CRYPT_AsnEncodeOid(attr->pszObjId, NULL, &size);
737 if (ret)
739 bytesNeeded += size;
740 /* hack: a CERT_RDN_ATTR is identical to a CERT_NAME_VALUE beginning
741 * with dwValueType, so "cast" it to get its encoded size
743 ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
744 (CERT_NAME_VALUE *)&attr->dwValueType, NULL, &size);
745 if (ret)
747 bytesNeeded += size;
748 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
749 bytesNeeded += 1 + lenBytes;
750 if (pbEncoded)
752 if (*pcbEncoded < bytesNeeded)
754 SetLastError(ERROR_MORE_DATA);
755 ret = FALSE;
757 else
759 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SEQUENCE;
760 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
761 &lenBytes);
762 pbEncoded += lenBytes;
763 size = bytesNeeded - 1 - lenBytes;
764 ret = CRYPT_AsnEncodeOid(attr->pszObjId, pbEncoded, &size);
765 if (ret)
767 pbEncoded += size;
768 size = bytesNeeded - 1 - lenBytes - size;
769 ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
770 (CERT_NAME_VALUE *)&attr->dwValueType, pbEncoded,
771 &size);
775 *pcbEncoded = bytesNeeded;
778 return ret;
781 static int BLOBComp(const void *l, const void *r)
783 CRYPT_DER_BLOB *a = (CRYPT_DER_BLOB *)l, *b = (CRYPT_DER_BLOB *)r;
784 int ret;
786 if (!(ret = memcmp(a->pbData, b->pbData, min(a->cbData, b->cbData))))
787 ret = a->cbData - b->cbData;
788 return ret;
791 /* This encodes as a SET OF, which in DER must be lexicographically sorted.
793 static BOOL WINAPI CRYPT_AsnEncodeRdn(DWORD dwCertEncodingType, CERT_RDN *rdn,
794 BYTE *pbEncoded, DWORD *pcbEncoded)
796 BOOL ret;
797 CRYPT_DER_BLOB *blobs = NULL;
799 __TRY
801 DWORD bytesNeeded = 0, lenBytes, i;
803 ret = TRUE;
804 if (rdn->cRDNAttr)
806 blobs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
807 rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
808 if (!blobs)
809 ret = FALSE;
811 for (i = 0; ret && i < rdn->cRDNAttr; i++)
813 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType, &rdn->rgRDNAttr[i],
814 NULL, &blobs[i].cbData);
815 if (ret)
816 bytesNeeded += blobs[i].cbData;
818 if (ret)
820 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
821 bytesNeeded += 1 + lenBytes;
822 if (pbEncoded)
824 if (*pcbEncoded < bytesNeeded)
826 SetLastError(ERROR_MORE_DATA);
827 ret = FALSE;
829 else
831 for (i = 0; ret && i < rdn->cRDNAttr; i++)
833 blobs[i].pbData = HeapAlloc(GetProcessHeap(), 0,
834 blobs[i].cbData);
835 if (!blobs[i].pbData)
836 ret = FALSE;
837 else
838 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType,
839 &rdn->rgRDNAttr[i], blobs[i].pbData,
840 &blobs[i].cbData);
842 if (ret)
844 qsort(blobs, rdn->cRDNAttr, sizeof(CRYPT_DER_BLOB),
845 BLOBComp);
846 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF;
847 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
848 &lenBytes);
849 pbEncoded += lenBytes;
850 for (i = 0; ret && i < rdn->cRDNAttr; i++)
852 memcpy(pbEncoded, blobs[i].pbData, blobs[i].cbData);
853 pbEncoded += blobs[i].cbData;
858 *pcbEncoded = bytesNeeded;
860 if (blobs)
862 for (i = 0; i < rdn->cRDNAttr; i++)
863 HeapFree(GetProcessHeap(), 0, blobs[i].pbData);
866 __EXCEPT(page_fault)
868 SetLastError(STATUS_ACCESS_VIOLATION);
869 ret = FALSE;
871 __ENDTRY
872 HeapFree(GetProcessHeap(), 0, blobs);
873 return ret;
876 static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
877 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
878 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
880 BOOL ret;
882 __TRY
884 CERT_NAME_INFO *info = (CERT_NAME_INFO *)pvStructInfo;
885 DWORD bytesNeeded = 0, lenBytes, size, i;
887 TRACE("encoding name with %ld RDNs\n", info->cRDN);
888 ret = TRUE;
889 for (i = 0; ret && i < info->cRDN; i++)
891 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i], NULL,
892 &size);
893 if (ret)
894 bytesNeeded += size;
896 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
897 bytesNeeded += 1 + lenBytes;
898 if (ret)
900 if (!pbEncoded)
901 *pcbEncoded = bytesNeeded;
902 else
904 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
905 pbEncoded, pcbEncoded, bytesNeeded)))
907 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
908 pbEncoded = *(BYTE **)pbEncoded;
909 *pbEncoded++ = ASN_SEQUENCEOF;
910 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
911 &lenBytes);
912 pbEncoded += lenBytes;
913 for (i = 0; ret && i < info->cRDN; i++)
915 size = bytesNeeded;
916 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType,
917 &info->rgRDN[i], pbEncoded, &size);
918 if (ret)
920 pbEncoded += size;
921 bytesNeeded -= size;
928 __EXCEPT(page_fault)
930 SetLastError(STATUS_ACCESS_VIOLATION);
931 ret = FALSE;
933 __ENDTRY
934 return ret;
937 static BOOL CRYPT_EncodeBool(BOOL val, BYTE *pbEncoded, DWORD *pcbEncoded)
939 if (!pbEncoded)
941 *pcbEncoded = 3;
942 return TRUE;
944 if (*pcbEncoded < 3)
946 *pcbEncoded = 3;
947 SetLastError(ERROR_MORE_DATA);
948 return FALSE;
950 *pcbEncoded = 3;
951 *pbEncoded++ = ASN_BOOL;
952 *pbEncoded++ = 1;
953 *pbEncoded++ = val ? 0xff : 0;
954 return TRUE;
957 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
958 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
959 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
961 BOOL ret;
963 __TRY
965 CERT_BASIC_CONSTRAINTS2_INFO *info =
966 (CERT_BASIC_CONSTRAINTS2_INFO *)pvStructInfo;
967 DWORD bytesNeeded = 0, lenBytes, caLen = 0, pathConstraintLen = 0;
969 ret = TRUE;
970 if (info->fCA)
972 ret = CRYPT_EncodeBool(TRUE, NULL, &caLen);
973 if (ret)
974 bytesNeeded += caLen;
976 if (info->fPathLenConstraint)
978 ret = CRYPT_AsnEncodeInt(dwCertEncodingType, X509_INTEGER,
979 &info->dwPathLenConstraint, 0, NULL, NULL, &pathConstraintLen);
980 if (ret)
981 bytesNeeded += pathConstraintLen;
983 if (ret)
985 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
986 bytesNeeded += 1 + lenBytes;
987 if (!pbEncoded)
988 *pcbEncoded = bytesNeeded;
989 else
991 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
992 pbEncoded, pcbEncoded, bytesNeeded)))
994 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
995 pbEncoded = *(BYTE **)pbEncoded;
996 *pbEncoded++ = ASN_SEQUENCE;
997 CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded,
998 &lenBytes);
999 pbEncoded += lenBytes;
1000 if (info->fCA)
1002 ret = CRYPT_EncodeBool(TRUE, pbEncoded, &caLen);
1003 if (ret)
1004 pbEncoded += caLen;
1006 if (info->fPathLenConstraint)
1008 ret = CRYPT_AsnEncodeInt(dwCertEncodingType,
1009 X509_INTEGER, &info->dwPathLenConstraint, 0, NULL,
1010 pbEncoded, &pathConstraintLen);
1016 __EXCEPT(page_fault)
1018 SetLastError(STATUS_ACCESS_VIOLATION);
1019 ret = FALSE;
1021 __ENDTRY
1022 return ret;
1025 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
1026 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1027 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1029 BOOL ret;
1031 __TRY
1033 CRYPT_DATA_BLOB *blob = (CRYPT_DATA_BLOB *)pvStructInfo;
1034 DWORD bytesNeeded, lenBytes;
1036 CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
1037 bytesNeeded = 1 + lenBytes + blob->cbData;
1038 if (!pbEncoded)
1040 *pcbEncoded = bytesNeeded;
1041 ret = TRUE;
1043 else
1045 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1046 pcbEncoded, bytesNeeded)))
1048 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1049 pbEncoded = *(BYTE **)pbEncoded;
1050 *pbEncoded++ = ASN_OCTETSTRING;
1051 CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
1052 pbEncoded += lenBytes;
1053 if (blob->cbData)
1054 memcpy(pbEncoded, blob->pbData, blob->cbData);
1058 __EXCEPT(page_fault)
1060 SetLastError(STATUS_ACCESS_VIOLATION);
1061 ret = FALSE;
1063 __ENDTRY
1064 return ret;
1067 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
1068 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1069 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1071 BOOL ret;
1073 __TRY
1075 CRYPT_BIT_BLOB *blob = (CRYPT_BIT_BLOB *)pvStructInfo;
1076 DWORD bytesNeeded, lenBytes, dataBytes;
1077 BYTE unusedBits;
1079 /* yep, MS allows cUnusedBits to be >= 8 */
1080 if (blob->cbData * 8 > blob->cUnusedBits)
1082 dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
1083 unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
1084 blob->cUnusedBits;
1086 else
1088 dataBytes = 0;
1089 unusedBits = 0;
1091 CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
1092 bytesNeeded = 1 + lenBytes + dataBytes + 1;
1093 if (!pbEncoded)
1095 *pcbEncoded = bytesNeeded;
1096 ret = TRUE;
1098 else
1100 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1101 pcbEncoded, bytesNeeded)))
1103 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1104 pbEncoded = *(BYTE **)pbEncoded;
1105 *pbEncoded++ = ASN_BITSTRING;
1106 CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
1107 pbEncoded += lenBytes;
1108 *pbEncoded++ = unusedBits;
1109 if (dataBytes)
1111 BYTE mask = 0xff << unusedBits;
1113 if (dataBytes > 1)
1115 memcpy(pbEncoded, blob->pbData, dataBytes - 1);
1116 pbEncoded += dataBytes - 1;
1118 *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
1123 __EXCEPT(page_fault)
1125 SetLastError(STATUS_ACCESS_VIOLATION);
1126 ret = FALSE;
1128 __ENDTRY
1129 return ret;
1132 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
1133 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1134 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1136 CRYPT_INTEGER_BLOB blob = { sizeof(INT), (BYTE *)pvStructInfo };
1138 return CRYPT_AsnEncodeInteger(dwCertEncodingType, X509_MULTI_BYTE_INTEGER,
1139 &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1142 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
1143 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1144 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1146 BOOL ret;
1148 __TRY
1150 DWORD significantBytes, lenBytes;
1151 BYTE padByte = 0, bytesNeeded;
1152 BOOL pad = FALSE;
1153 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
1155 significantBytes = blob->cbData;
1156 if (significantBytes)
1158 if (blob->pbData[significantBytes - 1] & 0x80)
1160 /* negative, lop off leading (little-endian) 0xffs */
1161 for (; significantBytes > 0 &&
1162 blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
1164 if (blob->pbData[significantBytes - 1] < 0x80)
1166 padByte = 0xff;
1167 pad = TRUE;
1170 else
1172 /* positive, lop off leading (little-endian) zeroes */
1173 for (; significantBytes > 0 &&
1174 !blob->pbData[significantBytes - 1]; significantBytes--)
1176 if (significantBytes == 0)
1177 significantBytes = 1;
1178 if (blob->pbData[significantBytes - 1] > 0x7f)
1180 padByte = 0;
1181 pad = TRUE;
1185 if (pad)
1186 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
1187 else
1188 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
1189 bytesNeeded = 1 + lenBytes + significantBytes;
1190 if (pad)
1191 bytesNeeded++;
1192 if (!pbEncoded)
1194 *pcbEncoded = bytesNeeded;
1195 ret = TRUE;
1197 else
1199 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1200 pcbEncoded, bytesNeeded)))
1202 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1203 pbEncoded = *(BYTE **)pbEncoded;
1204 *pbEncoded++ = ASN_INTEGER;
1205 if (pad)
1207 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
1208 pbEncoded += lenBytes;
1209 *pbEncoded++ = padByte;
1211 else
1213 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
1214 pbEncoded += lenBytes;
1216 for (; significantBytes > 0; significantBytes--)
1217 *(pbEncoded++) = blob->pbData[significantBytes - 1];
1221 __EXCEPT(page_fault)
1223 SetLastError(STATUS_ACCESS_VIOLATION);
1224 ret = FALSE;
1226 __ENDTRY
1227 return ret;
1230 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
1231 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1232 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1234 BOOL ret;
1236 __TRY
1238 DWORD significantBytes, lenBytes;
1239 BYTE bytesNeeded;
1240 BOOL pad = FALSE;
1241 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
1243 significantBytes = blob->cbData;
1244 if (significantBytes)
1246 /* positive, lop off leading (little-endian) zeroes */
1247 for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
1248 significantBytes--)
1250 if (significantBytes == 0)
1251 significantBytes = 1;
1252 if (blob->pbData[significantBytes - 1] > 0x7f)
1253 pad = TRUE;
1255 if (pad)
1256 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
1257 else
1258 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
1259 bytesNeeded = 1 + lenBytes + significantBytes;
1260 if (pad)
1261 bytesNeeded++;
1262 if (!pbEncoded)
1264 *pcbEncoded = bytesNeeded;
1265 ret = TRUE;
1267 else
1269 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1270 pcbEncoded, bytesNeeded)))
1272 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1273 pbEncoded = *(BYTE **)pbEncoded;
1274 *pbEncoded++ = ASN_INTEGER;
1275 if (pad)
1277 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
1278 pbEncoded += lenBytes;
1279 *pbEncoded++ = 0;
1281 else
1283 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
1284 pbEncoded += lenBytes;
1286 for (; significantBytes > 0; significantBytes--)
1287 *(pbEncoded++) = blob->pbData[significantBytes - 1];
1291 __EXCEPT(page_fault)
1293 SetLastError(STATUS_ACCESS_VIOLATION);
1294 ret = FALSE;
1296 __ENDTRY
1297 return ret;
1300 static BOOL WINAPI CRYPT_AsnEncodeEnumerated(DWORD dwCertEncodingType,
1301 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1302 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1304 CRYPT_INTEGER_BLOB blob;
1305 BOOL ret;
1307 /* Encode as an unsigned integer, then change the tag to enumerated */
1308 blob.cbData = sizeof(DWORD);
1309 blob.pbData = (BYTE *)pvStructInfo;
1310 ret = CRYPT_AsnEncodeUnsignedInteger(dwCertEncodingType,
1311 X509_MULTI_BYTE_UINT, &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1312 if (ret && pbEncoded)
1314 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1315 pbEncoded = *(BYTE **)pbEncoded;
1316 pbEncoded[0] = ASN_ENUMERATED;
1318 return ret;
1321 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
1322 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1323 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1325 BOOL ret;
1327 __TRY
1329 SYSTEMTIME sysTime;
1330 /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0. I use a
1331 * temporary buffer because the output buffer is not NULL-terminated.
1333 char buf[16];
1334 static const DWORD bytesNeeded = sizeof(buf) - 1;
1336 if (!pbEncoded)
1338 *pcbEncoded = bytesNeeded;
1339 ret = TRUE;
1341 else
1343 /* Sanity check the year, this is a two-digit year format */
1344 ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
1345 &sysTime);
1346 if (ret && (sysTime.wYear < 1950 || sysTime.wYear > 2050))
1348 SetLastError(CRYPT_E_BAD_ENCODE);
1349 ret = FALSE;
1351 if (ret)
1353 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1354 pbEncoded, pcbEncoded, bytesNeeded)))
1356 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1357 pbEncoded = *(BYTE **)pbEncoded;
1358 buf[0] = ASN_UTCTIME;
1359 buf[1] = bytesNeeded - 2;
1360 snprintf(buf + 2, sizeof(buf) - 2,
1361 "%02d%02d%02d%02d%02d%02dZ", sysTime.wYear >= 2000 ?
1362 sysTime.wYear - 2000 : sysTime.wYear - 1900,
1363 sysTime.wDay, sysTime.wMonth, sysTime.wHour,
1364 sysTime.wMinute, sysTime.wSecond);
1365 memcpy(pbEncoded, buf, bytesNeeded);
1370 __EXCEPT(page_fault)
1372 SetLastError(STATUS_ACCESS_VIOLATION);
1373 ret = FALSE;
1375 __ENDTRY
1376 return ret;
1379 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
1380 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1381 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1383 BOOL ret;
1385 __TRY
1387 SYSTEMTIME sysTime;
1388 /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0. I use a
1389 * temporary buffer because the output buffer is not NULL-terminated.
1391 char buf[18];
1392 static const DWORD bytesNeeded = sizeof(buf) - 1;
1394 if (!pbEncoded)
1396 *pcbEncoded = bytesNeeded;
1397 ret = TRUE;
1399 else
1401 ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
1402 &sysTime);
1403 if (ret)
1404 ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1405 pcbEncoded, bytesNeeded);
1406 if (ret)
1408 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1409 pbEncoded = *(BYTE **)pbEncoded;
1410 buf[0] = ASN_GENERALTIME;
1411 buf[1] = bytesNeeded - 2;
1412 snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
1413 sysTime.wYear, sysTime.wDay, sysTime.wMonth, sysTime.wHour,
1414 sysTime.wMinute, sysTime.wSecond);
1415 memcpy(pbEncoded, buf, bytesNeeded);
1419 __EXCEPT(page_fault)
1421 SetLastError(STATUS_ACCESS_VIOLATION);
1422 ret = FALSE;
1424 __ENDTRY
1425 return ret;
1428 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
1429 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1430 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1432 BOOL ret;
1434 __TRY
1436 SYSTEMTIME sysTime;
1438 /* Check the year, if it's in the UTCTime range call that encode func */
1439 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
1440 return FALSE;
1441 if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
1442 ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
1443 pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1444 else
1445 ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
1446 lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
1447 pcbEncoded);
1449 __EXCEPT(page_fault)
1451 SetLastError(STATUS_ACCESS_VIOLATION);
1452 ret = FALSE;
1454 __ENDTRY
1455 return ret;
1458 static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
1459 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1460 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1462 BOOL ret;
1464 __TRY
1466 DWORD bytesNeeded, dataLen, lenBytes, i;
1467 CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
1469 for (i = 0, dataLen = 0; i < seq->cValue; i++)
1470 dataLen += seq->rgValue[i].cbData;
1471 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1472 bytesNeeded = 1 + lenBytes + dataLen;
1473 if (!pbEncoded)
1475 *pcbEncoded = bytesNeeded;
1476 ret = TRUE;
1478 else
1480 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1481 pcbEncoded, bytesNeeded)))
1483 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1484 pbEncoded = *(BYTE **)pbEncoded;
1485 *pbEncoded++ = ASN_SEQUENCEOF;
1486 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1487 pbEncoded += lenBytes;
1488 for (i = 0; i < seq->cValue; i++)
1490 memcpy(pbEncoded, seq->rgValue[i].pbData,
1491 seq->rgValue[i].cbData);
1492 pbEncoded += seq->rgValue[i].cbData;
1497 __EXCEPT(page_fault)
1499 SetLastError(STATUS_ACCESS_VIOLATION);
1500 ret = FALSE;
1502 __ENDTRY
1503 return ret;
1506 typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *,
1507 DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *);
1509 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
1510 const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
1511 void *pvEncoded, DWORD *pcbEncoded)
1513 BOOL ret = FALSE;
1514 HMODULE lib = NULL;
1515 CryptEncodeObjectExFunc encodeFunc = NULL;
1517 TRACE("(0x%08lx, %s, %p, 0x%08lx, %p, %p, %p)\n",
1518 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
1519 "(integer value)", pvStructInfo, dwFlags, pEncodePara, pvEncoded,
1520 pcbEncoded);
1522 if (!pvEncoded && !pcbEncoded)
1524 SetLastError(ERROR_INVALID_PARAMETER);
1525 return FALSE;
1527 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
1528 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
1530 SetLastError(ERROR_FILE_NOT_FOUND);
1531 return FALSE;
1534 SetLastError(NOERROR);
1535 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG && pvEncoded)
1536 *(BYTE **)pvEncoded = NULL;
1537 if (!HIWORD(lpszStructType))
1539 switch (LOWORD(lpszStructType))
1541 case (WORD)X509_EXTENSIONS:
1542 encodeFunc = CRYPT_AsnEncodeExtensions;
1543 break;
1544 case (WORD)X509_NAME:
1545 encodeFunc = CRYPT_AsnEncodeName;
1546 break;
1547 case (WORD)X509_BASIC_CONSTRAINTS2:
1548 encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
1549 break;
1550 case (WORD)X509_OCTET_STRING:
1551 encodeFunc = CRYPT_AsnEncodeOctets;
1552 break;
1553 case (WORD)X509_BITS:
1554 case (WORD)X509_KEY_USAGE:
1555 encodeFunc = CRYPT_AsnEncodeBits;
1556 break;
1557 case (WORD)X509_INTEGER:
1558 encodeFunc = CRYPT_AsnEncodeInt;
1559 break;
1560 case (WORD)X509_MULTI_BYTE_INTEGER:
1561 encodeFunc = CRYPT_AsnEncodeInteger;
1562 break;
1563 case (WORD)X509_MULTI_BYTE_UINT:
1564 encodeFunc = CRYPT_AsnEncodeUnsignedInteger;
1565 break;
1566 case (WORD)X509_ENUMERATED:
1567 encodeFunc = CRYPT_AsnEncodeEnumerated;
1568 break;
1569 case (WORD)X509_CHOICE_OF_TIME:
1570 encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
1571 break;
1572 case (WORD)X509_SEQUENCE_OF_ANY:
1573 encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
1574 break;
1575 case (WORD)PKCS_UTC_TIME:
1576 encodeFunc = CRYPT_AsnEncodeUtcTime;
1577 break;
1578 default:
1579 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
1582 else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
1583 encodeFunc = CRYPT_AsnEncodeExtensions;
1584 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
1585 encodeFunc = CRYPT_AsnEncodeUtcTime;
1586 else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
1587 encodeFunc = CRYPT_AsnEncodeEnumerated;
1588 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
1589 encodeFunc = CRYPT_AsnEncodeBits;
1590 else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
1591 encodeFunc = CRYPT_AsnEncodeOctets;
1592 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
1593 encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
1594 else
1595 TRACE("OID %s not found or unimplemented, looking for DLL\n",
1596 debugstr_a(lpszStructType));
1597 if (!encodeFunc)
1598 encodeFunc = (CryptEncodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
1599 lpszStructType, "CryptEncodeObjectEx", &lib);
1600 if (encodeFunc)
1601 ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
1602 dwFlags, pEncodePara, pvEncoded, pcbEncoded);
1603 else
1604 SetLastError(ERROR_FILE_NOT_FOUND);
1605 if (lib)
1606 FreeLibrary(lib);
1607 return ret;
1610 typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
1611 DWORD, DWORD, void *, DWORD *);
1613 BOOL WINAPI CryptDecodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
1614 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo,
1615 DWORD *pcbStructInfo)
1617 BOOL ret = FALSE;
1618 HMODULE lib;
1619 CryptDecodeObjectFunc pCryptDecodeObject;
1621 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p)\n",
1622 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
1623 "(integer value)", pbEncoded, cbEncoded, dwFlags, pvStructInfo,
1624 pcbStructInfo);
1626 if (!pvStructInfo && !pcbStructInfo)
1628 SetLastError(ERROR_INVALID_PARAMETER);
1629 return FALSE;
1632 /* Try registered DLL first.. */
1633 pCryptDecodeObject =
1634 (CryptDecodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
1635 lpszStructType, "CryptDecodeObject", &lib);
1636 if (pCryptDecodeObject)
1638 ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType,
1639 pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
1640 FreeLibrary(lib);
1642 else
1644 /* If not, use CryptDecodeObjectEx */
1645 ret = CryptDecodeObjectEx(dwCertEncodingType, lpszStructType, pbEncoded,
1646 cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo);
1648 return ret;
1651 /* Gets the number of length bytes from the given (leading) length byte */
1652 #define GET_LEN_BYTES(b) ((b) <= 0x7f ? 1 : 1 + ((b) & 0x7f))
1654 /* Helper function to get the encoded length of the data starting at pbEncoded,
1655 * where pbEncoded[0] is the tag. If the data are too short to contain a
1656 * length or if the length is too large for cbEncoded, sets an appropriate
1657 * error code and returns FALSE.
1659 static BOOL WINAPI CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded,
1660 DWORD *len)
1662 BOOL ret;
1664 if (cbEncoded <= 1)
1666 SetLastError(CRYPT_E_ASN1_EOD);
1667 ret = FALSE;
1669 else if (pbEncoded[1] <= 0x7f)
1671 *len = pbEncoded[1];
1672 ret = TRUE;
1674 else
1676 BYTE lenLen = GET_LEN_BYTES(pbEncoded[1]);
1678 if (lenLen > sizeof(DWORD) + 1)
1680 SetLastError(CRYPT_E_ASN1_LARGE);
1681 ret = FALSE;
1683 else if (lenLen + 2 > cbEncoded)
1685 SetLastError(CRYPT_E_ASN1_CORRUPT);
1686 ret = FALSE;
1688 else
1690 DWORD out = 0;
1692 pbEncoded += 2;
1693 while (--lenLen)
1695 out <<= 8;
1696 out |= *pbEncoded++;
1698 if (out + lenLen + 1 > cbEncoded)
1700 SetLastError(CRYPT_E_ASN1_EOD);
1701 ret = FALSE;
1703 else
1705 *len = out;
1706 ret = TRUE;
1710 return ret;
1713 /* Helper function to check *pcbStructInfo, set it to the required size, and
1714 * optionally to allocate memory. Assumes pvStructInfo is not NULL.
1715 * If CRYPT_DECODE_ALLOC_FLAG is set in dwFlags, *pvStructInfo will be set to a
1716 * pointer to the newly allocated memory.
1718 static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags,
1719 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo,
1720 DWORD bytesNeeded)
1722 BOOL ret = TRUE;
1724 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1726 if (pDecodePara && pDecodePara->pfnAlloc)
1727 *(BYTE **)pvStructInfo = pDecodePara->pfnAlloc(bytesNeeded);
1728 else
1729 *(BYTE **)pvStructInfo = LocalAlloc(0, bytesNeeded);
1730 if (!*(BYTE **)pvStructInfo)
1731 ret = FALSE;
1732 else
1733 *pcbStructInfo = bytesNeeded;
1735 else if (*pcbStructInfo < bytesNeeded)
1737 *pcbStructInfo = bytesNeeded;
1738 SetLastError(ERROR_MORE_DATA);
1739 ret = FALSE;
1741 return ret;
1744 /* Warning: assumes ext->Value.pbData is set ahead of time! */
1745 static BOOL CRYPT_AsnDecodeExtension(const BYTE *pbEncoded, DWORD cbEncoded,
1746 DWORD dwFlags, CERT_EXTENSION *ext, DWORD *pcbExt)
1748 BOOL ret = TRUE;
1750 if (pbEncoded[0] == ASN_SEQUENCE)
1752 DWORD dataLen, bytesNeeded;
1754 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1756 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]), oidLenBytes = 0;
1758 bytesNeeded = sizeof(CERT_EXTENSION);
1759 if (dataLen)
1761 const BYTE *ptr = pbEncoded + 1 + lenBytes;
1762 DWORD encodedOidLen, oidLen;
1764 CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
1765 &encodedOidLen);
1766 oidLenBytes = GET_LEN_BYTES(ptr[1]);
1767 ret = CRYPT_AsnDecodeOid(ptr, cbEncoded - (ptr - pbEncoded),
1768 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, &oidLen);
1769 if (ret)
1771 bytesNeeded += oidLen;
1772 ptr += 1 + encodedOidLen + oidLenBytes;
1773 if (*ptr == ASN_BOOL)
1774 ptr += 3;
1775 ret = CRYPT_AsnDecodeOctets(X509_ASN_ENCODING,
1776 X509_OCTET_STRING, ptr, cbEncoded - (ptr - pbEncoded),
1777 0, NULL, NULL, &dataLen);
1778 bytesNeeded += dataLen;
1779 if (ret)
1781 if (!ext)
1782 *pcbExt = bytesNeeded;
1783 else if (*pcbExt < bytesNeeded)
1785 SetLastError(ERROR_MORE_DATA);
1786 ret = FALSE;
1788 else
1790 ptr = pbEncoded + 2 + lenBytes + encodedOidLen +
1791 oidLenBytes;
1792 if (*ptr == ASN_BOOL)
1794 CRYPT_DecodeBool(ptr, cbEncoded -
1795 (ptr - pbEncoded), &ext->fCritical);
1796 ptr += 3;
1798 ret = CRYPT_AsnDecodeOctets(X509_ASN_ENCODING,
1799 X509_OCTET_STRING, ptr,
1800 cbEncoded - (ptr - pbEncoded),
1801 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
1802 &ext->Value, &dataLen);
1803 if (ret)
1805 ext->pszObjId = ext->Value.pbData +
1806 ext->Value.cbData;
1807 ptr = pbEncoded + 1 + lenBytes;
1808 ret = CRYPT_AsnDecodeOid(ptr,
1809 cbEncoded - (ptr - pbEncoded),
1810 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG,
1811 ext->pszObjId, &oidLen);
1817 else
1819 SetLastError(CRYPT_E_ASN1_EOD);
1820 ret = FALSE;
1824 else
1826 SetLastError(CRYPT_E_ASN1_BADTAG);
1827 ret = FALSE;
1829 return ret;
1832 static BOOL WINAPI CRYPT_AsnDecodeExtensions(DWORD dwCertEncodingType,
1833 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1834 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1836 BOOL ret = TRUE;
1838 __TRY
1840 if (pbEncoded[0] == ASN_SEQUENCEOF)
1842 DWORD dataLen, bytesNeeded;
1844 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1846 DWORD cExtension = 0;
1847 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1849 bytesNeeded = sizeof(CERT_EXTENSIONS);
1850 if (dataLen)
1852 const BYTE *ptr;
1853 DWORD size;
1855 for (ptr = pbEncoded + 1 + lenBytes; ret &&
1856 ptr - pbEncoded - 1 - lenBytes < dataLen; )
1858 ret = CRYPT_AsnDecodeExtension(ptr,
1859 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
1860 if (ret)
1862 DWORD nextLen;
1864 cExtension++;
1865 bytesNeeded += size;
1866 ret = CRYPT_GetLen(ptr,
1867 cbEncoded - (ptr - pbEncoded), &nextLen);
1868 if (ret)
1869 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
1873 if (ret)
1875 if (!pvStructInfo)
1876 *pcbStructInfo = bytesNeeded;
1877 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
1878 pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
1880 DWORD size, i;
1881 BYTE *nextData;
1882 const BYTE *ptr;
1883 CERT_EXTENSIONS *exts;
1885 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1886 pvStructInfo = *(BYTE **)pvStructInfo;
1887 *pcbStructInfo = bytesNeeded;
1888 exts = (CERT_EXTENSIONS *)pvStructInfo;
1889 exts->cExtension = cExtension;
1890 exts->rgExtension = (CERT_EXTENSION *)((BYTE *)exts +
1891 sizeof(CERT_EXTENSIONS));
1892 nextData = (BYTE *)exts->rgExtension +
1893 exts->cExtension * sizeof(CERT_EXTENSION);
1894 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
1895 i < cExtension && ptr - pbEncoded - 1 - lenBytes <
1896 dataLen; i++)
1898 exts->rgExtension[i].Value.pbData = nextData;
1899 size = bytesNeeded;
1900 ret = CRYPT_AsnDecodeExtension(ptr,
1901 cbEncoded - (ptr - pbEncoded), dwFlags,
1902 &exts->rgExtension[i], &size);
1903 if (ret)
1905 DWORD nextLen;
1907 bytesNeeded -= size;
1908 /* If dwFlags & CRYPT_DECODE_NOCOPY_FLAG, the
1909 * data may not have been copied.
1911 if (exts->rgExtension[i].Value.pbData ==
1912 nextData)
1913 nextData +=
1914 exts->rgExtension[i].Value.cbData;
1915 /* Ugly: the OID, if copied, is stored in
1916 * memory after the value, so increment by its
1917 * string length if it's set and points here.
1919 if ((const BYTE *)exts->rgExtension[i].pszObjId
1920 == nextData)
1921 nextData += strlen(
1922 exts->rgExtension[i].pszObjId) + 1;
1923 ret = CRYPT_GetLen(ptr,
1924 cbEncoded - (ptr - pbEncoded), &nextLen);
1925 if (ret)
1926 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
1933 else
1935 SetLastError(CRYPT_E_ASN1_BADTAG);
1936 ret = FALSE;
1939 __EXCEPT(page_fault)
1941 SetLastError(STATUS_ACCESS_VIOLATION);
1942 ret = FALSE;
1944 __ENDTRY
1945 return ret;
1948 /* FIXME: honor the CRYPT_DECODE_SHARE_OID_STRING_FLAG. */
1949 static BOOL WINAPI CRYPT_AsnDecodeOid(const BYTE *pbEncoded, DWORD cbEncoded,
1950 DWORD dwFlags, LPSTR pszObjId, DWORD *pcbObjId)
1952 BOOL ret = TRUE;
1954 __TRY
1956 if (pbEncoded[0] == ASN_OBJECTIDENTIFIER)
1958 DWORD dataLen;
1960 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1962 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1963 DWORD bytesNeeded;
1965 if (dataLen)
1967 /* The largest possible string for the first two components
1968 * is 2.175 (= 2 * 40 + 175 = 255), so this is big enough.
1970 char firstTwo[6];
1971 const BYTE *ptr;
1973 snprintf(firstTwo, sizeof(firstTwo), "%d.%d",
1974 pbEncoded[1 + lenBytes] / 40,
1975 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40)
1976 * 40);
1977 bytesNeeded = strlen(firstTwo) + 1;
1978 for (ptr = pbEncoded + 2 + lenBytes; ret &&
1979 ptr - pbEncoded - 1 - lenBytes < dataLen; )
1981 /* large enough for ".4000000" */
1982 char str[9];
1983 int val = 0;
1985 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
1986 (*ptr & 0x80))
1988 val <<= 7;
1989 val |= *ptr & 0x7f;
1990 ptr++;
1992 if (ptr - pbEncoded - 1 - lenBytes >= dataLen ||
1993 (*ptr & 0x80))
1995 SetLastError(CRYPT_E_ASN1_CORRUPT);
1996 ret = FALSE;
1998 else
2000 val <<= 7;
2001 val |= *ptr++;
2002 snprintf(str, sizeof(str), ".%d", val);
2003 bytesNeeded += strlen(str);
2006 if (!pszObjId)
2007 *pcbObjId = bytesNeeded;
2008 else if (*pcbObjId < bytesNeeded)
2010 *pcbObjId = bytesNeeded;
2011 SetLastError(ERROR_MORE_DATA);
2012 ret = FALSE;
2014 else
2016 sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40,
2017 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] /
2018 40) * 40);
2019 pszObjId += strlen(pszObjId);
2020 for (ptr = pbEncoded + 2 + lenBytes; ret &&
2021 ptr - pbEncoded - 1 - lenBytes < dataLen; )
2023 int val = 0;
2025 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
2026 (*ptr & 0x80))
2028 val <<= 7;
2029 val |= *ptr & 0x7f;
2030 ptr++;
2032 val <<= 7;
2033 val |= *ptr++;
2034 sprintf(pszObjId, ".%d", val);
2035 pszObjId += strlen(pszObjId);
2039 else
2040 bytesNeeded = 0;
2041 *pcbObjId = bytesNeeded;
2044 else
2046 SetLastError(CRYPT_E_ASN1_BADTAG);
2047 ret = FALSE;
2050 __EXCEPT(page_fault)
2052 SetLastError(STATUS_ACCESS_VIOLATION);
2053 ret = FALSE;
2055 __ENDTRY
2056 return ret;
2059 /* Warning: this assumes the address of value->Value.pbData is already set, in
2060 * order to avoid overwriting memory. (In some cases, it may change it, if it
2061 * doesn't copy anything to memory.) Be sure to set it correctly!
2063 static BOOL WINAPI CRYPT_AsnDecodeNameValue(const BYTE *pbEncoded,
2064 DWORD cbEncoded, DWORD dwFlags, CERT_NAME_VALUE *value, DWORD *pcbValue)
2066 BOOL ret = TRUE;
2068 __TRY
2070 DWORD dataLen;
2072 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2074 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2076 switch (pbEncoded[0])
2078 case ASN_NUMERICSTRING:
2079 case ASN_PRINTABLESTRING:
2080 case ASN_IA5STRING:
2081 break;
2082 default:
2083 FIXME("Unimplemented string type %02x\n", pbEncoded[0]);
2084 SetLastError(OSS_UNIMPLEMENTED);
2085 ret = FALSE;
2087 if (ret)
2089 DWORD bytesNeeded = sizeof(CERT_NAME_VALUE);
2091 switch (pbEncoded[0])
2093 case ASN_NUMERICSTRING:
2094 case ASN_PRINTABLESTRING:
2095 case ASN_IA5STRING:
2096 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
2097 bytesNeeded += dataLen;
2098 break;
2100 if (!value)
2101 *pcbValue = bytesNeeded;
2102 else if (*pcbValue < bytesNeeded)
2104 *pcbValue = bytesNeeded;
2105 SetLastError(ERROR_MORE_DATA);
2106 ret = FALSE;
2108 else
2110 *pcbValue = bytesNeeded;
2111 switch (pbEncoded[0])
2113 case ASN_NUMERICSTRING:
2114 value->dwValueType = CERT_RDN_NUMERIC_STRING;
2115 break;
2116 case ASN_PRINTABLESTRING:
2117 value->dwValueType = CERT_RDN_PRINTABLE_STRING;
2118 break;
2119 case ASN_IA5STRING:
2120 value->dwValueType = CERT_RDN_IA5_STRING;
2121 break;
2123 if (dataLen)
2125 switch (pbEncoded[0])
2127 case ASN_NUMERICSTRING:
2128 case ASN_PRINTABLESTRING:
2129 case ASN_IA5STRING:
2130 value->Value.cbData = dataLen;
2131 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
2132 value->Value.pbData = (BYTE *)pbEncoded + 1 +
2133 lenBytes;
2134 else
2136 if (!value->Value.pbData)
2138 SetLastError(CRYPT_E_ASN1_INTERNAL);
2139 ret = FALSE;
2141 else
2142 memcpy(value->Value.pbData,
2143 pbEncoded + 1 + lenBytes, dataLen);
2145 break;
2148 else
2150 value->Value.cbData = 0;
2151 value->Value.pbData = NULL;
2157 __EXCEPT(page_fault)
2159 SetLastError(STATUS_ACCESS_VIOLATION);
2160 ret = FALSE;
2162 __ENDTRY
2163 return ret;
2166 static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(const BYTE *pbEncoded,
2167 DWORD cbEncoded, DWORD dwFlags, CERT_RDN_ATTR *attr, DWORD *pcbAttr)
2169 BOOL ret;
2171 __TRY
2173 if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SEQUENCE))
2175 DWORD bytesNeeded, dataLen, size;
2176 BYTE lenBytes;
2178 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2180 /* The data length must be at least 4, two for the tag and
2181 * length for the OID, and two for the string (assuming both
2182 * have short-form lengths.)
2184 if (dataLen < 4)
2186 SetLastError(CRYPT_E_ASN1_EOD);
2187 ret = FALSE;
2189 else
2191 bytesNeeded = sizeof(CERT_RDN_ATTR);
2192 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2193 ret = CRYPT_AsnDecodeOid(pbEncoded + 1 + lenBytes,
2194 cbEncoded - 1 - lenBytes, dwFlags, NULL, &size);
2195 if (ret)
2197 /* ugly: need to know the size of the next element of
2198 * the sequence, so get it directly
2200 DWORD objIdOfset = 1 + lenBytes, objIdLen,
2201 nameValueOffset = 0;
2203 ret = CRYPT_GetLen(pbEncoded + objIdOfset,
2204 cbEncoded - objIdOfset, &objIdLen);
2205 bytesNeeded += size;
2206 /* hack: like encoding, this takes advantage of the
2207 * fact that the rest of the structure is identical to
2208 * a CERT_NAME_VALUE.
2210 if (ret)
2212 nameValueOffset = objIdOfset + objIdLen + 1 +
2213 GET_LEN_BYTES(pbEncoded[objIdOfset]);
2214 ret = CRYPT_AsnDecodeNameValue(
2215 pbEncoded + nameValueOffset,
2216 cbEncoded - nameValueOffset, dwFlags, NULL, &size);
2218 if (ret)
2220 bytesNeeded += size;
2221 if (!attr)
2222 *pcbAttr = bytesNeeded;
2223 else if (*pcbAttr < bytesNeeded)
2225 *pcbAttr = bytesNeeded;
2226 SetLastError(ERROR_MORE_DATA);
2227 ret = FALSE;
2229 else
2231 BYTE *originalData = attr->Value.pbData;
2233 *pcbAttr = bytesNeeded;
2234 /* strange: decode the value first, because it
2235 * has a counted size, and we can store the OID
2236 * after it. Keep track of the original data
2237 * pointer, we'll need to know whether it was
2238 * changed.
2240 size = bytesNeeded;
2241 ret = CRYPT_AsnDecodeNameValue(
2242 pbEncoded + nameValueOffset,
2243 cbEncoded - nameValueOffset, dwFlags,
2244 (CERT_NAME_VALUE *)&attr->dwValueType, &size);
2245 if (ret)
2247 if (objIdLen)
2249 /* if the data were copied to the
2250 * original location, the OID goes
2251 * after. Otherwise it goes in the
2252 * spot originally reserved for the
2253 * data.
2255 if (attr->Value.pbData == originalData)
2256 attr->pszObjId =
2257 (LPSTR)(attr->Value.pbData +
2258 attr->Value.cbData);
2259 else
2260 attr->pszObjId = originalData;
2261 size = bytesNeeded - size;
2262 ret = CRYPT_AsnDecodeOid(
2263 pbEncoded + objIdOfset,
2264 cbEncoded - objIdOfset,
2265 dwFlags, attr->pszObjId, &size);
2267 else
2268 attr->pszObjId = NULL;
2276 else
2278 SetLastError(CRYPT_E_ASN1_BADTAG);
2279 ret = FALSE;
2282 __EXCEPT(page_fault)
2284 SetLastError(STATUS_ACCESS_VIOLATION);
2285 ret = FALSE;
2287 __ENDTRY
2288 return ret;
2291 static BOOL WINAPI CRYPT_AsnDecodeRdn(const BYTE *pbEncoded, DWORD cbEncoded,
2292 DWORD dwFlags, CERT_RDN *rdn, DWORD *pcbRdn)
2294 BOOL ret = TRUE;
2296 __TRY
2298 if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SETOF))
2300 DWORD dataLen;
2302 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2304 DWORD bytesNeeded, cRDNAttr = 0;
2305 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2307 bytesNeeded = sizeof(CERT_RDN);
2308 if (dataLen)
2310 const BYTE *ptr;
2311 DWORD size;
2313 for (ptr = pbEncoded + 1 + lenBytes; ret &&
2314 ptr - pbEncoded - 1 - lenBytes < dataLen; )
2316 ret = CRYPT_AsnDecodeRdnAttr(ptr,
2317 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
2318 if (ret)
2320 DWORD nextLen;
2322 cRDNAttr++;
2323 bytesNeeded += size;
2324 ret = CRYPT_GetLen(ptr,
2325 cbEncoded - (ptr - pbEncoded), &nextLen);
2326 if (ret)
2327 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
2331 if (ret)
2333 if (!rdn)
2334 *pcbRdn = bytesNeeded;
2335 else if (*pcbRdn < bytesNeeded)
2337 *pcbRdn = bytesNeeded;
2338 SetLastError(ERROR_MORE_DATA);
2339 ret = FALSE;
2341 else
2343 DWORD size, i;
2344 BYTE *nextData;
2345 const BYTE *ptr;
2347 *pcbRdn = bytesNeeded;
2348 rdn->cRDNAttr = cRDNAttr;
2349 rdn->rgRDNAttr = (CERT_RDN_ATTR *)((BYTE *)rdn +
2350 sizeof(CERT_RDN));
2351 nextData = (BYTE *)rdn->rgRDNAttr +
2352 rdn->cRDNAttr * sizeof(CERT_RDN_ATTR);
2353 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
2354 i < cRDNAttr && ptr - pbEncoded - 1 - lenBytes <
2355 dataLen; i++)
2357 rdn->rgRDNAttr[i].Value.pbData = nextData;
2358 size = bytesNeeded;
2359 ret = CRYPT_AsnDecodeRdnAttr(ptr,
2360 cbEncoded - (ptr - pbEncoded), dwFlags,
2361 &rdn->rgRDNAttr[i], &size);
2362 if (ret)
2364 DWORD nextLen;
2366 bytesNeeded -= size;
2367 /* If dwFlags & CRYPT_DECODE_NOCOPY_FLAG, the
2368 * data may not have been copied.
2370 if (rdn->rgRDNAttr[i].Value.pbData == nextData)
2371 nextData +=
2372 rdn->rgRDNAttr[i].Value.cbData;
2373 /* Ugly: the OID, if copied, is stored in
2374 * memory after the value, so increment by its
2375 * string length if it's set and points here.
2377 if ((const BYTE *)rdn->rgRDNAttr[i].pszObjId
2378 == nextData)
2379 nextData += strlen(
2380 rdn->rgRDNAttr[i].pszObjId) + 1;
2381 ret = CRYPT_GetLen(ptr,
2382 cbEncoded - (ptr - pbEncoded), &nextLen);
2383 if (ret)
2384 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
2391 else
2393 SetLastError(CRYPT_E_ASN1_BADTAG);
2394 ret = FALSE;
2397 __EXCEPT(page_fault)
2399 SetLastError(STATUS_ACCESS_VIOLATION);
2400 ret = FALSE;
2402 __ENDTRY
2403 return ret;
2406 static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType,
2407 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2408 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2410 BOOL ret = TRUE;
2412 __TRY
2414 if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SEQUENCEOF))
2416 DWORD dataLen;
2418 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2420 DWORD bytesNeeded, cRDN = 0;
2421 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2423 bytesNeeded = sizeof(CERT_NAME_INFO);
2424 if (dataLen)
2426 const BYTE *ptr;
2428 for (ptr = pbEncoded + 1 + lenBytes; ret &&
2429 ptr - pbEncoded - 1 - lenBytes < dataLen; )
2431 DWORD size;
2433 ret = CRYPT_AsnDecodeRdn(ptr,
2434 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
2435 if (ret)
2437 DWORD nextLen;
2439 cRDN++;
2440 bytesNeeded += size;
2441 ret = CRYPT_GetLen(ptr,
2442 cbEncoded - (ptr - pbEncoded), &nextLen);
2443 if (ret)
2444 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
2448 if (ret)
2450 if (!pvStructInfo)
2451 *pcbStructInfo = bytesNeeded;
2452 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
2453 pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
2455 CERT_NAME_INFO *info;
2457 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2458 pvStructInfo = *(BYTE **)pvStructInfo;
2459 info = (CERT_NAME_INFO *)pvStructInfo;
2460 info->cRDN = cRDN;
2461 if (info->cRDN == 0)
2462 info->rgRDN = NULL;
2463 else
2465 DWORD size, i;
2466 BYTE *nextData;
2467 const BYTE *ptr;
2469 info->rgRDN = (CERT_RDN *)((BYTE *)pvStructInfo +
2470 sizeof(CERT_NAME_INFO));
2471 nextData = (BYTE *)info->rgRDN +
2472 info->cRDN * sizeof(CERT_RDN);
2473 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
2474 i < cRDN && ptr - pbEncoded - 1 - lenBytes <
2475 dataLen; i++)
2477 info->rgRDN[i].rgRDNAttr =
2478 (CERT_RDN_ATTR *)nextData;
2479 size = bytesNeeded;
2480 ret = CRYPT_AsnDecodeRdn(ptr,
2481 cbEncoded - (ptr - pbEncoded), dwFlags,
2482 &info->rgRDN[i], &size);
2483 if (ret)
2485 DWORD nextLen;
2487 nextData += size;
2488 bytesNeeded -= size;
2489 ret = CRYPT_GetLen(ptr,
2490 cbEncoded - (ptr - pbEncoded), &nextLen);
2491 if (ret)
2492 ptr += nextLen + 1 +
2493 GET_LEN_BYTES(ptr[1]);
2499 else
2501 SetLastError(CRYPT_E_ASN1_BADTAG);
2502 ret = FALSE;
2507 __EXCEPT(page_fault)
2509 SetLastError(STATUS_ACCESS_VIOLATION);
2510 ret = FALSE;
2512 __ENDTRY
2513 return ret;
2516 static BOOL WINAPI CRYPT_DecodeBool(const BYTE *pbEncoded, DWORD cbEncoded,
2517 BOOL *val)
2519 if (cbEncoded < 3)
2521 SetLastError(CRYPT_E_ASN1_CORRUPT);
2522 return FALSE;
2524 if (pbEncoded[0] != ASN_BOOL)
2526 SetLastError(CRYPT_E_ASN1_BADTAG);
2527 return FALSE;
2529 if (GET_LEN_BYTES(pbEncoded[1]) > 1)
2531 SetLastError(CRYPT_E_ASN1_CORRUPT);
2532 return FALSE;
2534 if (pbEncoded[1] > 1)
2536 SetLastError(CRYPT_E_ASN1_CORRUPT);
2537 return FALSE;
2539 *val = pbEncoded[2] ? TRUE : FALSE;
2540 return TRUE;
2543 static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints2(DWORD dwCertEncodingType,
2544 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2545 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2547 BOOL ret;
2549 __TRY
2551 if (pbEncoded[0] == ASN_SEQUENCE)
2553 DWORD dataLen;
2555 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2557 /* sanity-check length, space enough for 7 bytes of integer and
2558 * 3 bytes of bool
2560 if (dataLen > 10)
2562 SetLastError(CRYPT_E_ASN1_CORRUPT);
2563 ret = FALSE;
2565 else
2567 DWORD bytesNeeded = sizeof(CERT_BASIC_CONSTRAINTS2_INFO);
2569 if (!pvStructInfo)
2570 *pcbStructInfo = bytesNeeded;
2571 else
2573 BYTE lenBytes;
2574 CERT_BASIC_CONSTRAINTS2_INFO info = { 0 };
2576 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2577 pbEncoded += 1 + lenBytes;
2578 cbEncoded -= 1 + lenBytes;
2579 if (cbEncoded)
2581 DWORD size;
2583 if (pbEncoded[0] == ASN_BOOL)
2585 ret = CRYPT_DecodeBool(pbEncoded, cbEncoded,
2586 &info.fCA);
2587 if (ret)
2589 cbEncoded -= 2 + pbEncoded[1];
2590 pbEncoded += 2 + pbEncoded[1];
2593 if (ret && cbEncoded && pbEncoded[0] == ASN_INTEGER)
2595 size = sizeof(info.dwPathLenConstraint);
2596 ret = CRYPT_AsnDecodeInt(dwCertEncodingType,
2597 X509_INTEGER, pbEncoded, cbEncoded, 0, NULL,
2598 &info.dwPathLenConstraint, &size);
2599 if (ret)
2601 cbEncoded -= 2 + pbEncoded[1];
2602 pbEncoded += 2 + pbEncoded[1];
2603 if (cbEncoded)
2605 SetLastError(CRYPT_E_ASN1_CORRUPT);
2606 ret = FALSE;
2608 else
2609 info.fPathLenConstraint = TRUE;
2613 if (ret)
2615 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
2616 pDecodePara, pvStructInfo, pcbStructInfo,
2617 bytesNeeded)))
2619 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2620 pvStructInfo = *(BYTE **)pvStructInfo;
2621 memcpy(pvStructInfo, &info,
2622 sizeof(CERT_BASIC_CONSTRAINTS2_INFO));
2629 else
2631 SetLastError(CRYPT_E_ASN1_BADTAG);
2632 ret = FALSE;
2635 __EXCEPT(page_fault)
2637 SetLastError(STATUS_ACCESS_VIOLATION);
2638 ret = FALSE;
2640 __ENDTRY
2641 return ret;
2644 static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
2645 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2646 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2648 BOOL ret;
2650 __TRY
2652 if (pbEncoded[0] == ASN_OCTETSTRING)
2654 DWORD bytesNeeded, dataLen;
2656 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2658 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
2659 bytesNeeded = sizeof(CRYPT_DATA_BLOB);
2660 else
2661 bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB);
2662 if (!pvStructInfo)
2663 *pcbStructInfo = bytesNeeded;
2664 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
2665 pvStructInfo, pcbStructInfo, bytesNeeded)))
2667 CRYPT_DATA_BLOB *blob;
2668 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2670 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2671 pvStructInfo = *(BYTE **)pvStructInfo;
2672 blob = (CRYPT_DATA_BLOB *)pvStructInfo;
2673 blob->cbData = dataLen;
2674 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
2675 blob->pbData = (BYTE *)pbEncoded + 1 + lenBytes;
2676 else
2678 blob->pbData = (BYTE *)pvStructInfo +
2679 sizeof(CRYPT_DATA_BLOB);
2680 if (blob->cbData)
2681 memcpy(blob->pbData, pbEncoded + 1 + lenBytes,
2682 blob->cbData);
2687 else
2689 SetLastError(CRYPT_E_ASN1_BADTAG);
2690 ret = FALSE;
2693 __EXCEPT(page_fault)
2695 SetLastError(STATUS_ACCESS_VIOLATION);
2696 ret = FALSE;
2698 __ENDTRY
2699 return ret;
2702 static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType,
2703 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2704 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2706 BOOL ret;
2708 __TRY
2710 if (pbEncoded[0] == ASN_BITSTRING)
2712 DWORD bytesNeeded, dataLen;
2714 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2716 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
2717 bytesNeeded = sizeof(CRYPT_BIT_BLOB);
2718 else
2719 bytesNeeded = dataLen - 1 + sizeof(CRYPT_BIT_BLOB);
2720 if (!pvStructInfo)
2721 *pcbStructInfo = bytesNeeded;
2722 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
2723 pvStructInfo, pcbStructInfo, bytesNeeded)))
2725 CRYPT_BIT_BLOB *blob;
2727 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2728 pvStructInfo = *(BYTE **)pvStructInfo;
2729 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
2730 blob->cbData = dataLen - 1;
2731 blob->cUnusedBits = *(pbEncoded + 1 +
2732 GET_LEN_BYTES(pbEncoded[1]));
2733 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
2734 blob->pbData = (BYTE *)pbEncoded + 2 +
2735 GET_LEN_BYTES(pbEncoded[1]);
2736 else
2738 blob->pbData = (BYTE *)pvStructInfo +
2739 sizeof(CRYPT_BIT_BLOB);
2740 if (blob->cbData)
2742 BYTE mask = 0xff << blob->cUnusedBits;
2744 memcpy(blob->pbData, pbEncoded + 2 +
2745 GET_LEN_BYTES(pbEncoded[1]), blob->cbData);
2746 blob->pbData[blob->cbData - 1] &= mask;
2752 else
2754 SetLastError(CRYPT_E_ASN1_BADTAG);
2755 ret = FALSE;
2758 __EXCEPT(page_fault)
2760 SetLastError(STATUS_ACCESS_VIOLATION);
2761 ret = FALSE;
2763 __ENDTRY
2764 return ret;
2767 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
2768 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2769 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2771 BOOL ret;
2773 if (!pvStructInfo)
2775 *pcbStructInfo = sizeof(int);
2776 return TRUE;
2778 __TRY
2780 BYTE buf[sizeof(CRYPT_INTEGER_BLOB) + sizeof(int)];
2781 DWORD size = sizeof(buf);
2783 ret = CRYPT_AsnDecodeInteger(dwCertEncodingType,
2784 X509_MULTI_BYTE_INTEGER, pbEncoded, cbEncoded, 0, NULL, &buf, &size);
2785 if (ret)
2787 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
2789 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
2790 pvStructInfo, pcbStructInfo, sizeof(int))))
2792 int val, i;
2794 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2795 pvStructInfo = *(BYTE **)pvStructInfo;
2796 if (blob->pbData[blob->cbData - 1] & 0x80)
2798 /* initialize to a negative value to sign-extend */
2799 val = -1;
2801 else
2802 val = 0;
2803 for (i = 0; i < blob->cbData; i++)
2805 val <<= 8;
2806 val |= blob->pbData[blob->cbData - i - 1];
2808 memcpy(pvStructInfo, &val, sizeof(int));
2811 else if (GetLastError() == ERROR_MORE_DATA)
2812 SetLastError(CRYPT_E_ASN1_LARGE);
2814 __EXCEPT(page_fault)
2816 SetLastError(STATUS_ACCESS_VIOLATION);
2817 ret = FALSE;
2819 __ENDTRY
2820 return ret;
2823 static BOOL WINAPI CRYPT_AsnDecodeInteger(DWORD dwCertEncodingType,
2824 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2825 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2827 BOOL ret;
2829 __TRY
2831 if (pbEncoded[0] == ASN_INTEGER)
2833 DWORD bytesNeeded, dataLen;
2835 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2837 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2839 bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
2840 if (!pvStructInfo)
2841 *pcbStructInfo = bytesNeeded;
2842 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
2843 pvStructInfo, pcbStructInfo, bytesNeeded)))
2845 CRYPT_INTEGER_BLOB *blob;
2847 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2848 pvStructInfo = *(BYTE **)pvStructInfo;
2849 blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
2850 blob->cbData = dataLen;
2851 blob->pbData = (BYTE *)pvStructInfo +
2852 sizeof(CRYPT_INTEGER_BLOB);
2853 if (blob->cbData)
2855 DWORD i;
2857 for (i = 0; i < blob->cbData; i++)
2858 blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
2859 dataLen - i - 1);
2864 else
2866 SetLastError(CRYPT_E_ASN1_BADTAG);
2867 ret = FALSE;
2870 __EXCEPT(page_fault)
2872 SetLastError(STATUS_ACCESS_VIOLATION);
2873 ret = FALSE;
2875 __ENDTRY
2876 return ret;
2879 static BOOL WINAPI CRYPT_AsnDecodeUnsignedInteger(DWORD dwCertEncodingType,
2880 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2881 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2883 BOOL ret;
2885 __TRY
2887 if (pbEncoded[0] == ASN_INTEGER)
2889 DWORD bytesNeeded, dataLen;
2890 CRYPT_INTEGER_BLOB *blob;
2892 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2894 bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
2895 if (!pvStructInfo)
2896 *pcbStructInfo = bytesNeeded;
2897 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
2898 pvStructInfo, pcbStructInfo, bytesNeeded)))
2900 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2902 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2903 pvStructInfo = *(BYTE **)pvStructInfo;
2904 blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
2905 blob->cbData = dataLen;
2906 blob->pbData = (BYTE *)pvStructInfo +
2907 sizeof(CRYPT_INTEGER_BLOB);
2908 /* remove leading zero byte if it exists */
2909 if (blob->cbData && *(pbEncoded + 1 + lenBytes) == 0)
2911 blob->cbData--;
2912 blob->pbData++;
2914 if (blob->cbData)
2916 DWORD i;
2918 for (i = 0; i < blob->cbData; i++)
2919 blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
2920 pbEncoded[1] - i - 1);
2925 else
2927 SetLastError(CRYPT_E_ASN1_BADTAG);
2928 ret = FALSE;
2931 __EXCEPT(page_fault)
2933 SetLastError(STATUS_ACCESS_VIOLATION);
2934 ret = FALSE;
2936 __ENDTRY
2937 return ret;
2940 static BOOL WINAPI CRYPT_AsnDecodeEnumerated(DWORD dwCertEncodingType,
2941 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2942 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2944 BOOL ret;
2946 if (!pvStructInfo)
2948 *pcbStructInfo = sizeof(int);
2949 return TRUE;
2951 __TRY
2953 if (pbEncoded[0] == ASN_ENUMERATED)
2955 unsigned int val = 0, i;
2957 if (cbEncoded <= 1)
2959 SetLastError(CRYPT_E_ASN1_EOD);
2960 ret = FALSE;
2962 else if (pbEncoded[1] == 0)
2964 SetLastError(CRYPT_E_ASN1_CORRUPT);
2965 ret = FALSE;
2967 else
2969 /* A little strange looking, but we have to accept a sign byte:
2970 * 0xffffffff gets encoded as 0a 05 00 ff ff ff ff. Also,
2971 * assuming a small length is okay here, it has to be in short
2972 * form.
2974 if (pbEncoded[1] > sizeof(unsigned int) + 1)
2976 SetLastError(CRYPT_E_ASN1_LARGE);
2977 return FALSE;
2979 for (i = 0; i < pbEncoded[1]; i++)
2981 val <<= 8;
2982 val |= pbEncoded[2 + i];
2984 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
2985 pvStructInfo, pcbStructInfo, sizeof(unsigned int))))
2987 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2988 pvStructInfo = *(BYTE **)pvStructInfo;
2989 memcpy(pvStructInfo, &val, sizeof(unsigned int));
2993 else
2995 SetLastError(CRYPT_E_ASN1_BADTAG);
2996 ret = FALSE;
2999 __EXCEPT(page_fault)
3001 SetLastError(STATUS_ACCESS_VIOLATION);
3002 ret = FALSE;
3004 __ENDTRY
3005 return ret;
3008 /* Modifies word, pbEncoded, and len, and magically sets a value ret to FALSE
3009 * if it fails.
3011 #define CRYPT_TIME_GET_DIGITS(pbEncoded, len, numDigits, word) \
3012 do { \
3013 BYTE i; \
3015 (word) = 0; \
3016 for (i = 0; (len) > 0 && i < (numDigits); i++, (len)--) \
3018 if (!isdigit(*(pbEncoded))) \
3020 SetLastError(CRYPT_E_ASN1_CORRUPT); \
3021 ret = FALSE; \
3023 else \
3025 (word) *= 10; \
3026 (word) += *(pbEncoded)++ - '0'; \
3029 } while (0)
3031 static BOOL CRYPT_AsnDecodeTimeZone(const BYTE *pbEncoded, DWORD len,
3032 SYSTEMTIME *sysTime)
3034 BOOL ret = TRUE;
3036 __TRY
3038 if (len >= 3 && (*pbEncoded == '+' || *pbEncoded == '-'))
3040 WORD hours, minutes = 0;
3041 BYTE sign = *pbEncoded++;
3043 len--;
3044 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, hours);
3045 if (ret && hours >= 24)
3047 SetLastError(CRYPT_E_ASN1_CORRUPT);
3048 ret = FALSE;
3050 else if (len >= 2)
3052 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, minutes);
3053 if (ret && minutes >= 60)
3055 SetLastError(CRYPT_E_ASN1_CORRUPT);
3056 ret = FALSE;
3059 if (ret)
3061 if (sign == '+')
3063 sysTime->wHour += hours;
3064 sysTime->wMinute += minutes;
3066 else
3068 if (hours > sysTime->wHour)
3070 sysTime->wDay--;
3071 sysTime->wHour = 24 - (hours - sysTime->wHour);
3073 else
3074 sysTime->wHour -= hours;
3075 if (minutes > sysTime->wMinute)
3077 sysTime->wHour--;
3078 sysTime->wMinute = 60 - (minutes - sysTime->wMinute);
3080 else
3081 sysTime->wMinute -= minutes;
3086 __EXCEPT(page_fault)
3088 SetLastError(STATUS_ACCESS_VIOLATION);
3089 ret = FALSE;
3091 __ENDTRY
3092 return ret;
3095 #define MIN_ENCODED_TIME_LENGTH 10
3097 static BOOL WINAPI CRYPT_AsnDecodeUtcTime(DWORD dwCertEncodingType,
3098 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3099 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3101 BOOL ret = TRUE;
3103 if (!pvStructInfo)
3105 *pcbStructInfo = sizeof(FILETIME);
3106 return TRUE;
3108 __TRY
3110 if (pbEncoded[0] == ASN_UTCTIME)
3112 if (cbEncoded <= 1)
3114 SetLastError(CRYPT_E_ASN1_EOD);
3115 ret = FALSE;
3117 else if (pbEncoded[1] > 0x7f)
3119 /* long-form date strings really can't be valid */
3120 SetLastError(CRYPT_E_ASN1_CORRUPT);
3121 ret = FALSE;
3123 else
3125 SYSTEMTIME sysTime = { 0 };
3126 BYTE len = pbEncoded[1];
3128 if (len < MIN_ENCODED_TIME_LENGTH)
3130 SetLastError(CRYPT_E_ASN1_CORRUPT);
3131 ret = FALSE;
3133 else
3135 pbEncoded += 2;
3136 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wYear);
3137 if (sysTime.wYear >= 50)
3138 sysTime.wYear += 1900;
3139 else
3140 sysTime.wYear += 2000;
3141 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
3142 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
3143 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
3144 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
3145 if (ret && len > 0)
3147 if (len >= 2 && isdigit(*pbEncoded) &&
3148 isdigit(*(pbEncoded + 1)))
3149 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
3150 sysTime.wSecond);
3151 else if (isdigit(*pbEncoded))
3152 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 1,
3153 sysTime.wSecond);
3154 if (ret)
3155 ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len,
3156 &sysTime);
3158 if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags,
3159 pDecodePara, pvStructInfo, pcbStructInfo,
3160 sizeof(FILETIME))))
3162 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3163 pvStructInfo = *(BYTE **)pvStructInfo;
3164 ret = SystemTimeToFileTime(&sysTime,
3165 (FILETIME *)pvStructInfo);
3170 else
3172 SetLastError(CRYPT_E_ASN1_BADTAG);
3173 ret = FALSE;
3176 __EXCEPT(page_fault)
3178 SetLastError(STATUS_ACCESS_VIOLATION);
3179 ret = FALSE;
3181 __ENDTRY
3182 return ret;
3185 static BOOL WINAPI CRYPT_AsnDecodeGeneralizedTime(DWORD dwCertEncodingType,
3186 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3187 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3189 BOOL ret = TRUE;
3191 if (!pvStructInfo)
3193 *pcbStructInfo = sizeof(FILETIME);
3194 return TRUE;
3196 __TRY
3198 if (pbEncoded[0] == ASN_GENERALTIME)
3200 if (cbEncoded <= 1)
3202 SetLastError(CRYPT_E_ASN1_EOD);
3203 ret = FALSE;
3205 else if (pbEncoded[1] > 0x7f)
3207 /* long-form date strings really can't be valid */
3208 SetLastError(CRYPT_E_ASN1_CORRUPT);
3209 ret = FALSE;
3211 else
3213 BYTE len = pbEncoded[1];
3215 if (len < MIN_ENCODED_TIME_LENGTH)
3217 SetLastError(CRYPT_E_ASN1_CORRUPT);
3218 ret = FALSE;
3220 else
3222 SYSTEMTIME sysTime = { 0 };
3224 pbEncoded += 2;
3225 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 4, sysTime.wYear);
3226 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
3227 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
3228 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
3229 if (ret && len > 0)
3231 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
3232 sysTime.wMinute);
3233 if (ret && len > 0)
3234 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
3235 sysTime.wSecond);
3236 if (ret && len > 0 && (*pbEncoded == '.' ||
3237 *pbEncoded == ','))
3239 BYTE digits;
3241 pbEncoded++;
3242 len--;
3243 /* workaround macro weirdness */
3244 digits = min(len, 3);
3245 CRYPT_TIME_GET_DIGITS(pbEncoded, len, digits,
3246 sysTime.wMilliseconds);
3248 if (ret)
3249 ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len,
3250 &sysTime);
3252 if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags,
3253 pDecodePara, pvStructInfo, pcbStructInfo,
3254 sizeof(FILETIME))))
3256 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3257 pvStructInfo = *(BYTE **)pvStructInfo;
3258 ret = SystemTimeToFileTime(&sysTime,
3259 (FILETIME *)pvStructInfo);
3264 else
3266 SetLastError(CRYPT_E_ASN1_BADTAG);
3267 ret = FALSE;
3270 __EXCEPT(page_fault)
3272 SetLastError(STATUS_ACCESS_VIOLATION);
3273 ret = FALSE;
3275 __ENDTRY
3276 return ret;
3279 static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
3280 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3281 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3283 BOOL ret;
3285 if (!pvStructInfo)
3287 *pcbStructInfo = sizeof(FILETIME);
3288 return TRUE;
3291 __TRY
3293 if (pbEncoded[0] == ASN_UTCTIME)
3294 ret = CRYPT_AsnDecodeUtcTime(dwCertEncodingType, lpszStructType,
3295 pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
3296 pcbStructInfo);
3297 else if (pbEncoded[0] == ASN_GENERALTIME)
3298 ret = CRYPT_AsnDecodeGeneralizedTime(dwCertEncodingType,
3299 lpszStructType, pbEncoded, cbEncoded, dwFlags, pDecodePara,
3300 pvStructInfo, pcbStructInfo);
3301 else
3303 SetLastError(CRYPT_E_ASN1_BADTAG);
3304 ret = FALSE;
3307 __EXCEPT(page_fault)
3309 SetLastError(STATUS_ACCESS_VIOLATION);
3310 ret = FALSE;
3312 __ENDTRY
3313 return ret;
3316 static BOOL WINAPI CRYPT_AsnDecodeSequenceOfAny(DWORD dwCertEncodingType,
3317 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3318 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3320 BOOL ret = TRUE;
3322 __TRY
3324 if (pbEncoded[0] == ASN_SEQUENCEOF)
3326 DWORD bytesNeeded, dataLen, remainingLen, cValue;
3328 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3330 BYTE lenBytes;
3331 const BYTE *ptr;
3333 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3334 bytesNeeded = sizeof(CRYPT_SEQUENCE_OF_ANY);
3335 cValue = 0;
3336 ptr = pbEncoded + 1 + lenBytes;
3337 remainingLen = dataLen;
3338 while (ret && remainingLen)
3340 DWORD nextLen;
3342 ret = CRYPT_GetLen(ptr, remainingLen, &nextLen);
3343 if (ret)
3345 DWORD nextLenBytes = GET_LEN_BYTES(ptr[1]);
3347 remainingLen -= 1 + nextLenBytes + nextLen;
3348 ptr += 1 + nextLenBytes + nextLen;
3349 bytesNeeded += sizeof(CRYPT_DER_BLOB);
3350 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
3351 bytesNeeded += 1 + nextLenBytes + nextLen;
3352 cValue++;
3355 if (ret)
3357 CRYPT_SEQUENCE_OF_ANY *seq;
3358 BYTE *nextPtr;
3359 DWORD i;
3361 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
3362 pvStructInfo, pcbStructInfo, bytesNeeded)))
3364 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3365 pvStructInfo = *(BYTE **)pvStructInfo;
3366 seq = (CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
3367 seq->cValue = cValue;
3368 seq->rgValue = (CRYPT_DER_BLOB *)((BYTE *)seq +
3369 sizeof(*seq));
3370 nextPtr = (BYTE *)seq->rgValue +
3371 cValue * sizeof(CRYPT_DER_BLOB);
3372 ptr = pbEncoded + 1 + lenBytes;
3373 remainingLen = dataLen;
3374 i = 0;
3375 while (ret && remainingLen)
3377 DWORD nextLen;
3379 ret = CRYPT_GetLen(ptr, remainingLen, &nextLen);
3380 if (ret)
3382 DWORD nextLenBytes = GET_LEN_BYTES(ptr[1]);
3384 seq->rgValue[i].cbData = 1 + nextLenBytes +
3385 nextLen;
3386 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
3387 seq->rgValue[i].pbData = (BYTE *)ptr;
3388 else
3390 seq->rgValue[i].pbData = nextPtr;
3391 memcpy(nextPtr, ptr, 1 + nextLenBytes +
3392 nextLen);
3393 nextPtr += 1 + nextLenBytes + nextLen;
3395 remainingLen -= 1 + nextLenBytes + nextLen;
3396 ptr += 1 + nextLenBytes + nextLen;
3397 i++;
3404 else
3406 SetLastError(CRYPT_E_ASN1_BADTAG);
3407 return FALSE;
3410 __EXCEPT(page_fault)
3412 SetLastError(STATUS_ACCESS_VIOLATION);
3413 ret = FALSE;
3415 __ENDTRY
3416 return ret;
3419 typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *,
3420 DWORD, DWORD, PCRYPT_DECODE_PARA, void *, DWORD *);
3422 BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
3423 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3424 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3426 BOOL ret = FALSE;
3427 HMODULE lib = NULL;
3428 CryptDecodeObjectExFunc decodeFunc = NULL;
3430 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p, %p)\n",
3431 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
3432 "(integer value)", pbEncoded, cbEncoded, dwFlags, pDecodePara,
3433 pvStructInfo, pcbStructInfo);
3435 if (!pvStructInfo && !pcbStructInfo)
3437 SetLastError(ERROR_INVALID_PARAMETER);
3438 return FALSE;
3440 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
3441 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
3443 SetLastError(ERROR_FILE_NOT_FOUND);
3444 return FALSE;
3446 if (!pbEncoded || !cbEncoded)
3448 SetLastError(CRYPT_E_ASN1_EOD);
3449 return FALSE;
3451 if (cbEncoded > MAX_ENCODED_LEN)
3453 SetLastError(CRYPT_E_ASN1_LARGE);
3454 return FALSE;
3457 SetLastError(NOERROR);
3458 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG && pvStructInfo)
3459 *(BYTE **)pvStructInfo = NULL;
3460 if (!HIWORD(lpszStructType))
3462 switch (LOWORD(lpszStructType))
3464 case (WORD)X509_EXTENSIONS:
3465 decodeFunc = CRYPT_AsnDecodeExtensions;
3466 break;
3467 case (WORD)X509_NAME:
3468 decodeFunc = CRYPT_AsnDecodeName;
3469 break;
3470 case (WORD)X509_BASIC_CONSTRAINTS2:
3471 decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
3472 break;
3473 case (WORD)X509_OCTET_STRING:
3474 decodeFunc = CRYPT_AsnDecodeOctets;
3475 break;
3476 case (WORD)X509_BITS:
3477 case (WORD)X509_KEY_USAGE:
3478 decodeFunc = CRYPT_AsnDecodeBits;
3479 break;
3480 case (WORD)X509_INTEGER:
3481 decodeFunc = CRYPT_AsnDecodeInt;
3482 break;
3483 case (WORD)X509_MULTI_BYTE_INTEGER:
3484 decodeFunc = CRYPT_AsnDecodeInteger;
3485 break;
3486 case (WORD)X509_MULTI_BYTE_UINT:
3487 decodeFunc = CRYPT_AsnDecodeUnsignedInteger;
3488 break;
3489 case (WORD)X509_ENUMERATED:
3490 decodeFunc = CRYPT_AsnDecodeEnumerated;
3491 break;
3492 case (WORD)X509_CHOICE_OF_TIME:
3493 decodeFunc = CRYPT_AsnDecodeChoiceOfTime;
3494 break;
3495 case (WORD)X509_SEQUENCE_OF_ANY:
3496 decodeFunc = CRYPT_AsnDecodeSequenceOfAny;
3497 break;
3498 case (WORD)PKCS_UTC_TIME:
3499 decodeFunc = CRYPT_AsnDecodeUtcTime;
3500 break;
3501 default:
3502 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
3505 else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
3506 decodeFunc = CRYPT_AsnDecodeExtensions;
3507 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
3508 decodeFunc = CRYPT_AsnDecodeUtcTime;
3509 else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
3510 decodeFunc = CRYPT_AsnDecodeEnumerated;
3511 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
3512 decodeFunc = CRYPT_AsnDecodeBits;
3513 else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
3514 decodeFunc = CRYPT_AsnDecodeOctets;
3515 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
3516 decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
3517 else
3518 TRACE("OID %s not found or unimplemented, looking for DLL\n",
3519 debugstr_a(lpszStructType));
3520 if (!decodeFunc)
3521 decodeFunc = (CryptDecodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
3522 lpszStructType, "CryptDecodeObjectEx", &lib);
3523 if (decodeFunc)
3524 ret = decodeFunc(dwCertEncodingType, lpszStructType, pbEncoded,
3525 cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
3526 else
3527 SetLastError(ERROR_FILE_NOT_FOUND);
3528 if (lib)
3529 FreeLibrary(lib);
3530 return ret;