wined3d: Default to GLSL. This is safe because we now have proper ps2.0/vs2.0 detection.
[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 #include "windef.h"
20 #include "winbase.h"
21 #include "winnls.h"
22 #include "winuser.h"
23 #include "wincrypt.h"
24 #include "wine/debug.h"
25 #include "wine/unicode.h"
26
27 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
28
29 DWORD WINAPI CertRDNValueToStrA(DWORD dwValueType, PCERT_RDN_VALUE_BLOB pValue,
30  LPSTR psz, DWORD csz)
31 {
32     DWORD ret = 0;
33
34     TRACE("(%d, %p, %p, %d)\n", dwValueType, pValue, psz, csz);
35
36     switch (dwValueType)
37     {
38     case CERT_RDN_ANY_TYPE:
39         break;
40     case CERT_RDN_NUMERIC_STRING:
41     case CERT_RDN_PRINTABLE_STRING:
42     case CERT_RDN_TELETEX_STRING:
43     case CERT_RDN_VIDEOTEX_STRING:
44     case CERT_RDN_IA5_STRING:
45     case CERT_RDN_GRAPHIC_STRING:
46     case CERT_RDN_VISIBLE_STRING:
47     case CERT_RDN_GENERAL_STRING:
48         if (!psz || !csz)
49             ret = pValue->cbData;
50         else
51         {
52             DWORD chars = min(pValue->cbData, csz - 1);
53
54             if (chars)
55             {
56                 memcpy(psz, pValue->pbData, chars);
57                 ret += chars;
58                 csz -= chars;
59             }
60         }
61         break;
62     case CERT_RDN_UTF8_STRING:
63         if (!psz || !csz)
64             ret = WideCharToMultiByte(CP_UTF8, 0, (LPWSTR)pValue->pbData,
65              pValue->cbData / sizeof(WCHAR) + 1, NULL, 0, NULL, NULL);
66         else
67         {
68             ret = WideCharToMultiByte(CP_UTF8, 0, (LPWSTR)pValue->pbData,
69              pValue->cbData / sizeof(WCHAR) + 1, psz, csz - 1, NULL, NULL);
70             csz -= ret;
71         }
72         break;
73     default:
74         FIXME("string type %d unimplemented\n", dwValueType);
75     }
76     if (psz && csz)
77     {
78         *(psz + ret) = '\0';
79         csz--;
80         ret++;
81     }
82     else
83         ret++;
84     TRACE("returning %d (%s)\n", ret, debugstr_a(psz));
85     return ret;
86 }
87
88 DWORD WINAPI CertRDNValueToStrW(DWORD dwValueType, PCERT_RDN_VALUE_BLOB pValue,
89  LPWSTR psz, DWORD csz)
90 {
91     DWORD ret = 0;
92
93     TRACE("(%d, %p, %p, %d)\n", dwValueType, pValue, psz, csz);
94
95     switch (dwValueType)
96     {
97     case CERT_RDN_ANY_TYPE:
98         break;
99     case CERT_RDN_NUMERIC_STRING:
100     case CERT_RDN_PRINTABLE_STRING:
101     case CERT_RDN_TELETEX_STRING:
102     case CERT_RDN_VIDEOTEX_STRING:
103     case CERT_RDN_IA5_STRING:
104     case CERT_RDN_GRAPHIC_STRING:
105     case CERT_RDN_VISIBLE_STRING:
106     case CERT_RDN_GENERAL_STRING:
107         if (!psz || !csz)
108             ret = pValue->cbData;
109         else
110         {
111             DWORD chars = min(pValue->cbData, csz - 1);
112
113             if (chars)
114             {
115                 DWORD i;
116
117                 for (i = 0; i < chars; i++)
118                     psz[i] = pValue->pbData[i];
119                 ret += chars;
120                 csz -= chars;
121             }
122         }
123         break;
124     case CERT_RDN_UTF8_STRING:
125         if (!psz || !csz)
126             ret = pValue->cbData / sizeof(WCHAR);
127         else
128         {
129             DWORD chars = min(pValue->cbData / sizeof(WCHAR), csz - 1);
130
131             if (chars)
132             {
133                 DWORD i;
134
135                 for (i = 0; i < chars; i++)
136                     psz[i] = *((LPWSTR)pValue->pbData + i);
137                 ret += chars;
138                 csz -= chars;
139             }
140         }
141         break;
142     default:
143         FIXME("string type %d unimplemented\n", dwValueType);
144     }
145     if (psz && csz)
146     {
147         *(psz + ret) = '\0';
148         csz--;
149         ret++;
150     }
151     else
152         ret++;
153     TRACE("returning %d (%s)\n", ret, debugstr_w(psz));
154     return ret;
155 }
156
157 /* Adds the prefix prefix to the string pointed to by psz, followed by the
158  * character '='.  Copies no more than csz characters.  Returns the number of
159  * characters copied.  If psz is NULL, returns the number of characters that
160  * would be copied.
161  */
162 static DWORD CRYPT_AddPrefixA(LPCSTR prefix, LPSTR psz, DWORD csz)
163 {
164     DWORD chars;
165
166     TRACE("(%s, %p, %d)\n", debugstr_a(prefix), psz, csz);
167
168     if (psz)
169     {
170         chars = min(lstrlenA(prefix), csz);
171         memcpy(psz, prefix, chars);
172         csz -= chars;
173         *(psz + chars) = '=';
174         chars++;
175         csz--;
176     }
177     else
178         chars = lstrlenA(prefix) + 1;
179     return chars;
180 }
181
182 DWORD WINAPI CertNameToStrA(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName,
183  DWORD dwStrType, LPSTR psz, DWORD csz)
184 {
185     static const DWORD unsupportedFlags = CERT_NAME_STR_NO_QUOTING_FLAG |
186      CERT_NAME_STR_REVERSE_FLAG | CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG;
187     static const char commaSep[] = ", ";
188     static const char semiSep[] = "; ";
189     static const char crlfSep[] = "\r\n";
190     static const char plusSep[] = " + ";
191     static const char spaceSep[] = " ";
192     DWORD ret = 0, bytes = 0;
193     BOOL bRet;
194     CERT_NAME_INFO *info;
195
196     TRACE("(%d, %p, %08x, %p, %d)\n", dwCertEncodingType, pName, dwStrType,
197      psz, csz);
198     if (dwStrType & unsupportedFlags)
199         FIXME("unsupported flags: %08x\n", dwStrType & unsupportedFlags);
200
201     bRet = CryptDecodeObjectEx(dwCertEncodingType, X509_NAME, pName->pbData,
202      pName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &bytes);
203     if (bRet)
204     {
205         DWORD i, j, sepLen, rdnSepLen;
206         LPCSTR sep, rdnSep;
207
208         if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG)
209             sep = semiSep;
210         else if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
211             sep = crlfSep;
212         else
213             sep = commaSep;
214         sepLen = strlen(sep);
215         if (dwStrType & CERT_NAME_STR_NO_PLUS_FLAG)
216             rdnSep = spaceSep;
217         else
218             rdnSep = plusSep;
219         rdnSepLen = strlen(rdnSep);
220         for (i = 0; (!psz || ret < csz) && i < info->cRDN; i++)
221         {
222             for (j = 0; (!psz || ret < csz) && j < info->rgRDN[i].cRDNAttr; j++)
223             {
224                 DWORD chars;
225                 char prefixBuf[10]; /* big enough for GivenName */
226                 LPCSTR prefix = NULL;
227
228                 if ((dwStrType & 0x000000ff) == CERT_OID_NAME_STR)
229                     prefix = info->rgRDN[i].rgRDNAttr[j].pszObjId;
230                 else if ((dwStrType & 0x000000ff) == CERT_X500_NAME_STR)
231                 {
232                     PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(
233                      CRYPT_OID_INFO_OID_KEY,
234                      info->rgRDN[i].rgRDNAttr[j].pszObjId,
235                      CRYPT_RDN_ATTR_OID_GROUP_ID);
236
237                     if (oidInfo)
238                     {
239                         WideCharToMultiByte(CP_ACP, 0, oidInfo->pwszName, -1,
240                          prefixBuf, sizeof(prefixBuf), NULL, NULL);
241                         prefix = prefixBuf;
242                     }
243                     else
244                         prefix = info->rgRDN[i].rgRDNAttr[j].pszObjId;
245                 }
246                 if (prefix)
247                 {
248                     /* - 1 is needed to account for the NULL terminator. */
249                     chars = CRYPT_AddPrefixA(prefix,
250                      psz ? psz + ret : NULL, psz ? csz - ret - 1 : 0);
251                     ret += chars;
252                     csz -= chars;
253                 }
254                 /* FIXME: handle quoting */
255                 chars = CertRDNValueToStrA(
256                  info->rgRDN[i].rgRDNAttr[j].dwValueType, 
257                  &info->rgRDN[i].rgRDNAttr[j].Value, psz ? psz + ret : NULL,
258                  psz ? csz - ret : 0);
259                 if (chars)
260                     ret += chars - 1;
261                 if (j < info->rgRDN[i].cRDNAttr - 1)
262                 {
263                     if (psz && ret < csz - rdnSepLen - 1)
264                         memcpy(psz + ret, rdnSep, rdnSepLen);
265                     ret += rdnSepLen;
266                 }
267             }
268             if (i < info->cRDN - 1)
269             {
270                 if (psz && ret < csz - sepLen - 1)
271                     memcpy(psz + ret, sep, sepLen);
272                 ret += sepLen;
273             }
274         }
275         LocalFree(info);
276     }
277     if (psz && csz)
278     {
279         *(psz + ret) = '\0';
280         csz--;
281         ret++;
282     }
283     else
284         ret++;
285     TRACE("Returning %s\n", debugstr_a(psz));
286     return ret;
287 }
288
289 /* Adds the prefix prefix to the wide-character string pointed to by psz,
290  * followed by the character '='.  Copies no more than csz characters.  Returns
291  * the number of characters copied.  If psz is NULL, returns the number of
292  * characters that would be copied.
293  * Assumes the characters in prefix are ASCII (not multibyte characters.)
294  */
295 static DWORD CRYPT_AddPrefixAToW(LPCSTR prefix, LPWSTR psz, DWORD csz)
296 {
297     DWORD chars;
298
299     TRACE("(%s, %p, %d)\n", debugstr_a(prefix), psz, csz);
300
301     if (psz)
302     {
303         DWORD i;
304
305         chars = min(lstrlenA(prefix), csz);
306         for (i = 0; i < chars; i++)
307             *(psz + i) = prefix[i];
308         csz -= chars;
309         *(psz + chars) = '=';
310         chars++;
311         csz--;
312     }
313     else
314         chars = lstrlenA(prefix) + 1;
315     return chars;
316 }
317
318 /* Adds the prefix prefix to the string pointed to by psz, followed by the
319  * character '='.  Copies no more than csz characters.  Returns the number of
320  * characters copied.  If psz is NULL, returns the number of characters that
321  * would be copied.
322  */
323 static DWORD CRYPT_AddPrefixW(LPCWSTR prefix, LPWSTR psz, DWORD csz)
324 {
325     DWORD chars;
326
327     TRACE("(%s, %p, %d)\n", debugstr_w(prefix), psz, csz);
328
329     if (psz)
330     {
331         chars = min(lstrlenW(prefix), csz);
332         memcpy(psz, prefix, chars * sizeof(WCHAR));
333         csz -= chars;
334         *(psz + chars) = '=';
335         chars++;
336         csz--;
337     }
338     else
339         chars = lstrlenW(prefix) + 1;
340     return chars;
341 }
342
343 DWORD WINAPI CertNameToStrW(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName,
344  DWORD dwStrType, LPWSTR psz, DWORD csz)
345 {
346     static const DWORD unsupportedFlags = CERT_NAME_STR_NO_QUOTING_FLAG |
347      CERT_NAME_STR_REVERSE_FLAG | CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG;
348     static const WCHAR commaSep[] = { ',',' ',0 };
349     static const WCHAR semiSep[] = { ';',' ',0 };
350     static const WCHAR crlfSep[] = { '\r','\n',0 };
351     static const WCHAR plusSep[] = { ' ','+',' ',0 };
352     static const WCHAR spaceSep[] = { ' ',0 };
353     DWORD ret = 0, bytes = 0;
354     BOOL bRet;
355     CERT_NAME_INFO *info;
356
357     TRACE("(%d, %p, %08x, %p, %d)\n", dwCertEncodingType, pName, dwStrType,
358      psz, csz);
359     if (dwStrType & unsupportedFlags)
360         FIXME("unsupported flags: %08x\n", dwStrType & unsupportedFlags);
361
362     bRet = CryptDecodeObjectEx(dwCertEncodingType, X509_NAME, pName->pbData,
363      pName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &bytes);
364     if (bRet)
365     {
366         DWORD i, j, sepLen, rdnSepLen;
367         LPCWSTR sep, rdnSep;
368
369         if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG)
370             sep = semiSep;
371         else if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
372             sep = crlfSep;
373         else
374             sep = commaSep;
375         sepLen = lstrlenW(sep);
376         if (dwStrType & CERT_NAME_STR_NO_PLUS_FLAG)
377             rdnSep = spaceSep;
378         else
379             rdnSep = plusSep;
380         rdnSepLen = lstrlenW(rdnSep);
381         for (i = 0; (!psz || ret < csz) && i < info->cRDN; i++)
382         {
383             for (j = 0; (!psz || ret < csz) && j < info->rgRDN[i].cRDNAttr; j++)
384             {
385                 DWORD chars;
386                 LPCSTR prefixA = NULL;
387                 LPCWSTR prefixW = NULL;
388
389                 if ((dwStrType & 0x000000ff) == CERT_OID_NAME_STR)
390                     prefixA = info->rgRDN[i].rgRDNAttr[j].pszObjId;
391                 else if ((dwStrType & 0x000000ff) == CERT_X500_NAME_STR)
392                 {
393                     PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(
394                      CRYPT_OID_INFO_OID_KEY,
395                      info->rgRDN[i].rgRDNAttr[j].pszObjId,
396                      CRYPT_RDN_ATTR_OID_GROUP_ID);
397
398                     if (oidInfo)
399                         prefixW = oidInfo->pwszName;
400                     else
401                         prefixA = info->rgRDN[i].rgRDNAttr[j].pszObjId;
402                 }
403                 if (prefixW)
404                 {
405                     /* - 1 is needed to account for the NULL terminator. */
406                     chars = CRYPT_AddPrefixW(prefixW,
407                      psz ? psz + ret : NULL, psz ? csz - ret - 1 : 0);
408                     ret += chars;
409                     csz -= chars;
410                 }
411                 else if (prefixA)
412                 {
413                     /* - 1 is needed to account for the NULL terminator. */
414                     chars = CRYPT_AddPrefixAToW(prefixA,
415                      psz ? psz + ret : NULL, psz ? csz - ret - 1 : 0);
416                     ret += chars;
417                     csz -= chars;
418                 }
419                 /* FIXME: handle quoting */
420                 chars = CertRDNValueToStrW(
421                  info->rgRDN[i].rgRDNAttr[j].dwValueType, 
422                  &info->rgRDN[i].rgRDNAttr[j].Value, psz ? psz + ret : NULL,
423                  psz ? csz - ret : 0);
424                 if (chars)
425                     ret += chars - 1;
426                 if (j < info->rgRDN[i].cRDNAttr - 1)
427                 {
428                     if (psz && ret < csz - rdnSepLen - 1)
429                         memcpy(psz + ret, rdnSep, rdnSepLen * sizeof(WCHAR));
430                     ret += rdnSepLen;
431                 }
432             }
433             if (i < info->cRDN - 1)
434             {
435                 if (psz && ret < csz - sepLen - 1)
436                     memcpy(psz + ret, sep, sepLen * sizeof(WCHAR));
437                 ret += sepLen;
438             }
439         }
440         LocalFree(info);
441     }
442     if (psz && csz)
443     {
444         *(psz + ret) = '\0';
445         csz--;
446         ret++;
447     }
448     else
449         ret++;
450     TRACE("Returning %s\n", debugstr_w(psz));
451     return ret;
452 }
453
454 BOOL WINAPI CertStrToNameA(DWORD dwCertEncodingType, LPCSTR pszX500,
455  DWORD dwStrType, void *pvReserved, BYTE *pbEncoded, DWORD *pcbEncoded,
456  LPCSTR *ppszError)
457 {
458     BOOL ret;
459     int len;
460
461     TRACE("(%08x, %s, %08x, %p, %p, %p, %p)\n", dwCertEncodingType,
462      debugstr_a(pszX500), dwStrType, pvReserved, pbEncoded, pcbEncoded,
463      ppszError);
464
465     len = MultiByteToWideChar(CP_ACP, 0, pszX500, -1, NULL, 0);
466     if (len)
467     {
468         LPWSTR x500, errorStr;
469
470         if ((x500 = CryptMemAlloc(len * sizeof(WCHAR))))
471         {
472             MultiByteToWideChar(CP_ACP, 0, pszX500, -1, x500, len);
473             ret = CertStrToNameW(dwCertEncodingType, x500, dwStrType,
474              pvReserved, pbEncoded, pcbEncoded,
475              ppszError ? (LPCWSTR *)&errorStr : NULL);
476             if (ppszError)
477             {
478                 if (!ret)
479                 {
480                     DWORD i;
481
482                     *ppszError = pszX500;
483                     for (i = 0; i < errorStr - x500; i++)
484                         *ppszError = CharNextA(*ppszError);
485                 }
486                 else
487                     *ppszError = NULL;
488             }
489             CryptMemFree(x500);
490         }
491         else
492         {
493             SetLastError(ERROR_OUTOFMEMORY);
494             ret = FALSE;
495         }
496     }
497     else
498     {
499         SetLastError(CRYPT_E_INVALID_X500_STRING);
500         if (ppszError)
501             *ppszError = pszX500;
502         ret = FALSE;
503     }
504     return ret;
505 }
506
507 struct KeynameKeeper
508 {
509     WCHAR  buf[10]; /* big enough for L"GivenName" */
510     LPWSTR keyName; /* usually = buf, but may be allocated */
511     DWORD  keyLen;
512 };
513
514 static void CRYPT_InitializeKeynameKeeper(struct KeynameKeeper *keeper)
515 {
516     keeper->keyName = keeper->buf;
517     keeper->keyLen = sizeof(keeper->buf) / sizeof(keeper->buf[0]);
518 }
519
520 static void CRYPT_FreeKeynameKeeper(struct KeynameKeeper *keeper)
521 {
522     if (keeper->keyName != keeper->buf)
523         CryptMemFree(keeper->keyName);
524 }
525
526 struct X500TokenW
527 {
528     LPCWSTR start;
529     LPCWSTR end;
530 };
531
532 static void CRYPT_KeynameKeeperFromTokenW(struct KeynameKeeper *keeper,
533  const struct X500TokenW *key)
534 {
535     DWORD len = key->end - key->start;
536
537     if (len > keeper->keyLen)
538     {
539         if (keeper->keyName == keeper->buf)
540             keeper->keyName = CryptMemAlloc(len * sizeof(WCHAR));
541         else
542             keeper->keyName = CryptMemRealloc(keeper->keyName,
543              len * sizeof(WCHAR));
544         keeper->keyLen = len;
545     }
546     memcpy(keeper->keyName, key->start, (key->end - key->start) *
547      sizeof(WCHAR));
548     keeper->keyName[len] = '\0';
549     TRACE("Keyname is %s\n", debugstr_w(keeper->keyName));
550 }
551
552 static DWORD CRYPT_GetNextKeyW(LPCWSTR str, struct X500TokenW *token,
553  LPCWSTR *ppszError)
554 {
555     DWORD ret = ERROR_SUCCESS;
556
557     while (*str && isspaceW(*str))
558         str++;
559     if (*str)
560     {
561         token->start = str;
562         while (*str && *str != '=' && !isspaceW(*str))
563             str++;
564         if (*str && (*str == '=' || isspaceW(*str)))
565             token->end = str;
566         else
567         {
568             TRACE("missing equals char at %s\n", debugstr_w(token->start));
569             if (ppszError)
570                 *ppszError = token->start;
571             ret = CRYPT_E_INVALID_X500_STRING;
572         }
573     }
574     else
575         token->start = NULL;
576     return ret;
577 }
578
579 /* Assumes separators are characters in the 0-255 range */
580 static DWORD CRYPT_GetNextValueW(LPCWSTR str, DWORD dwFlags, LPCWSTR separators,
581  struct X500TokenW *token, LPCWSTR *ppszError)
582 {
583     DWORD ret = ERROR_SUCCESS;
584
585     TRACE("(%s, %s, %p, %p)\n", debugstr_w(str), debugstr_w(separators), token,
586      ppszError);
587
588     while (*str && isspaceW(*str))
589         str++;
590     if (*str)
591     {
592         token->start = str;
593         if (!(dwFlags & CERT_NAME_STR_NO_QUOTING_FLAG) && *str == '"')
594         {
595             token->end = NULL;
596             str++;
597             while (!token->end && !ret)
598             {
599                 while (*str && *str != '"')
600                     str++;
601                 if (*str == '"')
602                 {
603                     if (*(str + 1) != '"')
604                         token->end = str + 1;
605                     else
606                         str += 2;
607                 }
608                 else
609                 {
610                     TRACE("unterminated quote at %s\n", debugstr_w(str));
611                     if (ppszError)
612                         *ppszError = str;
613                     ret = CRYPT_E_INVALID_X500_STRING;
614                 }
615             }
616         }
617         else
618         {
619             WCHAR map[256] = { 0 };
620
621             while (*separators)
622                 map[*separators++] = 1;
623             while (*str && (*str >= 0xff || !map[*(const unsigned short *)str]))
624                 str++;
625             token->end = str;
626         }
627     }
628     else
629     {
630         TRACE("missing value at %s\n", debugstr_w(str));
631         if (ppszError)
632             *ppszError = str;
633         ret = CRYPT_E_INVALID_X500_STRING;
634     }
635     return ret;
636 }
637
638 /* Encodes the string represented by value as the string type type into the
639  * CERT_NAME_BLOB output.  If there is an error and ppszError is not NULL,
640  * *ppszError is set to the first failing character.  If there is no error,
641  * output's pbData must be freed with LocalFree.
642  */
643 static BOOL CRYPT_EncodeValueWithType(DWORD dwCertEncodingType,
644  const struct X500TokenW *value, PCERT_NAME_BLOB output, DWORD type,
645  LPCWSTR *ppszError)
646 {
647     CERT_NAME_VALUE nameValue = { type, { 0, NULL } };
648     BOOL ret = TRUE;
649
650     if (value->end > value->start)
651     {
652         nameValue.Value.pbData = CryptMemAlloc((value->end - value->start) *
653          sizeof(WCHAR));
654         if (!nameValue.Value.pbData)
655         {
656             SetLastError(ERROR_OUTOFMEMORY);
657             ret = FALSE;
658         }
659     }
660     if (ret)
661     {
662         if (value->end > value->start)
663         {
664             DWORD i;
665             LPWSTR ptr = (LPWSTR)nameValue.Value.pbData;
666
667             for (i = 0; i < value->end - value->start; i++)
668             {
669                 *ptr++ = value->start[i];
670                 if (value->start[i] == '"')
671                     i++;
672             }
673             nameValue.Value.cbData = (LPBYTE)ptr - nameValue.Value.pbData;
674         }
675         ret = CryptEncodeObjectEx(dwCertEncodingType, X509_UNICODE_NAME_VALUE,
676          &nameValue, CRYPT_ENCODE_ALLOC_FLAG, NULL, &output->pbData,
677          &output->cbData);
678         if (!ret && ppszError)
679         {
680             if (type == CERT_RDN_NUMERIC_STRING &&
681              GetLastError() == CRYPT_E_INVALID_NUMERIC_STRING)
682                 *ppszError = value->start + output->cbData;
683             else if (type == CERT_RDN_PRINTABLE_STRING &&
684              GetLastError() == CRYPT_E_INVALID_PRINTABLE_STRING)
685                 *ppszError = value->start + output->cbData;
686             else if (type == CERT_RDN_IA5_STRING &&
687              GetLastError() == CRYPT_E_INVALID_IA5_STRING)
688                 *ppszError = value->start + output->cbData;
689         }
690         CryptMemFree(nameValue.Value.pbData);
691     }
692     return ret;
693 }
694
695 static BOOL CRYPT_EncodeValue(DWORD dwCertEncodingType,
696  const struct X500TokenW *value, PCERT_NAME_BLOB output, const DWORD *types,
697  LPCWSTR *ppszError)
698 {
699     DWORD i;
700     BOOL ret;
701
702     ret = FALSE;
703     for (i = 0; !ret && types[i]; i++)
704         ret = CRYPT_EncodeValueWithType(dwCertEncodingType, value, output,
705          types[i], ppszError);
706     return ret;
707 }
708
709 static BOOL CRYPT_ValueToRDN(DWORD dwCertEncodingType, PCERT_NAME_INFO info,
710  PCCRYPT_OID_INFO keyOID, struct X500TokenW *value, LPCWSTR *ppszError)
711 {
712     BOOL ret = FALSE;
713
714     TRACE("OID %s, value %s\n", debugstr_a(keyOID->pszOID),
715      debugstr_wn(value->start, value->end - value->start));
716
717     if (!info->rgRDN)
718         info->rgRDN = CryptMemAlloc(sizeof(CERT_RDN));
719     else
720         info->rgRDN = CryptMemRealloc(info->rgRDN,
721          (info->cRDN + 1) * sizeof(CERT_RDN));
722     if (info->rgRDN)
723     {
724         /* FIXME: support multiple RDN attrs */
725         info->rgRDN[info->cRDN].rgRDNAttr =
726          CryptMemAlloc(sizeof(CERT_RDN_ATTR));
727         if (info->rgRDN[info->cRDN].rgRDNAttr)
728         {
729             static const DWORD defaultTypes[] = { CERT_RDN_PRINTABLE_STRING,
730              CERT_RDN_BMP_STRING, 0 };
731             const DWORD *types;
732
733             info->rgRDN[info->cRDN].cRDNAttr = 1;
734             info->rgRDN[info->cRDN].rgRDNAttr[0].pszObjId =
735              (LPSTR)keyOID->pszOID;
736             info->rgRDN[info->cRDN].rgRDNAttr[0].dwValueType =
737              CERT_RDN_ENCODED_BLOB;
738             if (keyOID->ExtraInfo.cbData)
739                 types = (const DWORD *)keyOID->ExtraInfo.pbData;
740             else
741                 types = defaultTypes;
742
743             /* Remove surrounding quotes */
744             if (value->start[0] == '"')
745             {
746                 value->start++;
747                 value->end--;
748             }
749             ret = CRYPT_EncodeValue(dwCertEncodingType, value,
750              &info->rgRDN[info->cRDN].rgRDNAttr[0].Value, types, ppszError);
751         }
752     }
753     if (ret)
754         info->cRDN++;
755     return ret;
756 }
757
758 BOOL WINAPI CertStrToNameW(DWORD dwCertEncodingType, LPCWSTR pszX500,
759  DWORD dwStrType, void *pvReserved, BYTE *pbEncoded, DWORD *pcbEncoded,
760  LPCWSTR *ppszError)
761 {
762     CERT_NAME_INFO info = { 0, NULL };
763     LPCWSTR str;
764     struct KeynameKeeper keeper;
765     DWORD i, error = ERROR_SUCCESS;
766     BOOL ret = TRUE;
767
768     TRACE("(%08x, %s, %08x, %p, %p, %p, %p)\n", dwCertEncodingType,
769      debugstr_w(pszX500), dwStrType, pvReserved, pbEncoded, pcbEncoded,
770      ppszError);
771
772     CRYPT_InitializeKeynameKeeper(&keeper);
773     str = pszX500;
774     while (str && *str && !error && ret)
775     {
776         struct X500TokenW token;
777
778         error = CRYPT_GetNextKeyW(str, &token, ppszError);
779         if (!error && token.start)
780         {
781             PCCRYPT_OID_INFO keyOID;
782
783             CRYPT_KeynameKeeperFromTokenW(&keeper, &token);
784             keyOID = CryptFindOIDInfo(CRYPT_OID_INFO_NAME_KEY, keeper.keyName,
785              CRYPT_RDN_ATTR_OID_GROUP_ID);
786             if (!keyOID)
787             {
788                 if (ppszError)
789                     *ppszError = token.start;
790                 error = CRYPT_E_INVALID_X500_STRING;
791             }
792             else
793             {
794                 str = token.end;
795                 while (isspace(*str))
796                     str++;
797                 if (*str != '=')
798                 {
799                     if (ppszError)
800                         *ppszError = str;
801                     error = CRYPT_E_INVALID_X500_STRING;
802                 }
803                 else
804                 {
805                     static const WCHAR commaSep[] = { ',',0 };
806                     static const WCHAR semiSep[] = { ';',0 };
807                     static const WCHAR crlfSep[] = { '\r','\n',0 };
808                     static const WCHAR allSeps[] = { ',',';','\r','\n',0 };
809                     LPCWSTR sep;
810
811                     str++;
812                     if (dwStrType & CERT_NAME_STR_COMMA_FLAG)
813                         sep = commaSep;
814                     else if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG)
815                         sep = semiSep;
816                     else if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
817                         sep = crlfSep;
818                     else
819                         sep = allSeps;
820                     error = CRYPT_GetNextValueW(str, dwStrType, sep, &token,
821                      ppszError);
822                     if (!error)
823                     {
824                         str = token.end;
825                         ret = CRYPT_ValueToRDN(dwCertEncodingType, &info,
826                          keyOID, &token, ppszError);
827                     }
828                 }
829             }
830         }
831     }
832     CRYPT_FreeKeynameKeeper(&keeper);
833     if (!error)
834     {
835         if (ppszError)
836             *ppszError = NULL;
837         ret = CryptEncodeObjectEx(dwCertEncodingType, X509_NAME, &info,
838          0, NULL, pbEncoded, pcbEncoded);
839         for (i = 0; i < info.cRDN; i++)
840         {
841             DWORD j;
842
843             for (j = 0; j < info.rgRDN[i].cRDNAttr; j++)
844                 LocalFree(info.rgRDN[i].rgRDNAttr[j].Value.pbData);
845             CryptMemFree(info.rgRDN[i].rgRDNAttr);
846         }
847         CryptMemFree(info.rgRDN);
848     }
849     else
850     {
851         SetLastError(error);
852         ret = FALSE;
853     }
854     return ret;
855 }
856
857 DWORD WINAPI CertGetNameStringA(PCCERT_CONTEXT pCertContext, DWORD dwType,
858  DWORD dwFlags, void *pvTypePara, LPSTR pszNameString, DWORD cchNameString)
859 {
860     DWORD ret;
861
862     TRACE("(%p, %d, %08x, %p, %p, %d)\n", pCertContext, dwType, dwFlags,
863      pvTypePara, pszNameString, cchNameString);
864
865     if (pszNameString)
866     {
867         LPWSTR wideName;
868         DWORD nameLen;
869
870         nameLen = CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara,
871          NULL, 0);
872         wideName = CryptMemAlloc(nameLen * sizeof(WCHAR));
873         if (wideName)
874         {
875             CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara,
876              wideName, nameLen);
877             nameLen = WideCharToMultiByte(CP_ACP, 0, wideName, nameLen,
878              pszNameString, cchNameString, NULL, NULL);
879             if (nameLen <= cchNameString)
880                 ret = nameLen;
881             else
882             {
883                 pszNameString[cchNameString - 1] = '\0';
884                 ret = cchNameString;
885             }
886             CryptMemFree(wideName);
887         }
888         else
889         {
890             *pszNameString = '\0';
891             ret = 1;
892         }
893     }
894     else
895         ret = CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara,
896          NULL, 0);
897     return ret;
898 }
899
900 DWORD WINAPI CertGetNameStringW(PCCERT_CONTEXT pCertContext, DWORD dwType,
901  DWORD dwFlags, void *pvTypePara, LPWSTR pszNameString, DWORD cchNameString)
902 {
903     DWORD ret;
904     PCERT_NAME_BLOB name;
905     LPCSTR altNameOID;
906
907     TRACE("(%p, %d, %08x, %p, %p, %d)\n", pCertContext, dwType,
908      dwFlags, pvTypePara, pszNameString, cchNameString);
909
910     if (dwFlags & CERT_NAME_ISSUER_FLAG)
911     {
912         name = &pCertContext->pCertInfo->Issuer;
913         altNameOID = szOID_ISSUER_ALT_NAME;
914     }
915     else
916     {
917         name = &pCertContext->pCertInfo->Subject;
918         altNameOID = szOID_SUBJECT_ALT_NAME;
919     }
920
921     switch (dwType)
922     {
923     case CERT_NAME_SIMPLE_DISPLAY_TYPE:
924     {
925         static const LPCSTR simpleAttributeOIDs[] = { szOID_COMMON_NAME,
926          szOID_ORGANIZATIONAL_UNIT_NAME, szOID_ORGANIZATION_NAME,
927          szOID_RSA_emailAddr };
928         CERT_NAME_INFO *info = NULL;
929         PCERT_RDN_ATTR nameAttr = NULL;
930         DWORD bytes = 0, i;
931
932         if (CryptDecodeObjectEx(pCertContext->dwCertEncodingType, X509_NAME,
933          name->pbData, name->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info,
934          &bytes))
935         {
936             for (i = 0; !nameAttr && i < sizeof(simpleAttributeOIDs) /
937              sizeof(simpleAttributeOIDs[0]); i++)
938                 nameAttr = CertFindRDNAttr(simpleAttributeOIDs[i], info);
939         }
940         if (!nameAttr)
941         {
942             PCERT_EXTENSION ext = CertFindExtension(altNameOID,
943              pCertContext->pCertInfo->cExtension,
944              pCertContext->pCertInfo->rgExtension);
945
946             if (ext)
947             {
948                 for (i = 0; !nameAttr && i < sizeof(simpleAttributeOIDs) /
949                  sizeof(simpleAttributeOIDs[0]); i++)
950                     nameAttr = CertFindRDNAttr(simpleAttributeOIDs[i], info);
951                 if (!nameAttr)
952                 {
953                     /* FIXME: gotta then look for a rfc822Name choice in ext.
954                      * Failing that, look for the first attribute.
955                      */
956                     FIXME("CERT_NAME_SIMPLE_DISPLAY_TYPE: stub\n");
957                 }
958             }
959         }
960         if (nameAttr)
961             ret = CertRDNValueToStrW(nameAttr->dwValueType, &nameAttr->Value,
962                                      pszNameString, cchNameString);
963         else
964             ret = 0;
965         if (info)
966             LocalFree(info);
967         break;
968     }
969     case CERT_NAME_FRIENDLY_DISPLAY_TYPE:
970     {
971         DWORD cch = cchNameString;
972
973         if (CertGetCertificateContextProperty(pCertContext,
974          CERT_FRIENDLY_NAME_PROP_ID, pszNameString, &cch))
975             ret = cch;
976         else
977             ret = CertGetNameStringW(pCertContext,
978              CERT_NAME_SIMPLE_DISPLAY_TYPE, dwFlags, pvTypePara, pszNameString,
979              cchNameString);
980         break;
981     }
982     default:
983         FIXME("unimplemented for type %d\n", dwType);
984         ret = 0;
985     }
986     return ret;
987 }