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