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