[PATCH 7/7] crypt32: Reimplement CertNameToStrA() on top of CertNameToStrW().

Paul Gofman wine at gitlab.winehq.org
Thu Apr 28 18:51:41 CDT 2022


From: Paul Gofman <pgofman at codeweavers.com>

---
 dlls/crypt32/str.c       | 250 ++++-----------------------------------
 dlls/crypt32/tests/str.c | 107 ++++++++---------
 2 files changed, 72 insertions(+), 285 deletions(-)

diff --git a/dlls/crypt32/str.c b/dlls/crypt32/str.c
index 29882ab771e..2c667542dc8 100644
--- a/dlls/crypt32/str.c
+++ b/dlls/crypt32/str.c
@@ -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;
 }
 
diff --git a/dlls/crypt32/tests/str.c b/dlls/crypt32/tests/str.c
index be95a796846..d2106b728a9 100644
--- a/dlls/crypt32/tests/str.c
+++ b/dlls/crypt32/tests/str.c
@@ -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;
-
-    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);
+    char buffer[2000];
+    DWORD len, retlen;
+
+    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);
-        test_NameToStrConversionA(&context->pCertInfo->Issuer,
-         CERT_SIMPLE_NAME_STR | CERT_NAME_STR_SEMICOLON_FLAG,
-         issuerStrSemicolon, FALSE);
+         CERT_SIMPLE_NAME_STR | CERT_NAME_STR_SEMICOLON_FLAG, issuerStrSemicolon);
         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);
-        test_NameToStrConversionA(&context->pCertInfo->Subject,
-         CERT_OID_NAME_STR | CERT_NAME_STR_CRLF_FLAG,
-         subjectStrCRLF, FALSE);
+         CERT_OID_NAME_STR | CERT_NAME_STR_CRLF_FLAG, subjectStrCRLF);
         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)
-- 
GitLab

https://gitlab.winehq.org/wine/wine/-/merge_requests/12



More information about the wine-devel mailing list