Sweden-Number/dlls/crypt32/encode.c

606 lines
18 KiB
C

/*
* Copyright 2002 Mike McCormack for CodeWeavers
* Copyright 2005 Juan Lang
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdarg.h>
#include <stdio.h>
#include "windef.h"
#include "winbase.h"
#include "wincrypt.h"
#include "winreg.h"
#include "snmp.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(crypt);
static const WCHAR szDllName[] = { 'D','l','l',0 };
static char *CRYPT_GetKeyName(DWORD dwEncodingType, LPCSTR pszFuncName,
LPCSTR pszOID)
{
static const char szEncodingTypeFmt[] =
"Software\\Microsoft\\Cryptography\\OID\\EncodingType %ld\\%s\\%s";
UINT len;
char numericOID[7]; /* enough for "#65535" */
const char *oid;
LPSTR szKey;
/* MSDN says the encoding type is a mask, but it isn't treated that way.
* (E.g., if dwEncodingType were 3, the key names "EncodingType 1" and
* "EncodingType 2" would be expected if it were a mask. Instead native
* stores values in "EncodingType 3".
*/
if (!HIWORD(pszOID))
{
snprintf(numericOID, sizeof(numericOID), "#%d", (int)pszOID);
oid = numericOID;
}
else
oid = pszOID;
/* This is enough: the lengths of the two string parameters are explicitly
* counted, and we need up to five additional characters for the encoding
* type. These are covered by the "%d", "%s", and "%s" characters in the
* format specifier that are removed by sprintf.
*/
len = sizeof(szEncodingTypeFmt) + lstrlenA(pszFuncName) + lstrlenA(oid);
szKey = HeapAlloc(GetProcessHeap(), 0, len);
if (szKey)
sprintf(szKey, szEncodingTypeFmt, dwEncodingType, pszFuncName, oid);
return szKey;
}
BOOL WINAPI CryptRegisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
LPCSTR pszOID, LPCWSTR pwszDll, LPCSTR pszOverrideFuncName)
{
LONG r;
HKEY hKey;
LPSTR szKey;
TRACE("%lx %s %s %s %s\n", dwEncodingType, pszFuncName, pszOID,
debugstr_w(pwszDll), pszOverrideFuncName);
/* This only registers functions for encoding certs, not messages */
if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
return TRUE;
/* Native does nothing pwszDll is NULL */
if (!pwszDll)
return TRUE;
/* I'm not matching MS bug for bug here, because I doubt any app depends on
* it:
* - native "succeeds" if pszFuncName is NULL, but the nonsensical entry
* it creates would never be used
* - native returns an HRESULT rather than a Win32 error if pszOID is NULL.
* Instead I disallow both of these with ERROR_INVALID_PARAMETER.
*/
if (!pszFuncName || !pszOID)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
TRACE("Key name is %s\n", debugstr_a(szKey));
if (!szKey)
return FALSE;
r = RegCreateKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
HeapFree(GetProcessHeap(), 0, szKey);
if(r != ERROR_SUCCESS)
return FALSE;
/* write the values */
if (pszOverrideFuncName)
RegSetValueExA(hKey, "FuncName", 0, REG_SZ, pszOverrideFuncName,
lstrlenA(pszOverrideFuncName) + 1);
RegSetValueExW(hKey, szDllName, 0, REG_SZ, (const BYTE*) pwszDll,
(lstrlenW(pwszDll) + 1) * sizeof (WCHAR));
RegCloseKey(hKey);
return TRUE;
}
BOOL WINAPI CryptUnregisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
LPCSTR pszOID)
{
LPSTR szKey;
LONG rc;
TRACE("%lx %s %s\n", dwEncodingType, pszFuncName, pszOID);
if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
return TRUE;
if (!pszFuncName || !pszOID)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
rc = RegDeleteKeyA(HKEY_LOCAL_MACHINE, szKey);
HeapFree(GetProcessHeap(), 0, szKey);
if (rc)
SetLastError(rc);
return rc ? FALSE : TRUE;
}
BOOL WINAPI CryptGetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
LPCSTR pszOID, LPCWSTR pwszValueName, DWORD *pdwValueType, BYTE *pbValueData,
DWORD *pcbValueData)
{
LPSTR szKey;
LONG rc;
HKEY hKey;
TRACE("%lx %s %s %s %p %p %p\n", dwEncodingType, debugstr_a(pszFuncName),
debugstr_a(pszOID), debugstr_w(pwszValueName), pdwValueType, pbValueData,
pcbValueData);
if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
return TRUE;
if (!pszFuncName || !pszOID || !pwszValueName)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
HeapFree(GetProcessHeap(), 0, szKey);
if (rc)
SetLastError(rc);
else
{
rc = RegQueryValueExW(hKey, pwszValueName, NULL, pdwValueType,
pbValueData, pcbValueData);
if (rc)
SetLastError(rc);
RegCloseKey(hKey);
}
return rc ? FALSE : TRUE;
}
BOOL WINAPI CryptSetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
LPCSTR pszOID, LPCWSTR pwszValueName, DWORD dwValueType,
const BYTE *pbValueData, DWORD cbValueData)
{
LPSTR szKey;
LONG rc;
HKEY hKey;
TRACE("%lx %s %s %s %ld %p %ld\n", dwEncodingType, debugstr_a(pszFuncName),
debugstr_a(pszOID), debugstr_w(pwszValueName), dwValueType, pbValueData,
cbValueData);
if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
return TRUE;
if (!pszFuncName || !pszOID || !pwszValueName)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
HeapFree(GetProcessHeap(), 0, szKey);
if (rc)
SetLastError(rc);
else
{
rc = RegSetValueExW(hKey, pwszValueName, 0, dwValueType, pbValueData,
cbValueData);
if (rc)
SetLastError(rc);
RegCloseKey(hKey);
}
return rc ? FALSE : TRUE;
}
/* Gets the registered function named szFuncName for dwCertEncodingType and
* lpszStructType, or NULL if one could not be found. *lib will be set to the
* handle of the module it's in, or NULL if no module was loaded. If the
* return value is NULL, *lib will also be NULL, to simplify error handling.
*/
static void *CRYPT_GetFunc(DWORD dwCertEncodingType, LPCSTR lpszStructType,
LPCSTR szFuncName, HMODULE *lib)
{
void *ret = NULL;
char *szKey = CRYPT_GetKeyName(dwCertEncodingType, szFuncName,
lpszStructType);
const char *funcName;
long r;
HKEY hKey;
DWORD type, size = 0;
*lib = NULL;
r = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
HeapFree(GetProcessHeap(), 0, szKey);
if(r != ERROR_SUCCESS)
return NULL;
RegQueryValueExA(hKey, "FuncName", NULL, &type, NULL, &size);
if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
{
funcName = HeapAlloc(GetProcessHeap(), 0, size);
RegQueryValueExA(hKey, "FuncName", NULL, &type, (LPBYTE)funcName,
&size);
}
else
funcName = szFuncName;
RegQueryValueExW(hKey, szDllName, NULL, &type, NULL, &size);
if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
{
LPWSTR dllName = HeapAlloc(GetProcessHeap(), 0, size);
RegQueryValueExW(hKey, szDllName, NULL, &type, (LPBYTE)dllName,
&size);
*lib = LoadLibraryW(dllName);
if (*lib)
{
ret = GetProcAddress(*lib, funcName);
if (!ret)
{
/* Unload the library, the caller doesn't want to unload it
* when the return value is NULL.
*/
FreeLibrary(*lib);
*lib = NULL;
}
}
HeapFree(GetProcessHeap(), 0, dllName);
}
if (funcName != szFuncName)
HeapFree(GetProcessHeap(), 0, (char *)funcName);
return ret;
}
typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
BYTE *, DWORD *);
BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
{
BOOL ret = FALSE;
HMODULE lib;
CryptEncodeObjectFunc pCryptEncodeObject;
TRACE("(0x%08lx, %s, %p, %p, %p)\n",
dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
"(integer value)", pvStructInfo, pbEncoded, pcbEncoded);
if (!pbEncoded && !pcbEncoded)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
/* Try registered DLL first.. */
pCryptEncodeObject =
(CryptEncodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
lpszStructType, "CryptEncodeObject", &lib);
if (pCryptEncodeObject)
{
ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
pvStructInfo, pbEncoded, pcbEncoded);
FreeLibrary(lib);
}
else
{
/* If not, use CryptEncodeObjectEx */
ret = CryptEncodeObjectEx(dwCertEncodingType, lpszStructType,
pvStructInfo, 0, NULL, pbEncoded, pcbEncoded);
}
return ret;
}
static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
{
INT val, i;
BYTE significantBytes, padByte = 0, bytesNeeded;
BOOL neg = FALSE, pad = FALSE;
if (!pvStructInfo)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
memcpy(&val, pvStructInfo, sizeof(val));
/* Count the number of significant bytes. Temporarily swap sign for
* negatives so I count the minimum number of bytes.
*/
if (val < 0)
{
neg = TRUE;
val = -val;
}
for (significantBytes = sizeof(val); !(val & 0xff000000);
val <<= 8, significantBytes--)
;
if (neg)
{
val = -val;
if ((val & 0xff000000) < 0x80000000)
{
padByte = 0xff;
pad = TRUE;
}
}
else if ((val & 0xff000000) > 0x7f000000)
{
padByte = 0;
pad = TRUE;
}
bytesNeeded = 2 + significantBytes;
if (pad)
bytesNeeded++;
if (!pbEncoded || bytesNeeded > *pcbEncoded)
{
*pcbEncoded = bytesNeeded;
SetLastError(ERROR_MORE_DATA);
return FALSE;
}
if (!pbEncoded)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
{
if (pEncodePara && pEncodePara->pfnAlloc)
*(BYTE **)pbEncoded = pEncodePara->pfnAlloc(bytesNeeded);
else
*(BYTE **)pbEncoded = LocalAlloc(0, bytesNeeded);
if (!*(BYTE **)pbEncoded)
return FALSE;
pbEncoded = *(BYTE **)pbEncoded;
}
*pbEncoded++ = ASN_INTEGER;
if (pad)
{
*pbEncoded++ = significantBytes + 1;
*pbEncoded++ = padByte;
}
else
*pbEncoded++ = significantBytes;
for (i = 0; i < significantBytes; i++, val <<= 8)
*(pbEncoded + i) = (BYTE)((val & 0xff000000) >> 24);
return TRUE;
}
typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *,
DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *);
BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
BYTE *pbEncoded, DWORD *pcbEncoded)
{
BOOL ret = FALSE;
HMODULE lib = NULL;
CryptEncodeObjectExFunc encodeFunc = NULL;
TRACE("(0x%08lx, %s, %p, 0x%08lx, %p, %p, %p): semi-stub\n",
dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
"(integer value)", pvStructInfo, dwFlags, pEncodePara, pbEncoded,
pcbEncoded);
if (!pbEncoded && !pcbEncoded)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (!HIWORD(lpszStructType))
{
if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) == X509_ASN_ENCODING
|| (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) ==
PKCS_7_ASN_ENCODING)
{
switch (LOWORD(lpszStructType))
{
case (WORD)X509_INTEGER:
encodeFunc = CRYPT_AsnEncodeInt;
break;
default:
FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
}
}
}
if (!encodeFunc)
encodeFunc = (CryptEncodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
lpszStructType, "CryptEncodeObjectEx", &lib);
if (encodeFunc)
ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
dwFlags, pEncodePara, pbEncoded, pcbEncoded);
else
SetLastError(ERROR_FILE_NOT_FOUND);
if (lib)
FreeLibrary(lib);
return ret;
}
typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
DWORD, DWORD, void *, DWORD *);
BOOL WINAPI CryptDecodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo,
DWORD *pcbStructInfo)
{
BOOL ret = FALSE;
HMODULE lib;
CryptDecodeObjectFunc pCryptDecodeObject;
TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p)\n",
dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
"(integer value)", pbEncoded, cbEncoded, dwFlags, pvStructInfo,
pcbStructInfo);
if (!pvStructInfo && !pcbStructInfo)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
/* Try registered DLL first.. */
pCryptDecodeObject =
(CryptDecodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
lpszStructType, "CryptDecodeObject", &lib);
if (pCryptDecodeObject)
{
ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType,
pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
FreeLibrary(lib);
}
else
{
/* If not, use CryptDecodeObjectEx */
ret = CryptDecodeObjectEx(dwCertEncodingType, lpszStructType, pbEncoded,
cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo);
}
return ret;
}
static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
{
int val, i;
BOOL ret;
if (!pbEncoded || !cbEncoded)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (!pvStructInfo)
{
*pcbStructInfo = sizeof(int);
SetLastError(ERROR_MORE_DATA);
return FALSE;
}
if (pbEncoded[0] != ASN_INTEGER)
{
SetLastError(CRYPT_E_ASN1_BADTAG);
return FALSE;
}
if (pbEncoded[1] == 0)
{
SetLastError(CRYPT_E_ASN1_CORRUPT);
return FALSE;
}
if (pbEncoded[1] > sizeof(int))
{
SetLastError(CRYPT_E_ASN1_LARGE);
return FALSE;
}
if (pbEncoded[2] & 0x80)
{
/* initialize to a negative value to sign-extend */
val = -1;
}
else
val = 0;
for (i = 0; i < pbEncoded[1]; i++)
{
val <<= 8;
val |= pbEncoded[2 + i];
}
if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
{
if (pDecodePara && pDecodePara->pfnAlloc)
*(BYTE **)pvStructInfo = pDecodePara->pfnAlloc(sizeof(int));
else
*(BYTE **)pvStructInfo = LocalAlloc(0, sizeof(int));
if (!*(BYTE **)pvStructInfo)
return FALSE;
memcpy(*(BYTE **)pvStructInfo, &val, sizeof(int));
ret = TRUE;
}
else if (*pcbStructInfo < sizeof(int))
{
*pcbStructInfo = sizeof(int);
SetLastError(ERROR_MORE_DATA);
ret = FALSE;
}
else
{
*pcbStructInfo = sizeof(int);
memcpy(pvStructInfo, &val, sizeof(int));
ret = TRUE;
}
return ret;
}
typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *,
DWORD, DWORD, PCRYPT_DECODE_PARA, void *, DWORD *);
BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
{
BOOL ret = FALSE;
HMODULE lib = NULL;
CryptDecodeObjectExFunc decodeFunc = NULL;
TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p, %p): semi-stub\n",
dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
"(integer value)", pbEncoded, cbEncoded, dwFlags, pDecodePara,
pvStructInfo, pcbStructInfo);
if (!pvStructInfo && !pcbStructInfo)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (!HIWORD(lpszStructType))
{
if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) == X509_ASN_ENCODING
|| (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) ==
PKCS_7_ASN_ENCODING)
{
switch (LOWORD(lpszStructType))
{
case (WORD)X509_INTEGER:
decodeFunc = CRYPT_AsnDecodeInt;
break;
default:
FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
}
}
}
if (!decodeFunc)
decodeFunc = (CryptDecodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
lpszStructType, "CryptDecodeObjectEx", &lib);
if (decodeFunc)
ret = decodeFunc(dwCertEncodingType, lpszStructType, pbEncoded,
cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
else
SetLastError(ERROR_FILE_NOT_FOUND);
if (lib)
FreeLibrary(lib);
return ret;
}