Autosyncing with Wine HEAD
authorThe Wine Synchronizer <winesync@svn.reactos.org>
Fri, 21 Jul 2006 11:13:18 +0000 (11:13 +0000)
committerThe Wine Synchronizer <winesync@svn.reactos.org>
Fri, 21 Jul 2006 11:13:18 +0000 (11:13 +0000)
svn path=/trunk/; revision=23201

reactos/dll/win32/crypt32/cert.c
reactos/dll/win32/crypt32/crypt32.spec
reactos/dll/win32/crypt32/crypt32_private.h
reactos/dll/win32/crypt32/decode.c
reactos/dll/win32/crypt32/encode.c
reactos/dll/win32/crypt32/serialize.c
reactos/dll/win32/crypt32/store.c
reactos/dll/win32/crypt32/str.c

index 851c8c5..6297e72 100644 (file)
@@ -244,12 +244,7 @@ static BOOL WINAPI CertContext_GetProperty(void *context, DWORD dwPropId,
     return ret;
 }
 
-/* info is assumed to be a CRYPT_KEY_PROV_INFO, followed by its container name,
- * provider name, and any provider parameters, in a contiguous buffer, but
- * where info's pointers are assumed to be invalid.  Upon return, info's
- * pointers point to the appropriate memory locations.
- */
-static void CRYPT_FixKeyProvInfoPointers(PCRYPT_KEY_PROV_INFO info)
+void CRYPT_FixKeyProvInfoPointers(PCRYPT_KEY_PROV_INFO info)
 {
     DWORD i, containerLen, provNameLen;
     LPBYTE data = (LPBYTE)info + sizeof(CRYPT_KEY_PROV_INFO);
@@ -1826,6 +1821,7 @@ static PCCERT_CONTEXT CRYPT_CreateSignedCert(PCRYPT_DER_BLOB blob,
 }
 
 /* Copies data from the parameters into info, where:
+ * pSerialNumber: The serial number.  Must not be NULL.
  * pSubjectIssuerBlob: Specifies both the subject and issuer for info.
  *                     Must not be NULL
  * pSignatureAlgorithm: Optional.
@@ -1836,23 +1832,22 @@ static PCCERT_CONTEXT CRYPT_CreateSignedCert(PCRYPT_DER_BLOB blob,
  * pubKey: The public key of the certificate.  Must not be NULL.
  * pExtensions: Extensions to be included with the certificate.  Optional.
  */
-static void CRYPT_MakeCertInfo(PCERT_INFO info,
+static void CRYPT_MakeCertInfo(PCERT_INFO info, PCRYPT_DATA_BLOB pSerialNumber,
  PCERT_NAME_BLOB pSubjectIssuerBlob,
  PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm, PSYSTEMTIME pStartTime,
  PSYSTEMTIME pEndTime, PCERT_PUBLIC_KEY_INFO pubKey,
  PCERT_EXTENSIONS pExtensions)
 {
-    /* FIXME: what serial number to use? */
-    static const BYTE serialNum[] = { 1 };
     static CHAR oid[] = szOID_RSA_SHA1RSA;
 
     assert(info);
+    assert(pSerialNumber);
     assert(pSubjectIssuerBlob);
     assert(pubKey);
 
     info->dwVersion = CERT_V3;
-    info->SerialNumber.cbData = sizeof(serialNum);
-    info->SerialNumber.pbData = (LPBYTE)serialNum;
+    info->SerialNumber.cbData = pSerialNumber->cbData;
+    info->SerialNumber.pbData = pSerialNumber->pbData;
     if (pSignatureAlgorithm)
         memcpy(&info->SignatureAlgorithm, pSignatureAlgorithm,
          sizeof(info->SignatureAlgorithm));
@@ -1910,9 +1905,9 @@ static HCRYPTPROV CRYPT_CreateKeyProv(void)
         UuidCreateFunc uuidCreate = (UuidCreateFunc)GetProcAddress(rpcrt,
          "UuidCreate");
         UuidToStringFunc uuidToString = (UuidToStringFunc)GetProcAddress(rpcrt,
-         "UuidToString");
+         "UuidToStringA");
         RpcStringFreeFunc rpcStringFree = (RpcStringFreeFunc)GetProcAddress(
-         rpcrt, "RpcStringFree");
+         rpcrt, "RpcStringFreeA");
 
         if (uuidCreate && uuidToString && rpcStringFree)
         {
@@ -1978,10 +1973,12 @@ PCCERT_CONTEXT WINAPI CertCreateSelfSignCertificate(HCRYPTPROV hProv,
         {
             CERT_INFO info = { 0 };
             CRYPT_DER_BLOB blob = { 0, NULL };
-            BOOL ret;
+            BYTE serial[16];
+            CRYPT_DATA_BLOB serialBlob = { sizeof(serial), serial };
 
-            CRYPT_MakeCertInfo(&info, pSubjectIssuerBlob, pSignatureAlgorithm,
-             pStartTime, pEndTime, pubKey, pExtensions);
+            CryptGenRandom(hProv, sizeof(serial), serial);
+            CRYPT_MakeCertInfo(&info, &serialBlob, pSubjectIssuerBlob,
+             pSignatureAlgorithm, pStartTime, pEndTime, pubKey, pExtensions);
             ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
              &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&blob.pbData,
              &blob.cbData);
index 41ec54f..04b028c 100644 (file)
@@ -89,7 +89,7 @@
 @ stdcall CertVerifySubjectCertificateContext(ptr ptr ptr)
 @ stdcall CertVerifyTimeValidity(ptr ptr)
 @ stub CertVerifyValidityNesting
-@ stub CreateFileU
+@ stdcall CreateFileU(wstr long long ptr long long ptr) kernel32.CreateFileW
 @ stdcall CryptBinaryToStringA(ptr long long ptr ptr)
 @ stub CryptBinaryToStringW # (ptr long long ptr ptr)
 @ stdcall CryptStringToBinaryA(str long long ptr ptr ptr ptr)
index 3ef44b4..db87193 100644 (file)
 #define ASN_BOOL            (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x01)
 #define ASN_BITSTRING       (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x03)
 #define ASN_ENUMERATED      (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x0a)
+#define ASN_UTF8STRING      (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x0c)
 #define ASN_SETOF           (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x11)
 #define ASN_NUMERICSTRING   (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x12)
 #define ASN_PRINTABLESTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x13)
 #define ASN_T61STRING       (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x14)
+#define ASN_VIDEOTEXSTRING  (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x15)
 #define ASN_IA5STRING       (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x16)
 #define ASN_UTCTIME         (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x17)
 #define ASN_GENERALTIME     (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x18)
+#define ASN_GRAPHICSTRING   (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x19)
+#define ASN_VISIBLESTRING   (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x1a)
+#define ASN_GENERALSTRING   (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x1b)
+#define ASN_UNIVERSALSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x1c)
+#define ASN_BMPSTRING       (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x1e)
 
 /* The following aren't defined in wincrypt.h, as they're "reserved" */
 #define CERT_CERT_PROP_ID 32
@@ -97,6 +104,14 @@ extern PCWINE_CONTEXT_INTERFACE pCTLInterface;
 const void *CRYPT_ReadSerializedElement(const BYTE *pbElement,
  DWORD cbElement, DWORD dwContextTypeFlags, DWORD *pdwContentType);
 
+/* Fixes up the the pointers in info, where info is assumed to be a
+ * CRYPT_KEY_PROV_INFO, followed by its container name, provider name, and any
+ * provider parameters, in a contiguous buffer, but where info's pointers are
+ * assumed to be invalid.  Upon return, info's pointers point to the
+ * appropriate memory locations.
+ */
+void CRYPT_FixKeyProvInfoPointers(PCRYPT_KEY_PROV_INFO info);
+
 DWORD CertStore_GetAccessState(HCERTSTORE hCertStore);
 
 /**
index fe40ccc..f4e1885 100644 (file)
@@ -42,6 +42,7 @@
 #include "winbase.h"
 #include "excpt.h"
 #include "wincrypt.h"
+#include "winnls.h"
 #include "winreg.h"
 #include "snmp.h"
 #include "wine/debug.h"
@@ -1271,33 +1272,75 @@ static BOOL WINAPI CRYPT_AsnDecodeNameValueInternal(DWORD dwCertEncodingType,
     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
     {
         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
+        DWORD bytesNeeded = sizeof(CERT_NAME_VALUE), valueType;
 
         switch (pbEncoded[0])
         {
+        case ASN_OCTETSTRING:
+            valueType = CERT_RDN_OCTET_STRING;
+            if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
+                bytesNeeded += dataLen;
+            break;
         case ASN_NUMERICSTRING:
+            valueType = CERT_RDN_NUMERIC_STRING;
+            if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
+                bytesNeeded += dataLen;
+            break;
         case ASN_PRINTABLESTRING:
+            valueType = CERT_RDN_PRINTABLE_STRING;
+            if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
+                bytesNeeded += dataLen;
+            break;
         case ASN_IA5STRING:
+            valueType = CERT_RDN_IA5_STRING;
+            if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
+                bytesNeeded += dataLen;
+            break;
         case ASN_T61STRING:
+            valueType = CERT_RDN_T61_STRING;
+            if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
+                bytesNeeded += dataLen;
+            break;
+        case ASN_VIDEOTEXSTRING:
+            valueType = CERT_RDN_VIDEOTEX_STRING;
+            if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
+                bytesNeeded += dataLen;
+            break;
+        case ASN_GRAPHICSTRING:
+            valueType = CERT_RDN_GRAPHIC_STRING;
+            if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
+                bytesNeeded += dataLen;
+            break;
+        case ASN_VISIBLESTRING:
+            valueType = CERT_RDN_VISIBLE_STRING;
+            if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
+                bytesNeeded += dataLen;
+            break;
+        case ASN_GENERALSTRING:
+            valueType = CERT_RDN_GENERAL_STRING;
+            if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
+                bytesNeeded += dataLen;
+            break;
+        case ASN_UNIVERSALSTRING:
+            FIXME("ASN_UNIVERSALSTRING: unimplemented\n");
+            SetLastError(CRYPT_E_ASN1_BADTAG);
+            ret = FALSE;
+            break;
+        case ASN_BMPSTRING:
+            valueType = CERT_RDN_BMP_STRING;
+            bytesNeeded += dataLen;
+            break;
+        case ASN_UTF8STRING:
+            valueType = CERT_RDN_UTF8_STRING;
+            bytesNeeded += MultiByteToWideChar(CP_UTF8, 0,
+             (LPSTR)pbEncoded + 1 + lenBytes, dataLen, NULL, 0) * 2;
             break;
         default:
-            FIXME("Unimplemented string type %02x\n", pbEncoded[0]);
-            SetLastError(OSS_UNIMPLEMENTED);
+            SetLastError(CRYPT_E_ASN1_BADTAG);
             ret = FALSE;
         }
         if (ret)
         {
-            DWORD bytesNeeded = sizeof(CERT_NAME_VALUE);
-
-            switch (pbEncoded[0])
-            {
-            case ASN_NUMERICSTRING:
-            case ASN_PRINTABLESTRING:
-            case ASN_IA5STRING:
-            case ASN_T61STRING:
-                if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
-                    bytesNeeded += dataLen;
-                break;
-            }
             if (!value)
                 *pcbStructInfo = bytesNeeded;
             else if (*pcbStructInfo < bytesNeeded)
@@ -1309,40 +1352,53 @@ static BOOL WINAPI CRYPT_AsnDecodeNameValueInternal(DWORD dwCertEncodingType,
             else
             {
                 *pcbStructInfo = bytesNeeded;
-                switch (pbEncoded[0])
-                {
-                case ASN_NUMERICSTRING:
-                    value->dwValueType = CERT_RDN_NUMERIC_STRING;
-                    break;
-                case ASN_PRINTABLESTRING:
-                    value->dwValueType = CERT_RDN_PRINTABLE_STRING;
-                    break;
-                case ASN_IA5STRING:
-                    value->dwValueType = CERT_RDN_IA5_STRING;
-                    break;
-                case ASN_T61STRING:
-                    value->dwValueType = CERT_RDN_T61_STRING;
-                    break;
-                }
+                value->dwValueType = valueType;
                 if (dataLen)
                 {
+                    DWORD i;
+
+                    assert(value->Value.pbData);
                     switch (pbEncoded[0])
                     {
+                    case ASN_OCTETSTRING:
                     case ASN_NUMERICSTRING:
                     case ASN_PRINTABLESTRING:
                     case ASN_IA5STRING:
                     case ASN_T61STRING:
+                    case ASN_VIDEOTEXSTRING:
+                    case ASN_GRAPHICSTRING:
+                    case ASN_VISIBLESTRING:
+                    case ASN_GENERALSTRING:
                         value->Value.cbData = dataLen;
-                        if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
-                            value->Value.pbData = (BYTE *)pbEncoded + 1 +
-                             lenBytes;
-                        else
+                        if (dataLen)
                         {
-                            assert(value->Value.pbData);
-                            memcpy(value->Value.pbData,
-                             pbEncoded + 1 + lenBytes, dataLen);
+                            if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
+                                memcpy(value->Value.pbData,
+                                 pbEncoded + 1 + lenBytes, dataLen);
+                            else
+                                value->Value.pbData = (LPBYTE)pbEncoded + 1 +
+                                 lenBytes;
                         }
                         break;
+                    case ASN_BMPSTRING:
+                    {
+                        LPWSTR str = (LPWSTR)value->Value.pbData;
+
+                        value->Value.cbData = dataLen;
+                        for (i = 0; i < dataLen / 2; i++)
+                            str[i] = (pbEncoded[1 + lenBytes + 2 * i] << 8) |
+                             pbEncoded[1 + lenBytes + 2 * i + 1];
+                        break;
+                    }
+                    case ASN_UTF8STRING:
+                    {
+                        LPWSTR str = (LPWSTR)value->Value.pbData;
+
+                        value->Value.cbData = MultiByteToWideChar(CP_UTF8, 0,
+                         (LPSTR)pbEncoded + 1 + lenBytes, dataLen, 
+                         str, bytesNeeded - sizeof(CERT_NAME_VALUE)) * 2;
+                        break;
+                    }
                     }
                 }
                 else
@@ -1395,6 +1451,179 @@ static BOOL WINAPI CRYPT_AsnDecodeNameValue(DWORD dwCertEncodingType,
     return ret;
 }
 
+static BOOL WINAPI CRYPT_AsnDecodeUnicodeNameValueInternal(
+ DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
+ void *pvStructInfo, DWORD *pcbStructInfo)
+{
+    BOOL ret = TRUE;
+    DWORD dataLen;
+    CERT_NAME_VALUE *value = (CERT_NAME_VALUE *)pvStructInfo;
+
+    if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
+    {
+        BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
+        DWORD bytesNeeded = sizeof(CERT_NAME_VALUE), valueType;
+
+        switch (pbEncoded[0])
+        {
+        case ASN_NUMERICSTRING:
+            valueType = CERT_RDN_NUMERIC_STRING;
+            bytesNeeded += (dataLen + 1) * 2;
+            break;
+        case ASN_PRINTABLESTRING:
+            valueType = CERT_RDN_PRINTABLE_STRING;
+            bytesNeeded += (dataLen + 1) * 2;
+            break;
+        case ASN_IA5STRING:
+            valueType = CERT_RDN_IA5_STRING;
+            bytesNeeded += (dataLen + 1) * 2;
+            break;
+        case ASN_T61STRING:
+            valueType = CERT_RDN_T61_STRING;
+            bytesNeeded += (dataLen + 1) * 2;
+            break;
+        case ASN_VIDEOTEXSTRING:
+            valueType = CERT_RDN_VIDEOTEX_STRING;
+            bytesNeeded += (dataLen + 1) * 2;
+            break;
+        case ASN_GRAPHICSTRING:
+            valueType = CERT_RDN_GRAPHIC_STRING;
+            bytesNeeded += (dataLen + 1) * 2;
+            break;
+        case ASN_VISIBLESTRING:
+            valueType = CERT_RDN_VISIBLE_STRING;
+            bytesNeeded += (dataLen + 1) * 2;
+            break;
+        case ASN_GENERALSTRING:
+            valueType = CERT_RDN_GENERAL_STRING;
+            bytesNeeded += (dataLen + 1) * 2;
+            break;
+        case ASN_UNIVERSALSTRING:
+            valueType = CERT_RDN_UNIVERSAL_STRING;
+            bytesNeeded += dataLen / 2 + 2;
+            break;
+        case ASN_BMPSTRING:
+            valueType = CERT_RDN_BMP_STRING;
+            bytesNeeded += dataLen + 2;
+            break;
+        case ASN_UTF8STRING:
+            valueType = CERT_RDN_UTF8_STRING;
+            bytesNeeded += MultiByteToWideChar(CP_UTF8, 0,
+             (LPSTR)pbEncoded + 1 + lenBytes, dataLen, NULL, 0) * 2 + 2;
+            break;
+        default:
+            SetLastError(CRYPT_E_ASN1_BADTAG);
+            ret = FALSE;
+        }
+        if (ret)
+        {
+            if (!value)
+                *pcbStructInfo = bytesNeeded;
+            else if (*pcbStructInfo < bytesNeeded)
+            {
+                *pcbStructInfo = bytesNeeded;
+                SetLastError(ERROR_MORE_DATA);
+                ret = FALSE;
+            }
+            else
+            {
+                *pcbStructInfo = bytesNeeded;
+                value->dwValueType = valueType;
+                if (dataLen)
+                {
+                    DWORD i;
+                    LPWSTR str = (LPWSTR)value->Value.pbData;
+
+                    assert(value->Value.pbData);
+                    switch (pbEncoded[0])
+                    {
+                    case ASN_NUMERICSTRING:
+                    case ASN_PRINTABLESTRING:
+                    case ASN_IA5STRING:
+                    case ASN_T61STRING:
+                    case ASN_VIDEOTEXSTRING:
+                    case ASN_GRAPHICSTRING:
+                    case ASN_VISIBLESTRING:
+                    case ASN_GENERALSTRING:
+                        value->Value.cbData = dataLen * 2 + 2;
+                        for (i = 0; i < dataLen; i++)
+                            str[i] = pbEncoded[1 + lenBytes + i];
+                        str[i] = 0;
+                        break;
+                    case ASN_UNIVERSALSTRING:
+                        value->Value.cbData = dataLen / 2 + 2;
+                        for (i = 0; i < dataLen / 4; i++)
+                            str[i] = (pbEncoded[1 + lenBytes + 2 * i + 2] << 8)
+                             | pbEncoded[1 + lenBytes + 2 * i + 3];
+                        str[i] = 0;
+                        break;
+                    case ASN_BMPSTRING:
+                        value->Value.cbData = dataLen + 2;
+                        for (i = 0; i < dataLen / 2; i++)
+                            str[i] = (pbEncoded[1 + lenBytes + 2 * i] << 8) |
+                             pbEncoded[1 + lenBytes + 2 * i + 1];
+                        str[i] = 0;
+                        break;
+                    case ASN_UTF8STRING:
+                        value->Value.cbData = MultiByteToWideChar(CP_UTF8, 0,
+                         (LPSTR)pbEncoded + 1 + lenBytes, dataLen, 
+                         str, bytesNeeded - sizeof(CERT_NAME_VALUE)) * 2;
+                        str[value->Value.cbData / 2] = 0;
+                        value->Value.cbData += 2;
+                        break;
+                    }
+                }
+                else
+                {
+                    value->Value.cbData = 0;
+                    value->Value.pbData = NULL;
+                }
+            }
+        }
+    }
+    return ret;
+}
+
+static BOOL WINAPI CRYPT_AsnDecodeUnicodeNameValue(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
+ PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+{
+    BOOL ret = TRUE;
+
+    __TRY
+    {
+        ret = CRYPT_AsnDecodeUnicodeNameValueInternal(dwCertEncodingType,
+         lpszStructType, pbEncoded, cbEncoded,
+         dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, pcbStructInfo);
+        if (ret && pvStructInfo)
+        {
+            ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
+             pcbStructInfo, *pcbStructInfo);
+            if (ret)
+            {
+                CERT_NAME_VALUE *value;
+
+                if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
+                    pvStructInfo = *(BYTE **)pvStructInfo;
+                value = (CERT_NAME_VALUE *)pvStructInfo;
+                value->Value.pbData = ((BYTE *)value + sizeof(CERT_NAME_VALUE));
+                ret = CRYPT_AsnDecodeUnicodeNameValueInternal(
+                 dwCertEncodingType, lpszStructType, pbEncoded, cbEncoded,
+                 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
+                 pcbStructInfo);
+            }
+        }
+    }
+    __EXCEPT_PAGE_FAULT
+    {
+        SetLastError(STATUS_ACCESS_VIOLATION);
+        ret = FALSE;
+    }
+    __ENDTRY
+    return ret;
+}
+
 static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(DWORD dwCertEncodingType,
  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
@@ -3190,6 +3419,9 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
         case (WORD)RSA_CSP_PUBLICKEYBLOB:
             decodeFunc = CRYPT_AsnDecodeRsaPubKey;
             break;
+        case (WORD)X509_UNICODE_NAME_VALUE:
+            decodeFunc = CRYPT_AsnDecodeUnicodeNameValue;
+            break;
         case (WORD)X509_OCTET_STRING:
             decodeFunc = CRYPT_AsnDecodeOctets;
             break;
index 2f4e531..d1c8ff7 100644 (file)
@@ -46,6 +46,7 @@
 #include "snmp.h"
 #include "wine/debug.h"
 #include "wine/exception.h"
+#include "wine/unicode.h"
 #include "crypt32_private.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
@@ -163,6 +164,8 @@ static BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags,
         SetLastError(ERROR_MORE_DATA);
         ret = FALSE;
     }
+    else
+        *pcbEncoded = bytesNeeded;
     return ret;
 }
 
@@ -381,18 +384,18 @@ static BOOL WINAPI CRYPT_CopyEncodedBlob(DWORD dwCertEncodingType,
         *pcbEncoded = blob->cbData;
         ret = TRUE;
     }
-    else if (*pcbEncoded < blob->cbData)
-    {
-        *pcbEncoded = blob->cbData;
-        SetLastError(ERROR_MORE_DATA);
-        ret = FALSE;
-    }
     else
     {
-        if (blob->cbData)
-            memcpy(pbEncoded, blob->pbData, blob->cbData);
-        *pcbEncoded = blob->cbData;
-        ret = TRUE;
+        if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
+         pcbEncoded, blob->cbData)))
+        {
+            if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
+                pbEncoded = *(BYTE **)pbEncoded;
+            if (blob->cbData)
+                memcpy(pbEncoded, blob->pbData, blob->cbData);
+            *pcbEncoded = blob->cbData;
+            ret = TRUE;
+        }
     }
     return ret;
 }
@@ -910,6 +913,104 @@ static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
     return ret;
 }
 
+static BOOL CRYPT_AsnEncodeStringCoerce(const CERT_NAME_VALUE *value,
+ BYTE tag, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
+ DWORD *pcbEncoded)
+{
+    BOOL ret = TRUE;
+    LPCSTR str = (LPCSTR)value->Value.pbData;
+    DWORD bytesNeeded, lenBytes, encodedLen;
+
+    encodedLen = value->Value.cbData ? value->Value.cbData : lstrlenA(str);
+    CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
+    bytesNeeded = 1 + lenBytes + encodedLen;
+    if (!pbEncoded)
+        *pcbEncoded = bytesNeeded;
+    else
+    {
+        if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
+         pbEncoded, pcbEncoded, bytesNeeded)))
+        {
+            if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
+                pbEncoded = *(BYTE **)pbEncoded;
+            *pbEncoded++ = tag;
+            CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
+            pbEncoded += lenBytes;
+            memcpy(pbEncoded, str, encodedLen);
+        }
+    }
+    return ret;
+}
+
+static BOOL CRYPT_AsnEncodeBMPString(const CERT_NAME_VALUE *value,
+ DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
+ DWORD *pcbEncoded)
+{
+    BOOL ret = TRUE;
+    LPCWSTR str = (LPCWSTR)value->Value.pbData;
+    DWORD bytesNeeded, lenBytes, strLen;
+
+    strLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
+     lstrlenW(str);
+    CRYPT_EncodeLen(strLen * 2, NULL, &lenBytes);
+    bytesNeeded = 1 + lenBytes + strLen * 2;
+    if (!pbEncoded)
+        *pcbEncoded = bytesNeeded;
+    else
+    {
+        if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
+         pbEncoded, pcbEncoded, bytesNeeded)))
+        {
+            DWORD i;
+
+            if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
+                pbEncoded = *(BYTE **)pbEncoded;
+            *pbEncoded++ = ASN_BMPSTRING;
+            CRYPT_EncodeLen(strLen * 2, pbEncoded, &lenBytes);
+            pbEncoded += lenBytes;
+            for (i = 0; i < strLen; i++)
+            {
+                *pbEncoded++ = (str[i] & 0xff00) >> 8;
+                *pbEncoded++ = str[i] & 0x00ff;
+            }
+        }
+    }
+    return ret;
+}
+
+static BOOL CRYPT_AsnEncodeUTF8String(const CERT_NAME_VALUE *value,
+ DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
+ DWORD *pcbEncoded)
+{
+    BOOL ret = TRUE;
+    LPCWSTR str = (LPCWSTR)value->Value.pbData;
+    DWORD bytesNeeded, lenBytes, encodedLen, strLen;
+
+    strLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
+     lstrlenW(str);
+    encodedLen = WideCharToMultiByte(CP_UTF8, 0, str, strLen, NULL, 0, NULL,
+     NULL);
+    CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
+    bytesNeeded = 1 + lenBytes + encodedLen;
+    if (!pbEncoded)
+        *pcbEncoded = bytesNeeded;
+    else
+    {
+        if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
+         pbEncoded, pcbEncoded, bytesNeeded)))
+        {
+            if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
+                pbEncoded = *(BYTE **)pbEncoded;
+            *pbEncoded++ = ASN_UTF8STRING;
+            CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
+            pbEncoded += lenBytes;
+            WideCharToMultiByte(CP_UTF8, 0, str, strLen, (LPSTR)pbEncoded,
+             bytesNeeded - lenBytes - 1, NULL, NULL);
+        }
+    }
+    return ret;
+}
+
 static BOOL WINAPI CRYPT_AsnEncodeNameValue(DWORD dwCertEncodingType,
  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
@@ -918,65 +1019,355 @@ static BOOL WINAPI CRYPT_AsnEncodeNameValue(DWORD dwCertEncodingType,
 
     __TRY
     {
-        BYTE tag;
-        DWORD bytesNeeded, lenBytes, encodedLen;
         const CERT_NAME_VALUE *value = (CERT_NAME_VALUE *)pvStructInfo;
 
         switch (value->dwValueType)
         {
+        case CERT_RDN_ANY_TYPE:
+            /* explicitly disallowed */
+            SetLastError(E_INVALIDARG);
+            ret = FALSE;
+            break;
+        case CERT_RDN_ENCODED_BLOB:
+            ret = CRYPT_CopyEncodedBlob(dwCertEncodingType, NULL,
+             &value->Value, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
+            break;
+        case CERT_RDN_OCTET_STRING:
+            ret = CRYPT_AsnEncodeStringCoerce(value, ASN_OCTETSTRING,
+             dwFlags, pEncodePara, pbEncoded, pcbEncoded);
+            break;
         case CERT_RDN_NUMERIC_STRING:
-            tag = ASN_NUMERICSTRING;
-            encodedLen = value->Value.cbData;
+            ret = CRYPT_AsnEncodeStringCoerce(value, ASN_NUMERICSTRING,
+             dwFlags, pEncodePara, pbEncoded, pcbEncoded);
             break;
         case CERT_RDN_PRINTABLE_STRING:
-            tag = ASN_PRINTABLESTRING;
-            encodedLen = value->Value.cbData;
+            ret = CRYPT_AsnEncodeStringCoerce(value, ASN_PRINTABLESTRING,
+             dwFlags, pEncodePara, pbEncoded, pcbEncoded);
             break;
-        case CERT_RDN_T61_STRING:
-            tag = ASN_T61STRING;
-            encodedLen = value->Value.cbData;
+        case CERT_RDN_TELETEX_STRING:
+            ret = CRYPT_AsnEncodeStringCoerce(value, ASN_T61STRING,
+             dwFlags, pEncodePara, pbEncoded, pcbEncoded);
+            break;
+        case CERT_RDN_VIDEOTEX_STRING:
+            ret = CRYPT_AsnEncodeStringCoerce(value,
+             ASN_VIDEOTEXSTRING, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
             break;
         case CERT_RDN_IA5_STRING:
-            tag = ASN_IA5STRING;
-            encodedLen = value->Value.cbData;
+            ret = CRYPT_AsnEncodeStringCoerce(value, ASN_IA5STRING,
+             dwFlags, pEncodePara, pbEncoded, pcbEncoded);
+            break;
+        case CERT_RDN_GRAPHIC_STRING:
+            ret = CRYPT_AsnEncodeStringCoerce(value, ASN_GRAPHICSTRING,
+             dwFlags, pEncodePara, pbEncoded, pcbEncoded);
+            break;
+        case CERT_RDN_VISIBLE_STRING:
+            ret = CRYPT_AsnEncodeStringCoerce(value, ASN_VISIBLESTRING,
+             dwFlags, pEncodePara, pbEncoded, pcbEncoded);
+            break;
+        case CERT_RDN_GENERAL_STRING:
+            ret = CRYPT_AsnEncodeStringCoerce(value, ASN_GENERALSTRING,
+             dwFlags, pEncodePara, pbEncoded, pcbEncoded);
+            break;
+        case CERT_RDN_UNIVERSAL_STRING:
+            FIXME("CERT_RDN_UNIVERSAL_STRING: unimplemented\n");
+            SetLastError(CRYPT_E_ASN1_CHOICE);
+            ret = FALSE;
+            break;
+        case CERT_RDN_BMP_STRING:
+            ret = CRYPT_AsnEncodeBMPString(value, dwFlags, pEncodePara,
+             pbEncoded, pcbEncoded);
+            break;
+        case CERT_RDN_UTF8_STRING:
+            ret = CRYPT_AsnEncodeUTF8String(value, dwFlags, pEncodePara,
+             pbEncoded, pcbEncoded);
             break;
-        case CERT_RDN_ANY_TYPE:
-            /* explicitly disallowed */
-            SetLastError(E_INVALIDARG);
-            return FALSE;
         default:
-            FIXME("String type %ld unimplemented\n", value->dwValueType);
-            return FALSE;
+            SetLastError(CRYPT_E_ASN1_CHOICE);
+            ret = FALSE;
         }
-        CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
-        bytesNeeded = 1 + lenBytes + encodedLen;
-        if (!pbEncoded)
-            *pcbEncoded = bytesNeeded;
-        else
+    }
+    __EXCEPT_PAGE_FAULT
+    {
+        SetLastError(STATUS_ACCESS_VIOLATION);
+        ret = FALSE;
+    }
+    __ENDTRY
+    return ret;
+}
+
+static BOOL CRYPT_AsnEncodeUnicodeStringCoerce(const CERT_NAME_VALUE *value,
+ BYTE tag, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
+ DWORD *pcbEncoded)
+{
+    BOOL ret = TRUE;
+    LPCWSTR str = (LPCWSTR)value->Value.pbData;
+    DWORD bytesNeeded, lenBytes, encodedLen;
+
+    encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
+     lstrlenW(str);
+    CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
+    bytesNeeded = 1 + lenBytes + encodedLen;
+    if (!pbEncoded)
+        *pcbEncoded = bytesNeeded;
+    else
+    {
+        if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
+         pbEncoded, pcbEncoded, bytesNeeded)))
         {
-            if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
-             pcbEncoded, bytesNeeded)))
+            DWORD i;
+
+            if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
+                pbEncoded = *(BYTE **)pbEncoded;
+            *pbEncoded++ = tag;
+            CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
+            pbEncoded += lenBytes;
+            for (i = 0; i < encodedLen; i++)
+                *pbEncoded++ = (BYTE)str[i];
+        }
+    }
+    return ret;
+}
+
+static BOOL CRYPT_AsnEncodeNumericString(const CERT_NAME_VALUE *value,
+ DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
+ DWORD *pcbEncoded)
+{
+    BOOL ret = TRUE;
+    LPCWSTR str = (LPCWSTR)value->Value.pbData;
+    DWORD bytesNeeded, lenBytes, encodedLen;
+
+    encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
+     lstrlenW(str);
+    CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
+    bytesNeeded = 1 + lenBytes + encodedLen;
+    if (!pbEncoded)
+        *pcbEncoded = bytesNeeded;
+    else
+    {
+        if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
+         pbEncoded, pcbEncoded, bytesNeeded)))
+        {
+            DWORD i;
+
+            if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
+                pbEncoded = *(BYTE **)pbEncoded;
+            *pbEncoded++ = ASN_NUMERICSTRING;
+            CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
+            pbEncoded += lenBytes;
+            for (i = 0; ret && i < encodedLen; i++)
             {
-                if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
-                    pbEncoded = *(BYTE **)pbEncoded;
-                *pbEncoded++ = tag;
-                CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
-                pbEncoded += lenBytes;
-                switch (value->dwValueType)
+                if (isdigitW(str[i]))
+                    *pbEncoded++ = (BYTE)str[i];
+                else
+                {
+                    *pcbEncoded = i;
+                    SetLastError(CRYPT_E_INVALID_NUMERIC_STRING);
+                    ret = FALSE;
+                }
+            }
+        }
+    }
+    return ret;
+}
+
+static inline int isprintableW(WCHAR wc)
+{
+    return isalnumW(wc) || isspaceW(wc) || wc == '\'' || wc == '(' ||
+     wc == ')' || wc == '+' || wc == ',' || wc == '-' || wc == '.' ||
+     wc == '/' || wc == ':' || wc == '=' || wc == '?';
+}
+
+static BOOL CRYPT_AsnEncodePrintableString(const CERT_NAME_VALUE *value,
+ DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
+ DWORD *pcbEncoded)
+{
+    BOOL ret = TRUE;
+    LPCWSTR str = (LPCWSTR)value->Value.pbData;
+    DWORD bytesNeeded, lenBytes, encodedLen;
+
+    encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
+     lstrlenW(str);
+    CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
+    bytesNeeded = 1 + lenBytes + encodedLen;
+    if (!pbEncoded)
+        *pcbEncoded = bytesNeeded;
+    else
+    {
+        if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
+         pbEncoded, pcbEncoded, bytesNeeded)))
+        {
+            DWORD i;
+
+            if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
+                pbEncoded = *(BYTE **)pbEncoded;
+            *pbEncoded++ = ASN_PRINTABLESTRING;
+            CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
+            pbEncoded += lenBytes;
+            for (i = 0; ret && i < encodedLen; i++)
+            {
+                if (isprintableW(str[i]))
+                    *pbEncoded++ = (BYTE)str[i];
+                else
+                {
+                    *pcbEncoded = i;
+                    SetLastError(CRYPT_E_INVALID_PRINTABLE_STRING);
+                    ret = FALSE;
+                }
+            }
+        }
+    }
+    return ret;
+}
+
+static BOOL CRYPT_AsnEncodeIA5String(const CERT_NAME_VALUE *value,
+ DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
+ DWORD *pcbEncoded)
+{
+    BOOL ret = TRUE;
+    LPCWSTR str = (LPCWSTR)value->Value.pbData;
+    DWORD bytesNeeded, lenBytes, encodedLen;
+
+    encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
+     lstrlenW(str);
+    CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
+    bytesNeeded = 1 + lenBytes + encodedLen;
+    if (!pbEncoded)
+        *pcbEncoded = bytesNeeded;
+    else
+    {
+        if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
+         pbEncoded, pcbEncoded, bytesNeeded)))
+        {
+            DWORD i;
+
+            if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
+                pbEncoded = *(BYTE **)pbEncoded;
+            *pbEncoded++ = ASN_IA5STRING;
+            CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
+            pbEncoded += lenBytes;
+            for (i = 0; ret && i < encodedLen; i++)
+            {
+                if (str[i] <= 0x7f)
+                    *pbEncoded++ = (BYTE)str[i];
+                else
                 {
-                case CERT_RDN_NUMERIC_STRING:
-                case CERT_RDN_PRINTABLE_STRING:
-                case CERT_RDN_T61_STRING:
-                case CERT_RDN_IA5_STRING:
-                    memcpy(pbEncoded, value->Value.pbData, value->Value.cbData);
+                    *pcbEncoded = i;
+                    SetLastError(CRYPT_E_INVALID_IA5_STRING);
+                    ret = FALSE;
                 }
             }
         }
     }
