xref: /reactos/dll/win32/crypt32/str.c (revision 19b18ce2)
1 /*
2  * Copyright 2006 Juan Lang for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18 #include <stdarg.h>
19 
20 #define NONAMELESSUNION
21 
22 #include "windef.h"
23 #include "winbase.h"
24 #include "winnls.h"
25 #include "winuser.h"
26 #include "wincrypt.h"
27 #include "wine/debug.h"
28 #include "wine/unicode.h"
29 
30 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
31 
32 DWORD WINAPI CertRDNValueToStrA(DWORD dwValueType, PCERT_RDN_VALUE_BLOB pValue,
33  LPSTR psz, DWORD csz)
34 {
35     DWORD ret = 0, len;
36 
37     TRACE("(%d, %p, %p, %d)\n", dwValueType, pValue, psz, csz);
38 
39     switch (dwValueType)
40     {
41     case CERT_RDN_ANY_TYPE:
42         break;
43     case CERT_RDN_NUMERIC_STRING:
44     case CERT_RDN_PRINTABLE_STRING:
45     case CERT_RDN_TELETEX_STRING:
46     case CERT_RDN_VIDEOTEX_STRING:
47     case CERT_RDN_IA5_STRING:
48     case CERT_RDN_GRAPHIC_STRING:
49     case CERT_RDN_VISIBLE_STRING:
50     case CERT_RDN_GENERAL_STRING:
51         len = pValue->cbData;
52         if (!psz || !csz)
53             ret = len;
54         else
55         {
56             DWORD chars = min(len, csz - 1);
57 
58             if (chars)
59             {
60                 memcpy(psz, pValue->pbData, chars);
61                 ret += chars;
62                 csz -= chars;
63             }
64         }
65         break;
66     case CERT_RDN_BMP_STRING:
67     case CERT_RDN_UTF8_STRING:
68         len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)pValue->pbData,
69          pValue->cbData / sizeof(WCHAR), NULL, 0, NULL, NULL);
70         if (!psz || !csz)
71             ret = len;
72         else
73         {
74             DWORD chars = min(pValue->cbData / sizeof(WCHAR), csz - 1);
75 
76             if (chars)
77             {
78                 ret = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)pValue->pbData,
79                  chars, psz, csz - 1, NULL, NULL);
80                 csz -= ret;
81             }
82         }
83         break;
84     default:
85         FIXME("string type %d unimplemented\n", dwValueType);
86     }
87     if (psz && csz)
88     {
89         *(psz + ret) = '\0';
90         csz--;
91         ret++;
92     }
93     else
94         ret++;
95     TRACE("returning %d (%s)\n", ret, debugstr_a(psz));
96     return ret;
97 }
98 
99 DWORD WINAPI CertRDNValueToStrW(DWORD dwValueType, PCERT_RDN_VALUE_BLOB pValue,
100  LPWSTR psz, DWORD csz)
101 {
102     DWORD ret = 0, len, i, strLen;
103 
104     TRACE("(%d, %p, %p, %d)\n", dwValueType, pValue, psz, csz);
105 
106     switch (dwValueType)
107     {
108     case CERT_RDN_ANY_TYPE:
109         break;
110     case CERT_RDN_NUMERIC_STRING:
111     case CERT_RDN_PRINTABLE_STRING:
112     case CERT_RDN_TELETEX_STRING:
113     case CERT_RDN_VIDEOTEX_STRING:
114     case CERT_RDN_IA5_STRING:
115     case CERT_RDN_GRAPHIC_STRING:
116     case CERT_RDN_VISIBLE_STRING:
117     case CERT_RDN_GENERAL_STRING:
118         len = pValue->cbData;
119         if (!psz || !csz)
120             ret = len;
121         else
122         {
123             WCHAR *ptr = psz;
124 
125             for (i = 0; i < pValue->cbData && ptr - psz < csz; ptr++, i++)
126                 *ptr = pValue->pbData[i];
127             ret = ptr - psz;
128         }
129         break;
130     case CERT_RDN_BMP_STRING:
131     case CERT_RDN_UTF8_STRING:
132         strLen = len = pValue->cbData / sizeof(WCHAR);
133         if (!psz || !csz)
134             ret = len;
135         else
136         {
137             WCHAR *ptr = psz;
138 
139             for (i = 0; i < strLen && ptr - psz < csz; ptr++, i++)
140                 *ptr = ((LPCWSTR)pValue->pbData)[i];
141             ret = ptr - psz;
142         }
143         break;
144     default:
145         FIXME("string type %d unimplemented\n", dwValueType);
146     }
147     if (psz && csz)
148     {
149         *(psz + ret) = '\0';
150         csz--;
151         ret++;
152     }
153     else
154         ret++;
155     TRACE("returning %d (%s)\n", ret, debugstr_w(psz));
156     return ret;
157 }
158 
159 static inline BOOL is_quotable_char(char c)
160 {
161     switch(c)
162     {
163     case '+':
164     case ',':
165     case '"':
166     case '=':
167     case '<':
168     case '>':
169     case ';':
170     case '#':
171     case '\n':
172         return TRUE;
173     default:
174         return FALSE;
175     }
176 }
177 
178 static DWORD quote_rdn_value_to_str_a(DWORD dwValueType,
179  PCERT_RDN_VALUE_BLOB pValue, LPSTR psz, DWORD csz)
180 {
181     DWORD ret = 0, len, i;
182     BOOL needsQuotes = FALSE;
183 
184     TRACE("(%d, %p, %p, %d)\n", dwValueType, pValue, psz, csz);
185 
186     switch (dwValueType)
187     {
188     case CERT_RDN_ANY_TYPE:
189         break;
190     case CERT_RDN_NUMERIC_STRING:
191     case CERT_RDN_PRINTABLE_STRING:
192     case CERT_RDN_TELETEX_STRING:
193     case CERT_RDN_VIDEOTEX_STRING:
194     case CERT_RDN_IA5_STRING:
195     case CERT_RDN_GRAPHIC_STRING:
196     case CERT_RDN_VISIBLE_STRING:
197     case CERT_RDN_GENERAL_STRING:
198         len = pValue->cbData;
199         if (pValue->cbData && isspace(pValue->pbData[0]))
200             needsQuotes = TRUE;
201         if (pValue->cbData && isspace(pValue->pbData[pValue->cbData - 1]))
202             needsQuotes = TRUE;
203         for (i = 0; i < pValue->cbData; i++)
204         {
205             if (is_quotable_char(pValue->pbData[i]))
206                 needsQuotes = TRUE;
207             if (pValue->pbData[i] == '"')
208                 len += 1;
209         }
210         if (needsQuotes)
211             len += 2;
212         if (!psz || !csz)
213             ret = len;
214         else
215         {
216             char *ptr = psz;
217 
218             if (needsQuotes)
219                 *ptr++ = '"';
220             for (i = 0; i < pValue->cbData && ptr - psz < csz; ptr++, i++)
221             {
222                 *ptr = pValue->pbData[i];
223                 if (pValue->pbData[i] == '"' && ptr - psz < csz - 1)
224                     *(++ptr) = '"';
225             }
226             if (needsQuotes && ptr - psz < csz)
227                 *ptr++ = '"';
228             ret = ptr - psz;
229         }
230         break;
231     case CERT_RDN_BMP_STRING:
232     case CERT_RDN_UTF8_STRING:
233         len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)pValue->pbData,
234          pValue->cbData / sizeof(WCHAR), NULL, 0, NULL, NULL);
235         if (pValue->cbData && isspaceW(((LPCWSTR)pValue->pbData)[0]))
236             needsQuotes = TRUE;
237         if (pValue->cbData &&
238          isspaceW(((LPCWSTR)pValue->pbData)[pValue->cbData / sizeof(WCHAR)-1]))
239             needsQuotes = TRUE;
240         for (i = 0; i < pValue->cbData / sizeof(WCHAR); i++)
241         {
242             if (is_quotable_char(((LPCWSTR)pValue->pbData)[i]))
243                 needsQuotes = TRUE;
244             if (((LPCWSTR)pValue->pbData)[i] == '"')
245                 len += 1;
246         }
247         if (needsQuotes)
248             len += 2;
249         if (!psz || !csz)
250             ret = len;
251         else
252         {
253             char *dst = psz;
254 
255             if (needsQuotes)
256                 *dst++ = '"';
257             for (i = 0; i < pValue->cbData / sizeof(WCHAR) &&
258              dst - psz < csz; dst++, i++)
259             {
260                 LPCWSTR src = (LPCWSTR)pValue->pbData + i;
261 
262                 WideCharToMultiByte(CP_ACP, 0, src, 1, dst,
263                  csz - (dst - psz) - 1, NULL, NULL);
264                 if (*src == '"' && dst - psz < csz - 1)
265                     *(++dst) = '"';
266             }
267             if (needsQuotes && dst - psz < csz)
268                 *dst++ = '"';
269             ret = dst - psz;
270         }
271         break;
272     default:
273         FIXME("string type %d unimplemented\n", dwValueType);
274     }
275     if (psz && csz)
276     {
277         *(psz + ret) = '\0';
278         csz--;
279         ret++;
280     }
281     else
282         ret++;
283     TRACE("returning %d (%s)\n", ret, debugstr_a(psz));
284     return ret;
285 }
286 
287 static DWORD quote_rdn_value_to_str_w(DWORD dwValueType,
288  PCERT_RDN_VALUE_BLOB pValue, LPWSTR psz, DWORD csz)
289 {
290     DWORD ret = 0, len, i, strLen;
291     BOOL needsQuotes = FALSE;
292 
293     TRACE("(%d, %p, %p, %d)\n", dwValueType, pValue, psz, csz);
294 
295     switch (dwValueType)
296     {
297     case CERT_RDN_ANY_TYPE:
298         break;
299     case CERT_RDN_NUMERIC_STRING:
300     case CERT_RDN_PRINTABLE_STRING:
301     case CERT_RDN_TELETEX_STRING:
302     case CERT_RDN_VIDEOTEX_STRING:
303     case CERT_RDN_IA5_STRING:
304     case CERT_RDN_GRAPHIC_STRING:
305     case CERT_RDN_VISIBLE_STRING:
306     case CERT_RDN_GENERAL_STRING:
307         len = pValue->cbData;
308         if (pValue->cbData && isspace(pValue->pbData[0]))
309             needsQuotes = TRUE;
310         if (pValue->cbData && isspace(pValue->pbData[pValue->cbData - 1]))
311             needsQuotes = TRUE;
312         for (i = 0; i < pValue->cbData; i++)
313         {
314             if (is_quotable_char(pValue->pbData[i]))
315                 needsQuotes = TRUE;
316             if (pValue->pbData[i] == '"')
317                 len += 1;
318         }
319         if (needsQuotes)
320             len += 2;
321         if (!psz || !csz)
322             ret = len;
323         else
324         {
325             WCHAR *ptr = psz;
326 
327             if (needsQuotes)
328                 *ptr++ = '"';
329             for (i = 0; i < pValue->cbData && ptr - psz < csz; ptr++, i++)
330             {
331                 *ptr = pValue->pbData[i];
332                 if (pValue->pbData[i] == '"' && ptr - psz < csz - 1)
333                     *(++ptr) = '"';
334             }
335             if (needsQuotes && ptr - psz < csz)
336                 *ptr++ = '"';
337             ret = ptr - psz;
338         }
339         break;
340     case CERT_RDN_BMP_STRING:
341     case CERT_RDN_UTF8_STRING:
342         strLen = len = pValue->cbData / sizeof(WCHAR);
343         if (pValue->cbData && isspace(pValue->pbData[0]))
344             needsQuotes = TRUE;
345         if (pValue->cbData && isspace(pValue->pbData[strLen - 1]))
346             needsQuotes = TRUE;
347         for (i = 0; i < strLen; i++)
348         {
349             if (is_quotable_char(((LPCWSTR)pValue->pbData)[i]))
350                 needsQuotes = TRUE;
351             if (((LPCWSTR)pValue->pbData)[i] == '"')
352                 len += 1;
353         }
354         if (needsQuotes)
355             len += 2;
356         if (!psz || !csz)
357             ret = len;
358         else
359         {
360             WCHAR *ptr = psz;
361 
362             if (needsQuotes)
363                 *ptr++ = '"';
364             for (i = 0; i < strLen && ptr - psz < csz; ptr++, i++)
365             {
366                 *ptr = ((LPCWSTR)pValue->pbData)[i];
367                 if (((LPCWSTR)pValue->pbData)[i] == '"' && ptr - psz < csz - 1)
368                     *(++ptr) = '"';
369             }
370             if (needsQuotes && ptr - psz < csz)
371                 *ptr++ = '"';
372             ret = ptr - psz;
373         }
374         break;
375     default:
376         FIXME("string type %d unimplemented\n", dwValueType);
377     }
378     if (psz && csz)
379     {
380         *(psz + ret) = '\0';
381         csz--;
382         ret++;
383     }
384     else
385         ret++;
386     TRACE("returning %d (%s)\n", ret, debugstr_w(psz));
387     return ret;
388 }
389 
390 /* Adds the prefix prefix to the string pointed to by psz, followed by the
391  * character '='.  Copies no more than csz characters.  Returns the number of
392  * characters copied.  If psz is NULL, returns the number of characters that
393  * would be copied.
394  */
395 static DWORD CRYPT_AddPrefixA(LPCSTR prefix, LPSTR psz, DWORD csz)
396 {
397     DWORD chars;
398 
399     TRACE("(%s, %p, %d)\n", debugstr_a(prefix), psz, csz);
400 
401     if (psz)
402     {
403         chars = min(strlen(prefix), csz);
404         memcpy(psz, prefix, chars);
405         *(psz + chars) = '=';
406         chars++;
407     }
408     else
409         chars = lstrlenA(prefix) + 1;
410     return chars;
411 }
412 
413 DWORD WINAPI CertNameToStrA(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName,
414  DWORD dwStrType, LPSTR psz, DWORD csz)
415 {
416     static const DWORD unsupportedFlags = CERT_NAME_STR_NO_QUOTING_FLAG |
417      CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG;
418     static const char commaSep[] = ", ";
419     static const char semiSep[] = "; ";
420     static const char crlfSep[] = "\r\n";
421     static const char plusSep[] = " + ";
422     static const char spaceSep[] = " ";
423     DWORD ret = 0, bytes = 0;
424     BOOL bRet;
425     CERT_NAME_INFO *info;
426 
427     TRACE("(%d, %p, %08x, %p, %d)\n", dwCertEncodingType, pName, dwStrType,
428      psz, csz);
429     if (dwStrType & unsupportedFlags)
430         FIXME("unsupported flags: %08x\n", dwStrType & unsupportedFlags);
431 
432     bRet = CryptDecodeObjectEx(dwCertEncodingType, X509_NAME, pName->pbData,
433      pName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &bytes);
434     if (bRet)
435     {
436         DWORD i, j, sepLen, rdnSepLen;
437         LPCSTR sep, rdnSep;
438         BOOL reverse = dwStrType & CERT_NAME_STR_REVERSE_FLAG;
439         const CERT_RDN *rdn = info->rgRDN;
440 
441         if(reverse && info->cRDN > 1) rdn += (info->cRDN - 1);
442 
443         if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG)
444             sep = semiSep;
445         else if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
446             sep = crlfSep;
447         else
448             sep = commaSep;
449         sepLen = strlen(sep);
450         if (dwStrType & CERT_NAME_STR_NO_PLUS_FLAG)
451             rdnSep = spaceSep;
452         else
453             rdnSep = plusSep;
454         rdnSepLen = strlen(rdnSep);
455         for (i = 0; (!psz || ret < csz) && i < info->cRDN; i++)
456         {
457             for (j = 0; (!psz || ret < csz) && j < rdn->cRDNAttr; j++)
458             {
459                 DWORD chars;
460                 char prefixBuf[13]; /* big enough for SERIALNUMBER */
461                 LPCSTR prefix = NULL;
462 
463                 if ((dwStrType & 0x000000ff) == CERT_OID_NAME_STR)
464                     prefix = rdn->rgRDNAttr[j].pszObjId;
465                 else if ((dwStrType & 0x000000ff) == CERT_X500_NAME_STR)
466                 {
467                     PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(
468                      CRYPT_OID_INFO_OID_KEY,
469                      rdn->rgRDNAttr[j].pszObjId,
470                      CRYPT_RDN_ATTR_OID_GROUP_ID);
471 
472                     if (oidInfo)
473                     {
474                         WideCharToMultiByte(CP_ACP, 0, oidInfo->pwszName, -1,
475                          prefixBuf, sizeof(prefixBuf), NULL, NULL);
476                         prefix = prefixBuf;
477                     }
478                     else
479                         prefix = rdn->rgRDNAttr[j].pszObjId;
480                 }
481                 if (prefix)
482                 {
483                     /* - 1 is needed to account for the NULL terminator. */
484                     chars = CRYPT_AddPrefixA(prefix,
485                      psz ? psz + ret : NULL, psz ? csz - ret - 1 : 0);
486                     ret += chars;
487                 }
488                 chars = quote_rdn_value_to_str_a(
489                  rdn->rgRDNAttr[j].dwValueType,
490                  &rdn->rgRDNAttr[j].Value, psz ? psz + ret : NULL,
491                  psz ? csz - ret : 0);
492                 if (chars)
493                     ret += chars - 1;
494                 if (j < rdn->cRDNAttr - 1)
495                 {
496                     if (psz && ret < csz - rdnSepLen - 1)
497                         memcpy(psz + ret, rdnSep, rdnSepLen);
498                     ret += rdnSepLen;
499                 }
500             }
501             if (i < info->cRDN - 1)
502             {
503                 if (psz && ret < csz - sepLen - 1)
504                     memcpy(psz + ret, sep, sepLen);
505                 ret += sepLen;
506             }
507             if(reverse) rdn--;
508             else rdn++;
509         }
510         LocalFree(info);
511     }
512     if (psz && csz)
513     {
514         *(psz + ret) = '\0';
515         ret++;
516     }
517     else
518         ret++;
519     TRACE("Returning %s\n", debugstr_a(psz));
520     return ret;
521 }
522 
523 /* Adds the prefix prefix to the wide-character string pointed to by psz,
524  * followed by the character '='.  Copies no more than csz characters.  Returns
525  * the number of characters copied.  If psz is NULL, returns the number of
526  * characters that would be copied.
527  * Assumes the characters in prefix are ASCII (not multibyte characters.)
528  */
529 static DWORD CRYPT_AddPrefixAToW(LPCSTR prefix, LPWSTR psz, DWORD csz)
530 {
531     DWORD chars;
532 
533     TRACE("(%s, %p, %d)\n", debugstr_a(prefix), psz, csz);
534 
535     if (psz)
536     {
537         DWORD i;
538 
539         chars = min(strlen(prefix), csz);
540         for (i = 0; i < chars; i++)
541             *(psz + i) = prefix[i];
542         *(psz + chars) = '=';
543         chars++;
544     }
545     else
546         chars = lstrlenA(prefix) + 1;
547     return chars;
548 }
549 
550 /* Adds the prefix prefix to the string pointed to by psz, followed by the
551  * character '='.  Copies no more than csz characters.  Returns the number of
552  * characters copied.  If psz is NULL, returns the number of characters that
553  * would be copied.
554  */
555 static DWORD CRYPT_AddPrefixW(LPCWSTR prefix, LPWSTR psz, DWORD csz)
556 {
557     DWORD chars;
558 
559     TRACE("(%s, %p, %d)\n", debugstr_w(prefix), psz, csz);
560 
561     if (psz)
562     {
563         chars = min(strlenW(prefix), csz);
564         memcpy(psz, prefix, chars * sizeof(WCHAR));
565         *(psz + chars) = '=';
566         chars++;
567     }
568     else
569         chars = lstrlenW(prefix) + 1;
570     return chars;
571 }
572 
573 static const WCHAR indent[] = { ' ',' ',' ',' ',' ',0 };
574 
575 DWORD cert_name_to_str_with_indent(DWORD dwCertEncodingType, DWORD indentLevel,
576  const CERT_NAME_BLOB *pName, DWORD dwStrType, LPWSTR psz, DWORD csz)
577 {
578     static const DWORD unsupportedFlags = CERT_NAME_STR_NO_QUOTING_FLAG |
579      CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG;
580     static const WCHAR commaSep[] = { ',',' ',0 };
581     static const WCHAR semiSep[] = { ';',' ',0 };
582     static const WCHAR crlfSep[] = { '\r','\n',0 };
583     static const WCHAR plusSep[] = { ' ','+',' ',0 };
584     static const WCHAR spaceSep[] = { ' ',0 };
585     DWORD ret = 0, bytes = 0;
586     BOOL bRet;
587     CERT_NAME_INFO *info;
588 
589     if (dwStrType & unsupportedFlags)
590         FIXME("unsupported flags: %08x\n", dwStrType & unsupportedFlags);
591 
592     bRet = CryptDecodeObjectEx(dwCertEncodingType, X509_NAME, pName->pbData,
593      pName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &bytes);
594     if (bRet)
595     {
596         DWORD i, j, sepLen, rdnSepLen;
597         LPCWSTR sep, rdnSep;
598         BOOL reverse = dwStrType & CERT_NAME_STR_REVERSE_FLAG;
599         const CERT_RDN *rdn = info->rgRDN;
600 
601         if(reverse && info->cRDN > 1) rdn += (info->cRDN - 1);
602 
603         if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG)
604             sep = semiSep;
605         else if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
606             sep = crlfSep;
607         else
608             sep = commaSep;
609         sepLen = lstrlenW(sep);
610         if (dwStrType & CERT_NAME_STR_NO_PLUS_FLAG)
611             rdnSep = spaceSep;
612         else
613             rdnSep = plusSep;
614         rdnSepLen = lstrlenW(rdnSep);
615         for (i = 0; (!psz || ret < csz) && i < info->cRDN; i++)
616         {
617             for (j = 0; (!psz || ret < csz) && j < rdn->cRDNAttr; j++)
618             {
619                 DWORD chars;
620                 LPCSTR prefixA = NULL;
621                 LPCWSTR prefixW = NULL;
622 
623                 if ((dwStrType & 0x000000ff) == CERT_OID_NAME_STR)
624                     prefixA = rdn->rgRDNAttr[j].pszObjId;
625                 else if ((dwStrType & 0x000000ff) == CERT_X500_NAME_STR)
626                 {
627                     PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(
628                      CRYPT_OID_INFO_OID_KEY,
629                      rdn->rgRDNAttr[j].pszObjId,
630                      CRYPT_RDN_ATTR_OID_GROUP_ID);
631 
632                     if (oidInfo)
633                         prefixW = oidInfo->pwszName;
634                     else
635                         prefixA = rdn->rgRDNAttr[j].pszObjId;
636                 }
637                 if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
638                 {
639                     DWORD k;
640 
641                     for (k = 0; k < indentLevel; k++)
642                     {
643                         if (psz)
644                         {
645                             chars = min(strlenW(indent), csz - ret - 1);
646                             memcpy(psz + ret, indent, chars * sizeof(WCHAR));
647                         }
648                         else
649                             chars = strlenW(indent);
650                         ret += chars;
651                     }
652                 }
653                 if (prefixW)
654                 {
655                     /* - 1 is needed to account for the NULL terminator. */
656                     chars = CRYPT_AddPrefixW(prefixW,
657                      psz ? psz + ret : NULL, psz ? csz - ret - 1 : 0);
658                     ret += chars;
659                 }
660                 else if (prefixA)
661                 {
662                     /* - 1 is needed to account for the NULL terminator. */
663                     chars = CRYPT_AddPrefixAToW(prefixA,
664                      psz ? psz + ret : NULL, psz ? csz - ret - 1 : 0);
665                     ret += chars;
666                 }
667                 chars = quote_rdn_value_to_str_w(
668                  rdn->rgRDNAttr[j].dwValueType,
669                  &rdn->rgRDNAttr[j].Value, psz ? psz + ret : NULL,
670                  psz ? csz - ret : 0);
671                 if (chars)
672                     ret += chars - 1;
673                 if (j < rdn->cRDNAttr - 1)
674                 {
675                     if (psz && ret < csz - rdnSepLen - 1)
676                         memcpy(psz + ret, rdnSep, rdnSepLen * sizeof(WCHAR));
677                     ret += rdnSepLen;
678                 }
679             }
680             if (i < info->cRDN - 1)
681             {
682                 if (psz && ret < csz - sepLen - 1)
683                     memcpy(psz + ret, sep, sepLen * sizeof(WCHAR));
684                 ret += sepLen;
685             }
686             if(reverse) rdn--;
687             else rdn++;
688         }
689         LocalFree(info);
690     }
691     if (psz && csz)
692     {
693         *(psz + ret) = '\0';
694         ret++;
695     }
696     else
697         ret++;
698     return ret;
699 }
700 
701 DWORD WINAPI CertNameToStrW(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName,
702  DWORD dwStrType, LPWSTR psz, DWORD csz)
703 {
704     BOOL ret;
705 
706     TRACE("(%d, %p, %08x, %p, %d)\n", dwCertEncodingType, pName, dwStrType,
707      psz, csz);
708 
709     ret = cert_name_to_str_with_indent(dwCertEncodingType, 0, pName, dwStrType,
710      psz, csz);
711     TRACE("Returning %s\n", debugstr_w(psz));
712     return ret;
713 }
714 
715 BOOL WINAPI CertStrToNameA(DWORD dwCertEncodingType, LPCSTR pszX500,
716  DWORD dwStrType, void *pvReserved, BYTE *pbEncoded, DWORD *pcbEncoded,
717  LPCSTR *ppszError)
718 {
719     BOOL ret;
720     int len;
721 
722     TRACE("(%08x, %s, %08x, %p, %p, %p, %p)\n", dwCertEncodingType,
723      debugstr_a(pszX500), dwStrType, pvReserved, pbEncoded, pcbEncoded,
724      ppszError);
725 
726     len = MultiByteToWideChar(CP_ACP, 0, pszX500, -1, NULL, 0);
727     if (len)
728     {
729         LPWSTR x500, errorStr;
730 
731         if ((x500 = CryptMemAlloc(len * sizeof(WCHAR))))
732         {
733             MultiByteToWideChar(CP_ACP, 0, pszX500, -1, x500, len);
734             ret = CertStrToNameW(dwCertEncodingType, x500, dwStrType,
735              pvReserved, pbEncoded, pcbEncoded,
736              ppszError ? (LPCWSTR *)&errorStr : NULL);
737             if (ppszError)
738             {
739                 if (!ret)
740                 {
741                     LONG i;
742 
743                     *ppszError = pszX500;
744                     for (i = 0; i < errorStr - x500; i++)
745                         *ppszError = CharNextA(*ppszError);
746                 }
747                 else
748                     *ppszError = NULL;
749             }
750             CryptMemFree(x500);
751         }
752         else
753         {
754             SetLastError(ERROR_OUTOFMEMORY);
755             ret = FALSE;
756         }
757     }
758     else
759     {
760         SetLastError(CRYPT_E_INVALID_X500_STRING);
761         if (ppszError)
762             *ppszError = pszX500;
763         ret = FALSE;
764     }
765     return ret;
766 }
767 
768 struct KeynameKeeper
769 {
770     WCHAR  buf[10]; /* big enough for L"GivenName" */
771     LPWSTR keyName; /* usually = buf, but may be allocated */
772     DWORD  keyLen;  /* full available buffer size in WCHARs */
773 };
774 
775 static void CRYPT_InitializeKeynameKeeper(struct KeynameKeeper *keeper)
776 {
777     keeper->keyName = keeper->buf;
778     keeper->keyLen = sizeof(keeper->buf) / sizeof(keeper->buf[0]);
779 }
780 
781 static void CRYPT_FreeKeynameKeeper(struct KeynameKeeper *keeper)
782 {
783     if (keeper->keyName != keeper->buf)
784         CryptMemFree(keeper->keyName);
785 }
786 
787 struct X500TokenW
788 {
789     LPCWSTR start;
790     LPCWSTR end;
791 };
792 
793 static void CRYPT_KeynameKeeperFromTokenW(struct KeynameKeeper *keeper,
794  const struct X500TokenW *key)
795 {
796     DWORD len = key->end - key->start;
797 
798     if (len >= keeper->keyLen)
799     {
800         CRYPT_FreeKeynameKeeper( keeper );
801         keeper->keyLen = len + 1;
802         keeper->keyName = CryptMemAlloc(keeper->keyLen * sizeof(WCHAR));
803     }
804     memcpy(keeper->keyName, key->start, len * sizeof(WCHAR));
805     keeper->keyName[len] = '\0';
806     TRACE("Keyname is %s\n", debugstr_w(keeper->keyName));
807 }
808 
809 static BOOL CRYPT_GetNextKeyW(LPCWSTR str, struct X500TokenW *token,
810  LPCWSTR *ppszError)
811 {
812     BOOL ret = TRUE;
813 
814     while (*str && isspaceW(*str))
815         str++;
816     if (*str)
817     {
818         token->start = str;
819         while (*str && *str != '=' && !isspaceW(*str))
820             str++;
821         if (*str && (*str == '=' || isspaceW(*str)))
822             token->end = str;
823         else
824         {
825             TRACE("missing equals char at %s\n", debugstr_w(token->start));
826             if (ppszError)
827                 *ppszError = token->start;
828             SetLastError(CRYPT_E_INVALID_X500_STRING);
829             ret = FALSE;
830         }
831     }
832     else
833         token->start = NULL;
834     return ret;
835 }
836 
837 /* Assumes separators are characters in the 0-255 range */
838 static BOOL CRYPT_GetNextValueW(LPCWSTR str, DWORD dwFlags, LPCWSTR separators,
839  WCHAR *separator_used, struct X500TokenW *token, LPCWSTR *ppszError)
840 {
841     BOOL ret = TRUE;
842 
843     TRACE("(%s, %s, %p, %p)\n", debugstr_w(str), debugstr_w(separators), token,
844      ppszError);
845 
846     *separator_used = 0;
847     while (*str && isspaceW(*str))
848         str++;
849     if (*str)
850     {
851         token->start = str;
852         if (!(dwFlags & CERT_NAME_STR_NO_QUOTING_FLAG) && *str == '"')
853         {
854             token->end = NULL;
855             str++;
856             while (!token->end && ret)
857             {
858                 while (*str && *str != '"')
859                     str++;
860                 if (*str == '"')
861                 {
862                     if (*(str + 1) != '"')
863                         token->end = str + 1;
864                     else
865                         str += 2;
866                 }
867                 else
868                 {
869                     TRACE("unterminated quote at %s\n", debugstr_w(str));
870                     if (ppszError)
871                         *ppszError = str;
872                     SetLastError(CRYPT_E_INVALID_X500_STRING);
873                     ret = FALSE;
874                 }
875             }
876         }
877         else
878         {
879             WCHAR map[256] = { 0 };
880 
881             while (*separators)
882                 map[*separators++] = 1;
883             while (*str && (*str >= 0xff || !map[*str]))
884                 str++;
885             token->end = str;
886             if (map[*str]) *separator_used = *str;
887         }
888     }
889     else
890     {
891         TRACE("missing value at %s\n", debugstr_w(str));
892         if (ppszError)
893             *ppszError = str;
894         SetLastError(CRYPT_E_INVALID_X500_STRING);
895         ret = FALSE;
896     }
897     return ret;
898 }
899 
900 /* Encodes the string represented by value as the string type type into the
901  * CERT_NAME_BLOB output.  If there is an error and ppszError is not NULL,
902  * *ppszError is set to the first failing character.  If there is no error,
903  * output's pbData must be freed with LocalFree.
904  */
905 static BOOL CRYPT_EncodeValueWithType(DWORD dwCertEncodingType,
906  const struct X500TokenW *value, PCERT_NAME_BLOB output, DWORD type,
907  LPCWSTR *ppszError)
908 {
909     CERT_NAME_VALUE nameValue = { type, { 0, NULL } };
910     BOOL ret = TRUE;
911 
912     if (value->end > value->start)
913     {
914         LONG i;
915         LPWSTR ptr;
916 
917         nameValue.Value.pbData = CryptMemAlloc((value->end - value->start + 1) *
918          sizeof(WCHAR));
919         if (!nameValue.Value.pbData)
920         {
921             SetLastError(ERROR_OUTOFMEMORY);
922             return FALSE;
923         }
924         ptr = (LPWSTR)nameValue.Value.pbData;
925         for (i = 0; i < value->end - value->start; i++)
926         {
927             *ptr++ = value->start[i];
928             if (value->start[i] == '"')
929                 i++;
930         }
931         /* The string is NULL terminated because of a quirk in encoding
932          * unicode names values:  if the length is given as 0, the value is
933          * assumed to be a NULL-terminated string.
934          */
935         *ptr = 0;
936         nameValue.Value.cbData = (LPBYTE)ptr - nameValue.Value.pbData;
937     }
938     ret = CryptEncodeObjectEx(dwCertEncodingType, X509_UNICODE_NAME_VALUE,
939      &nameValue, CRYPT_ENCODE_ALLOC_FLAG, NULL, &output->pbData,
940      &output->cbData);
941     if (!ret && ppszError)
942     {
943         if (type == CERT_RDN_NUMERIC_STRING &&
944          GetLastError() == CRYPT_E_INVALID_NUMERIC_STRING)
945             *ppszError = value->start + output->cbData;
946         else if (type == CERT_RDN_PRINTABLE_STRING &&
947          GetLastError() == CRYPT_E_INVALID_PRINTABLE_STRING)
948             *ppszError = value->start + output->cbData;
949         else if (type == CERT_RDN_IA5_STRING &&
950          GetLastError() == CRYPT_E_INVALID_IA5_STRING)
951             *ppszError = value->start + output->cbData;
952     }
953     CryptMemFree(nameValue.Value.pbData);
954     return ret;
955 }
956 
957 static BOOL CRYPT_EncodeValue(DWORD dwCertEncodingType,
958  const struct X500TokenW *value, PCERT_NAME_BLOB output, const DWORD *types,
959  LPCWSTR *ppszError)
960 {
961     DWORD i;
962     BOOL ret;
963 
964     ret = FALSE;
965     for (i = 0; !ret && types[i]; i++)
966         ret = CRYPT_EncodeValueWithType(dwCertEncodingType, value, output,
967          types[i], ppszError);
968     return ret;
969 }
970 
971 static BOOL CRYPT_ValueToRDN(DWORD dwCertEncodingType, PCERT_NAME_INFO info,
972  PCCRYPT_OID_INFO keyOID, struct X500TokenW *value, DWORD dwStrType, LPCWSTR *ppszError)
973 {
974     BOOL ret = FALSE;
975 
976     TRACE("OID %s, value %s\n", debugstr_a(keyOID->pszOID),
977      debugstr_wn(value->start, value->end - value->start));
978 
979     if (!info->rgRDN)
980         info->rgRDN = CryptMemAlloc(sizeof(CERT_RDN));
981     else
982         info->rgRDN = CryptMemRealloc(info->rgRDN,
983          (info->cRDN + 1) * sizeof(CERT_RDN));
984     if (info->rgRDN)
985     {
986         /* FIXME: support multiple RDN attrs */
987         info->rgRDN[info->cRDN].rgRDNAttr =
988          CryptMemAlloc(sizeof(CERT_RDN_ATTR));
989         if (info->rgRDN[info->cRDN].rgRDNAttr)
990         {
991             static const DWORD defaultTypes[] = { CERT_RDN_PRINTABLE_STRING,
992              CERT_RDN_BMP_STRING, 0 };
993             const DWORD *types;
994 
995             info->rgRDN[info->cRDN].cRDNAttr = 1;
996             info->rgRDN[info->cRDN].rgRDNAttr[0].pszObjId =
997              (LPSTR)keyOID->pszOID;
998             info->rgRDN[info->cRDN].rgRDNAttr[0].dwValueType =
999              CERT_RDN_ENCODED_BLOB;
1000             if (keyOID->ExtraInfo.cbData)
1001                 types = (const DWORD *)keyOID->ExtraInfo.pbData;
1002             else
1003                 types = defaultTypes;
1004 
1005             /* Remove surrounding quotes */
1006             if (value->start[0] == '"' && !(dwStrType & CERT_NAME_STR_NO_QUOTING_FLAG))
1007             {
1008                 value->start++;
1009                 value->end--;
1010             }
1011             ret = CRYPT_EncodeValue(dwCertEncodingType, value,
1012              &info->rgRDN[info->cRDN].rgRDNAttr[0].Value, types, ppszError);
1013         }
1014         else
1015             SetLastError(ERROR_OUTOFMEMORY);
1016         info->cRDN++;
1017     }
1018     else
1019         SetLastError(ERROR_OUTOFMEMORY);
1020     return ret;
1021 }
1022 
1023 BOOL WINAPI CertStrToNameW(DWORD dwCertEncodingType, LPCWSTR pszX500,
1024  DWORD dwStrType, void *pvReserved, BYTE *pbEncoded, DWORD *pcbEncoded,
1025  LPCWSTR *ppszError)
1026 {
1027     CERT_NAME_INFO info = { 0, NULL };
1028     LPCWSTR str;
1029     struct KeynameKeeper keeper;
1030     DWORD i;
1031     BOOL ret = TRUE;
1032 
1033     TRACE("(%08x, %s, %08x, %p, %p, %p, %p)\n", dwCertEncodingType,
1034      debugstr_w(pszX500), dwStrType, pvReserved, pbEncoded, pcbEncoded,
1035      ppszError);
1036 
1037     CRYPT_InitializeKeynameKeeper(&keeper);
1038     str = pszX500;
1039     while (str && *str && ret)
1040     {
1041         struct X500TokenW token;
1042 
1043         ret = CRYPT_GetNextKeyW(str, &token, ppszError);
1044         if (ret && token.start)
1045         {
1046             PCCRYPT_OID_INFO keyOID;
1047 
1048             CRYPT_KeynameKeeperFromTokenW(&keeper, &token);
1049             keyOID = CryptFindOIDInfo(CRYPT_OID_INFO_NAME_KEY, keeper.keyName,
1050              CRYPT_RDN_ATTR_OID_GROUP_ID);
1051             if (!keyOID)
1052             {
1053                 if (ppszError)
1054                     *ppszError = token.start;
1055                 SetLastError(CRYPT_E_INVALID_X500_STRING);
1056                 ret = FALSE;
1057             }
1058             else
1059             {
1060                 str = token.end;
1061                 while (isspaceW(*str))
1062                     str++;
1063                 if (*str != '=')
1064                 {
1065                     if (ppszError)
1066                         *ppszError = str;
1067                     SetLastError(CRYPT_E_INVALID_X500_STRING);
1068                     ret = FALSE;
1069                 }
1070                 else
1071                 {
1072                     static const WCHAR commaSep[] = { ',',0 };
1073                     static const WCHAR semiSep[] = { ';',0 };
1074                     static const WCHAR crlfSep[] = { '\r','\n',0 };
1075                     static const WCHAR allSepsWithoutPlus[] = { ',',';','\r','\n',0 };
1076                     static const WCHAR allSeps[] = { '+',',',';','\r','\n',0 };
1077                     LPCWSTR sep;
1078                     WCHAR sep_used;
1079 
1080                     str++;
1081                     if (dwStrType & CERT_NAME_STR_COMMA_FLAG)
1082                         sep = commaSep;
1083                     else if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG)
1084                         sep = semiSep;
1085                     else if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
1086                         sep = crlfSep;
1087                     else if (dwStrType & CERT_NAME_STR_NO_PLUS_FLAG)
1088                         sep = allSepsWithoutPlus;
1089                     else
1090                         sep = allSeps;
1091                     ret = CRYPT_GetNextValueW(str, dwStrType, sep, &sep_used, &token,
1092                      ppszError);
1093                     if (ret)
1094                     {
1095                         str = token.end;
1096                         /* if token.end points to the separator, skip it */
1097                         if (str && sep_used && *str == sep_used) str++;
1098 
1099                         ret = CRYPT_ValueToRDN(dwCertEncodingType, &info,
1100                          keyOID, &token, dwStrType, ppszError);
1101                     }
1102                 }
1103             }
1104         }
1105     }
1106     CRYPT_FreeKeynameKeeper(&keeper);
1107     if (ret)
1108     {
1109         if (ppszError)
1110             *ppszError = NULL;
1111         ret = CryptEncodeObjectEx(dwCertEncodingType, X509_NAME, &info,
1112          0, NULL, pbEncoded, pcbEncoded);
1113     }
1114     for (i = 0; i < info.cRDN; i++)
1115     {
1116         DWORD j;
1117 
1118         for (j = 0; j < info.rgRDN[i].cRDNAttr; j++)
1119             LocalFree(info.rgRDN[i].rgRDNAttr[j].Value.pbData);
1120         CryptMemFree(info.rgRDN[i].rgRDNAttr);
1121     }
1122     CryptMemFree(info.rgRDN);
1123     return ret;
1124 }
1125 
1126 DWORD WINAPI CertGetNameStringA(PCCERT_CONTEXT pCertContext, DWORD dwType,
1127  DWORD dwFlags, void *pvTypePara, LPSTR pszNameString, DWORD cchNameString)
1128 {
1129     DWORD ret;
1130 
1131     TRACE("(%p, %d, %08x, %p, %p, %d)\n", pCertContext, dwType, dwFlags,
1132      pvTypePara, pszNameString, cchNameString);
1133 
1134     if (pszNameString)
1135     {
1136         LPWSTR wideName;
1137         DWORD nameLen;
1138 
1139         nameLen = CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara,
1140          NULL, 0);
1141         wideName = CryptMemAlloc(nameLen * sizeof(WCHAR));
1142         if (wideName)
1143         {
1144             CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara,
1145              wideName, nameLen);
1146             nameLen = WideCharToMultiByte(CP_ACP, 0, wideName, nameLen,
1147              pszNameString, cchNameString, NULL, NULL);
1148             if (nameLen <= cchNameString)
1149                 ret = nameLen;
1150             else
1151             {
1152                 pszNameString[cchNameString - 1] = '\0';
1153                 ret = cchNameString;
1154             }
1155             CryptMemFree(wideName);
1156         }
1157         else
1158         {
1159             *pszNameString = '\0';
1160             ret = 1;
1161         }
1162     }
1163     else
1164         ret = CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara,
1165          NULL, 0);
1166     return ret;
1167 }
1168 
1169 /* Searches cert's extensions for the alternate name extension with OID
1170  * altNameOID, and if found, searches it for the alternate name type entryType.
1171  * If found, returns a pointer to the entry, otherwise returns NULL.
1172  * Regardless of whether an entry of the desired type is found, if the
1173  * alternate name extension is present, sets *info to the decoded alternate
1174  * name extension, which you must free using LocalFree.
1175  * The return value is a pointer within *info, so don't free *info before
1176  * you're done with the return value.
1177  */
1178 static PCERT_ALT_NAME_ENTRY cert_find_alt_name_entry(PCCERT_CONTEXT cert,
1179  LPCSTR altNameOID, DWORD entryType, PCERT_ALT_NAME_INFO *info)
1180 {
1181     PCERT_ALT_NAME_ENTRY entry = NULL;
1182     PCERT_EXTENSION ext = CertFindExtension(altNameOID,
1183      cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
1184 
1185     if (ext)
1186     {
1187         DWORD bytes = 0;
1188 
1189         if (CryptDecodeObjectEx(cert->dwCertEncodingType, X509_ALTERNATE_NAME,
1190          ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL,
1191          info, &bytes))
1192         {
1193             DWORD i;
1194 
1195             for (i = 0; !entry && i < (*info)->cAltEntry; i++)
1196                 if ((*info)->rgAltEntry[i].dwAltNameChoice == entryType)
1197                     entry = &(*info)->rgAltEntry[i];
1198         }
1199     }
1200     else
1201         *info = NULL;
1202     return entry;
1203 }
1204 
1205 static DWORD cert_get_name_from_rdn_attr(DWORD encodingType,
1206  const CERT_NAME_BLOB *name, LPCSTR oid, LPWSTR pszNameString, DWORD cchNameString)
1207 {
1208     CERT_NAME_INFO *nameInfo;
1209     DWORD bytes = 0, ret = 0;
1210 
1211     if (CryptDecodeObjectEx(encodingType, X509_NAME, name->pbData,
1212      name->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &nameInfo, &bytes))
1213     {
1214         PCERT_RDN_ATTR nameAttr;
1215 
1216         if (!oid)
1217             oid = szOID_RSA_emailAddr;
1218         nameAttr = CertFindRDNAttr(oid, nameInfo);
1219         if (nameAttr)
1220             ret = CertRDNValueToStrW(nameAttr->dwValueType, &nameAttr->Value,
1221              pszNameString, cchNameString);
1222         LocalFree(nameInfo);
1223     }
1224     return ret;
1225 }
1226 
1227 DWORD WINAPI CertGetNameStringW(PCCERT_CONTEXT pCertContext, DWORD dwType,
1228  DWORD dwFlags, void *pvTypePara, LPWSTR pszNameString, DWORD cchNameString)
1229 {
1230     DWORD ret = 0;
1231     PCERT_NAME_BLOB name;
1232     LPCSTR altNameOID;
1233 
1234     TRACE("(%p, %d, %08x, %p, %p, %d)\n", pCertContext, dwType,
1235      dwFlags, pvTypePara, pszNameString, cchNameString);
1236 
1237     if (!pCertContext)
1238         goto done;
1239 
1240     if (dwFlags & CERT_NAME_ISSUER_FLAG)
1241     {
1242         name = &pCertContext->pCertInfo->Issuer;
1243         altNameOID = szOID_ISSUER_ALT_NAME;
1244     }
1245     else
1246     {
1247         name = &pCertContext->pCertInfo->Subject;
1248         altNameOID = szOID_SUBJECT_ALT_NAME;
1249     }
1250 
1251     switch (dwType)
1252     {
1253     case CERT_NAME_EMAIL_TYPE:
1254     {
1255         CERT_ALT_NAME_INFO *info;
1256         PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext,
1257          altNameOID, CERT_ALT_NAME_RFC822_NAME, &info);
1258 
1259         if (entry)
1260         {
1261             if (!pszNameString)
1262                 ret = strlenW(entry->u.pwszRfc822Name) + 1;
1263             else if (cchNameString)
1264             {
1265                 ret = min(strlenW(entry->u.pwszRfc822Name), cchNameString - 1);
1266                 memcpy(pszNameString, entry->u.pwszRfc822Name,
1267                  ret * sizeof(WCHAR));
1268                 pszNameString[ret++] = 0;
1269             }
1270         }
1271         if (info)
1272             LocalFree(info);
1273         if (!ret)
1274             ret = cert_get_name_from_rdn_attr(pCertContext->dwCertEncodingType,
1275              name, szOID_RSA_emailAddr, pszNameString, cchNameString);
1276         break;
1277     }
1278     case CERT_NAME_RDN_TYPE:
1279     {
1280         DWORD type = pvTypePara ? *(DWORD *)pvTypePara : 0;
1281 
1282         if (name->cbData)
1283             ret = CertNameToStrW(pCertContext->dwCertEncodingType, name,
1284              type, pszNameString, cchNameString);
1285         else
1286         {
1287             CERT_ALT_NAME_INFO *info;
1288             PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext,
1289              altNameOID, CERT_ALT_NAME_DIRECTORY_NAME, &info);
1290 
1291             if (entry)
1292                 ret = CertNameToStrW(pCertContext->dwCertEncodingType,
1293                  &entry->u.DirectoryName, type, pszNameString, cchNameString);
1294             if (info)
1295                 LocalFree(info);
1296         }
1297         break;
1298     }
1299     case CERT_NAME_ATTR_TYPE:
1300         ret = cert_get_name_from_rdn_attr(pCertContext->dwCertEncodingType,
1301          name, pvTypePara, pszNameString, cchNameString);
1302         if (!ret)
1303         {
1304             CERT_ALT_NAME_INFO *altInfo;
1305             PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext,
1306              altNameOID, CERT_ALT_NAME_DIRECTORY_NAME, &altInfo);
1307 
1308             if (entry)
1309                 ret = cert_name_to_str_with_indent(X509_ASN_ENCODING, 0,
1310                  &entry->u.DirectoryName, 0, pszNameString, cchNameString);
1311             if (altInfo)
1312                 LocalFree(altInfo);
1313         }
1314         break;
1315     case CERT_NAME_SIMPLE_DISPLAY_TYPE:
1316     {
1317         static const LPCSTR simpleAttributeOIDs[] = { szOID_COMMON_NAME,
1318          szOID_ORGANIZATIONAL_UNIT_NAME, szOID_ORGANIZATION_NAME,
1319          szOID_RSA_emailAddr };
1320         CERT_NAME_INFO *nameInfo = NULL;
1321         DWORD bytes = 0, i;
1322 
1323         if (CryptDecodeObjectEx(pCertContext->dwCertEncodingType, X509_NAME,
1324          name->pbData, name->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &nameInfo,
1325          &bytes))
1326         {
1327             PCERT_RDN_ATTR nameAttr = NULL;
1328 
1329             for (i = 0; !nameAttr && i < sizeof(simpleAttributeOIDs) /
1330              sizeof(simpleAttributeOIDs[0]); i++)
1331                 nameAttr = CertFindRDNAttr(simpleAttributeOIDs[i], nameInfo);
1332             if (nameAttr)
1333                 ret = CertRDNValueToStrW(nameAttr->dwValueType,
1334                  &nameAttr->Value, pszNameString, cchNameString);
1335             LocalFree(nameInfo);
1336         }
1337         if (!ret)
1338         {
1339             CERT_ALT_NAME_INFO *altInfo;
1340             PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext,
1341              altNameOID, CERT_ALT_NAME_RFC822_NAME, &altInfo);
1342 
1343             if (altInfo)
1344             {
1345                 if (!entry && altInfo->cAltEntry)
1346                     entry = &altInfo->rgAltEntry[0];
1347                 if (entry)
1348                 {
1349                     if (!pszNameString)
1350                         ret = strlenW(entry->u.pwszRfc822Name) + 1;
1351                     else if (cchNameString)
1352                     {
1353                         ret = min(strlenW(entry->u.pwszRfc822Name),
1354                          cchNameString - 1);
1355                         memcpy(pszNameString, entry->u.pwszRfc822Name,
1356                          ret * sizeof(WCHAR));
1357                         pszNameString[ret++] = 0;
1358                     }
1359                 }
1360                 LocalFree(altInfo);
1361             }
1362         }
1363         break;
1364     }
1365     case CERT_NAME_FRIENDLY_DISPLAY_TYPE:
1366     {
1367         DWORD cch = cchNameString;
1368 
1369         if (CertGetCertificateContextProperty(pCertContext,
1370          CERT_FRIENDLY_NAME_PROP_ID, pszNameString, &cch))
1371             ret = cch;
1372         else
1373             ret = CertGetNameStringW(pCertContext,
1374              CERT_NAME_SIMPLE_DISPLAY_TYPE, dwFlags, pvTypePara, pszNameString,
1375              cchNameString);
1376         break;
1377     }
1378     case CERT_NAME_DNS_TYPE:
1379     {
1380         CERT_ALT_NAME_INFO *info;
1381         PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext,
1382          altNameOID, CERT_ALT_NAME_DNS_NAME, &info);
1383 
1384         if (entry)
1385         {
1386             if (!pszNameString)
1387                 ret = strlenW(entry->u.pwszDNSName) + 1;
1388             else if (cchNameString)
1389             {
1390                 ret = min(strlenW(entry->u.pwszDNSName), cchNameString - 1);
1391                 memcpy(pszNameString, entry->u.pwszDNSName, ret * sizeof(WCHAR));
1392                 pszNameString[ret++] = 0;
1393             }
1394         }
1395         if (info)
1396             LocalFree(info);
1397         if (!ret)
1398             ret = cert_get_name_from_rdn_attr(pCertContext->dwCertEncodingType,
1399              name, szOID_COMMON_NAME, pszNameString, cchNameString);
1400         break;
1401     }
1402     case CERT_NAME_URL_TYPE:
1403     {
1404         CERT_ALT_NAME_INFO *info;
1405         PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext,
1406          altNameOID, CERT_ALT_NAME_URL, &info);
1407 
1408         if (entry)
1409         {
1410             if (!pszNameString)
1411                 ret = strlenW(entry->u.pwszURL) + 1;
1412             else if (cchNameString)
1413             {
1414                 ret = min(strlenW(entry->u.pwszURL), cchNameString - 1);
1415                 memcpy(pszNameString, entry->u.pwszURL, ret * sizeof(WCHAR));
1416                 pszNameString[ret++] = 0;
1417             }
1418         }
1419         if (info)
1420             LocalFree(info);
1421         break;
1422     }
1423     default:
1424         FIXME("unimplemented for type %d\n", dwType);
1425         ret = 0;
1426     }
1427 done:
1428     if (!ret)
1429     {
1430         if (!pszNameString)
1431             ret = 1;
1432         else if (cchNameString)
1433         {
1434             pszNameString[0] = 0;
1435             ret = 1;
1436         }
1437     }
1438     return ret;
1439 }
1440