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