+    return ret;
+}
+
+static BOOL CRYPT_AsnEncodeUniversalString(const CERT_NAME_VALUE *value,
+ DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
+ DWORD *pcbEncoded)
+{
+    BOOL ret = TRUE;
+    LPCWSTR str = (LPCWSTR)value->Value.pbData;
+    DWORD bytesNeeded, lenBytes, strLen;
+
+    /* FIXME: doesn't handle composite characters */
+    strLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
+     lstrlenW(str);
+    CRYPT_EncodeLen(strLen * 4, NULL, &lenBytes);
+    bytesNeeded = 1 + lenBytes + strLen * 4;
+    if (!pbEncoded)
+        *pcbEncoded = bytesNeeded;
+    else
+    {
+        if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
+         pbEncoded, pcbEncoded, bytesNeeded)))
+        {
+            DWORD i;
+
+            if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
+                pbEncoded = *(BYTE **)pbEncoded;
+            *pbEncoded++ = ASN_UNIVERSALSTRING;
+            CRYPT_EncodeLen(strLen * 4, pbEncoded, &lenBytes);
+            pbEncoded += lenBytes;
+            for (i = 0; i < strLen; i++)
+            {
+                *pbEncoded++ = 0;
+                *pbEncoded++ = 0;
+                *pbEncoded++ = (BYTE)((str[i] & 0xff00) >> 8);
+                *pbEncoded++ = (BYTE)(str[i] & 0x00ff);
+            }
+        }
+    }
+    return ret;
+}
+
+static BOOL WINAPI CRYPT_AsnEncodeUnicodeNameValue(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
+ PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
+{
+    BOOL ret = FALSE;
+
+    __TRY
+    {
+        const CERT_NAME_VALUE *value = (CERT_NAME_VALUE *)pvStructInfo;
+
+        switch (value->dwValueType)
+        {
+        case CERT_RDN_ANY_TYPE:
+        case CERT_RDN_ENCODED_BLOB:
+        case CERT_RDN_OCTET_STRING:
+            SetLastError(CRYPT_E_NOT_CHAR_STRING);
+            break;
+        case CERT_RDN_NUMERIC_STRING:
+            ret = CRYPT_AsnEncodeNumericString(value, dwFlags, pEncodePara,
+             pbEncoded, pcbEncoded);
+            break;
+        case CERT_RDN_PRINTABLE_STRING:
+            ret = CRYPT_AsnEncodePrintableString(value, dwFlags, pEncodePara,
+             pbEncoded, pcbEncoded);
+            break;
+        case CERT_RDN_TELETEX_STRING:
+            ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_T61STRING,
+             dwFlags, pEncodePara, pbEncoded, pcbEncoded);
+            break;
+        case CERT_RDN_VIDEOTEX_STRING:
+            ret = CRYPT_AsnEncodeUnicodeStringCoerce(value,
+             ASN_VIDEOTEXSTRING, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
+            break;
+        case CERT_RDN_IA5_STRING:
+            ret = CRYPT_AsnEncodeIA5String(value, dwFlags, pEncodePara,
+             pbEncoded, pcbEncoded);
+            break;
+        case CERT_RDN_GRAPHIC_STRING:
+            ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_GRAPHICSTRING,
+             dwFlags, pEncodePara, pbEncoded, pcbEncoded);
+            break;
+        case CERT_RDN_VISIBLE_STRING:
+            ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_VISIBLESTRING,
+             dwFlags, pEncodePara, pbEncoded, pcbEncoded);
+            break;
+        case CERT_RDN_GENERAL_STRING:
+            ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_GENERALSTRING,
+             dwFlags, pEncodePara, pbEncoded, pcbEncoded);
+            break;
+        case CERT_RDN_UNIVERSAL_STRING:
+            ret = CRYPT_AsnEncodeUniversalString(value, dwFlags, pEncodePara,
+             pbEncoded, pcbEncoded);
+            break;
+        case CERT_RDN_BMP_STRING:
+            ret = CRYPT_AsnEncodeBMPString(value, dwFlags, pEncodePara,
+             pbEncoded, pcbEncoded);
+            break;
+        case CERT_RDN_UTF8_STRING:
+            ret = CRYPT_AsnEncodeUTF8String(value, dwFlags, pEncodePara,
+             pbEncoded, pcbEncoded);
+            break;
+        default:
+            SetLastError(CRYPT_E_ASN1_CHOICE);
+        }
+    }
     __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
