[CRYPT32] Sync with Wine Staging 3.17. CORE-15127
[reactos.git] / dll / win32 / 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
20 #define NONAMELESSUNION
21
22 #include "windef.h"
23 #include "winbase.h"
24 #include "winnls.h"
25 #include "winuser.h"
26 #include "wincrypt.h"
27 #include "wine/debug.h"
28 #include "wine/unicode.h"
29 #include "crypt32_private.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
32
33 DWORD WINAPI CertRDNValueToStrA(DWORD dwValueType, PCERT_RDN_VALUE_BLOB pValue,
34 LPSTR psz, DWORD csz)
35 {
36 DWORD ret = 0, len;
37
38 TRACE("(%d, %p, %p, %d)\n", dwValueType, pValue, psz, csz);
39
40 switch (dwValueType)
41 {
42 case CERT_RDN_ANY_TYPE:
43 break;
44 case CERT_RDN_NUMERIC_STRING:
45 case CERT_RDN_PRINTABLE_STRING:
46 case CERT_RDN_TELETEX_STRING:
47 case CERT_RDN_VIDEOTEX_STRING:
48 case CERT_RDN_IA5_STRING:
49 case CERT_RDN_GRAPHIC_STRING:
50 case CERT_RDN_VISIBLE_STRING:
51 case CERT_RDN_GENERAL_STRING:
52 len = pValue->cbData;
53 if (!psz || !csz)
54 ret = len;
55 else
56 {
57 DWORD chars = min(len, csz - 1);
58
59 if (chars)
60 {
61 memcpy(psz, pValue->pbData, chars);
62 ret += chars;
63 csz -= chars;
64 }
65 }
66 break;
67 case CERT_RDN_BMP_STRING:
68 case CERT_RDN_UTF8_STRING:
69 len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)pValue->pbData,
70 pValue->cbData / sizeof(WCHAR), NULL, 0, NULL, NULL);
71 if (!psz || !csz)
72 ret = len;
73 else
74 {
75 DWORD chars = min(pValue->cbData / sizeof(WCHAR), csz - 1);
76
77 if (chars)
78 {
79 ret = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)pValue->pbData,
80 chars, psz, csz - 1, NULL, NULL);
81 csz -= ret;
82 }
83 }
84 break;
85 default:
86 FIXME("string type %d unimplemented\n", dwValueType);
87 }
88 if (psz && csz)
89 {
90 *(psz + ret) = '\0';
91 csz--;
92 ret++;
93 }
94 else
95 ret++;
96 TRACE("returning %d (%s)\n", ret, debugstr_a(psz));
97 return ret;
98 }
99
100 DWORD WINAPI CertRDNValueToStrW(DWORD dwValueType, PCERT_RDN_VALUE_BLOB pValue,
101 LPWSTR psz, DWORD csz)
102 {
103 DWORD ret = 0, len, i, strLen;
104
105 TRACE("(%d, %p, %p, %d)\n", dwValueType, pValue, psz, csz);
106
107 switch (dwValueType)
108 {
109 case CERT_RDN_ANY_TYPE:
110 break;
111 case CERT_RDN_NUMERIC_STRING:
112 case CERT_RDN_PRINTABLE_STRING:
113 case CERT_RDN_TELETEX_STRING:
114 case CERT_RDN_VIDEOTEX_STRING:
115 case CERT_RDN_IA5_STRING:
116 case CERT_RDN_GRAPHIC_STRING:
117 case CERT_RDN_VISIBLE_STRING:
118 case CERT_RDN_GENERAL_STRING:
119 len = pValue->cbData;
120 if (!psz || !csz)
121 ret = len;
122 else
123 {
124 WCHAR *ptr = psz;
125
126 for (i = 0; i < pValue->cbData && ptr - psz < csz; ptr++, i++)
127 *ptr = pValue->pbData[i];
128 ret = ptr - psz;
129 }
130 break;
131 case CERT_RDN_BMP_STRING:
132 case CERT_RDN_UTF8_STRING:
133 strLen = len = pValue->cbData / sizeof(WCHAR);
134 if (!psz || !csz)
135 ret = len;
136 else
137 {
138 WCHAR *ptr = psz;
139
140 for (i = 0; i < strLen && ptr - psz < csz; ptr++, i++)
141 *ptr = ((LPCWSTR)pValue->pbData)[i];
142 ret = ptr - psz;
143 }
144 break;
145 default:
146 FIXME("string type %d unimplemented\n", dwValueType);
147 }
148 if (psz && csz)
149 {
150 *(psz + ret) = '\0';
151 csz--;
152 ret++;
153 }
154 else
155 ret++;
156 TRACE("returning %d (%s)\n", ret, debugstr_w(psz));
157 return ret;
158 }
159
160 static inline BOOL is_quotable_char(char c)
161 {
162 switch(c)
163 {
164 case '+':
165 case ',':
166 case '"':
167 case '=':
168 case '<':
169 case '>':
170 case ';':
171 case '#':
172 case '\n':
173 return TRUE;
174 default:
175 return FALSE;
176 }
177 }
178
179 static DWORD quote_rdn_value_to_str_a(DWORD dwValueType,
180 PCERT_RDN_VALUE_BLOB pValue, LPSTR psz, DWORD csz)
181 {
182 DWORD ret = 0, len, i;
183 BOOL needsQuotes = FALSE;
184
185 TRACE("(%d, %p, %p, %d)\n", dwValueType, pValue, psz, csz);
186
187 switch (dwValueType)
188 {
189 case CERT_RDN_ANY_TYPE:
190 break;
191 case CERT_RDN_NUMERIC_STRING:
192 case CERT_RDN_PRINTABLE_STRING:
193 case CERT_RDN_TELETEX_STRING:
194 case CERT_RDN_VIDEOTEX_STRING:
195 case CERT_RDN_IA5_STRING:
196 case CERT_RDN_GRAPHIC_STRING:
197 case CERT_RDN_VISIBLE_STRING:
198 case CERT_RDN_GENERAL_STRING:
199 len = pValue->cbData;
200 if (pValue->cbData && isspace(pValue->pbData[0]))
201 needsQuotes = TRUE;
202 if (pValue->cbData && isspace(pValue->pbData[pValue->cbData - 1]))
203 needsQuotes = TRUE;
204 for (i = 0; i < pValue->cbData; i++)
205 {
206 if (is_quotable_char(pValue->pbData[i]))
207 needsQuotes = TRUE;
208 if (pValue->pbData[i] == '"')
209 len += 1;
210 }
211 if (needsQuotes)
212 len += 2;
213 if (!psz || !csz)
214 ret = len;
215 else
216 {
217 char *ptr = psz;
218
219 if (needsQuotes)
220 *ptr++ = '"';
221 for (i = 0; i < pValue->cbData && ptr - psz < csz; ptr++, i++)
222 {
223 *ptr = pValue->pbData[i];
224 if (pValue->pbData[i] == '"' && ptr - psz < csz - 1)
225 *(++ptr) = '"';
226 }
227 if (needsQuotes && ptr - psz < csz)
228 *ptr++ = '"';
229 ret = ptr - psz;
230 }
231 break;
232 case CERT_RDN_BMP_STRING:
233 case CERT_RDN_UTF8_STRING:
234 len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)pValue->pbData,
235 pValue->cbData / sizeof(WCHAR), NULL, 0, NULL, NULL);
236 if (pValue->cbData && isspaceW(((LPCWSTR)pValue->pbData)[0]))
237 needsQuotes = TRUE;
238 if (pValue->cbData &&
239 isspaceW(((LPCWSTR)pValue->pbData)[pValue->cbData / sizeof(WCHAR)-1]))
240 needsQuotes = TRUE;
241 for (i = 0; i < pValue->cbData / sizeof(WCHAR); i++)
242 {
243 if (is_quotable_char(((LPCWSTR)pValue->pbData)[i]))
244 needsQuotes = TRUE;
245 if (((LPCWSTR)pValue->pbData)[i] == '"')
246 len += 1;
247 }
248 if (needsQuotes)
249 len += 2;
250 if (!psz || !csz)
251 ret = len;
252 else
253 {
254 char *dst = psz;
255
256 if (needsQuotes)
257 *dst++ = '"';
258 for (i = 0; i < pValue->cbData / sizeof(WCHAR) &&
259 dst - psz < csz; dst++, i++)
260 {
261 LPCWSTR src = (LPCWSTR)pValue->pbData + i;
262
263 WideCharToMultiByte(CP_ACP, 0, src, 1, dst,
264 csz - (dst - psz) - 1, NULL, NULL);
265 if (*src == '"' && dst - psz < csz - 1)
266 *(++dst) = '"';
267 }
268 if (needsQuotes && dst - psz < csz)
269 *dst++ = '"';
270 ret = dst - psz;
271 }
272 break;
273 default:
274 FIXME("string type %d unimplemented\n", dwValueType);
275 }
276 if (psz && csz)
277 {
278 *(psz + ret) = '\0';
279 csz--;
280 ret++;
281 }
282 else
283 ret++;
284 TRACE("returning %d (%s)\n", ret, debugstr_a(psz));
285 return ret;
286 }
287
288 static DWORD quote_rdn_value_to_str_w(DWORD dwValueType,
289 PCERT_RDN_VALUE_BLOB pValue, LPWSTR psz, DWORD csz)
290 {
291 DWORD ret = 0, len, i, strLen;
292 BOOL needsQuotes = FALSE;
293
294 TRACE("(%d, %p, %p, %d)\n", dwValueType, pValue, psz, csz);
295
296 switch (dwValueType)
297 {
298 case CERT_RDN_ANY_TYPE:
299 break;
300 case CERT_RDN_NUMERIC_STRING:
301 case CERT_RDN_PRINTABLE_STRING:
302 case CERT_RDN_TELETEX_STRING:
303 case CERT_RDN_VIDEOTEX_STRING:
304 case CERT_RDN_IA5_STRING:
305 case CERT_RDN_GRAPHIC_STRING:
306 case CERT_RDN_VISIBLE_STRING:
307 case CERT_RDN_GENERAL_STRING:
308 len = pValue->cbData;
309 if (pValue->cbData && isspace(pValue->pbData[0]))
310 needsQuotes = TRUE;
311 if (pValue->cbData && isspace(pValue->pbData[pValue->cbData - 1]))
312 needsQuotes = TRUE;
313 for (i = 0; i < pValue->cbData; i++)
314 {
315 if (is_quotable_char(pValue->pbData[i]))
316 needsQuotes = TRUE;
317 if (pValue->pbData[i] == '"')
318 len += 1;
319 }
320 if (needsQuotes)
321 len += 2;
322 if (!psz || !csz)
323 ret = len;
324 else
325 {
326 WCHAR *ptr = psz;
327
328 if (needsQuotes)
329 *ptr++ = '"';
330 for (i = 0; i < pValue->cbData && ptr - psz < csz; ptr++, i++)
331 {
332 *ptr = pValue->pbData[i];
333 if (pValue->pbData[i] == '"' && ptr - psz < csz - 1)
334 *(++ptr) = '"';
335 }
336 if (needsQuotes && ptr - psz < csz)
337 *ptr++ = '"';
338 ret = ptr - psz;
339 }
340 break;
341 case CERT_RDN_BMP_STRING:
342 case CERT_RDN_UTF8_STRING:
343 strLen = len = pValue->cbData / sizeof(WCHAR);
344 if (pValue->cbData && isspace(pValue->pbData[0]))
345 needsQuotes = TRUE;
346 if (pValue->cbData && isspace(pValue->pbData[strLen - 1]))
347 needsQuotes = TRUE;
348 for (i = 0; i < strLen; i++)
349 {
350 if (is_quotable_char(((LPCWSTR)pValue->pbData)[i]))
351 needsQuotes = TRUE;
352 if (((LPCWSTR)pValue->pbData)[i] == '"')
353 len += 1;
354 }
355 if (needsQuotes)
356 len += 2;
357 if (!psz || !csz)
358 ret = len;
359 else
360 {
361 WCHAR *ptr = psz;
362
363 if (needsQuotes)
364 *ptr++ = '"';
365 for (i = 0; i < strLen && ptr - psz < csz; ptr++, i++)
366 {
367 *ptr = ((LPCWSTR)pValue->pbData)[i];
368 if (((LPCWSTR)pValue->pbData)[i] == '"' && ptr - psz < csz - 1)
369 *(++ptr) = '"';
370 }
371 if (needsQuotes && ptr - psz < csz)
372 *ptr++ = '"';
373 ret = ptr - psz;
374 }
375 break;
376 default:
377 FIXME("string type %d unimplemented\n", dwValueType);
378 }
379 if (psz && csz)
380 {
381 *(psz + ret) = '\0';
382 csz--;
383 ret++;
384 }
385 else
386 ret++;
387 TRACE("returning %d (%s)\n", ret, debugstr_w(psz));
388 return ret;
389 }
390
391 /* Adds the prefix prefix to the string pointed to by psz, followed by the
392 * character '='. Copies no more than csz characters. Returns the number of
393 * characters copied. If psz is NULL, returns the number of characters that
394 * would be copied.
395 */
396 static DWORD CRYPT_AddPrefixA(LPCSTR prefix, LPSTR psz, DWORD csz)
397 {
398 DWORD chars;
399
400 TRACE("(%s, %p, %d)\n", debugstr_a(prefix), psz, csz);
401
402 if (psz)
403 {
404 chars = min(strlen(prefix), csz);
405 memcpy(psz, prefix, chars);
406 *(psz + chars) = '=';
407 chars++;
408 }
409 else
410 chars = lstrlenA(prefix) + 1;
411 return chars;
412 }
413
414 DWORD WINAPI CertNameToStrA(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName,
415 DWORD dwStrType, LPSTR psz, DWORD csz)
416 {
417 static const DWORD unsupportedFlags = CERT_NAME_STR_NO_QUOTING_FLAG |
418 CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG;
419 static const char commaSep[] = ", ";
420 static const char semiSep[] = "; ";
421 static const char crlfSep[] = "\r\n";
422 static const char plusSep[] = " + ";
423 static const char spaceSep[] = " ";
424 DWORD ret = 0, bytes = 0;
425 BOOL bRet;
426 CERT_NAME_INFO *info;
427
428 TRACE("(%d, %p, %08x, %p, %d)\n", dwCertEncodingType, pName, dwStrType,
429 psz, csz);
430 if (dwStrType & unsupportedFlags)
431 FIXME("unsupported flags: %08x\n", dwStrType & unsupportedFlags);
432
433 bRet = CryptDecodeObjectEx(dwCertEncodingType, X509_NAME, pName->pbData,
434 pName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &bytes);
435 if (bRet)
436 {
437 DWORD i, j, sepLen, rdnSepLen;
438 LPCSTR sep, rdnSep;
439 BOOL reverse = dwStrType & CERT_NAME_STR_REVERSE_FLAG;
440 const CERT_RDN *rdn = info->rgRDN;
441
442 if(reverse && info->cRDN > 1) rdn += (info->cRDN - 1);
443
444 if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG)
445 sep = semiSep;
446 else if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
447 sep = crlfSep;
448 else
449 sep = commaSep;
450 sepLen = strlen(sep);
451 if (dwStrType & CERT_NAME_STR_NO_PLUS_FLAG)
452 rdnSep = spaceSep;
453 else
454 rdnSep = plusSep;
455 rdnSepLen = strlen(rdnSep);
456 for (i = 0; (!psz || ret < csz) && i < info->cRDN; i++)
457 {
458 for (j = 0; (!psz || ret < csz) && j < rdn->cRDNAttr; j++)
459 {
460 DWORD chars;
461 char prefixBuf[13]; /* big enough for SERIALNUMBER */
462 LPCSTR prefix = NULL;
463
464 if ((dwStrType & 0x000000ff) == CERT_OID_NAME_STR)
465 prefix = rdn->rgRDNAttr[j].pszObjId;
466 else if ((dwStrType & 0x000000ff) == CERT_X500_NAME_STR)
467 {
468 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(
469 CRYPT_OID_INFO_OID_KEY,
470 rdn->rgRDNAttr[j].pszObjId,
471 CRYPT_RDN_ATTR_OID_GROUP_ID);
472
473 if (oidInfo)
474 {
475 WideCharToMultiByte(CP_ACP, 0, oidInfo->pwszName, -1,
476 prefixBuf, sizeof(prefixBuf), NULL, NULL);
477 prefix = prefixBuf;
478 }
479 else
480 prefix = rdn->rgRDNAttr[j].pszObjId;
481 }
482 if (prefix)
483 {
484 /* - 1 is needed to account for the NULL terminator. */
485 chars = CRYPT_AddPrefixA(prefix,
486 psz ? psz + ret : NULL, psz ? csz - ret - 1 : 0);
487 ret += chars;
488 }
489 chars = quote_rdn_value_to_str_a(
490 rdn->rgRDNAttr[j].dwValueType,
491 &rdn->rgRDNAttr[j].Value, psz ? psz + ret : NULL,
492 psz ? csz - ret : 0);
493 if (chars)
494 ret += chars - 1;
495 if (j < rdn->cRDNAttr - 1)
496 {
497 if (psz && ret < csz - rdnSepLen - 1)
498 memcpy(psz + ret, rdnSep, rdnSepLen);
499 ret += rdnSepLen;
500 }
501 }
502 if (i < info->cRDN - 1)
503 {
504 if (psz && ret < csz - sepLen - 1)
505 memcpy(psz + ret, sep, sepLen);
506 ret += sepLen;
507 }
508 if(reverse) rdn--;
509 else rdn++;
510 }
511 LocalFree(info);
512 }
513 if (psz && csz)
514 {
515 *(psz + ret) = '\0';
516 ret++;
517 }
518 else
519 ret++;
520 TRACE("Returning %s\n", debugstr_a(psz));
521 return ret;
522 }
523
524 /* Adds the prefix prefix to the wide-character string pointed to by psz,
525 * followed by the character '='. Copies no more than csz characters. Returns
526 * the number of characters copied. If psz is NULL, returns the number of
527 * characters that would be copied.
528 * Assumes the characters in prefix are ASCII (not multibyte characters.)
529 */
530 static DWORD CRYPT_AddPrefixAToW(LPCSTR prefix, LPWSTR psz, DWORD csz)
531 {
532 DWORD chars;
533
534 TRACE("(%s, %p, %d)\n", debugstr_a(prefix), psz, csz);
535
536 if (psz)
537 {
538 DWORD i;
539
540 chars = min(strlen(prefix), csz);
541 for (i = 0; i < chars; i++)
542 *(psz + i) = prefix[i];
543 *(psz + chars) = '=';
544 chars++;
545 }
546 else
547 chars = lstrlenA(prefix) + 1;
548 return chars;
549 }
550
551 /* Adds the prefix prefix to the string pointed to by psz, followed by the
552 * character '='. Copies no more than csz characters. Returns the number of
553 * characters copied. If psz is NULL, returns the number of characters that
554 * would be copied.
555 */
556 static DWORD CRYPT_AddPrefixW(LPCWSTR prefix, LPWSTR psz, DWORD csz)
557 {
558 DWORD chars;
559
560 TRACE("(%s, %p, %d)\n", debugstr_w(prefix), psz, csz);
561
562 if (psz)
563 {
564 chars = min(strlenW(prefix), csz);
565 memcpy(psz, prefix, chars * sizeof(WCHAR));
566 *(psz + chars) = '=';
567 chars++;
568 }
569 else
570 chars = lstrlenW(prefix) + 1;
571 return chars;
572 }
573
574 static const WCHAR indent[] = { ' ',' ',' ',' ',' ',0 };
575
576 DWORD cert_name_to_str_with_indent(DWORD dwCertEncodingType, DWORD indentLevel,
577 const CERT_NAME_BLOB *pName, DWORD dwStrType, LPWSTR psz, DWORD csz)
578 {
579 static const DWORD unsupportedFlags = CERT_NAME_STR_NO_QUOTING_FLAG |
580 CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG;
581 static const WCHAR commaSep[] = { ',',' ',0 };
582 static const WCHAR semiSep[] = { ';',' ',0 };
583 static const WCHAR crlfSep[] = { '\r','\n',0 };
584 static const WCHAR plusSep[] = { ' ','+',' ',0 };
585 static const WCHAR spaceSep[] = { ' ',0 };
586 DWORD ret = 0, bytes = 0;
587 BOOL bRet;
588 CERT_NAME_INFO *info;
589
590 if (dwStrType & unsupportedFlags)
591 FIXME("unsupported flags: %08x\n", dwStrType & unsupportedFlags);
592
593 bRet = CryptDecodeObjectEx(dwCertEncodingType, X509_NAME, pName->pbData,
594 pName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &bytes);
595 if (bRet)
596 {
597 DWORD i, j, sepLen, rdnSepLen;
598 LPCWSTR sep, rdnSep;
599 BOOL reverse = dwStrType & CERT_NAME_STR_REVERSE_FLAG;
600 const CERT_RDN *rdn = info->rgRDN;
601
602 if(reverse && info->cRDN > 1) rdn += (info->cRDN - 1);
603
604 if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG)
605 sep = semiSep;
606 else if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
607 sep = crlfSep;
608 else
609 sep = commaSep;
610 sepLen = lstrlenW(sep);
611 if (dwStrType & CERT_NAME_STR_NO_PLUS_FLAG)
612 rdnSep = spaceSep;
613 else
614 rdnSep = plusSep;
615 rdnSepLen = lstrlenW(rdnSep);
616 for (i = 0; (!psz || ret < csz) && i < info->cRDN; i++)
617 {
618 for (j = 0; (!psz || ret < csz) && j < rdn->cRDNAttr; j++)
619 {
620 DWORD chars;
621 LPCSTR prefixA = NULL;
622 LPCWSTR prefixW = NULL;
623
624 if ((dwStrType & 0x000000ff) == CERT_OID_NAME_STR)
625 prefixA = rdn->rgRDNAttr[j].pszObjId;
626 else if ((dwStrType & 0x000000ff) == CERT_X500_NAME_STR)
627 {
628 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(
629 CRYPT_OID_INFO_OID_KEY,
630 rdn->rgRDNAttr[j].pszObjId,
631 CRYPT_RDN_ATTR_OID_GROUP_ID);
632
633 if (oidInfo)
634 prefixW = oidInfo->pwszName;
635 else
636 prefixA = rdn->rgRDNAttr[j].pszObjId;
637 }
638 if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
639 {
640 DWORD k;
641
642 for (k = 0; k < indentLevel; k++)
643 {
644 if (psz)
645 {
646 chars = min(strlenW(indent), csz - ret - 1);
647 memcpy(psz + ret, indent, chars * sizeof(WCHAR));
648 }
649 else
650 chars = strlenW(indent);
651 ret += chars;
652 }
653 }
654 if (prefixW)
655 {
656 /* - 1 is needed to account for the NULL terminator. */
657 chars = CRYPT_AddPrefixW(prefixW,
658 psz ? psz + ret : NULL, psz ? csz - ret - 1 : 0);
659 ret += chars;
660 }
661 else if (prefixA)
662 {
663 /* - 1 is needed to account for the NULL terminator. */
664 chars = CRYPT_AddPrefixAToW(prefixA,
665 psz ? psz + ret : NULL, psz ? csz - ret - 1 : 0);
666 ret += chars;
667 }
668 chars = quote_rdn_value_to_str_w(
669 rdn->rgRDNAttr[j].dwValueType,
670 &rdn->rgRDNAttr[j].Value, psz ? psz + ret : NULL,
671 psz ? csz - ret : 0);
672 if (chars)
673 ret += chars - 1;
674 if (j < rdn->cRDNAttr - 1)
675 {
676 if (psz && ret < csz - rdnSepLen - 1)
677 memcpy(psz + ret, rdnSep, rdnSepLen * sizeof(WCHAR));
678 ret += rdnSepLen;
679 }
680 }
681 if (i < info->cRDN - 1)
682 {
683 if (psz && ret < csz - sepLen - 1)
684 memcpy(psz + ret, sep, sepLen * sizeof(WCHAR));
685 ret += sepLen;
686 }
687 if(reverse) rdn--;
688 else rdn++;
689 }
690 LocalFree(info);
691 }
692 if (psz && csz)
693 {
694 *(psz + ret) = '\0';
695 ret++;
696 }
697 else
698 ret++;
699 return ret;
700 }
701
702 DWORD WINAPI CertNameToStrW(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName,
703 DWORD dwStrType, LPWSTR psz, DWORD csz)
704 {
705 BOOL ret;
706
707 TRACE("(%d, %p, %08x, %p, %d)\n", dwCertEncodingType, pName, dwStrType,
708 psz, csz);
709
710 ret = cert_name_to_str_with_indent(dwCertEncodingType, 0, pName, dwStrType,
711 psz, csz);
712 TRACE("Returning %s\n", debugstr_w(psz));
713 return ret;
714 }
715
716 BOOL WINAPI CertStrToNameA(DWORD dwCertEncodingType, LPCSTR pszX500,
717 DWORD dwStrType, void *pvReserved, BYTE *pbEncoded, DWORD *pcbEncoded,
718 LPCSTR *ppszError)
719 {
720 BOOL ret;
721 int len;
722
723 TRACE("(%08x, %s, %08x, %p, %p, %p, %p)\n", dwCertEncodingType,
724 debugstr_a(pszX500), dwStrType, pvReserved, pbEncoded, pcbEncoded,
725 ppszError);
726
727 len = MultiByteToWideChar(CP_ACP, 0, pszX500, -1, NULL, 0);
728 if (len)
729 {
730 LPWSTR x500, errorStr;
731
732 if ((x500 = CryptMemAlloc(len * sizeof(WCHAR))))
733 {
734 MultiByteToWideChar(CP_ACP, 0, pszX500, -1, x500, len);
735 ret = CertStrToNameW(dwCertEncodingType, x500, dwStrType,
736 pvReserved, pbEncoded, pcbEncoded,
737 ppszError ? (LPCWSTR *)&errorStr : NULL);
738 if (ppszError)
739 {
740 if (!ret)
741 {
742 LONG i;
743
744 *ppszError = pszX500;
745 for (i = 0; i < errorStr - x500; i++)
746 *ppszError = CharNextA(*ppszError);
747 }
748 else
749 *ppszError = NULL;
750 }
751 CryptMemFree(x500);
752 }
753 else
754 {
755 SetLastError(ERROR_OUTOFMEMORY);
756 ret = FALSE;
757 }
758 }
759 else
760 {
761 SetLastError(CRYPT_E_INVALID_X500_STRING);
762 if (ppszError)
763 *ppszError = pszX500;
764 ret = FALSE;
765 }
766 return ret;
767 }
768
769 struct KeynameKeeper
770 {
771 WCHAR buf[10]; /* big enough for L"GivenName" */
772 LPWSTR keyName; /* usually = buf, but may be allocated */
773 DWORD keyLen; /* full available buffer size in WCHARs */
774 };
775
776 static void CRYPT_InitializeKeynameKeeper(struct KeynameKeeper *keeper)
777 {
778 keeper->keyName = keeper->buf;
779 keeper->keyLen = ARRAY_SIZE(keeper->buf);
780 }
781
782 static void CRYPT_FreeKeynameKeeper(struct KeynameKeeper *keeper)
783 {
784 if (keeper->keyName != keeper->buf)
785 CryptMemFree(keeper->keyName);
786 }
787
788 struct X500TokenW
789 {
790 LPCWSTR start;
791 LPCWSTR end;
792 };
793
794 static void CRYPT_KeynameKeeperFromTokenW(struct KeynameKeeper *keeper,
795 const struct X500TokenW *key)
796 {
797 DWORD len = key->end - key->start;
798
799 if (len >= keeper->keyLen)
800 {
801 CRYPT_FreeKeynameKeeper( keeper );
802 keeper->keyLen = len + 1;
803 keeper->keyName = CryptMemAlloc(keeper->keyLen * sizeof(WCHAR));
804 }
805 memcpy(keeper->keyName, key->start, len * sizeof(WCHAR));
806 keeper->keyName[len] = '\0';
807 TRACE("Keyname is %s\n", debugstr_w(keeper->keyName));
808 }
809
810 static BOOL CRYPT_GetNextKeyW(LPCWSTR str, struct X500TokenW *token,
811 LPCWSTR *ppszError)
812 {
813 BOOL ret = TRUE;
814
815 while (*str && isspaceW(*str))
816 str++;
817 if (*str)
818 {
819 token->start = str;
820 while (*str && *str != '=' && !isspaceW(*str))
821 str++;
822 if (*str && (*str == '=' || isspaceW(*str)))
823 token->end = str;
824 else
825 {
826 TRACE("missing equals char at %s\n", debugstr_w(token->start));
827 if (ppszError)
828 *ppszError = token->start;
829 SetLastError(CRYPT_E_INVALID_X500_STRING);
830 ret = FALSE;
831 }
832 }
833 else
834 token->start = NULL;
835 return ret;
836 }
837
838 /* Assumes separators are characters in the 0-255 range */
839 static BOOL CRYPT_GetNextValueW(LPCWSTR str, DWORD dwFlags, LPCWSTR separators,
840 WCHAR *separator_used, struct X500TokenW *token, LPCWSTR *ppszError)
841 {
842 BOOL ret = TRUE;
843
844 TRACE("(%s, %s, %p, %p)\n", debugstr_w(str), debugstr_w(separators), token,
845 ppszError);
846
847 *separator_used = 0;
848 while (*str && isspaceW(*str))
849 str++;
850 if (*str)
851 {
852 token->start = str;
853 if (!(dwFlags & CERT_NAME_STR_NO_QUOTING_FLAG) && *str == '"')
854 {
855 token->end = NULL;
856 str++;
857 while (!token->end && ret)
858 {
859 while (*str && *str != '"')
860 str++;
861 if (*str == '"')
862 {
863 if (*(str + 1) != '"')
864 token->end = str + 1;
865 else
866 str += 2;
867 }
868 else
869 {
870 TRACE("unterminated quote at %s\n", debugstr_w(str));
871 if (ppszError)
872 *ppszError = str;
873 SetLastError(CRYPT_E_INVALID_X500_STRING);
874 ret = FALSE;
875 }
876 }
877 }
878 else
879 {
880 WCHAR map[256] = { 0 };
881
882 while (*separators)
883 map[*separators++] = 1;
884 while (*str && (*str >= 0xff || !map[*str]))
885 str++;
886 token->end = str;
887 if (map[*str]) *separator_used = *str;
888 }
889 }
890 else
891 {
892 TRACE("missing value at %s\n", debugstr_w(str));
893 if (ppszError)
894 *ppszError = str;
895 SetLastError(CRYPT_E_INVALID_X500_STRING);
896 ret = FALSE;
897 }
898 return ret;
899 }
900
901 /* Encodes the string represented by value as the string type type into the
902 * CERT_NAME_BLOB output. If there is an error and ppszError is not NULL,
903 * *ppszError is set to the first failing character. If there is no error,
904 * output's pbData must be freed with LocalFree.
905 */
906 static BOOL CRYPT_EncodeValueWithType(DWORD dwCertEncodingType,
907 const struct X500TokenW *value, PCERT_NAME_BLOB output, DWORD type,
908 LPCWSTR *ppszError)
909 {
910 CERT_NAME_VALUE nameValue = { type, { 0, NULL } };
911 BOOL ret = TRUE;
912
913 if (value->end > value->start)
914 {
915 LONG i;
916 LPWSTR ptr;
917
918 nameValue.Value.pbData = CryptMemAlloc((value->end - value->start + 1) *
919 sizeof(WCHAR));
920 if (!nameValue.Value.pbData)
921 {
922 SetLastError(ERROR_OUTOFMEMORY);
923 return FALSE;
924 }
925 ptr = (LPWSTR)nameValue.Value.pbData;
926 for (i = 0; i < value->end - value->start; i++)
927 {
928 *ptr++ = value->start[i];
929 if (value->start[i] == '"')
930 i++;
931 }
932 /* The string is NULL terminated because of a quirk in encoding
933 * unicode names values: if the length is given as 0, the value is
934 * assumed to be a NULL-terminated string.
935 */
936 *ptr = 0;
937 nameValue.Value.cbData = (LPBYTE)ptr - nameValue.Value.pbData;
938 }
939 ret = CryptEncodeObjectEx(dwCertEncodingType, X509_UNICODE_NAME_VALUE,
940 &nameValue, CRYPT_ENCODE_ALLOC_FLAG, NULL, &output->pbData,
941 &output->cbData);
942 if (!ret && ppszError)
943 {
944 if (type == CERT_RDN_NUMERIC_STRING &&
945 GetLastError() == CRYPT_E_INVALID_NUMERIC_STRING)
946 *ppszError = value->start + output->cbData;
947 else if (type == CERT_RDN_PRINTABLE_STRING &&
948 GetLastError() == CRYPT_E_INVALID_PRINTABLE_STRING)
949 *ppszError = value->start + output->cbData;
950 else if (type == CERT_RDN_IA5_STRING &&
951 GetLastError() == CRYPT_E_INVALID_IA5_STRING)
952 *ppszError = value->start + output->cbData;
953 }
954 CryptMemFree(nameValue.Value.pbData);
955 return ret;
956 }
957
958 static BOOL CRYPT_EncodeValue(DWORD dwCertEncodingType,
959 const struct X500TokenW *value, PCERT_NAME_BLOB output, const DWORD *types,
960 LPCWSTR *ppszError)
961 {
962 DWORD i;
963 BOOL ret;
964
965 ret = FALSE;
966 for (i = 0; !ret && types[i]; i++)
967 ret = CRYPT_EncodeValueWithType(dwCertEncodingType, value, output,
968 types[i], ppszError);
969 return ret;
970 }
971
972 static BOOL CRYPT_ValueToRDN(DWORD dwCertEncodingType, PCERT_NAME_INFO info,
973 PCCRYPT_OID_INFO keyOID, struct X500TokenW *value, DWORD dwStrType, LPCWSTR *ppszError)
974 {
975 BOOL ret = FALSE;
976
977 TRACE("OID %s, value %s\n", debugstr_a(keyOID->pszOID),
978 debugstr_wn(value->start, value->end - value->start));
979
980 if (!info->rgRDN)
981 info->rgRDN = CryptMemAlloc(sizeof(CERT_RDN));
982 else
983 info->rgRDN = CryptMemRealloc(info->rgRDN,
984 (info->cRDN + 1) * sizeof(CERT_RDN));
985 if (info->rgRDN)
986 {
987 /* FIXME: support multiple RDN attrs */
988 info->rgRDN[info->cRDN].rgRDNAttr =
989 CryptMemAlloc(sizeof(CERT_RDN_ATTR));
990 if (info->rgRDN[info->cRDN].rgRDNAttr)
991 {
992 static const DWORD defaultTypes[] = { CERT_RDN_PRINTABLE_STRING,
993 CERT_RDN_BMP_STRING, 0 };
994 const DWORD *types;
995
996 info->rgRDN[info->cRDN].cRDNAttr = 1;
997 info->rgRDN[info->cRDN].rgRDNAttr[0].pszObjId =
998 (LPSTR)keyOID->pszOID;
999 info->rgRDN[info->cRDN].rgRDNAttr[0].dwValueType =
1000 CERT_RDN_ENCODED_BLOB;
1001 if (keyOID->ExtraInfo.cbData)
1002 types = (const DWORD *)keyOID->ExtraInfo.pbData;
1003 else
1004 types = defaultTypes;
1005
1006 /* Remove surrounding quotes */
1007 if (value->start[0] == '"' && !(dwStrType & CERT_NAME_STR_NO_QUOTING_FLAG))
1008 {
1009 value->start++;
1010 value->end--;
1011 }
1012 ret = CRYPT_EncodeValue(dwCertEncodingType, value,
1013 &info->rgRDN[info->cRDN].rgRDNAttr[0].Value, types, ppszError);
1014 }
1015 else
1016 SetLastError(ERROR_OUTOFMEMORY);
1017 info->cRDN++;
1018 }
1019 else
1020 SetLastError(ERROR_OUTOFMEMORY);
1021 return ret;
1022 }
1023
1024 BOOL WINAPI CertStrToNameW(DWORD dwCertEncodingType, LPCWSTR pszX500,
1025 DWORD dwStrType, void *pvReserved, BYTE *pbEncoded, DWORD *pcbEncoded,
1026 LPCWSTR *ppszError)
1027 {
1028 CERT_NAME_INFO info = { 0, NULL };
1029 LPCWSTR str;
1030 struct KeynameKeeper keeper;
1031 DWORD i;
1032 BOOL ret = TRUE;
1033
1034 TRACE("(%08x, %s, %08x, %p, %p, %p, %p)\n", dwCertEncodingType,
1035 debugstr_w(pszX500), dwStrType, pvReserved, pbEncoded, pcbEncoded,
1036 ppszError);
1037
1038 CRYPT_InitializeKeynameKeeper(&keeper);
1039 str = pszX500;
1040 while (str && *str && ret)
1041 {
1042 struct X500TokenW token;
1043
1044 ret = CRYPT_GetNextKeyW(str, &token, ppszError);
1045 if (ret && token.start)
1046 {
1047 PCCRYPT_OID_INFO keyOID;
1048
1049 CRYPT_KeynameKeeperFromTokenW(&keeper, &token);
1050 keyOID = CryptFindOIDInfo(CRYPT_OID_INFO_NAME_KEY, keeper.keyName,
1051 CRYPT_RDN_ATTR_OID_GROUP_ID);
1052 if (!keyOID)
1053 {
1054 if (ppszError)
1055 *ppszError = token.start;
1056 SetLastError(CRYPT_E_INVALID_X500_STRING);
1057 ret = FALSE;
1058 }
1059 else
1060 {
1061 str = token.end;
1062 while (isspaceW(*str))
1063 str++;
1064 if (*str != '=')
1065 {
1066 if (ppszError)
1067 *ppszError = str;
1068 SetLastError(CRYPT_E_INVALID_X500_STRING);
1069 ret = FALSE;
1070 }
1071 else
1072 {
1073 static const WCHAR commaSep[] = { ',',0 };
1074 static const WCHAR semiSep[] = { ';',0 };
1075 static const WCHAR crlfSep[] = { '\r','\n',0 };
1076 static const WCHAR allSepsWithoutPlus[] = { ',',';','\r','\n',0 };
1077 static const WCHAR allSeps[] = { '+',',',';','\r','\n',0 };
1078 LPCWSTR sep;
1079 WCHAR sep_used;
1080
1081 str++;
1082 if (dwStrType & CERT_NAME_STR_COMMA_FLAG)
1083 sep = commaSep;
1084 else if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG)
1085 sep = semiSep;
1086 else if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
1087 sep = crlfSep;
1088 else if (dwStrType & CERT_NAME_STR_NO_PLUS_FLAG)
1089 sep = allSepsWithoutPlus;
1090 else
1091 sep = allSeps;
1092 ret = CRYPT_GetNextValueW(str, dwStrType, sep, &sep_used, &token,
1093 ppszError);
1094 if (ret)
1095 {
1096 str = token.end;
1097 /* if token.end points to the separator, skip it */
1098 if (str && sep_used && *str == sep_used) str++;
1099
1100 ret = CRYPT_ValueToRDN(dwCertEncodingType, &info,
1101 keyOID, &token, dwStrType, ppszError);
1102 }
1103 }
1104 }
1105 }
1106 }
1107 CRYPT_FreeKeynameKeeper(&keeper);
1108 if (ret)
1109 {
1110 if (ppszError)
1111 *ppszError = NULL;
1112 ret = CryptEncodeObjectEx(dwCertEncodingType, X509_NAME, &info,
1113 0, NULL, pbEncoded, pcbEncoded);
1114 }
1115 for (i = 0; i < info.cRDN; i++)
1116 {
1117 DWORD j;
1118
1119 for (j = 0; j < info.rgRDN[i].cRDNAttr; j++)
1120 LocalFree(info.rgRDN[i].rgRDNAttr[j].Value.pbData);
1121 CryptMemFree(info.rgRDN[i].rgRDNAttr);
1122 }
1123 CryptMemFree(info.rgRDN);
1124 return ret;
1125 }
1126
1127 DWORD WINAPI CertGetNameStringA(PCCERT_CONTEXT pCertContext, DWORD dwType,
1128 DWORD dwFlags, void *pvTypePara, LPSTR pszNameString, DWORD cchNameString)
1129 {
1130 DWORD ret;
1131
1132 TRACE("(%p, %d, %08x, %p, %p, %d)\n", pCertContext, dwType, dwFlags,
1133 pvTypePara, pszNameString, cchNameString);
1134
1135 if (pszNameString)
1136 {
1137 LPWSTR wideName;
1138 DWORD nameLen;
1139
1140 nameLen = CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara,
1141 NULL, 0);
1142 wideName = CryptMemAlloc(nameLen * sizeof(WCHAR));
1143 if (wideName)
1144 {
1145 CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara,
1146 wideName, nameLen);
1147 nameLen = WideCharToMultiByte(CP_ACP, 0, wideName, nameLen,
1148 pszNameString, cchNameString, NULL, NULL);
1149 if (nameLen <= cchNameString)
1150 ret = nameLen;
1151 else
1152 {
1153 pszNameString[cchNameString - 1] = '\0';
1154 ret = cchNameString;
1155 }
1156 CryptMemFree(wideName);
1157 }
1158 else
1159 {
1160 *pszNameString = '\0';
1161 ret = 1;
1162 }
1163 }
1164 else
1165 ret = CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara,
1166 NULL, 0);
1167 return ret;
1168 }
1169
1170 /* Searches cert's extensions for the alternate name extension with OID
1171 * altNameOID, and if found, searches it for the alternate name type entryType.
1172 * If found, returns a pointer to the entry, otherwise returns NULL.
1173 * Regardless of whether an entry of the desired type is found, if the
1174 * alternate name extension is present, sets *info to the decoded alternate
1175 * name extension, which you must free using LocalFree.
1176 * The return value is a pointer within *info, so don't free *info before
1177 * you're done with the return value.
1178 */
1179 static PCERT_ALT_NAME_ENTRY cert_find_alt_name_entry(PCCERT_CONTEXT cert,
1180 LPCSTR altNameOID, DWORD entryType, PCERT_ALT_NAME_INFO *info)
1181 {
1182 PCERT_ALT_NAME_ENTRY entry = NULL;
1183 PCERT_EXTENSION ext = CertFindExtension(altNameOID,
1184 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
1185
1186 if (ext)
1187 {
1188 DWORD bytes = 0;
1189
1190 if (CryptDecodeObjectEx(cert->dwCertEncodingType, X509_ALTERNATE_NAME,
1191 ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL,
1192 info, &bytes))
1193 {
1194 DWORD i;
1195
1196 for (i = 0; !entry && i < (*info)->cAltEntry; i++)
1197 if ((*info)->rgAltEntry[i].dwAltNameChoice == entryType)
1198 entry = &(*info)->rgAltEntry[i];
1199 }
1200 }
1201 else
1202 *info = NULL;
1203 return entry;
1204 }
1205
1206 static DWORD cert_get_name_from_rdn_attr(DWORD encodingType,
1207 const CERT_NAME_BLOB *name, LPCSTR oid, LPWSTR pszNameString, DWORD cchNameString)
1208 {
1209 CERT_NAME_INFO *nameInfo;
1210 DWORD bytes = 0, ret = 0;
1211
1212 if (CryptDecodeObjectEx(encodingType, X509_NAME, name->pbData,
1213 name->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &nameInfo, &bytes))
1214 {
1215 PCERT_RDN_ATTR nameAttr;
1216
1217 if (!oid)
1218 oid = szOID_RSA_emailAddr;
1219 nameAttr = CertFindRDNAttr(oid, nameInfo);
1220 if (nameAttr)
1221 ret = CertRDNValueToStrW(nameAttr->dwValueType, &nameAttr->Value,
1222 pszNameString, cchNameString);
1223 LocalFree(nameInfo);
1224 }
1225 return ret;
1226 }
1227
1228 DWORD WINAPI CertGetNameStringW(PCCERT_CONTEXT pCertContext, DWORD dwType,
1229 DWORD dwFlags, void *pvTypePara, LPWSTR pszNameString, DWORD cchNameString)
1230 {
1231 DWORD ret = 0;
1232 PCERT_NAME_BLOB name;
1233 LPCSTR altNameOID;
1234
1235 TRACE("(%p, %d, %08x, %p, %p, %d)\n", pCertContext, dwType,
1236 dwFlags, pvTypePara, pszNameString, cchNameString);
1237
1238 if (!pCertContext)
1239 goto done;
1240
1241 if (dwFlags & CERT_NAME_ISSUER_FLAG)
1242 {
1243 name = &pCertContext->pCertInfo->Issuer;
1244 altNameOID = szOID_ISSUER_ALT_NAME;
1245 }
1246 else
1247 {
1248 name = &pCertContext->pCertInfo->Subject;
1249 altNameOID = szOID_SUBJECT_ALT_NAME;
1250 }
1251
1252 switch (dwType)
1253 {
1254 case CERT_NAME_EMAIL_TYPE:
1255 {
1256 CERT_ALT_NAME_INFO *info;
1257 PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext,
1258 altNameOID, CERT_ALT_NAME_RFC822_NAME, &info);
1259
1260 if (entry)
1261 {
1262 if (!pszNameString)
1263 ret = strlenW(entry->u.pwszRfc822Name) + 1;
1264 else if (cchNameString)
1265 {
1266 ret = min(strlenW(entry->u.pwszRfc822Name), cchNameString - 1);
1267 memcpy(pszNameString, entry->u.pwszRfc822Name,
1268 ret * sizeof(WCHAR));
1269 pszNameString[ret++] = 0;
1270 }
1271 }
1272 if (info)
1273 LocalFree(info);
1274 if (!ret)
1275 ret = cert_get_name_from_rdn_attr(pCertContext->dwCertEncodingType,
1276 name, szOID_RSA_emailAddr, pszNameString, cchNameString);
1277 break;
1278 }
1279 case CERT_NAME_RDN_TYPE:
1280 {
1281 DWORD type = pvTypePara ? *(DWORD *)pvTypePara : 0;
1282
1283 if (name->cbData)
1284 ret = CertNameToStrW(pCertContext->dwCertEncodingType, name,
1285 type, pszNameString, cchNameString);
1286 else
1287 {
1288 CERT_ALT_NAME_INFO *info;
1289 PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext,
1290 altNameOID, CERT_ALT_NAME_DIRECTORY_NAME, &info);
1291
1292 if (entry)
1293 ret = CertNameToStrW(pCertContext->dwCertEncodingType,
1294 &entry->u.DirectoryName, type, pszNameString, cchNameString);
1295 if (info)
1296 LocalFree(info);
1297 }
1298 break;
1299 }
1300 case CERT_NAME_ATTR_TYPE:
1301 ret = cert_get_name_from_rdn_attr(pCertContext->dwCertEncodingType,
1302 name, pvTypePara, pszNameString, cchNameString);
1303 if (!ret)
1304 {
1305 CERT_ALT_NAME_INFO *altInfo;
1306 PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext,
1307 altNameOID, CERT_ALT_NAME_DIRECTORY_NAME, &altInfo);
1308
1309 if (entry)
1310 ret = cert_name_to_str_with_indent(X509_ASN_ENCODING, 0,
1311 &entry->u.DirectoryName, 0, pszNameString, cchNameString);
1312 if (altInfo)
1313 LocalFree(altInfo);
1314 }
1315 break;
1316 case CERT_NAME_SIMPLE_DISPLAY_TYPE:
1317 {
1318 static const LPCSTR simpleAttributeOIDs[] = { szOID_COMMON_NAME,
1319 szOID_ORGANIZATIONAL_UNIT_NAME, szOID_ORGANIZATION_NAME,
1320 szOID_RSA_emailAddr };
1321 CERT_NAME_INFO *nameInfo = NULL;
1322 DWORD bytes = 0, i;
1323
1324 if (CryptDecodeObjectEx(pCertContext->dwCertEncodingType, X509_NAME,
1325 name->pbData, name->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &nameInfo,
1326 &bytes))
1327 {
1328 PCERT_RDN_ATTR nameAttr = NULL;
1329
1330 for (i = 0; !nameAttr && i < ARRAY_SIZE(simpleAttributeOIDs); i++)
1331 nameAttr = CertFindRDNAttr(simpleAttributeOIDs[i], nameInfo);
1332 if (nameAttr)
1333 ret = CertRDNValueToStrW(nameAttr->dwValueType,
1334 &nameAttr->Value, pszNameString, cchNameString);
1335 LocalFree(nameInfo);
1336 }
1337 if (!ret)
1338 {
1339 CERT_ALT_NAME_INFO *altInfo;
1340 PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext,
1341 altNameOID, CERT_ALT_NAME_RFC822_NAME, &altInfo);
1342
1343 if (altInfo)
1344 {
1345 if (!entry && altInfo->cAltEntry)
1346 entry = &altInfo->rgAltEntry[0];
1347 if (entry)
1348 {
1349 if (!pszNameString)
1350 ret = strlenW(entry->u.pwszRfc822Name) + 1;
1351 else if (cchNameString)
1352 {
1353 ret = min(strlenW(entry->u.pwszRfc822Name),
1354 cchNameString - 1);
1355 memcpy(pszNameString, entry->u.pwszRfc822Name,
1356 ret * sizeof(WCHAR));
1357 pszNameString[ret++] = 0;
1358 }
1359 }
1360 LocalFree(altInfo);
1361 }
1362 }
1363 break;
1364 }
1365 case CERT_NAME_FRIENDLY_DISPLAY_TYPE:
1366 {
1367 DWORD cch = cchNameString;
1368
1369 if (CertGetCertificateContextProperty(pCertContext,
1370 CERT_FRIENDLY_NAME_PROP_ID, pszNameString, &cch))
1371 ret = cch;
1372 else
1373 ret = CertGetNameStringW(pCertContext,
1374 CERT_NAME_SIMPLE_DISPLAY_TYPE, dwFlags, pvTypePara, pszNameString,
1375 cchNameString);
1376 break;
1377 }
1378 case CERT_NAME_DNS_TYPE:
1379 {
1380 CERT_ALT_NAME_INFO *info;
1381 PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext,
1382 altNameOID, CERT_ALT_NAME_DNS_NAME, &info);
1383
1384 if (entry)
1385 {
1386 if (!pszNameString)
1387 ret = strlenW(entry->u.pwszDNSName) + 1;
1388 else if (cchNameString)
1389 {
1390 ret = min(strlenW(entry->u.pwszDNSName), cchNameString - 1);
1391 memcpy(pszNameString, entry->u.pwszDNSName, ret * sizeof(WCHAR));
1392 pszNameString[ret++] = 0;
1393 }
1394 }
1395 if (info)
1396 LocalFree(info);
1397 if (!ret)
1398 ret = cert_get_name_from_rdn_attr(pCertContext->dwCertEncodingType,
1399 name, szOID_COMMON_NAME, pszNameString, cchNameString);
1400 break;
1401 }
1402 case CERT_NAME_URL_TYPE:
1403 {
1404 CERT_ALT_NAME_INFO *info;
1405 PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext,
1406 altNameOID, CERT_ALT_NAME_URL, &info);
1407
1408 if (entry)
1409 {
1410 if (!pszNameString)
1411 ret = strlenW(entry->u.pwszURL) + 1;
1412 else if (cchNameString)
1413 {
1414 ret = min(strlenW(entry->u.pwszURL), cchNameString - 1);
1415 memcpy(pszNameString, entry->u.pwszURL, ret * sizeof(WCHAR));
1416 pszNameString[ret++] = 0;
1417 }
1418 }
1419 if (info)
1420 LocalFree(info);
1421 break;
1422 }
1423 default:
1424 FIXME("unimplemented for type %d\n", dwType);
1425 ret = 0;
1426 }
1427 done:
1428 if (!ret)
1429 {
1430 if (!pszNameString)
1431 ret = 1;
1432 else if (cchNameString)
1433 {
1434 pszNameString[0] = 0;
1435 ret = 1;
1436 }
1437 }
1438 return ret;
1439 }