~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/crypt32/str.c

Version: ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

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

~ [ source navigati