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
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
,
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
,
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
,
102 static const char szEncodingTypeFmt
[] =
103 "Software\\Microsoft\\Cryptography\\OID\\EncodingType %ld\\%s\\%s";
105 char numericOID
[7]; /* enough for "#65535" */
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".
116 snprintf(numericOID
, sizeof(numericOID
), "#%d", (int)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
);
130 sprintf(szKey
, szEncodingTypeFmt
, dwEncodingType
, pszFuncName
, oid
);
134 BOOL WINAPI
CryptRegisterOIDFunction(DWORD dwEncodingType
, LPCSTR pszFuncName
,
135 LPCSTR pszOID
, LPCWSTR pwszDll
, LPCSTR pszOverrideFuncName
)
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
))
148 /* Native does nothing pwszDll is NULL */
152 /* I'm not matching MS bug for bug here, because I doubt any app depends on
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
);
165 szKey
= CRYPT_GetKeyName(dwEncodingType
, pszFuncName
, pszOID
);
166 TRACE("Key name is %s\n", debugstr_a(szKey
));
171 r
= RegCreateKeyA(HKEY_LOCAL_MACHINE
, szKey
, &hKey
);
172 HeapFree(GetProcessHeap(), 0, szKey
);
173 if(r
!= ERROR_SUCCESS
)
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
));
187 BOOL WINAPI
CryptUnregisterOIDFunction(DWORD dwEncodingType
, LPCSTR pszFuncName
,
193 TRACE("%lx %s %s\n", dwEncodingType
, pszFuncName
, pszOID
);
195 if (!GET_CERT_ENCODING_TYPE(dwEncodingType
))
198 if (!pszFuncName
|| !pszOID
)
200 SetLastError(ERROR_INVALID_PARAMETER
);
204 szKey
= CRYPT_GetKeyName(dwEncodingType
, pszFuncName
, pszOID
);
205 rc
= RegDeleteKeyA(HKEY_LOCAL_MACHINE
, szKey
);
206 HeapFree(GetProcessHeap(), 0, szKey
);
209 return rc
? FALSE
: TRUE
;
212 BOOL WINAPI
CryptGetOIDFunctionValue(DWORD dwEncodingType
, LPCSTR pszFuncName
,
213 LPCSTR pszOID
, LPCWSTR pwszValueName
, DWORD
*pdwValueType
, BYTE
*pbValueData
,
220 TRACE("%lx %s %s %s %p %p %p\n", dwEncodingType
, debugstr_a(pszFuncName
),
221 debugstr_a(pszOID
), debugstr_w(pwszValueName
), pdwValueType
, pbValueData
,
224 if (!GET_CERT_ENCODING_TYPE(dwEncodingType
))
227 if (!pszFuncName
|| !pszOID
|| !pwszValueName
)
229 SetLastError(ERROR_INVALID_PARAMETER
);
233 szKey
= CRYPT_GetKeyName(dwEncodingType
, pszFuncName
, pszOID
);
234 rc
= RegOpenKeyA(HKEY_LOCAL_MACHINE
, szKey
, &hKey
);
235 HeapFree(GetProcessHeap(), 0, szKey
);
240 rc
= RegQueryValueExW(hKey
, pwszValueName
, NULL
, pdwValueType
,
241 pbValueData
, pcbValueData
);
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
)
257 TRACE("%lx %s %s %s %ld %p %ld\n", dwEncodingType
, debugstr_a(pszFuncName
),
258 debugstr_a(pszOID
), debugstr_w(pwszValueName
), dwValueType
, pbValueData
,
261 if (!GET_CERT_ENCODING_TYPE(dwEncodingType
))
264 if (!pszFuncName
|| !pszOID
|| !pwszValueName
)
266 SetLastError(ERROR_INVALID_PARAMETER
);
270 szKey
= CRYPT_GetKeyName(dwEncodingType
, pszFuncName
, pszOID
);
271 rc
= RegOpenKeyA(HKEY_LOCAL_MACHINE
, szKey
, &hKey
);
272 HeapFree(GetProcessHeap(), 0, szKey
);
277 rc
= RegSetValueExW(hKey
, pwszValueName
, 0, dwValueType
, pbValueData
,
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
)
295 char *szKey
= CRYPT_GetKeyName(dwCertEncodingType
, szFuncName
,
297 const char *funcName
;
300 DWORD type
, size
= 0;
302 TRACE("(%08lx %s %s %p)\n", dwCertEncodingType
, debugstr_a(lpszStructType
),
303 debugstr_a(szFuncName
), lib
);
306 r
= RegOpenKeyA(HKEY_LOCAL_MACHINE
, szKey
, &hKey
);
307 HeapFree(GetProcessHeap(), 0, szKey
);
308 if(r
!= ERROR_SUCCESS
)
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
,
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
,
327 *lib
= LoadLibraryW(dllName
);
330 ret
= GetProcAddress(*lib
, funcName
);
333 /* Unload the library, the caller doesn't want to unload it
334 * when the return value is NULL.
340 HeapFree(GetProcessHeap(), 0, dllName
);
342 if (funcName
!= szFuncName
)
343 HeapFree(GetProcessHeap(), 0, (char *)funcName
);
344 TRACE("returning %p\n", ret
);
348 typedef BOOL (WINAPI
*CryptEncodeObjectFunc
)(DWORD
, LPCSTR
, const void *,
351 BOOL WINAPI
CryptEncodeObject(DWORD dwCertEncodingType
, LPCSTR lpszStructType
,
352 const void *pvStructInfo
, BYTE
*pbEncoded
, DWORD
*pcbEncoded
)
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
);
368 /* Try registered DLL first.. */
370 (CryptEncodeObjectFunc
)CRYPT_GetFunc(dwCertEncodingType
,
371 lpszStructType
, "CryptEncodeObject", &lib
);
372 if (pCryptEncodeObject
)
374 ret
= pCryptEncodeObject(dwCertEncodingType
, lpszStructType
,
375 pvStructInfo
, pbEncoded
, pcbEncoded
);
380 /* If not, use CryptEncodeObjectEx */
381 ret
= CryptEncodeObjectEx(dwCertEncodingType
, lpszStructType
,
382 pvStructInfo
, 0, NULL
, pbEncoded
, pcbEncoded
);
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
,
398 if (dwFlags
& CRYPT_ENCODE_ALLOC_FLAG
)
400 if (pEncodePara
&& pEncodePara
->pfnAlloc
)
401 *(BYTE
**)pbEncoded
= pEncodePara
->pfnAlloc(bytesNeeded
);
403 *(BYTE
**)pbEncoded
= LocalAlloc(0, bytesNeeded
);
404 if (!*(BYTE
**)pbEncoded
)
407 *pcbEncoded
= bytesNeeded
;
409 else if (bytesNeeded
> *pcbEncoded
)
411 *pcbEncoded
= bytesNeeded
;
412 SetLastError(ERROR_MORE_DATA
);
418 static BOOL
CRYPT_EncodeLen(DWORD len
, BYTE
*pbEncoded
, DWORD
*pcbEncoded
)
420 DWORD bytesNeeded
, significantBytes
= 0;
428 for (temp
= len
, significantBytes
= sizeof(temp
); !(temp
& 0xff000000);
429 temp
<<= 8, significantBytes
--)
431 bytesNeeded
= significantBytes
+ 1;
435 *pcbEncoded
= bytesNeeded
;
438 if (*pcbEncoded
< bytesNeeded
)
440 SetLastError(ERROR_MORE_DATA
);
444 *pbEncoded
= (BYTE
)len
;
449 *pbEncoded
++ = significantBytes
| 0x80;
450 for (i
= 0; i
< significantBytes
; i
++)
452 *(pbEncoded
+ significantBytes
- i
- 1) = (BYTE
)(len
& 0xff);
456 *pcbEncoded
= bytesNeeded
;
460 static BOOL
CRYPT_AsnEncodeExtension(CERT_EXTENSION
*ext
, BYTE
*pbEncoded
,
464 DWORD dataLen
, octetsLen
, lenBytes
, size
;
466 ret
= CRYPT_AsnEncodeOid(ext
->pszObjId
, NULL
, &size
);
472 ret
= CRYPT_EncodeBool(TRUE
, NULL
, &size
);
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
);
495 ret
= CRYPT_EncodeBool(TRUE
, pbEncoded
, &size
);
500 ret
= CRYPT_AsnEncodeOctets(X509_ASN_ENCODING
,
501 X509_OCTET_STRING
, &ext
->Value
, 0, NULL
, pbEncoded
,
503 pbEncoded
+= octetsLen
;
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
)
518 DWORD bytesNeeded
, dataLen
, lenBytes
, i
;
519 CERT_EXTENSIONS
*exts
= (CERT_EXTENSIONS
*)pvStructInfo
;
522 for (i
= 0, dataLen
= 0; ret
&& i
< exts
->cExtension
; i
++)
526 ret
= CRYPT_AsnEncodeExtension(&exts
->rgExtension
[i
], NULL
, &size
);
530 CRYPT_EncodeLen(dataLen
, NULL
, &lenBytes
);
531 bytesNeeded
= 1 + lenBytes
+ dataLen
;
533 *pcbEncoded
= bytesNeeded
;
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
++)
548 ret
= CRYPT_AsnEncodeExtension(&exts
->rgExtension
[i
],
558 SetLastError(STATUS_ACCESS_VIOLATION
);
565 static BOOL WINAPI
CRYPT_AsnEncodeOid(LPCSTR pszObjId
, BYTE
*pbEncoded
,
568 DWORD bytesNeeded
= 0, lenBytes
;
578 if (sscanf(pszObjId
, "%d.%d.%n", &val1
, &val2
, &firstPos
) != 2)
580 SetLastError(CRYPT_E_ASN1_ERROR
);
584 firstByte
= val1
* 40 + val2
;
585 ptr
= pszObjId
+ firstPos
;
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)
595 else if (val1
>= 0x200000)
597 else if (val1
>= 0x4000)
599 else if (val1
>= 0x80)
609 SetLastError(CRYPT_E_ASN1_ERROR
);
613 CRYPT_EncodeLen(bytesNeeded
, NULL
, &lenBytes
);
617 bytesNeeded
+= 1 + lenBytes
;
620 if (*pbEncoded
< bytesNeeded
)
622 SetLastError(ERROR_MORE_DATA
);
627 *pbEncoded
++ = ASN_OBJECTIDENTIFIER
;
628 CRYPT_EncodeLen(bytesNeeded
- 1 - lenBytes
, pbEncoded
, &lenBytes
);
629 pbEncoded
+= lenBytes
;
635 *pbEncoded
++ = firstByte
;
636 ptr
= pszObjId
+ firstPos
;
639 sscanf(ptr
, "%d%n", &val
, &pos
);
641 unsigned char outBytes
[5];
644 if (val
>= 0x10000000)
646 else if (val
>= 0x200000)
648 else if (val
>= 0x4000)
650 else if (val
>= 0x80)
654 for (i
= numBytes
; i
> 0; i
--)
656 outBytes
[i
- 1] = val
& 0x7f;
659 for (i
= 0; i
< numBytes
- 1; i
++)
660 *pbEncoded
++ = outBytes
[i
] | 0x80;
661 *pbEncoded
++ = outBytes
[i
];
670 *pcbEncoded
= bytesNeeded
;
674 static BOOL WINAPI
CRYPT_AsnEncodeNameValue(DWORD dwCertEncodingType
,
675 CERT_NAME_VALUE
*value
, BYTE
*pbEncoded
, DWORD
*pcbEncoded
)
678 DWORD bytesNeeded
, lenBytes
, encodedLen
;
681 switch (value
->dwValueType
)
683 case CERT_RDN_NUMERIC_STRING
:
684 tag
= ASN_NUMERICSTRING
;
685 encodedLen
= value
->Value
.cbData
;
687 case CERT_RDN_PRINTABLE_STRING
:
688 tag
= ASN_PRINTABLESTRING
;
689 encodedLen
= value
->Value
.cbData
;
691 case CERT_RDN_IA5_STRING
:
693 encodedLen
= value
->Value
.cbData
;
695 case CERT_RDN_ANY_TYPE
:
696 /* explicitly disallowed */
697 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
700 FIXME("String type %ld unimplemented\n", value
->dwValueType
);
703 CRYPT_EncodeLen(encodedLen
, NULL
, &lenBytes
);
704 bytesNeeded
= 1 + lenBytes
+ encodedLen
;
707 if (*pcbEncoded
< bytesNeeded
)
709 SetLastError(ERROR_MORE_DATA
);
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
;
730 static BOOL WINAPI
CRYPT_AsnEncodeRdnAttr(DWORD dwCertEncodingType
,
731 CERT_RDN_ATTR
*attr
, BYTE
*pbEncoded
, DWORD
*pcbEncoded
)
733 DWORD bytesNeeded
= 0, lenBytes
, size
;
736 ret
= CRYPT_AsnEncodeOid(attr
->pszObjId
, NULL
, &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
);
748 CRYPT_EncodeLen(bytesNeeded
, NULL
, &lenBytes
);
749 bytesNeeded
+= 1 + lenBytes
;
752 if (*pcbEncoded
< bytesNeeded
)
754 SetLastError(ERROR_MORE_DATA
);
759 *pbEncoded
++ = ASN_CONSTRUCTOR
| ASN_SEQUENCE
;
760 CRYPT_EncodeLen(bytesNeeded
- lenBytes
- 1, pbEncoded
,
762 pbEncoded
+= lenBytes
;
763 size
= bytesNeeded
- 1 - lenBytes
;
764 ret
= CRYPT_AsnEncodeOid(attr
->pszObjId
, pbEncoded
, &size
);
768 size
= bytesNeeded
- 1 - lenBytes
- size
;
769 ret
= CRYPT_AsnEncodeNameValue(dwCertEncodingType
,
770 (CERT_NAME_VALUE
*)&attr
->dwValueType
, pbEncoded
,
775 *pcbEncoded
= bytesNeeded
;
781 static int BLOBComp(const void *l
, const void *r
)
783 CRYPT_DER_BLOB
*a
= (CRYPT_DER_BLOB
*)l
, *b
= (CRYPT_DER_BLOB
*)r
;
786 if (!(ret
= memcmp(a
->pbData
, b
->pbData
, min(a
->cbData
, b
->cbData
))))
787 ret
= a
->cbData
- b
->cbData
;
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
)
797 CRYPT_DER_BLOB
*blobs
= NULL
;
801 DWORD bytesNeeded
= 0, lenBytes
, i
;
806 blobs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
807 rdn
->cRDNAttr
* sizeof(CRYPT_DER_BLOB
));
811 for (i
= 0; ret
&& i
< rdn
->cRDNAttr
; i
++)
813 ret
= CRYPT_AsnEncodeRdnAttr(dwCertEncodingType
, &rdn
->rgRDNAttr
[i
],
814 NULL
, &blobs
[i
].cbData
);
816 bytesNeeded
+= blobs
[i
].cbData
;
820 CRYPT_EncodeLen(bytesNeeded
, NULL
, &lenBytes
);
821 bytesNeeded
+= 1 + lenBytes
;
824 if (*pcbEncoded
< bytesNeeded
)
826 SetLastError(ERROR_MORE_DATA
);
831 for (i
= 0; ret
&& i
< rdn
->cRDNAttr
; i
++)
833 blobs
[i
].pbData
= HeapAlloc(GetProcessHeap(), 0,
835 if (!blobs
[i
].pbData
)
838 ret
= CRYPT_AsnEncodeRdnAttr(dwCertEncodingType
,
839 &rdn
->rgRDNAttr
[i
], blobs
[i
].pbData
,
844 qsort(blobs
, rdn
->cRDNAttr
, sizeof(CRYPT_DER_BLOB
),
846 *pbEncoded
++ = ASN_CONSTRUCTOR
| ASN_SETOF
;
847 CRYPT_EncodeLen(bytesNeeded
- lenBytes
- 1, pbEncoded
,
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
;
862 for (i
= 0; i
< rdn
->cRDNAttr
; i
++)
863 HeapFree(GetProcessHeap(), 0, blobs
[i
].pbData
);
868 SetLastError(STATUS_ACCESS_VIOLATION
);
872 HeapFree(GetProcessHeap(), 0, blobs
);
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
)
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
);
889 for (i
= 0; ret
&& i
< info
->cRDN
; i
++)
891 ret
= CRYPT_AsnEncodeRdn(dwCertEncodingType
, &info
->rgRDN
[i
], NULL
,
896 CRYPT_EncodeLen(bytesNeeded
, NULL
, &lenBytes
);
897 bytesNeeded
+= 1 + lenBytes
;
901 *pcbEncoded
= bytesNeeded
;
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
,
912 pbEncoded
+= lenBytes
;
913 for (i
= 0; ret
&& i
< info
->cRDN
; i
++)
916 ret
= CRYPT_AsnEncodeRdn(dwCertEncodingType
,
917 &info
->rgRDN
[i
], pbEncoded
, &size
);
930 SetLastError(STATUS_ACCESS_VIOLATION
);
937 static BOOL
CRYPT_EncodeBool(BOOL val
, BYTE
*pbEncoded
, DWORD
*pcbEncoded
)
947 SetLastError(ERROR_MORE_DATA
);
951 *pbEncoded
++ = ASN_BOOL
;
953 *pbEncoded
++ = val
? 0xff : 0;
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
)
965 CERT_BASIC_CONSTRAINTS2_INFO
*info
=
966 (CERT_BASIC_CONSTRAINTS2_INFO
*)pvStructInfo
;
967 DWORD bytesNeeded
= 0, lenBytes
, caLen
= 0, pathConstraintLen
= 0;
972 ret
= CRYPT_EncodeBool(TRUE
, NULL
, &caLen
);
974 bytesNeeded
+= caLen
;
976 if (info
->fPathLenConstraint
)
978 ret
= CRYPT_AsnEncodeInt(dwCertEncodingType
, X509_INTEGER
,
979 &info
->dwPathLenConstraint
, 0, NULL
, NULL
, &pathConstraintLen
);
981 bytesNeeded
+= pathConstraintLen
;
985 CRYPT_EncodeLen(bytesNeeded
, NULL
, &lenBytes
);
986 bytesNeeded
+= 1 + lenBytes
;
988 *pcbEncoded
= bytesNeeded
;
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
,
999 pbEncoded
+= lenBytes
;
1002 ret
= CRYPT_EncodeBool(TRUE
, 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
);
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
)
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
;
1040 *pcbEncoded
= bytesNeeded
;
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
;
1054 memcpy(pbEncoded
, blob
->pbData
, blob
->cbData
);
1058 __EXCEPT(page_fault
)
1060 SetLastError(STATUS_ACCESS_VIOLATION
);
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
)
1075 CRYPT_BIT_BLOB
*blob
= (CRYPT_BIT_BLOB
*)pvStructInfo
;
1076 DWORD bytesNeeded
, lenBytes
, dataBytes
;
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 :
1091 CRYPT_EncodeLen(dataBytes
+ 1, NULL
, &lenBytes
);
1092 bytesNeeded
= 1 + lenBytes
+ dataBytes
+ 1;
1095 *pcbEncoded
= bytesNeeded
;
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
;
1111 BYTE mask
= 0xff << unusedBits
;
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
);
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
)
1150 DWORD significantBytes
, lenBytes
;
1151 BYTE padByte
= 0, bytesNeeded
;
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)
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)
1186 CRYPT_EncodeLen(significantBytes
+ 1, NULL
, &lenBytes
);
1188 CRYPT_EncodeLen(significantBytes
, NULL
, &lenBytes
);
1189 bytesNeeded
= 1 + lenBytes
+ significantBytes
;
1194 *pcbEncoded
= bytesNeeded
;
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
;
1207 CRYPT_EncodeLen(significantBytes
+ 1, pbEncoded
, &lenBytes
);
1208 pbEncoded
+= lenBytes
;
1209 *pbEncoded
++ = padByte
;
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
);
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
)
1238 DWORD significantBytes
, lenBytes
;
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];
1250 if (significantBytes
== 0)
1251 significantBytes
= 1;
1252 if (blob
->pbData
[significantBytes
- 1] > 0x7f)
1256 CRYPT_EncodeLen(significantBytes
+ 1, NULL
, &lenBytes
);
1258 CRYPT_EncodeLen(significantBytes
, NULL
, &lenBytes
);
1259 bytesNeeded
= 1 + lenBytes
+ significantBytes
;
1264 *pcbEncoded
= bytesNeeded
;
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
;
1277 CRYPT_EncodeLen(significantBytes
+ 1, pbEncoded
, &lenBytes
);
1278 pbEncoded
+= lenBytes
;
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
);
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
;
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
;
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
)
1330 /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0. I use a
1331 * temporary buffer because the output buffer is not NULL-terminated.
1334 static const DWORD bytesNeeded
= sizeof(buf
) - 1;
1338 *pcbEncoded
= bytesNeeded
;
1343 /* Sanity check the year, this is a two-digit year format */
1344 ret
= FileTimeToSystemTime((const FILETIME
*)pvStructInfo
,
1346 if (ret
&& (sysTime
.wYear
< 1950 || sysTime
.wYear
> 2050))
1348 SetLastError(CRYPT_E_BAD_ENCODE
);
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
);
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
)
1388 /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0. I use a
1389 * temporary buffer because the output buffer is not NULL-terminated.
1392 static const DWORD bytesNeeded
= sizeof(buf
) - 1;
1396 *pcbEncoded
= bytesNeeded
;
1401 ret
= FileTimeToSystemTime((const FILETIME
*)pvStructInfo
,
1404 ret
= CRYPT_EncodeEnsureSpace(dwFlags
, pEncodePara
, pbEncoded
,
1405 pcbEncoded
, bytesNeeded
);
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
);
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
)
1438 /* Check the year, if it's in the UTCTime range call that encode func */
1439 if (!FileTimeToSystemTime((const FILETIME
*)pvStructInfo
, &sysTime
))
1441 if (sysTime
.wYear
>= 1950 && sysTime
.wYear
<= 2050)
1442 ret
= CRYPT_AsnEncodeUtcTime(dwCertEncodingType
, lpszStructType
,
1443 pvStructInfo
, dwFlags
, pEncodePara
, pbEncoded
, pcbEncoded
);
1445 ret
= CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType
,
1446 lpszStructType
, pvStructInfo
, dwFlags
, pEncodePara
, pbEncoded
,
1449 __EXCEPT(page_fault
)
1451 SetLastError(STATUS_ACCESS_VIOLATION
);
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
)
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
;
1475 *pcbEncoded
= bytesNeeded
;
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
);
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
)
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
,
1522 if (!pvEncoded
&& !pcbEncoded
)
1524 SetLastError(ERROR_INVALID_PARAMETER
);
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
);
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
;
1544 case (WORD
)X509_NAME
:
1545 encodeFunc
= CRYPT_AsnEncodeName
;
1547 case (WORD
)X509_BASIC_CONSTRAINTS2
:
1548 encodeFunc
= CRYPT_AsnEncodeBasicConstraints2
;
1550 case (WORD
)X509_OCTET_STRING
:
1551 encodeFunc
= CRYPT_AsnEncodeOctets
;
1553 case (WORD
)X509_BITS
:
1554 case (WORD
)X509_KEY_USAGE
:
1555 encodeFunc
= CRYPT_AsnEncodeBits
;
1557 case (WORD
)X509_INTEGER
:
1558 encodeFunc
= CRYPT_AsnEncodeInt
;
1560 case (WORD
)X509_MULTI_BYTE_INTEGER
:
1561 encodeFunc
= CRYPT_AsnEncodeInteger
;
1563 case (WORD
)X509_MULTI_BYTE_UINT
:
1564 encodeFunc
= CRYPT_AsnEncodeUnsignedInteger
;
1566 case (WORD
)X509_ENUMERATED
:
1567 encodeFunc
= CRYPT_AsnEncodeEnumerated
;
1569 case (WORD
)X509_CHOICE_OF_TIME
:
1570 encodeFunc
= CRYPT_AsnEncodeChoiceOfTime
;
1572 case (WORD
)X509_SEQUENCE_OF_ANY
:
1573 encodeFunc
= CRYPT_AsnEncodeSequenceOfAny
;
1575 case (WORD
)PKCS_UTC_TIME
:
1576 encodeFunc
= CRYPT_AsnEncodeUtcTime
;
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
;
1595 TRACE("OID %s not found or unimplemented, looking for DLL\n",
1596 debugstr_a(lpszStructType
));
1598 encodeFunc
= (CryptEncodeObjectExFunc
)CRYPT_GetFunc(dwCertEncodingType
,
1599 lpszStructType
, "CryptEncodeObjectEx", &lib
);
1601 ret
= encodeFunc(dwCertEncodingType
, lpszStructType
, pvStructInfo
,
1602 dwFlags
, pEncodePara
, pvEncoded
, pcbEncoded
);
1604 SetLastError(ERROR_FILE_NOT_FOUND
);
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
)
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
,
1626 if (!pvStructInfo
&& !pcbStructInfo
)
1628 SetLastError(ERROR_INVALID_PARAMETER
);
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
);
1644 /* If not, use CryptDecodeObjectEx */
1645 ret
= CryptDecodeObjectEx(dwCertEncodingType
, lpszStructType
, pbEncoded
,
1646 cbEncoded
, dwFlags
, NULL
, pvStructInfo
, pcbStructInfo
);
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
,
1666 SetLastError(CRYPT_E_ASN1_EOD
);
1669 else if (pbEncoded
[1] <= 0x7f)
1671 *len
= pbEncoded
[1];
1676 BYTE lenLen
= GET_LEN_BYTES(pbEncoded
[1]);
1678 if (lenLen
> sizeof(DWORD
) + 1)
1680 SetLastError(CRYPT_E_ASN1_LARGE
);
1683 else if (lenLen
+ 2 > cbEncoded
)
1685 SetLastError(CRYPT_E_ASN1_CORRUPT
);
1696 out
|= *pbEncoded
++;
1698 if (out
+ lenLen
+ 1 > cbEncoded
)
1700 SetLastError(CRYPT_E_ASN1_EOD
);
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
,
1724 if (dwFlags
& CRYPT_DECODE_ALLOC_FLAG
)
1726 if (pDecodePara
&& pDecodePara
->pfnAlloc
)
1727 *(BYTE
**)pvStructInfo
= pDecodePara
->pfnAlloc(bytesNeeded
);
1729 *(BYTE
**)pvStructInfo
= LocalAlloc(0, bytesNeeded
);
1730 if (!*(BYTE
**)pvStructInfo
)
1733 *pcbStructInfo
= bytesNeeded
;
1735 else if (*pcbStructInfo
< bytesNeeded
)
1737 *pcbStructInfo
= bytesNeeded
;
1738 SetLastError(ERROR_MORE_DATA
);
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
)
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
);
1761 const BYTE
*ptr
= pbEncoded
+ 1 + lenBytes
;
1762 DWORD encodedOidLen
, oidLen
;
1764 CRYPT_GetLen(ptr
, cbEncoded
- (ptr
- pbEncoded
),
1766 oidLenBytes
= GET_LEN_BYTES(ptr
[1]);
1767 ret
= CRYPT_AsnDecodeOid(ptr
, cbEncoded
- (ptr
- pbEncoded
),
1768 dwFlags
& ~CRYPT_DECODE_ALLOC_FLAG
, NULL
, &oidLen
);
1771 bytesNeeded
+= oidLen
;
1772 ptr
+= 1 + encodedOidLen
+ oidLenBytes
;
1773 if (*ptr
== ASN_BOOL
)
1775 ret
= CRYPT_AsnDecodeOctets(X509_ASN_ENCODING
,
1776 X509_OCTET_STRING
, ptr
, cbEncoded
- (ptr
- pbEncoded
),
1777 0, NULL
, NULL
, &dataLen
);
1778 bytesNeeded
+= dataLen
;
1782 *pcbExt
= bytesNeeded
;
1783 else if (*pcbExt
< bytesNeeded
)
1785 SetLastError(ERROR_MORE_DATA
);
1790 ptr
= pbEncoded
+ 2 + lenBytes
+ encodedOidLen
+
1792 if (*ptr
== ASN_BOOL
)
1794 CRYPT_DecodeBool(ptr
, cbEncoded
-
1795 (ptr
- pbEncoded
), &ext
->fCritical
);
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
);
1805 ext
->pszObjId
= ext
->Value
.pbData
+
1807 ptr
= pbEncoded
+ 1 + lenBytes
;
1808 ret
= CRYPT_AsnDecodeOid(ptr
,
1809 cbEncoded
- (ptr
- pbEncoded
),
1810 dwFlags
& ~CRYPT_DECODE_ALLOC_FLAG
,
1811 ext
->pszObjId
, &oidLen
);
1819 SetLastError(CRYPT_E_ASN1_EOD
);
1826 SetLastError(CRYPT_E_ASN1_BADTAG
);
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
)
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
);
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
);
1865 bytesNeeded
+= size
;
1866 ret
= CRYPT_GetLen(ptr
,
1867 cbEncoded
- (ptr
- pbEncoded
), &nextLen
);
1869 ptr
+= nextLen
+ 1 + GET_LEN_BYTES(ptr
[1]);
1876 *pcbStructInfo
= bytesNeeded
;
1877 else if ((ret
= CRYPT_DecodeEnsureSpace(dwFlags
,
1878 pDecodePara
, pvStructInfo
, pcbStructInfo
, bytesNeeded
)))
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
<
1898 exts
->rgExtension
[i
].Value
.pbData
= nextData
;
1900 ret
= CRYPT_AsnDecodeExtension(ptr
,
1901 cbEncoded
- (ptr
- pbEncoded
), dwFlags
,
1902 &exts
->rgExtension
[i
], &size
);
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
==
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
1922 exts
->rgExtension
[i
].pszObjId
) + 1;
1923 ret
= CRYPT_GetLen(ptr
,
1924 cbEncoded
- (ptr
- pbEncoded
), &nextLen
);
1926 ptr
+= nextLen
+ 1 + GET_LEN_BYTES(ptr
[1]);
1935 SetLastError(CRYPT_E_ASN1_BADTAG
);
1939 __EXCEPT(page_fault
)
1941 SetLastError(STATUS_ACCESS_VIOLATION
);
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
)
1956 if (pbEncoded
[0] == ASN_OBJECTIDENTIFIER
)
1960 if ((ret
= CRYPT_GetLen(pbEncoded
, cbEncoded
, &dataLen
)))
1962 BYTE lenBytes
= GET_LEN_BYTES(pbEncoded
[1]);
1967 /* The largest possible string for the first two components
1968 * is 2.175 (= 2 * 40 + 175 = 255), so this is big enough.
1973 snprintf(firstTwo
, sizeof(firstTwo
), "%d.%d",
1974 pbEncoded
[1 + lenBytes
] / 40,
1975 pbEncoded
[1 + lenBytes
] - (pbEncoded
[1 + lenBytes
] / 40)
1977 bytesNeeded
= strlen(firstTwo
) + 1;
1978 for (ptr
= pbEncoded
+ 2 + lenBytes
; ret
&&
1979 ptr
- pbEncoded
- 1 - lenBytes
< dataLen
; )
1981 /* large enough for ".4000000" */
1985 while (ptr
- pbEncoded
- 1 - lenBytes
< dataLen
&&
1992 if (ptr
- pbEncoded
- 1 - lenBytes
>= dataLen
||
1995 SetLastError(CRYPT_E_ASN1_CORRUPT
);
2002 snprintf(str
, sizeof(str
), ".%d", val
);
2003 bytesNeeded
+= strlen(str
);
2007 *pcbObjId
= bytesNeeded
;
2008 else if (*pcbObjId
< bytesNeeded
)
2010 *pcbObjId
= bytesNeeded
;
2011 SetLastError(ERROR_MORE_DATA
);
2016 sprintf(pszObjId
, "%d.%d", pbEncoded
[1 + lenBytes
] / 40,
2017 pbEncoded
[1 + lenBytes
] - (pbEncoded
[1 + lenBytes
] /
2019 pszObjId
+= strlen(pszObjId
);
2020 for (ptr
= pbEncoded
+ 2 + lenBytes
; ret
&&
2021 ptr
- pbEncoded
- 1 - lenBytes
< dataLen
; )
2025 while (ptr
- pbEncoded
- 1 - lenBytes
< dataLen
&&
2034 sprintf(pszObjId
, ".%d", val
);
2035 pszObjId
+= strlen(pszObjId
);
2041 *pcbObjId
= bytesNeeded
;
2046 SetLastError(CRYPT_E_ASN1_BADTAG
);
2050 __EXCEPT(page_fault
)
2052 SetLastError(STATUS_ACCESS_VIOLATION
);
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
)
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
:
2083 FIXME("Unimplemented string type %02x\n", pbEncoded
[0]);
2084 SetLastError(OSS_UNIMPLEMENTED
);
2089 DWORD bytesNeeded
= sizeof(CERT_NAME_VALUE
);
2091 switch (pbEncoded
[0])
2093 case ASN_NUMERICSTRING
:
2094 case ASN_PRINTABLESTRING
:
2096 if (!(dwFlags
& CRYPT_DECODE_NOCOPY_FLAG
))
2097 bytesNeeded
+= dataLen
;
2101 *pcbValue
= bytesNeeded
;
2102 else if (*pcbValue
< bytesNeeded
)
2104 *pcbValue
= bytesNeeded
;
2105 SetLastError(ERROR_MORE_DATA
);
2110 *pcbValue
= bytesNeeded
;
2111 switch (pbEncoded
[0])
2113 case ASN_NUMERICSTRING
:
2114 value
->dwValueType
= CERT_RDN_NUMERIC_STRING
;
2116 case ASN_PRINTABLESTRING
:
2117 value
->dwValueType
= CERT_RDN_PRINTABLE_STRING
;
2120 value
->dwValueType
= CERT_RDN_IA5_STRING
;
2125 switch (pbEncoded
[0])
2127 case ASN_NUMERICSTRING
:
2128 case ASN_PRINTABLESTRING
:
2130 value
->Value
.cbData
= dataLen
;
2131 if (dwFlags
& CRYPT_DECODE_NOCOPY_FLAG
)
2132 value
->Value
.pbData
= (BYTE
*)pbEncoded
+ 1 +
2136 if (!value
->Value
.pbData
)
2138 SetLastError(CRYPT_E_ASN1_INTERNAL
);
2142 memcpy(value
->Value
.pbData
,
2143 pbEncoded
+ 1 + lenBytes
, dataLen
);
2150 value
->Value
.cbData
= 0;
2151 value
->Value
.pbData
= NULL
;
2157 __EXCEPT(page_fault
)
2159 SetLastError(STATUS_ACCESS_VIOLATION
);
2166 static BOOL WINAPI
CRYPT_AsnDecodeRdnAttr(const BYTE
*pbEncoded
,
2167 DWORD cbEncoded
, DWORD dwFlags
, CERT_RDN_ATTR
*attr
, DWORD
*pcbAttr
)
2173 if (pbEncoded
[0] == (ASN_CONSTRUCTOR
| ASN_SEQUENCE
))
2175 DWORD bytesNeeded
, dataLen
, size
;
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.)
2186 SetLastError(CRYPT_E_ASN1_EOD
);
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
);
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.
2212 nameValueOffset
= objIdOfset
+ objIdLen
+ 1 +
2213 GET_LEN_BYTES(pbEncoded
[objIdOfset
]);
2214 ret
= CRYPT_AsnDecodeNameValue(
2215 pbEncoded
+ nameValueOffset
,
2216 cbEncoded
- nameValueOffset
, dwFlags
, NULL
, &size
);
2220 bytesNeeded
+= size
;
2222 *pcbAttr
= bytesNeeded
;
2223 else if (*pcbAttr
< bytesNeeded
)
2225 *pcbAttr
= bytesNeeded
;
2226 SetLastError(ERROR_MORE_DATA
);
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
2241 ret
= CRYPT_AsnDecodeNameValue(
2242 pbEncoded
+ nameValueOffset
,
2243 cbEncoded
- nameValueOffset
, dwFlags
,
2244 (CERT_NAME_VALUE
*)&attr
->dwValueType
, &size
);
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
2255 if (attr
->Value
.pbData
== originalData
)
2257 (LPSTR
)(attr
->Value
.pbData
+
2258 attr
->Value
.cbData
);
2260 attr
->pszObjId
= originalData
;
2261 size
= bytesNeeded
- size
;
2262 ret
= CRYPT_AsnDecodeOid(
2263 pbEncoded
+ objIdOfset
,
2264 cbEncoded
- objIdOfset
,
2265 dwFlags
, attr
->pszObjId
, &size
);
2268 attr
->pszObjId
= NULL
;
2278 SetLastError(CRYPT_E_ASN1_BADTAG
);
2282 __EXCEPT(page_fault
)
2284 SetLastError(STATUS_ACCESS_VIOLATION
);
2291 static BOOL WINAPI
CRYPT_AsnDecodeRdn(const BYTE
*pbEncoded
, DWORD cbEncoded
,
2292 DWORD dwFlags
, CERT_RDN
*rdn
, DWORD
*pcbRdn
)
2298 if (pbEncoded
[0] == (ASN_CONSTRUCTOR
| ASN_SETOF
))
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
);
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
);
2323 bytesNeeded
+= size
;
2324 ret
= CRYPT_GetLen(ptr
,
2325 cbEncoded
- (ptr
- pbEncoded
), &nextLen
);
2327 ptr
+= nextLen
+ 1 + GET_LEN_BYTES(ptr
[1]);
2334 *pcbRdn
= bytesNeeded
;
2335 else if (*pcbRdn
< bytesNeeded
)
2337 *pcbRdn
= bytesNeeded
;
2338 SetLastError(ERROR_MORE_DATA
);
2347 *pcbRdn
= bytesNeeded
;
2348 rdn
->cRDNAttr
= cRDNAttr
;
2349 rdn
->rgRDNAttr
= (CERT_RDN_ATTR
*)((BYTE
*)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
<
2357 rdn
->rgRDNAttr
[i
].Value
.pbData
= nextData
;
2359 ret
= CRYPT_AsnDecodeRdnAttr(ptr
,
2360 cbEncoded
- (ptr
- pbEncoded
), dwFlags
,
2361 &rdn
->rgRDNAttr
[i
], &size
);
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
)
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
2380 rdn
->rgRDNAttr
[i
].pszObjId
) + 1;
2381 ret
= CRYPT_GetLen(ptr
,
2382 cbEncoded
- (ptr
- pbEncoded
), &nextLen
);
2384 ptr
+= nextLen
+ 1 + GET_LEN_BYTES(ptr
[1]);
2393 SetLastError(CRYPT_E_ASN1_BADTAG
);
2397 __EXCEPT(page_fault
)
2399 SetLastError(STATUS_ACCESS_VIOLATION
);
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
)
2414 if (pbEncoded
[0] == (ASN_CONSTRUCTOR
| ASN_SEQUENCEOF
))
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
);
2428 for (ptr
= pbEncoded
+ 1 + lenBytes
; ret
&&
2429 ptr
- pbEncoded
- 1 - lenBytes
< dataLen
; )
2433 ret
= CRYPT_AsnDecodeRdn(ptr
,
2434 cbEncoded
- (ptr
- pbEncoded
), dwFlags
, NULL
, &size
);
2440 bytesNeeded
+= size
;
2441 ret
= CRYPT_GetLen(ptr
,
2442 cbEncoded
- (ptr
- pbEncoded
), &nextLen
);
2444 ptr
+= nextLen
+ 1 + GET_LEN_BYTES(ptr
[1]);
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
;
2461 if (info
->cRDN
== 0)
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
<
2477 info
->rgRDN
[i
].rgRDNAttr
=
2478 (CERT_RDN_ATTR
*)nextData
;
2480 ret
= CRYPT_AsnDecodeRdn(ptr
,
2481 cbEncoded
- (ptr
- pbEncoded
), dwFlags
,
2482 &info
->rgRDN
[i
], &size
);
2488 bytesNeeded
-= size
;
2489 ret
= CRYPT_GetLen(ptr
,
2490 cbEncoded
- (ptr
- pbEncoded
), &nextLen
);
2492 ptr
+= nextLen
+ 1 +
2493 GET_LEN_BYTES(ptr
[1]);
2501 SetLastError(CRYPT_E_ASN1_BADTAG
);
2507 __EXCEPT(page_fault
)
2509 SetLastError(STATUS_ACCESS_VIOLATION
);
2516 static BOOL WINAPI
CRYPT_DecodeBool(const BYTE
*pbEncoded
, DWORD cbEncoded
,
2521 SetLastError(CRYPT_E_ASN1_CORRUPT
);
2524 if (pbEncoded
[0] != ASN_BOOL
)
2526 SetLastError(CRYPT_E_ASN1_BADTAG
);
2529 if (GET_LEN_BYTES(pbEncoded
[1]) > 1)
2531 SetLastError(CRYPT_E_ASN1_CORRUPT
);
2534 if (pbEncoded
[1] > 1)
2536 SetLastError(CRYPT_E_ASN1_CORRUPT
);
2539 *val
= pbEncoded
[2] ? TRUE
: FALSE
;
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
)
2551 if (pbEncoded
[0] == ASN_SEQUENCE
)
2555 if ((ret
= CRYPT_GetLen(pbEncoded
, cbEncoded
, &dataLen
)))
2557 /* sanity-check length, space enough for 7 bytes of integer and
2562 SetLastError(CRYPT_E_ASN1_CORRUPT
);
2567 DWORD bytesNeeded
= sizeof(CERT_BASIC_CONSTRAINTS2_INFO
);
2570 *pcbStructInfo
= bytesNeeded
;
2574 CERT_BASIC_CONSTRAINTS2_INFO info
= { 0 };
2576 lenBytes
= GET_LEN_BYTES(pbEncoded
[1]);
2577 pbEncoded
+= 1 + lenBytes
;
2578 cbEncoded
-= 1 + lenBytes
;
2583 if (pbEncoded
[0] == ASN_BOOL
)
2585 ret
= CRYPT_DecodeBool(pbEncoded
, cbEncoded
,
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
);
2601 cbEncoded
-= 2 + pbEncoded
[1];
2602 pbEncoded
+= 2 + pbEncoded
[1];
2605 SetLastError(CRYPT_E_ASN1_CORRUPT
);
2609 info
.fPathLenConstraint
= TRUE
;
2615 if ((ret
= CRYPT_DecodeEnsureSpace(dwFlags
,
2616 pDecodePara
, pvStructInfo
, pcbStructInfo
,
2619 if (dwFlags
& CRYPT_DECODE_ALLOC_FLAG
)
2620 pvStructInfo
= *(BYTE
**)pvStructInfo
;
2621 memcpy(pvStructInfo
, &info
,
2622 sizeof(CERT_BASIC_CONSTRAINTS2_INFO
));
2631 SetLastError(CRYPT_E_ASN1_BADTAG
);
2635 __EXCEPT(page_fault
)
2637 SetLastError(STATUS_ACCESS_VIOLATION
);
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
)
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
);
2661 bytesNeeded
= dataLen
+ sizeof(CRYPT_DATA_BLOB
);
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
;
2678 blob
->pbData
= (BYTE
*)pvStructInfo
+
2679 sizeof(CRYPT_DATA_BLOB
);
2681 memcpy(blob
->pbData
, pbEncoded
+ 1 + lenBytes
,
2689 SetLastError(CRYPT_E_ASN1_BADTAG
);
2693 __EXCEPT(page_fault
)
2695 SetLastError(STATUS_ACCESS_VIOLATION
);
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
)
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
);
2719 bytesNeeded
= dataLen
- 1 + sizeof(CRYPT_BIT_BLOB
);
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]);
2738 blob
->pbData
= (BYTE
*)pvStructInfo
+
2739 sizeof(CRYPT_BIT_BLOB
);
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
;
2754 SetLastError(CRYPT_E_ASN1_BADTAG
);
2758 __EXCEPT(page_fault
)
2760 SetLastError(STATUS_ACCESS_VIOLATION
);
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
)
2775 *pcbStructInfo
= sizeof(int);
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
);
2787 CRYPT_INTEGER_BLOB
*blob
= (CRYPT_INTEGER_BLOB
*)buf
;
2789 if ((ret
= CRYPT_DecodeEnsureSpace(dwFlags
, pDecodePara
,
2790 pvStructInfo
, pcbStructInfo
, sizeof(int))))
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 */
2803 for (i
= 0; i
< blob
->cbData
; i
++)
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
);
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
)
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
);
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
);
2857 for (i
= 0; i
< blob
->cbData
; i
++)
2858 blob
->pbData
[i
] = *(pbEncoded
+ 1 + lenBytes
+
2866 SetLastError(CRYPT_E_ASN1_BADTAG
);
2870 __EXCEPT(page_fault
)
2872 SetLastError(STATUS_ACCESS_VIOLATION
);
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
)
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
);
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)
2918 for (i
= 0; i
< blob
->cbData
; i
++)
2919 blob
->pbData
[i
] = *(pbEncoded
+ 1 + lenBytes
+
2920 pbEncoded
[1] - i
- 1);
2927 SetLastError(CRYPT_E_ASN1_BADTAG
);
2931 __EXCEPT(page_fault
)
2933 SetLastError(STATUS_ACCESS_VIOLATION
);
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
)
2948 *pcbStructInfo
= sizeof(int);
2953 if (pbEncoded
[0] == ASN_ENUMERATED
)
2955 unsigned int val
= 0, i
;
2959 SetLastError(CRYPT_E_ASN1_EOD
);
2962 else if (pbEncoded
[1] == 0)
2964 SetLastError(CRYPT_E_ASN1_CORRUPT
);
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
2974 if (pbEncoded
[1] > sizeof(unsigned int) + 1)
2976 SetLastError(CRYPT_E_ASN1_LARGE
);
2979 for (i
= 0; i
< pbEncoded
[1]; i
++)
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));
2995 SetLastError(CRYPT_E_ASN1_BADTAG
);
2999 __EXCEPT(page_fault
)
3001 SetLastError(STATUS_ACCESS_VIOLATION
);
3008 /* Modifies word, pbEncoded, and len, and magically sets a value ret to FALSE
3011 #define CRYPT_TIME_GET_DIGITS(pbEncoded, len, numDigits, word) \
3016 for (i = 0; (len) > 0 && i < (numDigits); i++, (len)--) \
3018 if (!isdigit(*(pbEncoded))) \
3020 SetLastError(CRYPT_E_ASN1_CORRUPT); \
3026 (word) += *(pbEncoded)++ - '0'; \
3031 static BOOL
CRYPT_AsnDecodeTimeZone(const BYTE
*pbEncoded
, DWORD len
,
3032 SYSTEMTIME
*sysTime
)
3038 if (len
>= 3 && (*pbEncoded
== '+' || *pbEncoded
== '-'))
3040 WORD hours
, minutes
= 0;
3041 BYTE sign
= *pbEncoded
++;
3044 CRYPT_TIME_GET_DIGITS(pbEncoded
, len
, 2, hours
);
3045 if (ret
&& hours
>= 24)
3047 SetLastError(CRYPT_E_ASN1_CORRUPT
);
3052 CRYPT_TIME_GET_DIGITS(pbEncoded
, len
, 2, minutes
);
3053 if (ret
&& minutes
>= 60)
3055 SetLastError(CRYPT_E_ASN1_CORRUPT
);
3063 sysTime
->wHour
+= hours
;
3064 sysTime
->wMinute
+= minutes
;
3068 if (hours
> sysTime
->wHour
)
3071 sysTime
->wHour
= 24 - (hours
- sysTime
->wHour
);
3074 sysTime
->wHour
-= hours
;
3075 if (minutes
> sysTime
->wMinute
)
3078 sysTime
->wMinute
= 60 - (minutes
- sysTime
->wMinute
);
3081 sysTime
->wMinute
-= minutes
;
3086 __EXCEPT(page_fault
)
3088 SetLastError(STATUS_ACCESS_VIOLATION
);
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
)
3105 *pcbStructInfo
= sizeof(FILETIME
);
3110 if (pbEncoded
[0] == ASN_UTCTIME
)
3114 SetLastError(CRYPT_E_ASN1_EOD
);
3117 else if (pbEncoded
[1] > 0x7f)
3119 /* long-form date strings really can't be valid */
3120 SetLastError(CRYPT_E_ASN1_CORRUPT
);
3125 SYSTEMTIME sysTime
= { 0 };
3126 BYTE len
= pbEncoded
[1];
3128 if (len
< MIN_ENCODED_TIME_LENGTH
)
3130 SetLastError(CRYPT_E_ASN1_CORRUPT
);
3136 CRYPT_TIME_GET_DIGITS(pbEncoded
, len
, 2, sysTime
.wYear
);
3137 if (sysTime
.wYear
>= 50)
3138 sysTime
.wYear
+= 1900;
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
);
3147 if (len
>= 2 && isdigit(*pbEncoded
) &&
3148 isdigit(*(pbEncoded
+ 1)))
3149 CRYPT_TIME_GET_DIGITS(pbEncoded
, len
, 2,
3151 else if (isdigit(*pbEncoded
))
3152 CRYPT_TIME_GET_DIGITS(pbEncoded
, len
, 1,
3155 ret
= CRYPT_AsnDecodeTimeZone(pbEncoded
, len
,
3158 if (ret
&& (ret
= CRYPT_DecodeEnsureSpace(dwFlags
,
3159 pDecodePara
, pvStructInfo
, pcbStructInfo
,
3162 if (dwFlags
& CRYPT_DECODE_ALLOC_FLAG
)
3163 pvStructInfo
= *(BYTE
**)pvStructInfo
;
3164 ret
= SystemTimeToFileTime(&sysTime
,
3165 (FILETIME
*)pvStructInfo
);
3172 SetLastError(CRYPT_E_ASN1_BADTAG
);
3176 __EXCEPT(page_fault
)
3178 SetLastError(STATUS_ACCESS_VIOLATION
);
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
)
3193 *pcbStructInfo
= sizeof(FILETIME
);
3198 if (pbEncoded
[0] == ASN_GENERALTIME
)
3202 SetLastError(CRYPT_E_ASN1_EOD
);
3205 else if (pbEncoded
[1] > 0x7f)
3207 /* long-form date strings really can't be valid */
3208 SetLastError(CRYPT_E_ASN1_CORRUPT
);
3213 BYTE len
= pbEncoded
[1];
3215 if (len
< MIN_ENCODED_TIME_LENGTH
)
3217 SetLastError(CRYPT_E_ASN1_CORRUPT
);
3222 SYSTEMTIME sysTime
= { 0 };
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
);
3231 CRYPT_TIME_GET_DIGITS(pbEncoded
, len
, 2,
3234 CRYPT_TIME_GET_DIGITS(pbEncoded
, len
, 2,
3236 if (ret
&& len
> 0 && (*pbEncoded
== '.' ||
3243 /* workaround macro weirdness */
3244 digits
= min(len
, 3);
3245 CRYPT_TIME_GET_DIGITS(pbEncoded
, len
, digits
,
3246 sysTime
.wMilliseconds
);
3249 ret
= CRYPT_AsnDecodeTimeZone(pbEncoded
, len
,
3252 if (ret
&& (ret
= CRYPT_DecodeEnsureSpace(dwFlags
,
3253 pDecodePara
, pvStructInfo
, pcbStructInfo
,
3256 if (dwFlags
& CRYPT_DECODE_ALLOC_FLAG
)
3257 pvStructInfo
= *(BYTE
**)pvStructInfo
;
3258 ret
= SystemTimeToFileTime(&sysTime
,
3259 (FILETIME
*)pvStructInfo
);
3266 SetLastError(CRYPT_E_ASN1_BADTAG
);
3270 __EXCEPT(page_fault
)
3272 SetLastError(STATUS_ACCESS_VIOLATION
);
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
)
3287 *pcbStructInfo
= sizeof(FILETIME
);
3293 if (pbEncoded
[0] == ASN_UTCTIME
)
3294 ret
= CRYPT_AsnDecodeUtcTime(dwCertEncodingType
, lpszStructType
,
3295 pbEncoded
, cbEncoded
, dwFlags
, pDecodePara
, pvStructInfo
,
3297 else if (pbEncoded
[0] == ASN_GENERALTIME
)
3298 ret
= CRYPT_AsnDecodeGeneralizedTime(dwCertEncodingType
,
3299 lpszStructType
, pbEncoded
, cbEncoded
, dwFlags
, pDecodePara
,
3300 pvStructInfo
, pcbStructInfo
);
3303 SetLastError(CRYPT_E_ASN1_BADTAG
);
3307 __EXCEPT(page_fault
)
3309 SetLastError(STATUS_ACCESS_VIOLATION
);
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
)
3324 if (pbEncoded
[0] == ASN_SEQUENCEOF
)
3326 DWORD bytesNeeded
, dataLen
, remainingLen
, cValue
;
3328 if ((ret
= CRYPT_GetLen(pbEncoded
, cbEncoded
, &dataLen
)))
3333 lenBytes
= GET_LEN_BYTES(pbEncoded
[1]);
3334 bytesNeeded
= sizeof(CRYPT_SEQUENCE_OF_ANY
);
3336 ptr
= pbEncoded
+ 1 + lenBytes
;
3337 remainingLen
= dataLen
;
3338 while (ret
&& remainingLen
)
3342 ret
= CRYPT_GetLen(ptr
, remainingLen
, &nextLen
);
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
;
3357 CRYPT_SEQUENCE_OF_ANY
*seq
;
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
+
3370 nextPtr
= (BYTE
*)seq
->rgValue
+
3371 cValue
* sizeof(CRYPT_DER_BLOB
);
3372 ptr
= pbEncoded
+ 1 + lenBytes
;
3373 remainingLen
= dataLen
;
3375 while (ret
&& remainingLen
)
3379 ret
= CRYPT_GetLen(ptr
, remainingLen
, &nextLen
);
3382 DWORD nextLenBytes
= GET_LEN_BYTES(ptr
[1]);
3384 seq
->rgValue
[i
].cbData
= 1 + nextLenBytes
+
3386 if (dwFlags
& CRYPT_DECODE_NOCOPY_FLAG
)
3387 seq
->rgValue
[i
].pbData
= (BYTE
*)ptr
;
3390 seq
->rgValue
[i
].pbData
= nextPtr
;
3391 memcpy(nextPtr
, ptr
, 1 + nextLenBytes
+
3393 nextPtr
+= 1 + nextLenBytes
+ nextLen
;
3395 remainingLen
-= 1 + nextLenBytes
+ nextLen
;
3396 ptr
+= 1 + nextLenBytes
+ nextLen
;
3406 SetLastError(CRYPT_E_ASN1_BADTAG
);
3410 __EXCEPT(page_fault
)
3412 SetLastError(STATUS_ACCESS_VIOLATION
);
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
)
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
);
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
);
3446 if (!pbEncoded
|| !cbEncoded
)
3448 SetLastError(CRYPT_E_ASN1_EOD
);
3451 if (cbEncoded
> MAX_ENCODED_LEN
)
3453 SetLastError(CRYPT_E_ASN1_LARGE
);
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
;
3467 case (WORD
)X509_NAME
:
3468 decodeFunc
= CRYPT_AsnDecodeName
;
3470 case (WORD
)X509_BASIC_CONSTRAINTS2
:
3471 decodeFunc
= CRYPT_AsnDecodeBasicConstraints2
;
3473 case (WORD
)X509_OCTET_STRING
:
3474 decodeFunc
= CRYPT_AsnDecodeOctets
;
3476 case (WORD
)X509_BITS
:
3477 case (WORD
)X509_KEY_USAGE
:
3478 decodeFunc
= CRYPT_AsnDecodeBits
;
3480 case (WORD
)X509_INTEGER
:
3481 decodeFunc
= CRYPT_AsnDecodeInt
;
3483 case (WORD
)X509_MULTI_BYTE_INTEGER
:
3484 decodeFunc
= CRYPT_AsnDecodeInteger
;
3486 case (WORD
)X509_MULTI_BYTE_UINT
:
3487 decodeFunc
= CRYPT_AsnDecodeUnsignedInteger
;
3489 case (WORD
)X509_ENUMERATED
:
3490 decodeFunc
= CRYPT_AsnDecodeEnumerated
;
3492 case (WORD
)X509_CHOICE_OF_TIME
:
3493 decodeFunc
= CRYPT_AsnDecodeChoiceOfTime
;
3495 case (WORD
)X509_SEQUENCE_OF_ANY
:
3496 decodeFunc
= CRYPT_AsnDecodeSequenceOfAny
;
3498 case (WORD
)PKCS_UTC_TIME
:
3499 decodeFunc
= CRYPT_AsnDecodeUtcTime
;
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
;
3518 TRACE("OID %s not found or unimplemented, looking for DLL\n",
3519 debugstr_a(lpszStructType
));
3521 decodeFunc
= (CryptDecodeObjectExFunc
)CRYPT_GetFunc(dwCertEncodingType
,
3522 lpszStructType
, "CryptDecodeObjectEx", &lib
);
3524 ret
= decodeFunc(dwCertEncodingType
, lpszStructType
, pbEncoded
,
3525 cbEncoded
, dwFlags
, pDecodePara
, pvStructInfo
, pcbStructInfo
);
3527 SetLastError(ERROR_FILE_NOT_FOUND
);