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