-        ret = FALSE;
     }
     __ENDTRY
     return ret;
@@ -2396,6 +2787,9 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
         case (WORD)RSA_CSP_PUBLICKEYBLOB:
             encodeFunc = CRYPT_AsnEncodeRsaPubKey;
             break;
+        case (WORD)X509_UNICODE_NAME_VALUE:
+            encodeFunc = CRYPT_AsnEncodeUnicodeNameValue;
+            break;
         case (WORD)X509_OCTET_STRING:
             encodeFunc = CRYPT_AsnEncodeOctets;
             break;
index b0765a7..afcd13f 100644 (file)
@@ -363,6 +363,16 @@ const void *CRYPT_ReadSerializedElement(const BYTE *pbElement, DWORD cbElement,
                             ret = contextInterface->setProp(context,
                              hdr->propID, 0, pbElement);
                             break;
+                        case CERT_KEY_PROV_INFO_PROP_ID:
+                        {
+                            PCRYPT_KEY_PROV_INFO info =
+                             (PCRYPT_KEY_PROV_INFO)pbElement;
+
+                            CRYPT_FixKeyProvInfoPointers(info);
+                            ret = contextInterface->setProp(context,
+                             hdr->propID, 0, pbElement);
+                            break;
+                        }
                         default:
                             FIXME("prop ID %ld: stub\n", hdr->propID);
                         }
