Release 9.12.
[wine.git] / dlls / cryptui / main.c
blob2bd6b0b9f6a1d788d6291b73217085bb073e4b38
1 /*
2 * Copyright 2008 Juan Lang
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.
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.
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
19 #include <stdarg.h>
20 #include <wchar.h>
22 #define COBJMACROS
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winnls.h"
26 #include "winuser.h"
27 #include "softpub.h"
28 #include "wingdi.h"
29 #include "richedit.h"
30 #include "ole2.h"
31 #include "richole.h"
32 #include "commdlg.h"
33 #include "commctrl.h"
34 #include "cryptuiapi.h"
35 #include "cryptuires.h"
36 #include "urlmon.h"
37 #include "hlink.h"
38 #include "winreg.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(cryptui);
43 static HINSTANCE hInstance;
45 static const WCHAR empty[] = {0};
47 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
49 TRACE("(0x%p, %ld, %p)\n", hinstDLL, fdwReason, lpvReserved);
51 switch (fdwReason)
53 case DLL_PROCESS_ATTACH:
54 hInstance = hinstDLL;
55 DisableThreadLibraryCalls(hinstDLL);
56 break;
58 return TRUE;
61 static WCHAR *strdupAtoW( const char *str )
63 DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
64 WCHAR *ret = malloc( len * sizeof(WCHAR) );
65 if (ret) MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
66 return ret;
69 #define MAX_STRING_LEN 512
71 static void add_cert_columns(HWND hwnd)
73 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
74 RECT rc;
75 WCHAR buf[MAX_STRING_LEN];
76 LVCOLUMNW column;
78 SendMessageW(lv, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
79 GetWindowRect(lv, &rc);
80 LoadStringW(hInstance, IDS_SUBJECT_COLUMN, buf, ARRAY_SIZE(buf));
81 column.mask = LVCF_WIDTH | LVCF_TEXT;
82 column.cx = (rc.right - rc.left) * 29 / 100 - 2;
83 column.pszText = buf;
84 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
85 LoadStringW(hInstance, IDS_ISSUER_COLUMN, buf, ARRAY_SIZE(buf));
86 SendMessageW(lv, LVM_INSERTCOLUMNW, 1, (LPARAM)&column);
87 column.cx = (rc.right - rc.left) * 16 / 100 - 2;
88 LoadStringW(hInstance, IDS_EXPIRATION_COLUMN, buf, ARRAY_SIZE(buf));
89 SendMessageW(lv, LVM_INSERTCOLUMNW, 2, (LPARAM)&column);
90 column.cx = (rc.right - rc.left) * 23 / 100 - 1;
91 LoadStringW(hInstance, IDS_FRIENDLY_NAME_COLUMN, buf, ARRAY_SIZE(buf));
92 SendMessageW(lv, LVM_INSERTCOLUMNW, 3, (LPARAM)&column);
95 static void add_cert_to_view(HWND lv, PCCERT_CONTEXT cert, DWORD *allocatedLen,
96 LPWSTR *str)
98 DWORD len;
99 LVITEMW item;
100 WCHAR dateFmt[80]; /* sufficient for LOCALE_SSHORTDATE */
101 WCHAR date[80];
102 SYSTEMTIME sysTime;
103 LPWSTR none;
105 item.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_TEXT;
106 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
107 item.iSubItem = 0;
108 item.iImage = 0;
109 item.lParam = (LPARAM)CertDuplicateCertificateContext(cert);
110 len = CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL,
111 NULL, 0);
112 if (len > *allocatedLen)
114 free(*str);
115 *str = malloc(len * sizeof(WCHAR));
116 if (*str)
117 *allocatedLen = len;
119 if (*str)
121 CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL,
122 *str, len);
123 item.pszText = *str;
124 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
127 item.mask = LVIF_TEXT;
128 len = CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
129 CERT_NAME_ISSUER_FLAG, NULL, NULL, 0);
130 if (len > *allocatedLen)
132 free(*str);
133 *str = malloc(len * sizeof(WCHAR));
134 if (*str)
135 *allocatedLen = len;
137 if (*str)
139 CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
140 CERT_NAME_ISSUER_FLAG, NULL, *str, len);
141 item.pszText = *str;
142 item.iSubItem = 1;
143 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
146 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SSHORTDATE, dateFmt, ARRAY_SIZE(dateFmt));
147 FileTimeToSystemTime(&cert->pCertInfo->NotAfter, &sysTime);
148 GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, date, ARRAY_SIZE(date));
149 item.pszText = date;
150 item.iSubItem = 2;
151 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
153 if (!CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID,
154 NULL, &len))
155 len = LoadStringW(hInstance, IDS_FRIENDLY_NAME_NONE, (LPWSTR)&none, 0);
156 if (len > *allocatedLen)
158 free(*str);
159 *str = malloc(len * sizeof(WCHAR));
160 if (*str)
161 *allocatedLen = len;
163 if (*str)
165 if (!CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID,
166 *str, &len))
167 item.pszText = none;
168 else
169 item.pszText = *str;
170 item.iSubItem = 3;
171 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
175 static LPSTR get_cert_mgr_usages(void)
177 static const WCHAR keyName[] = { 'S','o','f','t','w','a','r','e','\\','M',
178 'i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g','r','a',
179 'p','h','y','\\','U','I','\\','C','e','r','t','m','g','r','\\','P','u',
180 'r','p','o','s','e',0 };
181 LPSTR str = NULL;
182 HKEY key;
184 if (!RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, NULL, 0, KEY_READ,
185 NULL, &key, NULL))
187 LONG rc;
188 DWORD type, size;
190 rc = RegQueryValueExA(key, "Purpose", NULL, &type, NULL, &size);
191 if ((!rc || rc == ERROR_MORE_DATA) && type == REG_SZ)
193 str = malloc(size);
194 if (str)
196 rc = RegQueryValueExA(key, "Purpose", NULL, NULL, (LPBYTE)str,
197 &size);
198 if (rc)
200 free(str);
201 str = NULL;
205 RegCloseKey(key);
207 return str;
210 typedef enum {
211 PurposeFilterShowAll = 0,
212 PurposeFilterShowAdvanced = 1,
213 PurposeFilterShowOID = 2
214 } PurposeFilter;
216 static void initialize_purpose_selection(HWND hwnd)
218 HWND cb = GetDlgItem(hwnd, IDC_MGR_PURPOSE_SELECTION);
219 WCHAR buf[MAX_STRING_LEN];
220 LPSTR usages;
221 int index;
223 LoadStringW(hInstance, IDS_PURPOSE_ALL, buf, ARRAY_SIZE(buf));
224 index = SendMessageW(cb, CB_INSERTSTRING, -1, (LPARAM)buf);
225 SendMessageW(cb, CB_SETITEMDATA, index, (LPARAM)PurposeFilterShowAll);
226 LoadStringW(hInstance, IDS_PURPOSE_ADVANCED, buf, ARRAY_SIZE(buf));
227 index = SendMessageW(cb, CB_INSERTSTRING, -1, (LPARAM)buf);
228 SendMessageW(cb, CB_SETITEMDATA, index, (LPARAM)PurposeFilterShowAdvanced);
229 SendMessageW(cb, CB_SETCURSEL, 0, 0);
230 if ((usages = get_cert_mgr_usages()))
232 LPSTR ptr, comma;
234 for (ptr = usages, comma = strchr(ptr, ','); ptr && *ptr;
235 ptr = comma ? comma + 1 : NULL,
236 comma = ptr ? strchr(ptr, ',') : NULL)
238 PCCRYPT_OID_INFO info;
240 if (comma)
241 *comma = 0;
242 if ((info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, ptr, 0)))
244 index = SendMessageW(cb, CB_INSERTSTRING, 0,
245 (LPARAM)info->pwszName);
246 SendMessageW(cb, CB_SETITEMDATA, index, (LPARAM)info);
249 free(usages);
253 extern BOOL WINAPI WTHelperGetKnownUsages(DWORD action,
254 PCCRYPT_OID_INFO **usages);
256 static CERT_ENHKEY_USAGE *add_oid_to_usage(CERT_ENHKEY_USAGE *usage, LPSTR oid)
258 usage->rgpszUsageIdentifier = realloc(usage->rgpszUsageIdentifier,
259 (usage->cUsageIdentifier + 1) * sizeof(char *));
260 if (usage->rgpszUsageIdentifier)
261 usage->rgpszUsageIdentifier[usage->cUsageIdentifier++] = oid;
262 else
264 free(usage);
265 usage = NULL;
267 return usage;
270 static CERT_ENHKEY_USAGE *convert_usages_str_to_usage(LPSTR usageStr)
272 CERT_ENHKEY_USAGE *usage = calloc(1, sizeof(CERT_ENHKEY_USAGE));
274 if (usage)
276 LPSTR ptr, comma;
278 for (ptr = usageStr, comma = strchr(ptr, ','); usage && ptr && *ptr;
279 ptr = comma ? comma + 1 : NULL,
280 comma = ptr ? strchr(ptr, ',') : NULL)
282 if (comma)
283 *comma = 0;
284 usage = add_oid_to_usage(usage, ptr);
287 return usage;
290 static CERT_ENHKEY_USAGE *create_advanced_filter(void)
292 CERT_ENHKEY_USAGE *advancedUsage = calloc(1, sizeof(CERT_ENHKEY_USAGE));
294 if (advancedUsage)
296 PCCRYPT_OID_INFO *usages;
298 if (WTHelperGetKnownUsages(1, &usages))
300 LPSTR disabledUsagesStr;
302 if ((disabledUsagesStr = get_cert_mgr_usages()))
304 CERT_ENHKEY_USAGE *disabledUsages =
305 convert_usages_str_to_usage(disabledUsagesStr);
307 if (disabledUsages)
309 PCCRYPT_OID_INFO *ptr;
311 for (ptr = usages; advancedUsage && *ptr; ptr++)
313 DWORD i;
314 BOOL disabled = FALSE;
316 for (i = 0; !disabled &&
317 i < disabledUsages->cUsageIdentifier; i++)
318 if (!strcmp(disabledUsages->rgpszUsageIdentifier[i],
319 (*ptr)->pszOID))
320 disabled = TRUE;
321 if (!disabled)
322 advancedUsage = add_oid_to_usage(advancedUsage,
323 (LPSTR)(*ptr)->pszOID);
325 /* The individual strings are pointers to disabledUsagesStr,
326 * so they're freed when it is.
328 free(disabledUsages->rgpszUsageIdentifier);
329 free(disabledUsages);
331 free(disabledUsagesStr);
333 WTHelperGetKnownUsages(2, &usages);
336 return advancedUsage;
339 static int CALLBACK cert_mgr_sort_by_subject(LPARAM lp1, LPARAM lp2, LPARAM lp);
341 static void show_store_certs(HWND hwnd, HCERTSTORE store)
343 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
344 HWND cb = GetDlgItem(hwnd, IDC_MGR_PURPOSE_SELECTION);
345 PCCERT_CONTEXT cert = NULL;
346 DWORD allocatedLen = 0;
347 LPWSTR str = NULL;
348 int index;
349 PurposeFilter filter = PurposeFilterShowAll;
350 LPCSTR oid = NULL;
351 CERT_ENHKEY_USAGE *advanced = NULL;
353 index = SendMessageW(cb, CB_GETCURSEL, 0, 0);
354 if (index >= 0)
356 INT_PTR data = SendMessageW(cb, CB_GETITEMDATA, index, 0);
358 if (!HIWORD(data))
359 filter = data;
360 else
362 PCCRYPT_OID_INFO info = (PCCRYPT_OID_INFO)data;
364 filter = PurposeFilterShowOID;
365 oid = info->pszOID;
368 if (filter == PurposeFilterShowAdvanced)
369 advanced = create_advanced_filter();
370 do {
371 cert = CertEnumCertificatesInStore(store, cert);
372 if (cert)
374 BOOL show = FALSE;
376 if (filter == PurposeFilterShowAll)
377 show = TRUE;
378 else
380 int numOIDs;
381 DWORD cbOIDs = 0;
383 if (CertGetValidUsages(1, &cert, &numOIDs, NULL, &cbOIDs))
385 if (numOIDs == -1)
387 /* -1 implies all usages are valid */
388 show = TRUE;
390 else
392 char **oids = malloc(cbOIDs);
394 if (oids)
396 if (CertGetValidUsages(1, &cert, &numOIDs, oids,
397 &cbOIDs))
399 int i;
401 if (filter == PurposeFilterShowOID)
403 for (i = 0; !show && i < numOIDs; i++)
404 if (!strcmp(oids[i], oid))
405 show = TRUE;
407 else
409 for (i = 0; !show && i < numOIDs; i++)
411 DWORD j;
413 for (j = 0; !show &&
414 j < advanced->cUsageIdentifier; j++)
415 if (!strcmp(oids[i],
416 advanced->rgpszUsageIdentifier[j]))
417 show = TRUE;
421 free(oids);
426 if (show)
427 add_cert_to_view(lv, cert, &allocatedLen, &str);
429 } while (cert);
430 free(str);
431 if (advanced)
433 free(advanced->rgpszUsageIdentifier);
434 free(advanced);
436 SendMessageW(lv, LVM_SORTITEMSEX, (WPARAM)lv,
437 (LPARAM)cert_mgr_sort_by_subject);
440 static const WCHAR my[] = { 'M','y',0 };
441 static const WCHAR addressBook[] = {
442 'A','d','d','r','e','s','s','B','o','o','k',0 };
443 static const WCHAR ca[] = { 'C','A',0 };
444 static const WCHAR root[] = { 'R','o','o','t',0 };
445 static const WCHAR trustedPublisher[] = {
446 'T','r','u','s','t','e','d','P','u','b','l','i','s','h','e','r',0 };
447 static const WCHAR disallowed[] = { 'D','i','s','a','l','l','o','w','e','d',0 };
449 struct CertMgrStoreInfo
451 LPCWSTR name;
452 int removeWarning;
453 int removePluralWarning;
456 static const struct CertMgrStoreInfo defaultStoreList[] = {
457 { my, IDS_WARN_REMOVE_MY, IDS_WARN_REMOVE_PLURAL_MY },
458 { addressBook, IDS_WARN_REMOVE_ADDRESSBOOK,
459 IDS_WARN_REMOVE_PLURAL_ADDRESSBOOK },
460 { ca, IDS_WARN_REMOVE_CA, IDS_WARN_REMOVE_PLURAL_CA },
461 { root, IDS_WARN_REMOVE_ROOT, IDS_WARN_REMOVE_PLURAL_ROOT },
462 { trustedPublisher, IDS_WARN_REMOVE_TRUSTEDPUBLISHER,
463 IDS_WARN_REMOVE_PLURAL_TRUSTEDPUBLISHER },
464 { disallowed, IDS_WARN_REMOVE_DEFAULT },
467 static const struct CertMgrStoreInfo publisherStoreList[] = {
468 { root, IDS_WARN_REMOVE_ROOT, IDS_WARN_REMOVE_PLURAL_ROOT },
469 { trustedPublisher, IDS_WARN_REMOVE_TRUSTEDPUBLISHER,
470 IDS_WARN_REMOVE_PLURAL_TRUSTEDPUBLISHER },
471 { disallowed, IDS_WARN_REMOVE_PLURAL_DEFAULT },
474 struct CertMgrData
476 HIMAGELIST imageList;
477 LPCWSTR title;
478 DWORD nStores;
479 const struct CertMgrStoreInfo *stores;
482 static void show_cert_stores(HWND hwnd, DWORD dwFlags, struct CertMgrData *data)
484 const struct CertMgrStoreInfo *storeList;
485 int cStores, i;
486 HWND tab = GetDlgItem(hwnd, IDC_MGR_STORES);
488 if (dwFlags & CRYPTUI_CERT_MGR_PUBLISHER_TAB)
490 storeList = publisherStoreList;
491 cStores = ARRAY_SIZE(publisherStoreList);
493 else
495 storeList = defaultStoreList;
496 cStores = ARRAY_SIZE(defaultStoreList);
498 if (dwFlags & CRYPTUI_CERT_MGR_SINGLE_TAB_FLAG)
499 cStores = 1;
500 data->nStores = cStores;
501 data->stores = storeList;
502 for (i = 0; i < cStores; i++)
504 LPCWSTR name;
505 TCITEMW item;
506 HCERTSTORE store;
508 if (!(name = CryptFindLocalizedName(storeList[i].name)))
509 name = storeList[i].name;
510 store = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0,
511 CERT_SYSTEM_STORE_CURRENT_USER, storeList[i].name);
512 item.mask = TCIF_TEXT | TCIF_PARAM;
513 item.pszText = (LPWSTR)name;
514 item.lParam = (LPARAM)store;
515 SendMessageW(tab, TCM_INSERTITEMW, i, (LPARAM)&item);
519 static void free_certs(HWND lv)
521 LVITEMW item;
522 int items = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0), i;
524 for (i = 0; i < items; i++)
526 item.mask = LVIF_PARAM;
527 item.iItem = i;
528 item.iSubItem = 0;
529 SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item);
530 CertFreeCertificateContext((PCCERT_CONTEXT)item.lParam);
534 static HCERTSTORE cert_mgr_index_to_store(HWND tab, int index)
536 TCITEMW item;
538 item.mask = TCIF_PARAM;
539 SendMessageW(tab, TCM_GETITEMW, index, (LPARAM)&item);
540 return (HCERTSTORE)item.lParam;
543 static HCERTSTORE cert_mgr_current_store(HWND hwnd)
545 HWND tab = GetDlgItem(hwnd, IDC_MGR_STORES);
547 return cert_mgr_index_to_store(tab, SendMessageW(tab, TCM_GETCURSEL, 0, 0));
550 static void close_stores(HWND tab)
552 int i, tabs = SendMessageW(tab, TCM_GETITEMCOUNT, 0, 0);
554 for (i = 0; i < tabs; i++)
555 CertCloseStore(cert_mgr_index_to_store(tab, i), 0);
558 static void refresh_store_certs(HWND hwnd)
560 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
562 free_certs(lv);
563 SendMessageW(lv, LVM_DELETEALLITEMS, 0, 0);
564 show_store_certs(hwnd, cert_mgr_current_store(hwnd));
567 typedef enum {
568 CheckBitmapIndexUnchecked = 1,
569 CheckBitmapIndexChecked = 2,
570 CheckBitmapIndexDisabledUnchecked = 3,
571 CheckBitmapIndexDisabledChecked = 4
572 } CheckBitmapIndex;
574 static void add_known_usage(HWND lv, PCCRYPT_OID_INFO info,
575 CheckBitmapIndex state)
577 LVITEMW item;
579 item.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM;
580 item.state = INDEXTOSTATEIMAGEMASK(state);
581 item.stateMask = LVIS_STATEIMAGEMASK;
582 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
583 item.iSubItem = 0;
584 item.lParam = (LPARAM)info;
585 item.pszText = (LPWSTR)info->pwszName;
586 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
589 static void add_known_usages_to_list(HWND lv, CheckBitmapIndex state)
591 PCCRYPT_OID_INFO *usages;
593 if (WTHelperGetKnownUsages(1, &usages))
595 PCCRYPT_OID_INFO *ptr;
597 for (ptr = usages; *ptr; ptr++)
598 add_known_usage(lv, *ptr, state);
599 WTHelperGetKnownUsages(2, &usages);
603 static void toggle_usage(HWND hwnd, int iItem)
605 LVITEMW item;
606 int res;
607 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
609 item.mask = LVIF_STATE;
610 item.iItem = iItem;
611 item.iSubItem = 0;
612 item.stateMask = LVIS_STATEIMAGEMASK;
613 res = SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item);
614 if (res)
616 int state = item.state >> 12;
618 item.state = INDEXTOSTATEIMAGEMASK(
619 state == CheckBitmapIndexChecked ? CheckBitmapIndexUnchecked :
620 CheckBitmapIndexChecked);
621 SendMessageW(lv, LVM_SETITEMSTATE, iItem, (LPARAM)&item);
625 static LONG_PTR find_oid_in_list(HWND lv, LPCSTR oid)
627 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
628 (void *)oid, CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
629 LONG_PTR ret;
631 if (oidInfo)
633 LVFINDINFOW findInfo;
635 findInfo.flags = LVFI_PARAM;
636 findInfo.lParam = (LPARAM)oidInfo;
637 ret = SendMessageW(lv, LVM_FINDITEMW, -1, (LPARAM)&findInfo);
639 else
641 LVFINDINFOA findInfo;
643 findInfo.flags = LVFI_STRING;
644 findInfo.psz = oid;
645 ret = SendMessageW(lv, LVM_FINDITEMA, -1, (LPARAM)&findInfo);
647 return ret;
650 static void save_cert_mgr_usages(HWND hwnd)
652 static const WCHAR keyName[] = { 'S','o','f','t','w','a','r','e','\\','M',
653 'i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g','r','a',
654 'p','h','y','\\','U','I','\\','C','e','r','t','m','g','r','\\','P','u',
655 'r','p','o','s','e',0 };
656 HKEY key;
657 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
658 int purposes = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0), i;
659 LVITEMW item;
660 LPSTR str = NULL;
662 item.mask = LVIF_STATE | LVIF_PARAM;
663 item.iSubItem = 0;
664 item.stateMask = LVIS_STATEIMAGEMASK;
665 for (i = 0; i < purposes; i++)
667 item.iItem = i;
668 if (SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item))
670 int state = item.state >> 12;
672 if (state == CheckBitmapIndexUnchecked)
674 CRYPT_OID_INFO *info = (CRYPT_OID_INFO *)item.lParam;
675 BOOL firstString = TRUE;
677 if (!str)
678 str = malloc(strlen(info->pszOID) + 1);
679 else
681 str = realloc(str, strlen(str) + 1 + strlen(info->pszOID) + 1);
682 firstString = FALSE;
684 if (str)
686 LPSTR ptr = firstString ? str : str + strlen(str);
688 if (!firstString)
689 *ptr++ = ',';
690 strcpy(ptr, info->pszOID);
695 if (!RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, NULL, 0, KEY_ALL_ACCESS,
696 NULL, &key, NULL))
698 if (str)
699 RegSetValueExA(key, "Purpose", 0, REG_SZ, (const BYTE *)str,
700 strlen(str) + 1);
701 else
702 RegDeleteValueA(key, "Purpose");
703 RegCloseKey(key);
705 free(str);
708 static INT_PTR CALLBACK cert_mgr_advanced_dlg_proc(HWND hwnd, UINT msg,
709 WPARAM wp, LPARAM lp)
711 switch (msg)
713 case WM_INITDIALOG:
715 RECT rc;
716 LVCOLUMNW column;
717 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
718 HIMAGELIST imageList;
719 LPSTR disabledUsages;
721 GetWindowRect(lv, &rc);
722 column.mask = LVCF_WIDTH;
723 column.cx = rc.right - rc.left;
724 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
725 imageList = ImageList_Create(16, 16, ILC_COLOR4 | ILC_MASK, 4, 0);
726 if (imageList)
728 HBITMAP bmp;
729 COLORREF backColor = RGB(255, 0, 255);
731 bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_CHECKS));
732 ImageList_AddMasked(imageList, bmp, backColor);
733 DeleteObject(bmp);
734 ImageList_SetBkColor(imageList, CLR_NONE);
735 SendMessageW(lv, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)imageList);
736 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)imageList);
738 add_known_usages_to_list(lv, CheckBitmapIndexChecked);
739 if ((disabledUsages = get_cert_mgr_usages()))
741 LPSTR ptr, comma;
743 for (ptr = disabledUsages, comma = strchr(ptr, ','); ptr && *ptr;
744 ptr = comma ? comma + 1 : NULL,
745 comma = ptr ? strchr(ptr, ',') : NULL)
747 LONG_PTR index;
749 if (comma)
750 *comma = 0;
751 if ((index = find_oid_in_list(lv, ptr)) != -1)
752 toggle_usage(hwnd, index);
754 free(disabledUsages);
756 break;
758 case WM_NOTIFY:
760 NMHDR *hdr = (NMHDR *)lp;
761 NMITEMACTIVATE *nm;
763 switch (hdr->code)
765 case NM_CLICK:
766 nm = (NMITEMACTIVATE *)lp;
767 toggle_usage(hwnd, nm->iItem);
768 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
769 break;
771 break;
773 case WM_COMMAND:
774 switch (wp)
776 case IDOK:
777 save_cert_mgr_usages(hwnd);
778 ImageList_Destroy((HIMAGELIST)GetWindowLongPtrW(hwnd, DWLP_USER));
779 EndDialog(hwnd, IDOK);
780 break;
781 case IDCANCEL:
782 ImageList_Destroy((HIMAGELIST)GetWindowLongPtrW(hwnd, DWLP_USER));
783 EndDialog(hwnd, IDCANCEL);
784 break;
786 break;
788 return 0;
791 static void cert_mgr_clear_cert_selection(HWND hwnd)
793 EnableWindow(GetDlgItem(hwnd, IDC_MGR_EXPORT), FALSE);
794 EnableWindow(GetDlgItem(hwnd, IDC_MGR_REMOVE), FALSE);
795 EnableWindow(GetDlgItem(hwnd, IDC_MGR_VIEW), FALSE);
796 SendMessageW(GetDlgItem(hwnd, IDC_MGR_PURPOSES), WM_SETTEXT, 0,
797 (LPARAM)empty);
798 refresh_store_certs(hwnd);
801 static PCCERT_CONTEXT cert_mgr_index_to_cert(HWND hwnd, int index)
803 PCCERT_CONTEXT cert = NULL;
804 LVITEMW item;
806 item.mask = LVIF_PARAM;
807 item.iItem = index;
808 item.iSubItem = 0;
809 if (SendMessageW(GetDlgItem(hwnd, IDC_MGR_CERTS), LVM_GETITEMW, 0,
810 (LPARAM)&item))
811 cert = (PCCERT_CONTEXT)item.lParam;
812 return cert;
815 static void show_selected_cert(HWND hwnd, int index)
817 PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd, index);
819 if (cert)
821 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
823 memset(&viewInfo, 0, sizeof(viewInfo));
824 viewInfo.dwSize = sizeof(viewInfo);
825 viewInfo.hwndParent = hwnd;
826 viewInfo.pCertContext = cert;
827 /* FIXME: this should be modal */
828 CryptUIDlgViewCertificateW(&viewInfo, NULL);
832 static void get_cert_usages(PCCERT_CONTEXT cert, LPWSTR *str)
834 PCERT_ENHKEY_USAGE usage;
835 DWORD size;
837 /* Get enhanced key usage. Have to check for a property and an extension
838 * separately, because CertGetEnhancedKeyUsage will succeed and return an
839 * empty usage if neither is set. Unfortunately an empty usage implies
840 * no usage is allowed, so we have to distinguish between the two cases.
842 if (CertGetEnhancedKeyUsage(cert, CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG,
843 NULL, &size))
845 usage = malloc(size);
846 if (!CertGetEnhancedKeyUsage(cert,
847 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size))
849 free(usage);
850 usage = NULL;
853 else if (CertGetEnhancedKeyUsage(cert, CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
854 NULL, &size))
856 usage = malloc(size);
857 if (!CertGetEnhancedKeyUsage(cert,
858 CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, usage, &size))
860 free(usage);
861 usage = NULL;
864 else
865 usage = NULL;
866 if (usage)
868 if (usage->cUsageIdentifier)
870 static const WCHAR commaSpace[] = { ',',' ',0 };
871 DWORD i, len = 1;
872 LPWSTR ptr;
874 for (i = 0; i < usage->cUsageIdentifier; i++)
876 PCCRYPT_OID_INFO info =
877 CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
878 usage->rgpszUsageIdentifier[i],
879 CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
881 if (info)
882 len += lstrlenW(info->pwszName);
883 else
884 len += strlen(usage->rgpszUsageIdentifier[i]);
885 if (i < usage->cUsageIdentifier - 1)
886 len += lstrlenW(commaSpace);
888 *str = malloc(len * sizeof(WCHAR));
889 if (*str)
891 for (i = 0, ptr = *str; i < usage->cUsageIdentifier; i++)
893 PCCRYPT_OID_INFO info =
894 CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
895 usage->rgpszUsageIdentifier[i],
896 CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
898 if (info)
900 lstrcpyW(ptr, info->pwszName);
901 ptr += lstrlenW(info->pwszName);
903 else
905 LPCSTR src = usage->rgpszUsageIdentifier[i];
907 for (; *src; ptr++, src++)
908 *ptr = *src;
909 *ptr = 0;
911 if (i < usage->cUsageIdentifier - 1)
913 lstrcpyW(ptr, commaSpace);
914 ptr += lstrlenW(commaSpace);
917 *ptr = 0;
919 free(usage);
921 else
923 size = MAX_STRING_LEN * sizeof(WCHAR);
924 *str = malloc(size);
925 if (*str)
926 LoadStringW(hInstance, IDS_ALLOWED_PURPOSE_NONE, *str, MAX_STRING_LEN);
929 else
931 size = MAX_STRING_LEN * sizeof(WCHAR);
932 *str = malloc(size);
933 if (*str)
934 LoadStringW(hInstance, IDS_ALLOWED_PURPOSE_ALL, *str, MAX_STRING_LEN);
938 static void cert_mgr_show_cert_usages(HWND hwnd, int index)
940 HWND text = GetDlgItem(hwnd, IDC_MGR_PURPOSES);
941 PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd, index);
942 LPWSTR str = NULL;
944 get_cert_usages(cert, &str);
945 if (str)
947 SendMessageW(text, WM_SETTEXT, 0, (LPARAM)str);
948 free(str);
952 static void cert_mgr_do_remove(HWND hwnd)
954 int tabIndex = SendMessageW(GetDlgItem(hwnd, IDC_MGR_STORES),
955 TCM_GETCURSEL, 0, 0);
956 struct CertMgrData *data =
957 (struct CertMgrData *)GetWindowLongPtrW(hwnd, DWLP_USER);
959 if (tabIndex < data->nStores)
961 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
962 WCHAR warning[MAX_STRING_LEN], title[MAX_STRING_LEN];
963 LPCWSTR pTitle;
964 int warningID;
966 if (SendMessageW(lv, LVM_GETSELECTEDCOUNT, 0, 0) > 1)
967 warningID = data->stores[tabIndex].removePluralWarning;
968 else
969 warningID = data->stores[tabIndex].removeWarning;
970 if (data->title)
971 pTitle = data->title;
972 else
974 LoadStringW(hInstance, IDS_CERT_MGR, title, ARRAY_SIZE(title));
975 pTitle = title;
977 LoadStringW(hInstance, warningID, warning, ARRAY_SIZE(warning));
978 if (MessageBoxW(hwnd, warning, pTitle, MB_YESNO) == IDYES)
980 int selection = -1;
982 do {
983 selection = SendMessageW(lv, LVM_GETNEXTITEM, selection,
984 LVNI_SELECTED);
985 if (selection >= 0)
987 PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd,
988 selection);
990 CertDeleteCertificateFromStore(cert);
992 } while (selection >= 0);
993 cert_mgr_clear_cert_selection(hwnd);
998 static void cert_mgr_do_export(HWND hwnd)
1000 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
1001 int selectionCount = SendMessageW(lv, LVM_GETSELECTEDCOUNT, 0, 0);
1003 if (selectionCount == 1)
1005 int selection = SendMessageW(lv, LVM_GETNEXTITEM, -1,
1006 LVNI_SELECTED);
1008 if (selection >= 0)
1010 PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd, selection);
1012 if (cert)
1014 CRYPTUI_WIZ_EXPORT_INFO info;
1016 info.dwSize = sizeof(info);
1017 info.pwszExportFileName = NULL;
1018 info.dwSubjectChoice = CRYPTUI_WIZ_EXPORT_CERT_CONTEXT;
1019 info.pCertContext = cert;
1020 info.cStores = 0;
1021 CryptUIWizExport(0, hwnd, NULL, &info, NULL);
1025 else if (selectionCount > 1)
1027 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
1028 CERT_STORE_CREATE_NEW_FLAG, NULL);
1030 if (store)
1032 CRYPTUI_WIZ_EXPORT_INFO info;
1033 int selection = -1;
1035 info.dwSize = sizeof(info);
1036 info.pwszExportFileName = NULL;
1037 info.dwSubjectChoice =
1038 CRYPTUI_WIZ_EXPORT_CERT_STORE_CERTIFICATES_ONLY;
1039 info.hCertStore = store;
1040 info.cStores = 0;
1041 do {
1042 selection = SendMessageW(lv, LVM_GETNEXTITEM, selection,
1043 LVNI_SELECTED);
1044 if (selection >= 0)
1046 PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd,
1047 selection);
1049 CertAddCertificateContextToStore(store, cert,
1050 CERT_STORE_ADD_ALWAYS, NULL);
1052 } while (selection >= 0);
1053 CryptUIWizExport(0, hwnd, NULL, &info, NULL);
1054 CertCloseStore(store, 0);
1059 static int cert_mgr_sort_by_text(HWND lv, int col, int index1, int index2)
1061 LVITEMW item;
1062 WCHAR buf1[MAX_STRING_LEN];
1063 WCHAR buf2[MAX_STRING_LEN];
1065 item.cchTextMax = ARRAY_SIZE(buf1);
1066 item.mask = LVIF_TEXT;
1067 item.pszText = buf1;
1068 item.iItem = index1;
1069 item.iSubItem = col;
1070 SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item);
1071 item.pszText = buf2;
1072 item.iItem = index2;
1073 SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item);
1074 return lstrcmpW(buf1, buf2);
1077 static int CALLBACK cert_mgr_sort_by_subject(LPARAM lp1, LPARAM lp2, LPARAM lp)
1079 return cert_mgr_sort_by_text((HWND)lp, 0, lp1, lp2);
1082 static int CALLBACK cert_mgr_sort_by_issuer(LPARAM lp1, LPARAM lp2, LPARAM lp)
1084 return cert_mgr_sort_by_text((HWND)lp, 1, lp1, lp2);
1087 static int CALLBACK cert_mgr_sort_by_date(LPARAM lp1, LPARAM lp2, LPARAM lp)
1089 PCCERT_CONTEXT cert1 = (PCCERT_CONTEXT)lp1;
1090 PCCERT_CONTEXT cert2 = (PCCERT_CONTEXT)lp2;
1091 return CompareFileTime(&cert1->pCertInfo->NotAfter,
1092 &cert2->pCertInfo->NotAfter);
1095 static int CALLBACK cert_mgr_sort_by_friendly_name(LPARAM lp1, LPARAM lp2,
1096 LPARAM lp)
1098 return cert_mgr_sort_by_text((HWND)lp, 3, lp1, lp2);
1101 static INT_PTR CALLBACK cert_mgr_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
1102 LPARAM lp)
1104 struct CertMgrData *data;
1106 switch (msg)
1108 case WM_INITDIALOG:
1110 PCCRYPTUI_CERT_MGR_STRUCT pCryptUICertMgr =
1111 (PCCRYPTUI_CERT_MGR_STRUCT)lp;
1112 HWND tab = GetDlgItem(hwnd, IDC_MGR_STORES);
1114 data = malloc(sizeof(struct CertMgrData));
1115 if (!data)
1116 return 0;
1117 data->imageList = ImageList_Create(16, 16, ILC_COLOR4 | ILC_MASK, 2, 0);
1118 if (data->imageList)
1120 HBITMAP bmp;
1121 COLORREF backColor = RGB(255, 0, 255);
1123 bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_SMALL_ICONS));
1124 ImageList_AddMasked(data->imageList, bmp, backColor);
1125 DeleteObject(bmp);
1126 ImageList_SetBkColor(data->imageList, CLR_NONE);
1127 SendMessageW(GetDlgItem(hwnd, IDC_MGR_CERTS), LVM_SETIMAGELIST,
1128 LVSIL_SMALL, (LPARAM)data->imageList);
1130 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
1131 data->title = pCryptUICertMgr->pwszTitle;
1133 initialize_purpose_selection(hwnd);
1134 add_cert_columns(hwnd);
1135 if (pCryptUICertMgr->pwszTitle)
1136 SendMessageW(hwnd, WM_SETTEXT, 0,
1137 (LPARAM)pCryptUICertMgr->pwszTitle);
1138 show_cert_stores(hwnd, pCryptUICertMgr->dwFlags, data);
1139 show_store_certs(hwnd, cert_mgr_index_to_store(tab, 0));
1140 break;
1142 case WM_NOTIFY:
1144 NMHDR *hdr = (NMHDR *)lp;
1146 switch (hdr->code)
1148 case TCN_SELCHANGE:
1149 cert_mgr_clear_cert_selection(hwnd);
1150 break;
1151 case LVN_ITEMCHANGED:
1153 NMITEMACTIVATE *nm = (NMITEMACTIVATE*)lp;
1154 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
1155 int numSelected = SendMessageW(lv, LVM_GETSELECTEDCOUNT, 0, 0);
1157 EnableWindow(GetDlgItem(hwnd, IDC_MGR_EXPORT), numSelected > 0);
1158 EnableWindow(GetDlgItem(hwnd, IDC_MGR_REMOVE), numSelected > 0);
1159 EnableWindow(GetDlgItem(hwnd, IDC_MGR_VIEW), numSelected == 1);
1160 if (numSelected == 1)
1161 cert_mgr_show_cert_usages(hwnd, nm->iItem);
1162 else
1163 SendMessageW(GetDlgItem(hwnd, IDC_MGR_PURPOSES), WM_SETTEXT, 0,
1164 (LPARAM)empty);
1165 break;
1167 case NM_DBLCLK:
1168 show_selected_cert(hwnd, ((NMITEMACTIVATE *)lp)->iItem);
1169 break;
1170 case LVN_KEYDOWN:
1172 NMLVKEYDOWN *lvk = (NMLVKEYDOWN *)lp;
1174 if (lvk->wVKey == VK_DELETE)
1175 cert_mgr_do_remove(hwnd);
1176 break;
1178 case LVN_COLUMNCLICK:
1180 NMLISTVIEW *nmlv = (NMLISTVIEW *)lp;
1181 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
1183 /* FIXME: doesn't support swapping sort order between ascending
1184 * and descending.
1186 switch (nmlv->iSubItem)
1188 case 0:
1189 SendMessageW(lv, LVM_SORTITEMSEX, (WPARAM)lv,
1190 (LPARAM)cert_mgr_sort_by_subject);
1191 break;
1192 case 1:
1193 SendMessageW(lv, LVM_SORTITEMSEX, (WPARAM)lv,
1194 (LPARAM)cert_mgr_sort_by_issuer);
1195 break;
1196 case 2:
1197 SendMessageW(lv, LVM_SORTITEMS, 0,
1198 (LPARAM)cert_mgr_sort_by_date);
1199 break;
1200 case 3:
1201 SendMessageW(lv, LVM_SORTITEMSEX, (WPARAM)lv,
1202 (LPARAM)cert_mgr_sort_by_friendly_name);
1203 break;
1205 break;
1208 break;
1210 case WM_COMMAND:
1211 switch (wp)
1213 case ((CBN_SELCHANGE << 16) | IDC_MGR_PURPOSE_SELECTION):
1214 cert_mgr_clear_cert_selection(hwnd);
1215 break;
1216 case IDC_MGR_IMPORT:
1217 if (CryptUIWizImport(0, hwnd, NULL, NULL,
1218 cert_mgr_current_store(hwnd)))
1219 refresh_store_certs(hwnd);
1220 break;
1221 case IDC_MGR_ADVANCED:
1222 if (DialogBoxW(hInstance, MAKEINTRESOURCEW(IDD_CERT_MGR_ADVANCED),
1223 hwnd, cert_mgr_advanced_dlg_proc) == IDOK)
1225 HWND cb = GetDlgItem(hwnd, IDC_MGR_PURPOSE_SELECTION);
1226 int index, len;
1227 LPWSTR curString = NULL;
1229 index = SendMessageW(cb, CB_GETCURSEL, 0, 0);
1230 if (index >= 0)
1232 len = SendMessageW(cb, CB_GETLBTEXTLEN, index, 0);
1233 curString = malloc((len + 1) * sizeof(WCHAR));
1234 SendMessageW(cb, CB_GETLBTEXT, index, (LPARAM)curString);
1236 SendMessageW(cb, CB_RESETCONTENT, 0, 0);
1237 initialize_purpose_selection(hwnd);
1238 if (curString)
1240 index = SendMessageW(cb, CB_FINDSTRINGEXACT, -1,
1241 (LPARAM)curString);
1242 if (index >= 0)
1243 SendMessageW(cb, CB_SETCURSEL, index, 0);
1244 free(curString);
1246 refresh_store_certs(hwnd);
1248 break;
1249 case IDC_MGR_VIEW:
1251 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
1252 int selection = SendMessageW(lv, LVM_GETNEXTITEM, -1,
1253 LVNI_SELECTED);
1255 if (selection >= 0)
1256 show_selected_cert(hwnd, selection);
1257 break;
1259 case IDC_MGR_EXPORT:
1260 cert_mgr_do_export(hwnd);
1261 break;
1262 case IDC_MGR_REMOVE:
1263 cert_mgr_do_remove(hwnd);
1264 break;
1265 case IDCANCEL:
1266 free_certs(GetDlgItem(hwnd, IDC_MGR_CERTS));
1267 close_stores(GetDlgItem(hwnd, IDC_MGR_STORES));
1268 data = (struct CertMgrData *)GetWindowLongPtrW(hwnd, DWLP_USER);
1269 ImageList_Destroy(data->imageList);
1270 free(data);
1271 EndDialog(hwnd, IDCANCEL);
1272 break;
1274 break;
1276 return 0;
1279 /***********************************************************************
1280 * CryptUIDlgCertMgr (CRYPTUI.@)
1282 BOOL WINAPI CryptUIDlgCertMgr(PCCRYPTUI_CERT_MGR_STRUCT pCryptUICertMgr)
1284 TRACE("(%p)\n", pCryptUICertMgr);
1286 if (pCryptUICertMgr->dwSize != sizeof(CRYPTUI_CERT_MGR_STRUCT))
1288 WARN("unexpected size %ld\n", pCryptUICertMgr->dwSize);
1289 SetLastError(E_INVALIDARG);
1290 return FALSE;
1292 DialogBoxParamW(hInstance, MAKEINTRESOURCEW(IDD_CERT_MGR),
1293 pCryptUICertMgr->hwndParent, cert_mgr_dlg_proc, (LPARAM)pCryptUICertMgr);
1294 return TRUE;
1297 /* FIXME: real names are unknown, functions are undocumented */
1298 typedef struct _CRYPTUI_ENUM_SYSTEM_STORE_ARGS
1300 DWORD dwFlags;
1301 void *pvSystemStoreLocationPara;
1302 } CRYPTUI_ENUM_SYSTEM_STORE_ARGS, *PCRYPTUI_ENUM_SYSTEM_STORE_ARGS;
1304 typedef struct _CRYPTUI_ENUM_DATA
1306 DWORD cStores;
1307 HCERTSTORE *rghStore;
1308 DWORD cEnumArgs;
1309 PCRYPTUI_ENUM_SYSTEM_STORE_ARGS rgEnumArgs;
1310 } CRYPTUI_ENUM_DATA, *PCRYPTUI_ENUM_DATA;
1312 typedef BOOL (WINAPI *PFN_SELECTED_STORE_CB)(HCERTSTORE store, HWND hwnd,
1313 void *pvArg);
1315 /* Values for dwFlags */
1316 #define CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE 0x00000001
1318 typedef struct _CRYPTUI_SELECTSTORE_INFO_A
1320 DWORD dwSize;
1321 HWND parent;
1322 DWORD dwFlags;
1323 LPSTR pszTitle;
1324 LPSTR pszText;
1325 CRYPTUI_ENUM_DATA *pEnumData;
1326 PFN_SELECTED_STORE_CB pfnSelectedStoreCallback;
1327 void *pvArg;
1328 } CRYPTUI_SELECTSTORE_INFO_A, *PCRYPTUI_SELECTSTORE_INFO_A;
1330 typedef struct _CRYPTUI_SELECTSTORE_INFO_W
1332 DWORD dwSize;
1333 HWND parent;
1334 DWORD dwFlags;
1335 LPWSTR pwszTitle;
1336 LPWSTR pwszText;
1337 CRYPTUI_ENUM_DATA *pEnumData;
1338 PFN_SELECTED_STORE_CB pfnSelectedStoreCallback;
1339 void *pvArg;
1340 } CRYPTUI_SELECTSTORE_INFO_W, *PCRYPTUI_SELECTSTORE_INFO_W;
1342 struct StoreInfo
1344 enum {
1345 StoreHandle,
1346 SystemStore
1347 } type;
1348 union {
1349 HCERTSTORE store;
1350 LPWSTR name;
1351 } DUMMYUNIONNAME;
1354 static BOOL WINAPI enum_store_callback(const void *pvSystemStore,
1355 DWORD dwFlags, PCERT_SYSTEM_STORE_INFO pStoreInfo, void *pvReserved,
1356 void *pvArg)
1358 HWND tree = GetDlgItem(pvArg, IDC_STORE_LIST);
1359 TVINSERTSTRUCTW tvis;
1360 LPCWSTR localizedName;
1361 BOOL ret = TRUE;
1363 tvis.hParent = NULL;
1364 tvis.hInsertAfter = TVI_LAST;
1365 tvis.item.mask = TVIF_TEXT;
1366 if ((localizedName = CryptFindLocalizedName(pvSystemStore)))
1368 struct StoreInfo *storeInfo = malloc(sizeof(struct StoreInfo));
1370 if (storeInfo)
1372 storeInfo->type = SystemStore;
1373 storeInfo->name = wcsdup(pvSystemStore);
1374 if (storeInfo->name)
1376 tvis.item.mask |= TVIF_PARAM;
1377 tvis.item.lParam = (LPARAM)storeInfo;
1379 else
1381 free(storeInfo);
1382 ret = FALSE;
1385 else
1386 ret = FALSE;
1387 tvis.item.pszText = (LPWSTR)localizedName;
1389 else
1390 tvis.item.pszText = (LPWSTR)pvSystemStore;
1391 /* FIXME: need a folder icon for the store too */
1392 if (ret)
1393 SendMessageW(tree, TVM_INSERTITEMW, 0, (LPARAM)&tvis);
1394 return ret;
1397 static void enumerate_stores(HWND hwnd, CRYPTUI_ENUM_DATA *pEnumData)
1399 DWORD i;
1400 HWND tree = GetDlgItem(hwnd, IDC_STORE_LIST);
1402 for (i = 0; i < pEnumData->cEnumArgs; i++)
1403 CertEnumSystemStore(pEnumData->rgEnumArgs[i].dwFlags,
1404 pEnumData->rgEnumArgs[i].pvSystemStoreLocationPara,
1405 hwnd, enum_store_callback);
1406 for (i = 0; i < pEnumData->cStores; i++)
1408 DWORD size;
1410 if (CertGetStoreProperty(pEnumData->rghStore[i],
1411 CERT_STORE_LOCALIZED_NAME_PROP_ID, NULL, &size))
1413 WCHAR *name = malloc(size);
1415 if (name)
1417 if (CertGetStoreProperty(pEnumData->rghStore[i],
1418 CERT_STORE_LOCALIZED_NAME_PROP_ID, name, &size))
1420 struct StoreInfo *storeInfo = malloc(sizeof(struct StoreInfo));
1422 if (storeInfo)
1424 TVINSERTSTRUCTW tvis;
1426 storeInfo->type = StoreHandle;
1427 storeInfo->store = pEnumData->rghStore[i];
1428 tvis.hParent = NULL;
1429 tvis.hInsertAfter = TVI_LAST;
1430 tvis.item.mask = TVIF_TEXT | TVIF_PARAM;
1431 tvis.item.pszText = name;
1432 tvis.item.lParam = (LPARAM)storeInfo;
1433 SendMessageW(tree, TVM_INSERTITEMW, 0, (LPARAM)&tvis);
1436 free(name);
1442 static void free_store_info(HWND tree)
1444 HTREEITEM next = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM, TVGN_CHILD,
1447 while (next)
1449 TVITEMW item;
1451 memset(&item, 0, sizeof(item));
1452 item.mask = TVIF_HANDLE | TVIF_PARAM;
1453 item.hItem = next;
1454 SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item);
1455 if (item.lParam)
1457 struct StoreInfo *storeInfo = (struct StoreInfo *)item.lParam;
1459 if (storeInfo->type == SystemStore)
1460 free(storeInfo->name);
1461 free(storeInfo);
1463 next = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM, TVGN_NEXT,
1464 (LPARAM)next);
1468 static HCERTSTORE selected_item_to_store(HWND tree, HTREEITEM hItem)
1470 WCHAR buf[MAX_STRING_LEN];
1471 TVITEMW item;
1472 HCERTSTORE store;
1474 memset(&item, 0, sizeof(item));
1475 item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_TEXT;
1476 item.hItem = hItem;
1477 item.cchTextMax = ARRAY_SIZE(buf);
1478 item.pszText = buf;
1479 SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item);
1480 if (item.lParam)
1482 struct StoreInfo *storeInfo = (struct StoreInfo *)item.lParam;
1484 if (storeInfo->type == StoreHandle)
1485 store = storeInfo->store;
1486 else
1487 store = CertOpenSystemStoreW(0, storeInfo->name);
1489 else
1491 /* It's implicitly a system store */
1492 store = CertOpenSystemStoreW(0, buf);
1494 return store;
1497 struct SelectStoreInfo
1499 PCRYPTUI_SELECTSTORE_INFO_W info;
1500 HCERTSTORE store;
1503 static INT_PTR CALLBACK select_store_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
1504 LPARAM lp)
1506 struct SelectStoreInfo *selectInfo;
1507 INT_PTR ret = 0;
1509 switch (msg)
1511 case WM_INITDIALOG:
1513 selectInfo = (struct SelectStoreInfo *)lp;
1514 SetWindowLongPtrW(hwnd, DWLP_USER, lp);
1515 if (selectInfo->info->pwszTitle)
1516 SendMessageW(hwnd, WM_SETTEXT, 0,
1517 (LPARAM)selectInfo->info->pwszTitle);
1518 if (selectInfo->info->pwszText)
1519 SendMessageW(GetDlgItem(hwnd, IDC_STORE_TEXT), WM_SETTEXT, 0,
1520 (LPARAM)selectInfo->info->pwszText);
1521 if (!(selectInfo->info->dwFlags & CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE))
1522 ShowWindow(GetDlgItem(hwnd, IDC_SHOW_PHYSICAL_STORES), FALSE);
1523 enumerate_stores(hwnd, selectInfo->info->pEnumData);
1524 break;
1526 case WM_COMMAND:
1527 switch (wp)
1529 case IDOK:
1531 HWND tree = GetDlgItem(hwnd, IDC_STORE_LIST);
1532 HTREEITEM selection = (HTREEITEM)SendMessageW(tree,
1533 TVM_GETNEXTITEM, TVGN_CARET, 0);
1535 selectInfo = (struct SelectStoreInfo *)GetWindowLongPtrW(hwnd,
1536 DWLP_USER);
1537 if (!selection)
1539 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN], *pTitle;
1541 if (selectInfo->info->pwszTitle)
1542 pTitle = selectInfo->info->pwszTitle;
1543 else
1545 LoadStringW(hInstance, IDS_SELECT_STORE_TITLE, title, ARRAY_SIZE(title));
1546 pTitle = title;
1548 LoadStringW(hInstance, IDS_SELECT_STORE, error, ARRAY_SIZE(error));
1549 MessageBoxW(hwnd, error, pTitle, MB_ICONEXCLAMATION | MB_OK);
1551 else
1553 HCERTSTORE store = selected_item_to_store(tree, selection);
1555 if (!selectInfo->info->pfnSelectedStoreCallback ||
1556 selectInfo->info->pfnSelectedStoreCallback(store, hwnd,
1557 selectInfo->info->pvArg))
1559 selectInfo->store = store;
1560 free_store_info(tree);
1561 EndDialog(hwnd, IDOK);
1563 else
1564 CertCloseStore(store, 0);
1566 ret = TRUE;
1567 break;
1569 case IDCANCEL:
1570 free_store_info(GetDlgItem(hwnd, IDC_STORE_LIST));
1571 EndDialog(hwnd, IDCANCEL);
1572 ret = TRUE;
1573 break;
1575 break;
1577 return ret;
1580 /***********************************************************************
1581 * CryptUIDlgSelectStoreW (CRYPTUI.@)
1583 HCERTSTORE WINAPI CryptUIDlgSelectStoreW(PCRYPTUI_SELECTSTORE_INFO_W info)
1585 struct SelectStoreInfo selectInfo = { info, NULL };
1587 TRACE("(%p)\n", info);
1589 if (info->dwSize != sizeof(CRYPTUI_SELECTSTORE_INFO_W))
1591 WARN("unexpected size %ld\n", info->dwSize);
1592 SetLastError(E_INVALIDARG);
1593 return NULL;
1595 DialogBoxParamW(hInstance, MAKEINTRESOURCEW(IDD_SELECT_STORE), info->parent,
1596 select_store_dlg_proc, (LPARAM)&selectInfo);
1597 return selectInfo.store;
1600 /***********************************************************************
1601 * CryptUIDlgSelectStoreA (CRYPTUI.@)
1603 HCERTSTORE WINAPI CryptUIDlgSelectStoreA(PCRYPTUI_SELECTSTORE_INFO_A info)
1605 CRYPTUI_SELECTSTORE_INFO_W infoW;
1606 HCERTSTORE ret;
1607 int len;
1609 TRACE("(%p)\n", info);
1611 if (info->dwSize != sizeof(CRYPTUI_SELECTSTORE_INFO_A))
1613 WARN("unexpected size %ld\n", info->dwSize);
1614 SetLastError(E_INVALIDARG);
1615 return NULL;
1617 memcpy(&infoW, info, sizeof(*info));
1618 if (info->pszTitle)
1620 len = MultiByteToWideChar(CP_ACP, 0, info->pszTitle, -1, NULL, 0);
1621 infoW.pwszTitle = malloc(len * sizeof(WCHAR));
1622 MultiByteToWideChar(CP_ACP, 0, info->pszTitle, -1, infoW.pwszTitle,
1623 len);
1625 if (info->pszText)
1627 len = MultiByteToWideChar(CP_ACP, 0, info->pszText, -1, NULL, 0);
1628 infoW.pwszText = malloc(len * sizeof(WCHAR));
1629 MultiByteToWideChar(CP_ACP, 0, info->pszText, -1, infoW.pwszText, len);
1631 ret = CryptUIDlgSelectStoreW(&infoW);
1632 free(infoW.pwszText);
1633 free(infoW.pwszTitle);
1634 return ret;
1637 /***********************************************************************
1638 * CryptUIDlgViewCertificateA (CRYPTUI.@)
1640 BOOL WINAPI CryptUIDlgViewCertificateA(
1641 PCCRYPTUI_VIEWCERTIFICATE_STRUCTA pCertViewInfo, BOOL *pfPropertiesChanged)
1643 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
1644 LPWSTR title = NULL;
1645 BOOL ret;
1647 TRACE("(%p, %p)\n", pCertViewInfo, pfPropertiesChanged);
1649 memcpy(&viewInfo, pCertViewInfo, sizeof(viewInfo));
1650 if (pCertViewInfo->szTitle)
1652 int len = MultiByteToWideChar(CP_ACP, 0, pCertViewInfo->szTitle, -1,
1653 NULL, 0);
1655 title = malloc(len * sizeof(WCHAR));
1656 if (title)
1658 MultiByteToWideChar(CP_ACP, 0, pCertViewInfo->szTitle, -1, title,
1659 len);
1660 viewInfo.szTitle = title;
1662 else
1664 ret = FALSE;
1665 goto error;
1668 if (pCertViewInfo->cPropSheetPages)
1670 FIXME("ignoring additional prop sheet pages\n");
1671 viewInfo.cPropSheetPages = 0;
1673 ret = CryptUIDlgViewCertificateW(&viewInfo, pfPropertiesChanged);
1674 free(title);
1675 error:
1676 return ret;
1679 struct ReadStringStruct
1681 LPCWSTR buf;
1682 LONG pos;
1683 LONG len;
1686 static DWORD CALLBACK read_text_callback(DWORD_PTR dwCookie, LPBYTE buf,
1687 LONG cb, LONG *pcb)
1689 struct ReadStringStruct *string = (struct ReadStringStruct *)dwCookie;
1690 LONG cch = min(cb / sizeof(WCHAR), string->len - string->pos);
1692 TRACE("(%p, %p, %ld, %p)\n", string, buf, cb, pcb);
1694 memmove(buf, string->buf + string->pos, cch * sizeof(WCHAR));
1695 string->pos += cch;
1696 *pcb = cch * sizeof(WCHAR);
1697 return 0;
1700 static void add_unformatted_text_to_control(HWND hwnd, LPCWSTR text, LONG len)
1702 struct ReadStringStruct string;
1703 EDITSTREAM editstream;
1705 TRACE("(%p, %s)\n", hwnd, debugstr_wn(text, len));
1707 string.buf = text;
1708 string.pos = 0;
1709 string.len = len;
1710 editstream.dwCookie = (DWORD_PTR)&string;
1711 editstream.dwError = 0;
1712 editstream.pfnCallback = read_text_callback;
1713 SendMessageW(hwnd, EM_STREAMIN, SF_TEXT | SFF_SELECTION | SF_UNICODE,
1714 (LPARAM)&editstream);
1717 static void add_string_resource_to_control(HWND hwnd, int id)
1719 LPWSTR str;
1720 LONG len;
1722 len = LoadStringW(hInstance, id, (LPWSTR)&str, 0);
1723 add_unformatted_text_to_control(hwnd, str, len);
1726 static void add_text_with_paraformat_to_control(HWND hwnd, LPCWSTR text,
1727 LONG len, const PARAFORMAT2 *fmt)
1729 add_unformatted_text_to_control(hwnd, text, len);
1730 SendMessageW(hwnd, EM_SETPARAFORMAT, 0, (LPARAM)fmt);
1733 static void add_string_resource_with_paraformat_to_control(HWND hwnd, int id,
1734 const PARAFORMAT2 *fmt)
1736 LPWSTR str;
1737 LONG len;
1739 len = LoadStringW(hInstance, id, (LPWSTR)&str, 0);
1740 add_text_with_paraformat_to_control(hwnd, str, len, fmt);
1743 static LPWSTR get_cert_name_string(PCCERT_CONTEXT pCertContext, DWORD dwType,
1744 DWORD dwFlags)
1746 LPWSTR buf = NULL;
1747 DWORD len;
1749 len = CertGetNameStringW(pCertContext, dwType, dwFlags, NULL, NULL, 0);
1750 if (len)
1752 buf = malloc(len * sizeof(WCHAR));
1753 if (buf)
1754 CertGetNameStringW(pCertContext, dwType, dwFlags, NULL, buf, len);
1756 return buf;
1759 static void add_cert_string_to_control(HWND hwnd, PCCERT_CONTEXT pCertContext,
1760 DWORD dwType, DWORD dwFlags)
1762 LPWSTR name = get_cert_name_string(pCertContext, dwType, dwFlags);
1764 if (name)
1766 /* Don't include NULL-terminator in output */
1767 DWORD len = lstrlenW(name);
1769 add_unformatted_text_to_control(hwnd, name, len);
1770 free(name);
1774 static void add_icon_to_control(HWND hwnd, int id)
1776 HRESULT hr;
1777 IRichEditOle *richEditOle = NULL;
1778 IOleObject *object = NULL;
1779 CLSID clsid;
1780 LPOLECACHE oleCache = NULL;
1781 FORMATETC formatEtc;
1782 DWORD conn;
1783 IDataObject *dataObject = NULL;
1784 HBITMAP bitmap = NULL;
1785 STGMEDIUM stgm;
1786 IOleClientSite *clientSite = NULL;
1787 REOBJECT reObject;
1789 TRACE("(%p, %d)\n", hwnd, id);
1791 SendMessageW(hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&richEditOle);
1792 if (!richEditOle)
1793 goto end;
1794 hr = OleCreateDefaultHandler(&CLSID_NULL, NULL, &IID_IOleObject,
1795 (void**)&object);
1796 if (FAILED(hr))
1797 goto end;
1798 hr = IOleObject_GetUserClassID(object, &clsid);
1799 if (FAILED(hr))
1800 goto end;
1801 hr = IOleObject_QueryInterface(object, &IID_IOleCache, (void**)&oleCache);
1802 if (FAILED(hr))
1803 goto end;
1804 formatEtc.cfFormat = CF_BITMAP;
1805 formatEtc.ptd = NULL;
1806 formatEtc.dwAspect = DVASPECT_CONTENT;
1807 formatEtc.lindex = -1;
1808 formatEtc.tymed = TYMED_GDI;
1809 hr = IOleCache_Cache(oleCache, &formatEtc, 0, &conn);
1810 if (FAILED(hr))
1811 goto end;
1812 hr = IOleObject_QueryInterface(object, &IID_IDataObject,
1813 (void**)&dataObject);
1814 if (FAILED(hr))
1815 goto end;
1816 hr = IRichEditOle_GetClientSite(richEditOle, &clientSite);
1817 if (FAILED(hr))
1818 goto end;
1819 bitmap = LoadImageW(hInstance, MAKEINTRESOURCEW(id), IMAGE_BITMAP, 0, 0,
1820 LR_DEFAULTSIZE | LR_LOADTRANSPARENT);
1821 if (!bitmap)
1822 goto end;
1823 stgm.tymed = TYMED_GDI;
1824 stgm.hBitmap = bitmap;
1825 stgm.pUnkForRelease = NULL;
1826 hr = IDataObject_SetData(dataObject, &formatEtc, &stgm, TRUE);
1827 if (FAILED(hr))
1828 goto end;
1830 reObject.cbStruct = sizeof(reObject);
1831 reObject.cp = REO_CP_SELECTION;
1832 reObject.clsid = clsid;
1833 reObject.poleobj = object;
1834 reObject.pstg = NULL;
1835 reObject.polesite = clientSite;
1836 reObject.sizel.cx = reObject.sizel.cy = 0;
1837 reObject.dvaspect = DVASPECT_CONTENT;
1838 reObject.dwFlags = 0;
1839 reObject.dwUser = 0;
1841 IRichEditOle_InsertObject(richEditOle, &reObject);
1843 end:
1844 if (clientSite)
1845 IOleClientSite_Release(clientSite);
1846 if (dataObject)
1847 IDataObject_Release(dataObject);
1848 if (oleCache)
1849 IOleCache_Release(oleCache);
1850 if (object)
1851 IOleObject_Release(object);
1852 if (richEditOle)
1853 IRichEditOle_Release(richEditOle);
1856 #define MY_INDENT 200
1858 static void add_oid_text_to_control(HWND hwnd, char *oid)
1860 WCHAR nl = '\n';
1861 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, oid, 0);
1862 PARAFORMAT2 parFmt;
1864 parFmt.cbSize = sizeof(parFmt);
1865 parFmt.dwMask = PFM_STARTINDENT;
1866 parFmt.dxStartIndent = MY_INDENT * 3;
1867 if (oidInfo)
1869 add_text_with_paraformat_to_control(hwnd, oidInfo->pwszName,
1870 lstrlenW(oidInfo->pwszName), &parFmt);
1871 add_unformatted_text_to_control(hwnd, &nl, 1);
1875 struct OIDToString
1877 LPCSTR oid;
1878 int id;
1881 /* The following list MUST be lexicographically sorted by OID */
1882 static struct OIDToString oidMap[] = {
1883 /* 1.3.6.1.4.1.311.10.3.1 */
1884 { szOID_KP_CTL_USAGE_SIGNING, IDS_PURPOSE_CTL_USAGE_SIGNING },
1885 /* 1.3.6.1.4.1.311.10.3.4 */
1886 { szOID_KP_EFS, IDS_PURPOSE_EFS },
1887 /* 1.3.6.1.4.1.311.10.3.4.1 */
1888 { szOID_EFS_RECOVERY, IDS_PURPOSE_EFS_RECOVERY },
1889 /* 1.3.6.1.4.1.311.10.3.5 */
1890 { szOID_WHQL_CRYPTO, IDS_PURPOSE_WHQL },
1891 /* 1.3.6.1.4.1.311.10.3.6 */
1892 { szOID_NT5_CRYPTO, IDS_PURPOSE_NT5 },
1893 /* 1.3.6.1.4.1.311.10.3.7 */
1894 { szOID_OEM_WHQL_CRYPTO, IDS_PURPOSE_OEM_WHQL },
1895 /* 1.3.6.1.4.1.311.10.3.8 */
1896 { szOID_EMBEDDED_NT_CRYPTO, IDS_PURPOSE_EMBEDDED_NT },
1897 /* 1.3.6.1.4.1.311.10.3.9 */
1898 { szOID_ROOT_LIST_SIGNER, IDS_PURPOSE_ROOT_LIST_SIGNER },
1899 /* 1.3.6.1.4.1.311.10.3.10 */
1900 { szOID_KP_QUALIFIED_SUBORDINATION, IDS_PURPOSE_QUALIFIED_SUBORDINATION },
1901 /* 1.3.6.1.4.1.311.10.3.11 */
1902 { szOID_KP_KEY_RECOVERY, IDS_PURPOSE_KEY_RECOVERY },
1903 /* 1.3.6.1.4.1.311.10.3.12 */
1904 { szOID_KP_DOCUMENT_SIGNING, IDS_PURPOSE_DOCUMENT_SIGNING },
1905 /* 1.3.6.1.4.1.311.10.3.13 */
1906 { szOID_KP_LIFETIME_SIGNING, IDS_PURPOSE_LIFETIME_SIGNING },
1907 /* 1.3.6.1.4.1.311.10.5.1 */
1908 { szOID_DRM, IDS_PURPOSE_DRM },
1909 /* 1.3.6.1.4.1.311.10.6.1 */
1910 { szOID_LICENSES, IDS_PURPOSE_LICENSES },
1911 /* 1.3.6.1.4.1.311.10.6.2 */
1912 { szOID_LICENSE_SERVER, IDS_PURPOSE_LICENSE_SERVER },
1913 /* 1.3.6.1.4.1.311.20.2.1 */
1914 { szOID_ENROLLMENT_AGENT, IDS_PURPOSE_ENROLLMENT_AGENT },
1915 /* 1.3.6.1.4.1.311.20.2.2 */
1916 { szOID_KP_SMARTCARD_LOGON, IDS_PURPOSE_SMARTCARD_LOGON },
1917 /* 1.3.6.1.4.1.311.21.5 */
1918 { szOID_KP_CA_EXCHANGE, IDS_PURPOSE_CA_EXCHANGE },
1919 /* 1.3.6.1.4.1.311.21.6 */
1920 { szOID_KP_KEY_RECOVERY_AGENT, IDS_PURPOSE_KEY_RECOVERY_AGENT },
1921 /* 1.3.6.1.4.1.311.21.19 */
1922 { szOID_DS_EMAIL_REPLICATION, IDS_PURPOSE_DS_EMAIL_REPLICATION },
1923 /* 1.3.6.1.5.5.7.3.1 */
1924 { szOID_PKIX_KP_SERVER_AUTH, IDS_PURPOSE_SERVER_AUTH },
1925 /* 1.3.6.1.5.5.7.3.2 */
1926 { szOID_PKIX_KP_CLIENT_AUTH, IDS_PURPOSE_CLIENT_AUTH },
1927 /* 1.3.6.1.5.5.7.3.3 */
1928 { szOID_PKIX_KP_CODE_SIGNING, IDS_PURPOSE_CODE_SIGNING },
1929 /* 1.3.6.1.5.5.7.3.4 */
1930 { szOID_PKIX_KP_EMAIL_PROTECTION, IDS_PURPOSE_EMAIL_PROTECTION },
1931 /* 1.3.6.1.5.5.7.3.5 */
1932 { szOID_PKIX_KP_IPSEC_END_SYSTEM, IDS_PURPOSE_IPSEC },
1933 /* 1.3.6.1.5.5.7.3.6 */
1934 { szOID_PKIX_KP_IPSEC_TUNNEL, IDS_PURPOSE_IPSEC },
1935 /* 1.3.6.1.5.5.7.3.7 */
1936 { szOID_PKIX_KP_IPSEC_USER, IDS_PURPOSE_IPSEC },
1937 /* 1.3.6.1.5.5.7.3.8 */
1938 { szOID_PKIX_KP_TIMESTAMP_SIGNING, IDS_PURPOSE_TIMESTAMP_SIGNING },
1941 static struct OIDToString *findSupportedOID(LPCSTR oid)
1943 int indexHigh = ARRAY_SIZE(oidMap) - 1, indexLow = 0;
1945 while (indexLow <= indexHigh)
1947 int cmp, i = (indexLow + indexHigh) / 2;
1948 if (!(cmp = strcmp(oid, oidMap[i].oid)))
1949 return &oidMap[i];
1950 if (cmp > 0)
1951 indexLow = i + 1;
1952 else
1953 indexHigh = i - 1;
1955 return NULL;
1958 static void add_local_oid_text_to_control(HWND text, LPCSTR oid)
1960 struct OIDToString *entry;
1961 WCHAR nl = '\n';
1962 PARAFORMAT2 parFmt;
1964 parFmt.cbSize = sizeof(parFmt);
1965 parFmt.dwMask = PFM_STARTINDENT;
1966 parFmt.dxStartIndent = MY_INDENT * 3;
1967 if ((entry = findSupportedOID(oid)))
1969 WCHAR *str, *linebreak, *ptr;
1970 BOOL multiline = FALSE;
1971 int len;
1973 len = LoadStringW(hInstance, entry->id, (LPWSTR)&str, 0);
1974 ptr = str;
1975 do {
1976 if ((linebreak = wmemchr(ptr, '\n', len)))
1978 WCHAR copy[MAX_STRING_LEN];
1980 multiline = TRUE;
1981 /* The source string contains a newline, which the richedit
1982 * control won't find since it's interpreted as a paragraph
1983 * break. Therefore copy up to the newline. lstrcpynW always
1984 * NULL-terminates, so pass one more than the length of the
1985 * source line so the copy includes the entire line and the
1986 * NULL-terminator.
1988 lstrcpynW(copy, ptr, linebreak - ptr + 1);
1989 add_text_with_paraformat_to_control(text, copy,
1990 linebreak - ptr, &parFmt);
1991 ptr = linebreak + 1;
1992 add_unformatted_text_to_control(text, &nl, 1);
1994 else if (multiline && *ptr)
1996 /* Add the last line */
1997 add_text_with_paraformat_to_control(text, ptr,
1998 len - (ptr - str), &parFmt);
1999 add_unformatted_text_to_control(text, &nl, 1);
2001 } while (linebreak);
2002 if (!multiline)
2004 add_text_with_paraformat_to_control(text, str, len, &parFmt);
2005 add_unformatted_text_to_control(text, &nl, 1);
2008 else
2010 WCHAR *oidW = malloc((strlen(oid) + 1) * sizeof(WCHAR));
2012 if (oidW)
2014 LPCSTR src;
2015 WCHAR *dst;
2017 for (src = oid, dst = oidW; *src; src++, dst++)
2018 *dst = *src;
2019 *dst = 0;
2020 add_text_with_paraformat_to_control(text, oidW, lstrlenW(oidW),
2021 &parFmt);
2022 add_unformatted_text_to_control(text, &nl, 1);
2023 free(oidW);
2028 static void display_app_usages(HWND text, PCCERT_CONTEXT cert,
2029 BOOL *anyUsageAdded)
2031 static char any_app_policy[] = szOID_ANY_APPLICATION_POLICY;
2032 WCHAR nl = '\n';
2033 CHARFORMATW charFmt;
2034 PCERT_EXTENSION policyExt;
2035 if (!*anyUsageAdded)
2037 PARAFORMAT2 parFmt;
2039 parFmt.cbSize = sizeof(parFmt);
2040 parFmt.dwMask = PFM_STARTINDENT;
2041 parFmt.dxStartIndent = MY_INDENT;
2042 add_string_resource_with_paraformat_to_control(text,
2043 IDS_CERT_INFO_PURPOSES, &parFmt);
2044 add_unformatted_text_to_control(text, &nl, 1);
2045 *anyUsageAdded = TRUE;
2047 memset(&charFmt, 0, sizeof(charFmt));
2048 charFmt.cbSize = sizeof(charFmt);
2049 charFmt.dwMask = CFM_BOLD;
2050 charFmt.dwEffects = 0;
2051 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2052 if ((policyExt = CertFindExtension(szOID_APPLICATION_CERT_POLICIES,
2053 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension)))
2055 CERT_POLICIES_INFO *policies;
2056 DWORD size;
2058 if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_POLICIES,
2059 policyExt->Value.pbData, policyExt->Value.cbData,
2060 CRYPT_DECODE_ALLOC_FLAG, NULL, &policies, &size))
2062 DWORD i;
2064 for (i = 0; i < policies->cPolicyInfo; i++)
2066 DWORD j;
2068 for (j = 0; j < policies->rgPolicyInfo[i].cPolicyQualifier; j++)
2069 add_local_oid_text_to_control(text,
2070 policies->rgPolicyInfo[i].rgPolicyQualifier[j].
2071 pszPolicyQualifierId);
2073 LocalFree(policies);
2076 else
2077 add_oid_text_to_control(text, any_app_policy);
2080 static BOOL display_cert_usages(HWND text, PCCERT_CONTEXT cert,
2081 BOOL *anyUsageAdded)
2083 WCHAR nl = '\n';
2084 DWORD size;
2085 BOOL badUsages = FALSE;
2087 if (CertGetEnhancedKeyUsage(cert, 0, NULL, &size))
2089 CHARFORMATW charFmt;
2090 static char any_cert_policy[] = szOID_ANY_CERT_POLICY;
2091 CERT_ENHKEY_USAGE *usage = malloc(size);
2093 if (usage)
2095 if (CertGetEnhancedKeyUsage(cert, 0, usage, &size))
2097 DWORD i;
2099 if (!*anyUsageAdded)
2101 PARAFORMAT2 parFmt;
2103 parFmt.cbSize = sizeof(parFmt);
2104 parFmt.dwMask = PFM_STARTINDENT;
2105 parFmt.dxStartIndent = MY_INDENT;
2106 add_string_resource_with_paraformat_to_control(text,
2107 IDS_CERT_INFO_PURPOSES, &parFmt);
2108 add_unformatted_text_to_control(text, &nl, 1);
2109 *anyUsageAdded = TRUE;
2111 memset(&charFmt, 0, sizeof(charFmt));
2112 charFmt.cbSize = sizeof(charFmt);
2113 charFmt.dwMask = CFM_BOLD;
2114 charFmt.dwEffects = 0;
2115 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION,
2116 (LPARAM)&charFmt);
2117 if (!usage->cUsageIdentifier)
2118 add_oid_text_to_control(text, any_cert_policy);
2119 else
2120 for (i = 0; i < usage->cUsageIdentifier; i++)
2121 add_local_oid_text_to_control(text,
2122 usage->rgpszUsageIdentifier[i]);
2124 else
2125 badUsages = TRUE;
2126 free(usage);
2128 else
2129 badUsages = TRUE;
2131 else
2132 badUsages = TRUE;
2133 return badUsages;
2136 static void set_policy_text(HWND text,
2137 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
2139 BOOL includeCertUsages = FALSE, includeAppUsages = FALSE;
2140 BOOL badUsages = FALSE, anyUsageAdded = FALSE;
2142 if (pCertViewInfo->cPurposes)
2144 DWORD i;
2146 for (i = 0; i < pCertViewInfo->cPurposes; i++)
2148 if (!strcmp(pCertViewInfo->rgszPurposes[i], szOID_ANY_CERT_POLICY))
2149 includeCertUsages = TRUE;
2150 else if (!strcmp(pCertViewInfo->rgszPurposes[i],
2151 szOID_ANY_APPLICATION_POLICY))
2152 includeAppUsages = TRUE;
2153 else
2154 badUsages = TRUE;
2157 else
2158 includeAppUsages = includeCertUsages = TRUE;
2159 if (includeAppUsages)
2160 display_app_usages(text, pCertViewInfo->pCertContext, &anyUsageAdded);
2161 if (includeCertUsages)
2162 badUsages = display_cert_usages(text, pCertViewInfo->pCertContext,
2163 &anyUsageAdded);
2164 if (badUsages)
2166 PARAFORMAT2 parFmt;
2168 parFmt.cbSize = sizeof(parFmt);
2169 parFmt.dwMask = PFM_STARTINDENT;
2170 parFmt.dxStartIndent = MY_INDENT;
2171 add_string_resource_with_paraformat_to_control(text,
2172 IDS_CERT_INFO_BAD_PURPOSES, &parFmt);
2176 static CRYPT_OBJID_BLOB *find_policy_qualifier(CERT_POLICIES_INFO *policies,
2177 LPCSTR policyOid)
2179 CRYPT_OBJID_BLOB *ret = NULL;
2180 DWORD i;
2182 for (i = 0; !ret && i < policies->cPolicyInfo; i++)
2184 DWORD j;
2186 for (j = 0; !ret && j < policies->rgPolicyInfo[i].cPolicyQualifier; j++)
2187 if (!strcmp(policies->rgPolicyInfo[i].rgPolicyQualifier[j].
2188 pszPolicyQualifierId, policyOid))
2189 ret = &policies->rgPolicyInfo[i].rgPolicyQualifier[j].
2190 Qualifier;
2192 return ret;
2195 static WCHAR *get_cps_str_from_qualifier(const CRYPT_OBJID_BLOB *qualifier)
2197 LPWSTR qualifierStr = NULL;
2198 CERT_NAME_VALUE *qualifierValue;
2199 DWORD size;
2201 if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME_VALUE,
2202 qualifier->pbData, qualifier->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL,
2203 &qualifierValue, &size))
2205 size = CertRDNValueToStrW(qualifierValue->dwValueType,
2206 &qualifierValue->Value, NULL, 0);
2207 qualifierStr = malloc(size * sizeof(WCHAR));
2208 if (qualifierStr)
2209 CertRDNValueToStrW(qualifierValue->dwValueType,
2210 &qualifierValue->Value, qualifierStr, size);
2211 LocalFree(qualifierValue);
2213 return qualifierStr;
2216 static WCHAR *get_user_notice_from_qualifier(const CRYPT_OBJID_BLOB *qualifier)
2218 LPWSTR str = NULL;
2219 CERT_POLICY_QUALIFIER_USER_NOTICE *qualifierValue;
2220 DWORD size;
2222 if (CryptDecodeObjectEx(X509_ASN_ENCODING,
2223 X509_PKIX_POLICY_QUALIFIER_USERNOTICE,
2224 qualifier->pbData, qualifier->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL,
2225 &qualifierValue, &size))
2227 str = wcsdup(qualifierValue->pszDisplayText);
2228 LocalFree(qualifierValue);
2230 return str;
2233 struct IssuerStatement
2235 LPWSTR cps;
2236 LPWSTR userNotice;
2239 static void set_issuer_statement(HWND hwnd,
2240 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
2242 PCERT_EXTENSION policyExt;
2244 if (!(pCertViewInfo->dwFlags & CRYPTUI_DISABLE_ISSUERSTATEMENT) &&
2245 (policyExt = CertFindExtension(szOID_CERT_POLICIES,
2246 pCertViewInfo->pCertContext->pCertInfo->cExtension,
2247 pCertViewInfo->pCertContext->pCertInfo->rgExtension)))
2249 CERT_POLICIES_INFO *policies;
2250 DWORD size;
2252 if (CryptDecodeObjectEx(X509_ASN_ENCODING, policyExt->pszObjId,
2253 policyExt->Value.pbData, policyExt->Value.cbData,
2254 CRYPT_DECODE_ALLOC_FLAG, NULL, &policies, &size))
2256 CRYPT_OBJID_BLOB *qualifier;
2257 LPWSTR cps = NULL, userNotice = NULL;
2259 if ((qualifier = find_policy_qualifier(policies,
2260 szOID_PKIX_POLICY_QUALIFIER_CPS)))
2261 cps = get_cps_str_from_qualifier(qualifier);
2262 if ((qualifier = find_policy_qualifier(policies,
2263 szOID_PKIX_POLICY_QUALIFIER_USERNOTICE)))
2264 userNotice = get_user_notice_from_qualifier(qualifier);
2265 if (cps || userNotice)
2267 struct IssuerStatement *issuerStatement = malloc(sizeof(struct IssuerStatement));
2269 if (issuerStatement)
2271 issuerStatement->cps = cps;
2272 issuerStatement->userNotice = userNotice;
2273 EnableWindow(GetDlgItem(hwnd, IDC_ISSUERSTATEMENT), TRUE);
2274 SetWindowLongPtrW(hwnd, DWLP_USER,
2275 (ULONG_PTR)issuerStatement);
2278 LocalFree(policies);
2283 static void set_cert_info(HWND hwnd,
2284 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
2286 CHARFORMATW charFmt;
2287 PARAFORMAT2 parFmt;
2288 HWND icon = GetDlgItem(hwnd, IDC_CERTIFICATE_ICON);
2289 HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_INFO);
2290 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
2291 (CRYPT_PROVIDER_DATA *)pCertViewInfo->pCryptProviderData,
2292 pCertViewInfo->idxSigner, pCertViewInfo->fCounterSigner,
2293 pCertViewInfo->idxCounterSigner);
2294 CRYPT_PROVIDER_CERT *root =
2295 &provSigner->pasCertChain[provSigner->csCertChain - 1];
2297 if (!provSigner->pChainContext ||
2298 (provSigner->pChainContext->TrustStatus.dwErrorStatus &
2299 CERT_TRUST_IS_PARTIAL_CHAIN))
2300 add_icon_to_control(icon, IDB_CERT_WARNING);
2301 else if (!root->fTrustedRoot)
2302 add_icon_to_control(icon, IDB_CERT_ERROR);
2303 else
2304 add_icon_to_control(icon, IDB_CERT);
2306 memset(&charFmt, 0, sizeof(charFmt));
2307 charFmt.cbSize = sizeof(charFmt);
2308 charFmt.dwMask = CFM_BOLD;
2309 charFmt.dwEffects = CFE_BOLD;
2310 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2311 /* FIXME: vertically center text */
2312 parFmt.cbSize = sizeof(parFmt);
2313 parFmt.dwMask = PFM_STARTINDENT;
2314 parFmt.dxStartIndent = MY_INDENT;
2315 add_string_resource_with_paraformat_to_control(text,
2316 IDS_CERTIFICATEINFORMATION, &parFmt);
2318 text = GetDlgItem(hwnd, IDC_CERTIFICATE_STATUS);
2319 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2320 if (provSigner->dwError == TRUST_E_CERT_SIGNATURE)
2321 add_string_resource_with_paraformat_to_control(text,
2322 IDS_CERT_INFO_BAD_SIG, &parFmt);
2323 else if (!provSigner->pChainContext ||
2324 (provSigner->pChainContext->TrustStatus.dwErrorStatus &
2325 CERT_TRUST_IS_PARTIAL_CHAIN))
2326 add_string_resource_with_paraformat_to_control(text,
2327 IDS_CERT_INFO_PARTIAL_CHAIN, &parFmt);
2328 else if (!root->fTrustedRoot)
2330 if (provSigner->csCertChain == 1 && root->fSelfSigned)
2331 add_string_resource_with_paraformat_to_control(text,
2332 IDS_CERT_INFO_UNTRUSTED_CA, &parFmt);
2333 else
2334 add_string_resource_with_paraformat_to_control(text,
2335 IDS_CERT_INFO_UNTRUSTED_ROOT, &parFmt);
2337 else
2339 set_policy_text(text, pCertViewInfo);
2340 set_issuer_statement(hwnd, pCertViewInfo);
2344 static void set_cert_name_string(HWND hwnd, PCCERT_CONTEXT cert,
2345 DWORD nameFlags, int heading)
2347 WCHAR nl = '\n';
2348 HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_NAMES);
2349 CHARFORMATW charFmt;
2350 PARAFORMAT2 parFmt;
2352 memset(&charFmt, 0, sizeof(charFmt));
2353 charFmt.cbSize = sizeof(charFmt);
2354 charFmt.dwMask = CFM_BOLD;
2355 charFmt.dwEffects = CFE_BOLD;
2356 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2357 parFmt.cbSize = sizeof(parFmt);
2358 parFmt.dwMask = PFM_STARTINDENT;
2359 parFmt.dxStartIndent = MY_INDENT * 3;
2360 add_string_resource_with_paraformat_to_control(text, heading, &parFmt);
2361 charFmt.dwEffects = 0;
2362 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2363 add_cert_string_to_control(text, cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
2364 nameFlags);
2365 add_unformatted_text_to_control(text, &nl, 1);
2366 add_unformatted_text_to_control(text, &nl, 1);
2367 add_unformatted_text_to_control(text, &nl, 1);
2371 static void add_date_string_to_control(HWND hwnd, const FILETIME *fileTime)
2373 WCHAR dateFmt[80]; /* sufficient for all versions of LOCALE_SSHORTDATE */
2374 WCHAR date[80];
2375 SYSTEMTIME sysTime;
2377 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SSHORTDATE, dateFmt, ARRAY_SIZE(dateFmt));
2378 FileTimeToSystemTime(fileTime, &sysTime);
2379 GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, date, ARRAY_SIZE(date));
2380 add_unformatted_text_to_control(hwnd, date, lstrlenW(date));
2383 static void set_cert_validity_period(HWND hwnd, PCCERT_CONTEXT cert)
2385 WCHAR nl = '\n';
2386 HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_NAMES);
2387 CHARFORMATW charFmt;
2388 PARAFORMAT2 parFmt;
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, IDS_VALID_FROM,
2399 &parFmt);
2400 charFmt.dwEffects = 0;
2401 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2402 add_date_string_to_control(text, &cert->pCertInfo->NotBefore);
2403 charFmt.dwEffects = CFE_BOLD;
2404 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2405 add_string_resource_to_control(text, IDS_VALID_TO);
2406 charFmt.dwEffects = 0;
2407 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2408 add_date_string_to_control(text, &cert->pCertInfo->NotAfter);
2409 add_unformatted_text_to_control(text, &nl, 1);
2412 static void set_general_info(HWND hwnd,
2413 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
2415 set_cert_info(hwnd, pCertViewInfo);
2416 set_cert_name_string(hwnd, pCertViewInfo->pCertContext, 0,
2417 IDS_SUBJECT_HEADING);
2418 set_cert_name_string(hwnd, pCertViewInfo->pCertContext,
2419 CERT_NAME_ISSUER_FLAG, IDS_ISSUER_HEADING);
2420 set_cert_validity_period(hwnd, pCertViewInfo->pCertContext);
2423 static INT_PTR CALLBACK user_notice_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
2424 LPARAM lp)
2426 INT_PTR ret = 0;
2427 HWND text;
2428 struct IssuerStatement *issuerStatement;
2430 switch (msg)
2432 case WM_INITDIALOG:
2433 text = GetDlgItem(hwnd, IDC_USERNOTICE);
2434 issuerStatement = (struct IssuerStatement *)lp;
2435 add_unformatted_text_to_control(text, issuerStatement->userNotice,
2436 lstrlenW(issuerStatement->userNotice));
2437 if (issuerStatement->cps)
2438 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)issuerStatement->cps);
2439 else
2440 EnableWindow(GetDlgItem(hwnd, IDC_CPS), FALSE);
2441 break;
2442 case WM_COMMAND:
2443 switch (wp)
2445 case IDOK:
2446 EndDialog(hwnd, IDOK);
2447 ret = TRUE;
2448 break;
2449 case IDC_CPS:
2451 IBindCtx *bctx = NULL;
2452 LPWSTR cps;
2454 CreateBindCtx(0, &bctx);
2455 cps = (LPWSTR)GetWindowLongPtrW(hwnd, DWLP_USER);
2456 HlinkSimpleNavigateToString(cps, NULL, NULL, NULL, bctx, NULL,
2457 HLNF_OPENINNEWWINDOW, 0);
2458 IBindCtx_Release(bctx);
2459 break;
2463 return ret;
2466 static void show_user_notice(HWND hwnd, struct IssuerStatement *issuerStatement)
2468 DialogBoxParamW(hInstance, MAKEINTRESOURCEW(IDD_USERNOTICE), hwnd,
2469 user_notice_dlg_proc, (LPARAM)issuerStatement);
2472 static INT_PTR CALLBACK general_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
2473 LPARAM lp)
2475 PROPSHEETPAGEW *page;
2476 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo;
2478 TRACE("(%p, %08x, %08Ix, %08Ix)\n", hwnd, msg, wp, lp);
2480 switch (msg)
2482 case WM_INITDIALOG:
2483 page = (PROPSHEETPAGEW *)lp;
2484 pCertViewInfo = (PCCRYPTUI_VIEWCERTIFICATE_STRUCTW)page->lParam;
2485 if (pCertViewInfo->dwFlags & CRYPTUI_DISABLE_ADDTOSTORE)
2486 ShowWindow(GetDlgItem(hwnd, IDC_ADDTOSTORE), FALSE);
2487 EnableWindow(GetDlgItem(hwnd, IDC_ISSUERSTATEMENT), FALSE);
2488 set_general_info(hwnd, pCertViewInfo);
2489 break;
2490 case WM_COMMAND:
2491 switch (wp)
2493 case IDC_ADDTOSTORE:
2494 CryptUIWizImport(0, hwnd, NULL, NULL, NULL);
2495 break;
2496 case IDC_ISSUERSTATEMENT:
2498 struct IssuerStatement *issuerStatement =
2499 (struct IssuerStatement *)GetWindowLongPtrW(hwnd, DWLP_USER);
2501 if (issuerStatement)
2503 if (issuerStatement->userNotice)
2504 show_user_notice(hwnd, issuerStatement);
2505 else if (issuerStatement->cps)
2507 IBindCtx *bctx = NULL;
2509 CreateBindCtx(0, &bctx);
2510 HlinkSimpleNavigateToString(issuerStatement->cps, NULL,
2511 NULL, NULL, bctx, NULL, HLNF_OPENINNEWWINDOW, 0);
2512 IBindCtx_Release(bctx);
2515 break;
2518 break;
2520 return 0;
2523 static UINT CALLBACK general_callback_proc(HWND hwnd, UINT msg,
2524 PROPSHEETPAGEW *page)
2526 struct IssuerStatement *issuerStatement;
2528 switch (msg)
2530 case PSPCB_RELEASE:
2531 issuerStatement =
2532 (struct IssuerStatement *)GetWindowLongPtrW(hwnd, DWLP_USER);
2533 if (issuerStatement)
2535 free(issuerStatement->cps);
2536 free(issuerStatement->userNotice);
2537 free(issuerStatement);
2539 break;
2541 return 1;
2544 static void init_general_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
2545 PROPSHEETPAGEW *page)
2547 memset(page, 0, sizeof(PROPSHEETPAGEW));
2548 page->dwSize = sizeof(PROPSHEETPAGEW);
2549 page->dwFlags = PSP_USECALLBACK;
2550 page->pfnCallback = general_callback_proc;
2551 page->hInstance = hInstance;
2552 page->pszTemplate = MAKEINTRESOURCEW(IDD_GENERAL);
2553 page->pfnDlgProc = general_dlg_proc;
2554 page->lParam = (LPARAM)pCertViewInfo;
2557 typedef WCHAR * (*field_format_func)(PCCERT_CONTEXT cert);
2559 static WCHAR *field_format_version(PCCERT_CONTEXT cert)
2561 static const WCHAR fmt[] = { 'V','%','d',0 };
2562 WCHAR *buf = malloc(12 * sizeof(WCHAR));
2564 if (buf)
2565 swprintf(buf, 12, fmt, cert->pCertInfo->dwVersion);
2566 return buf;
2569 static WCHAR *format_hex_string(void *pb, DWORD cb)
2571 WCHAR *buf = malloc((cb * 3 + 1) * sizeof(WCHAR));
2573 if (buf)
2575 static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
2576 DWORD i;
2577 WCHAR *ptr;
2579 for (i = 0, ptr = buf; i < cb; i++, ptr += 3)
2580 swprintf(ptr, 4, fmt, ((BYTE *)pb)[i]);
2582 return buf;
2585 static WCHAR *field_format_serial_number(PCCERT_CONTEXT cert)
2587 return format_hex_string(cert->pCertInfo->SerialNumber.pbData,
2588 cert->pCertInfo->SerialNumber.cbData);
2591 static WCHAR *field_format_issuer(PCCERT_CONTEXT cert)
2593 return get_cert_name_string(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
2594 CERT_NAME_ISSUER_FLAG);
2597 static WCHAR *field_format_detailed_cert_name(PCERT_NAME_BLOB name)
2599 WCHAR *str = NULL;
2600 DWORD len = CertNameToStrW(X509_ASN_ENCODING, name,
2601 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG | CERT_NAME_STR_NO_QUOTING_FLAG, NULL, 0);
2603 if (len)
2605 str = malloc(len * sizeof(WCHAR));
2606 if (str)
2607 CertNameToStrW(X509_ASN_ENCODING, name,
2608 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG | CERT_NAME_STR_NO_QUOTING_FLAG, str, len);
2610 return str;
2613 static WCHAR *field_format_detailed_issuer(PCCERT_CONTEXT cert, void *param)
2615 return field_format_detailed_cert_name(&cert->pCertInfo->Issuer);
2618 static WCHAR *field_format_subject(PCCERT_CONTEXT cert)
2620 return get_cert_name_string(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0);
2623 static WCHAR *field_format_detailed_subject(PCCERT_CONTEXT cert, void *param)
2625 return field_format_detailed_cert_name(&cert->pCertInfo->Subject);
2628 static WCHAR *format_long_date(const FILETIME *fileTime)
2630 WCHAR dateFmt[80]; /* long enough for LOCALE_SLONGDATE */
2631 DWORD len;
2632 WCHAR *buf = NULL;
2633 SYSTEMTIME sysTime;
2635 /* FIXME: format isn't quite right, want time too */
2636 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SLONGDATE, dateFmt, ARRAY_SIZE(dateFmt));
2637 FileTimeToSystemTime(fileTime, &sysTime);
2638 len = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, NULL, 0);
2639 if (len)
2641 buf = malloc(len * sizeof(WCHAR));
2642 if (buf)
2643 GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, buf,
2644 len);
2646 return buf;
2649 static WCHAR *field_format_from_date(PCCERT_CONTEXT cert)
2651 return format_long_date(&cert->pCertInfo->NotBefore);
2654 static WCHAR *field_format_to_date(PCCERT_CONTEXT cert)
2656 return format_long_date(&cert->pCertInfo->NotAfter);
2659 static WCHAR *field_format_public_key(PCCERT_CONTEXT cert)
2661 PCCRYPT_OID_INFO oidInfo;
2662 WCHAR *buf = NULL;
2664 oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2665 cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, 0);
2666 if (oidInfo)
2668 WCHAR fmt[MAX_STRING_LEN];
2670 if (LoadStringW(hInstance, IDS_FIELD_PUBLIC_KEY_FORMAT, fmt, ARRAY_SIZE(fmt)))
2672 DWORD len;
2674 /* Allocate the output buffer. Use the number of bytes in the
2675 * public key as a conservative (high) estimate for the number of
2676 * digits in its output.
2677 * The output is of the form (in English)
2678 * "<public key algorithm> (<public key bit length> bits)".
2679 * Ordinarily having two positional parameters in a string is not a
2680 * good idea, but as this isn't a sentence fragment, it shouldn't
2681 * be word-order dependent.
2683 len = lstrlenW(fmt) + lstrlenW(oidInfo->pwszName) +
2684 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData * 8;
2685 buf = malloc(len * sizeof(*buf));
2686 if (buf)
2688 DWORD_PTR args[2];
2689 args[0] = (DWORD_PTR)oidInfo->pwszName;
2690 args[1] = CertGetPublicKeyLength(X509_ASN_ENCODING,
2691 &cert->pCertInfo->SubjectPublicKeyInfo);
2692 FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
2693 fmt, 0, 0, buf, len, (va_list *)args);
2697 return buf;
2700 static WCHAR *field_format_detailed_public_key(PCCERT_CONTEXT cert, void *param)
2702 return format_hex_string(
2703 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
2704 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData);
2707 struct field_value_data;
2708 struct detail_data
2710 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo;
2711 BOOL *pfPropertiesChanged;
2712 int cFields;
2713 struct field_value_data *fields;
2716 typedef void (*add_fields_func)(HWND hwnd, struct detail_data *data);
2718 typedef WCHAR *(*create_detailed_value_func)(PCCERT_CONTEXT cert, void *param);
2720 struct field_value_data
2722 create_detailed_value_func create;
2723 LPWSTR detailed_value;
2724 void *param;
2727 static void add_field_value_data(struct detail_data *data,
2728 create_detailed_value_func create, void *param)
2730 data->fields = realloc(data->fields, (data->cFields + 1) * sizeof(struct field_value_data));
2731 if (data->fields)
2733 data->fields[data->cFields].create = create;
2734 data->fields[data->cFields].detailed_value = NULL;
2735 data->fields[data->cFields].param = param;
2736 data->cFields++;
2740 static void add_field_and_value_to_list(HWND hwnd, struct detail_data *data,
2741 LPWSTR field, LPWSTR value, create_detailed_value_func create, void *param)
2743 LVITEMW item;
2744 int iItem = SendMessageW(hwnd, LVM_GETITEMCOUNT, 0, 0);
2746 item.mask = LVIF_TEXT | LVIF_PARAM;
2747 item.iItem = iItem;
2748 item.iSubItem = 0;
2749 item.pszText = field;
2750 item.lParam = (LPARAM)data;
2751 SendMessageW(hwnd, LVM_INSERTITEMW, 0, (LPARAM)&item);
2752 if (value)
2754 item.pszText = value;
2755 item.iSubItem = 1;
2756 SendMessageW(hwnd, LVM_SETITEMTEXTW, iItem, (LPARAM)&item);
2758 add_field_value_data(data, create, param);
2761 static void add_string_id_and_value_to_list(HWND hwnd, struct detail_data *data,
2762 int id, LPWSTR value, create_detailed_value_func create, void *param)
2764 WCHAR buf[MAX_STRING_LEN];
2766 LoadStringW(hInstance, id, buf, ARRAY_SIZE(buf));
2767 add_field_and_value_to_list(hwnd, data, buf, value, create, param);
2770 struct v1_field
2772 int id;
2773 field_format_func format;
2774 create_detailed_value_func create_detailed_value;
2777 static void add_v1_field(HWND hwnd, struct detail_data *data,
2778 const struct v1_field *field)
2780 WCHAR *val = field->format(data->pCertViewInfo->pCertContext);
2782 if (val)
2784 add_string_id_and_value_to_list(hwnd, data, field->id, val,
2785 field->create_detailed_value, NULL);
2786 free(val);
2790 static const struct v1_field v1_fields[] = {
2791 { IDS_FIELD_VERSION, field_format_version, NULL },
2792 { IDS_FIELD_SERIAL_NUMBER, field_format_serial_number, NULL },
2793 { IDS_FIELD_ISSUER, field_format_issuer, field_format_detailed_issuer },
2794 { IDS_FIELD_VALID_FROM, field_format_from_date, NULL },
2795 { IDS_FIELD_VALID_TO, field_format_to_date, NULL },
2796 { IDS_FIELD_SUBJECT, field_format_subject, field_format_detailed_subject },
2797 { IDS_FIELD_PUBLIC_KEY, field_format_public_key,
2798 field_format_detailed_public_key }
2801 static void add_v1_fields(HWND hwnd, struct detail_data *data)
2803 unsigned int i;
2804 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
2806 /* The last item in v1_fields is the public key, which is not in the loop
2807 * because it's a special case.
2809 for (i = 0; i < ARRAY_SIZE(v1_fields) - 1; i++)
2810 add_v1_field(hwnd, data, &v1_fields[i]);
2811 if (cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData)
2812 add_v1_field(hwnd, data, &v1_fields[i]);
2815 static WCHAR *crypt_format_extension(const CERT_EXTENSION *ext, DWORD formatStrType)
2817 WCHAR *str = NULL;
2818 DWORD size;
2820 if (CryptFormatObject(X509_ASN_ENCODING, 0, formatStrType, NULL,
2821 ext->pszObjId, ext->Value.pbData, ext->Value.cbData, NULL, &size))
2823 str = malloc(size);
2824 CryptFormatObject(X509_ASN_ENCODING, 0, formatStrType, NULL,
2825 ext->pszObjId, ext->Value.pbData, ext->Value.cbData, str, &size);
2827 return str;
2830 static WCHAR *field_format_extension_hex_with_ascii(const CERT_EXTENSION *ext)
2832 WCHAR *str = NULL;
2834 if (ext->Value.cbData)
2836 /* The output is formatted as:
2837 * <hex bytes> <ascii bytes>\n
2838 * where <hex bytes> is a string of up to 8 bytes, output as %02x,
2839 * and <ascii bytes> is the ASCII equivalent of each byte, or '.' if
2840 * the byte is not printable.
2841 * So, for example, the extension value consisting of the following
2842 * bytes:
2843 * 0x30,0x14,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x03,
2844 * 0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67
2845 * is output as:
2846 * 30 14 31 12 30 10 06 03 0.1.0...
2847 * 55 04 03 13 09 4a 75 61 U....Jua
2848 * 6e 20 4c 61 6e 67 n Lang
2849 * The allocation size therefore requires:
2850 * - 4 characters per character in an 8-byte line
2851 * (2 for the hex format, one for the space, one for the ASCII value)
2852 * - 3 more characters per 8-byte line (two spaces and a newline)
2853 * - 1 character for the terminating nul
2854 * FIXME: should use a fixed-width font for this
2856 DWORD lines = (ext->Value.cbData + 7) / 8;
2858 str = malloc((lines * 8 * 4 + lines * 3 + 1) * sizeof(WCHAR));
2859 if (str)
2861 static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
2862 DWORD i, j;
2863 WCHAR *ptr;
2865 for (i = 0, ptr = str; i < ext->Value.cbData; i += 8)
2867 /* Output as hex bytes first */
2868 for (j = i; j < min(i + 8, ext->Value.cbData); j++, ptr += 3)
2869 swprintf(ptr, 4, fmt, ext->Value.pbData[j]);
2870 /* Pad the hex output with spaces for alignment */
2871 if (j == ext->Value.cbData && j % 8)
2873 static const WCHAR pad[] = { ' ',' ',' ' };
2875 for (; j % 8; j++, ptr += ARRAY_SIZE(pad))
2876 memcpy(ptr, pad, sizeof(pad));
2878 /* The last swprintf included a space, so just insert one
2879 * more space between the hex bytes and the ASCII output
2881 *ptr++ = ' ';
2882 /* Output as ASCII bytes */
2883 for (j = i; j < min(i + 8, ext->Value.cbData); j++, ptr++)
2885 if (iswprint(ext->Value.pbData[j]) &&
2886 !iswspace(ext->Value.pbData[j]))
2887 *ptr = ext->Value.pbData[j];
2888 else
2889 *ptr = '.';
2891 *ptr++ = '\n';
2893 *ptr++ = '\0';
2896 return str;
2899 static WCHAR *field_format_detailed_extension(PCCERT_CONTEXT cert, void *param)
2901 PCERT_EXTENSION ext = param;
2902 LPWSTR str = crypt_format_extension(ext,
2903 CRYPT_FORMAT_STR_MULTI_LINE | CRYPT_FORMAT_STR_NO_HEX);
2905 if (!str)
2906 str = field_format_extension_hex_with_ascii(ext);
2907 return str;
2910 static void add_cert_extension_detail(HWND hwnd, struct detail_data *data,
2911 PCERT_EXTENSION ext)
2913 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2914 ext->pszObjId, 0);
2915 LPWSTR val = crypt_format_extension(ext, 0);
2917 if (oidInfo)
2918 add_field_and_value_to_list(hwnd, data, (LPWSTR)oidInfo->pwszName,
2919 val, field_format_detailed_extension, ext);
2920 else
2922 DWORD len = strlen(ext->pszObjId);
2923 WCHAR *oidW = malloc((len + 1) * sizeof(WCHAR));
2925 if (oidW)
2927 DWORD i;
2929 for (i = 0; i <= len; i++)
2930 oidW[i] = ext->pszObjId[i];
2931 add_field_and_value_to_list(hwnd, data, oidW, val,
2932 field_format_detailed_extension, ext);
2933 free(oidW);
2936 free(val);
2939 static void add_all_extensions(HWND hwnd, struct detail_data *data)
2941 DWORD i;
2942 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
2944 for (i = 0; i < cert->pCertInfo->cExtension; i++)
2945 add_cert_extension_detail(hwnd, data, &cert->pCertInfo->rgExtension[i]);
2948 static void add_critical_extensions(HWND hwnd, struct detail_data *data)
2950 DWORD i;
2951 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
2953 for (i = 0; i < cert->pCertInfo->cExtension; i++)
2954 if (cert->pCertInfo->rgExtension[i].fCritical)
2955 add_cert_extension_detail(hwnd, data,
2956 &cert->pCertInfo->rgExtension[i]);
2959 typedef WCHAR * (*prop_to_value_func)(void *pb, DWORD cb);
2961 struct prop_id_to_string_id
2963 DWORD prop;
2964 int id;
2965 BOOL prop_is_string;
2966 prop_to_value_func prop_to_value;
2969 static WCHAR *format_enhanced_key_usage_value(void *pb, DWORD cb)
2971 CERT_EXTENSION ext;
2973 ext.pszObjId = (LPSTR)X509_ENHANCED_KEY_USAGE;
2974 ext.fCritical = FALSE;
2975 ext.Value.pbData = pb;
2976 ext.Value.cbData = cb;
2977 return crypt_format_extension(&ext, 0);
2980 /* Logically the access state should also be checked, and IDC_EDITPROPERTIES
2981 * disabled for read-only certificates, but native doesn't appear to do that.
2983 static const struct prop_id_to_string_id prop_id_map[] = {
2984 { CERT_HASH_PROP_ID, IDS_PROP_HASH, FALSE, format_hex_string },
2985 { CERT_FRIENDLY_NAME_PROP_ID, IDS_PROP_FRIENDLY_NAME, TRUE, NULL },
2986 { CERT_DESCRIPTION_PROP_ID, IDS_PROP_DESCRIPTION, TRUE, NULL },
2987 { CERT_ENHKEY_USAGE_PROP_ID, IDS_PROP_ENHKEY_USAGE, FALSE,
2988 format_enhanced_key_usage_value },
2991 static void add_properties(HWND hwnd, struct detail_data *data)
2993 DWORD i;
2994 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
2996 for (i = 0; i < ARRAY_SIZE(prop_id_map); i++)
2998 DWORD cb;
3000 if (CertGetCertificateContextProperty(cert, prop_id_map[i].prop, NULL,
3001 &cb))
3003 BYTE *pb;
3004 WCHAR *val = NULL;
3006 /* FIXME: MS adds a separate value for the signature hash
3007 * algorithm.
3009 pb = malloc(cb);
3010 if (pb)
3012 if (CertGetCertificateContextProperty(cert,
3013 prop_id_map[i].prop, pb, &cb))
3015 if (prop_id_map[i].prop_is_string)
3017 val = (LPWSTR)pb;
3018 /* Don't double-free pb */
3019 pb = NULL;
3021 else
3022 val = prop_id_map[i].prop_to_value(pb, cb);
3024 free(pb);
3026 add_string_id_and_value_to_list(hwnd, data, prop_id_map[i].id, val,
3027 NULL, NULL);
3032 static void add_all_fields(HWND hwnd, struct detail_data *data)
3034 add_v1_fields(hwnd, data);
3035 add_all_extensions(hwnd, data);
3036 add_properties(hwnd, data);
3039 struct selection_list_item
3041 int id;
3042 add_fields_func add;
3045 static const struct selection_list_item listItems[] = {
3046 { IDS_FIELDS_ALL, add_all_fields },
3047 { IDS_FIELDS_V1, add_v1_fields },
3048 { IDS_FIELDS_EXTENSIONS, add_all_extensions },
3049 { IDS_FIELDS_CRITICAL_EXTENSIONS, add_critical_extensions },
3050 { IDS_FIELDS_PROPERTIES, add_properties },
3053 static void create_show_list(HWND hwnd, struct detail_data *data)
3055 HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT);
3056 WCHAR buf[MAX_STRING_LEN];
3057 int i;
3059 for (i = 0; i < ARRAY_SIZE(listItems); i++)
3061 int index;
3063 LoadStringW(hInstance, listItems[i].id, buf, ARRAY_SIZE(buf));
3064 index = SendMessageW(cb, CB_INSERTSTRING, -1, (LPARAM)buf);
3065 SendMessageW(cb, CB_SETITEMDATA, index, (LPARAM)data);
3067 SendMessageW(cb, CB_SETCURSEL, 0, 0);
3070 static void create_listview_columns(HWND hwnd)
3072 HWND lv = GetDlgItem(hwnd, IDC_DETAIL_LIST);
3073 RECT rc;
3074 WCHAR buf[MAX_STRING_LEN];
3075 LVCOLUMNW column;
3077 SendMessageW(lv, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
3078 GetWindowRect(lv, &rc);
3079 LoadStringW(hInstance, IDS_FIELD, buf, ARRAY_SIZE(buf));
3080 column.mask = LVCF_WIDTH | LVCF_TEXT;
3081 column.cx = (rc.right - rc.left) / 2 - 2;
3082 column.pszText = buf;
3083 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
3084 LoadStringW(hInstance, IDS_VALUE, buf, ARRAY_SIZE(buf));
3085 SendMessageW(lv, LVM_INSERTCOLUMNW, 1, (LPARAM)&column);
3088 static void set_fields_selection(HWND hwnd, struct detail_data *data, int sel)
3090 HWND list = GetDlgItem(hwnd, IDC_DETAIL_LIST);
3092 if (sel >= 0 && sel < ARRAY_SIZE(listItems))
3094 SendMessageW(list, LVM_DELETEALLITEMS, 0, 0);
3095 listItems[sel].add(list, data);
3099 static void create_cert_details_list(HWND hwnd, struct detail_data *data)
3101 create_show_list(hwnd, data);
3102 create_listview_columns(hwnd);
3103 set_fields_selection(hwnd, data, 0);
3106 static void add_purpose(HWND hwnd, LPCSTR oid)
3108 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
3109 CRYPT_OID_INFO *info = calloc(1, sizeof(CRYPT_OID_INFO));
3111 if (info)
3113 char *oidCopy = strdup(oid);
3115 if (oidCopy)
3117 LVITEMA item;
3119 info->cbSize = sizeof(CRYPT_OID_INFO);
3120 info->pszOID = oidCopy;
3121 item.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM;
3122 item.state = INDEXTOSTATEIMAGEMASK(CheckBitmapIndexChecked);
3123 item.stateMask = LVIS_STATEIMAGEMASK;
3124 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
3125 item.iSubItem = 0;
3126 item.lParam = (LPARAM)info;
3127 item.pszText = oidCopy;
3128 SendMessageA(lv, LVM_INSERTITEMA, 0, (LPARAM)&item);
3130 else
3131 free(info);
3135 static BOOL is_valid_oid(LPCSTR oid)
3137 BOOL ret;
3139 if (oid[0] != '0' && oid[0] != '1' && oid[0] != '2')
3140 ret = FALSE;
3141 else if (oid[1] != '.')
3142 ret = FALSE;
3143 else if (!oid[2])
3144 ret = FALSE;
3145 else
3147 const char *ptr;
3148 BOOL expectNum = TRUE;
3150 for (ptr = oid + 2, ret = TRUE; ret && *ptr; ptr++)
3152 if (expectNum)
3154 if (!isdigit(*ptr))
3155 ret = FALSE;
3156 else if (*(ptr + 1) == '.')
3157 expectNum = FALSE;
3159 else
3161 if (*ptr != '.')
3162 ret = FALSE;
3163 else if (!(*(ptr + 1)))
3164 ret = FALSE;
3165 else
3166 expectNum = TRUE;
3170 return ret;
3173 static BOOL is_oid_in_list(HWND hwnd, LPCSTR oid)
3175 return find_oid_in_list(GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES), oid)
3176 != -1;
3179 #define MAX_PURPOSE 255
3181 static INT_PTR CALLBACK add_purpose_dlg_proc(HWND hwnd, UINT msg,
3182 WPARAM wp, LPARAM lp)
3184 INT_PTR ret = 0;
3185 char buf[MAX_PURPOSE + 1];
3187 switch (msg)
3189 case WM_INITDIALOG:
3190 SendMessageW(GetDlgItem(hwnd, IDC_NEW_PURPOSE), EM_SETLIMITTEXT,
3191 MAX_PURPOSE, 0);
3192 ShowScrollBar(GetDlgItem(hwnd, IDC_NEW_PURPOSE), SB_VERT, FALSE);
3193 SetWindowLongPtrW(hwnd, DWLP_USER, lp);
3194 break;
3195 case WM_COMMAND:
3196 switch (HIWORD(wp))
3198 case EN_CHANGE:
3199 if (LOWORD(wp) == IDC_NEW_PURPOSE)
3201 /* Show/hide scroll bar on description depending on how much
3202 * text it has.
3204 HWND description = GetDlgItem(hwnd, IDC_NEW_PURPOSE);
3205 int lines = SendMessageW(description, EM_GETLINECOUNT, 0, 0);
3207 ShowScrollBar(description, SB_VERT, lines > 1);
3209 break;
3210 case BN_CLICKED:
3211 switch (LOWORD(wp))
3213 case IDOK:
3214 SendMessageA(GetDlgItem(hwnd, IDC_NEW_PURPOSE), WM_GETTEXT, ARRAY_SIZE(buf),
3215 (LPARAM)buf);
3216 if (!buf[0])
3218 /* An empty purpose is the same as cancelling */
3219 EndDialog(hwnd, IDCANCEL);
3220 ret = TRUE;
3222 else if (!is_valid_oid(buf))
3224 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
3226 LoadStringW(hInstance, IDS_CERTIFICATE_PURPOSE_ERROR, error, ARRAY_SIZE(error));
3227 LoadStringW(hInstance, IDS_CERTIFICATE_PROPERTIES, title, ARRAY_SIZE(title));
3228 MessageBoxW(hwnd, error, title, MB_ICONERROR | MB_OK);
3230 else if (is_oid_in_list(
3231 (HWND)GetWindowLongPtrW(hwnd, DWLP_USER), buf))
3233 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
3235 LoadStringW(hInstance, IDS_CERTIFICATE_PURPOSE_EXISTS, error,
3236 ARRAY_SIZE(error));
3237 LoadStringW(hInstance, IDS_CERTIFICATE_PROPERTIES, title, ARRAY_SIZE(title));
3238 MessageBoxW(hwnd, error, title, MB_ICONEXCLAMATION | MB_OK);
3240 else
3242 HWND parent = (HWND)GetWindowLongPtrW(hwnd, DWLP_USER);
3244 add_purpose(parent, buf);
3245 EndDialog(hwnd, wp);
3246 ret = TRUE;
3248 break;
3249 case IDCANCEL:
3250 EndDialog(hwnd, wp);
3251 ret = TRUE;
3252 break;
3254 break;
3256 break;
3258 return ret;
3261 static WCHAR *get_cert_property_as_string(PCCERT_CONTEXT cert, DWORD prop)
3263 WCHAR *name = NULL;
3264 DWORD cb;
3266 if (CertGetCertificateContextProperty(cert, prop, NULL, &cb))
3268 name = malloc(cb);
3269 if (name)
3271 if (!CertGetCertificateContextProperty(cert, prop, name, &cb))
3273 free(name);
3274 name = NULL;
3278 return name;
3281 static void redraw_states(HWND list, BOOL enabled)
3283 int items = SendMessageW(list, LVM_GETITEMCOUNT, 0, 0), i;
3285 for (i = 0; i < items; i++)
3287 BOOL change = FALSE;
3288 int state;
3290 state = SendMessageW(list, LVM_GETITEMSTATE, i, LVIS_STATEIMAGEMASK);
3291 /* This reverses the INDEXTOSTATEIMAGEMASK shift. There doesn't appear
3292 * to be a handy macro for it.
3294 state >>= 12;
3295 if (enabled)
3297 if (state == CheckBitmapIndexDisabledChecked)
3299 state = CheckBitmapIndexChecked;
3300 change = TRUE;
3302 if (state == CheckBitmapIndexDisabledUnchecked)
3304 state = CheckBitmapIndexUnchecked;
3305 change = TRUE;
3308 else
3310 if (state == CheckBitmapIndexChecked)
3312 state = CheckBitmapIndexDisabledChecked;
3313 change = TRUE;
3315 if (state == CheckBitmapIndexUnchecked)
3317 state = CheckBitmapIndexDisabledUnchecked;
3318 change = TRUE;
3321 if (change)
3323 LVITEMW item;
3325 item.state = INDEXTOSTATEIMAGEMASK(state);
3326 item.stateMask = LVIS_STATEIMAGEMASK;
3327 SendMessageW(list, LVM_SETITEMSTATE, i, (LPARAM)&item);
3332 typedef enum {
3333 PurposeEnableAll = 0,
3334 PurposeDisableAll,
3335 PurposeEnableSelected
3336 } PurposeSelection;
3338 static void select_purposes(HWND hwnd, PurposeSelection selection)
3340 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
3342 switch (selection)
3344 case PurposeEnableAll:
3345 case PurposeDisableAll:
3346 EnableWindow(lv, FALSE);
3347 redraw_states(lv, FALSE);
3348 EnableWindow(GetDlgItem(hwnd, IDC_ADD_PURPOSE), FALSE);
3349 break;
3350 case PurposeEnableSelected:
3351 EnableWindow(lv, TRUE);
3352 redraw_states(lv, TRUE);
3353 EnableWindow(GetDlgItem(hwnd, IDC_ADD_PURPOSE), TRUE);
3357 struct edit_cert_data
3359 PCCERT_CONTEXT cert;
3360 BOOL *pfPropertiesChanged;
3361 HIMAGELIST imageList;
3364 static void show_cert_usages(HWND hwnd, struct edit_cert_data *data)
3366 PCCERT_CONTEXT cert = data->cert;
3367 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
3368 PCERT_ENHKEY_USAGE usage;
3369 DWORD size;
3370 RECT rc;
3371 LVCOLUMNW column;
3372 PurposeSelection purposeSelection = PurposeEnableAll;
3374 GetWindowRect(lv, &rc);
3375 column.mask = LVCF_WIDTH;
3376 column.cx = rc.right - rc.left;
3377 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
3378 SendMessageW(lv, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)data->imageList);
3380 /* Get enhanced key usage. Have to check for a property and an extension
3381 * separately, because CertGetEnhancedKeyUsage will succeed and return an
3382 * empty usage if neither is set. Unfortunately an empty usage implies
3383 * no usage is allowed, so we have to distinguish between the two cases.
3385 if (CertGetEnhancedKeyUsage(cert, CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG,
3386 NULL, &size))
3388 usage = malloc(size);
3389 if (!CertGetEnhancedKeyUsage(cert,
3390 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size))
3392 free(usage);
3393 usage = NULL;
3395 else if (usage->cUsageIdentifier)
3396 purposeSelection = PurposeEnableSelected;
3397 else
3398 purposeSelection = PurposeDisableAll;
3400 else if (CertGetEnhancedKeyUsage(cert, CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
3401 NULL, &size))
3403 usage = malloc(size);
3404 if (!CertGetEnhancedKeyUsage(cert,
3405 CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, usage, &size))
3407 free(usage);
3408 usage = NULL;
3410 else if (usage->cUsageIdentifier)
3411 purposeSelection = PurposeEnableAll;
3412 else
3413 purposeSelection = PurposeDisableAll;
3415 else
3417 purposeSelection = PurposeEnableAll;
3418 usage = NULL;
3420 if (usage)
3422 DWORD i;
3424 for (i = 0; i < usage->cUsageIdentifier; i++)
3426 PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
3427 usage->rgpszUsageIdentifier[i], CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
3429 if (info)
3430 add_known_usage(lv, info, CheckBitmapIndexDisabledChecked);
3431 else
3432 add_purpose(hwnd, usage->rgpszUsageIdentifier[i]);
3434 free(usage);
3436 else
3437 add_known_usages_to_list(lv, CheckBitmapIndexDisabledChecked);
3438 select_purposes(hwnd, purposeSelection);
3439 SendMessageW(GetDlgItem(hwnd, IDC_ENABLE_ALL_PURPOSES + purposeSelection),
3440 BM_CLICK, 0, 0);
3443 static void set_general_cert_properties(HWND hwnd, struct edit_cert_data *data)
3445 PCCERT_CONTEXT cert = data->cert;
3446 WCHAR *str;
3448 if ((str = get_cert_property_as_string(cert, CERT_FRIENDLY_NAME_PROP_ID)))
3450 SendMessageW(GetDlgItem(hwnd, IDC_FRIENDLY_NAME), WM_SETTEXT, 0,
3451 (LPARAM)str);
3452 free(str);
3454 if ((str = get_cert_property_as_string(cert, CERT_DESCRIPTION_PROP_ID)))
3456 SendMessageW(GetDlgItem(hwnd, IDC_DESCRIPTION), WM_SETTEXT, 0,
3457 (LPARAM)str);
3458 free(str);
3460 show_cert_usages(hwnd, data);
3463 static void set_cert_string_property(PCCERT_CONTEXT cert, DWORD prop,
3464 LPWSTR str)
3466 if (str && *str)
3468 CRYPT_DATA_BLOB blob;
3470 blob.pbData = (BYTE *)str;
3471 blob.cbData = (lstrlenW(str) + 1) * sizeof(WCHAR);
3472 CertSetCertificateContextProperty(cert, prop, 0, &blob);
3474 else
3475 CertSetCertificateContextProperty(cert, prop, 0, NULL);
3478 #define WM_REFRESH_VIEW WM_USER + 0
3480 static BOOL CALLBACK refresh_propsheet_pages(HWND hwnd, LPARAM lParam)
3482 if ((GetClassLongW(hwnd, GCW_ATOM) == WC_DIALOG))
3483 SendMessageW(hwnd, WM_REFRESH_VIEW, 0, 0);
3484 return TRUE;
3487 #define MAX_FRIENDLY_NAME 40
3488 #define MAX_DESCRIPTION 255
3490 static void apply_general_changes(HWND hwnd)
3492 WCHAR buf[MAX_DESCRIPTION + 1];
3493 struct edit_cert_data *data =
3494 (struct edit_cert_data *)GetWindowLongPtrW(hwnd, DWLP_USER);
3496 SendMessageW(GetDlgItem(hwnd, IDC_FRIENDLY_NAME), WM_GETTEXT, ARRAY_SIZE(buf), (LPARAM)buf);
3497 set_cert_string_property(data->cert, CERT_FRIENDLY_NAME_PROP_ID, buf);
3498 SendMessageW(GetDlgItem(hwnd, IDC_DESCRIPTION), WM_GETTEXT, ARRAY_SIZE(buf), (LPARAM)buf);
3499 set_cert_string_property(data->cert, CERT_DESCRIPTION_PROP_ID, buf);
3500 if (IsDlgButtonChecked(hwnd, IDC_ENABLE_ALL_PURPOSES))
3502 /* Setting a NULL usage removes the enhanced key usage property. */
3503 CertSetEnhancedKeyUsage(data->cert, NULL);
3505 else if (IsDlgButtonChecked(hwnd, IDC_DISABLE_ALL_PURPOSES))
3507 CERT_ENHKEY_USAGE usage = { 0, NULL };
3509 CertSetEnhancedKeyUsage(data->cert, &usage);
3511 else if (IsDlgButtonChecked(hwnd, IDC_ENABLE_SELECTED_PURPOSES))
3513 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
3514 CERT_ENHKEY_USAGE usage = { 0, NULL };
3515 int purposes = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0), i;
3516 LVITEMW item;
3518 item.mask = LVIF_STATE | LVIF_PARAM;
3519 item.iSubItem = 0;
3520 item.stateMask = LVIS_STATEIMAGEMASK;
3521 for (i = 0; i < purposes; i++)
3523 item.iItem = i;
3524 if (SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item))
3526 int state = item.state >> 12;
3528 if (state == CheckBitmapIndexChecked)
3530 CRYPT_OID_INFO *info = (CRYPT_OID_INFO *)item.lParam;
3532 usage.rgpszUsageIdentifier = realloc(usage.rgpszUsageIdentifier,
3533 (usage.cUsageIdentifier + 1) * sizeof(char *));
3534 if (usage.rgpszUsageIdentifier)
3535 usage.rgpszUsageIdentifier[usage.cUsageIdentifier++] =
3536 (LPSTR)info->pszOID;
3540 CertSetEnhancedKeyUsage(data->cert, &usage);
3541 free(usage.rgpszUsageIdentifier);
3543 EnumChildWindows(GetParent(GetParent(hwnd)), refresh_propsheet_pages, 0);
3544 if (data->pfPropertiesChanged)
3545 *data->pfPropertiesChanged = TRUE;
3548 static INT_PTR CALLBACK cert_properties_general_dlg_proc(HWND hwnd, UINT msg,
3549 WPARAM wp, LPARAM lp)
3551 PROPSHEETPAGEW *page;
3553 TRACE("(%p, %08x, %08Ix, %08Ix)\n", hwnd, msg, wp, lp);
3555 switch (msg)
3557 case WM_INITDIALOG:
3559 HWND description = GetDlgItem(hwnd, IDC_DESCRIPTION);
3560 struct detail_data *detailData;
3561 struct edit_cert_data *editData;
3563 page = (PROPSHEETPAGEW *)lp;
3564 detailData = (struct detail_data *)page->lParam;
3565 SendMessageW(GetDlgItem(hwnd, IDC_FRIENDLY_NAME), EM_SETLIMITTEXT,
3566 MAX_FRIENDLY_NAME, 0);
3567 SendMessageW(description, EM_SETLIMITTEXT, MAX_DESCRIPTION, 0);
3568 ShowScrollBar(description, SB_VERT, FALSE);
3569 editData = malloc(sizeof(struct edit_cert_data));
3570 if (editData)
3572 editData->imageList = ImageList_Create(16, 16,
3573 ILC_COLOR4 | ILC_MASK, 4, 0);
3574 if (editData->imageList)
3576 HBITMAP bmp;
3577 COLORREF backColor = RGB(255, 0, 255);
3579 bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_CHECKS));
3580 ImageList_AddMasked(editData->imageList, bmp, backColor);
3581 DeleteObject(bmp);
3582 ImageList_SetBkColor(editData->imageList, CLR_NONE);
3584 editData->cert = detailData->pCertViewInfo->pCertContext;
3585 editData->pfPropertiesChanged = detailData->pfPropertiesChanged;
3586 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)editData);
3587 set_general_cert_properties(hwnd, editData);
3589 break;
3591 case WM_NOTIFY:
3593 NMHDR *hdr = (NMHDR *)lp;
3594 NMITEMACTIVATE *nm;
3596 switch (hdr->code)
3598 case NM_CLICK:
3599 nm = (NMITEMACTIVATE *)lp;
3600 toggle_usage(hwnd, nm->iItem);
3601 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
3602 break;
3603 case PSN_APPLY:
3604 apply_general_changes(hwnd);
3605 break;
3607 break;
3609 case WM_COMMAND:
3610 switch (HIWORD(wp))
3612 case EN_CHANGE:
3613 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
3614 if (LOWORD(wp) == IDC_DESCRIPTION)
3616 /* Show/hide scroll bar on description depending on how much
3617 * text it has.
3619 HWND description = GetDlgItem(hwnd, IDC_DESCRIPTION);
3620 int lines = SendMessageW(description, EM_GETLINECOUNT, 0, 0);
3622 ShowScrollBar(description, SB_VERT, lines > 1);
3624 break;
3625 case BN_CLICKED:
3626 switch (LOWORD(wp))
3628 case IDC_ADD_PURPOSE:
3629 if (DialogBoxParamW(hInstance,
3630 MAKEINTRESOURCEW(IDD_ADD_CERT_PURPOSE), hwnd,
3631 add_purpose_dlg_proc, (LPARAM)hwnd) == IDOK)
3632 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
3633 break;
3634 case IDC_ENABLE_ALL_PURPOSES:
3635 case IDC_DISABLE_ALL_PURPOSES:
3636 case IDC_ENABLE_SELECTED_PURPOSES:
3637 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
3638 select_purposes(hwnd, LOWORD(wp) - IDC_ENABLE_ALL_PURPOSES);
3639 break;
3641 break;
3643 break;
3645 return 0;
3648 static UINT CALLBACK cert_properties_general_callback(HWND hwnd, UINT msg,
3649 PROPSHEETPAGEW *page)
3651 HWND lv;
3652 int cItem, i;
3653 struct edit_cert_data *data;
3655 switch (msg)
3657 case PSPCB_RELEASE:
3658 lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
3659 cItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
3660 for (i = 0; i < cItem; i++)
3662 LVITEMW item;
3664 item.mask = LVIF_PARAM;
3665 item.iItem = i;
3666 item.iSubItem = 0;
3667 if (SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item) && item.lParam)
3669 PCRYPT_OID_INFO info = (PCRYPT_OID_INFO)item.lParam;
3671 if (info->cbSize == sizeof(CRYPT_OID_INFO) && !info->dwGroupId)
3673 free((char *)info->pszOID);
3674 free(info);
3678 data = (struct edit_cert_data *)GetWindowLongPtrW(hwnd, DWLP_USER);
3679 if (data)
3681 ImageList_Destroy(data->imageList);
3682 free(data);
3684 break;
3686 return 1;
3689 static void show_edit_cert_properties_dialog(HWND parent,
3690 struct detail_data *data)
3692 PROPSHEETHEADERW hdr;
3693 PROPSHEETPAGEW page; /* FIXME: need to add a cross-certificate page */
3695 TRACE("(%p)\n", data);
3697 memset(&page, 0, sizeof(PROPSHEETPAGEW));
3698 page.dwSize = sizeof(page);
3699 page.dwFlags = PSP_USECALLBACK;
3700 page.pfnCallback = cert_properties_general_callback;
3701 page.hInstance = hInstance;
3702 page.pszTemplate = MAKEINTRESOURCEW(IDD_CERT_PROPERTIES_GENERAL);
3703 page.pfnDlgProc = cert_properties_general_dlg_proc;
3704 page.lParam = (LPARAM)data;
3706 memset(&hdr, 0, sizeof(hdr));
3707 hdr.dwSize = sizeof(hdr);
3708 hdr.hwndParent = parent;
3709 hdr.dwFlags = PSH_PROPSHEETPAGE;
3710 hdr.hInstance = hInstance;
3711 hdr.pszCaption = MAKEINTRESOURCEW(IDS_CERTIFICATE_PROPERTIES);
3712 hdr.ppsp = &page;
3713 hdr.nPages = 1;
3714 PropertySheetW(&hdr);
3717 static void free_detail_fields(struct detail_data *data)
3719 int i;
3721 for (i = 0; i < data->cFields; i++)
3722 free(data->fields[i].detailed_value);
3723 free(data->fields);
3724 data->fields = NULL;
3725 data->cFields = 0;
3728 static void refresh_details_view(HWND hwnd)
3730 HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT);
3731 int curSel;
3732 struct detail_data *data;
3734 curSel = SendMessageW(cb, CB_GETCURSEL, 0, 0);
3735 /* Actually, any index will do, since they all store the same data value */
3736 data = (struct detail_data *)SendMessageW(cb, CB_GETITEMDATA, curSel, 0);
3737 free_detail_fields(data);
3738 set_fields_selection(hwnd, data, curSel);
3741 static INT_PTR CALLBACK detail_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
3742 LPARAM lp)
3744 PROPSHEETPAGEW *page;
3745 struct detail_data *data;
3747 TRACE("(%p, %08x, %08Ix, %08Ix)\n", hwnd, msg, wp, lp);
3749 switch (msg)
3751 case WM_INITDIALOG:
3752 page = (PROPSHEETPAGEW *)lp;
3753 data = (struct detail_data *)page->lParam;
3754 create_cert_details_list(hwnd, data);
3755 if (!(data->pCertViewInfo->dwFlags & CRYPTUI_ENABLE_EDITPROPERTIES))
3756 EnableWindow(GetDlgItem(hwnd, IDC_EDITPROPERTIES), FALSE);
3757 if (data->pCertViewInfo->dwFlags & CRYPTUI_DISABLE_EXPORT)
3758 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT), FALSE);
3759 break;
3760 case WM_NOTIFY:
3762 NMITEMACTIVATE *nm;
3763 HWND list = GetDlgItem(hwnd, IDC_DETAIL_LIST);
3765 nm = (NMITEMACTIVATE*)lp;
3766 if (nm->hdr.hwndFrom == list && nm->uNewState & LVN_ITEMACTIVATE
3767 && nm->hdr.code == LVN_ITEMCHANGED)
3769 data = (struct detail_data *)nm->lParam;
3770 if (nm->iItem >= 0 && data && nm->iItem < data->cFields)
3772 WCHAR buf[MAX_STRING_LEN], *val = NULL;
3773 HWND valueCtl = GetDlgItem(hwnd, IDC_DETAIL_VALUE);
3775 if (data->fields[nm->iItem].create)
3776 val = data->fields[nm->iItem].create(
3777 data->pCertViewInfo->pCertContext,
3778 data->fields[nm->iItem].param);
3779 else
3781 LVITEMW item;
3782 int res;
3784 item.cchTextMax = ARRAY_SIZE(buf);
3785 item.mask = LVIF_TEXT;
3786 item.pszText = buf;
3787 item.iItem = nm->iItem;
3788 item.iSubItem = 1;
3789 res = SendMessageW(list, LVM_GETITEMW, 0, (LPARAM)&item);
3790 if (res)
3791 val = buf;
3793 /* Select all the text in the control, the next update will
3794 * replace it
3796 SendMessageW(valueCtl, EM_SETSEL, 0, -1);
3797 add_unformatted_text_to_control(valueCtl, val,
3798 val ? lstrlenW(val) : 0);
3799 if (val != buf)
3800 free(val);
3803 break;
3805 case WM_COMMAND:
3806 switch (wp)
3808 case IDC_EXPORT:
3810 HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT);
3811 CRYPTUI_WIZ_EXPORT_INFO info;
3813 data = (struct detail_data *)SendMessageW(cb, CB_GETITEMDATA, 0, 0);
3814 info.dwSize = sizeof(info);
3815 info.pwszExportFileName = NULL;
3816 info.dwSubjectChoice = CRYPTUI_WIZ_EXPORT_CERT_CONTEXT;
3817 info.pCertContext = data->pCertViewInfo->pCertContext;
3818 info.cStores = 0;
3819 CryptUIWizExport(0, hwnd, NULL, &info, NULL);
3820 break;
3822 case IDC_EDITPROPERTIES:
3824 HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT);
3825 int curSel;
3827 curSel = SendMessageW(cb, CB_GETCURSEL, 0, 0);
3828 /* Actually, any index will do, since they all store the same
3829 * data value
3831 data = (struct detail_data *)SendMessageW(cb, CB_GETITEMDATA,
3832 curSel, 0);
3833 show_edit_cert_properties_dialog(GetParent(hwnd), data);
3834 break;
3836 case ((CBN_SELCHANGE << 16) | IDC_DETAIL_SELECT):
3837 refresh_details_view(hwnd);
3838 break;
3840 break;
3841 case WM_REFRESH_VIEW:
3842 refresh_details_view(hwnd);
3843 break;
3845 return 0;
3848 static UINT CALLBACK detail_callback(HWND hwnd, UINT msg,
3849 PROPSHEETPAGEW *page)
3851 struct detail_data *data;
3853 switch (msg)
3855 case PSPCB_RELEASE:
3856 data = (struct detail_data *)page->lParam;
3857 free_detail_fields(data);
3858 free(data);
3859 break;
3861 return 0;
3864 static BOOL init_detail_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
3865 BOOL *pfPropertiesChanged, PROPSHEETPAGEW *page)
3867 BOOL ret;
3868 struct detail_data *data = malloc(sizeof(struct detail_data));
3870 if (data)
3872 data->pCertViewInfo = pCertViewInfo;
3873 data->pfPropertiesChanged = pfPropertiesChanged;
3874 data->cFields = 0;
3875 data->fields = NULL;
3876 memset(page, 0, sizeof(PROPSHEETPAGEW));
3877 page->dwSize = sizeof(PROPSHEETPAGEW);
3878 page->dwFlags = PSP_USECALLBACK;
3879 page->pfnCallback = detail_callback;
3880 page->hInstance = hInstance;
3881 page->pszTemplate = MAKEINTRESOURCEW(IDD_DETAIL);
3882 page->pfnDlgProc = detail_dlg_proc;
3883 page->lParam = (LPARAM)data;
3884 ret = TRUE;
3886 else
3887 ret = FALSE;
3888 return ret;
3891 struct hierarchy_data
3893 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo;
3894 HIMAGELIST imageList;
3895 DWORD selectedCert;
3898 static LPARAM index_to_lparam(struct hierarchy_data *data, DWORD index)
3900 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
3901 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->pCryptProviderData,
3902 data->pCertViewInfo->idxSigner, data->pCertViewInfo->fCounterSigner,
3903 data->pCertViewInfo->idxCounterSigner);
3905 /* Takes advantage of the fact that a pointer is 32-bit aligned, and
3906 * therefore always even.
3908 if (index == provSigner->csCertChain - 1)
3909 return (LPARAM)data;
3910 return index << 1 | 1;
3913 static inline DWORD lparam_to_index(struct hierarchy_data *data, LPARAM lp)
3915 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
3916 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->pCryptProviderData,
3917 data->pCertViewInfo->idxSigner, data->pCertViewInfo->fCounterSigner,
3918 data->pCertViewInfo->idxCounterSigner);
3920 if (!(lp & 1))
3921 return provSigner->csCertChain - 1;
3922 return lp >> 1;
3925 static struct hierarchy_data *get_hierarchy_data_from_tree_item(HWND tree,
3926 HTREEITEM hItem)
3928 struct hierarchy_data *data = NULL;
3929 HTREEITEM root = NULL;
3931 do {
3932 HTREEITEM parent = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM,
3933 TVGN_PARENT, (LPARAM)hItem);
3935 if (!parent)
3936 root = hItem;
3937 hItem = parent;
3938 } while (hItem);
3939 if (root)
3941 TVITEMW item;
3943 item.mask = TVIF_PARAM;
3944 item.hItem = root;
3945 SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item);
3946 data = (struct hierarchy_data *)item.lParam;
3948 return data;
3951 static WCHAR *get_cert_display_name(PCCERT_CONTEXT cert)
3953 WCHAR *name = get_cert_property_as_string(cert, CERT_FRIENDLY_NAME_PROP_ID);
3955 if (!name)
3956 name = get_cert_name_string(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0);
3957 return name;
3960 static void show_cert_chain(HWND hwnd, struct hierarchy_data *data)
3962 HWND tree = GetDlgItem(hwnd, IDC_CERTPATH);
3963 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
3964 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->pCryptProviderData,
3965 data->pCertViewInfo->idxSigner, data->pCertViewInfo->fCounterSigner,
3966 data->pCertViewInfo->idxCounterSigner);
3967 DWORD i;
3968 HTREEITEM parent = NULL;
3970 SendMessageW(tree, TVM_SETIMAGELIST, TVSIL_NORMAL, (LPARAM)data->imageList);
3971 for (i = provSigner->csCertChain; i; i--)
3973 LPWSTR name;
3975 name = get_cert_display_name(provSigner->pasCertChain[i - 1].pCert);
3976 if (name)
3978 TVINSERTSTRUCTW tvis;
3980 tvis.hParent = parent;
3981 tvis.hInsertAfter = TVI_LAST;
3982 tvis.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_IMAGE |
3983 TVIF_SELECTEDIMAGE | TVIF_PARAM;
3984 tvis.item.pszText = name;
3985 tvis.item.state = TVIS_EXPANDED;
3986 tvis.item.stateMask = TVIS_EXPANDED;
3987 if (i == 1 && (!provSigner->pChainContext ||
3988 provSigner->pChainContext->TrustStatus.dwErrorStatus &
3989 CERT_TRUST_IS_PARTIAL_CHAIN))
3991 /* The root of the chain has a special case: if the chain is
3992 * a partial chain, the icon is a warning icon rather than an
3993 * error icon.
3995 tvis.item.iImage = 2;
3997 else if (provSigner->pasCertChain[i - 1].pChainElement->TrustStatus.
3998 dwErrorStatus == 0)
3999 tvis.item.iImage = 0;
4000 else
4001 tvis.item.iImage = 1;
4002 tvis.item.iSelectedImage = tvis.item.iImage;
4003 tvis.item.lParam = index_to_lparam(data, i - 1);
4004 parent = (HTREEITEM)SendMessageW(tree, TVM_INSERTITEMW, 0,
4005 (LPARAM)&tvis);
4006 free(name);
4011 static void set_certificate_status(HWND hwnd, const CRYPT_PROVIDER_CERT *cert)
4013 /* Select all the text in the control, the next update will replace it */
4014 SendMessageW(hwnd, EM_SETSEL, 0, -1);
4015 /* Set the highest priority error messages first. */
4016 if (!(cert->dwConfidence & CERT_CONFIDENCE_SIG))
4017 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_BAD_SIGNATURE);
4018 else if (!(cert->dwConfidence & CERT_CONFIDENCE_TIME))
4019 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_BAD_TIME);
4020 else if (!(cert->dwConfidence & CERT_CONFIDENCE_TIMENEST))
4021 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_BAD_TIMENEST);
4022 else if (cert->dwRevokedReason)
4023 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_REVOKED);
4024 else
4025 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_VALID);
4028 static void set_certificate_status_for_end_cert(HWND hwnd,
4029 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
4031 HWND status = GetDlgItem(hwnd, IDC_CERTIFICATESTATUSTEXT);
4032 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
4033 (CRYPT_PROVIDER_DATA *)pCertViewInfo->pCryptProviderData,
4034 pCertViewInfo->idxSigner, pCertViewInfo->fCounterSigner,
4035 pCertViewInfo->idxCounterSigner);
4036 CRYPT_PROVIDER_CERT *provCert = WTHelperGetProvCertFromChain(provSigner,
4037 pCertViewInfo->idxCert);
4039 set_certificate_status(status, provCert);
4042 static void show_cert_hierarchy(HWND hwnd, struct hierarchy_data *data)
4044 /* Disable view certificate button until a certificate is selected */
4045 EnableWindow(GetDlgItem(hwnd, IDC_VIEWCERTIFICATE), FALSE);
4046 show_cert_chain(hwnd, data);
4047 set_certificate_status_for_end_cert(hwnd, data->pCertViewInfo);
4050 static void show_dialog_for_selected_cert(HWND hwnd)
4052 HWND tree = GetDlgItem(hwnd, IDC_CERTPATH);
4053 TVITEMW item;
4054 struct hierarchy_data *data;
4055 DWORD selection;
4057 memset(&item, 0, sizeof(item));
4058 item.mask = TVIF_HANDLE | TVIF_PARAM;
4059 item.hItem = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM, TVGN_CARET, 0);
4060 SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item);
4061 data = get_hierarchy_data_from_tree_item(tree, item.hItem);
4062 selection = lparam_to_index(data, item.lParam);
4063 if (selection != 0)
4065 CRYPT_PROVIDER_SGNR *provSigner;
4066 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
4067 BOOL changed = FALSE;
4069 provSigner = WTHelperGetProvSignerFromChain(
4070 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->pCryptProviderData,
4071 data->pCertViewInfo->idxSigner,
4072 data->pCertViewInfo->fCounterSigner,
4073 data->pCertViewInfo->idxCounterSigner);
4074 memset(&viewInfo, 0, sizeof(viewInfo));
4075 viewInfo.dwSize = sizeof(viewInfo);
4076 viewInfo.dwFlags = data->pCertViewInfo->dwFlags;
4077 viewInfo.szTitle = data->pCertViewInfo->szTitle;
4078 viewInfo.pCertContext = provSigner->pasCertChain[selection].pCert;
4079 viewInfo.cStores = data->pCertViewInfo->cStores;
4080 viewInfo.rghStores = data->pCertViewInfo->rghStores;
4081 viewInfo.cPropSheetPages = data->pCertViewInfo->cPropSheetPages;
4082 viewInfo.rgPropSheetPages = data->pCertViewInfo->rgPropSheetPages;
4083 viewInfo.nStartPage = data->pCertViewInfo->nStartPage;
4084 CryptUIDlgViewCertificateW(&viewInfo, &changed);
4085 if (changed)
4087 /* Delete the contents of the tree */
4088 SendMessageW(tree, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT);
4089 /* Reinitialize the tree */
4090 show_cert_hierarchy(hwnd, data);
4095 static INT_PTR CALLBACK hierarchy_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
4096 LPARAM lp)
4098 PROPSHEETPAGEW *page;
4099 struct hierarchy_data *data;
4100 INT_PTR ret = 0;
4101 HWND tree = GetDlgItem(hwnd, IDC_CERTPATH);
4103 TRACE("(%p, %08x, %08Ix, %08Ix)\n", hwnd, msg, wp, lp);
4105 switch (msg)
4107 case WM_INITDIALOG:
4108 page = (PROPSHEETPAGEW *)lp;
4109 data = (struct hierarchy_data *)page->lParam;
4110 show_cert_hierarchy(hwnd, data);
4111 break;
4112 case WM_NOTIFY:
4114 NMHDR *hdr;
4116 hdr = (NMHDR *)lp;
4117 switch (hdr->code)
4119 case TVN_SELCHANGEDW:
4121 NMTREEVIEWW *nm = (NMTREEVIEWW*)lp;
4122 DWORD selection;
4123 CRYPT_PROVIDER_SGNR *provSigner;
4125 data = get_hierarchy_data_from_tree_item(tree, nm->itemNew.hItem);
4126 selection = lparam_to_index(data, nm->itemNew.lParam);
4127 provSigner = WTHelperGetProvSignerFromChain(
4128 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->pCryptProviderData,
4129 data->pCertViewInfo->idxSigner,
4130 data->pCertViewInfo->fCounterSigner,
4131 data->pCertViewInfo->idxCounterSigner);
4132 EnableWindow(GetDlgItem(hwnd, IDC_VIEWCERTIFICATE), selection != 0);
4133 set_certificate_status(GetDlgItem(hwnd, IDC_CERTIFICATESTATUSTEXT),
4134 &provSigner->pasCertChain[selection]);
4135 break;
4137 case NM_DBLCLK:
4138 show_dialog_for_selected_cert(hwnd);
4139 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
4140 ret = 1;
4141 break;
4143 break;
4145 case WM_COMMAND:
4146 switch (wp)
4148 case IDC_VIEWCERTIFICATE:
4149 show_dialog_for_selected_cert(hwnd);
4150 break;
4152 break;
4153 case WM_REFRESH_VIEW:
4155 TVITEMW item;
4157 /* Get hierarchy data */
4158 memset(&item, 0, sizeof(item));
4159 item.mask = TVIF_HANDLE | TVIF_PARAM;
4160 item.hItem = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM, TVGN_ROOT,
4162 data = get_hierarchy_data_from_tree_item(tree, item.hItem);
4163 /* Delete the contents of the tree */
4164 SendMessageW(tree, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT);
4165 /* Reinitialize the tree */
4166 show_cert_hierarchy(hwnd, data);
4167 break;
4170 return ret;
4173 static UINT CALLBACK hierarchy_callback(HWND hwnd, UINT msg,
4174 PROPSHEETPAGEW *page)
4176 struct hierarchy_data *data;
4178 switch (msg)
4180 case PSPCB_RELEASE:
4181 data = (struct hierarchy_data *)page->lParam;
4182 ImageList_Destroy(data->imageList);
4183 free(data);
4184 break;
4186 return 0;
4189 static BOOL init_hierarchy_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
4190 PROPSHEETPAGEW *page)
4192 struct hierarchy_data *data = malloc(sizeof(struct hierarchy_data));
4193 BOOL ret = FALSE;
4195 if (data)
4197 data->imageList = ImageList_Create(16, 16, ILC_COLOR4 | ILC_MASK, 2, 0);
4198 if (data->imageList)
4200 HBITMAP bmp;
4201 COLORREF backColor = RGB(255, 0, 255);
4203 data->pCertViewInfo = pCertViewInfo;
4204 data->selectedCert = 0xffffffff;
4206 bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_SMALL_ICONS));
4207 ImageList_AddMasked(data->imageList, bmp, backColor);
4208 DeleteObject(bmp);
4209 ImageList_SetBkColor(data->imageList, CLR_NONE);
4211 memset(page, 0, sizeof(PROPSHEETPAGEW));
4212 page->dwSize = sizeof(PROPSHEETPAGEW);
4213 page->dwFlags = PSP_USECALLBACK;
4214 page->hInstance = hInstance;
4215 page->pszTemplate = MAKEINTRESOURCEW(IDD_HIERARCHY);
4216 page->pfnDlgProc = hierarchy_dlg_proc;
4217 page->lParam = (LPARAM)data;
4218 page->pfnCallback = hierarchy_callback;
4219 ret = TRUE;
4221 else
4222 free(data);
4224 return ret;
4227 static int CALLBACK cert_prop_sheet_proc(HWND hwnd, UINT msg, LPARAM lp)
4229 RECT rc;
4231 TRACE("(%p, %08x, %08Ix)\n", hwnd, msg, lp);
4233 switch (msg)
4235 case PSCB_INITIALIZED:
4236 /* Get cancel button's position.. */
4237 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rc);
4238 MapWindowPoints( 0, hwnd, (POINT *)&rc, 2 );
4239 /* hide the cancel button.. */
4240 ShowWindow(GetDlgItem(hwnd, IDCANCEL), FALSE);
4241 /* and move the OK button to the cancel button's original position. */
4242 SetWindowPos(GetDlgItem(hwnd, IDOK), 0, rc.left, rc.top, 0, 0,
4243 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW );
4244 break;
4246 return 0;
4249 static BOOL show_cert_dialog(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
4250 CRYPT_PROVIDER_CERT *provCert, BOOL *pfPropertiesChanged)
4252 static const WCHAR riched[] = { 'r','i','c','h','e','d','2','0',0 };
4253 DWORD nPages;
4254 PROPSHEETPAGEW *pages;
4255 BOOL ret = FALSE;
4256 HMODULE lib = LoadLibraryW(riched);
4258 nPages = pCertViewInfo->cPropSheetPages + 1; /* one for the General tab */
4259 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_DETAILPAGE))
4260 nPages++;
4261 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_HIERARCHYPAGE))
4262 nPages++;
4263 pages = malloc(nPages * sizeof(PROPSHEETPAGEW));
4264 if (pages)
4266 PROPSHEETHEADERW hdr;
4267 CRYPTUI_INITDIALOG_STRUCT *init = NULL;
4268 DWORD i;
4270 memset(&hdr, 0, sizeof(hdr));
4271 hdr.dwSize = sizeof(hdr);
4272 hdr.dwFlags = PSH_NOAPPLYNOW | PSH_PROPSHEETPAGE | PSH_USECALLBACK;
4273 hdr.hInstance = hInstance;
4274 if (pCertViewInfo->szTitle)
4275 hdr.pszCaption = pCertViewInfo->szTitle;
4276 else
4277 hdr.pszCaption = MAKEINTRESOURCEW(IDS_CERTIFICATE);
4278 init_general_page(pCertViewInfo, &pages[hdr.nPages++]);
4279 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_DETAILPAGE))
4281 if (init_detail_page(pCertViewInfo, pfPropertiesChanged,
4282 &pages[hdr.nPages]))
4283 hdr.nPages++;
4285 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_HIERARCHYPAGE))
4287 if (init_hierarchy_page(pCertViewInfo, &pages[hdr.nPages]))
4288 hdr.nPages++;
4290 /* Copy each additional page, and create the init dialog struct for it
4292 if (pCertViewInfo->cPropSheetPages)
4294 init = malloc(pCertViewInfo->cPropSheetPages * sizeof(CRYPTUI_INITDIALOG_STRUCT));
4295 if (init)
4297 for (i = 0; i < pCertViewInfo->cPropSheetPages; i++)
4299 memcpy(&pages[hdr.nPages + i],
4300 &pCertViewInfo->rgPropSheetPages[i],
4301 sizeof(PROPSHEETPAGEW));
4302 init[i].lParam = pCertViewInfo->rgPropSheetPages[i].lParam;
4303 init[i].pCertContext = pCertViewInfo->pCertContext;
4304 pages[hdr.nPages + i].lParam = (LPARAM)&init[i];
4306 if (pCertViewInfo->nStartPage & 0x8000)
4308 /* Start page index is relative to the number of default
4309 * pages
4311 hdr.nStartPage = pCertViewInfo->nStartPage + hdr.nPages;
4313 else
4314 hdr.nStartPage = pCertViewInfo->nStartPage;
4315 hdr.nPages = nPages;
4316 ret = TRUE;
4318 else
4319 SetLastError(ERROR_OUTOFMEMORY);
4321 else
4323 /* Ignore the relative flag if there aren't any additional pages */
4324 hdr.nStartPage = pCertViewInfo->nStartPage & 0x7fff;
4325 ret = TRUE;
4327 if (ret)
4329 INT_PTR l;
4331 hdr.ppsp = pages;
4332 hdr.pfnCallback = cert_prop_sheet_proc;
4333 l = PropertySheetW(&hdr);
4334 if (l == 0)
4336 SetLastError(ERROR_CANCELLED);
4337 ret = FALSE;
4340 free(init);
4341 free(pages);
4343 else
4344 SetLastError(ERROR_OUTOFMEMORY);
4345 FreeLibrary(lib);
4346 return ret;
4349 /***********************************************************************
4350 * CryptUIDlgViewCertificateW (CRYPTUI.@)
4352 BOOL WINAPI CryptUIDlgViewCertificateW(
4353 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo, BOOL *pfPropertiesChanged)
4355 static GUID generic_cert_verify = WINTRUST_ACTION_GENERIC_CERT_VERIFY;
4356 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
4357 WINTRUST_DATA wvt;
4358 WINTRUST_CERT_INFO cert;
4359 BOOL ret = FALSE;
4360 CRYPT_PROVIDER_SGNR *signer;
4361 CRYPT_PROVIDER_CERT *provCert = NULL;
4363 TRACE("(%p, %p)\n", pCertViewInfo, pfPropertiesChanged);
4365 if (pCertViewInfo->dwSize != sizeof(CRYPTUI_VIEWCERTIFICATE_STRUCTW))
4367 SetLastError(ERROR_INVALID_PARAMETER);
4368 return FALSE;
4370 /* Make a local copy in case we have to call WinVerifyTrust ourselves */
4371 memcpy(&viewInfo, pCertViewInfo, sizeof(viewInfo));
4372 if (!pCertViewInfo->hWVTStateData)
4374 memset(&wvt, 0, sizeof(wvt));
4375 wvt.cbStruct = sizeof(wvt);
4376 wvt.dwUIChoice = WTD_UI_NONE;
4377 if (viewInfo.dwFlags &
4378 CRYPTUI_ENABLE_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT)
4379 wvt.fdwRevocationChecks |= WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
4380 if (viewInfo.dwFlags & CRYPTUI_ENABLE_REVOCATION_CHECK_END_CERT)
4381 wvt.fdwRevocationChecks |= WTD_REVOCATION_CHECK_END_CERT;
4382 if (viewInfo.dwFlags & CRYPTUI_ENABLE_REVOCATION_CHECK_CHAIN)
4383 wvt.fdwRevocationChecks |= WTD_REVOCATION_CHECK_CHAIN;
4384 wvt.dwUnionChoice = WTD_CHOICE_CERT;
4385 memset(&cert, 0, sizeof(cert));
4386 cert.cbStruct = sizeof(cert);
4387 cert.psCertContext = (CERT_CONTEXT *)viewInfo.pCertContext;
4388 cert.chStores = viewInfo.cStores;
4389 cert.pahStores = viewInfo.rghStores;
4390 wvt.pCert = &cert;
4391 wvt.dwStateAction = WTD_STATEACTION_VERIFY;
4392 WinVerifyTrust(NULL, &generic_cert_verify, &wvt);
4393 viewInfo.pCryptProviderData =
4394 WTHelperProvDataFromStateData(wvt.hWVTStateData);
4395 signer = WTHelperGetProvSignerFromChain(
4396 (CRYPT_PROVIDER_DATA *)viewInfo.pCryptProviderData, 0, FALSE, 0);
4397 provCert = WTHelperGetProvCertFromChain(signer, 0);
4398 ret = TRUE;
4400 else
4402 viewInfo.pCryptProviderData =
4403 WTHelperProvDataFromStateData(viewInfo.hWVTStateData);
4404 signer = WTHelperGetProvSignerFromChain(
4405 (CRYPT_PROVIDER_DATA *)viewInfo.pCryptProviderData,
4406 viewInfo.idxSigner, viewInfo.fCounterSigner,
4407 viewInfo.idxCounterSigner);
4408 provCert = WTHelperGetProvCertFromChain(signer, viewInfo.idxCert);
4409 ret = TRUE;
4411 if (ret)
4413 ret = show_cert_dialog(&viewInfo, provCert, pfPropertiesChanged);
4414 if (!pCertViewInfo->hWVTStateData)
4416 wvt.dwStateAction = WTD_STATEACTION_CLOSE;
4417 WinVerifyTrust(NULL, &generic_cert_verify, &wvt);
4420 return ret;
4423 /***********************************************************************
4424 * CryptUIDlgViewContext (CRYPTUI.@)
4426 BOOL WINAPI CryptUIDlgViewContext(DWORD dwContextType, LPVOID pvContext,
4427 HWND hwnd, LPCWSTR pwszTitle, DWORD dwFlags, LPVOID pvReserved)
4429 BOOL ret;
4431 TRACE("(%ld, %p, %p, %s, %08lx, %p)\n", dwContextType, pvContext, hwnd,
4432 debugstr_w(pwszTitle), dwFlags, pvReserved);
4434 switch (dwContextType)
4436 case CERT_STORE_CERTIFICATE_CONTEXT:
4438 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
4440 memset(&viewInfo, 0, sizeof(viewInfo));
4441 viewInfo.dwSize = sizeof(viewInfo);
4442 viewInfo.hwndParent = hwnd;
4443 viewInfo.szTitle = pwszTitle;
4444 viewInfo.pCertContext = pvContext;
4445 ret = CryptUIDlgViewCertificateW(&viewInfo, NULL);
4446 break;
4448 default:
4449 FIXME("unimplemented for context type %ld\n", dwContextType);
4450 SetLastError(E_INVALIDARG);
4451 ret = FALSE;
4453 return ret;
4456 /* Decodes a cert's basic constraints extension (either szOID_BASIC_CONSTRAINTS
4457 * or szOID_BASIC_CONSTRAINTS2, whichever is present) to determine if it
4458 * should be a CA. If neither extension is present, returns
4459 * defaultIfNotSpecified.
4461 static BOOL is_ca_cert(PCCERT_CONTEXT cert, BOOL defaultIfNotSpecified)
4463 BOOL isCA = defaultIfNotSpecified;
4464 PCERT_EXTENSION ext = CertFindExtension(szOID_BASIC_CONSTRAINTS,
4465 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
4467 if (ext)
4469 CERT_BASIC_CONSTRAINTS_INFO *info;
4470 DWORD size = 0;
4472 if (CryptDecodeObjectEx(X509_ASN_ENCODING, szOID_BASIC_CONSTRAINTS,
4473 ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG,
4474 NULL, &info, &size))
4476 if (info->SubjectType.cbData == 1)
4477 isCA = info->SubjectType.pbData[0] & CERT_CA_SUBJECT_FLAG;
4478 LocalFree(info);
4481 else
4483 ext = CertFindExtension(szOID_BASIC_CONSTRAINTS2,
4484 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
4485 if (ext)
4487 CERT_BASIC_CONSTRAINTS2_INFO info;
4488 DWORD size = sizeof(CERT_BASIC_CONSTRAINTS2_INFO);
4490 if (CryptDecodeObjectEx(X509_ASN_ENCODING,
4491 szOID_BASIC_CONSTRAINTS2, ext->Value.pbData, ext->Value.cbData,
4492 0, NULL, &info, &size))
4493 isCA = info.fCA;
4496 return isCA;
4499 static HCERTSTORE choose_store_for_cert(PCCERT_CONTEXT cert)
4501 LPCWSTR storeName;
4503 if (is_ca_cert(cert, TRUE))
4504 storeName = ca;
4505 else
4506 storeName = addressBook;
4507 return CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0,
4508 CERT_SYSTEM_STORE_CURRENT_USER, storeName);
4511 static BOOL import_cert(PCCERT_CONTEXT cert, HCERTSTORE hDestCertStore)
4513 HCERTSTORE store;
4514 BOOL ret;
4516 if (!cert)
4518 SetLastError(E_INVALIDARG);
4519 return FALSE;
4521 if (hDestCertStore) store = hDestCertStore;
4522 else
4524 if (!(store = choose_store_for_cert(cert)))
4526 WARN("unable to open certificate store\n");
4527 return FALSE;
4530 ret = CertAddCertificateContextToStore(store, cert,
4531 CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES, NULL);
4532 if (!hDestCertStore) CertCloseStore(store, 0);
4533 return ret;
4536 static BOOL import_crl(PCCRL_CONTEXT crl, HCERTSTORE hDestCertStore)
4538 HCERTSTORE store;
4539 BOOL ret;
4541 if (!crl)
4543 SetLastError(E_INVALIDARG);
4544 return FALSE;
4546 if (hDestCertStore) store = hDestCertStore;
4547 else
4549 if (!(store = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0,
4550 CERT_SYSTEM_STORE_CURRENT_USER, ca)))
4552 WARN("unable to open certificate store\n");
4553 return FALSE;
4556 ret = CertAddCRLContextToStore(store, crl,
4557 CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES, NULL);
4558 if (!hDestCertStore) CertCloseStore(store, 0);
4559 return ret;
4562 static BOOL import_ctl(PCCTL_CONTEXT ctl, HCERTSTORE hDestCertStore)
4564 HCERTSTORE store;
4565 BOOL ret;
4567 if (!ctl)
4569 SetLastError(E_INVALIDARG);
4570 return FALSE;
4572 if (hDestCertStore) store = hDestCertStore;
4573 else
4575 static const WCHAR trust[] = { 'T','r','u','s','t',0 };
4577 if (!(store = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0,
4578 CERT_SYSTEM_STORE_CURRENT_USER, trust)))
4580 WARN("unable to open certificate store\n");
4581 return FALSE;
4584 ret = CertAddCTLContextToStore(store, ctl,
4585 CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES, NULL);
4586 if (!hDestCertStore) CertCloseStore(store, 0);
4587 return ret;
4590 /* Checks type, a type such as CERT_QUERY_CONTENT_CERT returned by
4591 * CryptQueryObject, against the allowed types. Returns TRUE if the
4592 * type is allowed, FALSE otherwise.
4594 static BOOL check_context_type(DWORD dwFlags, DWORD type)
4596 BOOL ret;
4598 if (dwFlags &
4599 (CRYPTUI_WIZ_IMPORT_ALLOW_CERT | CRYPTUI_WIZ_IMPORT_ALLOW_CRL |
4600 CRYPTUI_WIZ_IMPORT_ALLOW_CTL))
4602 switch (type)
4604 case CERT_QUERY_CONTENT_CERT:
4605 case CERT_QUERY_CONTENT_SERIALIZED_CERT:
4606 ret = dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CERT;
4607 break;
4608 case CERT_QUERY_CONTENT_CRL:
4609 case CERT_QUERY_CONTENT_SERIALIZED_CRL:
4610 ret = dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CRL;
4611 break;
4612 case CERT_QUERY_CONTENT_CTL:
4613 case CERT_QUERY_CONTENT_SERIALIZED_CTL:
4614 ret = dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CTL;
4615 break;
4616 default:
4617 /* The remaining types contain more than one type, so allow
4618 * any combination.
4620 ret = TRUE;
4623 else
4625 /* No allowed types specified, so any type is allowed */
4626 ret = TRUE;
4628 if (!ret)
4629 SetLastError(E_INVALIDARG);
4630 return ret;
4634 static void import_warning(DWORD dwFlags, HWND hwnd, LPCWSTR szTitle,
4635 int warningID)
4637 if (!(dwFlags & CRYPTUI_WIZ_NO_UI))
4639 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
4640 LPCWSTR pTitle;
4642 if (szTitle)
4643 pTitle = szTitle;
4644 else
4646 LoadStringW(hInstance, IDS_IMPORT_WIZARD, title, ARRAY_SIZE(title));
4647 pTitle = title;
4649 LoadStringW(hInstance, warningID, error, ARRAY_SIZE(error));
4650 MessageBoxW(hwnd, error, pTitle, MB_ICONERROR | MB_OK);
4654 static void import_warn_type_mismatch(DWORD dwFlags, HWND hwnd, LPCWSTR szTitle)
4656 import_warning(dwFlags, hwnd, szTitle, IDS_IMPORT_TYPE_MISMATCH);
4659 static BOOL check_store_context_type(DWORD dwFlags, HCERTSTORE store)
4661 BOOL ret;
4663 if (dwFlags &
4664 (CRYPTUI_WIZ_IMPORT_ALLOW_CERT | CRYPTUI_WIZ_IMPORT_ALLOW_CRL |
4665 CRYPTUI_WIZ_IMPORT_ALLOW_CTL))
4667 PCCERT_CONTEXT cert;
4668 PCCRL_CONTEXT crl;
4669 PCCTL_CONTEXT ctl;
4671 ret = TRUE;
4672 if ((cert = CertEnumCertificatesInStore(store, NULL)))
4674 CertFreeCertificateContext(cert);
4675 if (!(dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CERT))
4676 ret = FALSE;
4678 if (ret && (crl = CertEnumCRLsInStore(store, NULL)))
4680 CertFreeCRLContext(crl);
4681 if (!(dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CRL))
4682 ret = FALSE;
4684 if (ret && (ctl = CertEnumCTLsInStore(store, NULL)))
4686 CertFreeCTLContext(ctl);
4687 if (!(dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CTL))
4688 ret = FALSE;
4691 else
4692 ret = TRUE;
4693 if (!ret)
4694 SetLastError(E_INVALIDARG);
4695 return ret;
4698 static BOOL import_store(DWORD dwFlags, HWND hwnd, LPCWSTR szTitle,
4699 HCERTSTORE source, HCERTSTORE dest)
4701 BOOL ret;
4703 if ((ret = check_store_context_type(dwFlags, source)))
4705 PCCERT_CONTEXT cert = NULL;
4706 PCCRL_CONTEXT crl = NULL;
4707 PCCTL_CONTEXT ctl = NULL;
4709 do {
4710 cert = CertEnumCertificatesInStore(source, cert);
4711 if (cert)
4712 ret = import_cert(cert, dest);
4713 } while (ret && cert);
4714 do {
4715 crl = CertEnumCRLsInStore(source, crl);
4716 if (crl)
4717 ret = import_crl(crl, dest);
4718 } while (ret && crl);
4719 do {
4720 ctl = CertEnumCTLsInStore(source, ctl);
4721 if (ctl)
4722 ret = import_ctl(ctl, dest);
4723 } while (ret && ctl);
4725 else
4726 import_warn_type_mismatch(dwFlags, hwnd, szTitle);
4727 return ret;
4730 static HCERTSTORE open_store_from_file(DWORD dwFlags, LPCWSTR fileName,
4731 DWORD *pContentType)
4733 HCERTSTORE store = NULL;
4734 DWORD contentType = 0, expectedContentTypeFlags;
4736 if (dwFlags &
4737 (CRYPTUI_WIZ_IMPORT_ALLOW_CERT | CRYPTUI_WIZ_IMPORT_ALLOW_CRL |
4738 CRYPTUI_WIZ_IMPORT_ALLOW_CTL))
4740 expectedContentTypeFlags =
4741 CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE |
4742 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED |
4743 CERT_QUERY_CONTENT_FLAG_PFX;
4744 if (dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CERT)
4745 expectedContentTypeFlags |=
4746 CERT_QUERY_CONTENT_FLAG_CERT |
4747 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT;
4748 if (dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CRL)
4749 expectedContentTypeFlags |=
4750 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL |
4751 CERT_QUERY_CONTENT_FLAG_CRL;
4752 if (dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CTL)
4753 expectedContentTypeFlags |=
4754 CERT_QUERY_CONTENT_FLAG_CTL |
4755 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL;
4757 else
4758 expectedContentTypeFlags =
4759 CERT_QUERY_CONTENT_FLAG_CERT |
4760 CERT_QUERY_CONTENT_FLAG_CTL |
4761 CERT_QUERY_CONTENT_FLAG_CRL |
4762 CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE |
4763 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT |
4764 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL |
4765 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL |
4766 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED |
4767 CERT_QUERY_CONTENT_FLAG_PFX;
4769 CryptQueryObject(CERT_QUERY_OBJECT_FILE, fileName,
4770 expectedContentTypeFlags, CERT_QUERY_FORMAT_FLAG_ALL, 0, NULL,
4771 &contentType, NULL, &store, NULL, NULL);
4772 if (pContentType)
4773 *pContentType = contentType;
4774 return store;
4777 static BOOL import_file(DWORD dwFlags, HWND hwnd, LPCWSTR szTitle,
4778 LPCWSTR fileName, HCERTSTORE dest)
4780 HCERTSTORE source;
4781 BOOL ret;
4783 if ((source = open_store_from_file(dwFlags, fileName, NULL)))
4785 ret = import_store(dwFlags, hwnd, szTitle, source, dest);
4786 CertCloseStore(source, 0);
4788 else
4789 ret = FALSE;
4790 return ret;
4793 struct ImportWizData
4795 HFONT titleFont;
4796 DWORD dwFlags;
4797 LPCWSTR pwszWizardTitle;
4798 CRYPTUI_WIZ_IMPORT_SRC_INFO importSrc;
4799 LPWSTR fileName;
4800 DWORD contentType;
4801 BOOL freeSource;
4802 HCERTSTORE hDestCertStore;
4803 BOOL freeDest;
4804 BOOL autoDest;
4805 BOOL success;
4808 static INT_PTR CALLBACK import_welcome_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
4809 LPARAM lp)
4811 INT_PTR ret = 0;
4813 switch (msg)
4815 case WM_INITDIALOG:
4817 struct ImportWizData *data;
4818 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
4819 WCHAR fontFace[MAX_STRING_LEN];
4820 HDC hDC = GetDC(hwnd);
4821 int height;
4823 data = (struct ImportWizData *)page->lParam;
4824 LoadStringW(hInstance, IDS_WIZARD_TITLE_FONT, fontFace, ARRAY_SIZE(fontFace));
4825 height = -MulDiv(12, GetDeviceCaps(hDC, LOGPIXELSY), 72);
4826 data->titleFont = CreateFontW(height, 0, 0, 0, FW_BOLD, 0, 0, 0,
4827 DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
4828 DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, fontFace);
4829 SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_TITLE), WM_SETFONT,
4830 (WPARAM)data->titleFont, TRUE);
4831 ReleaseDC(hwnd, hDC);
4832 break;
4834 case WM_NOTIFY:
4836 NMHDR *hdr = (NMHDR *)lp;
4838 switch (hdr->code)
4840 case PSN_SETACTIVE:
4841 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0, PSWIZB_NEXT);
4842 ret = TRUE;
4843 break;
4845 break;
4848 return ret;
4851 static const WCHAR filter_cert[] = { '*','.','c','e','r',';','*','.',
4852 'c','r','t',0 };
4853 static const WCHAR filter_pfx[] = { '*','.','p','f','x',';','*','.',
4854 'p','1','2',0 };
4855 static const WCHAR filter_crl[] = { '*','.','c','r','l',0 };
4856 static const WCHAR filter_ctl[] = { '*','.','s','t','l',0 };
4857 static const WCHAR filter_serialized_store[] = { '*','.','s','s','t',0 };
4858 static const WCHAR filter_cms[] = { '*','.','s','p','c',';','*','.',
4859 'p','7','b',0 };
4860 static const WCHAR filter_all[] = { '*','.','*',0 };
4862 static const struct
4864 int id;
4865 DWORD allowFlags;
4866 LPCWSTR filter;
4867 } import_filters[] = {
4868 { IDS_IMPORT_FILTER_CERT, CRYPTUI_WIZ_IMPORT_ALLOW_CERT, filter_cert },
4869 { IDS_IMPORT_FILTER_PFX, 0, filter_pfx },
4870 { IDS_IMPORT_FILTER_CRL, CRYPTUI_WIZ_IMPORT_ALLOW_CRL, filter_crl },
4871 { IDS_IMPORT_FILTER_CTL, CRYPTUI_WIZ_IMPORT_ALLOW_CTL, filter_ctl },
4872 { IDS_IMPORT_FILTER_SERIALIZED_STORE, 0, filter_serialized_store },
4873 { IDS_IMPORT_FILTER_CMS, 0, filter_cms },
4874 { IDS_IMPORT_FILTER_ALL, 0, filter_all },
4877 static WCHAR *make_import_file_filter(DWORD dwFlags)
4879 DWORD i;
4880 int len, totalLen = 2;
4881 LPWSTR filter = NULL, str;
4883 for (i = 0; i < ARRAY_SIZE(import_filters); i++)
4885 if (!import_filters[i].allowFlags || !dwFlags ||
4886 (dwFlags & import_filters[i].allowFlags))
4888 len = LoadStringW(hInstance, import_filters[i].id, (LPWSTR)&str, 0);
4889 totalLen += len + lstrlenW(import_filters[i].filter) + 2;
4892 filter = malloc(totalLen * sizeof(WCHAR));
4893 if (filter)
4895 LPWSTR ptr;
4897 ptr = filter;
4898 for (i = 0; i < ARRAY_SIZE(import_filters); i++)
4900 if (!import_filters[i].allowFlags || !dwFlags ||
4901 (dwFlags & import_filters[i].allowFlags))
4903 len = LoadStringW(hInstance, import_filters[i].id,
4904 (LPWSTR)&str, 0);
4905 memcpy(ptr, str, len * sizeof(WCHAR));
4906 ptr += len;
4907 *ptr++ = 0;
4908 lstrcpyW(ptr, import_filters[i].filter);
4909 ptr += lstrlenW(import_filters[i].filter) + 1;
4912 *ptr++ = 0;
4914 return filter;
4917 static BOOL import_validate_filename(HWND hwnd, struct ImportWizData *data,
4918 LPCWSTR fileName)
4920 HANDLE file;
4921 BOOL ret = FALSE;
4923 file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
4924 OPEN_EXISTING, 0, NULL);
4925 if (file != INVALID_HANDLE_VALUE)
4927 HCERTSTORE source = open_store_from_file(data->dwFlags, fileName,
4928 &data->contentType);
4929 int warningID = 0;
4931 if (!source)
4932 warningID = IDS_IMPORT_BAD_FORMAT;
4933 else if (!check_store_context_type(data->dwFlags, source))
4934 warningID = IDS_IMPORT_TYPE_MISMATCH;
4935 else
4937 data->importSrc.dwSubjectChoice =
4938 CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE;
4939 data->importSrc.hCertStore = source;
4940 data->freeSource = TRUE;
4941 ret = TRUE;
4943 if (warningID)
4945 import_warning(data->dwFlags, hwnd, data->pwszWizardTitle,
4946 warningID);
4948 CloseHandle(file);
4950 else
4952 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
4953 LPCWSTR pTitle;
4954 LPWSTR msgBuf, fullError;
4956 if (data->pwszWizardTitle)
4957 pTitle = data->pwszWizardTitle;
4958 else
4960 LoadStringW(hInstance, IDS_IMPORT_WIZARD, title, ARRAY_SIZE(title));
4961 pTitle = title;
4963 LoadStringW(hInstance, IDS_IMPORT_OPEN_FAILED, error, ARRAY_SIZE(error));
4964 FormatMessageW(
4965 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
4966 GetLastError(), 0, (LPWSTR) &msgBuf, 0, NULL);
4967 fullError = malloc((wcslen(error) + wcslen(fileName) + wcslen(msgBuf) + 3) * sizeof(WCHAR));
4968 if (fullError)
4970 LPWSTR ptr = fullError;
4972 lstrcpyW(ptr, error);
4973 ptr += lstrlenW(error);
4974 lstrcpyW(ptr, fileName);
4975 ptr += lstrlenW(fileName);
4976 *ptr++ = ':';
4977 *ptr++ = '\n';
4978 lstrcpyW(ptr, msgBuf);
4979 MessageBoxW(hwnd, fullError, pTitle, MB_ICONERROR | MB_OK);
4980 free(fullError);
4982 LocalFree(msgBuf);
4984 return ret;
4987 static INT_PTR CALLBACK import_file_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
4988 LPARAM lp)
4990 INT_PTR ret = 0;
4991 struct ImportWizData *data;
4993 switch (msg)
4995 case WM_INITDIALOG:
4997 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
4999 data = (struct ImportWizData *)page->lParam;
5000 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
5001 if (data->fileName)
5003 HWND fileNameEdit = GetDlgItem(hwnd, IDC_IMPORT_FILENAME);
5005 SendMessageW(fileNameEdit, WM_SETTEXT, 0, (LPARAM)data->fileName);
5007 break;
5009 case WM_NOTIFY:
5011 NMHDR *hdr = (NMHDR *)lp;
5013 switch (hdr->code)
5015 case PSN_SETACTIVE:
5016 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
5017 PSWIZB_BACK | PSWIZB_NEXT);
5018 ret = TRUE;
5019 break;
5020 case PSN_WIZNEXT:
5022 HWND fileNameEdit = GetDlgItem(hwnd, IDC_IMPORT_FILENAME);
5023 DWORD len = SendMessageW(fileNameEdit, WM_GETTEXTLENGTH, 0, 0);
5025 data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5026 if (!len)
5028 import_warning(data->dwFlags, hwnd, data->pwszWizardTitle,
5029 IDS_IMPORT_EMPTY_FILE);
5030 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
5031 ret = 1;
5033 else
5035 WCHAR *fileName = malloc((len + 1) * sizeof(WCHAR));
5037 if (fileName)
5039 SendMessageW(fileNameEdit, WM_GETTEXT, len + 1,
5040 (LPARAM)fileName);
5041 if (!import_validate_filename(hwnd, data, fileName))
5043 free(fileName);
5044 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
5045 ret = 1;
5047 else
5048 data->fileName = fileName;
5051 break;
5054 break;
5056 case WM_COMMAND:
5057 switch (wp)
5059 case IDC_IMPORT_BROWSE_FILE:
5061 OPENFILENAMEW ofn;
5062 WCHAR fileBuf[MAX_PATH];
5064 data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5065 memset(&ofn, 0, sizeof(ofn));
5066 ofn.lStructSize = sizeof(ofn);
5067 ofn.hwndOwner = hwnd;
5068 ofn.lpstrFilter = make_import_file_filter(data->dwFlags);
5069 ofn.lpstrFile = fileBuf;
5070 ofn.nMaxFile = ARRAY_SIZE(fileBuf);
5071 fileBuf[0] = 0;
5072 if (GetOpenFileNameW(&ofn))
5073 SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_FILENAME), WM_SETTEXT,
5074 0, (LPARAM)ofn.lpstrFile);
5075 free((WCHAR *)ofn.lpstrFilter);
5076 break;
5079 break;
5081 return ret;
5084 static INT_PTR CALLBACK import_store_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
5085 LPARAM lp)
5087 INT_PTR ret = 0;
5088 struct ImportWizData *data;
5090 switch (msg)
5092 case WM_INITDIALOG:
5094 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
5096 data = (struct ImportWizData *)page->lParam;
5097 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
5098 if (!data->hDestCertStore)
5100 SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_AUTO_STORE), BM_CLICK,
5101 0, 0);
5102 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_STORE), FALSE);
5103 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_BROWSE_STORE), FALSE);
5104 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_SPECIFY_STORE), FALSE);
5106 else
5108 WCHAR storeTitle[MAX_STRING_LEN];
5110 SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_SPECIFY_STORE), BM_CLICK,
5111 0, 0);
5112 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_STORE), TRUE);
5113 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_BROWSE_STORE), TRUE);
5114 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_SPECIFY_STORE),
5115 !(data->dwFlags & CRYPTUI_WIZ_IMPORT_NO_CHANGE_DEST_STORE));
5116 LoadStringW(hInstance, IDS_IMPORT_DEST_DETERMINED, storeTitle, ARRAY_SIZE(storeTitle));
5117 SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_STORE), WM_SETTEXT,
5118 0, (LPARAM)storeTitle);
5120 break;
5122 case WM_NOTIFY:
5124 NMHDR *hdr = (NMHDR *)lp;
5126 switch (hdr->code)
5128 case PSN_SETACTIVE:
5129 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
5130 PSWIZB_BACK | PSWIZB_NEXT);
5131 ret = TRUE;
5132 break;
5133 case PSN_WIZNEXT:
5135 data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5136 if (IsDlgButtonChecked(hwnd, IDC_IMPORT_SPECIFY_STORE) &&
5137 !data->hDestCertStore)
5139 import_warning(data->dwFlags, hwnd, data->pwszWizardTitle,
5140 IDS_IMPORT_SELECT_STORE);
5141 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
5142 ret = 1;
5144 break;
5147 break;
5149 case WM_COMMAND:
5150 switch (wp)
5152 case IDC_IMPORT_AUTO_STORE:
5153 data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5154 data->autoDest = TRUE;
5155 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_STORE), FALSE);
5156 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_BROWSE_STORE), FALSE);
5157 break;
5158 case IDC_IMPORT_SPECIFY_STORE:
5159 data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5160 data->autoDest = FALSE;
5161 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_STORE), TRUE);
5162 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_BROWSE_STORE), TRUE);
5163 break;
5164 case IDC_IMPORT_BROWSE_STORE:
5166 CRYPTUI_ENUM_SYSTEM_STORE_ARGS enumArgs = {
5167 CERT_SYSTEM_STORE_CURRENT_USER, NULL };
5168 CRYPTUI_ENUM_DATA enumData = { 0, NULL, 1, &enumArgs };
5169 CRYPTUI_SELECTSTORE_INFO_W selectInfo;
5170 HCERTSTORE store;
5172 data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5173 selectInfo.dwSize = sizeof(selectInfo);
5174 selectInfo.parent = hwnd;
5175 selectInfo.dwFlags = CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE;
5176 selectInfo.pwszTitle = NULL;
5177 selectInfo.pwszText = NULL;
5178 selectInfo.pEnumData = &enumData;
5179 selectInfo.pfnSelectedStoreCallback = NULL;
5180 if ((store = CryptUIDlgSelectStoreW(&selectInfo)))
5182 WCHAR storeTitle[MAX_STRING_LEN];
5184 LoadStringW(hInstance, IDS_IMPORT_DEST_DETERMINED, storeTitle,
5185 ARRAY_SIZE(storeTitle));
5186 SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_STORE), WM_SETTEXT,
5187 0, (LPARAM)storeTitle);
5188 data->hDestCertStore = store;
5189 data->freeDest = TRUE;
5191 break;
5194 break;
5196 return ret;
5199 static void show_import_details(HWND lv, struct ImportWizData *data)
5201 WCHAR text[MAX_STRING_LEN];
5202 LVITEMW item;
5203 int contentID;
5205 item.mask = LVIF_TEXT;
5206 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
5207 item.iSubItem = 0;
5208 LoadStringW(hInstance, IDS_IMPORT_STORE_SELECTION, text, ARRAY_SIZE(text));
5209 item.pszText = text;
5210 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
5211 item.iSubItem = 1;
5212 if (data->autoDest)
5213 LoadStringW(hInstance, IDS_IMPORT_DEST_AUTOMATIC, text, ARRAY_SIZE(text));
5214 else
5215 LoadStringW(hInstance, IDS_IMPORT_DEST_DETERMINED, text, ARRAY_SIZE(text));
5216 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
5217 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
5218 item.iSubItem = 0;
5219 LoadStringW(hInstance, IDS_IMPORT_CONTENT, text, ARRAY_SIZE(text));
5220 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
5221 switch (data->contentType)
5223 case CERT_QUERY_CONTENT_CERT:
5224 case CERT_QUERY_CONTENT_SERIALIZED_CERT:
5225 contentID = IDS_IMPORT_CONTENT_CERT;
5226 break;
5227 case CERT_QUERY_CONTENT_CRL:
5228 case CERT_QUERY_CONTENT_SERIALIZED_CRL:
5229 contentID = IDS_IMPORT_CONTENT_CRL;
5230 break;
5231 case CERT_QUERY_CONTENT_CTL:
5232 case CERT_QUERY_CONTENT_SERIALIZED_CTL:
5233 contentID = IDS_IMPORT_CONTENT_CTL;
5234 break;
5235 case CERT_QUERY_CONTENT_PKCS7_SIGNED:
5236 contentID = IDS_IMPORT_CONTENT_CMS;
5237 break;
5238 case CERT_QUERY_CONTENT_FLAG_PFX:
5239 contentID = IDS_IMPORT_CONTENT_PFX;
5240 break;
5241 default:
5242 contentID = IDS_IMPORT_CONTENT_STORE;
5243 break;
5245 LoadStringW(hInstance, contentID, text, ARRAY_SIZE(text));
5246 item.iSubItem = 1;
5247 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
5248 if (data->fileName)
5250 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
5251 item.iSubItem = 0;
5252 LoadStringW(hInstance, IDS_IMPORT_FILE, text, ARRAY_SIZE(text));
5253 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
5254 item.iSubItem = 1;
5255 item.pszText = data->fileName;
5256 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
5260 static BOOL do_import(DWORD dwFlags, HWND hwndParent, LPCWSTR pwszWizardTitle,
5261 PCCRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc, HCERTSTORE hDestCertStore)
5263 BOOL ret;
5265 switch (pImportSrc->dwSubjectChoice)
5267 case CRYPTUI_WIZ_IMPORT_SUBJECT_FILE:
5268 ret = import_file(dwFlags, hwndParent, pwszWizardTitle,
5269 pImportSrc->pwszFileName, hDestCertStore);
5270 break;
5271 case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_CONTEXT:
5272 if ((ret = check_context_type(dwFlags, CERT_QUERY_CONTENT_CERT)))
5273 ret = import_cert(pImportSrc->pCertContext, hDestCertStore);
5274 else
5275 import_warn_type_mismatch(dwFlags, hwndParent, pwszWizardTitle);
5276 break;
5277 case CRYPTUI_WIZ_IMPORT_SUBJECT_CRL_CONTEXT:
5278 if ((ret = check_context_type(dwFlags, CERT_QUERY_CONTENT_CRL)))
5279 ret = import_crl(pImportSrc->pCRLContext, hDestCertStore);
5280 else
5281 import_warn_type_mismatch(dwFlags, hwndParent, pwszWizardTitle);
5282 break;
5283 case CRYPTUI_WIZ_IMPORT_SUBJECT_CTL_CONTEXT:
5284 if ((ret = check_context_type(dwFlags, CERT_QUERY_CONTENT_CTL)))
5285 ret = import_ctl(pImportSrc->pCTLContext, hDestCertStore);
5286 else
5287 import_warn_type_mismatch(dwFlags, hwndParent, pwszWizardTitle);
5288 break;
5289 case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE:
5290 ret = import_store(dwFlags, hwndParent, pwszWizardTitle,
5291 pImportSrc->hCertStore, hDestCertStore);
5292 break;
5293 default:
5294 WARN("unknown source type: %lu\n", pImportSrc->dwSubjectChoice);
5295 SetLastError(E_INVALIDARG);
5296 ret = FALSE;
5298 return ret;
5301 static INT_PTR CALLBACK import_finish_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
5302 LPARAM lp)
5304 INT_PTR ret = 0;
5305 struct ImportWizData *data;
5307 switch (msg)
5309 case WM_INITDIALOG:
5311 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
5312 HWND lv = GetDlgItem(hwnd, IDC_IMPORT_SETTINGS);
5313 RECT rc;
5314 LVCOLUMNW column;
5316 data = (struct ImportWizData *)page->lParam;
5317 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
5318 SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_TITLE), WM_SETFONT,
5319 (WPARAM)data->titleFont, TRUE);
5320 GetWindowRect(lv, &rc);
5321 column.mask = LVCF_WIDTH;
5322 column.cx = (rc.right - rc.left) / 2 - 2;
5323 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
5324 SendMessageW(lv, LVM_INSERTCOLUMNW, 1, (LPARAM)&column);
5325 show_import_details(lv, data);
5326 break;
5328 case WM_NOTIFY:
5330 NMHDR *hdr = (NMHDR *)lp;
5332 switch (hdr->code)
5334 case PSN_SETACTIVE:
5336 HWND lv = GetDlgItem(hwnd, IDC_IMPORT_SETTINGS);
5338 data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5339 SendMessageW(lv, LVM_DELETEALLITEMS, 0, 0);
5340 show_import_details(lv, data);
5341 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
5342 PSWIZB_BACK | PSWIZB_FINISH);
5343 ret = TRUE;
5344 break;
5346 case PSN_WIZFINISH:
5348 data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5349 if ((data->success = do_import(data->dwFlags, hwnd,
5350 data->pwszWizardTitle, &data->importSrc, data->hDestCertStore)))
5352 WCHAR title[MAX_STRING_LEN], message[MAX_STRING_LEN];
5353 LPCWSTR pTitle;
5355 if (data->pwszWizardTitle)
5356 pTitle = data->pwszWizardTitle;
5357 else
5359 LoadStringW(hInstance, IDS_IMPORT_WIZARD, title, ARRAY_SIZE(title));
5360 pTitle = title;
5362 LoadStringW(hInstance, IDS_IMPORT_SUCCEEDED, message, ARRAY_SIZE(message));
5363 MessageBoxW(hwnd, message, pTitle, MB_OK);
5365 else
5366 import_warning(data->dwFlags, hwnd, data->pwszWizardTitle,
5367 IDS_IMPORT_FAILED);
5368 break;
5371 break;
5374 return ret;
5377 static BOOL show_import_ui(DWORD dwFlags, HWND hwndParent,
5378 LPCWSTR pwszWizardTitle, PCCRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc,
5379 HCERTSTORE hDestCertStore)
5381 PROPSHEETHEADERW hdr;
5382 PROPSHEETPAGEW pages[4];
5383 struct ImportWizData data;
5384 int nPages = 0;
5386 data.dwFlags = dwFlags;
5387 data.pwszWizardTitle = pwszWizardTitle;
5388 if (pImportSrc)
5390 memcpy(&data.importSrc, pImportSrc, sizeof(data.importSrc));
5391 data.fileName = (LPWSTR)pImportSrc->pwszFileName;
5393 else
5395 memset(&data.importSrc, 0, sizeof(data.importSrc));
5396 data.fileName = NULL;
5398 data.freeSource = FALSE;
5399 data.hDestCertStore = hDestCertStore;
5400 data.freeDest = FALSE;
5401 data.autoDest = TRUE;
5402 data.success = TRUE;
5404 memset(pages, 0, sizeof(pages));
5406 pages[nPages].dwSize = sizeof(pages[0]);
5407 pages[nPages].hInstance = hInstance;
5408 pages[nPages].pszTemplate = MAKEINTRESOURCEW(IDD_IMPORT_WELCOME);
5409 pages[nPages].pfnDlgProc = import_welcome_dlg_proc;
5410 pages[nPages].dwFlags = PSP_HIDEHEADER;
5411 pages[nPages].lParam = (LPARAM)&data;
5412 nPages++;
5414 if (!pImportSrc ||
5415 pImportSrc->dwSubjectChoice == CRYPTUI_WIZ_IMPORT_SUBJECT_FILE)
5417 pages[nPages].dwSize = sizeof(pages[0]);
5418 pages[nPages].hInstance = hInstance;
5419 pages[nPages].pszTemplate = MAKEINTRESOURCEW(IDD_IMPORT_FILE);
5420 pages[nPages].pfnDlgProc = import_file_dlg_proc;
5421 pages[nPages].dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
5422 pages[nPages].pszHeaderTitle = MAKEINTRESOURCEW(IDS_IMPORT_FILE_TITLE);
5423 pages[nPages].pszHeaderSubTitle =
5424 MAKEINTRESOURCEW(IDS_IMPORT_FILE_SUBTITLE);
5425 pages[nPages].lParam = (LPARAM)&data;
5426 nPages++;
5428 else
5430 switch (pImportSrc->dwSubjectChoice)
5432 case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_CONTEXT:
5433 data.contentType = CERT_QUERY_CONTENT_CERT;
5434 break;
5435 case CRYPTUI_WIZ_IMPORT_SUBJECT_CRL_CONTEXT:
5436 data.contentType = CERT_QUERY_CONTENT_CRL;
5437 break;
5438 case CRYPTUI_WIZ_IMPORT_SUBJECT_CTL_CONTEXT:
5439 data.contentType = CERT_QUERY_CONTENT_CTL;
5440 break;
5441 case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE:
5442 data.contentType = CERT_QUERY_CONTENT_SERIALIZED_STORE;
5443 break;
5447 pages[nPages].dwSize = sizeof(pages[0]);
5448 pages[nPages].hInstance = hInstance;
5449 pages[nPages].pszTemplate = MAKEINTRESOURCEW(IDD_IMPORT_STORE);
5450 pages[nPages].pfnDlgProc = import_store_dlg_proc;
5451 pages[nPages].dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
5452 pages[nPages].pszHeaderTitle = MAKEINTRESOURCEW(IDS_IMPORT_STORE_TITLE);
5453 pages[nPages].pszHeaderSubTitle =
5454 MAKEINTRESOURCEW(IDS_IMPORT_STORE_SUBTITLE);
5455 pages[nPages].lParam = (LPARAM)&data;
5456 nPages++;
5458 pages[nPages].dwSize = sizeof(pages[0]);
5459 pages[nPages].hInstance = hInstance;
5460 pages[nPages].pszTemplate = MAKEINTRESOURCEW(IDD_IMPORT_FINISH);
5461 pages[nPages].pfnDlgProc = import_finish_dlg_proc;
5462 pages[nPages].dwFlags = PSP_HIDEHEADER;
5463 pages[nPages].lParam = (LPARAM)&data;
5464 nPages++;
5466 memset(&hdr, 0, sizeof(hdr));
5467 hdr.dwSize = sizeof(hdr);
5468 hdr.hwndParent = hwndParent;
5469 hdr.dwFlags = PSH_PROPSHEETPAGE | PSH_WIZARD97_NEW | PSH_HEADER |
5470 PSH_WATERMARK;
5471 hdr.hInstance = hInstance;
5472 if (pwszWizardTitle)
5473 hdr.pszCaption = pwszWizardTitle;
5474 else
5475 hdr.pszCaption = MAKEINTRESOURCEW(IDS_IMPORT_WIZARD);
5476 hdr.ppsp = pages;
5477 hdr.nPages = nPages;
5478 hdr.pszbmWatermark = MAKEINTRESOURCEW(IDB_CERT_WATERMARK);
5479 hdr.pszbmHeader = MAKEINTRESOURCEW(IDB_CERT_HEADER);
5480 PropertySheetW(&hdr);
5481 if (data.fileName != data.importSrc.pwszFileName)
5482 free(data.fileName);
5483 if (data.freeSource &&
5484 data.importSrc.dwSubjectChoice == CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE)
5485 CertCloseStore(data.importSrc.hCertStore, 0);
5486 DeleteObject(data.titleFont);
5487 return data.success;
5490 BOOL WINAPI CryptUIWizImport(DWORD dwFlags, HWND hwndParent, LPCWSTR pwszWizardTitle,
5491 PCCRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc, HCERTSTORE hDestCertStore)
5493 BOOL ret;
5495 TRACE("(0x%08lx, %p, %s, %p, %p)\n", dwFlags, hwndParent, debugstr_w(pwszWizardTitle),
5496 pImportSrc, hDestCertStore);
5498 if (pImportSrc &&
5499 pImportSrc->dwSize != sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO))
5501 SetLastError(E_INVALIDARG);
5502 return FALSE;
5505 if (!(dwFlags & CRYPTUI_WIZ_NO_UI))
5506 ret = show_import_ui(dwFlags, hwndParent, pwszWizardTitle, pImportSrc,
5507 hDestCertStore);
5508 else if (pImportSrc)
5509 ret = do_import(dwFlags, hwndParent, pwszWizardTitle, pImportSrc,
5510 hDestCertStore);
5511 else
5513 /* Can't have no UI without specifying source */
5514 SetLastError(E_INVALIDARG);
5515 ret = FALSE;
5518 return ret;
5521 struct ExportWizData
5523 HFONT titleFont;
5524 DWORD dwFlags;
5525 LPCWSTR pwszWizardTitle;
5526 CRYPTUI_WIZ_EXPORT_INFO exportInfo;
5527 CRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO contextInfo;
5528 BOOL freePassword;
5529 PCRYPT_KEY_PROV_INFO keyProvInfo;
5530 BOOL deleteKeys;
5531 LPWSTR fileName;
5532 HANDLE file;
5533 BOOL success;
5536 static INT_PTR CALLBACK export_welcome_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
5537 LPARAM lp)
5539 INT_PTR ret = 0;
5541 switch (msg)
5543 case WM_INITDIALOG:
5545 struct ExportWizData *data;
5546 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
5547 WCHAR fontFace[MAX_STRING_LEN];
5548 HDC hDC = GetDC(hwnd);
5549 int height;
5551 data = (struct ExportWizData *)page->lParam;
5552 LoadStringW(hInstance, IDS_WIZARD_TITLE_FONT, fontFace, ARRAY_SIZE(fontFace));
5553 height = -MulDiv(12, GetDeviceCaps(hDC, LOGPIXELSY), 72);
5554 data->titleFont = CreateFontW(height, 0, 0, 0, FW_BOLD, 0, 0, 0,
5555 DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
5556 DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, fontFace);
5557 SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_TITLE), WM_SETFONT,
5558 (WPARAM)data->titleFont, TRUE);
5559 ReleaseDC(hwnd, hDC);
5560 break;
5562 case WM_NOTIFY:
5564 NMHDR *hdr = (NMHDR *)lp;
5566 switch (hdr->code)
5568 case PSN_SETACTIVE:
5569 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0, PSWIZB_NEXT);
5570 ret = TRUE;
5571 break;
5573 break;
5576 return ret;
5579 static PCRYPT_KEY_PROV_INFO export_get_private_key_info(PCCERT_CONTEXT cert)
5581 PCRYPT_KEY_PROV_INFO info = NULL;
5582 DWORD size;
5584 if (CertGetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID,
5585 NULL, &size))
5587 info = malloc(size);
5588 if (info)
5590 if (!CertGetCertificateContextProperty(cert,
5591 CERT_KEY_PROV_INFO_PROP_ID, info, &size))
5593 free(info);
5594 info = NULL;
5598 return info;
5601 static BOOL export_acquire_private_key(const CRYPT_KEY_PROV_INFO *info,
5602 HCRYPTPROV *phProv)
5604 BOOL ret;
5606 ret = CryptAcquireContextW(phProv, info->pwszContainerName,
5607 info->pwszProvName, info->dwProvType, 0);
5608 if (ret)
5610 DWORD i;
5612 for (i = 0; i < info->cProvParam; i++)
5613 CryptSetProvParam(*phProv, info->rgProvParam[i].dwParam,
5614 info->rgProvParam[i].pbData, info->rgProvParam[i].dwFlags);
5616 return ret;
5619 static BOOL export_is_key_exportable(HCRYPTPROV hProv, DWORD keySpec)
5621 BOOL ret;
5622 HCRYPTKEY key;
5624 if ((ret = CryptGetUserKey(hProv, keySpec, &key)))
5626 DWORD permissions, size = sizeof(permissions);
5628 if ((ret = CryptGetKeyParam(key, KP_PERMISSIONS, (BYTE *)&permissions,
5629 &size, 0)) && !(permissions & CRYPT_EXPORT))
5630 ret = FALSE;
5631 CryptDestroyKey(key);
5633 return ret;
5636 static INT_PTR CALLBACK export_private_key_dlg_proc(HWND hwnd, UINT msg,
5637 WPARAM wp, LPARAM lp)
5639 INT_PTR ret = 0;
5640 struct ExportWizData *data;
5642 switch (msg)
5644 case WM_INITDIALOG:
5646 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
5647 PCRYPT_KEY_PROV_INFO info;
5648 HCRYPTPROV hProv = 0;
5649 int errorID = 0;
5651 data = (struct ExportWizData *)page->lParam;
5652 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
5653 /* Get enough information about a key to see whether it's exportable.
5655 if (!(info = export_get_private_key_info(
5656 data->exportInfo.pCertContext)))
5657 errorID = IDS_EXPORT_PRIVATE_KEY_UNAVAILABLE;
5658 else if (!export_acquire_private_key(info, &hProv))
5659 errorID = IDS_EXPORT_PRIVATE_KEY_UNAVAILABLE;
5660 else if (!export_is_key_exportable(hProv, info->dwKeySpec))
5661 errorID = IDS_EXPORT_PRIVATE_KEY_NON_EXPORTABLE;
5663 if (errorID)
5665 WCHAR error[MAX_STRING_LEN];
5667 LoadStringW(hInstance, errorID, error, ARRAY_SIZE(error));
5668 SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_PRIVATE_KEY_UNAVAILABLE),
5669 WM_SETTEXT, 0, (LPARAM)error);
5670 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_PRIVATE_KEY_YES), FALSE);
5672 else
5673 data->keyProvInfo = info;
5674 if (hProv)
5675 CryptReleaseContext(hProv, 0);
5676 SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_PRIVATE_KEY_NO), BM_CLICK,
5677 0, 0);
5678 break;
5680 case WM_NOTIFY:
5682 NMHDR *hdr = (NMHDR *)lp;
5684 switch (hdr->code)
5686 case PSN_SETACTIVE:
5687 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
5688 PSWIZB_BACK | PSWIZB_NEXT);
5689 ret = TRUE;
5690 break;
5691 case PSN_WIZNEXT:
5692 data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5693 if (IsDlgButtonChecked(hwnd, IDC_EXPORT_PRIVATE_KEY_NO))
5695 data->contextInfo.dwExportFormat =
5696 CRYPTUI_WIZ_EXPORT_FORMAT_DER;
5697 data->contextInfo.fExportPrivateKeys = FALSE;
5699 else
5701 data->contextInfo.dwExportFormat =
5702 CRYPTUI_WIZ_EXPORT_FORMAT_PFX;
5703 data->contextInfo.fExportPrivateKeys = TRUE;
5705 break;
5707 break;
5710 return ret;
5713 static BOOL export_info_has_private_key(PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo)
5715 BOOL ret = FALSE;
5717 if (pExportInfo->dwSubjectChoice == CRYPTUI_WIZ_EXPORT_CERT_CONTEXT)
5719 DWORD size;
5721 /* If there's a CRYPT_KEY_PROV_INFO set for this cert, assume the
5722 * cert has a private key.
5724 if (CertGetCertificateContextProperty(pExportInfo->pCertContext,
5725 CERT_KEY_PROV_INFO_PROP_ID, NULL, &size))
5726 ret = TRUE;
5728 return ret;
5731 static void export_format_enable_controls(HWND hwnd, const struct ExportWizData *data)
5733 int defaultFormatID;
5735 switch (data->contextInfo.dwExportFormat)
5737 case CRYPTUI_WIZ_EXPORT_FORMAT_BASE64:
5738 defaultFormatID = IDC_EXPORT_FORMAT_BASE64;
5739 break;
5740 case CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7:
5741 defaultFormatID = IDC_EXPORT_FORMAT_CMS;
5742 break;
5743 case CRYPTUI_WIZ_EXPORT_FORMAT_PFX:
5744 defaultFormatID = IDC_EXPORT_FORMAT_PFX;
5745 break;
5746 default:
5747 defaultFormatID = IDC_EXPORT_FORMAT_DER;
5749 SendMessageW(GetDlgItem(hwnd, defaultFormatID), BM_CLICK, 0, 0);
5750 if (defaultFormatID == IDC_EXPORT_FORMAT_PFX)
5752 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_DER), FALSE);
5753 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_BASE64), FALSE);
5754 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_CMS), FALSE);
5755 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_PFX), TRUE);
5757 else
5759 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_DER), TRUE);
5760 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_BASE64), TRUE);
5761 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_CMS), TRUE);
5762 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_PFX), FALSE);
5766 static INT_PTR CALLBACK export_format_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
5767 LPARAM lp)
5769 INT_PTR ret = 0;
5770 struct ExportWizData *data;
5772 switch (msg)
5774 case WM_INITDIALOG:
5776 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
5778 data = (struct ExportWizData *)page->lParam;
5779 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
5780 export_format_enable_controls(hwnd, data);
5781 break;
5783 case WM_NOTIFY:
5785 NMHDR *hdr = (NMHDR *)lp;
5787 switch (hdr->code)
5789 case PSN_SETACTIVE:
5790 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
5791 PSWIZB_BACK | PSWIZB_NEXT);
5792 data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5793 export_format_enable_controls(hwnd, data);
5794 ret = TRUE;
5795 break;
5796 case PSN_WIZNEXT:
5798 BOOL skipPasswordPage = TRUE;
5800 data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5801 if (IsDlgButtonChecked(hwnd, IDC_EXPORT_FORMAT_DER))
5802 data->contextInfo.dwExportFormat =
5803 CRYPTUI_WIZ_EXPORT_FORMAT_DER;
5804 else if (IsDlgButtonChecked(hwnd, IDC_EXPORT_FORMAT_BASE64))
5805 data->contextInfo.dwExportFormat =
5806 CRYPTUI_WIZ_EXPORT_FORMAT_BASE64;
5807 else if (IsDlgButtonChecked(hwnd, IDC_EXPORT_FORMAT_CMS))
5809 data->contextInfo.dwExportFormat =
5810 CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7;
5811 if (IsDlgButtonChecked(hwnd, IDC_EXPORT_CMS_INCLUDE_CHAIN))
5812 data->contextInfo.fExportChain =
5813 CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7;
5815 else
5817 data->contextInfo.dwExportFormat =
5818 CRYPTUI_WIZ_EXPORT_FORMAT_PFX;
5819 if (IsDlgButtonChecked(hwnd, IDC_EXPORT_PFX_INCLUDE_CHAIN))
5820 data->contextInfo.fExportChain = TRUE;
5821 if (IsDlgButtonChecked(hwnd, IDC_EXPORT_PFX_STRONG_ENCRYPTION))
5822 data->contextInfo.fStrongEncryption = TRUE;
5823 if (IsDlgButtonChecked(hwnd, IDC_EXPORT_PFX_DELETE_PRIVATE_KEY))
5824 data->deleteKeys = TRUE;
5825 skipPasswordPage = FALSE;
5827 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT,
5828 skipPasswordPage ? IDD_EXPORT_FILE : 0);
5829 ret = 1;
5830 break;
5833 break;
5835 case WM_COMMAND:
5836 switch (HIWORD(wp))
5838 case BN_CLICKED:
5839 switch (LOWORD(wp))
5841 case IDC_EXPORT_FORMAT_DER:
5842 case IDC_EXPORT_FORMAT_BASE64:
5843 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_CMS_INCLUDE_CHAIN),
5844 FALSE);
5845 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_PFX_INCLUDE_CHAIN),
5846 FALSE);
5847 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_PFX_STRONG_ENCRYPTION),
5848 FALSE);
5849 EnableWindow(GetDlgItem(hwnd,
5850 IDC_EXPORT_PFX_DELETE_PRIVATE_KEY), FALSE);
5851 break;
5852 case IDC_EXPORT_FORMAT_CMS:
5853 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_CMS_INCLUDE_CHAIN),
5854 TRUE);
5855 break;
5856 case IDC_EXPORT_FORMAT_PFX:
5857 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_PFX_INCLUDE_CHAIN),
5858 TRUE);
5859 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_PFX_STRONG_ENCRYPTION),
5860 TRUE);
5861 EnableWindow(GetDlgItem(hwnd,
5862 IDC_EXPORT_PFX_DELETE_PRIVATE_KEY), TRUE);
5863 break;
5865 break;
5867 break;
5869 return ret;
5872 static void export_password_mismatch(HWND hwnd, const struct ExportWizData *data)
5874 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
5875 LPCWSTR pTitle;
5877 if (data->pwszWizardTitle)
5878 pTitle = data->pwszWizardTitle;
5879 else
5881 LoadStringW(hInstance, IDS_EXPORT_WIZARD, title, ARRAY_SIZE(title));
5882 pTitle = title;
5884 LoadStringW(hInstance, IDS_EXPORT_PASSWORD_MISMATCH, error, ARRAY_SIZE(error));
5885 MessageBoxW(hwnd, error, pTitle, MB_ICONERROR | MB_OK);
5886 SetFocus(GetDlgItem(hwnd, IDC_EXPORT_PASSWORD));
5889 static INT_PTR CALLBACK export_password_dlg_proc(HWND hwnd, UINT msg,
5890 WPARAM wp, LPARAM lp)
5892 INT_PTR ret = 0;
5893 struct ExportWizData *data;
5895 switch (msg)
5897 case WM_INITDIALOG:
5899 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
5901 data = (struct ExportWizData *)page->lParam;
5902 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
5903 break;
5905 case WM_NOTIFY:
5907 NMHDR *hdr = (NMHDR *)lp;
5909 switch (hdr->code)
5911 case PSN_SETACTIVE:
5912 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
5913 PSWIZB_BACK | PSWIZB_NEXT);
5914 ret = TRUE;
5915 break;
5916 case PSN_WIZNEXT:
5918 HWND passwordEdit = GetDlgItem(hwnd, IDC_EXPORT_PASSWORD);
5919 HWND passwordConfirmEdit = GetDlgItem(hwnd,
5920 IDC_EXPORT_PASSWORD_CONFIRM);
5921 DWORD passwordLen = SendMessageW(passwordEdit, WM_GETTEXTLENGTH,
5922 0, 0);
5923 DWORD passwordConfirmLen = SendMessageW(passwordConfirmEdit,
5924 WM_GETTEXTLENGTH, 0, 0);
5926 data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5927 if (!passwordLen && !passwordConfirmLen)
5928 data->contextInfo.pwszPassword = NULL;
5929 else if (passwordLen != passwordConfirmLen)
5931 export_password_mismatch(hwnd, data);
5932 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
5933 ret = 1;
5935 else
5937 WCHAR *password = malloc((passwordLen + 1) * sizeof(WCHAR));
5938 WCHAR *passwordConfirm = malloc((passwordConfirmLen + 1) * sizeof(WCHAR));
5939 BOOL freePassword = TRUE;
5941 if (password && passwordConfirm)
5943 SendMessageW(passwordEdit, WM_GETTEXT, passwordLen + 1,
5944 (LPARAM)password);
5945 SendMessageW(passwordConfirmEdit, WM_GETTEXT,
5946 passwordConfirmLen + 1, (LPARAM)passwordConfirm);
5947 if (lstrcmpW(password, passwordConfirm))
5949 export_password_mismatch(hwnd, data);
5950 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
5951 ret = 1;
5953 else
5955 data->contextInfo.pwszPassword = password;
5956 freePassword = FALSE;
5957 data->freePassword = TRUE;
5960 if (freePassword)
5961 free(password);
5962 free(passwordConfirm);
5964 break;
5967 break;
5970 return ret;
5973 static LPWSTR export_append_extension(const struct ExportWizData *data,
5974 LPWSTR fileName)
5976 static const WCHAR cer[] = { '.','c','e','r',0 };
5977 static const WCHAR crl[] = { '.','c','r','l',0 };
5978 static const WCHAR ctl[] = { '.','c','t','l',0 };
5979 static const WCHAR p7b[] = { '.','p','7','b',0 };
5980 static const WCHAR pfx[] = { '.','p','f','x',0 };
5981 static const WCHAR sst[] = { '.','s','s','t',0 };
5982 LPCWSTR extension;
5983 LPWSTR dot;
5984 BOOL appendExtension;
5986 switch (data->contextInfo.dwExportFormat)
5988 case CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7:
5989 extension = p7b;
5990 break;
5991 case CRYPTUI_WIZ_EXPORT_FORMAT_PFX:
5992 extension = pfx;
5993 break;
5994 default:
5995 switch (data->exportInfo.dwSubjectChoice)
5997 case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
5998 extension = crl;
5999 break;
6000 case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT:
6001 extension = ctl;
6002 break;
6003 case CRYPTUI_WIZ_EXPORT_CERT_STORE:
6004 extension = sst;
6005 break;
6006 default:
6007 extension = cer;
6010 dot = wcsrchr(fileName, '.');
6011 if (dot)
6012 appendExtension = wcsicmp(dot, extension) != 0;
6013 else
6014 appendExtension = TRUE;
6015 if (appendExtension)
6017 fileName = realloc(fileName, (wcslen(fileName) + wcslen(extension) + 1) * sizeof(WCHAR));
6018 if (fileName)
6019 lstrcatW(fileName, extension);
6021 return fileName;
6024 static BOOL export_validate_filename(HWND hwnd, struct ExportWizData *data,
6025 LPCWSTR fileName)
6027 HANDLE file;
6028 BOOL tryCreate = TRUE, forceCreate = FALSE, ret = FALSE;
6030 file = CreateFileW(fileName, GENERIC_WRITE,
6031 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
6032 if (file != INVALID_HANDLE_VALUE)
6034 WCHAR warning[MAX_STRING_LEN], title[MAX_STRING_LEN];
6035 LPCWSTR pTitle;
6037 if (data->pwszWizardTitle)
6038 pTitle = data->pwszWizardTitle;
6039 else
6041 LoadStringW(hInstance, IDS_EXPORT_WIZARD, title, ARRAY_SIZE(title));
6042 pTitle = title;
6044 LoadStringW(hInstance, IDS_EXPORT_FILE_EXISTS, warning, ARRAY_SIZE(warning));
6045 if (MessageBoxW(hwnd, warning, pTitle, MB_YESNO) == IDYES)
6046 forceCreate = TRUE;
6047 else
6048 tryCreate = FALSE;
6049 CloseHandle(file);
6051 if (tryCreate)
6053 file = CreateFileW(fileName, GENERIC_WRITE,
6054 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
6055 forceCreate ? CREATE_ALWAYS : CREATE_NEW,
6056 0, NULL);
6057 if (file != INVALID_HANDLE_VALUE)
6059 data->file = file;
6060 ret = TRUE;
6062 else
6064 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
6065 LPCWSTR pTitle;
6066 LPWSTR msgBuf, fullError;
6068 if (data->pwszWizardTitle)
6069 pTitle = data->pwszWizardTitle;
6070 else
6072 LoadStringW(hInstance, IDS_EXPORT_WIZARD, title, ARRAY_SIZE(title));
6073 pTitle = title;
6075 LoadStringW(hInstance, IDS_IMPORT_OPEN_FAILED, error, ARRAY_SIZE(error));
6076 FormatMessageW(
6077 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
6078 GetLastError(), 0, (LPWSTR) &msgBuf, 0, NULL);
6079 fullError = malloc((wcslen(error) + wcslen(fileName) + wcslen(msgBuf) + 3) * sizeof(WCHAR));
6080 if (fullError)
6082 LPWSTR ptr = fullError;
6084 lstrcpyW(ptr, error);
6085 ptr += lstrlenW(error);
6086 lstrcpyW(ptr, fileName);
6087 ptr += lstrlenW(fileName);
6088 *ptr++ = ':';
6089 *ptr++ = '\n';
6090 lstrcpyW(ptr, msgBuf);
6091 MessageBoxW(hwnd, fullError, pTitle, MB_ICONERROR | MB_OK);
6092 free(fullError);
6094 LocalFree(msgBuf);
6097 return ret;
6100 static const WCHAR export_filter_cert[] = { '*','.','c','e','r',0 };
6101 static const WCHAR export_filter_crl[] = { '*','.','c','r','l',0 };
6102 static const WCHAR export_filter_ctl[] = { '*','.','s','t','l',0 };
6103 static const WCHAR export_filter_cms[] = { '*','.','p','7','b',0 };
6104 static const WCHAR export_filter_pfx[] = { '*','.','p','f','x',0 };
6105 static const WCHAR export_filter_sst[] = { '*','.','s','s','t',0 };
6107 static WCHAR *make_export_file_filter(DWORD exportFormat, DWORD subjectChoice)
6109 int baseLen, allLen, totalLen = 2, baseID;
6110 LPWSTR filter = NULL, baseFilter, all;
6111 LPCWSTR filterStr;
6113 switch (exportFormat)
6115 case CRYPTUI_WIZ_EXPORT_FORMAT_BASE64:
6116 baseID = IDS_EXPORT_FILTER_BASE64_CERT;
6117 filterStr = export_filter_cert;
6118 break;
6119 case CRYPTUI_WIZ_EXPORT_FORMAT_PFX:
6120 baseID = IDS_EXPORT_FILTER_PFX;
6121 filterStr = export_filter_pfx;
6122 break;
6123 case CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7:
6124 baseID = IDS_EXPORT_FILTER_CMS;
6125 filterStr = export_filter_cms;
6126 break;
6127 default:
6128 switch (subjectChoice)
6130 case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
6131 baseID = IDS_EXPORT_FILTER_CRL;
6132 filterStr = export_filter_crl;
6133 break;
6134 case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT:
6135 baseID = IDS_EXPORT_FILTER_CTL;
6136 filterStr = export_filter_ctl;
6137 break;
6138 case CRYPTUI_WIZ_EXPORT_CERT_STORE:
6139 baseID = IDS_EXPORT_FILTER_SERIALIZED_CERT_STORE;
6140 filterStr = export_filter_sst;
6141 break;
6142 default:
6143 baseID = IDS_EXPORT_FILTER_CERT;
6144 filterStr = export_filter_cert;
6145 break;
6148 baseLen = LoadStringW(hInstance, baseID, (LPWSTR)&baseFilter, 0);
6149 totalLen += baseLen + lstrlenW(filterStr) + 2;
6150 allLen = LoadStringW(hInstance, IDS_IMPORT_FILTER_ALL, (LPWSTR)&all, 0);
6151 totalLen += allLen + lstrlenW(filter_all) + 2;
6152 filter = malloc(totalLen * sizeof(WCHAR));
6153 if (filter)
6155 LPWSTR ptr;
6157 ptr = filter;
6158 memcpy(ptr, baseFilter, baseLen * sizeof(WCHAR));
6159 ptr += baseLen;
6160 *ptr++ = 0;
6161 lstrcpyW(ptr, filterStr);
6162 ptr += lstrlenW(filterStr) + 1;
6163 memcpy(ptr, all, allLen * sizeof(WCHAR));
6164 ptr += allLen;
6165 *ptr++ = 0;
6166 lstrcpyW(ptr, filter_all);
6167 ptr += lstrlenW(filter_all) + 1;
6168 *ptr++ = 0;
6170 return filter;
6173 static INT_PTR CALLBACK export_file_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
6174 LPARAM lp)
6176 INT_PTR ret = 0;
6177 struct ExportWizData *data;
6179 switch (msg)
6181 case WM_INITDIALOG:
6183 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
6185 data = (struct ExportWizData *)page->lParam;
6186 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
6187 if (data->exportInfo.pwszExportFileName)
6188 SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_FILENAME), WM_SETTEXT, 0,
6189 (LPARAM)data->exportInfo.pwszExportFileName);
6190 break;
6192 case WM_NOTIFY:
6194 NMHDR *hdr = (NMHDR *)lp;
6196 switch (hdr->code)
6198 case PSN_WIZBACK:
6199 data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
6200 if (data->contextInfo.dwExportFormat !=
6201 CRYPTUI_WIZ_EXPORT_FORMAT_PFX)
6203 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, IDD_EXPORT_FORMAT);
6204 ret = 1;
6206 break;
6207 case PSN_WIZNEXT:
6209 HWND fileNameEdit = GetDlgItem(hwnd, IDC_EXPORT_FILENAME);
6210 DWORD len = SendMessageW(fileNameEdit, WM_GETTEXTLENGTH, 0, 0);
6212 data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
6213 if (!len)
6215 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
6216 LPCWSTR pTitle;
6218 if (data->pwszWizardTitle)
6219 pTitle = data->pwszWizardTitle;
6220 else
6222 LoadStringW(hInstance, IDS_EXPORT_WIZARD, title, ARRAY_SIZE(title));
6223 pTitle = title;
6225 LoadStringW(hInstance, IDS_IMPORT_EMPTY_FILE, error, ARRAY_SIZE(error));
6226 MessageBoxW(hwnd, error, pTitle, MB_ICONERROR | MB_OK);
6227 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
6228 ret = 1;
6230 else
6232 WCHAR *fileName = malloc((len + 1) * sizeof(WCHAR));
6234 if (fileName)
6236 SendMessageW(fileNameEdit, WM_GETTEXT, len + 1,
6237 (LPARAM)fileName);
6238 fileName = export_append_extension(data, fileName);
6239 if (!export_validate_filename(hwnd, data, fileName))
6241 free(fileName);
6242 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
6243 ret = 1;
6245 else
6246 data->fileName = fileName;
6249 break;
6251 case PSN_SETACTIVE:
6252 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
6253 PSWIZB_BACK | PSWIZB_NEXT);
6254 ret = TRUE;
6255 break;
6257 break;
6259 case WM_COMMAND:
6260 switch (wp)
6262 case IDC_EXPORT_BROWSE_FILE:
6264 OPENFILENAMEW ofn;
6265 WCHAR fileBuf[MAX_PATH];
6267 data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
6268 memset(&ofn, 0, sizeof(ofn));
6269 ofn.lStructSize = sizeof(ofn);
6270 ofn.hwndOwner = hwnd;
6271 ofn.lpstrFilter = make_export_file_filter(
6272 data->contextInfo.dwExportFormat,
6273 data->exportInfo.dwSubjectChoice);
6274 ofn.lpstrFile = fileBuf;
6275 ofn.nMaxFile = ARRAY_SIZE(fileBuf);
6276 fileBuf[0] = 0;
6277 if (GetSaveFileNameW(&ofn))
6278 SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_FILENAME), WM_SETTEXT,
6279 0, (LPARAM)ofn.lpstrFile);
6280 free((WCHAR *)ofn.lpstrFilter);
6281 break;
6284 break;
6286 return ret;
6289 static void show_export_details(HWND lv, const struct ExportWizData *data)
6291 WCHAR text[MAX_STRING_LEN];
6292 LVITEMW item;
6293 int contentID;
6295 item.mask = LVIF_TEXT;
6296 if (data->fileName)
6298 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
6299 item.iSubItem = 0;
6300 LoadStringW(hInstance, IDS_IMPORT_FILE, text, ARRAY_SIZE(text));
6301 item.pszText = text;
6302 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
6303 item.iSubItem = 1;
6304 item.pszText = data->fileName;
6305 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
6308 item.pszText = text;
6309 switch (data->exportInfo.dwSubjectChoice)
6311 case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
6312 case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT:
6313 case CRYPTUI_WIZ_EXPORT_CERT_STORE:
6314 case CRYPTUI_WIZ_EXPORT_CERT_STORE_CERTIFICATES_ONLY:
6315 /* do nothing */
6316 break;
6317 default:
6319 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
6320 item.iSubItem = 0;
6321 LoadStringW(hInstance, IDS_EXPORT_INCLUDE_CHAIN, text, ARRAY_SIZE(text));
6322 SendMessageW(lv, LVM_INSERTITEMW, item.iItem, (LPARAM)&item);
6323 item.iSubItem = 1;
6324 LoadStringW(hInstance, data->contextInfo.fExportChain ? IDS_YES : IDS_NO, text,
6325 ARRAY_SIZE(text));
6326 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
6328 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
6329 item.iSubItem = 0;
6330 LoadStringW(hInstance, IDS_EXPORT_KEYS, text, ARRAY_SIZE(text));
6331 SendMessageW(lv, LVM_INSERTITEMW, item.iItem, (LPARAM)&item);
6332 item.iSubItem = 1;
6333 LoadStringW(hInstance, data->contextInfo.fExportPrivateKeys ? IDS_YES : IDS_NO, text,
6334 ARRAY_SIZE(text));
6335 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
6339 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
6340 item.iSubItem = 0;
6341 LoadStringW(hInstance, IDS_EXPORT_FORMAT, text, ARRAY_SIZE(text));
6342 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
6344 item.iSubItem = 1;
6345 switch (data->exportInfo.dwSubjectChoice)
6347 case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
6348 contentID = IDS_EXPORT_FILTER_CRL;
6349 break;
6350 case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT:
6351 contentID = IDS_EXPORT_FILTER_CTL;
6352 break;
6353 case CRYPTUI_WIZ_EXPORT_CERT_STORE:
6354 contentID = IDS_EXPORT_FILTER_SERIALIZED_CERT_STORE;
6355 break;
6356 default:
6357 switch (data->contextInfo.dwExportFormat)
6359 case CRYPTUI_WIZ_EXPORT_FORMAT_BASE64:
6360 contentID = IDS_EXPORT_FILTER_BASE64_CERT;
6361 break;
6362 case CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7:
6363 contentID = IDS_EXPORT_FILTER_CMS;
6364 break;
6365 case CRYPTUI_WIZ_EXPORT_FORMAT_PFX:
6366 contentID = IDS_EXPORT_FILTER_PFX;
6367 break;
6368 default:
6369 contentID = IDS_EXPORT_FILTER_CERT;
6372 LoadStringW(hInstance, contentID, text, ARRAY_SIZE(text));
6373 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
6376 static inline BOOL save_der(HANDLE file, const BYTE *pb, DWORD cb)
6378 DWORD bytesWritten;
6380 return WriteFile(file, pb, cb, &bytesWritten, NULL);
6383 static BOOL save_base64(HANDLE file, const BYTE *pb, DWORD cb)
6385 BOOL ret;
6386 DWORD size = 0;
6388 if ((ret = CryptBinaryToStringA(pb, cb, CRYPT_STRING_BASE64, NULL, &size)))
6390 char *buf = malloc(size);
6392 if (buf)
6394 if ((ret = CryptBinaryToStringA(pb, cb, CRYPT_STRING_BASE64, buf,
6395 &size)))
6396 ret = WriteFile(file, buf, size, &size, NULL);
6397 free(buf);
6399 else
6401 SetLastError(ERROR_OUTOFMEMORY);
6402 ret = FALSE;
6405 return ret;
6408 static inline BOOL save_store_as_cms(HANDLE file, HCERTSTORE store)
6410 return CertSaveStore(store, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
6411 CERT_STORE_SAVE_AS_PKCS7, CERT_STORE_SAVE_TO_FILE, file, 0);
6414 static BOOL save_cert_as_cms(HANDLE file, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo,
6415 BOOL includeChain)
6417 BOOL ret;
6418 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
6419 CERT_STORE_CREATE_NEW_FLAG, NULL);
6421 if (store)
6423 if (includeChain)
6425 HCERTSTORE addlStore = CertOpenStore(CERT_STORE_PROV_COLLECTION,
6426 0, 0, CERT_STORE_CREATE_NEW_FLAG, NULL);
6428 if (addlStore)
6430 DWORD i;
6432 ret = TRUE;
6433 for (i = 0; ret && i < pExportInfo->cStores; i++)
6434 ret = CertAddStoreToCollection(addlStore,
6435 pExportInfo->rghStores, 0, 0);
6436 if (ret)
6438 PCCERT_CHAIN_CONTEXT chain;
6440 ret = CertGetCertificateChain(NULL,
6441 pExportInfo->pCertContext, NULL, addlStore, NULL, 0,
6442 NULL, &chain);
6443 if (ret)
6445 DWORD j;
6447 for (i = 0; ret && i < chain->cChain; i++)
6448 for (j = 0; ret && j < chain->rgpChain[i]->cElement;
6449 j++)
6450 ret = CertAddCertificateContextToStore(store,
6451 chain->rgpChain[i]->rgpElement[j]->pCertContext,
6452 CERT_STORE_ADD_ALWAYS, NULL);
6453 CertFreeCertificateChain(chain);
6455 else
6457 /* No chain could be created, just add the individual
6458 * cert to the message.
6460 ret = CertAddCertificateContextToStore(store,
6461 pExportInfo->pCertContext, CERT_STORE_ADD_ALWAYS,
6462 NULL);
6465 CertCloseStore(addlStore, 0);
6467 else
6468 ret = FALSE;
6470 else
6471 ret = CertAddCertificateContextToStore(store,
6472 pExportInfo->pCertContext, CERT_STORE_ADD_ALWAYS, NULL);
6473 if (ret)
6474 ret = save_store_as_cms(file, store);
6475 CertCloseStore(store, 0);
6477 else
6478 ret = FALSE;
6479 return ret;
6482 static BOOL save_serialized_store(HANDLE file, HCERTSTORE store)
6484 return CertSaveStore(store, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
6485 CERT_STORE_SAVE_AS_STORE, CERT_STORE_SAVE_TO_FILE, file, 0);
6488 static BOOL save_pfx(HANDLE file, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo,
6489 PCCRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO pContextInfo,
6490 PCRYPT_KEY_PROV_INFO keyProvInfo, BOOL deleteKeys)
6492 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING,
6493 0, CERT_STORE_CREATE_NEW_FLAG, NULL);
6494 BOOL ret = FALSE;
6496 if (store)
6498 CRYPT_DATA_BLOB pfxBlob = { 0, NULL };
6499 PCCERT_CONTEXT cert = NULL;
6500 BOOL freeKeyProvInfo = FALSE;
6502 if (pContextInfo->fExportChain)
6504 HCERTCHAINENGINE engine = NULL;
6506 if (pExportInfo->cStores)
6508 CERT_CHAIN_ENGINE_CONFIG config;
6510 memset(&config, 0, sizeof(config));
6511 config.cbSize = sizeof(config);
6512 config.cAdditionalStore = pExportInfo->cStores;
6513 config.rghAdditionalStore = pExportInfo->rghStores;
6514 ret = CertCreateCertificateChainEngine(&config, &engine);
6516 else
6517 ret = TRUE;
6518 if (ret)
6520 CERT_CHAIN_PARA chainPara;
6521 PCCERT_CHAIN_CONTEXT chain;
6523 memset(&chainPara, 0, sizeof(chainPara));
6524 chainPara.cbSize = sizeof(chainPara);
6525 ret = CertGetCertificateChain(engine,
6526 pExportInfo->pCertContext, NULL, NULL, &chainPara, 0, NULL,
6527 &chain);
6528 if (ret)
6530 DWORD i, j;
6532 for (i = 0; ret && i < chain->cChain; i++)
6533 for (j = 0; ret && j < chain->rgpChain[i]->cElement;
6534 j++)
6536 if (i == 0 && j == 0)
6537 ret = CertAddCertificateContextToStore(store,
6538 chain->rgpChain[i]->rgpElement[j]->pCertContext,
6539 CERT_STORE_ADD_ALWAYS, &cert);
6540 else
6541 ret = CertAddCertificateContextToStore(store,
6542 chain->rgpChain[i]->rgpElement[j]->pCertContext,
6543 CERT_STORE_ADD_ALWAYS, NULL);
6545 CertFreeCertificateChain(chain);
6548 if (engine)
6549 CertFreeCertificateChainEngine(engine);
6551 else
6552 ret = CertAddCertificateContextToStore(store,
6553 pExportInfo->pCertContext, CERT_STORE_ADD_ALWAYS, &cert);
6554 /* Copy private key info to newly created cert, so it'll get exported
6555 * along with the cert.
6557 if (ret && pContextInfo->fExportPrivateKeys)
6559 if (keyProvInfo)
6560 ret = CertSetCertificateContextProperty(cert,
6561 CERT_KEY_PROV_INFO_PROP_ID, 0, keyProvInfo);
6562 else
6564 if (!(keyProvInfo = export_get_private_key_info(cert)))
6565 ret = FALSE;
6566 else
6568 ret = CertSetCertificateContextProperty(cert,
6569 CERT_KEY_PROV_INFO_PROP_ID, 0, keyProvInfo);
6570 freeKeyProvInfo = TRUE;
6574 if (ret)
6576 DWORD exportFlags =
6577 REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY | EXPORT_PRIVATE_KEYS;
6579 ret = PFXExportCertStore(store, &pfxBlob,
6580 pContextInfo->pwszPassword, exportFlags);
6581 if (ret)
6583 pfxBlob.pbData = malloc(pfxBlob.cbData);
6584 if (pfxBlob.pbData)
6586 ret = PFXExportCertStore(store, &pfxBlob,
6587 pContextInfo->pwszPassword, exportFlags);
6588 if (ret)
6590 DWORD bytesWritten;
6592 ret = WriteFile(file, pfxBlob.pbData, pfxBlob.cbData,
6593 &bytesWritten, NULL);
6596 else
6598 SetLastError(ERROR_OUTOFMEMORY);
6599 ret = FALSE;
6603 if (ret && deleteKeys)
6605 HCRYPTPROV prov;
6607 CryptAcquireContextW(&prov, keyProvInfo->pwszContainerName,
6608 keyProvInfo->pwszProvName, keyProvInfo->dwProvType,
6609 CRYPT_DELETEKEYSET);
6611 if (freeKeyProvInfo)
6612 free(keyProvInfo);
6613 CertFreeCertificateContext(cert);
6614 CertCloseStore(store, 0);
6616 return ret;
6619 static BOOL do_export(HANDLE file, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo,
6620 PCCRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO pContextInfo,
6621 PCRYPT_KEY_PROV_INFO keyProvInfo, BOOL deleteKeys)
6623 BOOL ret;
6625 if (pContextInfo->dwSize != sizeof(CRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO))
6627 SetLastError(E_INVALIDARG);
6628 return FALSE;
6630 switch (pExportInfo->dwSubjectChoice)
6632 case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
6633 ret = save_der(file,
6634 pExportInfo->pCRLContext->pbCrlEncoded,
6635 pExportInfo->pCRLContext->cbCrlEncoded);
6636 break;
6637 case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT:
6638 ret = save_der(file,
6639 pExportInfo->pCTLContext->pbCtlEncoded,
6640 pExportInfo->pCTLContext->cbCtlEncoded);
6641 break;
6642 case CRYPTUI_WIZ_EXPORT_CERT_STORE:
6643 ret = save_serialized_store(file, pExportInfo->hCertStore);
6644 break;
6645 case CRYPTUI_WIZ_EXPORT_CERT_STORE_CERTIFICATES_ONLY:
6646 ret = save_store_as_cms(file, pExportInfo->hCertStore);
6647 break;
6648 default:
6649 switch (pContextInfo->dwExportFormat)
6651 case CRYPTUI_WIZ_EXPORT_FORMAT_DER:
6652 ret = save_der(file, pExportInfo->pCertContext->pbCertEncoded,
6653 pExportInfo->pCertContext->cbCertEncoded);
6654 break;
6655 case CRYPTUI_WIZ_EXPORT_FORMAT_BASE64:
6656 ret = save_base64(file,
6657 pExportInfo->pCertContext->pbCertEncoded,
6658 pExportInfo->pCertContext->cbCertEncoded);
6659 break;
6660 case CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7:
6661 ret = save_cert_as_cms(file, pExportInfo,
6662 pContextInfo->fExportChain);
6663 break;
6664 case CRYPTUI_WIZ_EXPORT_FORMAT_PFX:
6665 ret = save_pfx(file, pExportInfo, pContextInfo, keyProvInfo,
6666 deleteKeys);
6667 break;
6668 default:
6669 SetLastError(E_FAIL);
6670 ret = FALSE;
6673 return ret;
6676 static INT_PTR CALLBACK export_finish_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
6677 LPARAM lp)
6679 INT_PTR ret = 0;
6680 struct ExportWizData *data;
6682 switch (msg)
6684 case WM_INITDIALOG:
6686 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
6687 HWND lv = GetDlgItem(hwnd, IDC_EXPORT_SETTINGS);
6688 RECT rc;
6689 LVCOLUMNW column;
6691 data = (struct ExportWizData *)page->lParam;
6692 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
6693 SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_TITLE), WM_SETFONT,
6694 (WPARAM)data->titleFont, TRUE);
6695 GetWindowRect(lv, &rc);
6696 column.mask = LVCF_WIDTH;
6697 column.cx = (rc.right - rc.left) / 2 - 2;
6698 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
6699 SendMessageW(lv, LVM_INSERTCOLUMNW, 1, (LPARAM)&column);
6700 show_export_details(lv, data);
6701 break;
6703 case WM_NOTIFY:
6705 NMHDR *hdr = (NMHDR *)lp;
6707 switch (hdr->code)
6709 case PSN_SETACTIVE:
6711 HWND lv = GetDlgItem(hwnd, IDC_EXPORT_SETTINGS);
6713 data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
6714 SendMessageW(lv, LVM_DELETEALLITEMS, 0, 0);
6715 show_export_details(lv, data);
6716 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
6717 PSWIZB_BACK | PSWIZB_FINISH);
6718 ret = TRUE;
6719 break;
6721 case PSN_WIZFINISH:
6723 int messageID;
6724 WCHAR title[MAX_STRING_LEN], message[MAX_STRING_LEN];
6725 LPCWSTR pTitle;
6726 DWORD mbFlags;
6728 data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
6729 if ((data->success = do_export(data->file, &data->exportInfo,
6730 &data->contextInfo, data->keyProvInfo, data->deleteKeys)))
6732 messageID = IDS_EXPORT_SUCCEEDED;
6733 mbFlags = MB_OK;
6735 else
6737 messageID = IDS_EXPORT_FAILED;
6738 mbFlags = MB_OK | MB_ICONERROR;
6740 if (data->pwszWizardTitle)
6741 pTitle = data->pwszWizardTitle;
6742 else
6744 LoadStringW(hInstance, IDS_EXPORT_WIZARD, title, ARRAY_SIZE(title));
6745 pTitle = title;
6747 LoadStringW(hInstance, messageID, message, ARRAY_SIZE(message));
6748 MessageBoxW(hwnd, message, pTitle, mbFlags);
6749 break;
6752 break;
6755 return ret;
6758 static BOOL show_export_ui(DWORD dwFlags, HWND hwndParent,
6759 LPCWSTR pwszWizardTitle, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo, const void *pvoid)
6761 PROPSHEETHEADERW hdr;
6762 PROPSHEETPAGEW pages[6];
6763 struct ExportWizData data;
6764 int nPages = 0;
6765 BOOL hasPrivateKey, showFormatPage = TRUE;
6766 INT_PTR l;
6768 data.dwFlags = dwFlags;
6769 data.pwszWizardTitle = pwszWizardTitle;
6770 memset(&data.exportInfo, 0, sizeof(data.exportInfo));
6771 memcpy(&data.exportInfo, pExportInfo,
6772 min(sizeof(data.exportInfo), pExportInfo->dwSize));
6773 if (pExportInfo->dwSize > sizeof(data.exportInfo))
6774 data.exportInfo.dwSize = sizeof(data.exportInfo);
6775 data.contextInfo.dwSize = sizeof(data.contextInfo);
6776 data.contextInfo.dwExportFormat = CRYPTUI_WIZ_EXPORT_FORMAT_DER;
6777 data.contextInfo.fExportChain = FALSE;
6778 data.contextInfo.fStrongEncryption = FALSE;
6779 data.contextInfo.fExportPrivateKeys = FALSE;
6780 data.contextInfo.pwszPassword = NULL;
6781 data.freePassword = FALSE;
6782 if (pExportInfo->dwSubjectChoice == CRYPTUI_WIZ_EXPORT_CERT_CONTEXT &&
6783 pvoid)
6784 memcpy(&data.contextInfo, pvoid,
6785 min(((PCCRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO)pvoid)->dwSize,
6786 sizeof(data.contextInfo)));
6787 data.keyProvInfo = NULL;
6788 data.deleteKeys = FALSE;
6789 data.fileName = NULL;
6790 data.file = INVALID_HANDLE_VALUE;
6791 data.success = FALSE;
6793 memset(pages, 0, sizeof(pages));
6795 pages[nPages].dwSize = sizeof(pages[0]);
6796 pages[nPages].hInstance = hInstance;
6797 pages[nPages].pszTemplate = MAKEINTRESOURCEW(IDD_EXPORT_WELCOME);
6798 pages[nPages].pfnDlgProc = export_welcome_dlg_proc;
6799 pages[nPages].dwFlags = PSP_HIDEHEADER;
6800 pages[nPages].lParam = (LPARAM)&data;
6801 nPages++;
6803 hasPrivateKey = export_info_has_private_key(pExportInfo);
6804 switch (pExportInfo->dwSubjectChoice)
6806 case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
6807 case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT:
6808 showFormatPage = FALSE;
6809 data.contextInfo.dwExportFormat = CRYPTUI_WIZ_EXPORT_FORMAT_DER;
6810 break;
6811 case CRYPTUI_WIZ_EXPORT_CERT_STORE:
6812 showFormatPage = FALSE;
6813 data.contextInfo.dwExportFormat =
6814 CRYPTUI_WIZ_EXPORT_FORMAT_SERIALIZED_CERT_STORE;
6815 break;
6816 case CRYPTUI_WIZ_EXPORT_CERT_STORE_CERTIFICATES_ONLY:
6817 showFormatPage = FALSE;
6818 data.contextInfo.dwExportFormat = CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7;
6819 break;
6822 if (hasPrivateKey && showFormatPage)
6824 pages[nPages].dwSize = sizeof(pages[0]);
6825 pages[nPages].hInstance = hInstance;
6826 pages[nPages].pszTemplate = MAKEINTRESOURCEW(IDD_EXPORT_PRIVATE_KEY);
6827 pages[nPages].pfnDlgProc = export_private_key_dlg_proc;
6828 pages[nPages].dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
6829 pages[nPages].pszHeaderTitle =
6830 MAKEINTRESOURCEW(IDS_EXPORT_PRIVATE_KEY_TITLE);
6831 pages[nPages].pszHeaderSubTitle =
6832 MAKEINTRESOURCEW(IDS_EXPORT_PRIVATE_KEY_SUBTITLE);
6833 pages[nPages].lParam = (LPARAM)&data;
6834 nPages++;
6836 if (showFormatPage)
6838 pages[nPages].dwSize = sizeof(pages[0]);
6839 pages[nPages].hInstance = hInstance;
6840 pages[nPages].pszTemplate = MAKEINTRESOURCEW(IDD_EXPORT_FORMAT);
6841 pages[nPages].pfnDlgProc = export_format_dlg_proc;
6842 pages[nPages].dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
6843 pages[nPages].pszHeaderTitle =
6844 MAKEINTRESOURCEW(IDS_EXPORT_FORMAT_TITLE);
6845 pages[nPages].pszHeaderSubTitle =
6846 MAKEINTRESOURCEW(IDS_EXPORT_FORMAT_SUBTITLE);
6847 pages[nPages].lParam = (LPARAM)&data;
6848 nPages++;
6850 if (hasPrivateKey && showFormatPage)
6852 pages[nPages].dwSize = sizeof(pages[0]);
6853 pages[nPages].hInstance = hInstance;
6854 pages[nPages].pszTemplate = MAKEINTRESOURCEW(IDD_EXPORT_PASSWORD);
6855 pages[nPages].pfnDlgProc = export_password_dlg_proc;
6856 pages[nPages].dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
6857 pages[nPages].pszHeaderTitle =
6858 MAKEINTRESOURCEW(IDS_EXPORT_PASSWORD_TITLE);
6859 pages[nPages].pszHeaderSubTitle =
6860 MAKEINTRESOURCEW(IDS_EXPORT_PASSWORD_SUBTITLE);
6861 pages[nPages].lParam = (LPARAM)&data;
6862 nPages++;
6865 pages[nPages].dwSize = sizeof(pages[0]);
6866 pages[nPages].hInstance = hInstance;
6867 pages[nPages].pszTemplate = MAKEINTRESOURCEW(IDD_EXPORT_FILE);
6868 pages[nPages].pfnDlgProc = export_file_dlg_proc;
6869 pages[nPages].dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
6870 pages[nPages].pszHeaderTitle = MAKEINTRESOURCEW(IDS_EXPORT_FILE_TITLE);
6871 pages[nPages].pszHeaderSubTitle =
6872 MAKEINTRESOURCEW(IDS_EXPORT_FILE_SUBTITLE);
6873 pages[nPages].lParam = (LPARAM)&data;
6874 nPages++;
6876 pages[nPages].dwSize = sizeof(pages[0]);
6877 pages[nPages].hInstance = hInstance;
6878 pages[nPages].pszTemplate = MAKEINTRESOURCEW(IDD_EXPORT_FINISH);
6879 pages[nPages].pfnDlgProc = export_finish_dlg_proc;
6880 pages[nPages].dwFlags = PSP_HIDEHEADER;
6881 pages[nPages].lParam = (LPARAM)&data;
6882 nPages++;
6884 memset(&hdr, 0, sizeof(hdr));
6885 hdr.dwSize = sizeof(hdr);
6886 hdr.hwndParent = hwndParent;
6887 hdr.dwFlags = PSH_PROPSHEETPAGE | PSH_WIZARD97_NEW | PSH_HEADER |
6888 PSH_WATERMARK;
6889 hdr.hInstance = hInstance;
6890 if (pwszWizardTitle)
6891 hdr.pszCaption = pwszWizardTitle;
6892 else
6893 hdr.pszCaption = MAKEINTRESOURCEW(IDS_EXPORT_WIZARD);
6894 hdr.ppsp = pages;
6895 hdr.nPages = nPages;
6896 hdr.pszbmWatermark = MAKEINTRESOURCEW(IDB_CERT_WATERMARK);
6897 hdr.pszbmHeader = MAKEINTRESOURCEW(IDB_CERT_HEADER);
6898 l = PropertySheetW(&hdr);
6899 DeleteObject(data.titleFont);
6900 if (data.freePassword)
6901 free((WCHAR *)data.contextInfo.pwszPassword);
6902 free(data.keyProvInfo);
6903 CloseHandle(data.file);
6904 free(data.fileName);
6905 if (l == 0)
6907 SetLastError(ERROR_CANCELLED);
6908 return FALSE;
6910 else
6911 return data.success;
6914 BOOL WINAPI CryptUIWizExport(DWORD dwFlags, HWND hwndParent,
6915 LPCWSTR pwszWizardTitle, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo, void *pvoid)
6917 BOOL ret;
6919 TRACE("(%08lx, %p, %s, %p, %p)\n", dwFlags, hwndParent,
6920 debugstr_w(pwszWizardTitle), pExportInfo, pvoid);
6922 if (!(dwFlags & CRYPTUI_WIZ_NO_UI))
6923 ret = show_export_ui(dwFlags, hwndParent, pwszWizardTitle, pExportInfo,
6924 pvoid);
6925 else
6927 HANDLE file = CreateFileW(pExportInfo->pwszExportFileName,
6928 GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
6929 CREATE_ALWAYS, 0, NULL);
6931 if (file != INVALID_HANDLE_VALUE)
6933 ret = do_export(file, pExportInfo, pvoid, NULL, FALSE);
6934 CloseHandle(file);
6936 else
6937 ret = FALSE;
6939 return ret;
6942 BOOL WINAPI CryptUIDlgViewSignerInfoA(CRYPTUI_VIEWSIGNERINFO_STRUCTA *pcvsi)
6944 FIXME("%p: stub\n", pcvsi);
6945 return FALSE;
6948 static void init_columns(HWND lv, DWORD flags)
6950 WCHAR buf[MAX_STRING_LEN];
6951 LVCOLUMNW column;
6952 DWORD i = 0;
6954 SendMessageW(lv, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
6955 column.mask = LVCF_WIDTH | LVCF_TEXT;
6956 column.cx = 90;
6957 column.pszText = buf;
6958 if (!(flags & CRYPTUI_SELECT_ISSUEDTO_COLUMN))
6960 LoadStringW(hInstance, IDS_SUBJECT_COLUMN, buf, ARRAY_SIZE(buf));
6961 SendMessageW(lv, LVM_INSERTCOLUMNW, i++, (LPARAM)&column);
6963 if (!(flags & CRYPTUI_SELECT_ISSUEDBY_COLUMN))
6965 LoadStringW(hInstance, IDS_ISSUER_COLUMN, buf, ARRAY_SIZE(buf));
6966 SendMessageW(lv, LVM_INSERTCOLUMNW, i++, (LPARAM)&column);
6968 if (!(flags & CRYPTUI_SELECT_INTENDEDUSE_COLUMN))
6970 LoadStringW(hInstance, IDS_INTENDED_USE_COLUMN, buf, ARRAY_SIZE(buf));
6971 SendMessageW(lv, LVM_INSERTCOLUMNW, i++, (LPARAM)&column);
6973 if (!(flags & CRYPTUI_SELECT_FRIENDLYNAME_COLUMN))
6975 LoadStringW(hInstance, IDS_FRIENDLY_NAME_COLUMN, buf, ARRAY_SIZE(buf));
6976 SendMessageW(lv, LVM_INSERTCOLUMNW, i++, (LPARAM)&column);
6978 if (!(flags & CRYPTUI_SELECT_EXPIRATION_COLUMN))
6980 LoadStringW(hInstance, IDS_EXPIRATION_COLUMN, buf, ARRAY_SIZE(buf));
6981 SendMessageW(lv, LVM_INSERTCOLUMNW, i++, (LPARAM)&column);
6983 if (!(flags & CRYPTUI_SELECT_LOCATION_COLUMN))
6985 LoadStringW(hInstance, IDS_LOCATION_COLUMN, buf, ARRAY_SIZE(buf));
6986 SendMessageW(lv, LVM_INSERTCOLUMNW, i++, (LPARAM)&column);
6990 static void add_cert_to_list(HWND lv, PCCERT_CONTEXT cert, DWORD flags, DWORD *allocatedLen,
6991 LPWSTR *str)
6993 DWORD len;
6994 LVITEMW item;
6995 WCHAR dateFmt[80]; /* sufficient for LOCALE_SSHORTDATE */
6996 WCHAR buf[80];
6997 SYSTEMTIME sysTime;
6998 LPWSTR none, usages;
7000 item.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_TEXT;
7001 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
7002 item.iSubItem = 0;
7003 item.iImage = 0;
7004 item.lParam = (LPARAM)CertDuplicateCertificateContext(cert);
7005 if (!item.iItem)
7007 item.mask |= LVIF_STATE;
7008 item.state = LVIS_SELECTED;
7009 item.stateMask = -1;
7011 if (!(flags & CRYPTUI_SELECT_ISSUEDTO_COLUMN))
7013 len = CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, NULL, 0);
7014 if (len > *allocatedLen)
7016 free(*str);
7017 *str = malloc(len * sizeof(WCHAR));
7018 if (*str)
7019 *allocatedLen = len;
7021 if (*str)
7023 CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, *str, len);
7024 item.pszText = *str;
7025 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
7027 item.mask = LVIF_TEXT;
7028 ++item.iSubItem;
7030 if (!(flags & CRYPTUI_SELECT_ISSUEDBY_COLUMN))
7032 len = CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG, NULL,
7033 NULL, 0);
7034 if (len > *allocatedLen)
7036 free(*str);
7037 *str = malloc(len * sizeof(WCHAR));
7038 if (*str)
7039 *allocatedLen = len;
7041 if (*str)
7043 CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG, NULL,
7044 *str, len);
7045 item.pszText = *str;
7046 if (!item.iSubItem)
7047 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
7048 else
7049 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
7051 item.mask = LVIF_TEXT;
7052 ++item.iSubItem;
7054 if (!(flags & CRYPTUI_SELECT_INTENDEDUSE_COLUMN))
7056 get_cert_usages(cert, &usages);
7057 if (usages)
7059 item.pszText = usages;
7060 if (!item.iSubItem)
7061 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
7062 else
7063 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
7064 free(usages);
7066 item.mask = LVIF_TEXT;
7067 ++item.iSubItem;
7069 if (!(flags & CRYPTUI_SELECT_FRIENDLYNAME_COLUMN))
7071 if (!CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID, NULL, &len))
7072 len = LoadStringW(hInstance, IDS_FRIENDLY_NAME_NONE, (LPWSTR)&none, 0);
7073 if (len > *allocatedLen)
7075 free(*str);
7076 *str = malloc(len * sizeof(WCHAR));
7077 if (*str)
7078 *allocatedLen = len;
7080 if (*str)
7082 if (!CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID, *str, &len))
7083 item.pszText = none;
7084 else
7085 item.pszText = *str;
7086 if (!item.iSubItem)
7087 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
7088 else
7089 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
7091 item.mask = LVIF_TEXT;
7092 ++item.iSubItem;
7094 if (!(flags & CRYPTUI_SELECT_EXPIRATION_COLUMN))
7096 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SSHORTDATE, dateFmt, ARRAY_SIZE(dateFmt));
7097 FileTimeToSystemTime(&cert->pCertInfo->NotAfter, &sysTime);
7098 GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, buf, ARRAY_SIZE(buf));
7099 item.pszText = buf;
7100 if (!item.iSubItem)
7101 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
7102 else
7103 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
7104 item.mask = LVIF_TEXT;
7105 ++item.iSubItem;
7107 if (!(flags & CRYPTUI_SELECT_LOCATION_COLUMN))
7109 static int show_fixme;
7110 if (!show_fixme++)
7111 FIXME("showing location is not implemented\n");
7112 LoadStringW(hInstance, IDS_NO_IMPL, buf, ARRAY_SIZE(buf));
7113 if (!item.iSubItem)
7114 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
7115 else
7116 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
7120 static void add_store_certs(HWND lv, HCERTSTORE store, DWORD flags, PFNCFILTERPROC filter,
7121 void *callback_data)
7123 PCCERT_CONTEXT cert = NULL;
7124 BOOL select = FALSE;
7125 DWORD allocatedLen = 0;
7126 LPWSTR str = NULL;
7128 do {
7129 cert = CertEnumCertificatesInStore(store, cert);
7130 if (cert && (!filter || filter(cert, &select, callback_data)))
7131 add_cert_to_list(lv, cert, flags, &allocatedLen, &str);
7132 } while (cert);
7133 free(str);
7136 static PCCERT_CONTEXT select_cert_get_selected(HWND hwnd, int selection)
7138 HWND lv = GetDlgItem(hwnd, IDC_SELECT_CERTS);
7139 PCCERT_CONTEXT cert = NULL;
7140 LVITEMW item;
7142 if (selection < 0)
7143 selection = SendMessageW(lv, LVM_GETNEXTITEM, -1, LVNI_SELECTED);
7144 if (selection < 0)
7145 return NULL;
7146 item.mask = LVIF_PARAM;
7147 item.iItem = selection;
7148 item.iSubItem = 0;
7149 if (SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item))
7150 cert = (PCCERT_CONTEXT)item.lParam;
7151 return cert;
7154 static void select_cert_update_view_button(HWND hwnd)
7156 HWND lv = GetDlgItem(hwnd, IDC_SELECT_CERTS);
7157 int numSelected = SendMessageW(lv, LVM_GETSELECTEDCOUNT, 0, 0);
7159 EnableWindow(GetDlgItem(hwnd, IDC_SELECT_VIEW_CERT), numSelected == 1);
7162 struct SelectCertData
7164 PCCERT_CONTEXT *cert;
7165 DWORD dateColumn;
7166 HIMAGELIST imageList;
7167 LPCWSTR title;
7168 DWORD cStores;
7169 HCERTSTORE *rghStores;
7170 DWORD cPropSheetPages;
7171 LPCPROPSHEETPAGEW rgPropSheetPages;
7172 PFNCCERTDISPLAYPROC displayProc;
7173 void *callbackData;
7176 static void select_cert_view(HWND hwnd, PCCERT_CONTEXT cert, struct SelectCertData *data)
7178 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
7180 if (data->displayProc && data->displayProc(cert, hwnd, data->callbackData))
7181 return;
7182 memset(&viewInfo, 0, sizeof(viewInfo));
7183 viewInfo.dwSize = sizeof(viewInfo);
7184 viewInfo.hwndParent = hwnd;
7185 viewInfo.pCertContext = cert;
7186 viewInfo.cStores = data->cStores;
7187 viewInfo.rghStores = data->rghStores;
7188 viewInfo.cPropSheetPages = data->cPropSheetPages;
7189 viewInfo.rgPropSheetPages = data->rgPropSheetPages;
7190 /* FIXME: this should be modal */
7191 CryptUIDlgViewCertificateW(&viewInfo, NULL);
7194 struct SortData
7196 HWND hwnd;
7197 int column;
7200 static int CALLBACK select_cert_sort_by_text(LPARAM lp1, LPARAM lp2, LPARAM lp)
7202 struct SortData *data = (struct SortData *)lp;
7203 return cert_mgr_sort_by_text(data->hwnd, data->column, lp1, lp2);
7206 struct SelectCertParam
7208 PCCRYPTUI_SELECTCERTIFICATE_STRUCTW pcsc;
7209 PCCERT_CONTEXT cert;
7212 static INT_PTR CALLBACK select_cert_dlg_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
7214 struct SelectCertData *data;
7216 switch (msg)
7218 case WM_INITDIALOG:
7220 struct SelectCertParam *param = (struct SelectCertParam *)lp;
7221 PCCRYPTUI_SELECTCERTIFICATE_STRUCTW pcsc = param->pcsc;
7222 HWND lv = GetDlgItem(hwnd, IDC_SELECT_CERTS);
7223 DWORD i = 0;
7225 data = malloc(sizeof(*data));
7226 if (!data)
7227 return 0;
7228 data->cert = &param->cert;
7229 data->dateColumn = 4 -
7230 ((pcsc->dwDontUseColumn & CRYPTUI_SELECT_ISSUEDTO_COLUMN) ? 1 : 0) -
7231 ((pcsc->dwDontUseColumn & CRYPTUI_SELECT_ISSUEDBY_COLUMN) ? 1 : 0) -
7232 ((pcsc->dwDontUseColumn & CRYPTUI_SELECT_INTENDEDUSE_COLUMN) ? 1 : 0) -
7233 ((pcsc->dwDontUseColumn & CRYPTUI_SELECT_FRIENDLYNAME_COLUMN) ? 1 : 0);
7234 data->imageList = ImageList_Create(16, 16, ILC_COLOR4 | ILC_MASK, 2, 0);
7235 if (data->imageList)
7237 HBITMAP bmp;
7238 COLORREF backColor = RGB(255, 0, 255);
7240 bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_SMALL_ICONS));
7241 ImageList_AddMasked(data->imageList, bmp, backColor);
7242 DeleteObject(bmp);
7243 ImageList_SetBkColor(data->imageList, CLR_NONE);
7244 SendMessageW(GetDlgItem(hwnd, IDC_SELECT_CERTS), LVM_SETIMAGELIST, LVSIL_SMALL,
7245 (LPARAM)data->imageList);
7247 data->title = pcsc->szTitle;
7248 data->cStores = pcsc->cStores;
7249 data->rghStores = pcsc->rghStores;
7250 data->cPropSheetPages = pcsc->cPropSheetPages;
7251 data->rgPropSheetPages = pcsc->rgPropSheetPages;
7252 data->displayProc = pcsc->pDisplayCallback;
7253 data->callbackData = pcsc->pvCallbackData;
7254 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
7256 if (pcsc->szTitle)
7257 SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)pcsc->szTitle);
7258 if (pcsc->szDisplayString)
7259 SendMessageW(GetDlgItem(hwnd, IDC_SELECT_DISPLAY_STRING), WM_SETTEXT, 0,
7260 (LPARAM)pcsc->szDisplayString);
7261 init_columns(lv, pcsc->dwDontUseColumn);
7262 while (i < pcsc->cDisplayStores)
7263 add_store_certs(lv, pcsc->rghDisplayStores[i++], pcsc->dwDontUseColumn,
7264 pcsc->pFilterCallback, pcsc->pvCallbackData);
7265 select_cert_update_view_button(hwnd);
7266 break;
7268 case WM_NOTIFY:
7270 NMHDR *hdr = (NMHDR *)lp;
7272 switch (hdr->code)
7274 case NM_DBLCLK:
7276 PCCERT_CONTEXT cert = select_cert_get_selected(hwnd, ((NMITEMACTIVATE *)lp)->iItem);
7278 data = (struct SelectCertData *)GetWindowLongPtrW(hwnd, DWLP_USER);
7279 if (cert)
7280 select_cert_view(hwnd, cert, data);
7281 break;
7283 case LVN_COLUMNCLICK:
7285 NMLISTVIEW *nmlv = (NMLISTVIEW *)lp;
7286 HWND lv = GetDlgItem(hwnd, IDC_SELECT_CERTS);
7288 /* FIXME: doesn't support swapping sort order between ascending and descending. */
7289 data = (struct SelectCertData *)GetWindowLongPtrW(hwnd, DWLP_USER);
7290 if (nmlv->iSubItem == data->dateColumn)
7291 SendMessageW(lv, LVM_SORTITEMS, 0, (LPARAM)cert_mgr_sort_by_date);
7292 else
7294 struct SortData sortData;
7296 sortData.hwnd = lv;
7297 sortData.column = nmlv->iSubItem;
7298 SendMessageW(lv, LVM_SORTITEMSEX, (WPARAM)&sortData,
7299 (LPARAM)select_cert_sort_by_text);
7301 break;
7304 break;
7306 case WM_COMMAND:
7307 switch (wp)
7309 case IDOK:
7311 PCCERT_CONTEXT cert = select_cert_get_selected(hwnd, -1);
7313 data = (struct SelectCertData *)GetWindowLongPtrW(hwnd, DWLP_USER);
7314 if (!cert)
7316 WCHAR buf[40], title[40];
7318 LoadStringW(hInstance, IDS_SELECT_CERT, buf, ARRAY_SIZE(buf));
7319 if (!data->title)
7320 LoadStringW(hInstance, IDS_SELECT_CERT_TITLE, title, ARRAY_SIZE(title));
7321 MessageBoxW(hwnd, buf, data->title ? data->title : title, MB_OK | MB_ICONWARNING);
7322 break;
7324 *data->cert = CertDuplicateCertificateContext(cert);
7325 free_certs(GetDlgItem(hwnd, IDC_SELECT_CERTS));
7326 ImageList_Destroy(data->imageList);
7327 free(data);
7328 EndDialog(hwnd, IDOK);
7329 break;
7331 case IDCANCEL:
7332 data = (struct SelectCertData *)GetWindowLongPtrW(hwnd, DWLP_USER);
7333 free_certs(GetDlgItem(hwnd, IDC_SELECT_CERTS));
7334 ImageList_Destroy(data->imageList);
7335 free(data);
7336 EndDialog(hwnd, IDCANCEL);
7337 break;
7338 case IDC_SELECT_VIEW_CERT:
7340 PCCERT_CONTEXT cert = select_cert_get_selected(hwnd, -1);
7342 data = (struct SelectCertData *)GetWindowLongPtrW(hwnd, DWLP_USER);
7343 if (cert)
7344 select_cert_view(hwnd, cert, data);
7345 break;
7348 break;
7350 return 0;
7353 PCCERT_CONTEXT WINAPI CryptUIDlgSelectCertificateW(PCCRYPTUI_SELECTCERTIFICATE_STRUCTW pcsc)
7355 struct SelectCertParam param;
7357 TRACE("%p\n", pcsc);
7359 if (pcsc->dwSize != sizeof(*pcsc) && pcsc->dwSize != sizeof(*pcsc) - sizeof(HCERTSTORE))
7361 WARN("unexpected size %ld\n", pcsc->dwSize);
7362 SetLastError(E_INVALIDARG);
7363 return NULL;
7365 if (pcsc->dwFlags & CRYPTUI_SELECTCERT_MULTISELECT)
7366 FIXME("ignoring CRYPTUI_SELECTCERT_MULTISELECT\n");
7367 param.pcsc = pcsc;
7368 param.cert = NULL;
7369 DialogBoxParamW(hInstance, MAKEINTRESOURCEW(IDD_SELECT_CERT), pcsc->hwndParent,
7370 select_cert_dlg_proc, (LPARAM)&param);
7371 return param.cert;
7374 static void free_prop_sheet_pages(PROPSHEETPAGEW *pages, DWORD num)
7376 DWORD i;
7378 for (i = 0; i < num; i++)
7380 if (!(pages[i].dwFlags & PSP_DLGINDIRECT) && !IS_INTRESOURCE(pages[i].pszTemplate))
7381 free((void *)pages[i].pszTemplate);
7382 if ((pages[i].dwFlags & PSP_USEICONID) && !IS_INTRESOURCE(pages[i].pszIcon))
7383 free((void *)pages[i].pszIcon);
7384 if ((pages[i].dwFlags & PSP_USETITLE) && !IS_INTRESOURCE(pages[i].pszTitle))
7385 free((void *)pages[i].pszTitle);
7386 if ((pages[i].dwFlags & PSP_USEHEADERTITLE) && !IS_INTRESOURCE(pages[i].pszHeaderTitle))
7387 free((void *)pages[i].pszHeaderTitle);
7388 if ((pages[i].dwFlags & PSP_USEHEADERSUBTITLE) &&
7389 !IS_INTRESOURCE(pages[i].pszHeaderSubTitle))
7390 free((void *)pages[i].pszHeaderSubTitle);
7392 free(pages);
7395 static PROPSHEETPAGEW *prop_sheet_pages_AtoW(LPCPROPSHEETPAGEA pages, DWORD num)
7397 PROPSHEETPAGEW *psp;
7398 DWORD i, size = sizeof(*psp) * num;
7400 psp = malloc(size);
7401 if (!psp)
7402 return NULL;
7403 memcpy(psp, pages, size);
7404 for (i = 0; i < num; i++)
7406 if (!(pages[i].dwFlags & PSP_DLGINDIRECT) && !IS_INTRESOURCE(pages[i].pszTemplate))
7407 psp[i].pszTemplate = NULL;
7408 if ((pages[i].dwFlags & PSP_USEICONID) && !IS_INTRESOURCE(pages[i].pszIcon))
7409 psp[i].pszIcon = NULL;
7410 if ((pages[i].dwFlags & PSP_USETITLE) && !IS_INTRESOURCE(pages[i].pszTitle))
7411 psp[i].pszTitle = NULL;
7412 if (pages[i].dwFlags & PSP_USECALLBACK)
7413 psp[i].pfnCallback = NULL;
7414 if ((pages[i].dwFlags & PSP_USEHEADERTITLE) && !IS_INTRESOURCE(pages[i].pszHeaderTitle))
7415 psp[i].pszHeaderTitle = NULL;
7416 if ((pages[i].dwFlags & PSP_USEHEADERSUBTITLE) &&
7417 !IS_INTRESOURCE(pages[i].pszHeaderSubTitle))
7418 psp[i].pszHeaderSubTitle = NULL;
7420 for (i = 0; i < num; i++)
7422 if (!(pages[i].dwFlags & PSP_DLGINDIRECT) && !IS_INTRESOURCE(pages[i].pszTemplate))
7424 if (!(psp[i].pszTemplate = strdupAtoW( pages[i].pszTemplate ))) goto error;
7426 if ((pages[i].dwFlags & PSP_USEICONID) && !IS_INTRESOURCE(pages[i].pszIcon))
7428 if (!(psp[i].pszIcon = strdupAtoW( pages[i].pszIcon ))) goto error;
7430 if ((pages[i].dwFlags & PSP_USETITLE) && !IS_INTRESOURCE(pages[i].pszTitle))
7432 if (!(psp[i].pszTitle = strdupAtoW( pages[i].pszTitle ))) goto error;
7434 if (pages[i].dwFlags & PSP_USECALLBACK)
7435 FIXME("ignoring pfnCallback\n");
7436 if ((pages[i].dwFlags & PSP_USEHEADERTITLE) && !IS_INTRESOURCE(pages[i].pszHeaderTitle))
7438 if (!(psp[i].pszHeaderTitle = strdupAtoW( pages[i].pszHeaderTitle ))) goto error;
7440 if ((pages[i].dwFlags & PSP_USEHEADERSUBTITLE) &&
7441 !IS_INTRESOURCE(pages[i].pszHeaderSubTitle))
7443 if (!(psp[i].pszHeaderSubTitle = strdupAtoW( pages[i].pszHeaderSubTitle ))) goto error;
7446 return psp;
7447 error:
7448 free_prop_sheet_pages(psp, num);
7449 return NULL;
7452 PCCERT_CONTEXT WINAPI CryptUIDlgSelectCertificateA(PCCRYPTUI_SELECTCERTIFICATE_STRUCTA pcsc)
7454 PCCERT_CONTEXT cert = NULL;
7455 CRYPTUI_SELECTCERTIFICATE_STRUCTW selCertInfo;
7456 LPWSTR title = NULL, display_str = NULL;
7457 PROPSHEETPAGEW *pages = NULL;
7459 TRACE("%p\n", pcsc);
7461 if (pcsc->dwSize != sizeof(*pcsc) && pcsc->dwSize != sizeof(*pcsc) - sizeof(HCERTSTORE))
7463 WARN("unexpected size %ld\n", pcsc->dwSize);
7464 SetLastError(E_INVALIDARG);
7465 return NULL;
7467 memcpy(&selCertInfo, pcsc, pcsc->dwSize);
7468 if (pcsc->szTitle)
7470 if (!(title = strdupAtoW( pcsc->szTitle ))) goto error;
7471 selCertInfo.szTitle = title;
7473 if (pcsc->szDisplayString)
7475 if (!(display_str = strdupAtoW( pcsc->szDisplayString ))) goto error;
7476 selCertInfo.szDisplayString = display_str;
7478 if (pcsc->cPropSheetPages)
7480 pages = prop_sheet_pages_AtoW(pcsc->rgPropSheetPages, pcsc->cPropSheetPages);
7481 if (!pages)
7482 goto error;
7483 selCertInfo.rgPropSheetPages = pages;
7485 cert = CryptUIDlgSelectCertificateW(&selCertInfo);
7486 error:
7487 free(title);
7488 free(display_str);
7489 if (pcsc->cPropSheetPages)
7490 free_prop_sheet_pages(pages, pcsc->cPropSheetPages);
7491 return cert;
7494 PCCERT_CONTEXT WINAPI CryptUIDlgSelectCertificateFromStore(HCERTSTORE hCertStore, HWND hwnd, LPCWSTR pwszTitle,
7495 LPCWSTR pwszDisplayString, DWORD dwDontUseColumn,
7496 DWORD dwFlags, void *pvReserved)
7498 CRYPTUI_SELECTCERTIFICATE_STRUCTW sc;
7500 TRACE("%p %p %s %s %lx %lx %p\n", hCertStore, hwnd, debugstr_w(pwszTitle), debugstr_w(pwszDisplayString), dwDontUseColumn, dwFlags, pvReserved);
7502 memset(&sc, 0, sizeof(sc));
7504 sc.dwSize = sizeof(sc);
7505 sc.hwndParent = hwnd;
7506 sc.dwFlags = dwFlags;
7507 sc.szTitle = pwszTitle;
7508 sc.szDisplayString = pwszDisplayString;
7509 sc.dwDontUseColumn = dwDontUseColumn;
7510 sc.cDisplayStores = 1;
7511 sc.rghDisplayStores = &hCertStore;
7512 return CryptUIDlgSelectCertificateW(&sc);
7515 BOOL WINAPI CryptUIWizDigitalSign(DWORD flags, HWND parent, LPCWSTR title, PCCRYPTUI_WIZ_DIGITAL_SIGN_INFO info,
7516 PCCRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT *context)
7518 FIXME("%ld %p %s %p %p: stub\n", flags, parent, debugstr_w(title), info, context);
7519 return FALSE;