crypt32: Implement CryptStrToNameA/W, with tests.
This commit is contained in:
parent
8ccbdb801e
commit
3882b4f66a
|
@ -80,8 +80,8 @@
|
||||||
@ stdcall CertSetCTLContextProperty(ptr long long ptr)
|
@ stdcall CertSetCTLContextProperty(ptr long long ptr)
|
||||||
@ stdcall CertSetCertificateContextProperty(ptr long long ptr)
|
@ stdcall CertSetCertificateContextProperty(ptr long long ptr)
|
||||||
@ stdcall CertSetEnhancedKeyUsage(ptr ptr)
|
@ stdcall CertSetEnhancedKeyUsage(ptr ptr)
|
||||||
@ stub CertStrToNameA
|
@ stdcall CertStrToNameA(long str long ptr ptr ptr ptr)
|
||||||
@ stub CertStrToNameW
|
@ stdcall CertStrToNameW(long wstr long ptr ptr ptr ptr)
|
||||||
@ stdcall CertVerifyCRLRevocation(long ptr long ptr)
|
@ stdcall CertVerifyCRLRevocation(long ptr long ptr)
|
||||||
@ stdcall CertVerifyCRLTimeValidity(ptr ptr)
|
@ stdcall CertVerifyCRLTimeValidity(ptr ptr)
|
||||||
@ stub CertVerifyCTLUsage
|
@ stub CertVerifyCTLUsage
|
||||||
|
|
|
@ -19,8 +19,10 @@
|
||||||
#include "windef.h"
|
#include "windef.h"
|
||||||
#include "winbase.h"
|
#include "winbase.h"
|
||||||
#include "winnls.h"
|
#include "winnls.h"
|
||||||
|
#include "winuser.h"
|
||||||
#include "wincrypt.h"
|
#include "wincrypt.h"
|
||||||
#include "wine/debug.h"
|
#include "wine/debug.h"
|
||||||
|
#include "wine/unicode.h"
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(crypt);
|
WINE_DEFAULT_DEBUG_CHANNEL(crypt);
|
||||||
|
|
||||||
|
@ -408,6 +410,377 @@ DWORD WINAPI CertNameToStrW(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOL WINAPI CertStrToNameA(DWORD dwCertEncodingType, LPCSTR pszX500,
|
||||||
|
DWORD dwStrType, void *pvReserved, BYTE *pbEncoded, DWORD *pcbEncoded,
|
||||||
|
LPCSTR *ppszError)
|
||||||
|
{
|
||||||
|
LPWSTR x500, errorStr;
|
||||||
|
BOOL ret;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
TRACE("(%08lx, %s, %08lx, %p, %p, %p, %p)\n", dwCertEncodingType,
|
||||||
|
debugstr_a(pszX500), dwStrType, pvReserved, pbEncoded, pcbEncoded,
|
||||||
|
ppszError);
|
||||||
|
|
||||||
|
len = MultiByteToWideChar(CP_ACP, 0, pszX500, -1, NULL, 0);
|
||||||
|
x500 = CryptMemAlloc(len * sizeof(WCHAR));
|
||||||
|
if (x500)
|
||||||
|
{
|
||||||
|
MultiByteToWideChar(CP_ACP, 0, pszX500, -1, x500, len);
|
||||||
|
ret = CertStrToNameW(dwCertEncodingType, x500, dwStrType, pvReserved,
|
||||||
|
pbEncoded, pcbEncoded, ppszError ? (LPCWSTR *)&errorStr : NULL);
|
||||||
|
if (ppszError)
|
||||||
|
{
|
||||||
|
DWORD i;
|
||||||
|
|
||||||
|
*ppszError = pszX500;
|
||||||
|
for (i = 0; i < errorStr - x500; i++)
|
||||||
|
CharNextA(*ppszError);
|
||||||
|
}
|
||||||
|
CryptMemFree(x500);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ret = FALSE;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct KeynameKeeper
|
||||||
|
{
|
||||||
|
WCHAR buf[10]; /* big enough for L"GivenName" */
|
||||||
|
LPWSTR keyName; /* usually = buf, but may be allocated */
|
||||||
|
DWORD keyLen;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void CRYPT_InitializeKeynameKeeper(struct KeynameKeeper *keeper)
|
||||||
|
{
|
||||||
|
keeper->keyName = keeper->buf;
|
||||||
|
keeper->keyLen = sizeof(keeper->buf) / sizeof(keeper->buf[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CRYPT_FreeKeynameKeeper(struct KeynameKeeper *keeper)
|
||||||
|
{
|
||||||
|
if (keeper->keyName != keeper->buf)
|
||||||
|
CryptMemFree(keeper->keyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct X500TokenW
|
||||||
|
{
|
||||||
|
LPCWSTR start;
|
||||||
|
LPCWSTR end;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void CRYPT_KeynameKeeperFromTokenW(struct KeynameKeeper *keeper,
|
||||||
|
struct X500TokenW *key)
|
||||||
|
{
|
||||||
|
DWORD len = key->end - key->start;
|
||||||
|
|
||||||
|
if (len > keeper->keyLen)
|
||||||
|
{
|
||||||
|
if (keeper->keyName == keeper->buf)
|
||||||
|
keeper->keyName = CryptMemAlloc(len * sizeof(WCHAR));
|
||||||
|
else
|
||||||
|
keeper->keyName = CryptMemRealloc(keeper->keyName,
|
||||||
|
len * sizeof(WCHAR));
|
||||||
|
keeper->keyLen = len;
|
||||||
|
}
|
||||||
|
memcpy(keeper->keyName, key->start, (key->end - key->start) *
|
||||||
|
sizeof(WCHAR));
|
||||||
|
keeper->keyName[len] = '\0';
|
||||||
|
TRACE("Keyname is %s\n", debugstr_w(keeper->keyName));
|
||||||
|
}
|
||||||
|
|
||||||
|
static DWORD CRYPT_GetNextKeyW(LPCWSTR str, struct X500TokenW *token,
|
||||||
|
LPCWSTR *ppszError)
|
||||||
|
{
|
||||||
|
DWORD ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
while (*str && isspaceW(*str))
|
||||||
|
str++;
|
||||||
|
if (*str)
|
||||||
|
{
|
||||||
|
token->start = str;
|
||||||
|
while (*str && *str != '=' && !isspaceW(*str))
|
||||||
|
str++;
|
||||||
|
if (*str && (*str == '=' || isspaceW(*str)))
|
||||||
|
token->end = str;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TRACE("missing equals char at %s\n", debugstr_w(token->start));
|
||||||
|
if (ppszError)
|
||||||
|
*ppszError = token->start;
|
||||||
|
ret = CRYPT_E_INVALID_X500_STRING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
token->start = NULL;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assumes separators are characters in the 0-255 range */
|
||||||
|
static DWORD CRYPT_GetNextValueW(LPCWSTR str, DWORD dwFlags, LPCWSTR separators,
|
||||||
|
struct X500TokenW *token, LPCWSTR *ppszError)
|
||||||
|
{
|
||||||
|
DWORD ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
TRACE("(%s, %s, %p, %p)\n", debugstr_w(str), debugstr_w(separators), token,
|
||||||
|
ppszError);
|
||||||
|
|
||||||
|
while (*str && isspaceW(*str))
|
||||||
|
str++;
|
||||||
|
if (*str)
|
||||||
|
{
|
||||||
|
token->start = str;
|
||||||
|
if (!(dwFlags & CERT_NAME_STR_NO_QUOTING_FLAG) && *str == '"')
|
||||||
|
{
|
||||||
|
token->end = NULL;
|
||||||
|
str++;
|
||||||
|
while (!token->end && !ret)
|
||||||
|
{
|
||||||
|
while (*str && *str != '"')
|
||||||
|
str++;
|
||||||
|
if (*str == '"')
|
||||||
|
{
|
||||||
|
if (*(str + 1) != '"')
|
||||||
|
token->end = str + 1;
|
||||||
|
else
|
||||||
|
str += 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TRACE("unterminated quote at %s\n", debugstr_w(str));
|
||||||
|
if (ppszError)
|
||||||
|
*ppszError = str;
|
||||||
|
ret = CRYPT_E_INVALID_X500_STRING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WCHAR map[256] = { 0 };
|
||||||
|
|
||||||
|
while (*separators)
|
||||||
|
map[*separators++] = 1;
|
||||||
|
while (*str && (*str >= 0xff || !map[*(unsigned short *)str]))
|
||||||
|
str++;
|
||||||
|
token->end = str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TRACE("missing value at %s\n", debugstr_w(str));
|
||||||
|
if (ppszError)
|
||||||
|
*ppszError = str;
|
||||||
|
ret = CRYPT_E_INVALID_X500_STRING;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Encodes the string represented by value as the string type type into the
|
||||||
|
* CERT_NAME_BLOB output. If there is an error and ppszError is not NULL,
|
||||||
|
* *ppszError is set to the first failing character. If there is no error,
|
||||||
|
* output's pbData must be freed with LocalFree.
|
||||||
|
*/
|
||||||
|
static BOOL CRYPT_EncodeValueWithType(DWORD dwCertEncodingType,
|
||||||
|
struct X500TokenW *value, PCERT_NAME_BLOB output, DWORD type,
|
||||||
|
LPCWSTR *ppszError)
|
||||||
|
{
|
||||||
|
CERT_NAME_VALUE nameValue = { type, { 0, NULL } };
|
||||||
|
BOOL ret = FALSE;
|
||||||
|
|
||||||
|
nameValue.Value.pbData = CryptMemAlloc((value->end - value->start) *
|
||||||
|
sizeof(WCHAR));
|
||||||
|
if (nameValue.Value.pbData)
|
||||||
|
{
|
||||||
|
DWORD i;
|
||||||
|
LPWSTR ptr = (LPWSTR)nameValue.Value.pbData;
|
||||||
|
|
||||||
|
for (i = 0; i < value->end - value->start; i++)
|
||||||
|
{
|
||||||
|
*ptr++ = value->start[i];
|
||||||
|
if (value->start[i] == '"')
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
nameValue.Value.cbData = (LPBYTE)ptr - nameValue.Value.pbData;
|
||||||
|
ret = CryptEncodeObjectEx(dwCertEncodingType, X509_UNICODE_NAME_VALUE,
|
||||||
|
&nameValue, CRYPT_ENCODE_ALLOC_FLAG, NULL, &output->pbData,
|
||||||
|
&output->cbData);
|
||||||
|
if (!ret && ppszError)
|
||||||
|
{
|
||||||
|
if (type == CERT_RDN_NUMERIC_STRING &&
|
||||||
|
GetLastError() == CRYPT_E_INVALID_NUMERIC_STRING)
|
||||||
|
*ppszError = value->start + output->cbData;
|
||||||
|
else if (type == CERT_RDN_PRINTABLE_STRING &&
|
||||||
|
GetLastError() == CRYPT_E_INVALID_PRINTABLE_STRING)
|
||||||
|
*ppszError = value->start + output->cbData;
|
||||||
|
else if (type == CERT_RDN_IA5_STRING &&
|
||||||
|
GetLastError() == CRYPT_E_INVALID_IA5_STRING)
|
||||||
|
*ppszError = value->start + output->cbData;
|
||||||
|
}
|
||||||
|
CryptMemFree(nameValue.Value.pbData);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL CRYPT_EncodeValue(DWORD dwCertEncodingType,
|
||||||
|
struct X500TokenW *value, PCERT_NAME_BLOB output, const DWORD *types,
|
||||||
|
LPCWSTR *ppszError)
|
||||||
|
{
|
||||||
|
DWORD i;
|
||||||
|
BOOL ret;
|
||||||
|
|
||||||
|
ret = FALSE;
|
||||||
|
for (i = 0; !ret && types[i]; i++)
|
||||||
|
ret = CRYPT_EncodeValueWithType(dwCertEncodingType, value, output,
|
||||||
|
types[i], ppszError);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL CRYPT_ValueToRDN(DWORD dwCertEncodingType, PCERT_NAME_INFO info,
|
||||||
|
PCCRYPT_OID_INFO keyOID, struct X500TokenW *value, LPCWSTR *ppszError)
|
||||||
|
{
|
||||||
|
BOOL ret = FALSE;
|
||||||
|
|
||||||
|
TRACE("OID %s, value %s\n", debugstr_a(keyOID->pszOID),
|
||||||
|
debugstr_wn(value->start, value->end - value->start));
|
||||||
|
|
||||||
|
if (!info->rgRDN)
|
||||||
|
info->rgRDN = CryptMemAlloc(sizeof(CERT_RDN));
|
||||||
|
else
|
||||||
|
info->rgRDN = CryptMemRealloc(info->rgRDN,
|
||||||
|
(info->cRDN + 1) * sizeof(CERT_RDN));
|
||||||
|
if (info->rgRDN)
|
||||||
|
{
|
||||||
|
/* FIXME: support multiple RDN attrs */
|
||||||
|
info->rgRDN[info->cRDN].rgRDNAttr =
|
||||||
|
CryptMemAlloc(sizeof(CERT_RDN_ATTR));
|
||||||
|
if (info->rgRDN[info->cRDN].rgRDNAttr)
|
||||||
|
{
|
||||||
|
static const DWORD defaultTypes[] = { CERT_RDN_PRINTABLE_STRING,
|
||||||
|
CERT_RDN_BMP_STRING, 0 };
|
||||||
|
const DWORD *types;
|
||||||
|
|
||||||
|
info->rgRDN[info->cRDN].cRDNAttr = 1;
|
||||||
|
info->rgRDN[info->cRDN].rgRDNAttr[0].pszObjId =
|
||||||
|
(LPSTR)keyOID->pszOID;
|
||||||
|
info->rgRDN[info->cRDN].rgRDNAttr[0].dwValueType =
|
||||||
|
CERT_RDN_ENCODED_BLOB;
|
||||||
|
if (keyOID->ExtraInfo.cbData)
|
||||||
|
types = (const DWORD *)keyOID->ExtraInfo.pbData;
|
||||||
|
else
|
||||||
|
types = defaultTypes;
|
||||||
|
|
||||||
|
/* Remove surrounding quotes */
|
||||||
|
if (value->start[0] == '"')
|
||||||
|
{
|
||||||
|
value->start++;
|
||||||
|
value->end--;
|
||||||
|
}
|
||||||
|
ret = CRYPT_EncodeValue(dwCertEncodingType, value,
|
||||||
|
&info->rgRDN[info->cRDN].rgRDNAttr[0].Value, types, ppszError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ret)
|
||||||
|
info->cRDN++;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL WINAPI CertStrToNameW(DWORD dwCertEncodingType, LPCWSTR pszX500,
|
||||||
|
DWORD dwStrType, void *pvReserved, BYTE *pbEncoded, DWORD *pcbEncoded,
|
||||||
|
LPCWSTR *ppszError)
|
||||||
|
{
|
||||||
|
CERT_NAME_INFO info = { 0, NULL };
|
||||||
|
LPCWSTR str;
|
||||||
|
struct KeynameKeeper keeper;
|
||||||
|
DWORD i, error = ERROR_SUCCESS;
|
||||||
|
BOOL ret = TRUE;
|
||||||
|
|
||||||
|
TRACE("(%08lx, %s, %08lx, %p, %p, %p, %p)\n", dwCertEncodingType,
|
||||||
|
debugstr_w(pszX500), dwStrType, pvReserved, pbEncoded, pcbEncoded,
|
||||||
|
ppszError);
|
||||||
|
|
||||||
|
CRYPT_InitializeKeynameKeeper(&keeper);
|
||||||
|
str = pszX500;
|
||||||
|
while (str && *str && !error && ret)
|
||||||
|
{
|
||||||
|
struct X500TokenW token;
|
||||||
|
|
||||||
|
error = CRYPT_GetNextKeyW(str, &token, ppszError);
|
||||||
|
if (!error && token.start)
|
||||||
|
{
|
||||||
|
PCCRYPT_OID_INFO keyOID;
|
||||||
|
|
||||||
|
CRYPT_KeynameKeeperFromTokenW(&keeper, &token);
|
||||||
|
keyOID = CryptFindOIDInfo(CRYPT_OID_INFO_NAME_KEY, keeper.keyName,
|
||||||
|
CRYPT_RDN_ATTR_OID_GROUP_ID);
|
||||||
|
if (!keyOID)
|
||||||
|
{
|
||||||
|
if (ppszError)
|
||||||
|
*ppszError = token.start;
|
||||||
|
error = CRYPT_E_INVALID_X500_STRING;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
str = token.end;
|
||||||
|
while (isspace(*str))
|
||||||
|
str++;
|
||||||
|
if (*str != '=')
|
||||||
|
{
|
||||||
|
if (ppszError)
|
||||||
|
*ppszError = str;
|
||||||
|
error = CRYPT_E_INVALID_X500_STRING;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
static const WCHAR commaSep[] = { ',',0 };
|
||||||
|
static const WCHAR semiSep[] = { ';',0 };
|
||||||
|
static const WCHAR crlfSep[] = { '\r','\n',0 };
|
||||||
|
static const WCHAR allSeps[] = { ',',';','\r','\n',0 };
|
||||||
|
LPCWSTR sep;
|
||||||
|
|
||||||
|
str++;
|
||||||
|
if (dwStrType & CERT_NAME_STR_COMMA_FLAG)
|
||||||
|
sep = commaSep;
|
||||||
|
else if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG)
|
||||||
|
sep = semiSep;
|
||||||
|
else if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
|
||||||
|
sep = crlfSep;
|
||||||
|
else
|
||||||
|
sep = allSeps;
|
||||||
|
error = CRYPT_GetNextValueW(str, dwStrType, sep, &token,
|
||||||
|
ppszError);
|
||||||
|
if (!error)
|
||||||
|
{
|
||||||
|
str = token.end;
|
||||||
|
ret = CRYPT_ValueToRDN(dwCertEncodingType, &info,
|
||||||
|
keyOID, &token, ppszError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CRYPT_FreeKeynameKeeper(&keeper);
|
||||||
|
if (!error)
|
||||||
|
{
|
||||||
|
ret = CryptEncodeObjectEx(dwCertEncodingType, X509_NAME, &info,
|
||||||
|
0, NULL, pbEncoded, pcbEncoded);
|
||||||
|
for (i = 0; i < info.cRDN; i++)
|
||||||
|
{
|
||||||
|
DWORD j;
|
||||||
|
|
||||||
|
for (j = 0; j < info.rgRDN[i].cRDNAttr; j++)
|
||||||
|
LocalFree(info.rgRDN[i].rgRDNAttr[j].Value.pbData);
|
||||||
|
CryptMemFree(info.rgRDN[i].rgRDNAttr);
|
||||||
|
}
|
||||||
|
CryptMemFree(info.rgRDN);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetLastError(error);
|
||||||
|
ret = FALSE;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
DWORD WINAPI CertGetNameStringA(PCCERT_CONTEXT pCertContext, DWORD dwType,
|
DWORD WINAPI CertGetNameStringA(PCCERT_CONTEXT pCertContext, DWORD dwType,
|
||||||
DWORD dwFlags, void *pvTypePara, LPSTR pszNameString, DWORD cchNameString)
|
DWORD dwFlags, void *pvTypePara, LPSTR pszNameString, DWORD cchNameString)
|
||||||
{
|
{
|
||||||
|
|
|
@ -176,6 +176,12 @@ typedef DWORD (WINAPI *CertRDNValueToStrAFunc)(DWORD, PCERT_RDN_VALUE_BLOB,
|
||||||
LPSTR, DWORD);
|
LPSTR, DWORD);
|
||||||
typedef DWORD (WINAPI *CertRDNValueToStrWFunc)(DWORD, PCERT_RDN_VALUE_BLOB,
|
typedef DWORD (WINAPI *CertRDNValueToStrWFunc)(DWORD, PCERT_RDN_VALUE_BLOB,
|
||||||
LPWSTR, DWORD);
|
LPWSTR, DWORD);
|
||||||
|
typedef BOOL (WINAPI *CertStrToNameAFunc)(DWORD dwCertEncodingType,
|
||||||
|
LPCSTR pszX500, DWORD dwStrType, void *pvReserved, BYTE *pbEncoded,
|
||||||
|
DWORD *pcbEncoded, LPCSTR *ppszError);
|
||||||
|
typedef BOOL (WINAPI *CertStrToNameWFunc)(DWORD dwCertEncodingType,
|
||||||
|
LPCWSTR pszX500, DWORD dwStrType, void *pvReserved, BYTE *pbEncoded,
|
||||||
|
DWORD *pcbEncoded, LPCWSTR *ppszError);
|
||||||
|
|
||||||
HMODULE dll;
|
HMODULE dll;
|
||||||
static CertNameToStrAFunc pCertNameToStrA;
|
static CertNameToStrAFunc pCertNameToStrA;
|
||||||
|
@ -183,6 +189,8 @@ static CertNameToStrWFunc pCertNameToStrW;
|
||||||
static CryptDecodeObjectFunc pCryptDecodeObject;
|
static CryptDecodeObjectFunc pCryptDecodeObject;
|
||||||
static CertRDNValueToStrAFunc pCertRDNValueToStrA;
|
static CertRDNValueToStrAFunc pCertRDNValueToStrA;
|
||||||
static CertRDNValueToStrWFunc pCertRDNValueToStrW;
|
static CertRDNValueToStrWFunc pCertRDNValueToStrW;
|
||||||
|
static CertStrToNameAFunc pCertStrToNameA;
|
||||||
|
static CertStrToNameWFunc pCertStrToNameW;
|
||||||
|
|
||||||
static void test_CertRDNValueToStrA(void)
|
static void test_CertRDNValueToStrA(void)
|
||||||
{
|
{
|
||||||
|
@ -431,6 +439,165 @@ static void test_CertNameToStrW(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct StrToNameA
|
||||||
|
{
|
||||||
|
LPCSTR x500;
|
||||||
|
DWORD encodedSize;
|
||||||
|
const BYTE *encoded;
|
||||||
|
};
|
||||||
|
|
||||||
|
const BYTE encodedSimpleCN[] = {
|
||||||
|
0x30,0x0c,0x31,0x0a,0x30,0x08,0x06,0x03,0x55,0x04,0x03,0x13,0x01,0x31 };
|
||||||
|
static const BYTE encodedSingleQuotedCN[] = { 0x30,0x0e,0x31,0x0c,0x30,0x0a,
|
||||||
|
0x06,0x03,0x55,0x04,0x03,0x13,0x03,0x27,0x31,0x27 };
|
||||||
|
static const BYTE encodedSpacedCN[] = { 0x30,0x0e,0x31,0x0c,0x30,0x0a,0x06,0x03,
|
||||||
|
0x55,0x04,0x03,0x13,0x03,0x20,0x31,0x20 };
|
||||||
|
static const BYTE encodedQuotedCN[] = { 0x30,0x11,0x31,0x0f,0x30,0x0d,0x06,0x03,
|
||||||
|
0x55, 0x04,0x03,0x1e,0x06,0x00,0x22,0x00,0x31,0x00,0x22, };
|
||||||
|
static const BYTE encodedMultipleAttrCN[] = { 0x30,0x0e,0x31,0x0c,0x30,0x0a,
|
||||||
|
0x06,0x03,0x55,0x04,0x03,0x13,0x03,0x31,0x2b,0x32 };
|
||||||
|
|
||||||
|
struct StrToNameA namesA[] = {
|
||||||
|
{ "CN=1", sizeof(encodedSimpleCN), encodedSimpleCN },
|
||||||
|
{ "CN=\"1\"", sizeof(encodedSimpleCN), encodedSimpleCN },
|
||||||
|
{ "CN = \"1\"", sizeof(encodedSimpleCN), encodedSimpleCN },
|
||||||
|
{ "CN='1'", sizeof(encodedSingleQuotedCN), encodedSingleQuotedCN },
|
||||||
|
{ "CN=\" 1 \"", sizeof(encodedSpacedCN), encodedSpacedCN },
|
||||||
|
{ "CN=\"\"\"1\"\"\"", sizeof(encodedQuotedCN), encodedQuotedCN },
|
||||||
|
{ "CN=\"1+2\"", sizeof(encodedMultipleAttrCN), encodedMultipleAttrCN },
|
||||||
|
};
|
||||||
|
|
||||||
|
static void test_CertStrToNameA(void)
|
||||||
|
{
|
||||||
|
BOOL ret;
|
||||||
|
DWORD size, i;
|
||||||
|
BYTE buf[100];
|
||||||
|
|
||||||
|
if (!pCertStrToNameA) return;
|
||||||
|
|
||||||
|
/* Crash
|
||||||
|
ret = pCertStrToNameA(0, NULL, 0, NULL, NULL, NULL, NULL);
|
||||||
|
*/
|
||||||
|
ret = pCertStrToNameA(0, NULL, 0, NULL, NULL, &size, NULL);
|
||||||
|
ok(!ret, "Expected failure\n");
|
||||||
|
ret = pCertStrToNameA(0, "bogus", 0, NULL, NULL, &size, NULL);
|
||||||
|
ok(!ret && GetLastError() == CRYPT_E_INVALID_X500_STRING,
|
||||||
|
"Expected CRYPT_E_INVALID_X500_STRING, got %08lx\n", GetLastError());
|
||||||
|
ret = pCertStrToNameA(0, "foo=1", 0, NULL, NULL, &size, NULL);
|
||||||
|
ok(!ret && GetLastError() == CRYPT_E_INVALID_X500_STRING,
|
||||||
|
"Expected CRYPT_E_INVALID_X500_STRING, got %08lx\n", GetLastError());
|
||||||
|
ret = pCertStrToNameA(0, "CN=1", 0, NULL, NULL, &size, NULL);
|
||||||
|
ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
|
||||||
|
"Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
|
||||||
|
ret = pCertStrToNameA(X509_ASN_ENCODING, "CN=1", 0, NULL, NULL, &size, NULL);
|
||||||
|
ok(ret, "CertStrToNameA failed: %08lx\n", GetLastError());
|
||||||
|
size = sizeof(buf);
|
||||||
|
ret = pCertStrToNameA(X509_ASN_ENCODING, "CN=\"\"1\"\"", 0, NULL, buf, &size,
|
||||||
|
NULL);
|
||||||
|
ok(!ret && GetLastError() == CRYPT_E_INVALID_X500_STRING,
|
||||||
|
"Expected CRYPT_E_INVALID_X500_STRING, got %08lx\n", GetLastError());
|
||||||
|
ret = pCertStrToNameA(X509_ASN_ENCODING, "CN=1+2", 0, NULL, buf,
|
||||||
|
&size, NULL);
|
||||||
|
todo_wine ok(!ret && GetLastError() == CRYPT_E_INVALID_X500_STRING,
|
||||||
|
"Expected CRYPT_E_INVALID_X500_STRING, got %08lx\n", GetLastError());
|
||||||
|
for (i = 0; i < sizeof(namesA) / sizeof(namesA[0]); i++)
|
||||||
|
{
|
||||||
|
size = sizeof(buf);
|
||||||
|
ret = pCertStrToNameA(X509_ASN_ENCODING, namesA[i].x500, 0, NULL, buf,
|
||||||
|
&size, NULL);
|
||||||
|
ok(ret, "CertStrToNameA failed on string %s: %08lx\n", namesA[i].x500,
|
||||||
|
GetLastError());
|
||||||
|
ok(size == namesA[i].encodedSize,
|
||||||
|
"Expected size %ld, got %ld\n", namesA[i].encodedSize, size);
|
||||||
|
if (ret)
|
||||||
|
ok(!memcmp(buf, namesA[i].encoded, namesA[i].encodedSize),
|
||||||
|
"Unexpected value for string %s\n", namesA[i].x500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct StrToNameW
|
||||||
|
{
|
||||||
|
LPCWSTR x500;
|
||||||
|
DWORD encodedSize;
|
||||||
|
const BYTE *encoded;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const WCHAR badlyQuotedCN_W[] = { 'C','N','=','"','"','1','"','"',0 };
|
||||||
|
static const WCHAR simpleCN_W[] = { 'C','N','=','1',0 };
|
||||||
|
static const WCHAR simpleCN2_W[] = { 'C','N','=','"','1','"',0 };
|
||||||
|
static const WCHAR simpleCN3_W[] = { 'C','N',' ','=',' ','"','1','"',0 };
|
||||||
|
static const WCHAR singledQuotedCN_W[] = { 'C','N','=','\'','1','\'',0 };
|
||||||
|
static const WCHAR spacedCN_W[] = { 'C','N','=','"',' ','1',' ','"',0 };
|
||||||
|
static const WCHAR quotedCN_W[] = { 'C','N','=','"','"','"','1','"','"','"',0 };
|
||||||
|
static const WCHAR multipleAttrCN_W[] = { 'C','N','=','"','1','+','2','"',0 };
|
||||||
|
static const WCHAR japaneseCN_W[] = { 'C','N','=',0x226f,0x575b,0 };
|
||||||
|
static const BYTE encodedJapaneseCN[] = { 0x30,0x0f,0x31,0x0d,0x30,0x0b,0x06,
|
||||||
|
0x03,0x55,0x04,0x03,0x1e,0x04,0x22,0x6f,0x57,0x5b };
|
||||||
|
|
||||||
|
struct StrToNameW namesW[] = {
|
||||||
|
{ simpleCN_W, sizeof(encodedSimpleCN), encodedSimpleCN },
|
||||||
|
{ simpleCN2_W, sizeof(encodedSimpleCN), encodedSimpleCN },
|
||||||
|
{ simpleCN3_W, sizeof(encodedSimpleCN), encodedSimpleCN },
|
||||||
|
{ singledQuotedCN_W, sizeof(encodedSingleQuotedCN), encodedSingleQuotedCN },
|
||||||
|
{ spacedCN_W, sizeof(encodedSpacedCN), encodedSpacedCN },
|
||||||
|
{ quotedCN_W, sizeof(encodedQuotedCN), encodedQuotedCN },
|
||||||
|
{ multipleAttrCN_W, sizeof(encodedMultipleAttrCN), encodedMultipleAttrCN },
|
||||||
|
{ japaneseCN_W, sizeof(encodedJapaneseCN), encodedJapaneseCN },
|
||||||
|
};
|
||||||
|
|
||||||
|
static void test_CertStrToNameW(void)
|
||||||
|
{
|
||||||
|
static const WCHAR bogusW[] = { 'b','o','g','u','s',0 };
|
||||||
|
static const WCHAR fooW[] = { 'f','o','o','=','1',0 };
|
||||||
|
BOOL ret;
|
||||||
|
DWORD size, i;
|
||||||
|
LPCWSTR errorPtr;
|
||||||
|
BYTE buf[100];
|
||||||
|
|
||||||
|
if (!pCertStrToNameW) return;
|
||||||
|
|
||||||
|
/* Crash
|
||||||
|
ret = pCertStrToNameW(0, NULL, 0, NULL, NULL, NULL, NULL);
|
||||||
|
*/
|
||||||
|
ret = pCertStrToNameW(0, NULL, 0, NULL, NULL, &size, NULL);
|
||||||
|
ok(!ret, "Expected failure\n");
|
||||||
|
ret = pCertStrToNameW(0, bogusW, 0, NULL, NULL, &size, NULL);
|
||||||
|
ok(!ret && GetLastError() == CRYPT_E_INVALID_X500_STRING,
|
||||||
|
"Expected CRYPT_E_INVALID_X500_STRING, got %08lx\n", GetLastError());
|
||||||
|
ret = pCertStrToNameW(0, fooW, 0, NULL, NULL, &size, NULL);
|
||||||
|
ok(!ret && GetLastError() == CRYPT_E_INVALID_X500_STRING,
|
||||||
|
"Expected CRYPT_E_INVALID_X500_STRING, got %08lx\n", GetLastError());
|
||||||
|
ret = pCertStrToNameW(0, simpleCN_W, 0, NULL, NULL, &size, NULL);
|
||||||
|
ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
|
||||||
|
"Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
|
||||||
|
ret = pCertStrToNameW(X509_ASN_ENCODING, simpleCN_W, 0, NULL, NULL, &size,
|
||||||
|
NULL);
|
||||||
|
ok(ret, "CertStrToNameW failed: %08lx\n", GetLastError());
|
||||||
|
size = sizeof(buf);
|
||||||
|
ret = pCertStrToNameW(X509_ASN_ENCODING, badlyQuotedCN_W, 0, NULL, buf,
|
||||||
|
&size, NULL);
|
||||||
|
ok(!ret && GetLastError() == CRYPT_E_INVALID_X500_STRING,
|
||||||
|
"Expected CRYPT_E_INVALID_X500_STRING, got %08lx\n", GetLastError());
|
||||||
|
ret = pCertStrToNameW(X509_ASN_ENCODING, badlyQuotedCN_W, 0, NULL, buf,
|
||||||
|
&size, &errorPtr);
|
||||||
|
ok(!ret && GetLastError() == CRYPT_E_INVALID_X500_STRING,
|
||||||
|
"Expected CRYPT_E_INVALID_X500_STRING, got %08lx\n", GetLastError());
|
||||||
|
ok(errorPtr && *errorPtr == '1', "Expected first error character was 1\n");
|
||||||
|
for (i = 0; i < sizeof(namesW) / sizeof(namesW[0]); i++)
|
||||||
|
{
|
||||||
|
size = sizeof(buf);
|
||||||
|
ret = pCertStrToNameW(X509_ASN_ENCODING, namesW[i].x500, 0, NULL, buf,
|
||||||
|
&size, NULL);
|
||||||
|
ok(ret, "Index %ld: CertStrToNameW failed: %08lx\n", i, GetLastError());
|
||||||
|
ok(size == namesW[i].encodedSize,
|
||||||
|
"Index %ld: expected size %ld, got %ld\n", i, namesW[i].encodedSize,
|
||||||
|
size);
|
||||||
|
if (ret)
|
||||||
|
ok(!memcmp(buf, namesW[i].encoded, size),
|
||||||
|
"Index %ld: unexpected value\n", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
START_TEST(str)
|
START_TEST(str)
|
||||||
{
|
{
|
||||||
dll = LoadLibrary("Crypt32.dll");
|
dll = LoadLibrary("Crypt32.dll");
|
||||||
|
@ -443,11 +610,15 @@ START_TEST(str)
|
||||||
"CertRDNValueToStrW");
|
"CertRDNValueToStrW");
|
||||||
pCryptDecodeObject = (CryptDecodeObjectFunc)GetProcAddress(dll,
|
pCryptDecodeObject = (CryptDecodeObjectFunc)GetProcAddress(dll,
|
||||||
"CryptDecodeObject");
|
"CryptDecodeObject");
|
||||||
|
pCertStrToNameA = (CertStrToNameAFunc)GetProcAddress(dll,"CertStrToNameA");
|
||||||
|
pCertStrToNameW = (CertStrToNameWFunc)GetProcAddress(dll,"CertStrToNameW");
|
||||||
|
|
||||||
test_CertRDNValueToStrA();
|
test_CertRDNValueToStrA();
|
||||||
test_CertRDNValueToStrW();
|
test_CertRDNValueToStrW();
|
||||||
test_CertNameToStrA();
|
test_CertNameToStrA();
|
||||||
test_CertNameToStrW();
|
test_CertNameToStrW();
|
||||||
|
test_CertStrToNameA();
|
||||||
|
test_CertStrToNameW();
|
||||||
|
|
||||||
FreeLibrary(dll);
|
FreeLibrary(dll);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue