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