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