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