diff --git a/reactos/dll/win32/cryptui/certheader.bmp b/reactos/dll/win32/cryptui/certheader.bmp
new file mode 100644
index 00000000000..de67d4ed738
Binary files /dev/null and b/reactos/dll/win32/cryptui/certheader.bmp differ
diff --git a/reactos/dll/win32/cryptui/certwatermark.bmp b/reactos/dll/win32/cryptui/certwatermark.bmp
new file mode 100644
index 00000000000..213ff3bb26e
Binary files /dev/null and b/reactos/dll/win32/cryptui/certwatermark.bmp differ
diff --git a/reactos/dll/win32/cryptui/cryptui.rbuild b/reactos/dll/win32/cryptui/cryptui.rbuild
index 08451e0519a..932bffe383c 100644
--- a/reactos/dll/win32/cryptui/cryptui.rbuild
+++ b/reactos/dll/win32/cryptui/cryptui.rbuild
@@ -15,10 +15,12 @@
ole32
crypt32
gdi32
+ advapi32
uuid
urlmon
wintrust
comctl32
+ comdlg32
ntdll
diff --git a/reactos/dll/win32/cryptui/cryptui.rc b/reactos/dll/win32/cryptui/cryptui.rc
index 71dc3a08084..c0bc8233aa5 100644
--- a/reactos/dll/win32/cryptui/cryptui.rc
+++ b/reactos/dll/win32/cryptui/cryptui.rc
@@ -40,4 +40,10 @@ IDB_CERT_WARNING BITMAP LOADONCALL DISCARDABLE certwarning.bmp
/* @makedep: checks.bmp */
IDB_CHECKS BITMAP LOADONCALL DISCARDABLE checks.bmp
+/* @makedep: certwatermark.bmp */
+IDB_CERT_WATERMARK BITMAP LOADONCALL DISCARDABLE certwatermark.bmp
+
+/* @makedep: certheader.bmp */
+IDB_CERT_HEADER BITMAP LOADONCALL DISCARDABLE certheader.bmp
+
#include "cryptui_En.rc"
diff --git a/reactos/dll/win32/cryptui/cryptui.spec b/reactos/dll/win32/cryptui/cryptui.spec
index 9c5a8612640..c8b161f4d04 100644
--- a/reactos/dll/win32/cryptui/cryptui.spec
+++ b/reactos/dll/win32/cryptui/cryptui.spec
@@ -5,8 +5,8 @@
5 stub CryptUIDlgSelectCertificateA
6 stub CryptUIDlgSelectCertificateFromStore
7 stub CryptUIDlgSelectCertificateW
-8 stub CryptUIDlgSelectStoreA
-9 stub CryptUIDlgSelectStoreW
+8 stdcall CryptUIDlgSelectStoreA(ptr)
+9 stdcall CryptUIDlgSelectStoreW(ptr)
10 stub CryptUIDlgViewCRLA
11 stub CryptUIDlgViewCRLW
12 stub CryptUIDlgViewCTLA
diff --git a/reactos/dll/win32/cryptui/cryptui_En.rc b/reactos/dll/win32/cryptui/cryptui_En.rc
index f904fa7d6ac..119eac6996e 100644
--- a/reactos/dll/win32/cryptui/cryptui_En.rc
+++ b/reactos/dll/win32/cryptui/cryptui_En.rc
@@ -61,6 +61,60 @@ STRINGTABLE DISCARDABLE
IDS_CERTIFICATE_PROPERTIES "Certificate Properties"
IDS_CERTIFICATE_PURPOSE_ERROR "Please enter an OID in the form 1.2.3.4"
IDS_CERTIFICATE_PURPOSE_EXISTS "The OID you entered already exists."
+ IDS_SELECT_STORE_TITLE "Select Certificate Store"
+ IDS_SELECT_STORE "Please select a certificate store."
+ IDS_IMPORT_WIZARD "Certificate Import Wizard"
+ IDS_IMPORT_TYPE_MISMATCH "The file contains objects that do not match the given criteria. Please select another file."
+ IDS_IMPORT_FILE_TITLE "File to Import"
+ IDS_IMPORT_FILE_SUBTITLE "Specify the file you want to import."
+ IDS_IMPORT_STORE_TITLE "Certificate Store"
+ IDS_IMPORT_STORE_SUBTITLE "Certificate stores are collections of certificates, certificate revocation lists, and certificate trust lists."
+ IDS_IMPORT_FILTER_CERT "X.509 Certificate (*.cer; *.crt)"
+ IDS_IMPORT_FILTER_PFX "Personal Information Exchange (*.pfx; *.p12)"
+ IDS_IMPORT_FILTER_CRL "Certificate Revocation List (*.crl)"
+ IDS_IMPORT_FILTER_CTL "Certificate Trust List (*.stl)"
+ IDS_IMPORT_FILTER_SERIALIZED_STORE "Microsoft Serialized Certificate Store (*.sst)"
+ IDS_IMPORT_FILTER_CMS "CMS/PKCS #7 Messages (*.spc; *.p7b)"
+ IDS_IMPORT_FILTER_ALL "All Files (*.*)"
+ IDS_IMPORT_EMPTY_FILE "Please select a file."
+ IDS_IMPORT_BAD_FORMAT "The file format is not recognized. Please select another file."
+ IDS_IMPORT_OPEN_FAILED "Could not open "
+ IDS_IMPORT_DEST_DETERMINED "Determined by the program"
+ IDS_IMPORT_SELECT_STORE "Please select a store"
+ IDS_IMPORT_STORE_SELECTION "Certificate Store Selected"
+ IDS_IMPORT_DEST_AUTOMATIC "Automatically determined by the program"
+ IDS_IMPORT_FILE "File"
+ IDS_IMPORT_CONTENT "Content"
+ IDS_IMPORT_CONTENT_CERT "Certificate"
+ IDS_IMPORT_CONTENT_CRL "Certificate Revocation List"
+ IDS_IMPORT_CONTENT_CTL "Certificate Trust List"
+ IDS_IMPORT_CONTENT_CMS "CMS/PKCS #7 Message"
+ IDS_IMPORT_CONTENT_PFX "Personal Information Exchange"
+ IDS_IMPORT_CONTENT_STORE "Certificate Store"
+ IDS_IMPORT_SUCCEEDED "The import was successful."
+ IDS_IMPORT_FAILED "The import failed."
+ IDS_WIZARD_TITLE_FONT "Arial"
+ IDS_PURPOSE_ALL ""
+ IDS_PURPOSE_ADVANCED ""
+ IDS_SUBJECT_COLUMN "Issued To"
+ IDS_ISSUER_COLUMN "Issued By"
+ IDS_EXPIRATION_COLUMN "Expiration Date"
+ IDS_FRIENDLY_NAME_COLUMN "Friendly Name"
+ IDS_ALLOWED_PURPOSE_ALL ""
+ IDS_ALLOWED_PURPOSE_NONE ""
+ IDS_WARN_REMOVE_MY "You will no longer be able to decrypt mesages with this certificate, or sign messages with it.\nAre you sure you want to remove this certificate?"
+ IDS_WARN_REMOVE_PLURAL_MY "You will no longer be able to decrypt mesages with these certificate, or sign messages with them.\nAre you sure you want to remove these certificates?"
+ IDS_WARN_REMOVE_ADDRESSBOOK "You will no longer be able to encrypt messages with this certificate, or verify messages signed with it.\nAre you sure you want to remove this certificate?"
+ IDS_WARN_REMOVE_PLURAL_ADDRESSBOOK "You will no longer be able to encrypt messages with these certificates, or verify messages signed with it.\nAre you sure you want to remove these certificates?"
+ IDS_WARN_REMOVE_CA "Certificates issued by this certification authority will no longer be trusted.\nAre you sure you want to remove this certificate?"
+ IDS_WARN_REMOVE_PLURAL_CA "Certificates issued by these certification authorities will no longer be trusted.\nAre you sure you want to remove these certificates?"
+ IDS_WARN_REMOVE_ROOT "Certificates issued by this root certification authority, or any certification authorities it issued, will no longer be trusted.\nAre you sure you want to remove this trusted root certificate?"
+ IDS_WARN_REMOVE_PLURAL_ROOT "Certificates issued by these root certification authorities, or any certification authorities they issued, will no longer be trusted.\nAre you sure you want to remove these trusted root certificates?"
+ IDS_WARN_REMOVE_TRUSTEDPUBLISHER "Software signed by this publisher will no longer be trusted.\nAre you sure you want to remove this certificate?"
+ IDS_WARN_REMOVE_PLURAL_TRUSTEDPUBLISHER "Software signed by these publishers will no longer be trusted.\nAre you sure you want to remove these certificates?"
+ IDS_WARN_REMOVE_DEFAULT "Are you sure you want to remove this certificate?"
+ IDS_WARN_REMOVE_PLURAL_DEFAULT "Are you sure you want to remove these certificates?"
+ IDS_CERT_MGR "Certificates"
IDS_PURPOSE_SERVER_AUTH "Ensures the identify of a remote computer"
IDS_PURPOSE_CLIENT_AUTH "Proves your identity to a remote computer"
IDS_PURPOSE_CODE_SIGNING "Ensures software came from software publisher\nProtects software from alteration after publication"
@@ -101,10 +155,10 @@ BEGIN
ES_READONLY|WS_DISABLED,34,11,212,26
CONTROL "", IDC_STATIC, "Static", SS_BLACKFRAME, 16,37,222,1
CONTROL "", IDC_CERTIFICATE_STATUS,"RichEdit20W",
- ES_READONLY|ES_MULTILINE|WS_DISABLED,8,38,238,78
+ ES_READONLY|ES_MULTILINE,8,38,238,78
CONTROL "", IDC_STATIC, "Static", SS_BLACKFRAME, 16,116,222,1
CONTROL "", IDC_CERTIFICATE_NAMES,"RichEdit20W",
- ES_READONLY|ES_MULTILINE|WS_DISABLED,8,117,238,91
+ ES_READONLY|ES_MULTILINE|WS_DISABLED,8,118,238,90
PUSHBUTTON "&Install Certificate...", IDC_ADDTOSTORE,103,216,70,14
PUSHBUTTON "Issuer &Statement", IDC_ISSUERSTATEMENT,177,216,70,14
END
@@ -183,3 +237,110 @@ BEGIN
PUSHBUTTON "OK", IDOK, 33,48,60,14
PUSHBUTTON "Cancel", IDCANCEL, 100,48,60,14
END
+
+IDD_SELECT_STORE DIALOG DISCARDABLE 0,0,200,136
+CAPTION "Select Certificate Store"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Select the certificate store you want to use:", IDC_STORE_TEXT, 6,6,190,28
+ CONTROL "",IDC_STORE_LIST, "SysTreeView32", TVS_HASLINES|WS_BORDER|WS_TABSTOP,
+ 6,28,188,70
+ CHECKBOX "&Show physical stores", IDC_SHOW_PHYSICAL_STORES, 6,102,90,14,
+ BS_AUTOCHECKBOX|WS_TABSTOP
+ PUSHBUTTON "OK", IDOK, 90,118,50,14, BS_DEFPUSHBUTTON
+ PUSHBUTTON "Cancel", IDCANCEL, 144,118,50,14
+END
+
+IDD_IMPORT_WELCOME DIALOG DISCARDABLE 0,0,317,143
+CAPTION "Certificate Import Wizard"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Welcome to the Certificate Import Wizard", IDC_IMPORT_TITLE,
+ 115,1,195,40
+ LTEXT "This wizard helps you import certificates, certificate revocation lists, and certificate trust lists from a file to a certificate store.",
+ stc1, 115,33,195,16
+ LTEXT "A certificate can be used to identify you or the computer with which you are communicating. It can also be used for authentication, and to sign messages. Certificate stores are collections of certificates, certificate revocation lists, and certificate trust lists.",
+ stc2, 115,56,195,40
+ LTEXT "To continue, click Next.",
+ stc3, 115,103,195,8
+END
+
+IDD_IMPORT_FILE DIALOG DISCARDABLE 0,0,317,143
+CAPTION "Certificate Import Wizard"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&File name:", stc1, 21,1,195,10
+ EDITTEXT IDC_IMPORT_FILENAME, 21,11,208,14, ES_AUTOHSCROLL|WS_TABSTOP
+ PUSHBUTTON "B&rowse...", IDC_IMPORT_BROWSE_FILE, 236,11,60,14
+ LTEXT "Note: The following file formats may contain more than one certificate, certificate revocation list, or certificate trust list:", stc2, 21,26,265,16
+ LTEXT "Cryptographic Message Syntax Standard/PKCS #7 Messages (.p7b)",
+ stc3, 31,49,265,10
+ LTEXT "Personal Information Exchange/PKCS #12 (.pfx, .p12)",
+ stc3, 31,64,265,10
+ LTEXT "Microsoft Serialized Certificate Store (.sst)",
+ stc3, 31,79,265,10
+END
+
+IDD_IMPORT_STORE DIALOG DISCARDABLE 0,0,317,143
+CAPTION "Certificate Import Wizard"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Wine can automatically select the certificate store, or you can specify a location for the certificates.", stc1, 21,1,195,20
+ AUTORADIOBUTTON "&Automatically select certificate store",
+ IDC_IMPORT_AUTO_STORE, 31,18,180,12, BS_AUTORADIOBUTTON|WS_TABSTOP
+ AUTORADIOBUTTON "&Place all certificates in the following store:",
+ IDC_IMPORT_SPECIFY_STORE, 31,30,180,12, BS_AUTORADIOBUTTON
+ EDITTEXT IDC_IMPORT_STORE, 44,49,185,14, ES_READONLY
+ PUSHBUTTON "B&rowse...", IDC_IMPORT_BROWSE_STORE, 236,49,60,14
+END
+
+IDD_IMPORT_FINISH DIALOG DISCARDABLE 0,0,317,143
+CAPTION "Certificate Import Wizard"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Completing the Certificate Import Wizard", IDC_IMPORT_TITLE,
+ 115,1,195,40
+ LTEXT "You have successfully completed the Certificate Import Wizard.",
+ stc1, 115,33,195,24
+ LTEXT "You have specified the following settings:",
+ stc2, 115,57,195,12
+ CONTROL "", IDC_IMPORT_SETTINGS, "SysListView32",
+ LVS_REPORT|LVS_NOCOLUMNHEADER|LVS_SINGLESEL|WS_CHILD|WS_VISIBLE|WS_TABSTOP|WS_BORDER,
+ 115,67,174,100
+END
+
+IDD_CERT_MGR DIALOG DISCARDABLE 0,0,335,270
+CAPTION "Certificates"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "I&ntended purpose:", IDC_STATIC, 7,9,100,12
+ COMBOBOX IDC_MGR_PURPOSE_SELECTION, 83,7,245,14,
+ CBS_DROPDOWNLIST|WS_BORDER|WS_VSCROLL|WS_TABSTOP
+ CONTROL "", IDC_MGR_STORES, "SysTabControl32",
+ WS_CLIPSIBLINGS|WS_TABSTOP, 7,25,321,140
+ CONTROL "", IDC_MGR_CERTS, "SysListView32",
+ LVS_REPORT|WS_CHILD|WS_VISIBLE|WS_TABSTOP|WS_BORDER, 15,46,305,111
+ PUSHBUTTON "&Import...", IDC_MGR_IMPORT, 7,172,51,14
+ PUSHBUTTON "&Export...", IDC_MGR_EXPORT, 62,172,51,14, WS_DISABLED
+ PUSHBUTTON "&Remove", IDC_MGR_REMOVE, 117,172,51,14, WS_DISABLED
+ PUSHBUTTON "&Advanced...", IDC_MGR_ADVANCED, 277,172,51,14
+ GROUPBOX "Certificate intended purposes", grp1,7,194,321,47, BS_GROUPBOX
+ LTEXT "", IDC_MGR_PURPOSES, 13,208,252,30
+ PUSHBUTTON "&View...", IDC_MGR_VIEW, 269,218,51,14, WS_DISABLED
+ PUSHBUTTON "&Close", IDCANCEL, 277,249,51,14, BS_DEFPUSHBUTTON
+END
+
+IDD_CERT_MGR_ADVANCED DIALOG DISCARDABLE 0,0,248,176
+CAPTION "Advanced Options"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ GROUPBOX "Certificate purpose", grp1, 7,7,234,141, BS_GROUPBOX
+ LTEXT "Select one or more purposes to be listed when Advanced Purposes is selected.",
+ IDC_STATIC, 14,18,220,16
+ LTEXT "&Certificate purposes:", IDC_STATIC, 14,41,90,12, WS_TABSTOP
+ CONTROL "", IDC_CERTIFICATE_USAGES,"SysListView32",
+ LVS_REPORT|LVS_NOCOLUMNHEADER|LVS_SINGLESEL|WS_CHILD|WS_VISIBLE|WS_TABSTOP|WS_BORDER,
+ 14,51,220,90
+ PUSHBUTTON "OK", IDOK, 132,155,51,14, BS_DEFPUSHBUTTON
+ PUSHBUTTON "Cancel", IDCANCEL, 190,155,51,14
+END
diff --git a/reactos/dll/win32/cryptui/cryptuires.h b/reactos/dll/win32/cryptui/cryptuires.h
index 9e188524594..4f2cc7f86d6 100644
--- a/reactos/dll/win32/cryptui/cryptuires.h
+++ b/reactos/dll/win32/cryptui/cryptuires.h
@@ -58,6 +58,60 @@
#define IDS_CERTIFICATE_PROPERTIES 1038
#define IDS_CERTIFICATE_PURPOSE_ERROR 1039
#define IDS_CERTIFICATE_PURPOSE_EXISTS 1040
+#define IDS_SELECT_STORE_TITLE 1041
+#define IDS_SELECT_STORE 1042
+#define IDS_IMPORT_WIZARD 1043
+#define IDS_IMPORT_TYPE_MISMATCH 1044
+#define IDS_IMPORT_FILE_TITLE 1045
+#define IDS_IMPORT_FILE_SUBTITLE 1046
+#define IDS_IMPORT_STORE_TITLE 1047
+#define IDS_IMPORT_STORE_SUBTITLE 1048
+#define IDS_IMPORT_FILTER_CERT 1049
+#define IDS_IMPORT_FILTER_PFX 1050
+#define IDS_IMPORT_FILTER_CRL 1051
+#define IDS_IMPORT_FILTER_CTL 1052
+#define IDS_IMPORT_FILTER_SERIALIZED_STORE 1053
+#define IDS_IMPORT_FILTER_CMS 1054
+#define IDS_IMPORT_FILTER_ALL 1055
+#define IDS_IMPORT_EMPTY_FILE 1056
+#define IDS_IMPORT_BAD_FORMAT 1057
+#define IDS_IMPORT_OPEN_FAILED 1058
+#define IDS_IMPORT_DEST_DETERMINED 1059
+#define IDS_IMPORT_SELECT_STORE 1060
+#define IDS_IMPORT_STORE_SELECTION 1061
+#define IDS_IMPORT_DEST_AUTOMATIC 1062
+#define IDS_IMPORT_FILE 1063
+#define IDS_IMPORT_CONTENT 1064
+#define IDS_IMPORT_CONTENT_CERT 1065
+#define IDS_IMPORT_CONTENT_CRL 1066
+#define IDS_IMPORT_CONTENT_CTL 1067
+#define IDS_IMPORT_CONTENT_CMS 1068
+#define IDS_IMPORT_CONTENT_PFX 1069
+#define IDS_IMPORT_CONTENT_STORE 1070
+#define IDS_IMPORT_SUCCEEDED 1071
+#define IDS_IMPORT_FAILED 1072
+#define IDS_WIZARD_TITLE_FONT 1073
+#define IDS_PURPOSE_ALL 1074
+#define IDS_PURPOSE_ADVANCED 1075
+#define IDS_SUBJECT_COLUMN 1076
+#define IDS_ISSUER_COLUMN 1077
+#define IDS_EXPIRATION_COLUMN 1078
+#define IDS_FRIENDLY_NAME_COLUMN 1079
+#define IDS_ALLOWED_PURPOSE_ALL 1080
+#define IDS_ALLOWED_PURPOSE_NONE 1081
+#define IDS_WARN_REMOVE_MY 1082
+#define IDS_WARN_REMOVE_PLURAL_MY 1083
+#define IDS_WARN_REMOVE_ADDRESSBOOK 1084
+#define IDS_WARN_REMOVE_PLURAL_ADDRESSBOOK 1085
+#define IDS_WARN_REMOVE_CA 1086
+#define IDS_WARN_REMOVE_PLURAL_CA 1087
+#define IDS_WARN_REMOVE_ROOT 1088
+#define IDS_WARN_REMOVE_PLURAL_ROOT 1089
+#define IDS_WARN_REMOVE_TRUSTEDPUBLISHER 1090
+#define IDS_WARN_REMOVE_PLURAL_TRUSTEDPUBLISHER 1091
+#define IDS_WARN_REMOVE_DEFAULT 1092
+#define IDS_WARN_REMOVE_PLURAL_DEFAULT 1093
+#define IDS_CERT_MGR 1094
#define IDS_PURPOSE_SERVER_AUTH 1100
#define IDS_PURPOSE_CLIENT_AUTH 1101
@@ -92,12 +146,21 @@
#define IDD_USERNOTICE 103
#define IDD_CERT_PROPERTIES_GENERAL 104
#define IDD_ADD_CERT_PURPOSE 105
+#define IDD_SELECT_STORE 106
+#define IDD_IMPORT_WELCOME 107
+#define IDD_IMPORT_FILE 108
+#define IDD_IMPORT_STORE 109
+#define IDD_IMPORT_FINISH 110
+#define IDD_CERT_MGR 111
+#define IDD_CERT_MGR_ADVANCED 112
#define IDB_SMALL_ICONS 200
#define IDB_CERT 201
#define IDB_CERT_ERROR 202
#define IDB_CERT_WARNING 203
#define IDB_CHECKS 204
+#define IDB_CERT_WATERMARK 205
+#define IDB_CERT_HEADER 206
#define IDC_STATIC 2000
#define IDC_CERTIFICATE_ICON 2001
@@ -131,4 +194,27 @@
#define IDC_NEW_PURPOSE 2500
+#define IDC_STORE_TEXT 2600
+#define IDC_STORE_LIST 2601
+#define IDC_SHOW_PHYSICAL_STORES 2602
+
+#define IDC_IMPORT_TITLE 2700
+#define IDC_IMPORT_FILENAME 2701
+#define IDC_IMPORT_BROWSE_FILE 2702
+#define IDC_IMPORT_AUTO_STORE 2703
+#define IDC_IMPORT_SPECIFY_STORE 2704
+#define IDC_IMPORT_STORE 2705
+#define IDC_IMPORT_BROWSE_STORE 2706
+#define IDC_IMPORT_SETTINGS 2707
+
+#define IDC_MGR_PURPOSE_SELECTION 2800
+#define IDC_MGR_STORES 2801
+#define IDC_MGR_CERTS 2802
+#define IDC_MGR_IMPORT 2803
+#define IDC_MGR_EXPORT 2804
+#define IDC_MGR_REMOVE 2805
+#define IDC_MGR_ADVANCED 2806
+#define IDC_MGR_PURPOSES 2807
+#define IDC_MGR_VIEW 2808
+
#endif /* ndef __CRYPTUIRES_H_ */
diff --git a/reactos/dll/win32/cryptui/main.c b/reactos/dll/win32/cryptui/main.c
index 82a877f0456..a5fb5808b4f 100644
--- a/reactos/dll/win32/cryptui/main.c
+++ b/reactos/dll/win32/cryptui/main.c
@@ -32,11 +32,13 @@
#include "richedit.h"
#include "ole2.h"
#include "richole.h"
+#include "commdlg.h"
#include "commctrl.h"
#include "cryptuiapi.h"
#include "cryptuires.h"
#include "urlmon.h"
#include "hlink.h"
+#include "winreg.h"
#include "wine/debug.h"
#include "wine/unicode.h"
@@ -64,13 +66,1454 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
return TRUE;
}
+#define MAX_STRING_LEN 512
+
+static void add_cert_columns(HWND hwnd)
+{
+ HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
+ RECT rc;
+ WCHAR buf[MAX_STRING_LEN];
+ LVCOLUMNW column;
+
+ SendMessageW(lv, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
+ GetWindowRect(lv, &rc);
+ LoadStringW(hInstance, IDS_SUBJECT_COLUMN, buf,
+ sizeof(buf) / sizeof(buf[0]));
+ column.mask = LVCF_WIDTH | LVCF_TEXT;
+ column.cx = (rc.right - rc.left) * 29 / 100 - 2;
+ column.pszText = buf;
+ SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
+ LoadStringW(hInstance, IDS_ISSUER_COLUMN, buf,
+ sizeof(buf) / sizeof(buf[0]));
+ SendMessageW(lv, LVM_INSERTCOLUMNW, 1, (LPARAM)&column);
+ column.cx = (rc.right - rc.left) * 16 / 100 - 2;
+ LoadStringW(hInstance, IDS_EXPIRATION_COLUMN, buf,
+ sizeof(buf) / sizeof(buf[0]));
+ SendMessageW(lv, LVM_INSERTCOLUMNW, 2, (LPARAM)&column);
+ column.cx = (rc.right - rc.left) * 23 / 100 - 1;
+ LoadStringW(hInstance, IDS_FRIENDLY_NAME_COLUMN, buf,
+ sizeof(buf) / sizeof(buf[0]));
+ SendMessageW(lv, LVM_INSERTCOLUMNW, 3, (LPARAM)&column);
+}
+
+static void add_cert_to_view(HWND lv, PCCERT_CONTEXT cert, DWORD *allocatedLen,
+ LPWSTR *str)
+{
+ DWORD len;
+ LVITEMW item;
+ WCHAR dateFmt[80]; /* sufficient for LOCALE_SSHORTDATE */
+ WCHAR date[80];
+ SYSTEMTIME sysTime;
+
+ item.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_TEXT;
+ item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
+ item.iSubItem = 0;
+ item.iImage = 0;
+ item.lParam = (LPARAM)CertDuplicateCertificateContext(cert);
+ len = CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL,
+ NULL, 0);
+ if (len > *allocatedLen)
+ {
+ HeapFree(GetProcessHeap(), 0, *str);
+ *str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ if (*str)
+ *allocatedLen = len;
+ }
+ if (*str)
+ {
+ CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL,
+ *str, len);
+ item.pszText = *str;
+ SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
+ }
+
+ item.mask = LVIF_TEXT;
+ len = CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
+ CERT_NAME_ISSUER_FLAG, NULL, NULL, 0);
+ if (len > *allocatedLen)
+ {
+ HeapFree(GetProcessHeap(), 0, *str);
+ *str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ if (*str)
+ *allocatedLen = len;
+ }
+ if (*str)
+ {
+ CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
+ CERT_NAME_ISSUER_FLAG, NULL, *str, len);
+ item.pszText = *str;
+ item.iSubItem = 1;
+ SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
+ }
+
+ GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SSHORTDATE, dateFmt,
+ sizeof(dateFmt) / sizeof(dateFmt[0]));
+ FileTimeToSystemTime(&cert->pCertInfo->NotAfter, &sysTime);
+ GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, date,
+ sizeof(date) / sizeof(date[0]));
+ item.pszText = date;
+ item.iSubItem = 2;
+ SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
+
+ len = CertGetNameStringW(cert, CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL,
+ NULL, 0);
+ if (len > *allocatedLen)
+ {
+ HeapFree(GetProcessHeap(), 0, *str);
+ *str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ if (*str)
+ *allocatedLen = len;
+ }
+ if (*str)
+ {
+ CertGetNameStringW(cert, CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL,
+ *str, len);
+ item.pszText = *str;
+ item.iSubItem = 3;
+ SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
+ }
+}
+
+static LPSTR get_cert_mgr_usages(void)
+{
+ static const WCHAR keyName[] = { 'S','o','f','t','w','a','r','e','\\','M',
+ 'i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g','r','a',
+ 'p','h','y','\\','U','I','\\','C','e','r','t','m','g','r','\\','P','u',
+ 'r','p','o','s','e',0 };
+ LPSTR str = NULL;
+ HKEY key;
+
+ if (!RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, NULL, 0, KEY_READ,
+ NULL, &key, NULL))
+ {
+ LONG rc;
+ DWORD type, size;
+
+ rc = RegQueryValueExA(key, "Purpose", NULL, &type, NULL, &size);
+ if ((!rc || rc == ERROR_MORE_DATA) && type == REG_SZ)
+ {
+ str = HeapAlloc(GetProcessHeap(), 0, size);
+ if (str)
+ {
+ rc = RegQueryValueExA(key, "Purpose", NULL, NULL, (LPBYTE)str,
+ &size);
+ if (rc)
+ {
+ HeapFree(GetProcessHeap(), 0, str);
+ str = NULL;
+ }
+ }
+ }
+ RegCloseKey(key);
+ }
+ return str;
+}
+
+typedef enum {
+ PurposeFilterShowAll = 0,
+ PurposeFilterShowAdvanced = 1,
+ PurposeFilterShowOID = 2
+} PurposeFilter;
+
+static void initialize_purpose_selection(HWND hwnd)
+{
+ HWND cb = GetDlgItem(hwnd, IDC_MGR_PURPOSE_SELECTION);
+ WCHAR buf[MAX_STRING_LEN];
+ LPSTR usages;
+ int index;
+
+ LoadStringW(hInstance, IDS_PURPOSE_ALL, buf,
+ sizeof(buf) / sizeof(buf[0]));
+ index = SendMessageW(cb, CB_INSERTSTRING, -1, (LPARAM)buf);
+ SendMessageW(cb, CB_SETITEMDATA, index, (LPARAM)PurposeFilterShowAll);
+ LoadStringW(hInstance, IDS_PURPOSE_ADVANCED, buf,
+ sizeof(buf) / sizeof(buf[0]));
+ index = SendMessageW(cb, CB_INSERTSTRING, -1, (LPARAM)buf);
+ SendMessageW(cb, CB_SETITEMDATA, index, (LPARAM)PurposeFilterShowAdvanced);
+ SendMessageW(cb, CB_SETCURSEL, 0, 0);
+ if ((usages = get_cert_mgr_usages()))
+ {
+ LPSTR ptr, comma;
+
+ for (ptr = usages, comma = strchr(ptr, ','); ptr && *ptr;
+ ptr = comma ? comma + 1 : NULL,
+ comma = ptr ? strchr(ptr, ',') : NULL)
+ {
+ PCCRYPT_OID_INFO info;
+
+ if (comma)
+ *comma = 0;
+ if ((info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, ptr, 0)))
+ {
+ index = SendMessageW(cb, CB_INSERTSTRING, 0,
+ (LPARAM)info->pwszName);
+ SendMessageW(cb, CB_SETITEMDATA, index, (LPARAM)info);
+ }
+ }
+ HeapFree(GetProcessHeap(), 0, usages);
+ }
+}
+
+extern BOOL WINAPI WTHelperGetKnownUsages(DWORD action,
+ PCCRYPT_OID_INFO **usages);
+
+static CERT_ENHKEY_USAGE *add_oid_to_usage(CERT_ENHKEY_USAGE *usage, LPSTR oid)
+{
+ if (!usage->cUsageIdentifier)
+ usage->rgpszUsageIdentifier = HeapAlloc(GetProcessHeap(), 0,
+ sizeof(LPSTR));
+ else
+ usage->rgpszUsageIdentifier = HeapReAlloc(GetProcessHeap(), 0,
+ usage->rgpszUsageIdentifier,
+ (usage->cUsageIdentifier + 1) * sizeof(LPSTR));
+ if (usage->rgpszUsageIdentifier)
+ usage->rgpszUsageIdentifier[usage->cUsageIdentifier++] = oid;
+ else
+ {
+ HeapFree(GetProcessHeap(), 0, usage);
+ usage = NULL;
+ }
+ return usage;
+}
+
+static CERT_ENHKEY_USAGE *convert_usages_str_to_usage(LPSTR usageStr)
+{
+ CERT_ENHKEY_USAGE *usage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+ sizeof(CERT_ENHKEY_USAGE));
+
+ if (usage)
+ {
+ LPSTR ptr, comma;
+
+ for (ptr = usageStr, comma = strchr(ptr, ','); usage && ptr && *ptr;
+ ptr = comma ? comma + 1 : NULL,
+ comma = ptr ? strchr(ptr, ',') : NULL)
+ {
+ if (comma)
+ *comma = 0;
+ add_oid_to_usage(usage, ptr);
+ }
+ }
+ return usage;
+}
+
+static CERT_ENHKEY_USAGE *create_advanced_filter(void)
+{
+ CERT_ENHKEY_USAGE *advancedUsage = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY, sizeof(CERT_ENHKEY_USAGE));
+
+ if (advancedUsage)
+ {
+ PCCRYPT_OID_INFO *usages;
+
+ if (WTHelperGetKnownUsages(1, &usages))
+ {
+ LPSTR disabledUsagesStr;
+
+ if ((disabledUsagesStr = get_cert_mgr_usages()))
+ {
+ CERT_ENHKEY_USAGE *disabledUsages =
+ convert_usages_str_to_usage(disabledUsagesStr);
+
+ if (disabledUsages)
+ {
+ PCCRYPT_OID_INFO *ptr;
+
+ for (ptr = usages; *ptr; ptr++)
+ {
+ DWORD i;
+ BOOL disabled = FALSE;
+
+ for (i = 0; !disabled &&
+ i < disabledUsages->cUsageIdentifier; i++)
+ if (!strcmp(disabledUsages->rgpszUsageIdentifier[i],
+ (*ptr)->pszOID))
+ disabled = TRUE;
+ if (!disabled)
+ add_oid_to_usage(advancedUsage,
+ (LPSTR)(*ptr)->pszOID);
+ }
+ /* The individual strings are pointers to disabledUsagesStr,
+ * so they're freed when it is.
+ */
+ HeapFree(GetProcessHeap(), 0,
+ disabledUsages->rgpszUsageIdentifier);
+ HeapFree(GetProcessHeap(), 0, disabledUsages);
+ }
+ HeapFree(GetProcessHeap(), 0, disabledUsagesStr);
+ }
+ WTHelperGetKnownUsages(2, &usages);
+ }
+ }
+ return advancedUsage;
+}
+
+static void show_store_certs(HWND hwnd, HCERTSTORE store)
+{
+ HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
+ HWND cb = GetDlgItem(hwnd, IDC_MGR_PURPOSE_SELECTION);
+ PCCERT_CONTEXT cert = NULL;
+ DWORD allocatedLen = 0;
+ LPWSTR str = NULL;
+ int index;
+ PurposeFilter filter = PurposeFilterShowAll;
+ LPCSTR oid = NULL;
+ CERT_ENHKEY_USAGE *advanced = NULL;
+
+ index = SendMessageW(cb, CB_GETCURSEL, 0, 0);
+ if (index >= 0)
+ {
+ INT_PTR data = SendMessageW(cb, CB_GETITEMDATA, index, 0);
+
+ if (!HIWORD(data))
+ filter = data;
+ else
+ {
+ PCCRYPT_OID_INFO info = (PCCRYPT_OID_INFO)data;
+
+ filter = PurposeFilterShowOID;
+ oid = info->pszOID;
+ }
+ }
+ if (filter == PurposeFilterShowAdvanced)
+ advanced = create_advanced_filter();
+ do {
+ cert = CertEnumCertificatesInStore(store, cert);
+ if (cert)
+ {
+ BOOL show = FALSE;
+
+ if (filter == PurposeFilterShowAll)
+ show = TRUE;
+ else
+ {
+ int numOIDs;
+ DWORD cbOIDs = 0;
+
+ if (CertGetValidUsages(1, &cert, &numOIDs, NULL, &cbOIDs))
+ {
+ if (numOIDs == -1)
+ {
+ /* -1 implies all usages are valid */
+ show = TRUE;
+ }
+ else
+ {
+ LPSTR *oids = HeapAlloc(GetProcessHeap(), 0, cbOIDs);
+
+ if (oids)
+ {
+ if (CertGetValidUsages(1, &cert, &numOIDs, oids,
+ &cbOIDs))
+ {
+ int i;
+
+ if (filter == PurposeFilterShowOID)
+ {
+ for (i = 0; !show && i < numOIDs; i++)
+ if (!strcmp(oids[i], oid))
+ show = TRUE;
+ }
+ else
+ {
+ for (i = 0; !show && i < numOIDs; i++)
+ {
+ DWORD j;
+
+ for (j = 0; !show &&
+ j < advanced->cUsageIdentifier; j++)
+ if (!strcmp(oids[i],
+ advanced->rgpszUsageIdentifier[j]))
+ show = TRUE;
+ }
+ }
+ }
+ HeapFree(GetProcessHeap(), 0, oids);
+ }
+ }
+ }
+ }
+ if (show)
+ add_cert_to_view(lv, cert, &allocatedLen, &str);
+ }
+ } while (cert);
+ HeapFree(GetProcessHeap(), 0, str);
+ if (advanced)
+ {
+ HeapFree(GetProcessHeap(), 0, advanced->rgpszUsageIdentifier);
+ HeapFree(GetProcessHeap(), 0, advanced);
+ }
+}
+
+static const WCHAR my[] = { 'M','y',0 };
+static const WCHAR addressBook[] = {
+ 'A','d','d','r','e','s','s','B','o','o','k',0 };
+static const WCHAR ca[] = { 'C','A',0 };
+static const WCHAR root[] = { 'R','o','o','t',0 };
+static const WCHAR trustedPublisher[] = {
+ 'T','r','u','s','t','e','d','P','u','b','l','i','s','h','e','r',0 };
+static const WCHAR disallowed[] = { 'D','i','s','a','l','l','o','w','e','d',0 };
+
+struct CertMgrStoreInfo
+{
+ LPCWSTR name;
+ int removeWarning;
+ int removePluralWarning;
+};
+
+static const struct CertMgrStoreInfo defaultStoreList[] = {
+ { my, IDS_WARN_REMOVE_MY, IDS_WARN_REMOVE_PLURAL_MY },
+ { addressBook, IDS_WARN_REMOVE_ADDRESSBOOK,
+ IDS_WARN_REMOVE_PLURAL_ADDRESSBOOK },
+ { ca, IDS_WARN_REMOVE_CA, IDS_WARN_REMOVE_PLURAL_CA },
+ { root, IDS_WARN_REMOVE_ROOT, IDS_WARN_REMOVE_PLURAL_ROOT },
+ { trustedPublisher, IDS_WARN_REMOVE_TRUSTEDPUBLISHER,
+ IDS_WARN_REMOVE_PLURAL_TRUSTEDPUBLISHER },
+ { disallowed, IDS_WARN_REMOVE_DEFAULT },
+};
+
+static const struct CertMgrStoreInfo publisherStoreList[] = {
+ { root, IDS_WARN_REMOVE_ROOT, IDS_WARN_REMOVE_PLURAL_ROOT },
+ { trustedPublisher, IDS_WARN_REMOVE_TRUSTEDPUBLISHER,
+ IDS_WARN_REMOVE_PLURAL_TRUSTEDPUBLISHER },
+ { disallowed, IDS_WARN_REMOVE_PLURAL_DEFAULT },
+};
+
+struct CertMgrData
+{
+ HIMAGELIST imageList;
+ LPCWSTR title;
+ DWORD nStores;
+ const struct CertMgrStoreInfo *stores;
+};
+
+static void show_cert_stores(HWND hwnd, DWORD dwFlags, struct CertMgrData *data)
+{
+ const struct CertMgrStoreInfo *storeList;
+ int cStores, i;
+ HWND tab = GetDlgItem(hwnd, IDC_MGR_STORES);
+
+ if (dwFlags & CRYPTUI_CERT_MGR_PUBLISHER_TAB)
+ {
+ storeList = publisherStoreList;
+ cStores = sizeof(publisherStoreList) / sizeof(publisherStoreList[0]);
+ }
+ else
+ {
+ storeList = defaultStoreList;
+ cStores = sizeof(defaultStoreList) / sizeof(defaultStoreList[0]);
+ }
+ if (dwFlags & CRYPTUI_CERT_MGR_SINGLE_TAB_FLAG)
+ cStores = 1;
+ data->nStores = cStores;
+ data->stores = storeList;
+ for (i = 0; i < cStores; i++)
+ {
+ LPCWSTR name;
+ TCITEMW item;
+ HCERTSTORE store;
+
+ if (!(name = CryptFindLocalizedName(storeList[i].name)))
+ name = storeList[i].name;
+ store = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0,
+ CERT_SYSTEM_STORE_CURRENT_USER, storeList[i].name);
+ item.mask = TCIF_TEXT | TCIF_PARAM;
+ item.pszText = (LPWSTR)name;
+ item.lParam = (LPARAM)store;
+ SendMessageW(tab, TCM_INSERTITEMW, i, (LPARAM)&item);
+ }
+}
+
+static void free_certs(HWND lv)
+{
+ LVITEMW item;
+ int items = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0), i;
+
+ for (i = 0; i < items; i++)
+ {
+ item.mask = LVIF_PARAM;
+ item.iItem = i;
+ item.iSubItem = 0;
+ SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item);
+ CertFreeCertificateContext((PCCERT_CONTEXT)item.lParam);
+ }
+}
+
+static HCERTSTORE cert_mgr_index_to_store(HWND tab, int index)
+{
+ TCITEMW item;
+
+ item.mask = TCIF_PARAM;
+ SendMessageW(tab, TCM_GETITEMW, index, (LPARAM)&item);
+ return (HCERTSTORE)item.lParam;
+}
+
+static HCERTSTORE cert_mgr_current_store(HWND hwnd)
+{
+ HWND tab = GetDlgItem(hwnd, IDC_MGR_STORES);
+
+ return cert_mgr_index_to_store(tab, SendMessageW(tab, TCM_GETCURSEL, 0, 0));
+}
+
+static void close_stores(HWND tab)
+{
+ int i, tabs = SendMessageW(tab, TCM_GETITEMCOUNT, 0, 0);
+
+ for (i = 0; i < tabs; i++)
+ CertCloseStore(cert_mgr_index_to_store(tab, i), 0);
+}
+
+static void refresh_store_certs(HWND hwnd)
+{
+ HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
+
+ free_certs(lv);
+ SendMessageW(lv, LVM_DELETEALLITEMS, 0, 0);
+ show_store_certs(hwnd, cert_mgr_current_store(hwnd));
+}
+
+typedef enum {
+ CheckBitmapIndexUnchecked = 1,
+ CheckBitmapIndexChecked = 2,
+ CheckBitmapIndexDisabledUnchecked = 3,
+ CheckBitmapIndexDisabledChecked = 4
+} CheckBitmapIndex;
+
+static void add_known_usage(HWND lv, PCCRYPT_OID_INFO info,
+ CheckBitmapIndex state)
+{
+ LVITEMW item;
+
+ item.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM;
+ item.state = INDEXTOSTATEIMAGEMASK(state);
+ item.stateMask = LVIS_STATEIMAGEMASK;
+ item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
+ item.iSubItem = 0;
+ item.lParam = (LPARAM)info;
+ item.pszText = (LPWSTR)info->pwszName;
+ SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
+}
+
+static void add_known_usages_to_list(HWND lv, CheckBitmapIndex state)
+{
+ PCCRYPT_OID_INFO *usages;
+
+ if (WTHelperGetKnownUsages(1, &usages))
+ {
+ PCCRYPT_OID_INFO *ptr;
+
+ for (ptr = usages; *ptr; ptr++)
+ add_known_usage(lv, *ptr, state);
+ WTHelperGetKnownUsages(2, &usages);
+ }
+}
+
+static void toggle_usage(HWND hwnd, int iItem)
+{
+ LVITEMW item;
+ int res;
+ HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
+
+ item.mask = LVIF_STATE;
+ item.iItem = iItem;
+ item.iSubItem = 0;
+ item.stateMask = LVIS_STATEIMAGEMASK;
+ res = SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item);
+ if (res)
+ {
+ int state = item.state >> 12;
+
+ item.state = INDEXTOSTATEIMAGEMASK(
+ state == CheckBitmapIndexChecked ? CheckBitmapIndexUnchecked :
+ CheckBitmapIndexChecked);
+ SendMessageW(lv, LVM_SETITEMSTATE, iItem, (LPARAM)&item);
+ }
+}
+
+static LONG_PTR find_oid_in_list(HWND lv, LPCSTR oid)
+{
+ PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
+ (void *)oid, CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
+ LONG_PTR ret;
+
+ if (oidInfo)
+ {
+ LVFINDINFOW findInfo;
+
+ findInfo.flags = LVFI_PARAM;
+ findInfo.lParam = (LPARAM)oidInfo;
+ ret = SendMessageW(lv, LVM_FINDITEMW, -1, (LPARAM)&findInfo);
+ }
+ else
+ {
+ LVFINDINFOA findInfo;
+
+ findInfo.flags = LVFI_STRING;
+ findInfo.psz = oid;
+ ret = SendMessageW(lv, LVM_FINDITEMA, -1, (LPARAM)&findInfo);
+ }
+ return ret;
+}
+
+static void save_cert_mgr_usages(HWND hwnd)
+{
+ static const WCHAR keyName[] = { 'S','o','f','t','w','a','r','e','\\','M',
+ 'i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g','r','a',
+ 'p','h','y','\\','U','I','\\','C','e','r','t','m','g','r','\\','P','u',
+ 'r','p','o','s','e',0 };
+ HKEY key;
+ HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
+ int purposes = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0), i;
+ LVITEMW item;
+ LPSTR str = NULL;
+
+ item.mask = LVIF_STATE | LVIF_PARAM;
+ item.iSubItem = 0;
+ item.stateMask = LVIS_STATEIMAGEMASK;
+ for (i = 0; i < purposes; i++)
+ {
+ item.iItem = i;
+ if (SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item))
+ {
+ int state = item.state >> 12;
+
+ if (state == CheckBitmapIndexUnchecked)
+ {
+ CRYPT_OID_INFO *info = (CRYPT_OID_INFO *)item.lParam;
+ BOOL firstString = TRUE;
+
+ if (!str)
+ str = HeapAlloc(GetProcessHeap(), 0,
+ strlen(info->pszOID) + 1);
+ else
+ {
+ str = HeapReAlloc(GetProcessHeap(), 0, str,
+ strlen(str) + 1 + strlen(info->pszOID) + 1);
+ firstString = FALSE;
+ }
+ if (str)
+ {
+ LPSTR ptr = firstString ? str : str + strlen(str);
+
+ if (!firstString)
+ *ptr++ = ',';
+ strcpy(ptr, info->pszOID);
+ }
+ }
+ }
+ }
+ if (!RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, NULL, 0, KEY_ALL_ACCESS,
+ NULL, &key, NULL))
+ {
+ if (str)
+ RegSetValueExA(key, "Purpose", 0, REG_SZ, (const BYTE *)str,
+ strlen(str) + 1);
+ else
+ RegDeleteValueA(key, "Purpose");
+ RegCloseKey(key);
+ }
+ HeapFree(GetProcessHeap(), 0, str);
+}
+
+static LRESULT CALLBACK cert_mgr_advanced_dlg_proc(HWND hwnd, UINT msg,
+ WPARAM wp, LPARAM lp)
+{
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ RECT rc;
+ LVCOLUMNW column;
+ HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
+ HIMAGELIST imageList;
+ LPSTR disabledUsages;
+
+ GetWindowRect(lv, &rc);
+ column.mask = LVCF_WIDTH;
+ column.cx = rc.right - rc.left;
+ SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
+ imageList = ImageList_Create(16, 16, ILC_COLOR4 | ILC_MASK, 4, 0);
+ if (imageList)
+ {
+ HBITMAP bmp;
+ COLORREF backColor = RGB(255, 0, 255);
+
+ bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_CHECKS));
+ ImageList_AddMasked(imageList, bmp, backColor);
+ DeleteObject(bmp);
+ ImageList_SetBkColor(imageList, CLR_NONE);
+ SendMessageW(lv, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)imageList);
+ SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)imageList);
+ }
+ add_known_usages_to_list(lv, CheckBitmapIndexChecked);
+ if ((disabledUsages = get_cert_mgr_usages()))
+ {
+ LPSTR ptr, comma;
+
+ for (ptr = disabledUsages, comma = strchr(ptr, ','); ptr && *ptr;
+ ptr = comma ? comma + 1 : NULL,
+ comma = ptr ? strchr(ptr, ',') : NULL)
+ {
+ LONG_PTR index;
+
+ if (comma)
+ *comma = 0;
+ if ((index = find_oid_in_list(lv, ptr)) != -1)
+ toggle_usage(hwnd, index);
+ }
+ HeapFree(GetProcessHeap(), 0, disabledUsages);
+ }
+ break;
+ }
+ case WM_NOTIFY:
+ {
+ NMHDR *hdr = (NMHDR *)lp;
+ NMITEMACTIVATE *nm;
+
+ switch (hdr->code)
+ {
+ case NM_CLICK:
+ nm = (NMITEMACTIVATE *)lp;
+ toggle_usage(hwnd, nm->iItem);
+ SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
+ break;
+ }
+ break;
+ }
+ case WM_COMMAND:
+ switch (wp)
+ {
+ case IDOK:
+ save_cert_mgr_usages(hwnd);
+ ImageList_Destroy((HIMAGELIST)GetWindowLongPtrW(hwnd, DWLP_USER));
+ EndDialog(hwnd, IDOK);
+ break;
+ case IDCANCEL:
+ ImageList_Destroy((HIMAGELIST)GetWindowLongPtrW(hwnd, DWLP_USER));
+ EndDialog(hwnd, IDCANCEL);
+ break;
+ }
+ break;
+ }
+ return 0;
+}
+
+static void cert_mgr_clear_cert_selection(HWND hwnd)
+{
+ WCHAR empty[] = { 0 };
+
+ EnableWindow(GetDlgItem(hwnd, IDC_MGR_EXPORT), FALSE);
+ EnableWindow(GetDlgItem(hwnd, IDC_MGR_REMOVE), FALSE);
+ EnableWindow(GetDlgItem(hwnd, IDC_MGR_VIEW), FALSE);
+ SendMessageW(GetDlgItem(hwnd, IDC_MGR_PURPOSES), WM_SETTEXT, 0,
+ (LPARAM)empty);
+ refresh_store_certs(hwnd);
+}
+
+static PCCERT_CONTEXT cert_mgr_index_to_cert(HWND hwnd, int index)
+{
+ PCCERT_CONTEXT cert = NULL;
+ LVITEMW item;
+
+ item.mask = LVIF_PARAM;
+ item.iItem = index;
+ item.iSubItem = 0;
+ if (SendMessageW(GetDlgItem(hwnd, IDC_MGR_CERTS), LVM_GETITEMW, 0,
+ (LPARAM)&item))
+ cert = (PCCERT_CONTEXT)item.lParam;
+ return cert;
+}
+
+static void show_selected_cert(HWND hwnd, int index)
+{
+ PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd, index);
+
+ if (cert)
+ {
+ CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
+
+ memset(&viewInfo, 0, sizeof(viewInfo));
+ viewInfo.dwSize = sizeof(viewInfo);
+ viewInfo.hwndParent = hwnd;
+ viewInfo.pCertContext = cert;
+ /* FIXME: this should be modal */
+ CryptUIDlgViewCertificateW(&viewInfo, NULL);
+ }
+}
+
+static void cert_mgr_show_cert_usages(HWND hwnd, int index)
+{
+ HWND text = GetDlgItem(hwnd, IDC_MGR_PURPOSES);
+ PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd, index);
+ PCERT_ENHKEY_USAGE usage;
+ DWORD size;
+
+ /* Get enhanced key usage. Have to check for a property and an extension
+ * separately, because CertGetEnhancedKeyUsage will succeed and return an
+ * empty usage if neither is set. Unfortunately an empty usage implies
+ * no usage is allowed, so we have to distinguish between the two cases.
+ */
+ if (CertGetEnhancedKeyUsage(cert, CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG,
+ NULL, &size))
+ {
+ usage = HeapAlloc(GetProcessHeap(), 0, size);
+ if (!CertGetEnhancedKeyUsage(cert,
+ CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size))
+ {
+ HeapFree(GetProcessHeap(), 0, usage);
+ usage = NULL;
+ }
+ }
+ else if (CertGetEnhancedKeyUsage(cert, CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
+ NULL, &size))
+ {
+ usage = HeapAlloc(GetProcessHeap(), 0, size);
+ if (!CertGetEnhancedKeyUsage(cert,
+ CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, usage, &size))
+ {
+ HeapFree(GetProcessHeap(), 0, usage);
+ usage = NULL;
+ }
+ }
+ else
+ usage = NULL;
+ if (usage)
+ {
+ if (usage->cUsageIdentifier)
+ {
+ static const WCHAR commaSpace[] = { ',',' ',0 };
+ DWORD i, len = 1;
+ LPWSTR str, ptr;
+
+ for (i = 0; i < usage->cUsageIdentifier; i++)
+ {
+ PCCRYPT_OID_INFO info =
+ CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
+ usage->rgpszUsageIdentifier[i],
+ CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
+
+ if (info)
+ len += strlenW(info->pwszName);
+ else
+ len += strlen(usage->rgpszUsageIdentifier[i]);
+ if (i < usage->cUsageIdentifier - 1)
+ len += strlenW(commaSpace);
+ }
+ str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ if (str)
+ {
+ for (i = 0, ptr = str; i < usage->cUsageIdentifier; i++)
+ {
+ PCCRYPT_OID_INFO info =
+ CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
+ usage->rgpszUsageIdentifier[i],
+ CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
+
+ if (info)
+ {
+ strcpyW(ptr, info->pwszName);
+ ptr += strlenW(info->pwszName);
+ }
+ else
+ {
+ LPCSTR src = usage->rgpszUsageIdentifier[i];
+
+ for (; *src; ptr++, src++)
+ *ptr = *src;
+ *ptr = 0;
+ }
+ if (i < usage->cUsageIdentifier - 1)
+ {
+ strcpyW(ptr, commaSpace);
+ ptr += strlenW(commaSpace);
+ }
+ }
+ *ptr = 0;
+ SendMessageW(text, WM_SETTEXT, 0, (LPARAM)str);
+ HeapFree(GetProcessHeap(), 0, str);
+ }
+ HeapFree(GetProcessHeap(), 0, usage);
+ }
+ else
+ {
+ WCHAR buf[MAX_STRING_LEN];
+
+ LoadStringW(hInstance, IDS_ALLOWED_PURPOSE_NONE, buf,
+ sizeof(buf) / sizeof(buf[0]));
+ SendMessageW(text, WM_SETTEXT, 0, (LPARAM)buf);
+ }
+ }
+ else
+ {
+ WCHAR buf[MAX_STRING_LEN];
+
+ LoadStringW(hInstance, IDS_ALLOWED_PURPOSE_ALL, buf,
+ sizeof(buf) / sizeof(buf[0]));
+ SendMessageW(text, WM_SETTEXT, 0, (LPARAM)buf);
+ }
+}
+
+static void cert_mgr_do_remove(HWND hwnd)
+{
+ int tabIndex = SendMessageW(GetDlgItem(hwnd, IDC_MGR_STORES),
+ TCM_GETCURSEL, 0, 0);
+ struct CertMgrData *data =
+ (struct CertMgrData *)GetWindowLongPtrW(hwnd, DWLP_USER);
+
+ if (tabIndex < data->nStores)
+ {
+ HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
+ WCHAR warning[MAX_STRING_LEN], title[MAX_STRING_LEN];
+ LPCWSTR pTitle;
+ int warningID;
+
+ if (SendMessageW(lv, LVM_GETSELECTEDCOUNT, 0, 0) > 1)
+ warningID = data->stores[tabIndex].removePluralWarning;
+ else
+ warningID = data->stores[tabIndex].removeWarning;
+ if (data->title)
+ pTitle = data->title;
+ else
+ {
+ LoadStringW(hInstance, IDS_CERT_MGR, title,
+ sizeof(title) / sizeof(title[0]));
+ pTitle = title;
+ }
+ LoadStringW(hInstance, warningID, warning,
+ sizeof(warning) / sizeof(warning[0]));
+ if (MessageBoxW(hwnd, warning, pTitle, MB_YESNO) == IDYES)
+ {
+ int selection = -1;
+
+ do {
+ selection = SendMessageW(lv, LVM_GETNEXTITEM, selection,
+ LVNI_SELECTED);
+ if (selection >= 0)
+ {
+ PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd,
+ selection);
+
+ CertDeleteCertificateFromStore(cert);
+ }
+ } while (selection >= 0);
+ cert_mgr_clear_cert_selection(hwnd);
+ }
+ }
+}
+
+static LRESULT CALLBACK cert_mgr_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
+ LPARAM lp)
+{
+ struct CertMgrData *data;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ PCCRYPTUI_CERT_MGR_STRUCT pCryptUICertMgr =
+ (PCCRYPTUI_CERT_MGR_STRUCT)lp;
+ HWND tab = GetDlgItem(hwnd, IDC_MGR_STORES);
+
+ data = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CertMgrData));
+ if (data)
+ {
+ data->imageList = ImageList_Create(16, 16, ILC_COLOR4 | ILC_MASK,
+ 2, 0);
+ if (data->imageList)
+ {
+ HBITMAP bmp;
+ COLORREF backColor = RGB(255, 0, 255);
+
+ bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_SMALL_ICONS));
+ ImageList_AddMasked(data->imageList, bmp, backColor);
+ DeleteObject(bmp);
+ ImageList_SetBkColor(data->imageList, CLR_NONE);
+ SendMessageW(GetDlgItem(hwnd, IDC_MGR_CERTS), LVM_SETIMAGELIST,
+ LVSIL_SMALL, (LPARAM)data->imageList);
+ }
+ SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
+ data->title = pCryptUICertMgr->pwszTitle;
+ }
+ initialize_purpose_selection(hwnd);
+ add_cert_columns(hwnd);
+ if (pCryptUICertMgr->pwszTitle)
+ SendMessageW(hwnd, WM_SETTEXT, 0,
+ (LPARAM)pCryptUICertMgr->pwszTitle);
+ show_cert_stores(hwnd, pCryptUICertMgr->dwFlags, data);
+ show_store_certs(hwnd, cert_mgr_index_to_store(tab, 0));
+ break;
+ }
+ case WM_NOTIFY:
+ {
+ NMHDR *hdr = (NMHDR *)lp;
+
+ switch (hdr->code)
+ {
+ case TCN_SELCHANGE:
+ cert_mgr_clear_cert_selection(hwnd);
+ break;
+ case LVN_ITEMCHANGED:
+ {
+ NMITEMACTIVATE *nm;
+ HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
+
+ nm = (NMITEMACTIVATE*)lp;
+ if (nm->uNewState & LVN_ITEMACTIVATE)
+ {
+ int numSelected = SendMessageW(lv, LVM_GETSELECTEDCOUNT, 0, 0);
+
+ EnableWindow(GetDlgItem(hwnd, IDC_MGR_EXPORT), numSelected > 0);
+ EnableWindow(GetDlgItem(hwnd, IDC_MGR_REMOVE), numSelected > 0);
+ EnableWindow(GetDlgItem(hwnd, IDC_MGR_VIEW), numSelected == 1);
+ if (numSelected == 1)
+ cert_mgr_show_cert_usages(hwnd, nm->iItem);
+ }
+ break;
+ }
+ case NM_DBLCLK:
+ show_selected_cert(hwnd, ((NMITEMACTIVATE *)lp)->iItem);
+ break;
+ case LVN_KEYDOWN:
+ {
+ NMLVKEYDOWN *lvk = (NMLVKEYDOWN *)lp;
+
+ if (lvk->wVKey == VK_DELETE)
+ cert_mgr_do_remove(hwnd);
+ break;
+ }
+ }
+ break;
+ }
+ case WM_COMMAND:
+ switch (wp)
+ {
+ case ((CBN_SELCHANGE << 16) | IDC_MGR_PURPOSE_SELECTION):
+ cert_mgr_clear_cert_selection(hwnd);
+ break;
+ case IDC_MGR_IMPORT:
+ if (CryptUIWizImport(0, hwnd, NULL, NULL,
+ cert_mgr_current_store(hwnd)))
+ refresh_store_certs(hwnd);
+ break;
+ case IDC_MGR_ADVANCED:
+ if (DialogBoxW(hInstance, MAKEINTRESOURCEW(IDD_CERT_MGR_ADVANCED),
+ hwnd, cert_mgr_advanced_dlg_proc) == IDOK)
+ {
+ HWND cb = GetDlgItem(hwnd, IDC_MGR_PURPOSE_SELECTION);
+ int index, len;
+ LPWSTR curString = NULL;
+
+ index = SendMessageW(cb, CB_GETCURSEL, 0, 0);
+ if (index >= 0)
+ {
+ len = SendMessageW(cb, CB_GETLBTEXTLEN, index, 0);
+ curString = HeapAlloc(GetProcessHeap(), 0,
+ (len + 1) * sizeof(WCHAR));
+ SendMessageW(cb, CB_GETLBTEXT, index, (LPARAM)curString);
+ }
+ SendMessageW(cb, CB_RESETCONTENT, 0, 0);
+ initialize_purpose_selection(hwnd);
+ if (curString)
+ {
+ index = SendMessageW(cb, CB_FINDSTRINGEXACT, -1,
+ (LPARAM)curString);
+ if (index >= 0)
+ SendMessageW(cb, CB_SETCURSEL, index, 0);
+ HeapFree(GetProcessHeap(), 0, curString);
+ }
+ refresh_store_certs(hwnd);
+ }
+ break;
+ case IDC_MGR_VIEW:
+ {
+ HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
+ int selection = SendMessageW(lv, LVM_GETNEXTITEM, -1,
+ LVNI_SELECTED);
+
+ if (selection >= 0)
+ show_selected_cert(hwnd, selection);
+ break;
+ }
+ case IDC_MGR_REMOVE:
+ cert_mgr_do_remove(hwnd);
+ break;
+ case IDCANCEL:
+ free_certs(GetDlgItem(hwnd, IDC_MGR_CERTS));
+ close_stores(GetDlgItem(hwnd, IDC_MGR_STORES));
+ close_stores(GetDlgItem(hwnd, IDC_MGR_STORES));
+ data = (struct CertMgrData *)GetWindowLongPtrW(hwnd, DWLP_USER);
+ ImageList_Destroy(data->imageList);
+ HeapFree(GetProcessHeap(), 0, data);
+ EndDialog(hwnd, IDCANCEL);
+ break;
+ }
+ break;
+ }
+ return 0;
+}
+
/***********************************************************************
* CryptUIDlgCertMgr (CRYPTUI.@)
*/
BOOL WINAPI CryptUIDlgCertMgr(PCCRYPTUI_CERT_MGR_STRUCT pCryptUICertMgr)
{
- FIXME("(%p): stub\n", pCryptUICertMgr);
- return FALSE;
+ TRACE("(%p)\n", pCryptUICertMgr);
+
+ if (pCryptUICertMgr->dwSize != sizeof(CRYPTUI_CERT_MGR_STRUCT))
+ {
+ WARN("unexpected size %d\n", pCryptUICertMgr->dwSize);
+ SetLastError(E_INVALIDARG);
+ return FALSE;
+ }
+ DialogBoxParamW(hInstance, MAKEINTRESOURCEW(IDD_CERT_MGR),
+ pCryptUICertMgr->hwndParent, cert_mgr_dlg_proc, (LPARAM)pCryptUICertMgr);
+ return TRUE;
+}
+
+/* FIXME: real names are unknown, functions are undocumented */
+typedef struct _CRYPTUI_ENUM_SYSTEM_STORE_ARGS
+{
+ DWORD dwFlags;
+ void *pvSystemStoreLocationPara;
+} CRYPTUI_ENUM_SYSTEM_STORE_ARGS, *PCRYPTUI_ENUM_SYSTEM_STORE_ARGS;
+
+typedef struct _CRYPTUI_ENUM_DATA
+{
+ DWORD cStores;
+ HCERTSTORE *rghStore;
+ DWORD cEnumArgs;
+ PCRYPTUI_ENUM_SYSTEM_STORE_ARGS rgEnumArgs;
+} CRYPTUI_ENUM_DATA, *PCRYPTUI_ENUM_DATA;
+
+typedef BOOL (WINAPI *PFN_SELECTED_STORE_CB)(HCERTSTORE store, HWND hwnd,
+ void *pvArg);
+
+/* Values for dwFlags */
+#define CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE 0x00000001
+
+typedef struct _CRYPTUI_SELECTSTORE_INFO_A
+{
+ DWORD dwSize;
+ HWND parent;
+ DWORD dwFlags;
+ LPSTR pszTitle;
+ LPSTR pszText;
+ CRYPTUI_ENUM_DATA *pEnumData;
+ PFN_SELECTED_STORE_CB pfnSelectedStoreCallback;
+ void *pvArg;
+} CRYPTUI_SELECTSTORE_INFO_A, *PCRYPTUI_SELECTSTORE_INFO_A;
+
+typedef struct _CRYPTUI_SELECTSTORE_INFO_W
+{
+ DWORD dwSize;
+ HWND parent;
+ DWORD dwFlags;
+ LPWSTR pwszTitle;
+ LPWSTR pwszText;
+ CRYPTUI_ENUM_DATA *pEnumData;
+ PFN_SELECTED_STORE_CB pfnSelectedStoreCallback;
+ void *pvArg;
+} CRYPTUI_SELECTSTORE_INFO_W, *PCRYPTUI_SELECTSTORE_INFO_W;
+
+struct StoreInfo
+{
+ enum {
+ StoreHandle,
+ SystemStore
+ } type;
+ union {
+ HCERTSTORE store;
+ LPWSTR name;
+ } DUMMYUNIONNAME;
+};
+
+static BOOL WINAPI enum_store_callback(const void *pvSystemStore,
+ DWORD dwFlags, PCERT_SYSTEM_STORE_INFO pStoreInfo, void *pvReserved,
+ void *pvArg)
+{
+ HWND tree = GetDlgItem(pvArg, IDC_STORE_LIST);
+ TVINSERTSTRUCTW tvis;
+ LPCWSTR localizedName;
+ BOOL ret = TRUE;
+
+ tvis.hParent = NULL;
+ tvis.hInsertAfter = TVI_LAST;
+ tvis.u.item.mask = TVIF_TEXT;
+ if ((localizedName = CryptFindLocalizedName(pvSystemStore)))
+ {
+ struct StoreInfo *storeInfo = HeapAlloc(GetProcessHeap(), 0,
+ sizeof(struct StoreInfo));
+
+ if (storeInfo)
+ {
+ storeInfo->type = SystemStore;
+ storeInfo->u.name = HeapAlloc(GetProcessHeap(), 0,
+ (strlenW(pvSystemStore) + 1) * sizeof(WCHAR));
+ if (storeInfo->u.name)
+ {
+ tvis.u.item.mask |= TVIF_PARAM;
+ tvis.u.item.lParam = (LPARAM)storeInfo;
+ strcpyW(storeInfo->u.name, pvSystemStore);
+ }
+ else
+ {
+ HeapFree(GetProcessHeap(), 0, storeInfo);
+ ret = FALSE;
+ }
+ }
+ else
+ ret = FALSE;
+ tvis.u.item.pszText = (LPWSTR)localizedName;
+ }
+ else
+ tvis.u.item.pszText = (LPWSTR)pvSystemStore;
+ /* FIXME: need a folder icon for the store too */
+ if (ret)
+ SendMessageW(tree, TVM_INSERTITEMW, 0, (LPARAM)&tvis);
+ return ret;
+}
+
+static void enumerate_stores(HWND hwnd, CRYPTUI_ENUM_DATA *pEnumData)
+{
+ DWORD i;
+ HWND tree = GetDlgItem(hwnd, IDC_STORE_LIST);
+
+ for (i = 0; i < pEnumData->cEnumArgs; i++)
+ CertEnumSystemStore(pEnumData->rgEnumArgs[i].dwFlags,
+ pEnumData->rgEnumArgs[i].pvSystemStoreLocationPara,
+ hwnd, enum_store_callback);
+ for (i = 0; i < pEnumData->cStores; i++)
+ {
+ DWORD size;
+
+ if (CertGetStoreProperty(pEnumData->rghStore[i],
+ CERT_STORE_LOCALIZED_NAME_PROP_ID, NULL, &size))
+ {
+ LPWSTR name = HeapAlloc(GetProcessHeap(), 0, size);
+
+ if (name)
+ {
+ if (CertGetStoreProperty(pEnumData->rghStore[i],
+ CERT_STORE_LOCALIZED_NAME_PROP_ID, name, &size))
+ {
+ struct StoreInfo *storeInfo = HeapAlloc(GetProcessHeap(),
+ 0, sizeof(struct StoreInfo));
+
+ if (storeInfo)
+ {
+ TVINSERTSTRUCTW tvis;
+
+ storeInfo->type = StoreHandle;
+ storeInfo->u.store = pEnumData->rghStore[i];
+ tvis.hParent = NULL;
+ tvis.hInsertAfter = TVI_LAST;
+ tvis.u.item.mask = TVIF_TEXT | TVIF_PARAM;
+ tvis.u.item.pszText = name;
+ tvis.u.item.lParam = (LPARAM)storeInfo;
+ SendMessageW(tree, TVM_INSERTITEMW, 0, (LPARAM)&tvis);
+ }
+ }
+ HeapFree(GetProcessHeap(), 0, name);
+ }
+ }
+ }
+}
+
+static void free_store_info(HWND tree)
+{
+ HTREEITEM next = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM, TVGN_CHILD,
+ (LPARAM)NULL);
+
+ while (next)
+ {
+ TVITEMW item;
+
+ memset(&item, 0, sizeof(item));
+ item.mask = TVIF_HANDLE | TVIF_PARAM;
+ item.hItem = next;
+ SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item);
+ if (item.lParam)
+ {
+ struct StoreInfo *storeInfo = (struct StoreInfo *)item.lParam;
+
+ if (storeInfo->type == SystemStore)
+ HeapFree(GetProcessHeap(), 0, storeInfo->u.name);
+ HeapFree(GetProcessHeap(), 0, storeInfo);
+ }
+ next = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM, TVGN_NEXT,
+ (LPARAM)next);
+ }
+}
+
+static HCERTSTORE selected_item_to_store(HWND tree, HTREEITEM hItem)
+{
+ WCHAR buf[MAX_STRING_LEN];
+ TVITEMW item;
+ HCERTSTORE store;
+
+ memset(&item, 0, sizeof(item));
+ item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_TEXT;
+ item.hItem = hItem;
+ item.cchTextMax = sizeof(buf) / sizeof(buf[0]);
+ item.pszText = buf;
+ SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item);
+ if (item.lParam)
+ {
+ struct StoreInfo *storeInfo = (struct StoreInfo *)item.lParam;
+
+ if (storeInfo->type == StoreHandle)
+ store = storeInfo->u.store;
+ else
+ store = CertOpenSystemStoreW(0, storeInfo->u.name);
+ }
+ else
+ {
+ /* It's implicitly a system store */
+ store = CertOpenSystemStoreW(0, buf);
+ }
+ return store;
+}
+
+struct SelectStoreInfo
+{
+ PCRYPTUI_SELECTSTORE_INFO_W info;
+ HCERTSTORE store;
+};
+
+static LRESULT CALLBACK select_store_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
+ LPARAM lp)
+{
+ struct SelectStoreInfo *selectInfo;
+ LRESULT ret = 0;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ selectInfo = (struct SelectStoreInfo *)lp;
+ SetWindowLongPtrW(hwnd, DWLP_USER, lp);
+ if (selectInfo->info->pwszTitle)
+ SendMessageW(hwnd, WM_SETTEXT, 0,
+ (LPARAM)selectInfo->info->pwszTitle);
+ if (selectInfo->info->pwszText)
+ SendMessageW(GetDlgItem(hwnd, IDC_STORE_TEXT), WM_SETTEXT, 0,
+ (LPARAM)selectInfo->info->pwszText);
+ if (!(selectInfo->info->dwFlags & CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE))
+ ShowWindow(GetDlgItem(hwnd, IDC_SHOW_PHYSICAL_STORES), FALSE);
+ enumerate_stores(hwnd, selectInfo->info->pEnumData);
+ break;
+ }
+ case WM_COMMAND:
+ switch (wp)
+ {
+ case IDOK:
+ {
+ HWND tree = GetDlgItem(hwnd, IDC_STORE_LIST);
+ HTREEITEM selection = (HTREEITEM)SendMessageW(tree,
+ TVM_GETNEXTITEM, TVGN_CARET, (LPARAM)NULL);
+
+ selectInfo = (struct SelectStoreInfo *)GetWindowLongPtrW(hwnd,
+ DWLP_USER);
+ if (!selection)
+ {
+ WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN], *pTitle;
+
+ if (selectInfo->info->pwszTitle)
+ pTitle = selectInfo->info->pwszTitle;
+ else
+ {
+ LoadStringW(hInstance, IDS_SELECT_STORE_TITLE, title,
+ sizeof(title) / sizeof(title[0]));
+ pTitle = title;
+ }
+ LoadStringW(hInstance, IDS_SELECT_STORE, error,
+ sizeof(error) / sizeof(error[0]));
+ MessageBoxW(hwnd, error, pTitle, MB_ICONEXCLAMATION | MB_OK);
+ }
+ else
+ {
+ HCERTSTORE store = selected_item_to_store(tree, selection);
+
+ if (!selectInfo->info->pfnSelectedStoreCallback ||
+ selectInfo->info->pfnSelectedStoreCallback(store, hwnd,
+ selectInfo->info->pvArg))
+ {
+ selectInfo->store = store;
+ free_store_info(tree);
+ EndDialog(hwnd, IDOK);
+ }
+ else
+ CertCloseStore(store, 0);
+ }
+ ret = TRUE;
+ break;
+ }
+ case IDCANCEL:
+ free_store_info(GetDlgItem(hwnd, IDC_STORE_LIST));
+ EndDialog(hwnd, IDCANCEL);
+ ret = TRUE;
+ break;
+ }
+ break;
+ }
+ return ret;
+}
+
+/***********************************************************************
+ * CryptUIDlgSelectStoreW (CRYPTUI.@)
+ */
+HCERTSTORE WINAPI CryptUIDlgSelectStoreW(PCRYPTUI_SELECTSTORE_INFO_W info)
+{
+ struct SelectStoreInfo selectInfo = { info, NULL };
+
+ TRACE("(%p)\n", info);
+
+ if (info->dwSize != sizeof(CRYPTUI_SELECTSTORE_INFO_W))
+ {
+ WARN("unexpected size %d\n", info->dwSize);
+ SetLastError(E_INVALIDARG);
+ return NULL;
+ }
+ DialogBoxParamW(hInstance, MAKEINTRESOURCEW(IDD_SELECT_STORE), info->parent,
+ select_store_dlg_proc, (LPARAM)&selectInfo);
+ return selectInfo.store;
+}
+
+/***********************************************************************
+ * CryptUIDlgSelectStoreA (CRYPTUI.@)
+ */
+HCERTSTORE WINAPI CryptUIDlgSelectStoreA(PCRYPTUI_SELECTSTORE_INFO_A info)
+{
+ CRYPTUI_SELECTSTORE_INFO_W infoW;
+ HCERTSTORE ret;
+ int len;
+
+ TRACE("(%p)\n", info);
+
+ if (info->dwSize != sizeof(CRYPTUI_SELECTSTORE_INFO_A))
+ {
+ WARN("unexpected size %d\n", info->dwSize);
+ SetLastError(E_INVALIDARG);
+ return NULL;
+ }
+ memcpy(&infoW, &info, sizeof(info));
+ if (info->pszTitle)
+ {
+ len = MultiByteToWideChar(CP_ACP, 0, info->pszTitle, -1, NULL, 0);
+ infoW.pwszTitle = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ MultiByteToWideChar(CP_ACP, 0, info->pszTitle, -1, infoW.pwszTitle,
+ len);
+ }
+ if (info->pszText)
+ {
+ len = MultiByteToWideChar(CP_ACP, 0, info->pszText, -1, NULL, 0);
+ infoW.pwszText = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ MultiByteToWideChar(CP_ACP, 0, info->pszText, -1, infoW.pwszText, len);
+ }
+ ret = CryptUIDlgSelectStoreW(&infoW);
+ HeapFree(GetProcessHeap(), 0, infoW.pwszText);
+ HeapFree(GetProcessHeap(), 0, infoW.pwszTitle);
+ return ret;
}
/***********************************************************************
@@ -223,6 +1666,7 @@ static void add_icon_to_control(HWND hwnd, int id)
HBITMAP bitmap = NULL;
RECT rect;
STGMEDIUM stgm;
+ LPOLECLIENTSITE clientSite = NULL;
REOBJECT reObject;
TRACE("(%p, %d)\n", hwnd, id);
@@ -250,6 +1694,9 @@ static void add_icon_to_control(HWND hwnd, int id)
goto end;
hr = IOleObject_QueryInterface(object, &IID_IDataObject,
(void**)&dataObject);
+ if (FAILED(hr))
+ goto end;
+ hr = IRichEditOle_GetClientSite(richEditOle, &clientSite);
if (FAILED(hr))
goto end;
bitmap = LoadImageW(hInstance, MAKEINTRESOURCEW(id), IMAGE_BITMAP, 0, 0,
@@ -271,7 +1718,7 @@ static void add_icon_to_control(HWND hwnd, int id)
reObject.clsid = clsid;
reObject.poleobj = object;
reObject.pstg = NULL;
- reObject.polesite = NULL;
+ reObject.polesite = clientSite;
reObject.sizel.cx = reObject.sizel.cy = 0;
reObject.dvaspect = DVASPECT_CONTENT;
reObject.dwFlags = 0;
@@ -280,6 +1727,8 @@ static void add_icon_to_control(HWND hwnd, int id)
IRichEditOle_InsertObject(richEditOle, &reObject);
end:
+ if (clientSite)
+ IOleClientSite_Release(clientSite);
if (dataObject)
IDataObject_Release(dataObject);
if (oleCache)
@@ -309,8 +1758,6 @@ static void add_oid_text_to_control(HWND hwnd, char *oid)
}
}
-#define MAX_STRING_LEN 512
-
struct OIDToString
{
LPCSTR oid;
@@ -941,7 +2388,7 @@ static LRESULT CALLBACK general_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
switch (wp)
{
case IDC_ADDTOSTORE:
- FIXME("call CryptUIWizImport\n");
+ CryptUIWizImport(0, hwnd, NULL, NULL, NULL);
break;
case IDC_ISSUERSTATEMENT:
{
@@ -1556,13 +3003,6 @@ static void create_cert_details_list(HWND hwnd, struct detail_data *data)
set_fields_selection(hwnd, data, 0);
}
-typedef enum {
- CheckBitmapIndexUnchecked = 1,
- CheckBitmapIndexChecked = 2,
- CheckBitmapIndexDisabledUnchecked = 3,
- CheckBitmapIndexDisabledChecked = 4
-} CheckBitmapIndex;
-
static void add_purpose(HWND hwnd, LPCSTR oid)
{
HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
@@ -1634,30 +3074,8 @@ static BOOL is_valid_oid(LPCSTR oid)
static BOOL is_oid_in_list(HWND hwnd, LPCSTR oid)
{
- HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
- PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
- (void *)oid, CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
- BOOL ret = FALSE;
-
- if (oidInfo)
- {
- LVFINDINFOW findInfo;
-
- findInfo.flags = LVFI_PARAM;
- findInfo.lParam = (LPARAM)oidInfo;
- if (SendMessageW(lv, LVM_FINDITEMW, -1, (LPARAM)&findInfo) != -1)
- ret = TRUE;
- }
- else
- {
- LVFINDINFOA findInfo;
-
- findInfo.flags = LVFI_STRING;
- findInfo.psz = oid;
- if (SendMessageW(lv, LVM_FINDITEMA, -1, (LPARAM)&findInfo) != -1)
- ret = TRUE;
- }
- return ret;
+ return find_oid_in_list(GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES), oid)
+ != -1;
}
#define MAX_PURPOSE 255
@@ -1842,23 +3260,6 @@ static void select_purposes(HWND hwnd, PurposeSelection selection)
}
}
-extern BOOL WINAPI WTHelperGetKnownUsages(DWORD action,
- PCCRYPT_OID_INFO **usages);
-
-static void add_known_usage(HWND lv, PCCRYPT_OID_INFO info)
-{
- LVITEMW item;
-
- item.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM;
- item.state = INDEXTOSTATEIMAGEMASK(CheckBitmapIndexDisabledChecked);
- item.stateMask = LVIS_STATEIMAGEMASK;
- item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
- item.iSubItem = 0;
- item.lParam = (LPARAM)info;
- item.pszText = (LPWSTR)info->pwszName;
- SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
-}
-
struct edit_cert_data
{
PCCERT_CONTEXT cert;
@@ -1872,7 +3273,6 @@ static void show_cert_usages(HWND hwnd, struct edit_cert_data *data)
HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
PCERT_ENHKEY_USAGE usage;
DWORD size;
- PCCRYPT_OID_INFO *usages;
RECT rc;
LVCOLUMNW column;
PurposeSelection purposeSelection;
@@ -1933,23 +3333,14 @@ static void show_cert_usages(HWND hwnd, struct edit_cert_data *data)
usage->rgpszUsageIdentifier[i], CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
if (info)
- add_known_usage(lv, info);
+ add_known_usage(lv, info, CheckBitmapIndexDisabledChecked);
else
add_purpose(hwnd, usage->rgpszUsageIdentifier[i]);
}
HeapFree(GetProcessHeap(), 0, usage);
}
else
- {
- if (WTHelperGetKnownUsages(1, &usages))
- {
- PCCRYPT_OID_INFO *ptr;
-
- for (ptr = usages; *ptr; ptr++)
- add_known_usage(lv, *ptr);
- WTHelperGetKnownUsages(2, &usages);
- }
- }
+ add_known_usages_to_list(lv, CheckBitmapIndexDisabledChecked);
select_purposes(hwnd, purposeSelection);
SendMessageW(GetDlgItem(hwnd, IDC_ENABLE_ALL_PURPOSES + purposeSelection),
BM_CLICK, 0, 0);
@@ -1975,28 +3366,6 @@ static void set_general_cert_properties(HWND hwnd, struct edit_cert_data *data)
show_cert_usages(hwnd, data);
}
-static void toggle_usage(HWND hwnd, int iItem)
-{
- LVITEMW item;
- int res;
- HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
-
- item.mask = LVIF_STATE;
- item.iItem = iItem;
- item.iSubItem = 0;
- item.stateMask = LVIS_STATEIMAGEMASK;
- res = SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item);
- if (res)
- {
- int state = item.state >> 12;
-
- item.state = INDEXTOSTATEIMAGEMASK(
- state == CheckBitmapIndexChecked ? CheckBitmapIndexUnchecked :
- CheckBitmapIndexChecked);
- SendMessageW(lv, LVM_SETITEMSTATE, iItem, (LPARAM)&item);
- }
-}
-
static void set_cert_string_property(PCCERT_CONTEXT cert, DWORD prop,
LPWSTR str)
{
@@ -2999,46 +4368,6 @@ BOOL WINAPI CryptUIDlgViewContext(DWORD dwContextType, LPVOID pvContext,
return ret;
}
-static PCCERT_CONTEXT make_cert_from_file(LPCWSTR fileName)
-{
- HANDLE file;
- DWORD size, encoding = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
- BYTE *buffer;
- PCCERT_CONTEXT cert;
-
- file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
- OPEN_EXISTING, 0, NULL);
- if (file == INVALID_HANDLE_VALUE)
- {
- WARN("can't open certificate file %s\n", debugstr_w(fileName));
- return NULL;
- }
- if ((size = GetFileSize(file, NULL)))
- {
- if ((buffer = HeapAlloc(GetProcessHeap(), 0, size)))
- {
- DWORD read;
- if (!ReadFile(file, buffer, size, &read, NULL) || read != size)
- {
- WARN("can't read certificate file %s\n", debugstr_w(fileName));
- HeapFree(GetProcessHeap(), 0, buffer);
- CloseHandle(file);
- return NULL;
- }
- }
- }
- else
- {
- WARN("empty file %s\n", debugstr_w(fileName));
- CloseHandle(file);
- return NULL;
- }
- CloseHandle(file);
- cert = CertCreateCertificateContext(encoding, buffer, size);
- HeapFree(GetProcessHeap(), 0, buffer);
- return cert;
-}
-
/* Decodes a cert's basic constraints extension (either szOID_BASIC_CONSTRAINTS
* or szOID_BASIC_CONSTRAINTS2, whichever is present) to determine if it
* should be a CA. If neither extension is present, returns
@@ -3084,77 +4413,1025 @@ static BOOL is_ca_cert(PCCERT_CONTEXT cert, BOOL defaultIfNotSpecified)
static HCERTSTORE choose_store_for_cert(PCCERT_CONTEXT cert)
{
- static const WCHAR AddressBook[] = { 'A','d','d','r','e','s','s',
- 'B','o','o','k',0 };
- static const WCHAR CA[] = { 'C','A',0 };
LPCWSTR storeName;
if (is_ca_cert(cert, TRUE))
- storeName = CA;
+ storeName = ca;
else
- storeName = AddressBook;
+ storeName = addressBook;
return CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0,
CERT_SYSTEM_STORE_CURRENT_USER, storeName);
}
-BOOL WINAPI CryptUIWizImport(DWORD dwFlags, HWND hwndParent, LPCWSTR pwszWizardTitle,
- PCCRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc, HCERTSTORE hDestCertStore)
+static BOOL import_cert(PCCERT_CONTEXT cert, HCERTSTORE hDestCertStore)
{
- BOOL ret;
HCERTSTORE store;
- const CERT_CONTEXT *cert;
- BOOL freeCert = FALSE;
+ BOOL ret;
- TRACE("(0x%08x, %p, %s, %p, %p)\n", dwFlags, hwndParent, debugstr_w(pwszWizardTitle),
- pImportSrc, hDestCertStore);
-
- if (!(dwFlags & CRYPTUI_WIZ_NO_UI)) FIXME("UI not implemented\n");
-
- if (!pImportSrc ||
- pImportSrc->dwSize != sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO))
+ if (!cert)
{
SetLastError(E_INVALIDARG);
return FALSE;
}
-
- switch (pImportSrc->dwSubjectChoice)
- {
- case CRYPTUI_WIZ_IMPORT_SUBJECT_FILE:
- if (!(cert = make_cert_from_file(pImportSrc->u.pwszFileName)))
- {
- WARN("unable to create certificate context\n");
- return FALSE;
- }
- else
- freeCert = TRUE;
- break;
- case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_CONTEXT:
- cert = pImportSrc->u.pCertContext;
- if (!cert)
- {
- SetLastError(E_INVALIDARG);
- return FALSE;
- }
- break;
- default:
- FIXME("source type not implemented: %u\n", pImportSrc->dwSubjectChoice);
- SetLastError(E_INVALIDARG);
- return FALSE;
- }
if (hDestCertStore) store = hDestCertStore;
else
{
if (!(store = choose_store_for_cert(cert)))
{
WARN("unable to open certificate store\n");
- CertFreeCertificateContext(cert);
return FALSE;
}
}
- ret = CertAddCertificateContextToStore(store, cert, CERT_STORE_ADD_REPLACE_EXISTING, NULL);
-
+ ret = CertAddCertificateContextToStore(store, cert,
+ CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES, NULL);
if (!hDestCertStore) CertCloseStore(store, 0);
- if (freeCert)
- CertFreeCertificateContext(cert);
+ return ret;
+}
+
+static BOOL import_crl(PCCRL_CONTEXT crl, HCERTSTORE hDestCertStore)
+{
+ HCERTSTORE store;
+ BOOL ret;
+
+ if (!crl)
+ {
+ SetLastError(E_INVALIDARG);
+ return FALSE;
+ }
+ if (hDestCertStore) store = hDestCertStore;
+ else
+ {
+ if (!(store = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0,
+ CERT_SYSTEM_STORE_CURRENT_USER, ca)))
+ {
+ WARN("unable to open certificate store\n");
+ return FALSE;
+ }
+ }
+ ret = CertAddCRLContextToStore(store, crl,
+ CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES, NULL);
+ if (!hDestCertStore) CertCloseStore(store, 0);
+ return ret;
+}
+
+static BOOL import_ctl(PCCTL_CONTEXT ctl, HCERTSTORE hDestCertStore)
+{
+ HCERTSTORE store;
+ BOOL ret;
+
+ if (!ctl)
+ {
+ SetLastError(E_INVALIDARG);
+ return FALSE;
+ }
+ if (hDestCertStore) store = hDestCertStore;
+ else
+ {
+ static const WCHAR trust[] = { 'T','r','u','s','t',0 };
+
+ if (!(store = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0,
+ CERT_SYSTEM_STORE_CURRENT_USER, trust)))
+ {
+ WARN("unable to open certificate store\n");
+ return FALSE;
+ }
+ }
+ ret = CertAddCTLContextToStore(store, ctl,
+ CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES, NULL);
+ if (!hDestCertStore) CertCloseStore(store, 0);
+ return ret;
+}
+
+/* Checks type, a type such as CERT_QUERY_CONTENT_CERT returned by
+ * CryptQueryObject, against the allowed types. Returns TRUE if the
+ * type is allowed, FALSE otherwise.
+ */
+static BOOL check_context_type(DWORD dwFlags, DWORD type)
+{
+ BOOL ret;
+
+ if (dwFlags &
+ (CRYPTUI_WIZ_IMPORT_ALLOW_CERT | CRYPTUI_WIZ_IMPORT_ALLOW_CRL |
+ CRYPTUI_WIZ_IMPORT_ALLOW_CTL))
+ {
+ switch (type)
+ {
+ case CERT_QUERY_CONTENT_CERT:
+ case CERT_QUERY_CONTENT_SERIALIZED_CERT:
+ ret = dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CERT;
+ break;
+ case CERT_QUERY_CONTENT_CRL:
+ case CERT_QUERY_CONTENT_SERIALIZED_CRL:
+ ret = dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CRL;
+ break;
+ case CERT_QUERY_CONTENT_CTL:
+ case CERT_QUERY_CONTENT_SERIALIZED_CTL:
+ ret = dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CTL;
+ break;
+ default:
+ /* The remaining types contain more than one type, so allow
+ * any combination.
+ */
+ ret = TRUE;
+ }
+ }
+ else
+ {
+ /* No allowed types specified, so any type is allowed */
+ ret = TRUE;
+ }
+ if (!ret)
+ SetLastError(E_INVALIDARG);
+ return ret;
+}
+
+
+static void import_warning(DWORD dwFlags, HWND hwnd, LPCWSTR szTitle,
+ int warningID)
+{
+ if (!(dwFlags & CRYPTUI_WIZ_NO_UI))
+ {
+ WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
+ LPCWSTR pTitle;
+
+ if (szTitle)
+ pTitle = szTitle;
+ else
+ {
+ LoadStringW(hInstance, IDS_IMPORT_WIZARD, title,
+ sizeof(title) / sizeof(title[0]));
+ pTitle = title;
+ }
+ LoadStringW(hInstance, warningID, error,
+ sizeof(error) / sizeof(error[0]));
+ MessageBoxW(hwnd, error, pTitle, MB_ICONERROR | MB_OK);
+ }
+}
+
+static void import_warn_type_mismatch(DWORD dwFlags, HWND hwnd, LPCWSTR szTitle)
+{
+ import_warning(dwFlags, hwnd, szTitle, IDS_IMPORT_TYPE_MISMATCH);
+}
+
+static BOOL check_store_context_type(DWORD dwFlags, HCERTSTORE store)
+{
+ BOOL ret;
+
+ if (dwFlags &
+ (CRYPTUI_WIZ_IMPORT_ALLOW_CERT | CRYPTUI_WIZ_IMPORT_ALLOW_CRL |
+ CRYPTUI_WIZ_IMPORT_ALLOW_CTL))
+ {
+ PCCERT_CONTEXT cert;
+ PCCRL_CONTEXT crl;
+ PCCTL_CONTEXT ctl;
+
+ ret = TRUE;
+ if ((cert = CertEnumCertificatesInStore(store, NULL)))
+ {
+ CertFreeCertificateContext(cert);
+ if (!(dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CERT))
+ ret = FALSE;
+ }
+ if (ret && (crl = CertEnumCRLsInStore(store, NULL)))
+ {
+ CertFreeCRLContext(crl);
+ if (!(dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CRL))
+ ret = FALSE;
+ }
+ if (ret && (ctl = CertEnumCTLsInStore(store, NULL)))
+ {
+ CertFreeCTLContext(ctl);
+ if (!(dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CTL))
+ ret = FALSE;
+ }
+ }
+ else
+ ret = TRUE;
+ if (!ret)
+ SetLastError(E_INVALIDARG);
+ return ret;
+}
+
+static BOOL import_store(DWORD dwFlags, HWND hwnd, LPCWSTR szTitle,
+ HCERTSTORE source, HCERTSTORE dest)
+{
+ BOOL ret;
+
+ if ((ret = check_store_context_type(dwFlags, source)))
+ {
+ PCCERT_CONTEXT cert = NULL;
+ PCCRL_CONTEXT crl = NULL;
+ PCCTL_CONTEXT ctl = NULL;
+
+ do {
+ cert = CertEnumCertificatesInStore(source, cert);
+ if (cert)
+ ret = import_cert(cert, dest);
+ } while (ret && cert);
+ do {
+ crl = CertEnumCRLsInStore(source, crl);
+ if (crl)
+ ret = import_crl(crl, dest);
+ } while (ret && crl);
+ do {
+ ctl = CertEnumCTLsInStore(source, ctl);
+ if (ctl)
+ ret = import_ctl(ctl, dest);
+ } while (ret && ctl);
+ }
+ else
+ import_warn_type_mismatch(dwFlags, hwnd, szTitle);
+ return ret;
+}
+
+static HCERTSTORE open_store_from_file(DWORD dwFlags, LPCWSTR fileName,
+ DWORD *pContentType)
+{
+ HCERTSTORE store = NULL;
+ DWORD contentType = 0, expectedContentTypeFlags;
+
+ if (dwFlags &
+ (CRYPTUI_WIZ_IMPORT_ALLOW_CERT | CRYPTUI_WIZ_IMPORT_ALLOW_CRL |
+ CRYPTUI_WIZ_IMPORT_ALLOW_CTL))
+ {
+ expectedContentTypeFlags =
+ CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE |
+ CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED |
+ CERT_QUERY_CONTENT_FLAG_PFX;
+ if (dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CERT)
+ expectedContentTypeFlags |=
+ CERT_QUERY_CONTENT_FLAG_CERT |
+ CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT;
+ if (dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CRL)
+ expectedContentTypeFlags |=
+ CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL |
+ CERT_QUERY_CONTENT_FLAG_CRL;
+ if (dwFlags & CRYPTUI_WIZ_IMPORT_ALLOW_CTL)
+ expectedContentTypeFlags |=
+ CERT_QUERY_CONTENT_FLAG_CTL |
+ CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL;
+ }
+ else
+ expectedContentTypeFlags =
+ CERT_QUERY_CONTENT_FLAG_CERT |
+ CERT_QUERY_CONTENT_FLAG_CTL |
+ CERT_QUERY_CONTENT_FLAG_CRL |
+ CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE |
+ CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT |
+ CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL |
+ CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL |
+ CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED |
+ CERT_QUERY_CONTENT_FLAG_PFX;
+
+ CryptQueryObject(CERT_QUERY_OBJECT_FILE, fileName,
+ expectedContentTypeFlags, CERT_QUERY_FORMAT_FLAG_ALL, 0, NULL,
+ &contentType, NULL, &store, NULL, NULL);
+ if (pContentType)
+ *pContentType = contentType;
+ return store;
+}
+
+static BOOL import_file(DWORD dwFlags, HWND hwnd, LPCWSTR szTitle,
+ LPCWSTR fileName, HCERTSTORE dest)
+{
+ HCERTSTORE source;
+ BOOL ret;
+
+ if ((source = open_store_from_file(dwFlags, fileName, NULL)))
+ {
+ ret = import_store(dwFlags, hwnd, szTitle, source, dest);
+ CertCloseStore(source, 0);
+ }
+ else
+ ret = FALSE;
+ return ret;
+}
+
+struct ImportWizData
+{
+ HFONT titleFont;
+ DWORD dwFlags;
+ LPCWSTR pwszWizardTitle;
+ CRYPTUI_WIZ_IMPORT_SRC_INFO importSrc;
+ LPWSTR fileName;
+ DWORD contentType;
+ BOOL freeSource;
+ HCERTSTORE hDestCertStore;
+ BOOL freeDest;
+ BOOL autoDest;
+ BOOL success;
+};
+
+static LRESULT CALLBACK import_welcome_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
+ LPARAM lp)
+{
+ LRESULT ret = 0;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ struct ImportWizData *data;
+ PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
+ WCHAR fontFace[MAX_STRING_LEN];
+ HDC hDC = GetDC(hwnd);
+ int height;
+
+ data = (struct ImportWizData *)page->lParam;
+ LoadStringW(hInstance, IDS_WIZARD_TITLE_FONT, fontFace,
+ sizeof(fontFace) / sizeof(fontFace[0]));
+ height = -MulDiv(12, GetDeviceCaps(hDC, LOGPIXELSY), 72);
+ data->titleFont = CreateFontW(height, 0, 0, 0, FW_BOLD, 0, 0, 0,
+ DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
+ DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, fontFace);
+ SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_TITLE), WM_SETFONT,
+ (WPARAM)data->titleFont, TRUE);
+ ReleaseDC(hwnd, hDC);
+ break;
+ }
+ case WM_NOTIFY:
+ {
+ NMHDR *hdr = (NMHDR *)lp;
+
+ switch (hdr->code)
+ {
+ case PSN_SETACTIVE:
+ PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0, PSWIZB_NEXT);
+ ret = TRUE;
+ break;
+ }
+ break;
+ }
+ }
+ return ret;
+}
+
+static const WCHAR filter_cert[] = { '*','.','c','e','r',';','*','.',
+ 'c','r','t',0 };
+static const WCHAR filter_pfx[] = { '*','.','p','f','x',';','*','.',
+ 'p','1','2',0 };
+static const WCHAR filter_crl[] = { '*','.','c','r','l',0 };
+static const WCHAR filter_ctl[] = { '*','.','s','t','l',0 };
+static const WCHAR filter_serialized_store[] = { '*','.','s','s','t',0 };
+static const WCHAR filter_cms[] = { '*','.','s','p','c',';','*','.',
+ 'p','7','b',0 };
+static const WCHAR filter_all[] = { '*','.','*',0 };
+
+struct StringToFilter
+{
+ int id;
+ DWORD allowFlags;
+ LPCWSTR filter;
+} import_filters[] = {
+ { IDS_IMPORT_FILTER_CERT, CRYPTUI_WIZ_IMPORT_ALLOW_CERT, filter_cert },
+ { IDS_IMPORT_FILTER_PFX, 0, filter_pfx },
+ { IDS_IMPORT_FILTER_CRL, CRYPTUI_WIZ_IMPORT_ALLOW_CRL, filter_crl },
+ { IDS_IMPORT_FILTER_CTL, CRYPTUI_WIZ_IMPORT_ALLOW_CTL, filter_ctl },
+ { IDS_IMPORT_FILTER_SERIALIZED_STORE, 0, filter_serialized_store },
+ { IDS_IMPORT_FILTER_CMS, 0, filter_cms },
+ { IDS_IMPORT_FILTER_ALL, 0, filter_all },
+};
+
+static WCHAR *make_import_file_filter(DWORD dwFlags)
+{
+ DWORD i;
+ int len, totalLen = 2;
+ LPWSTR filter = NULL, str;
+
+ for (i = 0; i < sizeof(import_filters) / sizeof(import_filters[0]); i++)
+ {
+ if (!import_filters[i].allowFlags || !dwFlags ||
+ (dwFlags & import_filters[i].allowFlags))
+ {
+ len = LoadStringW(hInstance, import_filters[i].id, (LPWSTR)&str, 0);
+ totalLen += len + strlenW(import_filters[i].filter) + 2;
+ }
+ }
+ filter = HeapAlloc(GetProcessHeap(), 0, totalLen * sizeof(WCHAR));
+ if (filter)
+ {
+ LPWSTR ptr;
+
+ ptr = filter;
+ for (i = 0; i < sizeof(import_filters) / sizeof(import_filters[0]); i++)
+ {
+ if (!import_filters[i].allowFlags || !dwFlags ||
+ (dwFlags & import_filters[i].allowFlags))
+ {
+ len = LoadStringW(hInstance, import_filters[i].id,
+ (LPWSTR)&str, 0);
+ memcpy(ptr, str, len * sizeof(WCHAR));
+ ptr += len;
+ *ptr++ = 0;
+ strcpyW(ptr, import_filters[i].filter);
+ ptr += strlenW(import_filters[i].filter) + 1;
+ }
+ }
+ *ptr++ = 0;
+ }
+ return filter;
+}
+
+static BOOL import_validate_filename(HWND hwnd, struct ImportWizData *data,
+ LPCWSTR fileName)
+{
+ HANDLE file;
+ BOOL ret = FALSE;
+
+ file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
+ OPEN_EXISTING, 0, NULL);
+ if (file != INVALID_HANDLE_VALUE)
+ {
+ HCERTSTORE source = open_store_from_file(data->dwFlags, fileName,
+ &data->contentType);
+ int warningID = 0;
+
+ if (!source)
+ warningID = IDS_IMPORT_BAD_FORMAT;
+ else if (!check_store_context_type(data->dwFlags, source))
+ warningID = IDS_IMPORT_TYPE_MISMATCH;
+ else
+ {
+ data->importSrc.dwSubjectChoice =
+ CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE;
+ data->importSrc.u.hCertStore = source;
+ data->freeSource = TRUE;
+ ret = TRUE;
+ }
+ if (warningID)
+ {
+ import_warning(data->dwFlags, hwnd, data->pwszWizardTitle,
+ warningID);
+ }
+ CloseHandle(file);
+ }
+ else
+ {
+ WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
+ LPCWSTR pTitle;
+ LPWSTR msgBuf, fullError;
+
+ if (data->pwszWizardTitle)
+ pTitle = data->pwszWizardTitle;
+ else
+ {
+ LoadStringW(hInstance, IDS_IMPORT_WIZARD, title,
+ sizeof(title) / sizeof(title[0]));
+ pTitle = title;
+ }
+ LoadStringW(hInstance, IDS_IMPORT_OPEN_FAILED, error,
+ sizeof(error) / sizeof(error[0]));
+ FormatMessageW(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
+ GetLastError(), 0, (LPWSTR) &msgBuf, 0, NULL);
+ fullError = HeapAlloc(GetProcessHeap(), 0,
+ (strlenW(error) + strlenW(fileName) + strlenW(msgBuf) + 3)
+ * sizeof(WCHAR));
+ if (fullError)
+ {
+ LPWSTR ptr = fullError;
+
+ strcpyW(ptr, error);
+ ptr += strlenW(error);
+ strcpyW(ptr, fileName);
+ ptr += strlenW(fileName);
+ *ptr++ = ':';
+ *ptr++ = '\n';
+ strcpyW(ptr, msgBuf);
+ MessageBoxW(hwnd, fullError, pTitle, MB_ICONERROR | MB_OK);
+ HeapFree(GetProcessHeap(), 0, fullError);
+ }
+ LocalFree(msgBuf);
+ }
+ return ret;
+}
+
+static LRESULT CALLBACK import_file_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
+ LPARAM lp)
+{
+ LRESULT ret = 0;
+ struct ImportWizData *data;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
+
+ data = (struct ImportWizData *)page->lParam;
+ SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
+ break;
+ }
+ case WM_NOTIFY:
+ {
+ NMHDR *hdr = (NMHDR *)lp;
+
+ switch (hdr->code)
+ {
+ case PSN_SETACTIVE:
+ PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
+ PSWIZB_BACK | PSWIZB_NEXT);
+ ret = TRUE;
+ break;
+ case PSN_WIZNEXT:
+ {
+ HWND fileNameEdit = GetDlgItem(hwnd, IDC_IMPORT_FILENAME);
+ DWORD len = SendMessageW(fileNameEdit, WM_GETTEXTLENGTH, 0, 0);
+
+ data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
+ if (!len)
+ {
+ import_warning(data->dwFlags, hwnd, data->pwszWizardTitle,
+ IDS_IMPORT_EMPTY_FILE);
+ SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
+ ret = 1;
+ }
+ else
+ {
+ LPWSTR fileName = HeapAlloc(GetProcessHeap(), 0,
+ (len + 1) * sizeof(WCHAR));
+
+ if (fileName)
+ {
+ SendMessageW(fileNameEdit, WM_GETTEXT, len + 1,
+ (LPARAM)fileName);
+ if (!import_validate_filename(hwnd, data, fileName))
+ {
+ HeapFree(GetProcessHeap(), 0, fileName);
+ SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
+ ret = 1;
+ }
+ else
+ data->fileName = fileName;
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case WM_COMMAND:
+ switch (wp)
+ {
+ case IDC_IMPORT_BROWSE_FILE:
+ {
+ OPENFILENAMEW ofn;
+ WCHAR fileBuf[MAX_PATH];
+
+ data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
+ memset(&ofn, 0, sizeof(ofn));
+ ofn.lStructSize = sizeof(ofn);
+ ofn.hwndOwner = hwnd;
+ ofn.lpstrFilter = make_import_file_filter(data->dwFlags);
+ ofn.lpstrFile = fileBuf;
+ ofn.nMaxFile = sizeof(fileBuf) / sizeof(fileBuf[0]);
+ fileBuf[0] = 0;
+ if (GetOpenFileNameW(&ofn))
+ SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_FILENAME), WM_SETTEXT,
+ 0, (LPARAM)ofn.lpstrFile);
+ HeapFree(GetProcessHeap(), 0, (LPWSTR)ofn.lpstrFilter);
+ break;
+ }
+ }
+ break;
+ }
+ return ret;
+}
+
+static LRESULT CALLBACK import_store_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
+ LPARAM lp)
+{
+ LRESULT ret = 0;
+ struct ImportWizData *data;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
+
+ data = (struct ImportWizData *)page->lParam;
+ SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
+ if (!data->hDestCertStore)
+ {
+ SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_AUTO_STORE), BM_CLICK,
+ 0, 0);
+ EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_STORE), FALSE);
+ EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_BROWSE_STORE), FALSE);
+ EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_SPECIFY_STORE), FALSE);
+ }
+ else
+ {
+ WCHAR storeTitle[MAX_STRING_LEN];
+
+ SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_SPECIFY_STORE), BM_CLICK,
+ 0, 0);
+ EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_STORE), TRUE);
+ EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_BROWSE_STORE), TRUE);
+ EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_SPECIFY_STORE),
+ !(data->dwFlags & CRYPTUI_WIZ_IMPORT_NO_CHANGE_DEST_STORE));
+ LoadStringW(hInstance, IDS_IMPORT_DEST_DETERMINED,
+ storeTitle, sizeof(storeTitle) / sizeof(storeTitle[0]));
+ SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_STORE), WM_SETTEXT,
+ 0, (LPARAM)storeTitle);
+ }
+ break;
+ }
+ case WM_NOTIFY:
+ {
+ NMHDR *hdr = (NMHDR *)lp;
+
+ switch (hdr->code)
+ {
+ case PSN_SETACTIVE:
+ PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
+ PSWIZB_BACK | PSWIZB_NEXT);
+ ret = TRUE;
+ break;
+ case PSN_WIZNEXT:
+ {
+ data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
+ if (IsDlgButtonChecked(hwnd, IDC_IMPORT_SPECIFY_STORE) &&
+ !data->hDestCertStore)
+ {
+ import_warning(data->dwFlags, hwnd, data->pwszWizardTitle,
+ IDS_IMPORT_SELECT_STORE);
+ SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
+ ret = 1;
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case WM_COMMAND:
+ switch (wp)
+ {
+ case IDC_IMPORT_AUTO_STORE:
+ data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
+ data->autoDest = TRUE;
+ EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_STORE), FALSE);
+ EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_BROWSE_STORE), FALSE);
+ break;
+ case IDC_IMPORT_SPECIFY_STORE:
+ data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
+ data->autoDest = FALSE;
+ EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_STORE), TRUE);
+ EnableWindow(GetDlgItem(hwnd, IDC_IMPORT_BROWSE_STORE), TRUE);
+ break;
+ case IDC_IMPORT_BROWSE_STORE:
+ {
+ CRYPTUI_ENUM_SYSTEM_STORE_ARGS enumArgs = {
+ CERT_SYSTEM_STORE_CURRENT_USER, NULL };
+ CRYPTUI_ENUM_DATA enumData = { 0, NULL, 1, &enumArgs };
+ CRYPTUI_SELECTSTORE_INFO_W selectInfo;
+ HCERTSTORE store;
+
+ data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
+ selectInfo.dwSize = sizeof(selectInfo);
+ selectInfo.parent = hwnd;
+ selectInfo.dwFlags = CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE;
+ selectInfo.pwszTitle = selectInfo.pwszTitle = NULL;
+ selectInfo.pEnumData = &enumData;
+ selectInfo.pfnSelectedStoreCallback = NULL;
+ if ((store = CryptUIDlgSelectStoreW(&selectInfo)))
+ {
+ WCHAR storeTitle[MAX_STRING_LEN];
+
+ LoadStringW(hInstance, IDS_IMPORT_DEST_DETERMINED,
+ storeTitle, sizeof(storeTitle) / sizeof(storeTitle[0]));
+ SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_STORE), WM_SETTEXT,
+ 0, (LPARAM)storeTitle);
+ data->hDestCertStore = store;
+ data->freeDest = TRUE;
+ }
+ break;
+ }
+ }
+ break;
+ }
+ return ret;
+}
+
+static void show_import_details(HWND lv, struct ImportWizData *data)
+{
+ WCHAR text[MAX_STRING_LEN];
+ LVITEMW item;
+ int contentID;
+
+ item.mask = LVIF_TEXT;
+ item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
+ item.iSubItem = 0;
+ LoadStringW(hInstance, IDS_IMPORT_STORE_SELECTION, text,
+ sizeof(text)/ sizeof(text[0]));
+ item.pszText = text;
+ SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
+ item.iSubItem = 1;
+ if (data->autoDest)
+ LoadStringW(hInstance, IDS_IMPORT_DEST_AUTOMATIC, text,
+ sizeof(text)/ sizeof(text[0]));
+ else
+ LoadStringW(hInstance, IDS_IMPORT_DEST_DETERMINED, text,
+ sizeof(text)/ sizeof(text[0]));
+ SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
+ item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
+ item.iSubItem = 0;
+ LoadStringW(hInstance, IDS_IMPORT_CONTENT, text,
+ sizeof(text)/ sizeof(text[0]));
+ SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
+ switch (data->contentType)
+ {
+ case CERT_QUERY_CONTENT_CERT:
+ case CERT_QUERY_CONTENT_SERIALIZED_CERT:
+ contentID = IDS_IMPORT_CONTENT_CERT;
+ break;
+ case CERT_QUERY_CONTENT_CRL:
+ case CERT_QUERY_CONTENT_SERIALIZED_CRL:
+ contentID = IDS_IMPORT_CONTENT_CRL;
+ break;
+ case CERT_QUERY_CONTENT_CTL:
+ case CERT_QUERY_CONTENT_SERIALIZED_CTL:
+ contentID = IDS_IMPORT_CONTENT_CTL;
+ break;
+ case CERT_QUERY_CONTENT_PKCS7_SIGNED:
+ contentID = IDS_IMPORT_CONTENT_CMS;
+ break;
+ case CERT_QUERY_CONTENT_FLAG_PFX:
+ contentID = IDS_IMPORT_CONTENT_PFX;
+ break;
+ default:
+ contentID = IDS_IMPORT_CONTENT_STORE;
+ break;
+ }
+ LoadStringW(hInstance, contentID, text, sizeof(text)/ sizeof(text[0]));
+ item.iSubItem = 1;
+ SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
+ if (data->fileName)
+ {
+ item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
+ item.iSubItem = 0;
+ LoadStringW(hInstance, IDS_IMPORT_FILE, text,
+ sizeof(text)/ sizeof(text[0]));
+ SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
+ item.iSubItem = 1;
+ item.pszText = data->fileName;
+ SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
+ }
+}
+
+static BOOL do_import(DWORD dwFlags, HWND hwndParent, LPCWSTR pwszWizardTitle,
+ PCCRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc, HCERTSTORE hDestCertStore)
+{
+ BOOL ret;
+
+ switch (pImportSrc->dwSubjectChoice)
+ {
+ case CRYPTUI_WIZ_IMPORT_SUBJECT_FILE:
+ ret = import_file(dwFlags, hwndParent, pwszWizardTitle,
+ pImportSrc->u.pwszFileName, hDestCertStore);
+ break;
+ case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_CONTEXT:
+ if ((ret = check_context_type(dwFlags, CERT_QUERY_CONTENT_CERT)))
+ ret = import_cert(pImportSrc->u.pCertContext, hDestCertStore);
+ else
+ import_warn_type_mismatch(dwFlags, hwndParent, pwszWizardTitle);
+ break;
+ case CRYPTUI_WIZ_IMPORT_SUBJECT_CRL_CONTEXT:
+ if ((ret = check_context_type(dwFlags, CERT_QUERY_CONTENT_CRL)))
+ ret = import_crl(pImportSrc->u.pCRLContext, hDestCertStore);
+ else
+ import_warn_type_mismatch(dwFlags, hwndParent, pwszWizardTitle);
+ break;
+ case CRYPTUI_WIZ_IMPORT_SUBJECT_CTL_CONTEXT:
+ if ((ret = check_context_type(dwFlags, CERT_QUERY_CONTENT_CTL)))
+ ret = import_ctl(pImportSrc->u.pCTLContext, hDestCertStore);
+ else
+ import_warn_type_mismatch(dwFlags, hwndParent, pwszWizardTitle);
+ break;
+ case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE:
+ ret = import_store(dwFlags, hwndParent, pwszWizardTitle,
+ pImportSrc->u.hCertStore, hDestCertStore);
+ break;
+ default:
+ WARN("unknown source type: %u\n", pImportSrc->dwSubjectChoice);
+ SetLastError(E_INVALIDARG);
+ ret = FALSE;
+ }
+ return ret;
+}
+
+static LRESULT CALLBACK import_finish_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
+ LPARAM lp)
+{
+ LRESULT ret = 0;
+ struct ImportWizData *data;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ PROPSHEETPAGEW *page = (PROPSHEETPAGEW *)lp;
+ HWND lv = GetDlgItem(hwnd, IDC_IMPORT_SETTINGS);
+ RECT rc;
+ LVCOLUMNW column;
+
+ data = (struct ImportWizData *)page->lParam;
+ SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
+ SendMessageW(GetDlgItem(hwnd, IDC_IMPORT_TITLE), WM_SETFONT,
+ (WPARAM)data->titleFont, TRUE);
+ GetWindowRect(lv, &rc);
+ column.mask = LVCF_WIDTH;
+ column.cx = (rc.right - rc.left) / 2 - 2;
+ SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
+ SendMessageW(lv, LVM_INSERTCOLUMNW, 1, (LPARAM)&column);
+ show_import_details(lv, data);
+ break;
+ }
+ case WM_NOTIFY:
+ {
+ NMHDR *hdr = (NMHDR *)lp;
+
+ switch (hdr->code)
+ {
+ case PSN_SETACTIVE:
+ {
+ HWND lv = GetDlgItem(hwnd, IDC_IMPORT_SETTINGS);
+
+ data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
+ SendMessageW(lv, LVM_DELETEALLITEMS, 0, 0);
+ show_import_details(lv, data);
+ PostMessageW(GetParent(hwnd), PSM_SETWIZBUTTONS, 0,
+ PSWIZB_BACK | PSWIZB_FINISH);
+ ret = TRUE;
+ break;
+ }
+ case PSN_WIZFINISH:
+ {
+ data = (struct ImportWizData *)GetWindowLongPtrW(hwnd, DWLP_USER);
+ if ((data->success = do_import(data->dwFlags, hwnd,
+ data->pwszWizardTitle, &data->importSrc, data->hDestCertStore)))
+ {
+ WCHAR title[MAX_STRING_LEN], message[MAX_STRING_LEN];
+ LPCWSTR pTitle;
+
+ if (data->pwszWizardTitle)
+ pTitle = data->pwszWizardTitle;
+ else
+ {
+ LoadStringW(hInstance, IDS_IMPORT_WIZARD, title,
+ sizeof(title) / sizeof(title[0]));
+ pTitle = title;
+ }
+ LoadStringW(hInstance, IDS_IMPORT_SUCCEEDED, message,
+ sizeof(message) / sizeof(message[0]));
+ MessageBoxW(hwnd, message, pTitle, MB_OK);
+ }
+ else
+ import_warning(data->dwFlags, hwnd, data->pwszWizardTitle,
+ IDS_IMPORT_SUCCEEDED);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ return ret;
+}
+
+static BOOL show_import_ui(DWORD dwFlags, HWND hwndParent,
+ LPCWSTR pwszWizardTitle, PCCRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc,
+ HCERTSTORE hDestCertStore)
+{
+ PROPSHEETHEADERW hdr;
+ PROPSHEETPAGEW pages[4];
+ struct ImportWizData data;
+ int nPages = 0;
+
+ data.dwFlags = dwFlags;
+ data.pwszWizardTitle = pwszWizardTitle;
+ if (pImportSrc)
+ memcpy(&data.importSrc, pImportSrc, sizeof(data.importSrc));
+ else
+ memset(&data.importSrc, 0, sizeof(data.importSrc));
+ data.fileName = NULL;
+ data.freeSource = FALSE;
+ data.hDestCertStore = hDestCertStore;
+ data.freeDest = FALSE;
+ data.autoDest = TRUE;
+ data.success = TRUE;
+
+ memset(&pages, 0, sizeof(pages));
+
+ pages[nPages].dwSize = sizeof(pages[0]);
+ pages[nPages].hInstance = hInstance;
+ pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_IMPORT_WELCOME);
+ pages[nPages].pfnDlgProc = import_welcome_dlg_proc;
+ pages[nPages].dwFlags = PSP_HIDEHEADER;
+ pages[nPages].lParam = (LPARAM)&data;
+ nPages++;
+
+ if (!pImportSrc ||
+ pImportSrc->dwSubjectChoice == CRYPTUI_WIZ_IMPORT_SUBJECT_FILE)
+ {
+ pages[nPages].dwSize = sizeof(pages[0]);
+ pages[nPages].hInstance = hInstance;
+ pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_IMPORT_FILE);
+ pages[nPages].pfnDlgProc = import_file_dlg_proc;
+ pages[nPages].dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
+ pages[nPages].pszHeaderTitle = MAKEINTRESOURCEW(IDS_IMPORT_FILE_TITLE);
+ pages[nPages].pszHeaderSubTitle =
+ MAKEINTRESOURCEW(IDS_IMPORT_FILE_SUBTITLE);
+ pages[nPages].lParam = (LPARAM)&data;
+ nPages++;
+ }
+ else
+ {
+ switch (pImportSrc->dwSubjectChoice)
+ {
+ case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_CONTEXT:
+ data.contentType = CERT_QUERY_CONTENT_CERT;
+ break;
+ case CRYPTUI_WIZ_IMPORT_SUBJECT_CRL_CONTEXT:
+ data.contentType = CERT_QUERY_CONTENT_CRL;
+ break;
+ case CRYPTUI_WIZ_IMPORT_SUBJECT_CTL_CONTEXT:
+ data.contentType = CERT_QUERY_CONTENT_CTL;
+ break;
+ case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE:
+ data.contentType = CERT_QUERY_CONTENT_SERIALIZED_STORE;
+ break;
+ }
+ }
+
+ pages[nPages].dwSize = sizeof(pages[0]);
+ pages[nPages].hInstance = hInstance;
+ pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_IMPORT_STORE);
+ pages[nPages].pfnDlgProc = import_store_dlg_proc;
+ pages[nPages].dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
+ pages[nPages].pszHeaderTitle = MAKEINTRESOURCEW(IDS_IMPORT_STORE_TITLE);
+ pages[nPages].pszHeaderSubTitle =
+ MAKEINTRESOURCEW(IDS_IMPORT_STORE_SUBTITLE);
+ pages[nPages].lParam = (LPARAM)&data;
+ nPages++;
+
+ pages[nPages].dwSize = sizeof(pages[0]);
+ pages[nPages].hInstance = hInstance;
+ pages[nPages].u.pszTemplate = MAKEINTRESOURCEW(IDD_IMPORT_FINISH);
+ pages[nPages].pfnDlgProc = import_finish_dlg_proc;
+ pages[nPages].dwFlags = PSP_HIDEHEADER;
+ pages[nPages].lParam = (LPARAM)&data;
+ nPages++;
+
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.dwSize = sizeof(hdr);
+ hdr.hwndParent = hwndParent;
+ hdr.dwFlags = PSH_PROPSHEETPAGE | PSH_WIZARD97_NEW | PSH_HEADER |
+ PSH_WATERMARK;
+ hdr.hInstance = hInstance;
+ if (pwszWizardTitle)
+ hdr.pszCaption = pwszWizardTitle;
+ else
+ hdr.pszCaption = MAKEINTRESOURCEW(IDS_IMPORT_WIZARD);
+ hdr.u3.ppsp = pages;
+ hdr.nPages = nPages;
+ hdr.u4.pszbmWatermark = MAKEINTRESOURCEW(IDB_CERT_WATERMARK);
+ hdr.u5.pszbmHeader = MAKEINTRESOURCEW(IDB_CERT_HEADER);
+ PropertySheetW(&hdr);
+ HeapFree(GetProcessHeap(), 0, data.fileName);
+ if (data.freeSource &&
+ data.importSrc.dwSubjectChoice == CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE)
+ CertCloseStore(data.importSrc.u.hCertStore, 0);
+ DeleteObject(data.titleFont);
+ return data.success;
+}
+
+BOOL WINAPI CryptUIWizImport(DWORD dwFlags, HWND hwndParent, LPCWSTR pwszWizardTitle,
+ PCCRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc, HCERTSTORE hDestCertStore)
+{
+ BOOL ret;
+
+ TRACE("(0x%08x, %p, %s, %p, %p)\n", dwFlags, hwndParent, debugstr_w(pwszWizardTitle),
+ pImportSrc, hDestCertStore);
+
+ if (pImportSrc &&
+ pImportSrc->dwSize != sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO))
+ {
+ SetLastError(E_INVALIDARG);
+ return FALSE;
+ }
+
+ if (!(dwFlags & CRYPTUI_WIZ_NO_UI))
+ ret = show_import_ui(dwFlags, hwndParent, pwszWizardTitle, pImportSrc,
+ hDestCertStore);
+ else if (pImportSrc)
+ ret = do_import(dwFlags, hwndParent, pwszWizardTitle, pImportSrc,
+ hDestCertStore);
+ else
+ {
+ /* Can't have no UI without specifying source */
+ SetLastError(E_INVALIDARG);
+ ret = FALSE;
+ }
+
return ret;
}