From 3882b4f66ad2ee2a225a7365559a97ff7ac48678 Mon Sep 17 00:00:00 2001 From: Juan Lang Date: Wed, 26 Jul 2006 10:57:32 -0700 Subject: [PATCH] crypt32: Implement CryptStrToNameA/W, with tests. --- dlls/crypt32/crypt32.spec | 4 +- dlls/crypt32/str.c | 373 ++++++++++++++++++++++++++++++++++++++ dlls/crypt32/tests/str.c | 171 +++++++++++++++++ 3 files changed, 546 insertions(+), 2 deletions(-) diff --git a/dlls/crypt32/crypt32.spec b/dlls/crypt32/crypt32.spec index 04b028c4719..1293816a636 100644 --- a/dlls/crypt32/crypt32.spec +++ b/dlls/crypt32/crypt32.spec @@ -80,8 +80,8 @@ @ stdcall CertSetCTLContextProperty(ptr long long ptr) @ stdcall CertSetCertificateContextProperty(ptr long long ptr) @ stdcall CertSetEnhancedKeyUsage(ptr ptr) -@ stub CertStrToNameA -@ stub CertStrToNameW +@ stdcall CertStrToNameA(long str long ptr ptr ptr ptr) +@ stdcall CertStrToNameW(long wstr long ptr ptr ptr ptr) @ stdcall CertVerifyCRLRevocation(long ptr long ptr) @ stdcall CertVerifyCRLTimeValidity(ptr ptr) @ stub CertVerifyCTLUsage diff --git a/dlls/crypt32/str.c b/dlls/crypt32/str.c index 32986524b9b..5888aef4627 100644 --- a/dlls/crypt32/str.c +++ b/dlls/crypt32/str.c @@ -19,8 +19,10 @@ #include "windef.h" #include "winbase.h" #include "winnls.h" +#include "winuser.h" #include "wincrypt.h" #include "wine/debug.h" +#include "wine/unicode.h" WINE_DEFAULT_DEBUG_CHANNEL(crypt); @@ -408,6 +410,377 @@ DWORD WINAPI CertNameToStrW(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName, 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 dwFlags, void *pvTypePara, LPSTR pszNameString, DWORD cchNameString) { diff --git a/dlls/crypt32/tests/str.c b/dlls/crypt32/tests/str.c index 15a8a2b0d29..25e7749ebb4 100644 --- a/dlls/crypt32/tests/str.c +++ b/dlls/crypt32/tests/str.c @@ -176,6 +176,12 @@ typedef DWORD (WINAPI *CertRDNValueToStrAFunc)(DWORD, PCERT_RDN_VALUE_BLOB, LPSTR, DWORD); typedef DWORD (WINAPI *CertRDNValueToStrWFunc)(DWORD, PCERT_RDN_VALUE_BLOB, 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; static CertNameToStrAFunc pCertNameToStrA; @@ -183,6 +189,8 @@ static CertNameToStrWFunc pCertNameToStrW; static CryptDecodeObjectFunc pCryptDecodeObject; static CertRDNValueToStrAFunc pCertRDNValueToStrA; static CertRDNValueToStrWFunc pCertRDNValueToStrW; +static CertStrToNameAFunc pCertStrToNameA; +static CertStrToNameWFunc pCertStrToNameW; 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) { dll = LoadLibrary("Crypt32.dll"); @@ -443,11 +610,15 @@ START_TEST(str) "CertRDNValueToStrW"); pCryptDecodeObject = (CryptDecodeObjectFunc)GetProcAddress(dll, "CryptDecodeObject"); + pCertStrToNameA = (CertStrToNameAFunc)GetProcAddress(dll,"CertStrToNameA"); + pCertStrToNameW = (CertStrToNameWFunc)GetProcAddress(dll,"CertStrToNameW"); test_CertRDNValueToStrA(); test_CertRDNValueToStrW(); test_CertNameToStrA(); test_CertNameToStrW(); + test_CertStrToNameA(); + test_CertStrToNameW(); FreeLibrary(dll); }