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