-- v3: cryptui: Use CertNameToStr(CERT_NAME_STR_NO_QUOTING_FLAG) to disable quoting. crypt32: Add support for CERT_NAME_STR_NO_QUOTING_FLAG to CertNameToStr(). crypt32/tests: Add some tests for quoted RDN values. crypt32: Avoid truncating unicode chars.
From: Dmitry Timoshkov dmitry@baikal.ru
So that strings containing Cyrillic Capital Letter ER (0x420) won't be quoted when not needed.
Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/crypt32/str.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/dlls/crypt32/str.c b/dlls/crypt32/str.c index 855e5a1c123..7904b8c8551 100644 --- a/dlls/crypt32/str.c +++ b/dlls/crypt32/str.c @@ -139,6 +139,11 @@ static inline BOOL is_quotable_char(WCHAR c) } }
+static inline BOOL is_spaceW(WCHAR c) +{ + return c <= 0xff && isspace((char)c); +} + static DWORD quote_rdn_value_to_str_w(DWORD dwValueType, PCERT_RDN_VALUE_BLOB pValue, LPWSTR psz, DWORD csz) { @@ -195,9 +200,9 @@ static DWORD quote_rdn_value_to_str_w(DWORD dwValueType, case CERT_RDN_BMP_STRING: case CERT_RDN_UTF8_STRING: strLen = len = pValue->cbData / sizeof(WCHAR); - if (pValue->cbData && isspace(pValue->pbData[0])) + if (pValue->cbData && is_spaceW(((LPCWSTR)pValue->pbData)[0])) needsQuotes = TRUE; - if (pValue->cbData && isspace(pValue->pbData[strLen - 1])) + if (pValue->cbData && is_spaceW(((LPCWSTR)pValue->pbData)[strLen - 1])) needsQuotes = TRUE; for (i = 0; i < strLen; i++) {
From: Dmitry Timoshkov dmitry@baikal.ru
Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/crypt32/tests/str.c | 145 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+)
diff --git a/dlls/crypt32/tests/str.c b/dlls/crypt32/tests/str.c index 9e4ca37bcd6..89611076ab4 100644 --- a/dlls/crypt32/tests/str.c +++ b/dlls/crypt32/tests/str.c @@ -23,6 +23,7 @@ #include <winbase.h> #include <winerror.h> #include <wincrypt.h> +#include <winnls.h>
#include "wine/test.h"
@@ -1079,8 +1080,152 @@ static void test_CertGetNameString(void) CertFreeCertificateContext(context); }
+static void test_quoted_RDN(void) +{ + static const WCHAR str1[] = { '1',0x00a0,0 }; + static const WCHAR str2[] = { '1',0x3000,0 }; + static const struct + { + const WCHAR *CN; + const WCHAR *X500_CN; + } test[] = + { + { L"1", L"1" }, + { L" 1", L"" 1"" }, + { L"1 ", L""1 "" }, + { L""1"", L""""1"""" }, + { L"" 1 "", L"""" 1 """" }, + { L""""1"""", L""""""""1"""""""" }, + { L"1+", L""1+"" }, + { L"1=", L""1="" }, + { L"1"", L""1"""" }, + { L"1<", L""1<"" }, + { L"1>", L""1>"" }, + { L"1#", L""1#"" }, + { L"1+", L""1+"" }, + { str1, str1 }, + { str2, str2 }, + }; + CERT_RDN_ATTR attr; + CERT_RDN rdn; + CERT_NAME_INFO info; + CERT_NAME_BLOB blob; + BYTE *buf; + WCHAR str[256]; + DWORD size, ret, i; + + for (i = 0; i < ARRAY_SIZE(test); i++) + { + winetest_push_context("%lu", i); + + attr.pszObjId = (LPSTR)szOID_COMMON_NAME; + attr.dwValueType = CERT_RDN_UNICODE_STRING; + attr.Value.cbData = wcslen(test[i].CN) * sizeof(WCHAR); + attr.Value.pbData = (BYTE *)test[i].CN; + rdn.cRDNAttr = 1; + rdn.rgRDNAttr = &attr; + info.cRDN = 1; + info.rgRDN = &rdn; + buf = NULL; + size = 0; + ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_UNICODE_NAME, &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx error %08lx\n", GetLastError()); + + blob.pbData = buf; + blob.cbData = size; + + str[0] = 0; + ret = CertNameToStrW(X509_ASN_ENCODING, &blob, 0, str, ARRAY_SIZE(str)); + ok(ret, "CertNameToStr error %08lx\n", GetLastError()); + ok(!wcscmp(str, test[i].X500_CN), "got %s, expected %s\n", debugstr_w(str), debugstr_w(test[i].X500_CN)); + + str[0] = 0; + ret = CertNameToStrW(X509_ASN_ENCODING, &blob, CERT_SIMPLE_NAME_STR, str, ARRAY_SIZE(str)); + ok(ret, "CertNameToStr error %08lx\n", GetLastError()); + ok(!wcscmp(str, test[i].X500_CN), "got %s, expected %s\n", debugstr_w(str), debugstr_w(test[i].X500_CN)); + + str[0] = 0; + ret = CertNameToStrW(X509_ASN_ENCODING, &blob, CERT_OID_NAME_STR, str, ARRAY_SIZE(str)); + ok(ret, "CertNameToStr error %08lx\n", GetLastError()); + ok(!wcsncmp(str, L"2.5.4.3=", 8), "got %s\n", debugstr_w(str)); + ok(!wcscmp(&str[8], test[i].X500_CN), "got %s, expected %s\n", debugstr_w(&str[8]), debugstr_w(test[i].X500_CN)); + + str[0] = 0; + ret = CertNameToStrW(X509_ASN_ENCODING, &blob, CERT_X500_NAME_STR, str, ARRAY_SIZE(str)); + ok(ret, "CertNameToStr error %08lx\n", GetLastError()); + ok(!wcsncmp(str, L"CN=", 3), "got %s\n", debugstr_w(str)); + ok(!wcscmp(&str[3], test[i].X500_CN), "got %s, expected %s\n", debugstr_w(&str[3]), debugstr_w(test[i].X500_CN)); + + str[0] = 0; + ret = CertNameToStrW(X509_ASN_ENCODING, &blob, CERT_X500_NAME_STR | CERT_NAME_STR_NO_QUOTING_FLAG, str, ARRAY_SIZE(str)); + ok(ret, "CertNameToStr error %08lx\n", GetLastError()); + ok(!wcsncmp(str, L"CN=", 3), "got %s\n", debugstr_w(str)); + todo_wine_if(i != 0 && i != 13 && i != 14) + ok(!wcscmp(&str[3], test[i].CN), "got %s, expected %s\n", debugstr_w(&str[3]), debugstr_w(test[i].CN)); + + LocalFree(buf); + + winetest_pop_context(); + } + + for (i = 0; i < ARRAY_SIZE(test); i++) + { + winetest_push_context("%lu", i); + + attr.pszObjId = (LPSTR)szOID_COMMON_NAME; + attr.dwValueType = CERT_RDN_UTF8_STRING; + attr.Value.cbData = wcslen(test[i].CN) * sizeof(WCHAR); + attr.Value.pbData = (BYTE *)test[i].CN; + rdn.cRDNAttr = 1; + rdn.rgRDNAttr = &attr; + info.cRDN = 1; + info.rgRDN = &rdn; + buf = NULL; + size = 0; + ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_UNICODE_NAME, &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx error %08lx\n", GetLastError()); + + blob.pbData = buf; + blob.cbData = size; + + str[0] = 0; + ret = CertNameToStrW(X509_ASN_ENCODING, &blob, 0, str, ARRAY_SIZE(str)); + ok(ret, "CertNameToStr error %08lx\n", GetLastError()); + ok(!wcscmp(str, test[i].X500_CN), "got %s, expected %s\n", debugstr_w(str), debugstr_w(test[i].X500_CN)); + + str[0] = 0; + ret = CertNameToStrW(X509_ASN_ENCODING, &blob, CERT_SIMPLE_NAME_STR, str, ARRAY_SIZE(str)); + ok(ret, "CertNameToStr error %08lx\n", GetLastError()); + ok(!wcscmp(str, test[i].X500_CN), "got %s, expected %s\n", debugstr_w(str), debugstr_w(test[i].X500_CN)); + + str[0] = 0; + ret = CertNameToStrW(X509_ASN_ENCODING, &blob, CERT_OID_NAME_STR, str, ARRAY_SIZE(str)); + ok(ret, "CertNameToStr error %08lx\n", GetLastError()); + ok(!wcsncmp(str, L"2.5.4.3=", 8), "got %s\n", debugstr_w(str)); + ok(!wcscmp(&str[8], test[i].X500_CN), "got %s, expected %s\n", debugstr_w(&str[8]), debugstr_w(test[i].X500_CN)); + + str[0] = 0; + ret = CertNameToStrW(X509_ASN_ENCODING, &blob, CERT_X500_NAME_STR, str, ARRAY_SIZE(str)); + ok(ret, "CertNameToStr error %08lx\n", GetLastError()); + ok(!wcsncmp(str, L"CN=", 3), "got %s\n", debugstr_w(str)); + ok(!wcscmp(&str[3], test[i].X500_CN), "got %s, expected %s\n", debugstr_w(&str[3]), debugstr_w(test[i].X500_CN)); + + str[0] = 0; + ret = CertNameToStrW(X509_ASN_ENCODING, &blob, CERT_X500_NAME_STR | CERT_NAME_STR_NO_QUOTING_FLAG, str, ARRAY_SIZE(str)); + ok(ret, "CertNameToStr error %08lx\n", GetLastError()); + ok(!wcsncmp(str, L"CN=", 3), "got %s\n", debugstr_w(str)); + todo_wine_if(i != 0 && i != 13 && i != 14) + ok(!wcscmp(&str[3], test[i].CN), "got %s, expected %s\n", debugstr_w(&str[3]), debugstr_w(test[i].CN)); + + LocalFree(buf); + + winetest_pop_context(); + } +} + START_TEST(str) { + test_quoted_RDN(); test_CertRDNValueToStrA(); test_CertRDNValueToStrW(); test_CertNameToStrA();
From: Dmitry Timoshkov dmitry@baikal.ru
Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/crypt32/str.c | 61 ++++++++++++++++++++++------------------ dlls/crypt32/tests/str.c | 2 -- 2 files changed, 34 insertions(+), 29 deletions(-)
diff --git a/dlls/crypt32/str.c b/dlls/crypt32/str.c index 7904b8c8551..cbe1a95a65d 100644 --- a/dlls/crypt32/str.c +++ b/dlls/crypt32/str.c @@ -144,8 +144,8 @@ static inline BOOL is_spaceW(WCHAR c) return c <= 0xff && isspace((char)c); }
-static DWORD quote_rdn_value_to_str_w(DWORD dwValueType, - PCERT_RDN_VALUE_BLOB pValue, LPWSTR psz, DWORD csz) +static DWORD quote_rdn_value_to_str_w(DWORD dwValueType, PCERT_RDN_VALUE_BLOB pValue, + DWORD dwStrType, LPWSTR psz, DWORD csz) { DWORD ret = 0, len, i, strLen; BOOL needsQuotes = FALSE; @@ -165,19 +165,22 @@ static DWORD quote_rdn_value_to_str_w(DWORD dwValueType, 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 (!(dwStrType & CERT_NAME_STR_NO_QUOTING_FLAG)) { - if (is_quotable_char(pValue->pbData[i])) + if (pValue->cbData && isspace(pValue->pbData[0])) needsQuotes = TRUE; - if (pValue->pbData[i] == '"') - len += 1; + 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 (needsQuotes) - len += 2; if (!psz || !csz) ret = len; else @@ -189,7 +192,8 @@ static DWORD quote_rdn_value_to_str_w(DWORD dwValueType, for (i = 0; i < pValue->cbData && ptr - psz < csz; ptr++, i++) { *ptr = pValue->pbData[i]; - if (pValue->pbData[i] == '"' && ptr - psz < csz - 1) + if (!(dwStrType & CERT_NAME_STR_NO_QUOTING_FLAG) && + pValue->pbData[i] == '"' && ptr - psz < csz - 1) *(++ptr) = '"'; } if (needsQuotes && ptr - psz < csz) @@ -200,19 +204,22 @@ static DWORD quote_rdn_value_to_str_w(DWORD dwValueType, case CERT_RDN_BMP_STRING: case CERT_RDN_UTF8_STRING: strLen = len = pValue->cbData / sizeof(WCHAR); - if (pValue->cbData && is_spaceW(((LPCWSTR)pValue->pbData)[0])) - needsQuotes = TRUE; - if (pValue->cbData && is_spaceW(((LPCWSTR)pValue->pbData)[strLen - 1])) - needsQuotes = TRUE; - for (i = 0; i < strLen; i++) + if (!(dwStrType & CERT_NAME_STR_NO_QUOTING_FLAG)) { - if (is_quotable_char(((LPCWSTR)pValue->pbData)[i])) + if (pValue->cbData && is_spaceW(((LPCWSTR)pValue->pbData)[0])) needsQuotes = TRUE; - if (((LPCWSTR)pValue->pbData)[i] == '"') - len += 1; + if (pValue->cbData && is_spaceW(((LPCWSTR)pValue->pbData)[strLen - 1])) + needsQuotes = TRUE; + for (i = 0; i < strLen; i++) + { + if (is_quotable_char(((LPCWSTR)pValue->pbData)[i])) + needsQuotes = TRUE; + if (((LPCWSTR)pValue->pbData)[i] == '"') + len += 1; + } + if (needsQuotes) + len += 2; } - if (needsQuotes) - len += 2; if (!psz || !csz) ret = len; else @@ -224,7 +231,8 @@ static DWORD quote_rdn_value_to_str_w(DWORD dwValueType, for (i = 0; i < strLen && ptr - psz < csz; ptr++, i++) { *ptr = ((LPCWSTR)pValue->pbData)[i]; - if (((LPCWSTR)pValue->pbData)[i] == '"' && ptr - psz < csz - 1) + if (!(dwStrType & CERT_NAME_STR_NO_QUOTING_FLAG) && + ((LPCWSTR)pValue->pbData)[i] == '"' && ptr - psz < csz - 1) *(++ptr) = '"'; } if (needsQuotes && ptr - psz < csz) @@ -328,8 +336,7 @@ static const WCHAR indent[] = L" "; DWORD cert_name_to_str_with_indent(DWORD dwCertEncodingType, DWORD indentLevel, const CERT_NAME_BLOB *pName, DWORD dwStrType, LPWSTR psz, DWORD csz) { - static const DWORD unsupportedFlags = CERT_NAME_STR_NO_QUOTING_FLAG | - CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG; + static const DWORD unsupportedFlags = CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG; DWORD ret = 0, bytes = 0; BOOL bRet; CERT_NAME_INFO *info; @@ -419,7 +426,7 @@ DWORD cert_name_to_str_with_indent(DWORD dwCertEncodingType, DWORD indentLevel, } if (psz && ret + 1 == csz) break;
- chars = quote_rdn_value_to_str_w(rdn->rgRDNAttr[j].dwValueType, &rdn->rgRDNAttr[j].Value, + chars = quote_rdn_value_to_str_w(rdn->rgRDNAttr[j].dwValueType, &rdn->rgRDNAttr[j].Value, dwStrType, psz ? psz + ret : NULL, psz ? csz - ret - 1 : 0); ret += chars; if (j < rdn->cRDNAttr - 1) diff --git a/dlls/crypt32/tests/str.c b/dlls/crypt32/tests/str.c index 89611076ab4..a067b2b0bf7 100644 --- a/dlls/crypt32/tests/str.c +++ b/dlls/crypt32/tests/str.c @@ -1160,7 +1160,6 @@ static void test_quoted_RDN(void) ret = CertNameToStrW(X509_ASN_ENCODING, &blob, CERT_X500_NAME_STR | CERT_NAME_STR_NO_QUOTING_FLAG, str, ARRAY_SIZE(str)); ok(ret, "CertNameToStr error %08lx\n", GetLastError()); ok(!wcsncmp(str, L"CN=", 3), "got %s\n", debugstr_w(str)); - todo_wine_if(i != 0 && i != 13 && i != 14) ok(!wcscmp(&str[3], test[i].CN), "got %s, expected %s\n", debugstr_w(&str[3]), debugstr_w(test[i].CN));
LocalFree(buf); @@ -1214,7 +1213,6 @@ static void test_quoted_RDN(void) ret = CertNameToStrW(X509_ASN_ENCODING, &blob, CERT_X500_NAME_STR | CERT_NAME_STR_NO_QUOTING_FLAG, str, ARRAY_SIZE(str)); ok(ret, "CertNameToStr error %08lx\n", GetLastError()); ok(!wcsncmp(str, L"CN=", 3), "got %s\n", debugstr_w(str)); - todo_wine_if(i != 0 && i != 13 && i != 14) ok(!wcscmp(&str[3], test[i].CN), "got %s, expected %s\n", debugstr_w(&str[3]), debugstr_w(test[i].CN));
LocalFree(buf);
From: Dmitry Timoshkov dmitry@baikal.ru
This makes the certificate selecting UI look similar to Windows.
Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/cryptui/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/cryptui/main.c b/dlls/cryptui/main.c index ee5d7037366..2bd6b0b9f6a 100644 --- a/dlls/cryptui/main.c +++ b/dlls/cryptui/main.c @@ -2598,14 +2598,14 @@ static WCHAR *field_format_detailed_cert_name(PCERT_NAME_BLOB name) { WCHAR *str = NULL; DWORD len = CertNameToStrW(X509_ASN_ENCODING, name, - CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, NULL, 0); + CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG | CERT_NAME_STR_NO_QUOTING_FLAG, NULL, 0);
if (len) { str = malloc(len * sizeof(WCHAR)); if (str) CertNameToStrW(X509_ASN_ENCODING, name, - CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, str, len); + CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG | CERT_NAME_STR_NO_QUOTING_FLAG, str, len); } return str; }
Is there anything else that should be addressed in these patches?