d3dx9/tests: Add tests for using D3DXLoadSurfaceFromSurface() with default render...
[wine.git] / dlls / cryptui / main.c
blobb62ce9ef689bf68fd0d44179a40462c759f2e37b
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;
62 return TRUE;
65 static WCHAR *strdupAtoW( const char *str )
67 DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
68 WCHAR *ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
69 if (ret) MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
70 return ret;
73 #define MAX_STRING_LEN 512
75 static void add_cert_columns(HWND hwnd)
77 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
78 RECT rc;
79 WCHAR buf[MAX_STRING_LEN];
80 LVCOLUMNW column;
82 SendMessageW(lv, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
83 GetWindowRect(lv, &rc);
84 LoadStringW(hInstance, IDS_SUBJECT_COLUMN, buf, ARRAY_SIZE(buf));
85 column.mask = LVCF_WIDTH | LVCF_TEXT;
86 column.cx = (rc.right - rc.left) * 29 / 100 - 2;
87 column.pszText = buf;
88 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
89 LoadStringW(hInstance, IDS_ISSUER_COLUMN, buf, ARRAY_SIZE(buf));
90 SendMessageW(lv, LVM_INSERTCOLUMNW, 1, (LPARAM)&column);
91 column.cx = (rc.right - rc.left) * 16 / 100 - 2;
92 LoadStringW(hInstance, IDS_EXPIRATION_COLUMN, buf, ARRAY_SIZE(buf));
93 SendMessageW(lv, LVM_INSERTCOLUMNW, 2, (LPARAM)&column);
94 column.cx = (rc.right - rc.left) * 23 / 100 - 1;
95 LoadStringW(hInstance, IDS_FRIENDLY_NAME_COLUMN, buf, ARRAY_SIZE(buf));
96 SendMessageW(lv, LVM_INSERTCOLUMNW, 3, (LPARAM)&column);
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;
107 LPWSTR none;
109 item.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_TEXT;
110 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
111 item.iSubItem = 0;
112 item.iImage = 0;
113 item.lParam = (LPARAM)CertDuplicateCertificateContext(cert);
114 len = CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL,
115 NULL, 0);
116 if (len > *allocatedLen)
118 HeapFree(GetProcessHeap(), 0, *str);
119 *str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
120 if (*str)
121 *allocatedLen = len;
123 if (*str)
125 CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL,
126 *str, len);
127 item.pszText = *str;
128 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
131 item.mask = LVIF_TEXT;
132 len = CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
133 CERT_NAME_ISSUER_FLAG, NULL, NULL, 0);
134 if (len > *allocatedLen)
136 HeapFree(GetProcessHeap(), 0, *str);
137 *str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
138 if (*str)
139 *allocatedLen = len;
141 if (*str)
143 CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
144 CERT_NAME_ISSUER_FLAG, NULL, *str, len);
145 item.pszText = *str;
146 item.iSubItem = 1;
147 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
150 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SSHORTDATE, dateFmt, ARRAY_SIZE(dateFmt));
151 FileTimeToSystemTime(&cert->pCertInfo->NotAfter, &sysTime);
152 GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, date, ARRAY_SIZE(date));
153 item.pszText = date;
154 item.iSubItem = 2;
155 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
157 if (!CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID,
158 NULL, &len))
159 len = LoadStringW(hInstance, IDS_FRIENDLY_NAME_NONE, (LPWSTR)&none, 0);
160 if (len > *allocatedLen)
162 HeapFree(GetProcessHeap(), 0, *str);
163 *str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
164 if (*str)
165 *allocatedLen = len;
167 if (*str)
169 if (!CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID,
170 *str, &len))
171 item.pszText = none;
172 else
173 item.pszText = *str;
174 item.iSubItem = 3;
175 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
179 static LPSTR get_cert_mgr_usages(void)
181 static const WCHAR keyName[] = { 'S','o','f','t','w','a','r','e','\\','M',
182 'i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g','r','a',
183 'p','h','y','\\','U','I','\\','C','e','r','t','m','g','r','\\','P','u',
184 'r','p','o','s','e',0 };
185 LPSTR str = NULL;
186 HKEY key;
188 if (!RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, NULL, 0, KEY_READ,
189 NULL, &key, NULL))
191 LONG rc;
192 DWORD type, size;
194 rc = RegQueryValueExA(key, "Purpose", NULL, &type, NULL, &size);
195 if ((!rc || rc == ERROR_MORE_DATA) && type == REG_SZ)
197 str = HeapAlloc(GetProcessHeap(), 0, size);
198 if (str)
200 rc = RegQueryValueExA(key, "Purpose", NULL, NULL, (LPBYTE)str,
201 &size);
202 if (rc)
204 HeapFree(GetProcessHeap(), 0, str);
205 str = NULL;
209 RegCloseKey(key);
211 return str;
214 typedef enum {
215 PurposeFilterShowAll = 0,
216 PurposeFilterShowAdvanced = 1,
217 PurposeFilterShowOID = 2
218 } PurposeFilter;
220 static void initialize_purpose_selection(HWND hwnd)
222 HWND cb = GetDlgItem(hwnd, IDC_MGR_PURPOSE_SELECTION);
223 WCHAR buf[MAX_STRING_LEN];
224 LPSTR usages;
225 int index;
227 LoadStringW(hInstance, IDS_PURPOSE_ALL, buf, ARRAY_SIZE(buf));
228 index = SendMessageW(cb, CB_INSERTSTRING, -1, (LPARAM)buf);
229 SendMessageW(cb, CB_SETITEMDATA, index, (LPARAM)PurposeFilterShowAll);
230 LoadStringW(hInstance, IDS_PURPOSE_ADVANCED, buf, ARRAY_SIZE(buf));
231 index = SendMessageW(cb, CB_INSERTSTRING, -1, (LPARAM)buf);
232 SendMessageW(cb, CB_SETITEMDATA, index, (LPARAM)PurposeFilterShowAdvanced);
233 SendMessageW(cb, CB_SETCURSEL, 0, 0);
234 if ((usages = get_cert_mgr_usages()))
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 usage = 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; advancedUsage && *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 advancedUsage = 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 int CALLBACK cert_mgr_sort_by_subject(LPARAM lp1, LPARAM lp2, LPARAM lp);
353 static void show_store_certs(HWND hwnd, HCERTSTORE store)
355 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
356 HWND cb = GetDlgItem(hwnd, IDC_MGR_PURPOSE_SELECTION);
357 PCCERT_CONTEXT cert = NULL;
358 DWORD allocatedLen = 0;
359 LPWSTR str = NULL;
360 int index;
361 PurposeFilter filter = PurposeFilterShowAll;
362 LPCSTR oid = NULL;
363 CERT_ENHKEY_USAGE *advanced = NULL;
365 index = SendMessageW(cb, CB_GETCURSEL, 0, 0);
366 if (index >= 0)
368 INT_PTR data = SendMessageW(cb, CB_GETITEMDATA, index, 0);
370 if (!HIWORD(data))
371 filter = data;
372 else
374 PCCRYPT_OID_INFO info = (PCCRYPT_OID_INFO)data;
376 filter = PurposeFilterShowOID;
377 oid = info->pszOID;
380 if (filter == PurposeFilterShowAdvanced)
381 advanced = create_advanced_filter();
382 do {
383 cert = CertEnumCertificatesInStore(store, cert);
384 if (cert)
386 BOOL show = FALSE;
388 if (filter == PurposeFilterShowAll)
389 show = TRUE;
390 else
392 int numOIDs;
393 DWORD cbOIDs = 0;
395 if (CertGetValidUsages(1, &cert, &numOIDs, NULL, &cbOIDs))
397 if (numOIDs == -1)
399 /* -1 implies all usages are valid */
400 show = TRUE;
402 else
404 LPSTR *oids = HeapAlloc(GetProcessHeap(), 0, cbOIDs);
406 if (oids)
408 if (CertGetValidUsages(1, &cert, &numOIDs, oids,
409 &cbOIDs))
411 int i;
413 if (filter == PurposeFilterShowOID)
415 for (i = 0; !show && i < numOIDs; i++)
416 if (!strcmp(oids[i], oid))
417 show = TRUE;
419 else
421 for (i = 0; !show && i < numOIDs; i++)
423 DWORD j;
425 for (j = 0; !show &&
426 j < advanced->cUsageIdentifier; j++)
427 if (!strcmp(oids[i],
428 advanced->rgpszUsageIdentifier[j]))
429 show = TRUE;
433 HeapFree(GetProcessHeap(), 0, oids);
438 if (show)
439 add_cert_to_view(lv, cert, &allocatedLen, &str);
441 } while (cert);
442 HeapFree(GetProcessHeap(), 0, str);
443 if (advanced)
445 HeapFree(GetProcessHeap(), 0, advanced->rgpszUsageIdentifier);
446 HeapFree(GetProcessHeap(), 0, advanced);
448 SendMessageW(lv, LVM_SORTITEMSEX, (WPARAM)lv,
449 (LPARAM)cert_mgr_sort_by_subject);
452 static const WCHAR my[] = { 'M','y',0 };
453 static const WCHAR addressBook[] = {
454 'A','d','d','r','e','s','s','B','o','o','k',0 };
455 static const WCHAR ca[] = { 'C','A',0 };
456 static const WCHAR root[] = { 'R','o','o','t',0 };
457 static const WCHAR trustedPublisher[] = {
458 'T','r','u','s','t','e','d','P','u','b','l','i','s','h','e','r',0 };
459 static const WCHAR disallowed[] = { 'D','i','s','a','l','l','o','w','e','d',0 };
461 struct CertMgrStoreInfo
463 LPCWSTR name;
464 int removeWarning;
465 int removePluralWarning;
468 static const struct CertMgrStoreInfo defaultStoreList[] = {
469 { my, IDS_WARN_REMOVE_MY, IDS_WARN_REMOVE_PLURAL_MY },
470 { addressBook, IDS_WARN_REMOVE_ADDRESSBOOK,
471 IDS_WARN_REMOVE_PLURAL_ADDRESSBOOK },
472 { ca, IDS_WARN_REMOVE_CA, IDS_WARN_REMOVE_PLURAL_CA },
473 { root, IDS_WARN_REMOVE_ROOT, IDS_WARN_REMOVE_PLURAL_ROOT },
474 { trustedPublisher, IDS_WARN_REMOVE_TRUSTEDPUBLISHER,
475 IDS_WARN_REMOVE_PLURAL_TRUSTEDPUBLISHER },
476 { disallowed, IDS_WARN_REMOVE_DEFAULT },
479 static const struct CertMgrStoreInfo publisherStoreList[] = {
480 { root, IDS_WARN_REMOVE_ROOT, IDS_WARN_REMOVE_PLURAL_ROOT },
481 { trustedPublisher, IDS_WARN_REMOVE_TRUSTEDPUBLISHER,
482 IDS_WARN_REMOVE_PLURAL_TRUSTEDPUBLISHER },
483 { disallowed, IDS_WARN_REMOVE_PLURAL_DEFAULT },
486 struct CertMgrData
488 HIMAGELIST imageList;
489 LPCWSTR title;
490 DWORD nStores;
491 const struct CertMgrStoreInfo *stores;
494 static void show_cert_stores(HWND hwnd, DWORD dwFlags, struct CertMgrData *data)
496 const struct CertMgrStoreInfo *storeList;
497 int cStores, i;
498 HWND tab = GetDlgItem(hwnd, IDC_MGR_STORES);
500 if (dwFlags & CRYPTUI_CERT_MGR_PUBLISHER_TAB)
502 storeList = publisherStoreList;
503 cStores = ARRAY_SIZE(publisherStoreList);
505 else
507 storeList = defaultStoreList;
508 cStores = ARRAY_SIZE(defaultStoreList);
510 if (dwFlags & CRYPTUI_CERT_MGR_SINGLE_TAB_FLAG)
511 cStores = 1;
512 data->nStores = cStores;
513 data->stores = storeList;
514 for (i = 0; i < cStores; i++)
516 LPCWSTR name;
517 TCITEMW item;
518 HCERTSTORE store;
520 if (!(name = CryptFindLocalizedName(storeList[i].name)))
521 name = storeList[i].name;
522 store = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0,
523 CERT_SYSTEM_STORE_CURRENT_USER, storeList[i].name);
524 item.mask = TCIF_TEXT | TCIF_PARAM;
525 item.pszText = (LPWSTR)name;
526 item.lParam = (LPARAM)store;
527 SendMessageW(tab, TCM_INSERTITEMW, i, (LPARAM)&item);
531 static void free_certs(HWND lv)
533 LVITEMW item;
534 int items = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0), i;
536 for (i = 0; i < items; i++)
538 item.mask = LVIF_PARAM;
539 item.iItem = i;
540 item.iSubItem = 0;
541 SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item);
542 CertFreeCertificateContext((PCCERT_CONTEXT)item.lParam);
546 static HCERTSTORE cert_mgr_index_to_store(HWND tab, int index)
548 TCITEMW item;
550 item.mask = TCIF_PARAM;
551 SendMessageW(tab, TCM_GETITEMW, index, (LPARAM)&item);
552 return (HCERTSTORE)item.lParam;
555 static HCERTSTORE cert_mgr_current_store(HWND hwnd)
557 HWND tab = GetDlgItem(hwnd, IDC_MGR_STORES);
559 return cert_mgr_index_to_store(tab, SendMessageW(tab, TCM_GETCURSEL, 0, 0));
562 static void close_stores(HWND tab)
564 int i, tabs = SendMessageW(tab, TCM_GETITEMCOUNT, 0, 0);
566 for (i = 0; i < tabs; i++)
567 CertCloseStore(cert_mgr_index_to_store(tab, i), 0);
570 static void refresh_store_certs(HWND hwnd)
572 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
574 free_certs(lv);
575 SendMessageW(lv, LVM_DELETEALLITEMS, 0, 0);
576 show_store_certs(hwnd, cert_mgr_current_store(hwnd));
579 typedef enum {
580 CheckBitmapIndexUnchecked = 1,
581 CheckBitmapIndexChecked = 2,
582 CheckBitmapIndexDisabledUnchecked = 3,
583 CheckBitmapIndexDisabledChecked = 4
584 } CheckBitmapIndex;
586 static void add_known_usage(HWND lv, PCCRYPT_OID_INFO info,
587 CheckBitmapIndex state)
589 LVITEMW item;
591 item.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM;
592 item.state = INDEXTOSTATEIMAGEMASK(state);
593 item.stateMask = LVIS_STATEIMAGEMASK;
594 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
595 item.iSubItem = 0;
596 item.lParam = (LPARAM)info;
597 item.pszText = (LPWSTR)info->pwszName;
598 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
601 static void add_known_usages_to_list(HWND lv, CheckBitmapIndex state)
603 PCCRYPT_OID_INFO *usages;
605 if (WTHelperGetKnownUsages(1, &usages))
607 PCCRYPT_OID_INFO *ptr;
609 for (ptr = usages; *ptr; ptr++)
610 add_known_usage(lv, *ptr, state);
611 WTHelperGetKnownUsages(2, &usages);
615 static void toggle_usage(HWND hwnd, int iItem)
617 LVITEMW item;
618 int res;
619 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
621 item.mask = LVIF_STATE;
622 item.iItem = iItem;
623 item.iSubItem = 0;
624 item.stateMask = LVIS_STATEIMAGEMASK;
625 res = SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item);
626 if (res)
628 int state = item.state >> 12;
630 item.state = INDEXTOSTATEIMAGEMASK(
631 state == CheckBitmapIndexChecked ? CheckBitmapIndexUnchecked :
632 CheckBitmapIndexChecked);
633 SendMessageW(lv, LVM_SETITEMSTATE, iItem, (LPARAM)&item);
637 static LONG_PTR find_oid_in_list(HWND lv, LPCSTR oid)
639 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
640 (void *)oid, CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
641 LONG_PTR ret;
643 if (oidInfo)
645 LVFINDINFOW findInfo;
647 findInfo.flags = LVFI_PARAM;
648 findInfo.lParam = (LPARAM)oidInfo;
649 ret = SendMessageW(lv, LVM_FINDITEMW, -1, (LPARAM)&findInfo);
651 else
653 LVFINDINFOA findInfo;
655 findInfo.flags = LVFI_STRING;
656 findInfo.psz = oid;
657 ret = SendMessageW(lv, LVM_FINDITEMA, -1, (LPARAM)&findInfo);
659 return ret;
662 static void save_cert_mgr_usages(HWND hwnd)
664 static const WCHAR keyName[] = { 'S','o','f','t','w','a','r','e','\\','M',
665 'i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g','r','a',
666 'p','h','y','\\','U','I','\\','C','e','r','t','m','g','r','\\','P','u',
667 'r','p','o','s','e',0 };
668 HKEY key;
669 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
670 int purposes = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0), i;
671 LVITEMW item;
672 LPSTR str = NULL;
674 item.mask = LVIF_STATE | LVIF_PARAM;
675 item.iSubItem = 0;
676 item.stateMask = LVIS_STATEIMAGEMASK;
677 for (i = 0; i < purposes; i++)
679 item.iItem = i;
680 if (SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item))
682 int state = item.state >> 12;
684 if (state == CheckBitmapIndexUnchecked)
686 CRYPT_OID_INFO *info = (CRYPT_OID_INFO *)item.lParam;
687 BOOL firstString = TRUE;
689 if (!str)
690 str = HeapAlloc(GetProcessHeap(), 0,
691 strlen(info->pszOID) + 1);
692 else
694 str = HeapReAlloc(GetProcessHeap(), 0, str,
695 strlen(str) + 1 + strlen(info->pszOID) + 1);
696 firstString = FALSE;
698 if (str)
700 LPSTR ptr = firstString ? str : str + strlen(str);
702 if (!firstString)
703 *ptr++ = ',';
704 strcpy(ptr, info->pszOID);
709 if (!RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, NULL, 0, KEY_ALL_ACCESS,
710 NULL, &key, NULL))
712 if (str)
713 RegSetValueExA(key, "Purpose", 0, REG_SZ, (const BYTE *)str,
714 strlen(str) + 1);
715 else
716 RegDeleteValueA(key, "Purpose");
717 RegCloseKey(key);
719 HeapFree(GetProcessHeap(), 0, str);
722 static LRESULT CALLBACK cert_mgr_advanced_dlg_proc(HWND hwnd, UINT msg,
723 WPARAM wp, LPARAM lp)
725 switch (msg)
727 case WM_INITDIALOG:
729 RECT rc;
730 LVCOLUMNW column;
731 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
732 HIMAGELIST imageList;
733 LPSTR disabledUsages;
735 GetWindowRect(lv, &rc);
736 column.mask = LVCF_WIDTH;
737 column.cx = rc.right - rc.left;
738 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
739 imageList = ImageList_Create(16, 16, ILC_COLOR4 | ILC_MASK, 4, 0);
740 if (imageList)
742 HBITMAP bmp;
743 COLORREF backColor = RGB(255, 0, 255);
745 bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_CHECKS));
746 ImageList_AddMasked(imageList, bmp, backColor);
747 DeleteObject(bmp);
748 ImageList_SetBkColor(imageList, CLR_NONE);
749 SendMessageW(lv, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)imageList);
750 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)imageList);
752 add_known_usages_to_list(lv, CheckBitmapIndexChecked);
753 if ((disabledUsages = get_cert_mgr_usages()))
755 LPSTR ptr, comma;
757 for (ptr = disabledUsages, comma = strchr(ptr, ','); ptr && *ptr;
758 ptr = comma ? comma + 1 : NULL,
759 comma = ptr ? strchr(ptr, ',') : NULL)
761 LONG_PTR index;
763 if (comma)
764 *comma = 0;
765 if ((index = find_oid_in_list(lv, ptr)) != -1)
766 toggle_usage(hwnd, index);
768 HeapFree(GetProcessHeap(), 0, disabledUsages);
770 break;
772 case WM_NOTIFY:
774 NMHDR *hdr = (NMHDR *)lp;
775 NMITEMACTIVATE *nm;
777 switch (hdr->code)
779 case NM_CLICK:
780 nm = (NMITEMACTIVATE *)lp;
781 toggle_usage(hwnd, nm->iItem);
782 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
783 break;
785 break;
787 case WM_COMMAND:
788 switch (wp)
790 case IDOK:
791 save_cert_mgr_usages(hwnd);
792 ImageList_Destroy((HIMAGELIST)GetWindowLongPtrW(hwnd, DWLP_USER));
793 EndDialog(hwnd, IDOK);
794 break;
795 case IDCANCEL:
796 ImageList_Destroy((HIMAGELIST)GetWindowLongPtrW(hwnd, DWLP_USER));
797 EndDialog(hwnd, IDCANCEL);
798 break;
800 break;
802 return 0;
805 static void cert_mgr_clear_cert_selection(HWND hwnd)
807 WCHAR empty[] = { 0 };
809 EnableWindow(GetDlgItem(hwnd, IDC_MGR_EXPORT), FALSE);
810 EnableWindow(GetDlgItem(hwnd, IDC_MGR_REMOVE), FALSE);
811 EnableWindow(GetDlgItem(hwnd, IDC_MGR_VIEW), FALSE);
812 SendMessageW(GetDlgItem(hwnd, IDC_MGR_PURPOSES), WM_SETTEXT, 0,
813 (LPARAM)empty);
814 refresh_store_certs(hwnd);
817 static PCCERT_CONTEXT cert_mgr_index_to_cert(HWND hwnd, int index)
819 PCCERT_CONTEXT cert = NULL;
820 LVITEMW item;
822 item.mask = LVIF_PARAM;
823 item.iItem = index;
824 item.iSubItem = 0;
825 if (SendMessageW(GetDlgItem(hwnd, IDC_MGR_CERTS), LVM_GETITEMW, 0,
826 (LPARAM)&item))
827 cert = (PCCERT_CONTEXT)item.lParam;
828 return cert;
831 static void show_selected_cert(HWND hwnd, int index)
833 PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd, index);
835 if (cert)
837 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
839 memset(&viewInfo, 0, sizeof(viewInfo));
840 viewInfo.dwSize = sizeof(viewInfo);
841 viewInfo.hwndParent = hwnd;
842 viewInfo.pCertContext = cert;
843 /* FIXME: this should be modal */
844 CryptUIDlgViewCertificateW(&viewInfo, NULL);
848 static void get_cert_usages(PCCERT_CONTEXT cert, LPWSTR *str)
850 PCERT_ENHKEY_USAGE usage;
851 DWORD size;
853 /* Get enhanced key usage. Have to check for a property and an extension
854 * separately, because CertGetEnhancedKeyUsage will succeed and return an
855 * empty usage if neither is set. Unfortunately an empty usage implies
856 * no usage is allowed, so we have to distinguish between the two cases.
858 if (CertGetEnhancedKeyUsage(cert, CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG,
859 NULL, &size))
861 usage = HeapAlloc(GetProcessHeap(), 0, size);
862 if (!CertGetEnhancedKeyUsage(cert,
863 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size))
865 HeapFree(GetProcessHeap(), 0, usage);
866 usage = NULL;
869 else if (CertGetEnhancedKeyUsage(cert, CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
870 NULL, &size))
872 usage = HeapAlloc(GetProcessHeap(), 0, size);
873 if (!CertGetEnhancedKeyUsage(cert,
874 CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, usage, &size))
876 HeapFree(GetProcessHeap(), 0, usage);
877 usage = NULL;
880 else
881 usage = NULL;
882 if (usage)
884 if (usage->cUsageIdentifier)
886 static const WCHAR commaSpace[] = { ',',' ',0 };
887 DWORD i, len = 1;
888 LPWSTR ptr;
890 for (i = 0; i < usage->cUsageIdentifier; i++)
892 PCCRYPT_OID_INFO info =
893 CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
894 usage->rgpszUsageIdentifier[i],
895 CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
897 if (info)
898 len += strlenW(info->pwszName);
899 else
900 len += strlen(usage->rgpszUsageIdentifier[i]);
901 if (i < usage->cUsageIdentifier - 1)
902 len += strlenW(commaSpace);
904 *str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
905 if (*str)
907 for (i = 0, ptr = *str; i < usage->cUsageIdentifier; i++)
909 PCCRYPT_OID_INFO info =
910 CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
911 usage->rgpszUsageIdentifier[i],
912 CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
914 if (info)
916 strcpyW(ptr, info->pwszName);
917 ptr += strlenW(info->pwszName);
919 else
921 LPCSTR src = usage->rgpszUsageIdentifier[i];
923 for (; *src; ptr++, src++)
924 *ptr = *src;
925 *ptr = 0;
927 if (i < usage->cUsageIdentifier - 1)
929 strcpyW(ptr, commaSpace);
930 ptr += strlenW(commaSpace);
933 *ptr = 0;
935 HeapFree(GetProcessHeap(), 0, usage);
937 else
939 size = MAX_STRING_LEN * sizeof(WCHAR);
940 *str = HeapAlloc(GetProcessHeap(), 0, size);
941 if (*str)
942 LoadStringW(hInstance, IDS_ALLOWED_PURPOSE_NONE, *str, size);
945 else
947 size = MAX_STRING_LEN * sizeof(WCHAR);
948 *str = HeapAlloc(GetProcessHeap(), 0, size);
949 if (*str)
950 LoadStringW(hInstance, IDS_ALLOWED_PURPOSE_ALL, *str, size);
954 static void cert_mgr_show_cert_usages(HWND hwnd, int index)
956 HWND text = GetDlgItem(hwnd, IDC_MGR_PURPOSES);
957 PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd, index);
958 LPWSTR str = NULL;
960 get_cert_usages(cert, &str);
961 if (str)
963 SendMessageW(text, WM_SETTEXT, 0, (LPARAM)str);
964 HeapFree(GetProcessHeap(), 0, str);
968 static void cert_mgr_do_remove(HWND hwnd)
970 int tabIndex = SendMessageW(GetDlgItem(hwnd, IDC_MGR_STORES),
971 TCM_GETCURSEL, 0, 0);
972 struct CertMgrData *data =
973 (struct CertMgrData *)GetWindowLongPtrW(hwnd, DWLP_USER);
975 if (tabIndex < data->nStores)
977 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
978 WCHAR warning[MAX_STRING_LEN], title[MAX_STRING_LEN];
979 LPCWSTR pTitle;
980 int warningID;
982 if (SendMessageW(lv, LVM_GETSELECTEDCOUNT, 0, 0) > 1)
983 warningID = data->stores[tabIndex].removePluralWarning;
984 else
985 warningID = data->stores[tabIndex].removeWarning;
986 if (data->title)
987 pTitle = data->title;
988 else
990 LoadStringW(hInstance, IDS_CERT_MGR, title, ARRAY_SIZE(title));
991 pTitle = title;
993 LoadStringW(hInstance, warningID, warning, ARRAY_SIZE(warning));
994 if (MessageBoxW(hwnd, warning, pTitle, MB_YESNO) == IDYES)
996 int selection = -1;
998 do {
999 selection = SendMessageW(lv, LVM_GETNEXTITEM, selection,
1000 LVNI_SELECTED);
1001 if (selection >= 0)
1003 PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd,
1004 selection);
1006 CertDeleteCertificateFromStore(cert);
1008 } while (selection >= 0);
1009 cert_mgr_clear_cert_selection(hwnd);
1014 static void cert_mgr_do_export(HWND hwnd)
1016 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
1017 int selectionCount = SendMessageW(lv, LVM_GETSELECTEDCOUNT, 0, 0);
1019 if (selectionCount == 1)
1021 int selection = SendMessageW(lv, LVM_GETNEXTITEM, -1,
1022 LVNI_SELECTED);
1024 if (selection >= 0)
1026 PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd, selection);
1028 if (cert)
1030 CRYPTUI_WIZ_EXPORT_INFO info;
1032 info.dwSize = sizeof(info);
1033 info.pwszExportFileName = NULL;
1034 info.dwSubjectChoice = CRYPTUI_WIZ_EXPORT_CERT_CONTEXT;
1035 info.u.pCertContext = cert;
1036 info.cStores = 0;
1037 CryptUIWizExport(0, hwnd, NULL, &info, NULL);
1041 else if (selectionCount > 1)
1043 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
1044 CERT_STORE_CREATE_NEW_FLAG, NULL);
1046 if (store)
1048 CRYPTUI_WIZ_EXPORT_INFO info;
1049 int selection = -1;
1051 info.dwSize = sizeof(info);
1052 info.pwszExportFileName = NULL;
1053 info.dwSubjectChoice =
1054 CRYPTUI_WIZ_EXPORT_CERT_STORE_CERTIFICATES_ONLY;
1055 info.u.hCertStore = store;
1056 info.cStores = 0;
1057 do {
1058 selection = SendMessageW(lv, LVM_GETNEXTITEM, selection,
1059 LVNI_SELECTED);
1060 if (selection >= 0)
1062 PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd,
1063 selection);
1065 CertAddCertificateContextToStore(store, cert,
1066 CERT_STORE_ADD_ALWAYS, NULL);
1068 } while (selection >= 0);
1069 CryptUIWizExport(0, hwnd, NULL, &info, NULL);
1070 CertCloseStore(store, 0);
1075 static int cert_mgr_sort_by_text(HWND lv, int col, int index1, int index2)
1077 LVITEMW item;
1078 WCHAR buf1[MAX_STRING_LEN];
1079 WCHAR buf2[MAX_STRING_LEN];
1081 item.cchTextMax = ARRAY_SIZE(buf1);
1082 item.mask = LVIF_TEXT;
1083 item.pszText = buf1;
1084 item.iItem = index1;
1085 item.iSubItem = col;
1086 SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item);
1087 item.pszText = buf2;
1088 item.iItem = index2;
1089 SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item);
1090 return strcmpW(buf1, buf2);
1093 static int CALLBACK cert_mgr_sort_by_subject(LPARAM lp1, LPARAM lp2, LPARAM lp)
1095 return cert_mgr_sort_by_text((HWND)lp, 0, lp1, lp2);
1098 static int CALLBACK cert_mgr_sort_by_issuer(LPARAM lp1, LPARAM lp2, LPARAM lp)
1100 return cert_mgr_sort_by_text((HWND)lp, 1, lp1, lp2);
1103 static int CALLBACK cert_mgr_sort_by_date(LPARAM lp1, LPARAM lp2, LPARAM lp)
1105 PCCERT_CONTEXT cert1 = (PCCERT_CONTEXT)lp1;
1106 PCCERT_CONTEXT cert2 = (PCCERT_CONTEXT)lp2;
1107 return CompareFileTime(&cert1->pCertInfo->NotAfter,
1108 &cert2->pCertInfo->NotAfter);
1111 static int CALLBACK cert_mgr_sort_by_friendly_name(LPARAM lp1, LPARAM lp2,
1112 LPARAM lp)
1114 return cert_mgr_sort_by_text((HWND)lp, 3, lp1, lp2);
1117 static LRESULT CALLBACK cert_mgr_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
1118 LPARAM lp)
1120 struct CertMgrData *data;
1122 switch (msg)
1124 case WM_INITDIALOG:
1126 PCCRYPTUI_CERT_MGR_STRUCT pCryptUICertMgr =
1127 (PCCRYPTUI_CERT_MGR_STRUCT)lp;
1128 HWND tab = GetDlgItem(hwnd, IDC_MGR_STORES);
1130 data = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CertMgrData));
1131 if (!data)
1132 return 0;
1133 data->imageList = ImageList_Create(16, 16, ILC_COLOR4 | ILC_MASK, 2, 0);
1134 if (data->imageList)
1136 HBITMAP bmp;
1137 COLORREF backColor = RGB(255, 0, 255);
1139 bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_SMALL_ICONS));
1140 ImageList_AddMasked(data->imageList, bmp, backColor);
1141 DeleteObject(bmp);
1142 ImageList_SetBkColor(data->imageList, CLR_NONE);
1143 SendMessageW(GetDlgItem(hwnd, IDC_MGR_CERTS), LVM_SETIMAGELIST,
1144 LVSIL_SMALL, (LPARAM)data->imageList);
1146 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
1147 data->title = pCryptUICertMgr->pwszTitle;
1149 initialize_purpose_selection(hwnd);
1150 add_cert_columns(hwnd);
1151 if (pCryptUICertMgr->pwszTitle)
1152 SendMessageW(hwnd, WM_SETTEXT, 0,
1153 (LPARAM)pCryptUICertMgr->pwszTitle);
1154 show_cert_stores(hwnd, pCryptUICertMgr->dwFlags, data);
1155 show_store_certs(hwnd, cert_mgr_index_to_store(tab, 0));
1156 break;
1158 case WM_NOTIFY:
1160 NMHDR *hdr = (NMHDR *)lp;
1162 switch (hdr->code)
1164 case TCN_SELCHANGE:
1165 cert_mgr_clear_cert_selection(hwnd);
1166 break;
1167 case LVN_ITEMCHANGED:
1169 WCHAR empty[] = { 0 };
1170 NMITEMACTIVATE *nm = (NMITEMACTIVATE*)lp;
1171 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
1172 int numSelected = SendMessageW(lv, LVM_GETSELECTEDCOUNT, 0, 0);
1174 EnableWindow(GetDlgItem(hwnd, IDC_MGR_EXPORT), numSelected > 0);
1175 EnableWindow(GetDlgItem(hwnd, IDC_MGR_REMOVE), numSelected > 0);
1176 EnableWindow(GetDlgItem(hwnd, IDC_MGR_VIEW), numSelected == 1);
1177 if (numSelected == 1)
1178 cert_mgr_show_cert_usages(hwnd, nm->iItem);
1179 else
1180 SendMessageW(GetDlgItem(hwnd, IDC_MGR_PURPOSES), WM_SETTEXT, 0,
1181 (LPARAM)empty);
1182 break;
1184 case NM_DBLCLK:
1185 show_selected_cert(hwnd, ((NMITEMACTIVATE *)lp)->iItem);
1186 break;
1187 case LVN_KEYDOWN:
1189 NMLVKEYDOWN *lvk = (NMLVKEYDOWN *)lp;
1191 if (lvk->wVKey == VK_DELETE)
1192 cert_mgr_do_remove(hwnd);
1193 break;
1195 case LVN_COLUMNCLICK:
1197 NMLISTVIEW *nmlv = (NMLISTVIEW *)lp;
1198 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
1200 /* FIXME: doesn't support swapping sort order between ascending
1201 * and descending.
1203 switch (nmlv->iSubItem)
1205 case 0:
1206 SendMessageW(lv, LVM_SORTITEMSEX, (WPARAM)lv,
1207 (LPARAM)cert_mgr_sort_by_subject);
1208 break;
1209 case 1:
1210 SendMessageW(lv, LVM_SORTITEMSEX, (WPARAM)lv,
1211 (LPARAM)cert_mgr_sort_by_issuer);
1212 break;
1213 case 2:
1214 SendMessageW(lv, LVM_SORTITEMS, 0,
1215 (LPARAM)cert_mgr_sort_by_date);
1216 break;
1217 case 3:
1218 SendMessageW(lv, LVM_SORTITEMSEX, (WPARAM)lv,
1219 (LPARAM)cert_mgr_sort_by_friendly_name);
1220 break;
1222 break;
1225 break;
1227 case WM_COMMAND:
1228 switch (wp)
1230 case ((CBN_SELCHANGE << 16) | IDC_MGR_PURPOSE_SELECTION):
1231 cert_mgr_clear_cert_selection(hwnd);
1232 break;
1233 case IDC_MGR_IMPORT:
1234 if (CryptUIWizImport(0, hwnd, NULL, NULL,
1235 cert_mgr_current_store(hwnd)))
1236 refresh_store_certs(hwnd);
1237 break;
1238 case IDC_MGR_ADVANCED:
1239 if (DialogBoxW(hInstance, MAKEINTRESOURCEW(IDD_CERT_MGR_ADVANCED),
1240 hwnd, cert_mgr_advanced_dlg_proc) == IDOK)
1242 HWND cb = GetDlgItem(hwnd, IDC_MGR_PURPOSE_SELECTION);
1243 int index, len;
1244 LPWSTR curString = NULL;
1246 index = SendMessageW(cb, CB_GETCURSEL, 0, 0);
1247 if (index >= 0)
1249 len = SendMessageW(cb, CB_GETLBTEXTLEN, index, 0);
1250 curString = HeapAlloc(GetProcessHeap(), 0,
1251 (len + 1) * sizeof(WCHAR));
1252 SendMessageW(cb, CB_GETLBTEXT, index, (LPARAM)curString);
1254 SendMessageW(cb, CB_RESETCONTENT, 0, 0);
1255 initialize_purpose_selection(hwnd);
1256 if (curString)
1258 index = SendMessageW(cb, CB_FINDSTRINGEXACT, -1,
1259 (LPARAM)curString);
1260 if (index >= 0)
1261 SendMessageW(cb, CB_SETCURSEL, index, 0);
1262 HeapFree(GetProcessHeap(), 0, curString);
1264 refresh_store_certs(hwnd);
1266 break;
1267 case IDC_MGR_VIEW:
1269 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
1270 int selection = SendMessageW(lv, LVM_GETNEXTITEM, -1,
1271 LVNI_SELECTED);
1273 if (selection >= 0)
1274 show_selected_cert(hwnd, selection);
1275 break;
1277 case IDC_MGR_EXPORT:
1278 cert_mgr_do_export(hwnd);
1279 break;
1280 case IDC_MGR_REMOVE:
1281 cert_mgr_do_remove(hwnd);
1282 break;
1283 case IDCANCEL:
1284 free_certs(GetDlgItem(hwnd, IDC_MGR_CERTS));
1285 close_stores(GetDlgItem(hwnd, IDC_MGR_STORES));
1286 data = (struct CertMgrData *)GetWindowLongPtrW(hwnd, DWLP_USER);
1287 ImageList_Destroy(data->imageList);
1288 HeapFree(GetProcessHeap(), 0, data);
1289 EndDialog(hwnd, IDCANCEL);
1290 break;
1292 break;
1294 return 0;
1297 /***********************************************************************
1298 * CryptUIDlgCertMgr (CRYPTUI.@)
1300 BOOL WINAPI CryptUIDlgCertMgr(PCCRYPTUI_CERT_MGR_STRUCT pCryptUICertMgr)
1302 TRACE("(%p)\n", pCryptUICertMgr);
1304 if (pCryptUICertMgr->dwSize != sizeof(CRYPTUI_CERT_MGR_STRUCT))
1306 WARN("unexpected size %d\n", pCryptUICertMgr->dwSize);
1307 SetLastError(E_INVALIDARG);
1308 return FALSE;
1310 DialogBoxParamW(hInstance, MAKEINTRESOURCEW(IDD_CERT_MGR),
1311 pCryptUICertMgr->hwndParent, cert_mgr_dlg_proc, (LPARAM)pCryptUICertMgr);
1312 return TRUE;
1315 /* FIXME: real names are unknown, functions are undocumented */
1316 typedef struct _CRYPTUI_ENUM_SYSTEM_STORE_ARGS
1318 DWORD dwFlags;
1319 void *pvSystemStoreLocationPara;
1320 } CRYPTUI_ENUM_SYSTEM_STORE_ARGS, *PCRYPTUI_ENUM_SYSTEM_STORE_ARGS;
1322 typedef struct _CRYPTUI_ENUM_DATA
1324 DWORD cStores;
1325 HCERTSTORE *rghStore;
1326 DWORD cEnumArgs;
1327 PCRYPTUI_ENUM_SYSTEM_STORE_ARGS rgEnumArgs;
1328 } CRYPTUI_ENUM_DATA, *PCRYPTUI_ENUM_DATA;
1330 typedef BOOL (WINAPI *PFN_SELECTED_STORE_CB)(HCERTSTORE store, HWND hwnd,
1331 void *pvArg);
1333 /* Values for dwFlags */
1334 #define CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE 0x00000001
1336 typedef struct _CRYPTUI_SELECTSTORE_INFO_A
1338 DWORD dwSize;
1339 HWND parent;
1340 DWORD dwFlags;
1341 LPSTR pszTitle;
1342 LPSTR pszText;
1343 CRYPTUI_ENUM_DATA *pEnumData;
1344 PFN_SELECTED_STORE_CB pfnSelectedStoreCallback;
1345 void *pvArg;
1346 } CRYPTUI_SELECTSTORE_INFO_A, *PCRYPTUI_SELECTSTORE_INFO_A;
1348 typedef struct _CRYPTUI_SELECTSTORE_INFO_W
1350 DWORD dwSize;
1351 HWND parent;
1352 DWORD dwFlags;
1353 LPWSTR pwszTitle;
1354 LPWSTR pwszText;
1355 CRYPTUI_ENUM_DATA *pEnumData;
1356 PFN_SELECTED_STORE_CB pfnSelectedStoreCallback;
1357 void *pvArg;
1358 } CRYPTUI_SELECTSTORE_INFO_W, *PCRYPTUI_SELECTSTORE_INFO_W;
1360 struct StoreInfo
1362 enum {
1363 StoreHandle,
1364 SystemStore
1365 } type;
1366 union {
1367 HCERTSTORE store;
1368 LPWSTR name;
1369 } DUMMYUNIONNAME;
1372 static BOOL WINAPI enum_store_callback(const void *pvSystemStore,
1373 DWORD dwFlags, PCERT_SYSTEM_STORE_INFO pStoreInfo, void *pvReserved,
1374 void *pvArg)
1376 HWND tree = GetDlgItem(pvArg, IDC_STORE_LIST);
1377 TVINSERTSTRUCTW tvis;
1378 LPCWSTR localizedName;
1379 BOOL ret = TRUE;
1381 tvis.hParent = NULL;
1382 tvis.hInsertAfter = TVI_LAST;
1383 tvis.u.item.mask = TVIF_TEXT;
1384 if ((localizedName = CryptFindLocalizedName(pvSystemStore)))
1386 struct StoreInfo *storeInfo = HeapAlloc(GetProcessHeap(), 0,
1387 sizeof(struct StoreInfo));
1389 if (storeInfo)
1391 storeInfo->type = SystemStore;
1392 storeInfo->u.name = HeapAlloc(GetProcessHeap(), 0,
1393 (strlenW(pvSystemStore) + 1) * sizeof(WCHAR));
1394 if (storeInfo->u.name)
1396 tvis.u.item.mask |= TVIF_PARAM;
1397 tvis.u.item.lParam = (LPARAM)storeInfo;
1398 strcpyW(storeInfo->u.name, pvSystemStore);
1400 else
1402 HeapFree(GetProcessHeap(), 0, storeInfo);
1403 ret = FALSE;
1406 else
1407 ret = FALSE;
1408 tvis.u.item.pszText = (LPWSTR)localizedName;
1410 else
1411 tvis.u.item.pszText = (LPWSTR)pvSystemStore;
1412 /* FIXME: need a folder icon for the store too */
1413 if (ret)
1414 SendMessageW(tree, TVM_INSERTITEMW, 0, (LPARAM)&tvis);
1415 return ret;
1418 static void enumerate_stores(HWND hwnd, CRYPTUI_ENUM_DATA *pEnumData)
1420 DWORD i;
1421 HWND tree = GetDlgItem(hwnd, IDC_STORE_LIST);
1423 for (i = 0; i < pEnumData->cEnumArgs; i++)
1424 CertEnumSystemStore(pEnumData->rgEnumArgs[i].dwFlags,
1425 pEnumData->rgEnumArgs[i].pvSystemStoreLocationPara,
1426 hwnd, enum_store_callback);
1427 for (i = 0; i < pEnumData->cStores; i++)
1429 DWORD size;
1431 if (CertGetStoreProperty(pEnumData->rghStore[i],
1432 CERT_STORE_LOCALIZED_NAME_PROP_ID, NULL, &size))
1434 LPWSTR name = HeapAlloc(GetProcessHeap(), 0, size);
1436 if (name)
1438 if (CertGetStoreProperty(pEnumData->rghStore[i],
1439 CERT_STORE_LOCALIZED_NAME_PROP_ID, name, &size))
1441 struct StoreInfo *storeInfo = HeapAlloc(GetProcessHeap(),
1442 0, sizeof(struct StoreInfo));
1444 if (storeInfo)
1446 TVINSERTSTRUCTW tvis;
1448 storeInfo->type = StoreHandle;
1449 storeInfo->u.store = pEnumData->rghStore[i];
1450 tvis.hParent = NULL;
1451 tvis.hInsertAfter = TVI_LAST;
1452 tvis.u.item.mask = TVIF_TEXT | TVIF_PARAM;
1453 tvis.u.item.pszText = name;
1454 tvis.u.item.lParam = (LPARAM)storeInfo;
1455 SendMessageW(tree, TVM_INSERTITEMW, 0, (LPARAM)&tvis);
1458 HeapFree(GetProcessHeap(), 0, name);
1464 static void free_store_info(HWND tree)
1466 HTREEITEM next = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM, TVGN_CHILD,
1469 while (next)
1471 TVITEMW item;
1473 memset(&item, 0, sizeof(item));
1474 item.mask = TVIF_HANDLE | TVIF_PARAM;
1475 item.hItem = next;
1476 SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item);
1477 if (item.lParam)
1479 struct StoreInfo *storeInfo = (struct StoreInfo *)item.lParam;
1481 if (storeInfo->type == SystemStore)
1482 HeapFree(GetProcessHeap(), 0, storeInfo->u.name);
1483 HeapFree(GetProcessHeap(), 0, storeInfo);
1485 next = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM, TVGN_NEXT,
1486 (LPARAM)next);
1490 static HCERTSTORE selected_item_to_store(HWND tree, HTREEITEM hItem)
1492 WCHAR buf[MAX_STRING_LEN];
1493 TVITEMW item;
1494 HCERTSTORE store;
1496 memset(&item, 0, sizeof(item));
1497 item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_TEXT;
1498 item.hItem = hItem;
1499 item.cchTextMax = ARRAY_SIZE(buf);
1500 item.pszText = buf;
1501 SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item);
1502 if (item.lParam)
1504 struct StoreInfo *storeInfo = (struct StoreInfo *)item.lParam;
1506 if (storeInfo->type == StoreHandle)
1507 store = storeInfo->u.store;
1508 else
1509 store = CertOpenSystemStoreW(0, storeInfo->u.name);
1511 else
1513 /* It's implicitly a system store */
1514 store = CertOpenSystemStoreW(0, buf);
1516 return store;
1519 struct SelectStoreInfo
1521 PCRYPTUI_SELECTSTORE_INFO_W info;
1522 HCERTSTORE store;
1525 static LRESULT CALLBACK select_store_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
1526 LPARAM lp)
1528 struct SelectStoreInfo *selectInfo;
1529 LRESULT ret = 0;
1531 switch (msg)
1533 case WM_INITDIALOG:
1535 selectInfo = (struct SelectStoreInfo *)lp;
1536 SetWindowLongPtrW(hwnd, DWLP_USER, lp);
1537 if (selectInfo->info->pwszTitle)
1538 SendMessageW(hwnd, WM_SETTEXT, 0,
1539 (LPARAM)selectInfo->info->pwszTitle);
1540 if (selectInfo->info->pwszText)
1541 SendMessageW(GetDlgItem(hwnd, IDC_STORE_TEXT), WM_SETTEXT, 0,
1542 (LPARAM)selectInfo->info->pwszText);
1543 if (!(selectInfo->info->dwFlags & CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE))
1544 ShowWindow(GetDlgItem(hwnd, IDC_SHOW_PHYSICAL_STORES), FALSE);
1545 enumerate_stores(hwnd, selectInfo->info->pEnumData);
1546 break;
1548 case WM_COMMAND:
1549 switch (wp)
1551 case IDOK:
1553 HWND tree = GetDlgItem(hwnd, IDC_STORE_LIST);
1554 HTREEITEM selection = (HTREEITEM)SendMessageW(tree,
1555 TVM_GETNEXTITEM, TVGN_CARET, 0);
1557 selectInfo = (struct SelectStoreInfo *)GetWindowLongPtrW(hwnd,
1558 DWLP_USER);
1559 if (!selection)
1561 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN], *pTitle;
1563 if (selectInfo->info->pwszTitle)
1564 pTitle = selectInfo->info->pwszTitle;
1565 else
1567 LoadStringW(hInstance, IDS_SELECT_STORE_TITLE, title, ARRAY_SIZE(title));
1568 pTitle = title;
1570 LoadStringW(hInstance, IDS_SELECT_STORE, error, ARRAY_SIZE(error));
1571 MessageBoxW(hwnd, error, pTitle, MB_ICONEXCLAMATION | MB_OK);
1573 else
1575 HCERTSTORE store = selected_item_to_store(tree, selection);
1577 if (!selectInfo->info->pfnSelectedStoreCallback ||
1578 selectInfo->info->pfnSelectedStoreCallback(store, hwnd,
1579 selectInfo->info->pvArg))
1581 selectInfo->store = store;
1582 free_store_info(tree);
1583 EndDialog(hwnd, IDOK);
1585 else
1586 CertCloseStore(store, 0);
1588 ret = TRUE;
1589 break;
1591 case IDCANCEL:
1592 free_store_info(GetDlgItem(hwnd, IDC_STORE_LIST));
1593 EndDialog(hwnd, IDCANCEL);
1594 ret = TRUE;
1595 break;
1597 break;
1599 return ret;
1602 /***********************************************************************
1603 * CryptUIDlgSelectStoreW (CRYPTUI.@)
1605 HCERTSTORE WINAPI CryptUIDlgSelectStoreW(PCRYPTUI_SELECTSTORE_INFO_W info)
1607 struct SelectStoreInfo selectInfo = { info, NULL };
1609 TRACE("(%p)\n", info);
1611 if (info->dwSize != sizeof(CRYPTUI_SELECTSTORE_INFO_W))
1613 WARN("unexpected size %d\n", info->dwSize);
1614 SetLastError(E_INVALIDARG);
1615 return NULL;
1617 DialogBoxParamW(hInstance, MAKEINTRESOURCEW(IDD_SELECT_STORE), info->parent,
1618 select_store_dlg_proc, (LPARAM)&selectInfo);
1619 return selectInfo.store;
1622 /***********************************************************************
1623 * CryptUIDlgSelectStoreA (CRYPTUI.@)
1625 HCERTSTORE WINAPI CryptUIDlgSelectStoreA(PCRYPTUI_SELECTSTORE_INFO_A info)
1627 CRYPTUI_SELECTSTORE_INFO_W infoW;
1628 HCERTSTORE ret;
1629 int len;
1631 TRACE("(%p)\n", info);
1633 if (info->dwSize != sizeof(CRYPTUI_SELECTSTORE_INFO_A))
1635 WARN("unexpected size %d\n", info->dwSize);
1636 SetLastError(E_INVALIDARG);
1637 return NULL;
1639 memcpy(&infoW, info, sizeof(*info));
1640 if (info->pszTitle)
1642 len = MultiByteToWideChar(CP_ACP, 0, info->pszTitle, -1, NULL, 0);
1643 infoW.pwszTitle = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1644 MultiByteToWideChar(CP_ACP, 0, info->pszTitle, -1, infoW.pwszTitle,
1645 len);
1647 if (info->pszText)
1649 len = MultiByteToWideChar(CP_ACP, 0, info->pszText, -1, NULL, 0);
1650 infoW.pwszText = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1651 MultiByteToWideChar(CP_ACP, 0, info->pszText, -1, infoW.pwszText, len);
1653 ret = CryptUIDlgSelectStoreW(&infoW);
1654 HeapFree(GetProcessHeap(), 0, infoW.pwszText);
1655 HeapFree(GetProcessHeap(), 0, infoW.pwszTitle);
1656 return ret;
1659 /***********************************************************************
1660 * CryptUIDlgViewCertificateA (CRYPTUI.@)
1662 BOOL WINAPI CryptUIDlgViewCertificateA(
1663 PCCRYPTUI_VIEWCERTIFICATE_STRUCTA pCertViewInfo, BOOL *pfPropertiesChanged)
1665 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
1666 LPWSTR title = NULL;
1667 BOOL ret;
1669 TRACE("(%p, %p)\n", pCertViewInfo, pfPropertiesChanged);
1671 memcpy(&viewInfo, pCertViewInfo, sizeof(viewInfo));
1672 if (pCertViewInfo->szTitle)
1674 int len = MultiByteToWideChar(CP_ACP, 0, pCertViewInfo->szTitle, -1,
1675 NULL, 0);
1677 title = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1678 if (title)
1680 MultiByteToWideChar(CP_ACP, 0, pCertViewInfo->szTitle, -1, title,
1681 len);
1682 viewInfo.szTitle = title;
1684 else
1686 ret = FALSE;
1687 goto error;
1690 if (pCertViewInfo->cPropSheetPages)
1692 FIXME("ignoring additional prop sheet pages\n");
1693 viewInfo.cPropSheetPages = 0;
1695 ret = CryptUIDlgViewCertificateW(&viewInfo, pfPropertiesChanged);
1696 HeapFree(GetProcessHeap(), 0, title);
1697 error:
1698 return ret;
1701 struct ReadStringStruct
1703 LPCWSTR buf;
1704 LONG pos;
1705 LONG len;
1708 static DWORD CALLBACK read_text_callback(DWORD_PTR dwCookie, LPBYTE buf,
1709 LONG cb, LONG *pcb)
1711 struct ReadStringStruct *string = (struct ReadStringStruct *)dwCookie;
1712 LONG cch = min(cb / sizeof(WCHAR), string->len - string->pos);
1714 TRACE("(%p, %p, %d, %p)\n", string, buf, cb, pcb);
1716 memmove(buf, string->buf + string->pos, cch * sizeof(WCHAR));
1717 string->pos += cch;
1718 *pcb = cch * sizeof(WCHAR);
1719 return 0;
1722 static void add_unformatted_text_to_control(HWND hwnd, LPCWSTR text, LONG len)
1724 struct ReadStringStruct string;
1725 EDITSTREAM editstream;
1727 TRACE("(%p, %s)\n", hwnd, debugstr_wn(text, len));
1729 string.buf = text;
1730 string.pos = 0;
1731 string.len = len;
1732 editstream.dwCookie = (DWORD_PTR)&string;
1733 editstream.dwError = 0;
1734 editstream.pfnCallback = read_text_callback;
1735 SendMessageW(hwnd, EM_STREAMIN, SF_TEXT | SFF_SELECTION | SF_UNICODE,
1736 (LPARAM)&editstream);
1739 static void add_string_resource_to_control(HWND hwnd, int id)
1741 LPWSTR str;
1742 LONG len;
1744 len = LoadStringW(hInstance, id, (LPWSTR)&str, 0);
1745 add_unformatted_text_to_control(hwnd, str, len);
1748 static void add_text_with_paraformat_to_control(HWND hwnd, LPCWSTR text,
1749 LONG len, const PARAFORMAT2 *fmt)
1751 add_unformatted_text_to_control(hwnd, text, len);
1752 SendMessageW(hwnd, EM_SETPARAFORMAT, 0, (LPARAM)fmt);
1755 static void add_string_resource_with_paraformat_to_control(HWND hwnd, int id,
1756 const PARAFORMAT2 *fmt)
1758 LPWSTR str;
1759 LONG len;
1761 len = LoadStringW(hInstance, id, (LPWSTR)&str, 0);
1762 add_text_with_paraformat_to_control(hwnd, str, len, fmt);
1765 static LPWSTR get_cert_name_string(PCCERT_CONTEXT pCertContext, DWORD dwType,
1766 DWORD dwFlags)
1768 LPWSTR buf = NULL;
1769 DWORD len;
1771 len = CertGetNameStringW(pCertContext, dwType, dwFlags, NULL, NULL, 0);
1772 if (len)
1774 buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1775 if (buf)
1776 CertGetNameStringW(pCertContext, dwType, dwFlags, NULL, buf, len);
1778 return buf;
1781 static void add_cert_string_to_control(HWND hwnd, PCCERT_CONTEXT pCertContext,
1782 DWORD dwType, DWORD dwFlags)
1784 LPWSTR name = get_cert_name_string(pCertContext, dwType, dwFlags);
1786 if (name)
1788 /* Don't include NULL-terminator in output */
1789 DWORD len = lstrlenW(name);
1791 add_unformatted_text_to_control(hwnd, name, len);
1792 HeapFree(GetProcessHeap(), 0, name);
1796 static void add_icon_to_control(HWND hwnd, int id)
1798 HRESULT hr;
1799 IRichEditOle *richEditOle = NULL;
1800 IOleObject *object = NULL;
1801 CLSID clsid;
1802 LPOLECACHE oleCache = NULL;
1803 FORMATETC formatEtc;
1804 DWORD conn;
1805 IDataObject *dataObject = NULL;
1806 HBITMAP bitmap = NULL;
1807 STGMEDIUM stgm;
1808 IOleClientSite *clientSite = NULL;
1809 REOBJECT reObject;
1811 TRACE("(%p, %d)\n", hwnd, id);
1813 SendMessageW(hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&richEditOle);
1814 if (!richEditOle)
1815 goto end;
1816 hr = OleCreateDefaultHandler(&CLSID_NULL, NULL, &IID_IOleObject,
1817 (void**)&object);
1818 if (FAILED(hr))
1819 goto end;
1820 hr = IOleObject_GetUserClassID(object, &clsid);
1821 if (FAILED(hr))
1822 goto end;
1823 hr = IOleObject_QueryInterface(object, &IID_IOleCache, (void**)&oleCache);
1824 if (FAILED(hr))
1825 goto end;
1826 formatEtc.cfFormat = CF_BITMAP;
1827 formatEtc.ptd = NULL;
1828 formatEtc.dwAspect = DVASPECT_CONTENT;
1829 formatEtc.lindex = -1;
1830 formatEtc.tymed = TYMED_GDI;
1831 hr = IOleCache_Cache(oleCache, &formatEtc, 0, &conn);
1832 if (FAILED(hr))
1833 goto end;
1834 hr = IOleObject_QueryInterface(object, &IID_IDataObject,
1835 (void**)&dataObject);
1836 if (FAILED(hr))
1837 goto end;
1838 hr = IRichEditOle_GetClientSite(richEditOle, &clientSite);
1839 if (FAILED(hr))
1840 goto end;
1841 bitmap = LoadImageW(hInstance, MAKEINTRESOURCEW(id), IMAGE_BITMAP, 0, 0,
1842 LR_DEFAULTSIZE | LR_LOADTRANSPARENT);
1843 if (!bitmap)
1844 goto end;
1845 stgm.tymed = TYMED_GDI;
1846 stgm.u.hBitmap = bitmap;
1847 stgm.pUnkForRelease = NULL;
1848 hr = IDataObject_SetData(dataObject, &formatEtc, &stgm, TRUE);
1849 if (FAILED(hr))
1850 goto end;
1852 reObject.cbStruct = sizeof(reObject);
1853 reObject.cp = REO_CP_SELECTION;
1854 reObject.clsid = clsid;
1855 reObject.poleobj = object;
1856 reObject.pstg = NULL;
1857 reObject.polesite = clientSite;
1858 reObject.sizel.cx = reObject.sizel.cy = 0;
1859 reObject.dvaspect = DVASPECT_CONTENT;
1860 reObject.dwFlags = 0;
1861 reObject.dwUser = 0;
1863 IRichEditOle_InsertObject(richEditOle, &reObject);
1865 end:
1866 if (clientSite)
1867 IOleClientSite_Release(clientSite);
1868 if (dataObject)
1869 IDataObject_Release(dataObject);
1870 if (oleCache)
1871 IOleCache_Release(oleCache);
1872 if (object)
1873 IOleObject_Release(object);
1874 if (richEditOle)
1875 IRichEditOle_Release(richEditOle);
1878 #define MY_INDENT 200
1880 static void add_oid_text_to_control(HWND hwnd, char *oid)
1882 WCHAR nl = '\n';
1883 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, oid, 0);
1884 PARAFORMAT2 parFmt;
1886 parFmt.cbSize = sizeof(parFmt);
1887 parFmt.dwMask = PFM_STARTINDENT;
1888 parFmt.dxStartIndent = MY_INDENT * 3;
1889 if (oidInfo)
1891 add_text_with_paraformat_to_control(hwnd, oidInfo->pwszName,
1892 lstrlenW(oidInfo->pwszName), &parFmt);
1893 add_unformatted_text_to_control(hwnd, &nl, 1);
1897 struct OIDToString
1899 LPCSTR oid;
1900 int id;
1903 /* The following list MUST be lexicographically sorted by OID */
1904 static struct OIDToString oidMap[] = {
1905 /* 1.3.6.1.4.1.311.10.3.1 */
1906 { szOID_KP_CTL_USAGE_SIGNING, IDS_PURPOSE_CTL_USAGE_SIGNING },
1907 /* 1.3.6.1.4.1.311.10.3.4 */
1908 { szOID_KP_EFS, IDS_PURPOSE_EFS },
1909 /* 1.3.6.1.4.1.311.10.3.4.1 */
1910 { szOID_EFS_RECOVERY, IDS_PURPOSE_EFS_RECOVERY },
1911 /* 1.3.6.1.4.1.311.10.3.5 */
1912 { szOID_WHQL_CRYPTO, IDS_PURPOSE_WHQL },
1913 /* 1.3.6.1.4.1.311.10.3.6 */
1914 { szOID_NT5_CRYPTO, IDS_PURPOSE_NT5 },
1915 /* 1.3.6.1.4.1.311.10.3.7 */
1916 { szOID_OEM_WHQL_CRYPTO, IDS_PURPOSE_OEM_WHQL },
1917 /* 1.3.6.1.4.1.311.10.3.8 */
1918 { szOID_EMBEDDED_NT_CRYPTO, IDS_PURPOSE_EMBEDDED_NT },
1919 /* 1.3.6.1.4.1.311.10.3.9 */
1920 { szOID_ROOT_LIST_SIGNER, IDS_PURPOSE_ROOT_LIST_SIGNER },
1921 /* 1.3.6.1.4.1.311.10.3.10 */
1922 { szOID_KP_QUALIFIED_SUBORDINATION, IDS_PURPOSE_QUALIFIED_SUBORDINATION },
1923 /* 1.3.6.1.4.1.311.10.3.11 */
1924 { szOID_KP_KEY_RECOVERY, IDS_PURPOSE_KEY_RECOVERY },
1925 /* 1.3.6.1.4.1.311.10.3.12 */
1926 { szOID_KP_DOCUMENT_SIGNING, IDS_PURPOSE_DOCUMENT_SIGNING },
1927 /* 1.3.6.1.4.1.311.10.3.13 */
1928 { szOID_KP_LIFETIME_SIGNING, IDS_PURPOSE_LIFETIME_SIGNING },
1929 /* 1.3.6.1.4.1.311.10.5.1 */
1930 { szOID_DRM, IDS_PURPOSE_DRM },
1931 /* 1.3.6.1.4.1.311.10.6.1 */
1932 { szOID_LICENSES, IDS_PURPOSE_LICENSES },
1933 /* 1.3.6.1.4.1.311.10.6.2 */
1934 { szOID_LICENSE_SERVER, IDS_PURPOSE_LICENSE_SERVER },
1935 /* 1.3.6.1.4.1.311.20.2.1 */
1936 { szOID_ENROLLMENT_AGENT, IDS_PURPOSE_ENROLLMENT_AGENT },
1937 /* 1.3.6.1.4.1.311.20.2.2 */
1938 { szOID_KP_SMARTCARD_LOGON, IDS_PURPOSE_SMARTCARD_LOGON },
1939 /* 1.3.6.1.4.1.311.21.5 */
1940 { szOID_KP_CA_EXCHANGE, IDS_PURPOSE_CA_EXCHANGE },
1941 /* 1.3.6.1.4.1.311.21.6 */
1942 { szOID_KP_KEY_RECOVERY_AGENT, IDS_PURPOSE_KEY_RECOVERY_AGENT },
1943 /* 1.3.6.1.4.1.311.21.19 */
1944 { szOID_DS_EMAIL_REPLICATION, IDS_PURPOSE_DS_EMAIL_REPLICATION },
1945 /* 1.3.6.1.5.5.7.3.1 */
1946 { szOID_PKIX_KP_SERVER_AUTH, IDS_PURPOSE_SERVER_AUTH },
1947 /* 1.3.6.1.5.5.7.3.2 */
1948 { szOID_PKIX_KP_CLIENT_AUTH, IDS_PURPOSE_CLIENT_AUTH },
1949 /* 1.3.6.1.5.5.7.3.3 */
1950 { szOID_PKIX_KP_CODE_SIGNING, IDS_PURPOSE_CODE_SIGNING },
1951 /* 1.3.6.1.5.5.7.3.4 */
1952 { szOID_PKIX_KP_EMAIL_PROTECTION, IDS_PURPOSE_EMAIL_PROTECTION },
1953 /* 1.3.6.1.5.5.7.3.5 */
1954 { szOID_PKIX_KP_IPSEC_END_SYSTEM, IDS_PURPOSE_IPSEC },
1955 /* 1.3.6.1.5.5.7.3.6 */
1956 { szOID_PKIX_KP_IPSEC_TUNNEL, IDS_PURPOSE_IPSEC },
1957 /* 1.3.6.1.5.5.7.3.7 */
1958 { szOID_PKIX_KP_IPSEC_USER, IDS_PURPOSE_IPSEC },
1959 /* 1.3.6.1.5.5.7.3.8 */
1960 { szOID_PKIX_KP_TIMESTAMP_SIGNING, IDS_PURPOSE_TIMESTAMP_SIGNING },
1963 static struct OIDToString *findSupportedOID(LPCSTR oid)
1965 int indexHigh = ARRAY_SIZE(oidMap) - 1, indexLow = 0;
1967 while (indexLow <= indexHigh)
1969 int cmp, i = (indexLow + indexHigh) / 2;
1970 if (!(cmp = strcmp(oid, oidMap[i].oid)))
1971 return &oidMap[i];
1972 if (cmp > 0)
1973 indexLow = i + 1;
1974 else
1975 indexHigh = i - 1;
1977 return NULL;
1980 static void add_local_oid_text_to_control(HWND text, LPCSTR oid)
1982 struct OIDToString *entry;
1983 WCHAR nl = '\n';
1984 PARAFORMAT2 parFmt;
1986 parFmt.cbSize = sizeof(parFmt);
1987 parFmt.dwMask = PFM_STARTINDENT;
1988 parFmt.dxStartIndent = MY_INDENT * 3;
1989 if ((entry = findSupportedOID(oid)))
1991 WCHAR *str, *linebreak, *ptr;
1992 BOOL multiline = FALSE;
1993 int len;
1995 len = LoadStringW(hInstance, entry->id, (LPWSTR)&str, 0);
1996 ptr = str;
1997 do {
1998 if ((linebreak = memchrW(ptr, '\n', len)))
2000 WCHAR copy[MAX_STRING_LEN];
2002 multiline = TRUE;
2003 /* The source string contains a newline, which the richedit
2004 * control won't find since it's interpreted as a paragraph
2005 * break. Therefore copy up to the newline. lstrcpynW always
2006 * NULL-terminates, so pass one more than the length of the
2007 * source line so the copy includes the entire line and the
2008 * NULL-terminator.
2010 lstrcpynW(copy, ptr, linebreak - ptr + 1);
2011 add_text_with_paraformat_to_control(text, copy,
2012 linebreak - ptr, &parFmt);
2013 ptr = linebreak + 1;
2014 add_unformatted_text_to_control(text, &nl, 1);
2016 else if (multiline && *ptr)
2018 /* Add the last line */
2019 add_text_with_paraformat_to_control(text, ptr,
2020 len - (ptr - str), &parFmt);
2021 add_unformatted_text_to_control(text, &nl, 1);
2023 } while (linebreak);
2024 if (!multiline)
2026 add_text_with_paraformat_to_control(text, str, len, &parFmt);
2027 add_unformatted_text_to_control(text, &nl, 1);
2030 else
2032 WCHAR *oidW = HeapAlloc(GetProcessHeap(), 0,
2033 (strlen(oid) + 1) * sizeof(WCHAR));
2035 if (oidW)
2037 LPCSTR src;
2038 WCHAR *dst;
2040 for (src = oid, dst = oidW; *src; src++, dst++)
2041 *dst = *src;
2042 *dst = 0;
2043 add_text_with_paraformat_to_control(text, oidW, lstrlenW(oidW),
2044 &parFmt);
2045 add_unformatted_text_to_control(text, &nl, 1);
2046 HeapFree(GetProcessHeap(), 0, oidW);
2051 static void display_app_usages(HWND text, PCCERT_CONTEXT cert,
2052 BOOL *anyUsageAdded)
2054 static char any_app_policy[] = szOID_ANY_APPLICATION_POLICY;
2055 WCHAR nl = '\n';
2056 CHARFORMATW charFmt;
2057 PCERT_EXTENSION policyExt;
2058 if (!*anyUsageAdded)
2060 PARAFORMAT2 parFmt;
2062 parFmt.cbSize = sizeof(parFmt);
2063 parFmt.dwMask = PFM_STARTINDENT;
2064 parFmt.dxStartIndent = MY_INDENT;
2065 add_string_resource_with_paraformat_to_control(text,
2066 IDS_CERT_INFO_PURPOSES, &parFmt);
2067 add_unformatted_text_to_control(text, &nl, 1);
2068 *anyUsageAdded = TRUE;
2070 memset(&charFmt, 0, sizeof(charFmt));
2071 charFmt.cbSize = sizeof(charFmt);
2072 charFmt.dwMask = CFM_BOLD;
2073 charFmt.dwEffects = 0;
2074 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2075 if ((policyExt = CertFindExtension(szOID_APPLICATION_CERT_POLICIES,
2076 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension)))
2078 CERT_POLICIES_INFO *policies;
2079 DWORD size;
2081 if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_POLICIES,
2082 policyExt->Value.pbData, policyExt->Value.cbData,
2083 CRYPT_DECODE_ALLOC_FLAG, NULL, &policies, &size))
2085 DWORD i;
2087 for (i = 0; i < policies->cPolicyInfo; i++)
2089 DWORD j;
2091 for (j = 0; j < policies->rgPolicyInfo[i].cPolicyQualifier; j++)
2092 add_local_oid_text_to_control(text,
2093 policies->rgPolicyInfo[i].rgPolicyQualifier[j].
2094 pszPolicyQualifierId);
2096 LocalFree(policies);
2099 else
2100 add_oid_text_to_control(text, any_app_policy);
2103 static BOOL display_cert_usages(HWND text, PCCERT_CONTEXT cert,
2104 BOOL *anyUsageAdded)
2106 WCHAR nl = '\n';
2107 DWORD size;
2108 BOOL badUsages = FALSE;
2110 if (CertGetEnhancedKeyUsage(cert, 0, NULL, &size))
2112 CHARFORMATW charFmt;
2113 static char any_cert_policy[] = szOID_ANY_CERT_POLICY;
2114 PCERT_ENHKEY_USAGE usage = HeapAlloc(GetProcessHeap(), 0, size);
2116 if (usage)
2118 if (CertGetEnhancedKeyUsage(cert, 0, usage, &size))
2120 DWORD i;
2122 if (!*anyUsageAdded)
2124 PARAFORMAT2 parFmt;
2126 parFmt.cbSize = sizeof(parFmt);
2127 parFmt.dwMask = PFM_STARTINDENT;
2128 parFmt.dxStartIndent = MY_INDENT;
2129 add_string_resource_with_paraformat_to_control(text,
2130 IDS_CERT_INFO_PURPOSES, &parFmt);
2131 add_unformatted_text_to_control(text, &nl, 1);
2132 *anyUsageAdded = TRUE;
2134 memset(&charFmt, 0, sizeof(charFmt));
2135 charFmt.cbSize = sizeof(charFmt);
2136 charFmt.dwMask = CFM_BOLD;
2137 charFmt.dwEffects = 0;
2138 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION,
2139 (LPARAM)&charFmt);
2140 if (!usage->cUsageIdentifier)
2141 add_oid_text_to_control(text, any_cert_policy);
2142 else
2143 for (i = 0; i < usage->cUsageIdentifier; i++)
2144 add_local_oid_text_to_control(text,
2145 usage->rgpszUsageIdentifier[i]);
2147 else
2148 badUsages = TRUE;
2149 HeapFree(GetProcessHeap(), 0, usage);
2151 else
2152 badUsages = TRUE;
2154 else
2155 badUsages = TRUE;
2156 return badUsages;
2159 static void set_policy_text(HWND text,
2160 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
2162 BOOL includeCertUsages = FALSE, includeAppUsages = FALSE;
2163 BOOL badUsages = FALSE, anyUsageAdded = FALSE;
2165 if (pCertViewInfo->cPurposes)
2167 DWORD i;
2169 for (i = 0; i < pCertViewInfo->cPurposes; i++)
2171 if (!strcmp(pCertViewInfo->rgszPurposes[i], szOID_ANY_CERT_POLICY))
2172 includeCertUsages = TRUE;
2173 else if (!strcmp(pCertViewInfo->rgszPurposes[i],
2174 szOID_ANY_APPLICATION_POLICY))
2175 includeAppUsages = TRUE;
2176 else
2177 badUsages = TRUE;
2180 else
2181 includeAppUsages = includeCertUsages = TRUE;
2182 if (includeAppUsages)
2183 display_app_usages(text, pCertViewInfo->pCertContext, &anyUsageAdded);
2184 if (includeCertUsages)
2185 badUsages = display_cert_usages(text, pCertViewInfo->pCertContext,
2186 &anyUsageAdded);
2187 if (badUsages)
2189 PARAFORMAT2 parFmt;
2191 parFmt.cbSize = sizeof(parFmt);
2192 parFmt.dwMask = PFM_STARTINDENT;
2193 parFmt.dxStartIndent = MY_INDENT;
2194 add_string_resource_with_paraformat_to_control(text,
2195 IDS_CERT_INFO_BAD_PURPOSES, &parFmt);
2199 static CRYPT_OBJID_BLOB *find_policy_qualifier(CERT_POLICIES_INFO *policies,
2200 LPCSTR policyOid)
2202 CRYPT_OBJID_BLOB *ret = NULL;
2203 DWORD i;
2205 for (i = 0; !ret && i < policies->cPolicyInfo; i++)
2207 DWORD j;
2209 for (j = 0; !ret && j < policies->rgPolicyInfo[i].cPolicyQualifier; j++)
2210 if (!strcmp(policies->rgPolicyInfo[i].rgPolicyQualifier[j].
2211 pszPolicyQualifierId, policyOid))
2212 ret = &policies->rgPolicyInfo[i].rgPolicyQualifier[j].
2213 Qualifier;
2215 return ret;
2218 static WCHAR *get_cps_str_from_qualifier(const CRYPT_OBJID_BLOB *qualifier)
2220 LPWSTR qualifierStr = NULL;
2221 CERT_NAME_VALUE *qualifierValue;
2222 DWORD size;
2224 if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME_VALUE,
2225 qualifier->pbData, qualifier->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL,
2226 &qualifierValue, &size))
2228 size = CertRDNValueToStrW(qualifierValue->dwValueType,
2229 &qualifierValue->Value, NULL, 0);
2230 qualifierStr = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
2231 if (qualifierStr)
2232 CertRDNValueToStrW(qualifierValue->dwValueType,
2233 &qualifierValue->Value, qualifierStr, size);
2234 LocalFree(qualifierValue);
2236 return qualifierStr;
2239 static WCHAR *get_user_notice_from_qualifier(const CRYPT_OBJID_BLOB *qualifier)
2241 LPWSTR str = NULL;
2242 CERT_POLICY_QUALIFIER_USER_NOTICE *qualifierValue;
2243 DWORD size;
2245 if (CryptDecodeObjectEx(X509_ASN_ENCODING,
2246 X509_PKIX_POLICY_QUALIFIER_USERNOTICE,
2247 qualifier->pbData, qualifier->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL,
2248 &qualifierValue, &size))
2250 str = HeapAlloc(GetProcessHeap(), 0,
2251 (strlenW(qualifierValue->pszDisplayText) + 1) * sizeof(WCHAR));
2252 if (str)
2253 strcpyW(str, qualifierValue->pszDisplayText);
2254 LocalFree(qualifierValue);
2256 return str;
2259 struct IssuerStatement
2261 LPWSTR cps;
2262 LPWSTR userNotice;
2265 static void set_issuer_statement(HWND hwnd,
2266 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
2268 PCERT_EXTENSION policyExt;
2270 if (!(pCertViewInfo->dwFlags & CRYPTUI_DISABLE_ISSUERSTATEMENT) &&
2271 (policyExt = CertFindExtension(szOID_CERT_POLICIES,
2272 pCertViewInfo->pCertContext->pCertInfo->cExtension,
2273 pCertViewInfo->pCertContext->pCertInfo->rgExtension)))
2275 CERT_POLICIES_INFO *policies;
2276 DWORD size;
2278 if (CryptDecodeObjectEx(X509_ASN_ENCODING, policyExt->pszObjId,
2279 policyExt->Value.pbData, policyExt->Value.cbData,
2280 CRYPT_DECODE_ALLOC_FLAG, NULL, &policies, &size))
2282 CRYPT_OBJID_BLOB *qualifier;
2283 LPWSTR cps = NULL, userNotice = NULL;
2285 if ((qualifier = find_policy_qualifier(policies,
2286 szOID_PKIX_POLICY_QUALIFIER_CPS)))
2287 cps = get_cps_str_from_qualifier(qualifier);
2288 if ((qualifier = find_policy_qualifier(policies,
2289 szOID_PKIX_POLICY_QUALIFIER_USERNOTICE)))
2290 userNotice = get_user_notice_from_qualifier(qualifier);
2291 if (cps || userNotice)
2293 struct IssuerStatement *issuerStatement =
2294 HeapAlloc(GetProcessHeap(), 0, sizeof(struct IssuerStatement));
2296 if (issuerStatement)
2298 issuerStatement->cps = cps;
2299 issuerStatement->userNotice = userNotice;
2300 EnableWindow(GetDlgItem(hwnd, IDC_ISSUERSTATEMENT), TRUE);
2301 SetWindowLongPtrW(hwnd, DWLP_USER,
2302 (ULONG_PTR)issuerStatement);
2305 LocalFree(policies);
2310 static void set_cert_info(HWND hwnd,
2311 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
2313 CHARFORMATW charFmt;
2314 PARAFORMAT2 parFmt;
2315 HWND icon = GetDlgItem(hwnd, IDC_CERTIFICATE_ICON);
2316 HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_INFO);
2317 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
2318 (CRYPT_PROVIDER_DATA *)pCertViewInfo->u.pCryptProviderData,
2319 pCertViewInfo->idxSigner, pCertViewInfo->fCounterSigner,
2320 pCertViewInfo->idxCounterSigner);
2321 CRYPT_PROVIDER_CERT *root =
2322 &provSigner->pasCertChain[provSigner->csCertChain - 1];
2324 if (!provSigner->pChainContext ||
2325 (provSigner->pChainContext->TrustStatus.dwErrorStatus &
2326 CERT_TRUST_IS_PARTIAL_CHAIN))
2327 add_icon_to_control(icon, IDB_CERT_WARNING);
2328 else if (!root->fTrustedRoot)
2329 add_icon_to_control(icon, IDB_CERT_ERROR);
2330 else
2331 add_icon_to_control(icon, IDB_CERT);
2333 memset(&charFmt, 0, sizeof(charFmt));
2334 charFmt.cbSize = sizeof(charFmt);
2335 charFmt.dwMask = CFM_BOLD;
2336 charFmt.dwEffects = CFE_BOLD;
2337 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2338 /* FIXME: vertically center text */
2339 parFmt.cbSize = sizeof(parFmt);
2340 parFmt.dwMask = PFM_STARTINDENT;
2341 parFmt.dxStartIndent = MY_INDENT;
2342 add_string_resource_with_paraformat_to_control(text,
2343 IDS_CERTIFICATEINFORMATION, &parFmt);
2345 text = GetDlgItem(hwnd, IDC_CERTIFICATE_STATUS);
2346 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2347 if (provSigner->dwError == TRUST_E_CERT_SIGNATURE)
2348 add_string_resource_with_paraformat_to_control(text,
2349 IDS_CERT_INFO_BAD_SIG, &parFmt);
2350 else if (!provSigner->pChainContext ||
2351 (provSigner->pChainContext->TrustStatus.dwErrorStatus &
2352 CERT_TRUST_IS_PARTIAL_CHAIN))
2353 add_string_resource_with_paraformat_to_control(text,
2354 IDS_CERT_INFO_PARTIAL_CHAIN, &parFmt);
2355 else if (!root->fTrustedRoot)
2357 if (provSigner->csCertChain == 1 && root->fSelfSigned)
2358 add_string_resource_with_paraformat_to_control(text,
2359 IDS_CERT_INFO_UNTRUSTED_CA, &parFmt);
2360 else
2361 add_string_resource_with_paraformat_to_control(text,
2362 IDS_CERT_INFO_UNTRUSTED_ROOT, &parFmt);
2364 else
2366 set_policy_text(text, pCertViewInfo);
2367 set_issuer_statement(hwnd, pCertViewInfo);
2371 static void set_cert_name_string(HWND hwnd, PCCERT_CONTEXT cert,
2372 DWORD nameFlags, int heading)
2374 WCHAR nl = '\n';
2375 HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_NAMES);
2376 CHARFORMATW charFmt;
2377 PARAFORMAT2 parFmt;
2379 memset(&charFmt, 0, sizeof(charFmt));
2380 charFmt.cbSize = sizeof(charFmt);
2381 charFmt.dwMask = CFM_BOLD;
2382 charFmt.dwEffects = CFE_BOLD;
2383 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2384 parFmt.cbSize = sizeof(parFmt);
2385 parFmt.dwMask = PFM_STARTINDENT;
2386 parFmt.dxStartIndent = MY_INDENT * 3;
2387 add_string_resource_with_paraformat_to_control(text, heading, &parFmt);
2388 charFmt.dwEffects = 0;
2389 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2390 add_cert_string_to_control(text, cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
2391 nameFlags);
2392 add_unformatted_text_to_control(text, &nl, 1);
2393 add_unformatted_text_to_control(text, &nl, 1);
2394 add_unformatted_text_to_control(text, &nl, 1);
2398 static void add_date_string_to_control(HWND hwnd, const FILETIME *fileTime)
2400 WCHAR dateFmt[80]; /* sufficient for all versions of LOCALE_SSHORTDATE */
2401 WCHAR date[80];
2402 SYSTEMTIME sysTime;
2404 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SSHORTDATE, dateFmt, ARRAY_SIZE(dateFmt));
2405 FileTimeToSystemTime(fileTime, &sysTime);
2406 GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, date, ARRAY_SIZE(date));
2407 add_unformatted_text_to_control(hwnd, date, lstrlenW(date));
2410 static void set_cert_validity_period(HWND hwnd, PCCERT_CONTEXT cert)
2412 WCHAR nl = '\n';
2413 HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_NAMES);
2414 CHARFORMATW charFmt;
2415 PARAFORMAT2 parFmt;
2417 memset(&charFmt, 0, sizeof(charFmt));
2418 charFmt.cbSize = sizeof(charFmt);
2419 charFmt.dwMask = CFM_BOLD;
2420 charFmt.dwEffects = CFE_BOLD;
2421 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2422 parFmt.cbSize = sizeof(parFmt);
2423 parFmt.dwMask = PFM_STARTINDENT;
2424 parFmt.dxStartIndent = MY_INDENT * 3;
2425 add_string_resource_with_paraformat_to_control(text, IDS_VALID_FROM,
2426 &parFmt);
2427 charFmt.dwEffects = 0;
2428 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2429 add_date_string_to_control(text, &cert->pCertInfo->NotBefore);
2430 charFmt.dwEffects = CFE_BOLD;
2431 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2432 add_string_resource_to_control(text, IDS_VALID_TO);
2433 charFmt.dwEffects = 0;
2434 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2435 add_date_string_to_control(text, &cert->pCertInfo->NotAfter);
2436 add_unformatted_text_to_control(text, &nl, 1);
2439 static void set_general_info(HWND hwnd,
2440 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
2442 set_cert_info(hwnd, pCertViewInfo);
2443 set_cert_name_string(hwnd, pCertViewInfo->pCertContext, 0,
2444 IDS_SUBJECT_HEADING);
2445 set_cert_name_string(hwnd, pCertViewInfo->pCertContext,
2446 CERT_NAME_ISSUER_FLAG, IDS_ISSUER_HEADING);
2447 set_cert_validity_period(hwnd, pCertViewInfo->pCertContext);
2450 static LRESULT CALLBACK user_notice_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
2451 LPARAM lp)
2453 LRESULT ret = 0;
2454 HWND text;
2455 struct IssuerStatement *issuerStatement;
2457 switch (msg)
2459 case WM_INITDIALOG:
2460 text = GetDlgItem(hwnd, IDC_USERNOTICE);
2461 issuerStatement = (struct IssuerStatement *)lp;
2462 add_unformatted_text_to_control(text, issuerStatement->userNotice,
2463 strlenW(issuerStatement->userNotice));
2464 if (issuerStatement->cps)
2465 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)issuerStatement->cps);
2466 else
2467 EnableWindow(GetDlgItem(hwnd, IDC_CPS), FALSE);
2468 break;
2469 case WM_COMMAND:
2470 switch (wp)
2472 case IDOK:
2473 EndDialog(hwnd, IDOK);
2474 ret = TRUE;
2475 break;
2476 case IDC_CPS:
2478 IBindCtx *bctx = NULL;
2479 LPWSTR cps;
2481 CreateBindCtx(0, &bctx);
2482 cps = (LPWSTR)GetWindowLongPtrW(hwnd, DWLP_USER);
2483 HlinkSimpleNavigateToString(cps, NULL, NULL, NULL, bctx, NULL,
2484 HLNF_OPENINNEWWINDOW, 0);
2485 IBindCtx_Release(bctx);
2486 break;
2490 return ret;
2493 static void show_user_notice(HWND hwnd, struct IssuerStatement *issuerStatement)
2495 DialogBoxParamW(hInstance, MAKEINTRESOURCEW(IDD_USERNOTICE), hwnd,
2496 user_notice_dlg_proc, (LPARAM)issuerStatement);
2499 static LRESULT CALLBACK general_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
2500 LPARAM lp)
2502 PROPSHEETPAGEW *page;
2503 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo;
2505 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
2507 switch (msg)
2509 case WM_INITDIALOG:
2510 page = (PROPSHEETPAGEW *)lp;
2511 pCertViewInfo = (PCCRYPTUI_VIEWCERTIFICATE_STRUCTW)page->lParam;
2512 if (pCertViewInfo->dwFlags & CRYPTUI_DISABLE_ADDTOSTORE)
2513 ShowWindow(GetDlgItem(hwnd, IDC_ADDTOSTORE), FALSE);
2514 EnableWindow(GetDlgItem(hwnd, IDC_ISSUERSTATEMENT), FALSE);
2515 set_general_info(hwnd, pCertViewInfo);
2516 break;
2517 case WM_COMMAND:
2518 switch (wp)
2520 case IDC_ADDTOSTORE:
2521 CryptUIWizImport(0, hwnd, NULL, NULL, NULL);
2522 break;
2523 case IDC_ISSUERSTATEMENT:
2525 struct IssuerStatement *issuerStatement =
2526 (struct IssuerStatement *)GetWindowLongPtrW(hwnd, DWLP_USER);
2528 if (issuerStatement)
2530 if (issuerStatement->userNotice)
2531 show_user_notice(hwnd, issuerStatement);
2532 else if (issuerStatement->cps)
2534 IBindCtx *bctx = NULL;
2536 CreateBindCtx(0, &bctx);
2537 HlinkSimpleNavigateToString(issuerStatement->cps, NULL,
2538 NULL, NULL, bctx, NULL, HLNF_OPENINNEWWINDOW, 0);
2539 IBindCtx_Release(bctx);
2542 break;
2545 break;
2547 return 0;
2550 static UINT CALLBACK general_callback_proc(HWND hwnd, UINT msg,
2551 PROPSHEETPAGEW *page)
2553 struct IssuerStatement *issuerStatement;
2555 switch (msg)
2557 case PSPCB_RELEASE:
2558 issuerStatement =
2559 (struct IssuerStatement *)GetWindowLongPtrW(hwnd, DWLP_USER);
2560 if (issuerStatement)
2562 HeapFree(GetProcessHeap(), 0, issuerStatement->cps);
2563 HeapFree(GetProcessHeap(), 0, issuerStatement->userNotice);
2564 HeapFree(GetProcessHeap(), 0, issuerStatement);
2566 break;
2568 return 1;
2571 static void init_general_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
2572 PROPSHEETPAGEW *page)
2574 memset(page, 0, sizeof(PROPSHEETPAGEW));
2575 page->dwSize = sizeof(PROPSHEETPAGEW);
2576 page->dwFlags = PSP_USECALLBACK;
2577 page->pfnCallback = general_callback_proc;
2578 page->hInstance = hInstance;
2579 page->u.pszTemplate = MAKEINTRESOURCEW(IDD_GENERAL);
2580 page->pfnDlgProc = general_dlg_proc;
2581 page->lParam = (LPARAM)pCertViewInfo;
2584 typedef WCHAR * (*field_format_func)(PCCERT_CONTEXT cert);
2586 static WCHAR *field_format_version(PCCERT_CONTEXT cert)
2588 static const WCHAR fmt[] = { 'V','%','d',0 };
2589 WCHAR *buf = HeapAlloc(GetProcessHeap(), 0, 12 * sizeof(WCHAR));
2591 if (buf)
2592 sprintfW(buf, fmt, cert->pCertInfo->dwVersion);
2593 return buf;
2596 static WCHAR *format_hex_string(void *pb, DWORD cb)
2598 WCHAR *buf = HeapAlloc(GetProcessHeap(), 0, (cb * 3 + 1) * sizeof(WCHAR));
2600 if (buf)
2602 static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
2603 DWORD i;
2604 WCHAR *ptr;
2606 for (i = 0, ptr = buf; i < cb; i++, ptr += 3)
2607 sprintfW(ptr, fmt, ((BYTE *)pb)[i]);
2609 return buf;
2612 static WCHAR *field_format_serial_number(PCCERT_CONTEXT cert)
2614 return format_hex_string(cert->pCertInfo->SerialNumber.pbData,
2615 cert->pCertInfo->SerialNumber.cbData);
2618 static WCHAR *field_format_issuer(PCCERT_CONTEXT cert)
2620 return get_cert_name_string(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
2621 CERT_NAME_ISSUER_FLAG);
2624 static WCHAR *field_format_detailed_cert_name(PCERT_NAME_BLOB name)
2626 WCHAR *str = NULL;
2627 DWORD len = CertNameToStrW(X509_ASN_ENCODING, name,
2628 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, NULL, 0);
2630 if (len)
2632 str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2633 if (str)
2634 CertNameToStrW(X509_ASN_ENCODING, name,
2635 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, str, len);
2637 return str;
2640 static WCHAR *field_format_detailed_issuer(PCCERT_CONTEXT cert, void *param)
2642 return field_format_detailed_cert_name(&cert->pCertInfo->Issuer);
2645 static WCHAR *field_format_subject(PCCERT_CONTEXT cert)
2647 return get_cert_name_string(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0);
2650 static WCHAR *field_format_detailed_subject(PCCERT_CONTEXT cert, void *param)
2652 return field_format_detailed_cert_name(&cert->pCertInfo->Subject);
2655 static WCHAR *format_long_date(const FILETIME *fileTime)
2657 WCHAR dateFmt[80]; /* long enough for LOCALE_SLONGDATE */
2658 DWORD len;
2659 WCHAR *buf = NULL;
2660 SYSTEMTIME sysTime;
2662 /* FIXME: format isn't quite right, want time too */
2663 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SLONGDATE, dateFmt, ARRAY_SIZE(dateFmt));
2664 FileTimeToSystemTime(fileTime, &sysTime);
2665 len = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, NULL, 0);
2666 if (len)
2668 buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2669 if (buf)
2670 GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, buf,
2671 len);
2673 return buf;
2676 static WCHAR *field_format_from_date(PCCERT_CONTEXT cert)
2678 return format_long_date(&cert->pCertInfo->NotBefore);
2681 static WCHAR *field_format_to_date(PCCERT_CONTEXT cert)
2683 return format_long_date(&cert->pCertInfo->NotAfter);
2686 static WCHAR *field_format_public_key(PCCERT_CONTEXT cert)
2688 PCCRYPT_OID_INFO oidInfo;
2689 WCHAR *buf = NULL;
2691 oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2692 cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, 0);
2693 if (oidInfo)
2695 WCHAR fmt[MAX_STRING_LEN];
2697 if (LoadStringW(hInstance, IDS_FIELD_PUBLIC_KEY_FORMAT, fmt, ARRAY_SIZE(fmt)))
2699 DWORD len;
2701 /* Allocate the output buffer. Use the number of bytes in the
2702 * public key as a conservative (high) estimate for the number of
2703 * digits in its output.
2704 * The output is of the form (in English)
2705 * "<public key algorithm> (<public key bit length> bits)".
2706 * Ordinarily having two positional parameters in a string is not a
2707 * good idea, but as this isn't a sentence fragment, it shouldn't
2708 * be word-order dependent.
2710 len = strlenW(fmt) + strlenW(oidInfo->pwszName) +
2711 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData * 8;
2712 buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(*buf));
2713 if (buf)
2715 DWORD_PTR args[2];
2716 args[0] = (DWORD_PTR)oidInfo->pwszName;
2717 args[1] = CertGetPublicKeyLength(X509_ASN_ENCODING,
2718 &cert->pCertInfo->SubjectPublicKeyInfo);
2719 FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
2720 fmt, 0, 0, buf, len, (__ms_va_list*)args);
2724 return buf;
2727 static WCHAR *field_format_detailed_public_key(PCCERT_CONTEXT cert, void *param)
2729 return format_hex_string(
2730 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
2731 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData);
2734 struct field_value_data;
2735 struct detail_data
2737 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo;
2738 BOOL *pfPropertiesChanged;
2739 int cFields;
2740 struct field_value_data *fields;
2743 typedef void (*add_fields_func)(HWND hwnd, struct detail_data *data);
2745 typedef WCHAR *(*create_detailed_value_func)(PCCERT_CONTEXT cert, void *param);
2747 struct field_value_data
2749 create_detailed_value_func create;
2750 LPWSTR detailed_value;
2751 void *param;
2754 static void add_field_value_data(struct detail_data *data,
2755 create_detailed_value_func create, void *param)
2757 if (data->cFields)
2758 data->fields = HeapReAlloc(GetProcessHeap(), 0, data->fields,
2759 (data->cFields + 1) * sizeof(struct field_value_data));
2760 else
2761 data->fields = HeapAlloc(GetProcessHeap(), 0,
2762 sizeof(struct field_value_data));
2763 if (data->fields)
2765 data->fields[data->cFields].create = create;
2766 data->fields[data->cFields].detailed_value = NULL;
2767 data->fields[data->cFields].param = param;
2768 data->cFields++;
2772 static void add_field_and_value_to_list(HWND hwnd, struct detail_data *data,
2773 LPWSTR field, LPWSTR value, create_detailed_value_func create, void *param)
2775 LVITEMW item;
2776 int iItem = SendMessageW(hwnd, LVM_GETITEMCOUNT, 0, 0);
2778 item.mask = LVIF_TEXT | LVIF_PARAM;
2779 item.iItem = iItem;
2780 item.iSubItem = 0;
2781 item.pszText = field;
2782 item.lParam = (LPARAM)data;
2783 SendMessageW(hwnd, LVM_INSERTITEMW, 0, (LPARAM)&item);
2784 if (value)
2786 item.pszText = value;
2787 item.iSubItem = 1;
2788 SendMessageW(hwnd, LVM_SETITEMTEXTW, iItem, (LPARAM)&item);
2790 add_field_value_data(data, create, param);
2793 static void add_string_id_and_value_to_list(HWND hwnd, struct detail_data *data,
2794 int id, LPWSTR value, create_detailed_value_func create, void *param)
2796 WCHAR buf[MAX_STRING_LEN];
2798 LoadStringW(hInstance, id, buf, ARRAY_SIZE(buf));
2799 add_field_and_value_to_list(hwnd, data, buf, value, create, param);
2802 struct v1_field
2804 int id;
2805 field_format_func format;
2806 create_detailed_value_func create_detailed_value;
2809 static void add_v1_field(HWND hwnd, struct detail_data *data,
2810 const struct v1_field *field)
2812 WCHAR *val = field->format(data->pCertViewInfo->pCertContext);
2814 if (val)
2816 add_string_id_and_value_to_list(hwnd, data, field->id, val,
2817 field->create_detailed_value, NULL);
2818 HeapFree(GetProcessHeap(), 0, val);
2822 static const struct v1_field v1_fields[] = {
2823 { IDS_FIELD_VERSION, field_format_version, NULL },
2824 { IDS_FIELD_SERIAL_NUMBER, field_format_serial_number, NULL },
2825 { IDS_FIELD_ISSUER, field_format_issuer, field_format_detailed_issuer },
2826 { IDS_FIELD_VALID_FROM, field_format_from_date, NULL },
2827 { IDS_FIELD_VALID_TO, field_format_to_date, NULL },
2828 { IDS_FIELD_SUBJECT, field_format_subject, field_format_detailed_subject },
2829 { IDS_FIELD_PUBLIC_KEY, field_format_public_key,
2830 field_format_detailed_public_key }
2833 static void add_v1_fields(HWND hwnd, struct detail_data *data)
2835 unsigned int i;
2836 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
2838 /* The last item in v1_fields is the public key, which is not in the loop
2839 * because it's a special case.
2841 for (i = 0; i < ARRAY_SIZE(v1_fields) - 1; i++)
2842 add_v1_field(hwnd, data, &v1_fields[i]);
2843 if (cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData)
2844 add_v1_field(hwnd, data, &v1_fields[i]);
2847 static WCHAR *crypt_format_extension(const CERT_EXTENSION *ext, DWORD formatStrType)
2849 WCHAR *str = NULL;
2850 DWORD size;
2852 if (CryptFormatObject(X509_ASN_ENCODING, 0, formatStrType, NULL,
2853 ext->pszObjId, ext->Value.pbData, ext->Value.cbData, NULL, &size))
2855 str = HeapAlloc(GetProcessHeap(), 0, size);
2856 CryptFormatObject(X509_ASN_ENCODING, 0, formatStrType, NULL,
2857 ext->pszObjId, ext->Value.pbData, ext->Value.cbData, str, &size);
2859 return str;
2862 static WCHAR *field_format_extension_hex_with_ascii(const CERT_EXTENSION *ext)
2864 WCHAR *str = NULL;
2866 if (ext->Value.cbData)
2868 /* The output is formatted as:
2869 * <hex bytes> <ascii bytes>\n
2870 * where <hex bytes> is a string of up to 8 bytes, output as %02x,
2871 * and <ascii bytes> is the ASCII equivalent of each byte, or '.' if
2872 * the byte is not printable.
2873 * So, for example, the extension value consisting of the following
2874 * bytes:
2875 * 0x30,0x14,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x03,
2876 * 0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67
2877 * is output as:
2878 * 30 14 31 12 30 10 06 03 0.1.0...
2879 * 55 04 03 13 09 4a 75 61 U....Jua
2880 * 6e 20 4c 61 6e 67 n Lang
2881 * The allocation size therefore requires:
2882 * - 4 characters per character in an 8-byte line
2883 * (2 for the hex format, one for the space, one for the ASCII value)
2884 * - 3 more characters per 8-byte line (two spaces and a newline)
2885 * - 1 character for the terminating nul
2886 * FIXME: should use a fixed-width font for this
2888 DWORD lines = (ext->Value.cbData + 7) / 8;
2890 str = HeapAlloc(GetProcessHeap(), 0,
2891 (lines * 8 * 4 + lines * 3 + 1) * sizeof(WCHAR));
2892 if (str)
2894 static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
2895 DWORD i, j;
2896 WCHAR *ptr;
2898 for (i = 0, ptr = str; i < ext->Value.cbData; i += 8)
2900 /* Output as hex bytes first */
2901 for (j = i; j < min(i + 8, ext->Value.cbData); j++, ptr += 3)
2902 sprintfW(ptr, fmt, ext->Value.pbData[j]);
2903 /* Pad the hex output with spaces for alignment */
2904 if (j == ext->Value.cbData && j % 8)
2906 static const WCHAR pad[] = { ' ',' ',' ' };
2908 for (; j % 8; j++, ptr += ARRAY_SIZE(pad))
2909 memcpy(ptr, pad, sizeof(pad));
2911 /* The last sprintfW included a space, so just insert one
2912 * more space between the hex bytes and the ASCII output
2914 *ptr++ = ' ';
2915 /* Output as ASCII bytes */
2916 for (j = i; j < min(i + 8, ext->Value.cbData); j++, ptr++)
2918 if (isprintW(ext->Value.pbData[j]) &&
2919 !isspaceW(ext->Value.pbData[j]))
2920 *ptr = ext->Value.pbData[j];
2921 else
2922 *ptr = '.';
2924 *ptr++ = '\n';
2926 *ptr++ = '\0';
2929 return str;
2932 static WCHAR *field_format_detailed_extension(PCCERT_CONTEXT cert, void *param)
2934 PCERT_EXTENSION ext = param;
2935 LPWSTR str = crypt_format_extension(ext,
2936 CRYPT_FORMAT_STR_MULTI_LINE | CRYPT_FORMAT_STR_NO_HEX);
2938 if (!str)
2939 str = field_format_extension_hex_with_ascii(ext);
2940 return str;
2943 static void add_cert_extension_detail(HWND hwnd, struct detail_data *data,
2944 PCERT_EXTENSION ext)
2946 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2947 ext->pszObjId, 0);
2948 LPWSTR val = crypt_format_extension(ext, 0);
2950 if (oidInfo)
2951 add_field_and_value_to_list(hwnd, data, (LPWSTR)oidInfo->pwszName,
2952 val, field_format_detailed_extension, ext);
2953 else
2955 DWORD len = strlen(ext->pszObjId);
2956 LPWSTR oidW = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2958 if (oidW)
2960 DWORD i;
2962 for (i = 0; i <= len; i++)
2963 oidW[i] = ext->pszObjId[i];
2964 add_field_and_value_to_list(hwnd, data, oidW, val,
2965 field_format_detailed_extension, ext);
2966 HeapFree(GetProcessHeap(), 0, oidW);
2969 HeapFree(GetProcessHeap(), 0, val);
2972 static void add_all_extensions(HWND hwnd, struct detail_data *data)
2974 DWORD i;
2975 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
2977 for (i = 0; i < cert->pCertInfo->cExtension; i++)
2978 add_cert_extension_detail(hwnd, data, &cert->pCertInfo->rgExtension[i]);
2981 static void add_critical_extensions(HWND hwnd, struct detail_data *data)
2983 DWORD i;
2984 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
2986 for (i = 0; i < cert->pCertInfo->cExtension; i++)
2987 if (cert->pCertInfo->rgExtension[i].fCritical)
2988 add_cert_extension_detail(hwnd, data,
2989 &cert->pCertInfo->rgExtension[i]);
2992 typedef WCHAR * (*prop_to_value_func)(void *pb, DWORD cb);
2994 struct prop_id_to_string_id
2996 DWORD prop;
2997 int id;
2998 BOOL prop_is_string;
2999 prop_to_value_func prop_to_value;
3002 static WCHAR *format_enhanced_key_usage_value(void *pb, DWORD cb)
3004 CERT_EXTENSION ext;
3006 ext.pszObjId = (LPSTR)X509_ENHANCED_KEY_USAGE;
3007 ext.fCritical = FALSE;
3008 ext.Value.pbData = pb;
3009 ext.Value.cbData = cb;
3010 return crypt_format_extension(&ext, 0);
3013 /* Logically the access state should also be checked, and IDC_EDITPROPERTIES
3014 * disabled for read-only certificates, but native doesn't appear to do that.
3016 static const struct prop_id_to_string_id prop_id_map[] = {
3017 { CERT_HASH_PROP_ID, IDS_PROP_HASH, FALSE, format_hex_string },
3018 { CERT_FRIENDLY_NAME_PROP_ID, IDS_PROP_FRIENDLY_NAME, TRUE, NULL },
3019 { CERT_DESCRIPTION_PROP_ID, IDS_PROP_DESCRIPTION, TRUE, NULL },
3020 { CERT_ENHKEY_USAGE_PROP_ID, IDS_PROP_ENHKEY_USAGE, FALSE,
3021 format_enhanced_key_usage_value },
3024 static void add_properties(HWND hwnd, struct detail_data *data)
3026 DWORD i;
3027 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
3029 for (i = 0; i < ARRAY_SIZE(prop_id_map); i++)
3031 DWORD cb;
3033 if (CertGetCertificateContextProperty(cert, prop_id_map[i].prop, NULL,
3034 &cb))
3036 BYTE *pb;
3037 WCHAR *val = NULL;
3039 /* FIXME: MS adds a separate value for the signature hash
3040 * algorithm.
3042 pb = HeapAlloc(GetProcessHeap(), 0, cb);
3043 if (pb)
3045 if (CertGetCertificateContextProperty(cert,
3046 prop_id_map[i].prop, pb, &cb))
3048 if (prop_id_map[i].prop_is_string)
3050 val = (LPWSTR)pb;
3051 /* Don't double-free pb */
3052 pb = NULL;
3054 else
3055 val = prop_id_map[i].prop_to_value(pb, cb);
3057 HeapFree(GetProcessHeap(), 0, pb);
3059 add_string_id_and_value_to_list(hwnd, data, prop_id_map[i].id, val,
3060 NULL, NULL);
3065 static void add_all_fields(HWND hwnd, struct detail_data *data)
3067 add_v1_fields(hwnd, data);
3068 add_all_extensions(hwnd, data);
3069 add_properties(hwnd, data);
3072 struct selection_list_item
3074 int id;
3075 add_fields_func add;
3078 static const struct selection_list_item listItems[] = {
3079 { IDS_FIELDS_ALL, add_all_fields },
3080 { IDS_FIELDS_V1, add_v1_fields },
3081 { IDS_FIELDS_EXTENSIONS, add_all_extensions },
3082 { IDS_FIELDS_CRITICAL_EXTENSIONS, add_critical_extensions },
3083 { IDS_FIELDS_PROPERTIES, add_properties },
3086 static void create_show_list(HWND hwnd, struct detail_data *data)
3088 HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT);
3089 WCHAR buf[MAX_STRING_LEN];
3090 int i;
3092 for (i = 0; i < ARRAY_SIZE(listItems); i++)
3094 int index;
3096 LoadStringW(hInstance, listItems[i].id, buf, ARRAY_SIZE(buf));
3097 index = SendMessageW(cb, CB_INSERTSTRING, -1, (LPARAM)buf);
3098 SendMessageW(cb, CB_SETITEMDATA, index, (LPARAM)data);
3100 SendMessageW(cb, CB_SETCURSEL, 0, 0);
3103 static void create_listview_columns(HWND hwnd)
3105 HWND lv = GetDlgItem(hwnd, IDC_DETAIL_LIST);
3106 RECT rc;
3107 WCHAR buf[MAX_STRING_LEN];
3108 LVCOLUMNW column;
3110 SendMessageW(lv, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
3111 GetWindowRect(lv, &rc);
3112 LoadStringW(hInstance, IDS_FIELD, buf, ARRAY_SIZE(buf));
3113 column.mask = LVCF_WIDTH | LVCF_TEXT;
3114 column.cx = (rc.right - rc.left) / 2 - 2;
3115 column.pszText = buf;
3116 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
3117 LoadStringW(hInstance, IDS_VALUE, buf, ARRAY_SIZE(buf));
3118 SendMessageW(lv, LVM_INSERTCOLUMNW, 1, (LPARAM)&column);
3121 static void set_fields_selection(HWND hwnd, struct detail_data *data, int sel)
3123 HWND list = GetDlgItem(hwnd, IDC_DETAIL_LIST);
3125 if (sel >= 0 && sel < ARRAY_SIZE(listItems))
3127 SendMessageW(list, LVM_DELETEALLITEMS, 0, 0);
3128 listItems[sel].add(list, data);
3132 static void create_cert_details_list(HWND hwnd, struct detail_data *data)
3134 create_show_list(hwnd, data);
3135 create_listview_columns(hwnd);
3136 set_fields_selection(hwnd, data, 0);
3139 static void add_purpose(HWND hwnd, LPCSTR oid)
3141 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
3142 PCRYPT_OID_INFO info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3143 sizeof(CRYPT_OID_INFO));
3145 if (info)
3147 char *oidCopy = HeapAlloc(GetProcessHeap(), 0, strlen(oid) + 1);
3149 if (oidCopy)
3151 LVITEMA item;
3153 strcpy(oidCopy, oid);
3154 info->cbSize = sizeof(CRYPT_OID_INFO);
3155 info->pszOID = oidCopy;
3156 item.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM;
3157 item.state = INDEXTOSTATEIMAGEMASK(CheckBitmapIndexChecked);
3158 item.stateMask = LVIS_STATEIMAGEMASK;
3159 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
3160 item.iSubItem = 0;
3161 item.lParam = (LPARAM)info;
3162 item.pszText = oidCopy;
3163 SendMessageA(lv, LVM_INSERTITEMA, 0, (LPARAM)&item);
3165 else
3166 HeapFree(GetProcessHeap(), 0, info);
3170 static BOOL is_valid_oid(LPCSTR oid)
3172 BOOL ret;
3174 if (oid[0] != '0' && oid[0] != '1' && oid[0] != '2')
3175 ret = FALSE;
3176 else if (oid[1] != '.')
3177 ret = FALSE;
3178 else if (!oid[2])
3179 ret = FALSE;
3180 else
3182 const char *ptr;
3183 BOOL expectNum = TRUE;
3185 for (ptr = oid + 2, ret = TRUE; ret && *ptr; ptr++)
3187 if (expectNum)
3189 if (!isdigit(*ptr))
3190 ret = FALSE;
3191 else if (*(ptr + 1) == '.')
3192 expectNum = FALSE;
3194 else
3196 if (*ptr != '.')
3197 ret = FALSE;
3198 else if (!(*(ptr + 1)))
3199 ret = FALSE;
3200 else
3201 expectNum = TRUE;
3205 return ret;
3208 static BOOL is_oid_in_list(HWND hwnd, LPCSTR oid)
3210 return find_oid_in_list(GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES), oid)
3211 != -1;
3214 #define MAX_PURPOSE 255
3216 static LRESULT CALLBACK add_purpose_dlg_proc(HWND hwnd, UINT msg,
3217 WPARAM wp, LPARAM lp)
3219 LRESULT ret = 0;
3220 char buf[MAX_PURPOSE + 1];
3222 switch (msg)
3224 case WM_INITDIALOG:
3225 SendMessageW(GetDlgItem(hwnd, IDC_NEW_PURPOSE), EM_SETLIMITTEXT,
3226 MAX_PURPOSE, 0);
3227 ShowScrollBar(GetDlgItem(hwnd, IDC_NEW_PURPOSE), SB_VERT, FALSE);
3228 SetWindowLongPtrW(hwnd, DWLP_USER, lp);
3229 break;
3230 case WM_COMMAND:
3231 switch (HIWORD(wp))
3233 case EN_CHANGE:
3234 if (LOWORD(wp) == IDC_NEW_PURPOSE)
3236 /* Show/hide scroll bar on description depending on how much
3237 * text it has.
3239 HWND description = GetDlgItem(hwnd, IDC_NEW_PURPOSE);
3240 int lines = SendMessageW(description, EM_GETLINECOUNT, 0, 0);
3242 ShowScrollBar(description, SB_VERT, lines > 1);
3244 break;
3245 case BN_CLICKED:
3246 switch (LOWORD(wp))
3248 case IDOK:
3249 SendMessageA(GetDlgItem(hwnd, IDC_NEW_PURPOSE), WM_GETTEXT, ARRAY_SIZE(buf),
3250 (LPARAM)buf);
3251 if (!buf[0])
3253 /* An empty purpose is the same as cancelling */
3254 EndDialog(hwnd, IDCANCEL);
3255 ret = TRUE;
3257 else if (!is_valid_oid(buf))
3259 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
3261 LoadStringW(hInstance, IDS_CERTIFICATE_PURPOSE_ERROR, error, ARRAY_SIZE(error));
3262 LoadStringW(hInstance, IDS_CERTIFICATE_PROPERTIES, title, ARRAY_SIZE(title));
3263 MessageBoxW(hwnd, error, title, MB_ICONERROR | MB_OK);
3265 else if (is_oid_in_list(
3266 (HWND)GetWindowLongPtrW(hwnd, DWLP_USER), buf))
3268 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
3270 LoadStringW(hInstance, IDS_CERTIFICATE_PURPOSE_EXISTS, error,
3271 ARRAY_SIZE(error));
3272 LoadStringW(hInstance, IDS_CERTIFICATE_PROPERTIES, title, ARRAY_SIZE(title));
3273 MessageBoxW(hwnd, error, title, MB_ICONEXCLAMATION | MB_OK);
3275 else
3277 HWND parent = (HWND)GetWindowLongPtrW(hwnd, DWLP_USER);
3279 add_purpose(parent, buf);
3280 EndDialog(hwnd, wp);
3281 ret = TRUE;
3283 break;
3284 case IDCANCEL:
3285 EndDialog(hwnd, wp);
3286 ret = TRUE;
3287 break;
3289 break;
3291 break;
3293 return ret;
3296 static WCHAR *get_cert_property_as_string(PCCERT_CONTEXT cert, DWORD prop)
3298 WCHAR *name = NULL;
3299 DWORD cb;
3301 if (CertGetCertificateContextProperty(cert, prop, NULL, &cb))
3303 name = HeapAlloc(GetProcessHeap(), 0, cb);
3304 if (name)
3306 if (!CertGetCertificateContextProperty(cert, prop, name, &cb))
3308 HeapFree(GetProcessHeap(), 0, name);
3309 name = NULL;
3313 return name;
3316 static void redraw_states(HWND list, BOOL enabled)
3318 int items = SendMessageW(list, LVM_GETITEMCOUNT, 0, 0), i;
3320 for (i = 0; i < items; i++)
3322 BOOL change = FALSE;
3323 int state;
3325 state = SendMessageW(list, LVM_GETITEMSTATE, i, LVIS_STATEIMAGEMASK);
3326 /* This reverses the INDEXTOSTATEIMAGEMASK shift. There doesn't appear
3327 * to be a handy macro for it.
3329 state >>= 12;
3330 if (enabled)
3332 if (state == CheckBitmapIndexDisabledChecked)
3334 state = CheckBitmapIndexChecked;
3335 change = TRUE;
3337 if (state == CheckBitmapIndexDisabledUnchecked)
3339 state = CheckBitmapIndexUnchecked;
3340 change = TRUE;
3343 else
3345 if (state == CheckBitmapIndexChecked)
3347 state = CheckBitmapIndexDisabledChecked;
3348 change = TRUE;
3350 if (state == CheckBitmapIndexUnchecked)
3352 state = CheckBitmapIndexDisabledUnchecked;
3353 change = TRUE;
3356 if (change)
3358 LVITEMW item;
3360 item.state = INDEXTOSTATEIMAGEMASK(state);
3361 item.stateMask = LVIS_STATEIMAGEMASK;
3362 SendMessageW(list, LVM_SETITEMSTATE, i, (LPARAM)&item);
3367 typedef enum {
3368 PurposeEnableAll = 0,
3369 PurposeDisableAll,
3370 PurposeEnableSelected
3371 } PurposeSelection;
3373 static void select_purposes(HWND hwnd, PurposeSelection selection)
3375 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
3377 switch (selection)
3379 case PurposeEnableAll:
3380 case PurposeDisableAll:
3381 EnableWindow(lv, FALSE);
3382 redraw_states(lv, FALSE);
3383 EnableWindow(GetDlgItem(hwnd, IDC_ADD_PURPOSE), FALSE);
3384 break;
3385 case PurposeEnableSelected:
3386 EnableWindow(lv, TRUE);
3387 redraw_states(lv, TRUE);
3388 EnableWindow(GetDlgItem(hwnd, IDC_ADD_PURPOSE), TRUE);
3392 struct edit_cert_data
3394 PCCERT_CONTEXT cert;
3395 BOOL *pfPropertiesChanged;
3396 HIMAGELIST imageList;
3399 static void show_cert_usages(HWND hwnd, struct edit_cert_data *data)
3401 PCCERT_CONTEXT cert = data->cert;
3402 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
3403 PCERT_ENHKEY_USAGE usage;
3404 DWORD size;
3405 RECT rc;
3406 LVCOLUMNW column;
3407 PurposeSelection purposeSelection = PurposeEnableAll;
3409 GetWindowRect(lv, &rc);
3410 column.mask = LVCF_WIDTH;
3411 column.cx = rc.right - rc.left;
3412 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
3413 SendMessageW(lv, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)data->imageList);
3415 /* Get enhanced key usage. Have to check for a property and an extension
3416 * separately, because CertGetEnhancedKeyUsage will succeed and return an
3417 * empty usage if neither is set. Unfortunately an empty usage implies
3418 * no usage is allowed, so we have to distinguish between the two cases.
3420 if (CertGetEnhancedKeyUsage(cert, CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG,
3421 NULL, &size))
3423 usage = HeapAlloc(GetProcessHeap(), 0, size);
3424 if (!CertGetEnhancedKeyUsage(cert,
3425 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size))
3427 HeapFree(GetProcessHeap(), 0, usage);
3428 usage = NULL;
3430 else if (usage->cUsageIdentifier)
3431 purposeSelection = PurposeEnableSelected;
3432 else
3433 purposeSelection = PurposeDisableAll;
3435 else if (CertGetEnhancedKeyUsage(cert, CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
3436 NULL, &size))
3438 usage = HeapAlloc(GetProcessHeap(), 0, size);
3439 if (!CertGetEnhancedKeyUsage(cert,
3440 CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, usage, &size))
3442 HeapFree(GetProcessHeap(), 0, usage);
3443 usage = NULL;
3445 else if (usage->cUsageIdentifier)
3446 purposeSelection = PurposeEnableAll;
3447 else
3448 purposeSelection = PurposeDisableAll;
3450 else
3452 purposeSelection = PurposeEnableAll;
3453 usage = NULL;
3455 if (usage)
3457 DWORD i;
3459 for (i = 0; i < usage->cUsageIdentifier; i++)
3461 PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
3462 usage->rgpszUsageIdentifier[i], CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
3464 if (info)
3465 add_known_usage(lv, info, CheckBitmapIndexDisabledChecked);
3466 else
3467 add_purpose(hwnd, usage->rgpszUsageIdentifier[i]);
3469 HeapFree(GetProcessHeap(), 0, usage);
3471 else
3472 add_known_usages_to_list(lv, CheckBitmapIndexDisabledChecked);
3473 select_purposes(hwnd, purposeSelection);
3474 SendMessageW(GetDlgItem(hwnd, IDC_ENABLE_ALL_PURPOSES + purposeSelection),
3475 BM_CLICK, 0, 0);
3478 static void set_general_cert_properties(HWND hwnd, struct edit_cert_data *data)
3480 PCCERT_CONTEXT cert = data->cert;
3481 WCHAR *str;
3483 if ((str = get_cert_property_as_string(cert, CERT_FRIENDLY_NAME_PROP_ID)))
3485 SendMessageW(GetDlgItem(hwnd, IDC_FRIENDLY_NAME), WM_SETTEXT, 0,
3486 (LPARAM)str);
3487 HeapFree(GetProcessHeap(), 0, str);
3489 if ((str = get_cert_property_as_string(cert, CERT_DESCRIPTION_PROP_ID)))
3491 SendMessageW(GetDlgItem(hwnd, IDC_DESCRIPTION), WM_SETTEXT, 0,
3492 (LPARAM)str);
3493 HeapFree(GetProcessHeap(), 0, str);
3495 show_cert_usages(hwnd, data);
3498 static void set_cert_string_property(PCCERT_CONTEXT cert, DWORD prop,
3499 LPWSTR str)
3501 if (str && strlenW(str))
3503 CRYPT_DATA_BLOB blob;
3505 blob.pbData = (BYTE *)str;
3506 blob.cbData = (strlenW(str) + 1) * sizeof(WCHAR);
3507 CertSetCertificateContextProperty(cert, prop, 0, &blob);
3509 else
3510 CertSetCertificateContextProperty(cert, prop, 0, NULL);
3513 #define WM_REFRESH_VIEW WM_USER + 0
3515 static BOOL CALLBACK refresh_propsheet_pages(HWND hwnd, LPARAM lParam)
3517 if ((GetClassLongW(hwnd, GCW_ATOM) == WC_DIALOG))
3518 SendMessageW(hwnd, WM_REFRESH_VIEW, 0, 0);
3519 return TRUE;
3522 #define MAX_FRIENDLY_NAME 40
3523 #define MAX_DESCRIPTION 255
3525 static void apply_general_changes(HWND hwnd)
3527 WCHAR buf[MAX_DESCRIPTION + 1];
3528 struct edit_cert_data *data =
3529 (struct edit_cert_data *)GetWindowLongPtrW(hwnd, DWLP_USER);
3531 SendMessageW(GetDlgItem(hwnd, IDC_FRIENDLY_NAME), WM_GETTEXT, ARRAY_SIZE(buf), (LPARAM)buf);
3532 set_cert_string_property(data->cert, CERT_FRIENDLY_NAME_PROP_ID, buf);
3533 SendMessageW(GetDlgItem(hwnd, IDC_DESCRIPTION), WM_GETTEXT, ARRAY_SIZE(buf), (LPARAM)buf);
3534 set_cert_string_property(data->cert, CERT_DESCRIPTION_PROP_ID, buf);
3535 if (IsDlgButtonChecked(hwnd, IDC_ENABLE_ALL_PURPOSES))
3537 /* Setting a NULL usage removes the enhanced key usage property. */
3538 CertSetEnhancedKeyUsage(data->cert, NULL);
3540 else if (IsDlgButtonChecked(hwnd, IDC_DISABLE_ALL_PURPOSES))
3542 CERT_ENHKEY_USAGE usage = { 0, NULL };
3544 CertSetEnhancedKeyUsage(data->cert, &usage);
3546 else if (IsDlgButtonChecked(hwnd, IDC_ENABLE_SELECTED_PURPOSES))
3548 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
3549 CERT_ENHKEY_USAGE usage = { 0, NULL };
3550 int purposes = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0), i;
3551 LVITEMW item;
3553 item.mask = LVIF_STATE | LVIF_PARAM;
3554 item.iSubItem = 0;
3555 item.stateMask = LVIS_STATEIMAGEMASK;
3556 for (i = 0; i < purposes; i++)
3558 item.iItem = i;
3559 if (SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item))
3561 int state = item.state >> 12;
3563 if (state == CheckBitmapIndexChecked)
3565 CRYPT_OID_INFO *info = (CRYPT_OID_INFO *)item.lParam;
3567 if (usage.cUsageIdentifier)
3568 usage.rgpszUsageIdentifier =
3569 HeapReAlloc(GetProcessHeap(), 0,
3570 usage.rgpszUsageIdentifier,
3571 (usage.cUsageIdentifier + 1) * sizeof(LPSTR));
3572 else
3573 usage.rgpszUsageIdentifier =
3574 HeapAlloc(GetProcessHeap(), 0, sizeof(LPSTR));
3575 if (usage.rgpszUsageIdentifier)
3576 usage.rgpszUsageIdentifier[usage.cUsageIdentifier++] =
3577 (LPSTR)info->pszOID;
3581 CertSetEnhancedKeyUsage(data->cert, &usage);
3582 HeapFree(GetProcessHeap(), 0, usage.rgpszUsageIdentifier);
3584 EnumChildWindows(GetParent(GetParent(hwnd)), refresh_propsheet_pages, 0);
3585 if (data->pfPropertiesChanged)
3586 *data->pfPropertiesChanged = TRUE;
3589 static LRESULT CALLBACK cert_properties_general_dlg_proc(HWND hwnd, UINT msg,
3590 WPARAM wp, LPARAM lp)
3592 PROPSHEETPAGEW *page;
3594 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
3596 switch (msg)
3598 case WM_INITDIALOG:
3600 HWND description = GetDlgItem(hwnd, IDC_DESCRIPTION);
3601 struct detail_data *detailData;
3602 struct edit_cert_data *editData;
3604 page = (PROPSHEETPAGEW *)lp;
3605 detailData = (struct detail_data *)page->lParam;
3606 SendMessageW(GetDlgItem(hwnd, IDC_FRIENDLY_NAME), EM_SETLIMITTEXT,
3607 MAX_FRIENDLY_NAME, 0);
3608 SendMessageW(description, EM_SETLIMITTEXT, MAX_DESCRIPTION, 0);
3609 ShowScrollBar(description, SB_VERT, FALSE);
3610 editData = HeapAlloc(GetProcessHeap(), 0,
3611 sizeof(struct edit_cert_data));
3612 if (editData)
3614 editData->imageList = ImageList_Create(16, 16,
3615 ILC_COLOR4 | ILC_MASK, 4, 0);
3616 if (editData->imageList)
3618 HBITMAP bmp;
3619 COLORREF backColor = RGB(255, 0, 255);
3621 bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_CHECKS));
3622 ImageList_AddMasked(editData->imageList, bmp, backColor);
3623 DeleteObject(bmp);
3624 ImageList_SetBkColor(editData->imageList, CLR_NONE);
3626 editData->cert = detailData->pCertViewInfo->pCertContext;
3627 editData->pfPropertiesChanged = detailData->pfPropertiesChanged;
3628 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)editData);
3629 set_general_cert_properties(hwnd, editData);
3631 break;
3633 case WM_NOTIFY:
3635 NMHDR *hdr = (NMHDR *)lp;
3636 NMITEMACTIVATE *nm;
3638 switch (hdr->code)
3640 case NM_CLICK:
3641 nm = (NMITEMACTIVATE *)lp;
3642 toggle_usage(hwnd, nm->iItem);
3643 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
3644 break;
3645 case PSN_APPLY:
3646 apply_general_changes(hwnd);
3647 break;
3649 break;
3651 case WM_COMMAND:
3652 switch (HIWORD(wp))
3654 case EN_CHANGE:
3655 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
3656 if (LOWORD(wp) == IDC_DESCRIPTION)
3658 /* Show/hide scroll bar on description depending on how much
3659 * text it has.
3661 HWND description = GetDlgItem(hwnd, IDC_DESCRIPTION);
3662 int lines = SendMessageW(description, EM_GETLINECOUNT, 0, 0);
3664 ShowScrollBar(description, SB_VERT, lines > 1);
3666 break;
3667 case BN_CLICKED:
3668 switch (LOWORD(wp))
3670 case IDC_ADD_PURPOSE:
3671 if (DialogBoxParamW(hInstance,
3672 MAKEINTRESOURCEW(IDD_ADD_CERT_PURPOSE), hwnd,
3673 add_purpose_dlg_proc, (LPARAM)hwnd) == IDOK)
3674 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
3675 break;
3676 case IDC_ENABLE_ALL_PURPOSES:
3677 case IDC_DISABLE_ALL_PURPOSES:
3678 case IDC_ENABLE_SELECTED_PURPOSES:
3679 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
3680 select_purposes(hwnd, LOWORD(wp) - IDC_ENABLE_ALL_PURPOSES);
3681 break;
3683 break;
3685 break;
3687 return 0;
3690 static UINT CALLBACK cert_properties_general_callback(HWND hwnd, UINT msg,
3691 PROPSHEETPAGEW *page)
3693 HWND lv;
3694 int cItem, i;
3695 struct edit_cert_data *data;
3697 switch (msg)
3699 case PSPCB_RELEASE:
3700 lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
3701 cItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
3702 for (i = 0; i < cItem; i++)
3704 LVITEMW item;
3706 item.mask = LVIF_PARAM;
3707 item.iItem = i;
3708 item.iSubItem = 0;
3709 if (SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item) && item.lParam)
3711 PCRYPT_OID_INFO info = (PCRYPT_OID_INFO)item.lParam;
3713 if (info->cbSize == sizeof(CRYPT_OID_INFO) && !info->dwGroupId)
3715 HeapFree(GetProcessHeap(), 0, (LPSTR)info->pszOID);
3716 HeapFree(GetProcessHeap(), 0, info);
3720 data = (struct edit_cert_data *)GetWindowLongPtrW(hwnd, DWLP_USER);
3721 if (data)
3723 ImageList_Destroy(data->imageList);
3724 HeapFree(GetProcessHeap(), 0, data);
3726 break;
3728 return 1;
3731 static void show_edit_cert_properties_dialog(HWND parent,
3732 struct detail_data *data)
3734 PROPSHEETHEADERW hdr;
3735 PROPSHEETPAGEW page; /* FIXME: need to add a cross-certificate page */
3737 TRACE("(%p)\n", data);
3739 memset(&page, 0, sizeof(PROPSHEETPAGEW));
3740 page.dwSize = sizeof(page);
3741 page.dwFlags = PSP_USECALLBACK;
3742 page.pfnCallback = cert_properties_general_callback;
3743 page.hInstance = hInstance;
3744 page.u.pszTemplate = MAKEINTRESOURCEW(IDD_CERT_PROPERTIES_GENERAL);
3745 page.pfnDlgProc = cert_properties_general_dlg_proc;
3746 page.lParam = (LPARAM)data;
3748 memset(&hdr, 0, sizeof(hdr));
3749 hdr.dwSize = sizeof(hdr);
3750 hdr.hwndParent = parent;
3751 hdr.dwFlags = PSH_PROPSHEETPAGE;
3752 hdr.hInstance = hInstance;
3753 hdr.pszCaption = MAKEINTRESOURCEW(IDS_CERTIFICATE_PROPERTIES);
3754 hdr.u3.ppsp = &page;
3755 hdr.nPages = 1;
3756 PropertySheetW(&hdr);
3759 static void free_detail_fields(struct detail_data *data)
3761 int i;
3763 for (i = 0; i < data->cFields; i++)
3764 HeapFree(GetProcessHeap(), 0, data->fields[i].detailed_value);
3765 HeapFree(GetProcessHeap(), 0, data->fields);
3766 data->fields = NULL;
3767 data->cFields = 0;
3770 static void refresh_details_view(HWND hwnd)
3772 HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT);
3773 int curSel;
3774 struct detail_data *data;
3776 curSel = SendMessageW(cb, CB_GETCURSEL, 0, 0);
3777 /* Actually, any index will do, since they all store the same data value */
3778 data = (struct detail_data *)SendMessageW(cb, CB_GETITEMDATA, curSel, 0);
3779 free_detail_fields(data);
3780 set_fields_selection(hwnd, data, curSel);
3783 static LRESULT CALLBACK detail_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
3784 LPARAM lp)
3786 PROPSHEETPAGEW *page;
3787 struct detail_data *data;
3789 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
3791 switch (msg)
3793 case WM_INITDIALOG:
3794 page = (PROPSHEETPAGEW *)lp;
3795 data = (struct detail_data *)page->lParam;
3796 create_cert_details_list(hwnd, data);
3797 if (!(data->pCertViewInfo->dwFlags & CRYPTUI_ENABLE_EDITPROPERTIES))
3798 EnableWindow(GetDlgItem(hwnd, IDC_EDITPROPERTIES), FALSE);
3799 if (data->pCertViewInfo->dwFlags & CRYPTUI_DISABLE_EXPORT)
3800 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT), FALSE);
3801 break;
3802 case WM_NOTIFY:
3804 NMITEMACTIVATE *nm;
3805 HWND list = GetDlgItem(hwnd, IDC_DETAIL_LIST);
3807 nm = (NMITEMACTIVATE*)lp;
3808 if (nm->hdr.hwndFrom == list && nm->uNewState & LVN_ITEMACTIVATE
3809 && nm->hdr.code == LVN_ITEMCHANGED)
3811 data = (struct detail_data *)nm->lParam;
3812 if (nm->iItem >= 0 && data && nm->iItem < data->cFields)
3814 WCHAR buf[MAX_STRING_LEN], *val = NULL;
3815 HWND valueCtl = GetDlgItem(hwnd, IDC_DETAIL_VALUE);
3817 if (data->fields[nm->iItem].create)
3818 val = data->fields[nm->iItem].create(
3819 data->pCertViewInfo->pCertContext,
3820 data->fields[nm->iItem].param);
3821 else
3823 LVITEMW item;
3824 int res;
3826 item.cchTextMax = ARRAY_SIZE(buf);
3827 item.mask = LVIF_TEXT;
3828 item.pszText = buf;
3829 item.iItem = nm->iItem;
3830 item.iSubItem = 1;
3831 res = SendMessageW(list, LVM_GETITEMW, 0, (LPARAM)&item);
3832 if (res)
3833 val = buf;
3835 /* Select all the text in the control, the next update will
3836 * replace it
3838 SendMessageW(valueCtl, EM_SETSEL, 0, -1);
3839 add_unformatted_text_to_control(valueCtl, val,
3840 val ? strlenW(val) : 0);
3841 if (val != buf)
3842 HeapFree(GetProcessHeap(), 0, val);
3845 break;
3847 case WM_COMMAND:
3848 switch (wp)
3850 case IDC_EXPORT:
3852 HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT);
3853 CRYPTUI_WIZ_EXPORT_INFO info;
3855 data = (struct detail_data *)SendMessageW(cb, CB_GETITEMDATA, 0, 0);
3856 info.dwSize = sizeof(info);
3857 info.pwszExportFileName = NULL;
3858 info.dwSubjectChoice = CRYPTUI_WIZ_EXPORT_CERT_CONTEXT;
3859 info.u.pCertContext = data->pCertViewInfo->pCertContext;
3860 info.cStores = 0;
3861 CryptUIWizExport(0, hwnd, NULL, &info, NULL);
3862 break;
3864 case IDC_EDITPROPERTIES:
3866 HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT);
3867 int curSel;
3869 curSel = SendMessageW(cb, CB_GETCURSEL, 0, 0);
3870 /* Actually, any index will do, since they all store the same
3871 * data value
3873 data = (struct detail_data *)SendMessageW(cb, CB_GETITEMDATA,
3874 curSel, 0);
3875 show_edit_cert_properties_dialog(GetParent(hwnd), data);
3876 break;
3878 case ((CBN_SELCHANGE << 16) | IDC_DETAIL_SELECT):
3879 refresh_details_view(hwnd);
3880 break;
3882 break;
3883 case WM_REFRESH_VIEW:
3884 refresh_details_view(hwnd);
3885 break;
3887 return 0;
3890 static UINT CALLBACK detail_callback(HWND hwnd, UINT msg,
3891 PROPSHEETPAGEW *page)
3893 struct detail_data *data;
3895 switch (msg)
3897 case PSPCB_RELEASE:
3898 data = (struct detail_data *)page->lParam;
3899 free_detail_fields(data);
3900 HeapFree(GetProcessHeap(), 0, data);
3901 break;
3903 return 0;
3906 static BOOL init_detail_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
3907 BOOL *pfPropertiesChanged, PROPSHEETPAGEW *page)
3909 BOOL ret;
3910 struct detail_data *data = HeapAlloc(GetProcessHeap(), 0,
3911 sizeof(struct detail_data));
3913 if (data)
3915 data->pCertViewInfo = pCertViewInfo;
3916 data->pfPropertiesChanged = pfPropertiesChanged;
3917 data->cFields = 0;
3918 data->fields = NULL;
3919 memset(page, 0, sizeof(PROPSHEETPAGEW));
3920 page->dwSize = sizeof(PROPSHEETPAGEW);
3921 page->dwFlags = PSP_USECALLBACK;
3922 page->pfnCallback = detail_callback;
3923 page->hInstance = hInstance;
3924 page->u.pszTemplate = MAKEINTRESOURCEW(IDD_DETAIL);
3925 page->pfnDlgProc = detail_dlg_proc;
3926 page->lParam = (LPARAM)data;
3927 ret = TRUE;
3929 else
3930 ret = FALSE;
3931 return ret;
3934 struct hierarchy_data
3936 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo;
3937 HIMAGELIST imageList;
3938 DWORD selectedCert;
3941 static LPARAM index_to_lparam(struct hierarchy_data *data, DWORD index)
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);
3948 /* Takes advantage of the fact that a pointer is 32-bit aligned, and
3949 * therefore always even.
3951 if (index == provSigner->csCertChain - 1)
3952 return (LPARAM)data;
3953 return index << 1 | 1;
3956 static inline DWORD lparam_to_index(struct hierarchy_data *data, LPARAM lp)
3958 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
3959 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData,
3960 data->pCertViewInfo->idxSigner, data->pCertViewInfo->fCounterSigner,
3961 data->pCertViewInfo->idxCounterSigner);
3963 if (!(lp & 1))
3964 return provSigner->csCertChain - 1;
3965 return lp >> 1;
3968 static struct hierarchy_data *get_hierarchy_data_from_tree_item(HWND tree,
3969 HTREEITEM hItem)
3971 struct hierarchy_data *data = NULL;
3972 HTREEITEM root = NULL;
3974 do {
3975 HTREEITEM parent = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM,
3976 TVGN_PARENT, (LPARAM)hItem);
3978 if (!parent)
3979 root = hItem;
3980 hItem = parent;
3981 } while (hItem);
3982 if (root)
3984 TVITEMW item;
3986 item.mask = TVIF_PARAM;
3987 item.hItem = root;
3988 SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item);
3989 data = (struct hierarchy_data *)item.lParam;
3991 return data;
3994 static WCHAR *get_cert_display_name(PCCERT_CONTEXT cert)
3996 WCHAR *name = get_cert_property_as_string(cert, CERT_FRIENDLY_NAME_PROP_ID);
3998 if (!name)
3999 name = get_cert_name_string(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0);
4000 return name;
4003 static void show_cert_chain(HWND hwnd, struct hierarchy_data *data)
4005 HWND tree = GetDlgItem(hwnd, IDC_CERTPATH);
4006 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
4007 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData,
4008 data->pCertViewInfo->idxSigner, data->pCertViewInfo->fCounterSigner,
4009 data->pCertViewInfo->idxCounterSigner);
4010 DWORD i;
4011 HTREEITEM parent = NULL;
4013 SendMessageW(tree, TVM_SETIMAGELIST, TVSIL_NORMAL, (LPARAM)data->imageList);
4014 for (i = provSigner->csCertChain; i; i--)
4016 LPWSTR name;
4018 name = get_cert_display_name(provSigner->pasCertChain[i - 1].pCert);
4019 if (name)
4021 TVINSERTSTRUCTW tvis;
4023 tvis.hParent = parent;
4024 tvis.hInsertAfter = TVI_LAST;
4025 tvis.u.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_IMAGE |
4026 TVIF_SELECTEDIMAGE | TVIF_PARAM;
4027 tvis.u.item.pszText = name;
4028 tvis.u.item.state = TVIS_EXPANDED;
4029 tvis.u.item.stateMask = TVIS_EXPANDED;
4030 if (i == 1 && (!provSigner->pChainContext ||
4031 provSigner->pChainContext->TrustStatus.dwErrorStatus &
4032 CERT_TRUST_IS_PARTIAL_CHAIN))
4034 /* The root of the chain has a special case: if the chain is
4035 * a partial chain, the icon is a warning icon rather than an
4036 * error icon.
4038 tvis.u.item.iImage = 2;
4040 else if (provSigner->pasCertChain[i - 1].pChainElement->TrustStatus.
4041 dwErrorStatus == 0)
4042 tvis.u.item.iImage = 0;
4043 else
4044 tvis.u.item.iImage = 1;
4045 tvis.u.item.iSelectedImage = tvis.u.item.iImage;
4046 tvis.u.item.lParam = index_to_lparam(data, i - 1);
4047 parent = (HTREEITEM)SendMessageW(tree, TVM_INSERTITEMW, 0,
4048 (LPARAM)&tvis);
4049 HeapFree(GetProcessHeap(), 0, name);
4054 static void set_certificate_status(HWND hwnd, const CRYPT_PROVIDER_CERT *cert)
4056 /* Select all the text in the control, the next update will replace it */
4057 SendMessageW(hwnd, EM_SETSEL, 0, -1);
4058 /* Set the highest priority error messages first. */
4059 if (!(cert->dwConfidence & CERT_CONFIDENCE_SIG))
4060 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_BAD_SIGNATURE);
4061 else if (!(cert->dwConfidence & CERT_CONFIDENCE_TIME))
4062 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_BAD_TIME);
4063 else if (!(cert->dwConfidence & CERT_CONFIDENCE_TIMENEST))
4064 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_BAD_TIMENEST);
4065 else if (cert->dwRevokedReason)
4066 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_REVOKED);
4067 else
4068 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_VALID);
4071 static void set_certificate_status_for_end_cert(HWND hwnd,
4072 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
4074 HWND status = GetDlgItem(hwnd, IDC_CERTIFICATESTATUSTEXT);
4075 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
4076 (CRYPT_PROVIDER_DATA *)pCertViewInfo->u.pCryptProviderData,
4077 pCertViewInfo->idxSigner, pCertViewInfo->fCounterSigner,
4078 pCertViewInfo->idxCounterSigner);
4079 CRYPT_PROVIDER_CERT *provCert = WTHelperGetProvCertFromChain(provSigner,
4080 pCertViewInfo->idxCert);
4082 set_certificate_status(status, provCert);
4085 static void show_cert_hierarchy(HWND hwnd, struct hierarchy_data *data)
4087 /* Disable view certificate button until a certificate is selected */
4088 EnableWindow(GetDlgItem(hwnd, IDC_VIEWCERTIFICATE), FALSE);
4089 show_cert_chain(hwnd, data);
4090 set_certificate_status_for_end_cert(hwnd, data->pCertViewInfo);
4093 static void show_dialog_for_selected_cert(HWND hwnd)
4095 HWND tree = GetDlgItem(hwnd, IDC_CERTPATH);
4096 TVITEMW item;
4097 struct hierarchy_data *data;
4098 DWORD selection;
4100 memset(&item, 0, sizeof(item));
4101 item.mask = TVIF_HANDLE | TVIF_PARAM;
4102 item.hItem = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM, TVGN_CARET, 0);
4103 SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item);
4104 data = get_hierarchy_data_from_tree_item(tree, item.hItem);
4105 selection = lparam_to_index(data, item.lParam);
4106 if (selection != 0)
4108 CRYPT_PROVIDER_SGNR *provSigner;
4109 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
4110 BOOL changed = FALSE;
4112 provSigner = WTHelperGetProvSignerFromChain(
4113 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData,
4114 data->pCertViewInfo->idxSigner,
4115 data->pCertViewInfo->fCounterSigner,
4116 data->pCertViewInfo->idxCounterSigner);
4117 memset(&viewInfo, 0, sizeof(viewInfo));
4118 viewInfo.dwSize = sizeof(viewInfo);
4119 viewInfo.dwFlags = data->pCertViewInfo->dwFlags;
4120 viewInfo.szTitle = data->pCertViewInfo->szTitle;
4121 viewInfo.pCertContext = provSigner->pasCertChain[selection].pCert;
4122 viewInfo.cStores = data->pCertViewInfo->cStores;
4123 viewInfo.rghStores = data->pCertViewInfo->rghStores;
4124 viewInfo.cPropSheetPages = data->pCertViewInfo->cPropSheetPages;
4125 viewInfo.rgPropSheetPages = data->pCertViewInfo->rgPropSheetPages;
4126 viewInfo.nStartPage = data->pCertViewInfo->nStartPage;
4127 CryptUIDlgViewCertificateW(&viewInfo, &changed);
4128 if (changed)
4130 /* Delete the contents of the tree */
4131 SendMessageW(tree, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT);
4132 /* Reinitialize the tree */
4133 show_cert_hierarchy(hwnd, data);
4138 static LRESULT CALLBACK hierarchy_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
4139 LPARAM lp)
4141 PROPSHEETPAGEW *page;
4142 struct hierarchy_data *data;
4143 LRESULT ret = 0;
4144 HWND tree = GetDlgItem(hwnd, IDC_CERTPATH);
4146 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
4148 switch (msg)
4150 case WM_INITDIALOG:
4151 page = (PROPSHEETPAGEW *)lp;
4152 data = (struct hierarchy_data *)page->lParam;
4153 show_cert_hierarchy(hwnd, data);
4154 break;
4155 case WM_NOTIFY:
4157 NMHDR *hdr;
4159 hdr = (NMHDR *)lp;
4160 switch (hdr->code)
4162 case TVN_SELCHANGEDW:
4164 NMTREEVIEWW *nm = (NMTREEVIEWW*)lp;
4165 DWORD selection;
4166 CRYPT_PROVIDER_SGNR *provSigner;
4168 data = get_hierarchy_data_from_tree_item(tree, nm->itemNew.hItem);
4169 selection = lparam_to_index(data, nm->itemNew.lParam);
4170 provSigner = WTHelperGetProvSignerFromChain(
4171 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData,
4172 data->pCertViewInfo->idxSigner,
4173 data->pCertViewInfo->fCounterSigner,
4174 data->pCertViewInfo->idxCounterSigner);
4175 EnableWindow(GetDlgItem(hwnd, IDC_VIEWCERTIFICATE), selection != 0);
4176 set_certificate_status(GetDlgItem(hwnd, IDC_CERTIFICATESTATUSTEXT),
4177 &provSigner->pasCertChain[selection]);
4178 break;
4180 case NM_DBLCLK:
4181 show_dialog_for_selected_cert(hwnd);
4182 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
4183 ret = 1;
4184 break;
4186 break;
4188 case WM_COMMAND:
4189 switch (wp)
4191 case IDC_VIEWCERTIFICATE:
4192 show_dialog_for_selected_cert(hwnd);
4193 break;
4195 break;
4196 case WM_REFRESH_VIEW:
4198 TVITEMW item;
4200 /* Get hierarchy data */
4201 memset(&item, 0, sizeof(item));
4202 item.mask = TVIF_HANDLE | TVIF_PARAM;
4203 item.hItem = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM, TVGN_ROOT,
4205 data = get_hierarchy_data_from_tree_item(tree, item.hItem);
4206 /* Delete the contents of the tree */
4207 SendMessageW(tree, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT);
4208 /* Reinitialize the tree */
4209 show_cert_hierarchy(hwnd, data);
4210 break;
4213 return ret;
4216 static UINT CALLBACK hierarchy_callback(HWND hwnd, UINT msg,
4217 PROPSHEETPAGEW *page)
4219 struct hierarchy_data *data;
4221 switch (msg)
4223 case PSPCB_RELEASE:
4224 data = (struct hierarchy_data *)page->lParam;
4225 ImageList_Destroy(data->imageList);
4226 HeapFree(GetProcessHeap(), 0, data);
4227 break;
4229 return 0;
4232 static BOOL init_hierarchy_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
4233 PROPSHEETPAGEW *page)
4235 struct hierarchy_data *data = HeapAlloc(GetProcessHeap(), 0,
4236 sizeof(struct hierarchy_data));
4237 BOOL ret = FALSE;
4239 if (data)
4241 data->imageList = ImageList_Create(16, 16, ILC_COLOR4 | ILC_MASK, 2, 0);
4242 if (data->imageList)
4244 HBITMAP bmp;
4245 COLORREF backColor = RGB(255, 0, 255);
4247 data->pCertViewInfo = pCertViewInfo;
4248 data->selectedCert = 0xffffffff;
4250 bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_SMALL_ICONS));
4251 ImageList_AddMasked(data->imageList, bmp, backColor);
4252 DeleteObject(bmp);
4253 ImageList_SetBkColor(data->imageList, CLR_NONE);
4255 memset(page, 0, sizeof(PROPSHEETPAGEW));
4256 page->dwSize = sizeof(PROPSHEETPAGEW);
4257 page->dwFlags = PSP_USECALLBACK;
4258 page->hInstance = hInstance;
4259 page->u.pszTemplate = MAKEINTRESOURCEW(IDD_HIERARCHY);
4260 page->pfnDlgProc = hierarchy_dlg_proc;
4261 page->lParam = (LPARAM)data;
4262 page->pfnCallback = hierarchy_callback;
4263 ret = TRUE;
4265 else
4266 HeapFree(GetProcessHeap(), 0, data);
4268 return ret;
4271 static int CALLBACK cert_prop_sheet_proc(HWND hwnd, UINT msg, LPARAM lp)
4273 RECT rc;
4275 TRACE("(%p, %08x, %08lx)\n", hwnd, msg, lp);
4277 switch (msg)
4279 case PSCB_INITIALIZED:
4280 /* Get cancel button's position.. */
4281 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rc);
4282 MapWindowPoints( 0, hwnd, (POINT *)&rc, 2 );
4283 /* hide the cancel button.. */
4284 ShowWindow(GetDlgItem(hwnd, IDCANCEL), FALSE);
4285 /* and move the OK button to the cancel button's original position. */
4286 SetWindowPos(GetDlgItem(hwnd, IDOK), 0, rc.left, rc.top, 0, 0,
4287 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW );
4288 break;
4290 return 0;
4293 static BOOL show_cert_dialog(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
4294 CRYPT_PROVIDER_CERT *provCert, BOOL *pfPropertiesChanged)
4296 static const WCHAR riched[] = { 'r','i','c','h','e','d','2','0',0 };
4297 DWORD nPages;
4298 PROPSHEETPAGEW *pages;
4299 BOOL ret = FALSE;
4300 HMODULE lib = LoadLibraryW(riched);
4302 nPages = pCertViewInfo->cPropSheetPages + 1; /* one for the General tab */
4303 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_DETAILPAGE))
4304 nPages++;
4305 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_HIERARCHYPAGE))
4306 nPages++;
4307 pages = HeapAlloc(GetProcessHeap(), 0, nPages * sizeof(PROPSHEETPAGEW));
4308 if (pages)
4310 PROPSHEETHEADERW hdr;
4311 CRYPTUI_INITDIALOG_STRUCT *init = NULL;
4312 DWORD i;
4314 memset(&hdr, 0, sizeof(hdr));
4315 hdr.dwSize = sizeof(hdr);
4316 hdr.dwFlags = PSH_NOAPPLYNOW | PSH_PROPSHEETPAGE | PSH_USECALLBACK;
4317 hdr.hInstance = hInstance;
4318 if (pCertViewInfo->szTitle)
4319 hdr.pszCaption = pCertViewInfo->szTitle;
4320 else
4321 hdr.pszCaption = MAKEINTRESOURCEW(IDS_CERTIFICATE);
4322 init_general_page(pCertViewInfo, &pages[hdr.nPages++]);
4323 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_DETAILPAGE))
4325 if (init_detail_page(pCertViewInfo, pfPropertiesChanged,
4326 &pages[hdr.nPages]))
4327 hdr.nPages++;
4329 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_HIERARCHYPAGE))
4331 if (init_hierarchy_page(pCertViewInfo, &pages[hdr.nPages]))
4332 hdr.nPages++;
4334 /* Copy each additional page, and create the init dialog struct for it
4336 if (pCertViewInfo->cPropSheetPages)
4338 init = HeapAlloc(GetProcessHeap(), 0,
4339 pCertViewInfo->cPropSheetPages *
4340 sizeof(CRYPTUI_INITDIALOG_STRUCT));
4341 if (init)
4343 for (i = 0; i < pCertViewInfo->cPropSheetPages; i++)
4345 memcpy(&pages[hdr.nPages + i],
4346 &pCertViewInfo->rgPropSheetPages[i],
4347 sizeof(PROPSHEETPAGEW));
4348 init[i].lParam = pCertViewInfo->rgPropSheetPages[i].lParam;
4349 init[i].pCertContext = pCertViewInfo->pCertContext;
4350 pages[hdr.nPages + i].lParam = (LPARAM)&init[i];
4352 if (pCertViewInfo->nStartPage & 0x8000)
4354 /* Start page index is relative to the number of default
4355 * pages
4357 hdr.u2.nStartPage = pCertViewInfo->nStartPage + hdr.nPages;
4359 else
4360 hdr.u2.nStartPage = pCertViewInfo->nStartPage;
4361 hdr.nPages = nPages;
4362 ret = TRUE;
4364 else
4365 SetLastError(ERROR_OUTOFMEMORY);
4367 else
4369 /* Ignore the relative flag if there aren't any additional pages */
4370 hdr.u2.nStartPage = pCertViewInfo->nStartPage & 0x7fff;
4371 ret = TRUE;
4373 if (ret)
4375 INT_PTR l;
4377 hdr.u3.ppsp = pages;
4378 hdr.pfnCallback = cert_prop_sheet_proc;
4379 l = PropertySheetW(&hdr);
4380 if (l == 0)
4382 SetLastError(ERROR_CANCELLED);
4383 ret = FALSE;
4386 HeapFree(GetProcessHeap(), 0, init);
4387 HeapFree(GetProcessHeap(), 0, pages);
4389 else
4390 SetLastError(ERROR_OUTOFMEMORY);
4391 FreeLibrary(lib);
4392 return ret;
4395 /***********************************************************************
4396 * CryptUIDlgViewCertificateW (CRYPTUI.@)
4398 BOOL WINAPI CryptUIDlgViewCertificateW(
4399 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo, BOOL *pfPropertiesChanged)
4401 static GUID generic_cert_verify = WINTRUST_ACTION_GENERIC_CERT_VERIFY;
4402 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
4403 WINTRUST_DATA wvt;
4404 WINTRUST_CERT_INFO cert;
4405 BOOL ret = FALSE;
4406 CRYPT_PROVIDER_SGNR *signer;
4407 CRYPT_PROVIDER_CERT *provCert = NULL;
4409 TRACE("(%p, %p)\n", pCertViewInfo, pfPropertiesChanged);
4411 if (pCertViewInfo->dwSize != sizeof(CRYPTUI_VIEWCERTIFICATE_STRUCTW))
4413 SetLastError(ERROR_INVALID_PARAMETER);
4414 return FALSE;
4416 /* Make a local copy in case we have to call WinVerifyTrust ourselves */
4417 memcpy(&viewInfo, pCertViewInfo, sizeof(viewInfo));
4418 if (!pCertViewInfo->u.hWVTStateData)
4420 memset(&wvt, 0, sizeof(wvt));
4421 wvt.cbStruct = sizeof(wvt);
4422 wvt.dwUIChoice = WTD_UI_NONE;
4423 if (viewInfo.dwFlags &
4424 CRYPTUI_ENABLE_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT)
4425 wvt.fdwRevocationChecks |= WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
4426 if (viewInfo.dwFlags & CRYPTUI_ENABLE_REVOCATION_CHECK_END_CERT)
4427 wvt.fdwRevocationChecks |= WTD_REVOCATION_CHECK_END_CERT;
4428 if (viewInfo.dwFlags & CRYPTUI_ENABLE_REVOCATION_CHECK_CHAIN)
4429 wvt.fdwRevocationChecks |= WTD_REVOCATION_CHECK_CHAIN;
4430 wvt.dwUnionChoice = WTD_CHOICE_CERT;
4431 memset(&cert, 0, sizeof(cert));
4432 cert.cbStruct = sizeof(cert);
4433 cert.psCertContext = (CERT_CONTEXT *)viewInfo.pCertContext;
4434 cert.chStores = viewInfo.cStores;
4435 cert.pahStores = viewInfo.rghStores;
4436 wvt.u.pCert = &cert;
4437 wvt.dwStateAction = WTD_STATEACTION_VERIFY;
4438 WinVerifyTrust(NULL, &generic_cert_verify, &wvt);
4439 viewInfo.u.pCryptProviderData =
4440 WTHelperProvDataFromStateData(wvt.hWVTStateData);
4441 signer = WTHelperGetProvSignerFromChain(
4442 (CRYPT_PROVIDER_DATA *)viewInfo.u.pCryptProviderData, 0, FALSE, 0);
4443 provCert = WTHelperGetProvCertFromChain(signer, 0);
4444 ret = TRUE;
4446 else
4448 viewInfo.u.pCryptProviderData =
4449 WTHelperProvDataFromStateData(viewInfo.u.hWVTStateData);
4450 signer = WTHelperGetProvSignerFromChain(
4451 (CRYPT_PROVIDER_DATA *)viewInfo.u.pCryptProviderData,
4452 viewInfo.idxSigner, viewInfo.fCounterSigner,
4453 viewInfo.idxCounterSigner);
4454 provCert = WTHelperGetProvCertFromChain(signer, viewInfo.idxCert);
4455 ret = TRUE;
4457 if (ret)
4459 ret = show_cert_dialog(&viewInfo, provCert, pfPropertiesChanged);
4460 if (!pCertViewInfo->u.hWVTStateData)
4462 wvt.dwStateAction = WTD_STATEACTION_CLOSE;
4463 WinVerifyTrust(NULL, &generic_cert_verify, &wvt);
4466 return ret;
4469 /***********************************************************************
4470 * CryptUIDlgViewContext (CRYPTUI.@)
4472 BOOL WINAPI CryptUIDlgViewContext(DWORD dwContextType, LPVOID pvContext,
4473 HWND hwnd, LPCWSTR pwszTitle, DWORD dwFlags, LPVOID pvReserved)
4475 BOOL ret;
4477 TRACE("(%d, %p, %p, %s, %08x, %p)\n", dwContextType, pvContext, hwnd,
4478 debugstr_w(pwszTitle), dwFlags, pvReserved);
4480 switch (dwContextType)
4482 case CERT_STORE_CERTIFICATE_CONTEXT:
4484 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
4486 memset(&viewInfo, 0, sizeof(viewInfo));
4487 viewInfo.dwSize = sizeof(viewInfo);
4488 viewInfo.hwndParent = hwnd;
4489 viewInfo.szTitle = pwszTitle;
4490 viewInfo.pCertContext = pvContext;
4491 ret = CryptUIDlgViewCertificateW(&viewInfo, NULL);
4492 break;
4494 default:
4495 FIXME("unimplemented for context type %d\n", dwContextType);
4496 SetLastError(E_INVALIDARG);
4497 ret = FALSE;
4499 return ret;
4502 /* Decodes a cert's basic constraints extension (either szOID_BASIC_CONSTRAINTS
4503 * or szOID_BASIC_CONSTRAINTS2, whichever is present) to determine if it
4504 * should be a CA. If neither extension is present, returns
4505 * defaultIfNotSpecified.
4507 static BOOL is_ca_cert(PCCERT_CONTEXT cert, BOOL defaultIfNotSpecified)
4509 BOOL isCA = defaultIfNotSpecified;
4510 PCERT_EXTENSION ext = CertFindExtension(szOID_BASIC_CONSTRAINTS,
4511 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
4513 if (ext)
4515 CERT_BASIC_CONSTRAINTS_INFO *info;
4516 DWORD size = 0;
4518 if (CryptDecodeObjectEx(X509_ASN_ENCODING, szOID_BASIC_CONSTRAINTS,
4519 ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG,
4520 NULL, &info, &size))
4522 if (info->SubjectType.cbData == 1)
4523 isCA = info->SubjectType.pbData[0] & CERT_CA_SUBJECT_FLAG;
4524 LocalFree(info);
4527 else
4529 ext = CertFindExtension(szOID_BASIC_CONSTRAINTS2,
4530 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
4531 if (ext)
4533 CERT_BASIC_CONSTRAINTS2_INFO info;
4534 DWORD size = sizeof(CERT_BASIC_CONSTRAINTS2_INFO);
4536 if (CryptDecodeObjectEx(X509_ASN_ENCODING,
4537 szOID_BASIC_CONSTRAINTS2, ext->Value.pbData, ext->Value.cbData,
4538 0, NULL, &info, &size))
4539 isCA = info.fCA;
4542 return isCA;
4545 static HCERTSTORE choose_store_for_cert(PCCERT_CONTEXT cert)
4547 LPCWSTR storeName;
4549 if (is_ca_cert(cert, TRUE))
4550 storeName = ca;
4551 else
4552 storeName = addressBook;
4553 return CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0,
4554 CERT_SYSTEM_STORE_CURRENT_USER, storeName);
4557 static BOOL import_cert(PCCERT_CONTEXT cert, HCERTSTORE hDestCertStore)
4559 HCERTSTORE store;
4560 BOOL ret;
4562 if (!cert)
4564 SetLastError(E_INVALIDARG);
4565 return FALSE;
4567 if (hDestCertStore) store = hDestCertStore;
4568 else
4570 if (!(store = choose_store_for_cert(cert)))
4572 WARN("unable to open certificate store\n");
4573 return FALSE;
4576 ret = CertAddCertificateContextToStore(store, cert,
4577 CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES, NULL);
4578 if (!hDestCertStore) CertCloseStore(store, 0);
4579 return ret;
4582 static BOOL import_crl(PCCRL_CONTEXT crl, HCERTSTORE hDestCertStore)
4584 HCERTSTORE store;
4585 BOOL ret;
4587 if (!crl)
4589 SetLastError(E_INVALIDARG);
4590 return FALSE;
4592 if (hDestCertStore) store = hDestCertStore;
4593 else
4595 if (!(store = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0,
4596 CERT_SYSTEM_STORE_CURRENT_USER, ca)))
4598 WARN("unable to open certificate store\n");
4599 return FALSE;
4602 ret = CertAddCRLContextToStore(store, crl,
4603 CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES, NULL);
4604 if (!hDestCertStore) CertCloseStore(store, 0);
4605 return ret;
4608 static BOOL import_ctl(PCCTL_CONTEXT ctl, HCERTSTORE hDestCertStore)
4610 HCERTSTORE store;
4611 BOOL ret;
4613 if (!ctl)
4615 SetLastError(E_INVALIDARG);
4616 return FALSE;
4618 if (hDestCertStore) store = hDestCertStore;
4619 else
4621 static const WCHAR trust[] = { 'T','r','u','s','t',0 };
4623 if (!(store = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0,
4624 CERT_SYSTEM_STORE_CURRENT_USER, trust)))
4626 WARN("unable to open certificate store\n");
4627 return FALSE;
4630 ret = CertAddCTLContextToStore(store, ctl,
4631 CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES, NULL);
4632 if (!hDestCertStore) CertCloseStore(store, 0);
4633 return ret;
4636 /* Checks type, a type such as CERT_QUERY_CONTENT_CERT returned by
4637 * CryptQueryObject, against the allowed types. Returns TRUE if the
4638 * type is allowed, FALSE otherwise.
4640 static BOOL check_context_type(DWORD dwFlags, DWORD type)
4642 BOOL ret;
4644 if (dwFlags &
4645 (CRYPTUI_WIZ_IMPORT_ALLOW_CERT | CRYPTUI_WIZ_IMPORT_ALLOW_CRL |
4646 CRYPTUI_WIZ_IMPORT_ALLOW_CTL))
4648 switch (type)
4650 case CERT_QUERY_CONTENT_CERT:
4651 case CERT_QUERY_CONTENT_SERIALIZED_CERT:
4652 ret = dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CERT;
4653 break;
4654 case CERT_QUERY_CONTENT_CRL:
4655 case CERT_QUERY_CONTENT_SERIALIZED_CRL:
4656 ret = dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CRL;
4657 break;
4658 case CERT_QUERY_CONTENT_CTL:
4659 case CERT_QUERY_CONTENT_SERIALIZED_CTL:
4660 ret = dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CTL;
4661 break;
4662 default:
4663 /* The remaining types contain more than one type, so allow
4664 * any combination.
4666 ret = TRUE;
4669 else
4671 /* No allowed types specified, so any type is allowed */
4672 ret = TRUE;
4674 if (!ret)
4675 SetLastError(E_INVALIDARG);
4676 return ret;
4680 static void import_warning(DWORD dwFlags, HWND hwnd, LPCWSTR szTitle,
4681 int warningID)
4683 if (!(dwFlags & CRYPTUI_WIZ_NO_UI))
4685 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
4686 LPCWSTR pTitle;
4688 if (szTitle)
4689 pTitle = szTitle;
4690 else
4692 LoadStringW(hInstance, IDS_IMPORT_WIZARD, title, ARRAY_SIZE(title));
4693 pTitle = title;
4695 LoadStringW(hInstance, warningID, error, ARRAY_SIZE(error));
4696 MessageBoxW(hwnd, error, pTitle, MB_ICONERROR | MB_OK);
4700 static void import_warn_type_mismatch(DWORD dwFlags, HWND hwnd, LPCWSTR szTitle)
4702 import_warning(dwFlags, hwnd, szTitle, IDS_IMPORT_TYPE_MISMATCH);
4705 static BOOL check_store_context_type(DWORD dwFlags, HCERTSTORE store)
4707 BOOL ret;
4709 if (dwFlags &
4710 (CRYPTUI_WIZ_IMPORT_ALLOW_CERT | CRYPTUI_WIZ_IMPORT_ALLOW_CRL |
4711 CRYPTUI_WIZ_IMPORT_ALLOW_CTL))
4713 PCCERT_CONTEXT cert;
4714 PCCRL_CONTEXT crl;
4715 PCCTL_CONTEXT ctl;
4717 ret = TRUE;
4718 if ((cert = CertEnumCertificatesInStore(store, NULL)))
4720 CertFreeCertificateContext(cert);
4721 if (!(dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CERT))
4722 ret = FALSE;
4724 if (ret && (crl = CertEnumCRLsInStore(store, NULL)))
4726 CertFreeCRLContext(crl);
4727 if (!(dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CRL))
4728 ret = FALSE;
4730 if (ret && (ctl = CertEnumCTLsInStore(store, NULL)))
4732 CertFreeCTLContext(ctl);
4733 if (!(dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CTL))
4734 ret = FALSE;
4737 else
4738 ret = TRUE;
4739 if (!ret)
4740 SetLastError(E_INVALIDARG);
4741 return ret;
4744 static BOOL import_store(DWORD dwFlags, HWND hwnd, LPCWSTR szTitle,
4745 HCERTSTORE source, HCERTSTORE dest)
4747 BOOL ret;
4749 if ((ret = check_store_context_type(dwFlags, source)))
4751 PCCERT_CONTEXT cert = NULL;
4752 PCCRL_CONTEXT crl = NULL;
4753 PCCTL_CONTEXT ctl = NULL;
4755 do {
4756 cert = CertEnumCertificatesInStore(source, cert);
4757 if (cert)
4758 ret = import_cert(cert, dest);
4759 } while (ret && cert);
4760 do {
4761 crl = CertEnumCRLsInStore(source, crl);
4762 if (crl)
4763 ret = import_crl(crl, dest);
4764 } while (ret && crl);
4765 do {
4766 ctl = CertEnumCTLsInStore(source, ctl);
4767 if (ctl)
4768 ret = import_ctl(ctl, dest);
4769 } while (ret && ctl);
4771 else
4772 import_warn_type_mismatch(dwFlags, hwnd, szTitle);
4773 return ret;
4776 static HCERTSTORE open_store_from_file(DWORD dwFlags, LPCWSTR fileName,
4777 DWORD *pContentType)
4779 HCERTSTORE store = NULL;
4780 DWORD contentType = 0, expectedContentTypeFlags;
4782 if (dwFlags &
4783 (CRYPTUI_WIZ_IMPORT_ALLOW_CERT | CRYPTUI_WIZ_IMPORT_ALLOW_CRL |
4784 CRYPTUI_WIZ_IMPORT_ALLOW_CTL))
4786 expectedContentTypeFlags =
4787 CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE |
4788 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED |
4789 CERT_QUERY_CONTENT_FLAG_PFX;
4790 if (dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CERT)
4791 expectedContentTypeFlags |=
4792 CERT_QUERY_CONTENT_FLAG_CERT |
4793 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT;
4794 if (dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CRL)
4795 expectedContentTypeFlags |=
4796 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL |
4797 CERT_QUERY_CONTENT_FLAG_CRL;
4798 if (dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CTL)
4799 expectedContentTypeFlags |=
4800 CERT_QUERY_CONTENT_FLAG_CTL |
4801 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL;
4803 else
4804 expectedContentTypeFlags =
4805 CERT_QUERY_CONTENT_FLAG_CERT |
4806 CERT_QUERY_CONTENT_FLAG_CTL |
4807 CERT_QUERY_CONTENT_FLAG_CRL |
4808 CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE |
4809 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT |
4810 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL |
4811 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL |
4812 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED |
4813 CERT_QUERY_CONTENT_FLAG_PFX;
4815 CryptQueryObject(CERT_QUERY_OBJECT_FILE, fileName,
4816 expectedContentTypeFlags, CERT_QUERY_FORMAT_FLAG_ALL, 0, NULL,
4817 &contentType, NULL, &store, NULL, NULL);
4818 if (pContentType)
4819 *pContentType = contentType;
4820 return store;
4823 static BOOL import_file(DWORD dwFlags, HWND hwnd, LPCWSTR szTitle,
4824 LPCWSTR fileName, HCERTSTORE dest)
4826 HCERTSTORE source;
4827 BOOL ret;
4829 if ((source = open_store_from_file(dwFlags, fileName, NULL)))
4831 ret = import_store(dwFlags, hwnd, szTitle, source, dest);
4832 CertCloseStore(source, 0);
4834 else
4835 ret = FALSE;
4836 return ret;
4839 struct ImportWizData
4841 HFONT titleFont;
4842 DWORD dwFlags;
4843 LPCWSTR pwszWizardTitle;
4844 CRYPTUI_WIZ_IMPORT_SRC_INFO importSrc;
4845 LPWSTR fileName;
4846 DWORD contentType;
4847 BOOL freeSource;
4848 HCERTSTORE hDestCertStore;
4849 BOOL freeDest;
4850 BOOL autoDest;
4851 BOOL success;
4854 static LRESULT CALLBACK import_welcome_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
4855 LPARAM lp)
4857 LRESULT ret = 0;
4859 switch (msg)
4861 case WM_INITDIALOG:
4863 struct ImportWizData *data;
4864 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
4865 WCHAR fontFace[MAX_STRING_LEN];
4866 HDC hDC = GetDC(hwnd);
4867 int height;
4869 data = (struct ImportWizData *)page->lParam;
4870 LoadStringW(hInstance, IDS_WIZARD_TITLE_FONT, fontFace, ARRAY_SIZE(fontFace));
4871 height = -MulDiv(12, GetDeviceCaps(hDC, LOGPIXELSY), 72);
4872 data->titleFont = CreateFontW(height, 0, 0, 0, FW_BOLD, 0, 0, 0,
4873 DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
4874 DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, fontFace);
4875 SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_TITLE), WM_SETFONT,
4876 (WPARAM)data->titleFont, TRUE);
4877 ReleaseDC(hwnd, hDC);
4878 break;
4880 case WM_NOTIFY:
4882 NMHDR *hdr = (NMHDR *)lp;
4884 switch (hdr->code)
4886 case PSN_SETACTIVE:
4887 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0, PSWIZB_NEXT);
4888 ret = TRUE;
4889 break;
4891 break;
4894 return ret;
4897 static const WCHAR filter_cert[] = { '*','.','c','e','r',';','*','.',
4898 'c','r','t',0 };
4899 static const WCHAR filter_pfx[] = { '*','.','p','f','x',';','*','.',
4900 'p','1','2',0 };
4901 static const WCHAR filter_crl[] = { '*','.','c','r','l',0 };
4902 static const WCHAR filter_ctl[] = { '*','.','s','t','l',0 };
4903 static const WCHAR filter_serialized_store[] = { '*','.','s','s','t',0 };
4904 static const WCHAR filter_cms[] = { '*','.','s','p','c',';','*','.',
4905 'p','7','b',0 };
4906 static const WCHAR filter_all[] = { '*','.','*',0 };
4908 static struct StringToFilter
4910 int id;
4911 DWORD allowFlags;
4912 LPCWSTR filter;
4913 } import_filters[] = {
4914 { IDS_IMPORT_FILTER_CERT, CRYPTUI_WIZ_IMPORT_ALLOW_CERT, filter_cert },
4915 { IDS_IMPORT_FILTER_PFX, 0, filter_pfx },
4916 { IDS_IMPORT_FILTER_CRL, CRYPTUI_WIZ_IMPORT_ALLOW_CRL, filter_crl },
4917 { IDS_IMPORT_FILTER_CTL, CRYPTUI_WIZ_IMPORT_ALLOW_CTL, filter_ctl },
4918 { IDS_IMPORT_FILTER_SERIALIZED_STORE, 0, filter_serialized_store },
4919 { IDS_IMPORT_FILTER_CMS, 0, filter_cms },
4920 { IDS_IMPORT_FILTER_ALL, 0, filter_all },
4923 static WCHAR *make_import_file_filter(DWORD dwFlags)
4925 DWORD i;
4926 int len, totalLen = 2;
4927 LPWSTR filter = NULL, str;
4929 for (i = 0; i < ARRAY_SIZE(import_filters); i++)
4931 if (!import_filters[i].allowFlags || !dwFlags ||
4932 (dwFlags & import_filters[i].allowFlags))
4934 len = LoadStringW(hInstance, import_filters[i].id, (LPWSTR)&str, 0);
4935 totalLen += len + strlenW(import_filters[i].filter) + 2;
4938 filter = HeapAlloc(GetProcessHeap(), 0, totalLen * sizeof(WCHAR));
4939 if (filter)
4941 LPWSTR ptr;
4943 ptr = filter;
4944 for (i = 0; i < ARRAY_SIZE(import_filters); i++)
4946 if (!import_filters[i].allowFlags || !dwFlags ||
4947 (dwFlags & import_filters[i].allowFlags))
4949 len = LoadStringW(hInstance, import_filters[i].id,
4950 (LPWSTR)&str, 0);
4951 memcpy(ptr, str, len * sizeof(WCHAR));
4952 ptr += len;
4953 *ptr++ = 0;
4954 strcpyW(ptr, import_filters[i].filter);
4955 ptr += strlenW(import_filters[i].filter) + 1;
4958 *ptr++ = 0;
4960 return filter;
4963 static BOOL import_validate_filename(HWND hwnd, struct ImportWizData *data,
4964 LPCWSTR fileName)
4966 HANDLE file;
4967 BOOL ret = FALSE;
4969 file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
4970 OPEN_EXISTING, 0, NULL);
4971 if (file != INVALID_HANDLE_VALUE)
4973 HCERTSTORE source = open_store_from_file(data->dwFlags, fileName,
4974 &data->contentType);
4975 int warningID = 0;
4977 if (!source)
4978 warningID = IDS_IMPORT_BAD_FORMAT;
4979 else if (!check_store_context_type(data->dwFlags, source))
4980 warningID = IDS_IMPORT_TYPE_MISMATCH;
4981 else
4983 data->importSrc.dwSubjectChoice =
4984 CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE;
4985 data->importSrc.u.hCertStore = source;
4986 data->freeSource = TRUE;
4987 ret = TRUE;
4989 if (warningID)
4991 import_warning(data->dwFlags, hwnd, data->pwszWizardTitle,
4992 warningID);
4994 CloseHandle(file);
4996 else
4998 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
4999 LPCWSTR pTitle;
5000 LPWSTR msgBuf, fullError;
5002 if (data->pwszWizardTitle)
5003 pTitle = data->pwszWizardTitle;
5004 else
5006 LoadStringW(hInstance, IDS_IMPORT_WIZARD, title, ARRAY_SIZE(title));
5007 pTitle = title;
5009 LoadStringW(hInstance, IDS_IMPORT_OPEN_FAILED, error, ARRAY_SIZE(error));
5010 FormatMessageW(
5011 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
5012 GetLastError(), 0, (LPWSTR) &msgBuf, 0, NULL);
5013 fullError = HeapAlloc(GetProcessHeap(), 0,
5014 (strlenW(error) + strlenW(fileName) + strlenW(msgBuf) + 3)
5015 * sizeof(WCHAR));
5016 if (fullError)
5018 LPWSTR ptr = fullError;
5020 strcpyW(ptr, error);
5021 ptr += strlenW(error);
5022 strcpyW(ptr, fileName);
5023 ptr += strlenW(fileName);
5024 *ptr++ = ':';
5025 *ptr++ = '\n';
5026 strcpyW(ptr, msgBuf);
5027 MessageBoxW(hwnd, fullError, pTitle, MB_ICONERROR | MB_OK);
5028 HeapFree(GetProcessHeap(), 0, fullError);
5030 LocalFree(msgBuf);
5032 return ret;
5035 static LRESULT CALLBACK import_file_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
5036 LPARAM lp)
5038 LRESULT ret = 0;
5039 struct ImportWizData *data;
5041 switch (msg)
5043 case WM_INITDIALOG:
5045 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
5047 data = (struct ImportWizData *)page->lParam;
5048 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
5049 if (data->fileName)
5051 HWND fileNameEdit = GetDlgItem(hwnd, IDC_IMPORT_FILENAME);
5053 SendMessageW(fileNameEdit, WM_SETTEXT, 0, (LPARAM)data->fileName);
5055 break;
5057 case WM_NOTIFY:
5059 NMHDR *hdr = (NMHDR *)lp;
5061 switch (hdr->code)
5063 case PSN_SETACTIVE:
5064 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
5065 PSWIZB_BACK | PSWIZB_NEXT);
5066 ret = TRUE;
5067 break;
5068 case PSN_WIZNEXT:
5070 HWND fileNameEdit = GetDlgItem(hwnd, IDC_IMPORT_FILENAME);
5071 DWORD len = SendMessageW(fileNameEdit, WM_GETTEXTLENGTH, 0, 0);
5073 data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5074 if (!len)
5076 import_warning(data->dwFlags, hwnd, data->pwszWizardTitle,
5077 IDS_IMPORT_EMPTY_FILE);
5078 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
5079 ret = 1;
5081 else
5083 LPWSTR fileName = HeapAlloc(GetProcessHeap(), 0,
5084 (len + 1) * sizeof(WCHAR));
5086 if (fileName)
5088 SendMessageW(fileNameEdit, WM_GETTEXT, len + 1,
5089 (LPARAM)fileName);
5090 if (!import_validate_filename(hwnd, data, fileName))
5092 HeapFree(GetProcessHeap(), 0, fileName);
5093 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
5094 ret = 1;
5096 else
5097 data->fileName = fileName;
5100 break;
5103 break;
5105 case WM_COMMAND:
5106 switch (wp)
5108 case IDC_IMPORT_BROWSE_FILE:
5110 OPENFILENAMEW ofn;
5111 WCHAR fileBuf[MAX_PATH];
5113 data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5114 memset(&ofn, 0, sizeof(ofn));
5115 ofn.lStructSize = sizeof(ofn);
5116 ofn.hwndOwner = hwnd;
5117 ofn.lpstrFilter = make_import_file_filter(data->dwFlags);
5118 ofn.lpstrFile = fileBuf;
5119 ofn.nMaxFile = ARRAY_SIZE(fileBuf);
5120 fileBuf[0] = 0;
5121 if (GetOpenFileNameW(&ofn))
5122 SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_FILENAME), WM_SETTEXT,
5123 0, (LPARAM)ofn.lpstrFile);
5124 HeapFree(GetProcessHeap(), 0, (LPWSTR)ofn.lpstrFilter);
5125 break;
5128 break;
5130 return ret;
5133 static LRESULT CALLBACK import_store_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
5134 LPARAM lp)
5136 LRESULT ret = 0;
5137 struct ImportWizData *data;
5139 switch (msg)
5141 case WM_INITDIALOG:
5143 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
5145 data = (struct ImportWizData *)page->lParam;
5146 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
5147 if (!data->hDestCertStore)
5149 SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_AUTO_STORE), BM_CLICK,
5150 0, 0);
5151 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_STORE), FALSE);
5152 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_BROWSE_STORE), FALSE);
5153 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_SPECIFY_STORE), FALSE);
5155 else
5157 WCHAR storeTitle[MAX_STRING_LEN];
5159 SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_SPECIFY_STORE), BM_CLICK,
5160 0, 0);
5161 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_STORE), TRUE);
5162 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_BROWSE_STORE), TRUE);
5163 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_SPECIFY_STORE),
5164 !(data->dwFlags & CRYPTUI_WIZ_IMPORT_NO_CHANGE_DEST_STORE));
5165 LoadStringW(hInstance, IDS_IMPORT_DEST_DETERMINED, storeTitle, ARRAY_SIZE(storeTitle));
5166 SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_STORE), WM_SETTEXT,
5167 0, (LPARAM)storeTitle);
5169 break;
5171 case WM_NOTIFY:
5173 NMHDR *hdr = (NMHDR *)lp;
5175 switch (hdr->code)
5177 case PSN_SETACTIVE:
5178 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
5179 PSWIZB_BACK | PSWIZB_NEXT);
5180 ret = TRUE;
5181 break;
5182 case PSN_WIZNEXT:
5184 data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5185 if (IsDlgButtonChecked(hwnd, IDC_IMPORT_SPECIFY_STORE) &&
5186 !data->hDestCertStore)
5188 import_warning(data->dwFlags, hwnd, data->pwszWizardTitle,
5189 IDS_IMPORT_SELECT_STORE);
5190 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
5191 ret = 1;
5193 break;
5196 break;
5198 case WM_COMMAND:
5199 switch (wp)
5201 case IDC_IMPORT_AUTO_STORE:
5202 data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5203 data->autoDest = TRUE;
5204 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_STORE), FALSE);
5205 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_BROWSE_STORE), FALSE);
5206 break;
5207 case IDC_IMPORT_SPECIFY_STORE:
5208 data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5209 data->autoDest = FALSE;
5210 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_STORE), TRUE);
5211 EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_BROWSE_STORE), TRUE);
5212 break;
5213 case IDC_IMPORT_BROWSE_STORE:
5215 CRYPTUI_ENUM_SYSTEM_STORE_ARGS enumArgs = {
5216 CERT_SYSTEM_STORE_CURRENT_USER, NULL };
5217 CRYPTUI_ENUM_DATA enumData = { 0, NULL, 1, &enumArgs };
5218 CRYPTUI_SELECTSTORE_INFO_W selectInfo;
5219 HCERTSTORE store;
5221 data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5222 selectInfo.dwSize = sizeof(selectInfo);
5223 selectInfo.parent = hwnd;
5224 selectInfo.dwFlags = CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE;
5225 selectInfo.pwszTitle = NULL;
5226 selectInfo.pwszText = NULL;
5227 selectInfo.pEnumData = &enumData;
5228 selectInfo.pfnSelectedStoreCallback = NULL;
5229 if ((store = CryptUIDlgSelectStoreW(&selectInfo)))
5231 WCHAR storeTitle[MAX_STRING_LEN];
5233 LoadStringW(hInstance, IDS_IMPORT_DEST_DETERMINED, storeTitle,
5234 ARRAY_SIZE(storeTitle));
5235 SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_STORE), WM_SETTEXT,
5236 0, (LPARAM)storeTitle);
5237 data->hDestCertStore = store;
5238 data->freeDest = TRUE;
5240 break;
5243 break;
5245 return ret;
5248 static void show_import_details(HWND lv, struct ImportWizData *data)
5250 WCHAR text[MAX_STRING_LEN];
5251 LVITEMW item;
5252 int contentID;
5254 item.mask = LVIF_TEXT;
5255 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
5256 item.iSubItem = 0;
5257 LoadStringW(hInstance, IDS_IMPORT_STORE_SELECTION, text, ARRAY_SIZE(text));
5258 item.pszText = text;
5259 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
5260 item.iSubItem = 1;
5261 if (data->autoDest)
5262 LoadStringW(hInstance, IDS_IMPORT_DEST_AUTOMATIC, text, ARRAY_SIZE(text));
5263 else
5264 LoadStringW(hInstance, IDS_IMPORT_DEST_DETERMINED, text, ARRAY_SIZE(text));
5265 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
5266 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
5267 item.iSubItem = 0;
5268 LoadStringW(hInstance, IDS_IMPORT_CONTENT, text, ARRAY_SIZE(text));
5269 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
5270 switch (data->contentType)
5272 case CERT_QUERY_CONTENT_CERT:
5273 case CERT_QUERY_CONTENT_SERIALIZED_CERT:
5274 contentID = IDS_IMPORT_CONTENT_CERT;
5275 break;
5276 case CERT_QUERY_CONTENT_CRL:
5277 case CERT_QUERY_CONTENT_SERIALIZED_CRL:
5278 contentID = IDS_IMPORT_CONTENT_CRL;
5279 break;
5280 case CERT_QUERY_CONTENT_CTL:
5281 case CERT_QUERY_CONTENT_SERIALIZED_CTL:
5282 contentID = IDS_IMPORT_CONTENT_CTL;
5283 break;
5284 case CERT_QUERY_CONTENT_PKCS7_SIGNED:
5285 contentID = IDS_IMPORT_CONTENT_CMS;
5286 break;
5287 case CERT_QUERY_CONTENT_FLAG_PFX:
5288 contentID = IDS_IMPORT_CONTENT_PFX;
5289 break;
5290 default:
5291 contentID = IDS_IMPORT_CONTENT_STORE;
5292 break;
5294 LoadStringW(hInstance, contentID, text, ARRAY_SIZE(text));
5295 item.iSubItem = 1;
5296 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
5297 if (data->fileName)
5299 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
5300 item.iSubItem = 0;
5301 LoadStringW(hInstance, IDS_IMPORT_FILE, text, ARRAY_SIZE(text));
5302 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
5303 item.iSubItem = 1;
5304 item.pszText = data->fileName;
5305 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
5309 static BOOL do_import(DWORD dwFlags, HWND hwndParent, LPCWSTR pwszWizardTitle,
5310 PCCRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc, HCERTSTORE hDestCertStore)
5312 BOOL ret;
5314 switch (pImportSrc->dwSubjectChoice)
5316 case CRYPTUI_WIZ_IMPORT_SUBJECT_FILE:
5317 ret = import_file(dwFlags, hwndParent, pwszWizardTitle,
5318 pImportSrc->u.pwszFileName, hDestCertStore);
5319 break;
5320 case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_CONTEXT:
5321 if ((ret = check_context_type(dwFlags, CERT_QUERY_CONTENT_CERT)))
5322 ret = import_cert(pImportSrc->u.pCertContext, hDestCertStore);
5323 else
5324 import_warn_type_mismatch(dwFlags, hwndParent, pwszWizardTitle);
5325 break;
5326 case CRYPTUI_WIZ_IMPORT_SUBJECT_CRL_CONTEXT:
5327 if ((ret = check_context_type(dwFlags, CERT_QUERY_CONTENT_CRL)))
5328 ret = import_crl(pImportSrc->u.pCRLContext, hDestCertStore);
5329 else
5330 import_warn_type_mismatch(dwFlags, hwndParent, pwszWizardTitle);
5331 break;
5332 case CRYPTUI_WIZ_IMPORT_SUBJECT_CTL_CONTEXT:
5333 if ((ret = check_context_type(dwFlags, CERT_QUERY_CONTENT_CTL)))
5334 ret = import_ctl(pImportSrc->u.pCTLContext, hDestCertStore);
5335 else
5336 import_warn_type_mismatch(dwFlags, hwndParent, pwszWizardTitle);
5337 break;
5338 case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE:
5339 ret = import_store(dwFlags, hwndParent, pwszWizardTitle,
5340 pImportSrc->u.hCertStore, hDestCertStore);
5341 break;
5342 default:
5343 WARN("unknown source type: %u\n", pImportSrc->dwSubjectChoice);
5344 SetLastError(E_INVALIDARG);
5345 ret = FALSE;
5347 return ret;
5350 static LRESULT CALLBACK import_finish_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
5351 LPARAM lp)
5353 LRESULT ret = 0;
5354 struct ImportWizData *data;
5356 switch (msg)
5358 case WM_INITDIALOG:
5360 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
5361 HWND lv = GetDlgItem(hwnd, IDC_IMPORT_SETTINGS);
5362 RECT rc;
5363 LVCOLUMNW column;
5365 data = (struct ImportWizData *)page->lParam;
5366 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
5367 SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_TITLE), WM_SETFONT,
5368 (WPARAM)data->titleFont, TRUE);
5369 GetWindowRect(lv, &rc);
5370 column.mask = LVCF_WIDTH;
5371 column.cx = (rc.right - rc.left) / 2 - 2;
5372 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
5373 SendMessageW(lv, LVM_INSERTCOLUMNW, 1, (LPARAM)&column);
5374 show_import_details(lv, data);
5375 break;
5377 case WM_NOTIFY:
5379 NMHDR *hdr = (NMHDR *)lp;
5381 switch (hdr->code)
5383 case PSN_SETACTIVE:
5385 HWND lv = GetDlgItem(hwnd, IDC_IMPORT_SETTINGS);
5387 data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5388 SendMessageW(lv, LVM_DELETEALLITEMS, 0, 0);
5389 show_import_details(lv, data);
5390 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
5391 PSWIZB_BACK | PSWIZB_FINISH);
5392 ret = TRUE;
5393 break;
5395 case PSN_WIZFINISH:
5397 data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5398 if ((data->success = do_import(data->dwFlags, hwnd,
5399 data->pwszWizardTitle, &data->importSrc, data->hDestCertStore)))
5401 WCHAR title[MAX_STRING_LEN], message[MAX_STRING_LEN];
5402 LPCWSTR pTitle;
5404 if (data->pwszWizardTitle)
5405 pTitle = data->pwszWizardTitle;
5406 else
5408 LoadStringW(hInstance, IDS_IMPORT_WIZARD, title, ARRAY_SIZE(title));
5409 pTitle = title;
5411 LoadStringW(hInstance, IDS_IMPORT_SUCCEEDED, message, ARRAY_SIZE(message));
5412 MessageBoxW(hwnd, message, pTitle, MB_OK);
5414 else
5415 import_warning(data->dwFlags, hwnd, data->pwszWizardTitle,
5416 IDS_IMPORT_FAILED);
5417 break;
5420 break;
5423 return ret;
5426 static BOOL show_import_ui(DWORD dwFlags, HWND hwndParent,
5427 LPCWSTR pwszWizardTitle, PCCRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc,
5428 HCERTSTORE hDestCertStore)
5430 PROPSHEETHEADERW hdr;
5431 PROPSHEETPAGEW pages[4];
5432 struct ImportWizData data;
5433 int nPages = 0;
5435 data.dwFlags = dwFlags;
5436 data.pwszWizardTitle = pwszWizardTitle;
5437 if (pImportSrc)
5439 memcpy(&data.importSrc, pImportSrc, sizeof(data.importSrc));
5440 data.fileName = (LPWSTR)pImportSrc->u.pwszFileName;
5442 else
5444 memset(&data.importSrc, 0, sizeof(data.importSrc));
5445 data.fileName = NULL;
5447 data.freeSource = FALSE;
5448 data.hDestCertStore = hDestCertStore;
5449 data.freeDest = FALSE;
5450 data.autoDest = TRUE;
5451 data.success = TRUE;
5453 memset(pages, 0, sizeof(pages));
5455 pages[nPages].dwSize = sizeof(pages[0]);
5456 pages[nPages].hInstance = hInstance;
5457 pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_IMPORT_WELCOME);
5458 pages[nPages].pfnDlgProc = import_welcome_dlg_proc;
5459 pages[nPages].dwFlags = PSP_HIDEHEADER;
5460 pages[nPages].lParam = (LPARAM)&data;
5461 nPages++;
5463 if (!pImportSrc ||
5464 pImportSrc->dwSubjectChoice == CRYPTUI_WIZ_IMPORT_SUBJECT_FILE)
5466 pages[nPages].dwSize = sizeof(pages[0]);
5467 pages[nPages].hInstance = hInstance;
5468 pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_IMPORT_FILE);
5469 pages[nPages].pfnDlgProc = import_file_dlg_proc;
5470 pages[nPages].dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
5471 pages[nPages].pszHeaderTitle = MAKEINTRESOURCEW(IDS_IMPORT_FILE_TITLE);
5472 pages[nPages].pszHeaderSubTitle =
5473 MAKEINTRESOURCEW(IDS_IMPORT_FILE_SUBTITLE);
5474 pages[nPages].lParam = (LPARAM)&data;
5475 nPages++;
5477 else
5479 switch (pImportSrc->dwSubjectChoice)
5481 case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_CONTEXT:
5482 data.contentType = CERT_QUERY_CONTENT_CERT;
5483 break;
5484 case CRYPTUI_WIZ_IMPORT_SUBJECT_CRL_CONTEXT:
5485 data.contentType = CERT_QUERY_CONTENT_CRL;
5486 break;
5487 case CRYPTUI_WIZ_IMPORT_SUBJECT_CTL_CONTEXT:
5488 data.contentType = CERT_QUERY_CONTENT_CTL;
5489 break;
5490 case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE:
5491 data.contentType = CERT_QUERY_CONTENT_SERIALIZED_STORE;
5492 break;
5496 pages[nPages].dwSize = sizeof(pages[0]);
5497 pages[nPages].hInstance = hInstance;
5498 pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_IMPORT_STORE);
5499 pages[nPages].pfnDlgProc = import_store_dlg_proc;
5500 pages[nPages].dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
5501 pages[nPages].pszHeaderTitle = MAKEINTRESOURCEW(IDS_IMPORT_STORE_TITLE);
5502 pages[nPages].pszHeaderSubTitle =
5503 MAKEINTRESOURCEW(IDS_IMPORT_STORE_SUBTITLE);
5504 pages[nPages].lParam = (LPARAM)&data;
5505 nPages++;
5507 pages[nPages].dwSize = sizeof(pages[0]);
5508 pages[nPages].hInstance = hInstance;
5509 pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_IMPORT_FINISH);
5510 pages[nPages].pfnDlgProc = import_finish_dlg_proc;
5511 pages[nPages].dwFlags = PSP_HIDEHEADER;
5512 pages[nPages].lParam = (LPARAM)&data;
5513 nPages++;
5515 memset(&hdr, 0, sizeof(hdr));
5516 hdr.dwSize = sizeof(hdr);
5517 hdr.hwndParent = hwndParent;
5518 hdr.dwFlags = PSH_PROPSHEETPAGE | PSH_WIZARD97_NEW | PSH_HEADER |
5519 PSH_WATERMARK;
5520 hdr.hInstance = hInstance;
5521 if (pwszWizardTitle)
5522 hdr.pszCaption = pwszWizardTitle;
5523 else
5524 hdr.pszCaption = MAKEINTRESOURCEW(IDS_IMPORT_WIZARD);
5525 hdr.u3.ppsp = pages;
5526 hdr.nPages = nPages;
5527 hdr.u4.pszbmWatermark = MAKEINTRESOURCEW(IDB_CERT_WATERMARK);
5528 hdr.u5.pszbmHeader = MAKEINTRESOURCEW(IDB_CERT_HEADER);
5529 PropertySheetW(&hdr);
5530 if (data.fileName != data.importSrc.u.pwszFileName)
5531 HeapFree(GetProcessHeap(), 0, data.fileName);
5532 if (data.freeSource &&
5533 data.importSrc.dwSubjectChoice == CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE)
5534 CertCloseStore(data.importSrc.u.hCertStore, 0);
5535 DeleteObject(data.titleFont);
5536 return data.success;
5539 BOOL WINAPI CryptUIWizImport(DWORD dwFlags, HWND hwndParent, LPCWSTR pwszWizardTitle,
5540 PCCRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc, HCERTSTORE hDestCertStore)
5542 BOOL ret;
5544 TRACE("(0x%08x, %p, %s, %p, %p)\n", dwFlags, hwndParent, debugstr_w(pwszWizardTitle),
5545 pImportSrc, hDestCertStore);
5547 if (pImportSrc &&
5548 pImportSrc->dwSize != sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO))
5550 SetLastError(E_INVALIDARG);
5551 return FALSE;
5554 if (!(dwFlags & CRYPTUI_WIZ_NO_UI))
5555 ret = show_import_ui(dwFlags, hwndParent, pwszWizardTitle, pImportSrc,
5556 hDestCertStore);
5557 else if (pImportSrc)
5558 ret = do_import(dwFlags, hwndParent, pwszWizardTitle, pImportSrc,
5559 hDestCertStore);
5560 else
5562 /* Can't have no UI without specifying source */
5563 SetLastError(E_INVALIDARG);
5564 ret = FALSE;
5567 return ret;
5570 struct ExportWizData
5572 HFONT titleFont;
5573 DWORD dwFlags;
5574 LPCWSTR pwszWizardTitle;
5575 CRYPTUI_WIZ_EXPORT_INFO exportInfo;
5576 CRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO contextInfo;
5577 BOOL freePassword;
5578 PCRYPT_KEY_PROV_INFO keyProvInfo;
5579 BOOL deleteKeys;
5580 LPWSTR fileName;
5581 HANDLE file;
5582 BOOL success;
5585 static LRESULT CALLBACK export_welcome_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
5586 LPARAM lp)
5588 LRESULT ret = 0;
5590 switch (msg)
5592 case WM_INITDIALOG:
5594 struct ExportWizData *data;
5595 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
5596 WCHAR fontFace[MAX_STRING_LEN];
5597 HDC hDC = GetDC(hwnd);
5598 int height;
5600 data = (struct ExportWizData *)page->lParam;
5601 LoadStringW(hInstance, IDS_WIZARD_TITLE_FONT, fontFace, ARRAY_SIZE(fontFace));
5602 height = -MulDiv(12, GetDeviceCaps(hDC, LOGPIXELSY), 72);
5603 data->titleFont = CreateFontW(height, 0, 0, 0, FW_BOLD, 0, 0, 0,
5604 DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
5605 DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, fontFace);
5606 SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_TITLE), WM_SETFONT,
5607 (WPARAM)data->titleFont, TRUE);
5608 ReleaseDC(hwnd, hDC);
5609 break;
5611 case WM_NOTIFY:
5613 NMHDR *hdr = (NMHDR *)lp;
5615 switch (hdr->code)
5617 case PSN_SETACTIVE:
5618 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0, PSWIZB_NEXT);
5619 ret = TRUE;
5620 break;
5622 break;
5625 return ret;
5628 static PCRYPT_KEY_PROV_INFO export_get_private_key_info(PCCERT_CONTEXT cert)
5630 PCRYPT_KEY_PROV_INFO info = NULL;
5631 DWORD size;
5633 if (CertGetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID,
5634 NULL, &size))
5636 info = HeapAlloc(GetProcessHeap(), 0, size);
5637 if (info)
5639 if (!CertGetCertificateContextProperty(cert,
5640 CERT_KEY_PROV_INFO_PROP_ID, info, &size))
5642 HeapFree(GetProcessHeap(), 0, info);
5643 info = NULL;
5647 return info;
5650 static BOOL export_acquire_private_key(const CRYPT_KEY_PROV_INFO *info,
5651 HCRYPTPROV *phProv)
5653 BOOL ret;
5655 ret = CryptAcquireContextW(phProv, info->pwszContainerName,
5656 info->pwszProvName, info->dwProvType, 0);
5657 if (ret)
5659 DWORD i;
5661 for (i = 0; i < info->cProvParam; i++)
5662 CryptSetProvParam(*phProv, info->rgProvParam[i].dwParam,
5663 info->rgProvParam[i].pbData, info->rgProvParam[i].dwFlags);
5665 return ret;
5668 static BOOL export_is_key_exportable(HCRYPTPROV hProv, DWORD keySpec)
5670 BOOL ret;
5671 HCRYPTKEY key;
5673 if ((ret = CryptGetUserKey(hProv, keySpec, &key)))
5675 DWORD permissions, size = sizeof(permissions);
5677 if ((ret = CryptGetKeyParam(key, KP_PERMISSIONS, (BYTE *)&permissions,
5678 &size, 0)) && !(permissions & CRYPT_EXPORT))
5679 ret = FALSE;
5680 CryptDestroyKey(key);
5682 return ret;
5685 static LRESULT CALLBACK export_private_key_dlg_proc(HWND hwnd, UINT msg,
5686 WPARAM wp, LPARAM lp)
5688 LRESULT ret = 0;
5689 struct ExportWizData *data;
5691 switch (msg)
5693 case WM_INITDIALOG:
5695 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
5696 PCRYPT_KEY_PROV_INFO info;
5697 HCRYPTPROV hProv = 0;
5698 int errorID = 0;
5700 data = (struct ExportWizData *)page->lParam;
5701 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
5702 /* Get enough information about a key to see whether it's exportable.
5704 if (!(info = export_get_private_key_info(
5705 data->exportInfo.u.pCertContext)))
5706 errorID = IDS_EXPORT_PRIVATE_KEY_UNAVAILABLE;
5707 else if (!export_acquire_private_key(info, &hProv))
5708 errorID = IDS_EXPORT_PRIVATE_KEY_UNAVAILABLE;
5709 else if (!export_is_key_exportable(hProv, info->dwKeySpec))
5710 errorID = IDS_EXPORT_PRIVATE_KEY_NON_EXPORTABLE;
5712 if (errorID)
5714 WCHAR error[MAX_STRING_LEN];
5716 LoadStringW(hInstance, errorID, error, ARRAY_SIZE(error));
5717 SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_PRIVATE_KEY_UNAVAILABLE),
5718 WM_SETTEXT, 0, (LPARAM)error);
5719 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_PRIVATE_KEY_YES), FALSE);
5721 else
5722 data->keyProvInfo = info;
5723 if (hProv)
5724 CryptReleaseContext(hProv, 0);
5725 SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_PRIVATE_KEY_NO), BM_CLICK,
5726 0, 0);
5727 break;
5729 case WM_NOTIFY:
5731 NMHDR *hdr = (NMHDR *)lp;
5733 switch (hdr->code)
5735 case PSN_SETACTIVE:
5736 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
5737 PSWIZB_BACK | PSWIZB_NEXT);
5738 ret = TRUE;
5739 break;
5740 case PSN_WIZNEXT:
5741 data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5742 if (IsDlgButtonChecked(hwnd, IDC_EXPORT_PRIVATE_KEY_NO))
5744 data->contextInfo.dwExportFormat =
5745 CRYPTUI_WIZ_EXPORT_FORMAT_DER;
5746 data->contextInfo.fExportPrivateKeys = FALSE;
5748 else
5750 data->contextInfo.dwExportFormat =
5751 CRYPTUI_WIZ_EXPORT_FORMAT_PFX;
5752 data->contextInfo.fExportPrivateKeys = TRUE;
5754 break;
5756 break;
5759 return ret;
5762 static BOOL export_info_has_private_key(PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo)
5764 BOOL ret = FALSE;
5766 if (pExportInfo->dwSubjectChoice == CRYPTUI_WIZ_EXPORT_CERT_CONTEXT)
5768 DWORD size;
5770 /* If there's a CRYPT_KEY_PROV_INFO set for this cert, assume the
5771 * cert has a private key.
5773 if (CertGetCertificateContextProperty(pExportInfo->u.pCertContext,
5774 CERT_KEY_PROV_INFO_PROP_ID, NULL, &size))
5775 ret = TRUE;
5777 return ret;
5780 static void export_format_enable_controls(HWND hwnd, const struct ExportWizData *data)
5782 int defaultFormatID;
5784 switch (data->contextInfo.dwExportFormat)
5786 case CRYPTUI_WIZ_EXPORT_FORMAT_BASE64:
5787 defaultFormatID = IDC_EXPORT_FORMAT_BASE64;
5788 break;
5789 case CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7:
5790 defaultFormatID = IDC_EXPORT_FORMAT_CMS;
5791 break;
5792 case CRYPTUI_WIZ_EXPORT_FORMAT_PFX:
5793 defaultFormatID = IDC_EXPORT_FORMAT_PFX;
5794 break;
5795 default:
5796 defaultFormatID = IDC_EXPORT_FORMAT_DER;
5798 SendMessageW(GetDlgItem(hwnd, defaultFormatID), BM_CLICK, 0, 0);
5799 if (defaultFormatID == IDC_EXPORT_FORMAT_PFX)
5801 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_DER), FALSE);
5802 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_BASE64), FALSE);
5803 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_CMS), FALSE);
5804 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_PFX), TRUE);
5806 else
5808 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_DER), TRUE);
5809 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_BASE64), TRUE);
5810 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_CMS), TRUE);
5811 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_FORMAT_PFX), FALSE);
5815 static LRESULT CALLBACK export_format_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
5816 LPARAM lp)
5818 LRESULT ret = 0;
5819 struct ExportWizData *data;
5821 switch (msg)
5823 case WM_INITDIALOG:
5825 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
5827 data = (struct ExportWizData *)page->lParam;
5828 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
5829 export_format_enable_controls(hwnd, data);
5830 break;
5832 case WM_NOTIFY:
5834 NMHDR *hdr = (NMHDR *)lp;
5836 switch (hdr->code)
5838 case PSN_SETACTIVE:
5839 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
5840 PSWIZB_BACK | PSWIZB_NEXT);
5841 data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5842 export_format_enable_controls(hwnd, data);
5843 ret = TRUE;
5844 break;
5845 case PSN_WIZNEXT:
5847 BOOL skipPasswordPage = TRUE;
5849 data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5850 if (IsDlgButtonChecked(hwnd, IDC_EXPORT_FORMAT_DER))
5851 data->contextInfo.dwExportFormat =
5852 CRYPTUI_WIZ_EXPORT_FORMAT_DER;
5853 else if (IsDlgButtonChecked(hwnd, IDC_EXPORT_FORMAT_BASE64))
5854 data->contextInfo.dwExportFormat =
5855 CRYPTUI_WIZ_EXPORT_FORMAT_BASE64;
5856 else if (IsDlgButtonChecked(hwnd, IDC_EXPORT_FORMAT_CMS))
5858 data->contextInfo.dwExportFormat =
5859 CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7;
5860 if (IsDlgButtonChecked(hwnd, IDC_EXPORT_CMS_INCLUDE_CHAIN))
5861 data->contextInfo.fExportChain =
5862 CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7;
5864 else
5866 data->contextInfo.dwExportFormat =
5867 CRYPTUI_WIZ_EXPORT_FORMAT_PFX;
5868 if (IsDlgButtonChecked(hwnd, IDC_EXPORT_PFX_INCLUDE_CHAIN))
5869 data->contextInfo.fExportChain = TRUE;
5870 if (IsDlgButtonChecked(hwnd, IDC_EXPORT_PFX_STRONG_ENCRYPTION))
5871 data->contextInfo.fStrongEncryption = TRUE;
5872 if (IsDlgButtonChecked(hwnd, IDC_EXPORT_PFX_DELETE_PRIVATE_KEY))
5873 data->deleteKeys = TRUE;
5874 skipPasswordPage = FALSE;
5876 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT,
5877 skipPasswordPage ? IDD_EXPORT_FILE : 0);
5878 ret = 1;
5879 break;
5882 break;
5884 case WM_COMMAND:
5885 switch (HIWORD(wp))
5887 case BN_CLICKED:
5888 switch (LOWORD(wp))
5890 case IDC_EXPORT_FORMAT_DER:
5891 case IDC_EXPORT_FORMAT_BASE64:
5892 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_CMS_INCLUDE_CHAIN),
5893 FALSE);
5894 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_PFX_INCLUDE_CHAIN),
5895 FALSE);
5896 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_PFX_STRONG_ENCRYPTION),
5897 FALSE);
5898 EnableWindow(GetDlgItem(hwnd,
5899 IDC_EXPORT_PFX_DELETE_PRIVATE_KEY), FALSE);
5900 break;
5901 case IDC_EXPORT_FORMAT_CMS:
5902 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_CMS_INCLUDE_CHAIN),
5903 TRUE);
5904 break;
5905 case IDC_EXPORT_FORMAT_PFX:
5906 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_PFX_INCLUDE_CHAIN),
5907 TRUE);
5908 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT_PFX_STRONG_ENCRYPTION),
5909 TRUE);
5910 EnableWindow(GetDlgItem(hwnd,
5911 IDC_EXPORT_PFX_DELETE_PRIVATE_KEY), TRUE);
5912 break;
5914 break;
5916 break;
5918 return ret;
5921 static void export_password_mismatch(HWND hwnd, const struct ExportWizData *data)
5923 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
5924 LPCWSTR pTitle;
5926 if (data->pwszWizardTitle)
5927 pTitle = data->pwszWizardTitle;
5928 else
5930 LoadStringW(hInstance, IDS_EXPORT_WIZARD, title, ARRAY_SIZE(title));
5931 pTitle = title;
5933 LoadStringW(hInstance, IDS_EXPORT_PASSWORD_MISMATCH, error, ARRAY_SIZE(error));
5934 MessageBoxW(hwnd, error, pTitle, MB_ICONERROR | MB_OK);
5935 SetFocus(GetDlgItem(hwnd, IDC_EXPORT_PASSWORD));
5938 static LRESULT CALLBACK export_password_dlg_proc(HWND hwnd, UINT msg,
5939 WPARAM wp, LPARAM lp)
5941 LRESULT ret = 0;
5942 struct ExportWizData *data;
5944 switch (msg)
5946 case WM_INITDIALOG:
5948 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
5950 data = (struct ExportWizData *)page->lParam;
5951 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
5952 break;
5954 case WM_NOTIFY:
5956 NMHDR *hdr = (NMHDR *)lp;
5958 switch (hdr->code)
5960 case PSN_SETACTIVE:
5961 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
5962 PSWIZB_BACK | PSWIZB_NEXT);
5963 ret = TRUE;
5964 break;
5965 case PSN_WIZNEXT:
5967 HWND passwordEdit = GetDlgItem(hwnd, IDC_EXPORT_PASSWORD);
5968 HWND passwordConfirmEdit = GetDlgItem(hwnd,
5969 IDC_EXPORT_PASSWORD_CONFIRM);
5970 DWORD passwordLen = SendMessageW(passwordEdit, WM_GETTEXTLENGTH,
5971 0, 0);
5972 DWORD passwordConfirmLen = SendMessageW(passwordConfirmEdit,
5973 WM_GETTEXTLENGTH, 0, 0);
5975 data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
5976 if (!passwordLen && !passwordConfirmLen)
5977 data->contextInfo.pwszPassword = NULL;
5978 else if (passwordLen != passwordConfirmLen)
5980 export_password_mismatch(hwnd, data);
5981 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
5982 ret = 1;
5984 else
5986 LPWSTR password = HeapAlloc(GetProcessHeap(), 0,
5987 (passwordLen + 1) * sizeof(WCHAR));
5988 LPWSTR passwordConfirm = HeapAlloc(GetProcessHeap(), 0,
5989 (passwordConfirmLen + 1) * sizeof(WCHAR));
5990 BOOL freePassword = TRUE;
5992 if (password && passwordConfirm)
5994 SendMessageW(passwordEdit, WM_GETTEXT, passwordLen + 1,
5995 (LPARAM)password);
5996 SendMessageW(passwordConfirmEdit, WM_GETTEXT,
5997 passwordConfirmLen + 1, (LPARAM)passwordConfirm);
5998 if (strcmpW(password, passwordConfirm))
6000 export_password_mismatch(hwnd, data);
6001 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
6002 ret = 1;
6004 else
6006 data->contextInfo.pwszPassword = password;
6007 freePassword = FALSE;
6008 data->freePassword = TRUE;
6011 if (freePassword)
6012 HeapFree(GetProcessHeap(), 0, password);
6013 HeapFree(GetProcessHeap(), 0, passwordConfirm);
6015 break;
6018 break;
6021 return ret;
6024 static LPWSTR export_append_extension(const struct ExportWizData *data,
6025 LPWSTR fileName)
6027 static const WCHAR cer[] = { '.','c','e','r',0 };
6028 static const WCHAR crl[] = { '.','c','r','l',0 };
6029 static const WCHAR ctl[] = { '.','c','t','l',0 };
6030 static const WCHAR p7b[] = { '.','p','7','b',0 };
6031 static const WCHAR pfx[] = { '.','p','f','x',0 };
6032 static const WCHAR sst[] = { '.','s','s','t',0 };
6033 LPCWSTR extension;
6034 LPWSTR dot;
6035 BOOL appendExtension;
6037 switch (data->contextInfo.dwExportFormat)
6039 case CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7:
6040 extension = p7b;
6041 break;
6042 case CRYPTUI_WIZ_EXPORT_FORMAT_PFX:
6043 extension = pfx;
6044 break;
6045 default:
6046 switch (data->exportInfo.dwSubjectChoice)
6048 case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
6049 extension = crl;
6050 break;
6051 case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT:
6052 extension = ctl;
6053 break;
6054 case CRYPTUI_WIZ_EXPORT_CERT_STORE:
6055 extension = sst;
6056 break;
6057 default:
6058 extension = cer;
6061 dot = strrchrW(fileName, '.');
6062 if (dot)
6063 appendExtension = strcmpiW(dot, extension) != 0;
6064 else
6065 appendExtension = TRUE;
6066 if (appendExtension)
6068 fileName = HeapReAlloc(GetProcessHeap(), 0, fileName,
6069 (strlenW(fileName) + strlenW(extension) + 1) * sizeof(WCHAR));
6070 if (fileName)
6071 strcatW(fileName, extension);
6073 return fileName;
6076 static BOOL export_validate_filename(HWND hwnd, struct ExportWizData *data,
6077 LPCWSTR fileName)
6079 HANDLE file;
6080 BOOL tryCreate = TRUE, forceCreate = FALSE, ret = FALSE;
6082 file = CreateFileW(fileName, GENERIC_WRITE,
6083 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
6084 if (file != INVALID_HANDLE_VALUE)
6086 WCHAR warning[MAX_STRING_LEN], title[MAX_STRING_LEN];
6087 LPCWSTR pTitle;
6089 if (data->pwszWizardTitle)
6090 pTitle = data->pwszWizardTitle;
6091 else
6093 LoadStringW(hInstance, IDS_EXPORT_WIZARD, title, ARRAY_SIZE(title));
6094 pTitle = title;
6096 LoadStringW(hInstance, IDS_EXPORT_FILE_EXISTS, warning, ARRAY_SIZE(warning));
6097 if (MessageBoxW(hwnd, warning, pTitle, MB_YESNO) == IDYES)
6098 forceCreate = TRUE;
6099 else
6100 tryCreate = FALSE;
6101 CloseHandle(file);
6103 if (tryCreate)
6105 file = CreateFileW(fileName, GENERIC_WRITE,
6106 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
6107 forceCreate ? CREATE_ALWAYS : CREATE_NEW,
6108 0, NULL);
6109 if (file != INVALID_HANDLE_VALUE)
6111 data->file = file;
6112 ret = TRUE;
6114 else
6116 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
6117 LPCWSTR pTitle;
6118 LPWSTR msgBuf, fullError;
6120 if (data->pwszWizardTitle)
6121 pTitle = data->pwszWizardTitle;
6122 else
6124 LoadStringW(hInstance, IDS_EXPORT_WIZARD, title, ARRAY_SIZE(title));
6125 pTitle = title;
6127 LoadStringW(hInstance, IDS_IMPORT_OPEN_FAILED, error, ARRAY_SIZE(error));
6128 FormatMessageW(
6129 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
6130 GetLastError(), 0, (LPWSTR) &msgBuf, 0, NULL);
6131 fullError = HeapAlloc(GetProcessHeap(), 0,
6132 (strlenW(error) + strlenW(fileName) + strlenW(msgBuf) + 3)
6133 * sizeof(WCHAR));
6134 if (fullError)
6136 LPWSTR ptr = fullError;
6138 strcpyW(ptr, error);
6139 ptr += strlenW(error);
6140 strcpyW(ptr, fileName);
6141 ptr += strlenW(fileName);
6142 *ptr++ = ':';
6143 *ptr++ = '\n';
6144 strcpyW(ptr, msgBuf);
6145 MessageBoxW(hwnd, fullError, pTitle, MB_ICONERROR | MB_OK);
6146 HeapFree(GetProcessHeap(), 0, fullError);
6148 LocalFree(msgBuf);
6151 return ret;
6154 static const WCHAR export_filter_cert[] = { '*','.','c','e','r',0 };
6155 static const WCHAR export_filter_crl[] = { '*','.','c','r','l',0 };
6156 static const WCHAR export_filter_ctl[] = { '*','.','s','t','l',0 };
6157 static const WCHAR export_filter_cms[] = { '*','.','p','7','b',0 };
6158 static const WCHAR export_filter_pfx[] = { '*','.','p','f','x',0 };
6159 static const WCHAR export_filter_sst[] = { '*','.','s','s','t',0 };
6161 static WCHAR *make_export_file_filter(DWORD exportFormat, DWORD subjectChoice)
6163 int baseLen, allLen, totalLen = 2, baseID;
6164 LPWSTR filter = NULL, baseFilter, all;
6165 LPCWSTR filterStr;
6167 switch (exportFormat)
6169 case CRYPTUI_WIZ_EXPORT_FORMAT_BASE64:
6170 baseID = IDS_EXPORT_FILTER_BASE64_CERT;
6171 filterStr = export_filter_cert;
6172 break;
6173 case CRYPTUI_WIZ_EXPORT_FORMAT_PFX:
6174 baseID = IDS_EXPORT_FILTER_PFX;
6175 filterStr = export_filter_pfx;
6176 break;
6177 case CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7:
6178 baseID = IDS_EXPORT_FILTER_CMS;
6179 filterStr = export_filter_cms;
6180 break;
6181 default:
6182 switch (subjectChoice)
6184 case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
6185 baseID = IDS_EXPORT_FILTER_CRL;
6186 filterStr = export_filter_crl;
6187 break;
6188 case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT:
6189 baseID = IDS_EXPORT_FILTER_CTL;
6190 filterStr = export_filter_ctl;
6191 break;
6192 case CRYPTUI_WIZ_EXPORT_CERT_STORE:
6193 baseID = IDS_EXPORT_FILTER_SERIALIZED_CERT_STORE;
6194 filterStr = export_filter_sst;
6195 break;
6196 default:
6197 baseID = IDS_EXPORT_FILTER_CERT;
6198 filterStr = export_filter_cert;
6199 break;
6202 baseLen = LoadStringW(hInstance, baseID, (LPWSTR)&baseFilter, 0);
6203 totalLen += baseLen + strlenW(filterStr) + 2;
6204 allLen = LoadStringW(hInstance, IDS_IMPORT_FILTER_ALL, (LPWSTR)&all, 0);
6205 totalLen += allLen + strlenW(filter_all) + 2;
6206 filter = HeapAlloc(GetProcessHeap(), 0, totalLen * sizeof(WCHAR));
6207 if (filter)
6209 LPWSTR ptr;
6211 ptr = filter;
6212 memcpy(ptr, baseFilter, baseLen * sizeof(WCHAR));
6213 ptr += baseLen;
6214 *ptr++ = 0;
6215 strcpyW(ptr, filterStr);
6216 ptr += strlenW(filterStr) + 1;
6217 memcpy(ptr, all, allLen * sizeof(WCHAR));
6218 ptr += allLen;
6219 *ptr++ = 0;
6220 strcpyW(ptr, filter_all);
6221 ptr += strlenW(filter_all) + 1;
6222 *ptr++ = 0;
6224 return filter;
6227 static LRESULT CALLBACK export_file_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
6228 LPARAM lp)
6230 LRESULT ret = 0;
6231 struct ExportWizData *data;
6233 switch (msg)
6235 case WM_INITDIALOG:
6237 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
6239 data = (struct ExportWizData *)page->lParam;
6240 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
6241 if (data->exportInfo.pwszExportFileName)
6242 SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_FILENAME), WM_SETTEXT, 0,
6243 (LPARAM)data->exportInfo.pwszExportFileName);
6244 break;
6246 case WM_NOTIFY:
6248 NMHDR *hdr = (NMHDR *)lp;
6250 switch (hdr->code)
6252 case PSN_WIZBACK:
6253 data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
6254 if (data->contextInfo.dwExportFormat !=
6255 CRYPTUI_WIZ_EXPORT_FORMAT_PFX)
6257 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, IDD_EXPORT_FORMAT);
6258 ret = 1;
6260 break;
6261 case PSN_WIZNEXT:
6263 HWND fileNameEdit = GetDlgItem(hwnd, IDC_EXPORT_FILENAME);
6264 DWORD len = SendMessageW(fileNameEdit, WM_GETTEXTLENGTH, 0, 0);
6266 data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
6267 if (!len)
6269 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
6270 LPCWSTR pTitle;
6272 if (data->pwszWizardTitle)
6273 pTitle = data->pwszWizardTitle;
6274 else
6276 LoadStringW(hInstance, IDS_EXPORT_WIZARD, title, ARRAY_SIZE(title));
6277 pTitle = title;
6279 LoadStringW(hInstance, IDS_IMPORT_EMPTY_FILE, error, ARRAY_SIZE(error));
6280 MessageBoxW(hwnd, error, pTitle, MB_ICONERROR | MB_OK);
6281 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
6282 ret = 1;
6284 else
6286 LPWSTR fileName = HeapAlloc(GetProcessHeap(), 0,
6287 (len + 1) * sizeof(WCHAR));
6289 if (fileName)
6291 SendMessageW(fileNameEdit, WM_GETTEXT, len + 1,
6292 (LPARAM)fileName);
6293 fileName = export_append_extension(data, fileName);
6294 if (!export_validate_filename(hwnd, data, fileName))
6296 HeapFree(GetProcessHeap(), 0, fileName);
6297 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
6298 ret = 1;
6300 else
6301 data->fileName = fileName;
6304 break;
6306 case PSN_SETACTIVE:
6307 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
6308 PSWIZB_BACK | PSWIZB_NEXT);
6309 ret = TRUE;
6310 break;
6312 break;
6314 case WM_COMMAND:
6315 switch (wp)
6317 case IDC_EXPORT_BROWSE_FILE:
6319 OPENFILENAMEW ofn;
6320 WCHAR fileBuf[MAX_PATH];
6322 data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
6323 memset(&ofn, 0, sizeof(ofn));
6324 ofn.lStructSize = sizeof(ofn);
6325 ofn.hwndOwner = hwnd;
6326 ofn.lpstrFilter = make_export_file_filter(
6327 data->contextInfo.dwExportFormat,
6328 data->exportInfo.dwSubjectChoice);
6329 ofn.lpstrFile = fileBuf;
6330 ofn.nMaxFile = ARRAY_SIZE(fileBuf);
6331 fileBuf[0] = 0;
6332 if (GetSaveFileNameW(&ofn))
6333 SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_FILENAME), WM_SETTEXT,
6334 0, (LPARAM)ofn.lpstrFile);
6335 HeapFree(GetProcessHeap(), 0, (LPWSTR)ofn.lpstrFilter);
6336 break;
6339 break;
6341 return ret;
6344 static void show_export_details(HWND lv, const struct ExportWizData *data)
6346 WCHAR text[MAX_STRING_LEN];
6347 LVITEMW item;
6348 int contentID;
6350 item.mask = LVIF_TEXT;
6351 if (data->fileName)
6353 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
6354 item.iSubItem = 0;
6355 LoadStringW(hInstance, IDS_IMPORT_FILE, text, ARRAY_SIZE(text));
6356 item.pszText = text;
6357 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
6358 item.iSubItem = 1;
6359 item.pszText = data->fileName;
6360 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
6363 item.pszText = text;
6364 switch (data->exportInfo.dwSubjectChoice)
6366 case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
6367 case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT:
6368 case CRYPTUI_WIZ_EXPORT_CERT_STORE:
6369 case CRYPTUI_WIZ_EXPORT_CERT_STORE_CERTIFICATES_ONLY:
6370 /* do nothing */
6371 break;
6372 default:
6374 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
6375 item.iSubItem = 0;
6376 LoadStringW(hInstance, IDS_EXPORT_INCLUDE_CHAIN, text, ARRAY_SIZE(text));
6377 SendMessageW(lv, LVM_INSERTITEMW, item.iItem, (LPARAM)&item);
6378 item.iSubItem = 1;
6379 LoadStringW(hInstance, data->contextInfo.fExportChain ? IDS_YES : IDS_NO, text,
6380 ARRAY_SIZE(text));
6381 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
6383 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
6384 item.iSubItem = 0;
6385 LoadStringW(hInstance, IDS_EXPORT_KEYS, text, ARRAY_SIZE(text));
6386 SendMessageW(lv, LVM_INSERTITEMW, item.iItem, (LPARAM)&item);
6387 item.iSubItem = 1;
6388 LoadStringW(hInstance, data->contextInfo.fExportPrivateKeys ? IDS_YES : IDS_NO, text,
6389 ARRAY_SIZE(text));
6390 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
6394 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
6395 item.iSubItem = 0;
6396 LoadStringW(hInstance, IDS_EXPORT_FORMAT, text, ARRAY_SIZE(text));
6397 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
6399 item.iSubItem = 1;
6400 switch (data->exportInfo.dwSubjectChoice)
6402 case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
6403 contentID = IDS_EXPORT_FILTER_CRL;
6404 break;
6405 case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT:
6406 contentID = IDS_EXPORT_FILTER_CTL;
6407 break;
6408 case CRYPTUI_WIZ_EXPORT_CERT_STORE:
6409 contentID = IDS_EXPORT_FILTER_SERIALIZED_CERT_STORE;
6410 break;
6411 default:
6412 switch (data->contextInfo.dwExportFormat)
6414 case CRYPTUI_WIZ_EXPORT_FORMAT_BASE64:
6415 contentID = IDS_EXPORT_FILTER_BASE64_CERT;
6416 break;
6417 case CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7:
6418 contentID = IDS_EXPORT_FILTER_CMS;
6419 break;
6420 case CRYPTUI_WIZ_EXPORT_FORMAT_PFX:
6421 contentID = IDS_EXPORT_FILTER_PFX;
6422 break;
6423 default:
6424 contentID = IDS_EXPORT_FILTER_CERT;
6427 LoadStringW(hInstance, contentID, text, ARRAY_SIZE(text));
6428 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
6431 static inline BOOL save_der(HANDLE file, const BYTE *pb, DWORD cb)
6433 DWORD bytesWritten;
6435 return WriteFile(file, pb, cb, &bytesWritten, NULL);
6438 static BOOL save_base64(HANDLE file, const BYTE *pb, DWORD cb)
6440 BOOL ret;
6441 DWORD size = 0;
6443 if ((ret = CryptBinaryToStringA(pb, cb, CRYPT_STRING_BASE64, NULL, &size)))
6445 LPSTR buf = HeapAlloc(GetProcessHeap(), 0, size);
6447 if (buf)
6449 if ((ret = CryptBinaryToStringA(pb, cb, CRYPT_STRING_BASE64, buf,
6450 &size)))
6451 ret = WriteFile(file, buf, size, &size, NULL);
6452 HeapFree(GetProcessHeap(), 0, buf);
6454 else
6456 SetLastError(ERROR_OUTOFMEMORY);
6457 ret = FALSE;
6460 return ret;
6463 static inline BOOL save_store_as_cms(HANDLE file, HCERTSTORE store)
6465 return CertSaveStore(store, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
6466 CERT_STORE_SAVE_AS_PKCS7, CERT_STORE_SAVE_TO_FILE, file, 0);
6469 static BOOL save_cert_as_cms(HANDLE file, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo,
6470 BOOL includeChain)
6472 BOOL ret;
6473 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
6474 CERT_STORE_CREATE_NEW_FLAG, NULL);
6476 if (store)
6478 if (includeChain)
6480 HCERTSTORE addlStore = CertOpenStore(CERT_STORE_PROV_COLLECTION,
6481 0, 0, CERT_STORE_CREATE_NEW_FLAG, NULL);
6483 if (addlStore)
6485 DWORD i;
6487 ret = TRUE;
6488 for (i = 0; ret && i < pExportInfo->cStores; i++)
6489 ret = CertAddStoreToCollection(addlStore,
6490 pExportInfo->rghStores, 0, 0);
6491 if (ret)
6493 PCCERT_CHAIN_CONTEXT chain;
6495 ret = CertGetCertificateChain(NULL,
6496 pExportInfo->u.pCertContext, NULL, addlStore, NULL, 0,
6497 NULL, &chain);
6498 if (ret)
6500 DWORD j;
6502 for (i = 0; ret && i < chain->cChain; i++)
6503 for (j = 0; ret && j < chain->rgpChain[i]->cElement;
6504 j++)
6505 ret = CertAddCertificateContextToStore(store,
6506 chain->rgpChain[i]->rgpElement[j]->pCertContext,
6507 CERT_STORE_ADD_ALWAYS, NULL);
6508 CertFreeCertificateChain(chain);
6510 else
6512 /* No chain could be created, just add the individual
6513 * cert to the message.
6515 ret = CertAddCertificateContextToStore(store,
6516 pExportInfo->u.pCertContext, CERT_STORE_ADD_ALWAYS,
6517 NULL);
6520 CertCloseStore(addlStore, 0);
6522 else
6523 ret = FALSE;
6525 else
6526 ret = CertAddCertificateContextToStore(store,
6527 pExportInfo->u.pCertContext, CERT_STORE_ADD_ALWAYS, NULL);
6528 if (ret)
6529 ret = save_store_as_cms(file, store);
6530 CertCloseStore(store, 0);
6532 else
6533 ret = FALSE;
6534 return ret;
6537 static BOOL save_serialized_store(HANDLE file, HCERTSTORE store)
6539 return CertSaveStore(store, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
6540 CERT_STORE_SAVE_AS_STORE, CERT_STORE_SAVE_TO_FILE, file, 0);
6543 static BOOL save_pfx(HANDLE file, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo,
6544 PCCRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO pContextInfo,
6545 PCRYPT_KEY_PROV_INFO keyProvInfo, BOOL deleteKeys)
6547 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING,
6548 0, CERT_STORE_CREATE_NEW_FLAG, NULL);
6549 BOOL ret = FALSE;
6551 if (store)
6553 CRYPT_DATA_BLOB pfxBlob = { 0, NULL };
6554 PCCERT_CONTEXT cert = NULL;
6555 BOOL freeKeyProvInfo = FALSE;
6557 if (pContextInfo->fExportChain)
6559 HCERTCHAINENGINE engine = NULL;
6561 if (pExportInfo->cStores)
6563 CERT_CHAIN_ENGINE_CONFIG config;
6565 memset(&config, 0, sizeof(config));
6566 config.cbSize = sizeof(config);
6567 config.cAdditionalStore = pExportInfo->cStores;
6568 config.rghAdditionalStore = pExportInfo->rghStores;
6569 ret = CertCreateCertificateChainEngine(&config, &engine);
6571 else
6572 ret = TRUE;
6573 if (ret)
6575 CERT_CHAIN_PARA chainPara;
6576 PCCERT_CHAIN_CONTEXT chain;
6578 memset(&chainPara, 0, sizeof(chainPara));
6579 chainPara.cbSize = sizeof(chainPara);
6580 ret = CertGetCertificateChain(engine,
6581 pExportInfo->u.pCertContext, NULL, NULL, &chainPara, 0, NULL,
6582 &chain);
6583 if (ret)
6585 DWORD i, j;
6587 for (i = 0; ret && i < chain->cChain; i++)
6588 for (j = 0; ret && j < chain->rgpChain[i]->cElement;
6589 j++)
6591 if (i == 0 && j == 0)
6592 ret = CertAddCertificateContextToStore(store,
6593 chain->rgpChain[i]->rgpElement[j]->pCertContext,
6594 CERT_STORE_ADD_ALWAYS, &cert);
6595 else
6596 ret = CertAddCertificateContextToStore(store,
6597 chain->rgpChain[i]->rgpElement[j]->pCertContext,
6598 CERT_STORE_ADD_ALWAYS, NULL);
6600 CertFreeCertificateChain(chain);
6603 if (engine)
6604 CertFreeCertificateChainEngine(engine);
6606 else
6607 ret = CertAddCertificateContextToStore(store,
6608 pExportInfo->u.pCertContext, CERT_STORE_ADD_ALWAYS, &cert);
6609 /* Copy private key info to newly created cert, so it'll get exported
6610 * along with the cert.
6612 if (ret && pContextInfo->fExportPrivateKeys)
6614 if (keyProvInfo)
6615 ret = CertSetCertificateContextProperty(cert,
6616 CERT_KEY_PROV_INFO_PROP_ID, 0, keyProvInfo);
6617 else
6619 if (!(keyProvInfo = export_get_private_key_info(cert)))
6620 ret = FALSE;
6621 else
6623 ret = CertSetCertificateContextProperty(cert,
6624 CERT_KEY_PROV_INFO_PROP_ID, 0, keyProvInfo);
6625 freeKeyProvInfo = TRUE;
6629 if (ret)
6631 DWORD exportFlags =
6632 REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY | EXPORT_PRIVATE_KEYS;
6634 ret = PFXExportCertStore(store, &pfxBlob,
6635 pContextInfo->pwszPassword, exportFlags);
6636 if (ret)
6638 pfxBlob.pbData = HeapAlloc(GetProcessHeap(), 0, pfxBlob.cbData);
6639 if (pfxBlob.pbData)
6641 ret = PFXExportCertStore(store, &pfxBlob,
6642 pContextInfo->pwszPassword, exportFlags);
6643 if (ret)
6645 DWORD bytesWritten;
6647 ret = WriteFile(file, pfxBlob.pbData, pfxBlob.cbData,
6648 &bytesWritten, NULL);
6651 else
6653 SetLastError(ERROR_OUTOFMEMORY);
6654 ret = FALSE;
6658 if (ret && deleteKeys)
6660 HCRYPTPROV prov;
6662 CryptAcquireContextW(&prov, keyProvInfo->pwszContainerName,
6663 keyProvInfo->pwszProvName, keyProvInfo->dwProvType,
6664 CRYPT_DELETEKEYSET);
6666 if (freeKeyProvInfo)
6667 HeapFree(GetProcessHeap(), 0, keyProvInfo);
6668 CertFreeCertificateContext(cert);
6669 CertCloseStore(store, 0);
6671 return ret;
6674 static BOOL do_export(HANDLE file, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo,
6675 PCCRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO pContextInfo,
6676 PCRYPT_KEY_PROV_INFO keyProvInfo, BOOL deleteKeys)
6678 BOOL ret;
6680 if (pContextInfo->dwSize != sizeof(CRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO))
6682 SetLastError(E_INVALIDARG);
6683 return FALSE;
6685 switch (pExportInfo->dwSubjectChoice)
6687 case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
6688 ret = save_der(file,
6689 pExportInfo->u.pCRLContext->pbCrlEncoded,
6690 pExportInfo->u.pCRLContext->cbCrlEncoded);
6691 break;
6692 case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT:
6693 ret = save_der(file,
6694 pExportInfo->u.pCTLContext->pbCtlEncoded,
6695 pExportInfo->u.pCTLContext->cbCtlEncoded);
6696 break;
6697 case CRYPTUI_WIZ_EXPORT_CERT_STORE:
6698 ret = save_serialized_store(file, pExportInfo->u.hCertStore);
6699 break;
6700 case CRYPTUI_WIZ_EXPORT_CERT_STORE_CERTIFICATES_ONLY:
6701 ret = save_store_as_cms(file, pExportInfo->u.hCertStore);
6702 break;
6703 default:
6704 switch (pContextInfo->dwExportFormat)
6706 case CRYPTUI_WIZ_EXPORT_FORMAT_DER:
6707 ret = save_der(file, pExportInfo->u.pCertContext->pbCertEncoded,
6708 pExportInfo->u.pCertContext->cbCertEncoded);
6709 break;
6710 case CRYPTUI_WIZ_EXPORT_FORMAT_BASE64:
6711 ret = save_base64(file,
6712 pExportInfo->u.pCertContext->pbCertEncoded,
6713 pExportInfo->u.pCertContext->cbCertEncoded);
6714 break;
6715 case CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7:
6716 ret = save_cert_as_cms(file, pExportInfo,
6717 pContextInfo->fExportChain);
6718 break;
6719 case CRYPTUI_WIZ_EXPORT_FORMAT_PFX:
6720 ret = save_pfx(file, pExportInfo, pContextInfo, keyProvInfo,
6721 deleteKeys);
6722 break;
6723 default:
6724 SetLastError(E_FAIL);
6725 ret = FALSE;
6728 return ret;
6731 static LRESULT CALLBACK export_finish_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
6732 LPARAM lp)
6734 LRESULT ret = 0;
6735 struct ExportWizData *data;
6737 switch (msg)
6739 case WM_INITDIALOG:
6741 PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
6742 HWND lv = GetDlgItem(hwnd, IDC_EXPORT_SETTINGS);
6743 RECT rc;
6744 LVCOLUMNW column;
6746 data = (struct ExportWizData *)page->lParam;
6747 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
6748 SendMessageW(GetDlgItem(hwnd, IDC_EXPORT_TITLE), WM_SETFONT,
6749 (WPARAM)data->titleFont, TRUE);
6750 GetWindowRect(lv, &rc);
6751 column.mask = LVCF_WIDTH;
6752 column.cx = (rc.right - rc.left) / 2 - 2;
6753 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
6754 SendMessageW(lv, LVM_INSERTCOLUMNW, 1, (LPARAM)&column);
6755 show_export_details(lv, data);
6756 break;
6758 case WM_NOTIFY:
6760 NMHDR *hdr = (NMHDR *)lp;
6762 switch (hdr->code)
6764 case PSN_SETACTIVE:
6766 HWND lv = GetDlgItem(hwnd, IDC_EXPORT_SETTINGS);
6768 data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
6769 SendMessageW(lv, LVM_DELETEALLITEMS, 0, 0);
6770 show_export_details(lv, data);
6771 PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
6772 PSWIZB_BACK | PSWIZB_FINISH);
6773 ret = TRUE;
6774 break;
6776 case PSN_WIZFINISH:
6778 int messageID;
6779 WCHAR title[MAX_STRING_LEN], message[MAX_STRING_LEN];
6780 LPCWSTR pTitle;
6781 DWORD mbFlags;
6783 data = (struct ExportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
6784 if ((data->success = do_export(data->file, &data->exportInfo,
6785 &data->contextInfo, data->keyProvInfo, data->deleteKeys)))
6787 messageID = IDS_EXPORT_SUCCEEDED;
6788 mbFlags = MB_OK;
6790 else
6792 messageID = IDS_EXPORT_FAILED;
6793 mbFlags = MB_OK | MB_ICONERROR;
6795 if (data->pwszWizardTitle)
6796 pTitle = data->pwszWizardTitle;
6797 else
6799 LoadStringW(hInstance, IDS_EXPORT_WIZARD, title, ARRAY_SIZE(title));
6800 pTitle = title;
6802 LoadStringW(hInstance, messageID, message, ARRAY_SIZE(message));
6803 MessageBoxW(hwnd, message, pTitle, mbFlags);
6804 break;
6807 break;
6810 return ret;
6813 static BOOL show_export_ui(DWORD dwFlags, HWND hwndParent,
6814 LPCWSTR pwszWizardTitle, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo, const void *pvoid)
6816 PROPSHEETHEADERW hdr;
6817 PROPSHEETPAGEW pages[6];
6818 struct ExportWizData data;
6819 int nPages = 0;
6820 BOOL hasPrivateKey, showFormatPage = TRUE;
6821 INT_PTR l;
6823 data.dwFlags = dwFlags;
6824 data.pwszWizardTitle = pwszWizardTitle;
6825 memset(&data.exportInfo, 0, sizeof(data.exportInfo));
6826 memcpy(&data.exportInfo, pExportInfo,
6827 min(sizeof(data.exportInfo), pExportInfo->dwSize));
6828 if (pExportInfo->dwSize > sizeof(data.exportInfo))
6829 data.exportInfo.dwSize = sizeof(data.exportInfo);
6830 data.contextInfo.dwSize = sizeof(data.contextInfo);
6831 data.contextInfo.dwExportFormat = CRYPTUI_WIZ_EXPORT_FORMAT_DER;
6832 data.contextInfo.fExportChain = FALSE;
6833 data.contextInfo.fStrongEncryption = FALSE;
6834 data.contextInfo.fExportPrivateKeys = FALSE;
6835 data.contextInfo.pwszPassword = NULL;
6836 data.freePassword = FALSE;
6837 if (pExportInfo->dwSubjectChoice == CRYPTUI_WIZ_EXPORT_CERT_CONTEXT &&
6838 pvoid)
6839 memcpy(&data.contextInfo, pvoid,
6840 min(((PCCRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO)pvoid)->dwSize,
6841 sizeof(data.contextInfo)));
6842 data.keyProvInfo = NULL;
6843 data.deleteKeys = FALSE;
6844 data.fileName = NULL;
6845 data.file = INVALID_HANDLE_VALUE;
6846 data.success = FALSE;
6848 memset(pages, 0, sizeof(pages));
6850 pages[nPages].dwSize = sizeof(pages[0]);
6851 pages[nPages].hInstance = hInstance;
6852 pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_EXPORT_WELCOME);
6853 pages[nPages].pfnDlgProc = export_welcome_dlg_proc;
6854 pages[nPages].dwFlags = PSP_HIDEHEADER;
6855 pages[nPages].lParam = (LPARAM)&data;
6856 nPages++;
6858 hasPrivateKey = export_info_has_private_key(pExportInfo);
6859 switch (pExportInfo->dwSubjectChoice)
6861 case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT:
6862 case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT:
6863 showFormatPage = FALSE;
6864 data.contextInfo.dwExportFormat = CRYPTUI_WIZ_EXPORT_FORMAT_DER;
6865 break;
6866 case CRYPTUI_WIZ_EXPORT_CERT_STORE:
6867 showFormatPage = FALSE;
6868 data.contextInfo.dwExportFormat =
6869 CRYPTUI_WIZ_EXPORT_FORMAT_SERIALIZED_CERT_STORE;
6870 break;
6871 case CRYPTUI_WIZ_EXPORT_CERT_STORE_CERTIFICATES_ONLY:
6872 showFormatPage = FALSE;
6873 data.contextInfo.dwExportFormat = CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7;
6874 break;
6877 if (hasPrivateKey && showFormatPage)
6879 pages[nPages].dwSize = sizeof(pages[0]);
6880 pages[nPages].hInstance = hInstance;
6881 pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_EXPORT_PRIVATE_KEY);
6882 pages[nPages].pfnDlgProc = export_private_key_dlg_proc;
6883 pages[nPages].dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
6884 pages[nPages].pszHeaderTitle =
6885 MAKEINTRESOURCEW(IDS_EXPORT_PRIVATE_KEY_TITLE);
6886 pages[nPages].pszHeaderSubTitle =
6887 MAKEINTRESOURCEW(IDS_EXPORT_PRIVATE_KEY_SUBTITLE);
6888 pages[nPages].lParam = (LPARAM)&data;
6889 nPages++;
6891 if (showFormatPage)
6893 pages[nPages].dwSize = sizeof(pages[0]);
6894 pages[nPages].hInstance = hInstance;
6895 pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_EXPORT_FORMAT);
6896 pages[nPages].pfnDlgProc = export_format_dlg_proc;
6897 pages[nPages].dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
6898 pages[nPages].pszHeaderTitle =
6899 MAKEINTRESOURCEW(IDS_EXPORT_FORMAT_TITLE);
6900 pages[nPages].pszHeaderSubTitle =
6901 MAKEINTRESOURCEW(IDS_EXPORT_FORMAT_SUBTITLE);
6902 pages[nPages].lParam = (LPARAM)&data;
6903 nPages++;
6905 if (hasPrivateKey && showFormatPage)
6907 pages[nPages].dwSize = sizeof(pages[0]);
6908 pages[nPages].hInstance = hInstance;
6909 pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_EXPORT_PASSWORD);
6910 pages[nPages].pfnDlgProc = export_password_dlg_proc;
6911 pages[nPages].dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
6912 pages[nPages].pszHeaderTitle =
6913 MAKEINTRESOURCEW(IDS_EXPORT_PASSWORD_TITLE);
6914 pages[nPages].pszHeaderSubTitle =
6915 MAKEINTRESOURCEW(IDS_EXPORT_PASSWORD_SUBTITLE);
6916 pages[nPages].lParam = (LPARAM)&data;
6917 nPages++;
6920 pages[nPages].dwSize = sizeof(pages[0]);
6921 pages[nPages].hInstance = hInstance;
6922 pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_EXPORT_FILE);
6923 pages[nPages].pfnDlgProc = export_file_dlg_proc;
6924 pages[nPages].dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
6925 pages[nPages].pszHeaderTitle = MAKEINTRESOURCEW(IDS_EXPORT_FILE_TITLE);
6926 pages[nPages].pszHeaderSubTitle =
6927 MAKEINTRESOURCEW(IDS_EXPORT_FILE_SUBTITLE);
6928 pages[nPages].lParam = (LPARAM)&data;
6929 nPages++;
6931 pages[nPages].dwSize = sizeof(pages[0]);
6932 pages[nPages].hInstance = hInstance;
6933 pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_EXPORT_FINISH);
6934 pages[nPages].pfnDlgProc = export_finish_dlg_proc;
6935 pages[nPages].dwFlags = PSP_HIDEHEADER;
6936 pages[nPages].lParam = (LPARAM)&data;
6937 nPages++;
6939 memset(&hdr, 0, sizeof(hdr));
6940 hdr.dwSize = sizeof(hdr);
6941 hdr.hwndParent = hwndParent;
6942 hdr.dwFlags = PSH_PROPSHEETPAGE | PSH_WIZARD97_NEW | PSH_HEADER |
6943 PSH_WATERMARK;
6944 hdr.hInstance = hInstance;
6945 if (pwszWizardTitle)
6946 hdr.pszCaption = pwszWizardTitle;
6947 else
6948 hdr.pszCaption = MAKEINTRESOURCEW(IDS_EXPORT_WIZARD);
6949 hdr.u3.ppsp = pages;
6950 hdr.nPages = nPages;
6951 hdr.u4.pszbmWatermark = MAKEINTRESOURCEW(IDB_CERT_WATERMARK);
6952 hdr.u5.pszbmHeader = MAKEINTRESOURCEW(IDB_CERT_HEADER);
6953 l = PropertySheetW(&hdr);
6954 DeleteObject(data.titleFont);
6955 if (data.freePassword)
6956 HeapFree(GetProcessHeap(), 0,
6957 (LPWSTR)data.contextInfo.pwszPassword);
6958 HeapFree(GetProcessHeap(), 0, data.keyProvInfo);
6959 CloseHandle(data.file);
6960 HeapFree(GetProcessHeap(), 0, data.fileName);
6961 if (l == 0)
6963 SetLastError(ERROR_CANCELLED);
6964 return FALSE;
6966 else
6967 return data.success;
6970 BOOL WINAPI CryptUIWizExport(DWORD dwFlags, HWND hwndParent,
6971 LPCWSTR pwszWizardTitle, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo, void *pvoid)
6973 BOOL ret;
6975 TRACE("(%08x, %p, %s, %p, %p)\n", dwFlags, hwndParent,
6976 debugstr_w(pwszWizardTitle), pExportInfo, pvoid);
6978 if (!(dwFlags & CRYPTUI_WIZ_NO_UI))
6979 ret = show_export_ui(dwFlags, hwndParent, pwszWizardTitle, pExportInfo,
6980 pvoid);
6981 else
6983 HANDLE file = CreateFileW(pExportInfo->pwszExportFileName,
6984 GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
6985 CREATE_ALWAYS, 0, NULL);
6987 if (file != INVALID_HANDLE_VALUE)
6989 ret = do_export(file, pExportInfo, pvoid, NULL, FALSE);
6990 CloseHandle(file);
6992 else
6993 ret = FALSE;
6995 return ret;
6998 BOOL WINAPI CryptUIDlgViewSignerInfoA(CRYPTUI_VIEWSIGNERINFO_STRUCTA *pcvsi)
7000 FIXME("%p: stub\n", pcvsi);
7001 return FALSE;
7004 static void init_columns(HWND lv, DWORD flags)
7006 WCHAR buf[MAX_STRING_LEN];
7007 LVCOLUMNW column;
7008 DWORD i = 0;
7010 SendMessageW(lv, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
7011 column.mask = LVCF_WIDTH | LVCF_TEXT;
7012 column.cx = 90;
7013 column.pszText = buf;
7014 if (!(flags & CRYPTUI_SELECT_ISSUEDTO_COLUMN))
7016 LoadStringW(hInstance, IDS_SUBJECT_COLUMN, buf, ARRAY_SIZE(buf));
7017 SendMessageW(lv, LVM_INSERTCOLUMNW, i++, (LPARAM)&column);
7019 if (!(flags & CRYPTUI_SELECT_ISSUEDBY_COLUMN))
7021 LoadStringW(hInstance, IDS_ISSUER_COLUMN, buf, ARRAY_SIZE(buf));
7022 SendMessageW(lv, LVM_INSERTCOLUMNW, i++, (LPARAM)&column);
7024 if (!(flags & CRYPTUI_SELECT_INTENDEDUSE_COLUMN))
7026 LoadStringW(hInstance, IDS_INTENDED_USE_COLUMN, buf, ARRAY_SIZE(buf));
7027 SendMessageW(lv, LVM_INSERTCOLUMNW, i++, (LPARAM)&column);
7029 if (!(flags & CRYPTUI_SELECT_FRIENDLYNAME_COLUMN))
7031 LoadStringW(hInstance, IDS_FRIENDLY_NAME_COLUMN, buf, ARRAY_SIZE(buf));
7032 SendMessageW(lv, LVM_INSERTCOLUMNW, i++, (LPARAM)&column);
7034 if (!(flags & CRYPTUI_SELECT_EXPIRATION_COLUMN))
7036 LoadStringW(hInstance, IDS_EXPIRATION_COLUMN, buf, ARRAY_SIZE(buf));
7037 SendMessageW(lv, LVM_INSERTCOLUMNW, i++, (LPARAM)&column);
7039 if (!(flags & CRYPTUI_SELECT_LOCATION_COLUMN))
7041 LoadStringW(hInstance, IDS_LOCATION_COLUMN, buf, ARRAY_SIZE(buf));
7042 SendMessageW(lv, LVM_INSERTCOLUMNW, i++, (LPARAM)&column);
7046 static void add_cert_to_list(HWND lv, PCCERT_CONTEXT cert, DWORD flags, DWORD *allocatedLen,
7047 LPWSTR *str)
7049 DWORD len;
7050 LVITEMW item;
7051 WCHAR dateFmt[80]; /* sufficient for LOCALE_SSHORTDATE */
7052 WCHAR buf[80];
7053 SYSTEMTIME sysTime;
7054 LPWSTR none, usages;
7056 item.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_TEXT;
7057 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
7058 item.iSubItem = 0;
7059 item.iImage = 0;
7060 item.lParam = (LPARAM)CertDuplicateCertificateContext(cert);
7061 if (!item.iItem)
7063 item.mask |= LVIF_STATE;
7064 item.state = LVIS_SELECTED;
7065 item.stateMask = -1;
7067 if (!(flags & CRYPTUI_SELECT_ISSUEDTO_COLUMN))
7069 len = CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, NULL, 0);
7070 if (len > *allocatedLen)
7072 HeapFree(GetProcessHeap(), 0, *str);
7073 *str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7074 if (*str)
7075 *allocatedLen = len;
7077 if (*str)
7079 CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, *str, len);
7080 item.pszText = *str;
7081 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
7083 item.mask = LVIF_TEXT;
7084 ++item.iSubItem;
7086 if (!(flags & CRYPTUI_SELECT_ISSUEDBY_COLUMN))
7088 len = CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG, NULL,
7089 NULL, 0);
7090 if (len > *allocatedLen)
7092 HeapFree(GetProcessHeap(), 0, *str);
7093 *str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7094 if (*str)
7095 *allocatedLen = len;
7097 if (*str)
7099 CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG, NULL,
7100 *str, len);
7101 item.pszText = *str;
7102 if (!item.iSubItem)
7103 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
7104 else
7105 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
7107 item.mask = LVIF_TEXT;
7108 ++item.iSubItem;
7110 if (!(flags & CRYPTUI_SELECT_INTENDEDUSE_COLUMN))
7112 get_cert_usages(cert, &usages);
7113 if (usages)
7115 item.pszText = usages;
7116 if (!item.iSubItem)
7117 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
7118 else
7119 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
7120 HeapFree(GetProcessHeap(), 0, usages);
7122 item.mask = LVIF_TEXT;
7123 ++item.iSubItem;
7125 if (!(flags & CRYPTUI_SELECT_FRIENDLYNAME_COLUMN))
7127 if (!CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID, NULL, &len))
7128 len = LoadStringW(hInstance, IDS_FRIENDLY_NAME_NONE, (LPWSTR)&none, 0);
7129 if (len > *allocatedLen)
7131 HeapFree(GetProcessHeap(), 0, *str);
7132 *str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7133 if (*str)
7134 *allocatedLen = len;
7136 if (*str)
7138 if (!CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID, *str, &len))
7139 item.pszText = none;
7140 else
7141 item.pszText = *str;
7142 if (!item.iSubItem)
7143 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
7144 else
7145 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
7147 item.mask = LVIF_TEXT;
7148 ++item.iSubItem;
7150 if (!(flags & CRYPTUI_SELECT_EXPIRATION_COLUMN))
7152 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SSHORTDATE, dateFmt, ARRAY_SIZE(dateFmt));
7153 FileTimeToSystemTime(&cert->pCertInfo->NotAfter, &sysTime);
7154 GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, buf, ARRAY_SIZE(buf));
7155 item.pszText = buf;
7156 if (!item.iSubItem)
7157 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
7158 else
7159 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
7160 item.mask = LVIF_TEXT;
7161 ++item.iSubItem;
7163 if (!(flags & CRYPTUI_SELECT_LOCATION_COLUMN))
7165 static int show_fixme;
7166 if (!show_fixme++)
7167 FIXME("showing location is not implemented\n");
7168 LoadStringW(hInstance, IDS_NO_IMPL, buf, ARRAY_SIZE(buf));
7169 if (!item.iSubItem)
7170 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
7171 else
7172 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
7176 static void add_store_certs(HWND lv, HCERTSTORE store, DWORD flags, PFNCFILTERPROC filter,
7177 void *callback_data)
7179 PCCERT_CONTEXT cert = NULL;
7180 BOOL select = FALSE;
7181 DWORD allocatedLen = 0;
7182 LPWSTR str = NULL;
7184 do {
7185 cert = CertEnumCertificatesInStore(store, cert);
7186 if (cert && (!filter || filter(cert, &select, callback_data)))
7187 add_cert_to_list(lv, cert, flags, &allocatedLen, &str);
7188 } while (cert);
7189 HeapFree(GetProcessHeap(), 0, str);
7192 static PCCERT_CONTEXT select_cert_get_selected(HWND hwnd, int selection)
7194 HWND lv = GetDlgItem(hwnd, IDC_SELECT_CERTS);
7195 PCCERT_CONTEXT cert = NULL;
7196 LVITEMW item;
7198 if (selection < 0)
7199 selection = SendMessageW(lv, LVM_GETNEXTITEM, -1, LVNI_SELECTED);
7200 if (selection < 0)
7201 return NULL;
7202 item.mask = LVIF_PARAM;
7203 item.iItem = selection;
7204 item.iSubItem = 0;
7205 if (SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item))
7206 cert = (PCCERT_CONTEXT)item.lParam;
7207 return cert;
7210 static void select_cert_update_view_button(HWND hwnd)
7212 HWND lv = GetDlgItem(hwnd, IDC_SELECT_CERTS);
7213 int numSelected = SendMessageW(lv, LVM_GETSELECTEDCOUNT, 0, 0);
7215 EnableWindow(GetDlgItem(hwnd, IDC_SELECT_VIEW_CERT), numSelected == 1);
7218 struct SelectCertData
7220 PCCERT_CONTEXT *cert;
7221 DWORD dateColumn;
7222 HIMAGELIST imageList;
7223 LPCWSTR title;
7224 DWORD cStores;
7225 HCERTSTORE *rghStores;
7226 DWORD cPropSheetPages;
7227 LPCPROPSHEETPAGEW rgPropSheetPages;
7228 PFNCCERTDISPLAYPROC displayProc;
7229 void *callbackData;
7232 static void select_cert_view(HWND hwnd, PCCERT_CONTEXT cert, struct SelectCertData *data)
7234 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
7236 if (data->displayProc && data->displayProc(cert, hwnd, data->callbackData))
7237 return;
7238 memset(&viewInfo, 0, sizeof(viewInfo));
7239 viewInfo.dwSize = sizeof(viewInfo);
7240 viewInfo.hwndParent = hwnd;
7241 viewInfo.pCertContext = cert;
7242 viewInfo.cStores = data->cStores;
7243 viewInfo.rghStores = data->rghStores;
7244 viewInfo.cPropSheetPages = data->cPropSheetPages;
7245 viewInfo.rgPropSheetPages = data->rgPropSheetPages;
7246 /* FIXME: this should be modal */
7247 CryptUIDlgViewCertificateW(&viewInfo, NULL);
7250 struct SortData
7252 HWND hwnd;
7253 int column;
7256 static int CALLBACK select_cert_sort_by_text(LPARAM lp1, LPARAM lp2, LPARAM lp)
7258 struct SortData *data = (struct SortData *)lp;
7259 return cert_mgr_sort_by_text(data->hwnd, data->column, lp1, lp2);
7262 struct SelectCertParam
7264 PCCRYPTUI_SELECTCERTIFICATE_STRUCTW pcsc;
7265 PCCERT_CONTEXT cert;
7268 static LRESULT CALLBACK select_cert_dlg_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
7270 struct SelectCertData *data;
7272 switch (msg)
7274 case WM_INITDIALOG:
7276 struct SelectCertParam *param = (struct SelectCertParam *)lp;
7277 PCCRYPTUI_SELECTCERTIFICATE_STRUCTW pcsc = param->pcsc;
7278 HWND lv = GetDlgItem(hwnd, IDC_SELECT_CERTS);
7279 DWORD i = 0;
7281 data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data));
7282 if (!data)
7283 return 0;
7284 data->cert = &param->cert;
7285 data->dateColumn = 4 -
7286 ((pcsc->dwDontUseColumn & CRYPTUI_SELECT_ISSUEDTO_COLUMN) ? 1 : 0) -
7287 ((pcsc->dwDontUseColumn & CRYPTUI_SELECT_ISSUEDBY_COLUMN) ? 1 : 0) -
7288 ((pcsc->dwDontUseColumn & CRYPTUI_SELECT_INTENDEDUSE_COLUMN) ? 1 : 0) -
7289 ((pcsc->dwDontUseColumn & CRYPTUI_SELECT_FRIENDLYNAME_COLUMN) ? 1 : 0);
7290 data->imageList = ImageList_Create(16, 16, ILC_COLOR4 | ILC_MASK, 2, 0);
7291 if (data->imageList)
7293 HBITMAP bmp;
7294 COLORREF backColor = RGB(255, 0, 255);
7296 bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_SMALL_ICONS));
7297 ImageList_AddMasked(data->imageList, bmp, backColor);
7298 DeleteObject(bmp);
7299 ImageList_SetBkColor(data->imageList, CLR_NONE);
7300 SendMessageW(GetDlgItem(hwnd, IDC_SELECT_CERTS), LVM_SETIMAGELIST, LVSIL_SMALL,
7301 (LPARAM)data->imageList);
7303 data->title = pcsc->szTitle;
7304 data->cStores = pcsc->cStores;
7305 data->rghStores = pcsc->rghStores;
7306 data->cPropSheetPages = pcsc->cPropSheetPages;
7307 data->rgPropSheetPages = pcsc->rgPropSheetPages;
7308 data->displayProc = pcsc->pDisplayCallback;
7309 data->callbackData = pcsc->pvCallbackData;
7310 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
7312 if (pcsc->szTitle)
7313 SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)pcsc->szTitle);
7314 if (pcsc->szDisplayString)
7315 SendMessageW(GetDlgItem(hwnd, IDC_SELECT_DISPLAY_STRING), WM_SETTEXT, 0,
7316 (LPARAM)pcsc->szDisplayString);
7317 init_columns(lv, pcsc->dwDontUseColumn);
7318 while (i < pcsc->cDisplayStores)
7319 add_store_certs(lv, pcsc->rghDisplayStores[i++], pcsc->dwDontUseColumn,
7320 pcsc->pFilterCallback, pcsc->pvCallbackData);
7321 select_cert_update_view_button(hwnd);
7322 break;
7324 case WM_NOTIFY:
7326 NMHDR *hdr = (NMHDR *)lp;
7328 switch (hdr->code)
7330 case NM_DBLCLK:
7332 PCCERT_CONTEXT cert = select_cert_get_selected(hwnd, ((NMITEMACTIVATE *)lp)->iItem);
7334 data = (struct SelectCertData *)GetWindowLongPtrW(hwnd, DWLP_USER);
7335 if (cert)
7336 select_cert_view(hwnd, cert, data);
7337 break;
7339 case LVN_COLUMNCLICK:
7341 NMLISTVIEW *nmlv = (NMLISTVIEW *)lp;
7342 HWND lv = GetDlgItem(hwnd, IDC_SELECT_CERTS);
7344 /* FIXME: doesn't support swapping sort order between ascending and descending. */
7345 data = (struct SelectCertData *)GetWindowLongPtrW(hwnd, DWLP_USER);
7346 if (nmlv->iSubItem == data->dateColumn)
7347 SendMessageW(lv, LVM_SORTITEMS, 0, (LPARAM)cert_mgr_sort_by_date);
7348 else
7350 struct SortData sortData;
7352 sortData.hwnd = lv;
7353 sortData.column = nmlv->iSubItem;
7354 SendMessageW(lv, LVM_SORTITEMSEX, (WPARAM)&sortData,
7355 (LPARAM)select_cert_sort_by_text);
7357 break;
7360 break;
7362 case WM_COMMAND:
7363 switch (wp)
7365 case IDOK:
7367 PCCERT_CONTEXT cert = select_cert_get_selected(hwnd, -1);
7369 data = (struct SelectCertData *)GetWindowLongPtrW(hwnd, DWLP_USER);
7370 if (!cert)
7372 WCHAR buf[40], title[40];
7374 LoadStringW(hInstance, IDS_SELECT_CERT, buf, ARRAY_SIZE(buf));
7375 if (!data->title)
7376 LoadStringW(hInstance, IDS_SELECT_CERT_TITLE, title, ARRAY_SIZE(title));
7377 MessageBoxW(hwnd, buf, data->title ? data->title : title, MB_OK | MB_ICONWARNING);
7378 break;
7380 *data->cert = CertDuplicateCertificateContext(cert);
7381 free_certs(GetDlgItem(hwnd, IDC_SELECT_CERTS));
7382 ImageList_Destroy(data->imageList);
7383 HeapFree(GetProcessHeap(), 0, data);
7384 EndDialog(hwnd, IDOK);
7385 break;
7387 case IDCANCEL:
7388 data = (struct SelectCertData *)GetWindowLongPtrW(hwnd, DWLP_USER);
7389 free_certs(GetDlgItem(hwnd, IDC_SELECT_CERTS));
7390 ImageList_Destroy(data->imageList);
7391 HeapFree(GetProcessHeap(), 0, data);
7392 EndDialog(hwnd, IDCANCEL);
7393 break;
7394 case IDC_SELECT_VIEW_CERT:
7396 PCCERT_CONTEXT cert = select_cert_get_selected(hwnd, -1);
7398 data = (struct SelectCertData *)GetWindowLongPtrW(hwnd, DWLP_USER);
7399 if (cert)
7400 select_cert_view(hwnd, cert, data);
7401 break;
7404 break;
7406 return 0;
7409 PCCERT_CONTEXT WINAPI CryptUIDlgSelectCertificateW(PCCRYPTUI_SELECTCERTIFICATE_STRUCTW pcsc)
7411 struct SelectCertParam param;
7413 TRACE("%p\n", pcsc);
7415 if (pcsc->dwSize != sizeof(*pcsc) && pcsc->dwSize != sizeof(*pcsc) - sizeof(HCERTSTORE))
7417 WARN("unexpected size %d\n", pcsc->dwSize);
7418 SetLastError(E_INVALIDARG);
7419 return NULL;
7421 if (pcsc->dwFlags & CRYPTUI_SELECTCERT_MULTISELECT)
7422 FIXME("ignoring CRYPTUI_SELECTCERT_MULTISELECT\n");
7423 param.pcsc = pcsc;
7424 param.cert = NULL;
7425 DialogBoxParamW(hInstance, MAKEINTRESOURCEW(IDD_SELECT_CERT), pcsc->hwndParent,
7426 select_cert_dlg_proc, (LPARAM)&param);
7427 return param.cert;
7430 static void free_prop_sheet_pages(PROPSHEETPAGEW *pages, DWORD num)
7432 DWORD i;
7434 for (i = 0; i < num; i++)
7436 if (!(pages[i].dwFlags & PSP_DLGINDIRECT) && !IS_INTRESOURCE(pages[i].u.pszTemplate))
7437 HeapFree(GetProcessHeap(), 0, (void *)pages[i].u.pszTemplate);
7438 if ((pages[i].dwFlags & PSP_USEICONID) && !IS_INTRESOURCE(pages[i].u2.pszIcon))
7439 HeapFree(GetProcessHeap(), 0, (void *)pages[i].u2.pszIcon);
7440 if ((pages[i].dwFlags & PSP_USETITLE) && !IS_INTRESOURCE(pages[i].pszTitle))
7441 HeapFree(GetProcessHeap(), 0, (void *)pages[i].pszTitle);
7442 if ((pages[i].dwFlags & PSP_USEHEADERTITLE) && !IS_INTRESOURCE(pages[i].pszHeaderTitle))
7443 HeapFree(GetProcessHeap(), 0, (void *)pages[i].pszHeaderTitle);
7444 if ((pages[i].dwFlags & PSP_USEHEADERSUBTITLE) &&
7445 !IS_INTRESOURCE(pages[i].pszHeaderSubTitle))
7446 HeapFree(GetProcessHeap(), 0, (void *)pages[i].pszHeaderSubTitle);
7448 HeapFree(GetProcessHeap(), 0, pages);
7451 static PROPSHEETPAGEW *prop_sheet_pages_AtoW(LPCPROPSHEETPAGEA pages, DWORD num)
7453 PROPSHEETPAGEW *psp;
7454 DWORD i, size = sizeof(*psp) * num;
7456 psp = HeapAlloc(GetProcessHeap(), 0, size);
7457 if (!psp)
7458 return NULL;
7459 memcpy(psp, pages, size);
7460 for (i = 0; i < num; i++)
7462 if (!(pages[i].dwFlags & PSP_DLGINDIRECT) && !IS_INTRESOURCE(pages[i].u.pszTemplate))
7463 psp[i].u.pszTemplate = NULL;
7464 if ((pages[i].dwFlags & PSP_USEICONID) && !IS_INTRESOURCE(pages[i].u2.pszIcon))
7465 psp[i].u2.pszIcon = NULL;
7466 if ((pages[i].dwFlags & PSP_USETITLE) && !IS_INTRESOURCE(pages[i].pszTitle))
7467 psp[i].pszTitle = NULL;
7468 if (pages[i].dwFlags & PSP_USECALLBACK)
7469 psp[i].pfnCallback = NULL;
7470 if ((pages[i].dwFlags & PSP_USEHEADERTITLE) && !IS_INTRESOURCE(pages[i].pszHeaderTitle))
7471 psp[i].pszHeaderTitle = NULL;
7472 if ((pages[i].dwFlags & PSP_USEHEADERSUBTITLE) &&
7473 !IS_INTRESOURCE(pages[i].pszHeaderSubTitle))
7474 psp[i].pszHeaderSubTitle = NULL;
7476 for (i = 0; i < num; i++)
7478 if (!(pages[i].dwFlags & PSP_DLGINDIRECT) && !IS_INTRESOURCE(pages[i].u.pszTemplate))
7480 if (!(psp[i].u.pszTemplate = strdupAtoW( pages[i].u.pszTemplate ))) goto error;
7482 if ((pages[i].dwFlags & PSP_USEICONID) && !IS_INTRESOURCE(pages[i].u2.pszIcon))
7484 if (!(psp[i].u2.pszIcon = strdupAtoW( pages[i].u2.pszIcon ))) goto error;
7486 if ((pages[i].dwFlags & PSP_USETITLE) && !IS_INTRESOURCE(pages[i].pszTitle))
7488 if (!(psp[i].pszTitle = strdupAtoW( pages[i].pszTitle ))) goto error;
7490 if (pages[i].dwFlags & PSP_USECALLBACK)
7491 FIXME("ignoring pfnCallback\n");
7492 if ((pages[i].dwFlags & PSP_USEHEADERTITLE) && !IS_INTRESOURCE(pages[i].pszHeaderTitle))
7494 if (!(psp[i].pszHeaderTitle = strdupAtoW( pages[i].pszHeaderTitle ))) goto error;
7496 if ((pages[i].dwFlags & PSP_USEHEADERSUBTITLE) &&
7497 !IS_INTRESOURCE(pages[i].pszHeaderSubTitle))
7499 if (!(psp[i].pszHeaderSubTitle = strdupAtoW( pages[i].pszHeaderSubTitle ))) goto error;
7502 return psp;
7503 error:
7504 free_prop_sheet_pages(psp, num);
7505 return NULL;
7508 PCCERT_CONTEXT WINAPI CryptUIDlgSelectCertificateA(PCCRYPTUI_SELECTCERTIFICATE_STRUCTA pcsc)
7510 PCCERT_CONTEXT cert = NULL;
7511 CRYPTUI_SELECTCERTIFICATE_STRUCTW selCertInfo;
7512 LPWSTR title = NULL, display_str = NULL;
7513 PROPSHEETPAGEW *pages = NULL;
7515 TRACE("%p\n", pcsc);
7517 if (pcsc->dwSize != sizeof(*pcsc) && pcsc->dwSize != sizeof(*pcsc) - sizeof(HCERTSTORE))
7519 WARN("unexpected size %d\n", pcsc->dwSize);
7520 SetLastError(E_INVALIDARG);
7521 return NULL;
7523 memcpy(&selCertInfo, pcsc, pcsc->dwSize);
7524 if (pcsc->szTitle)
7526 if (!(title = strdupAtoW( pcsc->szTitle ))) goto error;
7527 selCertInfo.szTitle = title;
7529 if (pcsc->szDisplayString)
7531 if (!(display_str = strdupAtoW( pcsc->szDisplayString ))) goto error;
7532 selCertInfo.szDisplayString = display_str;
7534 if (pcsc->cPropSheetPages)
7536 pages = prop_sheet_pages_AtoW(pcsc->rgPropSheetPages, pcsc->cPropSheetPages);
7537 if (!pages)
7538 goto error;
7539 selCertInfo.rgPropSheetPages = pages;
7541 cert = CryptUIDlgSelectCertificateW(&selCertInfo);
7542 error:
7543 HeapFree(GetProcessHeap(), 0, title);
7544 HeapFree(GetProcessHeap(), 0, display_str);
7545 if (pcsc->cPropSheetPages)
7546 free_prop_sheet_pages(pages, pcsc->cPropSheetPages);
7547 return cert;
7550 PCCERT_CONTEXT WINAPI CryptUIDlgSelectCertificateFromStore(HCERTSTORE hCertStore, HWND hwnd, LPCWSTR pwszTitle,
7551 LPCWSTR pwszDisplayString, DWORD dwDontUseColumn,
7552 DWORD dwFlags, void *pvReserved)
7554 FIXME("%p %p %s %s %d %d %p: stub\n", hCertStore, hwnd, debugstr_w(pwszTitle), debugstr_w(pwszDisplayString), dwDontUseColumn, dwFlags, pvReserved);
7555 return NULL;
7558 BOOL WINAPI CryptUIWizDigitalSign(DWORD flags, HWND parent, LPCWSTR title, PCCRYPTUI_WIZ_DIGITAL_SIGN_INFO info,
7559 PCCRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT *context)
7561 FIXME("%d %p %s %p %p: stub\n", flags, parent, debugstr_w(title), info, context);
7562 return FALSE;