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