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
26 #include "wine/debug.h"
28 /* a few asn.1 tags we need */
29 #define ASN_UTCTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x17)
30 #define ASN_GENERALTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x18)
32 WINE_DEFAULT_DEBUG_CHANNEL(crypt
);
34 static const WCHAR szDllName
[] = { 'D','l','l',0 };
36 static char *CRYPT_GetKeyName(DWORD dwEncodingType
, LPCSTR pszFuncName
,
39 static const char szEncodingTypeFmt
[] =
40 "Software\\Microsoft\\Cryptography\\OID\\EncodingType %ld\\%s\\%s";
42 char numericOID
[7]; /* enough for "#65535" */
46 /* MSDN says the encoding type is a mask, but it isn't treated that way.
47 * (E.g., if dwEncodingType were 3, the key names "EncodingType 1" and
48 * "EncodingType 2" would be expected if it were a mask. Instead native
49 * stores values in "EncodingType 3".
53 snprintf(numericOID
, sizeof(numericOID
), "#%d", (int)pszOID
);
59 /* This is enough: the lengths of the two string parameters are explicitly
60 * counted, and we need up to five additional characters for the encoding
61 * type. These are covered by the "%d", "%s", and "%s" characters in the
62 * format specifier that are removed by sprintf.
64 len
= sizeof(szEncodingTypeFmt
) + lstrlenA(pszFuncName
) + lstrlenA(oid
);
65 szKey
= HeapAlloc(GetProcessHeap(), 0, len
);
67 sprintf(szKey
, szEncodingTypeFmt
, dwEncodingType
, pszFuncName
, oid
);
71 BOOL WINAPI
CryptRegisterOIDFunction(DWORD dwEncodingType
, LPCSTR pszFuncName
,
72 LPCSTR pszOID
, LPCWSTR pwszDll
, LPCSTR pszOverrideFuncName
)
78 TRACE("%lx %s %s %s %s\n", dwEncodingType
, pszFuncName
, pszOID
,
79 debugstr_w(pwszDll
), pszOverrideFuncName
);
81 /* This only registers functions for encoding certs, not messages */
82 if (!GET_CERT_ENCODING_TYPE(dwEncodingType
))
85 /* Native does nothing pwszDll is NULL */
89 /* I'm not matching MS bug for bug here, because I doubt any app depends on
91 * - native "succeeds" if pszFuncName is NULL, but the nonsensical entry
92 * it creates would never be used
93 * - native returns an HRESULT rather than a Win32 error if pszOID is NULL.
94 * Instead I disallow both of these with ERROR_INVALID_PARAMETER.
96 if (!pszFuncName
|| !pszOID
)
98 SetLastError(ERROR_INVALID_PARAMETER
);
102 szKey
= CRYPT_GetKeyName(dwEncodingType
, pszFuncName
, pszOID
);
103 TRACE("Key name is %s\n", debugstr_a(szKey
));
108 r
= RegCreateKeyA(HKEY_LOCAL_MACHINE
, szKey
, &hKey
);
109 HeapFree(GetProcessHeap(), 0, szKey
);
110 if(r
!= ERROR_SUCCESS
)
113 /* write the values */
114 if (pszOverrideFuncName
)
115 RegSetValueExA(hKey
, "FuncName", 0, REG_SZ
, pszOverrideFuncName
,
116 lstrlenA(pszOverrideFuncName
) + 1);
117 RegSetValueExW(hKey
, szDllName
, 0, REG_SZ
, (const BYTE
*) pwszDll
,
118 (lstrlenW(pwszDll
) + 1) * sizeof (WCHAR
));
124 BOOL WINAPI
CryptUnregisterOIDFunction(DWORD dwEncodingType
, LPCSTR pszFuncName
,
130 TRACE("%lx %s %s\n", dwEncodingType
, pszFuncName
, pszOID
);
132 if (!GET_CERT_ENCODING_TYPE(dwEncodingType
))
135 if (!pszFuncName
|| !pszOID
)
137 SetLastError(ERROR_INVALID_PARAMETER
);
141 szKey
= CRYPT_GetKeyName(dwEncodingType
, pszFuncName
, pszOID
);
142 rc
= RegDeleteKeyA(HKEY_LOCAL_MACHINE
, szKey
);
143 HeapFree(GetProcessHeap(), 0, szKey
);
146 return rc
? FALSE
: TRUE
;
149 BOOL WINAPI
CryptGetOIDFunctionValue(DWORD dwEncodingType
, LPCSTR pszFuncName
,
150 LPCSTR pszOID
, LPCWSTR pwszValueName
, DWORD
*pdwValueType
, BYTE
*pbValueData
,
157 TRACE("%lx %s %s %s %p %p %p\n", dwEncodingType
, debugstr_a(pszFuncName
),
158 debugstr_a(pszOID
), debugstr_w(pwszValueName
), pdwValueType
, pbValueData
,
161 if (!GET_CERT_ENCODING_TYPE(dwEncodingType
))
164 if (!pszFuncName
|| !pszOID
|| !pwszValueName
)
166 SetLastError(ERROR_INVALID_PARAMETER
);
170 szKey
= CRYPT_GetKeyName(dwEncodingType
, pszFuncName
, pszOID
);
171 rc
= RegOpenKeyA(HKEY_LOCAL_MACHINE
, szKey
, &hKey
);
172 HeapFree(GetProcessHeap(), 0, szKey
);
177 rc
= RegQueryValueExW(hKey
, pwszValueName
, NULL
, pdwValueType
,
178 pbValueData
, pcbValueData
);
183 return rc
? FALSE
: TRUE
;
186 BOOL WINAPI
CryptSetOIDFunctionValue(DWORD dwEncodingType
, LPCSTR pszFuncName
,
187 LPCSTR pszOID
, LPCWSTR pwszValueName
, DWORD dwValueType
,
188 const BYTE
*pbValueData
, DWORD cbValueData
)
194 TRACE("%lx %s %s %s %ld %p %ld\n", dwEncodingType
, debugstr_a(pszFuncName
),
195 debugstr_a(pszOID
), debugstr_w(pwszValueName
), dwValueType
, pbValueData
,
198 if (!GET_CERT_ENCODING_TYPE(dwEncodingType
))
201 if (!pszFuncName
|| !pszOID
|| !pwszValueName
)
203 SetLastError(ERROR_INVALID_PARAMETER
);
207 szKey
= CRYPT_GetKeyName(dwEncodingType
, pszFuncName
, pszOID
);
208 rc
= RegOpenKeyA(HKEY_LOCAL_MACHINE
, szKey
, &hKey
);
209 HeapFree(GetProcessHeap(), 0, szKey
);
214 rc
= RegSetValueExW(hKey
, pwszValueName
, 0, dwValueType
, pbValueData
,
220 return rc
? FALSE
: TRUE
;
223 /* Gets the registered function named szFuncName for dwCertEncodingType and
224 * lpszStructType, or NULL if one could not be found. *lib will be set to the
225 * handle of the module it's in, or NULL if no module was loaded. If the
226 * return value is NULL, *lib will also be NULL, to simplify error handling.
228 static void *CRYPT_GetFunc(DWORD dwCertEncodingType
, LPCSTR lpszStructType
,
229 LPCSTR szFuncName
, HMODULE
*lib
)
232 char *szKey
= CRYPT_GetKeyName(dwCertEncodingType
, szFuncName
,
234 const char *funcName
;
237 DWORD type
, size
= 0;
240 r
= RegOpenKeyA(HKEY_LOCAL_MACHINE
, szKey
, &hKey
);
241 HeapFree(GetProcessHeap(), 0, szKey
);
242 if(r
!= ERROR_SUCCESS
)
245 RegQueryValueExA(hKey
, "FuncName", NULL
, &type
, NULL
, &size
);
246 if (GetLastError() == ERROR_MORE_DATA
&& type
== REG_SZ
)
248 funcName
= HeapAlloc(GetProcessHeap(), 0, size
);
249 RegQueryValueExA(hKey
, "FuncName", NULL
, &type
, (LPBYTE
)funcName
,
253 funcName
= szFuncName
;
254 RegQueryValueExW(hKey
, szDllName
, NULL
, &type
, NULL
, &size
);
255 if (GetLastError() == ERROR_MORE_DATA
&& type
== REG_SZ
)
257 LPWSTR dllName
= HeapAlloc(GetProcessHeap(), 0, size
);
259 RegQueryValueExW(hKey
, szDllName
, NULL
, &type
, (LPBYTE
)dllName
,
261 *lib
= LoadLibraryW(dllName
);
264 ret
= GetProcAddress(*lib
, funcName
);
267 /* Unload the library, the caller doesn't want to unload it
268 * when the return value is NULL.
274 HeapFree(GetProcessHeap(), 0, dllName
);
276 if (funcName
!= szFuncName
)
277 HeapFree(GetProcessHeap(), 0, (char *)funcName
);
281 typedef BOOL (WINAPI
*CryptEncodeObjectFunc
)(DWORD
, LPCSTR
, const void *,
284 BOOL WINAPI
CryptEncodeObject(DWORD dwCertEncodingType
, LPCSTR lpszStructType
,
285 const void *pvStructInfo
, BYTE
*pbEncoded
, DWORD
*pcbEncoded
)
289 CryptEncodeObjectFunc pCryptEncodeObject
;
291 TRACE("(0x%08lx, %s, %p, %p, %p)\n",
292 dwCertEncodingType
, HIWORD(lpszStructType
) ? debugstr_a(lpszStructType
) :
293 "(integer value)", pvStructInfo
, pbEncoded
, pcbEncoded
);
295 if (!pbEncoded
&& !pcbEncoded
)
297 SetLastError(ERROR_INVALID_PARAMETER
);
301 /* Try registered DLL first.. */
303 (CryptEncodeObjectFunc
)CRYPT_GetFunc(dwCertEncodingType
,
304 lpszStructType
, "CryptEncodeObject", &lib
);
305 if (pCryptEncodeObject
)
307 ret
= pCryptEncodeObject(dwCertEncodingType
, lpszStructType
,
308 pvStructInfo
, pbEncoded
, pcbEncoded
);
313 /* If not, use CryptEncodeObjectEx */
314 ret
= CryptEncodeObjectEx(dwCertEncodingType
, lpszStructType
,
315 pvStructInfo
, 0, NULL
, pbEncoded
, pcbEncoded
);
320 /* Helper function to check *pcbEncoded, set it to the required size, and
321 * optionally to allocate memory. Assumes pbEncoded is not NULL.
322 * If CRYPT_ENCODE_ALLOC_FLAG is set in dwFlags, *pbEncoded will be set to a
323 * pointer to the newly allocated memory.
325 static BOOL
CRYPT_EncodeEnsureSpace(DWORD dwFlags
,
326 PCRYPT_ENCODE_PARA pEncodePara
, BYTE
*pbEncoded
, DWORD
*pcbEncoded
,
331 if (dwFlags
& CRYPT_ENCODE_ALLOC_FLAG
)
333 if (pEncodePara
&& pEncodePara
->pfnAlloc
)
334 *(BYTE
**)pbEncoded
= pEncodePara
->pfnAlloc(bytesNeeded
);
336 *(BYTE
**)pbEncoded
= LocalAlloc(0, bytesNeeded
);
337 if (!*(BYTE
**)pbEncoded
)
340 else if (bytesNeeded
> *pcbEncoded
)
342 *pcbEncoded
= bytesNeeded
;
343 SetLastError(ERROR_MORE_DATA
);
349 static BOOL WINAPI
CRYPT_AsnEncodeInt(DWORD dwCertEncodingType
,
350 LPCSTR lpszStructType
, const void *pvStructInfo
, DWORD dwFlags
,
351 PCRYPT_ENCODE_PARA pEncodePara
, BYTE
*pbEncoded
, DWORD
*pcbEncoded
)
354 BYTE significantBytes
, padByte
= 0, bytesNeeded
;
355 BOOL neg
= FALSE
, pad
= FALSE
;
359 SetLastError(ERROR_INVALID_PARAMETER
);
363 memcpy(&val
, pvStructInfo
, sizeof(val
));
364 /* Count the number of significant bytes. Temporarily swap sign for
365 * negatives so I count the minimum number of bytes.
372 for (significantBytes
= sizeof(val
); !(val
& 0xff000000);
373 val
<<= 8, significantBytes
--)
378 if ((val
& 0xff000000) < 0x80000000)
384 else if ((val
& 0xff000000) > 0x7f000000)
389 bytesNeeded
= 2 + significantBytes
;
394 *pcbEncoded
= bytesNeeded
;
397 if (!CRYPT_EncodeEnsureSpace(dwFlags
, pEncodePara
, pbEncoded
, pcbEncoded
,
400 if (dwFlags
& CRYPT_ENCODE_ALLOC_FLAG
)
401 pbEncoded
= *(BYTE
**)pbEncoded
;
402 *pbEncoded
++ = ASN_INTEGER
;
405 *pbEncoded
++ = significantBytes
+ 1;
406 *pbEncoded
++ = padByte
;
409 *pbEncoded
++ = significantBytes
;
410 for (i
= 0; i
< significantBytes
; i
++, val
<<= 8)
411 *(pbEncoded
+ i
) = (BYTE
)((val
& 0xff000000) >> 24);
415 static BOOL WINAPI
CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType
,
416 LPCSTR lpszStructType
, const void *pvStructInfo
, DWORD dwFlags
,
417 PCRYPT_ENCODE_PARA pEncodePara
, BYTE
*pbEncoded
, DWORD
*pcbEncoded
)
420 /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0. I use a
421 * temporary buffer because the output buffer is not NULL-terminated.
424 static const DWORD bytesNeeded
= sizeof(buf
) - 1;
428 SetLastError(ERROR_INVALID_PARAMETER
);
431 /* Sanity check the year, this is a two-digit year format */
432 if (!FileTimeToSystemTime((const FILETIME
*)pvStructInfo
, &sysTime
))
434 if (sysTime
.wYear
< 1950 || sysTime
.wYear
> 2050)
436 SetLastError(CRYPT_E_BAD_ENCODE
);
441 *pcbEncoded
= bytesNeeded
;
444 if (!CRYPT_EncodeEnsureSpace(dwFlags
, pEncodePara
, pbEncoded
, pcbEncoded
,
447 if (dwFlags
& CRYPT_ENCODE_ALLOC_FLAG
)
448 pbEncoded
= *(BYTE
**)pbEncoded
;
449 buf
[0] = ASN_UTCTIME
;
450 buf
[1] = bytesNeeded
- 2;
451 snprintf(buf
+ 2, sizeof(buf
) - 2, "%02d%02d%02d%02d%02d%02dZ",
452 sysTime
.wYear
>= 2000 ? sysTime
.wYear
- 2000 : sysTime
.wYear
- 1900,
453 sysTime
.wDay
, sysTime
.wMonth
, sysTime
.wHour
, sysTime
.wMinute
,
455 memcpy(pbEncoded
, buf
, bytesNeeded
);
459 static BOOL WINAPI
CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType
,
460 LPCSTR lpszStructType
, const void *pvStructInfo
, DWORD dwFlags
,
461 PCRYPT_ENCODE_PARA pEncodePara
, BYTE
*pbEncoded
, DWORD
*pcbEncoded
)
464 /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0. I use a
465 * temporary buffer because the output buffer is not NULL-terminated.
468 static const DWORD bytesNeeded
= sizeof(buf
) - 1;
472 SetLastError(ERROR_INVALID_PARAMETER
);
477 *pcbEncoded
= bytesNeeded
;
480 if (!FileTimeToSystemTime((const FILETIME
*)pvStructInfo
, &sysTime
))
482 if (!CRYPT_EncodeEnsureSpace(dwFlags
, pEncodePara
, pbEncoded
, pcbEncoded
,
485 if (dwFlags
& CRYPT_ENCODE_ALLOC_FLAG
)
486 pbEncoded
= *(BYTE
**)pbEncoded
;
487 buf
[0] = ASN_GENERALTIME
;
488 buf
[1] = bytesNeeded
- 2;
489 snprintf(buf
+ 2, sizeof(buf
) - 2, "%04d%02d%02d%02d%02d%02dZ",
490 sysTime
.wYear
, sysTime
.wDay
, sysTime
.wMonth
, sysTime
.wHour
,
491 sysTime
.wMinute
, sysTime
.wSecond
);
492 memcpy(pbEncoded
, buf
, bytesNeeded
);
496 static BOOL WINAPI
CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType
,
497 LPCSTR lpszStructType
, const void *pvStructInfo
, DWORD dwFlags
,
498 PCRYPT_ENCODE_PARA pEncodePara
, BYTE
*pbEncoded
, DWORD
*pcbEncoded
)
505 SetLastError(ERROR_INVALID_PARAMETER
);
508 /* Check the year, if it's in the UTCTime range call that encode func */
509 if (!FileTimeToSystemTime((const FILETIME
*)pvStructInfo
, &sysTime
))
511 if (sysTime
.wYear
>= 1950 && sysTime
.wYear
<= 2050)
512 ret
= CRYPT_AsnEncodeUtcTime(dwCertEncodingType
, lpszStructType
,
513 pvStructInfo
, dwFlags
, pEncodePara
, pbEncoded
, pcbEncoded
);
515 ret
= CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType
,
516 lpszStructType
, pvStructInfo
, dwFlags
, pEncodePara
, pbEncoded
,
521 typedef BOOL (WINAPI
*CryptEncodeObjectExFunc
)(DWORD
, LPCSTR
, const void *,
522 DWORD
, PCRYPT_ENCODE_PARA
, BYTE
*, DWORD
*);
524 BOOL WINAPI
CryptEncodeObjectEx(DWORD dwCertEncodingType
, LPCSTR lpszStructType
,
525 const void *pvStructInfo
, DWORD dwFlags
, PCRYPT_ENCODE_PARA pEncodePara
,
526 BYTE
*pbEncoded
, DWORD
*pcbEncoded
)
530 CryptEncodeObjectExFunc encodeFunc
= NULL
;
532 TRACE("(0x%08lx, %s, %p, 0x%08lx, %p, %p, %p): semi-stub\n",
533 dwCertEncodingType
, HIWORD(lpszStructType
) ? debugstr_a(lpszStructType
) :
534 "(integer value)", pvStructInfo
, dwFlags
, pEncodePara
, pbEncoded
,
537 if (!pbEncoded
&& !pcbEncoded
)
539 SetLastError(ERROR_INVALID_PARAMETER
);
542 if ((dwCertEncodingType
& CERT_ENCODING_TYPE_MASK
) != X509_ASN_ENCODING
543 && (dwCertEncodingType
& CMSG_ENCODING_TYPE_MASK
) != PKCS_7_ASN_ENCODING
)
545 SetLastError(ERROR_FILE_NOT_FOUND
);
549 SetLastError(NOERROR
);
550 if (!HIWORD(lpszStructType
))
552 switch (LOWORD(lpszStructType
))
554 case (WORD
)X509_INTEGER
:
555 encodeFunc
= CRYPT_AsnEncodeInt
;
557 case (WORD
)X509_CHOICE_OF_TIME
:
558 encodeFunc
= CRYPT_AsnEncodeChoiceOfTime
;
560 case (WORD
)PKCS_UTC_TIME
:
561 encodeFunc
= CRYPT_AsnEncodeUtcTime
;
564 FIXME("%d: unimplemented\n", LOWORD(lpszStructType
));
567 else if (!strcmp(lpszStructType
, szOID_RSA_signingTime
))
568 encodeFunc
= CRYPT_AsnEncodeUtcTime
;
570 encodeFunc
= (CryptEncodeObjectExFunc
)CRYPT_GetFunc(dwCertEncodingType
,
571 lpszStructType
, "CryptEncodeObjectEx", &lib
);
573 ret
= encodeFunc(dwCertEncodingType
, lpszStructType
, pvStructInfo
,
574 dwFlags
, pEncodePara
, pbEncoded
, pcbEncoded
);
576 SetLastError(ERROR_FILE_NOT_FOUND
);
582 typedef BOOL (WINAPI
*CryptDecodeObjectFunc
)(DWORD
, LPCSTR
, const BYTE
*,
583 DWORD
, DWORD
, void *, DWORD
*);
585 BOOL WINAPI
CryptDecodeObject(DWORD dwCertEncodingType
, LPCSTR lpszStructType
,
586 const BYTE
*pbEncoded
, DWORD cbEncoded
, DWORD dwFlags
, void *pvStructInfo
,
587 DWORD
*pcbStructInfo
)
591 CryptDecodeObjectFunc pCryptDecodeObject
;
593 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p)\n",
594 dwCertEncodingType
, HIWORD(lpszStructType
) ? debugstr_a(lpszStructType
) :
595 "(integer value)", pbEncoded
, cbEncoded
, dwFlags
, pvStructInfo
,
598 if (!pvStructInfo
&& !pcbStructInfo
)
600 SetLastError(ERROR_INVALID_PARAMETER
);
604 /* Try registered DLL first.. */
606 (CryptDecodeObjectFunc
)CRYPT_GetFunc(dwCertEncodingType
,
607 lpszStructType
, "CryptDecodeObject", &lib
);
608 if (pCryptDecodeObject
)
610 ret
= pCryptDecodeObject(dwCertEncodingType
, lpszStructType
,
611 pbEncoded
, cbEncoded
, dwFlags
, pvStructInfo
, pcbStructInfo
);
616 /* If not, use CryptDecodeObjectEx */
617 ret
= CryptDecodeObjectEx(dwCertEncodingType
, lpszStructType
, pbEncoded
,
618 cbEncoded
, dwFlags
, NULL
, pvStructInfo
, pcbStructInfo
);
623 /* Helper function to check *pcbStructInfo, set it to the required size, and
624 * optionally to allocate memory. Assumes pvStructInfo is not NULL.
625 * If CRYPT_DECODE_ALLOC_FLAG is set in dwFlags, *pvStructInfo will be set to a
626 * pointer to the newly allocated memory.
628 static BOOL
CRYPT_DecodeEnsureSpace(DWORD dwFlags
,
629 PCRYPT_DECODE_PARA pDecodePara
, void *pvStructInfo
, DWORD
*pcbStructInfo
,
634 if (dwFlags
& CRYPT_DECODE_ALLOC_FLAG
)
636 if (pDecodePara
&& pDecodePara
->pfnAlloc
)
637 *(BYTE
**)pvStructInfo
= pDecodePara
->pfnAlloc(bytesNeeded
);
639 *(BYTE
**)pvStructInfo
= LocalAlloc(0, bytesNeeded
);
640 if (!*(BYTE
**)pvStructInfo
)
643 else if (*pcbStructInfo
< bytesNeeded
)
645 *pcbStructInfo
= bytesNeeded
;
646 SetLastError(ERROR_MORE_DATA
);
652 static BOOL WINAPI
CRYPT_AsnDecodeInt(DWORD dwCertEncodingType
,
653 LPCSTR lpszStructType
, const BYTE
*pbEncoded
, DWORD cbEncoded
, DWORD dwFlags
,
654 PCRYPT_DECODE_PARA pDecodePara
, void *pvStructInfo
, DWORD
*pcbStructInfo
)
658 if (!pbEncoded
|| !cbEncoded
)
660 SetLastError(ERROR_INVALID_PARAMETER
);
665 *pcbStructInfo
= sizeof(int);
668 if (pbEncoded
[0] != ASN_INTEGER
)
670 SetLastError(CRYPT_E_ASN1_BADTAG
);
673 if (pbEncoded
[1] == 0)
675 SetLastError(CRYPT_E_ASN1_CORRUPT
);
678 if (pbEncoded
[1] > sizeof(int))
680 SetLastError(CRYPT_E_ASN1_LARGE
);
683 if (pbEncoded
[2] & 0x80)
685 /* initialize to a negative value to sign-extend */
690 for (i
= 0; i
< pbEncoded
[1]; i
++)
693 val
|= pbEncoded
[2 + i
];
695 if (!CRYPT_DecodeEnsureSpace(dwFlags
, pDecodePara
, pvStructInfo
,
696 pcbStructInfo
, sizeof(int)))
698 if (dwFlags
& CRYPT_DECODE_ALLOC_FLAG
)
699 pvStructInfo
= *(BYTE
**)pvStructInfo
;
700 *pcbStructInfo
= sizeof(int);
701 memcpy(pvStructInfo
, &val
, sizeof(int));
705 #define CRYPT_TIME_GET_DIGITS(pbEncoded, len, numDigits, word) \
710 for (i = 0; (len) > 0 && i < (numDigits); i++, (len)--) \
712 if (!isdigit(*(pbEncoded))) \
714 SetLastError(CRYPT_E_ASN1_CORRUPT); \
718 (word) += *(pbEncoded)++ - '0'; \
722 static BOOL WINAPI
CRYPT_AsnDecodeUtcTime(DWORD dwCertEncodingType
,
723 LPCSTR lpszStructType
, const BYTE
*pbEncoded
, DWORD cbEncoded
, DWORD dwFlags
,
724 PCRYPT_DECODE_PARA pDecodePara
, void *pvStructInfo
, DWORD
*pcbStructInfo
)
726 SYSTEMTIME sysTime
= { 0 };
729 if (!pbEncoded
|| !cbEncoded
)
731 SetLastError(ERROR_INVALID_PARAMETER
);
736 *pcbStructInfo
= sizeof(FILETIME
);
739 if (pbEncoded
[0] != ASN_UTCTIME
)
741 SetLastError(CRYPT_E_ASN1_BADTAG
);
748 SetLastError(CRYPT_E_ASN1_CORRUPT
);
752 CRYPT_TIME_GET_DIGITS(pbEncoded
, len
, 2, sysTime
.wYear
);
753 if (sysTime
.wYear
>= 50)
754 sysTime
.wYear
+= 1900;
756 sysTime
.wYear
+= 2000;
757 CRYPT_TIME_GET_DIGITS(pbEncoded
, len
, 2, sysTime
.wMonth
);
758 CRYPT_TIME_GET_DIGITS(pbEncoded
, len
, 2, sysTime
.wDay
);
759 CRYPT_TIME_GET_DIGITS(pbEncoded
, len
, 2, sysTime
.wHour
);
760 CRYPT_TIME_GET_DIGITS(pbEncoded
, len
, 2, sysTime
.wMinute
);
763 if (len
>= 2 && isdigit(*pbEncoded
) && isdigit(*(pbEncoded
+ 1)))
764 CRYPT_TIME_GET_DIGITS(pbEncoded
, len
, 2, sysTime
.wSecond
);
765 else if (isdigit(*pbEncoded
))
766 CRYPT_TIME_GET_DIGITS(pbEncoded
, len
, 1, sysTime
.wSecond
);
769 /* FIXME: get timezone, for now assuming UTC (no adjustment) */
773 if (!CRYPT_DecodeEnsureSpace(dwFlags
, pDecodePara
, pvStructInfo
,
774 pcbStructInfo
, sizeof(FILETIME
)))
776 if (dwFlags
& CRYPT_DECODE_ALLOC_FLAG
)
777 pvStructInfo
= *(BYTE
**)pvStructInfo
;
778 *pcbStructInfo
= sizeof(FILETIME
);
779 return SystemTimeToFileTime(&sysTime
, (FILETIME
*)pvStructInfo
);
782 static BOOL WINAPI
CRYPT_AsnDecodeGeneralizedTime(DWORD dwCertEncodingType
,
783 LPCSTR lpszStructType
, const BYTE
*pbEncoded
, DWORD cbEncoded
, DWORD dwFlags
,
784 PCRYPT_DECODE_PARA pDecodePara
, void *pvStructInfo
, DWORD
*pcbStructInfo
)
786 SYSTEMTIME sysTime
= { 0 };
789 if (!pbEncoded
|| !cbEncoded
)
791 SetLastError(ERROR_INVALID_PARAMETER
);
796 *pcbStructInfo
= sizeof(FILETIME
);
799 if (pbEncoded
[0] != ASN_GENERALTIME
)
801 SetLastError(CRYPT_E_ASN1_BADTAG
);
808 SetLastError(CRYPT_E_ASN1_CORRUPT
);
812 CRYPT_TIME_GET_DIGITS(pbEncoded
, len
, 4, sysTime
.wYear
);
813 CRYPT_TIME_GET_DIGITS(pbEncoded
, len
, 2, sysTime
.wMonth
);
814 CRYPT_TIME_GET_DIGITS(pbEncoded
, len
, 2, sysTime
.wDay
);
815 CRYPT_TIME_GET_DIGITS(pbEncoded
, len
, 2, sysTime
.wHour
);
818 CRYPT_TIME_GET_DIGITS(pbEncoded
, len
, 2, sysTime
.wMinute
);
820 CRYPT_TIME_GET_DIGITS(pbEncoded
, len
, 2, sysTime
.wSecond
);
821 if (len
> 0 && (*pbEncoded
== '.' || *pbEncoded
== ','))
827 digits
= min(len
, 3); /* workaround macro weirdness */
828 CRYPT_TIME_GET_DIGITS(pbEncoded
, len
, digits
,
829 sysTime
.wMilliseconds
);
831 if (len
>= 5 && (*pbEncoded
== '+' || *pbEncoded
== '-'))
834 BYTE sign
= *pbEncoded
++;
837 CRYPT_TIME_GET_DIGITS(pbEncoded
, len
, 2, hours
);
839 return CRYPT_E_ASN1_CORRUPT
;
840 CRYPT_TIME_GET_DIGITS(pbEncoded
, len
, 2, minutes
);
842 return CRYPT_E_ASN1_CORRUPT
;
845 sysTime
.wHour
+= hours
;
846 sysTime
.wMinute
+= minutes
;
850 if (hours
> sysTime
.wHour
)
853 sysTime
.wHour
= 24 - (hours
- sysTime
.wHour
);
856 sysTime
.wHour
-= hours
;
857 if (minutes
> sysTime
.wMinute
)
860 sysTime
.wMinute
= 60 - (minutes
- sysTime
.wMinute
);
863 sysTime
.wMinute
-= minutes
;
868 if (!CRYPT_DecodeEnsureSpace(dwFlags
, pDecodePara
, pvStructInfo
,
869 pcbStructInfo
, sizeof(FILETIME
)))
871 if (dwFlags
& CRYPT_DECODE_ALLOC_FLAG
)
872 pvStructInfo
= *(BYTE
**)pvStructInfo
;
873 *pcbStructInfo
= sizeof(FILETIME
);
874 return SystemTimeToFileTime(&sysTime
, (FILETIME
*)pvStructInfo
);
877 static BOOL WINAPI
CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType
,
878 LPCSTR lpszStructType
, const BYTE
*pbEncoded
, DWORD cbEncoded
, DWORD dwFlags
,
879 PCRYPT_DECODE_PARA pDecodePara
, void *pvStructInfo
, DWORD
*pcbStructInfo
)
883 if (!pbEncoded
|| !cbEncoded
)
885 SetLastError(ERROR_INVALID_PARAMETER
);
890 *pcbStructInfo
= sizeof(FILETIME
);
894 if (pbEncoded
[0] == ASN_UTCTIME
)
895 ret
= CRYPT_AsnDecodeUtcTime(dwCertEncodingType
, lpszStructType
,
896 pbEncoded
, cbEncoded
, dwFlags
, pDecodePara
, pvStructInfo
,
898 else if (pbEncoded
[0] == ASN_GENERALTIME
)
899 ret
= CRYPT_AsnDecodeGeneralizedTime(dwCertEncodingType
,
900 lpszStructType
, pbEncoded
, cbEncoded
, dwFlags
, pDecodePara
,
901 pvStructInfo
, pcbStructInfo
);
904 SetLastError(CRYPT_E_ASN1_BADTAG
);
910 typedef BOOL (WINAPI
*CryptDecodeObjectExFunc
)(DWORD
, LPCSTR
, const BYTE
*,
911 DWORD
, DWORD
, PCRYPT_DECODE_PARA
, void *, DWORD
*);
913 BOOL WINAPI
CryptDecodeObjectEx(DWORD dwCertEncodingType
, LPCSTR lpszStructType
,
914 const BYTE
*pbEncoded
, DWORD cbEncoded
, DWORD dwFlags
,
915 PCRYPT_DECODE_PARA pDecodePara
, void *pvStructInfo
, DWORD
*pcbStructInfo
)
919 CryptDecodeObjectExFunc decodeFunc
= NULL
;
921 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p, %p): semi-stub\n",
922 dwCertEncodingType
, HIWORD(lpszStructType
) ? debugstr_a(lpszStructType
) :
923 "(integer value)", pbEncoded
, cbEncoded
, dwFlags
, pDecodePara
,
924 pvStructInfo
, pcbStructInfo
);
926 if (!pvStructInfo
&& !pcbStructInfo
)
928 SetLastError(ERROR_INVALID_PARAMETER
);
931 if ((dwCertEncodingType
& CERT_ENCODING_TYPE_MASK
) != X509_ASN_ENCODING
932 && (dwCertEncodingType
& CMSG_ENCODING_TYPE_MASK
) != PKCS_7_ASN_ENCODING
)
934 SetLastError(ERROR_FILE_NOT_FOUND
);
938 SetLastError(NOERROR
);
939 if (!HIWORD(lpszStructType
))
941 switch (LOWORD(lpszStructType
))
943 case (WORD
)X509_INTEGER
:
944 decodeFunc
= CRYPT_AsnDecodeInt
;
946 case (WORD
)X509_CHOICE_OF_TIME
:
947 decodeFunc
= CRYPT_AsnDecodeChoiceOfTime
;
949 case (WORD
)PKCS_UTC_TIME
:
950 decodeFunc
= CRYPT_AsnDecodeUtcTime
;
953 FIXME("%d: unimplemented\n", LOWORD(lpszStructType
));
956 else if (!strcmp(lpszStructType
, szOID_RSA_signingTime
))
957 decodeFunc
= CRYPT_AsnDecodeUtcTime
;
959 decodeFunc
= (CryptDecodeObjectExFunc
)CRYPT_GetFunc(dwCertEncodingType
,
960 lpszStructType
, "CryptDecodeObjectEx", &lib
);
962 ret
= decodeFunc(dwCertEncodingType
, lpszStructType
, pbEncoded
,
963 cbEncoded
, dwFlags
, pDecodePara
, pvStructInfo
, pcbStructInfo
);
965 SetLastError(ERROR_FILE_NOT_FOUND
);