1 /* 2 * Copyright 2008 Juan Lang 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 19 #include "config.h" 20 21 #include <stdarg.h> 22 23 #define COBJMACROS 24 #define NONAMELESSUNION 25 26 #include "windef.h" 27 #include "winbase.h" 28 #include "winnls.h" 29 #include "winuser.h" 30 #include "softpub.h" 31 #include "wingdi.h" 32 #include "richedit.h" 33 #include "ole2.h" 34 #include "richole.h" 35 #include "commdlg.h" 36 #include "commctrl.h" 37 #include "cryptuiapi.h" 38 #include "cryptuires.h" 39 #include "urlmon.h" 40 #include "hlink.h" 41 #include "winreg.h" 42 #include "wine/debug.h" 43 #include "wine/unicode.h" 44 45 WINE_DEFAULT_DEBUG_CHANNEL(cryptui); 46 47 static HINSTANCE hInstance; 48 49 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) 50 { 51 TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved); 52 53 switch (fdwReason) 54 { 55 case DLL_WINE_PREATTACH: 56 return FALSE; /* prefer native version */ 57 case DLL_PROCESS_ATTACH: 58 hInstance = hinstDLL; 59 DisableThreadLibraryCalls(hinstDLL); 60 break; 61 } 62 return TRUE; 63 } 64 65 #define MAX_STRING_LEN 512 66 67 static void add_cert_columns(HWND hwnd) 68 { 69 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS); 70 RECT rc; 71 WCHAR buf[MAX_STRING_LEN]; 72 LVCOLUMNW column; 73 74 SendMessageW(lv, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT); 75 GetWindowRect(lv, &rc); 76 LoadStringW(hInstance, IDS_SUBJECT_COLUMN, buf, 77 sizeof(buf) / sizeof(buf[0])); 78 column.mask = LVCF_WIDTH | LVCF_TEXT; 79 column.cx = (rc.right - rc.left) * 29 / 100 - 2; 80 column.pszText = buf; 81 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column); 82 LoadStringW(hInstance, IDS_ISSUER_COLUMN, buf, 83 sizeof(buf) / sizeof(buf[0])); 84 SendMessageW(lv, LVM_INSERTCOLUMNW, 1, (LPARAM)&column); 85 column.cx = (rc.right - rc.left) * 16 / 100 - 2; 86 LoadStringW(hInstance, IDS_EXPIRATION_COLUMN, buf, 87 sizeof(buf) / sizeof(buf[0])); 88 SendMessageW(lv, LVM_INSERTCOLUMNW, 2, (LPARAM)&column); 89 column.cx = (rc.right - rc.left) * 23 / 100 - 1; 90 LoadStringW(hInstance, IDS_FRIENDLY_NAME_COLUMN, buf, 91 sizeof(buf) / sizeof(buf[0])); 92 SendMessageW(lv, LVM_INSERTCOLUMNW, 3, (LPARAM)&column); 93 } 94 95 static void add_cert_to_view(HWND lv, PCCERT_CONTEXT cert, DWORD *allocatedLen, 96 LPWSTR *str) 97 { 98 DWORD len; 99 LVITEMW item; 100 WCHAR dateFmt[80]; /* sufficient for LOCALE_SSHORTDATE */ 101 WCHAR date[80]; 102 SYSTEMTIME sysTime; 103 LPWSTR none; 104 105 item.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_TEXT; 106 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0); 107 item.iSubItem = 0; 108 item.iImage = 0; 109 item.lParam = (LPARAM)CertDuplicateCertificateContext(cert); 110 len = CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, 111 NULL, 0); 112 if (len > *allocatedLen) 113 { 114 HeapFree(GetProcessHeap(), 0, *str); 115 *str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 116 if (*str) 117 *allocatedLen = len; 118 } 119 if (*str) 120 { 121 CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, 122 *str, len); 123 item.pszText = *str; 124 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item); 125 } 126 127 item.mask = LVIF_TEXT; 128 len = CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 129 CERT_NAME_ISSUER_FLAG, NULL, NULL, 0); 130 if (len > *allocatedLen) 131 { 132 HeapFree(GetProcessHeap(), 0, *str); 133 *str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 134 if (*str) 135 *allocatedLen = len; 136 } 137 if (*str) 138 { 139 CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 140 CERT_NAME_ISSUER_FLAG, NULL, *str, len); 141 item.pszText = *str; 142 item.iSubItem = 1; 143 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item); 144 } 145 146 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SSHORTDATE, dateFmt, 147 sizeof(dateFmt) / sizeof(dateFmt[0])); 148 FileTimeToSystemTime(&cert->pCertInfo->NotAfter, &sysTime); 149 GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, date, 150 sizeof(date) / sizeof(date[0])); 151 item.pszText = date; 152 item.iSubItem = 2; 153 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item); 154 155 if (!CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID, 156 NULL, &len)) 157 len = LoadStringW(hInstance, IDS_FRIENDLY_NAME_NONE, (LPWSTR)&none, 0); 158 if (len > *allocatedLen) 159 { 160 HeapFree(GetProcessHeap(), 0, *str); 161 *str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 162 if (*str) 163 *allocatedLen = len; 164 } 165 if (*str) 166 { 167 if (!CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID, 168 *str, &len)) 169 item.pszText = none; 170 else 171 item.pszText = *str; 172 item.iSubItem = 3; 173 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item); 174 } 175 } 176 177 static LPSTR get_cert_mgr_usages(void) 178 { 179 static const WCHAR keyName[] = { 'S','o','f','t','w','a','r','e','\\','M', 180 'i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g','r','a', 181 'p','h','y','\\','U','I','\\','C','e','r','t','m','g','r','\\','P','u', 182 'r','p','o','s','e',0 }; 183 LPSTR str = NULL; 184 HKEY key; 185 186 if (!RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, NULL, 0, KEY_READ, 187 NULL, &key, NULL)) 188 { 189 LONG rc; 190 DWORD type, size; 191 192 rc = RegQueryValueExA(key, "Purpose", NULL, &type, NULL, &size); 193 if ((!rc || rc == ERROR_MORE_DATA) && type == REG_SZ) 194 { 195 str = HeapAlloc(GetProcessHeap(), 0, size); 196 if (str) 197 { 198 rc = RegQueryValueExA(key, "Purpose", NULL, NULL, (LPBYTE)str, 199 &size); 200 if (rc) 201 { 202 HeapFree(GetProcessHeap(), 0, str); 203 str = NULL; 204 } 205 } 206 } 207 RegCloseKey(key); 208 } 209 return str; 210 } 211 212 typedef enum { 213 PurposeFilterShowAll = 0, 214 PurposeFilterShowAdvanced = 1, 215 PurposeFilterShowOID = 2 216 } PurposeFilter; 217 218 static void initialize_purpose_selection(HWND hwnd) 219 { 220 HWND cb = GetDlgItem(hwnd, IDC_MGR_PURPOSE_SELECTION); 221 WCHAR buf[MAX_STRING_LEN]; 222 LPSTR usages; 223 int index; 224 225 LoadStringW(hInstance, IDS_PURPOSE_ALL, buf, 226 sizeof(buf) / sizeof(buf[0])); 227 index = SendMessageW(cb, CB_INSERTSTRING, -1, (LPARAM)buf); 228 SendMessageW(cb, CB_SETITEMDATA, index, (LPARAM)PurposeFilterShowAll); 229 LoadStringW(hInstance, IDS_PURPOSE_ADVANCED, buf, 230 sizeof(buf) / sizeof(buf[0])); 231 index = SendMessageW(cb, CB_INSERTSTRING, -1, (LPARAM)buf); 232 SendMessageW(cb, CB_SETITEMDATA, index, (LPARAM)PurposeFilterShowAdvanced); 233 SendMessageW(cb, CB_SETCURSEL, 0, 0); 234 if ((usages = get_cert_mgr_usages())) 235 { 236 LPSTR ptr, comma; 237 238 for (ptr = usages, comma = strchr(ptr, ','); ptr && *ptr; 239 ptr = comma ? comma + 1 : NULL, 240 comma = ptr ? strchr(ptr, ',') : NULL) 241 { 242 PCCRYPT_OID_INFO info; 243 244 if (comma) 245 *comma = 0; 246 if ((info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, ptr, 0))) 247 { 248 index = SendMessageW(cb, CB_INSERTSTRING, 0, 249 (LPARAM)info->pwszName); 250 SendMessageW(cb, CB_SETITEMDATA, index, (LPARAM)info); 251 } 252 } 253 HeapFree(GetProcessHeap(), 0, usages); 254 } 255 } 256 257 extern BOOL WINAPI WTHelperGetKnownUsages(DWORD action, 258 PCCRYPT_OID_INFO **usages); 259 260 static CERT_ENHKEY_USAGE *add_oid_to_usage(CERT_ENHKEY_USAGE *usage, LPSTR oid) 261 { 262 if (!usage->cUsageIdentifier) 263 usage->rgpszUsageIdentifier = HeapAlloc(GetProcessHeap(), 0, 264 sizeof(LPSTR)); 265 else 266 usage->rgpszUsageIdentifier = HeapReAlloc(GetProcessHeap(), 0, 267 usage->rgpszUsageIdentifier, 268 (usage->cUsageIdentifier + 1) * sizeof(LPSTR)); 269 if (usage->rgpszUsageIdentifier) 270 usage->rgpszUsageIdentifier[usage->cUsageIdentifier++] = oid; 271 else 272 { 273 HeapFree(GetProcessHeap(), 0, usage); 274 usage = NULL; 275 } 276 return usage; 277 } 278 279 static CERT_ENHKEY_USAGE *convert_usages_str_to_usage(LPSTR usageStr) 280 { 281 CERT_ENHKEY_USAGE *usage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 282 sizeof(CERT_ENHKEY_USAGE)); 283 284 if (usage) 285 { 286 LPSTR ptr, comma; 287 288 for (ptr = usageStr, comma = strchr(ptr, ','); usage && ptr && *ptr; 289 ptr = comma ? comma + 1 : NULL, 290 comma = ptr ? strchr(ptr, ',') : NULL) 291 { 292 if (comma) 293 *comma = 0; 294 usage = add_oid_to_usage(usage, ptr); 295 } 296 } 297 return usage; 298 } 299 300 static CERT_ENHKEY_USAGE *create_advanced_filter(void) 301 { 302 CERT_ENHKEY_USAGE *advancedUsage = HeapAlloc(GetProcessHeap(), 303 HEAP_ZERO_MEMORY, sizeof(CERT_ENHKEY_USAGE)); 304 305 if (advancedUsage) 306 { 307 PCCRYPT_OID_INFO *usages; 308 309 if (WTHelperGetKnownUsages(1, &usages)) 310 { 311 LPSTR disabledUsagesStr; 312 313 if ((disabledUsagesStr = get_cert_mgr_usages())) 314 { 315 CERT_ENHKEY_USAGE *disabledUsages = 316 convert_usages_str_to_usage(disabledUsagesStr); 317 318 if (disabledUsages) 319 { 320 PCCRYPT_OID_INFO *ptr; 321 322 for (ptr = usages; advancedUsage && *ptr; ptr++) 323 { 324 DWORD i; 325 BOOL disabled = FALSE; 326 327 for (i = 0; !disabled && 328 i < disabledUsages->cUsageIdentifier; i++) 329 if (!strcmp(disabledUsages->rgpszUsageIdentifier[i], 330 (*ptr)->pszOID)) 331 disabled = TRUE; 332 if (!disabled) 333 advancedUsage = add_oid_to_usage(advancedUsage, 334 (LPSTR)(*ptr)->pszOID); 335 } 336 /* The individual strings are pointers to disabledUsagesStr, 337 * so they're freed when it is. 338 */ 339 HeapFree(GetProcessHeap(), 0, 340 disabledUsages->rgpszUsageIdentifier); 341 HeapFree(GetProcessHeap(), 0, disabledUsages); 342 } 343 HeapFree(GetProcessHeap(), 0, disabledUsagesStr); 344 } 345 WTHelperGetKnownUsages(2, &usages); 346 } 347 } 348 return advancedUsage; 349 } 350 351 static int CALLBACK cert_mgr_sort_by_subject(LPARAM lp1, LPARAM lp2, LPARAM lp); 352 353 static void show_store_certs(HWND hwnd, HCERTSTORE store) 354 { 355 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS); 356 HWND cb = GetDlgItem(hwnd, IDC_MGR_PURPOSE_SELECTION); 357 PCCERT_CONTEXT cert = NULL; 358 DWORD allocatedLen = 0; 359 LPWSTR str = NULL; 360 int index; 361 PurposeFilter filter = PurposeFilterShowAll; 362 LPCSTR oid = NULL; 363 CERT_ENHKEY_USAGE *advanced = NULL; 364 365 index = SendMessageW(cb, CB_GETCURSEL, 0, 0); 366 if (index >= 0) 367 { 368 INT_PTR data = SendMessageW(cb, CB_GETITEMDATA, index, 0); 369 370 if (!HIWORD(data)) 371 filter = data; 372 else 373 { 374 PCCRYPT_OID_INFO info = (PCCRYPT_OID_INFO)data; 375 376 filter = PurposeFilterShowOID; 377 oid = info->pszOID; 378 } 379 } 380 if (filter == PurposeFilterShowAdvanced) 381 advanced = create_advanced_filter(); 382 do { 383 cert = CertEnumCertificatesInStore(store, cert); 384 if (cert) 385 { 386 BOOL show = FALSE; 387 388 if (filter == PurposeFilterShowAll) 389 show = TRUE; 390 else 391 { 392 int numOIDs; 393 DWORD cbOIDs = 0; 394 395 if (CertGetValidUsages(1, &cert, &numOIDs, NULL, &cbOIDs)) 396 { 397 if (numOIDs == -1) 398 { 399 /* -1 implies all usages are valid */ 400 show = TRUE; 401 } 402 else 403 { 404 LPSTR *oids = HeapAlloc(GetProcessHeap(), 0, cbOIDs); 405 406 if (oids) 407 { 408 if (CertGetValidUsages(1, &cert, &numOIDs, oids, 409 &cbOIDs)) 410 { 411 int i; 412 413 if (filter == PurposeFilterShowOID) 414 { 415 for (i = 0; !show && i < numOIDs; i++) 416 if (!strcmp(oids[i], oid)) 417 show = TRUE; 418 } 419 else 420 { 421 for (i = 0; !show && i < numOIDs; i++) 422 { 423 DWORD j; 424 425 for (j = 0; !show && 426 j < advanced->cUsageIdentifier; j++) 427 if (!strcmp(oids[i], 428 advanced->rgpszUsageIdentifier[j])) 429 show = TRUE; 430 } 431 } 432 } 433 HeapFree(GetProcessHeap(), 0, oids); 434 } 435 } 436 } 437 } 438 if (show) 439 add_cert_to_view(lv, cert, &allocatedLen, &str); 440 } 441 } while (cert); 442 HeapFree(GetProcessHeap(), 0, str); 443 if (advanced) 444 { 445 HeapFree(GetProcessHeap(), 0, advanced->rgpszUsageIdentifier); 446 HeapFree(GetProcessHeap(), 0, advanced); 447 } 448 SendMessageW(lv, LVM_SORTITEMSEX, (WPARAM)lv, 449 (LPARAM)cert_mgr_sort_by_subject); 450 } 451 452 static const WCHAR my[] = { 'M','y',0 }; 453 static const WCHAR addressBook[] = { 454 'A','d','d','r','e','s','s','B','o','o','k',0 }; 455 static const WCHAR ca[] = { 'C','A',0 }; 456 static const WCHAR root[] = { 'R','o','o','t',0 }; 457 static const WCHAR trustedPublisher[] = { 458 'T','r','u','s','t','e','d','P','u','b','l','i','s','h','e','r',0 }; 459 static const WCHAR disallowed[] = { 'D','i','s','a','l','l','o','w','e','d',0 }; 460 461 struct CertMgrStoreInfo 462 { 463 LPCWSTR name; 464 int removeWarning; 465 int removePluralWarning; 466 }; 467 468 static const struct CertMgrStoreInfo defaultStoreList[] = { 469 { my, IDS_WARN_REMOVE_MY, IDS_WARN_REMOVE_PLURAL_MY }, 470 { addressBook, IDS_WARN_REMOVE_ADDRESSBOOK, 471 IDS_WARN_REMOVE_PLURAL_ADDRESSBOOK }, 472 { ca, IDS_WARN_REMOVE_CA, IDS_WARN_REMOVE_PLURAL_CA }, 473 { root, IDS_WARN_REMOVE_ROOT, IDS_WARN_REMOVE_PLURAL_ROOT }, 474 { trustedPublisher, IDS_WARN_REMOVE_TRUSTEDPUBLISHER, 475 IDS_WARN_REMOVE_PLURAL_TRUSTEDPUBLISHER }, 476 { disallowed, IDS_WARN_REMOVE_DEFAULT }, 477 }; 478 479 static const struct CertMgrStoreInfo publisherStoreList[] = { 480 { root, IDS_WARN_REMOVE_ROOT, IDS_WARN_REMOVE_PLURAL_ROOT }, 481 { trustedPublisher, IDS_WARN_REMOVE_TRUSTEDPUBLISHER, 482 IDS_WARN_REMOVE_PLURAL_TRUSTEDPUBLISHER }, 483 { disallowed, IDS_WARN_REMOVE_PLURAL_DEFAULT }, 484 }; 485 486 struct CertMgrData 487 { 488 HIMAGELIST imageList; 489 LPCWSTR title; 490 DWORD nStores; 491 const struct CertMgrStoreInfo *stores; 492 }; 493 494 static void show_cert_stores(HWND hwnd, DWORD dwFlags, struct CertMgrData *data) 495 { 496 const struct CertMgrStoreInfo *storeList; 497 int cStores, i; 498 HWND tab = GetDlgItem(hwnd, IDC_MGR_STORES); 499 500 if (dwFlags & CRYPTUI_CERT_MGR_PUBLISHER_TAB) 501 { 502 storeList = publisherStoreList; 503 cStores = sizeof(publisherStoreList) / sizeof(publisherStoreList[0]); 504 } 505 else 506 { 507 storeList = defaultStoreList; 508 cStores = sizeof(defaultStoreList) / sizeof(defaultStoreList[0]); 509 } 510 if (dwFlags & CRYPTUI_CERT_MGR_SINGLE_TAB_FLAG) 511 cStores = 1; 512 data->nStores = cStores; 513 data->stores = storeList; 514 for (i = 0; i < cStores; i++) 515 { 516 LPCWSTR name; 517 TCITEMW item; 518 HCERTSTORE store; 519 520 if (!(name = CryptFindLocalizedName(storeList[i].name))) 521 name = storeList[i].name; 522 store = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0, 523 CERT_SYSTEM_STORE_CURRENT_USER, storeList[i].name); 524 item.mask = TCIF_TEXT | TCIF_PARAM; 525 item.pszText = (LPWSTR)name; 526 item.lParam = (LPARAM)store; 527 SendMessageW(tab, TCM_INSERTITEMW, i, (LPARAM)&item); 528 } 529 } 530 531 static void free_certs(HWND lv) 532 { 533 LVITEMW item; 534 int items = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0), i; 535 536 for (i = 0; i < items; i++) 537 { 538 item.mask = LVIF_PARAM; 539 item.iItem = i; 540 item.iSubItem = 0; 541 SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item); 542 CertFreeCertificateContext((PCCERT_CONTEXT)item.lParam); 543 } 544 } 545 546 static HCERTSTORE cert_mgr_index_to_store(HWND tab, int index) 547 { 548 TCITEMW item; 549 550 item.mask = TCIF_PARAM; 551 SendMessageW(tab, TCM_GETITEMW, index, (LPARAM)&item); 552 return (HCERTSTORE)item.lParam; 553 } 554 555 static HCERTSTORE cert_mgr_current_store(HWND hwnd) 556 { 557 HWND tab = GetDlgItem(hwnd, IDC_MGR_STORES); 558 559 return cert_mgr_index_to_store(tab, SendMessageW(tab, TCM_GETCURSEL, 0, 0)); 560 } 561 562 static void close_stores(HWND tab) 563 { 564 int i, tabs = SendMessageW(tab, TCM_GETITEMCOUNT, 0, 0); 565 566 for (i = 0; i < tabs; i++) 567 CertCloseStore(cert_mgr_index_to_store(tab, i), 0); 568 } 569 570 static void refresh_store_certs(HWND hwnd) 571 { 572 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS); 573 574 free_certs(lv); 575 SendMessageW(lv, LVM_DELETEALLITEMS, 0, 0); 576 show_store_certs(hwnd, cert_mgr_current_store(hwnd)); 577 } 578 579 typedef enum { 580 CheckBitmapIndexUnchecked = 1, 581 CheckBitmapIndexChecked = 2, 582 CheckBitmapIndexDisabledUnchecked = 3, 583 CheckBitmapIndexDisabledChecked = 4 584 } CheckBitmapIndex; 585 586 static void add_known_usage(HWND lv, PCCRYPT_OID_INFO info, 587 CheckBitmapIndex state) 588 { 589 LVITEMW item; 590 591 item.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM; 592 item.state = INDEXTOSTATEIMAGEMASK(state); 593 item.stateMask = LVIS_STATEIMAGEMASK; 594 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0); 595 item.iSubItem = 0; 596 item.lParam = (LPARAM)info; 597 item.pszText = (LPWSTR)info->pwszName; 598 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item); 599 } 600 601 static void add_known_usages_to_list(HWND lv, CheckBitmapIndex state) 602 { 603 PCCRYPT_OID_INFO *usages; 604 605 if (WTHelperGetKnownUsages(1, &usages)) 606 { 607 PCCRYPT_OID_INFO *ptr; 608 609 for (ptr = usages; *ptr; ptr++) 610 add_known_usage(lv, *ptr, state); 611 WTHelperGetKnownUsages(2, &usages); 612 } 613 } 614 615 static void toggle_usage(HWND hwnd, int iItem) 616 { 617 LVITEMW item; 618 int res; 619 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES); 620 621 item.mask = LVIF_STATE; 622 item.iItem = iItem; 623 item.iSubItem = 0; 624 item.stateMask = LVIS_STATEIMAGEMASK; 625 res = SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item); 626 if (res) 627 { 628 int state = item.state >> 12; 629 630 item.state = INDEXTOSTATEIMAGEMASK( 631 state == CheckBitmapIndexChecked ? CheckBitmapIndexUnchecked : 632 CheckBitmapIndexChecked); 633 SendMessageW(lv, LVM_SETITEMSTATE, iItem, (LPARAM)&item); 634 } 635 } 636 637 static LONG_PTR find_oid_in_list(HWND lv, LPCSTR oid) 638 { 639 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, 640 (void *)oid, CRYPT_ENHKEY_USAGE_OID_GROUP_ID); 641 LONG_PTR ret; 642 643 if (oidInfo) 644 { 645 LVFINDINFOW findInfo; 646 647 findInfo.flags = LVFI_PARAM; 648 findInfo.lParam = (LPARAM)oidInfo; 649 ret = SendMessageW(lv, LVM_FINDITEMW, -1, (LPARAM)&findInfo); 650 } 651 else 652 { 653 LVFINDINFOA findInfo; 654 655 findInfo.flags = LVFI_STRING; 656 findInfo.psz = oid; 657 ret = SendMessageW(lv, LVM_FINDITEMA, -1, (LPARAM)&findInfo); 658 } 659 return ret; 660 } 661 662 static void save_cert_mgr_usages(HWND hwnd) 663 { 664 static const WCHAR keyName[] = { 'S','o','f','t','w','a','r','e','\\','M', 665 'i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g','r','a', 666 'p','h','y','\\','U','I','\\','C','e','r','t','m','g','r','\\','P','u', 667 'r','p','o','s','e',0 }; 668 HKEY key; 669 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES); 670 int purposes = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0), i; 671 LVITEMW item; 672 LPSTR str = NULL; 673 674 item.mask = LVIF_STATE | LVIF_PARAM; 675 item.iSubItem = 0; 676 item.stateMask = LVIS_STATEIMAGEMASK; 677 for (i = 0; i < purposes; i++) 678 { 679 item.iItem = i; 680 if (SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item)) 681 { 682 int state = item.state >> 12; 683 684 if (state == CheckBitmapIndexUnchecked) 685 { 686 CRYPT_OID_INFO *info = (CRYPT_OID_INFO *)item.lParam; 687 BOOL firstString = TRUE; 688 689 if (!str) 690 str = HeapAlloc(GetProcessHeap(), 0, 691 strlen(info->pszOID) + 1); 692 else 693 { 694 str = HeapReAlloc(GetProcessHeap(), 0, str, 695 strlen(str) + 1 + strlen(info->pszOID) + 1); 696 firstString = FALSE; 697 } 698 if (str) 699 { 700 LPSTR ptr = firstString ? str : str + strlen(str); 701 702 if (!firstString) 703 *ptr++ = ','; 704 strcpy(ptr, info->pszOID); 705 } 706 } 707 } 708 } 709 if (!RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, NULL, 0, KEY_ALL_ACCESS, 710 NULL, &key, NULL)) 711 { 712 if (str) 713 RegSetValueExA(key, "Purpose", 0, REG_SZ, (const BYTE *)str, 714 strlen(str) + 1); 715 else 716 RegDeleteValueA(key, "Purpose"); 717 RegCloseKey(key); 718 } 719 HeapFree(GetProcessHeap(), 0, str); 720 } 721 722 static LRESULT CALLBACK cert_mgr_advanced_dlg_proc(HWND hwnd, UINT msg, 723 WPARAM wp, LPARAM lp) 724 { 725 switch (msg) 726 { 727 case WM_INITDIALOG: 728 { 729 RECT rc; 730 LVCOLUMNW column; 731 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES); 732 HIMAGELIST imageList; 733 LPSTR disabledUsages; 734 735 GetWindowRect(lv, &rc); 736 column.mask = LVCF_WIDTH; 737 column.cx = rc.right - rc.left; 738 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column); 739 imageList = ImageList_Create(16, 16, ILC_COLOR4 | ILC_MASK, 4, 0); 740 if (imageList) 741 { 742 HBITMAP bmp; 743 COLORREF backColor = RGB(255, 0, 255); 744 745 bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_CHECKS)); 746 ImageList_AddMasked(imageList, bmp, backColor); 747 DeleteObject(bmp); 748 ImageList_SetBkColor(imageList, CLR_NONE); 749 SendMessageW(lv, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)imageList); 750 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)imageList); 751 } 752 add_known_usages_to_list(lv, CheckBitmapIndexChecked); 753 if ((disabledUsages = get_cert_mgr_usages())) 754 { 755 LPSTR ptr, comma; 756 757 for (ptr = disabledUsages, comma = strchr(ptr, ','); ptr && *ptr; 758 ptr = comma ? comma + 1 : NULL, 759 comma = ptr ? strchr(ptr, ',') : NULL) 760 { 761 LONG_PTR index; 762 763 if (comma) 764 *comma = 0; 765 if ((index = find_oid_in_list(lv, ptr)) != -1) 766 toggle_usage(hwnd, index); 767 } 768 HeapFree(GetProcessHeap(), 0, disabledUsages); 769 } 770 break; 771 } 772 case WM_NOTIFY: 773 { 774 NMHDR *hdr = (NMHDR *)lp; 775 NMITEMACTIVATE *nm; 776 777 switch (hdr->code) 778 { 779 case NM_CLICK: 780 nm = (NMITEMACTIVATE *)lp; 781 toggle_usage(hwnd, nm->iItem); 782 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0); 783 break; 784 } 785 break; 786 } 787 case WM_COMMAND: 788 switch (wp) 789 { 790 case IDOK: 791 save_cert_mgr_usages(hwnd); 792 ImageList_Destroy((HIMAGELIST)GetWindowLongPtrW(hwnd, DWLP_USER)); 793 EndDialog(hwnd, IDOK); 794 break; 795 case IDCANCEL: 796 ImageList_Destroy((HIMAGELIST)GetWindowLongPtrW(hwnd, DWLP_USER)); 797 EndDialog(hwnd, IDCANCEL); 798 break; 799 } 800 break; 801 } 802 return 0; 803 } 804 805 static void cert_mgr_clear_cert_selection(HWND hwnd) 806 { 807 WCHAR empty[] = { 0 }; 808 809 EnableWindow(GetDlgItem(hwnd, IDC_MGR_EXPORT), FALSE); 810 EnableWindow(GetDlgItem(hwnd, IDC_MGR_REMOVE), FALSE); 811 EnableWindow(GetDlgItem(hwnd, IDC_MGR_VIEW), FALSE); 812 SendMessageW(GetDlgItem(hwnd, IDC_MGR_PURPOSES), WM_SETTEXT, 0, 813 (LPARAM)empty); 814 refresh_store_certs(hwnd); 815 } 816 817 static PCCERT_CONTEXT cert_mgr_index_to_cert(HWND hwnd, int index) 818 { 819 PCCERT_CONTEXT cert = NULL; 820 LVITEMW item; 821 822 item.mask = LVIF_PARAM; 823 item.iItem = index; 824 item.iSubItem = 0; 825 if (SendMessageW(GetDlgItem(hwnd, IDC_MGR_CERTS), LVM_GETITEMW, 0, 826 (LPARAM)&item)) 827 cert = (PCCERT_CONTEXT)item.lParam; 828 return cert; 829 } 830 831 static void show_selected_cert(HWND hwnd, int index) 832 { 833 PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd, index); 834 835 if (cert) 836 { 837 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo; 838 839 memset(&viewInfo, 0, sizeof(viewInfo)); 840 viewInfo.dwSize = sizeof(viewInfo); 841 viewInfo.hwndParent = hwnd; 842 viewInfo.pCertContext = cert; 843 /* FIXME: this should be modal */ 844 CryptUIDlgViewCertificateW(&viewInfo, NULL); 845 } 846 } 847 848 static void cert_mgr_show_cert_usages(HWND hwnd, int index) 849 { 850 HWND text = GetDlgItem(hwnd, IDC_MGR_PURPOSES); 851 PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd, index); 852 PCERT_ENHKEY_USAGE usage; 853 DWORD size; 854 855 /* Get enhanced key usage. Have to check for a property and an extension 856 * separately, because CertGetEnhancedKeyUsage will succeed and return an 857 * empty usage if neither is set. Unfortunately an empty usage implies 858 * no usage is allowed, so we have to distinguish between the two cases. 859 */ 860 if (CertGetEnhancedKeyUsage(cert, CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, 861 NULL, &size)) 862 { 863 usage = HeapAlloc(GetProcessHeap(), 0, size); 864 if (!CertGetEnhancedKeyUsage(cert, 865 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size)) 866 { 867 HeapFree(GetProcessHeap(), 0, usage); 868 usage = NULL; 869 } 870 } 871 else if (CertGetEnhancedKeyUsage(cert, CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, 872 NULL, &size)) 873 { 874 usage = HeapAlloc(GetProcessHeap(), 0, size); 875 if (!CertGetEnhancedKeyUsage(cert, 876 CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, usage, &size)) 877 { 878 HeapFree(GetProcessHeap(), 0, usage); 879 usage = NULL; 880 } 881 } 882 else 883 usage = NULL; 884 if (usage) 885 { 886 if (usage->cUsageIdentifier) 887 { 888 static const WCHAR commaSpace[] = { ',',' ',0 }; 889 DWORD i, len = 1; 890 LPWSTR str, ptr; 891 892 for (i = 0; i < usage->cUsageIdentifier; i++) 893 { 894 PCCRYPT_OID_INFO info = 895 CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, 896 usage->rgpszUsageIdentifier[i], 897 CRYPT_ENHKEY_USAGE_OID_GROUP_ID); 898 899 if (info) 900 len += strlenW(info->pwszName); 901 else 902 len += strlen(usage->rgpszUsageIdentifier[i]); 903 if (i < usage->cUsageIdentifier - 1) 904 len += strlenW(commaSpace); 905 } 906 str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 907 if (str) 908 { 909 for (i = 0, ptr = str; i < usage->cUsageIdentifier; i++) 910 { 911 PCCRYPT_OID_INFO info = 912 CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, 913 usage->rgpszUsageIdentifier[i], 914 CRYPT_ENHKEY_USAGE_OID_GROUP_ID); 915 916 if (info) 917 { 918 strcpyW(ptr, info->pwszName); 919 ptr += strlenW(info->pwszName); 920 } 921 else 922 { 923 LPCSTR src = usage->rgpszUsageIdentifier[i]; 924 925 for (; *src; ptr++, src++) 926 *ptr = *src; 927 *ptr = 0; 928 } 929 if (i < usage->cUsageIdentifier - 1) 930 { 931 strcpyW(ptr, commaSpace); 932 ptr += strlenW(commaSpace); 933 } 934 } 935 *ptr = 0; 936 SendMessageW(text, WM_SETTEXT, 0, (LPARAM)str); 937 HeapFree(GetProcessHeap(), 0, str); 938 } 939 HeapFree(GetProcessHeap(), 0, usage); 940 } 941 else 942 { 943 WCHAR buf[MAX_STRING_LEN]; 944 945 LoadStringW(hInstance, IDS_ALLOWED_PURPOSE_NONE, buf, 946 sizeof(buf) / sizeof(buf[0])); 947 SendMessageW(text, WM_SETTEXT, 0, (LPARAM)buf); 948 } 949 } 950 else 951 { 952 WCHAR buf[MAX_STRING_LEN]; 953 954 LoadStringW(hInstance, IDS_ALLOWED_PURPOSE_ALL, buf, 955 sizeof(buf) / sizeof(buf[0])); 956 SendMessageW(text, WM_SETTEXT, 0, (LPARAM)buf); 957 } 958 } 959 960 static void cert_mgr_do_remove(HWND hwnd) 961 { 962 int tabIndex = SendMessageW(GetDlgItem(hwnd, IDC_MGR_STORES), 963 TCM_GETCURSEL, 0, 0); 964 struct CertMgrData *data = 965 (struct CertMgrData *)GetWindowLongPtrW(hwnd, DWLP_USER); 966 967 if (tabIndex < data->nStores) 968 { 969 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS); 970 WCHAR warning[MAX_STRING_LEN], title[MAX_STRING_LEN]; 971 LPCWSTR pTitle; 972 int warningID; 973 974 if (SendMessageW(lv, LVM_GETSELECTEDCOUNT, 0, 0) > 1) 975 warningID = data->stores[tabIndex].removePluralWarning; 976 else 977 warningID = data->stores[tabIndex].removeWarning; 978 if (data->title) 979 pTitle = data->title; 980 else 981 { 982 LoadStringW(hInstance, IDS_CERT_MGR, title, 983 sizeof(title) / sizeof(title[0])); 984 pTitle = title; 985 } 986 LoadStringW(hInstance, warningID, warning, 987 sizeof(warning) / sizeof(warning[0])); 988 if (MessageBoxW(hwnd, warning, pTitle, MB_YESNO) == IDYES) 989 { 990 int selection = -1; 991 992 do { 993 selection = SendMessageW(lv, LVM_GETNEXTITEM, selection, 994 LVNI_SELECTED); 995 if (selection >= 0) 996 { 997 PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd, 998 selection); 999 1000 CertDeleteCertificateFromStore(cert); 1001 } 1002 } while (selection >= 0); 1003 cert_mgr_clear_cert_selection(hwnd); 1004 } 1005 } 1006 } 1007 1008 static void cert_mgr_do_export(HWND hwnd) 1009 { 1010 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS); 1011 int selectionCount = SendMessageW(lv, LVM_GETSELECTEDCOUNT, 0, 0); 1012 1013 if (selectionCount == 1) 1014 { 1015 int selection = SendMessageW(lv, LVM_GETNEXTITEM, -1, 1016 LVNI_SELECTED); 1017 1018 if (selection >= 0) 1019 { 1020 PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd, selection); 1021 1022 if (cert) 1023 { 1024 CRYPTUI_WIZ_EXPORT_INFO info; 1025 1026 info.dwSize = sizeof(info); 1027 info.pwszExportFileName = NULL; 1028 info.dwSubjectChoice = CRYPTUI_WIZ_EXPORT_CERT_CONTEXT; 1029 info.u.pCertContext = cert; 1030 info.cStores = 0; 1031 CryptUIWizExport(0, hwnd, NULL, &info, NULL); 1032 } 1033 } 1034 } 1035 else if (selectionCount > 1) 1036 { 1037 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, 1038 CERT_STORE_CREATE_NEW_FLAG, NULL); 1039 1040 if (store) 1041 { 1042 CRYPTUI_WIZ_EXPORT_INFO info; 1043 int selection = -1; 1044 1045 info.dwSize = sizeof(info); 1046 info.pwszExportFileName = NULL; 1047 info.dwSubjectChoice = 1048 CRYPTUI_WIZ_EXPORT_CERT_STORE_CERTIFICATES_ONLY; 1049 info.u.hCertStore = store; 1050 info.cStores = 0; 1051 do { 1052 selection = SendMessageW(lv, LVM_GETNEXTITEM, selection, 1053 LVNI_SELECTED); 1054 if (selection >= 0) 1055 { 1056 PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd, 1057 selection); 1058 1059 CertAddCertificateContextToStore(store, cert, 1060 CERT_STORE_ADD_ALWAYS, NULL); 1061 } 1062 } while (selection >= 0); 1063 CryptUIWizExport(0, hwnd, NULL, &info, NULL); 1064 CertCloseStore(store, 0); 1065 } 1066 } 1067 } 1068 1069 static int cert_mgr_sort_by_text(HWND lv, int col, int index1, int index2) 1070 { 1071 LVITEMW item; 1072 WCHAR buf1[MAX_STRING_LEN]; 1073 WCHAR buf2[MAX_STRING_LEN]; 1074 1075 item.cchTextMax = sizeof(buf1) / sizeof(buf1[0]); 1076 item.mask = LVIF_TEXT; 1077 item.pszText = buf1; 1078 item.iItem = index1; 1079 item.iSubItem = col; 1080 SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item); 1081 item.pszText = buf2; 1082 item.iItem = index2; 1083 SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item); 1084 return strcmpW(buf1, buf2); 1085 } 1086 1087 static int CALLBACK cert_mgr_sort_by_subject(LPARAM lp1, LPARAM lp2, LPARAM lp) 1088 { 1089 return cert_mgr_sort_by_text((HWND)lp, 0, lp1, lp2); 1090 } 1091 1092 static int CALLBACK cert_mgr_sort_by_issuer(LPARAM lp1, LPARAM lp2, LPARAM lp) 1093 { 1094 return cert_mgr_sort_by_text((HWND)lp, 1, lp1, lp2); 1095 } 1096 1097 static int CALLBACK cert_mgr_sort_by_date(LPARAM lp1, LPARAM lp2, LPARAM lp) 1098 { 1099 PCCERT_CONTEXT cert1 = (PCCERT_CONTEXT)lp1; 1100 PCCERT_CONTEXT cert2 = (PCCERT_CONTEXT)lp2; 1101 return CompareFileTime(&cert1->pCertInfo->NotAfter, 1102 &cert2->pCertInfo->NotAfter); 1103 } 1104 1105 static int CALLBACK cert_mgr_sort_by_friendly_name(LPARAM lp1, LPARAM lp2, 1106 LPARAM lp) 1107 { 1108 return cert_mgr_sort_by_text((HWND)lp, 3, lp1, lp2); 1109 } 1110 1111 static LRESULT CALLBACK cert_mgr_dlg_proc(HWND hwnd, UINT msg, WPARAM wp, 1112 LPARAM lp) 1113 { 1114 struct CertMgrData *data; 1115 1116 switch (msg) 1117 { 1118 case WM_INITDIALOG: 1119 { 1120 PCCRYPTUI_CERT_MGR_STRUCT pCryptUICertMgr = 1121 (PCCRYPTUI_CERT_MGR_STRUCT)lp; 1122 HWND tab = GetDlgItem(hwnd, IDC_MGR_STORES); 1123 1124 data = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CertMgrData)); 1125 if (!data) 1126 return 0; 1127 data->imageList = ImageList_Create(16, 16, ILC_COLOR4 | ILC_MASK, 2, 0); 1128 if (data->imageList) 1129 { 1130 HBITMAP bmp; 1131 COLORREF backColor = RGB(255, 0, 255); 1132 1133 bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_SMALL_ICONS)); 1134 ImageList_AddMasked(data->imageList, bmp, backColor); 1135 DeleteObject(bmp); 1136 ImageList_SetBkColor(data->imageList, CLR_NONE); 1137 SendMessageW(GetDlgItem(hwnd, IDC_MGR_CERTS), LVM_SETIMAGELIST, 1138 LVSIL_SMALL, (LPARAM)data->imageList); 1139 } 1140 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data); 1141 data->title = pCryptUICertMgr->pwszTitle; 1142 1143 initialize_purpose_selection(hwnd); 1144 add_cert_columns(hwnd); 1145 if (pCryptUICertMgr->pwszTitle) 1146 SendMessageW(hwnd, WM_SETTEXT, 0, 1147 (LPARAM)pCryptUICertMgr->pwszTitle); 1148 show_cert_stores(hwnd, pCryptUICertMgr->dwFlags, data); 1149 show_store_certs(hwnd, cert_mgr_index_to_store(tab, 0)); 1150 break; 1151 } 1152 case WM_NOTIFY: 1153 { 1154 NMHDR *hdr = (NMHDR *)lp; 1155 1156 switch (hdr->code) 1157 { 1158 case TCN_SELCHANGE: 1159 cert_mgr_clear_cert_selection(hwnd); 1160 break; 1161 case LVN_ITEMCHANGED: 1162 { 1163 WCHAR empty[] = { 0 }; 1164 NMITEMACTIVATE *nm = (NMITEMACTIVATE*)lp; 1165 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS); 1166 int numSelected = SendMessageW(lv, LVM_GETSELECTEDCOUNT, 0, 0); 1167 1168 EnableWindow(GetDlgItem(hwnd, IDC_MGR_EXPORT), numSelected > 0); 1169 EnableWindow(GetDlgItem(hwnd, IDC_MGR_REMOVE), numSelected > 0); 1170 EnableWindow(GetDlgItem(hwnd, IDC_MGR_VIEW), numSelected == 1); 1171 if (numSelected == 1) 1172 cert_mgr_show_cert_usages(hwnd, nm->iItem); 1173 else 1174 SendMessageW(GetDlgItem(hwnd, IDC_MGR_PURPOSES), WM_SETTEXT, 0, 1175 (LPARAM)empty); 1176 break; 1177 } 1178 case NM_DBLCLK: 1179 show_selected_cert(hwnd, ((NMITEMACTIVATE *)lp)->iItem); 1180 break; 1181 case LVN_KEYDOWN: 1182 { 1183 NMLVKEYDOWN *lvk = (NMLVKEYDOWN *)lp; 1184 1185 if (lvk->wVKey == VK_DELETE) 1186 cert_mgr_do_remove(hwnd); 1187 break; 1188 } 1189 case LVN_COLUMNCLICK: 1190 { 1191 NMLISTVIEW *nmlv = (NMLISTVIEW *)lp; 1192 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS); 1193 1194 /* FIXME: doesn't support swapping sort order between ascending 1195 * and descending. 1196 */ 1197 switch (nmlv->iSubItem) 1198 { 1199 case 0: 1200 SendMessageW(lv, LVM_SORTITEMSEX, (WPARAM)lv, 1201 (LPARAM)cert_mgr_sort_by_subject); 1202 break; 1203 case 1: 1204 SendMessageW(lv, LVM_SORTITEMSEX, (WPARAM)lv, 1205 (LPARAM)cert_mgr_sort_by_issuer); 1206 break; 1207 case 2: 1208 SendMessageW(lv, LVM_SORTITEMS, 0, 1209 (LPARAM)cert_mgr_sort_by_date); 1210 break; 1211 case 3: 1212 SendMessageW(lv, LVM_SORTITEMSEX, (WPARAM)lv, 1213 (LPARAM)cert_mgr_sort_by_friendly_name); 1214 break; 1215 } 1216 break; 1217 } 1218 } 1219 break; 1220 } 1221 case WM_COMMAND: 1222 switch (wp) 1223 { 1224 case ((CBN_SELCHANGE << 16) | IDC_MGR_PURPOSE_SELECTION): 1225 cert_mgr_clear_cert_selection(hwnd); 1226 break; 1227 case IDC_MGR_IMPORT: 1228 if (CryptUIWizImport(0, hwnd, NULL, NULL, 1229 cert_mgr_current_store(hwnd))) 1230 refresh_store_certs(hwnd); 1231 break; 1232 case IDC_MGR_ADVANCED: 1233 if (DialogBoxW(hInstance, MAKEINTRESOURCEW(IDD_CERT_MGR_ADVANCED), 1234 hwnd, cert_mgr_advanced_dlg_proc) == IDOK) 1235 { 1236 HWND cb = GetDlgItem(hwnd, IDC_MGR_PURPOSE_SELECTION); 1237 int index, len; 1238 LPWSTR curString = NULL; 1239 1240 index = SendMessageW(cb, CB_GETCURSEL, 0, 0); 1241 if (index >= 0) 1242 { 1243 len = SendMessageW(cb, CB_GETLBTEXTLEN, index, 0); 1244 curString = HeapAlloc(GetProcessHeap(), 0, 1245 (len + 1) * sizeof(WCHAR)); 1246 SendMessageW(cb, CB_GETLBTEXT, index, (LPARAM)curString); 1247 } 1248 SendMessageW(cb, CB_RESETCONTENT, 0, 0); 1249 initialize_purpose_selection(hwnd); 1250 if (curString) 1251 { 1252 index = SendMessageW(cb, CB_FINDSTRINGEXACT, -1, 1253 (LPARAM)curString); 1254 if (index >= 0) 1255 SendMessageW(cb, CB_SETCURSEL, index, 0); 1256 HeapFree(GetProcessHeap(), 0, curString); 1257 } 1258 refresh_store_certs(hwnd); 1259 } 1260 break; 1261 case IDC_MGR_VIEW: 1262 { 1263 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS); 1264 int selection = SendMessageW(lv, LVM_GETNEXTITEM, -1, 1265 LVNI_SELECTED); 1266 1267 if (selection >= 0) 1268 show_selected_cert(hwnd, selection); 1269 break; 1270 } 1271 case IDC_MGR_EXPORT: 1272 cert_mgr_do_export(hwnd); 1273 break; 1274 case IDC_MGR_REMOVE: 1275 cert_mgr_do_remove(hwnd); 1276 break; 1277 case IDCANCEL: 1278 free_certs(GetDlgItem(hwnd, IDC_MGR_CERTS)); 1279 close_stores(GetDlgItem(hwnd, IDC_MGR_STORES)); 1280 data = (struct CertMgrData *)GetWindowLongPtrW(hwnd, DWLP_USER); 1281 ImageList_Destroy(data->imageList); 1282 HeapFree(GetProcessHeap(), 0, data); 1283 EndDialog(hwnd, IDCANCEL); 1284 break; 1285 } 1286 break; 1287 } 1288 return 0; 1289 } 1290 1291 /*********************************************************************** 1292 * CryptUIDlgCertMgr (CRYPTUI.@) 1293 */ 1294 BOOL WINAPI CryptUIDlgCertMgr(PCCRYPTUI_CERT_MGR_STRUCT pCryptUICertMgr) 1295 { 1296 TRACE("(%p)\n", pCryptUICertMgr); 1297 1298 if (pCryptUICertMgr->dwSize != sizeof(CRYPTUI_CERT_MGR_STRUCT)) 1299 { 1300 WARN("unexpected size %d\n", pCryptUICertMgr->dwSize); 1301 SetLastError(E_INVALIDARG); 1302 return FALSE; 1303 } 1304 DialogBoxParamW(hInstance, MAKEINTRESOURCEW(IDD_CERT_MGR), 1305 pCryptUICertMgr->hwndParent, cert_mgr_dlg_proc, (LPARAM)pCryptUICertMgr); 1306 return TRUE; 1307 } 1308 1309 /* FIXME: real names are unknown, functions are undocumented */ 1310 typedef struct _CRYPTUI_ENUM_SYSTEM_STORE_ARGS 1311 { 1312 DWORD dwFlags; 1313 void *pvSystemStoreLocationPara; 1314 } CRYPTUI_ENUM_SYSTEM_STORE_ARGS, *PCRYPTUI_ENUM_SYSTEM_STORE_ARGS; 1315 1316 typedef struct _CRYPTUI_ENUM_DATA 1317 { 1318 DWORD cStores; 1319 HCERTSTORE *rghStore; 1320 DWORD cEnumArgs; 1321 PCRYPTUI_ENUM_SYSTEM_STORE_ARGS rgEnumArgs; 1322 } CRYPTUI_ENUM_DATA, *PCRYPTUI_ENUM_DATA; 1323 1324 typedef BOOL (WINAPI *PFN_SELECTED_STORE_CB)(HCERTSTORE store, HWND hwnd, 1325 void *pvArg); 1326 1327 /* Values for dwFlags */ 1328 #define CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE 0x00000001 1329 1330 typedef struct _CRYPTUI_SELECTSTORE_INFO_A 1331 { 1332 DWORD dwSize; 1333 HWND parent; 1334 DWORD dwFlags; 1335 LPSTR pszTitle; 1336 LPSTR pszText; 1337 CRYPTUI_ENUM_DATA *pEnumData; 1338 PFN_SELECTED_STORE_CB pfnSelectedStoreCallback; 1339 void *pvArg; 1340 } CRYPTUI_SELECTSTORE_INFO_A, *PCRYPTUI_SELECTSTORE_INFO_A; 1341 1342 typedef struct _CRYPTUI_SELECTSTORE_INFO_W 1343 { 1344 DWORD dwSize; 1345 HWND parent; 1346 DWORD dwFlags; 1347 LPWSTR pwszTitle; 1348 LPWSTR pwszText; 1349 CRYPTUI_ENUM_DATA *pEnumData; 1350 PFN_SELECTED_STORE_CB pfnSelectedStoreCallback; 1351 void *pvArg; 1352 } CRYPTUI_SELECTSTORE_INFO_W, *PCRYPTUI_SELECTSTORE_INFO_W; 1353 1354 struct StoreInfo 1355 { 1356 enum { 1357 StoreHandle, 1358 SystemStore 1359 } type; 1360 union { 1361 HCERTSTORE store; 1362 LPWSTR name; 1363 } DUMMYUNIONNAME; 1364 }; 1365 1366 static BOOL WINAPI enum_store_callback(const void *pvSystemStore, 1367 DWORD dwFlags, PCERT_SYSTEM_STORE_INFO pStoreInfo, void *pvReserved, 1368 void *pvArg) 1369 { 1370 HWND tree = GetDlgItem(pvArg, IDC_STORE_LIST); 1371 TVINSERTSTRUCTW tvis; 1372 LPCWSTR localizedName; 1373 BOOL ret = TRUE; 1374 1375 tvis.hParent = NULL; 1376 tvis.hInsertAfter = TVI_LAST; 1377 tvis.u.item.mask = TVIF_TEXT; 1378 if ((localizedName = CryptFindLocalizedName(pvSystemStore))) 1379 { 1380 struct StoreInfo *storeInfo = HeapAlloc(GetProcessHeap(), 0, 1381 sizeof(struct StoreInfo)); 1382 1383 if (storeInfo) 1384 { 1385 storeInfo->type = SystemStore; 1386 storeInfo->u.name = HeapAlloc(GetProcessHeap(), 0, 1387 (strlenW(pvSystemStore) + 1) * sizeof(WCHAR)); 1388 if (storeInfo->u.name) 1389 { 1390 tvis.u.item.mask |= TVIF_PARAM; 1391 tvis.u.item.lParam = (LPARAM)storeInfo; 1392 strcpyW(storeInfo->u.name, pvSystemStore); 1393 } 1394 else 1395 { 1396 HeapFree(GetProcessHeap(), 0, storeInfo); 1397 ret = FALSE; 1398 } 1399 } 1400 else 1401 ret = FALSE; 1402 tvis.u.item.pszText = (LPWSTR)localizedName; 1403 } 1404 else 1405 tvis.u.item.pszText = (LPWSTR)pvSystemStore; 1406 /* FIXME: need a folder icon for the store too */ 1407 if (ret) 1408 SendMessageW(tree, TVM_INSERTITEMW, 0, (LPARAM)&tvis); 1409 return ret; 1410 } 1411 1412 static void enumerate_stores(HWND hwnd, CRYPTUI_ENUM_DATA *pEnumData) 1413 { 1414 DWORD i; 1415 HWND tree = GetDlgItem(hwnd, IDC_STORE_LIST); 1416 1417 for (i = 0; i < pEnumData->cEnumArgs; i++) 1418 CertEnumSystemStore(pEnumData->rgEnumArgs[i].dwFlags, 1419 pEnumData->rgEnumArgs[i].pvSystemStoreLocationPara, 1420 hwnd, enum_store_callback); 1421 for (i = 0; i < pEnumData->cStores; i++) 1422 { 1423 DWORD size; 1424 1425 if (CertGetStoreProperty(pEnumData->rghStore[i], 1426 CERT_STORE_LOCALIZED_NAME_PROP_ID, NULL, &size)) 1427 { 1428 LPWSTR name = HeapAlloc(GetProcessHeap(), 0, size); 1429 1430 if (name) 1431 { 1432 if (CertGetStoreProperty(pEnumData->rghStore[i], 1433 CERT_STORE_LOCALIZED_NAME_PROP_ID, name, &size)) 1434 { 1435 struct StoreInfo *storeInfo = HeapAlloc(GetProcessHeap(), 1436 0, sizeof(struct StoreInfo)); 1437 1438 if (storeInfo) 1439 { 1440 TVINSERTSTRUCTW tvis; 1441 1442 storeInfo->type = StoreHandle; 1443 storeInfo->u.store = pEnumData->rghStore[i]; 1444 tvis.hParent = NULL; 1445 tvis.hInsertAfter = TVI_LAST; 1446 tvis.u.item.mask = TVIF_TEXT | TVIF_PARAM; 1447 tvis.u.item.pszText = name; 1448 tvis.u.item.lParam = (LPARAM)storeInfo; 1449 SendMessageW(tree, TVM_INSERTITEMW, 0, (LPARAM)&tvis); 1450 } 1451 } 1452 HeapFree(GetProcessHeap(), 0, name); 1453 } 1454 } 1455 } 1456 } 1457 1458 static void free_store_info(HWND tree) 1459 { 1460 HTREEITEM next = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM, TVGN_CHILD, 1461 0); 1462 1463 while (next) 1464 { 1465 TVITEMW item; 1466 1467 memset(&item, 0, sizeof(item)); 1468 item.mask = TVIF_HANDLE | TVIF_PARAM; 1469 item.hItem = next; 1470 SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item); 1471 if (item.lParam) 1472 { 1473 struct StoreInfo *storeInfo = (struct StoreInfo *)item.lParam; 1474 1475 if (storeInfo->type == SystemStore) 1476 HeapFree(GetProcessHeap(), 0, storeInfo->u.name); 1477 HeapFree(GetProcessHeap(), 0, storeInfo); 1478 } 1479 next = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM, TVGN_NEXT, 1480 (LPARAM)next); 1481 } 1482 } 1483 1484 static HCERTSTORE selected_item_to_store(HWND tree, HTREEITEM hItem) 1485 { 1486 WCHAR buf[MAX_STRING_LEN]; 1487 TVITEMW item; 1488 HCERTSTORE store; 1489 1490 memset(&item, 0, sizeof(item)); 1491 item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_TEXT; 1492 item.hItem = hItem; 1493 item.cchTextMax = sizeof(buf) / sizeof(buf[0]); 1494 item.pszText = buf; 1495 SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item); 1496 if (item.lParam) 1497 { 1498 struct StoreInfo *storeInfo = (struct StoreInfo *)item.lParam; 1499 1500 if (storeInfo->type == StoreHandle) 1501 store = storeInfo->u.store; 1502 else 1503 store = CertOpenSystemStoreW(0, storeInfo->u.name); 1504 } 1505 else 1506 { 1507 /* It's implicitly a system store */ 1508 store = CertOpenSystemStoreW(0, buf); 1509 } 1510 return store; 1511 } 1512 1513 struct SelectStoreInfo 1514 { 1515 PCRYPTUI_SELECTSTORE_INFO_W info; 1516 HCERTSTORE store; 1517 }; 1518 1519 static LRESULT CALLBACK select_store_dlg_proc(HWND hwnd, UINT msg, WPARAM wp, 1520 LPARAM lp) 1521 { 1522 struct SelectStoreInfo *selectInfo; 1523 LRESULT ret = 0; 1524 1525 switch (msg) 1526 { 1527 case WM_INITDIALOG: 1528 { 1529 selectInfo = (struct SelectStoreInfo *)lp; 1530 SetWindowLongPtrW(hwnd, DWLP_USER, lp); 1531 if (selectInfo->info->pwszTitle) 1532 SendMessageW(hwnd, WM_SETTEXT, 0, 1533 (LPARAM)selectInfo->info->pwszTitle); 1534 if (selectInfo->info->pwszText) 1535 SendMessageW(GetDlgItem(hwnd, IDC_STORE_TEXT), WM_SETTEXT, 0, 1536 (LPARAM)selectInfo->info->pwszText); 1537 if (!(selectInfo->info->dwFlags & CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE)) 1538 ShowWindow(GetDlgItem(hwnd, IDC_SHOW_PHYSICAL_STORES), FALSE); 1539 enumerate_stores(hwnd, selectInfo->info->pEnumData); 1540 break; 1541 } 1542 case WM_COMMAND: 1543 switch (wp) 1544 { 1545 case IDOK: 1546 { 1547 HWND tree = GetDlgItem(hwnd, IDC_STORE_LIST); 1548 HTREEITEM selection = (HTREEITEM)SendMessageW(tree, 1549 TVM_GETNEXTITEM, TVGN_CARET, 0); 1550 1551 selectInfo = (struct SelectStoreInfo *)GetWindowLongPtrW(hwnd, 1552 DWLP_USER); 1553 if (!selection) 1554 { 1555 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN], *pTitle; 1556 1557 if (selectInfo->info->pwszTitle) 1558 pTitle = selectInfo->info->pwszTitle; 1559 else 1560 { 1561 LoadStringW(hInstance, IDS_SELECT_STORE_TITLE, title, 1562 sizeof(title) / sizeof(title[0])); 1563 pTitle = title; 1564 } 1565 LoadStringW(hInstance, IDS_SELECT_STORE, error, 1566 sizeof(error) / sizeof(error[0])); 1567 MessageBoxW(hwnd, error, pTitle, MB_ICONEXCLAMATION | MB_OK); 1568 } 1569 else 1570 { 1571 HCERTSTORE store = selected_item_to_store(tree, selection); 1572 1573 if (!selectInfo->info->pfnSelectedStoreCallback || 1574 selectInfo->info->pfnSelectedStoreCallback(store, hwnd, 1575 selectInfo->info->pvArg)) 1576 { 1577 selectInfo->store = store; 1578 free_store_info(tree); 1579 EndDialog(hwnd, IDOK); 1580 } 1581 else 1582 CertCloseStore(store, 0); 1583 } 1584 ret = TRUE; 1585 break; 1586 } 1587 case IDCANCEL: 1588 free_store_info(GetDlgItem(hwnd, IDC_STORE_LIST)); 1589 EndDialog(hwnd, IDCANCEL); 1590 ret = TRUE; 1591 break; 1592 } 1593 break; 1594 } 1595 return ret; 1596 } 1597 1598 /*********************************************************************** 1599 * CryptUIDlgSelectStoreW (CRYPTUI.@) 1600 */ 1601 HCERTSTORE WINAPI CryptUIDlgSelectStoreW(PCRYPTUI_SELECTSTORE_INFO_W info) 1602 { 1603 struct SelectStoreInfo selectInfo = { info, NULL }; 1604 1605 TRACE("(%p)\n", info); 1606 1607 if (info->dwSize != sizeof(CRYPTUI_SELECTSTORE_INFO_W)) 1608 { 1609 WARN("unexpected size %d\n", info->dwSize); 1610 SetLastError(E_INVALIDARG); 1611 return NULL; 1612 } 1613 DialogBoxParamW(hInstance, MAKEINTRESOURCEW(IDD_SELECT_STORE), info->parent, 1614 select_store_dlg_proc, (LPARAM)&selectInfo); 1615 return selectInfo.store; 1616 } 1617 1618 /*********************************************************************** 1619 * CryptUIDlgSelectStoreA (CRYPTUI.@) 1620 */ 1621 HCERTSTORE WINAPI CryptUIDlgSelectStoreA(PCRYPTUI_SELECTSTORE_INFO_A info) 1622 { 1623 CRYPTUI_SELECTSTORE_INFO_W infoW; 1624 HCERTSTORE ret; 1625 int len; 1626 1627 TRACE("(%p)\n", info); 1628 1629 if (info->dwSize != sizeof(CRYPTUI_SELECTSTORE_INFO_A)) 1630 { 1631 WARN("unexpected size %d\n", info->dwSize); 1632 SetLastError(E_INVALIDARG); 1633 return NULL; 1634 } 1635 memcpy(&infoW, info, sizeof(*info)); 1636 if (info->pszTitle) 1637 { 1638 len = MultiByteToWideChar(CP_ACP, 0, info->pszTitle, -1, NULL, 0); 1639 infoW.pwszTitle = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 1640 MultiByteToWideChar(CP_ACP, 0, info->pszTitle, -1, infoW.pwszTitle, 1641 len); 1642 } 1643 if (info->pszText) 1644 { 1645 len = MultiByteToWideChar(CP_ACP, 0, info->pszText, -1, NULL, 0); 1646 infoW.pwszText = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 1647 MultiByteToWideChar(CP_ACP, 0, info->pszText, -1, infoW.pwszText, len); 1648 } 1649 ret = CryptUIDlgSelectStoreW(&infoW); 1650 HeapFree(GetProcessHeap(), 0, infoW.pwszText); 1651 HeapFree(GetProcessHeap(), 0, infoW.pwszTitle); 1652 return ret; 1653 } 1654 1655 /*********************************************************************** 1656 * CryptUIDlgViewCertificateA (CRYPTUI.@) 1657 */ 1658 BOOL WINAPI CryptUIDlgViewCertificateA( 1659 PCCRYPTUI_VIEWCERTIFICATE_STRUCTA pCertViewInfo, BOOL *pfPropertiesChanged) 1660 { 1661 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo; 1662 LPWSTR title = NULL; 1663 BOOL ret; 1664 1665 TRACE("(%p, %p)\n", pCertViewInfo, pfPropertiesChanged); 1666 1667 memcpy(&viewInfo, pCertViewInfo, sizeof(viewInfo)); 1668 if (pCertViewInfo->szTitle) 1669 { 1670 int len = MultiByteToWideChar(CP_ACP, 0, pCertViewInfo->szTitle, -1, 1671 NULL, 0); 1672 1673 title = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 1674 if (title) 1675 { 1676 MultiByteToWideChar(CP_ACP, 0, pCertViewInfo->szTitle, -1, title, 1677 len); 1678 viewInfo.szTitle = title; 1679 } 1680 else 1681 { 1682 ret = FALSE; 1683 goto error; 1684 } 1685 } 1686 if (pCertViewInfo->cPropSheetPages) 1687 { 1688 FIXME("ignoring additional prop sheet pages\n"); 1689 viewInfo.cPropSheetPages = 0; 1690 } 1691 ret = CryptUIDlgViewCertificateW(&viewInfo, pfPropertiesChanged); 1692 HeapFree(GetProcessHeap(), 0, title); 1693 error: 1694 return ret; 1695 } 1696 1697 struct ReadStringStruct 1698 { 1699 LPCWSTR buf; 1700 LONG pos; 1701 LONG len; 1702 }; 1703 1704 static DWORD CALLBACK read_text_callback(DWORD_PTR dwCookie, LPBYTE buf, 1705 LONG cb, LONG *pcb) 1706 { 1707 struct ReadStringStruct *string = (struct ReadStringStruct *)dwCookie; 1708 LONG cch = min(cb / sizeof(WCHAR), string->len - string->pos); 1709 1710 TRACE("(%p, %p, %d, %p)\n", string, buf, cb, pcb); 1711 1712 memmove(buf, string->buf + string->pos, cch * sizeof(WCHAR)); 1713 string->pos += cch; 1714 *pcb = cch * sizeof(WCHAR); 1715 return 0; 1716 } 1717 1718 static void add_unformatted_text_to_control(HWND hwnd, LPCWSTR text, LONG len) 1719 { 1720 struct ReadStringStruct string; 1721 EDITSTREAM editstream; 1722 1723 TRACE("(%p, %s)\n", hwnd, debugstr_wn(text, len)); 1724 1725 string.buf = text; 1726 string.pos = 0; 1727 string.len = len; 1728 editstream.dwCookie = (DWORD_PTR)&string; 1729 editstream.dwError = 0; 1730 editstream.pfnCallback = read_text_callback; 1731 SendMessageW(hwnd, EM_STREAMIN, SF_TEXT | SFF_SELECTION | SF_UNICODE, 1732 (LPARAM)&editstream); 1733 } 1734 1735 static void add_string_resource_to_control(HWND hwnd, int id) 1736 { 1737 LPWSTR str; 1738 LONG len; 1739 1740 len = LoadStringW(hInstance, id, (LPWSTR)&str, 0); 1741 add_unformatted_text_to_control(hwnd, str, len); 1742 } 1743 1744 static void add_text_with_paraformat_to_control(HWND hwnd, LPCWSTR text, 1745 LONG len, const PARAFORMAT2 *fmt) 1746 { 1747 add_unformatted_text_to_control(hwnd, text, len); 1748 SendMessageW(hwnd, EM_SETPARAFORMAT, 0, (LPARAM)fmt); 1749 } 1750 1751 static void add_string_resource_with_paraformat_to_control(HWND hwnd, int id, 1752 const PARAFORMAT2 *fmt) 1753 { 1754 LPWSTR str; 1755 LONG len; 1756 1757 len = LoadStringW(hInstance, id, (LPWSTR)&str, 0); 1758 add_text_with_paraformat_to_control(hwnd, str, len, fmt); 1759 } 1760 1761 static LPWSTR get_cert_name_string(PCCERT_CONTEXT pCertContext, DWORD dwType, 1762 DWORD dwFlags) 1763 { 1764 LPWSTR buf = NULL; 1765 DWORD len; 1766 1767 len = CertGetNameStringW(pCertContext, dwType, dwFlags, NULL, NULL, 0); 1768 if (len) 1769 { 1770 buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 1771 if (buf) 1772 CertGetNameStringW(pCertContext, dwType, dwFlags, NULL, buf, len); 1773 } 1774 return buf; 1775 } 1776 1777 static void add_cert_string_to_control(HWND hwnd, PCCERT_CONTEXT pCertContext, 1778 DWORD dwType, DWORD dwFlags) 1779 { 1780 LPWSTR name = get_cert_name_string(pCertContext, dwType, dwFlags); 1781 1782 if (name) 1783 { 1784 /* Don't include NULL-terminator in output */ 1785 DWORD len = lstrlenW(name); 1786 1787 add_unformatted_text_to_control(hwnd, name, len); 1788 HeapFree(GetProcessHeap(), 0, name); 1789 } 1790 } 1791 1792 static void add_icon_to_control(HWND hwnd, int id) 1793 { 1794 HRESULT hr; 1795 IRichEditOle *richEditOle = NULL; 1796 IOleObject *object = NULL; 1797 CLSID clsid; 1798 LPOLECACHE oleCache = NULL; 1799 FORMATETC formatEtc; 1800 DWORD conn; 1801 IDataObject *dataObject = NULL; 1802 HBITMAP bitmap = NULL; 1803 STGMEDIUM stgm; 1804 IOleClientSite *clientSite = NULL; 1805 REOBJECT reObject; 1806 1807 TRACE("(%p, %d)\n", hwnd, id); 1808 1809 SendMessageW(hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&richEditOle); 1810 if (!richEditOle) 1811 goto end; 1812 hr = OleCreateDefaultHandler(&CLSID_NULL, NULL, &IID_IOleObject, 1813 (void**)&object); 1814 if (FAILED(hr)) 1815 goto end; 1816 hr = IOleObject_GetUserClassID(object, &clsid); 1817 if (FAILED(hr)) 1818 goto end; 1819 hr = IOleObject_QueryInterface(object, &IID_IOleCache, (void**)&oleCache); 1820 if (FAILED(hr)) 1821 goto end; 1822 formatEtc.cfFormat = CF_BITMAP; 1823 formatEtc.ptd = NULL; 1824 formatEtc.dwAspect = DVASPECT_CONTENT; 1825 formatEtc.lindex = -1; 1826 formatEtc.tymed = TYMED_GDI; 1827 hr = IOleCache_Cache(oleCache, &formatEtc, 0, &conn); 1828 if (FAILED(hr)) 1829 goto end; 1830 hr = IOleObject_QueryInterface(object, &IID_IDataObject, 1831 (void**)&dataObject); 1832 if (FAILED(hr)) 1833 goto end; 1834 hr = IRichEditOle_GetClientSite(richEditOle, &clientSite); 1835 if (FAILED(hr)) 1836 goto end; 1837 bitmap = LoadImageW(hInstance, MAKEINTRESOURCEW(id), IMAGE_BITMAP, 0, 0, 1838 LR_DEFAULTSIZE | LR_LOADTRANSPARENT); 1839 if (!bitmap) 1840 goto end; 1841 stgm.tymed = TYMED_GDI; 1842 stgm.u.hBitmap = bitmap; 1843 stgm.pUnkForRelease = NULL; 1844 hr = IDataObject_SetData(dataObject, &formatEtc, &stgm, TRUE); 1845 if (FAILED(hr)) 1846 goto end; 1847 1848 reObject.cbStruct = sizeof(reObject); 1849 reObject.cp = REO_CP_SELECTION; 1850 reObject.clsid = clsid; 1851 reObject.poleobj = object; 1852 reObject.pstg = NULL; 1853 reObject.polesite = clientSite; 1854 reObject.sizel.cx = reObject.sizel.cy = 0; 1855 reObject.dvaspect = DVASPECT_CONTENT; 1856 reObject.dwFlags = 0; 1857 reObject.dwUser = 0; 1858 1859 IRichEditOle_InsertObject(richEditOle, &reObject); 1860 1861 end: 1862 if (clientSite) 1863 IOleClientSite_Release(clientSite); 1864 if (dataObject) 1865 IDataObject_Release(dataObject); 1866 if (oleCache) 1867 IOleCache_Release(oleCache); 1868 if (object) 1869 IOleObject_Release(object); 1870 if (richEditOle) 1871 IRichEditOle_Release(richEditOle); 1872 } 1873 1874 #define MY_INDENT 200 1875 1876 static void add_oid_text_to_control(HWND hwnd, char *oid) 1877 { 1878 WCHAR nl = '\n'; 1879 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, oid, 0); 1880 PARAFORMAT2 parFmt; 1881 1882 parFmt.cbSize = sizeof(parFmt); 1883 parFmt.dwMask = PFM_STARTINDENT; 1884 parFmt.dxStartIndent = MY_INDENT * 3; 1885 if (oidInfo) 1886 { 1887 add_text_with_paraformat_to_control(hwnd, oidInfo->pwszName, 1888 lstrlenW(oidInfo->pwszName), &parFmt); 1889 add_unformatted_text_to_control(hwnd, &nl, 1); 1890 } 1891 } 1892 1893 struct OIDToString 1894 { 1895 LPCSTR oid; 1896 int id; 1897 }; 1898 1899 /* The following list MUST be lexicographically sorted by OID */ 1900 static struct OIDToString oidMap[] = { 1901 /* 1.3.6.1.4.1.311.10.3.1 */ 1902 { szOID_KP_CTL_USAGE_SIGNING, IDS_PURPOSE_CTL_USAGE_SIGNING }, 1903 /* 1.3.6.1.4.1.311.10.3.4 */ 1904 { szOID_KP_EFS, IDS_PURPOSE_EFS }, 1905 /* 1.3.6.1.4.1.311.10.3.4.1 */ 1906 { szOID_EFS_RECOVERY, IDS_PURPOSE_EFS_RECOVERY }, 1907 /* 1.3.6.1.4.1.311.10.3.5 */ 1908 { szOID_WHQL_CRYPTO, IDS_PURPOSE_WHQL }, 1909 /* 1.3.6.1.4.1.311.10.3.6 */ 1910 { szOID_NT5_CRYPTO, IDS_PURPOSE_NT5 }, 1911 /* 1.3.6.1.4.1.311.10.3.7 */ 1912 { szOID_OEM_WHQL_CRYPTO, IDS_PURPOSE_OEM_WHQL }, 1913 /* 1.3.6.1.4.1.311.10.3.8 */ 1914 { szOID_EMBEDDED_NT_CRYPTO, IDS_PURPOSE_EMBEDDED_NT }, 1915 /* 1.3.6.1.4.1.311.10.3.9 */ 1916 { szOID_ROOT_LIST_SIGNER, IDS_PURPOSE_ROOT_LIST_SIGNER }, 1917 /* 1.3.6.1.4.1.311.10.3.10 */ 1918 { szOID_KP_QUALIFIED_SUBORDINATION, IDS_PURPOSE_QUALIFIED_SUBORDINATION }, 1919 /* 1.3.6.1.4.1.311.10.3.11 */ 1920 { szOID_KP_KEY_RECOVERY, IDS_PURPOSE_KEY_RECOVERY }, 1921 /* 1.3.6.1.4.1.311.10.3.12 */ 1922 { szOID_KP_DOCUMENT_SIGNING, IDS_PURPOSE_DOCUMENT_SIGNING }, 1923 /* 1.3.6.1.4.1.311.10.3.13 */ 1924 { szOID_KP_LIFETIME_SIGNING, IDS_PURPOSE_LIFETIME_SIGNING }, 1925 /* 1.3.6.1.4.1.311.10.5.1 */ 1926 { szOID_DRM, IDS_PURPOSE_DRM }, 1927 /* 1.3.6.1.4.1.311.10.6.1 */ 1928 { szOID_LICENSES, IDS_PURPOSE_LICENSES }, 1929 /* 1.3.6.1.4.1.311.10.6.2 */ 1930 { szOID_LICENSE_SERVER, IDS_PURPOSE_LICENSE_SERVER }, 1931 /* 1.3.6.1.4.1.311.20.2.1 */ 1932 { szOID_ENROLLMENT_AGENT, IDS_PURPOSE_ENROLLMENT_AGENT }, 1933 /* 1.3.6.1.4.1.311.20.2.2 */ 1934 { szOID_KP_SMARTCARD_LOGON, IDS_PURPOSE_SMARTCARD_LOGON }, 1935 /* 1.3.6.1.4.1.311.21.5 */ 1936 { szOID_KP_CA_EXCHANGE, IDS_PURPOSE_CA_EXCHANGE }, 1937 /* 1.3.6.1.4.1.311.21.6 */ 1938 { szOID_KP_KEY_RECOVERY_AGENT, IDS_PURPOSE_KEY_RECOVERY_AGENT }, 1939 /* 1.3.6.1.4.1.311.21.19 */ 1940 { szOID_DS_EMAIL_REPLICATION, IDS_PURPOSE_DS_EMAIL_REPLICATION }, 1941 /* 1.3.6.1.5.5.7.3.1 */ 1942 { szOID_PKIX_KP_SERVER_AUTH, IDS_PURPOSE_SERVER_AUTH }, 1943 /* 1.3.6.1.5.5.7.3.2 */ 1944 { szOID_PKIX_KP_CLIENT_AUTH, IDS_PURPOSE_CLIENT_AUTH }, 1945 /* 1.3.6.1.5.5.7.3.3 */ 1946 { szOID_PKIX_KP_CODE_SIGNING, IDS_PURPOSE_CODE_SIGNING }, 1947 /* 1.3.6.1.5.5.7.3.4 */ 1948 { szOID_PKIX_KP_EMAIL_PROTECTION, IDS_PURPOSE_EMAIL_PROTECTION }, 1949 /* 1.3.6.1.5.5.7.3.5 */ 1950 { szOID_PKIX_KP_IPSEC_END_SYSTEM, IDS_PURPOSE_IPSEC }, 1951 /* 1.3.6.1.5.5.7.3.6 */ 1952 { szOID_PKIX_KP_IPSEC_TUNNEL, IDS_PURPOSE_IPSEC }, 1953 /* 1.3.6.1.5.5.7.3.7 */ 1954 { szOID_PKIX_KP_IPSEC_USER, IDS_PURPOSE_IPSEC }, 1955 /* 1.3.6.1.5.5.7.3.8 */ 1956 { szOID_PKIX_KP_TIMESTAMP_SIGNING, IDS_PURPOSE_TIMESTAMP_SIGNING }, 1957 }; 1958 1959 static struct OIDToString *findSupportedOID(LPCSTR oid) 1960 { 1961 int indexHigh = sizeof(oidMap) / sizeof(oidMap[0]) - 1, indexLow = 0; 1962 1963 while (indexLow <= indexHigh) 1964 { 1965 int cmp, i = (indexLow + indexHigh) / 2; 1966 if (!(cmp = strcmp(oid, oidMap[i].oid))) 1967 return &oidMap[i]; 1968 if (cmp > 0) 1969 indexLow = i + 1; 1970 else 1971 indexHigh = i - 1; 1972 } 1973 return NULL; 1974 } 1975 1976 static void add_local_oid_text_to_control(HWND text, LPCSTR oid) 1977 { 1978 struct OIDToString *entry; 1979 WCHAR nl = '\n'; 1980 PARAFORMAT2 parFmt; 1981 1982 parFmt.cbSize = sizeof(parFmt); 1983 parFmt.dwMask = PFM_STARTINDENT; 1984 parFmt.dxStartIndent = MY_INDENT * 3; 1985 if ((entry = findSupportedOID(oid))) 1986 { 1987 WCHAR *str, *linebreak, *ptr; 1988 BOOL multiline = FALSE; 1989 int len; 1990 1991 len = LoadStringW(hInstance, entry->id, (LPWSTR)&str, 0); 1992 ptr = str; 1993 do { 1994 if ((linebreak = memchrW(ptr, '\n', len))) 1995 { 1996 WCHAR copy[MAX_STRING_LEN]; 1997 1998 multiline = TRUE; 1999 /* The source string contains a newline, which the richedit 2000 * control won't find since it's interpreted as a paragraph 2001 * break. Therefore copy up to the newline. lstrcpynW always 2002 * NULL-terminates, so pass one more than the length of the 2003 * source line so the copy includes the entire line and the 2004 * NULL-terminator. 2005 */ 2006 lstrcpynW(copy, ptr, linebreak - ptr + 1); 2007 add_text_with_paraformat_to_control(text, copy, 2008 linebreak - ptr, &parFmt); 2009 ptr = linebreak + 1; 2010 add_unformatted_text_to_control(text, &nl, 1); 2011 } 2012 else if (multiline && *ptr) 2013 { 2014 /* Add the last line */ 2015 add_text_with_paraformat_to_control(text, ptr, 2016 len - (ptr - str), &parFmt); 2017 add_unformatted_text_to_control(text, &nl, 1); 2018 } 2019 } while (linebreak); 2020 if (!multiline) 2021 { 2022 add_text_with_paraformat_to_control(text, str, len, &parFmt); 2023 add_unformatted_text_to_control(text, &nl, 1); 2024 } 2025 } 2026 else 2027 { 2028 WCHAR *oidW = HeapAlloc(GetProcessHeap(), 0, 2029 (strlen(oid) + 1) * sizeof(WCHAR)); 2030 2031 if (oidW) 2032 { 2033 LPCSTR src; 2034 WCHAR *dst; 2035 2036 for (src = oid, dst = oidW; *src; src++, dst++) 2037 *dst = *src; 2038 *dst = 0; 2039 add_text_with_paraformat_to_control(text, oidW, lstrlenW(oidW), 2040 &parFmt); 2041 add_unformatted_text_to_control(text, &nl, 1); 2042 HeapFree(GetProcessHeap(), 0, oidW); 2043 } 2044 } 2045 } 2046 2047 static void display_app_usages(HWND text, PCCERT_CONTEXT cert, 2048 BOOL *anyUsageAdded) 2049 { 2050 static char any_app_policy[] = szOID_ANY_APPLICATION_POLICY; 2051 WCHAR nl = '\n'; 2052 CHARFORMATW charFmt; 2053 PCERT_EXTENSION policyExt; 2054 if (!*anyUsageAdded) 2055 { 2056 PARAFORMAT2 parFmt; 2057 2058 parFmt.cbSize = sizeof(parFmt); 2059 parFmt.dwMask = PFM_STARTINDENT; 2060 parFmt.dxStartIndent = MY_INDENT; 2061 add_string_resource_with_paraformat_to_control(text, 2062 IDS_CERT_INFO_PURPOSES, &parFmt); 2063 add_unformatted_text_to_control(text, &nl, 1); 2064 *anyUsageAdded = TRUE; 2065 } 2066 memset(&charFmt, 0, sizeof(charFmt)); 2067 charFmt.cbSize = sizeof(charFmt); 2068 charFmt.dwMask = CFM_BOLD; 2069 charFmt.dwEffects = 0; 2070 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt); 2071 if ((policyExt = CertFindExtension(szOID_APPLICATION_CERT_POLICIES, 2072 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension))) 2073 { 2074 CERT_POLICIES_INFO *policies; 2075 DWORD size; 2076 2077 if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_POLICIES, 2078 policyExt->Value.pbData, policyExt->Value.cbData, 2079 CRYPT_DECODE_ALLOC_FLAG, NULL, &policies, &size)) 2080 { 2081 DWORD i; 2082 2083 for (i = 0; i < policies->cPolicyInfo; i++) 2084 { 2085 DWORD j; 2086 2087 for (j = 0; j < policies->rgPolicyInfo[i].cPolicyQualifier; j++) 2088 add_local_oid_text_to_control(text, 2089 policies->rgPolicyInfo[i].rgPolicyQualifier[j]. 2090 pszPolicyQualifierId); 2091 } 2092 LocalFree(policies); 2093 } 2094 } 2095 else 2096 add_oid_text_to_control(text, any_app_policy); 2097 } 2098 2099 static BOOL display_cert_usages(HWND text, PCCERT_CONTEXT cert, 2100 BOOL *anyUsageAdded) 2101 { 2102 WCHAR nl = '\n'; 2103 DWORD size; 2104 BOOL badUsages = FALSE; 2105 2106 if (CertGetEnhancedKeyUsage(cert, 0, NULL, &size)) 2107 { 2108 CHARFORMATW charFmt; 2109 static char any_cert_policy[] = szOID_ANY_CERT_POLICY; 2110 PCERT_ENHKEY_USAGE usage = HeapAlloc(GetProcessHeap(), 0, size); 2111 2112 if (usage) 2113 { 2114 if (CertGetEnhancedKeyUsage(cert, 0, usage, &size)) 2115 { 2116 DWORD i; 2117 2118 if (!*anyUsageAdded) 2119 { 2120 PARAFORMAT2 parFmt; 2121 2122 parFmt.cbSize = sizeof(parFmt); 2123 parFmt.dwMask = PFM_STARTINDENT; 2124 parFmt.dxStartIndent = MY_INDENT; 2125 add_string_resource_with_paraformat_to_control(text, 2126 IDS_CERT_INFO_PURPOSES, &parFmt); 2127 add_unformatted_text_to_control(text, &nl, 1); 2128 *anyUsageAdded = TRUE; 2129 } 2130 memset(&charFmt, 0, sizeof(charFmt)); 2131 charFmt.cbSize = sizeof(charFmt); 2132 charFmt.dwMask = CFM_BOLD; 2133 charFmt.dwEffects = 0; 2134 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, 2135 (LPARAM)&charFmt); 2136 if (!usage->cUsageIdentifier) 2137 add_oid_text_to_control(text, any_cert_policy); 2138 else 2139 for (i = 0; i < usage->cUsageIdentifier; i++) 2140 add_local_oid_text_to_control(text, 2141 usage->rgpszUsageIdentifier[i]); 2142 } 2143 else 2144 badUsages = TRUE; 2145 HeapFree(GetProcessHeap(), 0, usage); 2146 } 2147 else 2148 badUsages = TRUE; 2149 } 2150 else 2151 badUsages = TRUE; 2152 return badUsages; 2153 } 2154 2155 static void set_policy_text(HWND text, 2156 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo) 2157 { 2158 BOOL includeCertUsages = FALSE, includeAppUsages = FALSE; 2159 BOOL badUsages = FALSE, anyUsageAdded = FALSE; 2160 2161 if (pCertViewInfo->cPurposes) 2162 { 2163 DWORD i; 2164 2165 for (i = 0; i < pCertViewInfo->cPurposes; i++) 2166 { 2167 if (!strcmp(pCertViewInfo->rgszPurposes[i], szOID_ANY_CERT_POLICY)) 2168 includeCertUsages = TRUE; 2169 else if (!strcmp(pCertViewInfo->rgszPurposes[i], 2170 szOID_ANY_APPLICATION_POLICY)) 2171 includeAppUsages = TRUE; 2172 else 2173 badUsages = TRUE; 2174 } 2175 } 2176 else 2177 includeAppUsages = includeCertUsages = TRUE; 2178 if (includeAppUsages) 2179 display_app_usages(text, pCertViewInfo->pCertContext, &anyUsageAdded); 2180 if (includeCertUsages) 2181 badUsages = display_cert_usages(text, pCertViewInfo->pCertContext, 2182 &anyUsageAdded); 2183 if (badUsages) 2184 { 2185 PARAFORMAT2 parFmt; 2186 2187 parFmt.cbSize = sizeof(parFmt); 2188 parFmt.dwMask = PFM_STARTINDENT; 2189 parFmt.dxStartIndent = MY_INDENT; 2190 add_string_resource_with_paraformat_to_control(text, 2191 IDS_CERT_INFO_BAD_PURPOSES, &parFmt); 2192 } 2193 } 2194 2195 static CRYPT_OBJID_BLOB *find_policy_qualifier(CERT_POLICIES_INFO *policies, 2196 LPCSTR policyOid) 2197 { 2198 CRYPT_OBJID_BLOB *ret = NULL; 2199 DWORD i; 2200 2201 for (i = 0; !ret && i < policies->cPolicyInfo; i++) 2202 { 2203 DWORD j; 2204 2205 for (j = 0; !ret && j < policies->rgPolicyInfo[i].cPolicyQualifier; j++) 2206 if (!strcmp(policies->rgPolicyInfo[i].rgPolicyQualifier[j]. 2207 pszPolicyQualifierId, policyOid)) 2208 ret = &policies->rgPolicyInfo[i].rgPolicyQualifier[j]. 2209 Qualifier; 2210 } 2211 return ret; 2212 } 2213 2214 static WCHAR *get_cps_str_from_qualifier(const CRYPT_OBJID_BLOB *qualifier) 2215 { 2216 LPWSTR qualifierStr = NULL; 2217 CERT_NAME_VALUE *qualifierValue; 2218 DWORD size; 2219 2220 if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME_VALUE, 2221 qualifier->pbData, qualifier->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, 2222 &qualifierValue, &size)) 2223 { 2224 size = CertRDNValueToStrW(qualifierValue->dwValueType, 2225 &qualifierValue->Value, NULL, 0); 2226 qualifierStr = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)); 2227 if (qualifierStr) 2228 CertRDNValueToStrW(qualifierValue->dwValueType, 2229 &qualifierValue->Value, qualifierStr, size); 2230 LocalFree(qualifierValue); 2231 } 2232 return qualifierStr; 2233 } 2234 2235 static WCHAR *get_user_notice_from_qualifier(const CRYPT_OBJID_BLOB *qualifier) 2236 { 2237 LPWSTR str = NULL; 2238 CERT_POLICY_QUALIFIER_USER_NOTICE *qualifierValue; 2239 DWORD size; 2240 2241 if (CryptDecodeObjectEx(X509_ASN_ENCODING, 2242 X509_PKIX_POLICY_QUALIFIER_USERNOTICE, 2243 qualifier->pbData, qualifier->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, 2244 &qualifierValue, &size)) 2245 { 2246 str = HeapAlloc(GetProcessHeap(), 0, 2247 (strlenW(qualifierValue->pszDisplayText) + 1) * sizeof(WCHAR)); 2248 if (str) 2249 strcpyW(str, qualifierValue->pszDisplayText); 2250 LocalFree(qualifierValue); 2251 } 2252 return str; 2253 } 2254 2255 struct IssuerStatement 2256 { 2257 LPWSTR cps; 2258 LPWSTR userNotice; 2259 }; 2260 2261 static void set_issuer_statement(HWND hwnd, 2262 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo) 2263 { 2264 PCERT_EXTENSION policyExt; 2265 2266 if (!(pCertViewInfo->dwFlags & CRYPTUI_DISABLE_ISSUERSTATEMENT) && 2267 (policyExt = CertFindExtension(szOID_CERT_POLICIES, 2268 pCertViewInfo->pCertContext->pCertInfo->cExtension, 2269 pCertViewInfo->pCertContext->pCertInfo->rgExtension))) 2270 { 2271 CERT_POLICIES_INFO *policies; 2272 DWORD size; 2273 2274 if (CryptDecodeObjectEx(X509_ASN_ENCODING, policyExt->pszObjId, 2275 policyExt->Value.pbData, policyExt->Value.cbData, 2276 CRYPT_DECODE_ALLOC_FLAG, NULL, &policies, &size)) 2277 { 2278 CRYPT_OBJID_BLOB *qualifier; 2279 LPWSTR cps = NULL, userNotice = NULL; 2280 2281 if ((qualifier = find_policy_qualifier(policies, 2282 szOID_PKIX_POLICY_QUALIFIER_CPS))) 2283 cps = get_cps_str_from_qualifier(qualifier); 2284 if ((qualifier = find_policy_qualifier(policies, 2285 szOID_PKIX_POLICY_QUALIFIER_USERNOTICE))) 2286 userNotice = get_user_notice_from_qualifier(qualifier); 2287 if (cps || userNotice) 2288 { 2289 struct IssuerStatement *issuerStatement = 2290 HeapAlloc(GetProcessHeap(), 0, sizeof(struct IssuerStatement)); 2291 2292 if (issuerStatement) 2293 { 2294 issuerStatement->cps = cps; 2295 issuerStatement->userNotice = userNotice; 2296 EnableWindow(GetDlgItem(hwnd, IDC_ISSUERSTATEMENT), TRUE); 2297 SetWindowLongPtrW(hwnd, DWLP_USER, 2298 (ULONG_PTR)issuerStatement); 2299 } 2300 } 2301 LocalFree(policies); 2302 } 2303 } 2304 } 2305 2306 static void set_cert_info(HWND hwnd, 2307 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo) 2308 { 2309 CHARFORMATW charFmt; 2310 PARAFORMAT2 parFmt; 2311 HWND icon = GetDlgItem(hwnd, IDC_CERTIFICATE_ICON); 2312 HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_INFO); 2313 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain( 2314 (CRYPT_PROVIDER_DATA *)pCertViewInfo->u.pCryptProviderData, 2315 pCertViewInfo->idxSigner, pCertViewInfo->fCounterSigner, 2316 pCertViewInfo->idxCounterSigner); 2317 CRYPT_PROVIDER_CERT *root = 2318 &provSigner->pasCertChain[provSigner->csCertChain - 1]; 2319 2320 if (!provSigner->pChainContext || 2321 (provSigner->pChainContext->TrustStatus.dwErrorStatus & 2322 CERT_TRUST_IS_PARTIAL_CHAIN)) 2323 add_icon_to_control(icon, IDB_CERT_WARNING); 2324 else if (!root->fTrustedRoot) 2325 add_icon_to_control(icon, IDB_CERT_ERROR); 2326 else 2327 add_icon_to_control(icon, IDB_CERT); 2328 2329 memset(&charFmt, 0, sizeof(charFmt)); 2330 charFmt.cbSize = sizeof(charFmt); 2331 charFmt.dwMask = CFM_BOLD; 2332 charFmt.dwEffects = CFE_BOLD; 2333 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt); 2334 /* FIXME: vertically center text */ 2335 parFmt.cbSize = sizeof(parFmt); 2336 parFmt.dwMask = PFM_STARTINDENT; 2337 parFmt.dxStartIndent = MY_INDENT; 2338 add_string_resource_with_paraformat_to_control(text, 2339 IDS_CERTIFICATEINFORMATION, &parFmt); 2340 2341 text = GetDlgItem(hwnd, IDC_CERTIFICATE_STATUS); 2342 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt); 2343 if (provSigner->dwError == TRUST_E_CERT_SIGNATURE) 2344 add_string_resource_with_paraformat_to_control(text, 2345 IDS_CERT_INFO_BAD_SIG, &parFmt); 2346 else if (!provSigner->pChainContext || 2347 (provSigner->pChainContext->TrustStatus.dwErrorStatus & 2348 CERT_TRUST_IS_PARTIAL_CHAIN)) 2349 add_string_resource_with_paraformat_to_control(text, 2350 IDS_CERT_INFO_PARTIAL_CHAIN, &parFmt); 2351 else if (!root->fTrustedRoot) 2352 { 2353 if (provSigner->csCertChain == 1 && root->fSelfSigned) 2354 add_string_resource_with_paraformat_to_control(text, 2355 IDS_CERT_INFO_UNTRUSTED_CA, &parFmt); 2356 else 2357 add_string_resource_with_paraformat_to_control(text, 2358 IDS_CERT_INFO_UNTRUSTED_ROOT, &parFmt); 2359 } 2360 else 2361 { 2362 set_policy_text(text, pCertViewInfo); 2363 set_issuer_statement(hwnd, pCertViewInfo); 2364 } 2365 } 2366 2367 static void set_cert_name_string(HWND hwnd, PCCERT_CONTEXT cert, 2368 DWORD nameFlags, int heading) 2369 { 2370 WCHAR nl = '\n'; 2371 HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_NAMES); 2372 CHARFORMATW charFmt; 2373 PARAFORMAT2 parFmt; 2374 2375 memset(&charFmt, 0, sizeof(charFmt)); 2376 charFmt.cbSize = sizeof(charFmt); 2377 charFmt.dwMask = CFM_BOLD; 2378 charFmt.dwEffects = CFE_BOLD; 2379 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt); 2380 parFmt.cbSize = sizeof(parFmt); 2381 parFmt.dwMask = PFM_STARTINDENT; 2382 parFmt.dxStartIndent = MY_INDENT * 3; 2383 add_string_resource_with_paraformat_to_control(text, heading, &parFmt); 2384 charFmt.dwEffects = 0; 2385 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt); 2386 add_cert_string_to_control(text, cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 2387 nameFlags); 2388 add_unformatted_text_to_control(text, &nl, 1); 2389 add_unformatted_text_to_control(text, &nl, 1); 2390 add_unformatted_text_to_control(text, &nl, 1); 2391 2392 } 2393 2394 static void add_date_string_to_control(HWND hwnd, const FILETIME *fileTime) 2395 { 2396 WCHAR dateFmt[80]; /* sufficient for all versions of LOCALE_SSHORTDATE */ 2397 WCHAR date[80]; 2398 SYSTEMTIME sysTime; 2399 2400 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SSHORTDATE, dateFmt, 2401 sizeof(dateFmt) / sizeof(dateFmt[0])); 2402 FileTimeToSystemTime(fileTime, &sysTime); 2403 GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, date, 2404 sizeof(date) / sizeof(date[0])); 2405 add_unformatted_text_to_control(hwnd, date, lstrlenW(date)); 2406 } 2407 2408 static void set_cert_validity_period(HWND hwnd, PCCERT_CONTEXT cert) 2409 { 2410 WCHAR nl = '\n'; 2411 HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_NAMES); 2412 CHARFORMATW charFmt; 2413 PARAFORMAT2 parFmt; 2414 2415 memset(&charFmt, 0, sizeof(charFmt)); 2416 charFmt.cbSize = sizeof(charFmt); 2417 charFmt.dwMask = CFM_BOLD; 2418 charFmt.dwEffects = CFE_BOLD; 2419 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt); 2420 parFmt.cbSize = sizeof(parFmt); 2421 parFmt.dwMask = PFM_STARTINDENT; 2422 parFmt.dxStartIndent = MY_INDENT * 3; 2423 add_string_resource_with_paraformat_to_control(text, IDS_VALID_FROM, 2424 &parFmt); 2425 charFmt.dwEffects = 0; 2426 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt); 2427 add_date_string_to_control(text, &cert->pCertInfo->NotBefore); 2428 charFmt.dwEffects = CFE_BOLD; 2429 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt); 2430 add_string_resource_to_control(text, IDS_VALID_TO); 2431 charFmt.dwEffects = 0; 2432 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt); 2433 add_date_string_to_control(text, &cert->pCertInfo->NotAfter); 2434 add_unformatted_text_to_control(text, &nl, 1); 2435 } 2436 2437 static void set_general_info(HWND hwnd, 2438 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo) 2439 { 2440 set_cert_info(hwnd, pCertViewInfo); 2441 set_cert_name_string(hwnd, pCertViewInfo->pCertContext, 0, 2442 IDS_SUBJECT_HEADING); 2443 set_cert_name_string(hwnd, pCertViewInfo->pCertContext, 2444 CERT_NAME_ISSUER_FLAG, IDS_ISSUER_HEADING); 2445 set_cert_validity_period(hwnd, pCertViewInfo->pCertContext); 2446 } 2447 2448 static LRESULT CALLBACK user_notice_dlg_proc(HWND hwnd, UINT msg, WPARAM wp, 2449 LPARAM lp) 2450 { 2451 LRESULT ret = 0; 2452 HWND text; 2453 struct IssuerStatement *issuerStatement; 2454 2455 switch (msg) 2456 { 2457 case WM_INITDIALOG: 2458 text = GetDlgItem(hwnd, IDC_USERNOTICE); 2459 issuerStatement = (struct IssuerStatement *)lp; 2460 add_unformatted_text_to_control(text, issuerStatement->userNotice, 2461 strlenW(issuerStatement->userNotice)); 2462 if (issuerStatement->cps) 2463 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)issuerStatement->cps); 2464 else 2465 EnableWindow(GetDlgItem(hwnd, IDC_CPS), FALSE); 2466 break; 2467 case WM_COMMAND: 2468 switch (wp) 2469 { 2470 case IDOK: 2471 EndDialog(hwnd, IDOK); 2472 ret = TRUE; 2473 break; 2474 case IDC_CPS: 2475 { 2476 IBindCtx *bctx = NULL; 2477 LPWSTR cps; 2478 2479 CreateBindCtx(0, &bctx); 2480 cps = (LPWSTR)GetWindowLongPtrW(hwnd, DWLP_USER); 2481 HlinkSimpleNavigateToString(cps, NULL, NULL, NULL, bctx, NULL, 2482 HLNF_OPENINNEWWINDOW, 0); 2483 IBindCtx_Release(bctx); 2484 break; 2485 } 2486 } 2487 } 2488 return ret; 2489 } 2490 2491 static void show_user_notice(HWND hwnd, struct IssuerStatement *issuerStatement) 2492 { 2493 DialogBoxParamW(hInstance, MAKEINTRESOURCEW(IDD_USERNOTICE), hwnd, 2494 user_notice_dlg_proc, (LPARAM)issuerStatement); 2495 } 2496 2497 static LRESULT CALLBACK general_dlg_proc(HWND hwnd, UINT msg, WPARAM wp, 2498 LPARAM lp) 2499 { 2500 PROPSHEETPAGEW *page; 2501 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo; 2502 2503 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp); 2504 2505 switch (msg) 2506 { 2507 case WM_INITDIALOG: 2508 page = (PROPSHEETPAGEW *)lp; 2509 pCertViewInfo = (PCCRYPTUI_VIEWCERTIFICATE_STRUCTW)page->lParam; 2510 if (pCertViewInfo->dwFlags & CRYPTUI_DISABLE_ADDTOSTORE) 2511 ShowWindow(GetDlgItem(hwnd, IDC_ADDTOSTORE), FALSE); 2512 EnableWindow(GetDlgItem(hwnd, IDC_ISSUERSTATEMENT), FALSE); 2513 set_general_info(hwnd, pCertViewInfo); 2514 break; 2515 case WM_COMMAND: 2516 switch (wp) 2517 { 2518 case IDC_ADDTOSTORE: 2519 CryptUIWizImport(0, hwnd, NULL, NULL, NULL); 2520 break; 2521 case IDC_ISSUERSTATEMENT: 2522 { 2523 struct IssuerStatement *issuerStatement = 2524 (struct IssuerStatement *)GetWindowLongPtrW(hwnd, DWLP_USER); 2525 2526 if (issuerStatement) 2527 { 2528 if (issuerStatement->userNotice) 2529 show_user_notice(hwnd, issuerStatement); 2530 else if (issuerStatement->cps) 2531 { 2532 IBindCtx *bctx = NULL; 2533 2534 CreateBindCtx(0, &bctx); 2535 HlinkSimpleNavigateToString(issuerStatement->cps, NULL, 2536 NULL, NULL, bctx, NULL, HLNF_OPENINNEWWINDOW, 0); 2537 IBindCtx_Release(bctx); 2538 } 2539 } 2540 break; 2541 } 2542 } 2543 break; 2544 } 2545 return 0; 2546 } 2547 2548 static UINT CALLBACK general_callback_proc(HWND hwnd, UINT msg, 2549 PROPSHEETPAGEW *page) 2550 { 2551 struct IssuerStatement *issuerStatement; 2552 2553 switch (msg) 2554 { 2555 case PSPCB_RELEASE: 2556 issuerStatement = 2557 (struct IssuerStatement *)GetWindowLongPtrW(hwnd, DWLP_USER); 2558 if (issuerStatement) 2559 { 2560 HeapFree(GetProcessHeap(), 0, issuerStatement->cps); 2561 HeapFree(GetProcessHeap(), 0, issuerStatement->userNotice); 2562 HeapFree(GetProcessHeap(), 0, issuerStatement); 2563 } 2564 break; 2565 } 2566 return 1; 2567 } 2568 2569 static void init_general_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo, 2570 PROPSHEETPAGEW *page) 2571 { 2572 memset(page, 0, sizeof(PROPSHEETPAGEW)); 2573 page->dwSize = sizeof(PROPSHEETPAGEW); 2574 page->dwFlags = PSP_USECALLBACK; 2575 page->pfnCallback = general_callback_proc; 2576 page->hInstance = hInstance; 2577 page->u.pszTemplate = MAKEINTRESOURCEW(IDD_GENERAL); 2578 page->pfnDlgProc = general_dlg_proc; 2579 page->lParam = (LPARAM)pCertViewInfo; 2580 } 2581 2582 typedef WCHAR * (*field_format_func)(PCCERT_CONTEXT cert); 2583 2584 static WCHAR *field_format_version(PCCERT_CONTEXT cert) 2585 { 2586 static const WCHAR fmt[] = { 'V','%','d',0 }; 2587 WCHAR *buf = HeapAlloc(GetProcessHeap(), 0, 12 * sizeof(WCHAR)); 2588 2589 if (buf) 2590 sprintfW(buf, fmt, cert->pCertInfo->dwVersion); 2591 return buf; 2592 } 2593 2594 static WCHAR *format_hex_string(void *pb, DWORD cb) 2595 { 2596 WCHAR *buf = HeapAlloc(GetProcessHeap(), 0, (cb * 3 + 1) * sizeof(WCHAR)); 2597 2598 if (buf) 2599 { 2600 static const WCHAR fmt[] = { '%','0','2','x',' ',0 }; 2601 DWORD i; 2602 WCHAR *ptr; 2603 2604 for (i = 0, ptr = buf; i < cb; i++, ptr += 3) 2605 sprintfW(ptr, fmt, ((BYTE *)pb)[i]); 2606 } 2607 return buf; 2608 } 2609 2610 static WCHAR *field_format_serial_number(PCCERT_CONTEXT cert) 2611 { 2612 return format_hex_string(cert->pCertInfo->SerialNumber.pbData, 2613 cert->pCertInfo->SerialNumber.cbData); 2614 } 2615 2616 static WCHAR *field_format_issuer(PCCERT_CONTEXT cert) 2617 { 2618 return get_cert_name_string(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 2619 CERT_NAME_ISSUER_FLAG); 2620 } 2621 2622 static WCHAR *field_format_detailed_cert_name(PCERT_NAME_BLOB name) 2623 { 2624 WCHAR *str = NULL; 2625 DWORD len = CertNameToStrW(X509_ASN_ENCODING, name, 2626 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, NULL, 0); 2627 2628 if (len) 2629 { 2630 str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 2631 if (str) 2632 CertNameToStrW(X509_ASN_ENCODING, name, 2633 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, str, len); 2634 } 2635 return str; 2636 } 2637 2638 static WCHAR *field_format_detailed_issuer(PCCERT_CONTEXT cert, void *param) 2639 { 2640 return field_format_detailed_cert_name(&cert->pCertInfo->Issuer); 2641 } 2642 2643 static WCHAR *field_format_subject(PCCERT_CONTEXT cert) 2644 { 2645 return get_cert_name_string(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0); 2646 } 2647 2648 static WCHAR *field_format_detailed_subject(PCCERT_CONTEXT cert, void *param) 2649 { 2650 return field_format_detailed_cert_name(&cert->pCertInfo->Subject); 2651 } 2652 2653 static WCHAR *format_long_date(const FILETIME *fileTime) 2654 { 2655 WCHAR dateFmt[80]; /* long enough for LOCALE_SLONGDATE */ 2656 DWORD len; 2657 WCHAR *buf = NULL; 2658 SYSTEMTIME sysTime; 2659 2660 /* FIXME: format isn't quite right, want time too */ 2661 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SLONGDATE, dateFmt, 2662 sizeof(dateFmt) / sizeof(dateFmt[0])); 2663 FileTimeToSystemTime(fileTime, &sysTime); 2664 len = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, NULL, 0); 2665 if (len) 2666 { 2667 buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 2668 if (buf) 2669 GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, buf, 2670 len); 2671 } 2672 return buf; 2673 } 2674 2675 static WCHAR *field_format_from_date(PCCERT_CONTEXT cert) 2676 { 2677 return format_long_date(&cert->pCertInfo->NotBefore); 2678 } 2679 2680 static WCHAR *field_format_to_date(PCCERT_CONTEXT cert) 2681 { 2682 return format_long_date(&cert->pCertInfo->NotAfter); 2683 } 2684 2685 static WCHAR *field_format_public_key(PCCERT_CONTEXT cert) 2686 { 2687 PCCRYPT_OID_INFO oidInfo; 2688 WCHAR *buf = NULL; 2689 2690 oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, 2691 cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, 0); 2692 if (oidInfo) 2693 { 2694 WCHAR fmt[MAX_STRING_LEN]; 2695 2696 if (LoadStringW(hInstance, IDS_FIELD_PUBLIC_KEY_FORMAT, fmt, 2697 sizeof(fmt) / sizeof(fmt[0]))) 2698 { 2699 DWORD len; 2700 2701 /* Allocate the output buffer. Use the number of bytes in the 2702 * public key as a conservative (high) estimate for the number of 2703 * digits in its output. 2704 * The output is of the form (in English) 2705 * "<public key algorithm> (<public key bit length> bits)". 2706 * Ordinarily having two positional parameters in a string is not a 2707 * good idea, but as this isn't a sentence fragment, it shouldn't 2708 * be word-order dependent. 2709 */ 2710 len = strlenW(fmt) + strlenW(oidInfo->pwszName) + 2711 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData * 8; 2712 buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(*buf)); 2713 if (buf) 2714 { 2715 DWORD_PTR args[2]; 2716 args[0] = (DWORD_PTR)oidInfo->pwszName; 2717 args[1] = CertGetPublicKeyLength(X509_ASN_ENCODING, 2718 &cert->pCertInfo->SubjectPublicKeyInfo); 2719 FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY, 2720 fmt, 0, 0, buf, len, (__ms_va_list*)args); 2721 } 2722 } 2723 } 2724 return buf; 2725 } 2726 2727 static WCHAR *field_format_detailed_public_key(PCCERT_CONTEXT cert, void *param) 2728 { 2729 return format_hex_string( 2730 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData, 2731 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData); 2732 } 2733 2734 struct field_value_data; 2735 struct detail_data 2736 { 2737 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo; 2738 BOOL *pfPropertiesChanged; 2739 int cFields; 2740 struct field_value_data *fields; 2741 }; 2742 2743 typedef void (*add_fields_func)(HWND hwnd, struct detail_data *data); 2744 2745 typedef WCHAR *(*create_detailed_value_func)(PCCERT_CONTEXT cert, void *param); 2746 2747 struct field_value_data 2748 { 2749 create_detailed_value_func create; 2750 LPWSTR detailed_value; 2751 void *param; 2752 }; 2753 2754 static void add_field_value_data(struct detail_data *data, 2755 create_detailed_value_func create, void *param) 2756 { 2757 if (data->cFields) 2758 data->fields = HeapReAlloc(GetProcessHeap(), 0, data->fields, 2759 (data->cFields + 1) * sizeof(struct field_value_data)); 2760 else 2761 data->fields = HeapAlloc(GetProcessHeap(), 0, 2762 sizeof(struct field_value_data)); 2763 if (data->fields) 2764 { 2765 data->fields[data->cFields].create = create; 2766 data->fields[data->cFields].detailed_value = NULL; 2767 data->fields[data->cFields].param = param; 2768 data->cFields++; 2769 } 2770 } 2771 2772 static void add_field_and_value_to_list(HWND hwnd, struct detail_data *data, 2773 LPWSTR field, LPWSTR value, create_detailed_value_func create, void *param) 2774 { 2775 LVITEMW item; 2776 int iItem = SendMessageW(hwnd, LVM_GETITEMCOUNT, 0, 0); 2777 2778 item.mask = LVIF_TEXT | LVIF_PARAM; 2779 item.iItem = iItem; 2780 item.iSubItem = 0; 2781 item.pszText = field; 2782 item.lParam = (LPARAM)data; 2783 SendMessageW(hwnd, LVM_INSERTITEMW, 0, (LPARAM)&item); 2784 if (value) 2785 { 2786 item.pszText = value; 2787 item.iSubItem = 1; 2788 SendMessageW(hwnd, LVM_SETITEMTEXTW, iItem, (LPARAM)&item); 2789 } 2790 add_field_value_data(data, create, param); 2791 } 2792 2793 static void add_string_id_and_value_to_list(HWND hwnd, struct detail_data *data, 2794 int id, LPWSTR value, create_detailed_value_func create, void *param) 2795 { 2796 WCHAR buf[MAX_STRING_LEN]; 2797 2798 LoadStringW(hInstance, id, buf, sizeof(buf) / sizeof(buf[0])); 2799 add_field_and_value_to_list(hwnd, data, buf, value, create, param); 2800 } 2801 2802 struct v1_field 2803 { 2804 int id; 2805 field_format_func format; 2806 create_detailed_value_func create_detailed_value; 2807 }; 2808 2809 static void add_v1_field(HWND hwnd, struct detail_data *data, 2810 const struct v1_field *field) 2811 { 2812 WCHAR *val = field->format(data->pCertViewInfo->pCertContext); 2813 2814 if (val) 2815 { 2816 add_string_id_and_value_to_list(hwnd, data, field->id, val, 2817 field->create_detailed_value, NULL); 2818 HeapFree(GetProcessHeap(), 0, val); 2819 } 2820 } 2821 2822 static const struct v1_field v1_fields[] = { 2823 { IDS_FIELD_VERSION, field_format_version, NULL }, 2824 { IDS_FIELD_SERIAL_NUMBER, field_format_serial_number, NULL }, 2825 { IDS_FIELD_ISSUER, field_format_issuer, field_format_detailed_issuer }, 2826 { IDS_FIELD_VALID_FROM, field_format_from_date, NULL }, 2827 { IDS_FIELD_VALID_TO, field_format_to_date, NULL }, 2828 { IDS_FIELD_SUBJECT, field_format_subject, field_format_detailed_subject }, 2829 { IDS_FIELD_PUBLIC_KEY, field_format_public_key, 2830 field_format_detailed_public_key } 2831 }; 2832 2833 static void add_v1_fields(HWND hwnd, struct detail_data *data) 2834 { 2835 unsigned int i; 2836 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext; 2837 2838 /* The last item in v1_fields is the public key, which is not in the loop 2839 * because it's a special case. 2840 */ 2841 for (i = 0; i < sizeof(v1_fields) / sizeof(v1_fields[0]) - 1; i++) 2842 add_v1_field(hwnd, data, &v1_fields[i]); 2843 if (cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData) 2844 add_v1_field(hwnd, data, &v1_fields[i]); 2845 } 2846 2847 static WCHAR *crypt_format_extension(const CERT_EXTENSION *ext, DWORD formatStrType) 2848 { 2849 WCHAR *str = NULL; 2850 DWORD size; 2851 2852 if (CryptFormatObject(X509_ASN_ENCODING, 0, formatStrType, NULL, 2853 ext->pszObjId, ext->Value.pbData, ext->Value.cbData, NULL, &size)) 2854 { 2855 str = HeapAlloc(GetProcessHeap(), 0, size); 2856 CryptFormatObject(X509_ASN_ENCODING, 0, formatStrType, NULL, 2857 ext->pszObjId, ext->Value.pbData, ext->Value.cbData, str, &size); 2858 } 2859 return str; 2860 } 2861 2862 static WCHAR *field_format_extension_hex_with_ascii(const CERT_EXTENSION *ext) 2863 { 2864 WCHAR *str = NULL; 2865 2866 if (ext->Value.cbData) 2867 { 2868 /* The output is formatted as: 2869 * <hex bytes> <ascii bytes>\n 2870 * where <hex bytes> is a string of up to 8 bytes, output as %02x, 2871 * and <ascii bytes> is the ASCII equivalent of each byte, or '.' if 2872 * the byte is not printable. 2873 * So, for example, the extension value consisting of the following 2874 * bytes: 2875 * 0x30,0x14,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x03, 2876 * 0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67 2877 * is output as: 2878 * 30 14 31 12 30 10 06 03 0.1.0... 2879 * 55 04 03 13 09 4a 75 61 U....Jua 2880 * 6e 20 4c 61 6e 67 n Lang 2881 * The allocation size therefore requires: 2882 * - 4 characters per character in an 8-byte line 2883 * (2 for the hex format, one for the space, one for the ASCII value) 2884 * - 3 more characters per 8-byte line (two spaces and a newline) 2885 * - 1 character for the terminating nul 2886 * FIXME: should use a fixed-width font for this 2887 */ 2888 DWORD lines = (ext->Value.cbData + 7) / 8; 2889 2890 str = HeapAlloc(GetProcessHeap(), 0, 2891 (lines * 8 * 4 + lines * 3 + 1) * sizeof(WCHAR)); 2892 if (str) 2893 { 2894 static const WCHAR fmt[] = { '%','0','2','x',' ',0 }; 2895 DWORD i, j; 2896 WCHAR *ptr; 2897 2898 for (i = 0, ptr = str; i < ext->Value.cbData; i += 8) 2899 { 2900 /* Output as hex bytes first */ 2901 for (j = i; j < min(i + 8, ext->Value.cbData); j++, ptr += 3) 2902 sprintfW(ptr, fmt, ext->Value.pbData[j]); 2903 /* Pad the hex output with spaces for alignment */ 2904 if (j == ext->Value.cbData && j % 8) 2905 { 2906 static const WCHAR pad[] = { ' ',' ',' ' }; 2907 2908 for (; j % 8; j++, ptr += sizeof(pad) / sizeof(pad[0])) 2909 memcpy(ptr, pad, sizeof(pad)); 2910 } 2911 /* The last sprintfW included a space, so just insert one 2912 * more space between the hex bytes and the ASCII output 2913 */ 2914 *ptr++ = ' '; 2915 /* Output as ASCII bytes */ 2916 for (j = i; j < min(i + 8, ext->Value.cbData); j++, ptr++) 2917 { 2918 if (isprintW(ext->Value.pbData[j]) && 2919 !isspaceW(ext->Value.pbData[j])) 2920 *ptr = ext->Value.pbData[j]; 2921 else 2922 *ptr = '.'; 2923 } 2924 *ptr++ = '\n'; 2925 } 2926 *ptr++ = '\0'; 2927 } 2928 } 2929 return str; 2930 } 2931 2932 static WCHAR *field_format_detailed_extension(PCCERT_CONTEXT cert, void *param) 2933 { 2934 PCERT_EXTENSION ext = param; 2935 LPWSTR str = crypt_format_extension(ext, 2936 CRYPT_FORMAT_STR_MULTI_LINE | CRYPT_FORMAT_STR_NO_HEX); 2937 2938 if (!str) 2939 str = field_format_extension_hex_with_ascii(ext); 2940 return str; 2941 } 2942 2943 static void add_cert_extension_detail(HWND hwnd, struct detail_data *data, 2944 PCERT_EXTENSION ext) 2945 { 2946 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, 2947 ext->pszObjId, 0); 2948 LPWSTR val = crypt_format_extension(ext, 0); 2949 2950 if (oidInfo) 2951 add_field_and_value_to_list(hwnd, data, (LPWSTR)oidInfo->pwszName, 2952 val, field_format_detailed_extension, ext); 2953 else 2954 { 2955 DWORD len = strlen(ext->pszObjId); 2956 LPWSTR oidW = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); 2957 2958 if (oidW) 2959 { 2960 DWORD i; 2961 2962 for (i = 0; i <= len; i++) 2963 oidW[i] = ext->pszObjId[i]; 2964 add_field_and_value_to_list(hwnd, data, oidW, val, 2965 field_format_detailed_extension, ext); 2966 HeapFree(GetProcessHeap(), 0, oidW); 2967 } 2968 } 2969 HeapFree(GetProcessHeap(), 0, val); 2970 } 2971 2972 static void add_all_extensions(HWND hwnd, struct detail_data *data) 2973 { 2974 DWORD i; 2975 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext; 2976 2977 for (i = 0; i < cert->pCertInfo->cExtension; i++) 2978 add_cert_extension_detail(hwnd, data, &cert->pCertInfo->rgExtension[i]); 2979 } 2980 2981 static void add_critical_extensions(HWND hwnd, struct detail_data *data) 2982 { 2983 DWORD i; 2984 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext; 2985 2986 for (i = 0; i < cert->pCertInfo->cExtension; i++) 2987 if (cert->pCertInfo->rgExtension[i].fCritical) 2988 add_cert_extension_detail(hwnd, data, 2989 &cert->pCertInfo->rgExtension[i]); 2990 } 2991 2992 typedef WCHAR * (*prop_to_value_func)(void *pb, DWORD cb); 2993 2994 struct prop_id_to_string_id 2995 { 2996 DWORD prop; 2997 int id; 2998 BOOL prop_is_string; 2999 prop_to_value_func prop_to_value; 3000 }; 3001 3002 static WCHAR *format_enhanced_key_usage_value(void *pb, DWORD cb) 3003 { 3004 CERT_EXTENSION ext; 3005 3006 ext.pszObjId = (LPSTR)X509_ENHANCED_KEY_USAGE; 3007 ext.fCritical = FALSE; 3008 ext.Value.pbData = pb; 3009 ext.Value.cbData = cb; 3010 return crypt_format_extension(&ext, 0); 3011 } 3012 3013 /* Logically the access state should also be checked, and IDC_EDITPROPERTIES 3014 * disabled for read-only certificates, but native doesn't appear to do that. 3015 */ 3016 static const struct prop_id_to_string_id prop_id_map[] = { 3017 { CERT_HASH_PROP_ID, IDS_PROP_HASH, FALSE, format_hex_string }, 3018 { CERT_FRIENDLY_NAME_PROP_ID, IDS_PROP_FRIENDLY_NAME, TRUE, NULL }, 3019 { CERT_DESCRIPTION_PROP_ID, IDS_PROP_DESCRIPTION, TRUE, NULL }, 3020 { CERT_ENHKEY_USAGE_PROP_ID, IDS_PROP_ENHKEY_USAGE, FALSE, 3021 format_enhanced_key_usage_value }, 3022 }; 3023 3024 static void add_properties(HWND hwnd, struct detail_data *data) 3025 { 3026 DWORD i; 3027 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext; 3028 3029 for (i = 0; i < sizeof(prop_id_map) / sizeof(prop_id_map[0]); i++) 3030 { 3031 DWORD cb; 3032 3033 if (CertGetCertificateContextProperty(cert, prop_id_map[i].prop, NULL, 3034 &cb)) 3035 { 3036 BYTE *pb; 3037 WCHAR *val = NULL; 3038 3039 /* FIXME: MS adds a separate value for the signature hash 3040 * algorithm. 3041 */ 3042 pb = HeapAlloc(GetProcessHeap(), 0, cb); 3043 if (pb) 3044 { 3045 if (CertGetCertificateContextProperty(cert, 3046 prop_id_map[i].prop, pb, &cb)) 3047 { 3048 if (prop_id_map[i].prop_is_string) 3049 { 3050 val = (LPWSTR)pb; 3051 /* Don't double-free pb */ 3052 pb = NULL; 3053 } 3054 else 3055 val = prop_id_map[i].prop_to_value(pb, cb); 3056 } 3057 HeapFree(GetProcessHeap(), 0, pb); 3058 } 3059 add_string_id_and_value_to_list(hwnd, data, prop_id_map[i].id, val, 3060 NULL, NULL); 3061 } 3062 } 3063 } 3064 3065 static void add_all_fields(HWND hwnd, struct detail_data *data) 3066 { 3067 add_v1_fields(hwnd, data); 3068 add_all_extensions(hwnd, data); 3069 add_properties(hwnd, data); 3070 } 3071 3072 struct selection_list_item 3073 { 3074 int id; 3075 add_fields_func add; 3076 }; 3077 3078 static const struct selection_list_item listItems[] = { 3079 { IDS_FIELDS_ALL, add_all_fields }, 3080 { IDS_FIELDS_V1, add_v1_fields }, 3081 { IDS_FIELDS_EXTENSIONS, add_all_extensions }, 3082 { IDS_FIELDS_CRITICAL_EXTENSIONS, add_critical_extensions }, 3083 { IDS_FIELDS_PROPERTIES, add_properties }, 3084 }; 3085 3086 static void create_show_list(HWND hwnd, struct detail_data *data) 3087 { 3088 HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT); 3089 WCHAR buf[MAX_STRING_LEN]; 3090 int i; 3091 3092 for (i = 0; i < sizeof(listItems) / sizeof(listItems[0]); i++) 3093 { 3094 int index; 3095 3096 LoadStringW(hInstance, listItems[i].id, buf, 3097 sizeof(buf) / sizeof(buf[0])); 3098 index = SendMessageW(cb, CB_INSERTSTRING, -1, (LPARAM)buf); 3099 SendMessageW(cb, CB_SETITEMDATA, index, (LPARAM)data); 3100 } 3101 SendMessageW(cb, CB_SETCURSEL, 0, 0); 3102 } 3103 3104 static void create_listview_columns(HWND hwnd) 3105 { 3106 HWND lv = GetDlgItem(hwnd, IDC_DETAIL_LIST); 3107 RECT rc; 3108 WCHAR buf[MAX_STRING_LEN]; 3109 LVCOLUMNW column; 3110 3111 SendMessageW(lv, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT); 3112 GetWindowRect(lv, &rc); 3113 LoadStringW(hInstance, IDS_FIELD, buf, sizeof(buf) / sizeof(buf[0])); 3114 column.mask = LVCF_WIDTH | LVCF_TEXT; 3115 column.cx = (rc.right - rc.left) / 2 - 2; 3116 column.pszText = buf; 3117 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column); 3118 LoadStringW(hInstance, IDS_VALUE, buf, sizeof(buf) / sizeof(buf[0])); 3119 SendMessageW(lv, LVM_INSERTCOLUMNW, 1, (LPARAM)&column); 3120 } 3121 3122 static void set_fields_selection(HWND hwnd, struct detail_data *data, int sel) 3123 { 3124 HWND list = GetDlgItem(hwnd, IDC_DETAIL_LIST); 3125 3126 if (sel >= 0 && sel < sizeof(listItems) / sizeof(listItems[0])) 3127 { 3128 SendMessageW(list, LVM_DELETEALLITEMS, 0, 0); 3129 listItems[sel].add(list, data); 3130 } 3131 } 3132 3133 static void create_cert_details_list(HWND hwnd, struct detail_data *data) 3134 { 3135 create_show_list(hwnd, data); 3136 create_listview_columns(hwnd); 3137 set_fields_selection(hwnd, data, 0); 3138 } 3139 3140 static void add_purpose(HWND hwnd, LPCSTR oid) 3141 { 3142 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES); 3143 PCRYPT_OID_INFO info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 3144 sizeof(CRYPT_OID_INFO)); 3145 3146 if (info) 3147 { 3148 char *oidCopy = HeapAlloc(GetProcessHeap(), 0, strlen(oid) + 1); 3149 3150 if (oidCopy) 3151 { 3152 LVITEMA item; 3153 3154 strcpy(oidCopy, oid); 3155 info->cbSize = sizeof(CRYPT_OID_INFO); 3156 info->pszOID = oidCopy; 3157 item.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM; 3158 item.state = INDEXTOSTATEIMAGEMASK(CheckBitmapIndexChecked); 3159 item.stateMask = LVIS_STATEIMAGEMASK; 3160 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0); 3161 item.iSubItem = 0; 3162 item.lParam = (LPARAM)info; 3163 item.pszText = oidCopy; 3164 SendMessageA(lv, LVM_INSERTITEMA, 0, (LPARAM)&item); 3165 } 3166 else 3167 HeapFree(GetProcessHeap(), 0, info); 3168 } 3169 } 3170 3171 static BOOL is_valid_oid(LPCSTR oid) 3172 { 3173 BOOL ret; 3174 3175 if (oid[0] != '0' && oid[0] != '1' && oid[0] != '2') 3176 ret = FALSE; 3177 else if (oid[1] != '.') 3178 ret = FALSE; 3179 else if (!oid[2]) 3180 ret = FALSE; 3181 else 3182 { 3183 const char *ptr; 3184 BOOL expectNum = TRUE; 3185 3186 for (ptr = oid + 2, ret = TRUE; ret && *ptr; ptr++) 3187 { 3188 if (expectNum) 3189 { 3190 if (!isdigit(*ptr)) 3191 ret = FALSE; 3192 else if (*(ptr + 1) == '.') 3193 expectNum = FALSE; 3194 } 3195 else 3196 { 3197 if (*ptr != '.') 3198 ret = FALSE; 3199 else if (!(*(ptr + 1))) 3200 ret = FALSE; 3201 else 3202 expectNum = TRUE; 3203 } 3204 } 3205 } 3206 return ret; 3207 } 3208 3209 static BOOL is_oid_in_list(HWND hwnd, LPCSTR oid) 3210 { 3211 return find_oid_in_list(GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES), oid) 3212 != -1; 3213 } 3214 3215 #define MAX_PURPOSE 255 3216 3217 static LRESULT CALLBACK add_purpose_dlg_proc(HWND hwnd, UINT msg, 3218 WPARAM wp, LPARAM lp) 3219 { 3220 LRESULT ret = 0; 3221 char buf[MAX_PURPOSE + 1]; 3222 3223 switch (msg) 3224 { 3225 case WM_INITDIALOG: 3226 SendMessageW(GetDlgItem(hwnd, IDC_NEW_PURPOSE), EM_SETLIMITTEXT, 3227 MAX_PURPOSE, 0); 3228 ShowScrollBar(GetDlgItem(hwnd, IDC_NEW_PURPOSE), SB_VERT, FALSE); 3229 SetWindowLongPtrW(hwnd, DWLP_USER, lp); 3230 break; 3231 case WM_COMMAND: 3232 switch (HIWORD(wp)) 3233 { 3234 case EN_CHANGE: 3235 if (LOWORD(wp) == IDC_NEW_PURPOSE) 3236 { 3237 /* Show/hide scroll bar on description depending on how much 3238 * text it has. 3239 */ 3240 HWND description = GetDlgItem(hwnd, IDC_NEW_PURPOSE); 3241 int lines = SendMessageW(description, EM_GETLINECOUNT, 0, 0); 3242 3243 ShowScrollBar(description, SB_VERT, lines > 1); 3244 } 3245 break; 3246 case BN_CLICKED: 3247 switch (LOWORD(wp)) 3248 { 3249 case IDOK: 3250 SendMessageA(GetDlgItem(hwnd, IDC_NEW_PURPOSE), WM_GETTEXT, 3251 sizeof(buf) / sizeof(buf[0]), (LPARAM)buf); 3252 if (!buf[0]) 3253 { 3254 /* An empty purpose is the same as cancelling */ 3255 EndDialog(hwnd, IDCANCEL); 3256 ret = TRUE; 3257 } 3258 else if (!is_valid_oid(buf)) 3259 { 3260 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN]; 3261 3262 LoadStringW(hInstance, IDS_CERTIFICATE_PURPOSE_ERROR, error, 3263 sizeof(error) / sizeof(error[0])); 3264 LoadStringW(hInstance, IDS_CERTIFICATE_PROPERTIES, title, 3265 sizeof(title) / sizeof(title[0])); 3266 MessageBoxW(hwnd, error, title, MB_ICONERROR | MB_OK); 3267 } 3268 else if (is_oid_in_list( 3269 (HWND)GetWindowLongPtrW(hwnd, DWLP_USER), buf)) 3270 { 3271 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN]; 3272 3273 LoadStringW(hInstance, IDS_CERTIFICATE_PURPOSE_EXISTS, 3274 error, sizeof(error) / sizeof(error[0])); 3275 LoadStringW(hInstance, IDS_CERTIFICATE_PROPERTIES, title, 3276 sizeof(title) / sizeof(title[0])); 3277 MessageBoxW(hwnd, error, title, MB_ICONEXCLAMATION | MB_OK); 3278 } 3279 else 3280 { 3281 HWND parent = (HWND)GetWindowLongPtrW(hwnd, DWLP_USER); 3282 3283 add_purpose(parent, buf); 3284 EndDialog(hwnd, wp); 3285 ret = TRUE; 3286 } 3287 break; 3288 case IDCANCEL: 3289 EndDialog(hwnd, wp); 3290 ret = TRUE; 3291 break; 3292 } 3293 break; 3294 } 3295 break; 3296 } 3297 return ret; 3298 } 3299 3300 static WCHAR *get_cert_property_as_string(PCCERT_CONTEXT cert, DWORD prop) 3301 { 3302 WCHAR *name = NULL; 3303 DWORD cb; 3304 3305 if (CertGetCertificateContextProperty(cert, prop, NULL, &cb)) 3306 { 3307 name = HeapAlloc(GetProcessHeap(), 0, cb); 3308 if (name) 3309 { 3310 if (!CertGetCertificateContextProperty(cert, prop, name, &cb)) 3311 { 3312 HeapFree(GetProcessHeap(), 0, name); 3313 name = NULL; 3314 } 3315 } 3316 } 3317 return name; 3318 } 3319 3320 static void redraw_states(HWND list, BOOL enabled) 3321 { 3322 int items = SendMessageW(list, LVM_GETITEMCOUNT, 0, 0), i; 3323 3324 for (i = 0; i < items; i++) 3325 { 3326 BOOL change = FALSE; 3327 int state; 3328 3329 state = SendMessageW(list, LVM_GETITEMSTATE, i, LVIS_STATEIMAGEMASK); 3330 /* This reverses the INDEXTOSTATEIMAGEMASK shift. There doesn't appear 3331 * to be a handy macro for it. 3332 */ 3333 state >>= 12; 3334 if (enabled) 3335 { 3336 if (state == CheckBitmapIndexDisabledChecked) 3337 { 3338 state = CheckBitmapIndexChecked; 3339 change = TRUE; 3340 } 3341 if (state == CheckBitmapIndexDisabledUnchecked) 3342 { 3343 state = CheckBitmapIndexUnchecked; 3344 change = TRUE; 3345 } 3346 } 3347 else 3348 { 3349 if (state == CheckBitmapIndexChecked) 3350 { 3351 state = CheckBitmapIndexDisabledChecked; 3352 change = TRUE; 3353 } 3354 if (state == CheckBitmapIndexUnchecked) 3355 { 3356 state = CheckBitmapIndexDisabledUnchecked; 3357 change = TRUE; 3358 } 3359 } 3360 if (change) 3361 { 3362 LVITEMW item; 3363 3364 item.state = INDEXTOSTATEIMAGEMASK(state); 3365 item.stateMask = LVIS_STATEIMAGEMASK; 3366 SendMessageW(list, LVM_SETITEMSTATE, i, (LPARAM)&item); 3367 } 3368 } 3369 } 3370 3371 typedef enum { 3372 PurposeEnableAll = 0, 3373 PurposeDisableAll, 3374 PurposeEnableSelected 3375 } PurposeSelection; 3376 3377 static void select_purposes(HWND hwnd, PurposeSelection selection) 3378 { 3379 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES); 3380 3381 switch (selection) 3382 { 3383 case PurposeEnableAll: 3384 case PurposeDisableAll: 3385 EnableWindow(lv, FALSE); 3386 redraw_states(lv, FALSE); 3387 EnableWindow(GetDlgItem(hwnd, IDC_ADD_PURPOSE), FALSE); 3388 break; 3389 case PurposeEnableSelected: 3390 EnableWindow(lv, TRUE); 3391 redraw_states(lv, TRUE); 3392 EnableWindow(GetDlgItem(hwnd, IDC_ADD_PURPOSE), TRUE); 3393 } 3394 } 3395 3396 struct edit_cert_data 3397 { 3398 PCCERT_CONTEXT cert; 3399 BOOL *pfPropertiesChanged; 3400 HIMAGELIST imageList; 3401 }; 3402 3403 static void show_cert_usages(HWND hwnd, struct edit_cert_data *data) 3404 { 3405 PCCERT_CONTEXT cert = data->cert; 3406 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES); 3407 PCERT_ENHKEY_USAGE usage; 3408 DWORD size; 3409 RECT rc; 3410 LVCOLUMNW column; 3411 PurposeSelection purposeSelection = PurposeEnableAll; 3412 3413 GetWindowRect(lv, &rc); 3414 column.mask = LVCF_WIDTH; 3415 column.cx = rc.right - rc.left; 3416 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column); 3417 SendMessageW(lv, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)data->imageList); 3418 3419 /* Get enhanced key usage. Have to check for a property and an extension 3420 * separately, because CertGetEnhancedKeyUsage will succeed and return an 3421 * empty usage if neither is set. Unfortunately an empty usage implies 3422 * no usage is allowed, so we have to distinguish between the two cases. 3423 */ 3424 if (CertGetEnhancedKeyUsage(cert, CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, 3425 NULL, &size)) 3426 { 3427 usage = HeapAlloc(GetProcessHeap(), 0, size); 3428 if (!CertGetEnhancedKeyUsage(cert, 3429 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size)) 3430 { 3431 HeapFree(GetProcessHeap(), 0, usage); 3432 usage = NULL; 3433 } 3434 else if (usage->cUsageIdentifier) 3435 purposeSelection = PurposeEnableSelected; 3436 else 3437 purposeSelection = PurposeDisableAll; 3438 } 3439 else if (CertGetEnhancedKeyUsage(cert, CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, 3440 NULL, &size)) 3441 { 3442 usage = HeapAlloc(GetProcessHeap(), 0, size); 3443 if (!CertGetEnhancedKeyUsage(cert, 3444 CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, usage, &size)) 3445 { 3446 HeapFree(GetProcessHeap(), 0, usage); 3447 usage = NULL; 3448 } 3449 else if (usage->cUsageIdentifier) 3450 purposeSelection = PurposeEnableAll; 3451 else 3452 purposeSelection = PurposeDisableAll; 3453 } 3454 else 3455 { 3456 purposeSelection = PurposeEnableAll; 3457 usage = NULL; 3458 } 3459 if (usage) 3460 { 3461 DWORD i; 3462 3463 for (i = 0; i < usage->cUsageIdentifier; i++) 3464 { 3465 PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, 3466 usage->rgpszUsageIdentifier[i], CRYPT_ENHKEY_USAGE_OID_GROUP_ID); 3467 3468 if (info) 3469 add_known_usage(lv, info, CheckBitmapIndexDisabledChecked); 3470 else 3471 add_purpose(hwnd, usage->rgpszUsageIdentifier[i]); 3472 } 3473 HeapFree(GetProcessHeap(), 0, usage); 3474 } 3475 else 3476 add_known_usages_to_list(lv, CheckBitmapIndexDisabledChecked); 3477 select_purposes(hwnd, purposeSelection); 3478 SendMessageW(GetDlgItem(hwnd, IDC_ENABLE_ALL_PURPOSES + purposeSelection), 3479 BM_CLICK, 0, 0); 3480 } 3481 3482 static void set_general_cert_properties(HWND hwnd, struct edit_cert_data *data) 3483 { 3484 PCCERT_CONTEXT cert = data->cert; 3485 WCHAR *str; 3486 3487 if ((str = get_cert_property_as_string(cert, CERT_FRIENDLY_NAME_PROP_ID))) 3488 { 3489 SendMessageW(GetDlgItem(hwnd, IDC_FRIENDLY_NAME), WM_SETTEXT, 0, 3490 (LPARAM)str); 3491 HeapFree(GetProcessHeap(), 0, str); 3492 } 3493 if ((str = get_cert_property_as_string(cert, CERT_DESCRIPTION_PROP_ID))) 3494 { 3495 SendMessageW(GetDlgItem(hwnd, IDC_DESCRIPTION), WM_SETTEXT, 0, 3496 (LPARAM)str); 3497 HeapFree(GetProcessHeap(), 0, str); 3498 } 3499 show_cert_usages(hwnd, data); 3500 } 3501 3502 static void set_cert_string_property(PCCERT_CONTEXT cert, DWORD prop, 3503 LPWSTR str) 3504 { 3505 if (str && strlenW(str)) 3506 { 3507 CRYPT_DATA_BLOB blob; 3508 3509 blob.pbData = (BYTE *)str; 3510 blob.cbData = (strlenW(str) + 1) * sizeof(WCHAR); 3511 CertSetCertificateContextProperty(cert, prop, 0, &blob); 3512 } 3513 else 3514 CertSetCertificateContextProperty(cert, prop, 0, NULL); 3515 } 3516 3517 #define WM_REFRESH_VIEW WM_USER + 0 3518 3519 static BOOL CALLBACK refresh_propsheet_pages(HWND hwnd, LPARAM lParam) 3520 { 3521 if ((GetClassLongW(hwnd, GCW_ATOM) == WC_DIALOG)) 3522 SendMessageW(hwnd, WM_REFRESH_VIEW, 0, 0); 3523 return TRUE; 3524 } 3525 3526 #define MAX_FRIENDLY_NAME 40 3527 #define MAX_DESCRIPTION 255 3528 3529 static void apply_general_changes(HWND hwnd) 3530 { 3531 WCHAR buf[MAX_DESCRIPTION + 1]; 3532 struct edit_cert_data *data = 3533 (struct edit_cert_data *)GetWindowLongPtrW(hwnd, DWLP_USER); 3534 3535 SendMessageW(GetDlgItem(hwnd, IDC_FRIENDLY_NAME), WM_GETTEXT, 3536 sizeof(buf) / sizeof(buf[0]), (LPARAM)buf); 3537 set_cert_string_property(data->cert, CERT_FRIENDLY_NAME_PROP_ID, buf); 3538 SendMessageW(GetDlgItem(hwnd, IDC_DESCRIPTION), WM_GETTEXT, 3539 sizeof(buf) / sizeof(buf[0]), (LPARAM)buf); 3540 set_cert_string_property(data->cert, CERT_DESCRIPTION_PROP_ID, buf); 3541 if (IsDlgButtonChecked(hwnd, IDC_ENABLE_ALL_PURPOSES)) 3542 { 3543 /* Setting a NULL usage removes the enhanced key usage property. */ 3544 CertSetEnhancedKeyUsage(data->cert, NULL); 3545 } 3546 else if (IsDlgButtonChecked(hwnd, IDC_DISABLE_ALL_PURPOSES)) 3547 { 3548 CERT_ENHKEY_USAGE usage = { 0, NULL }; 3549 3550 CertSetEnhancedKeyUsage(data->cert, &usage); 3551 } 3552 else if (IsDlgButtonChecked(hwnd, IDC_ENABLE_SELECTED_PURPOSES)) 3553 { 3554 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES); 3555 CERT_ENHKEY_USAGE usage = { 0, NULL }; 3556 int purposes = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0), i; 3557 LVITEMW item; 3558 3559 item.mask = LVIF_STATE | LVIF_PARAM; 3560 item.iSubItem = 0; 3561 item.stateMask = LVIS_STATEIMAGEMASK; 3562 for (i = 0; i < purposes; i++) 3563 { 3564 item.iItem = i; 3565 if (SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item)) 3566 { 3567 int state = item.state >> 12; 3568 3569 if (state == CheckBitmapIndexChecked) 3570 { 3571 CRYPT_OID_INFO *info = (CRYPT_OID_INFO *)item.lParam; 3572 3573 if (usage.cUsageIdentifier) 3574 usage.rgpszUsageIdentifier = 3575 HeapReAlloc(GetProcessHeap(), 0, 3576 usage.rgpszUsageIdentifier, 3577 (usage.cUsageIdentifier + 1) * sizeof(LPSTR)); 3578 else 3579 usage.rgpszUsageIdentifier = 3580 HeapAlloc(GetProcessHeap(), 0, sizeof(LPSTR)); 3581 if (usage.rgpszUsageIdentifier) 3582 usage.rgpszUsageIdentifier[usage.cUsageIdentifier++] = 3583 (LPSTR)info->pszOID; 3584 } 3585 } 3586 } 3587 CertSetEnhancedKeyUsage(data->cert, &usage); 3588 HeapFree(GetProcessHeap(), 0, usage.rgpszUsageIdentifier); 3589 } 3590 EnumChildWindows(GetParent(GetParent(hwnd)), refresh_propsheet_pages, 0); 3591 if (data->pfPropertiesChanged) 3592 *data->pfPropertiesChanged = TRUE; 3593 } 3594 3595 static LRESULT CALLBACK cert_properties_general_dlg_proc(HWND hwnd, UINT msg, 3596 WPARAM wp, LPARAM lp) 3597 { 3598 PROPSHEETPAGEW *page; 3599 3600 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp); 3601 3602 switch (msg) 3603 { 3604 case WM_INITDIALOG: 3605 { 3606 HWND description = GetDlgItem(hwnd, IDC_DESCRIPTION); 3607 struct detail_data *detailData; 3608 struct edit_cert_data *editData; 3609 3610 page = (PROPSHEETPAGEW *)lp; 3611 detailData = (struct detail_data *)page->lParam; 3612 SendMessageW(GetDlgItem(hwnd, IDC_FRIENDLY_NAME), EM_SETLIMITTEXT, 3613 MAX_FRIENDLY_NAME, 0); 3614 SendMessageW(description, EM_SETLIMITTEXT, MAX_DESCRIPTION, 0); 3615 ShowScrollBar(description, SB_VERT, FALSE); 3616 editData = HeapAlloc(GetProcessHeap(), 0, 3617 sizeof(struct edit_cert_data)); 3618 if (editData) 3619 { 3620 editData->imageList = ImageList_Create(16, 16, 3621 ILC_COLOR4 | ILC_MASK, 4, 0); 3622 if (editData->imageList) 3623 { 3624 HBITMAP bmp; 3625 COLORREF backColor = RGB(255, 0, 255); 3626 3627 bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_CHECKS)); 3628 ImageList_AddMasked(editData->imageList, bmp, backColor); 3629 DeleteObject(bmp); 3630 ImageList_SetBkColor(editData->imageList, CLR_NONE); 3631 } 3632 editData->cert = detailData->pCertViewInfo->pCertContext; 3633 editData->pfPropertiesChanged = detailData->pfPropertiesChanged; 3634 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)editData); 3635 set_general_cert_properties(hwnd, editData); 3636 } 3637 break; 3638 } 3639 case WM_NOTIFY: 3640 { 3641 NMHDR *hdr = (NMHDR *)lp; 3642 NMITEMACTIVATE *nm; 3643 3644 switch (hdr->code) 3645 { 3646 case NM_CLICK: 3647 nm = (NMITEMACTIVATE *)lp; 3648 toggle_usage(hwnd, nm->iItem); 3649 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0); 3650 break; 3651 case PSN_APPLY: 3652 apply_general_changes(hwnd); 3653 break; 3654 } 3655 break; 3656 } 3657 case WM_COMMAND: 3658 switch (HIWORD(wp)) 3659 { 3660 case EN_CHANGE: 3661 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0); 3662 if (LOWORD(wp) == IDC_DESCRIPTION) 3663 { 3664 /* Show/hide scroll bar on description depending on how much 3665 * text it has. 3666 */ 3667 HWND description = GetDlgItem(hwnd, IDC_DESCRIPTION); 3668 int lines = SendMessageW(description, EM_GETLINECOUNT, 0, 0); 3669 3670 ShowScrollBar(description, SB_VERT, lines > 1); 3671 } 3672 break; 3673 case BN_CLICKED: 3674 switch (LOWORD(wp)) 3675 { 3676 case IDC_ADD_PURPOSE: 3677 if (DialogBoxParamW(hInstance, 3678 MAKEINTRESOURCEW(IDD_ADD_CERT_PURPOSE), hwnd, 3679 add_purpose_dlg_proc, (LPARAM)hwnd) == IDOK) 3680 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0); 3681 break; 3682 case IDC_ENABLE_ALL_PURPOSES: 3683 case IDC_DISABLE_ALL_PURPOSES: 3684 case IDC_ENABLE_SELECTED_PURPOSES: 3685 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0); 3686 select_purposes(hwnd, LOWORD(wp) - IDC_ENABLE_ALL_PURPOSES); 3687 break; 3688 } 3689 break; 3690 } 3691 break; 3692 } 3693 return 0; 3694 } 3695 3696 static UINT CALLBACK cert_properties_general_callback(HWND hwnd, UINT msg, 3697 PROPSHEETPAGEW *page) 3698 { 3699 HWND lv; 3700 int cItem, i; 3701 struct edit_cert_data *data; 3702 3703 switch (msg) 3704 { 3705 case PSPCB_RELEASE: 3706 lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES); 3707 cItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0); 3708 for (i = 0; i < cItem; i++) 3709 { 3710 LVITEMW item; 3711 3712 item.mask = LVIF_PARAM; 3713 item.iItem = i; 3714 item.iSubItem = 0; 3715 if (SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item) && item.lParam) 3716 { 3717 PCRYPT_OID_INFO info = (PCRYPT_OID_INFO)item.lParam; 3718 3719 if (info->cbSize == sizeof(CRYPT_OID_INFO) && !info->dwGroupId) 3720 { 3721 HeapFree(GetProcessHeap(), 0, (LPSTR)info->pszOID); 3722 HeapFree(GetProcessHeap(), 0, info); 3723 } 3724 } 3725 } 3726 data = (struct edit_cert_data *)GetWindowLongPtrW(hwnd, DWLP_USER); 3727 if (data) 3728 { 3729 ImageList_Destroy(data->imageList); 3730 HeapFree(GetProcessHeap(), 0, data); 3731 } 3732 break; 3733 } 3734 return 1; 3735 } 3736 3737 static void show_edit_cert_properties_dialog(HWND parent, 3738 struct detail_data *data) 3739 { 3740 PROPSHEETHEADERW hdr; 3741 PROPSHEETPAGEW page; /* FIXME: need to add a cross-certificate page */ 3742 3743 TRACE("(%p)\n", data); 3744 3745 memset(&page, 0, sizeof(PROPSHEETPAGEW)); 3746 page.dwSize = sizeof(page); 3747 page.dwFlags = PSP_USECALLBACK; 3748 page.pfnCallback = cert_properties_general_callback; 3749 page.hInstance = hInstance; 3750 page.u.pszTemplate = MAKEINTRESOURCEW(IDD_CERT_PROPERTIES_GENERAL); 3751 page.pfnDlgProc = cert_properties_general_dlg_proc; 3752 page.lParam = (LPARAM)data; 3753 3754 memset(&hdr, 0, sizeof(hdr)); 3755 hdr.dwSize = sizeof(hdr); 3756 hdr.hwndParent = parent; 3757 hdr.dwFlags = PSH_PROPSHEETPAGE; 3758 hdr.hInstance = hInstance; 3759 hdr.pszCaption = MAKEINTRESOURCEW(IDS_CERTIFICATE_PROPERTIES); 3760 hdr.u3.ppsp = &page; 3761 hdr.nPages = 1; 3762 PropertySheetW(&hdr); 3763 } 3764 3765 static void free_detail_fields(struct detail_data *data) 3766 { 3767 int i; 3768 3769 for (i = 0; i < data->cFields; i++) 3770 HeapFree(GetProcessHeap(), 0, data->fields[i].detailed_value); 3771 HeapFree(GetProcessHeap(), 0, data->fields); 3772 data->fields = NULL; 3773 data->cFields = 0; 3774 } 3775 3776 static void refresh_details_view(HWND hwnd) 3777 { 3778 HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT); 3779 int curSel; 3780 struct detail_data *data; 3781 3782 curSel = SendMessageW(cb, CB_GETCURSEL, 0, 0); 3783 /* Actually, any index will do, since they all store the same data value */ 3784 data = (struct detail_data *)SendMessageW(cb, CB_GETITEMDATA, curSel, 0); 3785 free_detail_fields(data); 3786 set_fields_selection(hwnd, data, curSel); 3787 } 3788 3789 static LRESULT CALLBACK detail_dlg_proc(HWND hwnd, UINT msg, WPARAM wp, 3790 LPARAM lp) 3791 { 3792 PROPSHEETPAGEW *page; 3793 struct detail_data *data; 3794 3795 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp); 3796 3797 switch (msg) 3798 { 3799 case WM_INITDIALOG: 3800 page = (PROPSHEETPAGEW *)lp; 3801 data = (struct detail_data *)page->lParam; 3802 create_cert_details_list(hwnd, data); 3803 if (!(data->pCertViewInfo->dwFlags & CRYPTUI_ENABLE_EDITPROPERTIES)) 3804 EnableWindow(GetDlgItem(hwnd, IDC_EDITPROPERTIES), FALSE); 3805 if (data->pCertViewInfo->dwFlags & CRYPTUI_DISABLE_EXPORT) 3806 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT), FALSE); 3807 break; 3808 case WM_NOTIFY: 3809 { 3810 NMITEMACTIVATE *nm; 3811 HWND list = GetDlgItem(hwnd, IDC_DETAIL_LIST); 3812 3813 nm = (NMITEMACTIVATE*)lp; 3814 if (nm->hdr.hwndFrom == list && nm->uNewState & LVN_ITEMACTIVATE 3815 && nm->hdr.code == LVN_ITEMCHANGED) 3816 { 3817 data = (struct detail_data *)nm->lParam; 3818 if (nm->iItem >= 0 && data && nm->iItem < data->cFields) 3819 { 3820 WCHAR buf[MAX_STRING_LEN], *val = NULL; 3821 HWND valueCtl = GetDlgItem(hwnd, IDC_DETAIL_VALUE); 3822 3823 if (data->fields[nm->iItem].create) 3824 val = data->fields[nm->iItem].create( 3825 data->pCertViewInfo->pCertContext, 3826 data->fields[nm->iItem].param); 3827 else 3828 { 3829 LVITEMW item; 3830 int res; 3831 3832 item.cchTextMax = sizeof(buf) / sizeof(buf[0]); 3833 item.mask = LVIF_TEXT; 3834 item.pszText = buf; 3835 item.iItem = nm->iItem; 3836 item.iSubItem = 1; 3837 res = SendMessageW(list, LVM_GETITEMW, 0, (LPARAM)&item); 3838 if (res) 3839 val = buf; 3840 } 3841 /* Select all the text in the control, the next update will 3842 * replace it 3843 */ 3844 SendMessageW(valueCtl, EM_SETSEL, 0, -1); 3845 add_unformatted_text_to_control(valueCtl, val, 3846 val ? strlenW(val) : 0); 3847 if (val != buf) 3848 HeapFree(GetProcessHeap(), 0, val); 3849 } 3850 } 3851 break; 3852 } 3853 case WM_COMMAND: 3854 switch (wp) 3855 { 3856 case IDC_EXPORT: 3857 { 3858 HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT); 3859 CRYPTUI_WIZ_EXPORT_INFO info; 3860 3861 data = (struct detail_data *)SendMessageW(cb, CB_GETITEMDATA, 0, 0); 3862 info.dwSize = sizeof(info); 3863 info.pwszExportFileName = NULL; 3864 info.dwSubjectChoice = CRYPTUI_WIZ_EXPORT_CERT_CONTEXT; 3865 info.u.pCertContext = data->pCertViewInfo->pCertContext; 3866 info.cStores = 0; 3867 CryptUIWizExport(0, hwnd, NULL, &info, NULL); 3868 break; 3869 } 3870 case IDC_EDITPROPERTIES: 3871 { 3872 HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT); 3873 int curSel; 3874 3875 curSel = SendMessageW(cb, CB_GETCURSEL, 0, 0); 3876 /* Actually, any index will do, since they all store the same 3877 * data value 3878 */ 3879 data = (struct detail_data *)SendMessageW(cb, CB_GETITEMDATA, 3880 curSel, 0); 3881 show_edit_cert_properties_dialog(GetParent(hwnd), data); 3882 break; 3883 } 3884 case ((CBN_SELCHANGE << 16) | IDC_DETAIL_SELECT): 3885 refresh_details_view(hwnd); 3886 break; 3887 } 3888 break; 3889 case WM_REFRESH_VIEW: 3890 refresh_details_view(hwnd); 3891 break; 3892 } 3893 return 0; 3894 } 3895 3896 static UINT CALLBACK detail_callback(HWND hwnd, UINT msg, 3897 PROPSHEETPAGEW *page) 3898 { 3899 struct detail_data *data; 3900 3901 switch (msg) 3902 { 3903 case PSPCB_RELEASE: 3904 data = (struct detail_data *)page->lParam; 3905 free_detail_fields(data); 3906 HeapFree(GetProcessHeap(), 0, data); 3907 break; 3908 } 3909 return 0; 3910 } 3911 3912 static BOOL init_detail_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo, 3913 BOOL *pfPropertiesChanged, PROPSHEETPAGEW *page) 3914 { 3915 BOOL ret; 3916 struct detail_data *data = HeapAlloc(GetProcessHeap(), 0, 3917 sizeof(struct detail_data)); 3918 3919 if (data) 3920 { 3921 data->pCertViewInfo = pCertViewInfo; 3922 data->pfPropertiesChanged = pfPropertiesChanged; 3923 data->cFields = 0; 3924 data->fields = NULL; 3925 memset(page, 0, sizeof(PROPSHEETPAGEW)); 3926 page->dwSize = sizeof(PROPSHEETPAGEW); 3927 page->dwFlags = PSP_USECALLBACK; 3928 page->pfnCallback = detail_callback; 3929 page->hInstance = hInstance; 3930 page->u.pszTemplate = MAKEINTRESOURCEW(IDD_DETAIL); 3931 page->pfnDlgProc = detail_dlg_proc; 3932 page->lParam = (LPARAM)data; 3933 ret = TRUE; 3934 } 3935 else 3936 ret = FALSE; 3937 return ret; 3938 } 3939 3940 struct hierarchy_data 3941 { 3942 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo; 3943 HIMAGELIST imageList; 3944 DWORD selectedCert; 3945 }; 3946 3947 static LPARAM index_to_lparam(struct hierarchy_data *data, DWORD index) 3948 { 3949 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain( 3950 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData, 3951 data->pCertViewInfo->idxSigner, data->pCertViewInfo->fCounterSigner, 3952 data->pCertViewInfo->idxCounterSigner); 3953 3954 /* Takes advantage of the fact that a pointer is 32-bit aligned, and 3955 * therefore always even. 3956 */ 3957 if (index == provSigner->csCertChain - 1) 3958 return (LPARAM)data; 3959 return index << 1 | 1; 3960 } 3961 3962 static inline DWORD lparam_to_index(struct hierarchy_data *data, LPARAM lp) 3963 { 3964 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain( 3965 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData, 3966 data->pCertViewInfo->idxSigner, data->pCertViewInfo->fCounterSigner, 3967 data->pCertViewInfo->idxCounterSigner); 3968 3969 if (!(lp & 1)) 3970 return provSigner->csCertChain - 1; 3971 return lp >> 1; 3972 } 3973 3974 static struct hierarchy_data *get_hierarchy_data_from_tree_item(HWND tree, 3975 HTREEITEM hItem) 3976 { 3977 struct hierarchy_data *data = NULL; 3978 HTREEITEM root = NULL; 3979 3980 do { 3981 HTREEITEM parent = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM, 3982 TVGN_PARENT, (LPARAM)hItem); 3983 3984 if (!parent) 3985 root = hItem; 3986 hItem = parent; 3987 } while (hItem); 3988 if (root) 3989 { 3990 TVITEMW item; 3991 3992 item.mask = TVIF_PARAM; 3993 item.hItem = root; 3994 SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item); 3995 data = (struct hierarchy_data *)item.lParam; 3996 } 3997 return data; 3998 } 3999 4000 static WCHAR *get_cert_display_name(PCCERT_CONTEXT cert) 4001 { 4002 WCHAR *name = get_cert_property_as_string(cert, CERT_FRIENDLY_NAME_PROP_ID); 4003 4004 if (!name) 4005 name = get_cert_name_string(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0); 4006 return name; 4007 } 4008 4009 static void show_cert_chain(HWND hwnd, struct hierarchy_data *data) 4010 { 4011 HWND tree = GetDlgItem(hwnd, IDC_CERTPATH); 4012 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain( 4013 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData, 4014 data->pCertViewInfo->idxSigner, data->pCertViewInfo->fCounterSigner, 4015 data->pCertViewInfo->idxCounterSigner); 4016 DWORD i; 4017 HTREEITEM parent = NULL; 4018 4019 SendMessageW(tree, TVM_SETIMAGELIST, TVSIL_NORMAL, (LPARAM)data->imageList); 4020 for (i = provSigner->csCertChain; i; i--) 4021 { 4022 LPWSTR name; 4023 4024 name = get_cert_display_name(provSigner->pasCertChain[i - 1].pCert); 4025 if (name) 4026 { 4027 TVINSERTSTRUCTW tvis; 4028 4029 tvis.hParent = parent; 4030 tvis.hInsertAfter = TVI_LAST; 4031 tvis.u.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_IMAGE | 4032 TVIF_SELECTEDIMAGE | TVIF_PARAM; 4033 tvis.u.item.pszText = name; 4034 tvis.u.item.state = TVIS_EXPANDED; 4035 tvis.u.item.stateMask = TVIS_EXPANDED; 4036 if (i == 1 && (!provSigner->pChainContext || 4037 provSigner->pChainContext->TrustStatus.dwErrorStatus & 4038 CERT_TRUST_IS_PARTIAL_CHAIN)) 4039 { 4040 /* The root of the chain has a special case: if the chain is 4041 * a partial chain, the icon is a warning icon rather than an 4042 * error icon. 4043 */ 4044 tvis.u.item.iImage = 2; 4045 } 4046 else if (provSigner->pasCertChain[i - 1].pChainElement->TrustStatus. 4047 dwErrorStatus == 0) 4048 tvis.u.item.iImage = 0; 4049 else 4050 tvis.u.item.iImage = 1; 4051 tvis.u.item.iSelectedImage = tvis.u.item.iImage; 4052 tvis.u.item.lParam = index_to_lparam(data, i - 1); 4053 parent = (HTREEITEM)SendMessageW(tree, TVM_INSERTITEMW, 0, 4054 (LPARAM)&tvis); 4055 HeapFree(GetProcessHeap(), 0, name); 4056 } 4057 } 4058 } 4059 4060 static void set_certificate_status(HWND hwnd, const CRYPT_PROVIDER_CERT *cert) 4061 { 4062 /* Select all the text in the control, the next update will replace it */ 4063 SendMessageW(hwnd, EM_SETSEL, 0, -1); 4064 /* Set the highest priority error messages first. */ 4065 if (!(cert->dwConfidence & CERT_CONFIDENCE_SIG)) 4066 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_BAD_SIGNATURE); 4067 else if (!(cert->dwConfidence & CERT_CONFIDENCE_TIME)) 4068 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_BAD_TIME); 4069 else if (!(cert->dwConfidence & CERT_CONFIDENCE_TIMENEST)) 4070 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_BAD_TIMENEST); 4071 else if (cert->dwRevokedReason) 4072 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_REVOKED); 4073 else 4074 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_VALID); 4075 } 4076 4077 static void set_certificate_status_for_end_cert(HWND hwnd, 4078 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo) 4079 { 4080 HWND status = GetDlgItem(hwnd, IDC_CERTIFICATESTATUSTEXT); 4081 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain( 4082 (CRYPT_PROVIDER_DATA *)pCertViewInfo->u.pCryptProviderData, 4083 pCertViewInfo->idxSigner, pCertViewInfo->fCounterSigner, 4084 pCertViewInfo->idxCounterSigner); 4085 CRYPT_PROVIDER_CERT *provCert = WTHelperGetProvCertFromChain(provSigner, 4086 pCertViewInfo->idxCert); 4087 4088 set_certificate_status(status, provCert); 4089 } 4090 4091 static void show_cert_hierarchy(HWND hwnd, struct hierarchy_data *data) 4092 { 4093 /* Disable view certificate button until a certificate is selected */ 4094 EnableWindow(GetDlgItem(hwnd, IDC_VIEWCERTIFICATE), FALSE); 4095 show_cert_chain(hwnd, data); 4096 set_certificate_status_for_end_cert(hwnd, data->pCertViewInfo); 4097 } 4098 4099 static void show_dialog_for_selected_cert(HWND hwnd) 4100 { 4101 HWND tree = GetDlgItem(hwnd, IDC_CERTPATH); 4102 TVITEMW item; 4103 struct hierarchy_data *data; 4104 DWORD selection; 4105 4106 memset(&item, 0, sizeof(item)); 4107 item.mask = TVIF_HANDLE | TVIF_PARAM; 4108 item.hItem = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM, TVGN_CARET, 0); 4109 SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item); 4110 data = get_hierarchy_data_from_tree_item(tree, item.hItem); 4111 selection = lparam_to_index(data, item.lParam); 4112 if (selection != 0) 4113 { 4114 CRYPT_PROVIDER_SGNR *provSigner; 4115 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo; 4116 BOOL changed = FALSE; 4117 4118 provSigner = WTHelperGetProvSignerFromChain( 4119 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData, 4120 data->pCertViewInfo->idxSigner, 4121 data->pCertViewInfo->fCounterSigner, 4122 data->pCertViewInfo->idxCounterSigner); 4123 memset(&viewInfo, 0, sizeof(viewInfo)); 4124 viewInfo.dwSize = sizeof(viewInfo); 4125 viewInfo.dwFlags = data->pCertViewInfo->dwFlags; 4126 viewInfo.szTitle = data->pCertViewInfo->szTitle; 4127 viewInfo.pCertContext = provSigner->pasCertChain[selection].pCert; 4128 viewInfo.cStores = data->pCertViewInfo->cStores; 4129 viewInfo.rghStores = data->pCertViewInfo->rghStores; 4130 viewInfo.cPropSheetPages = data->pCertViewInfo->cPropSheetPages; 4131 viewInfo.rgPropSheetPages = data->pCertViewInfo->rgPropSheetPages; 4132 viewInfo.nStartPage = data->pCertViewInfo->nStartPage; 4133 CryptUIDlgViewCertificateW(&viewInfo, &changed); 4134 if (changed) 4135 { 4136 /* Delete the contents of the tree */ 4137 SendMessageW(tree, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT); 4138 /* Reinitialize the tree */ 4139 show_cert_hierarchy(hwnd, data); 4140 } 4141 } 4142 } 4143 4144 static LRESULT CALLBACK hierarchy_dlg_proc(HWND hwnd, UINT msg, WPARAM wp, 4145 LPARAM lp) 4146 { 4147 PROPSHEETPAGEW *page; 4148 struct hierarchy_data *data; 4149 LRESULT ret = 0; 4150 HWND tree = GetDlgItem(hwnd, IDC_CERTPATH); 4151 4152 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp); 4153 4154 switch (msg) 4155 { 4156 case WM_INITDIALOG: 4157 page = (PROPSHEETPAGEW *)lp; 4158 data = (struct hierarchy_data *)page->lParam; 4159 show_cert_hierarchy(hwnd, data); 4160 break; 4161 case WM_NOTIFY: 4162 { 4163 NMHDR *hdr; 4164 4165 hdr = (NMHDR *)lp; 4166 switch (hdr->code) 4167 { 4168 case TVN_SELCHANGEDW: 4169 { 4170 NMTREEVIEWW *nm = (NMTREEVIEWW*)lp; 4171 DWORD selection; 4172 CRYPT_PROVIDER_SGNR *provSigner; 4173 4174 data = get_hierarchy_data_from_tree_item(tree, nm->itemNew.hItem); 4175 selection = lparam_to_index(data, nm->itemNew.lParam); 4176 provSigner = WTHelperGetProvSignerFromChain( 4177 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData, 4178 data->pCertViewInfo->idxSigner, 4179 data->pCertViewInfo->fCounterSigner, 4180 data->pCertViewInfo->idxCounterSigner); 4181 EnableWindow(GetDlgItem(hwnd, IDC_VIEWCERTIFICATE), selection != 0); 4182 set_certificate_status(GetDlgItem(hwnd, IDC_CERTIFICATESTATUSTEXT), 4183 &provSigner->pasCertChain[selection]); 4184 break; 4185 } 4186 case NM_DBLCLK: 4187 show_dialog_for_selected_cert(hwnd); 4188 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1); 4189 ret = 1; 4190 break; 4191 } 4192 break; 4193 } 4194 case WM_COMMAND: 4195 switch (wp) 4196 { 4197 case IDC_VIEWCERTIFICATE: 4198 show_dialog_for_selected_cert(hwnd); 4199 break; 4200 } 4201 break; 4202 case WM_REFRESH_VIEW: 4203 { 4204 TVITEMW item; 4205 4206 /* Get hierarchy data */ 4207 memset(&item, 0, sizeof(item)); 4208 item.mask = TVIF_HANDLE | TVIF_PARAM; 4209 item.hItem = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM, TVGN_ROOT, 4210 0); 4211 data = get_hierarchy_data_from_tree_item(tree, item.hItem); 4212 /* Delete the contents of the tree */ 4213 SendMessageW(tree, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT); 4214 /* Reinitialize the tree */ 4215 show_cert_hierarchy(hwnd, data); 4216 break; 4217 } 4218 } 4219 return ret; 4220 } 4221 4222 static UINT CALLBACK hierarchy_callback(HWND hwnd, UINT msg, 4223 PROPSHEETPAGEW *page) 4224 { 4225 struct hierarchy_data *data; 4226 4227 switch (msg) 4228 { 4229 case PSPCB_RELEASE: 4230 data = (struct hierarchy_data *)page->lParam; 4231 ImageList_Destroy(data->imageList); 4232 HeapFree(GetProcessHeap(), 0, data); 4233 break; 4234 } 4235 return 0; 4236 } 4237 4238 static BOOL init_hierarchy_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo, 4239 PROPSHEETPAGEW *page) 4240 { 4241 struct hierarchy_data *data = HeapAlloc(GetProcessHeap(), 0, 4242 sizeof(struct hierarchy_data)); 4243 BOOL ret = FALSE; 4244 4245 if (data) 4246 { 4247 data->imageList = ImageList_Create(16, 16, ILC_COLOR4 | ILC_MASK, 2, 0); 4248 if (data->imageList) 4249 { 4250 HBITMAP bmp; 4251 COLORREF backColor = RGB(255, 0, 255); 4252 4253 data->pCertViewInfo = pCertViewInfo; 4254 data->selectedCert = 0xffffffff; 4255 4256 bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_SMALL_ICONS)); 4257 ImageList_AddMasked(data->imageList, bmp, backColor); 4258 DeleteObject(bmp); 4259 ImageList_SetBkColor(data->imageList, CLR_NONE); 4260 4261 memset(page, 0, sizeof(PROPSHEETPAGEW)); 4262 page->dwSize = sizeof(PROPSHEETPAGEW); 4263 page->dwFlags = PSP_USECALLBACK; 4264 page->hInstance = hInstance; 4265 page->u.pszTemplate = MAKEINTRESOURCEW(IDD_HIERARCHY); 4266 page->pfnDlgProc = hierarchy_dlg_proc; 4267 page->lParam = (LPARAM)data; 4268 page->pfnCallback = hierarchy_callback; 4269 ret = TRUE; 4270 } 4271 else 4272 HeapFree(GetProcessHeap(), 0, data); 4273 } 4274 return ret; 4275 } 4276 4277 static int CALLBACK cert_prop_sheet_proc(HWND hwnd, UINT msg, LPARAM lp) 4278 { 4279 RECT rc; 4280 4281 TRACE("(%p, %08x, %08lx)\n", hwnd, msg, lp); 4282 4283 switch (msg) 4284 { 4285 case PSCB_INITIALIZED: 4286 /* Get cancel button's position.. */ 4287 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rc); 4288 MapWindowPoints( 0, hwnd, (POINT *)&rc, 2 ); 4289 /* hide the cancel button.. */ 4290 ShowWindow(GetDlgItem(hwnd, IDCANCEL), FALSE); 4291 /* and move the OK button to the cancel button's original position. */ 4292 SetWindowPos(GetDlgItem(hwnd, IDOK), 0, rc.left, rc.top, 0, 0, 4293 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW ); 4294 break; 4295 } 4296 return 0; 4297 } 4298 4299 static BOOL show_cert_dialog(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo, 4300 CRYPT_PROVIDER_CERT *provCert, BOOL *pfPropertiesChanged) 4301 { 4302 static const WCHAR riched[] = { 'r','i','c','h','e','d','2','0',0 }; 4303 DWORD nPages; 4304 PROPSHEETPAGEW *pages; 4305 BOOL ret = FALSE; 4306 HMODULE lib = LoadLibraryW(riched); 4307 4308 nPages = pCertViewInfo->cPropSheetPages + 1; /* one for the General tab */ 4309 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_DETAILPAGE)) 4310 nPages++; 4311 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_HIERARCHYPAGE)) 4312 nPages++; 4313 pages = HeapAlloc(GetProcessHeap(), 0, nPages * sizeof(PROPSHEETPAGEW)); 4314 if (pages) 4315 { 4316 PROPSHEETHEADERW hdr; 4317 CRYPTUI_INITDIALOG_STRUCT *init = NULL; 4318 DWORD i; 4319 4320 memset(&hdr, 0, sizeof(hdr)); 4321 hdr.dwSize = sizeof(hdr); 4322 hdr.dwFlags = PSH_NOAPPLYNOW | PSH_PROPSHEETPAGE | PSH_USECALLBACK; 4323 hdr.hInstance = hInstance; 4324 if (pCertViewInfo->szTitle) 4325 hdr.pszCaption = pCertViewInfo->szTitle; 4326 else 4327 hdr.pszCaption = MAKEINTRESOURCEW(IDS_CERTIFICATE); 4328 init_general_page(pCertViewInfo, &pages[hdr.nPages++]); 4329 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_DETAILPAGE)) 4330 { 4331 if (init_detail_page(pCertViewInfo, pfPropertiesChanged, 4332 &pages[hdr.nPages])) 4333 hdr.nPages++; 4334 } 4335 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_HIERARCHYPAGE)) 4336 { 4337 if (init_hierarchy_page(pCertViewInfo, &pages[hdr.nPages])) 4338 hdr.nPages++; 4339 } 4340 /* Copy each additional page, and create the init dialog struct for it 4341 */ 4342 if (pCertViewInfo->cPropSheetPages) 4343 { 4344 init = HeapAlloc(GetProcessHeap(), 0, 4345 pCertViewInfo->cPropSheetPages * 4346 sizeof(CRYPTUI_INITDIALOG_STRUCT)); 4347 if (init) 4348 { 4349 for (i = 0; i < pCertViewInfo->cPropSheetPages; i++) 4350 { 4351 memcpy(&pages[hdr.nPages + i], 4352 &pCertViewInfo->rgPropSheetPages[i], 4353 sizeof(PROPSHEETPAGEW)); 4354 init[i].lParam = pCertViewInfo->rgPropSheetPages[i].lParam; 4355 init[i].pCertContext = pCertViewInfo->pCertContext; 4356 pages[hdr.nPages + i].lParam = (LPARAM)&init[i]; 4357 } 4358 if (pCertViewInfo->nStartPage & 0x8000) 4359 { 4360 /* Start page index is relative to the number of default 4361 * pages 4362 */ 4363 hdr.u2.nStartPage = pCertViewInfo->nStartPage + hdr.nPages; 4364 } 4365 else 4366 hdr.u2.nStartPage = pCertViewInfo->nStartPage; 4367 hdr.nPages = nPages; 4368 ret = TRUE; 4369 } 4370 else 4371 SetLastError(ERROR_OUTOFMEMORY); 4372 } 4373 else 4374 { 4375 /* Ignore the relative flag if there aren't any additional pages */ 4376 hdr.u2.nStartPage = pCertViewInfo->nStartPage & 0x7fff; 4377 ret = TRUE; 4378 } 4379 if (ret) 4380 { 4381 INT_PTR l; 4382 4383 hdr.u3.ppsp = pages; 4384 hdr.pfnCallback = cert_prop_sheet_proc; 4385 l = PropertySheetW(&hdr); 4386 if (l == 0) 4387 { 4388 SetLastError(ERROR_CANCELLED); 4389 ret = FALSE; 4390 } 4391 } 4392 HeapFree(GetProcessHeap(), 0, init); 4393 HeapFree(GetProcessHeap(), 0, pages); 4394 } 4395 else 4396 SetLastError(ERROR_OUTOFMEMORY); 4397 FreeLibrary(lib); 4398 return ret; 4399 } 4400 4401 /*********************************************************************** 4402 * CryptUIDlgViewCertificateW (CRYPTUI.@) 4403 */ 4404 BOOL WINAPI CryptUIDlgViewCertificateW( 4405 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo, BOOL *pfPropertiesChanged) 4406 { 4407 static GUID generic_cert_verify = WINTRUST_ACTION_GENERIC_CERT_VERIFY; 4408 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo; 4409 WINTRUST_DATA wvt; 4410 WINTRUST_CERT_INFO cert; 4411 BOOL ret = FALSE; 4412 CRYPT_PROVIDER_SGNR *signer; 4413 CRYPT_PROVIDER_CERT *provCert = NULL; 4414 4415 TRACE("(%p, %p)\n", pCertViewInfo, pfPropertiesChanged); 4416 4417 if (pCertViewInfo->dwSize != sizeof(CRYPTUI_VIEWCERTIFICATE_STRUCTW)) 4418 { 4419 SetLastError(ERROR_INVALID_PARAMETER); 4420 return FALSE; 4421 } 4422 /* Make a local copy in case we have to call WinVerifyTrust ourselves */ 4423 memcpy(&viewInfo, pCertViewInfo, sizeof(viewInfo)); 4424 if (!pCertViewInfo->u.hWVTStateData) 4425 { 4426 memset(&wvt, 0, sizeof(wvt)); 4427 wvt.cbStruct = sizeof(wvt); 4428 wvt.dwUIChoice = WTD_UI_NONE; 4429 if (viewInfo.dwFlags & 4430 CRYPTUI_ENABLE_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT) 4431 wvt.fdwRevocationChecks |= WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT; 4432 if (viewInfo.dwFlags & CRYPTUI_ENABLE_REVOCATION_CHECK_END_CERT) 4433 wvt.fdwRevocationChecks |= WTD_REVOCATION_CHECK_END_CERT; 4434 if (viewInfo.dwFlags & CRYPTUI_ENABLE_REVOCATION_CHECK_CHAIN) 4435 wvt.fdwRevocationChecks |= WTD_REVOCATION_CHECK_CHAIN; 4436 wvt.dwUnionChoice = WTD_CHOICE_CERT; 4437 memset(&cert, 0, sizeof(cert)); 4438 cert.cbStruct = sizeof(cert); 4439 cert.psCertContext = (CERT_CONTEXT *)viewInfo.pCertContext; 4440 cert.chStores = viewInfo.cStores; 4441 cert.pahStores = viewInfo.rghStores; 4442 wvt.u.pCert = &cert; 4443 wvt.dwStateAction = WTD_STATEACTION_VERIFY; 4444 WinVerifyTrust(NULL, &generic_cert_verify, &wvt); 4445 viewInfo.u.pCryptProviderData = 4446 WTHelperProvDataFromStateData(wvt.hWVTStateData); 4447 signer = WTHelperGetProvSignerFromChain( 4448 (CRYPT_PROVIDER_DATA *)viewInfo.u.pCryptProviderData, 0, FALSE, 0); 4449 provCert = WTHelperGetProvCertFromChain(signer, 0); 4450 ret = TRUE; 4451 } 4452 else 4453 { 4454 viewInfo.u.pCryptProviderData = 4455 WTHelperProvDataFromStateData(viewInfo.u.hWVTStateData); 4456 signer = WTHelperGetProvSignerFromChain( 4457 (CRYPT_PROVIDER_DATA *)viewInfo.u.pCryptProviderData, 4458 viewInfo.idxSigner, viewInfo.fCounterSigner, 4459 viewInfo.idxCounterSigner); 4460 provCert = WTHelperGetProvCertFromChain(signer, viewInfo.idxCert); 4461 ret = TRUE; 4462 } 4463 if (ret) 4464 { 4465 ret = show_cert_dialog(&viewInfo, provCert, pfPropertiesChanged); 4466 if (!pCertViewInfo->u.hWVTStateData) 4467 { 4468 wvt.dwStateAction = WTD_STATEACTION_CLOSE; 4469 WinVerifyTrust(NULL, &generic_cert_verify, &wvt); 4470 } 4471 } 4472 return ret; 4473 } 4474 4475 /*********************************************************************** 4476 * CryptUIDlgViewContext (CRYPTUI.@) 4477 */ 4478 BOOL WINAPI CryptUIDlgViewContext(DWORD dwContextType, LPVOID pvContext, 4479 HWND hwnd, LPCWSTR pwszTitle, DWORD dwFlags, LPVOID pvReserved) 4480 { 4481 BOOL ret; 4482 4483 TRACE("(%d, %p, %p, %s, %08x, %p)\n", dwContextType, pvContext, hwnd, 4484 debugstr_w(pwszTitle), dwFlags, pvReserved); 4485 4486 switch (dwContextType) 4487 { 4488 case CERT_STORE_CERTIFICATE_CONTEXT: 4489 { 4490 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo; 4491 4492 memset(&viewInfo, 0, sizeof(viewInfo)); 4493 viewInfo.dwSize = sizeof(viewInfo); 4494 viewInfo.hwndParent = hwnd; 4495 viewInfo.szTitle = pwszTitle; 4496 viewInfo.pCertContext = pvContext; 4497 ret = CryptUIDlgViewCertificateW(&viewInfo, NULL); 4498 break; 4499 } 4500 default: 4501 FIXME("unimplemented for context type %d\n", dwContextType); 4502 SetLastError(E_INVALIDARG); 4503 ret = FALSE; 4504 } 4505 return ret; 4506 } 4507 4508 /* Decodes a cert's basic constraints extension (either szOID_BASIC_CONSTRAINTS 4509 * or szOID_BASIC_CONSTRAINTS2, whichever is present) to determine if it 4510 * should be a CA. If neither extension is present, returns 4511 * defaultIfNotSpecified. 4512 */ 4513 static BOOL is_ca_cert(PCCERT_CONTEXT cert, BOOL defaultIfNotSpecified) 4514 { 4515 BOOL isCA = defaultIfNotSpecified; 4516 PCERT_EXTENSION ext = CertFindExtension(szOID_BASIC_CONSTRAINTS, 4517 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension); 4518 4519 if (ext) 4520 { 4521 CERT_BASIC_CONSTRAINTS_INFO *info; 4522 DWORD size = 0; 4523 4524 if (CryptDecodeObjectEx(X509_ASN_ENCODING, szOID_BASIC_CONSTRAINTS, 4525 ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, 4526 NULL, &info, &size)) 4527 { 4528 if (info->SubjectType.cbData == 1) 4529 isCA = info->SubjectType.pbData[0] & CERT_CA_SUBJECT_FLAG; 4530 LocalFree(info); 4531 } 4532 } 4533 else 4534 { 4535 ext = CertFindExtension(szOID_BASIC_CONSTRAINTS2, 4536 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension); 4537 if (ext) 4538 { 4539 CERT_BASIC_CONSTRAINTS2_INFO info; 4540 DWORD size = sizeof(CERT_BASIC_CONSTRAINTS2_INFO); 4541 4542 if (CryptDecodeObjectEx(X509_ASN_ENCODING, 4543 szOID_BASIC_CONSTRAINTS2, ext->Value.pbData, ext->Value.cbData, 4544 0, NULL, &info, &size)) 4545 isCA = info.fCA; 4546 } 4547 } 4548 return isCA; 4549 } 4550 4551 static HCERTSTORE choose_store_for_cert(PCCERT_CONTEXT cert) 4552 { 4553 LPCWSTR storeName; 4554 4555 if (is_ca_cert(cert, TRUE)) 4556 storeName = ca; 4557 else 4558 storeName = addressBook; 4559 return CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0, 4560 CERT_SYSTEM_STORE_CURRENT_USER, storeName); 4561 } 4562 4563 static BOOL import_cert(PCCERT_CONTEXT cert, HCERTSTORE hDestCertStore) 4564 { 4565 HCERTSTORE store; 4566 BOOL ret; 4567 4568 if (!cert) 4569 { 4570 SetLastError(E_INVALIDARG); 4571 return FALSE; 4572 } 4573 if (hDestCertStore) store = hDestCertStore; 4574 else 4575 { 4576 if (!(store = choose_store_for_cert(cert))) 4577 { 4578 WARN("unable to open certificate store\n"); 4579 return FALSE; 4580 } 4581 } 4582 ret = CertAddCertificateContextToStore(store, cert, 4583 CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES, NULL); 4584 if (!hDestCertStore) CertCloseStore(store, 0); 4585 return ret; 4586 } 4587 4588 static BOOL import_crl(PCCRL_CONTEXT crl, HCERTSTORE hDestCertStore) 4589 { 4590 HCERTSTORE store; 4591 BOOL ret; 4592 4593 if (!crl) 4594 { 4595 SetLastError(E_INVALIDARG); 4596 return FALSE; 4597 } 4598 if (hDestCertStore) store = hDestCertStore; 4599 else 4600 { 4601 if (!(store = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0, 4602 CERT_SYSTEM_STORE_CURRENT_USER, ca))) 4603 { 4604 WARN("unable to open certificate store\n"); 4605 return FALSE; 4606 } 4607 } 4608 ret = CertAddCRLContextToStore(store, crl, 4609 CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES, NULL); 4610 if (!hDestCertStore) CertCloseStore(store, 0); 4611 return ret; 4612 } 4613 4614 static BOOL import_ctl(PCCTL_CONTEXT ctl, HCERTSTORE hDestCertStore) 4615 { 4616 HCERTSTORE store; 4617 BOOL ret; 4618 4619 if (!ctl) 4620 { 4621 SetLastError(E_INVALIDARG); 4622 return FALSE; 4623 } 4624 if (hDestCertStore) store = hDestCertStore; 4625 else 4626 { 4627 static const WCHAR trust[] = { 'T','r','u','s','t',0 }; 4628 4629 if (!(store = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0, 4630 CERT_SYSTEM_STORE_CURRENT_USER, trust))) 4631 { 4632 WARN("unable to open certificate store\n"); 4633 return FALSE; 4634 } 4635 } 4636 ret = CertAddCTLContextToStore(store, ctl, 4637 CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES, NULL); 4638 if (!hDestCertStore) CertCloseStore(store, 0); 4639 return ret; 4640 } 4641 4642 /* Checks type, a type such as CERT_QUERY_CONTENT_CERT returned by 4643 * CryptQueryObject, against the allowed types. Returns TRUE if the 4644 * type is allowed, FALSE otherwise. 4645 */ 4646 static BOOL check_context_type(DWORD dwFlags, DWORD type) 4647 { 4648 BOOL ret; 4649 4650 if (dwFlags & 4651 (CRYPTUI_WIZ_IMPORT_ALLOW_CERT | CRYPTUI_WIZ_IMPORT_ALLOW_CRL | 4652 CRYPTUI_WIZ_IMPORT_ALLOW_CTL)) 4653 { 4654 switch (type) 4655 { 4656 case CERT_QUERY_CONTENT_CERT: 4657 case CERT_QUERY_CONTENT_SERIALIZED_CERT: 4658 ret = dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CERT; 4659 break; 4660 case CERT_QUERY_CONTENT_CRL: 4661 case CERT_QUERY_CONTENT_SERIALIZED_CRL: 4662 ret = dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CRL; 4663 break; 4664 case CERT_QUERY_CONTENT_CTL: 4665 case CERT_QUERY_CONTENT_SERIALIZED_CTL: 4666 ret = dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CTL; 4667 break; 4668 default: 4669 /* The remaining types contain more than one type, so allow 4670 * any combination. 4671 */ 4672 ret = TRUE; 4673 } 4674 } 4675 else 4676 { 4677 /* No allowed types specified, so any type is allowed */ 4678 ret = TRUE; 4679 } 4680 if (!ret) 4681 SetLastError(E_INVALIDARG); 4682 return ret; 4683 } 4684 4685 4686 static void import_warning(DWORD dwFlags, HWND hwnd, LPCWSTR szTitle, 4687 int warningID) 4688 { 4689 if (!(dwFlags & CRYPTUI_WIZ_NO_UI)) 4690 { 4691 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN]; 4692 LPCWSTR pTitle; 4693 4694 if (szTitle) 4695 pTitle = szTitle; 4696 else 4697 { 4698 LoadStringW(hInstance, IDS_IMPORT_WIZARD, title, 4699 sizeof(title) / sizeof(title[0])); 4700 pTitle = title; 4701 } 4702 LoadStringW(hInstance, warningID, error, 4703 sizeof(error) / sizeof(error[0])); 4704 MessageBoxW(hwnd, error, pTitle, MB_ICONERROR | MB_OK); 4705 } 4706 } 4707 4708 static void import_warn_type_mismatch(DWORD dwFlags, HWND hwnd, LPCWSTR szTitle) 4709 { 4710 import_warning(dwFlags, hwnd, szTitle, IDS_IMPORT_TYPE_MISMATCH); 4711 } 4712 4713 static BOOL check_store_context_type(DWORD dwFlags, HCERTSTORE store) 4714 { 4715 BOOL ret; 4716 4717 if (dwFlags & 4718 (CRYPTUI_WIZ_IMPORT_ALLOW_CERT | CRYPTUI_WIZ_IMPORT_ALLOW_CRL | 4719 CRYPTUI_WIZ_IMPORT_ALLOW_CTL)) 4720 { 4721 PCCERT_CONTEXT cert; 4722 PCCRL_CONTEXT crl; 4723 PCCTL_CONTEXT ctl; 4724 4725 ret = TRUE; 4726 if ((cert = CertEnumCertificatesInStore(store, NULL))) 4727 { 4728 CertFreeCertificateContext(cert); 4729 if (!(dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CERT)) 4730 ret = FALSE; 4731 } 4732 if (ret && (crl = CertEnumCRLsInStore(store, NULL))) 4733 { 4734 CertFreeCRLContext(crl); 4735 if (!(dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CRL)) 4736 ret = FALSE; 4737 } 4738 if (ret && (ctl = CertEnumCTLsInStore(store, NULL))) 4739 { 4740 CertFreeCTLContext(ctl); 4741 if (!(dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CTL)) 4742 ret = FALSE; 4743 } 4744 } 4745 else 4746 ret = TRUE; 4747 if (!ret) 4748 SetLastError(E_INVALIDARG); 4749 return ret; 4750 } 4751 4752 static BOOL import_store(DWORD dwFlags, HWND hwnd, LPCWSTR szTitle, 4753 HCERTSTORE source, HCERTSTORE dest) 4754 { 4755 BOOL ret; 4756 4757 if ((ret = check_store_context_type(dwFlags, source))) 4758 { 4759 PCCERT_CONTEXT cert = NULL; 4760 PCCRL_CONTEXT crl = NULL; 4761 PCCTL_CONTEXT ctl = NULL; 4762 4763 do { 4764 cert = CertEnumCertificatesInStore(source, cert); 4765 if (cert) 4766 ret = import_cert(cert, dest); 4767 } while (ret && cert); 4768 do { 4769 crl = CertEnumCRLsInStore(source, crl); 4770 if (crl) 4771 ret = import_crl(crl, dest); 4772 } while (ret && crl); 4773 do { 4774 ctl = CertEnumCTLsInStore(source, ctl); 4775 if (ctl) 4776 ret = import_ctl(ctl, dest); 4777 } while (ret && ctl); 4778 } 4779 else 4780 import_warn_type_mismatch(dwFlags, hwnd, szTitle); 4781 return ret; 4782 } 4783 4784 static HCERTSTORE open_store_from_file(DWORD dwFlags, LPCWSTR fileName, 4785 DWORD *pContentType) 4786 { 4787 HCERTSTORE store = NULL; 4788 DWORD contentType = 0, expectedContentTypeFlags; 4789 4790 if (dwFlags & 4791 (CRYPTUI_WIZ_IMPORT_ALLOW_CERT | CRYPTUI_WIZ_IMPORT_ALLOW_CRL | 4792 CRYPTUI_WIZ_IMPORT_ALLOW_CTL)) 4793 { 4794 expectedContentTypeFlags = 4795 CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE | 4796 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED | 4797 CERT_QUERY_CONTENT_FLAG_PFX; 4798 if (dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CERT) 4799 expectedContentTypeFlags |= 4800 CERT_QUERY_CONTENT_FLAG_CERT | 4801 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT; 4802 if (dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CRL) 4803 expectedContentTypeFlags |= 4804 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL | 4805 CERT_QUERY_CONTENT_FLAG_CRL; 4806 if (dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CTL) 4807 expectedContentTypeFlags |= 4808 CERT_QUERY_CONTENT_FLAG_CTL | 4809 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL; 4810 } 4811 else 4812 expectedContentTypeFlags = 4813 CERT_QUERY_CONTENT_FLAG_CERT | 4814 CERT_QUERY_CONTENT_FLAG_CTL | 4815 CERT_QUERY_CONTENT_FLAG_CRL | 4816 CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE | 4817 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT | 4818 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL | 4819 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL | 4820 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED | 4821 CERT_QUERY_CONTENT_FLAG_PFX; 4822 4823 CryptQueryObject(CERT_QUERY_OBJECT_FILE, fileName, 4824 expectedContentTypeFlags, CERT_QUERY_FORMAT_FLAG_ALL, 0, NULL, 4825 &contentType, NULL, &store, NULL, NULL); 4826 if (pContentType) 4827 *pContentType = contentType; 4828 return store; 4829 } 4830 4831 static BOOL import_file(DWORD dwFlags, HWND hwnd, LPCWSTR szTitle, 4832 LPCWSTR fileName, HCERTSTORE dest) 4833 { 4834 HCERTSTORE source; 4835 BOOL ret; 4836 4837 if ((source = open_store_from_file(dwFlags, fileName, NULL))) 4838 { 4839 ret = import_store(dwFlags, hwnd, szTitle, source, dest); 4840 CertCloseStore(source, 0); 4841 } 4842 else 4843 ret = FALSE; 4844 return ret; 4845 } 4846 4847 struct ImportWizData 4848 { 4849 HFONT titleFont; 4850 DWORD dwFlags; 4851 LPCWSTR pwszWizardTitle; 4852 CRYPTUI_WIZ_IMPORT_SRC_INFO importSrc; 4853 LPWSTR fileName; 4854 DWORD contentType; 4855 BOOL freeSource; 4856 HCERTSTORE hDestCertStore; 4857 BOOL freeDest; 4858 BOOL autoDest; 4859 BOOL success; 4860 }; 4861 4862 static LRESULT CALLBACK import_welcome_dlg_proc(HWND hwnd, UINT msg, WPARAM wp, 4863 LPARAM lp) 4864 { 4865 LRESULT ret = 0; 4866 4867 switch (msg) 4868 { 4869 case WM_INITDIALOG: 4870 { 4871 struct ImportWizData *data; 4872 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp; 4873 WCHAR fontFace[MAX_STRING_LEN]; 4874 HDC hDC = GetDC(hwnd); 4875 int height; 4876 4877 data = (struct ImportWizData *)page->lParam; 4878 LoadStringW(hInstance, IDS_WIZARD_TITLE_FONT, fontFace, 4879 sizeof(fontFace) / sizeof(fontFace[0])); 4880 height = -MulDiv(12, GetDeviceCaps(hDC, LOGPIXELSY), 72); 4881 data->titleFont = CreateFontW(height, 0, 0, 0, FW_BOLD, 0, 0, 0, 4882 DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, 4883 DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, fontFace); 4884 SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_TITLE), WM_SETFONT, 4885 (WPARAM)data->titleFont, TRUE); 4886 ReleaseDC(hwnd, hDC); 4887 break; 4888 } 4889 case WM_NOTIFY: 4890 { 4891 NMHDR *hdr = (NMHDR *)lp; 4892 4893 switch (hdr->code) 4894 { 4895 case PSN_SETACTIVE: 4896 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0, PSWIZB_NEXT); 4897 ret = TRUE; 4898 break; 4899 } 4900 break; 4901 } 4902 } 4903 return ret; 4904 } 4905 4906 static const WCHAR filter_cert[] = { '*','.','c','e','r',';','*','.', 4907 'c','r','t',0 }; 4908 static const WCHAR filter_pfx[] = { '*','.','p','f','x',';','*','.', 4909 'p','1','2',0 }; 4910 static const WCHAR filter_crl[] = { '*','.','c','r','l',0 }; 4911 static const WCHAR filter_ctl[] = { '*','.','s','t','l',0 }; 4912 static const WCHAR filter_serialized_store[] = { '*','.','s','s','t',0 }; 4913 static const WCHAR filter_cms[] = { '*','.','s','p','c',';','*','.', 4914 'p','7','b',0 }; 4915 static const WCHAR filter_all[] = { '*','.','*',0 }; 4916 4917 static struct StringToFilter 4918 { 4919 int id; 4920 DWORD allowFlags; 4921 LPCWSTR filter; 4922 } import_filters[] = { 4923 { IDS_IMPORT_FILTER_CERT, CRYPTUI_WIZ_IMPORT_ALLOW_CERT, filter_cert }, 4924 { IDS_IMPORT_FILTER_PFX, 0, filter_pfx }, 4925 { IDS_IMPORT_FILTER_CRL, CRYPTUI_WIZ_IMPORT_ALLOW_CRL, filter_crl }, 4926 { IDS_IMPORT_FILTER_CTL, CRYPTUI_WIZ_IMPORT_ALLOW_CTL, filter_ctl }, 4927 { IDS_IMPORT_FILTER_SERIALIZED_STORE, 0, filter_serialized_store }, 4928 { IDS_IMPORT_FILTER_CMS, 0, filter_cms }, 4929 { IDS_IMPORT_FILTER_ALL, 0, filter_all }, 4930 }; 4931 4932 static WCHAR *make_import_file_filter(DWORD dwFlags) 4933 { 4934 DWORD i; 4935 int len, totalLen = 2; 4936 LPWSTR filter = NULL, str; 4937 4938 for (i = 0; i < sizeof(import_filters) / sizeof(import_filters[0]); i++) 4939 { 4940 if (!import_filters[i].allowFlags || !dwFlags || 4941 (dwFlags & import_filters[i].allowFlags)) 4942 { 4943 len = LoadStringW(hInstance, import_filters[i].id, (LPWSTR)&str, 0); 4944 totalLen += len + strlenW(import_filters[i].filter) + 2; 4945 } 4946 } 4947 filter = HeapAlloc(GetProcessHeap(), 0, totalLen * sizeof(WCHAR)); 4948 if (filter) 4949 { 4950 LPWSTR ptr; 4951 4952 ptr = filter; 4953 for (i = 0; i < sizeof(import_filters) / sizeof(import_filters[0]); i++) 4954 { 4955 if (!import_filters[i].allowFlags || !dwFlags || 4956 (dwFlags & import_filters[i].allowFlags)) 4957 { 4958 len = LoadStringW(hInstance, import_filters[i].id, 4959 (LPWSTR)&str, 0); 4960 memcpy(ptr, str, len * sizeof(WCHAR)); 4961 ptr += len; 4962 *ptr++ = 0; 4963 strcpyW(ptr, import_filters[i].filter); 4964 ptr += strlenW(import_filters[i].filter) + 1; 4965 } 4966 } 4967 *ptr++ = 0; 4968 } 4969 return filter; 4970 } 4971 4972 static BOOL import_validate_filename(HWND hwnd, struct ImportWizData *data, 4973 LPCWSTR fileName) 4974 { 4975 HANDLE file; 4976 BOOL ret = FALSE; 4977 4978 file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, 4979 OPEN_EXISTING, 0, NULL); 4980 if (file != INVALID_HANDLE_VALUE) 4981 { 4982 HCERTSTORE source = open_store_from_file(data->dwFlags, fileName, 4983 &data->contentType); 4984 int warningID = 0; 4985 4986 if (!source) 4987 warningID = IDS_IMPORT_BAD_FORMAT; 4988 else if (!check_store_context_type(data->dwFlags, source)) 4989 warningID = IDS_IMPORT_TYPE_MISMATCH; 4990 else 4991 { 4992 data->importSrc.dwSubjectChoice = 4993 CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE; 4994 data->importSrc.u.hCertStore = source; 4995 data->freeSource = TRUE; 4996 ret = TRUE; 4997 } 4998 if (warningID) 4999 { 5000 import_warning(data->dwFlags, hwnd, data->pwszWizardTitle, 5001 warningID); 5002 } 5003 CloseHandle(file); 5004 } 5005 else 5006 { 5007 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN]; 5008 LPCWSTR pTitle; 5009 LPWSTR msgBuf, fullError; 5010 5011 if (data->pwszWizardTitle) 5012 pTitle = data->pwszWizardTitle; 5013 else 5014 { 5015 LoadStringW(hInstance, IDS_IMPORT_WIZARD, title, 5016 sizeof(title) / sizeof(title[0])); 5017 pTitle = title; 5018 } 5019 LoadStringW(hInstance, IDS_IMPORT_OPEN_FAILED, error, 5020 sizeof(error) / sizeof(error[0])); 5021 FormatMessageW( 5022 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, 5023 GetLastError(), 0, (LPWSTR) &msgBuf, 0, NULL); 5024 fullError = HeapAlloc(GetProcessHeap(), 0, 5025 (strlenW(error) + strlenW(fileName) + strlenW(msgBuf) + 3) 5026 * sizeof(WCHAR)); 5027 if (fullError) 5028 { 5029 LPWSTR ptr = fullError; 5030 5031 strcpyW(ptr, error); 5032 ptr += strlenW(error); 5033 strcpyW(ptr, fileName); 5034 ptr += strlenW(fileName); 5035 *ptr++ = ':'; 5036 *ptr++ = '\n'; 5037 strcpyW(ptr, msgBuf); 5038 MessageBoxW(hwnd, fullError, pTitle, MB_ICONERROR | MB_OK); 5039 HeapFree(GetProcessHeap(), 0, fullError); 5040 } 5041 LocalFree(msgBuf); 5042 } 5043 return ret; 5044 } 5045 5046 static LRESULT CALLBACK import_file_dlg_proc(HWND hwnd, UINT msg, WPARAM wp, 5047 LPARAM lp) 5048 { 5049 LRESULT ret = 0; 5050 struct ImportWizData *data; 5051 5052 switch (msg) 5053 { 5054 case WM_INITDIALOG: 5055 { 5056 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp; 5057 5058 data = (struct ImportWizData *)page->lParam; 5059 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data); 5060 if (data->fileName) 5061 { 5062 HWND fileNameEdit = GetDlgItem(hwnd, IDC_IMPORT_FILENAME); 5063 5064 SendMessageW(fileNameEdit, WM_SETTEXT, 0, (LPARAM)data->fileName); 5065 } 5066 break; 5067 } 5068 case WM_NOTIFY: 5069 { 5070 NMHDR *hdr = (NMHDR *)lp; 5071 5072 switch (hdr->code) 5073 { 5074 case PSN_SETACTIVE: 5075 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0, 5076 PSWIZB_BACK | PSWIZB_NEXT); 5077 ret = TRUE; 5078 break; 5079 case PSN_WIZNEXT: 5080 { 5081 HWND fileNameEdit = GetDlgItem(hwnd, IDC_IMPORT_FILENAME); 5082 DWORD len = SendMessageW(fileNameEdit, WM_GETTEXTLENGTH, 0, 0); 5083 5084 data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER); 5085 if (!len) 5086 { 5087 import_warning(data->dwFlags, hwnd, data->pwszWizardTitle, 5088 IDS_IMPORT_EMPTY_FILE); 5089 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1); 5090 ret = 1; 5091 } 5092 else 5093 { 5094 LPWSTR fileName = HeapAlloc(GetProcessHeap(), 0, 5095 (len + 1) * sizeof(WCHAR)); 5096 5097 if (fileName) 5098 { 5099 SendMessageW(fileNameEdit, WM_GETTEXT, len + 1, 5100 (LPARAM)fileName); 5101 if (!import_validate_filename(hwnd, data, fileName)) 5102 { 5103 HeapFree(GetProcessHeap(), 0, fileName); 5104 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1); 5105 ret = 1; 5106 } 5107 else 5108 data->fileName = fileName; 5109 } 5110 } 5111 break; 5112 } 5113 } 5114 break; 5115 } 5116 case WM_COMMAND: 5117 switch (wp) 5118 { 5119 case IDC_IMPORT_BROWSE_FILE: 5120 { 5121 OPENFILENAMEW ofn; 5122 WCHAR fileBuf[MAX_PATH]; 5123 5124 data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER); 5125 memset(&ofn, 0, sizeof(ofn)); 5126 ofn.lStructSize = sizeof(ofn); 5127 ofn.hwndOwner = hwnd; 5128 ofn.lpstrFilter = make_import_file_filter(data->dwFlags); 5129 ofn.lpstrFile = fileBuf; 5130 ofn.nMaxFile = sizeof(fileBuf) / sizeof(fileBuf[0]); 5131 fileBuf[0] = 0; 5132 if (GetOpenFileNameW(&ofn)) 5133 SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_FILENAME), WM_SETTEXT, 5134 0, (LPARAM)ofn.lpstrFile); 5135 HeapFree(GetProcessHeap(), 0, (LPWSTR)ofn.lpstrFilter); 5136 break; 5137 } 5138 } 5139 break; 5140 } 5141 return ret; 5142 } 5143 5144 static LRESULT CALLBACK import_store_dlg_proc(HWND hwnd, UINT msg, WPARAM wp, 5145 LPARAM lp) 5146 { 5147 LRESULT ret = 0; 5148 struct ImportWizData *data; 5149 5150 switch (msg) 5151 { 5152 case WM_INITDIALOG: 5153 { 5154 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp; 5155 5156 data = (struct ImportWizData *)page->lParam; 5157 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data); 5158 if (!data->hDestCertStore) 5159 { 5160 SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_AUTO_STORE), BM_CLICK, 5161 0, 0); 5162 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_STORE), FALSE); 5163 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_BROWSE_STORE), FALSE); 5164 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_SPECIFY_STORE), FALSE); 5165 } 5166 else 5167 { 5168 WCHAR storeTitle[MAX_STRING_LEN]; 5169 5170 SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_SPECIFY_STORE), BM_CLICK, 5171 0, 0); 5172 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_STORE), TRUE); 5173 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_BROWSE_STORE), TRUE); 5174 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_SPECIFY_STORE), 5175 !(data->dwFlags & CRYPTUI_WIZ_IMPORT_NO_CHANGE_DEST_STORE)); 5176 LoadStringW(hInstance, IDS_IMPORT_DEST_DETERMINED, 5177 storeTitle, sizeof(storeTitle) / sizeof(storeTitle[0])); 5178 SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_STORE), WM_SETTEXT, 5179 0, (LPARAM)storeTitle); 5180 } 5181 break; 5182 } 5183 case WM_NOTIFY: 5184 { 5185 NMHDR *hdr = (NMHDR *)lp; 5186 5187 switch (hdr->code) 5188 { 5189 case PSN_SETACTIVE: 5190 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0, 5191 PSWIZB_BACK | PSWIZB_NEXT); 5192 ret = TRUE; 5193 break; 5194 case PSN_WIZNEXT: 5195 { 5196 data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER); 5197 if (IsDlgButtonChecked(hwnd, IDC_IMPORT_SPECIFY_STORE) && 5198 !data->hDestCertStore) 5199 { 5200 import_warning(data->dwFlags, hwnd, data->pwszWizardTitle, 5201 IDS_IMPORT_SELECT_STORE); 5202 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1); 5203 ret = 1; 5204 } 5205 break; 5206 } 5207 } 5208 break; 5209 } 5210 case WM_COMMAND: 5211 switch (wp) 5212 { 5213 case IDC_IMPORT_AUTO_STORE: 5214 data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER); 5215 data->autoDest = TRUE; 5216 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_STORE), FALSE); 5217 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_BROWSE_STORE), FALSE); 5218 break; 5219 case IDC_IMPORT_SPECIFY_STORE: 5220 data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER); 5221 data->autoDest = FALSE; 5222 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_STORE), TRUE); 5223 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_BROWSE_STORE), TRUE); 5224 break; 5225 case IDC_IMPORT_BROWSE_STORE: 5226 { 5227 CRYPTUI_ENUM_SYSTEM_STORE_ARGS enumArgs = { 5228 CERT_SYSTEM_STORE_CURRENT_USER, NULL }; 5229 CRYPTUI_ENUM_DATA enumData = { 0, NULL, 1, &enumArgs }; 5230 CRYPTUI_SELECTSTORE_INFO_W selectInfo; 5231 HCERTSTORE store; 5232 5233 data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER); 5234 selectInfo.dwSize = sizeof(selectInfo); 5235 selectInfo.parent = hwnd; 5236 selectInfo.dwFlags = CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE; 5237 selectInfo.pwszTitle = NULL; 5238 selectInfo.pwszText = NULL; 5239 selectInfo.pEnumData = &enumData; 5240 selectInfo.pfnSelectedStoreCallback = NULL; 5241 if ((store = CryptUIDlgSelectStoreW(&selectInfo))) 5242 { 5243 WCHAR storeTitle[MAX_STRING_LEN]; 5244 5245 LoadStringW(hInstance, IDS_IMPORT_DEST_DETERMINED, 5246 storeTitle, sizeof(storeTitle) / sizeof(storeTitle[0])); 5247 SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_STORE), WM_SETTEXT, 5248 0, (LPARAM)storeTitle); 5249 data->hDestCertStore = store; 5250 data->freeDest = TRUE; 5251 } 5252 break; 5253 } 5254 } 5255 break; 5256 } 5257 return ret; 5258 } 5259 5260 static void show_import_details(HWND lv, struct ImportWizData *data) 5261 { 5262 WCHAR text[MAX_STRING_LEN]; 5263 LVITEMW item; 5264 int contentID; 5265 5266 item.mask = LVIF_TEXT; 5267 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0); 5268 item.iSubItem = 0; 5269 LoadStringW(hInstance, IDS_IMPORT_STORE_SELECTION, text, 5270 sizeof(text)/ sizeof(text[0])); 5271 item.pszText = text; 5272 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item); 5273 item.iSubItem = 1; 5274 if (data->autoDest) 5275 LoadStringW(hInstance, IDS_IMPORT_DEST_AUTOMATIC, text, 5276 sizeof(text)/ sizeof(text[0])); 5277 else 5278 LoadStringW(hInstance, IDS_IMPORT_DEST_DETERMINED, text, 5279 sizeof(text)/ sizeof(text[0])); 5280 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item); 5281 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0); 5282 item.iSubItem = 0; 5283 LoadStringW(hInstance, IDS_IMPORT_CONTENT, text, 5284 sizeof(text)/ sizeof(text[0])); 5285 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item); 5286 switch (data->contentType) 5287 { 5288 case CERT_QUERY_CONTENT_CERT: 5289 case CERT_QUERY_CONTENT_SERIALIZED_CERT: 5290 contentID = IDS_IMPORT_CONTENT_CERT; 5291 break; 5292 case CERT_QUERY_CONTENT_CRL: 5293 case CERT_QUERY_CONTENT_SERIALIZED_CRL: 5294 contentID = IDS_IMPORT_CONTENT_CRL; 5295 break; 5296 case CERT_QUERY_CONTENT_CTL: 5297 case CERT_QUERY_CONTENT_SERIALIZED_CTL: 5298 contentID = IDS_IMPORT_CONTENT_CTL; 5299 break; 5300 case CERT_QUERY_CONTENT_PKCS7_SIGNED: 5301 contentID = IDS_IMPORT_CONTENT_CMS; 5302 break; 5303 case CERT_QUERY_CONTENT_FLAG_PFX: 5304 contentID = IDS_IMPORT_CONTENT_PFX; 5305 break; 5306 default: 5307 contentID = IDS_IMPORT_CONTENT_STORE; 5308 break; 5309 } 5310 LoadStringW(hInstance, contentID, text, sizeof(text)/ sizeof(text[0])); 5311 item.iSubItem = 1; 5312 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item); 5313 if (data->fileName) 5314 { 5315 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0); 5316 item.iSubItem = 0; 5317 LoadStringW(hInstance, IDS_IMPORT_FILE, text, 5318 sizeof(text)/ sizeof(text[0])); 5319 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item); 5320 item.iSubItem = 1; 5321 item.pszText = data->fileName; 5322 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item); 5323 } 5324 } 5325 5326 static BOOL do_import(DWORD dwFlags, HWND hwndParent, LPCWSTR pwszWizardTitle, 5327 PCCRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc, HCERTSTORE hDestCertStore) 5328 { 5329 BOOL ret; 5330 5331 switch (pImportSrc->dwSubjectChoice) 5332 { 5333 case CRYPTUI_WIZ_IMPORT_SUBJECT_FILE: 5334 ret = import_file(dwFlags, hwndParent, pwszWizardTitle, 5335 pImportSrc->u.pwszFileName, hDestCertStore); 5336 break; 5337 case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_CONTEXT: 5338 if ((ret = check_context_type(dwFlags, CERT_QUERY_CONTENT_CERT))) 5339 ret = import_cert(pImportSrc->u.pCertContext, hDestCertStore); 5340 else 5341 import_warn_type_mismatch(dwFlags, hwndParent, pwszWizardTitle); 5342 break; 5343 case CRYPTUI_WIZ_IMPORT_SUBJECT_CRL_CONTEXT: 5344 if ((ret = check_context_type(dwFlags, CERT_QUERY_CONTENT_CRL))) 5345 ret = import_crl(pImportSrc->u.pCRLContext, hDestCertStore); 5346 else 5347 import_warn_type_mismatch(dwFlags, hwndParent, pwszWizardTitle); 5348 break; 5349 case CRYPTUI_WIZ_IMPORT_SUBJECT_CTL_CONTEXT: 5350 if ((ret = check_context_type(dwFlags, CERT_QUERY_CONTENT_CTL))) 5351 ret = import_ctl(pImportSrc->u.pCTLContext, hDestCertStore); 5352 else 5353 import_warn_type_mismatch(dwFlags, hwndParent, pwszWizardTitle); 5354 break; 5355 case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE: 5356 ret = import_store(dwFlags, hwndParent, pwszWizardTitle, 5357 pImportSrc->u.hCertStore, hDestCertStore); 5358 break; 5359 default: 5360 WARN("unknown source type: %u\n", pImportSrc->dwSubjectChoice); 5361 SetLastError(E_INVALIDARG); 5362 ret = FALSE; 5363 } 5364 return ret; 5365 } 5366 5367 static LRESULT CALLBACK import_finish_dlg_proc(HWND hwnd, UINT msg, WPARAM wp, 5368 LPARAM lp) 5369 { 5370 LRESULT ret = 0; 5371 struct ImportWizData *data; 5372 5373 switch (msg) 5374 { 5375 case WM_INITDIALOG: 5376 { 5377 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp; 5378 HWND lv = GetDlgItem(hwnd, IDC_IMPORT_SETTINGS); 5379 RECT rc; 5380 LVCOLUMNW column; 5381 5382 data = (struct ImportWizData *)page->lParam; 5383 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data); 5384 SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_TITLE), WM_SETFONT, 5385 (WPARAM)data->titleFont, TRUE); 5386 GetWindowRect(lv, &rc); 5387 column.mask = LVCF_WIDTH; 5388 column.cx = (rc.right - rc.left) / 2 - 2; 5389 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column); 5390 SendMessageW(lv, LVM_INSERTCOLUMNW, 1, (LPARAM)&column); 5391 show_import_details(lv, data); 5392 break; 5393 } 5394 case WM_NOTIFY: 5395 { 5396 NMHDR *hdr = (NMHDR *)lp; 5397 5398 switch (hdr->code) 5399 { 5400 case PSN_SETACTIVE: 5401 { 5402 HWND lv = GetDlgItem(hwnd, IDC_IMPORT_SETTINGS); 5403 5404 data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER); 5405 SendMessageW(lv, LVM_DELETEALLITEMS, 0, 0); 5406 show_import_details(lv, data); 5407 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0, 5408 PSWIZB_BACK | PSWIZB_FINISH); 5409 ret = TRUE; 5410 break; 5411 } 5412 case PSN_WIZFINISH: 5413 { 5414 data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER); 5415 if ((data->success = do_import(data->dwFlags, hwnd, 5416 data->pwszWizardTitle, &data->importSrc, data->hDestCertStore))) 5417 { 5418 WCHAR title[MAX_STRING_LEN], message[MAX_STRING_LEN]; 5419 LPCWSTR pTitle; 5420 5421 if (data->pwszWizardTitle) 5422 pTitle = data->pwszWizardTitle; 5423 else 5424 { 5425 LoadStringW(hInstance, IDS_IMPORT_WIZARD, title, 5426 sizeof(title) / sizeof(title[0])); 5427 pTitle = title; 5428 } 5429 LoadStringW(hInstance, IDS_IMPORT_SUCCEEDED, message, 5430 sizeof(message) / sizeof(message[0])); 5431 MessageBoxW(hwnd, message, pTitle, MB_OK); 5432 } 5433 else 5434 import_warning(data->dwFlags, hwnd, data->pwszWizardTitle, 5435 IDS_IMPORT_FAILED); 5436 break; 5437 } 5438 } 5439 break; 5440 } 5441 } 5442 return ret; 5443 } 5444 5445 static BOOL show_import_ui(DWORD dwFlags, HWND hwndParent, 5446 LPCWSTR pwszWizardTitle, PCCRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc, 5447 HCERTSTORE hDestCertStore) 5448 { 5449 PROPSHEETHEADERW hdr; 5450 PROPSHEETPAGEW pages[4]; 5451 struct ImportWizData data; 5452 int nPages = 0; 5453 5454 data.dwFlags = dwFlags; 5455 data.pwszWizardTitle = pwszWizardTitle; 5456 if (pImportSrc) 5457 { 5458 memcpy(&data.importSrc, pImportSrc, sizeof(data.importSrc)); 5459 data.fileName = (LPWSTR)pImportSrc->u.pwszFileName; 5460 } 5461 else 5462 { 5463 memset(&data.importSrc, 0, sizeof(data.importSrc)); 5464 data.fileName = NULL; 5465 } 5466 data.freeSource = FALSE; 5467 data.hDestCertStore = hDestCertStore; 5468 data.freeDest = FALSE; 5469 data.autoDest = TRUE; 5470 data.success = TRUE; 5471 5472 memset(pages, 0, sizeof(pages)); 5473 5474 pages[nPages].dwSize = sizeof(pages[0]); 5475 pages[nPages].hInstance = hInstance; 5476 pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_IMPORT_WELCOME); 5477 pages[nPages].pfnDlgProc = import_welcome_dlg_proc; 5478 pages[nPages].dwFlags = PSP_HIDEHEADER; 5479 pages[nPages].lParam = (LPARAM)&data; 5480 nPages++; 5481 5482 if (!pImportSrc || 5483 pImportSrc->dwSubjectChoice == CRYPTUI_WIZ_IMPORT_SUBJECT_FILE) 5484 { 5485 pages[nPages].dwSize = sizeof(pages[0]); 5486 pages[nPages].hInstance = hInstance; 5487 pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_IMPORT_FILE); 5488 pages[nPages].pfnDlgProc = import_file_dlg_proc; 5489 pages[nPages].dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE; 5490 pages[nPages].pszHeaderTitle = MAKEINTRESOURCEW(IDS_IMPORT_FILE_TITLE); 5491 pages[nPages].pszHeaderSubTitle = 5492 MAKEINTRESOURCEW(IDS_IMPORT_FILE_SUBTITLE); 5493 pages[nPages].lParam = (LPARAM)&data; 5494 nPages++; 5495 } 5496 else 5497 { 5498 switch (pImportSrc->dwSubjectChoice) 5499 { 5500 case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_CONTEXT: 5501 data.contentType = CERT_QUERY_CONTENT_CERT; 5502 break; 5503 case CRYPTUI_WIZ_IMPORT_SUBJECT_CRL_CONTEXT: 5504 data.contentType = CERT_QUERY_CONTENT_CRL; 5505 break; 5506 case CRYPTUI_WIZ_IMPORT_SUBJECT_CTL_CONTEXT: 5507 data.contentType = CERT_QUERY_CONTENT_CTL; 5508 break; 5509 case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE: 5510 data.contentType = CERT_QUERY_CONTENT_SERIALIZED_STORE; 5511 break; 5512 } 5513 } 5514 5515 pages[nPages].dwSize = sizeof(pages[0]); 5516 pages[nPages].hInstance = hInstance; 5517 pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_IMPORT_STORE); 5518 pages[nPages].pfnDlgProc = import_store_dlg_proc; 5519 pages[nPages].dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE; 5520 pages[nPages].pszHeaderTitle = MAKEINTRESOURCEW(IDS_IMPORT_STORE_TITLE); 5521 pages[nPages].pszHeaderSubTitle = 5522 MAKEINTRESOURCEW(IDS_IMPORT_STORE_SUBTITLE); 5523 pages[nPages].lParam = (LPARAM)&data; 5524 nPages++; 5525 5526 pages[nPages].dwSize = sizeof(pages[0]); 5527 pages[nPages].hInstance = hInstance; 5528 pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_IMPORT_FINISH); 5529 pages[nPages].pfnDlgProc = import_finish_dlg_proc; 5530 pages[nPages].dwFlags = PSP_HIDEHEADER; 5531 pages[nPages].lParam = (LPARAM)&data; 5532 nPages++; 5533 5534 memset(&hdr, 0, sizeof(hdr)); 5535 hdr.dwSize = sizeof(hdr); 5536 hdr.hwndParent = hwndParent; 5537 hdr.dwFlags = PSH_PROPSHEETPAGE | PSH_WIZARD97_NEW | PSH_HEADER | 5538 PSH_WATERMARK; 5539 hdr.hInstance = hInstance; 5540 if (pwszWizardTitle) 5541 hdr.pszCaption = pwszWizardTitle; 5542 else 5543 hdr.pszCaption = MAKEINTRESOURCEW(IDS_IMPORT_WIZARD); 5544 hdr.u3.ppsp = pages; 5545 hdr.nPages = nPages; 5546 hdr.u4.pszbmWatermark = MAKEINTRESOURCEW(IDB_CERT_WATERMARK); 5547 hdr.u5.pszbmHeader = MAKEINTRESOURCEW(IDB_CERT_HEADER); 5548 PropertySheetW(&hdr); 5549 if (data.fileName != data.importSrc.u.pwszFileName) 5550 HeapFree(GetProcessHeap(), 0, data.fileName); 5551 if (data.freeSource && 5552 data.importSrc.dwSubjectChoice == CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE) 5553 CertCloseStore(data.importSrc.u.hCertStore, 0); 5554 DeleteObject(data.titleFont); 5555 return data.success; 5556 } 5557 5558 BOOL WINAPI CryptUIWizImport(DWORD dwFlags, HWND hwndParent, LPCWSTR pwszWizardTitle, 5559 PCCRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc, HCERTSTORE hDestCertStore) 5560 { 5561 BOOL ret; 5562 5563 TRACE("(0x%08x, %p, %s, %p, %p)\n", dwFlags, hwndParent, debugstr_w(pwszWizardTitle), 5564 pImportSrc, hDestCertStore); 5565 5566 if (pImportSrc && 5567 pImportSrc->dwSize != sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO)) 5568 { 5569 SetLastError(E_INVALIDARG); 5570 return FALSE; 5571 } 5572 5573 if (!(dwFlags & CRYPTUI_WIZ_NO_UI)) 5574 ret = show_import_ui(dwFlags, hwndParent, pwszWizardTitle, pImportSrc, 5575 hDestCertStore); 5576 else if (pImportSrc) 5577 ret = do_import(dwFlags, hwndParent, pwszWizardTitle, pImportSrc, 5578 hDestCertStore); 5579 else 5580 { 5581 /* Can't have no UI without specifying source */ 5582 SetLastError(E_INVALIDARG); 5583 ret = FALSE; 5584 } 5585 5586 return ret; 5587 } 5588 5589 struct ExportWizData 5590 { 5591 HFONT titleFont; 5592 DWORD dwFlags; 5593 LPCWSTR pwszWizardTitle; 5594 CRYPTUI_WIZ_EXPORT_INFO exportInfo; 5595 CRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO contextInfo; 5596 BOOL freePassword; 5597 PCRYPT_KEY_PROV_INFO keyProvInfo; 5598 BOOL deleteKeys; 5599 LPWSTR fileName; 5600 HANDLE file; 5601 BOOL success; 5602 }; 5603 5604 static LRESULT CALLBACK export_welcome_dlg_proc(HWND hwnd, UINT msg, WPARAM wp, 5605 LPARAM lp) 5606 { 5607 LRESULT ret = 0; 5608 5609 switch (msg) 5610 { 5611 case WM_INITDIALOG: 5612 { 5613 struct ExportWizData *data; 5614 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp; 5615 WCHAR fontFace[MAX_STRING_LEN]; 5616 HDC hDC = GetDC(hwnd); 5617 int height; 5618 5619 data = (struct ExportWizData *)page->lParam; 5620 LoadStringW(hInstance, IDS_WIZARD_TITLE_FONT, fontFace, 5621 sizeof(fontFace) / sizeof(fontFace[0])); 5622 height = -MulDiv(12, GetDeviceCaps(hDC, LOGPIXELSY), 72); 5623 data->titleFont = CreateFontW(height, 0, 0, 0, FW_BOLD, 0, 0, 0, 5624 DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, 5625 DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, fontFace); 5626 SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_TITLE), WM_SETFONT, 5627 (WPARAM)data->titleFont, TRUE); 5628 ReleaseDC(hwnd, hDC); 5629 break; 5630 } 5631 case WM_NOTIFY: 5632 { 5633 NMHDR *hdr = (NMHDR *)lp; 5634 5635 switch (hdr->code) 5636 { 5637 case PSN_SETACTIVE: 5638 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0, PSWIZB_NEXT); 5639 ret = TRUE; 5640 break; 5641 } 5642 break; 5643 } 5644 } 5645 return ret; 5646 } 5647 5648 static PCRYPT_KEY_PROV_INFO export_get_private_key_info(PCCERT_CONTEXT cert) 5649 { 5650 PCRYPT_KEY_PROV_INFO info = NULL; 5651 DWORD size; 5652 5653 if (CertGetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, 5654 NULL, &size)) 5655 { 5656 info = HeapAlloc(GetProcessHeap(), 0, size); 5657 if (info) 5658 { 5659 if (!CertGetCertificateContextProperty(cert, 5660 CERT_KEY_PROV_INFO_PROP_ID, info, &size)) 5661 { 5662 HeapFree(GetProcessHeap(), 0, info); 5663 info = NULL; 5664 } 5665 } 5666 } 5667 return info; 5668 } 5669 5670 static BOOL export_acquire_private_key(const CRYPT_KEY_PROV_INFO *info, 5671 HCRYPTPROV *phProv) 5672 { 5673 BOOL ret; 5674 5675 ret = CryptAcquireContextW(phProv, info->pwszContainerName, 5676 info->pwszProvName, info->dwProvType, 0); 5677 if (ret) 5678 { 5679 DWORD i; 5680 5681 for (i = 0; i < info->cProvParam; i++) 5682 CryptSetProvParam(*phProv, info->rgProvParam[i].dwParam, 5683 info->rgProvParam[i].pbData, info->rgProvParam[i].dwFlags); 5684 } 5685 return ret; 5686 } 5687 5688 static BOOL export_is_key_exportable(HCRYPTPROV hProv, DWORD keySpec) 5689 { 5690 BOOL ret; 5691 HCRYPTKEY key; 5692 5693 if ((ret = CryptGetUserKey(hProv, keySpec, &key))) 5694 { 5695 DWORD permissions, size = sizeof(permissions); 5696 5697 if ((ret = CryptGetKeyParam(key, KP_PERMISSIONS, (BYTE *)&permissions, 5698 &size, 0)) && !(permissions & CRYPT_EXPORT)) 5699 ret = FALSE; 5700 CryptDestroyKey(key); 5701 } 5702 return ret; 5703 } 5704 5705 static LRESULT CALLBACK export_private_key_dlg_proc(HWND hwnd, UINT msg, 5706 WPARAM wp, LPARAM lp) 5707 { 5708 LRESULT ret = 0; 5709 struct ExportWizData *data; 5710 5711 switch (msg) 5712 { 5713 case WM_INITDIALOG: 5714 { 5715 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp; 5716 PCRYPT_KEY_PROV_INFO info; 5717 HCRYPTPROV hProv = 0; 5718 int errorID = 0; 5719 5720 data = (struct ExportWizData *)page->lParam; 5721 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data); 5722 /* Get enough information about a key to see whether it's exportable. 5723 */ 5724 if (!(info = export_get_private_key_info( 5725 data->exportInfo.u.pCertContext))) 5726 errorID = IDS_EXPORT_PRIVATE_KEY_UNAVAILABLE; 5727 else if (!export_acquire_private_key(info, &hProv)) 5728 errorID = IDS_EXPORT_PRIVATE_KEY_UNAVAILABLE; 5729 else if (!export_is_key_exportable(hProv, info->dwKeySpec)) 5730 errorID = IDS_EXPORT_PRIVATE_KEY_NON_EXPORTABLE; 5731 5732 if (errorID) 5733 { 5734 WCHAR error[MAX_STRING_LEN]; 5735 5736 LoadStringW(hInstance, errorID, error, 5737 sizeof(error) / sizeof(error[0])); 5738 SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_PRIVATE_KEY_UNAVAILABLE), 5739 WM_SETTEXT, 0, (LPARAM)error); 5740 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_PRIVATE_KEY_YES), FALSE); 5741 } 5742 else 5743 data->keyProvInfo = info; 5744 if (hProv) 5745 CryptReleaseContext(hProv, 0); 5746 SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_PRIVATE_KEY_NO), BM_CLICK, 5747 0, 0); 5748 break; 5749 } 5750 case WM_NOTIFY: 5751 { 5752 NMHDR *hdr = (NMHDR *)lp; 5753 5754 switch (hdr->code) 5755 { 5756 case PSN_SETACTIVE: 5757 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0, 5758 PSWIZB_BACK | PSWIZB_NEXT); 5759 ret = TRUE; 5760 break; 5761 case PSN_WIZNEXT: 5762 data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER); 5763 if (IsDlgButtonChecked(hwnd, IDC_EXPORT_PRIVATE_KEY_NO)) 5764 { 5765 data->contextInfo.dwExportFormat = 5766 CRYPTUI_WIZ_EXPORT_FORMAT_DER; 5767 data->contextInfo.fExportPrivateKeys = FALSE; 5768 } 5769 else 5770 { 5771 data->contextInfo.dwExportFormat = 5772 CRYPTUI_WIZ_EXPORT_FORMAT_PFX; 5773 data->contextInfo.fExportPrivateKeys = TRUE; 5774 } 5775 break; 5776 } 5777 break; 5778 } 5779 } 5780 return ret; 5781 } 5782 5783 static BOOL export_info_has_private_key(PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo) 5784 { 5785 BOOL ret = FALSE; 5786 5787 if (pExportInfo->dwSubjectChoice == CRYPTUI_WIZ_EXPORT_CERT_CONTEXT) 5788 { 5789 DWORD size; 5790 5791 /* If there's a CRYPT_KEY_PROV_INFO set for this cert, assume the 5792 * cert has a private key. 5793 */ 5794 if (CertGetCertificateContextProperty(pExportInfo->u.pCertContext, 5795 CERT_KEY_PROV_INFO_PROP_ID, NULL, &size)) 5796 ret = TRUE; 5797 } 5798 return ret; 5799 } 5800 5801 static void export_format_enable_controls(HWND hwnd, const struct ExportWizData *data) 5802 { 5803 int defaultFormatID; 5804 5805 switch (data->contextInfo.dwExportFormat) 5806 { 5807 case CRYPTUI_WIZ_EXPORT_FORMAT_BASE64: 5808 defaultFormatID = IDC_EXPORT_FORMAT_BASE64; 5809 break; 5810 case CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7: 5811 defaultFormatID = IDC_EXPORT_FORMAT_CMS; 5812 break; 5813 case CRYPTUI_WIZ_EXPORT_FORMAT_PFX: 5814 defaultFormatID = IDC_EXPORT_FORMAT_PFX; 5815 break; 5816 default: 5817 defaultFormatID = IDC_EXPORT_FORMAT_DER; 5818 } 5819 SendMessageW(GetDlgItem(hwnd, defaultFormatID), BM_CLICK, 0, 0); 5820 if (defaultFormatID == IDC_EXPORT_FORMAT_PFX) 5821 { 5822 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_DER), FALSE); 5823 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_BASE64), FALSE); 5824 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_CMS), FALSE); 5825 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_PFX), TRUE); 5826 } 5827 else 5828 { 5829 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_DER), TRUE); 5830 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_BASE64), TRUE); 5831 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_CMS), TRUE); 5832 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_PFX), FALSE); 5833 } 5834 } 5835 5836 static LRESULT CALLBACK export_format_dlg_proc(HWND hwnd, UINT msg, WPARAM wp, 5837 LPARAM lp) 5838 { 5839 LRESULT ret = 0; 5840 struct ExportWizData *data; 5841 5842 switch (msg) 5843 { 5844 case WM_INITDIALOG: 5845 { 5846 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp; 5847 5848 data = (struct ExportWizData *)page->lParam; 5849 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data); 5850 export_format_enable_controls(hwnd, data); 5851 break; 5852 } 5853 case WM_NOTIFY: 5854 { 5855 NMHDR *hdr = (NMHDR *)lp; 5856 5857 switch (hdr->code) 5858 { 5859 case PSN_SETACTIVE: 5860 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0, 5861 PSWIZB_BACK | PSWIZB_NEXT); 5862 data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER); 5863 export_format_enable_controls(hwnd, data); 5864 ret = TRUE; 5865 break; 5866 case PSN_WIZNEXT: 5867 { 5868 BOOL skipPasswordPage = TRUE; 5869 5870 data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER); 5871 if (IsDlgButtonChecked(hwnd, IDC_EXPORT_FORMAT_DER)) 5872 data->contextInfo.dwExportFormat = 5873 CRYPTUI_WIZ_EXPORT_FORMAT_DER; 5874 else if (IsDlgButtonChecked(hwnd, IDC_EXPORT_FORMAT_BASE64)) 5875 data->contextInfo.dwExportFormat = 5876 CRYPTUI_WIZ_EXPORT_FORMAT_BASE64; 5877 else if (IsDlgButtonChecked(hwnd, IDC_EXPORT_FORMAT_CMS)) 5878 { 5879 data->contextInfo.dwExportFormat = 5880 CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7; 5881 if (IsDlgButtonChecked(hwnd, IDC_EXPORT_CMS_INCLUDE_CHAIN)) 5882 data->contextInfo.fExportChain = 5883 CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7; 5884 } 5885 else 5886 { 5887 data->contextInfo.dwExportFormat = 5888 CRYPTUI_WIZ_EXPORT_FORMAT_PFX; 5889 if (IsDlgButtonChecked(hwnd, IDC_EXPORT_PFX_INCLUDE_CHAIN)) 5890 data->contextInfo.fExportChain = TRUE; 5891 if (IsDlgButtonChecked(hwnd, IDC_EXPORT_PFX_STRONG_ENCRYPTION)) 5892 data->contextInfo.fStrongEncryption = TRUE; 5893 if (IsDlgButtonChecked(hwnd, IDC_EXPORT_PFX_DELETE_PRIVATE_KEY)) 5894 data->deleteKeys = TRUE; 5895 skipPasswordPage = FALSE; 5896 } 5897 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 5898 skipPasswordPage ? IDD_EXPORT_FILE : 0); 5899 ret = 1; 5900 break; 5901 } 5902 } 5903 break; 5904 } 5905 case WM_COMMAND: 5906 switch (HIWORD(wp)) 5907 { 5908 case BN_CLICKED: 5909 switch (LOWORD(wp)) 5910 { 5911 case IDC_EXPORT_FORMAT_DER: 5912 case IDC_EXPORT_FORMAT_BASE64: 5913 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_CMS_INCLUDE_CHAIN), 5914 FALSE); 5915 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_PFX_INCLUDE_CHAIN), 5916 FALSE); 5917 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_PFX_STRONG_ENCRYPTION), 5918 FALSE); 5919 EnableWindow(GetDlgItem(hwnd, 5920 IDC_EXPORT_PFX_DELETE_PRIVATE_KEY), FALSE); 5921 break; 5922 case IDC_EXPORT_FORMAT_CMS: 5923 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_CMS_INCLUDE_CHAIN), 5924 TRUE); 5925 break; 5926 case IDC_EXPORT_FORMAT_PFX: 5927 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_PFX_INCLUDE_CHAIN), 5928 TRUE); 5929 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_PFX_STRONG_ENCRYPTION), 5930 TRUE); 5931 EnableWindow(GetDlgItem(hwnd, 5932 IDC_EXPORT_PFX_DELETE_PRIVATE_KEY), TRUE); 5933 break; 5934 } 5935 break; 5936 } 5937 break; 5938 } 5939 return ret; 5940 } 5941 5942 static void export_password_mismatch(HWND hwnd, const struct ExportWizData *data) 5943 { 5944 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN]; 5945 LPCWSTR pTitle; 5946 5947 if (data->pwszWizardTitle) 5948 pTitle = data->pwszWizardTitle; 5949 else 5950 { 5951 LoadStringW(hInstance, IDS_EXPORT_WIZARD, title, 5952 sizeof(title) / sizeof(title[0])); 5953 pTitle = title; 5954 } 5955 LoadStringW(hInstance, IDS_EXPORT_PASSWORD_MISMATCH, error, 5956 sizeof(error) / sizeof(error[0])); 5957 MessageBoxW(hwnd, error, pTitle, MB_ICONERROR | MB_OK); 5958 SetFocus(GetDlgItem(hwnd, IDC_EXPORT_PASSWORD)); 5959 } 5960 5961 static LRESULT CALLBACK export_password_dlg_proc(HWND hwnd, UINT msg, 5962 WPARAM wp, LPARAM lp) 5963 { 5964 LRESULT ret = 0; 5965 struct ExportWizData *data; 5966 5967 switch (msg) 5968 { 5969 case WM_INITDIALOG: 5970 { 5971 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp; 5972 5973 data = (struct ExportWizData *)page->lParam; 5974 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data); 5975 break; 5976 } 5977 case WM_NOTIFY: 5978 { 5979 NMHDR *hdr = (NMHDR *)lp; 5980 5981 switch (hdr->code) 5982 { 5983 case PSN_SETACTIVE: 5984 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0, 5985 PSWIZB_BACK | PSWIZB_NEXT); 5986 ret = TRUE; 5987 break; 5988 case PSN_WIZNEXT: 5989 { 5990 HWND passwordEdit = GetDlgItem(hwnd, IDC_EXPORT_PASSWORD); 5991 HWND passwordConfirmEdit = GetDlgItem(hwnd, 5992 IDC_EXPORT_PASSWORD_CONFIRM); 5993 DWORD passwordLen = SendMessageW(passwordEdit, WM_GETTEXTLENGTH, 5994 0, 0); 5995 DWORD passwordConfirmLen = SendMessageW(passwordConfirmEdit, 5996 WM_GETTEXTLENGTH, 0, 0); 5997 5998 data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER); 5999 if (!passwordLen && !passwordConfirmLen) 6000 data->contextInfo.pwszPassword = NULL; 6001 else if (passwordLen != passwordConfirmLen) 6002 { 6003 export_password_mismatch(hwnd, data); 6004 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1); 6005 ret = 1; 6006 } 6007 else 6008 { 6009 LPWSTR password = HeapAlloc(GetProcessHeap(), 0, 6010 (passwordLen + 1) * sizeof(WCHAR)); 6011 LPWSTR passwordConfirm = HeapAlloc(GetProcessHeap(), 0, 6012 (passwordConfirmLen + 1) * sizeof(WCHAR)); 6013 BOOL freePassword = TRUE; 6014 6015 if (password && passwordConfirm) 6016 { 6017 SendMessageW(passwordEdit, WM_GETTEXT, passwordLen + 1, 6018 (LPARAM)password); 6019 SendMessageW(passwordConfirmEdit, WM_GETTEXT, 6020 passwordConfirmLen + 1, (LPARAM)passwordConfirm); 6021 if (strcmpW(password, passwordConfirm)) 6022 { 6023 export_password_mismatch(hwnd, data); 6024 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1); 6025 ret = 1; 6026 } 6027 else 6028 { 6029 data->contextInfo.pwszPassword = password; 6030 freePassword = FALSE; 6031 data->freePassword = TRUE; 6032 } 6033 } 6034 if (freePassword) 6035 HeapFree(GetProcessHeap(), 0, password); 6036 HeapFree(GetProcessHeap(), 0, passwordConfirm); 6037 } 6038 break; 6039 } 6040 } 6041 break; 6042 } 6043 } 6044 return ret; 6045 } 6046 6047 static LPWSTR export_append_extension(const struct ExportWizData *data, 6048 LPWSTR fileName) 6049 { 6050 static const WCHAR cer[] = { '.','c','e','r',0 }; 6051 static const WCHAR crl[] = { '.','c','r','l',0 }; 6052 static const WCHAR ctl[] = { '.','c','t','l',0 }; 6053 static const WCHAR p7b[] = { '.','p','7','b',0 }; 6054 static const WCHAR pfx[] = { '.','p','f','x',0 }; 6055 static const WCHAR sst[] = { '.','s','s','t',0 }; 6056 LPCWSTR extension; 6057 LPWSTR dot; 6058 BOOL appendExtension; 6059 6060 switch (data->contextInfo.dwExportFormat) 6061 { 6062 case CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7: 6063 extension = p7b; 6064 break; 6065 case CRYPTUI_WIZ_EXPORT_FORMAT_PFX: 6066 extension = pfx; 6067 break; 6068 default: 6069 switch (data->exportInfo.dwSubjectChoice) 6070 { 6071 case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT: 6072 extension = crl; 6073 break; 6074 case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT: 6075 extension = ctl; 6076 break; 6077 case CRYPTUI_WIZ_EXPORT_CERT_STORE: 6078 extension = sst; 6079 break; 6080 default: 6081 extension = cer; 6082 } 6083 } 6084 dot = strrchrW(fileName, '.'); 6085 if (dot) 6086 appendExtension = strcmpiW(dot, extension) != 0; 6087 else 6088 appendExtension = TRUE; 6089 if (appendExtension) 6090 { 6091 fileName = HeapReAlloc(GetProcessHeap(), 0, fileName, 6092 (strlenW(fileName) + strlenW(extension) + 1) * sizeof(WCHAR)); 6093 if (fileName) 6094 strcatW(fileName, extension); 6095 } 6096 return fileName; 6097 } 6098 6099 static BOOL export_validate_filename(HWND hwnd, struct ExportWizData *data, 6100 LPCWSTR fileName) 6101 { 6102 HANDLE file; 6103 BOOL tryCreate = TRUE, forceCreate = FALSE, ret = FALSE; 6104 6105 file = CreateFileW(fileName, GENERIC_WRITE, 6106 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); 6107 if (file != INVALID_HANDLE_VALUE) 6108 { 6109 WCHAR warning[MAX_STRING_LEN], title[MAX_STRING_LEN]; 6110 LPCWSTR pTitle; 6111 6112 if (data->pwszWizardTitle) 6113 pTitle = data->pwszWizardTitle; 6114 else 6115 { 6116 LoadStringW(hInstance, IDS_EXPORT_WIZARD, title, 6117 sizeof(title) / sizeof(title[0])); 6118 pTitle = title; 6119 } 6120 LoadStringW(hInstance, IDS_EXPORT_FILE_EXISTS, warning, 6121 sizeof(warning) / sizeof(warning[0])); 6122 if (MessageBoxW(hwnd, warning, pTitle, MB_YESNO) == IDYES) 6123 forceCreate = TRUE; 6124 else 6125 tryCreate = FALSE; 6126 CloseHandle(file); 6127 } 6128 if (tryCreate) 6129 { 6130 file = CreateFileW(fileName, GENERIC_WRITE, 6131 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 6132 forceCreate ? CREATE_ALWAYS : CREATE_NEW, 6133 0, NULL); 6134 if (file != INVALID_HANDLE_VALUE) 6135 { 6136 data->file = file; 6137 ret = TRUE; 6138 } 6139 else 6140 { 6141 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN]; 6142 LPCWSTR pTitle; 6143 LPWSTR msgBuf, fullError; 6144 6145 if (data->pwszWizardTitle) 6146 pTitle = data->pwszWizardTitle; 6147 else 6148 { 6149 LoadStringW(hInstance, IDS_EXPORT_WIZARD, title, 6150 sizeof(title) / sizeof(title[0])); 6151 pTitle = title; 6152 } 6153 LoadStringW(hInstance, IDS_IMPORT_OPEN_FAILED, error, 6154 sizeof(error) / sizeof(error[0])); 6155 FormatMessageW( 6156 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, 6157 GetLastError(), 0, (LPWSTR) &msgBuf, 0, NULL); 6158 fullError = HeapAlloc(GetProcessHeap(), 0, 6159 (strlenW(error) + strlenW(fileName) + strlenW(msgBuf) + 3) 6160 * sizeof(WCHAR)); 6161 if (fullError) 6162 { 6163 LPWSTR ptr = fullError; 6164 6165 strcpyW(ptr, error); 6166 ptr += strlenW(error); 6167 strcpyW(ptr, fileName); 6168 ptr += strlenW(fileName); 6169 *ptr++ = ':'; 6170 *ptr++ = '\n'; 6171 strcpyW(ptr, msgBuf); 6172 MessageBoxW(hwnd, fullError, pTitle, MB_ICONERROR | MB_OK); 6173 HeapFree(GetProcessHeap(), 0, fullError); 6174 } 6175 LocalFree(msgBuf); 6176 } 6177 } 6178 return ret; 6179 } 6180 6181 static const WCHAR export_filter_cert[] = { '*','.','c','e','r',0 }; 6182 static const WCHAR export_filter_crl[] = { '*','.','c','r','l',0 }; 6183 static const WCHAR export_filter_ctl[] = { '*','.','s','t','l',0 }; 6184 static const WCHAR export_filter_cms[] = { '*','.','p','7','b',0 }; 6185 static const WCHAR export_filter_pfx[] = { '*','.','p','f','x',0 }; 6186 static const WCHAR export_filter_sst[] = { '*','.','s','s','t',0 }; 6187 6188 static WCHAR *make_export_file_filter(DWORD exportFormat, DWORD subjectChoice) 6189 { 6190 int baseLen, allLen, totalLen = 2, baseID; 6191 LPWSTR filter = NULL, baseFilter, all; 6192 LPCWSTR filterStr; 6193 6194 switch (exportFormat) 6195 { 6196 case CRYPTUI_WIZ_EXPORT_FORMAT_BASE64: 6197 baseID = IDS_EXPORT_FILTER_BASE64_CERT; 6198 filterStr = export_filter_cert; 6199 break; 6200 case CRYPTUI_WIZ_EXPORT_FORMAT_PFX: 6201 baseID = IDS_EXPORT_FILTER_PFX; 6202 filterStr = export_filter_pfx; 6203 break; 6204 case CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7: 6205 baseID = IDS_EXPORT_FILTER_CMS; 6206 filterStr = export_filter_cms; 6207 break; 6208 default: 6209 switch (subjectChoice) 6210 { 6211 case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT: 6212 baseID = IDS_EXPORT_FILTER_CRL; 6213 filterStr = export_filter_crl; 6214 break; 6215 case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT: 6216 baseID = IDS_EXPORT_FILTER_CTL; 6217 filterStr = export_filter_ctl; 6218 break; 6219 case CRYPTUI_WIZ_EXPORT_CERT_STORE: 6220 baseID = IDS_EXPORT_FILTER_SERIALIZED_CERT_STORE; 6221 filterStr = export_filter_sst; 6222 break; 6223 default: 6224 baseID = IDS_EXPORT_FILTER_CERT; 6225 filterStr = export_filter_cert; 6226 break; 6227 } 6228 } 6229 baseLen = LoadStringW(hInstance, baseID, (LPWSTR)&baseFilter, 0); 6230 totalLen += baseLen + strlenW(filterStr) + 2; 6231 allLen = LoadStringW(hInstance, IDS_IMPORT_FILTER_ALL, (LPWSTR)&all, 0); 6232 totalLen += allLen + strlenW(filter_all) + 2; 6233 filter = HeapAlloc(GetProcessHeap(), 0, totalLen * sizeof(WCHAR)); 6234 if (filter) 6235 { 6236 LPWSTR ptr; 6237 6238 ptr = filter; 6239 memcpy(ptr, baseFilter, baseLen * sizeof(WCHAR)); 6240 ptr += baseLen; 6241 *ptr++ = 0; 6242 strcpyW(ptr, filterStr); 6243 ptr += strlenW(filterStr) + 1; 6244 memcpy(ptr, all, allLen * sizeof(WCHAR)); 6245 ptr += allLen; 6246 *ptr++ = 0; 6247 strcpyW(ptr, filter_all); 6248 ptr += strlenW(filter_all) + 1; 6249 *ptr++ = 0; 6250 } 6251 return filter; 6252 } 6253 6254 static LRESULT CALLBACK export_file_dlg_proc(HWND hwnd, UINT msg, WPARAM wp, 6255 LPARAM lp) 6256 { 6257 LRESULT ret = 0; 6258 struct ExportWizData *data; 6259 6260 switch (msg) 6261 { 6262 case WM_INITDIALOG: 6263 { 6264 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp; 6265 6266 data = (struct ExportWizData *)page->lParam; 6267 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data); 6268 if (data->exportInfo.pwszExportFileName) 6269 SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_FILENAME), WM_SETTEXT, 0, 6270 (LPARAM)data->exportInfo.pwszExportFileName); 6271 break; 6272 } 6273 case WM_NOTIFY: 6274 { 6275 NMHDR *hdr = (NMHDR *)lp; 6276 6277 switch (hdr->code) 6278 { 6279 case PSN_WIZBACK: 6280 data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER); 6281 if (data->contextInfo.dwExportFormat != 6282 CRYPTUI_WIZ_EXPORT_FORMAT_PFX) 6283 { 6284 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, IDD_EXPORT_FORMAT); 6285 ret = 1; 6286 } 6287 break; 6288 case PSN_WIZNEXT: 6289 { 6290 HWND fileNameEdit = GetDlgItem(hwnd, IDC_EXPORT_FILENAME); 6291 DWORD len = SendMessageW(fileNameEdit, WM_GETTEXTLENGTH, 0, 0); 6292 6293 data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER); 6294 if (!len) 6295 { 6296 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN]; 6297 LPCWSTR pTitle; 6298 6299 if (data->pwszWizardTitle) 6300 pTitle = data->pwszWizardTitle; 6301 else 6302 { 6303 LoadStringW(hInstance, IDS_EXPORT_WIZARD, title, 6304 sizeof(title) / sizeof(title[0])); 6305 pTitle = title; 6306 } 6307 LoadStringW(hInstance, IDS_IMPORT_EMPTY_FILE, error, 6308 sizeof(error) / sizeof(error[0])); 6309 MessageBoxW(hwnd, error, pTitle, MB_ICONERROR | MB_OK); 6310 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1); 6311 ret = 1; 6312 } 6313 else 6314 { 6315 LPWSTR fileName = HeapAlloc(GetProcessHeap(), 0, 6316 (len + 1) * sizeof(WCHAR)); 6317 6318 if (fileName) 6319 { 6320 SendMessageW(fileNameEdit, WM_GETTEXT, len + 1, 6321 (LPARAM)fileName); 6322 fileName = export_append_extension(data, fileName); 6323 if (!export_validate_filename(hwnd, data, fileName)) 6324 { 6325 HeapFree(GetProcessHeap(), 0, fileName); 6326 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1); 6327 ret = 1; 6328 } 6329 else 6330 data->fileName = fileName; 6331 } 6332 } 6333 break; 6334 } 6335 case PSN_SETACTIVE: 6336 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0, 6337 PSWIZB_BACK | PSWIZB_NEXT); 6338 ret = TRUE; 6339 break; 6340 } 6341 break; 6342 } 6343 case WM_COMMAND: 6344 switch (wp) 6345 { 6346 case IDC_EXPORT_BROWSE_FILE: 6347 { 6348 OPENFILENAMEW ofn; 6349 WCHAR fileBuf[MAX_PATH]; 6350 6351 data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER); 6352 memset(&ofn, 0, sizeof(ofn)); 6353 ofn.lStructSize = sizeof(ofn); 6354 ofn.hwndOwner = hwnd; 6355 ofn.lpstrFilter = make_export_file_filter( 6356 data->contextInfo.dwExportFormat, 6357 data->exportInfo.dwSubjectChoice); 6358 ofn.lpstrFile = fileBuf; 6359 ofn.nMaxFile = sizeof(fileBuf) / sizeof(fileBuf[0]); 6360 fileBuf[0] = 0; 6361 if (GetSaveFileNameW(&ofn)) 6362 SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_FILENAME), WM_SETTEXT, 6363 0, (LPARAM)ofn.lpstrFile); 6364 HeapFree(GetProcessHeap(), 0, (LPWSTR)ofn.lpstrFilter); 6365 break; 6366 } 6367 } 6368 break; 6369 } 6370 return ret; 6371 } 6372 6373 static void show_export_details(HWND lv, const struct ExportWizData *data) 6374 { 6375 WCHAR text[MAX_STRING_LEN]; 6376 LVITEMW item; 6377 int contentID; 6378 6379 item.mask = LVIF_TEXT; 6380 if (data->fileName) 6381 { 6382 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0); 6383 item.iSubItem = 0; 6384 LoadStringW(hInstance, IDS_IMPORT_FILE, text, 6385 sizeof(text)/ sizeof(text[0])); 6386 item.pszText = text; 6387 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item); 6388 item.iSubItem = 1; 6389 item.pszText = data->fileName; 6390 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item); 6391 } 6392 6393 item.pszText = text; 6394 switch (data->exportInfo.dwSubjectChoice) 6395 { 6396 case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT: 6397 case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT: 6398 case CRYPTUI_WIZ_EXPORT_CERT_STORE: 6399 case CRYPTUI_WIZ_EXPORT_CERT_STORE_CERTIFICATES_ONLY: 6400 /* do nothing */ 6401 break; 6402 default: 6403 { 6404 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0); 6405 item.iSubItem = 0; 6406 LoadStringW(hInstance, IDS_EXPORT_INCLUDE_CHAIN, text, 6407 sizeof(text) / sizeof(text[0])); 6408 SendMessageW(lv, LVM_INSERTITEMW, item.iItem, (LPARAM)&item); 6409 item.iSubItem = 1; 6410 LoadStringW(hInstance, 6411 data->contextInfo.fExportChain ? IDS_YES : IDS_NO, text, 6412 sizeof(text) / sizeof(text[0])); 6413 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item); 6414 6415 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0); 6416 item.iSubItem = 0; 6417 LoadStringW(hInstance, IDS_EXPORT_KEYS, text, 6418 sizeof(text) / sizeof(text[0])); 6419 SendMessageW(lv, LVM_INSERTITEMW, item.iItem, (LPARAM)&item); 6420 item.iSubItem = 1; 6421 LoadStringW(hInstance, 6422 data->contextInfo.fExportPrivateKeys ? IDS_YES : IDS_NO, text, 6423 sizeof(text) / sizeof(text[0])); 6424 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item); 6425 } 6426 } 6427 6428 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0); 6429 item.iSubItem = 0; 6430 LoadStringW(hInstance, IDS_EXPORT_FORMAT, text, 6431 sizeof(text)/ sizeof(text[0])); 6432 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item); 6433 6434 item.iSubItem = 1; 6435 switch (data->exportInfo.dwSubjectChoice) 6436 { 6437 case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT: 6438 contentID = IDS_EXPORT_FILTER_CRL; 6439 break; 6440 case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT: 6441 contentID = IDS_EXPORT_FILTER_CTL; 6442 break; 6443 case CRYPTUI_WIZ_EXPORT_CERT_STORE: 6444 contentID = IDS_EXPORT_FILTER_SERIALIZED_CERT_STORE; 6445 break; 6446 default: 6447 switch (data->contextInfo.dwExportFormat) 6448 { 6449 case CRYPTUI_WIZ_EXPORT_FORMAT_BASE64: 6450 contentID = IDS_EXPORT_FILTER_BASE64_CERT; 6451 break; 6452 case CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7: 6453 contentID = IDS_EXPORT_FILTER_CMS; 6454 break; 6455 case CRYPTUI_WIZ_EXPORT_FORMAT_PFX: 6456 contentID = IDS_EXPORT_FILTER_PFX; 6457 break; 6458 default: 6459 contentID = IDS_EXPORT_FILTER_CERT; 6460 } 6461 } 6462 LoadStringW(hInstance, contentID, text, sizeof(text) / sizeof(text[0])); 6463 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item); 6464 } 6465 6466 static inline BOOL save_der(HANDLE file, const BYTE *pb, DWORD cb) 6467 { 6468 DWORD bytesWritten; 6469 6470 return WriteFile(file, pb, cb, &bytesWritten, NULL); 6471 } 6472 6473 static BOOL save_base64(HANDLE file, const BYTE *pb, DWORD cb) 6474 { 6475 BOOL ret; 6476 DWORD size = 0; 6477 6478 if ((ret = CryptBinaryToStringA(pb, cb, CRYPT_STRING_BASE64, NULL, &size))) 6479 { 6480 LPSTR buf = HeapAlloc(GetProcessHeap(), 0, size); 6481 6482 if (buf) 6483 { 6484 if ((ret = CryptBinaryToStringA(pb, cb, CRYPT_STRING_BASE64, buf, 6485 &size))) 6486 ret = WriteFile(file, buf, size, &size, NULL); 6487 HeapFree(GetProcessHeap(), 0, buf); 6488 } 6489 else 6490 { 6491 SetLastError(ERROR_OUTOFMEMORY); 6492 ret = FALSE; 6493 } 6494 } 6495 return ret; 6496 } 6497 6498 static inline BOOL save_store_as_cms(HANDLE file, HCERTSTORE store) 6499 { 6500 return CertSaveStore(store, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, 6501 CERT_STORE_SAVE_AS_PKCS7, CERT_STORE_SAVE_TO_FILE, file, 0); 6502 } 6503 6504 static BOOL save_cert_as_cms(HANDLE file, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo, 6505 BOOL includeChain) 6506 { 6507 BOOL ret; 6508 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, 6509 CERT_STORE_CREATE_NEW_FLAG, NULL); 6510 6511 if (store) 6512 { 6513 if (includeChain) 6514 { 6515 HCERTSTORE addlStore = CertOpenStore(CERT_STORE_PROV_COLLECTION, 6516 0, 0, CERT_STORE_CREATE_NEW_FLAG, NULL); 6517 6518 if (addlStore) 6519 { 6520 DWORD i; 6521 6522 ret = TRUE; 6523 for (i = 0; ret && i < pExportInfo->cStores; i++) 6524 ret = CertAddStoreToCollection(addlStore, 6525 pExportInfo->rghStores, 0, 0); 6526 if (ret) 6527 { 6528 PCCERT_CHAIN_CONTEXT chain; 6529 6530 ret = CertGetCertificateChain(NULL, 6531 pExportInfo->u.pCertContext, NULL, addlStore, NULL, 0, 6532 NULL, &chain); 6533 if (ret) 6534 { 6535 DWORD j; 6536 6537 for (i = 0; ret && i < chain->cChain; i++) 6538 for (j = 0; ret && j < chain->rgpChain[i]->cElement; 6539 j++) 6540 ret = CertAddCertificateContextToStore(store, 6541 chain->rgpChain[i]->rgpElement[j]->pCertContext, 6542 CERT_STORE_ADD_ALWAYS, NULL); 6543 CertFreeCertificateChain(chain); 6544 } 6545 else 6546 { 6547 /* No chain could be created, just add the individual 6548 * cert to the message. 6549 */ 6550 ret = CertAddCertificateContextToStore(store, 6551 pExportInfo->u.pCertContext, CERT_STORE_ADD_ALWAYS, 6552 NULL); 6553 } 6554 } 6555 CertCloseStore(addlStore, 0); 6556 } 6557 else 6558 ret = FALSE; 6559 } 6560 else 6561 ret = CertAddCertificateContextToStore(store, 6562 pExportInfo->u.pCertContext, CERT_STORE_ADD_ALWAYS, NULL); 6563 if (ret) 6564 ret = save_store_as_cms(file, store); 6565 CertCloseStore(store, 0); 6566 } 6567 else 6568 ret = FALSE; 6569 return ret; 6570 } 6571 6572 static BOOL save_serialized_store(HANDLE file, HCERTSTORE store) 6573 { 6574 return CertSaveStore(store, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, 6575 CERT_STORE_SAVE_AS_STORE, CERT_STORE_SAVE_TO_FILE, file, 0); 6576 } 6577 6578 static BOOL save_pfx(HANDLE file, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo, 6579 PCCRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO pContextInfo, 6580 PCRYPT_KEY_PROV_INFO keyProvInfo, BOOL deleteKeys) 6581 { 6582 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, 6583 0, CERT_STORE_CREATE_NEW_FLAG, NULL); 6584 BOOL ret = FALSE; 6585 6586 if (store) 6587 { 6588 CRYPT_DATA_BLOB pfxBlob = { 0, NULL }; 6589 PCCERT_CONTEXT cert = NULL; 6590 BOOL freeKeyProvInfo = FALSE; 6591 6592 if (pContextInfo->fExportChain) 6593 { 6594 HCERTCHAINENGINE engine = NULL; 6595 6596 if (pExportInfo->cStores) 6597 { 6598 CERT_CHAIN_ENGINE_CONFIG config; 6599 6600 memset(&config, 0, sizeof(config)); 6601 config.cbSize = sizeof(config); 6602 config.cAdditionalStore = pExportInfo->cStores; 6603 config.rghAdditionalStore = pExportInfo->rghStores; 6604 ret = CertCreateCertificateChainEngine(&config, &engine); 6605 } 6606 else 6607 ret = TRUE; 6608 if (ret) 6609 { 6610 CERT_CHAIN_PARA chainPara; 6611 PCCERT_CHAIN_CONTEXT chain; 6612 6613 memset(&chainPara, 0, sizeof(chainPara)); 6614 chainPara.cbSize = sizeof(chainPara); 6615 ret = CertGetCertificateChain(engine, 6616 pExportInfo->u.pCertContext, NULL, NULL, &chainPara, 0, NULL, 6617 &chain); 6618 if (ret) 6619 { 6620 DWORD i, j; 6621 6622 for (i = 0; ret && i < chain->cChain; i++) 6623 for (j = 0; ret && j < chain->rgpChain[i]->cElement; 6624 j++) 6625 { 6626 if (i == 0 && j == 0) 6627 ret = CertAddCertificateContextToStore(store, 6628 chain->rgpChain[i]->rgpElement[j]->pCertContext, 6629 CERT_STORE_ADD_ALWAYS, &cert); 6630 else 6631 ret = CertAddCertificateContextToStore(store, 6632 chain->rgpChain[i]->rgpElement[j]->pCertContext, 6633 CERT_STORE_ADD_ALWAYS, NULL); 6634 } 6635 CertFreeCertificateChain(chain); 6636 } 6637 } 6638 if (engine) 6639 CertFreeCertificateChainEngine(engine); 6640 } 6641 else 6642 ret = CertAddCertificateContextToStore(store, 6643 pExportInfo->u.pCertContext, CERT_STORE_ADD_ALWAYS, &cert); 6644 /* Copy private key info to newly created cert, so it'll get exported 6645 * along with the cert. 6646 */ 6647 if (ret && pContextInfo->fExportPrivateKeys) 6648 { 6649 if (keyProvInfo) 6650 ret = CertSetCertificateContextProperty(cert, 6651 CERT_KEY_PROV_INFO_PROP_ID, 0, keyProvInfo); 6652 else 6653 { 6654 if (!(keyProvInfo = export_get_private_key_info(cert))) 6655 ret = FALSE; 6656 else 6657 { 6658 ret = CertSetCertificateContextProperty(cert, 6659 CERT_KEY_PROV_INFO_PROP_ID, 0, keyProvInfo); 6660 freeKeyProvInfo = TRUE; 6661 } 6662 } 6663 } 6664 if (ret) 6665 { 6666 DWORD exportFlags = 6667 REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY | EXPORT_PRIVATE_KEYS; 6668 6669 ret = PFXExportCertStore(store, &pfxBlob, 6670 pContextInfo->pwszPassword, exportFlags); 6671 if (ret) 6672 { 6673 pfxBlob.pbData = HeapAlloc(GetProcessHeap(), 0, pfxBlob.cbData); 6674 if (pfxBlob.pbData) 6675 { 6676 ret = PFXExportCertStore(store, &pfxBlob, 6677 pContextInfo->pwszPassword, exportFlags); 6678 if (ret) 6679 { 6680 DWORD bytesWritten; 6681 6682 ret = WriteFile(file, pfxBlob.pbData, pfxBlob.cbData, 6683 &bytesWritten, NULL); 6684 } 6685 } 6686 else 6687 { 6688 SetLastError(ERROR_OUTOFMEMORY); 6689 ret = FALSE; 6690 } 6691 } 6692 } 6693 if (ret && deleteKeys) 6694 { 6695 HCRYPTPROV prov; 6696 6697 CryptAcquireContextW(&prov, keyProvInfo->pwszContainerName, 6698 keyProvInfo->pwszProvName, keyProvInfo->dwProvType, 6699 CRYPT_DELETEKEYSET); 6700 } 6701 if (freeKeyProvInfo) 6702 HeapFree(GetProcessHeap(), 0, keyProvInfo); 6703 CertFreeCertificateContext(cert); 6704 CertCloseStore(store, 0); 6705 } 6706 return ret; 6707 } 6708 6709 static BOOL do_export(HANDLE file, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo, 6710 PCCRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO pContextInfo, 6711 PCRYPT_KEY_PROV_INFO keyProvInfo, BOOL deleteKeys) 6712 { 6713 BOOL ret; 6714 6715 if (pContextInfo->dwSize != sizeof(CRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO)) 6716 { 6717 SetLastError(E_INVALIDARG); 6718 return FALSE; 6719 } 6720 switch (pExportInfo->dwSubjectChoice) 6721 { 6722 case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT: 6723 ret = save_der(file, 6724 pExportInfo->u.pCRLContext->pbCrlEncoded, 6725 pExportInfo->u.pCRLContext->cbCrlEncoded); 6726 break; 6727 case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT: 6728 ret = save_der(file, 6729 pExportInfo->u.pCTLContext->pbCtlEncoded, 6730 pExportInfo->u.pCTLContext->cbCtlEncoded); 6731 break; 6732 case CRYPTUI_WIZ_EXPORT_CERT_STORE: 6733 ret = save_serialized_store(file, pExportInfo->u.hCertStore); 6734 break; 6735 case CRYPTUI_WIZ_EXPORT_CERT_STORE_CERTIFICATES_ONLY: 6736 ret = save_store_as_cms(file, pExportInfo->u.hCertStore); 6737 break; 6738 default: 6739 switch (pContextInfo->dwExportFormat) 6740 { 6741 case CRYPTUI_WIZ_EXPORT_FORMAT_DER: 6742 ret = save_der(file, pExportInfo->u.pCertContext->pbCertEncoded, 6743 pExportInfo->u.pCertContext->cbCertEncoded); 6744 break; 6745 case CRYPTUI_WIZ_EXPORT_FORMAT_BASE64: 6746 ret = save_base64(file, 6747 pExportInfo->u.pCertContext->pbCertEncoded, 6748 pExportInfo->u.pCertContext->cbCertEncoded); 6749 break; 6750 case CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7: 6751 ret = save_cert_as_cms(file, pExportInfo, 6752 pContextInfo->fExportChain); 6753 break; 6754 case CRYPTUI_WIZ_EXPORT_FORMAT_PFX: 6755 ret = save_pfx(file, pExportInfo, pContextInfo, keyProvInfo, 6756 deleteKeys); 6757 break; 6758 default: 6759 SetLastError(E_FAIL); 6760 ret = FALSE; 6761 } 6762 } 6763 return ret; 6764 } 6765 6766 static LRESULT CALLBACK export_finish_dlg_proc(HWND hwnd, UINT msg, WPARAM wp, 6767 LPARAM lp) 6768 { 6769 LRESULT ret = 0; 6770 struct ExportWizData *data; 6771 6772 switch (msg) 6773 { 6774 case WM_INITDIALOG: 6775 { 6776 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp; 6777 HWND lv = GetDlgItem(hwnd, IDC_EXPORT_SETTINGS); 6778 RECT rc; 6779 LVCOLUMNW column; 6780 6781 data = (struct ExportWizData *)page->lParam; 6782 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data); 6783 SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_TITLE), WM_SETFONT, 6784 (WPARAM)data->titleFont, TRUE); 6785 GetWindowRect(lv, &rc); 6786 column.mask = LVCF_WIDTH; 6787 column.cx = (rc.right - rc.left) / 2 - 2; 6788 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column); 6789 SendMessageW(lv, LVM_INSERTCOLUMNW, 1, (LPARAM)&column); 6790 show_export_details(lv, data); 6791 break; 6792 } 6793 case WM_NOTIFY: 6794 { 6795 NMHDR *hdr = (NMHDR *)lp; 6796 6797 switch (hdr->code) 6798 { 6799 case PSN_SETACTIVE: 6800 { 6801 HWND lv = GetDlgItem(hwnd, IDC_EXPORT_SETTINGS); 6802 6803 data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER); 6804 SendMessageW(lv, LVM_DELETEALLITEMS, 0, 0); 6805 show_export_details(lv, data); 6806 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0, 6807 PSWIZB_BACK | PSWIZB_FINISH); 6808 ret = TRUE; 6809 break; 6810 } 6811 case PSN_WIZFINISH: 6812 { 6813 int messageID; 6814 WCHAR title[MAX_STRING_LEN], message[MAX_STRING_LEN]; 6815 LPCWSTR pTitle; 6816 DWORD mbFlags; 6817 6818 data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER); 6819 if ((data->success = do_export(data->file, &data->exportInfo, 6820 &data->contextInfo, data->keyProvInfo, data->deleteKeys))) 6821 { 6822 messageID = IDS_EXPORT_SUCCEEDED; 6823 mbFlags = MB_OK; 6824 } 6825 else 6826 { 6827 messageID = IDS_EXPORT_FAILED; 6828 mbFlags = MB_OK | MB_ICONERROR; 6829 } 6830 if (data->pwszWizardTitle) 6831 pTitle = data->pwszWizardTitle; 6832 else 6833 { 6834 LoadStringW(hInstance, IDS_EXPORT_WIZARD, title, 6835 sizeof(title) / sizeof(title[0])); 6836 pTitle = title; 6837 } 6838 LoadStringW(hInstance, messageID, message, 6839 sizeof(message) / sizeof(message[0])); 6840 MessageBoxW(hwnd, message, pTitle, mbFlags); 6841 break; 6842 } 6843 } 6844 break; 6845 } 6846 } 6847 return ret; 6848 } 6849 6850 static BOOL show_export_ui(DWORD dwFlags, HWND hwndParent, 6851 LPCWSTR pwszWizardTitle, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo, const void *pvoid) 6852 { 6853 PROPSHEETHEADERW hdr; 6854 PROPSHEETPAGEW pages[6]; 6855 struct ExportWizData data; 6856 int nPages = 0; 6857 BOOL hasPrivateKey, showFormatPage = TRUE; 6858 INT_PTR l; 6859 6860 data.dwFlags = dwFlags; 6861 data.pwszWizardTitle = pwszWizardTitle; 6862 memset(&data.exportInfo, 0, sizeof(data.exportInfo)); 6863 memcpy(&data.exportInfo, pExportInfo, 6864 min(sizeof(data.exportInfo), pExportInfo->dwSize)); 6865 if (pExportInfo->dwSize > sizeof(data.exportInfo)) 6866 data.exportInfo.dwSize = sizeof(data.exportInfo); 6867 data.contextInfo.dwSize = sizeof(data.contextInfo); 6868 data.contextInfo.dwExportFormat = CRYPTUI_WIZ_EXPORT_FORMAT_DER; 6869 data.contextInfo.fExportChain = FALSE; 6870 data.contextInfo.fStrongEncryption = FALSE; 6871 data.contextInfo.fExportPrivateKeys = FALSE; 6872 data.contextInfo.pwszPassword = NULL; 6873 data.freePassword = FALSE; 6874 if (pExportInfo->dwSubjectChoice == CRYPTUI_WIZ_EXPORT_CERT_CONTEXT && 6875 pvoid) 6876 memcpy(&data.contextInfo, pvoid, 6877 min(((PCCRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO)pvoid)->dwSize, 6878 sizeof(data.contextInfo))); 6879 data.keyProvInfo = NULL; 6880 data.deleteKeys = FALSE; 6881 data.fileName = NULL; 6882 data.file = INVALID_HANDLE_VALUE; 6883 data.success = FALSE; 6884 6885 memset(pages, 0, sizeof(pages)); 6886 6887 pages[nPages].dwSize = sizeof(pages[0]); 6888 pages[nPages].hInstance = hInstance; 6889 pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_EXPORT_WELCOME); 6890 pages[nPages].pfnDlgProc = export_welcome_dlg_proc; 6891 pages[nPages].dwFlags = PSP_HIDEHEADER; 6892 pages[nPages].lParam = (LPARAM)&data; 6893 nPages++; 6894 6895 hasPrivateKey = export_info_has_private_key(pExportInfo); 6896 switch (pExportInfo->dwSubjectChoice) 6897 { 6898 case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT: 6899 case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT: 6900 showFormatPage = FALSE; 6901 data.contextInfo.dwExportFormat = CRYPTUI_WIZ_EXPORT_FORMAT_DER; 6902 break; 6903 case CRYPTUI_WIZ_EXPORT_CERT_STORE: 6904 showFormatPage = FALSE; 6905 data.contextInfo.dwExportFormat = 6906 CRYPTUI_WIZ_EXPORT_FORMAT_SERIALIZED_CERT_STORE; 6907 break; 6908 case CRYPTUI_WIZ_EXPORT_CERT_STORE_CERTIFICATES_ONLY: 6909 showFormatPage = FALSE; 6910 data.contextInfo.dwExportFormat = CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7; 6911 break; 6912 } 6913 6914 if (hasPrivateKey && showFormatPage) 6915 { 6916 pages[nPages].dwSize = sizeof(pages[0]); 6917 pages[nPages].hInstance = hInstance; 6918 pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_EXPORT_PRIVATE_KEY); 6919 pages[nPages].pfnDlgProc = export_private_key_dlg_proc; 6920 pages[nPages].dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE; 6921 pages[nPages].pszHeaderTitle = 6922 MAKEINTRESOURCEW(IDS_EXPORT_PRIVATE_KEY_TITLE); 6923 pages[nPages].pszHeaderSubTitle = 6924 MAKEINTRESOURCEW(IDS_EXPORT_PRIVATE_KEY_SUBTITLE); 6925 pages[nPages].lParam = (LPARAM)&data; 6926 nPages++; 6927 } 6928 if (showFormatPage) 6929 { 6930 pages[nPages].dwSize = sizeof(pages[0]); 6931 pages[nPages].hInstance = hInstance; 6932 pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_EXPORT_FORMAT); 6933 pages[nPages].pfnDlgProc = export_format_dlg_proc; 6934 pages[nPages].dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE; 6935 pages[nPages].pszHeaderTitle = 6936 MAKEINTRESOURCEW(IDS_EXPORT_FORMAT_TITLE); 6937 pages[nPages].pszHeaderSubTitle = 6938 MAKEINTRESOURCEW(IDS_EXPORT_FORMAT_SUBTITLE); 6939 pages[nPages].lParam = (LPARAM)&data; 6940 nPages++; 6941 } 6942 if (hasPrivateKey && showFormatPage) 6943 { 6944 pages[nPages].dwSize = sizeof(pages[0]); 6945 pages[nPages].hInstance = hInstance; 6946 pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_EXPORT_PASSWORD); 6947 pages[nPages].pfnDlgProc = export_password_dlg_proc; 6948 pages[nPages].dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE; 6949 pages[nPages].pszHeaderTitle = 6950 MAKEINTRESOURCEW(IDS_EXPORT_PASSWORD_TITLE); 6951 pages[nPages].pszHeaderSubTitle = 6952 MAKEINTRESOURCEW(IDS_EXPORT_PASSWORD_SUBTITLE); 6953 pages[nPages].lParam = (LPARAM)&data; 6954 nPages++; 6955 } 6956 6957 pages[nPages].dwSize = sizeof(pages[0]); 6958 pages[nPages].hInstance = hInstance; 6959 pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_EXPORT_FILE); 6960 pages[nPages].pfnDlgProc = export_file_dlg_proc; 6961 pages[nPages].dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE; 6962 pages[nPages].pszHeaderTitle = MAKEINTRESOURCEW(IDS_EXPORT_FILE_TITLE); 6963 pages[nPages].pszHeaderSubTitle = 6964 MAKEINTRESOURCEW(IDS_EXPORT_FILE_SUBTITLE); 6965 pages[nPages].lParam = (LPARAM)&data; 6966 nPages++; 6967 6968 pages[nPages].dwSize = sizeof(pages[0]); 6969 pages[nPages].hInstance = hInstance; 6970 pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_EXPORT_FINISH); 6971 pages[nPages].pfnDlgProc = export_finish_dlg_proc; 6972 pages[nPages].dwFlags = PSP_HIDEHEADER; 6973 pages[nPages].lParam = (LPARAM)&data; 6974 nPages++; 6975 6976 memset(&hdr, 0, sizeof(hdr)); 6977 hdr.dwSize = sizeof(hdr); 6978 hdr.hwndParent = hwndParent; 6979 hdr.dwFlags = PSH_PROPSHEETPAGE | PSH_WIZARD97_NEW | PSH_HEADER | 6980 PSH_WATERMARK; 6981 hdr.hInstance = hInstance; 6982 if (pwszWizardTitle) 6983 hdr.pszCaption = pwszWizardTitle; 6984 else 6985 hdr.pszCaption = MAKEINTRESOURCEW(IDS_EXPORT_WIZARD); 6986 hdr.u3.ppsp = pages; 6987 hdr.nPages = nPages; 6988 hdr.u4.pszbmWatermark = MAKEINTRESOURCEW(IDB_CERT_WATERMARK); 6989 hdr.u5.pszbmHeader = MAKEINTRESOURCEW(IDB_CERT_HEADER); 6990 l = PropertySheetW(&hdr); 6991 DeleteObject(data.titleFont); 6992 if (data.freePassword) 6993 HeapFree(GetProcessHeap(), 0, 6994 (LPWSTR)data.contextInfo.pwszPassword); 6995 HeapFree(GetProcessHeap(), 0, data.keyProvInfo); 6996 CloseHandle(data.file); 6997 HeapFree(GetProcessHeap(), 0, data.fileName); 6998 if (l == 0) 6999 { 7000 SetLastError(ERROR_CANCELLED); 7001 return FALSE; 7002 } 7003 else 7004 return data.success; 7005 } 7006 7007 BOOL WINAPI CryptUIWizExport(DWORD dwFlags, HWND hwndParent, 7008 LPCWSTR pwszWizardTitle, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo, void *pvoid) 7009 { 7010 BOOL ret; 7011 7012 TRACE("(%08x, %p, %s, %p, %p)\n", dwFlags, hwndParent, 7013 debugstr_w(pwszWizardTitle), pExportInfo, pvoid); 7014 7015 if (!(dwFlags & CRYPTUI_WIZ_NO_UI)) 7016 ret = show_export_ui(dwFlags, hwndParent, pwszWizardTitle, pExportInfo, 7017 pvoid); 7018 else 7019 { 7020 HANDLE file = CreateFileW(pExportInfo->pwszExportFileName, 7021 GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 7022 CREATE_ALWAYS, 0, NULL); 7023 7024 if (file != INVALID_HANDLE_VALUE) 7025 { 7026 ret = do_export(file, pExportInfo, pvoid, NULL, FALSE); 7027 CloseHandle(file); 7028 } 7029 else 7030 ret = FALSE; 7031 } 7032 return ret; 7033 } 7034 7035 BOOL WINAPI CryptUIDlgViewSignerInfoA(CRYPTUI_VIEWSIGNERINFO_STRUCTA *pcvsi) 7036 { 7037 FIXME("%p: stub\n", pcvsi); 7038 return FALSE; 7039 } 7040 7041 PCCERT_CONTEXT WINAPI CryptUIDlgSelectCertificateW(PCCRYPTUI_SELECTCERTIFICATE_STRUCTW pcsc) 7042 { 7043 FIXME("%p: stub\n", pcsc); 7044 return NULL; 7045 } 7046 7047 PCCERT_CONTEXT WINAPI CryptUIDlgSelectCertificateA(PCCRYPTUI_SELECTCERTIFICATE_STRUCTA pcsc) 7048 { 7049 FIXME("%p: stub\n", pcsc); 7050 return NULL; 7051 } 7052 7053 PCCERT_CONTEXT WINAPI CryptUIDlgSelectCertificateFromStore(HCERTSTORE hCertStore, HWND hwnd, LPCWSTR pwszTitle, 7054 LPCWSTR pwszDisplayString, DWORD dwDontUseColumn, 7055 DWORD dwFlags, void *pvReserved) 7056 { 7057 FIXME("%p %p %s %s %d %d %p: stub\n", hCertStore, hwnd, debugstr_w(pwszTitle), debugstr_w(pwszDisplayString), dwDontUseColumn, dwFlags, pvReserved); 7058 return NULL; 7059 } 7060 7061 BOOL WINAPI CryptUIWizDigitalSign(DWORD flags, HWND parent, LPCWSTR title, PCCRYPTUI_WIZ_DIGITAL_SIGN_INFO info, 7062 PCCRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT *context) 7063 { 7064 FIXME("%d %p %s %p %p: stub\n", flags, parent, debugstr_w(title), info, context); 7065 return FALSE; 7066 } 7067