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 } 1440