index 95b91da..f1cca0e 100644 (file)
@@ -1723,6 +1723,54 @@ static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreA(HCRYPTPROV hCryptProv,
     return ret;
 }
 
+static PWINECRYPT_CERTSTORE CRYPT_FileNameOpenStoreW(HCRYPTPROV hCryptProv,
+ DWORD dwFlags, const void *pvPara)
+{
+    FIXME("(%ld, %08lx, %s): stub\n", hCryptProv, dwFlags,
+     debugstr_w((LPCWSTR)pvPara));
+    return NULL;
+}
+
+static PWINECRYPT_CERTSTORE CRYPT_FileNameOpenStoreA(HCRYPTPROV hCryptProv,
+ DWORD dwFlags, const void *pvPara)
+{
+    int len;
+    PWINECRYPT_CERTSTORE ret = NULL;
+
+    TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
+     debugstr_a((LPCSTR)pvPara));
+
+    if (!pvPara)
+    {
+        SetLastError(ERROR_FILE_NOT_FOUND);
+        return NULL;
+    }
+    len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
+    if (len)
+    {
+        LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
+
+        if (storeName)
+        {
+            MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
+            ret = CRYPT_FileNameOpenStoreW(hCryptProv, dwFlags, storeName);
+            CryptMemFree(storeName);
+        }
+    }
+    return ret;
+}
+
+static PWINECRYPT_CERTSTORE CRYPT_PhysOpenStoreW(HCRYPTPROV hCryptProv,
+ DWORD dwFlags, const void *pvPara)
+{
+    if (dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG)
+        FIXME("(%ld, %08lx, %p): stub\n", hCryptProv, dwFlags, pvPara);
+    else
+        FIXME("(%ld, %08lx, %s): stub\n", hCryptProv, dwFlags,
+         debugstr_w((LPCWSTR)pvPara));
+    return NULL;
+}
+
 HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider,
  DWORD dwMsgAndCertEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags,
  const void* pvPara)
