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.
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
32 * http://msdn.microsoft.com/library/en-us/seccrypto/security/constants_for_cryptencodeobject_and_cryptdecodeobject.asp
42 #include "wine/debug.h"
44 /* a few asn.1 tags we need */
45 #define ASN_BITSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x03)
46 #define ASN_OCTETSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x04)
47 #define ASN_ENUMERATED (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x0a)
48 #define ASN_SETOF (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x11)
49 #define ASN_NUMERICSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x12)
50 #define ASN_PRINTABLESTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x13)
51 #define ASN_IA5STRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x16)
52 #define ASN_UTCTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x17)
53 #define ASN_GENERALTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x18)
55 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
57 static const WCHAR szDllName[] = { 'D','l','l',0 };
59 static char *CRYPT_GetKeyName(DWORD dwEncodingType, LPCSTR pszFuncName,
62 static const char szEncodingTypeFmt[] =
63 "Software\\Microsoft\\Cryptography\\OID\\EncodingType %ld\\%s\\%s";
65 char numericOID[7]; /* enough for "#65535" */
69 /* MSDN says the encoding type is a mask, but it isn't treated that way.
70 * (E.g., if dwEncodingType were 3, the key names "EncodingType 1" and
71 * "EncodingType 2" would be expected if it were a mask. Instead native
72 * stores values in "EncodingType 3".
76 snprintf(numericOID, sizeof(numericOID), "#%d", (int)pszOID);
82 /* This is enough: the lengths of the two string parameters are explicitly
83 * counted, and we need up to five additional characters for the encoding
84 * type. These are covered by the "%d", "%s", and "%s" characters in the
85 * format specifier that are removed by sprintf.
87 len = sizeof(szEncodingTypeFmt) + lstrlenA(pszFuncName) + lstrlenA(oid);
88 szKey = HeapAlloc(GetProcessHeap(), 0, len);
90 sprintf(szKey, szEncodingTypeFmt, dwEncodingType, pszFuncName, oid);
94 BOOL WINAPI CryptRegisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
95 LPCSTR pszOID, LPCWSTR pwszDll, LPCSTR pszOverrideFuncName)
101 TRACE("%lx %s %s %s %s\n", dwEncodingType, pszFuncName, pszOID,
102 debugstr_w(pwszDll), pszOverrideFuncName);
104 /* This only registers functions for encoding certs, not messages */
105 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
108 /* Native does nothing pwszDll is NULL */
112 /* I'm not matching MS bug for bug here, because I doubt any app depends on
114 * - native "succeeds" if pszFuncName is NULL, but the nonsensical entry
115 * it creates would never be used
116 * - native returns an HRESULT rather than a Win32 error if pszOID is NULL.
117 * Instead I disallow both of these with ERROR_INVALID_PARAMETER.
119 if (!pszFuncName || !pszOID)
121 SetLastError(ERROR_INVALID_PARAMETER);
125 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
126 TRACE("Key name is %s\n", debugstr_a(szKey));
131 r = RegCreateKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
132 HeapFree(GetProcessHeap(), 0, szKey);
133 if(r != ERROR_SUCCESS)
136 /* write the values */
137 if (pszOverrideFuncName)
138 RegSetValueExA(hKey, "FuncName", 0, REG_SZ, pszOverrideFuncName,
139 lstrlenA(pszOverrideFuncName) + 1);
140 RegSetValueExW(hKey, szDllName, 0, REG_SZ, (const BYTE*) pwszDll,
141 (lstrlenW(pwszDll) + 1) * sizeof (WCHAR));
147 BOOL WINAPI CryptUnregisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
153 TRACE("%lx %s %s\n", dwEncodingType, pszFuncName, pszOID);
155 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
158 if (!pszFuncName || !pszOID)
160 SetLastError(ERROR_INVALID_PARAMETER);
164 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
165 rc = RegDeleteKeyA(HKEY_LOCAL_MACHINE, szKey);
166 HeapFree(GetProcessHeap(), 0, szKey);
169 return rc ? FALSE : TRUE;
172 BOOL WINAPI CryptGetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
173 LPCSTR pszOID, LPCWSTR pwszValueName, DWORD *pdwValueType, BYTE *pbValueData,
180 TRACE("%lx %s %s %s %p %p %p\n", dwEncodingType, debugstr_a(pszFuncName),
181 debugstr_a(pszOID), debugstr_w(pwszValueName), pdwValueType, pbValueData,
184 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
187 if (!pszFuncName || !pszOID || !pwszValueName)
189 SetLastError(ERROR_INVALID_PARAMETER);
193 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
194 rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
195 HeapFree(GetProcessHeap(), 0, szKey);
200 rc = RegQueryValueExW(hKey, pwszValueName, NULL, pdwValueType,
201 pbValueData, pcbValueData);
206 return rc ? FALSE : TRUE;
209 BOOL WINAPI CryptSetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
210 LPCSTR pszOID, LPCWSTR pwszValueName, DWORD dwValueType,
211 const BYTE *pbValueData, DWORD cbValueData)
217 TRACE("%lx %s %s %s %ld %p %ld\n", dwEncodingType, debugstr_a(pszFuncName),
218 debugstr_a(pszOID), debugstr_w(pwszValueName), dwValueType, pbValueData,
221 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
224 if (!pszFuncName || !pszOID || !pwszValueName)
226 SetLastError(ERROR_INVALID_PARAMETER);
230 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
231 rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
232 HeapFree(GetProcessHeap(), 0, szKey);
237 rc = RegSetValueExW(hKey, pwszValueName, 0, dwValueType, pbValueData,
243 return rc ? FALSE : TRUE;
246 /* Gets the registered function named szFuncName for dwCertEncodingType and
247 * lpszStructType, or NULL if one could not be found. *lib will be set to the
248 * handle of the module it's in, or NULL if no module was loaded. If the
249 * return value is NULL, *lib will also be NULL, to simplify error handling.
251 static void *CRYPT_GetFunc(DWORD dwCertEncodingType, LPCSTR lpszStructType,
252 LPCSTR szFuncName, HMODULE *lib)
255 char *szKey = CRYPT_GetKeyName(dwCertEncodingType, szFuncName,
257 const char *funcName;
260 DWORD type, size = 0;
262 TRACE("(%08lx %s %s %p)\n", dwCertEncodingType, debugstr_a(lpszStructType),
263 debugstr_a(szFuncName), lib);
266 r = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
267 HeapFree(GetProcessHeap(), 0, szKey);
268 if(r != ERROR_SUCCESS)
271 RegQueryValueExA(hKey, "FuncName", NULL, &type, NULL, &size);
272 if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
274 funcName = HeapAlloc(GetProcessHeap(), 0, size);
275 RegQueryValueExA(hKey, "FuncName", NULL, &type, (LPBYTE)funcName,
279 funcName = szFuncName;
280 RegQueryValueExW(hKey, szDllName, NULL, &type, NULL, &size);
281 if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
283 LPWSTR dllName = HeapAlloc(GetProcessHeap(), 0, size);
285 RegQueryValueExW(hKey, szDllName, NULL, &type, (LPBYTE)dllName,
287 *lib = LoadLibraryW(dllName);
290 ret = GetProcAddress(*lib, funcName);
293 /* Unload the library, the caller doesn't want to unload it
294 * when the return value is NULL.
300 HeapFree(GetProcessHeap(), 0, dllName);
302 if (funcName != szFuncName)
303 HeapFree(GetProcessHeap(), 0, (char *)funcName);
304 TRACE("returning %p\n", ret);
308 typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
311 BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
312 const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
316 CryptEncodeObjectFunc pCryptEncodeObject;
318 TRACE("(0x%08lx, %s, %p, %p, %p)\n",
319 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
320 "(integer value)", pvStructInfo, pbEncoded, pcbEncoded);
322 if (!pbEncoded && !pcbEncoded)
324 SetLastError(ERROR_INVALID_PARAMETER);
328 /* Try registered DLL first.. */
330 (CryptEncodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
331 lpszStructType, "CryptEncodeObject", &lib);
332 if (pCryptEncodeObject)
334 ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
335 pvStructInfo, pbEncoded, pcbEncoded);
340 /* If not, use CryptEncodeObjectEx */
341 ret = CryptEncodeObjectEx(dwCertEncodingType, lpszStructType,
342 pvStructInfo, 0, NULL, pbEncoded, pcbEncoded);
347 /* Helper function to check *pcbEncoded, set it to the required size, and
348 * optionally to allocate memory. Assumes pbEncoded is not NULL.
349 * If CRYPT_ENCODE_ALLOC_FLAG is set in dwFlags, *pbEncoded will be set to a
350 * pointer to the newly allocated memory.
352 static BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags,
353 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded,
358 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
360 if (pEncodePara && pEncodePara->pfnAlloc)
361 *(BYTE **)pbEncoded = pEncodePara->pfnAlloc(bytesNeeded);
363 *(BYTE **)pbEncoded = LocalAlloc(0, bytesNeeded);
364 if (!*(BYTE **)pbEncoded)
367 *pcbEncoded = bytesNeeded;
369 else if (bytesNeeded > *pcbEncoded)
371 *pcbEncoded = bytesNeeded;
372 SetLastError(ERROR_MORE_DATA);
378 static BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded)
380 DWORD bytesNeeded, significantBytes = 0;
388 for (temp = len, significantBytes = sizeof(temp); !(temp & 0xff000000);
389 temp <<= 8, significantBytes--)
391 bytesNeeded = significantBytes + 1;
395 *pcbEncoded = bytesNeeded;
398 if (*pcbEncoded < bytesNeeded)
400 SetLastError(ERROR_MORE_DATA);
404 *pbEncoded = (BYTE)len;
409 *pbEncoded++ = significantBytes | 0x80;
410 for (i = 0; i < significantBytes; i++)
412 *(pbEncoded + significantBytes - i - 1) = (BYTE)(len & 0xff);
416 *pcbEncoded = bytesNeeded;
420 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
421 LPCSTR pszObjId, BYTE *pbEncoded, DWORD *pcbEncoded)
423 DWORD bytesNeeded = 0, lenBytes;
433 if (sscanf(pszObjId, "%d.%d.%n", &val1, &val2, &firstPos) != 2)
435 SetLastError(CRYPT_E_ASN1_ERROR);
439 firstByte = val1 * 40 + val2;
440 ptr = pszObjId + firstPos;
445 /* note I assume each component is at most 32-bits long in base 2 */
446 if (sscanf(ptr, "%d%n", &val1, &pos) == 1)
448 if (val1 >= 0x10000000)
450 else if (val1 >= 0x200000)
452 else if (val1 >= 0x4000)
454 else if (val1 >= 0x80)
464 SetLastError(CRYPT_E_ASN1_ERROR);
468 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
472 bytesNeeded += 1 + lenBytes;
475 if (*pbEncoded < bytesNeeded)
477 SetLastError(ERROR_MORE_DATA);
482 *pbEncoded++ = ASN_OBJECTIDENTIFIER;
483 CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded, &lenBytes);
484 pbEncoded += lenBytes;
490 *pbEncoded++ = firstByte;
491 ptr = pszObjId + firstPos;
494 sscanf(ptr, "%d%n", &val, &pos);
496 unsigned char outBytes[5];
499 if (val >= 0x10000000)
501 else if (val >= 0x200000)
503 else if (val >= 0x4000)
505 else if (val >= 0x80)
509 for (i = numBytes; i > 0; i--)
511 outBytes[i - 1] = val & 0x7f;
514 for (i = 0; i < numBytes - 1; i++)
515 *pbEncoded++ = outBytes[i] | 0x80;
516 *pbEncoded++ = outBytes[i];
525 *pcbEncoded = bytesNeeded;
529 static BOOL WINAPI CRYPT_AsnEncodeNameValue(DWORD dwCertEncodingType,
530 CERT_NAME_VALUE *value, BYTE *pbEncoded, DWORD *pcbEncoded)
533 DWORD bytesNeeded, lenBytes, encodedLen;
536 switch (value->dwValueType)
538 case CERT_RDN_NUMERIC_STRING:
539 tag = ASN_NUMERICSTRING;
540 encodedLen = value->Value.cbData;
542 case CERT_RDN_PRINTABLE_STRING:
543 tag = ASN_PRINTABLESTRING;
544 encodedLen = value->Value.cbData;
546 case CERT_RDN_IA5_STRING:
548 encodedLen = value->Value.cbData;
550 case CERT_RDN_ANY_TYPE:
551 /* explicitly disallowed */
552 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
555 FIXME("String type %ld unimplemented\n", value->dwValueType);
558 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
559 bytesNeeded = 1 + lenBytes + encodedLen;
562 if (*pcbEncoded < bytesNeeded)
564 SetLastError(ERROR_MORE_DATA);
570 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
571 pbEncoded += lenBytes;
572 switch (value->dwValueType)
574 case CERT_RDN_NUMERIC_STRING:
575 case CERT_RDN_PRINTABLE_STRING:
576 case CERT_RDN_IA5_STRING:
577 memcpy(pbEncoded, value->Value.pbData, value->Value.cbData);
581 *pcbEncoded = bytesNeeded;
585 static BOOL WINAPI CRYPT_AsnEncodeRdnAttr(DWORD dwCertEncodingType,
586 CERT_RDN_ATTR *attr, BYTE *pbEncoded, DWORD *pcbEncoded)
588 DWORD bytesNeeded = 0, lenBytes, size;
591 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, attr->pszObjId, NULL, &size);
595 /* hack: a CERT_RDN_ATTR is identical to a CERT_NAME_VALUE beginning
596 * with dwValueType, so "cast" it to get its encoded size
598 ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
599 (CERT_NAME_VALUE *)&attr->dwValueType, NULL, &size);
603 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
604 bytesNeeded += 1 + lenBytes;
607 if (*pcbEncoded < bytesNeeded)
609 SetLastError(ERROR_MORE_DATA);
614 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SEQUENCE;
615 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
617 pbEncoded += lenBytes;
618 size = bytesNeeded - 1 - lenBytes;
619 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, attr->pszObjId,
624 size = bytesNeeded - 1 - lenBytes - size;
625 ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
626 (CERT_NAME_VALUE *)&attr->dwValueType, pbEncoded,
631 *pcbEncoded = bytesNeeded;
637 static int BLOBComp(const void *l, const void *r)
639 CRYPT_DER_BLOB *a = (CRYPT_DER_BLOB *)l, *b = (CRYPT_DER_BLOB *)r;
642 if (!(ret = memcmp(a->pbData, b->pbData, min(a->cbData, b->cbData))))
643 ret = a->cbData - b->cbData;
647 /* This encodes as a SET OF, which in DER must be lexicographically sorted.
649 static BOOL WINAPI CRYPT_AsnEncodeRdn(DWORD dwCertEncodingType, CERT_RDN *rdn,
650 BYTE *pbEncoded, DWORD *pcbEncoded)
652 DWORD bytesNeeded = 0, lenBytes, i;
654 CRYPT_DER_BLOB *blobs = NULL;
661 SetLastError(STATUS_ACCESS_VIOLATION);
666 blobs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
667 rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
672 for (i = 0; ret && i < rdn->cRDNAttr; i++)
674 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType, &rdn->rgRDNAttr[i],
675 NULL, &blobs[i].cbData);
677 bytesNeeded += blobs[i].cbData;
679 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
680 bytesNeeded += 1 + lenBytes;
685 if (*pcbEncoded < bytesNeeded)
687 SetLastError(ERROR_MORE_DATA);
692 for (i = 0; ret && i < rdn->cRDNAttr; i++)
694 blobs[i].pbData = HeapAlloc(GetProcessHeap(), 0,
696 if (!blobs[i].pbData)
699 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType,
700 &rdn->rgRDNAttr[i], blobs[i].pbData, &blobs[i].cbData);
704 qsort(blobs, rdn->cRDNAttr, sizeof(CRYPT_DER_BLOB),
706 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF;
707 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
709 pbEncoded += lenBytes;
710 for (i = 0; ret && i < rdn->cRDNAttr; i++)
712 memcpy(pbEncoded, blobs[i].pbData, blobs[i].cbData);
713 pbEncoded += blobs[i].cbData;
718 *pcbEncoded = bytesNeeded;
722 for (i = 0; i < rdn->cRDNAttr; i++)
723 HeapFree(GetProcessHeap(), 0, blobs[i].pbData);
724 HeapFree(GetProcessHeap(), 0, blobs);
729 static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
730 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
731 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
733 CERT_NAME_INFO *info = (CERT_NAME_INFO *)pvStructInfo;
734 DWORD bytesNeeded = 0, lenBytes, size, i;
739 SetLastError(STATUS_ACCESS_VIOLATION);
742 if (info->cRDN && !info->rgRDN)
744 SetLastError(STATUS_ACCESS_VIOLATION);
747 TRACE("encoding name with %ld RDNs\n", info->cRDN);
749 for (i = 0; ret && i < info->cRDN; i++)
751 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i], NULL,
756 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
757 bytesNeeded += 1 + lenBytes;
762 *pcbEncoded = bytesNeeded;
765 if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
766 pcbEncoded, bytesNeeded))
768 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
769 pbEncoded = *(BYTE **)pbEncoded;
770 /* FIXME: could this be encoded using X509_SEQUENCE_OF_ANY? */
771 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SEQUENCEOF;
772 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded, &size);
774 for (i = 0; ret && i < info->cRDN; i++)
777 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i],
789 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
790 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
791 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
793 CRYPT_DATA_BLOB *blob = (CRYPT_DATA_BLOB *)pvStructInfo;
794 DWORD bytesNeeded, lenBytes;
798 SetLastError(STATUS_ACCESS_VIOLATION);
801 /* FIXME: use exception handling to catch bogus pointers */
802 CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
803 bytesNeeded = 1 + lenBytes + blob->cbData;
806 *pcbEncoded = bytesNeeded;
809 if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
812 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
813 pbEncoded = *(BYTE **)pbEncoded;
814 *pbEncoded++ = ASN_OCTETSTRING;
815 CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
816 pbEncoded += lenBytes;
818 memcpy(pbEncoded, blob->pbData, blob->cbData);
822 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
823 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
824 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
826 CRYPT_BIT_BLOB *blob = (CRYPT_BIT_BLOB *)pvStructInfo;
827 DWORD bytesNeeded, lenBytes, dataBytes;
832 SetLastError(STATUS_ACCESS_VIOLATION);
835 /* FIXME: use exception handling to catch bogus pointers */
836 /* yep, MS allows cUnusedBits to be >= 8 */
837 if (blob->cbData * 8 > blob->cUnusedBits)
839 dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
840 unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
848 CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
849 bytesNeeded = 1 + lenBytes + dataBytes + 1;
852 *pcbEncoded = bytesNeeded;
855 if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
858 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
859 pbEncoded = *(BYTE **)pbEncoded;
860 *pbEncoded++ = ASN_BITSTRING;
861 CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
862 pbEncoded += lenBytes;
863 *pbEncoded++ = unusedBits;
866 BYTE mask = 0xff << unusedBits;
870 memcpy(pbEncoded, blob->pbData, dataBytes - 1);
871 pbEncoded += dataBytes - 1;
873 *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
878 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
879 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
880 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
883 BYTE significantBytes, padByte = 0, bytesNeeded;
884 BOOL neg = FALSE, pad = FALSE;
888 SetLastError(STATUS_ACCESS_VIOLATION);
892 memcpy(&val, pvStructInfo, sizeof(val));
893 /* Count the number of significant bytes. Temporarily swap sign for
894 * negatives so I count the minimum number of bytes.
901 for (significantBytes = sizeof(val); !(val & 0xff000000);
902 val <<= 8, significantBytes--)
907 if ((val & 0xff000000) < 0x80000000)
913 else if ((val & 0xff000000) > 0x7f000000)
918 bytesNeeded = 2 + significantBytes;
923 *pcbEncoded = bytesNeeded;
926 if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
929 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
930 pbEncoded = *(BYTE **)pbEncoded;
931 *pbEncoded++ = ASN_INTEGER;
934 *pbEncoded++ = significantBytes + 1;
935 *pbEncoded++ = padByte;
938 *pbEncoded++ = significantBytes;
939 for (i = 0; i < significantBytes; i++, val <<= 8)
940 *(pbEncoded + i) = (BYTE)((val & 0xff000000) >> 24);
944 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
945 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
946 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
948 DWORD significantBytes, lenBytes;
949 BYTE padByte = 0, bytesNeeded;
951 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
955 SetLastError(STATUS_ACCESS_VIOLATION);
959 /* FIXME: use exception handling to protect against bogus pointers */
960 significantBytes = blob->cbData;
961 if (significantBytes)
963 if (blob->pbData[significantBytes - 1] & 0x80)
965 /* negative, lop off leading (little-endian) 0xffs */
966 for (; significantBytes > 0 &&
967 blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
969 if (blob->pbData[significantBytes - 1] < 0x80)
977 /* positive, lop off leading (little-endian) zeroes */
978 for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
981 if (blob->pbData[significantBytes - 1] > 0x7f)
989 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
991 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
992 bytesNeeded = 1 + lenBytes + significantBytes;
997 *pcbEncoded = bytesNeeded;
1000 if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
1003 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1004 pbEncoded = *(BYTE **)pbEncoded;
1005 *pbEncoded++ = ASN_INTEGER;
1008 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
1009 pbEncoded += lenBytes;
1010 *pbEncoded++ = padByte;
1014 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
1015 pbEncoded += lenBytes;
1017 for (; significantBytes > 0; significantBytes--)
1018 *(pbEncoded++) = blob->pbData[significantBytes - 1];
1022 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
1023 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1024 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1026 DWORD significantBytes, lenBytes;
1029 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
1033 SetLastError(STATUS_ACCESS_VIOLATION);
1037 /* FIXME: use exception handling to protect against bogus pointers */
1038 significantBytes = blob->cbData;
1039 if (significantBytes)
1041 /* positive, lop off leading (little-endian) zeroes */
1042 for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
1045 if (blob->pbData[significantBytes - 1] > 0x7f)
1049 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
1051 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
1052 bytesNeeded = 1 + lenBytes + significantBytes;
1057 *pcbEncoded = bytesNeeded;
1060 if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
1063 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1064 pbEncoded = *(BYTE **)pbEncoded;
1065 *pbEncoded++ = ASN_INTEGER;
1068 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
1069 pbEncoded += lenBytes;
1074 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
1075 pbEncoded += lenBytes;
1077 for (; significantBytes > 0; significantBytes--)
1078 *(pbEncoded++) = blob->pbData[significantBytes - 1];
1082 static BOOL WINAPI CRYPT_AsnEncodeEnumerated(DWORD dwCertEncodingType,
1083 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1084 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1086 CRYPT_INTEGER_BLOB blob;
1089 /* Encode as an unsigned integer, then change the tag to enumerated */
1090 blob.cbData = sizeof(DWORD);
1091 blob.pbData = (BYTE *)pvStructInfo;
1092 ret = CRYPT_AsnEncodeUnsignedInteger(dwCertEncodingType,
1093 X509_MULTI_BYTE_UINT, &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1094 if (ret && pbEncoded)
1096 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1097 pbEncoded = *(BYTE **)pbEncoded;
1098 pbEncoded[0] = ASN_ENUMERATED;
1103 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
1104 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1105 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1108 /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0. I use a
1109 * temporary buffer because the output buffer is not NULL-terminated.
1112 static const DWORD bytesNeeded = sizeof(buf) - 1;
1116 SetLastError(STATUS_ACCESS_VIOLATION);
1119 /* Sanity check the year, this is a two-digit year format */
1120 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
1122 if (sysTime.wYear < 1950 || sysTime.wYear > 2050)
1124 SetLastError(CRYPT_E_BAD_ENCODE);
1129 *pcbEncoded = bytesNeeded;
1132 if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
1135 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1136 pbEncoded = *(BYTE **)pbEncoded;
1137 buf[0] = ASN_UTCTIME;
1138 buf[1] = bytesNeeded - 2;
1139 snprintf(buf + 2, sizeof(buf) - 2, "%02d%02d%02d%02d%02d%02dZ",
1140 sysTime.wYear >= 2000 ? sysTime.wYear - 2000 : sysTime.wYear - 1900,
1141 sysTime.wDay, sysTime.wMonth, sysTime.wHour, sysTime.wMinute,
1143 memcpy(pbEncoded, buf, bytesNeeded);
1147 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
1148 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1149 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1152 /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0. I use a
1153 * temporary buffer because the output buffer is not NULL-terminated.
1156 static const DWORD bytesNeeded = sizeof(buf) - 1;
1160 SetLastError(STATUS_ACCESS_VIOLATION);
1165 *pcbEncoded = bytesNeeded;
1168 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
1170 if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
1173 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1174 pbEncoded = *(BYTE **)pbEncoded;
1175 buf[0] = ASN_GENERALTIME;
1176 buf[1] = bytesNeeded - 2;
1177 snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
1178 sysTime.wYear, sysTime.wDay, sysTime.wMonth, sysTime.wHour,
1179 sysTime.wMinute, sysTime.wSecond);
1180 memcpy(pbEncoded, buf, bytesNeeded);
1184 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
1185 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1186 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1193 SetLastError(STATUS_ACCESS_VIOLATION);
1196 /* Check the year, if it's in the UTCTime range call that encode func */
1197 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
1199 if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
1200 ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
1201 pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1203 ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
1204 lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
1209 typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *,
1210 DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *);
1212 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
1213 const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
1214 void *pvEncoded, DWORD *pcbEncoded)
1218 CryptEncodeObjectExFunc encodeFunc = NULL;
1220 TRACE("(0x%08lx, %s, %p, 0x%08lx, %p, %p, %p)\n",
1221 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
1222 "(integer value)", pvStructInfo, dwFlags, pEncodePara, pvEncoded,
1225 if (!pvEncoded && !pcbEncoded)
1227 SetLastError(ERROR_INVALID_PARAMETER);
1230 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
1231 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
1233 SetLastError(ERROR_FILE_NOT_FOUND);
1237 SetLastError(NOERROR);
1238 if (!HIWORD(lpszStructType))
1240 switch (LOWORD(lpszStructType))
1242 case (WORD)X509_NAME:
1243 encodeFunc = CRYPT_AsnEncodeName;
1245 case (WORD)X509_OCTET_STRING:
1246 encodeFunc = CRYPT_AsnEncodeOctets;
1248 case (WORD)X509_BITS:
1249 case (WORD)X509_KEY_USAGE:
1250 encodeFunc = CRYPT_AsnEncodeBits;
1252 case (WORD)X509_INTEGER:
1253 encodeFunc = CRYPT_AsnEncodeInt;
1255 case (WORD)X509_MULTI_BYTE_INTEGER:
1256 encodeFunc = CRYPT_AsnEncodeInteger;
1258 case (WORD)X509_MULTI_BYTE_UINT:
1259 encodeFunc = CRYPT_AsnEncodeUnsignedInteger;
1261 case (WORD)X509_ENUMERATED:
1262 encodeFunc = CRYPT_AsnEncodeEnumerated;
1264 case (WORD)X509_CHOICE_OF_TIME:
1265 encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
1267 case (WORD)PKCS_UTC_TIME:
1268 encodeFunc = CRYPT_AsnEncodeUtcTime;
1271 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
1274 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
1275 encodeFunc = CRYPT_AsnEncodeUtcTime;
1276 else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
1277 encodeFunc = CRYPT_AsnEncodeEnumerated;
1278 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
1279 encodeFunc = CRYPT_AsnEncodeBits;
1280 else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
1281 encodeFunc = CRYPT_AsnEncodeOctets;
1283 TRACE("OID %s not found or unimplemented, looking for DLL\n",
1284 debugstr_a(lpszStructType));
1286 encodeFunc = (CryptEncodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
1287 lpszStructType, "CryptEncodeObjectEx", &lib);
1289 ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
1290 dwFlags, pEncodePara, pvEncoded, pcbEncoded);
1292 SetLastError(ERROR_FILE_NOT_FOUND);
1298 typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
1299 DWORD, DWORD, void *, DWORD *);
1301 BOOL WINAPI CryptDecodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
1302 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo,
1303 DWORD *pcbStructInfo)
1307 CryptDecodeObjectFunc pCryptDecodeObject;
1309 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p)\n",
1310 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
1311 "(integer value)", pbEncoded, cbEncoded, dwFlags, pvStructInfo,
1314 if (!pvStructInfo && !pcbStructInfo)
1316 SetLastError(ERROR_INVALID_PARAMETER);
1320 /* Try registered DLL first.. */
1321 pCryptDecodeObject =
1322 (CryptDecodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
1323 lpszStructType, "CryptDecodeObject", &lib);
1324 if (pCryptDecodeObject)
1326 ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType,
1327 pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
1332 /* If not, use CryptDecodeObjectEx */
1333 ret = CryptDecodeObjectEx(dwCertEncodingType, lpszStructType, pbEncoded,
1334 cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo);
1339 /* Gets the number of length bytes from the given (leading) length byte */
1340 #define GET_LEN_BYTES(b) ((b) <= 0x7f ? 1 : 1 + ((b) & 0x7f))
1342 /* Helper function to get the encoded length of the data starting at pbEncoded,
1343 * where pbEncoded[0] is the tag. If the data are too short to contain a
1344 * length or if the length is too large for cbEncoded, sets an appropriate
1345 * error code and returns FALSE.
1347 static BOOL WINAPI CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded,
1354 SetLastError(CRYPT_E_ASN1_EOD);
1357 else if (pbEncoded[1] <= 0x7f)
1359 *len = pbEncoded[1];
1364 BYTE lenLen = GET_LEN_BYTES(pbEncoded[1]);
1366 if (lenLen > sizeof(DWORD))
1368 SetLastError(CRYPT_E_ASN1_LARGE);
1371 else if (lenLen + 2 > cbEncoded)
1373 SetLastError(CRYPT_E_ASN1_CORRUPT);
1384 out |= *pbEncoded++;
1386 if (out + lenLen + 1 > cbEncoded)
1388 SetLastError(CRYPT_E_ASN1_EOD);
1401 /* Helper function to check *pcbStructInfo, set it to the required size, and
1402 * optionally to allocate memory. Assumes pvStructInfo is not NULL.
1403 * If CRYPT_DECODE_ALLOC_FLAG is set in dwFlags, *pvStructInfo will be set to a
1404 * pointer to the newly allocated memory.
1406 static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags,
1407 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo,
1412 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1414 if (pDecodePara && pDecodePara->pfnAlloc)
1415 *(BYTE **)pvStructInfo = pDecodePara->pfnAlloc(bytesNeeded);
1417 *(BYTE **)pvStructInfo = LocalAlloc(0, bytesNeeded);
1418 if (!*(BYTE **)pvStructInfo)
1421 *pcbStructInfo = bytesNeeded;
1423 else if (*pcbStructInfo < bytesNeeded)
1425 *pcbStructInfo = bytesNeeded;
1426 SetLastError(ERROR_MORE_DATA);
1432 /* FIXME: honor the CRYPT_DECODE_SHARE_OID_FLAG. */
1433 static BOOL WINAPI CRYPT_AsnDecodeOid(DWORD dwCertEncodingType,
1434 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, LPSTR pszObjId,
1438 DWORD bytesNeeded, dataLen;
1441 if (!CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))
1443 if (pbEncoded[0] != ASN_OBJECTIDENTIFIER)
1445 SetLastError(CRYPT_E_ASN1_BADTAG);
1448 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1451 /* The largest possible string for the first two components is 2.175
1452 * (= 2 * 40 + 175 = 255), so this is big enough.
1457 snprintf(firstTwo, sizeof(firstTwo), "%d.%d",
1458 pbEncoded[1 + lenBytes] / 40,
1459 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40) * 40);
1460 bytesNeeded = strlen(firstTwo) + 1;
1461 for (ptr = pbEncoded + 2 + lenBytes; ret &&
1462 ptr - pbEncoded - 1 - lenBytes < dataLen; )
1464 /* large enough for ".4000000" */
1468 while (ptr - pbEncoded - 1 - lenBytes < dataLen && (*ptr & 0x80))
1474 if (ptr - pbEncoded - 1 - lenBytes >= dataLen || (*ptr & 0x80))
1476 SetLastError(CRYPT_E_ASN1_CORRUPT);
1483 snprintf(str, sizeof(str), ".%d", val);
1484 bytesNeeded += strlen(str);
1488 *pcbObjId = bytesNeeded;
1489 else if (*pcbObjId < bytesNeeded)
1491 *pcbObjId = bytesNeeded;
1492 SetLastError(ERROR_MORE_DATA);
1497 sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40,
1498 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40) * 40);
1499 pszObjId += strlen(pszObjId);
1500 for (ptr = pbEncoded + 2 + lenBytes; ret &&
1501 ptr - pbEncoded - 1 - lenBytes < dataLen; )
1505 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
1514 sprintf(pszObjId, ".%d", val);
1515 pszObjId += strlen(pszObjId);
1521 *pcbObjId = bytesNeeded;
1525 /* Warning: this assumes the address of value->Value.pbData is already set, in
1526 * order to avoid overwriting memory. (In some cases, it may change it, if it
1527 * doesn't copy anything to memory.) Be sure to set it correctly!
1529 static BOOL WINAPI CRYPT_AsnDecodeNameValue(DWORD dwCertEncodingType,
1530 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, CERT_NAME_VALUE *value,
1533 DWORD bytesNeeded, dataLen;
1537 if (!CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))
1539 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1540 switch (pbEncoded[0])
1542 case ASN_NUMERICSTRING:
1543 case ASN_PRINTABLESTRING:
1547 FIXME("Unimplemented string type %02x\n", pbEncoded[0]);
1548 SetLastError(OSS_UNIMPLEMENTED);
1551 bytesNeeded = sizeof(CERT_NAME_VALUE);
1554 switch (pbEncoded[0])
1556 case ASN_NUMERICSTRING:
1557 case ASN_PRINTABLESTRING:
1559 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
1560 bytesNeeded += dataLen;
1566 *pcbValue = bytesNeeded;
1569 if (*pcbValue < bytesNeeded)
1571 *pcbValue = bytesNeeded;
1572 SetLastError(ERROR_MORE_DATA);
1575 *pcbValue = bytesNeeded;
1576 switch (pbEncoded[0])
1578 case ASN_NUMERICSTRING:
1579 value->dwValueType = CERT_RDN_NUMERIC_STRING;
1581 case ASN_PRINTABLESTRING:
1582 value->dwValueType = CERT_RDN_PRINTABLE_STRING;
1585 value->dwValueType = CERT_RDN_IA5_STRING;
1590 switch (pbEncoded[0])
1592 case ASN_NUMERICSTRING:
1593 case ASN_PRINTABLESTRING:
1595 value->Value.cbData = dataLen;
1596 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1597 value->Value.pbData = (BYTE *)pbEncoded + 1 + lenBytes;
1600 if (!value->Value.pbData)
1602 SetLastError(CRYPT_E_ASN1_INTERNAL);
1606 memcpy(value->Value.pbData, pbEncoded + 1 + lenBytes,
1614 value->Value.cbData = 0;
1615 value->Value.pbData = NULL;
1620 static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(DWORD dwCertEncodingType,
1621 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, CERT_RDN_ATTR *attr,
1625 DWORD bytesNeeded, dataLen, size;
1628 if (!CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))
1630 /* The data length must be at least 4, two for the tag and length for the
1631 * OID, and two for the string (assuming both have short-form lengths.)
1635 SetLastError(CRYPT_E_ASN1_EOD);
1638 if (pbEncoded[0] != (ASN_CONSTRUCTOR | ASN_SEQUENCE))
1640 SetLastError(CRYPT_E_ASN1_BADTAG);
1643 bytesNeeded = sizeof(CERT_RDN_ATTR);
1644 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1645 ret = CRYPT_AsnDecodeOid(dwCertEncodingType, pbEncoded + 1 + lenBytes,
1646 cbEncoded - 1 - lenBytes, dwFlags, NULL, &size);
1649 /* ugly: need to know the size of the next element of the sequence,
1650 * so get it directly
1652 DWORD objIdOfset = 1 + lenBytes, objIdLen, nameValueOffset = 0;
1654 ret = CRYPT_GetLen(pbEncoded + objIdOfset, cbEncoded - objIdOfset,
1656 bytesNeeded += size;
1657 /* hack: like encoding, this takes advantage of the fact that the rest
1658 * of the structure is identical to a CERT_NAME_VALUE.
1662 nameValueOffset = objIdOfset + objIdLen + 1 +
1663 GET_LEN_BYTES(pbEncoded[objIdOfset]);
1664 ret = CRYPT_AsnDecodeNameValue(dwCertEncodingType,
1665 pbEncoded + nameValueOffset, cbEncoded - nameValueOffset, dwFlags,
1670 bytesNeeded += size;
1672 *pcbAttr = bytesNeeded;
1673 else if (*pcbAttr < bytesNeeded)
1675 *pcbAttr = bytesNeeded;
1676 SetLastError(ERROR_MORE_DATA);
1681 BYTE *originalData = attr->Value.pbData;
1683 *pcbAttr = bytesNeeded;
1684 /* strange: decode the value first, because it has a counted
1685 * size, and we can store the OID after it. Keep track of the
1686 * original data pointer, we'll need to know whether it was
1690 ret = CRYPT_AsnDecodeNameValue(dwCertEncodingType,
1691 pbEncoded + nameValueOffset, cbEncoded - nameValueOffset,
1692 dwFlags, (CERT_NAME_VALUE *)&attr->dwValueType, &size);
1697 /* if the data were copied to the original location,
1698 * the OID goes after. Otherwise it goes in the
1699 * spot originally reserved for the data.
1701 if (attr->Value.pbData == originalData)
1702 attr->pszObjId = (LPSTR)(attr->Value.pbData +
1703 attr->Value.cbData);
1705 attr->pszObjId = originalData;
1706 size = bytesNeeded - size;
1707 ret = CRYPT_AsnDecodeOid(dwCertEncodingType,
1708 pbEncoded + objIdOfset, cbEncoded - objIdOfset,
1709 dwFlags, attr->pszObjId, &size);
1712 attr->pszObjId = NULL;
1720 static BOOL WINAPI CRYPT_AsnDecodeRdn(DWORD dwCertEncodingType,
1721 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, CERT_RDN *rdn,
1725 DWORD bytesNeeded, dataLen, cRDNAttr = 0;
1728 if (!CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))
1730 if (pbEncoded[0] != (ASN_CONSTRUCTOR | ASN_SETOF))
1732 SetLastError(CRYPT_E_ASN1_BADTAG);
1735 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1736 bytesNeeded = sizeof(CERT_RDN);
1742 for (ptr = pbEncoded + 1 + lenBytes; ret &&
1743 ptr - pbEncoded - 1 - lenBytes < dataLen; )
1745 ret = CRYPT_AsnDecodeRdnAttr(dwCertEncodingType, ptr,
1746 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
1752 bytesNeeded += size;
1753 ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
1756 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
1764 *pcbRdn = bytesNeeded;
1767 if (*pcbRdn < bytesNeeded)
1769 *pcbRdn = bytesNeeded;
1770 SetLastError(ERROR_MORE_DATA);
1773 *pcbRdn = bytesNeeded;
1774 rdn->cRDNAttr = cRDNAttr;
1775 if (rdn->cRDNAttr == 0)
1776 rdn->rgRDNAttr = NULL;
1783 rdn->rgRDNAttr = (CERT_RDN_ATTR *)((BYTE *)rdn + sizeof(CERT_RDN));
1784 nextData = (BYTE *)rdn->rgRDNAttr +
1785 rdn->cRDNAttr * sizeof(CERT_RDN_ATTR);
1786 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret && i < cRDNAttr &&
1787 ptr - pbEncoded - 1 - lenBytes < dataLen; i++)
1789 rdn->rgRDNAttr[i].Value.pbData = nextData;
1791 ret = CRYPT_AsnDecodeRdnAttr(dwCertEncodingType, ptr,
1792 cbEncoded - (ptr - pbEncoded), dwFlags, &rdn->rgRDNAttr[i],
1798 bytesNeeded -= size;
1799 /* If dwFlags & CRYPT_DECODE_NOCOPY_FLAG, the data may not
1802 if (rdn->rgRDNAttr[i].Value.pbData == nextData)
1803 nextData += rdn->rgRDNAttr[i].Value.cbData;
1804 /* Ugly: the OID, if copied, is stored in memory after the
1805 * value, so increment by its string length if it's set and
1808 if ((const BYTE *)rdn->rgRDNAttr[i].pszObjId == nextData)
1809 nextData += strlen(rdn->rgRDNAttr[i].pszObjId) + 1;
1810 ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
1813 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
1821 static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType,
1822 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1823 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1826 DWORD bytesNeeded, dataLen, cRDN = 0;
1831 SetLastError(CRYPT_E_ASN1_EOD);
1834 if (!CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))
1836 if (pbEncoded[0] != (ASN_CONSTRUCTOR | ASN_SEQUENCEOF))
1838 SetLastError(CRYPT_E_ASN1_BADTAG);
1841 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1842 bytesNeeded = sizeof(CERT_NAME_INFO);
1848 for (ptr = pbEncoded + 1 + lenBytes; ret && ptr - pbEncoded - 1 -
1849 lenBytes < dataLen; )
1851 ret = CRYPT_AsnDecodeRdn(dwCertEncodingType, ptr,
1852 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
1858 bytesNeeded += size;
1859 ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
1862 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
1868 CERT_NAME_INFO *info;
1872 *pcbStructInfo = bytesNeeded;
1875 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
1876 pcbStructInfo, bytesNeeded))
1878 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1879 pvStructInfo = *(BYTE **)pvStructInfo;
1880 info = (CERT_NAME_INFO *)pvStructInfo;
1882 if (info->cRDN == 0)
1890 info->rgRDN = (CERT_RDN *)((BYTE *)pvStructInfo +
1891 sizeof(CERT_NAME_INFO));
1892 nextData = (BYTE *)info->rgRDN + info->cRDN * sizeof(CERT_RDN);
1893 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret && i < cRDN &&
1894 ptr - pbEncoded - 1 - lenBytes < dataLen; i++)
1896 info->rgRDN[i].rgRDNAttr = (CERT_RDN_ATTR *)nextData;
1898 ret = CRYPT_AsnDecodeRdn(dwCertEncodingType, ptr,
1899 cbEncoded - (ptr - pbEncoded), dwFlags, &info->rgRDN[i],
1906 bytesNeeded -= size;
1907 ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
1910 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
1918 static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
1919 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1920 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1922 CRYPT_DATA_BLOB *blob;
1923 DWORD bytesNeeded, dataLen;
1927 SetLastError(CRYPT_E_ASN1_EOD);
1930 if (!CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))
1932 if (pbEncoded[0] != ASN_OCTETSTRING)
1934 SetLastError(CRYPT_E_ASN1_BADTAG);
1937 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1938 bytesNeeded = sizeof(CRYPT_DATA_BLOB);
1940 bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB);
1943 *pcbStructInfo = bytesNeeded;
1946 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
1947 pcbStructInfo, bytesNeeded))
1949 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1950 pvStructInfo = *(BYTE **)pvStructInfo;
1951 blob = (CRYPT_DATA_BLOB *)pvStructInfo;
1952 blob->cbData = dataLen;
1953 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1954 blob->pbData = (BYTE *)pbEncoded + 1 + GET_LEN_BYTES(pbEncoded[1]);
1957 blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_DATA_BLOB);
1959 memcpy(blob->pbData, pbEncoded + 1 + GET_LEN_BYTES(pbEncoded[1]),
1965 static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType,
1966 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1967 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1969 CRYPT_BIT_BLOB *blob;
1970 DWORD bytesNeeded, dataLen;
1974 SetLastError(CRYPT_E_ASN1_EOD);
1977 if (!CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))
1979 if (pbEncoded[0] != ASN_BITSTRING)
1981 SetLastError(CRYPT_E_ASN1_BADTAG);
1984 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1985 bytesNeeded = sizeof(CRYPT_BIT_BLOB);
1987 bytesNeeded = dataLen - 1 + sizeof(CRYPT_BIT_BLOB);
1990 *pcbStructInfo = bytesNeeded;
1993 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
1994 pcbStructInfo, bytesNeeded))
1996 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1997 pvStructInfo = *(BYTE **)pvStructInfo;
1998 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
1999 blob->cbData = dataLen - 1;
2000 blob->cUnusedBits = *(pbEncoded + 1 + GET_LEN_BYTES(pbEncoded[1]));
2001 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
2002 blob->pbData = (BYTE *)pbEncoded + 2 + GET_LEN_BYTES(pbEncoded[1]);
2005 blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_BIT_BLOB);
2008 BYTE mask = 0xff << blob->cUnusedBits;
2010 memcpy(blob->pbData, pbEncoded + 2 + GET_LEN_BYTES(pbEncoded[1]),
2012 blob->pbData[blob->cbData - 1] &= mask;
2018 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
2019 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2020 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2024 if (!pbEncoded || !cbEncoded)
2026 SetLastError(CRYPT_E_ASN1_EOD);
2031 *pcbStructInfo = sizeof(int);
2034 if (pbEncoded[0] != ASN_INTEGER)
2036 SetLastError(CRYPT_E_ASN1_BADTAG);
2041 SetLastError(CRYPT_E_ASN1_EOD);
2044 if (pbEncoded[1] == 0)
2046 SetLastError(CRYPT_E_ASN1_CORRUPT);
2049 if (pbEncoded[1] > sizeof(int))
2051 SetLastError(CRYPT_E_ASN1_LARGE);
2054 if (pbEncoded[2] & 0x80)
2056 /* initialize to a negative value to sign-extend */
2061 for (i = 0; i < pbEncoded[1]; i++)
2064 val |= pbEncoded[2 + i];
2066 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
2067 pcbStructInfo, sizeof(int)))
2069 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2070 pvStructInfo = *(BYTE **)pvStructInfo;
2071 memcpy(pvStructInfo, &val, sizeof(int));
2075 static BOOL WINAPI CRYPT_AsnDecodeInteger(DWORD dwCertEncodingType,
2076 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2077 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2079 DWORD bytesNeeded, dataLen;
2081 CRYPT_INTEGER_BLOB *blob;
2085 SetLastError(CRYPT_E_ASN1_EOD);
2088 if (!CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))
2090 if (pbEncoded[0] != ASN_INTEGER)
2092 SetLastError(CRYPT_E_ASN1_BADTAG);
2095 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2096 bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
2099 *pcbStructInfo = bytesNeeded;
2102 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
2103 pcbStructInfo, bytesNeeded))
2105 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2106 pvStructInfo = *(BYTE **)pvStructInfo;
2107 blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
2108 blob->cbData = dataLen;
2109 blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_INTEGER_BLOB);
2114 for (i = 0; i < blob->cbData; i++)
2115 blob->pbData[i] = *(pbEncoded + 1 + lenBytes + dataLen - i - 1);
2120 static BOOL WINAPI CRYPT_AsnDecodeUnsignedInteger(DWORD dwCertEncodingType,
2121 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2122 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2124 DWORD bytesNeeded, dataLen;
2126 CRYPT_INTEGER_BLOB *blob;
2130 SetLastError(CRYPT_E_ASN1_EOD);
2133 if (!CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))
2135 if (pbEncoded[0] != ASN_INTEGER)
2137 SetLastError(CRYPT_E_ASN1_BADTAG);
2140 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2141 bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
2144 *pcbStructInfo = bytesNeeded;
2147 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
2148 pcbStructInfo, bytesNeeded))
2150 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2151 pvStructInfo = *(BYTE **)pvStructInfo;
2152 blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
2153 blob->cbData = dataLen;
2154 blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_INTEGER_BLOB);
2155 /* remove leading zero byte if it exists */
2156 if (blob->cbData && *(pbEncoded + 1 + lenBytes) == 0)
2165 for (i = 0; i < blob->cbData; i++)
2166 blob->pbData[i] = *(pbEncoded + 1 + lenBytes + pbEncoded[1] - i -
2172 static BOOL WINAPI CRYPT_AsnDecodeEnumerated(DWORD dwCertEncodingType,
2173 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2174 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2176 unsigned int val = 0, i;
2178 /* Based on CRYPT_AsnDecodeInt, but interprets as unsigned */
2179 if (!pbEncoded || !cbEncoded)
2181 SetLastError(CRYPT_E_ASN1_EOD);
2186 *pcbStructInfo = sizeof(int);
2189 if (pbEncoded[0] != ASN_ENUMERATED)
2191 SetLastError(CRYPT_E_ASN1_BADTAG);
2196 SetLastError(CRYPT_E_ASN1_EOD);
2199 if (pbEncoded[1] == 0)
2201 SetLastError(CRYPT_E_ASN1_CORRUPT);
2204 /* A little strange looking, but we have to accept a sign byte: 0xffffffff
2205 * gets encoded as 0a 05 00 ff ff ff ff. Also, assuming a small length is
2206 * okay here, it has to be in short form.
2208 if (pbEncoded[1] > sizeof(unsigned int) + 1)
2210 SetLastError(CRYPT_E_ASN1_LARGE);
2213 for (i = 0; i < pbEncoded[1]; i++)
2216 val |= pbEncoded[2 + i];
2218 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
2219 pcbStructInfo, sizeof(unsigned int)))
2221 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2222 pvStructInfo = *(BYTE **)pvStructInfo;
2223 memcpy(pvStructInfo, &val, sizeof(unsigned int));
2227 #define CRYPT_TIME_GET_DIGITS(pbEncoded, len, numDigits, word) \
2232 for (i = 0; (len) > 0 && i < (numDigits); i++, (len)--) \
2234 if (!isdigit(*(pbEncoded))) \
2236 SetLastError(CRYPT_E_ASN1_CORRUPT); \
2240 (word) += *(pbEncoded)++ - '0'; \
2244 static BOOL CRYPT_AsnDecodeTimeZone(const BYTE *pbEncoded, DWORD len,
2245 SYSTEMTIME *sysTime)
2249 if (len >= 3 && (*pbEncoded == '+' || *pbEncoded == '-'))
2251 WORD hours, minutes = 0;
2252 BYTE sign = *pbEncoded++;
2255 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, hours);
2258 SetLastError(CRYPT_E_ASN1_CORRUPT);
2264 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, minutes);
2267 SetLastError(CRYPT_E_ASN1_CORRUPT);
2274 sysTime->wHour += hours;
2275 sysTime->wMinute += minutes;
2279 if (hours > sysTime->wHour)
2282 sysTime->wHour = 24 - (hours - sysTime->wHour);
2285 sysTime->wHour -= hours;
2286 if (minutes > sysTime->wMinute)
2289 sysTime->wMinute = 60 - (minutes - sysTime->wMinute);
2292 sysTime->wMinute -= minutes;
2299 #define MIN_ENCODED_TIME_LENGTH 10
2301 static BOOL WINAPI CRYPT_AsnDecodeUtcTime(DWORD dwCertEncodingType,
2302 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2303 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2305 SYSTEMTIME sysTime = { 0 };
2309 if (!pbEncoded || !cbEncoded)
2311 SetLastError(CRYPT_E_ASN1_EOD);
2316 *pcbStructInfo = sizeof(FILETIME);
2319 if (pbEncoded[0] != ASN_UTCTIME)
2321 SetLastError(CRYPT_E_ASN1_BADTAG);
2326 SetLastError(CRYPT_E_ASN1_EOD);
2329 if (pbEncoded[1] > 0x7f)
2331 /* long-form date strings really can't be valid */
2332 SetLastError(CRYPT_E_ASN1_CORRUPT);
2336 if (len < MIN_ENCODED_TIME_LENGTH)
2338 SetLastError(CRYPT_E_ASN1_CORRUPT);
2342 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wYear);
2343 if (sysTime.wYear >= 50)
2344 sysTime.wYear += 1900;
2346 sysTime.wYear += 2000;
2347 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
2348 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
2349 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
2350 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
2353 if (len >= 2 && isdigit(*pbEncoded) && isdigit(*(pbEncoded + 1)))
2354 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wSecond);
2355 else if (isdigit(*pbEncoded))
2356 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 1, sysTime.wSecond);
2357 ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len, &sysTime);
2361 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
2362 pcbStructInfo, sizeof(FILETIME)))
2366 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2367 pvStructInfo = *(BYTE **)pvStructInfo;
2368 ret = SystemTimeToFileTime(&sysTime, (FILETIME *)pvStructInfo);
2374 static BOOL WINAPI CRYPT_AsnDecodeGeneralizedTime(DWORD dwCertEncodingType,
2375 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2376 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2378 SYSTEMTIME sysTime = { 0 };
2382 if (!pbEncoded || !cbEncoded)
2384 SetLastError(CRYPT_E_ASN1_EOD);
2389 *pcbStructInfo = sizeof(FILETIME);
2392 if (pbEncoded[0] != ASN_GENERALTIME)
2394 SetLastError(CRYPT_E_ASN1_BADTAG);
2399 SetLastError(CRYPT_E_ASN1_EOD);
2402 if (pbEncoded[1] > 0x7f)
2404 /* long-form date strings really can't be valid */
2405 SetLastError(CRYPT_E_ASN1_CORRUPT);
2409 if (len < MIN_ENCODED_TIME_LENGTH)
2411 SetLastError(CRYPT_E_ASN1_CORRUPT);
2415 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 4, sysTime.wYear);
2416 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
2417 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
2418 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
2421 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
2423 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wSecond);
2424 if (len > 0 && (*pbEncoded == '.' || *pbEncoded == ','))
2430 digits = min(len, 3); /* workaround macro weirdness */
2431 CRYPT_TIME_GET_DIGITS(pbEncoded, len, digits,
2432 sysTime.wMilliseconds);
2434 ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len, &sysTime);
2438 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
2439 pcbStructInfo, sizeof(FILETIME)))
2443 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2444 pvStructInfo = *(BYTE **)pvStructInfo;
2445 ret = SystemTimeToFileTime(&sysTime, (FILETIME *)pvStructInfo);
2451 static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
2452 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2453 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2457 if (!pbEncoded || !cbEncoded)
2459 SetLastError(CRYPT_E_ASN1_EOD);
2464 *pcbStructInfo = sizeof(FILETIME);
2468 if (pbEncoded[0] == ASN_UTCTIME)
2469 ret = CRYPT_AsnDecodeUtcTime(dwCertEncodingType, lpszStructType,
2470 pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
2472 else if (pbEncoded[0] == ASN_GENERALTIME)
2473 ret = CRYPT_AsnDecodeGeneralizedTime(dwCertEncodingType,
2474 lpszStructType, pbEncoded, cbEncoded, dwFlags, pDecodePara,
2475 pvStructInfo, pcbStructInfo);
2478 SetLastError(CRYPT_E_ASN1_BADTAG);
2484 typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *,
2485 DWORD, DWORD, PCRYPT_DECODE_PARA, void *, DWORD *);
2487 BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
2488 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2489 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2493 CryptDecodeObjectExFunc decodeFunc = NULL;
2495 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p, %p)\n",
2496 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
2497 "(integer value)", pbEncoded, cbEncoded, dwFlags, pDecodePara,
2498 pvStructInfo, pcbStructInfo);
2500 if (!pvStructInfo && !pcbStructInfo)
2502 SetLastError(ERROR_INVALID_PARAMETER);
2505 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
2506 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
2508 SetLastError(ERROR_FILE_NOT_FOUND);
2512 SetLastError(NOERROR);
2513 if (!HIWORD(lpszStructType))
2515 switch (LOWORD(lpszStructType))
2517 case (WORD)X509_NAME:
2518 decodeFunc = CRYPT_AsnDecodeName;
2520 case (WORD)X509_OCTET_STRING:
2521 decodeFunc = CRYPT_AsnDecodeOctets;
2523 case (WORD)X509_BITS:
2524 case (WORD)X509_KEY_USAGE:
2525 decodeFunc = CRYPT_AsnDecodeBits;
2527 case (WORD)X509_INTEGER:
2528 decodeFunc = CRYPT_AsnDecodeInt;
2530 case (WORD)X509_MULTI_BYTE_INTEGER:
2531 decodeFunc = CRYPT_AsnDecodeInteger;
2533 case (WORD)X509_MULTI_BYTE_UINT:
2534 decodeFunc = CRYPT_AsnDecodeUnsignedInteger;
2536 case (WORD)X509_ENUMERATED:
2537 decodeFunc = CRYPT_AsnDecodeEnumerated;
2539 case (WORD)X509_CHOICE_OF_TIME:
2540 decodeFunc = CRYPT_AsnDecodeChoiceOfTime;
2542 case (WORD)PKCS_UTC_TIME:
2543 decodeFunc = CRYPT_AsnDecodeUtcTime;
2546 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
2549 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
2550 decodeFunc = CRYPT_AsnDecodeUtcTime;
2551 else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
2552 decodeFunc = CRYPT_AsnDecodeEnumerated;
2553 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
2554 decodeFunc = CRYPT_AsnDecodeBits;
2555 else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
2556 decodeFunc = CRYPT_AsnDecodeOctets;
2558 TRACE("OID %s not found or unimplemented, looking for DLL\n",
2559 debugstr_a(lpszStructType));
2561 decodeFunc = (CryptDecodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
2562 lpszStructType, "CryptDecodeObjectEx", &lib);
2564 ret = decodeFunc(dwCertEncodingType, lpszStructType, pbEncoded,
2565 cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
2567 SetLastError(ERROR_FILE_NOT_FOUND);