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