@@ -1743,6 +1791,12 @@ HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider,
         case (int)CERT_STORE_PROV_REG:
             openFunc = CRYPT_RegOpenStore;
             break;
+        case (int)CERT_STORE_PROV_FILENAME_A:
+            openFunc = CRYPT_FileNameOpenStoreA;
+            break;
+        case (int)CERT_STORE_PROV_FILENAME_W:
+            openFunc = CRYPT_FileNameOpenStoreW;
+            break;
         case (int)CERT_STORE_PROV_COLLECTION:
             openFunc = CRYPT_CollectionOpenStore;
             break;
@@ -1758,6 +1812,9 @@ HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider,
         case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_W:
             openFunc = CRYPT_SysRegOpenStoreW;
             break;
+        case (int)CERT_STORE_PROV_PHYSICAL_W:
+            openFunc = CRYPT_PhysOpenStoreW;
+            break;
         default:
             if (LOWORD(lpszStoreProvider))
                 FIXME("unimplemented type %d\n", LOWORD(lpszStoreProvider));
index a80301e..3298652 100644 (file)
@@ -62,6 +62,7 @@ DWORD WINAPI CertRDNValueToStrA(DWORD dwValueType, PCERT_RDN_VALUE_BLOB pValue,
     }
     else
         ret++;
