crypt32: Fix string quoting in CertRDNValueToStrA/W and CertNameToStrA/W.
[wine] / dlls / crypt32 / str.c
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[10]; /* big enough for GivenName */
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;
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         if (keeper->keyName == keeper->buf)
801             keeper->keyName = CryptMemAlloc(len * sizeof(WCHAR));
802         else
803             keeper->keyName = CryptMemRealloc(keeper->keyName,
804              len * sizeof(WCHAR));
805         keeper->keyLen = len;
806     }
807     memcpy(keeper->keyName, key->start, (key->end - key->start) *
808      sizeof(WCHAR));
809     keeper->keyName[len] = '\0';
810     TRACE("Keyname is %s\n", debugstr_w(keeper->keyName));
811 }
812
813 static BOOL CRYPT_GetNextKeyW(LPCWSTR str, struct X500TokenW *token,
814  LPCWSTR *ppszError)
815 {
816     BOOL ret = TRUE;
817
818     while (*str && isspaceW(*str))
819         str++;
820     if (*str)
821     {
822         token->start = str;
823         while (*str && *str != '=' && !isspaceW(*str))
824             str++;
825         if (*str && (*str == '=' || isspaceW(*str)))
826             token->end = str;
827         else
828         {
829             TRACE("missing equals char at %s\n", debugstr_w(token->start));
830             if (ppszError)
831                 *ppszError = token->start;
832             SetLastError(CRYPT_E_INVALID_X500_STRING);
833             ret = FALSE;
834         }
835     }
836     else
837         token->start = NULL;
838     return ret;
839 }
840
841 /* Assumes separators are characters in the 0-255 range */
842 static BOOL CRYPT_GetNextValueW(LPCWSTR str, DWORD dwFlags, LPCWSTR separators,
843  struct X500TokenW *token, LPCWSTR *ppszError)
844 {
845     BOOL ret = TRUE;
846
847     TRACE("(%s, %s, %p, %p)\n", debugstr_w(str), debugstr_w(separators), token,
848      ppszError);
849
850     while (*str && isspaceW(*str))
851         str++;
852     if (*str)
853     {
854         token->start = str;
855         if (!(dwFlags & CERT_NAME_STR_NO_QUOTING_FLAG) && *str == '"')
856         {
857             token->end = NULL;
858             str++;
859             while (!token->end && ret)
860             {
861                 while (*str && *str != '"')
862                     str++;
863                 if (*str == '"')
864                 {
865                     if (*(str + 1) != '"')
866                         token->end = str + 1;
867                     else
868                         str += 2;
869                 }
870                 else
871                 {
872                     TRACE("unterminated quote at %s\n", debugstr_w(str));
873                     if (ppszError)
874                         *ppszError = str;
875                     SetLastError(CRYPT_E_INVALID_X500_STRING);
876                     ret = FALSE;
877                 }
878             }
879         }
880         else
881         {
882             WCHAR map[256] = { 0 };
883
884             while (*separators)
885                 map[*separators++] = 1;
886             while (*str && (*str >= 0xff || !map[*str]))
887                 str++;
888             token->end = str;
889         }
890     }
891     else
892     {
893         TRACE("missing value at %s\n", debugstr_w(str));
894         if (ppszError)
895             *ppszError = str;
896         SetLastError(CRYPT_E_INVALID_X500_STRING);
897         ret = FALSE;
898     }
899     return ret;
900 }
901
902 /* Encodes the string represented by value as the string type type into the
903  * CERT_NAME_BLOB output.  If there is an error and ppszError is not NULL,
904  * *ppszError is set to the first failing character.  If there is no error,
905  * output's pbData must be freed with LocalFree.
906  */
907 static BOOL CRYPT_EncodeValueWithType(DWORD dwCertEncodingType,
908  const struct X500TokenW *value, PCERT_NAME_BLOB output, DWORD type,
909  LPCWSTR *ppszError)
910 {
911     CERT_NAME_VALUE nameValue = { type, { 0, NULL } };
912     BOOL ret = TRUE;
913
914     if (value->end > value->start)
915     {
916         LONG i;
917         LPWSTR ptr;
918
919         nameValue.Value.pbData = CryptMemAlloc((value->end - value->start + 1) *
920          sizeof(WCHAR));
921         if (!nameValue.Value.pbData)
922         {
923             SetLastError(ERROR_OUTOFMEMORY);
924             return FALSE;
925         }
926         ptr = (LPWSTR)nameValue.Value.pbData;
927         for (i = 0; i < value->end - value->start; i++)
928         {
929             *ptr++ = value->start[i];
930             if (value->start[i] == '"')
931                 i++;
932         }
933         /* The string is NULL terminated because of a quirk in encoding
934          * unicode names values:  if the length is given as 0, the value is
935          * assumed to be a NULL-terminated string.
936          */
937         *ptr = 0;
938         nameValue.Value.cbData = (LPBYTE)ptr - nameValue.Value.pbData;
939     }
940     ret = CryptEncodeObjectEx(dwCertEncodingType, X509_UNICODE_NAME_VALUE,
941      &nameValue, CRYPT_ENCODE_ALLOC_FLAG, NULL, &output->pbData,
942      &output->cbData);
943     if (!ret && ppszError)
944     {
945         if (type == CERT_RDN_NUMERIC_STRING &&
946          GetLastError() == CRYPT_E_INVALID_NUMERIC_STRING)
947             *ppszError = value->start + output->cbData;
948         else if (type == CERT_RDN_PRINTABLE_STRING &&
949          GetLastError() == CRYPT_E_INVALID_PRINTABLE_STRING)
950             *ppszError = value->start + output->cbData;
951         else if (type == CERT_RDN_IA5_STRING &&
952          GetLastError() == CRYPT_E_INVALID_IA5_STRING)
953             *ppszError = value->start + output->cbData;
954     }
955     CryptMemFree(nameValue.Value.pbData);
956     return ret;
957 }
958
959 static BOOL CRYPT_EncodeValue(DWORD dwCertEncodingType,
960  const struct X500TokenW *value, PCERT_NAME_BLOB output, const DWORD *types,
961  LPCWSTR *ppszError)
962 {
963     DWORD i;
964     BOOL ret;
965
966     ret = FALSE;
967     for (i = 0; !ret && types[i]; i++)
968         ret = CRYPT_EncodeValueWithType(dwCertEncodingType, value, output,
969          types[i], ppszError);
970     return ret;
971 }
972
973 static BOOL CRYPT_ValueToRDN(DWORD dwCertEncodingType, PCERT_NAME_INFO info,
974  PCCRYPT_OID_INFO keyOID, struct X500TokenW *value, LPCWSTR *ppszError)
975 {
976     BOOL ret = FALSE;
977
978     TRACE("OID %s, value %s\n", debugstr_a(keyOID->pszOID),
979      debugstr_wn(value->start, value->end - value->start));
980
981     if (!info->rgRDN)
982         info->rgRDN = CryptMemAlloc(sizeof(CERT_RDN));
983     else
984         info->rgRDN = CryptMemRealloc(info->rgRDN,
985          (info->cRDN + 1) * sizeof(CERT_RDN));
986     if (info->rgRDN)
987     {
988         /* FIXME: support multiple RDN attrs */
989         info->rgRDN[info->cRDN].rgRDNAttr =
990          CryptMemAlloc(sizeof(CERT_RDN_ATTR));
991         if (info->rgRDN[info->cRDN].rgRDNAttr)
992         {
993             static const DWORD defaultTypes[] = { CERT_RDN_PRINTABLE_STRING,
994              CERT_RDN_BMP_STRING, 0 };
995             const DWORD *types;
996
997             info->rgRDN[info->cRDN].cRDNAttr = 1;
998             info->rgRDN[info->cRDN].rgRDNAttr[0].pszObjId =
999              (LPSTR)keyOID->pszOID;
1000             info->rgRDN[info->cRDN].rgRDNAttr[0].dwValueType =
1001              CERT_RDN_ENCODED_BLOB;
1002             if (keyOID->ExtraInfo.cbData)
1003                 types = (const DWORD *)keyOID->ExtraInfo.pbData;
1004             else
1005                 types = defaultTypes;
1006
1007             /* Remove surrounding quotes */
1008             if (value->start[0] == '"')
1009             {
1010                 value->start++;
1011                 value->end--;
1012             }
1013             ret = CRYPT_EncodeValue(dwCertEncodingType, value,
1014              &info->rgRDN[info->cRDN].rgRDNAttr[0].Value, types, ppszError);
1015         }
1016         else
1017             SetLastError(ERROR_OUTOFMEMORY);
1018         info->cRDN++;
1019     }
1020     else
1021         SetLastError(ERROR_OUTOFMEMORY);
1022     return ret;
1023 }
1024
1025 BOOL WINAPI CertStrToNameW(DWORD dwCertEncodingType, LPCWSTR pszX500,
1026  DWORD dwStrType, void *pvReserved, BYTE *pbEncoded, DWORD *pcbEncoded,
1027  LPCWSTR *ppszError)
1028 {
1029     CERT_NAME_INFO info = { 0, NULL };
1030     LPCWSTR str;
1031     struct KeynameKeeper keeper;
1032     DWORD i;
1033     BOOL ret = TRUE;
1034
1035     TRACE("(%08x, %s, %08x, %p, %p, %p, %p)\n", dwCertEncodingType,
1036      debugstr_w(pszX500), dwStrType, pvReserved, pbEncoded, pcbEncoded,
1037      ppszError);
1038
1039     CRYPT_InitializeKeynameKeeper(&keeper);
1040     str = pszX500;
1041     while (str && *str && ret)
1042     {
1043         struct X500TokenW token;
1044
1045         ret = CRYPT_GetNextKeyW(str, &token, ppszError);
1046         if (ret && token.start)
1047         {
1048             PCCRYPT_OID_INFO keyOID;
1049
1050             CRYPT_KeynameKeeperFromTokenW(&keeper, &token);
1051             keyOID = CryptFindOIDInfo(CRYPT_OID_INFO_NAME_KEY, keeper.keyName,
1052              CRYPT_RDN_ATTR_OID_GROUP_ID);
1053             if (!keyOID)
1054             {
1055                 if (ppszError)
1056                     *ppszError = token.start;
1057                 SetLastError(CRYPT_E_INVALID_X500_STRING);
1058                 ret = FALSE;
1059             }
1060             else
1061             {
1062                 str = token.end;
1063                 while (isspace(*str))
1064                     str++;
1065                 if (*str != '=')
1066                 {
1067                     if (ppszError)
1068                         *ppszError = str;
1069                     SetLastError(CRYPT_E_INVALID_X500_STRING);
1070                     ret = FALSE;
1071                 }
1072                 else
1073                 {
1074                     static const WCHAR commaSep[] = { ',',0 };
1075                     static const WCHAR semiSep[] = { ';',0 };
1076                     static const WCHAR crlfSep[] = { '\r','\n',0 };
1077                     static const WCHAR allSeps[] = { ',',';','\r','\n',0 };
1078                     LPCWSTR sep;
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
1088                         sep = allSeps;
1089                     ret = CRYPT_GetNextValueW(str, dwStrType, sep, &token,
1090                      ppszError);
1091                     if (ret)
1092                     {
1093                         str = token.end;
1094                         ret = CRYPT_ValueToRDN(dwCertEncodingType, &info,
1095                          keyOID, &token, ppszError);
1096                     }
1097                 }
1098             }
1099         }
1100     }
1101     CRYPT_FreeKeynameKeeper(&keeper);
1102     if (ret)
1103     {
1104         if (ppszError)
1105             *ppszError = NULL;
1106         ret = CryptEncodeObjectEx(dwCertEncodingType, X509_NAME, &info,
1107          0, NULL, pbEncoded, pcbEncoded);
1108     }
1109     for (i = 0; i < info.cRDN; i++)
1110     {
1111         DWORD j;
1112
1113         for (j = 0; j < info.rgRDN[i].cRDNAttr; j++)
1114             LocalFree(info.rgRDN[i].rgRDNAttr[j].Value.pbData);
1115         CryptMemFree(info.rgRDN[i].rgRDNAttr);
1116     }
1117     CryptMemFree(info.rgRDN);
1118     return ret;
1119 }
1120
1121 DWORD WINAPI CertGetNameStringA(PCCERT_CONTEXT pCertContext, DWORD dwType,
1122  DWORD dwFlags, void *pvTypePara, LPSTR pszNameString, DWORD cchNameString)
1123 {
1124     DWORD ret;
1125
1126     TRACE("(%p, %d, %08x, %p, %p, %d)\n", pCertContext, dwType, dwFlags,
1127      pvTypePara, pszNameString, cchNameString);
1128
1129     if (pszNameString)
1130     {
1131         LPWSTR wideName;
1132         DWORD nameLen;
1133
1134         nameLen = CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara,
1135          NULL, 0);
1136         wideName = CryptMemAlloc(nameLen * sizeof(WCHAR));
1137         if (wideName)
1138         {
1139             CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara,
1140              wideName, nameLen);
1141             nameLen = WideCharToMultiByte(CP_ACP, 0, wideName, nameLen,
1142              pszNameString, cchNameString, NULL, NULL);
1143             if (nameLen <= cchNameString)
1144                 ret = nameLen;
1145             else
1146             {
1147                 pszNameString[cchNameString - 1] = '\0';
1148                 ret = cchNameString;
1149             }
1150             CryptMemFree(wideName);
1151         }
1152         else
1153         {
1154             *pszNameString = '\0';
1155             ret = 1;
1156         }
1157     }
1158     else
1159         ret = CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara,
1160          NULL, 0);
1161     return ret;
1162 }
1163
1164 /* Searches cert's extensions for the alternate name extension with OID
1165  * altNameOID, and if found, searches it for the alternate name type entryType.
1166  * If found, returns a pointer to the entry, otherwise returns NULL.
1167  * Regardless of whether an entry of the desired type is found, if the
1168  * alternate name extension is present, sets *info to the decoded alternate
1169  * name extension, which you must free using LocalFree.
1170  * The return value is a pointer within *info, so don't free *info before
1171  * you're done with the return value.
1172  */
1173 static PCERT_ALT_NAME_ENTRY cert_find_alt_name_entry(PCCERT_CONTEXT cert,
1174  LPCSTR altNameOID, DWORD entryType, PCERT_ALT_NAME_INFO *info)
1175 {
1176     PCERT_ALT_NAME_ENTRY entry = NULL;
1177     PCERT_EXTENSION ext = CertFindExtension(altNameOID,
1178      cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
1179
1180     if (ext)
1181     {
1182         DWORD bytes = 0;
1183
1184         if (CryptDecodeObjectEx(cert->dwCertEncodingType, X509_ALTERNATE_NAME,
1185          ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL,
1186          info, &bytes))
1187         {
1188             DWORD i;
1189
1190             for (i = 0; !entry && i < (*info)->cAltEntry; i++)
1191                 if ((*info)->rgAltEntry[i].dwAltNameChoice == entryType)
1192                     entry = &(*info)->rgAltEntry[i];
1193         }
1194     }
1195     else
1196         *info = NULL;
1197     return entry;
1198 }
1199
1200 static DWORD cert_get_name_from_rdn_attr(DWORD encodingType,
1201  const CERT_NAME_BLOB *name, LPCSTR oid, LPWSTR pszNameString, DWORD cchNameString)
1202 {
1203     CERT_NAME_INFO *nameInfo;
1204     DWORD bytes = 0, ret = 0;
1205
1206     if (CryptDecodeObjectEx(encodingType, X509_NAME, name->pbData,
1207      name->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &nameInfo, &bytes))
1208     {
1209         PCERT_RDN_ATTR nameAttr = CertFindRDNAttr(oid, nameInfo);
1210
1211         if (nameAttr)
1212             ret = CertRDNValueToStrW(nameAttr->dwValueType, &nameAttr->Value,
1213              pszNameString, cchNameString);
1214         LocalFree(nameInfo);
1215     }
1216     return ret;
1217 }
1218
1219 DWORD WINAPI CertGetNameStringW(PCCERT_CONTEXT pCertContext, DWORD dwType,
1220  DWORD dwFlags, void *pvTypePara, LPWSTR pszNameString, DWORD cchNameString)
1221 {
1222     DWORD ret = 0;
1223     PCERT_NAME_BLOB name;
1224     LPCSTR altNameOID;
1225
1226     TRACE("(%p, %d, %08x, %p, %p, %d)\n", pCertContext, dwType,
1227      dwFlags, pvTypePara, pszNameString, cchNameString);
1228
1229     if (dwFlags & CERT_NAME_ISSUER_FLAG)
1230     {
1231         name = &pCertContext->pCertInfo->Issuer;
1232         altNameOID = szOID_ISSUER_ALT_NAME;
1233     }
1234     else
1235     {
1236         name = &pCertContext->pCertInfo->Subject;
1237         altNameOID = szOID_SUBJECT_ALT_NAME;
1238     }
1239
1240     switch (dwType)
1241     {
1242     case CERT_NAME_EMAIL_TYPE:
1243     {
1244         CERT_ALT_NAME_INFO *info;
1245         PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext,
1246          altNameOID, CERT_ALT_NAME_RFC822_NAME, &info);
1247
1248         if (entry)
1249         {
1250             if (!pszNameString)
1251                 ret = strlenW(entry->u.pwszRfc822Name) + 1;
1252             else if (cchNameString)
1253             {
1254                 ret = min(strlenW(entry->u.pwszRfc822Name), cchNameString - 1);
1255                 memcpy(pszNameString, entry->u.pwszRfc822Name,
1256                  ret * sizeof(WCHAR));
1257                 pszNameString[ret++] = 0;
1258             }
1259         }
1260         if (info)
1261             LocalFree(info);
1262         if (!ret)
1263             ret = cert_get_name_from_rdn_attr(pCertContext->dwCertEncodingType,
1264              name, szOID_RSA_emailAddr, pszNameString, cchNameString);
1265         break;
1266     }
1267     case CERT_NAME_RDN_TYPE:
1268         if (name->cbData)
1269             ret = CertNameToStrW(pCertContext->dwCertEncodingType, name,
1270              *(DWORD *)pvTypePara, pszNameString, cchNameString);
1271         else
1272         {
1273             CERT_ALT_NAME_INFO *info;
1274             PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext,
1275              altNameOID, CERT_ALT_NAME_DIRECTORY_NAME, &info);
1276
1277             if (entry)
1278                 ret = CertNameToStrW(pCertContext->dwCertEncodingType,
1279                  &entry->u.DirectoryName, *(DWORD *)pvTypePara, pszNameString,
1280                  cchNameString);
1281             if (info)
1282                 LocalFree(info);
1283         }
1284         break;
1285     case CERT_NAME_ATTR_TYPE:
1286         ret = cert_get_name_from_rdn_attr(pCertContext->dwCertEncodingType,
1287          name, pvTypePara, pszNameString, cchNameString);
1288         if (!ret)
1289         {
1290             CERT_ALT_NAME_INFO *altInfo;
1291             PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext,
1292              altNameOID, CERT_ALT_NAME_DIRECTORY_NAME, &altInfo);
1293
1294             if (entry)
1295                 ret = cert_name_to_str_with_indent(X509_ASN_ENCODING, 0,
1296                  &entry->u.DirectoryName, 0, pszNameString, cchNameString);
1297             if (altInfo)
1298                 LocalFree(altInfo);
1299         }
1300         break;
1301     case CERT_NAME_SIMPLE_DISPLAY_TYPE:
1302     {
1303         static const LPCSTR simpleAttributeOIDs[] = { szOID_COMMON_NAME,
1304          szOID_ORGANIZATIONAL_UNIT_NAME, szOID_ORGANIZATION_NAME,
1305          szOID_RSA_emailAddr };
1306         CERT_NAME_INFO *nameInfo = NULL;
1307         DWORD bytes = 0, i;
1308
1309         if (CryptDecodeObjectEx(pCertContext->dwCertEncodingType, X509_NAME,
1310          name->pbData, name->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &nameInfo,
1311          &bytes))
1312         {
1313             PCERT_RDN_ATTR nameAttr = NULL;
1314
1315             for (i = 0; !nameAttr && i < sizeof(simpleAttributeOIDs) /
1316              sizeof(simpleAttributeOIDs[0]); i++)
1317                 nameAttr = CertFindRDNAttr(simpleAttributeOIDs[i], nameInfo);
1318             if (nameAttr)
1319                 ret = CertRDNValueToStrW(nameAttr->dwValueType,
1320                  &nameAttr->Value, pszNameString, cchNameString);
1321             LocalFree(nameInfo);
1322         }
1323         if (!ret)
1324         {
1325             CERT_ALT_NAME_INFO *altInfo;
1326             PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext,
1327              altNameOID, CERT_ALT_NAME_RFC822_NAME, &altInfo);
1328
1329             if (altInfo)
1330             {
1331                 if (!entry && altInfo->cAltEntry)
1332                     entry = &altInfo->rgAltEntry[0];
1333                 if (entry)
1334                 {
1335                     if (!pszNameString)
1336                         ret = strlenW(entry->u.pwszRfc822Name) + 1;
1337                     else if (cchNameString)
1338                     {
1339                         ret = min(strlenW(entry->u.pwszRfc822Name),
1340                          cchNameString - 1);
1341                         memcpy(pszNameString, entry->u.pwszRfc822Name,
1342                          ret * sizeof(WCHAR));
1343                         pszNameString[ret++] = 0;
1344                     }
1345                 }
1346                 LocalFree(altInfo);
1347             }
1348         }
1349         break;
1350     }
1351     case CERT_NAME_FRIENDLY_DISPLAY_TYPE:
1352     {
1353         DWORD cch = cchNameString;
1354
1355         if (CertGetCertificateContextProperty(pCertContext,
1356          CERT_FRIENDLY_NAME_PROP_ID, pszNameString, &cch))
1357             ret = cch;
1358         else
1359             ret = CertGetNameStringW(pCertContext,
1360              CERT_NAME_SIMPLE_DISPLAY_TYPE, dwFlags, pvTypePara, pszNameString,
1361              cchNameString);
1362         break;
1363     }
1364     case CERT_NAME_DNS_TYPE:
1365     {
1366         CERT_ALT_NAME_INFO *info;
1367         PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext,
1368          altNameOID, CERT_ALT_NAME_DNS_NAME, &info);
1369
1370         if (entry)
1371         {
1372             if (!pszNameString)
1373                 ret = strlenW(entry->u.pwszDNSName) + 1;
1374             else if (cchNameString)
1375             {
1376                 ret = min(strlenW(entry->u.pwszDNSName), cchNameString - 1);
1377                 memcpy(pszNameString, entry->u.pwszDNSName, ret * sizeof(WCHAR));
1378                 pszNameString[ret++] = 0;
1379             }
1380         }
1381         if (info)
1382             LocalFree(info);
1383         if (!ret)
1384             ret = cert_get_name_from_rdn_attr(pCertContext->dwCertEncodingType,
1385              name, szOID_COMMON_NAME, pszNameString, cchNameString);
1386         break;
1387     }
1388     case CERT_NAME_URL_TYPE:
1389     {
1390         CERT_ALT_NAME_INFO *info;
1391         PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext,
1392          altNameOID, CERT_ALT_NAME_URL, &info);
1393
1394         if (entry)
1395         {
1396             if (!pszNameString)
1397                 ret = strlenW(entry->u.pwszURL) + 1;
1398             else if (cchNameString)
1399             {
1400                 ret = min(strlenW(entry->u.pwszURL), cchNameString - 1);
1401                 memcpy(pszNameString, entry->u.pwszURL, ret * sizeof(WCHAR));
1402                 pszNameString[ret++] = 0;
1403             }
1404         }
1405         if (info)
1406             LocalFree(info);
1407         break;
1408     }
1409     default:
1410         FIXME("unimplemented for type %d\n", dwType);
1411         ret = 0;
1412     }
1413     if (!ret)
1414     {
1415         if (!pszNameString)
1416             ret = 1;
1417         else if (cchNameString)
1418         {
1419             pszNameString[0] = 0;
1420             ret = 1;
1421         }
1422     }
1423     return ret;
1424 }