crypt32: Reimplement CertNameToStrA() on top of CertNameToStrW().

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Paul Gofman 2022-04-14 18:57:26 +03:00 committed by Alexandre Julliard
parent f560aab5f6
commit c515e55d71
2 changed files with 71 additions and 284 deletions

View File

@ -141,115 +141,6 @@ static inline BOOL is_quotable_char(WCHAR c)
}
}
static DWORD quote_rdn_value_to_str_a(DWORD dwValueType,
PCERT_RDN_VALUE_BLOB pValue, LPSTR psz, DWORD csz)
{
DWORD ret = 0, len, i;
BOOL needsQuotes = FALSE;
TRACE("(%ld, %p, %p, %ld)\n", dwValueType, pValue, psz, csz);
switch (dwValueType)
{
case CERT_RDN_ANY_TYPE:
break;
case CERT_RDN_NUMERIC_STRING:
case CERT_RDN_PRINTABLE_STRING:
case CERT_RDN_TELETEX_STRING:
case CERT_RDN_VIDEOTEX_STRING:
case CERT_RDN_IA5_STRING:
case CERT_RDN_GRAPHIC_STRING:
case CERT_RDN_VISIBLE_STRING:
case CERT_RDN_GENERAL_STRING:
len = pValue->cbData;
if (pValue->cbData && isspace(pValue->pbData[0]))
needsQuotes = TRUE;
if (pValue->cbData && isspace(pValue->pbData[pValue->cbData - 1]))
needsQuotes = TRUE;
for (i = 0; i < pValue->cbData; i++)
{
if (is_quotable_char(pValue->pbData[i]))
needsQuotes = TRUE;
if (pValue->pbData[i] == '"')
len += 1;
}
if (needsQuotes)
len += 2;
if (!psz || !csz)
ret = len;
else
{
char *ptr = psz;
if (needsQuotes)
*ptr++ = '"';
for (i = 0; i < pValue->cbData && ptr - psz < csz; ptr++, i++)
{
*ptr = pValue->pbData[i];
if (pValue->pbData[i] == '"' && ptr - psz < csz - 1)
*(++ptr) = '"';
}
if (needsQuotes && ptr - psz < csz)
*ptr++ = '"';
ret = ptr - psz;
}
break;
case CERT_RDN_BMP_STRING:
case CERT_RDN_UTF8_STRING:
len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)pValue->pbData,
pValue->cbData / sizeof(WCHAR), NULL, 0, NULL, NULL);
if (pValue->cbData && iswspace(((LPCWSTR)pValue->pbData)[0]))
needsQuotes = TRUE;
if (pValue->cbData &&
iswspace(((LPCWSTR)pValue->pbData)[pValue->cbData / sizeof(WCHAR)-1]))
needsQuotes = TRUE;
for (i = 0; i < pValue->cbData / sizeof(WCHAR); i++)
{
if (is_quotable_char(((LPCWSTR)pValue->pbData)[i]))
needsQuotes = TRUE;
if (((LPCWSTR)pValue->pbData)[i] == '"')
len += 1;
}
if (needsQuotes)
len += 2;
if (!psz || !csz)
ret = len;
else
{
char *dst = psz;
if (needsQuotes)
*dst++ = '"';
for (i = 0; i < pValue->cbData / sizeof(WCHAR) &&
dst - psz < csz; dst++, i++)
{
LPCWSTR src = (LPCWSTR)pValue->pbData + i;
WideCharToMultiByte(CP_ACP, 0, src, 1, dst,
csz - (dst - psz) - 1, NULL, NULL);
if (*src == '"' && dst - psz < csz - 1)
*(++dst) = '"';
}
if (needsQuotes && dst - psz < csz)
*dst++ = '"';
ret = dst - psz;
}
break;
default:
FIXME("string type %ld unimplemented\n", dwValueType);
}
if (psz && csz)
{
*(psz + ret) = '\0';
csz--;
ret++;
}
else
ret++;
TRACE("returning %ld (%s)\n", ret, debugstr_a(psz));
return ret;
}
static DWORD quote_rdn_value_to_str_w(DWORD dwValueType,
PCERT_RDN_VALUE_BLOB pValue, LPWSTR psz, DWORD csz)
{
@ -345,136 +236,37 @@ static DWORD quote_rdn_value_to_str_w(DWORD dwValueType,
return ret;
}
/* Adds the prefix prefix to the string pointed to by psz, followed by the
* character '='. Copies no more than csz characters. Returns the number of
* characters copied. If psz is NULL, returns the number of characters that
* would be copied.
*/
static DWORD CRYPT_AddPrefixA(LPCSTR prefix, LPSTR psz, DWORD csz)
DWORD WINAPI CertNameToStrA(DWORD encoding_type, PCERT_NAME_BLOB name_blob, DWORD str_type, LPSTR str, DWORD str_len)
{
DWORD chars;
DWORD len, len_mb, ret;
LPWSTR strW;
TRACE("(%s, %p, %ld)\n", debugstr_a(prefix), psz, csz);
TRACE("(%ld, %p, %08lx, %p, %ld)\n", encoding_type, name_blob, str_type, str, str_len);
if (psz)
len = CertNameToStrW(encoding_type, name_blob, str_type, NULL, 0);
if (!(strW = CryptMemAlloc(len * sizeof(*strW))))
{
chars = min(strlen(prefix), csz);
memcpy(psz, prefix, chars);
*(psz + chars) = '=';
chars++;
ERR("No memory.\n");
if (str && str_len) *str = 0;
return 1;
}
else
chars = lstrlenA(prefix) + 1;
return chars;
}
DWORD WINAPI CertNameToStrA(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName,
DWORD dwStrType, LPSTR psz, DWORD csz)
{
static const DWORD unsupportedFlags = CERT_NAME_STR_NO_QUOTING_FLAG |
CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG;
static const char commaSep[] = ", ";
static const char semiSep[] = "; ";
static const char crlfSep[] = "\r\n";
static const char plusSep[] = " + ";
static const char spaceSep[] = " ";
DWORD ret = 0, bytes = 0;
BOOL bRet;
CERT_NAME_INFO *info;
TRACE("(%ld, %p, %08lx, %p, %ld)\n", dwCertEncodingType, pName, dwStrType,
psz, csz);
if (dwStrType & unsupportedFlags)
FIXME("unsupported flags: %08lx\n", dwStrType & unsupportedFlags);
bRet = CryptDecodeObjectEx(dwCertEncodingType, X509_NAME, pName->pbData,
pName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &bytes);
if (bRet)
len = CertNameToStrW(encoding_type, name_blob, str_type, strW, len);
len_mb = WideCharToMultiByte(CP_ACP, 0, strW, len, NULL, 0, NULL, NULL);
if (!str || !str_len)
{
DWORD i, j, sepLen, rdnSepLen;
LPCSTR sep, rdnSep;
BOOL reverse = dwStrType & CERT_NAME_STR_REVERSE_FLAG;
const CERT_RDN *rdn = info->rgRDN;
if(reverse && info->cRDN > 1) rdn += (info->cRDN - 1);
if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG)
sep = semiSep;
else if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
sep = crlfSep;
else
sep = commaSep;
sepLen = strlen(sep);
if (dwStrType & CERT_NAME_STR_NO_PLUS_FLAG)
rdnSep = spaceSep;
else
rdnSep = plusSep;
rdnSepLen = strlen(rdnSep);
for (i = 0; (!psz || ret < csz) && i < info->cRDN; i++)
{
for (j = 0; (!psz || ret < csz) && j < rdn->cRDNAttr; j++)
{
DWORD chars;
char prefixBuf[13]; /* big enough for SERIALNUMBER */
LPCSTR prefix = NULL;
if ((dwStrType & 0x000000ff) == CERT_OID_NAME_STR)
prefix = rdn->rgRDNAttr[j].pszObjId;
else if ((dwStrType & 0x000000ff) == CERT_X500_NAME_STR)
{
PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(
CRYPT_OID_INFO_OID_KEY,
rdn->rgRDNAttr[j].pszObjId,
CRYPT_RDN_ATTR_OID_GROUP_ID);
if (oidInfo)
{
WideCharToMultiByte(CP_ACP, 0, oidInfo->pwszName, -1,
prefixBuf, sizeof(prefixBuf), NULL, NULL);
prefix = prefixBuf;
}
else
prefix = rdn->rgRDNAttr[j].pszObjId;
}
if (prefix)
{
/* - 1 is needed to account for the NULL terminator. */
chars = CRYPT_AddPrefixA(prefix,
psz ? psz + ret : NULL, psz ? csz - ret - 1 : 0);
ret += chars;
}
chars = quote_rdn_value_to_str_a(
rdn->rgRDNAttr[j].dwValueType,
&rdn->rgRDNAttr[j].Value, psz ? psz + ret : NULL,
psz ? csz - ret : 0);
if (chars)
ret += chars - 1;
if (j < rdn->cRDNAttr - 1)
{
if (psz && ret < csz - rdnSepLen - 1)
memcpy(psz + ret, rdnSep, rdnSepLen);
ret += rdnSepLen;
}
}
if (i < info->cRDN - 1)
{
if (psz && ret < csz - sepLen - 1)
memcpy(psz + ret, sep, sepLen);
ret += sepLen;
}
if(reverse) rdn--;
else rdn++;
}
LocalFree(info);
CryptMemFree(strW);
return len_mb;
}
if (psz && csz)
ret = WideCharToMultiByte(CP_ACP, 0, strW, len, str, str_len, NULL, NULL);
if (ret < len_mb)
{
*(psz + ret) = '\0';
ret++;
str[0] = 0;
ret = 1;
}
else
ret++;
TRACE("Returning %s\n", debugstr_a(psz));
CryptMemFree(strW);
return ret;
}