+    TRACE("returning %ld (%s)\n", ret, debugstr_a(psz));
     return ret;
 }
 
@@ -106,9 +107,35 @@ DWORD WINAPI CertRDNValueToStrW(DWORD dwValueType, PCERT_RDN_VALUE_BLOB pValue,
     }
     else
         ret++;
+    TRACE("returning %ld (%s)\n", ret, debugstr_w(psz));
     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 chars;
+
+    TRACE("(%s, %p, %ld)\n", debugstr_a(prefix), psz, csz);
+
+    if (psz)
+    {
+        chars = min(lstrlenA(prefix), csz);
+        memcpy(psz, prefix, chars);
+        csz -= chars;
+        *(psz + chars) = '=';
+        chars++;
+        csz--;
+    }
+    else
+        chars = lstrlenA(prefix) + 1;
+    return chars;
+}
+
 DWORD WINAPI CertNameToStrA(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName,
  DWORD dwStrType, LPSTR psz, DWORD csz)
 {
@@ -147,36 +174,45 @@ DWORD WINAPI CertNameToStrA(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName,
         else
             rdnSep = plusSep;
         rdnSepLen = strlen(rdnSep);
-        for (i = 0; ret < csz && i < info->cRDN; i++)
+        for (i = 0; (!psz || ret < csz) && i < info->cRDN; i++)
         {
-            for (j = 0; ret < csz && j < info->rgRDN[i].cRDNAttr; j++)
+            for (j = 0; (!psz || ret < csz) && j < info->rgRDN[i].cRDNAttr; j++)
             {
                 DWORD chars;
+                char prefixBuf[10]; /* big enough for GivenName */
+                LPCSTR prefix = NULL;
 
                 if ((dwStrType & 0x000000ff) == CERT_OID_NAME_STR)
+                    prefix = info->rgRDN[i].rgRDNAttr[j].pszObjId;
+                else if ((dwStrType & 0x000000ff) == CERT_X500_NAME_STR)
+                {
+                    PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(
+                     CRYPT_OID_INFO_OID_KEY,
+                     info->rgRDN[i].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 = info->rgRDN[i].rgRDNAttr[j].pszObjId;
+                }
+                if (prefix)
                 {
                     /* - 1 is needed to account for the NULL terminator. */
-                    chars = min(
-                     lstrlenA(info->rgRDN[i].rgRDNAttr[j].pszObjId),
-                     csz - ret - 1);
-                    if (psz && chars)
-                        memcpy(psz + ret, info->rgRDN[i].rgRDNAttr[j].pszObjId,
-                         chars);
+                    chars = CRYPT_AddPrefixA(prefix,
+                     psz ? psz + ret : NULL, psz ? csz - ret - 1 : 0);
                     ret += chars;
                     csz -= chars;
-                    if (csz > 1)
-                    {
-                        if (psz)
-                            *(psz + ret) = '=';
-                        ret++;
-                        csz--;
-                    }
                 }
                 /* FIXME: handle quoting */
                 chars = CertRDNValueToStrA(
                  info->rgRDN[i].rgRDNAttr[j].dwValueType, 
                  &info->rgRDN[i].rgRDNAttr[j].Value, psz ? psz + ret : NULL,
-                 csz - ret - 1);
+                 psz ? csz - ret : 0);
                 if (chars)
                     ret += chars - 1;
                 if (j < info->rgRDN[i].cRDNAttr - 1)
@@ -203,9 +239,64 @@ DWORD WINAPI CertNameToStrA(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName,
     }
     else
         ret++;
+    TRACE("Returning %s\n", debugstr_a(psz));
     return ret;
 }
 
+/* Adds the prefix prefix to the wide-character 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.
+ * Assumes the characters in prefix are ASCII (not multibyte characters.)
+ */
+static DWORD CRYPT_AddPrefixAToW(LPCSTR prefix, LPWSTR psz, DWORD csz)
+{
+    DWORD chars;
+
+    TRACE("(%s, %p, %ld)\n", debugstr_a(prefix), psz, csz);
+
+    if (psz)
+    {
+        DWORD i;
+
+        chars = min(lstrlenA(prefix), csz);
+        for (i = 0; i < chars; i++)
+            *(psz + i) = prefix[i];
+        csz -= chars;
+        *(psz + chars) = '=';
+        chars++;
+        csz--;
+    }
+    else
+        chars = lstrlenA(prefix) + 1;
+    return chars;
+}
+
+/* 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_AddPrefixW(LPCWSTR prefix, LPWSTR psz, DWORD csz)
+{
+    DWORD chars;
+
+    TRACE("(%s, %p, %ld)\n", debugstr_w(prefix), psz, csz);
+
+    if (psz)
+    {
+        chars = min(lstrlenW(prefix), csz);
+        memcpy(psz, prefix, chars * sizeof(WCHAR));
+        csz -= chars;
+        *(psz + chars) = '=';
+        chars++;
+        csz--;
+    }
+    else
+        chars = lstrlenW(prefix) + 1;
+    return chars;
+}
+
 DWORD WINAPI CertNameToStrW(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName,
  DWORD dwStrType, LPWSTR psz, DWORD csz)
 {
@@ -244,41 +335,49 @@ DWORD WINAPI CertNameToStrW(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName,
         else
             rdnSep = plusSep;
         rdnSepLen = lstrlenW(rdnSep);
-        for (i = 0; ret < csz && i < info->cRDN; i++)
+        for (i = 0; (!psz || ret < csz) && i < info->cRDN; i++)
         {
-            for (j = 0; ret < csz && j < info->rgRDN[i].cRDNAttr; j++)
+            for (j = 0; (!psz || ret < csz) && j < info->rgRDN[i].cRDNAttr; j++)
             {
                 DWORD chars;
+                LPCSTR prefixA = NULL;
+                LPCWSTR prefixW = NULL;
 
                 if ((dwStrType & 0x000000ff) == CERT_OID_NAME_STR)
+                    prefixA = info->rgRDN[i].rgRDNAttr[j].pszObjId;
+                else if ((dwStrType & 0x000000ff) == CERT_X500_NAME_STR)
+                {
+                    PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(
+                     CRYPT_OID_INFO_OID_KEY,
+                     info->rgRDN[i].rgRDNAttr[j].pszObjId,
+                     CRYPT_RDN_ATTR_OID_GROUP_ID);
+
+                    if (oidInfo)
+                        prefixW = oidInfo->pwszName;
+                    else
+                        prefixA = info->rgRDN[i].rgRDNAttr[j].pszObjId;
+                }
+                if (prefixW)
                 {
                     /* - 1 is needed to account for the NULL terminator. */
-                    chars = min(
-                     lstrlenA(info->rgRDN[i].rgRDNAttr[j].pszObjId),
-                     csz - ret - 1);
-                    if (psz && chars)
-                    {
-                        DWORD k;
-
-                        for (k = 0; k < chars; k++)
-                            *(psz + ret + k) =
-                             info->rgRDN[i].rgRDNAttr[j].pszObjId[k];
-                    }
+                    chars = CRYPT_AddPrefixW(prefixW,
+                     psz ? psz + ret : NULL, psz ? csz - ret - 1 : 0);
+                    ret += chars;
+                    csz -= chars;
+                }
+                else if (prefixA)
+                {
+                    /* - 1 is needed to account for the NULL terminator. */
+                    chars = CRYPT_AddPrefixAToW(prefixA,
+                     psz ? psz + ret : NULL, psz ? csz - ret - 1 : 0);
                     ret += chars;
                     csz -= chars;
-                    if (csz > 1)
-                    {
-                        if (psz)
-                            *(psz + ret) = '=';
-                        ret++;
-                        csz--;
-                    }
                 }
                 /* FIXME: handle quoting */
                 chars = CertRDNValueToStrW(
                  info->rgRDN[i].rgRDNAttr[j].dwValueType, 
                  &info->rgRDN[i].rgRDNAttr[j].Value, psz ? psz + ret : NULL,
-                 csz - ret - 1);
+                 psz ? csz - ret : 0);
                 if (chars)
                     ret += chars - 1;
                 if (j < info->rgRDN[i].cRDNAttr - 1)
@@ -305,6 +404,7 @@ DWORD WINAPI CertNameToStrW(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName,
     }
     else
         ret++;
+    TRACE("Returning %s\n", debugstr_w(psz));
     return ret;
 }