push 378fe7a60681a28e8b22f62dcfe122d585b92570
[wine/hacks.git] / dlls / cryptui / main.c
blob498c158f9bfcf45cd5d61961b5c07483f27aacfe
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 "config.h"
21 #include <stdarg.h>
23 #define COBJMACROS
24 #define NONAMELESSUNION
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winnls.h"
29 #include "winuser.h"
30 #include "softpub.h"
31 #include "wingdi.h"
32 #include "richedit.h"
33 #include "ole2.h"
34 #include "richole.h"
35 #include "commdlg.h"
36 #include "commctrl.h"
37 #include "cryptuiapi.h"
38 #include "cryptuires.h"
39 #include "urlmon.h"
40 #include "hlink.h"
41 #include "winreg.h"
42 #include "wine/debug.h"
43 #include "wine/unicode.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(cryptui);
47 static HINSTANCE hInstance;
49 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
51 TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
53 switch (fdwReason)
55 case DLL_WINE_PREATTACH:
56 return FALSE; /* prefer native version */
57 case DLL_PROCESS_ATTACH:
58 hInstance = hinstDLL;
59 DisableThreadLibraryCalls(hinstDLL);
60 break;
61 case DLL_PROCESS_DETACH:
62 break;
63 default:
64 break;
66 return TRUE;
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,
81 sizeof(buf) / sizeof(buf[0]));
82 column.mask = LVCF_WIDTH | LVCF_TEXT;
83 column.cx = (rc.right - rc.left) * 29 / 100 - 2;
84 column.pszText = buf;
85 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
86 LoadStringW(hInstance, IDS_ISSUER_COLUMN, buf,
87 sizeof(buf) / sizeof(buf[0]));
88 SendMessageW(lv, LVM_INSERTCOLUMNW, 1, (LPARAM)&column);
89 column.cx = (rc.right - rc.left) * 16 / 100 - 2;
90 LoadStringW(hInstance, IDS_EXPIRATION_COLUMN, buf,
91 sizeof(buf) / sizeof(buf[0]));
92 SendMessageW(lv, LVM_INSERTCOLUMNW, 2, (LPARAM)&column);
93 column.cx = (rc.right - rc.left) * 23 / 100 - 1;
94 LoadStringW(hInstance, IDS_FRIENDLY_NAME_COLUMN, buf,
95 sizeof(buf) / sizeof(buf[0]));
96 SendMessageW(lv, LVM_INSERTCOLUMNW, 3, (LPARAM)&column);
99 static void add_cert_to_view(HWND lv, PCCERT_CONTEXT cert, DWORD *allocatedLen,
100 LPWSTR *str)
102 DWORD len;
103 LVITEMW item;
104 WCHAR dateFmt[80]; /* sufficient for LOCALE_SSHORTDATE */
105 WCHAR date[80];
106 SYSTEMTIME sysTime;
108 item.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_TEXT;
109 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
110 item.iSubItem = 0;
111 item.iImage = 0;
112 item.lParam = (LPARAM)CertDuplicateCertificateContext(cert);
113 len = CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL,
114 NULL, 0);
115 if (len > *allocatedLen)
117 HeapFree(GetProcessHeap(), 0, *str);
118 *str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
119 if (*str)
120 *allocatedLen = len;
122 if (*str)
124 CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL,
125 *str, len);
126 item.pszText = *str;
127 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
130 item.mask = LVIF_TEXT;
131 len = CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
132 CERT_NAME_ISSUER_FLAG, NULL, NULL, 0);
133 if (len > *allocatedLen)
135 HeapFree(GetProcessHeap(), 0, *str);
136 *str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
137 if (*str)
138 *allocatedLen = len;
140 if (*str)
142 CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
143 CERT_NAME_ISSUER_FLAG, NULL, *str, len);
144 item.pszText = *str;
145 item.iSubItem = 1;
146 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
149 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SSHORTDATE, dateFmt,
150 sizeof(dateFmt) / sizeof(dateFmt[0]));
151 FileTimeToSystemTime(&cert->pCertInfo->NotAfter, &sysTime);
152 GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, date,
153 sizeof(date) / sizeof(date[0]));
154 item.pszText = date;
155 item.iSubItem = 2;
156 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
158 len = CertGetNameStringW(cert, CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL,
159 NULL, 0);
160 if (len > *allocatedLen)
162 HeapFree(GetProcessHeap(), 0, *str);
163 *str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
164 if (*str)
165 *allocatedLen = len;
167 if (*str)
169 CertGetNameStringW(cert, CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL,
170 *str, len);
171 item.pszText = *str;
172 item.iSubItem = 3;
173 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
177 static LPSTR get_cert_mgr_usages(void)
179 static const WCHAR keyName[] = { 'S','o','f','t','w','a','r','e','\\','M',
180 'i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g','r','a',
181 'p','h','y','\\','U','I','\\','C','e','r','t','m','g','r','\\','P','u',
182 'r','p','o','s','e',0 };
183 LPSTR str = NULL;
184 HKEY key;
186 if (!RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, NULL, 0, KEY_READ,
187 NULL, &key, NULL))
189 LONG rc;
190 DWORD type, size;
192 rc = RegQueryValueExA(key, "Purpose", NULL, &type, NULL, &size);
193 if ((!rc || rc == ERROR_MORE_DATA) && type == REG_SZ)
195 str = HeapAlloc(GetProcessHeap(), 0, size);
196 if (str)
198 rc = RegQueryValueExA(key, "Purpose", NULL, NULL, (LPBYTE)str,
199 &size);
200 if (rc)
202 HeapFree(GetProcessHeap(), 0, str);
203 str = NULL;
207 RegCloseKey(key);
209 return str;
212 typedef enum {
213 PurposeFilterShowAll = 0,
214 PurposeFilterShowAdvanced = 1,
215 PurposeFilterShowOID = 2
216 } PurposeFilter;
218 static void initialize_purpose_selection(HWND hwnd)
220 HWND cb = GetDlgItem(hwnd, IDC_MGR_PURPOSE_SELECTION);
221 WCHAR buf[MAX_STRING_LEN];
222 LPSTR usages;
223 int index;
225 LoadStringW(hInstance, IDS_PURPOSE_ALL, buf,
226 sizeof(buf) / sizeof(buf[0]));
227 index = SendMessageW(cb, CB_INSERTSTRING, -1, (LPARAM)buf);
228 SendMessageW(cb, CB_SETITEMDATA, index, (LPARAM)PurposeFilterShowAll);
229 LoadStringW(hInstance, IDS_PURPOSE_ADVANCED, buf,
230 sizeof(buf) / sizeof(buf[0]));
231 index = SendMessageW(cb, CB_INSERTSTRING, -1, (LPARAM)buf);
232 SendMessageW(cb, CB_SETITEMDATA, index, (LPARAM)PurposeFilterShowAdvanced);
233 SendMessageW(cb, CB_SETCURSEL, 0, 0);
234 if ((usages = get_cert_mgr_usages()))
236 LPSTR ptr, comma;
238 for (ptr = usages, comma = strchr(ptr, ','); ptr && *ptr;
239 ptr = comma ? comma + 1 : NULL,
240 comma = ptr ? strchr(ptr, ',') : NULL)
242 PCCRYPT_OID_INFO info;
244 if (comma)
245 *comma = 0;
246 if ((info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, ptr, 0)))
248 index = SendMessageW(cb, CB_INSERTSTRING, 0,
249 (LPARAM)info->pwszName);
250 SendMessageW(cb, CB_SETITEMDATA, index, (LPARAM)info);
253 HeapFree(GetProcessHeap(), 0, usages);
257 extern BOOL WINAPI WTHelperGetKnownUsages(DWORD action,
258 PCCRYPT_OID_INFO **usages);
260 static CERT_ENHKEY_USAGE *add_oid_to_usage(CERT_ENHKEY_USAGE *usage, LPSTR oid)
262 if (!usage->cUsageIdentifier)
263 usage->rgpszUsageIdentifier = HeapAlloc(GetProcessHeap(), 0,
264 sizeof(LPSTR));
265 else
266 usage->rgpszUsageIdentifier = HeapReAlloc(GetProcessHeap(), 0,
267 usage->rgpszUsageIdentifier,
268 (usage->cUsageIdentifier + 1) * sizeof(LPSTR));
269 if (usage->rgpszUsageIdentifier)
270 usage->rgpszUsageIdentifier[usage->cUsageIdentifier++] = oid;
271 else
273 HeapFree(GetProcessHeap(), 0, usage);
274 usage = NULL;
276 return usage;
279 static CERT_ENHKEY_USAGE *convert_usages_str_to_usage(LPSTR usageStr)
281 CERT_ENHKEY_USAGE *usage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
282 sizeof(CERT_ENHKEY_USAGE));
284 if (usage)
286 LPSTR ptr, comma;
288 for (ptr = usageStr, comma = strchr(ptr, ','); usage && ptr && *ptr;
289 ptr = comma ? comma + 1 : NULL,
290 comma = ptr ? strchr(ptr, ',') : NULL)
292 if (comma)
293 *comma = 0;
294 add_oid_to_usage(usage, ptr);
297 return usage;
300 static CERT_ENHKEY_USAGE *create_advanced_filter(void)
302 CERT_ENHKEY_USAGE *advancedUsage = HeapAlloc(GetProcessHeap(),
303 HEAP_ZERO_MEMORY, sizeof(CERT_ENHKEY_USAGE));
305 if (advancedUsage)
307 PCCRYPT_OID_INFO *usages;
309 if (WTHelperGetKnownUsages(1, &usages))
311 LPSTR disabledUsagesStr;
313 if ((disabledUsagesStr = get_cert_mgr_usages()))
315 CERT_ENHKEY_USAGE *disabledUsages =
316 convert_usages_str_to_usage(disabledUsagesStr);
318 if (disabledUsages)
320 PCCRYPT_OID_INFO *ptr;
322 for (ptr = usages; *ptr; ptr++)
324 DWORD i;
325 BOOL disabled = FALSE;
327 for (i = 0; !disabled &&
328 i < disabledUsages->cUsageIdentifier; i++)
329 if (!strcmp(disabledUsages->rgpszUsageIdentifier[i],
330 (*ptr)->pszOID))
331 disabled = TRUE;
332 if (!disabled)
333 add_oid_to_usage(advancedUsage,
334 (LPSTR)(*ptr)->pszOID);
336 /* The individual strings are pointers to disabledUsagesStr,
337 * so they're freed when it is.
339 HeapFree(GetProcessHeap(), 0,
340 disabledUsages->rgpszUsageIdentifier);
341 HeapFree(GetProcessHeap(), 0, disabledUsages);
343 HeapFree(GetProcessHeap(), 0, disabledUsagesStr);
345 WTHelperGetKnownUsages(2, &usages);
348 return advancedUsage;
351 static void show_store_certs(HWND hwnd, HCERTSTORE store)
353 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
354 HWND cb = GetDlgItem(hwnd, IDC_MGR_PURPOSE_SELECTION);
355 PCCERT_CONTEXT cert = NULL;
356 DWORD allocatedLen = 0;
357 LPWSTR str = NULL;
358 int index;
359 PurposeFilter filter = PurposeFilterShowAll;
360 LPCSTR oid = NULL;
361 CERT_ENHKEY_USAGE *advanced = NULL;
363 index = SendMessageW(cb, CB_GETCURSEL, 0, 0);
364 if (index >= 0)
366 INT_PTR data = SendMessageW(cb, CB_GETITEMDATA, index, 0);
368 if (!HIWORD(data))
369 filter = data;
370 else
372 PCCRYPT_OID_INFO info = (PCCRYPT_OID_INFO)data;
374 filter = PurposeFilterShowOID;
375 oid = info->pszOID;
378 if (filter == PurposeFilterShowAdvanced)
379 advanced = create_advanced_filter();
380 do {
381 cert = CertEnumCertificatesInStore(store, cert);
382 if (cert)
384 BOOL show = FALSE;
386 if (filter == PurposeFilterShowAll)
387 show = TRUE;
388 else
390 int numOIDs;
391 DWORD cbOIDs = 0;
393 if (CertGetValidUsages(1, &cert, &numOIDs, NULL, &cbOIDs))
395 if (numOIDs == -1)
397 /* -1 implies all usages are valid */
398 show = TRUE;
400 else
402 LPSTR *oids = HeapAlloc(GetProcessHeap(), 0, cbOIDs);
404 if (oids)
406 if (CertGetValidUsages(1, &cert, &numOIDs, oids,
407 &cbOIDs))
409 int i;
411 if (filter == PurposeFilterShowOID)
413 for (i = 0; !show && i < numOIDs; i++)
414 if (!strcmp(oids[i], oid))
415 show = TRUE;
417 else
419 for (i = 0; !show && i < numOIDs; i++)
421 DWORD j;
423 for (j = 0; !show &&
424 j < advanced->cUsageIdentifier; j++)
425 if (!strcmp(oids[i],
426 advanced->rgpszUsageIdentifier[j]))
427 show = TRUE;
431 HeapFree(GetProcessHeap(), 0, oids);
436 if (show)
437 add_cert_to_view(lv, cert, &allocatedLen, &str);
439 } while (cert);
440 HeapFree(GetProcessHeap(), 0, str);
441 if (advanced)
443 HeapFree(GetProcessHeap(), 0, advanced->rgpszUsageIdentifier);
444 HeapFree(GetProcessHeap(), 0, advanced);
448 static const WCHAR my[] = { 'M','y',0 };
449 static const WCHAR addressBook[] = {
450 'A','d','d','r','e','s','s','B','o','o','k',0 };
451 static const WCHAR ca[] = { 'C','A',0 };
452 static const WCHAR root[] = { 'R','o','o','t',0 };
453 static const WCHAR trustedPublisher[] = {
454 'T','r','u','s','t','e','d','P','u','b','l','i','s','h','e','r',0 };
455 static const WCHAR disallowed[] = { 'D','i','s','a','l','l','o','w','e','d',0 };
457 struct CertMgrStoreInfo
459 LPCWSTR name;
460 int removeWarning;
461 int removePluralWarning;
464 static const struct CertMgrStoreInfo defaultStoreList[] = {
465 { my, IDS_WARN_REMOVE_MY, IDS_WARN_REMOVE_PLURAL_MY },
466 { addressBook, IDS_WARN_REMOVE_ADDRESSBOOK,
467 IDS_WARN_REMOVE_PLURAL_ADDRESSBOOK },
468 { ca, IDS_WARN_REMOVE_CA, IDS_WARN_REMOVE_PLURAL_CA },
469 { root, IDS_WARN_REMOVE_ROOT, IDS_WARN_REMOVE_PLURAL_ROOT },
470 { trustedPublisher, IDS_WARN_REMOVE_TRUSTEDPUBLISHER,
471 IDS_WARN_REMOVE_PLURAL_TRUSTEDPUBLISHER },
472 { disallowed, IDS_WARN_REMOVE_DEFAULT },
475 static const struct CertMgrStoreInfo publisherStoreList[] = {
476 { root, IDS_WARN_REMOVE_ROOT, IDS_WARN_REMOVE_PLURAL_ROOT },
477 { trustedPublisher, IDS_WARN_REMOVE_TRUSTEDPUBLISHER,
478 IDS_WARN_REMOVE_PLURAL_TRUSTEDPUBLISHER },
479 { disallowed, IDS_WARN_REMOVE_PLURAL_DEFAULT },
482 struct CertMgrData
484 HIMAGELIST imageList;
485 LPCWSTR title;
486 DWORD nStores;
487 const struct CertMgrStoreInfo *stores;
490 static void show_cert_stores(HWND hwnd, DWORD dwFlags, struct CertMgrData *data)
492 const struct CertMgrStoreInfo *storeList;
493 int cStores, i;
494 HWND tab = GetDlgItem(hwnd, IDC_MGR_STORES);
496 if (dwFlags & CRYPTUI_CERT_MGR_PUBLISHER_TAB)
498 storeList = publisherStoreList;
499 cStores = sizeof(publisherStoreList) / sizeof(publisherStoreList[0]);
501 else
503 storeList = defaultStoreList;
504 cStores = sizeof(defaultStoreList) / sizeof(defaultStoreList[0]);
506 if (dwFlags & CRYPTUI_CERT_MGR_SINGLE_TAB_FLAG)
507 cStores = 1;
508 data->nStores = cStores;
509 data->stores = storeList;
510 for (i = 0; i < cStores; i++)
512 LPCWSTR name;
513 TCITEMW item;
514 HCERTSTORE store;
516 if (!(name = CryptFindLocalizedName(storeList[i].name)))
517 name = storeList[i].name;
518 store = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0,
519 CERT_SYSTEM_STORE_CURRENT_USER, storeList[i].name);
520 item.mask = TCIF_TEXT | TCIF_PARAM;
521 item.pszText = (LPWSTR)name;
522 item.lParam = (LPARAM)store;
523 SendMessageW(tab, TCM_INSERTITEMW, i, (LPARAM)&item);
527 static void free_certs(HWND lv)
529 LVITEMW item;
530 int items = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0), i;
532 for (i = 0; i < items; i++)
534 item.mask = LVIF_PARAM;
535 item.iItem = i;
536 item.iSubItem = 0;
537 SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item);
538 CertFreeCertificateContext((PCCERT_CONTEXT)item.lParam);
542 static HCERTSTORE cert_mgr_index_to_store(HWND tab, int index)
544 TCITEMW item;
546 item.mask = TCIF_PARAM;
547 SendMessageW(tab, TCM_GETITEMW, index, (LPARAM)&item);
548 return (HCERTSTORE)item.lParam;
551 static HCERTSTORE cert_mgr_current_store(HWND hwnd)
553 HWND tab = GetDlgItem(hwnd, IDC_MGR_STORES);
555 return cert_mgr_index_to_store(tab, SendMessageW(tab, TCM_GETCURSEL, 0, 0));
558 static void close_stores(HWND tab)
560 int i, tabs = SendMessageW(tab, TCM_GETITEMCOUNT, 0, 0);
562 for (i = 0; i < tabs; i++)
563 CertCloseStore(cert_mgr_index_to_store(tab, i), 0);
566 static void refresh_store_certs(HWND hwnd)
568 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
570 free_certs(lv);
571 SendMessageW(lv, LVM_DELETEALLITEMS, 0, 0);
572 show_store_certs(hwnd, cert_mgr_current_store(hwnd));
575 typedef enum {
576 CheckBitmapIndexUnchecked = 1,
577 CheckBitmapIndexChecked = 2,
578 CheckBitmapIndexDisabledUnchecked = 3,
579 CheckBitmapIndexDisabledChecked = 4
580 } CheckBitmapIndex;
582 static void add_known_usage(HWND lv, PCCRYPT_OID_INFO info,
583 CheckBitmapIndex state)
585 LVITEMW item;
587 item.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM;
588 item.state = INDEXTOSTATEIMAGEMASK(state);
589 item.stateMask = LVIS_STATEIMAGEMASK;
590 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
591 item.iSubItem = 0;
592 item.lParam = (LPARAM)info;
593 item.pszText = (LPWSTR)info->pwszName;
594 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
597 static void add_known_usages_to_list(HWND lv, CheckBitmapIndex state)
599 PCCRYPT_OID_INFO *usages;
601 if (WTHelperGetKnownUsages(1, &usages))
603 PCCRYPT_OID_INFO *ptr;
605 for (ptr = usages; *ptr; ptr++)
606 add_known_usage(lv, *ptr, state);
607 WTHelperGetKnownUsages(2, &usages);
611 static void toggle_usage(HWND hwnd, int iItem)
613 LVITEMW item;
614 int res;
615 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
617 item.mask = LVIF_STATE;
618 item.iItem = iItem;
619 item.iSubItem = 0;
620 item.stateMask = LVIS_STATEIMAGEMASK;
621 res = SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item);
622 if (res)
624 int state = item.state >> 12;
626 item.state = INDEXTOSTATEIMAGEMASK(
627 state == CheckBitmapIndexChecked ? CheckBitmapIndexUnchecked :
628 CheckBitmapIndexChecked);
629 SendMessageW(lv, LVM_SETITEMSTATE, iItem, (LPARAM)&item);
633 static LONG_PTR find_oid_in_list(HWND lv, LPCSTR oid)
635 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
636 (void *)oid, CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
637 LONG_PTR ret;
639 if (oidInfo)
641 LVFINDINFOW findInfo;
643 findInfo.flags = LVFI_PARAM;
644 findInfo.lParam = (LPARAM)oidInfo;
645 ret = SendMessageW(lv, LVM_FINDITEMW, -1, (LPARAM)&findInfo);
647 else
649 LVFINDINFOA findInfo;
651 findInfo.flags = LVFI_STRING;
652 findInfo.psz = oid;
653 ret = SendMessageW(lv, LVM_FINDITEMA, -1, (LPARAM)&findInfo);
655 return ret;
658 static void save_cert_mgr_usages(HWND hwnd)
660 static const WCHAR keyName[] = { 'S','o','f','t','w','a','r','e','\\','M',
661 'i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g','r','a',
662 'p','h','y','\\','U','I','\\','C','e','r','t','m','g','r','\\','P','u',
663 'r','p','o','s','e',0 };
664 HKEY key;
665 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
666 int purposes = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0), i;
667 LVITEMW item;
668 LPSTR str = NULL;
670 item.mask = LVIF_STATE | LVIF_PARAM;
671 item.iSubItem = 0;
672 item.stateMask = LVIS_STATEIMAGEMASK;
673 for (i = 0; i < purposes; i++)
675 item.iItem = i;
676 if (SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item))
678 int state = item.state >> 12;
680 if (state == CheckBitmapIndexUnchecked)
682 CRYPT_OID_INFO *info = (CRYPT_OID_INFO *)item.lParam;
683 BOOL firstString = TRUE;
685 if (!str)
686 str = HeapAlloc(GetProcessHeap(), 0,
687 strlen(info->pszOID) + 1);
688 else
690 str = HeapReAlloc(GetProcessHeap(), 0, str,
691 strlen(str) + 1 + strlen(info->pszOID) + 1);
692 firstString = FALSE;
694 if (str)
696 LPSTR ptr = firstString ? str : str + strlen(str);
698 if (!firstString)
699 *ptr++ = ',';
700 strcpy(ptr, info->pszOID);
705 if (!RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, NULL, 0, KEY_ALL_ACCESS,
706 NULL, &key, NULL))
708 if (str)
709 RegSetValueExA(key, "Purpose", 0, REG_SZ, (const BYTE *)str,
710 strlen(str) + 1);
711 else
712 RegDeleteValueA(key, "Purpose");
713 RegCloseKey(key);
715 HeapFree(GetProcessHeap(), 0, str);
718 static LRESULT CALLBACK cert_mgr_advanced_dlg_proc(HWND hwnd, UINT msg,
719 WPARAM wp, LPARAM lp)
721 switch (msg)
723 case WM_INITDIALOG:
725 RECT rc;
726 LVCOLUMNW column;
727 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
728 HIMAGELIST imageList;
729 LPSTR disabledUsages;
731 GetWindowRect(lv, &rc);
732 column.mask = LVCF_WIDTH;
733 column.cx = rc.right - rc.left;
734 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
735 imageList = ImageList_Create(16, 16, ILC_COLOR4 | ILC_MASK, 4, 0);
736 if (imageList)
738 HBITMAP bmp;
739 COLORREF backColor = RGB(255, 0, 255);
741 bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_CHECKS));
742 ImageList_AddMasked(imageList, bmp, backColor);
743 DeleteObject(bmp);
744 ImageList_SetBkColor(imageList, CLR_NONE);
745 SendMessageW(lv, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)imageList);
746 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)imageList);
748 add_known_usages_to_list(lv, CheckBitmapIndexChecked);
749 if ((disabledUsages = get_cert_mgr_usages()))
751 LPSTR ptr, comma;
753 for (ptr = disabledUsages, comma = strchr(ptr, ','); ptr && *ptr;
754 ptr = comma ? comma + 1 : NULL,
755 comma = ptr ? strchr(ptr, ',') : NULL)
757 LONG_PTR index;
759 if (comma)
760 *comma = 0;
761 if ((index = find_oid_in_list(lv, ptr)) != -1)
762 toggle_usage(hwnd, index);
764 HeapFree(GetProcessHeap(), 0, disabledUsages);
766 break;
768 case WM_NOTIFY:
770 NMHDR *hdr = (NMHDR *)lp;
771 NMITEMACTIVATE *nm;
773 switch (hdr->code)
775 case NM_CLICK:
776 nm = (NMITEMACTIVATE *)lp;
777 toggle_usage(hwnd, nm->iItem);
778 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
779 break;
781 break;
783 case WM_COMMAND:
784 switch (wp)
786 case IDOK:
787 save_cert_mgr_usages(hwnd);
788 ImageList_Destroy((HIMAGELIST)GetWindowLongPtrW(hwnd, DWLP_USER));
789 EndDialog(hwnd, IDOK);
790 break;
791 case IDCANCEL:
792 ImageList_Destroy((HIMAGELIST)GetWindowLongPtrW(hwnd, DWLP_USER));
793 EndDialog(hwnd, IDCANCEL);
794 break;
796 break;
798 return 0;
801 static void cert_mgr_clear_cert_selection(HWND hwnd)
803 WCHAR empty[] = { 0 };
805 EnableWindow(GetDlgItem(hwnd, IDC_MGR_EXPORT), FALSE);
806 EnableWindow(GetDlgItem(hwnd, IDC_MGR_REMOVE), FALSE);
807 EnableWindow(GetDlgItem(hwnd, IDC_MGR_VIEW), FALSE);
808 SendMessageW(GetDlgItem(hwnd, IDC_MGR_PURPOSES), WM_SETTEXT, 0,
809 (LPARAM)empty);
810 refresh_store_certs(hwnd);
813 static PCCERT_CONTEXT cert_mgr_index_to_cert(HWND hwnd, int index)
815 PCCERT_CONTEXT cert = NULL;
816 LVITEMW item;
818 item.mask = LVIF_PARAM;
819 item.iItem = index;
820 item.iSubItem = 0;
821 if (SendMessageW(GetDlgItem(hwnd, IDC_MGR_CERTS), LVM_GETITEMW, 0,
822 (LPARAM)&item))
823 cert = (PCCERT_CONTEXT)item.lParam;
824 return cert;
827 static void show_selected_cert(HWND hwnd, int index)
829 PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd, index);
831 if (cert)
833 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
835 memset(&viewInfo, 0, sizeof(viewInfo));
836 viewInfo.dwSize = sizeof(viewInfo);
837 viewInfo.hwndParent = hwnd;
838 viewInfo.pCertContext = cert;
839 /* FIXME: this should be modal */
840 CryptUIDlgViewCertificateW(&viewInfo, NULL);
844 static void cert_mgr_show_cert_usages(HWND hwnd, int index)
846 HWND text = GetDlgItem(hwnd, IDC_MGR_PURPOSES);
847 PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd, index);
848 PCERT_ENHKEY_USAGE usage;
849 DWORD size;
851 /* Get enhanced key usage. Have to check for a property and an extension
852 * separately, because CertGetEnhancedKeyUsage will succeed and return an
853 * empty usage if neither is set. Unfortunately an empty usage implies
854 * no usage is allowed, so we have to distinguish between the two cases.
856 if (CertGetEnhancedKeyUsage(cert, CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG,
857 NULL, &size))
859 usage = HeapAlloc(GetProcessHeap(), 0, size);
860 if (!CertGetEnhancedKeyUsage(cert,
861 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size))
863 HeapFree(GetProcessHeap(), 0, usage);
864 usage = NULL;
867 else if (CertGetEnhancedKeyUsage(cert, CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
868 NULL, &size))
870 usage = HeapAlloc(GetProcessHeap(), 0, size);
871 if (!CertGetEnhancedKeyUsage(cert,
872 CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, usage, &size))
874 HeapFree(GetProcessHeap(), 0, usage);
875 usage = NULL;
878 else
879 usage = NULL;
880 if (usage)
882 if (usage->cUsageIdentifier)
884 static const WCHAR commaSpace[] = { ',',' ',0 };
885 DWORD i, len = 1;
886 LPWSTR str, ptr;
888 for (i = 0; i < usage->cUsageIdentifier; i++)
890 PCCRYPT_OID_INFO info =
891 CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
892 usage->rgpszUsageIdentifier[i],
893 CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
895 if (info)
896 len += strlenW(info->pwszName);
897 else
898 len += strlen(usage->rgpszUsageIdentifier[i]);
899 if (i < usage->cUsageIdentifier - 1)
900 len += strlenW(commaSpace);
902 str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
903 if (str)
905 for (i = 0, ptr = str; i < usage->cUsageIdentifier; i++)
907 PCCRYPT_OID_INFO info =
908 CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
909 usage->rgpszUsageIdentifier[i],
910 CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
912 if (info)
914 strcpyW(ptr, info->pwszName);
915 ptr += strlenW(info->pwszName);
917 else
919 LPCSTR src = usage->rgpszUsageIdentifier[i];
921 for (; *src; ptr++, src++)
922 *ptr = *src;
923 *ptr = 0;
925 if (i < usage->cUsageIdentifier - 1)
927 strcpyW(ptr, commaSpace);
928 ptr += strlenW(commaSpace);
931 *ptr = 0;
932 SendMessageW(text, WM_SETTEXT, 0, (LPARAM)str);
933 HeapFree(GetProcessHeap(), 0, str);
935 HeapFree(GetProcessHeap(), 0, usage);
937 else
939 WCHAR buf[MAX_STRING_LEN];
941 LoadStringW(hInstance, IDS_ALLOWED_PURPOSE_NONE, buf,
942 sizeof(buf) / sizeof(buf[0]));
943 SendMessageW(text, WM_SETTEXT, 0, (LPARAM)buf);
946 else
948 WCHAR buf[MAX_STRING_LEN];
950 LoadStringW(hInstance, IDS_ALLOWED_PURPOSE_ALL, buf,
951 sizeof(buf) / sizeof(buf[0]));
952 SendMessageW(text, WM_SETTEXT, 0, (LPARAM)buf);
956 static void cert_mgr_do_remove(HWND hwnd)
958 int tabIndex = SendMessageW(GetDlgItem(hwnd, IDC_MGR_STORES),
959 TCM_GETCURSEL, 0, 0);
960 struct CertMgrData *data =
961 (struct CertMgrData *)GetWindowLongPtrW(hwnd, DWLP_USER);
963 if (tabIndex < data->nStores)
965 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
966 WCHAR warning[MAX_STRING_LEN], title[MAX_STRING_LEN];
967 LPCWSTR pTitle;
968 int warningID;
970 if (SendMessageW(lv, LVM_GETSELECTEDCOUNT, 0, 0) > 1)
971 warningID = data->stores[tabIndex].removePluralWarning;
972 else
973 warningID = data->stores[tabIndex].removeWarning;
974 if (data->title)
975 pTitle = data->title;
976 else
978 LoadStringW(hInstance, IDS_CERT_MGR, title,
979 sizeof(title) / sizeof(title[0]));
980 pTitle = title;
982 LoadStringW(hInstance, warningID, warning,
983 sizeof(warning) / sizeof(warning[0]));
984 if (MessageBoxW(hwnd, warning, pTitle, MB_YESNO) == IDYES)
986 int selection = -1;
988 do {
989 selection = SendMessageW(lv, LVM_GETNEXTITEM, selection,
990 LVNI_SELECTED);
991 if (selection >= 0)
993 PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd,
994 selection);
996 CertDeleteCertificateFromStore(cert);
998 } while (selection >= 0);
999 cert_mgr_clear_cert_selection(hwnd);
1004 static void cert_mgr_do_export(HWND hwnd)
1006 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
1007 int selectionCount = SendMessageW(lv, LVM_GETSELECTEDCOUNT, 0, 0);
1009 if (selectionCount == 1)
1011 int selection = SendMessageW(lv, LVM_GETNEXTITEM, -1,
1012 LVNI_SELECTED);
1014 if (selection >= 0)
1016 PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd, selection);
1018 if (cert)
1020 CRYPTUI_WIZ_EXPORT_INFO info;
1022 info.dwSize = sizeof(info);
1023 info.pwszExportFileName = NULL;
1024 info.dwSubjectChoice = CRYPTUI_WIZ_EXPORT_CERT_CONTEXT;
1025 info.u.pCertContext = cert;
1026 info.cStores = 0;
1027 CryptUIWizExport(0, hwnd, NULL, &info, NULL);
1031 else if (selectionCount > 1)
1033 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
1034 CERT_STORE_CREATE_NEW_FLAG, NULL);
1036 if (store)
1038 CRYPTUI_WIZ_EXPORT_INFO info;
1039 int selection = -1;
1041 info.dwSize = sizeof(info);
1042 info.pwszExportFileName = NULL;
1043 info.dwSubjectChoice =
1044 CRYPTUI_WIZ_EXPORT_CERT_STORE_CERTIFICATES_ONLY;
1045 info.u.hCertStore = store;
1046 info.cStores = 0;
1047 do {
1048 selection = SendMessageW(lv, LVM_GETNEXTITEM, selection,
1049 LVNI_SELECTED);
1050 if (selection >= 0)
1052 PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd,
1053 selection);
1055 CertAddCertificateContextToStore(store, cert,
1056 CERT_STORE_ADD_ALWAYS, NULL);
1058 } while (selection >= 0);
1059 CryptUIWizExport(0, hwnd, NULL, &info, NULL);
1060 CertCloseStore(store, 0);
1065 static LRESULT CALLBACK cert_mgr_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
1066 LPARAM lp)
1068 struct CertMgrData *data;
1070 switch (msg)
1072 case WM_INITDIALOG:
1074 PCCRYPTUI_CERT_MGR_STRUCT pCryptUICertMgr =
1075 (PCCRYPTUI_CERT_MGR_STRUCT)lp;
1076 HWND tab = GetDlgItem(hwnd, IDC_MGR_STORES);
1078 data = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CertMgrData));
1079 if (data)
1081 data->imageList = ImageList_Create(16, 16, ILC_COLOR4 | ILC_MASK,
1082 2, 0);
1083 if (data->imageList)
1085 HBITMAP bmp;
1086 COLORREF backColor = RGB(255, 0, 255);
1088 bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_SMALL_ICONS));
1089 ImageList_AddMasked(data->imageList, bmp, backColor);
1090 DeleteObject(bmp);
1091 ImageList_SetBkColor(data->imageList, CLR_NONE);
1092 SendMessageW(GetDlgItem(hwnd, IDC_MGR_CERTS), LVM_SETIMAGELIST,
1093 LVSIL_SMALL, (LPARAM)data->imageList);
1095 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
1096 data->title = pCryptUICertMgr->pwszTitle;
1098 initialize_purpose_selection(hwnd);
1099 add_cert_columns(hwnd);
1100 if (pCryptUICertMgr->pwszTitle)
1101 SendMessageW(hwnd, WM_SETTEXT, 0,
1102 (LPARAM)pCryptUICertMgr->pwszTitle);
1103 show_cert_stores(hwnd, pCryptUICertMgr->dwFlags, data);
1104 show_store_certs(hwnd, cert_mgr_index_to_store(tab, 0));
1105 break;
1107 case WM_NOTIFY:
1109 NMHDR *hdr = (NMHDR *)lp;
1111 switch (hdr->code)
1113 case TCN_SELCHANGE:
1114 cert_mgr_clear_cert_selection(hwnd);
1115 break;
1116 case LVN_ITEMCHANGED:
1118 NMITEMACTIVATE *nm;
1119 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
1121 nm = (NMITEMACTIVATE*)lp;
1122 if (nm->uNewState & LVN_ITEMACTIVATE)
1124 int numSelected = SendMessageW(lv, LVM_GETSELECTEDCOUNT, 0, 0);
1126 EnableWindow(GetDlgItem(hwnd, IDC_MGR_EXPORT), numSelected > 0);
1127 EnableWindow(GetDlgItem(hwnd, IDC_MGR_REMOVE), numSelected > 0);
1128 EnableWindow(GetDlgItem(hwnd, IDC_MGR_VIEW), numSelected == 1);
1129 if (numSelected == 1)
1130 cert_mgr_show_cert_usages(hwnd, nm->iItem);
1132 break;
1134 case NM_DBLCLK:
1135 show_selected_cert(hwnd, ((NMITEMACTIVATE *)lp)->iItem);
1136 break;
1137 case LVN_KEYDOWN:
1139 NMLVKEYDOWN *lvk = (NMLVKEYDOWN *)lp;
1141 if (lvk->wVKey == VK_DELETE)
1142 cert_mgr_do_remove(hwnd);
1143 break;
1146 break;
1148 case WM_COMMAND:
1149 switch (wp)
1151 case ((CBN_SELCHANGE << 16) | IDC_MGR_PURPOSE_SELECTION):
1152 cert_mgr_clear_cert_selection(hwnd);
1153 break;
1154 case IDC_MGR_IMPORT:
1155 if (CryptUIWizImport(0, hwnd, NULL, NULL,
1156 cert_mgr_current_store(hwnd)))
1157 refresh_store_certs(hwnd);
1158 break;
1159 case IDC_MGR_ADVANCED:
1160 if (DialogBoxW(hInstance, MAKEINTRESOURCEW(IDD_CERT_MGR_ADVANCED),
1161 hwnd, cert_mgr_advanced_dlg_proc) == IDOK)
1163 HWND cb = GetDlgItem(hwnd, IDC_MGR_PURPOSE_SELECTION);
1164 int index, len;
1165 LPWSTR curString = NULL;
1167 index = SendMessageW(cb, CB_GETCURSEL, 0, 0);
1168 if (index >= 0)
1170 len = SendMessageW(cb, CB_GETLBTEXTLEN, index, 0);
1171 curString = HeapAlloc(GetProcessHeap(), 0,
1172 (len + 1) * sizeof(WCHAR));
1173 SendMessageW(cb, CB_GETLBTEXT, index, (LPARAM)curString);
1175 SendMessageW(cb, CB_RESETCONTENT, 0, 0);
1176 initialize_purpose_selection(hwnd);
1177 if (curString)
1179 index = SendMessageW(cb, CB_FINDSTRINGEXACT, -1,
1180 (LPARAM)curString);
1181 if (index >= 0)
1182 SendMessageW(cb, CB_SETCURSEL, index, 0);
1183 HeapFree(GetProcessHeap(), 0, curString);
1185 refresh_store_certs(hwnd);
1187 break;
1188 case IDC_MGR_VIEW:
1190 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
1191 int selection = SendMessageW(lv, LVM_GETNEXTITEM, -1,
1192 LVNI_SELECTED);
1194 if (selection >= 0)
1195 show_selected_cert(hwnd, selection);
1196 break;
1198 case IDC_MGR_EXPORT:
1199 cert_mgr_do_export(hwnd);
1200 break;
1201 case IDC_MGR_REMOVE:
1202 cert_mgr_do_remove(hwnd);
1203 break;
1204 case IDCANCEL:
1205 free_certs(GetDlgItem(hwnd, IDC_MGR_CERTS));
1206 close_stores(GetDlgItem(hwnd, IDC_MGR_STORES));
1207 close_stores(GetDlgItem(hwnd, IDC_MGR_STORES));
1208 data = (struct CertMgrData *)GetWindowLongPtrW(hwnd, DWLP_USER);
1209 ImageList_Destroy(data->imageList);
1210 HeapFree(GetProcessHeap(), 0, data);
1211 EndDialog(hwnd, IDCANCEL);
1212 break;
1214 break;
1216 return 0;
1219 /***********************************************************************
1220 * CryptUIDlgCertMgr (CRYPTUI.@)
1222 BOOL WINAPI CryptUIDlgCertMgr(PCCRYPTUI_CERT_MGR_STRUCT pCryptUICertMgr)
1224 TRACE("(%p)\n", pCryptUICertMgr);
1226 if (pCryptUICertMgr->dwSize != sizeof(CRYPTUI_CERT_MGR_STRUCT))
1228 WARN("unexpected size %d\n", pCryptUICertMgr->dwSize);
1229 SetLastError(E_INVALIDARG);
1230 return FALSE;
1232 DialogBoxParamW(hInstance, MAKEINTRESOURCEW(IDD_CERT_MGR),
1233 pCryptUICertMgr->hwndParent, cert_mgr_dlg_proc, (LPARAM)pCryptUICertMgr);
1234 return TRUE;
1237 /* FIXME: real names are unknown, functions are undocumented */
1238 typedef struct _CRYPTUI_ENUM_SYSTEM_STORE_ARGS
1240 DWORD dwFlags;
1241 void *pvSystemStoreLocationPara;
1242 } CRYPTUI_ENUM_SYSTEM_STORE_ARGS, *PCRYPTUI_ENUM_SYSTEM_STORE_ARGS;
1244 typedef struct _CRYPTUI_ENUM_DATA
1246 DWORD cStores;
1247 HCERTSTORE *rghStore;
1248 DWORD cEnumArgs;
1249 PCRYPTUI_ENUM_SYSTEM_STORE_ARGS rgEnumArgs;
1250 } CRYPTUI_ENUM_DATA, *PCRYPTUI_ENUM_DATA;
1252 typedef BOOL (WINAPI *PFN_SELECTED_STORE_CB)(HCERTSTORE store, HWND hwnd,
1253 void *pvArg);
1255 /* Values for dwFlags */
1256 #define CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE 0x00000001
1258 typedef struct _CRYPTUI_SELECTSTORE_INFO_A
1260 DWORD dwSize;
1261 HWND parent;
1262 DWORD dwFlags;
1263 LPSTR pszTitle;
1264 LPSTR pszText;
1265 CRYPTUI_ENUM_DATA *pEnumData;
1266 PFN_SELECTED_STORE_CB pfnSelectedStoreCallback;
1267 void *pvArg;
1268 } CRYPTUI_SELECTSTORE_INFO_A, *PCRYPTUI_SELECTSTORE_INFO_A;
1270 typedef struct _CRYPTUI_SELECTSTORE_INFO_W
1272 DWORD dwSize;
1273 HWND parent;
1274 DWORD dwFlags;
1275 LPWSTR pwszTitle;
1276 LPWSTR pwszText;
1277 CRYPTUI_ENUM_DATA *pEnumData;
1278 PFN_SELECTED_STORE_CB pfnSelectedStoreCallback;
1279 void *pvArg;
1280 } CRYPTUI_SELECTSTORE_INFO_W, *PCRYPTUI_SELECTSTORE_INFO_W;
1282 struct StoreInfo
1284 enum {
1285 StoreHandle,
1286 SystemStore
1287 } type;
1288 union {
1289 HCERTSTORE store;
1290 LPWSTR name;
1291 } DUMMYUNIONNAME;
1294 static BOOL WINAPI enum_store_callback(const void *pvSystemStore,
1295 DWORD dwFlags, PCERT_SYSTEM_STORE_INFO pStoreInfo, void *pvReserved,
1296 void *pvArg)
1298 HWND tree = GetDlgItem(pvArg, IDC_STORE_LIST);
1299 TVINSERTSTRUCTW tvis;
1300 LPCWSTR localizedName;
1301 BOOL ret = TRUE;
1303 tvis.hParent = NULL;
1304 tvis.hInsertAfter = TVI_LAST;
1305 tvis.u.item.mask = TVIF_TEXT;
1306 if ((localizedName = CryptFindLocalizedName(pvSystemStore)))
1308 struct StoreInfo *storeInfo = HeapAlloc(GetProcessHeap(), 0,
1309 sizeof(struct StoreInfo));
1311 if (storeInfo)
1313 storeInfo->type = SystemStore;
1314 storeInfo->u.name = HeapAlloc(GetProcessHeap(), 0,
1315 (strlenW(pvSystemStore) + 1) * sizeof(WCHAR));
1316 if (storeInfo->u.name)
1318 tvis.u.item.mask |= TVIF_PARAM;
1319 tvis.u.item.lParam = (LPARAM)storeInfo;
1320 strcpyW(storeInfo->u.name, pvSystemStore);
1322 else
1324 HeapFree(GetProcessHeap(), 0, storeInfo);
1325 ret = FALSE;
1328 else
1329 ret = FALSE;
1330 tvis.u.item.pszText = (LPWSTR)localizedName;
1332 else
1333 tvis.u.item.pszText = (LPWSTR)pvSystemStore;
1334 /* FIXME: need a folder icon for the store too */
1335 if (ret)
1336 SendMessageW(tree, TVM_INSERTITEMW, 0, (LPARAM)&tvis);
1337 return ret;
1340 static void enumerate_stores(HWND hwnd, CRYPTUI_ENUM_DATA *pEnumData)
1342 DWORD i;
1343 HWND tree = GetDlgItem(hwnd, IDC_STORE_LIST);
1345 for (i = 0; i < pEnumData->cEnumArgs; i++)
1346 CertEnumSystemStore(pEnumData->rgEnumArgs[i].dwFlags,
1347 pEnumData->rgEnumArgs[i].pvSystemStoreLocationPara,
1348 hwnd, enum_store_callback);
1349 for (i = 0; i < pEnumData->cStores; i++)
1351 DWORD size;
1353 if (CertGetStoreProperty(pEnumData->rghStore[i],
1354 CERT_STORE_LOCALIZED_NAME_PROP_ID, NULL, &size))
1356 LPWSTR name = HeapAlloc(GetProcessHeap(), 0, size);
1358 if (name)
1360 if (CertGetStoreProperty(pEnumData->rghStore[i],
1361 CERT_STORE_LOCALIZED_NAME_PROP_ID, name, &size))
1363 struct StoreInfo *storeInfo = HeapAlloc(GetProcessHeap(),
1364 0, sizeof(struct StoreInfo));
1366 if (storeInfo)
1368 TVINSERTSTRUCTW tvis;
1370 storeInfo->type = StoreHandle;
1371 storeInfo->u.store = pEnumData->rghStore[i];
1372 tvis.hParent = NULL;
1373 tvis.hInsertAfter = TVI_LAST;
1374 tvis.u.item.mask = TVIF_TEXT | TVIF_PARAM;
1375 tvis.u.item.pszText = name;
1376 tvis.u.item.lParam = (LPARAM)storeInfo;
1377 SendMessageW(tree, TVM_INSERTITEMW, 0, (LPARAM)&tvis);
1380 HeapFree(GetProcessHeap(), 0, name);
1386 static void free_store_info(HWND tree)
1388 HTREEITEM next = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM, TVGN_CHILD,
1389 (LPARAM)NULL);
1391 while (next)
1393 TVITEMW item;
1395 memset(&item, 0, sizeof(item));
1396 item.mask = TVIF_HANDLE | TVIF_PARAM;
1397 item.hItem = next;
1398 SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item);
1399 if (item.lParam)
1401 struct StoreInfo *storeInfo = (struct StoreInfo *)item.lParam;
1403 if (storeInfo->type == SystemStore)
1404 HeapFree(GetProcessHeap(), 0, storeInfo->u.name);
1405 HeapFree(GetProcessHeap(), 0, storeInfo);
1407 next = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM, TVGN_NEXT,
1408 (LPARAM)next);
1412 static HCERTSTORE selected_item_to_store(HWND tree, HTREEITEM hItem)
1414 WCHAR buf[MAX_STRING_LEN];
1415 TVITEMW item;
1416 HCERTSTORE store;
1418 memset(&item, 0, sizeof(item));
1419 item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_TEXT;
1420 item.hItem = hItem;
1421 item.cchTextMax = sizeof(buf) / sizeof(buf[0]);
1422 item.pszText = buf;
1423 SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item);
1424 if (item.lParam)
1426 struct StoreInfo *storeInfo = (struct StoreInfo *)item.lParam;
1428 if (storeInfo->type == StoreHandle)
1429 store = storeInfo->u.store;
1430 else
1431 store = CertOpenSystemStoreW(0, storeInfo->u.name);
1433 else
1435 /* It's implicitly a system store */
1436 store = CertOpenSystemStoreW(0, buf);
1438 return store;
1441 struct SelectStoreInfo
1443 PCRYPTUI_SELECTSTORE_INFO_W info;
1444 HCERTSTORE store;
1447 static LRESULT CALLBACK select_store_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
1448 LPARAM lp)
1450 struct SelectStoreInfo *selectInfo;
1451 LRESULT ret = 0;
1453 switch (msg)
1455 case WM_INITDIALOG:
1457 selectInfo = (struct SelectStoreInfo *)lp;
1458 SetWindowLongPtrW(hwnd, DWLP_USER, lp);
1459 if (selectInfo->info->pwszTitle)
1460 SendMessageW(hwnd, WM_SETTEXT, 0,
1461 (LPARAM)selectInfo->info->pwszTitle);
1462 if (selectInfo->info->pwszText)
1463 SendMessageW(GetDlgItem(hwnd, IDC_STORE_TEXT), WM_SETTEXT, 0,
1464 (LPARAM)selectInfo->info->pwszText);
1465 if (!(selectInfo->info->dwFlags & CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE))
1466 ShowWindow(GetDlgItem(hwnd, IDC_SHOW_PHYSICAL_STORES), FALSE);
1467 enumerate_stores(hwnd, selectInfo->info->pEnumData);
1468 break;
1470 case WM_COMMAND:
1471 switch (wp)
1473 case IDOK:
1475 HWND tree = GetDlgItem(hwnd, IDC_STORE_LIST);
1476 HTREEITEM selection = (HTREEITEM)SendMessageW(tree,
1477 TVM_GETNEXTITEM, TVGN_CARET, (LPARAM)NULL);
1479 selectInfo = (struct SelectStoreInfo *)GetWindowLongPtrW(hwnd,
1480 DWLP_USER);
1481 if (!selection)
1483 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN], *pTitle;
1485 if (selectInfo->info->pwszTitle)
1486 pTitle = selectInfo->info->pwszTitle;
1487 else
1489 LoadStringW(hInstance, IDS_SELECT_STORE_TITLE, title,
1490 sizeof(title) / sizeof(title[0]));
1491 pTitle = title;
1493 LoadStringW(hInstance, IDS_SELECT_STORE, error,
1494 sizeof(error) / sizeof(error[0]));
1495 MessageBoxW(hwnd, error, pTitle, MB_ICONEXCLAMATION | MB_OK);
1497 else
1499 HCERTSTORE store = selected_item_to_store(tree, selection);
1501 if (!selectInfo->info->pfnSelectedStoreCallback ||
1502 selectInfo->info->pfnSelectedStoreCallback(store, hwnd,
1503 selectInfo->info->pvArg))
1505 selectInfo->store = store;
1506 free_store_info(tree);
1507 EndDialog(hwnd, IDOK);
1509 else
1510 CertCloseStore(store, 0);
1512 ret = TRUE;
1513 break;
1515 case IDCANCEL:
1516 free_store_info(GetDlgItem(hwnd, IDC_STORE_LIST));
1517 EndDialog(hwnd, IDCANCEL);
1518 ret = TRUE;
1519 break;
1521 break;
1523 return ret;
1526 /***********************************************************************
1527 * CryptUIDlgSelectStoreW (CRYPTUI.@)
1529 HCERTSTORE WINAPI CryptUIDlgSelectStoreW(PCRYPTUI_SELECTSTORE_INFO_W info)
1531 struct SelectStoreInfo selectInfo = { info, NULL };
1533 TRACE("(%p)\n", info);
1535 if (info->dwSize != sizeof(CRYPTUI_SELECTSTORE_INFO_W))
1537 WARN("unexpected size %d\n", info->dwSize);
1538 SetLastError(E_INVALIDARG);
1539 return NULL;
1541 DialogBoxParamW(hInstance, MAKEINTRESOURCEW(IDD_SELECT_STORE), info->parent,
1542 select_store_dlg_proc, (LPARAM)&selectInfo);
1543 return selectInfo.store;
1546 /***********************************************************************
1547 * CryptUIDlgSelectStoreA (CRYPTUI.@)
1549 HCERTSTORE WINAPI CryptUIDlgSelectStoreA(PCRYPTUI_SELECTSTORE_INFO_A info)
1551 CRYPTUI_SELECTSTORE_INFO_W infoW;
1552 HCERTSTORE ret;
1553 int len;
1555 TRACE("(%p)\n", info);
1557 if (info->dwSize != sizeof(CRYPTUI_SELECTSTORE_INFO_A))
1559 WARN("unexpected size %d\n", info->dwSize);
1560 SetLastError(E_INVALIDARG);
1561 return NULL;
1563 memcpy(&infoW, &info, sizeof(info));
1564 if (info->pszTitle)
1566 len = MultiByteToWideChar(CP_ACP, 0, info->pszTitle, -1, NULL, 0);
1567 infoW.pwszTitle = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1568 MultiByteToWideChar(CP_ACP, 0, info->pszTitle, -1, infoW.pwszTitle,
1569 len);
1571 if (info->pszText)
1573 len = MultiByteToWideChar(CP_ACP, 0, info->pszText, -1, NULL, 0);
1574 infoW.pwszText = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1575 MultiByteToWideChar(CP_ACP, 0, info->pszText, -1, infoW.pwszText, len);
1577 ret = CryptUIDlgSelectStoreW(&infoW);
1578 HeapFree(GetProcessHeap(), 0, infoW.pwszText);
1579 HeapFree(GetProcessHeap(), 0, infoW.pwszTitle);
1580 return ret;
1583 /***********************************************************************
1584 * CryptUIDlgViewCertificateA (CRYPTUI.@)
1586 BOOL WINAPI CryptUIDlgViewCertificateA(
1587 PCCRYPTUI_VIEWCERTIFICATE_STRUCTA pCertViewInfo, BOOL *pfPropertiesChanged)
1589 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
1590 LPWSTR title = NULL;
1591 BOOL ret;
1593 TRACE("(%p, %p)\n", pCertViewInfo, pfPropertiesChanged);
1595 memcpy(&viewInfo, pCertViewInfo, sizeof(viewInfo));
1596 if (pCertViewInfo->szTitle)
1598 int len = MultiByteToWideChar(CP_ACP, 0, pCertViewInfo->szTitle, -1,
1599 NULL, 0);
1601 title = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1602 if (title)
1604 MultiByteToWideChar(CP_ACP, 0, pCertViewInfo->szTitle, -1, title,
1605 len);
1606 viewInfo.szTitle = title;
1608 else
1610 ret = FALSE;
1611 goto error;
1614 if (pCertViewInfo->cPropSheetPages)
1616 FIXME("ignoring additional prop sheet pages\n");
1617 viewInfo.cPropSheetPages = 0;
1619 ret = CryptUIDlgViewCertificateW(&viewInfo, pfPropertiesChanged);
1620 HeapFree(GetProcessHeap(), 0, title);
1621 error:
1622 return ret;
1625 struct ReadStringStruct
1627 LPCWSTR buf;
1628 LONG pos;
1629 LONG len;
1632 static DWORD CALLBACK read_text_callback(DWORD_PTR dwCookie, LPBYTE buf,
1633 LONG cb, LONG *pcb)
1635 struct ReadStringStruct *string = (struct ReadStringStruct *)dwCookie;
1636 LONG cch = min(cb / sizeof(WCHAR), string->len - string->pos);
1638 TRACE("(%p, %p, %d, %p)\n", string, buf, cb, pcb);
1640 memmove(buf, string->buf + string->pos, cch * sizeof(WCHAR));
1641 string->pos += cch;
1642 *pcb = cch * sizeof(WCHAR);
1643 return 0;
1646 static void add_unformatted_text_to_control(HWND hwnd, LPCWSTR text, LONG len)
1648 struct ReadStringStruct string;
1649 EDITSTREAM editstream;
1651 TRACE("(%p, %s)\n", hwnd, debugstr_wn(text, len));
1653 string.buf = text;
1654 string.pos = 0;
1655 string.len = len;
1656 editstream.dwCookie = (DWORD_PTR)&string;
1657 editstream.dwError = 0;
1658 editstream.pfnCallback = read_text_callback;
1659 SendMessageW(hwnd, EM_STREAMIN, SF_TEXT | SFF_SELECTION | SF_UNICODE,
1660 (LPARAM)&editstream);
1663 static void add_string_resource_to_control(HWND hwnd, int id)
1665 LPWSTR str;
1666 LONG len;
1668 len = LoadStringW(hInstance, id, (LPWSTR)&str, 0);
1669 add_unformatted_text_to_control(hwnd, str, len);
1672 static void add_text_with_paraformat_to_control(HWND hwnd, LPCWSTR text,
1673 LONG len, const PARAFORMAT2 *fmt)
1675 add_unformatted_text_to_control(hwnd, text, len);
1676 SendMessageW(hwnd, EM_SETPARAFORMAT, 0, (LPARAM)fmt);
1679 static void add_string_resource_with_paraformat_to_control(HWND hwnd, int id,
1680 const PARAFORMAT2 *fmt)
1682 LPWSTR str;
1683 LONG len;
1685 len = LoadStringW(hInstance, id, (LPWSTR)&str, 0);
1686 add_text_with_paraformat_to_control(hwnd, str, len, fmt);
1689 static LPWSTR get_cert_name_string(PCCERT_CONTEXT pCertContext, DWORD dwType,
1690 DWORD dwFlags)
1692 LPWSTR buf = NULL;
1693 DWORD len;
1695 len = CertGetNameStringW(pCertContext, dwType, dwFlags, NULL, NULL, 0);
1696 if (len)
1698 buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1699 if (buf)
1700 CertGetNameStringW(pCertContext, dwType, dwFlags, NULL, buf, len);
1702 return buf;
1705 static void add_cert_string_to_control(HWND hwnd, PCCERT_CONTEXT pCertContext,
1706 DWORD dwType, DWORD dwFlags)
1708 LPWSTR name = get_cert_name_string(pCertContext, dwType, dwFlags);
1710 if (name)
1712 /* Don't include NULL-terminator in output */
1713 DWORD len = lstrlenW(name);
1715 add_unformatted_text_to_control(hwnd, name, len);
1716 HeapFree(GetProcessHeap(), 0, name);
1720 static void add_icon_to_control(HWND hwnd, int id)
1722 HRESULT hr;
1723 LPRICHEDITOLE richEditOle = NULL;
1724 LPOLEOBJECT object = NULL;
1725 CLSID clsid;
1726 LPOLECACHE oleCache = NULL;
1727 FORMATETC formatEtc;
1728 DWORD conn;
1729 LPDATAOBJECT dataObject = NULL;
1730 HBITMAP bitmap = NULL;
1731 RECT rect;
1732 STGMEDIUM stgm;
1733 LPOLECLIENTSITE clientSite = NULL;
1734 REOBJECT reObject;
1736 TRACE("(%p, %d)\n", hwnd, id);
1738 SendMessageW(hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&richEditOle);
1739 if (!richEditOle)
1740 goto end;
1741 hr = OleCreateDefaultHandler(&CLSID_NULL, NULL, &IID_IOleObject,
1742 (void**)&object);
1743 if (FAILED(hr))
1744 goto end;
1745 hr = IOleObject_GetUserClassID(object, &clsid);
1746 if (FAILED(hr))
1747 goto end;
1748 hr = IOleObject_QueryInterface(object, &IID_IOleCache, (void**)&oleCache);
1749 if (FAILED(hr))
1750 goto end;
1751 formatEtc.cfFormat = CF_BITMAP;
1752 formatEtc.ptd = NULL;
1753 formatEtc.dwAspect = DVASPECT_CONTENT;
1754 formatEtc.lindex = -1;
1755 formatEtc.tymed = TYMED_GDI;
1756 hr = IOleCache_Cache(oleCache, &formatEtc, 0, &conn);
1757 if (FAILED(hr))
1758 goto end;
1759 hr = IOleObject_QueryInterface(object, &IID_IDataObject,
1760 (void**)&dataObject);
1761 if (FAILED(hr))
1762 goto end;
1763 hr = IRichEditOle_GetClientSite(richEditOle, &clientSite);
1764 if (FAILED(hr))
1765 goto end;
1766 bitmap = LoadImageW(hInstance, MAKEINTRESOURCEW(id), IMAGE_BITMAP, 0, 0,
1767 LR_DEFAULTSIZE | LR_LOADTRANSPARENT);
1768 if (!bitmap)
1769 goto end;
1770 rect.left = rect.top = 0;
1771 rect.right = GetSystemMetrics(SM_CXICON);
1772 rect.bottom = GetSystemMetrics(SM_CYICON);
1773 stgm.tymed = TYMED_GDI;
1774 stgm.u.hBitmap = bitmap;
1775 stgm.pUnkForRelease = NULL;
1776 hr = IDataObject_SetData(dataObject, &formatEtc, &stgm, TRUE);
1777 if (FAILED(hr))
1778 goto end;
1780 reObject.cbStruct = sizeof(reObject);
1781 reObject.cp = REO_CP_SELECTION;
1782 reObject.clsid = clsid;
1783 reObject.poleobj = object;
1784 reObject.pstg = NULL;
1785 reObject.polesite = clientSite;
1786 reObject.sizel.cx = reObject.sizel.cy = 0;
1787 reObject.dvaspect = DVASPECT_CONTENT;
1788 reObject.dwFlags = 0;
1789 reObject.dwUser = 0;
1791 IRichEditOle_InsertObject(richEditOle, &reObject);
1793 end:
1794 if (clientSite)
1795 IOleClientSite_Release(clientSite);
1796 if (dataObject)
1797 IDataObject_Release(dataObject);
1798 if (oleCache)
1799 IOleCache_Release(oleCache);
1800 if (object)
1801 IOleObject_Release(object);
1802 if (richEditOle)
1803 IRichEditOle_Release(richEditOle);
1806 #define MY_INDENT 200
1808 static void add_oid_text_to_control(HWND hwnd, char *oid)
1810 WCHAR nl = '\n';
1811 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, oid, 0);
1812 PARAFORMAT2 parFmt;
1814 parFmt.cbSize = sizeof(parFmt);
1815 parFmt.dwMask = PFM_STARTINDENT;
1816 parFmt.dxStartIndent = MY_INDENT * 3;
1817 if (oidInfo)
1819 add_text_with_paraformat_to_control(hwnd, oidInfo->pwszName,
1820 lstrlenW(oidInfo->pwszName), &parFmt);
1821 add_unformatted_text_to_control(hwnd, &nl, 1);
1825 struct OIDToString
1827 LPCSTR oid;
1828 int id;
1831 /* The following list MUST be lexicographically sorted by OID */
1832 static struct OIDToString oidMap[] = {
1833 /* 1.3.6.1.4.1.311.10.3.1 */
1834 { szOID_KP_CTL_USAGE_SIGNING, IDS_PURPOSE_CTL_USAGE_SIGNING },
1835 /* 1.3.6.1.4.1.311.10.3.4 */
1836 { szOID_KP_EFS, IDS_PURPOSE_EFS },
1837 /* 1.3.6.1.4.1.311.10.3.4.1 */
1838 { szOID_EFS_RECOVERY, IDS_PURPOSE_EFS_RECOVERY },
1839 /* 1.3.6.1.4.1.311.10.3.5 */
1840 { szOID_WHQL_CRYPTO, IDS_PURPOSE_WHQL },
1841 /* 1.3.6.1.4.1.311.10.3.6 */
1842 { szOID_NT5_CRYPTO, IDS_PURPOSE_NT5 },
1843 /* 1.3.6.1.4.1.311.10.3.7 */
1844 { szOID_OEM_WHQL_CRYPTO, IDS_PURPOSE_OEM_WHQL },
1845 /* 1.3.6.1.4.1.311.10.3.8 */
1846 { szOID_EMBEDDED_NT_CRYPTO, IDS_PURPOSE_EMBEDDED_NT },
1847 /* 1.3.6.1.4.1.311.10.3.9 */
1848 { szOID_ROOT_LIST_SIGNER, IDS_PURPOSE_ROOT_LIST_SIGNER },
1849 /* 1.3.6.1.4.1.311.10.3.10 */
1850 { szOID_KP_QUALIFIED_SUBORDINATION, IDS_PURPOSE_QUALIFIED_SUBORDINATION },
1851 /* 1.3.6.1.4.1.311.10.3.11 */
1852 { szOID_KP_KEY_RECOVERY, IDS_PURPOSE_KEY_RECOVERY },
1853 /* 1.3.6.1.4.1.311.10.3.12 */
1854 { szOID_KP_DOCUMENT_SIGNING, IDS_PURPOSE_DOCUMENT_SIGNING },
1855 /* 1.3.6.1.4.1.311.10.3.13 */
1856 { szOID_KP_LIFETIME_SIGNING, IDS_PURPOSE_LIFETIME_SIGNING },
1857 /* 1.3.6.1.4.1.311.10.5.1 */
1858 { szOID_DRM, IDS_PURPOSE_DRM },
1859 /* 1.3.6.1.4.1.311.10.6.1 */
1860 { szOID_LICENSES, IDS_PURPOSE_LICENSES },
1861 /* 1.3.6.1.4.1.311.10.6.2 */
1862 { szOID_LICENSE_SERVER, IDS_PURPOSE_LICENSE_SERVER },
1863 /* 1.3.6.1.4.1.311.20.2.1 */
1864 { szOID_ENROLLMENT_AGENT, IDS_PURPOSE_ENROLLMENT_AGENT },
1865 /* 1.3.6.1.4.1.311.20.2.2 */
1866 { szOID_KP_SMARTCARD_LOGON, IDS_PURPOSE_SMARTCARD_LOGON },
1867 /* 1.3.6.1.4.1.311.21.5 */
1868 { szOID_KP_CA_EXCHANGE, IDS_PURPOSE_CA_EXCHANGE },
1869 /* 1.3.6.1.4.1.311.21.6 */
1870 { szOID_KP_KEY_RECOVERY_AGENT, IDS_PURPOSE_KEY_RECOVERY_AGENT },
1871 /* 1.3.6.1.4.1.311.21.19 */
1872 { szOID_DS_EMAIL_REPLICATION, IDS_PURPOSE_DS_EMAIL_REPLICATION },
1873 /* 1.3.6.1.5.5.7.3.1 */
1874 { szOID_PKIX_KP_SERVER_AUTH, IDS_PURPOSE_SERVER_AUTH },
1875 /* 1.3.6.1.5.5.7.3.2 */
1876 { szOID_PKIX_KP_CLIENT_AUTH, IDS_PURPOSE_CLIENT_AUTH },
1877 /* 1.3.6.1.5.5.7.3.3 */
1878 { szOID_PKIX_KP_CODE_SIGNING, IDS_PURPOSE_CODE_SIGNING },
1879 /* 1.3.6.1.5.5.7.3.4 */
1880 { szOID_PKIX_KP_EMAIL_PROTECTION, IDS_PURPOSE_EMAIL_PROTECTION },
1881 /* 1.3.6.1.5.5.7.3.5 */
1882 { szOID_PKIX_KP_IPSEC_END_SYSTEM, IDS_PURPOSE_IPSEC },
1883 /* 1.3.6.1.5.5.7.3.6 */
1884 { szOID_PKIX_KP_IPSEC_TUNNEL, IDS_PURPOSE_IPSEC },
1885 /* 1.3.6.1.5.5.7.3.7 */
1886 { szOID_PKIX_KP_IPSEC_USER, IDS_PURPOSE_IPSEC },
1887 /* 1.3.6.1.5.5.7.3.8 */
1888 { szOID_PKIX_KP_TIMESTAMP_SIGNING, IDS_PURPOSE_TIMESTAMP_SIGNING },
1891 static struct OIDToString *findSupportedOID(LPCSTR oid)
1893 int indexHigh = sizeof(oidMap) / sizeof(oidMap[0]) - 1, indexLow = 0, i;
1894 struct OIDToString *ret = NULL;
1896 for (i = (indexLow + indexHigh) / 2; !ret && indexLow <= indexHigh;
1897 i = (indexLow + indexHigh) / 2)
1899 int cmp;
1901 cmp = strcmp(oid, oidMap[i].oid);
1902 if (!cmp)
1903 ret = &oidMap[i];
1904 else if (cmp > 0)
1905 indexLow = i + 1;
1906 else
1907 indexHigh = i - 1;
1909 return ret;
1912 static void add_local_oid_text_to_control(HWND text, LPCSTR oid)
1914 struct OIDToString *entry;
1915 WCHAR nl = '\n';
1916 PARAFORMAT2 parFmt;
1918 parFmt.cbSize = sizeof(parFmt);
1919 parFmt.dwMask = PFM_STARTINDENT;
1920 parFmt.dxStartIndent = MY_INDENT * 3;
1921 if ((entry = findSupportedOID(oid)))
1923 WCHAR *str, *linebreak, *ptr;
1924 BOOL multiline = FALSE;
1925 int len;
1927 len = LoadStringW(hInstance, entry->id, (LPWSTR)&str, 0);
1928 ptr = str;
1929 do {
1930 if ((linebreak = memchrW(ptr, '\n', len)))
1932 WCHAR copy[MAX_STRING_LEN];
1934 multiline = TRUE;
1935 /* The source string contains a newline, which the richedit
1936 * control won't find since it's interpreted as a paragraph
1937 * break. Therefore copy up to the newline. lstrcpynW always
1938 * NULL-terminates, so pass one more than the length of the
1939 * source line so the copy includes the entire line and the
1940 * NULL-terminator.
1942 lstrcpynW(copy, ptr, linebreak - ptr + 1);
1943 add_text_with_paraformat_to_control(text, copy,
1944 linebreak - ptr, &parFmt);
1945 ptr = linebreak + 1;
1946 add_unformatted_text_to_control(text, &nl, 1);
1948 else if (multiline && *ptr)
1950 /* Add the last line */
1951 add_text_with_paraformat_to_control(text, ptr,
1952 len - (ptr - str), &parFmt);
1953 add_unformatted_text_to_control(text, &nl, 1);
1955 } while (linebreak);
1956 if (!multiline)
1958 add_text_with_paraformat_to_control(text, str, len, &parFmt);
1959 add_unformatted_text_to_control(text, &nl, 1);
1962 else
1964 WCHAR *oidW = HeapAlloc(GetProcessHeap(), 0,
1965 (strlen(oid) + 1) * sizeof(WCHAR));
1967 if (oidW)
1969 LPCSTR src;
1970 WCHAR *dst;
1972 for (src = oid, dst = oidW; *src; src++, dst++)
1973 *dst = *src;
1974 *dst = 0;
1975 add_text_with_paraformat_to_control(text, oidW, lstrlenW(oidW),
1976 &parFmt);
1977 add_unformatted_text_to_control(text, &nl, 1);
1978 HeapFree(GetProcessHeap(), 0, oidW);
1983 static void display_app_usages(HWND text, PCCERT_CONTEXT cert,
1984 BOOL *anyUsageAdded)
1986 static char any_app_policy[] = szOID_ANY_APPLICATION_POLICY;
1987 WCHAR nl = '\n';
1988 CHARFORMATW charFmt;
1989 PCERT_EXTENSION policyExt;
1990 if (!*anyUsageAdded)
1992 PARAFORMAT2 parFmt;
1994 parFmt.cbSize = sizeof(parFmt);
1995 parFmt.dwMask = PFM_STARTINDENT;
1996 parFmt.dxStartIndent = MY_INDENT;
1997 add_string_resource_with_paraformat_to_control(text,
1998 IDS_CERT_INFO_PURPOSES, &parFmt);
1999 add_unformatted_text_to_control(text, &nl, 1);
2000 *anyUsageAdded = TRUE;
2002 memset(&charFmt, 0, sizeof(charFmt));
2003 charFmt.cbSize = sizeof(charFmt);
2004 charFmt.dwMask = CFM_BOLD;
2005 charFmt.dwEffects = 0;
2006 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2007 if ((policyExt = CertFindExtension(szOID_APPLICATION_CERT_POLICIES,
2008 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension)))
2010 CERT_POLICIES_INFO *policies;
2011 DWORD size;
2013 if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_POLICIES,
2014 policyExt->Value.pbData, policyExt->Value.cbData,
2015 CRYPT_DECODE_ALLOC_FLAG, NULL, &policies, &size))
2017 DWORD i;
2019 for (i = 0; i < policies->cPolicyInfo; i++)
2021 DWORD j;
2023 for (j = 0; j < policies->rgPolicyInfo[i].cPolicyQualifier; j++)
2024 add_local_oid_text_to_control(text,
2025 policies->rgPolicyInfo[i].rgPolicyQualifier[j].
2026 pszPolicyQualifierId);
2028 LocalFree(policies);
2031 else
2032 add_oid_text_to_control(text, any_app_policy);
2035 static BOOL display_cert_usages(HWND text, PCCERT_CONTEXT cert,
2036 BOOL *anyUsageAdded)
2038 WCHAR nl = '\n';
2039 DWORD size;
2040 BOOL badUsages = FALSE;
2042 if (CertGetEnhancedKeyUsage(cert, 0, NULL, &size))
2044 CHARFORMATW charFmt;
2045 static char any_cert_policy[] = szOID_ANY_CERT_POLICY;
2046 PCERT_ENHKEY_USAGE usage = HeapAlloc(GetProcessHeap(), 0, size);
2048 if (usage)
2050 if (CertGetEnhancedKeyUsage(cert, 0, usage, &size))
2052 DWORD i;
2054 if (!*anyUsageAdded)
2056 PARAFORMAT2 parFmt;
2058 parFmt.cbSize = sizeof(parFmt);
2059 parFmt.dwMask = PFM_STARTINDENT;
2060 parFmt.dxStartIndent = MY_INDENT;
2061 add_string_resource_with_paraformat_to_control(text,
2062 IDS_CERT_INFO_PURPOSES, &parFmt);
2063 add_unformatted_text_to_control(text, &nl, 1);
2064 *anyUsageAdded = TRUE;
2066 memset(&charFmt, 0, sizeof(charFmt));
2067 charFmt.cbSize = sizeof(charFmt);
2068 charFmt.dwMask = CFM_BOLD;
2069 charFmt.dwEffects = 0;
2070 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION,
2071 (LPARAM)&charFmt);
2072 if (!usage->cUsageIdentifier)
2073 add_oid_text_to_control(text, any_cert_policy);
2074 else
2075 for (i = 0; i < usage->cUsageIdentifier; i++)
2076 add_local_oid_text_to_control(text,
2077 usage->rgpszUsageIdentifier[i]);
2079 else
2080 badUsages = TRUE;
2081 HeapFree(GetProcessHeap(), 0, usage);
2083 else
2084 badUsages = TRUE;
2086 else
2087 badUsages = TRUE;
2088 return badUsages;
2091 static void set_policy_text(HWND text,
2092 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
2094 BOOL includeCertUsages = FALSE, includeAppUsages = FALSE;
2095 BOOL badUsages = FALSE, anyUsageAdded = FALSE;
2097 if (pCertViewInfo->cPurposes)
2099 DWORD i;
2101 for (i = 0; i < pCertViewInfo->cPurposes; i++)
2103 if (!strcmp(pCertViewInfo->rgszPurposes[i], szOID_ANY_CERT_POLICY))
2104 includeCertUsages = TRUE;
2105 else if (!strcmp(pCertViewInfo->rgszPurposes[i],
2106 szOID_ANY_APPLICATION_POLICY))
2107 includeAppUsages = TRUE;
2108 else
2109 badUsages = TRUE;
2112 else
2113 includeAppUsages = includeCertUsages = TRUE;
2114 if (includeAppUsages)
2115 display_app_usages(text, pCertViewInfo->pCertContext, &anyUsageAdded);
2116 if (includeCertUsages)
2117 badUsages = display_cert_usages(text, pCertViewInfo->pCertContext,
2118 &anyUsageAdded);
2119 if (badUsages)
2121 PARAFORMAT2 parFmt;
2123 parFmt.cbSize = sizeof(parFmt);
2124 parFmt.dwMask = PFM_STARTINDENT;
2125 parFmt.dxStartIndent = MY_INDENT;
2126 add_string_resource_with_paraformat_to_control(text,
2127 IDS_CERT_INFO_BAD_PURPOSES, &parFmt);
2131 static CRYPT_OBJID_BLOB *find_policy_qualifier(CERT_POLICIES_INFO *policies,
2132 LPCSTR policyOid)
2134 CRYPT_OBJID_BLOB *ret = NULL;
2135 DWORD i;
2137 for (i = 0; !ret && i < policies->cPolicyInfo; i++)
2139 DWORD j;
2141 for (j = 0; !ret && j < policies->rgPolicyInfo[i].cPolicyQualifier; j++)
2142 if (!strcmp(policies->rgPolicyInfo[i].rgPolicyQualifier[j].
2143 pszPolicyQualifierId, policyOid))
2144 ret = &policies->rgPolicyInfo[i].rgPolicyQualifier[j].
2145 Qualifier;
2147 return ret;
2150 static WCHAR *get_cps_str_from_qualifier(CRYPT_OBJID_BLOB *qualifier)
2152 LPWSTR qualifierStr = NULL;
2153 CERT_NAME_VALUE *qualifierValue;
2154 DWORD size;
2156 if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME_VALUE,
2157 qualifier->pbData, qualifier->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL,
2158 &qualifierValue, &size))
2160 size = CertRDNValueToStrW(qualifierValue->dwValueType,
2161 &qualifierValue->Value, NULL, 0);
2162 qualifierStr = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
2163 if (qualifierStr)
2164 CertRDNValueToStrW(qualifierValue->dwValueType,
2165 &qualifierValue->Value, qualifierStr, size);
2166 LocalFree(qualifierValue);
2168 return qualifierStr;
2171 static WCHAR *get_user_notice_from_qualifier(CRYPT_OBJID_BLOB *qualifier)
2173 LPWSTR str = NULL;
2174 CERT_POLICY_QUALIFIER_USER_NOTICE *qualifierValue;
2175 DWORD size;
2177 if (CryptDecodeObjectEx(X509_ASN_ENCODING,
2178 X509_PKIX_POLICY_QUALIFIER_USERNOTICE,
2179 qualifier->pbData, qualifier->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL,
2180 &qualifierValue, &size))
2182 str = HeapAlloc(GetProcessHeap(), 0,
2183 (strlenW(qualifierValue->pszDisplayText) + 1) * sizeof(WCHAR));
2184 if (str)
2185 strcpyW(str, qualifierValue->pszDisplayText);
2186 LocalFree(qualifierValue);
2188 return str;
2191 struct IssuerStatement
2193 LPWSTR cps;
2194 LPWSTR userNotice;
2197 static void set_issuer_statement(HWND hwnd,
2198 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
2200 PCERT_EXTENSION policyExt;
2202 if (!(pCertViewInfo->dwFlags & CRYPTUI_DISABLE_ISSUERSTATEMENT) &&
2203 (policyExt = CertFindExtension(szOID_CERT_POLICIES,
2204 pCertViewInfo->pCertContext->pCertInfo->cExtension,
2205 pCertViewInfo->pCertContext->pCertInfo->rgExtension)))
2207 CERT_POLICIES_INFO *policies;
2208 DWORD size;
2210 if (CryptDecodeObjectEx(X509_ASN_ENCODING, policyExt->pszObjId,
2211 policyExt->Value.pbData, policyExt->Value.cbData,
2212 CRYPT_DECODE_ALLOC_FLAG, NULL, &policies, &size))
2214 CRYPT_OBJID_BLOB *qualifier;
2215 LPWSTR cps = NULL, userNotice = NULL;
2217 if ((qualifier = find_policy_qualifier(policies,
2218 szOID_PKIX_POLICY_QUALIFIER_CPS)))
2219 cps = get_cps_str_from_qualifier(qualifier);
2220 if ((qualifier = find_policy_qualifier(policies,
2221 szOID_PKIX_POLICY_QUALIFIER_USERNOTICE)))
2222 userNotice = get_user_notice_from_qualifier(qualifier);
2223 if (cps || userNotice)
2225 struct IssuerStatement *issuerStatement =
2226 HeapAlloc(GetProcessHeap(), 0, sizeof(struct IssuerStatement));
2228 if (issuerStatement)
2230 issuerStatement->cps = cps;
2231 issuerStatement->userNotice = userNotice;
2232 EnableWindow(GetDlgItem(hwnd, IDC_ISSUERSTATEMENT), TRUE);
2233 SetWindowLongPtrW(hwnd, DWLP_USER,
2234 (ULONG_PTR)issuerStatement);
2237 LocalFree(policies);
2242 static void set_cert_info(HWND hwnd,
2243 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
2245 CHARFORMATW charFmt;
2246 PARAFORMAT2 parFmt;
2247 HWND icon = GetDlgItem(hwnd, IDC_CERTIFICATE_ICON);
2248 HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_INFO);
2249 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
2250 (CRYPT_PROVIDER_DATA *)pCertViewInfo->u.pCryptProviderData,
2251 pCertViewInfo->idxSigner, pCertViewInfo->fCounterSigner,
2252 pCertViewInfo->idxCounterSigner);
2253 CRYPT_PROVIDER_CERT *root =
2254 &provSigner->pasCertChain[provSigner->csCertChain - 1];
2256 if (!provSigner->pChainContext ||
2257 (provSigner->pChainContext->TrustStatus.dwErrorStatus &
2258 CERT_TRUST_IS_PARTIAL_CHAIN))
2259 add_icon_to_control(icon, IDB_CERT_WARNING);
2260 else if (!root->fTrustedRoot)
2261 add_icon_to_control(icon, IDB_CERT_ERROR);
2262 else
2263 add_icon_to_control(icon, IDB_CERT);
2265 memset(&charFmt, 0, sizeof(charFmt));
2266 charFmt.cbSize = sizeof(charFmt);
2267 charFmt.dwMask = CFM_BOLD;
2268 charFmt.dwEffects = CFE_BOLD;
2269 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2270 /* FIXME: vertically center text */
2271 parFmt.cbSize = sizeof(parFmt);
2272 parFmt.dwMask = PFM_STARTINDENT;
2273 parFmt.dxStartIndent = MY_INDENT;
2274 add_string_resource_with_paraformat_to_control(text,
2275 IDS_CERTIFICATEINFORMATION, &parFmt);
2277 text = GetDlgItem(hwnd, IDC_CERTIFICATE_STATUS);
2278 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2279 if (provSigner->dwError == TRUST_E_CERT_SIGNATURE)
2280 add_string_resource_with_paraformat_to_control(text,
2281 IDS_CERT_INFO_BAD_SIG, &parFmt);
2282 else if (!provSigner->pChainContext ||
2283 (provSigner->pChainContext->TrustStatus.dwErrorStatus &
2284 CERT_TRUST_IS_PARTIAL_CHAIN))
2285 add_string_resource_with_paraformat_to_control(text,
2286 IDS_CERT_INFO_PARTIAL_CHAIN, &parFmt);
2287 else if (!root->fTrustedRoot)
2289 if (provSigner->csCertChain == 1 && root->fSelfSigned)
2290 add_string_resource_with_paraformat_to_control(text,
2291 IDS_CERT_INFO_UNTRUSTED_CA, &parFmt);
2292 else
2293 add_string_resource_with_paraformat_to_control(text,
2294 IDS_CERT_INFO_UNTRUSTED_ROOT, &parFmt);
2296 else
2298 set_policy_text(text, pCertViewInfo);
2299 set_issuer_statement(hwnd, pCertViewInfo);
2303 static void set_cert_name_string(HWND hwnd, PCCERT_CONTEXT cert,
2304 DWORD nameFlags, int heading)
2306 WCHAR nl = '\n';
2307 HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_NAMES);
2308 CHARFORMATW charFmt;
2309 PARAFORMAT2 parFmt;
2311 memset(&charFmt, 0, sizeof(charFmt));
2312 charFmt.cbSize = sizeof(charFmt);
2313 charFmt.dwMask = CFM_BOLD;
2314 charFmt.dwEffects = CFE_BOLD;
2315 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2316 parFmt.cbSize = sizeof(parFmt);
2317 parFmt.dwMask = PFM_STARTINDENT;
2318 parFmt.dxStartIndent = MY_INDENT * 3;
2319 add_string_resource_with_paraformat_to_control(text, heading, &parFmt);
2320 charFmt.dwEffects = 0;
2321 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2322 add_cert_string_to_control(text, cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
2323 nameFlags);
2324 add_unformatted_text_to_control(text, &nl, 1);
2325 add_unformatted_text_to_control(text, &nl, 1);
2326 add_unformatted_text_to_control(text, &nl, 1);
2330 static void add_date_string_to_control(HWND hwnd, const FILETIME *fileTime)
2332 WCHAR dateFmt[80]; /* sufficient for all versions of LOCALE_SSHORTDATE */
2333 WCHAR date[80];
2334 SYSTEMTIME sysTime;
2336 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SSHORTDATE, dateFmt,
2337 sizeof(dateFmt) / sizeof(dateFmt[0]));
2338 FileTimeToSystemTime(fileTime, &sysTime);
2339 GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, date,
2340 sizeof(date) / sizeof(date[0]));
2341 add_unformatted_text_to_control(hwnd, date, lstrlenW(date));
2344 static void set_cert_validity_period(HWND hwnd, PCCERT_CONTEXT cert)
2346 WCHAR nl = '\n';
2347 HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_NAMES);
2348 CHARFORMATW charFmt;
2349 PARAFORMAT2 parFmt;
2351 memset(&charFmt, 0, sizeof(charFmt));
2352 charFmt.cbSize = sizeof(charFmt);
2353 charFmt.dwMask = CFM_BOLD;
2354 charFmt.dwEffects = CFE_BOLD;
2355 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2356 parFmt.cbSize = sizeof(parFmt);
2357 parFmt.dwMask = PFM_STARTINDENT;
2358 parFmt.dxStartIndent = MY_INDENT * 3;
2359 add_string_resource_with_paraformat_to_control(text, IDS_VALID_FROM,
2360 &parFmt);
2361 charFmt.dwEffects = 0;
2362 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2363 add_date_string_to_control(text, &cert->pCertInfo->NotBefore);
2364 charFmt.dwEffects = CFE_BOLD;
2365 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2366 add_string_resource_to_control(text, IDS_VALID_TO);
2367 charFmt.dwEffects = 0;
2368 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2369 add_date_string_to_control(text, &cert->pCertInfo->NotAfter);
2370 add_unformatted_text_to_control(text, &nl, 1);
2373 static void set_general_info(HWND hwnd,
2374 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
2376 set_cert_info(hwnd, pCertViewInfo);
2377 set_cert_name_string(hwnd, pCertViewInfo->pCertContext, 0,
2378 IDS_SUBJECT_HEADING);
2379 set_cert_name_string(hwnd, pCertViewInfo->pCertContext,
2380 CERT_NAME_ISSUER_FLAG, IDS_ISSUER_HEADING);
2381 set_cert_validity_period(hwnd, pCertViewInfo->pCertContext);
2384 static LRESULT CALLBACK user_notice_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
2385 LPARAM lp)
2387 LRESULT ret = 0;
2388 HWND text;
2389 struct IssuerStatement *issuerStatement;
2391 switch (msg)
2393 case WM_INITDIALOG:
2394 text = GetDlgItem(hwnd, IDC_USERNOTICE);
2395 issuerStatement = (struct IssuerStatement *)lp;
2396 add_unformatted_text_to_control(text, issuerStatement->userNotice,
2397 strlenW(issuerStatement->userNotice));
2398 if (issuerStatement->cps)
2399 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)issuerStatement->cps);
2400 else
2401 EnableWindow(GetDlgItem(hwnd, IDC_CPS), FALSE);
2402 break;
2403 case WM_COMMAND:
2404 switch (wp)
2406 case IDOK:
2407 EndDialog(hwnd, IDOK);
2408 ret = TRUE;
2409 break;
2410 case IDC_CPS:
2412 IBindCtx *bctx = NULL;
2413 LPWSTR cps;
2415 CreateBindCtx(0, &bctx);
2416 cps = (LPWSTR)GetWindowLongPtrW(hwnd, DWLP_USER);
2417 HlinkSimpleNavigateToString(cps, NULL, NULL, NULL, bctx, NULL,
2418 HLNF_OPENINNEWWINDOW, 0);
2419 IBindCtx_Release(bctx);
2420 break;
2424 return ret;
2427 static void show_user_notice(HWND hwnd, struct IssuerStatement *issuerStatement)
2429 DialogBoxParamW(hInstance, MAKEINTRESOURCEW(IDD_USERNOTICE), hwnd,
2430 user_notice_dlg_proc, (LPARAM)issuerStatement);
2433 static LRESULT CALLBACK general_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
2434 LPARAM lp)
2436 PROPSHEETPAGEW *page;
2437 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo;
2439 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
2441 switch (msg)
2443 case WM_INITDIALOG:
2444 page = (PROPSHEETPAGEW *)lp;
2445 pCertViewInfo = (PCCRYPTUI_VIEWCERTIFICATE_STRUCTW)page->lParam;
2446 if (pCertViewInfo->dwFlags & CRYPTUI_DISABLE_ADDTOSTORE)
2447 ShowWindow(GetDlgItem(hwnd, IDC_ADDTOSTORE), FALSE);
2448 EnableWindow(GetDlgItem(hwnd, IDC_ISSUERSTATEMENT), FALSE);
2449 set_general_info(hwnd, pCertViewInfo);
2450 break;
2451 case WM_COMMAND:
2452 switch (wp)
2454 case IDC_ADDTOSTORE:
2455 CryptUIWizImport(0, hwnd, NULL, NULL, NULL);
2456 break;
2457 case IDC_ISSUERSTATEMENT:
2459 struct IssuerStatement *issuerStatement =
2460 (struct IssuerStatement *)GetWindowLongPtrW(hwnd, DWLP_USER);
2462 if (issuerStatement)
2464 if (issuerStatement->userNotice)
2465 show_user_notice(hwnd, issuerStatement);
2466 else if (issuerStatement->cps)
2468 IBindCtx *bctx = NULL;
2470 CreateBindCtx(0, &bctx);
2471 HlinkSimpleNavigateToString(issuerStatement->cps, NULL,
2472 NULL, NULL, bctx, NULL, HLNF_OPENINNEWWINDOW, 0);
2473 IBindCtx_Release(bctx);
2476 break;
2479 break;
2481 return 0;
2484 static UINT CALLBACK general_callback_proc(HWND hwnd, UINT msg,
2485 PROPSHEETPAGEW *page)
2487 struct IssuerStatement *issuerStatement;
2489 switch (msg)
2491 case PSPCB_RELEASE:
2492 issuerStatement =
2493 (struct IssuerStatement *)GetWindowLongPtrW(hwnd, DWLP_USER);
2494 if (issuerStatement)
2496 HeapFree(GetProcessHeap(), 0, issuerStatement->cps);
2497 HeapFree(GetProcessHeap(), 0, issuerStatement->userNotice);
2498 HeapFree(GetProcessHeap(), 0, issuerStatement);
2500 break;
2502 return 1;
2505 static void init_general_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
2506 PROPSHEETPAGEW *page)
2508 memset(page, 0, sizeof(PROPSHEETPAGEW));
2509 page->dwSize = sizeof(PROPSHEETPAGEW);
2510 page->dwFlags = PSP_USECALLBACK;
2511 page->pfnCallback = general_callback_proc;
2512 page->hInstance = hInstance;
2513 page->u.pszTemplate = MAKEINTRESOURCEW(IDD_GENERAL);
2514 page->pfnDlgProc = general_dlg_proc;
2515 page->lParam = (LPARAM)pCertViewInfo;
2518 typedef WCHAR * (*field_format_func)(PCCERT_CONTEXT cert);
2520 static WCHAR *field_format_version(PCCERT_CONTEXT cert)
2522 static const WCHAR fmt[] = { 'V','%','d',0 };
2523 WCHAR *buf = HeapAlloc(GetProcessHeap(), 0, 12 * sizeof(WCHAR));
2525 if (buf)
2526 sprintfW(buf, fmt, cert->pCertInfo->dwVersion);
2527 return buf;
2530 static WCHAR *format_hex_string(void *pb, DWORD cb)
2532 WCHAR *buf = HeapAlloc(GetProcessHeap(), 0, (cb * 3 + 1) * sizeof(WCHAR));
2534 if (buf)
2536 static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
2537 DWORD i;
2538 WCHAR *ptr;
2540 for (i = 0, ptr = buf; i < cb; i++, ptr += 3)
2541 sprintfW(ptr, fmt, ((BYTE *)pb)[i]);
2543 return buf;
2546 static WCHAR *field_format_serial_number(PCCERT_CONTEXT cert)
2548 return format_hex_string(cert->pCertInfo->SerialNumber.pbData,
2549 cert->pCertInfo->SerialNumber.cbData);
2552 static WCHAR *field_format_issuer(PCCERT_CONTEXT cert)
2554 return get_cert_name_string(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
2555 CERT_NAME_ISSUER_FLAG);
2558 static WCHAR *field_format_detailed_cert_name(PCERT_NAME_BLOB name)
2560 WCHAR *str = NULL;
2561 DWORD len = CertNameToStrW(X509_ASN_ENCODING, name,
2562 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, NULL, 0);
2564 if (len)
2566 str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2567 if (str)
2568 CertNameToStrW(X509_ASN_ENCODING, name,
2569 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, str, len);
2571 return str;
2574 static WCHAR *field_format_detailed_issuer(PCCERT_CONTEXT cert, void *param)
2576 return field_format_detailed_cert_name(&cert->pCertInfo->Issuer);
2579 static WCHAR *field_format_subject(PCCERT_CONTEXT cert)
2581 return get_cert_name_string(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0);
2584 static WCHAR *field_format_detailed_subject(PCCERT_CONTEXT cert, void *param)
2586 return field_format_detailed_cert_name(&cert->pCertInfo->Subject);
2589 static WCHAR *format_long_date(const FILETIME *fileTime)
2591 WCHAR dateFmt[80]; /* long enough for LOCALE_SLONGDATE */
2592 DWORD len;
2593 WCHAR *buf = NULL;
2594 SYSTEMTIME sysTime;
2596 /* FIXME: format isn't quite right, want time too */
2597 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SLONGDATE, dateFmt,
2598 sizeof(dateFmt) / sizeof(dateFmt[0]));
2599 FileTimeToSystemTime(fileTime, &sysTime);
2600 len = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, NULL, 0);
2601 if (len)
2603 buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2604 if (buf)
2605 GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, buf,
2606 len);
2608 return buf;
2611 static WCHAR *field_format_from_date(PCCERT_CONTEXT cert)
2613 return format_long_date(&cert->pCertInfo->NotBefore);
2616 static WCHAR *field_format_to_date(PCCERT_CONTEXT cert)
2618 return format_long_date(&cert->pCertInfo->NotAfter);
2621 static WCHAR *field_format_public_key(PCCERT_CONTEXT cert)
2623 PCCRYPT_OID_INFO oidInfo;
2624 WCHAR *buf = NULL;
2626 oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2627 cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, 0);
2628 if (oidInfo)
2630 WCHAR fmt[MAX_STRING_LEN];
2632 if (LoadStringW(hInstance, IDS_FIELD_PUBLIC_KEY_FORMAT, fmt,
2633 sizeof(fmt) / sizeof(fmt[0])))
2635 /* Allocate the output buffer. Use the number of bytes in the
2636 * public key as a conservative (high) estimate for the number of
2637 * digits in its output.
2638 * The output is of the form (in English)
2639 * "<public key algorithm> (<public key bit length> bits)".
2640 * Ordinarily having two positional parameters in a string is not a
2641 * good idea, but as this isn't a sentence fragment, it shouldn't
2642 * be word-order dependent.
2644 buf = HeapAlloc(GetProcessHeap(), 0,
2645 (strlenW(fmt) + strlenW(oidInfo->pwszName) +
2646 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData * 8)
2647 * sizeof(WCHAR));
2648 if (buf)
2649 sprintfW(buf, fmt, oidInfo->pwszName,
2650 CertGetPublicKeyLength(X509_ASN_ENCODING,
2651 &cert->pCertInfo->SubjectPublicKeyInfo));
2654 return buf;
2657 static WCHAR *field_format_detailed_public_key(PCCERT_CONTEXT cert, void *param)
2659 return format_hex_string(
2660 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
2661 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData);
2664 struct field_value_data;
2665 struct detail_data
2667 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo;
2668 BOOL *pfPropertiesChanged;
2669 int cFields;
2670 struct field_value_data *fields;
2673 typedef void (*add_fields_func)(HWND hwnd, struct detail_data *data);
2675 typedef WCHAR *(*create_detailed_value_func)(PCCERT_CONTEXT cert, void *param);
2677 struct field_value_data
2679 create_detailed_value_func create;
2680 LPWSTR detailed_value;
2681 void *param;
2684 static void add_field_value_data(struct detail_data *data,
2685 create_detailed_value_func create, void *param)
2687 if (data->cFields)
2688 data->fields = HeapReAlloc(GetProcessHeap(), 0, data->fields,
2689 (data->cFields + 1) * sizeof(struct field_value_data));
2690 else
2691 data->fields = HeapAlloc(GetProcessHeap(), 0,
2692 sizeof(struct field_value_data));
2693 if (data->fields)
2695 data->fields[data->cFields].create = create;
2696 data->fields[data->cFields].detailed_value = NULL;
2697 data->fields[data->cFields].param = param;
2698 data->cFields++;
2702 static void add_field_and_value_to_list(HWND hwnd, struct detail_data *data,
2703 LPWSTR field, LPWSTR value, create_detailed_value_func create, void *param)
2705 LVITEMW item;
2706 int iItem = SendMessageW(hwnd, LVM_GETITEMCOUNT, 0, 0);
2708 item.mask = LVIF_TEXT | LVIF_PARAM;
2709 item.iItem = iItem;
2710 item.iSubItem = 0;
2711 item.pszText = field;
2712 item.lParam = (LPARAM)data;
2713 SendMessageW(hwnd, LVM_INSERTITEMW, 0, (LPARAM)&item);
2714 if (value)
2716 item.pszText = value;
2717 item.iSubItem = 1;
2718 SendMessageW(hwnd, LVM_SETITEMTEXTW, iItem, (LPARAM)&item);
2720 add_field_value_data(data, create, param);
2723 static void add_string_id_and_value_to_list(HWND hwnd, struct detail_data *data,
2724 int id, LPWSTR value, create_detailed_value_func create, void *param)
2726 WCHAR buf[MAX_STRING_LEN];
2728 LoadStringW(hInstance, id, buf, sizeof(buf) / sizeof(buf[0]));
2729 add_field_and_value_to_list(hwnd, data, buf, value, create, param);
2732 struct v1_field
2734 int id;
2735 field_format_func format;
2736 create_detailed_value_func create_detailed_value;
2739 static void add_v1_field(HWND hwnd, struct detail_data *data,
2740 const struct v1_field *field)
2742 WCHAR *val = field->format(data->pCertViewInfo->pCertContext);
2744 if (val)
2746 add_string_id_and_value_to_list(hwnd, data, field->id, val,
2747 field->create_detailed_value, NULL);
2748 HeapFree(GetProcessHeap(), 0, val);
2752 static const struct v1_field v1_fields[] = {
2753 { IDS_FIELD_VERSION, field_format_version, NULL },
2754 { IDS_FIELD_SERIAL_NUMBER, field_format_serial_number, NULL },
2755 { IDS_FIELD_ISSUER, field_format_issuer, field_format_detailed_issuer },
2756 { IDS_FIELD_VALID_FROM, field_format_from_date, NULL },
2757 { IDS_FIELD_VALID_TO, field_format_to_date, NULL },
2758 { IDS_FIELD_SUBJECT, field_format_subject, field_format_detailed_subject },
2759 { IDS_FIELD_PUBLIC_KEY, field_format_public_key,
2760 field_format_detailed_public_key }
2763 static void add_v1_fields(HWND hwnd, struct detail_data *data)
2765 int i;
2766 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
2768 /* The last item in v1_fields is the public key, which is not in the loop
2769 * because it's a special case.
2771 for (i = 0; i < sizeof(v1_fields) / sizeof(v1_fields[0]) - 1; i++)
2772 add_v1_field(hwnd, data, &v1_fields[i]);
2773 if (cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData)
2774 add_v1_field(hwnd, data, &v1_fields[i]);
2777 static WCHAR *crypt_format_extension(PCERT_EXTENSION ext, DWORD formatStrType)
2779 WCHAR *str = NULL;
2780 DWORD size;
2782 if (CryptFormatObject(X509_ASN_ENCODING, 0, formatStrType, NULL,
2783 ext->pszObjId, ext->Value.pbData, ext->Value.cbData, NULL, &size))
2785 str = HeapAlloc(GetProcessHeap(), 0, size);
2786 CryptFormatObject(X509_ASN_ENCODING, 0, formatStrType, NULL,
2787 ext->pszObjId, ext->Value.pbData, ext->Value.cbData, str, &size);
2789 return str;
2792 static WCHAR *field_format_extension_hex_with_ascii(PCERT_EXTENSION ext)
2794 WCHAR *str = NULL;
2796 if (ext->Value.cbData)
2798 /* The output is formatted as:
2799 * <hex bytes> <ascii bytes>\n
2800 * where <hex bytes> is a string of up to 8 bytes, output as %02x,
2801 * and <ascii bytes> is the ASCII equivalent of each byte, or '.' if
2802 * the byte is not printable.
2803 * So, for example, the extension value consisting of the following
2804 * bytes:
2805 * 0x30,0x14,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x03,
2806 * 0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67
2807 * is output as:
2808 * 30 14 31 12 30 10 06 03 0.1.0...
2809 * 55 04 03 13 09 4a 75 61 U....Jua
2810 * 6e 20 4c 61 6e 67 n Lang
2811 * The allocation size therefore requires:
2812 * - 4 characters per character in an 8-byte line
2813 * (2 for the hex format, one for the space, one for the ASCII value)
2814 * - 3 more characters per 8-byte line (two spaces and a newline)
2815 * - 1 character for the terminating nul
2816 * FIXME: should use a fixed-width font for this
2818 DWORD lines = (ext->Value.cbData + 7) / 8;
2820 str = HeapAlloc(GetProcessHeap(), 0,
2821 (lines * 8 * 4 + lines * 3 + 1) * sizeof(WCHAR));
2822 if (str)
2824 static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
2825 DWORD i, j;
2826 WCHAR *ptr;
2828 for (i = 0, ptr = str; i < ext->Value.cbData; i += 8)
2830 /* Output as hex bytes first */
2831 for (j = i; j < min(i + 8, ext->Value.cbData); j++, ptr += 3)
2832 sprintfW(ptr, fmt, ext->Value.pbData[j]);
2833 /* Pad the hex output with spaces for alignment */
2834 if (j == ext->Value.cbData && j % 8)
2836 static const WCHAR pad[] = { ' ',' ',' ' };
2838 for (; j % 8; j++, ptr += sizeof(pad) / sizeof(pad[0]))
2839 memcpy(ptr, pad, sizeof(pad));
2841 /* The last sprintfW included a space, so just insert one
2842 * more space between the hex bytes and the ASCII output
2844 *ptr++ = ' ';
2845 /* Output as ASCII bytes */
2846 for (j = i; j < min(i + 8, ext->Value.cbData); j++, ptr++)
2848 if (isprintW(ext->Value.pbData[j]) &&
2849 !isspaceW(ext->Value.pbData[j]))
2850 *ptr = ext->Value.pbData[j];
2851 else
2852 *ptr = '.';
2854 *ptr++ = '\n';
2856 *ptr++ = '\0';
2859 return str;
2862 static WCHAR *field_format_detailed_extension(PCCERT_CONTEXT cert, void *param)
2864 PCERT_EXTENSION ext = param;
2865 LPWSTR str = crypt_format_extension(ext,
2866 CRYPT_FORMAT_STR_MULTI_LINE | CRYPT_FORMAT_STR_NO_HEX);
2868 if (!str)
2869 str = field_format_extension_hex_with_ascii(ext);
2870 return str;
2873 static void add_cert_extension_detail(HWND hwnd, struct detail_data *data,
2874 PCERT_EXTENSION ext)
2876 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2877 ext->pszObjId, 0);
2878 LPWSTR val = crypt_format_extension(ext, 0);
2880 if (oidInfo)
2881 add_field_and_value_to_list(hwnd, data, (LPWSTR)oidInfo->pwszName,
2882 val, field_format_detailed_extension, ext);
2883 else
2885 DWORD len = strlen(ext->pszObjId);
2886 LPWSTR oidW = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2888 if (oidW)
2890 DWORD i;
2892 for (i = 0; i <= len; i++)
2893 oidW[i] = ext->pszObjId[i];
2894 add_field_and_value_to_list(hwnd, data, oidW, val,
2895 field_format_detailed_extension, ext);
2896 HeapFree(GetProcessHeap(), 0, oidW);
2899 HeapFree(GetProcessHeap(), 0, val);
2902 static void add_all_extensions(HWND hwnd, struct detail_data *data)
2904 DWORD i;
2905 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
2907 for (i = 0; i < cert->pCertInfo->cExtension; i++)
2908 add_cert_extension_detail(hwnd, data, &cert->pCertInfo->rgExtension[i]);
2911 static void add_critical_extensions(HWND hwnd, struct detail_data *data)
2913 DWORD i;
2914 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
2916 for (i = 0; i < cert->pCertInfo->cExtension; i++)
2917 if (cert->pCertInfo->rgExtension[i].fCritical)
2918 add_cert_extension_detail(hwnd, data,
2919 &cert->pCertInfo->rgExtension[i]);
2922 typedef WCHAR * (*prop_to_value_func)(void *pb, DWORD cb);
2924 struct prop_id_to_string_id
2926 DWORD prop;
2927 int id;
2928 BOOL prop_is_string;
2929 prop_to_value_func prop_to_value;
2932 static WCHAR *format_enhanced_key_usage_value(void *pb, DWORD cb)
2934 CERT_EXTENSION ext;
2936 ext.pszObjId = (LPSTR)X509_ENHANCED_KEY_USAGE;
2937 ext.fCritical = FALSE;
2938 ext.Value.pbData = pb;
2939 ext.Value.cbData = cb;
2940 return crypt_format_extension(&ext, 0);
2943 /* Logically the access state should also be checked, and IDC_EDITPROPERTIES
2944 * disabled for read-only certificates, but native doesn't appear to do that.
2946 static const struct prop_id_to_string_id prop_id_map[] = {
2947 { CERT_HASH_PROP_ID, IDS_PROP_HASH, FALSE, format_hex_string },
2948 { CERT_FRIENDLY_NAME_PROP_ID, IDS_PROP_FRIENDLY_NAME, TRUE, NULL },
2949 { CERT_DESCRIPTION_PROP_ID, IDS_PROP_DESCRIPTION, TRUE, NULL },
2950 { CERT_ENHKEY_USAGE_PROP_ID, IDS_PROP_ENHKEY_USAGE, FALSE,
2951 format_enhanced_key_usage_value },
2954 static void add_properties(HWND hwnd, struct detail_data *data)
2956 DWORD i;
2957 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
2959 for (i = 0; i < sizeof(prop_id_map) / sizeof(prop_id_map[0]); i++)
2961 DWORD cb;
2963 if (CertGetCertificateContextProperty(cert, prop_id_map[i].prop, NULL,
2964 &cb))
2966 BYTE *pb;
2967 WCHAR *val = NULL;
2969 /* FIXME: MS adds a separate value for the signature hash
2970 * algorithm.
2972 pb = HeapAlloc(GetProcessHeap(), 0, cb);
2973 if (pb)
2975 if (CertGetCertificateContextProperty(cert,
2976 prop_id_map[i].prop, pb, &cb))
2978 if (prop_id_map[i].prop_is_string)
2980 val = (LPWSTR)pb;
2981 /* Don't double-free pb */
2982 pb = NULL;
2984 else
2985 val = prop_id_map[i].prop_to_value(pb, cb);
2987 HeapFree(GetProcessHeap(), 0, pb);
2989 add_string_id_and_value_to_list(hwnd, data, prop_id_map[i].id, val,
2990 NULL, NULL);
2995 static void add_all_fields(HWND hwnd, struct detail_data *data)
2997 add_v1_fields(hwnd, data);
2998 add_all_extensions(hwnd, data);
2999 add_properties(hwnd, data);
3002 struct selection_list_item
3004 int id;
3005 add_fields_func add;
3008 const struct selection_list_item listItems[] = {
3009 { IDS_FIELDS_ALL, add_all_fields },
3010 { IDS_FIELDS_V1, add_v1_fields },
3011 { IDS_FIELDS_EXTENSIONS, add_all_extensions },
3012 { IDS_FIELDS_CRITICAL_EXTENSIONS, add_critical_extensions },
3013 { IDS_FIELDS_PROPERTIES, add_properties },
3016 static void create_show_list(HWND hwnd, struct detail_data *data)
3018 HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT);
3019 WCHAR buf[MAX_STRING_LEN];
3020 int i;
3022 for (i = 0; i < sizeof(listItems) / sizeof(listItems[0]); i++)
3024 int index;
3026 LoadStringW(hInstance, listItems[i].id, buf,
3027 sizeof(buf) / sizeof(buf[0]));
3028 index = SendMessageW(cb, CB_INSERTSTRING, -1, (LPARAM)buf);
3029 SendMessageW(cb, CB_SETITEMDATA, index, (LPARAM)data);
3031 SendMessageW(cb, CB_SETCURSEL, 0, 0);
3034 static void create_listview_columns(HWND hwnd)
3036 HWND lv = GetDlgItem(hwnd, IDC_DETAIL_LIST);
3037 RECT rc;
3038 WCHAR buf[MAX_STRING_LEN];
3039 LVCOLUMNW column;
3041 SendMessageW(lv, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
3042 GetWindowRect(lv, &rc);
3043 LoadStringW(hInstance, IDS_FIELD, buf, sizeof(buf) / sizeof(buf[0]));
3044 column.mask = LVCF_WIDTH | LVCF_TEXT;
3045 column.cx = (rc.right - rc.left) / 2 - 2;
3046 column.pszText = buf;
3047 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
3048 LoadStringW(hInstance, IDS_VALUE, buf, sizeof(buf) / sizeof(buf[0]));
3049 SendMessageW(lv, LVM_INSERTCOLUMNW, 1, (LPARAM)&column);
3052 static void set_fields_selection(HWND hwnd, struct detail_data *data, int sel)
3054 HWND list = GetDlgItem(hwnd, IDC_DETAIL_LIST);
3056 if (sel >= 0 && sel < sizeof(listItems) / sizeof(listItems[0]))
3058 SendMessageW(list, LVM_DELETEALLITEMS, 0, 0);
3059 listItems[sel].add(list, data);
3063 static void create_cert_details_list(HWND hwnd, struct detail_data *data)
3065 create_show_list(hwnd, data);
3066 create_listview_columns(hwnd);
3067 set_fields_selection(hwnd, data, 0);
3070 static void add_purpose(HWND hwnd, LPCSTR oid)
3072 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
3073 PCRYPT_OID_INFO info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3074 sizeof(CRYPT_OID_INFO));
3076 if (info)
3078 char *oidCopy = HeapAlloc(GetProcessHeap(), 0, strlen(oid) + 1);
3080 if (oidCopy)
3082 LVITEMA item;
3084 strcpy(oidCopy, oid);
3085 info->cbSize = sizeof(CRYPT_OID_INFO);
3086 info->pszOID = oidCopy;
3087 item.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM;
3088 item.state = INDEXTOSTATEIMAGEMASK(CheckBitmapIndexChecked);
3089 item.stateMask = LVIS_STATEIMAGEMASK;
3090 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
3091 item.iSubItem = 0;
3092 item.lParam = (LPARAM)info;
3093 item.pszText = oidCopy;
3094 SendMessageA(lv, LVM_INSERTITEMA, 0, (LPARAM)&item);
3096 else
3097 HeapFree(GetProcessHeap(), 0, info);
3101 static BOOL is_valid_oid(LPCSTR oid)
3103 BOOL ret;
3105 if (oid[0] != '0' && oid[0] != '1' && oid[0] != '2')
3106 ret = FALSE;
3107 else if (oid[1] != '.')
3108 ret = FALSE;
3109 else if (!oid[2])
3110 ret = FALSE;
3111 else
3113 const char *ptr;
3114 BOOL expectNum = TRUE;
3116 for (ptr = oid + 2, ret = TRUE; ret && *ptr; ptr++)
3118 if (expectNum)
3120 if (!isdigit(*ptr))
3121 ret = FALSE;
3122 else if (*(ptr + 1) == '.')
3123 expectNum = FALSE;
3125 else
3127 if (*ptr != '.')
3128 ret = FALSE;
3129 else if (!(*(ptr + 1)))
3130 ret = FALSE;
3131 else
3132 expectNum = TRUE;
3136 return ret;
3139 static BOOL is_oid_in_list(HWND hwnd, LPCSTR oid)
3141 return find_oid_in_list(GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES), oid)
3142 != -1;
3145 #define MAX_PURPOSE 255
3147 static LRESULT CALLBACK add_purpose_dlg_proc(HWND hwnd, UINT msg,
3148 WPARAM wp, LPARAM lp)
3150 LRESULT ret = 0;
3151 char buf[MAX_PURPOSE + 1];
3153 switch (msg)
3155 case WM_INITDIALOG:
3156 SendMessageW(GetDlgItem(hwnd, IDC_NEW_PURPOSE), EM_SETLIMITTEXT,
3157 MAX_PURPOSE, 0);
3158 ShowScrollBar(GetDlgItem(hwnd, IDC_NEW_PURPOSE), SB_VERT, FALSE);
3159 SetWindowLongPtrW(hwnd, DWLP_USER, lp);
3160 break;
3161 case WM_COMMAND:
3162 switch (HIWORD(wp))
3164 case EN_CHANGE:
3165 if (LOWORD(wp) == IDC_NEW_PURPOSE)
3167 /* Show/hide scroll bar on description depending on how much
3168 * text it has.
3170 HWND description = GetDlgItem(hwnd, IDC_NEW_PURPOSE);
3171 int lines = SendMessageW(description, EM_GETLINECOUNT, 0, 0);
3173 ShowScrollBar(description, SB_VERT, lines > 1);
3175 break;
3176 case BN_CLICKED:
3177 switch (LOWORD(wp))
3179 case IDOK:
3180 SendMessageA(GetDlgItem(hwnd, IDC_NEW_PURPOSE), WM_GETTEXT,
3181 sizeof(buf) / sizeof(buf[0]), (LPARAM)buf);
3182 if (!buf[0])
3184 /* An empty purpose is the same as cancelling */
3185 EndDialog(hwnd, IDCANCEL);
3186 ret = TRUE;
3188 else if (!is_valid_oid(buf))
3190 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
3192 LoadStringW(hInstance, IDS_CERTIFICATE_PURPOSE_ERROR, error,
3193 sizeof(error) / sizeof(error[0]));
3194 LoadStringW(hInstance, IDS_CERTIFICATE_PROPERTIES, title,
3195 sizeof(title) / sizeof(title[0]));
3196 MessageBoxW(hwnd, error, title, MB_ICONERROR | MB_OK);
3198 else if (is_oid_in_list(
3199 (HWND)GetWindowLongPtrW(hwnd, DWLP_USER), buf))
3201 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
3203 LoadStringW(hInstance, IDS_CERTIFICATE_PURPOSE_EXISTS,
3204 error, sizeof(error) / sizeof(error[0]));
3205 LoadStringW(hInstance, IDS_CERTIFICATE_PROPERTIES, title,
3206 sizeof(title) / sizeof(title[0]));
3207 MessageBoxW(hwnd, error, title, MB_ICONEXCLAMATION | MB_OK);
3209 else
3211 HWND parent = (HWND)GetWindowLongPtrW(hwnd, DWLP_USER);
3213 add_purpose(parent, buf);
3214 EndDialog(hwnd, wp);
3215 ret = TRUE;
3217 break;
3218 case IDCANCEL:
3219 EndDialog(hwnd, wp);
3220 ret = TRUE;
3221 break;
3223 break;
3225 break;
3227 return ret;
3230 static WCHAR *get_cert_property_as_string(PCCERT_CONTEXT cert, DWORD prop)
3232 WCHAR *name = NULL;
3233 DWORD cb;
3235 if (CertGetCertificateContextProperty(cert, prop, NULL, &cb))
3237 name = HeapAlloc(GetProcessHeap(), 0, cb);
3238 if (name)
3240 if (!CertGetCertificateContextProperty(cert, prop, (LPBYTE)name,
3241 &cb))
3243 HeapFree(GetProcessHeap(), 0, name);
3244 name = NULL;
3248 return name;
3251 static void redraw_states(HWND list, BOOL enabled)
3253 int items = SendMessageW(list, LVM_GETITEMCOUNT, 0, 0), i;
3255 for (i = 0; i < items; i++)
3257 BOOL change = FALSE;
3258 int state;
3260 state = SendMessageW(list, LVM_GETITEMSTATE, i, LVIS_STATEIMAGEMASK);
3261 /* This reverses the INDEXTOSTATEIMAGEMASK shift. There doesn't appear
3262 * to be a handy macro for it.
3264 state >>= 12;
3265 if (enabled)
3267 if (state == CheckBitmapIndexDisabledChecked)
3269 state = CheckBitmapIndexChecked;
3270 change = TRUE;
3272 if (state == CheckBitmapIndexDisabledUnchecked)
3274 state = CheckBitmapIndexUnchecked;
3275 change = TRUE;
3278 else
3280 if (state == CheckBitmapIndexChecked)
3282 state = CheckBitmapIndexDisabledChecked;
3283 change = TRUE;
3285 if (state == CheckBitmapIndexUnchecked)
3287 state = CheckBitmapIndexDisabledUnchecked;
3288 change = TRUE;
3291 if (change)
3293 LVITEMW item;
3295 item.state = INDEXTOSTATEIMAGEMASK(state);
3296 item.stateMask = LVIS_STATEIMAGEMASK;
3297 SendMessageW(list, LVM_SETITEMSTATE, i, (LPARAM)&item);
3302 typedef enum {
3303 PurposeEnableAll = 0,
3304 PurposeDisableAll,
3305 PurposeEnableSelected
3306 } PurposeSelection;
3308 static void select_purposes(HWND hwnd, PurposeSelection selection)
3310 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
3312 switch (selection)
3314 case PurposeEnableAll:
3315 case PurposeDisableAll:
3316 EnableWindow(lv, FALSE);
3317 redraw_states(lv, FALSE);
3318 EnableWindow(GetDlgItem(hwnd, IDC_ADD_PURPOSE), FALSE);
3319 break;
3320 case PurposeEnableSelected:
3321 EnableWindow(lv, TRUE);
3322 redraw_states(lv, TRUE);
3323 EnableWindow(GetDlgItem(hwnd, IDC_ADD_PURPOSE), TRUE);
3327 struct edit_cert_data
3329 PCCERT_CONTEXT cert;
3330 BOOL *pfPropertiesChanged;
3331 HIMAGELIST imageList;
3334 static void show_cert_usages(HWND hwnd, struct edit_cert_data *data)
3336 PCCERT_CONTEXT cert = data->cert;
3337 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
3338 PCERT_ENHKEY_USAGE usage;
3339 DWORD size;
3340 RECT rc;
3341 LVCOLUMNW column;
3342 PurposeSelection purposeSelection;
3344 GetWindowRect(lv, &rc);
3345 column.mask = LVCF_WIDTH;
3346 column.cx = rc.right - rc.left;
3347 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
3348 SendMessageW(lv, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)data->imageList);
3350 /* Get enhanced key usage. Have to check for a property and an extension
3351 * separately, because CertGetEnhancedKeyUsage will succeed and return an
3352 * empty usage if neither is set. Unfortunately an empty usage implies
3353 * no usage is allowed, so we have to distinguish between the two cases.
3355 if (CertGetEnhancedKeyUsage(cert, CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG,
3356 NULL, &size))
3358 usage = HeapAlloc(GetProcessHeap(), 0, size);
3359 if (!CertGetEnhancedKeyUsage(cert,
3360 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size))
3362 HeapFree(GetProcessHeap(), 0, usage);
3363 usage = NULL;
3365 else if (usage->cUsageIdentifier)
3366 purposeSelection = PurposeEnableSelected;
3367 else
3368 purposeSelection = PurposeDisableAll;
3370 else if (CertGetEnhancedKeyUsage(cert, CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
3371 NULL, &size))
3373 usage = HeapAlloc(GetProcessHeap(), 0, size);
3374 if (!CertGetEnhancedKeyUsage(cert,
3375 CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, usage, &size))
3377 HeapFree(GetProcessHeap(), 0, usage);
3378 usage = NULL;
3380 else if (usage->cUsageIdentifier)
3381 purposeSelection = PurposeEnableAll;
3382 else
3383 purposeSelection = PurposeDisableAll;
3385 else
3387 purposeSelection = PurposeEnableAll;
3388 usage = NULL;
3390 if (usage)
3392 DWORD i;
3394 for (i = 0; i < usage->cUsageIdentifier; i++)
3396 PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
3397 usage->rgpszUsageIdentifier[i], CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
3399 if (info)
3400 add_known_usage(lv, info, CheckBitmapIndexDisabledChecked);
3401 else
3402 add_purpose(hwnd, usage->rgpszUsageIdentifier[i]);
3404 HeapFree(GetProcessHeap(), 0, usage);
3406 else
3407 add_known_usages_to_list(lv, CheckBitmapIndexDisabledChecked);
3408 select_purposes(hwnd, purposeSelection);
3409 SendMessageW(GetDlgItem(hwnd, IDC_ENABLE_ALL_PURPOSES + purposeSelection),
3410 BM_CLICK, 0, 0);
3413 static void set_general_cert_properties(HWND hwnd, struct edit_cert_data *data)
3415 PCCERT_CONTEXT cert = data->cert;
3416 WCHAR *str;
3418 if ((str = get_cert_property_as_string(cert, CERT_FRIENDLY_NAME_PROP_ID)))
3420 SendMessageW(GetDlgItem(hwnd, IDC_FRIENDLY_NAME), WM_SETTEXT, 0,
3421 (LPARAM)str);
3422 HeapFree(GetProcessHeap(), 0, str);
3424 if ((str = get_cert_property_as_string(cert, CERT_DESCRIPTION_PROP_ID)))
3426 SendMessageW(GetDlgItem(hwnd, IDC_DESCRIPTION), WM_SETTEXT, 0,
3427 (LPARAM)str);
3428 HeapFree(GetProcessHeap(), 0, str);
3430 show_cert_usages(hwnd, data);
3433 static void set_cert_string_property(PCCERT_CONTEXT cert, DWORD prop,
3434 LPWSTR str)
3436 if (str && strlenW(str))
3438 CRYPT_DATA_BLOB blob;
3440 blob.pbData = (BYTE *)str;
3441 blob.cbData = (strlenW(str) + 1) * sizeof(WCHAR);
3442 CertSetCertificateContextProperty(cert, prop, 0, &blob);
3444 else
3445 CertSetCertificateContextProperty(cert, prop, 0, NULL);
3448 #define WM_REFRESH_VIEW WM_USER + 0
3450 static BOOL CALLBACK refresh_propsheet_pages(HWND hwnd, LPARAM lParam)
3452 if ((GetClassLongW(hwnd, GCW_ATOM) == WC_DIALOG))
3453 SendMessageW(hwnd, WM_REFRESH_VIEW, 0, 0);
3454 return TRUE;
3457 #define MAX_FRIENDLY_NAME 40
3458 #define MAX_DESCRIPTION 255
3460 static void apply_general_changes(HWND hwnd)
3462 WCHAR buf[MAX_DESCRIPTION + 1];
3463 struct edit_cert_data *data =
3464 (struct edit_cert_data *)GetWindowLongPtrW(hwnd, DWLP_USER);
3466 SendMessageW(GetDlgItem(hwnd, IDC_FRIENDLY_NAME), WM_GETTEXT,
3467 sizeof(buf) / sizeof(buf[0]), (LPARAM)buf);
3468 set_cert_string_property(data->cert, CERT_FRIENDLY_NAME_PROP_ID, buf);
3469 SendMessageW(GetDlgItem(hwnd, IDC_DESCRIPTION), WM_GETTEXT,
3470 sizeof(buf) / sizeof(buf[0]), (LPARAM)buf);
3471 set_cert_string_property(data->cert, CERT_DESCRIPTION_PROP_ID, buf);
3472 if (IsDlgButtonChecked(hwnd, IDC_ENABLE_ALL_PURPOSES))
3474 /* Setting a NULL usage removes the enhanced key usage property. */
3475 CertSetEnhancedKeyUsage(data->cert, NULL);
3477 else if (IsDlgButtonChecked(hwnd, IDC_DISABLE_ALL_PURPOSES))
3479 CERT_ENHKEY_USAGE usage = { 0, NULL };
3481 CertSetEnhancedKeyUsage(data->cert, &usage);
3483 else if (IsDlgButtonChecked(hwnd, IDC_ENABLE_SELECTED_PURPOSES))
3485 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
3486 CERT_ENHKEY_USAGE usage = { 0, NULL };
3487 int purposes = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0), i;
3488 LVITEMW item;
3490 item.mask = LVIF_STATE | LVIF_PARAM;
3491 item.iSubItem = 0;
3492 item.stateMask = LVIS_STATEIMAGEMASK;
3493 for (i = 0; i < purposes; i++)
3495 item.iItem = i;
3496 if (SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item))
3498 int state = item.state >> 12;
3500 if (state == CheckBitmapIndexChecked)
3502 CRYPT_OID_INFO *info = (CRYPT_OID_INFO *)item.lParam;
3504 if (usage.cUsageIdentifier)
3505 usage.rgpszUsageIdentifier =
3506 HeapReAlloc(GetProcessHeap(), 0,
3507 usage.rgpszUsageIdentifier,
3508 (usage.cUsageIdentifier + 1) * sizeof(LPSTR));
3509 else
3510 usage.rgpszUsageIdentifier =
3511 HeapAlloc(GetProcessHeap(), 0, sizeof(LPSTR));
3512 if (usage.rgpszUsageIdentifier)
3513 usage.rgpszUsageIdentifier[usage.cUsageIdentifier++] =
3514 (LPSTR)info->pszOID;
3518 CertSetEnhancedKeyUsage(data->cert, &usage);
3519 HeapFree(GetProcessHeap(), 0, usage.rgpszUsageIdentifier);
3521 EnumChildWindows(GetParent(GetParent(hwnd)), refresh_propsheet_pages, 0);
3522 if (data->pfPropertiesChanged)
3523 *data->pfPropertiesChanged = TRUE;
3526 static LRESULT CALLBACK cert_properties_general_dlg_proc(HWND hwnd, UINT msg,
3527 WPARAM wp, LPARAM lp)
3529 PROPSHEETPAGEW *page;
3531 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
3533 switch (msg)
3535 case WM_INITDIALOG:
3537 HWND description = GetDlgItem(hwnd, IDC_DESCRIPTION);
3538 struct detail_data *detailData;
3539 struct edit_cert_data *editData;
3541 page = (PROPSHEETPAGEW *)lp;
3542 detailData = (struct detail_data *)page->lParam;
3543 SendMessageW(GetDlgItem(hwnd, IDC_FRIENDLY_NAME), EM_SETLIMITTEXT,
3544 MAX_FRIENDLY_NAME, 0);
3545 SendMessageW(description, EM_SETLIMITTEXT, MAX_DESCRIPTION, 0);
3546 ShowScrollBar(description, SB_VERT, FALSE);
3547 editData = HeapAlloc(GetProcessHeap(), 0,
3548 sizeof(struct edit_cert_data));
3549 if (editData)
3551 editData->imageList = ImageList_Create(16, 16,
3552 ILC_COLOR4 | ILC_MASK, 4, 0);
3553 if (editData->imageList)
3555 HBITMAP bmp;
3556 COLORREF backColor = RGB(255, 0, 255);
3558 bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_CHECKS));
3559 ImageList_AddMasked(editData->imageList, bmp, backColor);
3560 DeleteObject(bmp);
3561 ImageList_SetBkColor(editData->imageList, CLR_NONE);
3563 editData->cert = detailData->pCertViewInfo->pCertContext;
3564 editData->pfPropertiesChanged = detailData->pfPropertiesChanged;
3565 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)editData);
3566 set_general_cert_properties(hwnd, editData);
3568 break;
3570 case WM_NOTIFY:
3572 NMHDR *hdr = (NMHDR *)lp;
3573 NMITEMACTIVATE *nm;
3575 switch (hdr->code)
3577 case NM_CLICK:
3578 nm = (NMITEMACTIVATE *)lp;
3579 toggle_usage(hwnd, nm->iItem);
3580 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
3581 break;
3582 case PSN_APPLY:
3583 apply_general_changes(hwnd);
3584 break;
3586 break;
3588 case WM_COMMAND:
3589 switch (HIWORD(wp))
3591 case EN_CHANGE:
3592 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
3593 if (LOWORD(wp) == IDC_DESCRIPTION)
3595 /* Show/hide scroll bar on description depending on how much
3596 * text it has.
3598 HWND description = GetDlgItem(hwnd, IDC_DESCRIPTION);
3599 int lines = SendMessageW(description, EM_GETLINECOUNT, 0, 0);
3601 ShowScrollBar(description, SB_VERT, lines > 1);
3603 break;
3604 case BN_CLICKED:
3605 switch (LOWORD(wp))
3607 case IDC_ADD_PURPOSE:
3608 if (DialogBoxParamW(hInstance,
3609 MAKEINTRESOURCEW(IDD_ADD_CERT_PURPOSE), hwnd,
3610 add_purpose_dlg_proc, (LPARAM)hwnd) == IDOK)
3611 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
3612 break;
3613 case IDC_ENABLE_ALL_PURPOSES:
3614 case IDC_DISABLE_ALL_PURPOSES:
3615 case IDC_ENABLE_SELECTED_PURPOSES:
3616 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
3617 select_purposes(hwnd, LOWORD(wp) - IDC_ENABLE_ALL_PURPOSES);
3618 break;
3620 break;
3622 break;
3624 return 0;
3627 static UINT CALLBACK cert_properties_general_callback(HWND hwnd, UINT msg,
3628 PROPSHEETPAGEW *page)
3630 HWND lv;
3631 int cItem, i;
3632 struct edit_cert_data *data;
3634 switch (msg)
3636 case PSPCB_RELEASE:
3637 lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
3638 cItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
3639 for (i = 0; i < cItem; i++)
3641 LVITEMW item;
3643 item.mask = LVIF_PARAM;
3644 item.iItem = i;
3645 item.iSubItem = 0;
3646 if (SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item) && item.lParam)
3648 PCRYPT_OID_INFO info = (PCRYPT_OID_INFO)item.lParam;
3650 if (info->cbSize == sizeof(CRYPT_OID_INFO) && !info->dwGroupId)
3652 HeapFree(GetProcessHeap(), 0, (LPSTR)info->pszOID);
3653 HeapFree(GetProcessHeap(), 0, info);
3657 data = (struct edit_cert_data *)GetWindowLongPtrW(hwnd, DWLP_USER);
3658 if (data)
3660 ImageList_Destroy(data->imageList);
3661 HeapFree(GetProcessHeap(), 0, data);
3663 break;
3665 return 1;
3668 static void show_edit_cert_properties_dialog(HWND parent,
3669 struct detail_data *data)
3671 PROPSHEETHEADERW hdr;
3672 PROPSHEETPAGEW page; /* FIXME: need to add a cross-certificate page */
3674 TRACE("(%p)\n", data);
3676 memset(&page, 0, sizeof(PROPSHEETPAGEW));
3677 page.dwSize = sizeof(page);
3678 page.dwFlags = PSP_USECALLBACK;
3679 page.pfnCallback = cert_properties_general_callback;
3680 page.hInstance = hInstance;
3681 page.u.pszTemplate = MAKEINTRESOURCEW(IDD_CERT_PROPERTIES_GENERAL);
3682 page.pfnDlgProc = cert_properties_general_dlg_proc;
3683 page.lParam = (LPARAM)data;
3685 memset(&hdr, 0, sizeof(hdr));
3686 hdr.dwSize = sizeof(hdr);
3687 hdr.hwndParent = parent;
3688 hdr.dwFlags = PSH_PROPSHEETPAGE;
3689 hdr.hInstance = hInstance;
3690 hdr.pszCaption = MAKEINTRESOURCEW(IDS_CERTIFICATE_PROPERTIES);
3691 hdr.u3.ppsp = &page;
3692 hdr.nPages = 1;
3693 PropertySheetW(&hdr);
3696 static void free_detail_fields(struct detail_data *data)
3698 DWORD i;
3700 for (i = 0; i < data->cFields; i++)
3701 HeapFree(GetProcessHeap(), 0, data->fields[i].detailed_value);
3702 HeapFree(GetProcessHeap(), 0, data->fields);
3703 data->fields = NULL;
3704 data->cFields = 0;
3707 static void refresh_details_view(HWND hwnd)
3709 HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT);
3710 int curSel;
3711 struct detail_data *data;
3713 curSel = SendMessageW(cb, CB_GETCURSEL, 0, 0);
3714 /* Actually, any index will do, since they all store the same data value */
3715 data = (struct detail_data *)SendMessageW(cb, CB_GETITEMDATA, curSel, 0);
3716 free_detail_fields(data);
3717 set_fields_selection(hwnd, data, curSel);
3720 static LRESULT CALLBACK detail_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
3721 LPARAM lp)
3723 PROPSHEETPAGEW *page;
3724 struct detail_data *data;
3726 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
3728 switch (msg)
3730 case WM_INITDIALOG:
3731 page = (PROPSHEETPAGEW *)lp;
3732 data = (struct detail_data *)page->lParam;
3733 create_cert_details_list(hwnd, data);
3734 if (!(data->pCertViewInfo->dwFlags & CRYPTUI_ENABLE_EDITPROPERTIES))
3735 EnableWindow(GetDlgItem(hwnd, IDC_EDITPROPERTIES), FALSE);
3736 if (data->pCertViewInfo->dwFlags & CRYPTUI_DISABLE_EXPORT)
3737 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT), FALSE);
3738 break;
3739 case WM_NOTIFY:
3741 NMITEMACTIVATE *nm;
3742 HWND list = GetDlgItem(hwnd, IDC_DETAIL_LIST);
3744 nm = (NMITEMACTIVATE*)lp;
3745 if (nm->hdr.hwndFrom == list && nm->uNewState & LVN_ITEMACTIVATE
3746 && nm->hdr.code == LVN_ITEMCHANGED)
3748 data = (struct detail_data *)nm->lParam;
3749 if (nm->iItem >= 0 && data && nm->iItem < data->cFields)
3751 WCHAR buf[MAX_STRING_LEN], *val = NULL;
3752 HWND valueCtl = GetDlgItem(hwnd, IDC_DETAIL_VALUE);
3754 if (data->fields[nm->iItem].create)
3755 val = data->fields[nm->iItem].create(
3756 data->pCertViewInfo->pCertContext,
3757 data->fields[nm->iItem].param);
3758 else
3760 LVITEMW item;
3761 int res;
3763 item.cchTextMax = sizeof(buf) / sizeof(buf[0]);
3764 item.mask = LVIF_TEXT;
3765 item.pszText = buf;
3766 item.iItem = nm->iItem;
3767 item.iSubItem = 1;
3768 res = SendMessageW(list, LVM_GETITEMW, 0, (LPARAM)&item);
3769 if (res)
3770 val = buf;
3772 /* Select all the text in the control, the next update will
3773 * replace it
3775 SendMessageW(valueCtl, EM_SETSEL, 0, -1);
3776 add_unformatted_text_to_control(valueCtl, val,
3777 val ? strlenW(val) : 0);
3778 if (val != buf)
3779 HeapFree(GetProcessHeap(), 0, val);
3782 break;
3784 case WM_COMMAND:
3785 switch (wp)
3787 case IDC_EXPORT:
3789 HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT);
3790 CRYPTUI_WIZ_EXPORT_INFO info;
3792 data = (struct detail_data *)SendMessageW(cb, CB_GETITEMDATA, 0, 0);
3793 info.dwSize = sizeof(info);
3794 info.pwszExportFileName = NULL;
3795 info.dwSubjectChoice = CRYPTUI_WIZ_EXPORT_CERT_CONTEXT;
3796 info.u.pCertContext = data->pCertViewInfo->pCertContext;
3797 info.cStores = 0;
3798 CryptUIWizExport(0, hwnd, NULL, &info, NULL);
3799 break;
3801 case IDC_EDITPROPERTIES:
3803 HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT);
3804 int curSel;
3806 curSel = SendMessageW(cb, CB_GETCURSEL, 0, 0);
3807 /* Actually, any index will do, since they all store the same
3808 * data value
3810 data = (struct detail_data *)SendMessageW(cb, CB_GETITEMDATA,
3811 curSel, 0);
3812 show_edit_cert_properties_dialog(GetParent(hwnd), data);
3813 break;
3815 case ((CBN_SELCHANGE << 16) | IDC_DETAIL_SELECT):
3816 refresh_details_view(hwnd);
3817 break;
3819 break;
3820 case WM_REFRESH_VIEW:
3821 refresh_details_view(hwnd);
3822 break;
3824 return 0;
3827 static UINT CALLBACK detail_callback(HWND hwnd, UINT msg,
3828 PROPSHEETPAGEW *page)
3830 struct detail_data *data;
3832 switch (msg)
3834 case PSPCB_RELEASE:
3835 data = (struct detail_data *)page->lParam;
3836 free_detail_fields(data);
3837 HeapFree(GetProcessHeap(), 0, data);
3838 break;
3840 return 0;
3843 static BOOL init_detail_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
3844 BOOL *pfPropertiesChanged, PROPSHEETPAGEW *page)
3846 BOOL ret;
3847 struct detail_data *data = HeapAlloc(GetProcessHeap(), 0,
3848 sizeof(struct detail_data));
3850 if (data)
3852 data->pCertViewInfo = pCertViewInfo;
3853 data->pfPropertiesChanged = pfPropertiesChanged;
3854 data->cFields = 0;
3855 data->fields = NULL;
3856 memset(page, 0, sizeof(PROPSHEETPAGEW));
3857 page->dwSize = sizeof(PROPSHEETPAGEW);
3858 page->dwFlags = PSP_USECALLBACK;
3859 page->pfnCallback = detail_callback;
3860 page->hInstance = hInstance;
3861 page->u.pszTemplate = MAKEINTRESOURCEW(IDD_DETAIL);
3862 page->pfnDlgProc = detail_dlg_proc;
3863 page->lParam = (LPARAM)data;
3864 ret = TRUE;
3866 else
3867 ret = FALSE;
3868 return ret;
3871 struct hierarchy_data
3873 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo;
3874 HIMAGELIST imageList;
3875 DWORD selectedCert;
3878 static LPARAM index_to_lparam(struct hierarchy_data *data, DWORD index)
3880 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
3881 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData,
3882 data->pCertViewInfo->idxSigner, data->pCertViewInfo->fCounterSigner,
3883 data->pCertViewInfo->idxCounterSigner);
3885 /* Takes advantage of the fact that a pointer is 32-bit aligned, and
3886 * therefore always even.
3888 if (index == provSigner->csCertChain - 1)
3889 return (LPARAM)data;
3890 return index << 1 | 1;
3893 static inline DWORD lparam_to_index(struct hierarchy_data *data, LPARAM lp)
3895 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
3896 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData,
3897 data->pCertViewInfo->idxSigner, data->pCertViewInfo->fCounterSigner,
3898 data->pCertViewInfo->idxCounterSigner);
3900 if (!(lp & 1))
3901 return provSigner->csCertChain - 1;
3902 return lp >> 1;
3905 static struct hierarchy_data *get_hierarchy_data_from_tree_item(HWND tree,
3906 HTREEITEM hItem)
3908 struct hierarchy_data *data = NULL;
3909 HTREEITEM root = NULL;
3911 do {
3912 HTREEITEM parent = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM,
3913 TVGN_PARENT, (LPARAM)hItem);
3915 if (!parent)
3916 root = hItem;
3917 hItem = parent;
3918 } while (hItem);
3919 if (root)
3921 TVITEMW item;
3923 item.mask = TVIF_PARAM;
3924 item.hItem = root;
3925 SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item);
3926 data = (struct hierarchy_data *)item.lParam;
3928 return data;
3931 static WCHAR *get_cert_display_name(PCCERT_CONTEXT cert)
3933 WCHAR *name = get_cert_property_as_string(cert, CERT_FRIENDLY_NAME_PROP_ID);
3935 if (!name)
3936 name = get_cert_name_string(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0);
3937 return name;
3940 static void show_cert_chain(HWND hwnd, struct hierarchy_data *data)
3942 HWND tree = GetDlgItem(hwnd, IDC_CERTPATH);
3943 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
3944 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData,
3945 data->pCertViewInfo->idxSigner, data->pCertViewInfo->fCounterSigner,
3946 data->pCertViewInfo->idxCounterSigner);
3947 DWORD i;
3948 HTREEITEM parent = NULL;
3950 SendMessageW(tree, TVM_SETIMAGELIST, TVSIL_NORMAL, (LPARAM)data->imageList);
3951 for (i = provSigner->csCertChain; i; i--)
3953 LPWSTR name;
3955 name = get_cert_display_name(provSigner->pasCertChain[i - 1].pCert);
3956 if (name)
3958 TVINSERTSTRUCTW tvis;
3960 tvis.hParent = parent;
3961 tvis.hInsertAfter = TVI_LAST;
3962 tvis.u.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_IMAGE |
3963 TVIF_SELECTEDIMAGE | TVIF_PARAM;
3964 tvis.u.item.pszText = name;
3965 tvis.u.item.state = TVIS_EXPANDED;
3966 tvis.u.item.stateMask = TVIS_EXPANDED;
3967 if (i == 1 &&
3968 (provSigner->pChainContext->TrustStatus.dwErrorStatus &
3969 CERT_TRUST_IS_PARTIAL_CHAIN))
3971 /* The root of the chain has a special case: if the chain is
3972 * a partial chain, the icon is a warning icon rather than an
3973 * error icon.
3975 tvis.u.item.iImage = 2;
3977 else if (provSigner->pasCertChain[i - 1].pChainElement->TrustStatus.
3978 dwErrorStatus == 0)
3979 tvis.u.item.iImage = 0;
3980 else
3981 tvis.u.item.iImage = 1;
3982 tvis.u.item.iSelectedImage = tvis.u.item.iImage;
3983 tvis.u.item.lParam = index_to_lparam(data, i - 1);
3984 parent = (HTREEITEM)SendMessageW(tree, TVM_INSERTITEMW, 0,
3985 (LPARAM)&tvis);
3986 HeapFree(GetProcessHeap(), 0, name);
3991 static void set_certificate_status(HWND hwnd, CRYPT_PROVIDER_CERT *cert)
3993 /* Select all the text in the control, the next update will replace it */
3994 SendMessageW(hwnd, EM_SETSEL, 0, -1);
3995 /* Set the highest priority error messages first. */
3996 if (!(cert->dwConfidence & CERT_CONFIDENCE_SIG))
3997 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_BAD_SIGNATURE);
3998 else if (!(cert->dwConfidence & CERT_CONFIDENCE_TIME))
3999 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_BAD_TIME);
4000 else if (!(cert->dwConfidence & CERT_CONFIDENCE_TIMENEST))
4001 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_BAD_TIMENEST);
4002 else if (cert->dwRevokedReason)
4003 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_REVOKED);
4004 else
4005 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_VALID);
4008 static void set_certificate_status_for_end_cert(HWND hwnd,
4009 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
4011 HWND status = GetDlgItem(hwnd, IDC_CERTIFICATESTATUSTEXT);
4012 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
4013 (CRYPT_PROVIDER_DATA *)pCertViewInfo->u.pCryptProviderData,
4014 pCertViewInfo->idxSigner, pCertViewInfo->fCounterSigner,
4015 pCertViewInfo->idxCounterSigner);
4016 CRYPT_PROVIDER_CERT *provCert = WTHelperGetProvCertFromChain(provSigner,
4017 pCertViewInfo->idxCert);
4019 set_certificate_status(status, provCert);
4022 static void show_cert_hierarchy(HWND hwnd, struct hierarchy_data *data)
4024 /* Disable view certificate button until a certificate is selected */
4025 EnableWindow(GetDlgItem(hwnd, IDC_VIEWCERTIFICATE), FALSE);
4026 show_cert_chain(hwnd, data);
4027 set_certificate_status_for_end_cert(hwnd, data->pCertViewInfo);
4030 static void show_dialog_for_selected_cert(HWND hwnd)
4032 HWND tree = GetDlgItem(hwnd, IDC_CERTPATH);
4033 TVITEMW item;
4034 struct hierarchy_data *data;
4035 DWORD selection;
4037 memset(&item, 0, sizeof(item));
4038 item.mask = TVIF_HANDLE | TVIF_PARAM;
4039 item.hItem = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM, TVGN_CARET,
4040 (LPARAM)NULL);
4041 SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item);
4042 data = get_hierarchy_data_from_tree_item(tree, item.hItem);
4043 selection = lparam_to_index(data, item.lParam);
4044 if (selection != 0)
4046 CRYPT_PROVIDER_SGNR *provSigner;
4047 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
4048 BOOL changed = FALSE;
4050 provSigner = WTHelperGetProvSignerFromChain(
4051 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData,
4052 data->pCertViewInfo->idxSigner,
4053 data->pCertViewInfo->fCounterSigner,
4054 data->pCertViewInfo->idxCounterSigner);
4055 memset(&viewInfo, 0, sizeof(viewInfo));
4056 viewInfo.dwSize = sizeof(viewInfo);
4057 viewInfo.dwFlags = data->pCertViewInfo->dwFlags;
4058 viewInfo.szTitle = data->pCertViewInfo->szTitle;
4059 viewInfo.pCertContext = provSigner->pasCertChain[selection].pCert;
4060 viewInfo.cStores = data->pCertViewInfo->cStores;
4061 viewInfo.rghStores = data->pCertViewInfo->rghStores;
4062 viewInfo.cPropSheetPages = data->pCertViewInfo->cPropSheetPages;
4063 viewInfo.rgPropSheetPages = data->pCertViewInfo->rgPropSheetPages;
4064 viewInfo.nStartPage = data->pCertViewInfo->nStartPage;
4065 CryptUIDlgViewCertificateW(&viewInfo, &changed);
4066 if (changed)
4068 /* Delete the contents of the tree */
4069 SendMessageW(tree, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT);
4070 /* Reinitialize the tree */
4071 show_cert_hierarchy(hwnd, data);
4076 static LRESULT CALLBACK hierarchy_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
4077 LPARAM lp)
4079 PROPSHEETPAGEW *page;
4080 struct hierarchy_data *data;
4081 LRESULT ret = 0;
4082 HWND tree = GetDlgItem(hwnd, IDC_CERTPATH);
4084 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
4086 switch (msg)
4088 case WM_INITDIALOG:
4089 page = (PROPSHEETPAGEW *)lp;
4090 data = (struct hierarchy_data *)page->lParam;
4091 show_cert_hierarchy(hwnd, data);
4092 break;
4093 case WM_NOTIFY:
4095 NMHDR *hdr;
4097 hdr = (NMHDR *)lp;
4098 switch (hdr->code)
4100 case TVN_SELCHANGEDW:
4102 NMTREEVIEWW *nm = (NMTREEVIEWW*)lp;
4103 DWORD selection;
4104 CRYPT_PROVIDER_SGNR *provSigner;
4106 data = get_hierarchy_data_from_tree_item(tree, nm->itemNew.hItem);
4107 selection = lparam_to_index(data, nm->itemNew.lParam);
4108 provSigner = WTHelperGetProvSignerFromChain(
4109 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData,
4110 data->pCertViewInfo->idxSigner,
4111 data->pCertViewInfo->fCounterSigner,
4112 data->pCertViewInfo->idxCounterSigner);
4113 EnableWindow(GetDlgItem(hwnd, IDC_VIEWCERTIFICATE), selection != 0);
4114 set_certificate_status(GetDlgItem(hwnd, IDC_CERTIFICATESTATUSTEXT),
4115 &provSigner->pasCertChain[selection]);
4116 break;
4118 case NM_DBLCLK:
4119 show_dialog_for_selected_cert(hwnd);
4120 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
4121 ret = 1;
4122 break;
4124 break;
4126 case WM_COMMAND:
4127 switch (wp)
4129 case IDC_VIEWCERTIFICATE:
4130 show_dialog_for_selected_cert(hwnd);
4131 break;
4133 break;
4134 case WM_REFRESH_VIEW:
4136 TVITEMW item;
4138 /* Get hierarchy data */
4139 memset(&item, 0, sizeof(item));
4140 item.mask = TVIF_HANDLE | TVIF_PARAM;
4141 item.hItem = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM, TVGN_ROOT,
4142 (LPARAM)NULL);
4143 data = get_hierarchy_data_from_tree_item(tree, item.hItem);
4144 /* Delete the contents of the tree */
4145 SendMessageW(tree, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT);
4146 /* Reinitialize the tree */
4147 show_cert_hierarchy(hwnd, data);
4148 break;
4151 return ret;
4154 static UINT CALLBACK hierarchy_callback(HWND hwnd, UINT msg,
4155 PROPSHEETPAGEW *page)
4157 struct hierarchy_data *data;
4159 switch (msg)
4161 case PSPCB_RELEASE:
4162 data = (struct hierarchy_data *)page->lParam;
4163 ImageList_Destroy(data->imageList);
4164 HeapFree(GetProcessHeap(), 0, data);
4165 break;
4167 return 0;
4170 static BOOL init_hierarchy_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
4171 PROPSHEETPAGEW *page)
4173 struct hierarchy_data *data = HeapAlloc(GetProcessHeap(), 0,
4174 sizeof(struct hierarchy_data));
4175 BOOL ret = FALSE;
4177 if (data)
4179 data->imageList = ImageList_Create(16, 16, ILC_COLOR4 | ILC_MASK, 2, 0);
4180 if (data->imageList)
4182 HBITMAP bmp;
4183 COLORREF backColor = RGB(255, 0, 255);
4185 data->pCertViewInfo = pCertViewInfo;
4186 data->selectedCert = 0xffffffff;
4188 bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_SMALL_ICONS));
4189 ImageList_AddMasked(data->imageList, bmp, backColor);
4190 DeleteObject(bmp);
4191 ImageList_SetBkColor(data->imageList, CLR_NONE);
4193 memset(page, 0, sizeof(PROPSHEETPAGEW));
4194 page->dwSize = sizeof(PROPSHEETPAGEW);
4195 page->dwFlags = PSP_USECALLBACK;
4196 page->hInstance = hInstance;
4197 page->u.pszTemplate = MAKEINTRESOURCEW(IDD_HIERARCHY);
4198 page->pfnDlgProc = hierarchy_dlg_proc;
4199 page->lParam = (LPARAM)data;
4200 page->pfnCallback = hierarchy_callback;
4201 ret = TRUE;
4203 else
4204 HeapFree(GetProcessHeap(), 0, data);
4206 return ret;
4209 static int CALLBACK cert_prop_sheet_proc(HWND hwnd, UINT msg, LPARAM lp)
4211 RECT rc;
4212 POINT topLeft;
4214 TRACE("(%p, %08x, %08lx)\n", hwnd, msg, lp);
4216 switch (msg)
4218 case PSCB_INITIALIZED:
4219 /* Get cancel button's position.. */
4220 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rc);
4221 topLeft.x = rc.left;
4222 topLeft.y = rc.top;
4223 ScreenToClient(hwnd, &topLeft);
4224 /* hide the cancel button.. */
4225 ShowWindow(GetDlgItem(hwnd, IDCANCEL), FALSE);
4226 /* get the OK button's size.. */
4227 GetWindowRect(GetDlgItem(hwnd, IDOK), &rc);
4228 /* and move the OK button to the cancel button's original position. */
4229 MoveWindow(GetDlgItem(hwnd, IDOK), topLeft.x, topLeft.y,
4230 rc.right - rc.left, rc.bottom - rc.top, FALSE);
4231 GetWindowRect(GetDlgItem(hwnd, IDOK), &rc);
4232 break;
4234 return 0;
4237 static BOOL show_cert_dialog(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
4238 CRYPT_PROVIDER_CERT *provCert, BOOL *pfPropertiesChanged)
4240 static const WCHAR riched[] = { 'r','i','c','h','e','d','2','0',0 };
4241 DWORD nPages;
4242 PROPSHEETPAGEW *pages;
4243 BOOL ret = FALSE;
4244 HMODULE lib = LoadLibraryW(riched);
4246 nPages = pCertViewInfo->cPropSheetPages + 1; /* one for the General tab */
4247 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_DETAILPAGE))
4248 nPages++;
4249 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_HIERARCHYPAGE))
4250 nPages++;
4251 pages = HeapAlloc(GetProcessHeap(), 0, nPages * sizeof(PROPSHEETPAGEW));
4252 if (pages)
4254 PROPSHEETHEADERW hdr;
4255 CRYPTUI_INITDIALOG_STRUCT *init = NULL;
4256 DWORD i;
4258 memset(&hdr, 0, sizeof(hdr));
4259 hdr.dwSize = sizeof(hdr);
4260 hdr.dwFlags = PSH_NOAPPLYNOW | PSH_PROPSHEETPAGE | PSH_USECALLBACK;
4261 hdr.hInstance = hInstance;
4262 if (pCertViewInfo->szTitle)
4263 hdr.pszCaption = pCertViewInfo->szTitle;
4264 else
4265 hdr.pszCaption = MAKEINTRESOURCEW(IDS_CERTIFICATE);
4266 init_general_page(pCertViewInfo, &pages[hdr.nPages++]);
4267 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_DETAILPAGE))
4269 if (init_detail_page(pCertViewInfo, pfPropertiesChanged,
4270 &pages[hdr.nPages]))
4271 hdr.nPages++;
4273 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_HIERARCHYPAGE))
4275 if (init_hierarchy_page(pCertViewInfo, &pages[hdr.nPages]))
4276 hdr.nPages++;
4278 /* Copy each additional page, and create the init dialog struct for it
4280 if (pCertViewInfo->cPropSheetPages)
4282 init = HeapAlloc(GetProcessHeap(), 0,
4283 pCertViewInfo->cPropSheetPages *
4284 sizeof(CRYPTUI_INITDIALOG_STRUCT));
4285 if (init)
4287 for (i = 0; i < pCertViewInfo->cPropSheetPages; i++)
4289 memcpy(&pages[hdr.nPages + i],
4290 &pCertViewInfo->rgPropSheetPages[i],
4291 sizeof(PROPSHEETPAGEW));
4292 init[i].lParam = pCertViewInfo->rgPropSheetPages[i].lParam;
4293 init[i].pCertContext = pCertViewInfo->pCertContext;
4294 pages[hdr.nPages + i].lParam = (LPARAM)&init[i];
4296 if (pCertViewInfo->nStartPage & 0x8000)
4298 /* Start page index is relative to the number of default
4299 * pages
4301 hdr.u2.nStartPage = pCertViewInfo->nStartPage + hdr.nPages;
4303 else
4304 hdr.u2.nStartPage = pCertViewInfo->nStartPage;
4305 hdr.nPages = nPages;
4306 ret = TRUE;
4308 else
4309 SetLastError(ERROR_OUTOFMEMORY);
4311 else
4313 /* Ignore the relative flag if there aren't any additional pages */
4314 hdr.u2.nStartPage = pCertViewInfo->nStartPage & 0x7fff;
4315 ret = TRUE;
4317 if (ret)
4319 INT_PTR l;
4321 hdr.u3.ppsp = pages;
4322 hdr.pfnCallback = cert_prop_sheet_proc;
4323 l = PropertySheetW(&hdr);
4324 if (l == 0)
4326 SetLastError(ERROR_CANCELLED);
4327 ret = FALSE;
4330 HeapFree(GetProcessHeap(), 0, init);
4331 HeapFree(GetProcessHeap(), 0, pages);
4333 else
4334 SetLastError(ERROR_OUTOFMEMORY);
4335 FreeLibrary(lib);
4336 return ret;
4339 /***********************************************************************
4340 * CryptUIDlgViewCertificateW (CRYPTUI.@)
4342 BOOL WINAPI CryptUIDlgViewCertificateW(
4343 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo, BOOL *pfPropertiesChanged)
4345 static GUID generic_cert_verify = WINTRUST_ACTION_GENERIC_CERT_VERIFY;
4346 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
4347 WINTRUST_DATA wvt;
4348 WINTRUST_CERT_INFO cert;
4349 BOOL ret = FALSE;
4350 CRYPT_PROVIDER_SGNR *signer;
4351 CRYPT_PROVIDER_CERT *provCert = NULL;
4353 TRACE("(%p, %p)\n", pCertViewInfo, pfPropertiesChanged);
4355 if (pCertViewInfo->dwSize != sizeof(CRYPTUI_VIEWCERTIFICATE_STRUCTW))
4357 SetLastError(ERROR_INVALID_PARAMETER);
4358 return FALSE;
4360 /* Make a local copy in case we have to call WinVerifyTrust ourselves */
4361 memcpy(&viewInfo, pCertViewInfo, sizeof(viewInfo));
4362 if (!viewInfo.u.hWVTStateData)
4364 memset(&wvt, 0, sizeof(wvt));
4365 wvt.cbStruct = sizeof(wvt);
4366 wvt.dwUIChoice = WTD_UI_NONE;
4367 if (viewInfo.dwFlags &
4368 CRYPTUI_ENABLE_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT)
4369 wvt.fdwRevocationChecks |= WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
4370 if (viewInfo.dwFlags & CRYPTUI_ENABLE_REVOCATION_CHECK_END_CERT)
4371 wvt.fdwRevocationChecks |= WTD_REVOCATION_CHECK_END_CERT;
4372 if (viewInfo.dwFlags & CRYPTUI_ENABLE_REVOCATION_CHECK_CHAIN)
4373 wvt.fdwRevocationChecks |= WTD_REVOCATION_CHECK_CHAIN;
4374 wvt.dwUnionChoice = WTD_CHOICE_CERT;
4375 memset(&cert, 0, sizeof(cert));
4376 cert.cbStruct = sizeof(cert);
4377 cert.psCertContext = (CERT_CONTEXT *)viewInfo.pCertContext;
4378 cert.chStores = viewInfo.cStores;
4379 cert.pahStores = viewInfo.rghStores;
4380 wvt.u.pCert = &cert;
4381 wvt.dwStateAction = WTD_STATEACTION_VERIFY;
4382 WinVerifyTrust(NULL, &generic_cert_verify, &wvt);
4383 viewInfo.u.pCryptProviderData =
4384 WTHelperProvDataFromStateData(wvt.hWVTStateData);
4385 signer = WTHelperGetProvSignerFromChain(
4386 (CRYPT_PROVIDER_DATA *)viewInfo.u.pCryptProviderData, 0, FALSE, 0);
4387 provCert = WTHelperGetProvCertFromChain(signer, 0);
4388 ret = TRUE;
4390 else
4392 viewInfo.u.pCryptProviderData =
4393 WTHelperProvDataFromStateData(viewInfo.u.hWVTStateData);
4394 signer = WTHelperGetProvSignerFromChain(
4395 (CRYPT_PROVIDER_DATA *)viewInfo.u.pCryptProviderData,
4396 viewInfo.idxSigner, viewInfo.fCounterSigner,
4397 viewInfo.idxCounterSigner);
4398 provCert = WTHelperGetProvCertFromChain(signer, viewInfo.idxCert);
4399 ret = TRUE;
4401 if (ret)
4403 ret = show_cert_dialog(&viewInfo, provCert, pfPropertiesChanged);
4404 if (!viewInfo.u.hWVTStateData)
4406 wvt.dwStateAction = WTD_STATEACTION_CLOSE;
4407 WinVerifyTrust(NULL, &generic_cert_verify, &wvt);
4410 return ret;
4413 /***********************************************************************
4414 * CryptUIDlgViewContext (CRYPTUI.@)
4416 BOOL WINAPI CryptUIDlgViewContext(DWORD dwContextType, LPVOID pvContext,
4417 HWND hwnd, LPCWSTR pwszTitle, DWORD dwFlags, LPVOID pvReserved)
4419 BOOL ret;
4421 TRACE("(%d, %p, %p, %s, %08x, %p)\n", dwContextType, pvContext, hwnd,
4422 debugstr_w(pwszTitle), dwFlags, pvReserved);
4424 switch (dwContextType)
4426 case CERT_STORE_CERTIFICATE_CONTEXT:
4428 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
4430 memset(&viewInfo, 0, sizeof(viewInfo));
4431 viewInfo.dwSize = sizeof(viewInfo);
4432 viewInfo.hwndParent = hwnd;
4433 viewInfo.szTitle = pwszTitle;
4434 viewInfo.pCertContext = pvContext;
4435 ret = CryptUIDlgViewCertificateW(&viewInfo, NULL);
4436 break;
4438 default:
4439 FIXME("unimplemented for context type %d\n", dwContextType);
4440 SetLastError(E_INVALIDARG);
4441 ret = FALSE;
4443 return ret;
4446 /* Decodes a cert's basic constraints extension (either szOID_BASIC_CONSTRAINTS
4447 * or szOID_BASIC_CONSTRAINTS2, whichever is present) to determine if it
4448 * should be a CA. If neither extension is present, returns
4449 * defaultIfNotSpecified.
4451 static BOOL is_ca_cert(PCCERT_CONTEXT cert, BOOL defaultIfNotSpecified)
4453 BOOL isCA = defaultIfNotSpecified;
4454 PCERT_EXTENSION ext = CertFindExtension(szOID_BASIC_CONSTRAINTS,
4455 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
4457 if (ext)
4459 CERT_BASIC_CONSTRAINTS_INFO *info;
4460 DWORD size = 0;
4462 if (CryptDecodeObjectEx(X509_ASN_ENCODING, szOID_BASIC_CONSTRAINTS,
4463 ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG,
4464 NULL, (LPBYTE)&info, &size))
4466 if (info->SubjectType.cbData == 1)
4467 isCA = info->SubjectType.pbData[0] & CERT_CA_SUBJECT_FLAG;
4468 LocalFree(info);
4471 else
4473 ext = CertFindExtension(szOID_BASIC_CONSTRAINTS2,
4474 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
4475 if (ext)
4477 CERT_BASIC_CONSTRAINTS2_INFO info;
4478 DWORD size = sizeof(CERT_BASIC_CONSTRAINTS2_INFO);
4480 if (CryptDecodeObjectEx(X509_ASN_ENCODING,
4481 szOID_BASIC_CONSTRAINTS2, ext->Value.pbData, ext->Value.cbData,
4482 0, NULL, &info, &size))
4483 isCA = info.fCA;
4486 return isCA;
4489 static HCERTSTORE choose_store_for_cert(PCCERT_CONTEXT cert)
4491 LPCWSTR storeName;
4493 if (is_ca_cert(cert, TRUE))
4494 storeName = ca;
4495 else
4496 storeName = addressBook;
4497 return CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0,
4498 CERT_SYSTEM_STORE_CURRENT_USER, storeName);
4501 static BOOL import_cert(PCCERT_CONTEXT cert, HCERTSTORE hDestCertStore)
4503 HCERTSTORE store;
4504 BOOL ret;
4506 if (!cert)
4508 SetLastError(E_INVALIDARG);
4509 return FALSE;
4511 if (hDestCertStore) store = hDestCertStore;
4512 else
4514 if (!(store = choose_store_for_cert(cert)))
4516 WARN("unable to open certificate store\n");
4517 return FALSE;
4520 ret = CertAddCertificateContextToStore(store, cert,
4521 CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES, NULL);
4522 if (!hDestCertStore) CertCloseStore(store, 0);
4523 return ret;
4526 static BOOL import_crl(PCCRL_CONTEXT crl, HCERTSTORE hDestCertStore)
4528 HCERTSTORE store;
4529 BOOL ret;
4531 if (!crl)
4533 SetLastError(E_INVALIDARG);
4534 return FALSE;
4536 if (hDestCertStore) store = hDestCertStore;
4537 else
4539 if (!(store = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0,
4540 CERT_SYSTEM_STORE_CURRENT_USER, ca)))
4542 WARN("unable to open certificate store\n");
4543 return FALSE;
4546 ret = CertAddCRLContextToStore(store, crl,
4547 CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES, NULL);
4548 if (!hDestCertStore) CertCloseStore(store, 0);
4549 return ret;
4552 static BOOL import_ctl(PCCTL_CONTEXT ctl, HCERTSTORE hDestCertStore)
4554 HCERTSTORE store;
4555 BOOL ret;
4557 if (!ctl)
4559 SetLastError(E_INVALIDARG);
4560 return FALSE;
4562 if (hDestCertStore) store = hDestCertStore;
4563 else
4565 static const WCHAR trust[] = { 'T','r','u','s','t',0 };
4567 if (!(store = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0,
4568 CERT_SYSTEM_STORE_CURRENT_USER, trust)))
4570 WARN("unable to open certificate store\n");
4571 return FALSE;
4574 ret = CertAddCTLContextToStore(store, ctl,
4575 CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES, NULL);
4576 if (!hDestCertStore) CertCloseStore(store, 0);
4577 return ret;
4580 /* Checks type, a type such as CERT_QUERY_CONTENT_CERT returned by
4581 * CryptQueryObject, against the allowed types. Returns TRUE if the
4582 * type is allowed, FALSE otherwise.
4584 static BOOL check_context_type(DWORD dwFlags, DWORD type)
4586 BOOL ret;
4588 if (dwFlags &
4589 (CRYPTUI_WIZ_IMPORT_ALLOW_CERT | CRYPTUI_WIZ_IMPORT_ALLOW_CRL |
4590 CRYPTUI_WIZ_IMPORT_ALLOW_CTL))
4592 switch (type)
4594 case CERT_QUERY_CONTENT_CERT:
4595 case CERT_QUERY_CONTENT_SERIALIZED_CERT:
4596 ret = dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CERT;
4597 break;
4598 case CERT_QUERY_CONTENT_CRL:
4599 case CERT_QUERY_CONTENT_SERIALIZED_CRL:
4600 ret = dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CRL;
4601 break;
4602 case CERT_QUERY_CONTENT_CTL:
4603 case CERT_QUERY_CONTENT_SERIALIZED_CTL:
4604 ret = dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CTL;
4605 break;
4606 default:
4607 /* The remaining types contain more than one type, so allow
4608 * any combination.
4610 ret = TRUE;
4613 else
4615 /* No allowed types specified, so any type is allowed */
4616 ret = TRUE;
4618 if (!ret)
4619 SetLastError(E_INVALIDARG);
4620 return ret;
4624 static void import_warning(DWORD dwFlags, HWND hwnd, LPCWSTR szTitle,
4625 int warningID)
4627 if (!(dwFlags & CRYPTUI_WIZ_NO_UI))
4629 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
4630 LPCWSTR pTitle;
4632 if (szTitle)
4633 pTitle = szTitle;
4634 else
4636 LoadStringW(hInstance, IDS_IMPORT_WIZARD, title,
4637 sizeof(title) / sizeof(title[0]));
4638 pTitle = title;
4640 LoadStringW(hInstance, warningID, error,
4641 sizeof(error) / sizeof(error[0]));
4642 MessageBoxW(hwnd, error, pTitle, MB_ICONERROR | MB_OK);
4646 static void import_warn_type_mismatch(DWORD dwFlags, HWND hwnd, LPCWSTR szTitle)
4648 import_warning(dwFlags, hwnd, szTitle, IDS_IMPORT_TYPE_MISMATCH);
4651 static BOOL check_store_context_type(DWORD dwFlags, HCERTSTORE store)
4653 BOOL ret;
4655 if (dwFlags &
4656 (CRYPTUI_WIZ_IMPORT_ALLOW_CERT | CRYPTUI_WIZ_IMPORT_ALLOW_CRL |
4657 CRYPTUI_WIZ_IMPORT_ALLOW_CTL))
4659 PCCERT_CONTEXT cert;
4660 PCCRL_CONTEXT crl;
4661 PCCTL_CONTEXT ctl;
4663 ret = TRUE;
4664 if ((cert = CertEnumCertificatesInStore(store, NULL)))
4666 CertFreeCertificateContext(cert);
4667 if (!(dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CERT))
4668 ret = FALSE;
4670 if (ret && (crl = CertEnumCRLsInStore(store, NULL)))
4672 CertFreeCRLContext(crl);
4673 if (!(dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CRL))
4674 ret = FALSE;
4676 if (ret && (ctl = CertEnumCTLsInStore(store, NULL)))
4678 CertFreeCTLContext(ctl);
4679 if (!(dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CTL))
4680 ret = FALSE;
4683 else
4684 ret = TRUE;
4685 if (!ret)
4686 SetLastError(E_INVALIDARG);
4687 return ret;
4690 static BOOL import_store(DWORD dwFlags, HWND hwnd, LPCWSTR szTitle,
4691 HCERTSTORE source, HCERTSTORE dest)
4693 BOOL ret;
4695 if ((ret = check_store_context_type(dwFlags, source)))
4697 PCCERT_CONTEXT cert = NULL;
4698 PCCRL_CONTEXT crl = NULL;
4699 PCCTL_CONTEXT ctl = NULL;
4701 do {
4702 cert = CertEnumCertificatesInStore(source, cert);
4703 if (cert)
4704 ret = import_cert(cert, dest);
4705 } while (ret && cert);
4706 do {
4707 crl = CertEnumCRLsInStore(source, crl);
4708 if (crl)
4709 ret = import_crl(crl, dest);
4710 } while (ret && crl);
4711 do {
4712 ctl = CertEnumCTLsInStore(source, ctl);
4713 if (ctl)
4714 ret = import_ctl(ctl, dest);
4715 } while (ret && ctl);
4717 else
4718 import_warn_type_mismatch(dwFlags, hwnd, szTitle);
4719 return ret;
4722 static HCERTSTORE open_store_from_file(DWORD dwFlags, LPCWSTR fileName,
4723 DWORD *pContentType)
4725 HCERTSTORE store = NULL;
4726 DWORD contentType = 0, expectedContentTypeFlags;
4728 if (dwFlags &
4729 (CRYPTUI_WIZ_IMPORT_ALLOW_CERT | CRYPTUI_WIZ_IMPORT_ALLOW_CRL |
4730 CRYPTUI_WIZ_IMPORT_ALLOW_CTL))
4732 expectedContentTypeFlags =
4733 CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE |
4734 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED |
4735 CERT_QUERY_CONTENT_FLAG_PFX;
4736 if (dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CERT)
4737 expectedContentTypeFlags |=
4738 CERT_QUERY_CONTENT_FLAG_CERT |
4739 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT;
4740 if (dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CRL)
4741 expectedContentTypeFlags |=
4742 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL |
4743 CERT_QUERY_CONTENT_FLAG_CRL;
4744 if (dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CTL)
4745 expectedContentTypeFlags |=
4746 CERT_QUERY_CONTENT_FLAG_CTL |
4747 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL;
4749 else
4750 expectedContentTypeFlags =
4751 CERT_QUERY_CONTENT_FLAG_CERT |
4752 CERT_QUERY_CONTENT_FLAG_CTL |
4753 CERT_QUERY_CONTENT_FLAG_CRL |
4754 CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE |
4755 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT |
4756 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL |
4757 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL |
4758 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED |
4759 CERT_QUERY_CONTENT_FLAG_PFX;
4761 CryptQueryObject(CERT_QUERY_OBJECT_FILE, fileName,
4762 expectedContentTypeFlags, CERT_QUERY_FORMAT_FLAG_ALL, 0, NULL,
4763 &contentType, NULL, &store, NULL, NULL);
4764 if (pContentType)
4765 *pContentType = contentType;
4766 return store;
4769 static BOOL import_file(DWORD dwFlags, HWND hwnd, LPCWSTR szTitle,
4770 LPCWSTR fileName, HCERTSTORE dest)
4772 HCERTSTORE source;
4773 BOOL ret;
4775 if ((source = open_store_from_file(dwFlags, fileName, NULL)))
4777 ret = import_store(dwFlags, hwnd, szTitle, source, dest);
4778 CertCloseStore(source, 0);
4780 else
4781 ret = FALSE;
4782 return ret;
4785 struct ImportWizData
4787 HFONT titleFont;
4788 DWORD dwFlags;
4789 LPCWSTR pwszWizardTitle;
4790 CRYPTUI_WIZ_IMPORT_SRC_INFO importSrc;
4791 LPWSTR fileName;
4792 DWORD contentType;
4793 BOOL freeSource;
4794 HCERTSTORE hDestCertStore;
4795 BOOL freeDest;
4796 BOOL autoDest;
4797 BOOL success;
4800 static LRESULT CALLBACK import_welcome_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
4801 LPARAM lp)
4803 LRESULT ret = 0;
4805 switch (msg)
4807 case WM_INITDIALOG:
4809 struct ImportWizData *data;
4810 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
4811 WCHAR fontFace[MAX_STRING_LEN];
4812 HDC hDC = GetDC(hwnd);
4813 int height;
4815 data = (struct ImportWizData *)page->lParam;
4816 LoadStringW(hInstance, IDS_WIZARD_TITLE_FONT, fontFace,
4817 sizeof(fontFace) / sizeof(fontFace[0]));
4818 height = -MulDiv(12, GetDeviceCaps(hDC, LOGPIXELSY), 72);
4819 data->titleFont = CreateFontW(height, 0, 0, 0, FW_BOLD, 0, 0, 0,
4820 DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
4821 DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, fontFace);
4822 SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_TITLE), WM_SETFONT,
4823 (WPARAM)data->titleFont, TRUE);
4824 ReleaseDC(hwnd, hDC);
4825 break;
4827 case WM_NOTIFY:
4829 NMHDR *hdr = (NMHDR *)lp;
4831 switch (hdr->code)
4833 case PSN_SETACTIVE:
4834 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0, PSWIZB_NEXT);
4835 ret = TRUE;
4836 break;
4838 break;
4841 return ret;
4844 static const WCHAR filter_cert[] = { '*','.','c','e','r',';','*','.',
4845 'c','r','t',0 };
4846 static const WCHAR filter_pfx[] = { '*','.','p','f','x',';','*','.',
4847 'p','1','2',0 };
4848 static const WCHAR filter_crl[] = { '*','.','c','r','l',0 };
4849 static const WCHAR filter_ctl[] = { '*','.','s','t','l',0 };
4850 static const WCHAR filter_serialized_store[] = { '*','.','s','s','t',0 };
4851 static const WCHAR filter_cms[] = { '*','.','s','p','c',';','*','.',
4852 'p','7','b',0 };
4853 static const WCHAR filter_all[] = { '*','.','*',0 };
4855 struct StringToFilter
4857 int id;
4858 DWORD allowFlags;
4859 LPCWSTR filter;
4860 } import_filters[] = {
4861 { IDS_IMPORT_FILTER_CERT, CRYPTUI_WIZ_IMPORT_ALLOW_CERT, filter_cert },
4862 { IDS_IMPORT_FILTER_PFX, 0, filter_pfx },
4863 { IDS_IMPORT_FILTER_CRL, CRYPTUI_WIZ_IMPORT_ALLOW_CRL, filter_crl },
4864 { IDS_IMPORT_FILTER_CTL, CRYPTUI_WIZ_IMPORT_ALLOW_CTL, filter_ctl },
4865 { IDS_IMPORT_FILTER_SERIALIZED_STORE, 0, filter_serialized_store },
4866 { IDS_IMPORT_FILTER_CMS, 0, filter_cms },
4867 { IDS_IMPORT_FILTER_ALL, 0, filter_all },
4870 static WCHAR *make_import_file_filter(DWORD dwFlags)
4872 DWORD i;
4873 int len, totalLen = 2;
4874 LPWSTR filter = NULL, str;
4876 for (i = 0; i < sizeof(import_filters) / sizeof(import_filters[0]); i++)
4878 if (!import_filters[i].allowFlags || !dwFlags ||
4879 (dwFlags & import_filters[i].allowFlags))
4881 len = LoadStringW(hInstance, import_filters[i].id, (LPWSTR)&str, 0);
4882 totalLen += len + strlenW(import_filters[i].filter) + 2;
4885 filter = HeapAlloc(GetProcessHeap(), 0, totalLen * sizeof(WCHAR));
4886 if (filter)
4888 LPWSTR ptr;
4890 ptr = filter;
4891 for (i = 0; i < sizeof(import_filters) / sizeof(import_filters[0]); i++)
4893 if (!import_filters[i].allowFlags || !dwFlags ||
4894 (dwFlags & import_filters[i].allowFlags))
4896 len = LoadStringW(hInstance, import_filters[i].id,
4897 (LPWSTR)&str, 0);
4898 memcpy(ptr, str, len * sizeof(WCHAR));
4899 ptr += len;
4900 *ptr++ = 0;
4901 strcpyW(ptr, import_filters[i].filter);
4902 ptr += strlenW(import_filters[i].filter) + 1;
4905 *ptr++ = 0;
4907 return filter;
4910 static BOOL import_validate_filename(HWND hwnd, struct ImportWizData *data,
4911 LPCWSTR fileName)
4913 HANDLE file;
4914 BOOL ret = FALSE;
4916 file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
4917 OPEN_EXISTING, 0, NULL);
4918 if (file != INVALID_HANDLE_VALUE)
4920 HCERTSTORE source = open_store_from_file(data->dwFlags, fileName,
4921 &data->contentType);
4922 int warningID = 0;
4924 if (!source)
4925 warningID = IDS_IMPORT_BAD_FORMAT;
4926 else if (!check_store_context_type(data->dwFlags, source))
4927 warningID = IDS_IMPORT_TYPE_MISMATCH;
4928 else
4930 data->importSrc.dwSubjectChoice =
4931 CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE;
4932 data->importSrc.u.hCertStore = source;
4933 data->freeSource = TRUE;
4934 ret = TRUE;
4936 if (warningID)
4938 import_warning(data->dwFlags, hwnd, data->pwszWizardTitle,
4939 warningID);
4941 CloseHandle(file);
4943 else
4945 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
4946 LPCWSTR pTitle;
4947 LPWSTR msgBuf, fullError;
4949 if (data->pwszWizardTitle)
4950 pTitle = data->pwszWizardTitle;
4951 else
4953 LoadStringW(hInstance, IDS_IMPORT_WIZARD, title,
4954 sizeof(title) / sizeof(title[0]));
4955 pTitle = title;
4957 LoadStringW(hInstance, IDS_IMPORT_OPEN_FAILED, error,
4958 sizeof(error) / sizeof(error[0]));
4959 FormatMessageW(
4960 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
4961 GetLastError(), 0, (LPWSTR) &msgBuf, 0, NULL);
4962 fullError = HeapAlloc(GetProcessHeap(), 0,
4963 (strlenW(error) + strlenW(fileName) + strlenW(msgBuf) + 3)
4964 * sizeof(WCHAR));
4965 if (fullError)
4967 LPWSTR ptr = fullError;
4969 strcpyW(ptr, error);
4970 ptr += strlenW(error);
4971 strcpyW(ptr, fileName);
4972 ptr += strlenW(fileName);
4973 *ptr++ = ':';
4974 *ptr++ = '\n';
4975 strcpyW(ptr, msgBuf);
4976 MessageBoxW(hwnd, fullError, pTitle, MB_ICONERROR | MB_OK);
4977 HeapFree(GetProcessHeap(), 0, fullError);
4979 LocalFree(msgBuf);
4981 return ret;
4984 static LRESULT CALLBACK import_file_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
4985 LPARAM lp)
4987 LRESULT ret = 0;
4988 struct ImportWizData *data;
4990 switch (msg)
4992 case WM_INITDIALOG:
4994 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
4996 data = (struct ImportWizData *)page->lParam;
4997 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
4998 break;
5000 case WM_NOTIFY:
5002 NMHDR *hdr = (NMHDR *)lp;
5004 switch (hdr->code)
5006 case PSN_SETACTIVE:
5007 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
5008 PSWIZB_BACK | PSWIZB_NEXT);
5009 ret = TRUE;
5010 break;
5011 case PSN_WIZNEXT:
5013 HWND fileNameEdit = GetDlgItem(hwnd, IDC_IMPORT_FILENAME);
5014 DWORD len = SendMessageW(fileNameEdit, WM_GETTEXTLENGTH, 0, 0);
5016 data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5017 if (!len)
5019 import_warning(data->dwFlags, hwnd, data->pwszWizardTitle,
5020 IDS_IMPORT_EMPTY_FILE);
5021 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
5022 ret = 1;
5024 else
5026 LPWSTR fileName = HeapAlloc(GetProcessHeap(), 0,
5027 (len + 1) * sizeof(WCHAR));
5029 if (fileName)
5031 SendMessageW(fileNameEdit, WM_GETTEXT, len + 1,
5032 (LPARAM)fileName);
5033 if (!import_validate_filename(hwnd, data, fileName))
5035 HeapFree(GetProcessHeap(), 0, fileName);
5036 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
5037 ret = 1;
5039 else
5040 data->fileName = fileName;
5043 break;
5046 break;
5048 case WM_COMMAND:
5049 switch (wp)
5051 case IDC_IMPORT_BROWSE_FILE:
5053 OPENFILENAMEW ofn;
5054 WCHAR fileBuf[MAX_PATH];
5056 data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5057 memset(&ofn, 0, sizeof(ofn));
5058 ofn.lStructSize = sizeof(ofn);
5059 ofn.hwndOwner = hwnd;
5060 ofn.lpstrFilter = make_import_file_filter(data->dwFlags);
5061 ofn.lpstrFile = fileBuf;
5062 ofn.nMaxFile = sizeof(fileBuf) / sizeof(fileBuf[0]);
5063 fileBuf[0] = 0;
5064 if (GetOpenFileNameW(&ofn))
5065 SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_FILENAME), WM_SETTEXT,
5066 0, (LPARAM)ofn.lpstrFile);
5067 HeapFree(GetProcessHeap(), 0, (LPWSTR)ofn.lpstrFilter);
5068 break;
5071 break;
5073 return ret;
5076 static LRESULT CALLBACK import_store_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
5077 LPARAM lp)
5079 LRESULT ret = 0;
5080 struct ImportWizData *data;
5082 switch (msg)
5084 case WM_INITDIALOG:
5086 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
5088 data = (struct ImportWizData *)page->lParam;
5089 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
5090 if (!data->hDestCertStore)
5092 SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_AUTO_STORE), BM_CLICK,
5093 0, 0);
5094 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_STORE), FALSE);
5095 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_BROWSE_STORE), FALSE);
5096 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_SPECIFY_STORE), FALSE);
5098 else
5100 WCHAR storeTitle[MAX_STRING_LEN];
5102 SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_SPECIFY_STORE), BM_CLICK,
5103 0, 0);
5104 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_STORE), TRUE);
5105 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_BROWSE_STORE), TRUE);
5106 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_SPECIFY_STORE),
5107 !(data->dwFlags & CRYPTUI_WIZ_IMPORT_NO_CHANGE_DEST_STORE));
5108 LoadStringW(hInstance, IDS_IMPORT_DEST_DETERMINED,
5109 storeTitle, sizeof(storeTitle) / sizeof(storeTitle[0]));
5110 SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_STORE), WM_SETTEXT,
5111 0, (LPARAM)storeTitle);
5113 break;
5115 case WM_NOTIFY:
5117 NMHDR *hdr = (NMHDR *)lp;
5119 switch (hdr->code)
5121 case PSN_SETACTIVE:
5122 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
5123 PSWIZB_BACK | PSWIZB_NEXT);
5124 ret = TRUE;
5125 break;
5126 case PSN_WIZNEXT:
5128 data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5129 if (IsDlgButtonChecked(hwnd, IDC_IMPORT_SPECIFY_STORE) &&
5130 !data->hDestCertStore)
5132 import_warning(data->dwFlags, hwnd, data->pwszWizardTitle,
5133 IDS_IMPORT_SELECT_STORE);
5134 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
5135 ret = 1;
5137 break;
5140 break;
5142 case WM_COMMAND:
5143 switch (wp)
5145 case IDC_IMPORT_AUTO_STORE:
5146 data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5147 data->autoDest = TRUE;
5148 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_STORE), FALSE);
5149 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_BROWSE_STORE), FALSE);
5150 break;
5151 case IDC_IMPORT_SPECIFY_STORE:
5152 data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5153 data->autoDest = FALSE;
5154 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_STORE), TRUE);
5155 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_BROWSE_STORE), TRUE);
5156 break;
5157 case IDC_IMPORT_BROWSE_STORE:
5159 CRYPTUI_ENUM_SYSTEM_STORE_ARGS enumArgs = {
5160 CERT_SYSTEM_STORE_CURRENT_USER, NULL };
5161 CRYPTUI_ENUM_DATA enumData = { 0, NULL, 1, &enumArgs };
5162 CRYPTUI_SELECTSTORE_INFO_W selectInfo;
5163 HCERTSTORE store;
5165 data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5166 selectInfo.dwSize = sizeof(selectInfo);
5167 selectInfo.parent = hwnd;
5168 selectInfo.dwFlags = CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE;
5169 selectInfo.pwszTitle = selectInfo.pwszTitle = NULL;
5170 selectInfo.pEnumData = &enumData;
5171 selectInfo.pfnSelectedStoreCallback = NULL;
5172 if ((store = CryptUIDlgSelectStoreW(&selectInfo)))
5174 WCHAR storeTitle[MAX_STRING_LEN];
5176 LoadStringW(hInstance, IDS_IMPORT_DEST_DETERMINED,
5177 storeTitle, sizeof(storeTitle) / sizeof(storeTitle[0]));
5178 SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_STORE), WM_SETTEXT,
5179 0, (LPARAM)storeTitle);
5180 data->hDestCertStore = store;
5181 data->freeDest = TRUE;
5183 break;
5186 break;
5188 return ret;
5191 static void show_import_details(HWND lv, struct ImportWizData *data)
5193 WCHAR text[MAX_STRING_LEN];
5194 LVITEMW item;
5195 int contentID;
5197 item.mask = LVIF_TEXT;
5198 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
5199 item.iSubItem = 0;
5200 LoadStringW(hInstance, IDS_IMPORT_STORE_SELECTION, text,
5201 sizeof(text)/ sizeof(text[0]));
5202 item.pszText = text;
5203 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
5204 item.iSubItem = 1;
5205 if (data->autoDest)
5206 LoadStringW(hInstance, IDS_IMPORT_DEST_AUTOMATIC, text,
5207 sizeof(text)/ sizeof(text[0]));
5208 else
5209 LoadStringW(hInstance, IDS_IMPORT_DEST_DETERMINED, text,
5210 sizeof(text)/ sizeof(text[0]));
5211 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
5212 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
5213 item.iSubItem = 0;
5214 LoadStringW(hInstance, IDS_IMPORT_CONTENT, text,
5215 sizeof(text)/ sizeof(text[0]));
5216 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
5217 switch (data->contentType)
5219 case CERT_QUERY_CONTENT_CERT:
5220 case CERT_QUERY_CONTENT_SERIALIZED_CERT:
5221 contentID = IDS_IMPORT_CONTENT_CERT;
5222 break;
5223 case CERT_QUERY_CONTENT_CRL:
5224 case CERT_QUERY_CONTENT_SERIALIZED_CRL:
5225 contentID = IDS_IMPORT_CONTENT_CRL;
5226 break;
5227 case CERT_QUERY_CONTENT_CTL:
5228 case CERT_QUERY_CONTENT_SERIALIZED_CTL:
5229 contentID = IDS_IMPORT_CONTENT_CTL;
5230 break;
5231 case CERT_QUERY_CONTENT_PKCS7_SIGNED:
5232 contentID = IDS_IMPORT_CONTENT_CMS;
5233 break;
5234 case CERT_QUERY_CONTENT_FLAG_PFX:
5235 contentID = IDS_IMPORT_CONTENT_PFX;
5236 break;
5237 default:
5238 contentID = IDS_IMPORT_CONTENT_STORE;
5239 break;
5241 LoadStringW(hInstance, contentID, text, sizeof(text)/ sizeof(text[0]));
5242 item.iSubItem = 1;
5243 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
5244 if (data->fileName)
5246 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
5247 item.iSubItem = 0;
5248 LoadStringW(hInstance, IDS_IMPORT_FILE, text,
5249 sizeof(text)/ sizeof(text[0]));
5250 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
5251 item.iSubItem = 1;
5252 item.pszText = data->fileName;
5253 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
5257 static BOOL do_import(DWORD dwFlags, HWND hwndParent, LPCWSTR pwszWizardTitle,
5258 PCCRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc, HCERTSTORE hDestCertStore)
5260 BOOL ret;
5262 switch (pImportSrc->dwSubjectChoice)
5264 case CRYPTUI_WIZ_IMPORT_SUBJECT_FILE:
5265 ret = import_file(dwFlags, hwndParent, pwszWizardTitle,
5266 pImportSrc->u.pwszFileName, hDestCertStore);
5267 break;
5268 case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_CONTEXT:
5269 if ((ret = check_context_type(dwFlags, CERT_QUERY_CONTENT_CERT)))
5270 ret = import_cert(pImportSrc->u.pCertContext, hDestCertStore);
5271 else
5272 import_warn_type_mismatch(dwFlags, hwndParent, pwszWizardTitle);
5273 break;
5274 case CRYPTUI_WIZ_IMPORT_SUBJECT_CRL_CONTEXT:
5275 if ((ret = check_context_type(dwFlags, CERT_QUERY_CONTENT_CRL)))
5276 ret = import_crl(pImportSrc->u.pCRLContext, hDestCertStore);
5277 else
5278 import_warn_type_mismatch(dwFlags, hwndParent, pwszWizardTitle);
5279 break;
5280 case CRYPTUI_WIZ_IMPORT_SUBJECT_CTL_CONTEXT:
5281 if ((ret = check_context_type(dwFlags, CERT_QUERY_CONTENT_CTL)))
5282 ret = import_ctl(pImportSrc->u.pCTLContext, hDestCertStore);
5283 else
5284 import_warn_type_mismatch(dwFlags, hwndParent, pwszWizardTitle);
5285 break;
5286 case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE:
5287 ret = import_store(dwFlags, hwndParent, pwszWizardTitle,
5288 pImportSrc->u.hCertStore, hDestCertStore);
5289 break;
5290 default:
5291 WARN("unknown source type: %u\n", pImportSrc->dwSubjectChoice);
5292 SetLastError(E_INVALIDARG);
5293 ret = FALSE;
5295 return ret;
5298 static LRESULT CALLBACK import_finish_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
5299 LPARAM lp)
5301 LRESULT ret = 0;
5302 struct ImportWizData *data;
5304 switch (msg)
5306 case WM_INITDIALOG:
5308 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
5309 HWND lv = GetDlgItem(hwnd, IDC_IMPORT_SETTINGS);
5310 RECT rc;
5311 LVCOLUMNW column;
5313 data = (struct ImportWizData *)page->lParam;
5314 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
5315 SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_TITLE), WM_SETFONT,
5316 (WPARAM)data->titleFont, TRUE);
5317 GetWindowRect(lv, &rc);
5318 column.mask = LVCF_WIDTH;
5319 column.cx = (rc.right - rc.left) / 2 - 2;
5320 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
5321 SendMessageW(lv, LVM_INSERTCOLUMNW, 1, (LPARAM)&column);
5322 show_import_details(lv, data);
5323 break;
5325 case WM_NOTIFY:
5327 NMHDR *hdr = (NMHDR *)lp;
5329 switch (hdr->code)
5331 case PSN_SETACTIVE:
5333 HWND lv = GetDlgItem(hwnd, IDC_IMPORT_SETTINGS);
5335 data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5336 SendMessageW(lv, LVM_DELETEALLITEMS, 0, 0);
5337 show_import_details(lv, data);
5338 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
5339 PSWIZB_BACK | PSWIZB_FINISH);
5340 ret = TRUE;
5341 break;
5343 case PSN_WIZFINISH:
5345 data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5346 if ((data->success = do_import(data->dwFlags, hwnd,
5347 data->pwszWizardTitle, &data->importSrc, data->hDestCertStore)))
5349 WCHAR title[MAX_STRING_LEN], message[MAX_STRING_LEN];
5350 LPCWSTR pTitle;
5352 if (data->pwszWizardTitle)
5353 pTitle = data->pwszWizardTitle;
5354 else
5356 LoadStringW(hInstance, IDS_IMPORT_WIZARD, title,
5357 sizeof(title) / sizeof(title[0]));
5358 pTitle = title;
5360 LoadStringW(hInstance, IDS_IMPORT_SUCCEEDED, message,
5361 sizeof(message) / sizeof(message[0]));
5362 MessageBoxW(hwnd, message, pTitle, MB_OK);
5364 else
5365 import_warning(data->dwFlags, hwnd, data->pwszWizardTitle,
5366 IDS_IMPORT_FAILED);
5367 break;
5370 break;
5373 return ret;
5376 static BOOL show_import_ui(DWORD dwFlags, HWND hwndParent,
5377 LPCWSTR pwszWizardTitle, PCCRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc,
5378 HCERTSTORE hDestCertStore)
5380 PROPSHEETHEADERW hdr;
5381 PROPSHEETPAGEW pages[4];
5382 struct ImportWizData data;
5383 int nPages = 0;
5385 data.dwFlags = dwFlags;
5386 data.pwszWizardTitle = pwszWizardTitle;
5387 if (pImportSrc)
5388 memcpy(&data.importSrc, pImportSrc, sizeof(data.importSrc));
5389 else
5390 memset(&data.importSrc, 0, sizeof(data.importSrc));
5391 data.fileName = NULL;
5392 data.freeSource = FALSE;
5393 data.hDestCertStore = hDestCertStore;
5394 data.freeDest = FALSE;
5395 data.autoDest = TRUE;
5396 data.success = TRUE;
5398 memset(&pages, 0, sizeof(pages));
5400 pages[nPages].dwSize = sizeof(pages[0]);
5401 pages[nPages].hInstance = hInstance;
5402 pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_IMPORT_WELCOME);
5403 pages[nPages].pfnDlgProc = import_welcome_dlg_proc;
5404 pages[nPages].dwFlags = PSP_HIDEHEADER;
5405 pages[nPages].lParam = (LPARAM)&data;
5406 nPages++;
5408 if (!pImportSrc ||
5409 pImportSrc->dwSubjectChoice == CRYPTUI_WIZ_IMPORT_SUBJECT_FILE)
5411 pages[nPages].dwSize = sizeof(pages[0]);
5412 pages[nPages].hInstance = hInstance;
5413 pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_IMPORT_FILE);
5414 pages[nPages].pfnDlgProc = import_file_dlg_proc;
5415 pages[nPages].dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
5416 pages[nPages].pszHeaderTitle = MAKEINTRESOURCEW(IDS_IMPORT_FILE_TITLE);
5417 pages[nPages].pszHeaderSubTitle =
5418 MAKEINTRESOURCEW(IDS_IMPORT_FILE_SUBTITLE);
5419 pages[nPages].lParam = (LPARAM)&data;
5420 nPages++;
5422 else
5424 switch (pImportSrc->dwSubjectChoice)
5426 case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_CONTEXT:
5427 data.contentType = CERT_QUERY_CONTENT_CERT;
5428 break;
5429 case CRYPTUI_WIZ_IMPORT_SUBJECT_CRL_CONTEXT:
5430 data.contentType = CERT_QUERY_CONTENT_CRL;
5431 break;
5432 case CRYPTUI_WIZ_IMPORT_SUBJECT_CTL_CONTEXT:
5433 data.contentType = CERT_QUERY_CONTENT_CTL;
5434 break;
5435 case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE:
5436 data.contentType = CERT_QUERY_CONTENT_SERIALIZED_STORE;
5437 break;
5441 pages[nPages].dwSize = sizeof(pages[0]);
5442 pages[nPages].hInstance = hInstance;
5443 pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_IMPORT_STORE);
5444 pages[nPages].pfnDlgProc = import_store_dlg_proc;
5445 pages[nPages].dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
5446 pages[nPages].pszHeaderTitle = MAKEINTRESOURCEW(IDS_IMPORT_STORE_TITLE);
5447 pages[nPages].pszHeaderSubTitle =
5448 MAKEINTRESOURCEW(IDS_IMPORT_STORE_SUBTITLE);
5449 pages[nPages].lParam = (LPARAM)&data;
5450 nPages++;
5452 pages[nPages].dwSize = sizeof(pages[0]);
5453 pages[nPages].hInstance = hInstance;
5454 pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_IMPORT_FINISH);
5455 pages[nPages].pfnDlgProc = import_finish_dlg_proc;
5456 pages[nPages].dwFlags = PSP_HIDEHEADER;
5457 pages[nPages].lParam = (LPARAM)&data;
5458 nPages++;
5460 memset(&hdr, 0, sizeof(hdr));
5461 hdr.dwSize = sizeof(hdr);
5462 hdr.hwndParent = hwndParent;
5463 hdr.dwFlags = PSH_PROPSHEETPAGE | PSH_WIZARD97_NEW | PSH_HEADER |
5464 PSH_WATERMARK;
5465 hdr.hInstance = hInstance;
5466 if (pwszWizardTitle)
5467 hdr.pszCaption = pwszWizardTitle;
5468 else
5469 hdr.pszCaption = MAKEINTRESOURCEW(IDS_IMPORT_WIZARD);
5470 hdr.u3.ppsp = pages;
5471 hdr.nPages = nPages;
5472 hdr.u4.pszbmWatermark = MAKEINTRESOURCEW(IDB_CERT_WATERMARK);
5473 hdr.u5.pszbmHeader = MAKEINTRESOURCEW(IDB_CERT_HEADER);
5474 PropertySheetW(&hdr);
5475 HeapFree(GetProcessHeap(), 0, data.fileName);
5476 if (data.freeSource &&
5477 data.importSrc.dwSubjectChoice == CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE)
5478 CertCloseStore(data.importSrc.u.hCertStore, 0);
5479 DeleteObject(data.titleFont);
5480 return data.success;
5483 BOOL WINAPI CryptUIWizImport(DWORD dwFlags, HWND hwndParent, LPCWSTR pwszWizardTitle,
5484 PCCRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc, HCERTSTORE hDestCertStore)
5486 BOOL ret;
5488 TRACE("(0x%08x, %p, %s, %p, %p)\n", dwFlags, hwndParent, debugstr_w(pwszWizardTitle),
5489 pImportSrc, hDestCertStore);
5491 if (pImportSrc &&
5492 pImportSrc->dwSize != sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO))
5494 SetLastError(E_INVALIDARG);
5495 return FALSE;
5498 if (!(dwFlags & CRYPTUI_WIZ_NO_UI))
5499 ret = show_import_ui(dwFlags, hwndParent, pwszWizardTitle, pImportSrc,
5500 hDestCertStore);
5501 else if (pImportSrc)
5502 ret = do_import(dwFlags, hwndParent, pwszWizardTitle, pImportSrc,
5503 hDestCertStore);
5504 else
5506 /* Can't have no UI without specifying source */
5507 SetLastError(E_INVALIDARG);
5508 ret = FALSE;
5511 return ret;
5514 struct ExportWizData
5516 HFONT titleFont;
5517 DWORD dwFlags;
5518 LPCWSTR pwszWizardTitle;
5519 PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo;
5520 CRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO contextInfo;
5521 LPWSTR fileName;
5522 HANDLE file;
5523 BOOL success;
5526 static LRESULT CALLBACK export_welcome_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
5527 LPARAM lp)
5529 LRESULT ret = 0;
5531 switch (msg)
5533 case WM_INITDIALOG:
5535 struct ExportWizData *data;
5536 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
5537 WCHAR fontFace[MAX_STRING_LEN];
5538 HDC hDC = GetDC(hwnd);
5539 int height;
5541 data = (struct ExportWizData *)page->lParam;
5542 LoadStringW(hInstance, IDS_WIZARD_TITLE_FONT, fontFace,
5543 sizeof(fontFace) / sizeof(fontFace[0]));
5544 height = -MulDiv(12, GetDeviceCaps(hDC, LOGPIXELSY), 72);
5545 data->titleFont = CreateFontW(height, 0, 0, 0, FW_BOLD, 0, 0, 0,
5546 DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
5547 DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, fontFace);
5548 SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_TITLE), WM_SETFONT,
5549 (WPARAM)data->titleFont, TRUE);
5550 ReleaseDC(hwnd, hDC);
5551 break;
5553 case WM_NOTIFY:
5555 NMHDR *hdr = (NMHDR *)lp;
5557 switch (hdr->code)
5559 case PSN_SETACTIVE:
5560 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0, PSWIZB_NEXT);
5561 ret = TRUE;
5562 break;
5564 break;
5567 return ret;
5570 static BOOL export_info_has_private_key(PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo)
5572 BOOL ret = FALSE;
5574 if (pExportInfo->dwSubjectChoice == CRYPTUI_WIZ_EXPORT_CERT_CONTEXT)
5576 DWORD size;
5578 /* If there's a CRYPT_KEY_PROV_INFO set for this cert, assume the
5579 * cert has a private key.
5581 if (CertGetCertificateContextProperty(pExportInfo->u.pCertContext,
5582 CERT_KEY_PROV_INFO_PROP_ID, NULL, &size))
5583 ret = TRUE;
5585 return ret;
5588 static LRESULT CALLBACK export_format_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
5589 LPARAM lp)
5591 LRESULT ret = 0;
5592 struct ExportWizData *data;
5594 switch (msg)
5596 case WM_INITDIALOG:
5598 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
5599 int defaultFormatID;
5600 BOOL hasPrivateKey;
5602 data = (struct ExportWizData *)page->lParam;
5603 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
5604 hasPrivateKey = export_info_has_private_key(data->pExportInfo);
5605 if (hasPrivateKey)
5606 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_PFX), TRUE);
5607 switch (data->contextInfo.dwExportFormat)
5609 case CRYPTUI_WIZ_EXPORT_FORMAT_BASE64:
5610 defaultFormatID = IDC_EXPORT_FORMAT_BASE64;
5611 break;
5612 case CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7:
5613 defaultFormatID = IDC_EXPORT_FORMAT_CMS;
5614 break;
5615 case CRYPTUI_WIZ_EXPORT_FORMAT_PFX:
5616 if (hasPrivateKey)
5617 defaultFormatID = IDC_EXPORT_FORMAT_PFX;
5618 else
5619 defaultFormatID = IDC_EXPORT_FORMAT_DER;
5620 break;
5621 default:
5622 defaultFormatID = IDC_EXPORT_FORMAT_DER;
5624 SendMessageW(GetDlgItem(hwnd, defaultFormatID), BM_CLICK, 0, 0);
5625 break;
5627 case WM_NOTIFY:
5629 NMHDR *hdr = (NMHDR *)lp;
5631 switch (hdr->code)
5633 case PSN_SETACTIVE:
5634 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
5635 PSWIZB_BACK | PSWIZB_NEXT);
5636 ret = TRUE;
5637 break;
5638 case PSN_WIZNEXT:
5640 data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5641 if (IsDlgButtonChecked(hwnd, IDC_EXPORT_FORMAT_DER))
5642 data->contextInfo.dwExportFormat =
5643 CRYPTUI_WIZ_EXPORT_FORMAT_DER;
5644 else if (IsDlgButtonChecked(hwnd, IDC_EXPORT_FORMAT_BASE64))
5645 data->contextInfo.dwExportFormat =
5646 CRYPTUI_WIZ_EXPORT_FORMAT_BASE64;
5647 else if (IsDlgButtonChecked(hwnd, IDC_EXPORT_FORMAT_CMS))
5649 data->contextInfo.dwExportFormat =
5650 CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7;
5651 if (IsDlgButtonChecked(hwnd, IDC_EXPORT_CMS_INCLUDE_CHAIN))
5652 data->contextInfo.fExportChain =
5653 CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7;
5655 else
5657 data->contextInfo.dwExportFormat =
5658 CRYPTUI_WIZ_EXPORT_FORMAT_PFX;
5659 if (IsDlgButtonChecked(hwnd, IDC_EXPORT_PFX_INCLUDE_CHAIN))
5660 data->contextInfo.fExportChain = TRUE;
5661 if (IsDlgButtonChecked(hwnd, IDC_EXPORT_PFX_STRONG_ENCRYPTION))
5662 data->contextInfo.fStrongEncryption = TRUE;
5663 if (IsDlgButtonChecked(hwnd, IDC_EXPORT_PFX_DELETE_PRIVATE_KEY))
5664 data->contextInfo.fExportPrivateKeys = TRUE;
5666 break;
5669 break;
5671 case WM_COMMAND:
5672 switch (HIWORD(wp))
5674 case BN_CLICKED:
5675 switch (LOWORD(wp))
5677 case IDC_EXPORT_FORMAT_DER:
5678 case IDC_EXPORT_FORMAT_BASE64:
5679 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_CMS_INCLUDE_CHAIN),
5680 FALSE);
5681 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_PFX_INCLUDE_CHAIN),
5682 FALSE);
5683 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_PFX_STRONG_ENCRYPTION),
5684 FALSE);
5685 EnableWindow(GetDlgItem(hwnd,
5686 IDC_EXPORT_PFX_DELETE_PRIVATE_KEY), FALSE);
5687 break;
5688 case IDC_EXPORT_FORMAT_CMS:
5689 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_CMS_INCLUDE_CHAIN),
5690 TRUE);
5691 break;
5692 case IDC_EXPORT_FORMAT_PFX:
5693 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_PFX_INCLUDE_CHAIN),
5694 TRUE);
5695 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_PFX_STRONG_ENCRYPTION),
5696 TRUE);
5697 EnableWindow(GetDlgItem(hwnd,
5698 IDC_EXPORT_PFX_DELETE_PRIVATE_KEY), TRUE);
5699 break;
5701 break;
5703 break;
5705 return ret;
5708 static LPWSTR export_append_extension(struct ExportWizData *data,
5709 LPWSTR fileName)
5711 static const WCHAR cer[] = { '.','c','e','r',0 };
5712 static const WCHAR crl[] = { '.','c','r','l',0 };
5713 static const WCHAR ctl[] = { '.','c','t','l',0 };
5714 static const WCHAR p7b[] = { '.','p','7','b',0 };
5715 static const WCHAR pfx[] = { '.','p','f','x',0 };
5716 static const WCHAR sst[] = { '.','s','s','t',0 };
5717 LPCWSTR extension;
5718 LPWSTR dot;
5719 BOOL appendExtension;
5721 switch (data->contextInfo.dwExportFormat)
5723 case CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7:
5724 extension = p7b;
5725 break;
5726 case CRYPTUI_WIZ_EXPORT_FORMAT_PFX:
5727 extension = pfx;
5728 break;
5729 default:
5730 switch (data->pExportInfo->dwSubjectChoice)
5732 case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
5733 extension = crl;
5734 break;
5735 case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT:
5736 extension = ctl;
5737 break;
5738 case CRYPTUI_WIZ_EXPORT_CERT_STORE:
5739 extension = sst;
5740 break;
5741 default:
5742 extension = cer;
5745 dot = strrchrW(fileName, '.');
5746 if (dot)
5747 appendExtension = strcmpiW(dot, extension) != 0;
5748 else
5749 appendExtension = TRUE;
5750 if (appendExtension)
5752 fileName = HeapReAlloc(GetProcessHeap(), 0, fileName,
5753 (strlenW(fileName) + strlenW(extension) + 1) * sizeof(WCHAR));
5754 if (fileName)
5755 strcatW(fileName, extension);
5757 return fileName;
5760 static BOOL export_validate_filename(HWND hwnd, struct ExportWizData *data,
5761 LPCWSTR fileName)
5763 HANDLE file;
5764 BOOL tryCreate = TRUE, forceCreate = FALSE, ret = FALSE;
5766 file = CreateFileW(fileName, GENERIC_WRITE,
5767 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
5768 if (file != INVALID_HANDLE_VALUE)
5770 WCHAR warning[MAX_STRING_LEN], title[MAX_STRING_LEN];
5771 LPCWSTR pTitle;
5773 if (data->pwszWizardTitle)
5774 pTitle = data->pwszWizardTitle;
5775 else
5777 LoadStringW(hInstance, IDS_EXPORT_WIZARD, title,
5778 sizeof(title) / sizeof(title[0]));
5779 pTitle = title;
5781 LoadStringW(hInstance, IDS_EXPORT_FILE_EXISTS, warning,
5782 sizeof(warning) / sizeof(warning[0]));
5783 if (MessageBoxW(hwnd, warning, pTitle, MB_YESNO) == IDYES)
5784 forceCreate = TRUE;
5785 else
5786 tryCreate = FALSE;
5787 CloseHandle(file);
5789 if (tryCreate)
5791 file = CreateFileW(fileName, GENERIC_WRITE,
5792 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
5793 forceCreate ? CREATE_ALWAYS : CREATE_NEW,
5794 0, NULL);
5795 if (file != INVALID_HANDLE_VALUE)
5797 data->file = file;
5798 ret = TRUE;
5800 else
5802 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
5803 LPCWSTR pTitle;
5804 LPWSTR msgBuf, fullError;
5806 if (data->pwszWizardTitle)
5807 pTitle = data->pwszWizardTitle;
5808 else
5810 LoadStringW(hInstance, IDS_EXPORT_WIZARD, title,
5811 sizeof(title) / sizeof(title[0]));
5812 pTitle = title;
5814 LoadStringW(hInstance, IDS_IMPORT_OPEN_FAILED, error,
5815 sizeof(error) / sizeof(error[0]));
5816 FormatMessageW(
5817 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
5818 GetLastError(), 0, (LPWSTR) &msgBuf, 0, NULL);
5819 fullError = HeapAlloc(GetProcessHeap(), 0,
5820 (strlenW(error) + strlenW(fileName) + strlenW(msgBuf) + 3)
5821 * sizeof(WCHAR));
5822 if (fullError)
5824 LPWSTR ptr = fullError;
5826 strcpyW(ptr, error);
5827 ptr += strlenW(error);
5828 strcpyW(ptr, fileName);
5829 ptr += strlenW(fileName);
5830 *ptr++ = ':';
5831 *ptr++ = '\n';
5832 strcpyW(ptr, msgBuf);
5833 MessageBoxW(hwnd, fullError, pTitle, MB_ICONERROR | MB_OK);
5834 HeapFree(GetProcessHeap(), 0, fullError);
5836 LocalFree(msgBuf);
5839 return ret;
5842 static const WCHAR export_filter_cert[] = { '*','.','c','e','r',0 };
5843 static const WCHAR export_filter_crl[] = { '*','.','c','r','l',0 };
5844 static const WCHAR export_filter_ctl[] = { '*','.','s','t','l',0 };
5845 static const WCHAR export_filter_cms[] = { '*','.','p','7','b',0 };
5846 static const WCHAR export_filter_pfx[] = { '*','.','p','f','x',0 };
5847 static const WCHAR export_filter_sst[] = { '*','.','s','s','t',0 };
5849 static WCHAR *make_export_file_filter(DWORD exportFormat, DWORD subjectChoice)
5851 int baseLen, allLen, totalLen = 2, baseID;
5852 LPWSTR filter = NULL, baseFilter, all;
5853 LPCWSTR filterStr;
5855 switch (exportFormat)
5857 case CRYPTUI_WIZ_EXPORT_FORMAT_BASE64:
5858 baseID = IDS_EXPORT_FILTER_BASE64_CERT;
5859 filterStr = export_filter_cert;
5860 break;
5861 case CRYPTUI_WIZ_EXPORT_FORMAT_PFX:
5862 baseID = IDS_EXPORT_FILTER_PFX;
5863 filterStr = export_filter_pfx;
5864 break;
5865 case CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7:
5866 baseID = IDS_EXPORT_FILTER_CMS;
5867 filterStr = export_filter_cms;
5868 break;
5869 default:
5870 switch (subjectChoice)
5872 case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
5873 baseID = IDS_EXPORT_FILTER_CRL;
5874 filterStr = export_filter_crl;
5875 break;
5876 case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT:
5877 baseID = IDS_EXPORT_FILTER_CTL;
5878 filterStr = export_filter_ctl;
5879 break;
5880 case CRYPTUI_WIZ_EXPORT_CERT_STORE:
5881 baseID = IDS_EXPORT_FILTER_SERIALIZED_CERT_STORE;
5882 filterStr = export_filter_sst;
5883 break;
5884 default:
5885 baseID = IDS_EXPORT_FILTER_CERT;
5886 filterStr = export_filter_cert;
5887 break;
5890 baseLen = LoadStringW(hInstance, baseID, (LPWSTR)&baseFilter, 0);
5891 totalLen += baseLen + strlenW(filterStr) + 2;
5892 allLen = LoadStringW(hInstance, IDS_IMPORT_FILTER_ALL, (LPWSTR)&all, 0);
5893 totalLen += allLen + strlenW(filter_all) + 2;
5894 filter = HeapAlloc(GetProcessHeap(), 0, totalLen * sizeof(WCHAR));
5895 if (filter)
5897 LPWSTR ptr;
5899 ptr = filter;
5900 memcpy(ptr, baseFilter, baseLen * sizeof(WCHAR));
5901 ptr += baseLen;
5902 *ptr++ = 0;
5903 strcpyW(ptr, filterStr);
5904 ptr += strlenW(filterStr) + 1;
5905 memcpy(ptr, all, allLen * sizeof(WCHAR));
5906 ptr += allLen;
5907 *ptr++ = 0;
5908 strcpyW(ptr, filter_all);
5909 ptr += strlenW(filter_all) + 1;
5910 *ptr++ = 0;
5912 return filter;
5915 static LRESULT CALLBACK export_file_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
5916 LPARAM lp)
5918 LRESULT ret = 0;
5919 struct ExportWizData *data;
5921 switch (msg)
5923 case WM_INITDIALOG:
5925 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
5927 data = (struct ExportWizData *)page->lParam;
5928 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
5929 if (data->pExportInfo->pwszExportFileName)
5930 SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_FILENAME), WM_SETTEXT, 0,
5931 (LPARAM)data->pExportInfo->pwszExportFileName);
5932 break;
5934 case WM_NOTIFY:
5936 NMHDR *hdr = (NMHDR *)lp;
5938 switch (hdr->code)
5940 case PSN_WIZNEXT:
5942 HWND fileNameEdit = GetDlgItem(hwnd, IDC_EXPORT_FILENAME);
5943 DWORD len = SendMessageW(fileNameEdit, WM_GETTEXTLENGTH, 0, 0);
5945 data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5946 if (!len)
5948 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
5949 LPCWSTR pTitle;
5951 if (data->pwszWizardTitle)
5952 pTitle = data->pwszWizardTitle;
5953 else
5955 LoadStringW(hInstance, IDS_EXPORT_WIZARD, title,
5956 sizeof(title) / sizeof(title[0]));
5957 pTitle = title;
5959 LoadStringW(hInstance, IDS_IMPORT_EMPTY_FILE, error,
5960 sizeof(error) / sizeof(error[0]));
5961 MessageBoxW(hwnd, error, pTitle, MB_ICONERROR | MB_OK);
5962 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
5963 ret = 1;
5965 else
5967 LPWSTR fileName = HeapAlloc(GetProcessHeap(), 0,
5968 (len + 1) * sizeof(WCHAR));
5970 if (fileName)
5972 SendMessageW(fileNameEdit, WM_GETTEXT, len + 1,
5973 (LPARAM)fileName);
5974 fileName = export_append_extension(data, fileName);
5975 if (!export_validate_filename(hwnd, data, fileName))
5977 HeapFree(GetProcessHeap(), 0, fileName);
5978 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
5979 ret = 1;
5981 else
5982 data->fileName = fileName;
5985 break;
5987 case PSN_SETACTIVE:
5988 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
5989 PSWIZB_BACK | PSWIZB_NEXT);
5990 ret = TRUE;
5991 break;
5993 break;
5995 case WM_COMMAND:
5996 switch (wp)
5998 case IDC_EXPORT_BROWSE_FILE:
6000 OPENFILENAMEW ofn;
6001 WCHAR fileBuf[MAX_PATH];
6003 data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
6004 memset(&ofn, 0, sizeof(ofn));
6005 ofn.lStructSize = sizeof(ofn);
6006 ofn.hwndOwner = hwnd;
6007 ofn.lpstrFilter = make_export_file_filter(
6008 data->contextInfo.dwExportFormat,
6009 data->pExportInfo->dwSubjectChoice);
6010 ofn.lpstrFile = fileBuf;
6011 ofn.nMaxFile = sizeof(fileBuf) / sizeof(fileBuf[0]);
6012 fileBuf[0] = 0;
6013 if (GetSaveFileNameW(&ofn))
6014 SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_FILENAME), WM_SETTEXT,
6015 0, (LPARAM)ofn.lpstrFile);
6016 HeapFree(GetProcessHeap(), 0, (LPWSTR)ofn.lpstrFilter);
6017 break;
6020 break;
6022 return ret;
6025 static void show_export_details(HWND lv, struct ExportWizData *data)
6027 WCHAR text[MAX_STRING_LEN];
6028 LVITEMW item;
6029 int contentID;
6031 item.mask = LVIF_TEXT;
6032 if (data->fileName)
6034 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
6035 item.iSubItem = 0;
6036 LoadStringW(hInstance, IDS_IMPORT_FILE, text,
6037 sizeof(text)/ sizeof(text[0]));
6038 item.pszText = text;
6039 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
6040 item.iSubItem = 1;
6041 item.pszText = data->fileName;
6042 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
6045 item.pszText = text;
6046 switch (data->pExportInfo->dwSubjectChoice)
6048 case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
6049 case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT:
6050 case CRYPTUI_WIZ_EXPORT_CERT_STORE:
6051 case CRYPTUI_WIZ_EXPORT_CERT_STORE_CERTIFICATES_ONLY:
6052 /* do nothing */
6053 break;
6054 default:
6056 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
6057 item.iSubItem = 0;
6058 LoadStringW(hInstance, IDS_EXPORT_INCLUDE_CHAIN, text,
6059 sizeof(text) / sizeof(text[0]));
6060 SendMessageW(lv, LVM_INSERTITEMW, item.iItem, (LPARAM)&item);
6061 item.iSubItem = 1;
6062 LoadStringW(hInstance,
6063 data->contextInfo.fExportChain ? IDS_YES : IDS_NO, text,
6064 sizeof(text) / sizeof(text[0]));
6065 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
6067 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
6068 item.iSubItem = 0;
6069 LoadStringW(hInstance, IDS_EXPORT_KEYS, text,
6070 sizeof(text) / sizeof(text[0]));
6071 SendMessageW(lv, LVM_INSERTITEMW, item.iItem, (LPARAM)&item);
6072 item.iSubItem = 1;
6073 LoadStringW(hInstance,
6074 data->contextInfo.fExportPrivateKeys ? IDS_YES : IDS_NO, text,
6075 sizeof(text) / sizeof(text[0]));
6076 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
6080 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
6081 item.iSubItem = 0;
6082 LoadStringW(hInstance, IDS_EXPORT_FORMAT, text,
6083 sizeof(text)/ sizeof(text[0]));
6084 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
6086 item.iSubItem = 1;
6087 switch (data->pExportInfo->dwSubjectChoice)
6089 case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
6090 contentID = IDS_EXPORT_FILTER_CRL;
6091 break;
6092 case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT:
6093 contentID = IDS_EXPORT_FILTER_CTL;
6094 break;
6095 case CRYPTUI_WIZ_EXPORT_CERT_STORE:
6096 contentID = IDS_EXPORT_FILTER_SERIALIZED_CERT_STORE;
6097 break;
6098 default:
6099 switch (data->contextInfo.dwExportFormat)
6101 case CRYPTUI_WIZ_EXPORT_FORMAT_BASE64:
6102 contentID = IDS_EXPORT_FILTER_BASE64_CERT;
6103 break;
6104 case CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7:
6105 contentID = IDS_EXPORT_FILTER_CMS;
6106 break;
6107 case CRYPTUI_WIZ_EXPORT_FORMAT_PFX:
6108 contentID = IDS_EXPORT_FILTER_PFX;
6109 break;
6110 default:
6111 contentID = IDS_EXPORT_FILTER_CERT;
6114 LoadStringW(hInstance, contentID, text, sizeof(text) / sizeof(text[0]));
6115 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
6118 static inline BOOL save_der(HANDLE file, const BYTE *pb, DWORD cb)
6120 DWORD bytesWritten;
6122 return WriteFile(file, pb, cb, &bytesWritten, NULL);
6125 static BOOL save_base64(HANDLE file, const BYTE *pb, DWORD cb)
6127 BOOL ret;
6128 DWORD size = 0;
6130 if ((ret = CryptBinaryToStringA(pb, cb, CRYPT_STRING_BASE64, NULL, &size)))
6132 LPSTR buf = HeapAlloc(GetProcessHeap(), 0, size);
6134 if (buf)
6136 if ((ret = CryptBinaryToStringA(pb, cb, CRYPT_STRING_BASE64, buf,
6137 &size)))
6138 ret = WriteFile(file, buf, size, &size, NULL);
6139 HeapFree(GetProcessHeap(), 0, buf);
6141 else
6143 SetLastError(ERROR_OUTOFMEMORY);
6144 ret = FALSE;
6147 return ret;
6150 static inline BOOL save_store_as_cms(HANDLE file, HCERTSTORE store)
6152 return CertSaveStore(store, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
6153 CERT_STORE_SAVE_AS_PKCS7, CERT_STORE_SAVE_TO_FILE, file, 0);
6156 static BOOL save_cert_as_cms(HANDLE file, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo,
6157 BOOL includeChain)
6159 BOOL ret;
6160 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
6161 CERT_STORE_CREATE_NEW_FLAG, NULL);
6163 if (store)
6165 if (includeChain)
6167 HCERTSTORE addlStore = CertOpenStore(CERT_STORE_PROV_COLLECTION,
6168 0, 0, CERT_STORE_CREATE_NEW_FLAG, NULL);
6170 if (addlStore)
6172 DWORD i;
6174 ret = TRUE;
6175 for (i = 0; ret && i < pExportInfo->cStores; i++)
6176 ret = CertAddStoreToCollection(addlStore,
6177 pExportInfo->rghStores, 0, 0);
6178 if (ret)
6180 PCCERT_CHAIN_CONTEXT chain;
6182 ret = CertGetCertificateChain(NULL,
6183 pExportInfo->u.pCertContext, NULL, addlStore, NULL, 0,
6184 NULL, &chain);
6185 if (ret)
6187 DWORD j;
6189 for (i = 0; ret && i < chain->cChain; i++)
6190 for (j = 0; ret && j < chain->rgpChain[i]->cElement;
6191 j++)
6192 ret = CertAddCertificateContextToStore(store,
6193 chain->rgpChain[i]->rgpElement[j]->pCertContext,
6194 CERT_STORE_ADD_ALWAYS, NULL);
6195 CertFreeCertificateChain(chain);
6197 else
6199 /* No chain could be created, just add the individual
6200 * cert to the message.
6202 ret = CertAddCertificateContextToStore(store,
6203 pExportInfo->u.pCertContext, CERT_STORE_ADD_ALWAYS,
6204 NULL);
6207 CertCloseStore(addlStore, 0);
6209 else
6210 ret = FALSE;
6212 else
6213 ret = CertAddCertificateContextToStore(store,
6214 pExportInfo->u.pCertContext, CERT_STORE_ADD_ALWAYS, NULL);
6215 if (ret)
6216 ret = save_store_as_cms(file, store);
6217 CertCloseStore(store, 0);
6219 else
6220 ret = FALSE;
6221 return ret;
6224 static BOOL save_serialized_store(HANDLE file, HCERTSTORE store)
6226 return CertSaveStore(store, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
6227 CERT_STORE_SAVE_AS_STORE, CERT_STORE_SAVE_TO_FILE, file, 0);
6230 static BOOL do_export(HANDLE file, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo,
6231 PCCRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO pContextInfo)
6233 BOOL ret;
6235 if (pContextInfo->dwSize != sizeof(CRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO))
6237 SetLastError(E_INVALIDARG);
6238 return FALSE;
6240 switch (pExportInfo->dwSubjectChoice)
6242 case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
6243 ret = save_der(file,
6244 pExportInfo->u.pCRLContext->pbCrlEncoded,
6245 pExportInfo->u.pCRLContext->cbCrlEncoded);
6246 break;
6247 case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT:
6248 ret = save_der(file,
6249 pExportInfo->u.pCTLContext->pbCtlEncoded,
6250 pExportInfo->u.pCTLContext->cbCtlEncoded);
6251 break;
6252 case CRYPTUI_WIZ_EXPORT_CERT_STORE:
6253 ret = save_serialized_store(file, pExportInfo->u.hCertStore);
6254 break;
6255 case CRYPTUI_WIZ_EXPORT_CERT_STORE_CERTIFICATES_ONLY:
6256 ret = save_store_as_cms(file, pExportInfo->u.hCertStore);
6257 break;
6258 default:
6259 switch (pContextInfo->dwExportFormat)
6261 case CRYPTUI_WIZ_EXPORT_FORMAT_DER:
6262 ret = save_der(file, pExportInfo->u.pCertContext->pbCertEncoded,
6263 pExportInfo->u.pCertContext->cbCertEncoded);
6264 break;
6265 case CRYPTUI_WIZ_EXPORT_FORMAT_BASE64:
6266 ret = save_base64(file,
6267 pExportInfo->u.pCertContext->pbCertEncoded,
6268 pExportInfo->u.pCertContext->cbCertEncoded);
6269 break;
6270 case CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7:
6271 ret = save_cert_as_cms(file, pExportInfo,
6272 pContextInfo->fExportChain);
6273 break;
6274 case CRYPTUI_WIZ_EXPORT_FORMAT_PFX:
6275 FIXME("unimplemented for PFX\n");
6276 ret = FALSE;
6277 break;
6278 default:
6279 SetLastError(E_FAIL);
6280 ret = FALSE;
6283 return ret;
6286 static LRESULT CALLBACK export_finish_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
6287 LPARAM lp)
6289 LRESULT ret = 0;
6290 struct ExportWizData *data;
6292 switch (msg)
6294 case WM_INITDIALOG:
6296 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
6297 HWND lv = GetDlgItem(hwnd, IDC_EXPORT_SETTINGS);
6298 RECT rc;
6299 LVCOLUMNW column;
6301 data = (struct ExportWizData *)page->lParam;
6302 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
6303 SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_TITLE), WM_SETFONT,
6304 (WPARAM)data->titleFont, TRUE);
6305 GetWindowRect(lv, &rc);
6306 column.mask = LVCF_WIDTH;
6307 column.cx = (rc.right - rc.left) / 2 - 2;
6308 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
6309 SendMessageW(lv, LVM_INSERTCOLUMNW, 1, (LPARAM)&column);
6310 show_export_details(lv, data);
6311 break;
6313 case WM_NOTIFY:
6315 NMHDR *hdr = (NMHDR *)lp;
6317 switch (hdr->code)
6319 case PSN_SETACTIVE:
6321 HWND lv = GetDlgItem(hwnd, IDC_EXPORT_SETTINGS);
6323 data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
6324 SendMessageW(lv, LVM_DELETEALLITEMS, 0, 0);
6325 show_export_details(lv, data);
6326 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
6327 PSWIZB_BACK | PSWIZB_FINISH);
6328 ret = TRUE;
6329 break;
6331 case PSN_WIZFINISH:
6333 int messageID;
6334 WCHAR title[MAX_STRING_LEN], message[MAX_STRING_LEN];
6335 LPCWSTR pTitle;
6336 DWORD mbFlags;
6338 data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
6339 if ((data->success = do_export(data->file, data->pExportInfo,
6340 &data->contextInfo)))
6342 messageID = IDS_EXPORT_SUCCEEDED;
6343 mbFlags = MB_OK;
6345 else
6347 messageID = IDS_EXPORT_FAILED;
6348 mbFlags = MB_OK | MB_ICONERROR;
6350 if (data->pwszWizardTitle)
6351 pTitle = data->pwszWizardTitle;
6352 else
6354 LoadStringW(hInstance, IDS_EXPORT_WIZARD, title,
6355 sizeof(title) / sizeof(title[0]));
6356 pTitle = title;
6358 LoadStringW(hInstance, messageID, message,
6359 sizeof(message) / sizeof(message[0]));
6360 MessageBoxW(hwnd, message, pTitle, mbFlags);
6361 break;
6364 break;
6367 return ret;
6370 static BOOL show_export_ui(DWORD dwFlags, HWND hwndParent,
6371 LPCWSTR pwszWizardTitle, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo, void *pvoid)
6373 PROPSHEETHEADERW hdr;
6374 PROPSHEETPAGEW pages[4];
6375 struct ExportWizData data;
6376 int nPages = 0;
6377 BOOL showFormatPage = TRUE;
6379 data.dwFlags = dwFlags;
6380 data.pwszWizardTitle = pwszWizardTitle;
6381 data.pExportInfo = pExportInfo;
6382 data.contextInfo.dwSize = sizeof(data.contextInfo);
6383 data.contextInfo.dwExportFormat = CRYPTUI_WIZ_EXPORT_FORMAT_DER;
6384 data.contextInfo.fExportChain = FALSE;
6385 data.contextInfo.fStrongEncryption = FALSE;
6386 data.contextInfo.fExportPrivateKeys = FALSE;
6387 if (pExportInfo->dwSubjectChoice == CRYPTUI_WIZ_EXPORT_CERT_CONTEXT &&
6388 pvoid)
6389 memcpy(&data.contextInfo, pvoid,
6390 min(((PCCRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO)pvoid)->dwSize,
6391 sizeof(data.contextInfo)));
6392 data.fileName = NULL;
6393 data.file = INVALID_HANDLE_VALUE;
6394 data.success = FALSE;
6396 memset(&pages, 0, sizeof(pages));
6398 pages[nPages].dwSize = sizeof(pages[0]);
6399 pages[nPages].hInstance = hInstance;
6400 pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_EXPORT_WELCOME);
6401 pages[nPages].pfnDlgProc = export_welcome_dlg_proc;
6402 pages[nPages].dwFlags = PSP_HIDEHEADER;
6403 pages[nPages].lParam = (LPARAM)&data;
6404 nPages++;
6406 switch (pExportInfo->dwSubjectChoice)
6408 case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
6409 case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT:
6410 showFormatPage = FALSE;
6411 data.contextInfo.dwExportFormat = CRYPTUI_WIZ_EXPORT_FORMAT_DER;
6412 break;
6413 case CRYPTUI_WIZ_EXPORT_CERT_STORE:
6414 showFormatPage = FALSE;
6415 data.contextInfo.dwExportFormat =
6416 CRYPTUI_WIZ_EXPORT_FORMAT_SERIALIZED_CERT_STORE;
6417 break;
6418 case CRYPTUI_WIZ_EXPORT_CERT_STORE_CERTIFICATES_ONLY:
6419 showFormatPage = FALSE;
6420 data.contextInfo.dwExportFormat = CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7;
6421 break;
6423 if (showFormatPage)
6425 pages[nPages].dwSize = sizeof(pages[0]);
6426 pages[nPages].hInstance = hInstance;
6427 pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_EXPORT_FORMAT);
6428 pages[nPages].pfnDlgProc = export_format_dlg_proc;
6429 pages[nPages].dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
6430 pages[nPages].pszHeaderTitle =
6431 MAKEINTRESOURCEW(IDS_EXPORT_FORMAT_TITLE);
6432 pages[nPages].pszHeaderSubTitle =
6433 MAKEINTRESOURCEW(IDS_EXPORT_FORMAT_SUBTITLE);
6434 pages[nPages].lParam = (LPARAM)&data;
6435 nPages++;
6438 pages[nPages].dwSize = sizeof(pages[0]);
6439 pages[nPages].hInstance = hInstance;
6440 pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_EXPORT_FILE);
6441 pages[nPages].pfnDlgProc = export_file_dlg_proc;
6442 pages[nPages].dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
6443 pages[nPages].pszHeaderTitle = MAKEINTRESOURCEW(IDS_EXPORT_FILE_TITLE);
6444 pages[nPages].pszHeaderSubTitle =
6445 MAKEINTRESOURCEW(IDS_EXPORT_FILE_SUBTITLE);
6446 pages[nPages].lParam = (LPARAM)&data;
6447 nPages++;
6449 pages[nPages].dwSize = sizeof(pages[0]);
6450 pages[nPages].hInstance = hInstance;
6451 pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_EXPORT_FINISH);
6452 pages[nPages].pfnDlgProc = export_finish_dlg_proc;
6453 pages[nPages].dwFlags = PSP_HIDEHEADER;
6454 pages[nPages].lParam = (LPARAM)&data;
6455 nPages++;
6457 memset(&hdr, 0, sizeof(hdr));
6458 hdr.dwSize = sizeof(hdr);
6459 hdr.hwndParent = hwndParent;
6460 hdr.dwFlags = PSH_PROPSHEETPAGE | PSH_WIZARD97_NEW | PSH_HEADER |
6461 PSH_WATERMARK;
6462 hdr.hInstance = hInstance;
6463 if (pwszWizardTitle)
6464 hdr.pszCaption = pwszWizardTitle;
6465 else
6466 hdr.pszCaption = MAKEINTRESOURCEW(IDS_EXPORT_WIZARD);
6467 hdr.u3.ppsp = pages;
6468 hdr.nPages = nPages;
6469 hdr.u4.pszbmWatermark = MAKEINTRESOURCEW(IDB_CERT_WATERMARK);
6470 hdr.u5.pszbmHeader = MAKEINTRESOURCEW(IDB_CERT_HEADER);
6471 PropertySheetW(&hdr);
6472 DeleteObject(data.titleFont);
6473 CloseHandle(data.file);
6474 HeapFree(GetProcessHeap(), 0, data.fileName);
6475 return data.success;
6478 BOOL WINAPI CryptUIWizExport(DWORD dwFlags, HWND hwndParent,
6479 LPCWSTR pwszWizardTitle, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo, void *pvoid)
6481 BOOL ret;
6483 TRACE("(%08x, %p, %s, %p, %p)\n", dwFlags, hwndParent,
6484 debugstr_w(pwszWizardTitle), pExportInfo, pvoid);
6486 if (!(dwFlags & CRYPTUI_WIZ_NO_UI))
6487 ret = show_export_ui(dwFlags, hwndParent, pwszWizardTitle, pExportInfo,
6488 pvoid);
6489 else
6491 HANDLE file = CreateFileW(pExportInfo->pwszExportFileName,
6492 GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
6493 CREATE_ALWAYS, 0, NULL);
6495 if (file != INVALID_HANDLE_VALUE)
6497 ret = do_export(file, pExportInfo, pvoid);
6498 CloseHandle(file);
6500 else
6501 ret = FALSE;
6503 return ret;