View File

@ -276,24 +276,27 @@ static void test_CertRDNValueToStrW(void)
wine_dbgstr_w(ePKIW), wine_dbgstr_w(buffer));
}
static void test_NameToStrConversionA(PCERT_NAME_BLOB pName, DWORD dwStrType,
LPCSTR expected, BOOL todo)
#define test_NameToStrConversionA(a, b, c) test_NameToStrConversionA_(__LINE__, a, b, c)
static void test_NameToStrConversionA_(unsigned int line, PCERT_NAME_BLOB pName, DWORD dwStrType, LPCSTR expected)
{
char buffer[2000] = { 0 };
DWORD i;
char buffer[2000];
DWORD len, retlen;
i = CertNameToStrA(X509_ASN_ENCODING, pName, dwStrType, NULL, 0);
todo_wine_if (todo)
ok(i == strlen(expected) + 1, "Expected %d chars, got %ld\n",
lstrlenA(expected) + 1, i);
i = CertNameToStrA(X509_ASN_ENCODING,pName, dwStrType, buffer,
sizeof(buffer));
todo_wine_if (todo)
ok(i == strlen(expected) + 1, "Expected %d chars, got %ld\n",
lstrlenA(expected) + 1, i);
todo_wine_if (todo)
ok(!strcmp(buffer, expected), "Expected %s, got %s\n", expected,
buffer);
len = CertNameToStrA(X509_ASN_ENCODING, pName, dwStrType, NULL, 0);
ok(len == strlen(expected) + 1, "line %u: Expected %d chars, got %ld.\n", line, lstrlenA(expected) + 1, len);
len = CertNameToStrA(X509_ASN_ENCODING,pName, dwStrType, buffer, sizeof(buffer));
ok(len == strlen(expected) + 1, "line %u: Expected %d chars, got %ld.\n", line, lstrlenA(expected) + 1, len);
ok(!strcmp(buffer, expected), "line %u: Expected %s, got %s.\n", line, expected, buffer);
memset(buffer, 0xcc, sizeof(buffer));
retlen = CertNameToStrA(X509_ASN_ENCODING, pName, dwStrType, buffer, len - 1);
ok(retlen == 1, "line %u: expected 1, got %lu\n", line, retlen);
ok(!buffer[0], "line %u: string is not zero terminated.\n", line);
memset(buffer, 0xcc, sizeof(buffer));
retlen = CertNameToStrA(X509_ASN_ENCODING, pName, dwStrType, buffer, 0);
ok(retlen == len, "line %u: expected %lu chars, got %lu\n", line, len - 1, retlen);
ok((unsigned char)buffer[0] == 0xcc, "line %u: got %s\n", line, wine_dbgstr_a(buffer));
}
static BYTE encodedSimpleCN[] = {
@ -366,79 +369,71 @@ static void test_CertNameToStrA(void)
"Expected positive return and ERROR_SUCCESS, got %ld - %08lx\n",
ret, GetLastError());
test_NameToStrConversionA(&context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR, issuerStr);
test_NameToStrConversionA(&context->pCertInfo->Issuer,
CERT_SIMPLE_NAME_STR, issuerStr, FALSE);
CERT_SIMPLE_NAME_STR | CERT_NAME_STR_SEMICOLON_FLAG, issuerStrSemicolon);
test_NameToStrConversionA(&context->pCertInfo->Issuer,
CERT_SIMPLE_NAME_STR | CERT_NAME_STR_SEMICOLON_FLAG,
issuerStrSemicolon, FALSE);
test_NameToStrConversionA(&context->pCertInfo->Issuer,
CERT_SIMPLE_NAME_STR | CERT_NAME_STR_CRLF_FLAG,
issuerStrCRLF, FALSE);
CERT_SIMPLE_NAME_STR | CERT_NAME_STR_CRLF_FLAG, issuerStrCRLF);
test_NameToStrConversionA(&context->pCertInfo->Subject, CERT_OID_NAME_STR, subjectStr);
test_NameToStrConversionA(&context->pCertInfo->Subject,
CERT_OID_NAME_STR, subjectStr, FALSE);
CERT_OID_NAME_STR | CERT_NAME_STR_SEMICOLON_FLAG, subjectStrSemicolon);
test_NameToStrConversionA(&context->pCertInfo->Subject,
CERT_OID_NAME_STR | CERT_NAME_STR_SEMICOLON_FLAG,
subjectStrSemicolon, FALSE);
CERT_OID_NAME_STR | CERT_NAME_STR_CRLF_FLAG, subjectStrCRLF);
test_NameToStrConversionA(&context->pCertInfo->Subject,
CERT_OID_NAME_STR | CERT_NAME_STR_CRLF_FLAG,
subjectStrCRLF, FALSE);
test_NameToStrConversionA(&context->pCertInfo->Subject,
CERT_X500_NAME_STR, x500SubjectStr, FALSE);
CERT_X500_NAME_STR, x500SubjectStr);
test_NameToStrConversionA(&context->pCertInfo->Subject,
CERT_X500_NAME_STR | CERT_NAME_STR_SEMICOLON_FLAG | CERT_NAME_STR_REVERSE_FLAG,
x500SubjectStrSemicolonReverse, FALSE);
x500SubjectStrSemicolonReverse);
CertFreeCertificateContext(context);
}
blob.pbData = encodedSimpleCN;
blob.cbData = sizeof(encodedSimpleCN);
test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=1", FALSE);
test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=1");
blob.pbData = encodedSingleQuotedCN;
blob.cbData = sizeof(encodedSingleQuotedCN);
test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN='1'", FALSE);
test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "'1'", FALSE);
test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN='1'");
test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "'1'");
blob.pbData = encodedSpacedCN;
blob.cbData = sizeof(encodedSpacedCN);
test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\" 1 \"", FALSE);
test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\" 1 \"", FALSE);
test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\" 1 \"");
test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\" 1 \"");
blob.pbData = encodedQuotedCN;
blob.cbData = sizeof(encodedQuotedCN);
test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\"\"\"1\"\"\"",
FALSE);
test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\"\"\"1\"\"\"",
FALSE);
test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\"\"\"1\"\"\"");
test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\"\"\"1\"\"\"");
blob.pbData = encodedMultipleAttrCN;
blob.cbData = sizeof(encodedMultipleAttrCN);
test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\"1+2\"", FALSE);
test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\"1+2\"", FALSE);
test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\"1+2\"");
test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\"1+2\"");
blob.pbData = encodedCommaCN;
blob.cbData = sizeof(encodedCommaCN);
test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\"a,b\"", FALSE);
test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\"a,b\"", FALSE);
test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\"a,b\"");
test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\"a,b\"");
blob.pbData = encodedEqualCN;
blob.cbData = sizeof(encodedEqualCN);
test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\"a=b\"", FALSE);
test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\"a=b\"", FALSE);
test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\"a=b\"");
test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\"a=b\"");
blob.pbData = encodedLessThanCN;
blob.cbData = sizeof(encodedLessThanCN);
test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\"<\"", FALSE);
test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\"<\"", FALSE);
test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\"<\"");
test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\"<\"");
blob.pbData = encodedGreaterThanCN;
blob.cbData = sizeof(encodedGreaterThanCN);
test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\">\"", FALSE);
test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\">\"", FALSE);
test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\">\"");
test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\">\"");
blob.pbData = encodedHashCN;
blob.cbData = sizeof(encodedHashCN);
test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\"#\"", FALSE);
test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\"#\"", FALSE);
test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\"#\"");
test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\"#\"");
blob.pbData = encodedSemiCN;
blob.cbData = sizeof(encodedSemiCN);
test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\";\"", FALSE);
test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\";\"", FALSE);
test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\";\"");
test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\";\"");
blob.pbData = encodedNewlineCN;
blob.cbData = sizeof(encodedNewlineCN);
test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\"a\nb\"", FALSE);
test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\"a\nb\"", FALSE);
test_NameToStrConversionA(&blob, CERT_X500_NAME_STR, "CN=\"a\nb\"");
test_NameToStrConversionA(&blob, CERT_SIMPLE_NAME_STR, "\"a\nb\"");
}
#define test_NameToStrConversionW(a, b, c) test_NameToStrConversionW_(__LINE__, a, b, c)