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
24 #define NONAMELESSUNION
37 #include "cryptuiapi.h"
38 #include "cryptuires.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
);
55 case DLL_WINE_PREATTACH
:
56 return FALSE
; /* prefer native version */
57 case DLL_PROCESS_ATTACH
:
59 DisableThreadLibraryCalls(hinstDLL
);
61 case DLL_PROCESS_DETACH
:
69 #define MAX_STRING_LEN 512
71 static void add_cert_columns(HWND hwnd
)
73 HWND lv
= GetDlgItem(hwnd
, IDC_MGR_CERTS
);
75 WCHAR buf
[MAX_STRING_LEN
];
78 SendMessageW(lv
, LVM_SETEXTENDEDLISTVIEWSTYLE
, 0, LVS_EX_FULLROWSELECT
);
79 GetWindowRect(lv
, &rc
);
80 LoadStringW(hInstance
, IDS_SUBJECT_COLUMN
, buf
,
81 sizeof(buf
) / sizeof(buf
[0]));
82 column
.mask
= LVCF_WIDTH
| LVCF_TEXT
;
83 column
.cx
= (rc
.right
- rc
.left
) * 29 / 100 - 2;
85 SendMessageW(lv
, LVM_INSERTCOLUMNW
, 0, (LPARAM
)&column
);
86 LoadStringW(hInstance
, IDS_ISSUER_COLUMN
, buf
,
87 sizeof(buf
) / sizeof(buf
[0]));
88 SendMessageW(lv
, LVM_INSERTCOLUMNW
, 1, (LPARAM
)&column
);
89 column
.cx
= (rc
.right
- rc
.left
) * 16 / 100 - 2;
90 LoadStringW(hInstance
, IDS_EXPIRATION_COLUMN
, buf
,
91 sizeof(buf
) / sizeof(buf
[0]));
92 SendMessageW(lv
, LVM_INSERTCOLUMNW
, 2, (LPARAM
)&column
);
93 column
.cx
= (rc
.right
- rc
.left
) * 23 / 100 - 1;
94 LoadStringW(hInstance
, IDS_FRIENDLY_NAME_COLUMN
, buf
,
95 sizeof(buf
) / sizeof(buf
[0]));
96 SendMessageW(lv
, LVM_INSERTCOLUMNW
, 3, (LPARAM
)&column
);
99 static void add_cert_to_view(HWND lv
, PCCERT_CONTEXT cert
, DWORD
*allocatedLen
,
104 WCHAR dateFmt
[80]; /* sufficient for LOCALE_SSHORTDATE */
108 item
.mask
= LVIF_IMAGE
| LVIF_PARAM
| LVIF_TEXT
;
109 item
.iItem
= SendMessageW(lv
, LVM_GETITEMCOUNT
, 0, 0);
112 item
.lParam
= (LPARAM
)CertDuplicateCertificateContext(cert
);
113 len
= CertGetNameStringW(cert
, CERT_NAME_SIMPLE_DISPLAY_TYPE
, 0, NULL
,
115 if (len
> *allocatedLen
)
117 HeapFree(GetProcessHeap(), 0, *str
);
118 *str
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
124 CertGetNameStringW(cert
, CERT_NAME_SIMPLE_DISPLAY_TYPE
, 0, NULL
,
127 SendMessageW(lv
, LVM_INSERTITEMW
, 0, (LPARAM
)&item
);
130 item
.mask
= LVIF_TEXT
;
131 len
= CertGetNameStringW(cert
, CERT_NAME_SIMPLE_DISPLAY_TYPE
,
132 CERT_NAME_ISSUER_FLAG
, NULL
, NULL
, 0);
133 if (len
> *allocatedLen
)
135 HeapFree(GetProcessHeap(), 0, *str
);
136 *str
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
142 CertGetNameStringW(cert
, CERT_NAME_SIMPLE_DISPLAY_TYPE
,
143 CERT_NAME_ISSUER_FLAG
, NULL
, *str
, len
);
146 SendMessageW(lv
, LVM_SETITEMTEXTW
, item
.iItem
, (LPARAM
)&item
);
149 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT
, LOCALE_SSHORTDATE
, dateFmt
,
150 sizeof(dateFmt
) / sizeof(dateFmt
[0]));
151 FileTimeToSystemTime(&cert
->pCertInfo
->NotAfter
, &sysTime
);
152 GetDateFormatW(LOCALE_SYSTEM_DEFAULT
, 0, &sysTime
, dateFmt
, date
,
153 sizeof(date
) / sizeof(date
[0]));
156 SendMessageW(lv
, LVM_SETITEMTEXTW
, item
.iItem
, (LPARAM
)&item
);
158 len
= CertGetNameStringW(cert
, CERT_NAME_FRIENDLY_DISPLAY_TYPE
, 0, NULL
,
160 if (len
> *allocatedLen
)
162 HeapFree(GetProcessHeap(), 0, *str
);
163 *str
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
169 CertGetNameStringW(cert
, CERT_NAME_FRIENDLY_DISPLAY_TYPE
, 0, NULL
,
173 SendMessageW(lv
, LVM_SETITEMTEXTW
, item
.iItem
, (LPARAM
)&item
);
177 static LPSTR
get_cert_mgr_usages(void)
179 static const WCHAR keyName
[] = { 'S','o','f','t','w','a','r','e','\\','M',
180 'i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g','r','a',
181 'p','h','y','\\','U','I','\\','C','e','r','t','m','g','r','\\','P','u',
182 'r','p','o','s','e',0 };
186 if (!RegCreateKeyExW(HKEY_CURRENT_USER
, keyName
, 0, NULL
, 0, KEY_READ
,
192 rc
= RegQueryValueExA(key
, "Purpose", NULL
, &type
, NULL
, &size
);
193 if ((!rc
|| rc
== ERROR_MORE_DATA
) && type
== REG_SZ
)
195 str
= HeapAlloc(GetProcessHeap(), 0, size
);
198 rc
= RegQueryValueExA(key
, "Purpose", NULL
, NULL
, (LPBYTE
)str
,
202 HeapFree(GetProcessHeap(), 0, str
);
213 PurposeFilterShowAll
= 0,
214 PurposeFilterShowAdvanced
= 1,
215 PurposeFilterShowOID
= 2
218 static void initialize_purpose_selection(HWND hwnd
)
220 HWND cb
= GetDlgItem(hwnd
, IDC_MGR_PURPOSE_SELECTION
);
221 WCHAR buf
[MAX_STRING_LEN
];
225 LoadStringW(hInstance
, IDS_PURPOSE_ALL
, buf
,
226 sizeof(buf
) / sizeof(buf
[0]));
227 index
= SendMessageW(cb
, CB_INSERTSTRING
, -1, (LPARAM
)buf
);
228 SendMessageW(cb
, CB_SETITEMDATA
, index
, (LPARAM
)PurposeFilterShowAll
);
229 LoadStringW(hInstance
, IDS_PURPOSE_ADVANCED
, buf
,
230 sizeof(buf
) / sizeof(buf
[0]));
231 index
= SendMessageW(cb
, CB_INSERTSTRING
, -1, (LPARAM
)buf
);
232 SendMessageW(cb
, CB_SETITEMDATA
, index
, (LPARAM
)PurposeFilterShowAdvanced
);
233 SendMessageW(cb
, CB_SETCURSEL
, 0, 0);
234 if ((usages
= get_cert_mgr_usages()))
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
;
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,
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
;
273 HeapFree(GetProcessHeap(), 0, 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
));
288 for (ptr
= usageStr
, comma
= strchr(ptr
, ','); usage
&& ptr
&& *ptr
;
289 ptr
= comma
? comma
+ 1 : NULL
,
290 comma
= ptr
? strchr(ptr
, ',') : NULL
)
294 add_oid_to_usage(usage
, ptr
);
300 static CERT_ENHKEY_USAGE
*create_advanced_filter(void)
302 CERT_ENHKEY_USAGE
*advancedUsage
= HeapAlloc(GetProcessHeap(),
303 HEAP_ZERO_MEMORY
, sizeof(CERT_ENHKEY_USAGE
));
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
);
320 PCCRYPT_OID_INFO
*ptr
;
322 for (ptr
= usages
; *ptr
; ptr
++)
325 BOOL disabled
= FALSE
;
327 for (i
= 0; !disabled
&&
328 i
< disabledUsages
->cUsageIdentifier
; i
++)
329 if (!strcmp(disabledUsages
->rgpszUsageIdentifier
[i
],
333 add_oid_to_usage(advancedUsage
,
334 (LPSTR
)(*ptr
)->pszOID
);
336 /* The individual strings are pointers to disabledUsagesStr,
337 * so they're freed when it is.
339 HeapFree(GetProcessHeap(), 0,
340 disabledUsages
->rgpszUsageIdentifier
);
341 HeapFree(GetProcessHeap(), 0, disabledUsages
);
343 HeapFree(GetProcessHeap(), 0, disabledUsagesStr
);
345 WTHelperGetKnownUsages(2, &usages
);
348 return advancedUsage
;
351 static void show_store_certs(HWND hwnd
, HCERTSTORE store
)
353 HWND lv
= GetDlgItem(hwnd
, IDC_MGR_CERTS
);
354 HWND cb
= GetDlgItem(hwnd
, IDC_MGR_PURPOSE_SELECTION
);
355 PCCERT_CONTEXT cert
= NULL
;
356 DWORD allocatedLen
= 0;
359 PurposeFilter filter
= PurposeFilterShowAll
;
361 CERT_ENHKEY_USAGE
*advanced
= NULL
;
363 index
= SendMessageW(cb
, CB_GETCURSEL
, 0, 0);
366 INT_PTR data
= SendMessageW(cb
, CB_GETITEMDATA
, index
, 0);
372 PCCRYPT_OID_INFO info
= (PCCRYPT_OID_INFO
)data
;
374 filter
= PurposeFilterShowOID
;
378 if (filter
== PurposeFilterShowAdvanced
)
379 advanced
= create_advanced_filter();
381 cert
= CertEnumCertificatesInStore(store
, cert
);
386 if (filter
== PurposeFilterShowAll
)
393 if (CertGetValidUsages(1, &cert
, &numOIDs
, NULL
, &cbOIDs
))
397 /* -1 implies all usages are valid */
402 LPSTR
*oids
= HeapAlloc(GetProcessHeap(), 0, cbOIDs
);
406 if (CertGetValidUsages(1, &cert
, &numOIDs
, oids
,
411 if (filter
== PurposeFilterShowOID
)
413 for (i
= 0; !show
&& i
< numOIDs
; i
++)
414 if (!strcmp(oids
[i
], oid
))
419 for (i
= 0; !show
&& i
< numOIDs
; i
++)
424 j
< advanced
->cUsageIdentifier
; j
++)
426 advanced
->rgpszUsageIdentifier
[j
]))
431 HeapFree(GetProcessHeap(), 0, oids
);
437 add_cert_to_view(lv
, cert
, &allocatedLen
, &str
);
440 HeapFree(GetProcessHeap(), 0, str
);
443 HeapFree(GetProcessHeap(), 0, advanced
->rgpszUsageIdentifier
);
444 HeapFree(GetProcessHeap(), 0, advanced
);
448 static const WCHAR my
[] = { 'M','y',0 };
449 static const WCHAR addressBook
[] = {
450 'A','d','d','r','e','s','s','B','o','o','k',0 };
451 static const WCHAR ca
[] = { 'C','A',0 };
452 static const WCHAR root
[] = { 'R','o','o','t',0 };
453 static const WCHAR trustedPublisher
[] = {
454 'T','r','u','s','t','e','d','P','u','b','l','i','s','h','e','r',0 };
455 static const WCHAR disallowed
[] = { 'D','i','s','a','l','l','o','w','e','d',0 };
457 struct CertMgrStoreInfo
461 int removePluralWarning
;
464 static const struct CertMgrStoreInfo defaultStoreList
[] = {
465 { my
, IDS_WARN_REMOVE_MY
, IDS_WARN_REMOVE_PLURAL_MY
},
466 { addressBook
, IDS_WARN_REMOVE_ADDRESSBOOK
,
467 IDS_WARN_REMOVE_PLURAL_ADDRESSBOOK
},
468 { ca
, IDS_WARN_REMOVE_CA
, IDS_WARN_REMOVE_PLURAL_CA
},
469 { root
, IDS_WARN_REMOVE_ROOT
, IDS_WARN_REMOVE_PLURAL_ROOT
},
470 { trustedPublisher
, IDS_WARN_REMOVE_TRUSTEDPUBLISHER
,
471 IDS_WARN_REMOVE_PLURAL_TRUSTEDPUBLISHER
},
472 { disallowed
, IDS_WARN_REMOVE_DEFAULT
},
475 static const struct CertMgrStoreInfo publisherStoreList
[] = {
476 { root
, IDS_WARN_REMOVE_ROOT
, IDS_WARN_REMOVE_PLURAL_ROOT
},
477 { trustedPublisher
, IDS_WARN_REMOVE_TRUSTEDPUBLISHER
,
478 IDS_WARN_REMOVE_PLURAL_TRUSTEDPUBLISHER
},
479 { disallowed
, IDS_WARN_REMOVE_PLURAL_DEFAULT
},
484 HIMAGELIST imageList
;
487 const struct CertMgrStoreInfo
*stores
;
490 static void show_cert_stores(HWND hwnd
, DWORD dwFlags
, struct CertMgrData
*data
)
492 const struct CertMgrStoreInfo
*storeList
;
494 HWND tab
= GetDlgItem(hwnd
, IDC_MGR_STORES
);
496 if (dwFlags
& CRYPTUI_CERT_MGR_PUBLISHER_TAB
)
498 storeList
= publisherStoreList
;
499 cStores
= sizeof(publisherStoreList
) / sizeof(publisherStoreList
[0]);
503 storeList
= defaultStoreList
;
504 cStores
= sizeof(defaultStoreList
) / sizeof(defaultStoreList
[0]);
506 if (dwFlags
& CRYPTUI_CERT_MGR_SINGLE_TAB_FLAG
)
508 data
->nStores
= cStores
;
509 data
->stores
= storeList
;
510 for (i
= 0; i
< cStores
; i
++)
516 if (!(name
= CryptFindLocalizedName(storeList
[i
].name
)))
517 name
= storeList
[i
].name
;
518 store
= CertOpenStore(CERT_STORE_PROV_SYSTEM_W
, 0, 0,
519 CERT_SYSTEM_STORE_CURRENT_USER
, storeList
[i
].name
);
520 item
.mask
= TCIF_TEXT
| TCIF_PARAM
;
521 item
.pszText
= (LPWSTR
)name
;
522 item
.lParam
= (LPARAM
)store
;
523 SendMessageW(tab
, TCM_INSERTITEMW
, i
, (LPARAM
)&item
);
527 static void free_certs(HWND lv
)
530 int items
= SendMessageW(lv
, LVM_GETITEMCOUNT
, 0, 0), i
;
532 for (i
= 0; i
< items
; i
++)
534 item
.mask
= LVIF_PARAM
;
537 SendMessageW(lv
, LVM_GETITEMW
, 0, (LPARAM
)&item
);
538 CertFreeCertificateContext((PCCERT_CONTEXT
)item
.lParam
);
542 static HCERTSTORE
cert_mgr_index_to_store(HWND tab
, int index
)
546 item
.mask
= TCIF_PARAM
;
547 SendMessageW(tab
, TCM_GETITEMW
, index
, (LPARAM
)&item
);
548 return (HCERTSTORE
)item
.lParam
;
551 static HCERTSTORE
cert_mgr_current_store(HWND hwnd
)
553 HWND tab
= GetDlgItem(hwnd
, IDC_MGR_STORES
);
555 return cert_mgr_index_to_store(tab
, SendMessageW(tab
, TCM_GETCURSEL
, 0, 0));
558 static void close_stores(HWND tab
)
560 int i
, tabs
= SendMessageW(tab
, TCM_GETITEMCOUNT
, 0, 0);
562 for (i
= 0; i
< tabs
; i
++)
563 CertCloseStore(cert_mgr_index_to_store(tab
, i
), 0);
566 static void refresh_store_certs(HWND hwnd
)
568 HWND lv
= GetDlgItem(hwnd
, IDC_MGR_CERTS
);
571 SendMessageW(lv
, LVM_DELETEALLITEMS
, 0, 0);
572 show_store_certs(hwnd
, cert_mgr_current_store(hwnd
));
576 CheckBitmapIndexUnchecked
= 1,
577 CheckBitmapIndexChecked
= 2,
578 CheckBitmapIndexDisabledUnchecked
= 3,
579 CheckBitmapIndexDisabledChecked
= 4
582 static void add_known_usage(HWND lv
, PCCRYPT_OID_INFO info
,
583 CheckBitmapIndex state
)
587 item
.mask
= LVIF_TEXT
| LVIF_STATE
| LVIF_PARAM
;
588 item
.state
= INDEXTOSTATEIMAGEMASK(state
);
589 item
.stateMask
= LVIS_STATEIMAGEMASK
;
590 item
.iItem
= SendMessageW(lv
, LVM_GETITEMCOUNT
, 0, 0);
592 item
.lParam
= (LPARAM
)info
;
593 item
.pszText
= (LPWSTR
)info
->pwszName
;
594 SendMessageW(lv
, LVM_INSERTITEMW
, 0, (LPARAM
)&item
);
597 static void add_known_usages_to_list(HWND lv
, CheckBitmapIndex state
)
599 PCCRYPT_OID_INFO
*usages
;
601 if (WTHelperGetKnownUsages(1, &usages
))
603 PCCRYPT_OID_INFO
*ptr
;
605 for (ptr
= usages
; *ptr
; ptr
++)
606 add_known_usage(lv
, *ptr
, state
);
607 WTHelperGetKnownUsages(2, &usages
);
611 static void toggle_usage(HWND hwnd
, int iItem
)
615 HWND lv
= GetDlgItem(hwnd
, IDC_CERTIFICATE_USAGES
);
617 item
.mask
= LVIF_STATE
;
620 item
.stateMask
= LVIS_STATEIMAGEMASK
;
621 res
= SendMessageW(lv
, LVM_GETITEMW
, 0, (LPARAM
)&item
);
624 int state
= item
.state
>> 12;
626 item
.state
= INDEXTOSTATEIMAGEMASK(
627 state
== CheckBitmapIndexChecked
? CheckBitmapIndexUnchecked
:
628 CheckBitmapIndexChecked
);
629 SendMessageW(lv
, LVM_SETITEMSTATE
, iItem
, (LPARAM
)&item
);
633 static LONG_PTR
find_oid_in_list(HWND lv
, LPCSTR oid
)
635 PCCRYPT_OID_INFO oidInfo
= CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY
,
636 (void *)oid
, CRYPT_ENHKEY_USAGE_OID_GROUP_ID
);
641 LVFINDINFOW findInfo
;
643 findInfo
.flags
= LVFI_PARAM
;
644 findInfo
.lParam
= (LPARAM
)oidInfo
;
645 ret
= SendMessageW(lv
, LVM_FINDITEMW
, -1, (LPARAM
)&findInfo
);
649 LVFINDINFOA findInfo
;
651 findInfo
.flags
= LVFI_STRING
;
653 ret
= SendMessageW(lv
, LVM_FINDITEMA
, -1, (LPARAM
)&findInfo
);
658 static void save_cert_mgr_usages(HWND hwnd
)
660 static const WCHAR keyName
[] = { 'S','o','f','t','w','a','r','e','\\','M',
661 'i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g','r','a',
662 'p','h','y','\\','U','I','\\','C','e','r','t','m','g','r','\\','P','u',
663 'r','p','o','s','e',0 };
665 HWND lv
= GetDlgItem(hwnd
, IDC_CERTIFICATE_USAGES
);
666 int purposes
= SendMessageW(lv
, LVM_GETITEMCOUNT
, 0, 0), i
;
670 item
.mask
= LVIF_STATE
| LVIF_PARAM
;
672 item
.stateMask
= LVIS_STATEIMAGEMASK
;
673 for (i
= 0; i
< purposes
; i
++)
676 if (SendMessageW(lv
, LVM_GETITEMW
, 0, (LPARAM
)&item
))
678 int state
= item
.state
>> 12;
680 if (state
== CheckBitmapIndexUnchecked
)
682 CRYPT_OID_INFO
*info
= (CRYPT_OID_INFO
*)item
.lParam
;
683 BOOL firstString
= TRUE
;
686 str
= HeapAlloc(GetProcessHeap(), 0,
687 strlen(info
->pszOID
) + 1);
690 str
= HeapReAlloc(GetProcessHeap(), 0, str
,
691 strlen(str
) + 1 + strlen(info
->pszOID
) + 1);
696 LPSTR ptr
= firstString
? str
: str
+ strlen(str
);
700 strcpy(ptr
, info
->pszOID
);
705 if (!RegCreateKeyExW(HKEY_CURRENT_USER
, keyName
, 0, NULL
, 0, KEY_ALL_ACCESS
,
709 RegSetValueExA(key
, "Purpose", 0, REG_SZ
, (const BYTE
*)str
,
712 RegDeleteValueA(key
, "Purpose");
715 HeapFree(GetProcessHeap(), 0, str
);
718 static LRESULT CALLBACK
cert_mgr_advanced_dlg_proc(HWND hwnd
, UINT msg
,
719 WPARAM wp
, LPARAM lp
)
727 HWND lv
= GetDlgItem(hwnd
, IDC_CERTIFICATE_USAGES
);
728 HIMAGELIST imageList
;
729 LPSTR disabledUsages
;
731 GetWindowRect(lv
, &rc
);
732 column
.mask
= LVCF_WIDTH
;
733 column
.cx
= rc
.right
- rc
.left
;
734 SendMessageW(lv
, LVM_INSERTCOLUMNW
, 0, (LPARAM
)&column
);
735 imageList
= ImageList_Create(16, 16, ILC_COLOR4
| ILC_MASK
, 4, 0);
739 COLORREF backColor
= RGB(255, 0, 255);
741 bmp
= LoadBitmapW(hInstance
, MAKEINTRESOURCEW(IDB_CHECKS
));
742 ImageList_AddMasked(imageList
, bmp
, backColor
);
744 ImageList_SetBkColor(imageList
, CLR_NONE
);
745 SendMessageW(lv
, LVM_SETIMAGELIST
, LVSIL_STATE
, (LPARAM
)imageList
);
746 SetWindowLongPtrW(hwnd
, DWLP_USER
, (LPARAM
)imageList
);
748 add_known_usages_to_list(lv
, CheckBitmapIndexChecked
);
749 if ((disabledUsages
= get_cert_mgr_usages()))
753 for (ptr
= disabledUsages
, comma
= strchr(ptr
, ','); ptr
&& *ptr
;
754 ptr
= comma
? comma
+ 1 : NULL
,
755 comma
= ptr
? strchr(ptr
, ',') : NULL
)
761 if ((index
= find_oid_in_list(lv
, ptr
)) != -1)
762 toggle_usage(hwnd
, index
);
764 HeapFree(GetProcessHeap(), 0, disabledUsages
);
770 NMHDR
*hdr
= (NMHDR
*)lp
;
776 nm
= (NMITEMACTIVATE
*)lp
;
777 toggle_usage(hwnd
, nm
->iItem
);
778 SendMessageW(GetParent(hwnd
), PSM_CHANGED
, (WPARAM
)hwnd
, 0);
787 save_cert_mgr_usages(hwnd
);
788 ImageList_Destroy((HIMAGELIST
)GetWindowLongPtrW(hwnd
, DWLP_USER
));
789 EndDialog(hwnd
, IDOK
);
792 ImageList_Destroy((HIMAGELIST
)GetWindowLongPtrW(hwnd
, DWLP_USER
));
793 EndDialog(hwnd
, IDCANCEL
);
801 static void cert_mgr_clear_cert_selection(HWND hwnd
)
803 WCHAR empty
[] = { 0 };
805 EnableWindow(GetDlgItem(hwnd
, IDC_MGR_EXPORT
), FALSE
);
806 EnableWindow(GetDlgItem(hwnd
, IDC_MGR_REMOVE
), FALSE
);
807 EnableWindow(GetDlgItem(hwnd
, IDC_MGR_VIEW
), FALSE
);
808 SendMessageW(GetDlgItem(hwnd
, IDC_MGR_PURPOSES
), WM_SETTEXT
, 0,
810 refresh_store_certs(hwnd
);
813 static PCCERT_CONTEXT
cert_mgr_index_to_cert(HWND hwnd
, int index
)
815 PCCERT_CONTEXT cert
= NULL
;
818 item
.mask
= LVIF_PARAM
;
821 if (SendMessageW(GetDlgItem(hwnd
, IDC_MGR_CERTS
), LVM_GETITEMW
, 0,
823 cert
= (PCCERT_CONTEXT
)item
.lParam
;
827 static void show_selected_cert(HWND hwnd
, int index
)
829 PCCERT_CONTEXT cert
= cert_mgr_index_to_cert(hwnd
, index
);
833 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo
;
835 memset(&viewInfo
, 0, sizeof(viewInfo
));
836 viewInfo
.dwSize
= sizeof(viewInfo
);
837 viewInfo
.hwndParent
= hwnd
;
838 viewInfo
.pCertContext
= cert
;
839 /* FIXME: this should be modal */
840 CryptUIDlgViewCertificateW(&viewInfo
, NULL
);
844 static void cert_mgr_show_cert_usages(HWND hwnd
, int index
)
846 HWND text
= GetDlgItem(hwnd
, IDC_MGR_PURPOSES
);
847 PCCERT_CONTEXT cert
= cert_mgr_index_to_cert(hwnd
, index
);
848 PCERT_ENHKEY_USAGE usage
;
851 /* Get enhanced key usage. Have to check for a property and an extension
852 * separately, because CertGetEnhancedKeyUsage will succeed and return an
853 * empty usage if neither is set. Unfortunately an empty usage implies
854 * no usage is allowed, so we have to distinguish between the two cases.
856 if (CertGetEnhancedKeyUsage(cert
, CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG
,
859 usage
= HeapAlloc(GetProcessHeap(), 0, size
);
860 if (!CertGetEnhancedKeyUsage(cert
,
861 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG
, usage
, &size
))
863 HeapFree(GetProcessHeap(), 0, usage
);
867 else if (CertGetEnhancedKeyUsage(cert
, CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG
,
870 usage
= HeapAlloc(GetProcessHeap(), 0, size
);
871 if (!CertGetEnhancedKeyUsage(cert
,
872 CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG
, usage
, &size
))
874 HeapFree(GetProcessHeap(), 0, usage
);
882 if (usage
->cUsageIdentifier
)
884 static const WCHAR commaSpace
[] = { ',',' ',0 };
888 for (i
= 0; i
< usage
->cUsageIdentifier
; i
++)
890 PCCRYPT_OID_INFO info
=
891 CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY
,
892 usage
->rgpszUsageIdentifier
[i
],
893 CRYPT_ENHKEY_USAGE_OID_GROUP_ID
);
896 len
+= strlenW(info
->pwszName
);
898 len
+= strlen(usage
->rgpszUsageIdentifier
[i
]);
899 if (i
< usage
->cUsageIdentifier
- 1)
900 len
+= strlenW(commaSpace
);
902 str
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
905 for (i
= 0, ptr
= str
; i
< usage
->cUsageIdentifier
; i
++)
907 PCCRYPT_OID_INFO info
=
908 CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY
,
909 usage
->rgpszUsageIdentifier
[i
],
910 CRYPT_ENHKEY_USAGE_OID_GROUP_ID
);
914 strcpyW(ptr
, info
->pwszName
);
915 ptr
+= strlenW(info
->pwszName
);
919 LPCSTR src
= usage
->rgpszUsageIdentifier
[i
];
921 for (; *src
; ptr
++, src
++)
925 if (i
< usage
->cUsageIdentifier
- 1)
927 strcpyW(ptr
, commaSpace
);
928 ptr
+= strlenW(commaSpace
);
932 SendMessageW(text
, WM_SETTEXT
, 0, (LPARAM
)str
);
933 HeapFree(GetProcessHeap(), 0, str
);
935 HeapFree(GetProcessHeap(), 0, usage
);
939 WCHAR buf
[MAX_STRING_LEN
];
941 LoadStringW(hInstance
, IDS_ALLOWED_PURPOSE_NONE
, buf
,
942 sizeof(buf
) / sizeof(buf
[0]));
943 SendMessageW(text
, WM_SETTEXT
, 0, (LPARAM
)buf
);
948 WCHAR buf
[MAX_STRING_LEN
];
950 LoadStringW(hInstance
, IDS_ALLOWED_PURPOSE_ALL
, buf
,
951 sizeof(buf
) / sizeof(buf
[0]));
952 SendMessageW(text
, WM_SETTEXT
, 0, (LPARAM
)buf
);
956 static void cert_mgr_do_remove(HWND hwnd
)
958 int tabIndex
= SendMessageW(GetDlgItem(hwnd
, IDC_MGR_STORES
),
959 TCM_GETCURSEL
, 0, 0);
960 struct CertMgrData
*data
=
961 (struct CertMgrData
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
963 if (tabIndex
< data
->nStores
)
965 HWND lv
= GetDlgItem(hwnd
, IDC_MGR_CERTS
);
966 WCHAR warning
[MAX_STRING_LEN
], title
[MAX_STRING_LEN
];
970 if (SendMessageW(lv
, LVM_GETSELECTEDCOUNT
, 0, 0) > 1)
971 warningID
= data
->stores
[tabIndex
].removePluralWarning
;
973 warningID
= data
->stores
[tabIndex
].removeWarning
;
975 pTitle
= data
->title
;
978 LoadStringW(hInstance
, IDS_CERT_MGR
, title
,
979 sizeof(title
) / sizeof(title
[0]));
982 LoadStringW(hInstance
, warningID
, warning
,
983 sizeof(warning
) / sizeof(warning
[0]));
984 if (MessageBoxW(hwnd
, warning
, pTitle
, MB_YESNO
) == IDYES
)
989 selection
= SendMessageW(lv
, LVM_GETNEXTITEM
, selection
,
993 PCCERT_CONTEXT cert
= cert_mgr_index_to_cert(hwnd
,
996 CertDeleteCertificateFromStore(cert
);
998 } while (selection
>= 0);
999 cert_mgr_clear_cert_selection(hwnd
);
1004 static void cert_mgr_do_export(HWND hwnd
)
1006 HWND lv
= GetDlgItem(hwnd
, IDC_MGR_CERTS
);
1007 int selectionCount
= SendMessageW(lv
, LVM_GETSELECTEDCOUNT
, 0, 0);
1009 if (selectionCount
== 1)
1011 int selection
= SendMessageW(lv
, LVM_GETNEXTITEM
, -1,
1016 PCCERT_CONTEXT cert
= cert_mgr_index_to_cert(hwnd
, selection
);
1020 CRYPTUI_WIZ_EXPORT_INFO info
;
1022 info
.dwSize
= sizeof(info
);
1023 info
.pwszExportFileName
= NULL
;
1024 info
.dwSubjectChoice
= CRYPTUI_WIZ_EXPORT_CERT_CONTEXT
;
1025 info
.u
.pCertContext
= cert
;
1027 CryptUIWizExport(0, hwnd
, NULL
, &info
, NULL
);
1031 else if (selectionCount
> 1)
1033 HCERTSTORE store
= CertOpenStore(CERT_STORE_PROV_MEMORY
, 0, 0,
1034 CERT_STORE_CREATE_NEW_FLAG
, NULL
);
1038 CRYPTUI_WIZ_EXPORT_INFO info
;
1041 info
.dwSize
= sizeof(info
);
1042 info
.pwszExportFileName
= NULL
;
1043 info
.dwSubjectChoice
=
1044 CRYPTUI_WIZ_EXPORT_CERT_STORE_CERTIFICATES_ONLY
;
1045 info
.u
.hCertStore
= store
;
1048 selection
= SendMessageW(lv
, LVM_GETNEXTITEM
, selection
,
1052 PCCERT_CONTEXT cert
= cert_mgr_index_to_cert(hwnd
,
1055 CertAddCertificateContextToStore(store
, cert
,
1056 CERT_STORE_ADD_ALWAYS
, NULL
);
1058 } while (selection
>= 0);
1059 CryptUIWizExport(0, hwnd
, NULL
, &info
, NULL
);
1060 CertCloseStore(store
, 0);
1065 static LRESULT CALLBACK
cert_mgr_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wp
,
1068 struct CertMgrData
*data
;
1074 PCCRYPTUI_CERT_MGR_STRUCT pCryptUICertMgr
=
1075 (PCCRYPTUI_CERT_MGR_STRUCT
)lp
;
1076 HWND tab
= GetDlgItem(hwnd
, IDC_MGR_STORES
);
1078 data
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct CertMgrData
));
1081 data
->imageList
= ImageList_Create(16, 16, ILC_COLOR4
| ILC_MASK
, 2, 0);
1082 if (data
->imageList
)
1085 COLORREF backColor
= RGB(255, 0, 255);
1087 bmp
= LoadBitmapW(hInstance
, MAKEINTRESOURCEW(IDB_SMALL_ICONS
));
1088 ImageList_AddMasked(data
->imageList
, bmp
, backColor
);
1090 ImageList_SetBkColor(data
->imageList
, CLR_NONE
);
1091 SendMessageW(GetDlgItem(hwnd
, IDC_MGR_CERTS
), LVM_SETIMAGELIST
,
1092 LVSIL_SMALL
, (LPARAM
)data
->imageList
);
1094 SetWindowLongPtrW(hwnd
, DWLP_USER
, (LPARAM
)data
);
1095 data
->title
= pCryptUICertMgr
->pwszTitle
;
1097 initialize_purpose_selection(hwnd
);
1098 add_cert_columns(hwnd
);
1099 if (pCryptUICertMgr
->pwszTitle
)
1100 SendMessageW(hwnd
, WM_SETTEXT
, 0,
1101 (LPARAM
)pCryptUICertMgr
->pwszTitle
);
1102 show_cert_stores(hwnd
, pCryptUICertMgr
->dwFlags
, data
);
1103 show_store_certs(hwnd
, cert_mgr_index_to_store(tab
, 0));
1108 NMHDR
*hdr
= (NMHDR
*)lp
;
1113 cert_mgr_clear_cert_selection(hwnd
);
1115 case LVN_ITEMCHANGED
:
1118 HWND lv
= GetDlgItem(hwnd
, IDC_MGR_CERTS
);
1120 nm
= (NMITEMACTIVATE
*)lp
;
1121 if (nm
->uNewState
& LVN_ITEMACTIVATE
)
1123 int numSelected
= SendMessageW(lv
, LVM_GETSELECTEDCOUNT
, 0, 0);
1125 EnableWindow(GetDlgItem(hwnd
, IDC_MGR_EXPORT
), numSelected
> 0);
1126 EnableWindow(GetDlgItem(hwnd
, IDC_MGR_REMOVE
), numSelected
> 0);
1127 EnableWindow(GetDlgItem(hwnd
, IDC_MGR_VIEW
), numSelected
== 1);
1128 if (numSelected
== 1)
1129 cert_mgr_show_cert_usages(hwnd
, nm
->iItem
);
1134 show_selected_cert(hwnd
, ((NMITEMACTIVATE
*)lp
)->iItem
);
1138 NMLVKEYDOWN
*lvk
= (NMLVKEYDOWN
*)lp
;
1140 if (lvk
->wVKey
== VK_DELETE
)
1141 cert_mgr_do_remove(hwnd
);
1150 case ((CBN_SELCHANGE
<< 16) | IDC_MGR_PURPOSE_SELECTION
):
1151 cert_mgr_clear_cert_selection(hwnd
);
1153 case IDC_MGR_IMPORT
:
1154 if (CryptUIWizImport(0, hwnd
, NULL
, NULL
,
1155 cert_mgr_current_store(hwnd
)))
1156 refresh_store_certs(hwnd
);
1158 case IDC_MGR_ADVANCED
:
1159 if (DialogBoxW(hInstance
, MAKEINTRESOURCEW(IDD_CERT_MGR_ADVANCED
),
1160 hwnd
, cert_mgr_advanced_dlg_proc
) == IDOK
)
1162 HWND cb
= GetDlgItem(hwnd
, IDC_MGR_PURPOSE_SELECTION
);
1164 LPWSTR curString
= NULL
;
1166 index
= SendMessageW(cb
, CB_GETCURSEL
, 0, 0);
1169 len
= SendMessageW(cb
, CB_GETLBTEXTLEN
, index
, 0);
1170 curString
= HeapAlloc(GetProcessHeap(), 0,
1171 (len
+ 1) * sizeof(WCHAR
));
1172 SendMessageW(cb
, CB_GETLBTEXT
, index
, (LPARAM
)curString
);
1174 SendMessageW(cb
, CB_RESETCONTENT
, 0, 0);
1175 initialize_purpose_selection(hwnd
);
1178 index
= SendMessageW(cb
, CB_FINDSTRINGEXACT
, -1,
1181 SendMessageW(cb
, CB_SETCURSEL
, index
, 0);
1182 HeapFree(GetProcessHeap(), 0, curString
);
1184 refresh_store_certs(hwnd
);
1189 HWND lv
= GetDlgItem(hwnd
, IDC_MGR_CERTS
);
1190 int selection
= SendMessageW(lv
, LVM_GETNEXTITEM
, -1,
1194 show_selected_cert(hwnd
, selection
);
1197 case IDC_MGR_EXPORT
:
1198 cert_mgr_do_export(hwnd
);
1200 case IDC_MGR_REMOVE
:
1201 cert_mgr_do_remove(hwnd
);
1204 free_certs(GetDlgItem(hwnd
, IDC_MGR_CERTS
));
1205 close_stores(GetDlgItem(hwnd
, IDC_MGR_STORES
));
1206 close_stores(GetDlgItem(hwnd
, IDC_MGR_STORES
));
1207 data
= (struct CertMgrData
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
1208 ImageList_Destroy(data
->imageList
);
1209 HeapFree(GetProcessHeap(), 0, data
);
1210 EndDialog(hwnd
, IDCANCEL
);
1218 /***********************************************************************
1219 * CryptUIDlgCertMgr (CRYPTUI.@)
1221 BOOL WINAPI
CryptUIDlgCertMgr(PCCRYPTUI_CERT_MGR_STRUCT pCryptUICertMgr
)
1223 TRACE("(%p)\n", pCryptUICertMgr
);
1225 if (pCryptUICertMgr
->dwSize
!= sizeof(CRYPTUI_CERT_MGR_STRUCT
))
1227 WARN("unexpected size %d\n", pCryptUICertMgr
->dwSize
);
1228 SetLastError(E_INVALIDARG
);
1231 DialogBoxParamW(hInstance
, MAKEINTRESOURCEW(IDD_CERT_MGR
),
1232 pCryptUICertMgr
->hwndParent
, cert_mgr_dlg_proc
, (LPARAM
)pCryptUICertMgr
);
1236 /* FIXME: real names are unknown, functions are undocumented */
1237 typedef struct _CRYPTUI_ENUM_SYSTEM_STORE_ARGS
1240 void *pvSystemStoreLocationPara
;
1241 } CRYPTUI_ENUM_SYSTEM_STORE_ARGS
, *PCRYPTUI_ENUM_SYSTEM_STORE_ARGS
;
1243 typedef struct _CRYPTUI_ENUM_DATA
1246 HCERTSTORE
*rghStore
;
1248 PCRYPTUI_ENUM_SYSTEM_STORE_ARGS rgEnumArgs
;
1249 } CRYPTUI_ENUM_DATA
, *PCRYPTUI_ENUM_DATA
;
1251 typedef BOOL (WINAPI
*PFN_SELECTED_STORE_CB
)(HCERTSTORE store
, HWND hwnd
,
1254 /* Values for dwFlags */
1255 #define CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE 0x00000001
1257 typedef struct _CRYPTUI_SELECTSTORE_INFO_A
1264 CRYPTUI_ENUM_DATA
*pEnumData
;
1265 PFN_SELECTED_STORE_CB pfnSelectedStoreCallback
;
1267 } CRYPTUI_SELECTSTORE_INFO_A
, *PCRYPTUI_SELECTSTORE_INFO_A
;
1269 typedef struct _CRYPTUI_SELECTSTORE_INFO_W
1276 CRYPTUI_ENUM_DATA
*pEnumData
;
1277 PFN_SELECTED_STORE_CB pfnSelectedStoreCallback
;
1279 } CRYPTUI_SELECTSTORE_INFO_W
, *PCRYPTUI_SELECTSTORE_INFO_W
;
1293 static BOOL WINAPI
enum_store_callback(const void *pvSystemStore
,
1294 DWORD dwFlags
, PCERT_SYSTEM_STORE_INFO pStoreInfo
, void *pvReserved
,
1297 HWND tree
= GetDlgItem(pvArg
, IDC_STORE_LIST
);
1298 TVINSERTSTRUCTW tvis
;
1299 LPCWSTR localizedName
;
1302 tvis
.hParent
= NULL
;
1303 tvis
.hInsertAfter
= TVI_LAST
;
1304 tvis
.u
.item
.mask
= TVIF_TEXT
;
1305 if ((localizedName
= CryptFindLocalizedName(pvSystemStore
)))
1307 struct StoreInfo
*storeInfo
= HeapAlloc(GetProcessHeap(), 0,
1308 sizeof(struct StoreInfo
));
1312 storeInfo
->type
= SystemStore
;
1313 storeInfo
->u
.name
= HeapAlloc(GetProcessHeap(), 0,
1314 (strlenW(pvSystemStore
) + 1) * sizeof(WCHAR
));
1315 if (storeInfo
->u
.name
)
1317 tvis
.u
.item
.mask
|= TVIF_PARAM
;
1318 tvis
.u
.item
.lParam
= (LPARAM
)storeInfo
;
1319 strcpyW(storeInfo
->u
.name
, pvSystemStore
);
1323 HeapFree(GetProcessHeap(), 0, storeInfo
);
1329 tvis
.u
.item
.pszText
= (LPWSTR
)localizedName
;
1332 tvis
.u
.item
.pszText
= (LPWSTR
)pvSystemStore
;
1333 /* FIXME: need a folder icon for the store too */
1335 SendMessageW(tree
, TVM_INSERTITEMW
, 0, (LPARAM
)&tvis
);
1339 static void enumerate_stores(HWND hwnd
, CRYPTUI_ENUM_DATA
*pEnumData
)
1342 HWND tree
= GetDlgItem(hwnd
, IDC_STORE_LIST
);
1344 for (i
= 0; i
< pEnumData
->cEnumArgs
; i
++)
1345 CertEnumSystemStore(pEnumData
->rgEnumArgs
[i
].dwFlags
,
1346 pEnumData
->rgEnumArgs
[i
].pvSystemStoreLocationPara
,
1347 hwnd
, enum_store_callback
);
1348 for (i
= 0; i
< pEnumData
->cStores
; i
++)
1352 if (CertGetStoreProperty(pEnumData
->rghStore
[i
],
1353 CERT_STORE_LOCALIZED_NAME_PROP_ID
, NULL
, &size
))
1355 LPWSTR name
= HeapAlloc(GetProcessHeap(), 0, size
);
1359 if (CertGetStoreProperty(pEnumData
->rghStore
[i
],
1360 CERT_STORE_LOCALIZED_NAME_PROP_ID
, name
, &size
))
1362 struct StoreInfo
*storeInfo
= HeapAlloc(GetProcessHeap(),
1363 0, sizeof(struct StoreInfo
));
1367 TVINSERTSTRUCTW tvis
;
1369 storeInfo
->type
= StoreHandle
;
1370 storeInfo
->u
.store
= pEnumData
->rghStore
[i
];
1371 tvis
.hParent
= NULL
;
1372 tvis
.hInsertAfter
= TVI_LAST
;
1373 tvis
.u
.item
.mask
= TVIF_TEXT
| TVIF_PARAM
;
1374 tvis
.u
.item
.pszText
= name
;
1375 tvis
.u
.item
.lParam
= (LPARAM
)storeInfo
;
1376 SendMessageW(tree
, TVM_INSERTITEMW
, 0, (LPARAM
)&tvis
);
1379 HeapFree(GetProcessHeap(), 0, name
);
1385 static void free_store_info(HWND tree
)
1387 HTREEITEM next
= (HTREEITEM
)SendMessageW(tree
, TVM_GETNEXTITEM
, TVGN_CHILD
,
1394 memset(&item
, 0, sizeof(item
));
1395 item
.mask
= TVIF_HANDLE
| TVIF_PARAM
;
1397 SendMessageW(tree
, TVM_GETITEMW
, 0, (LPARAM
)&item
);
1400 struct StoreInfo
*storeInfo
= (struct StoreInfo
*)item
.lParam
;
1402 if (storeInfo
->type
== SystemStore
)
1403 HeapFree(GetProcessHeap(), 0, storeInfo
->u
.name
);
1404 HeapFree(GetProcessHeap(), 0, storeInfo
);
1406 next
= (HTREEITEM
)SendMessageW(tree
, TVM_GETNEXTITEM
, TVGN_NEXT
,
1411 static HCERTSTORE
selected_item_to_store(HWND tree
, HTREEITEM hItem
)
1413 WCHAR buf
[MAX_STRING_LEN
];
1417 memset(&item
, 0, sizeof(item
));
1418 item
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_TEXT
;
1420 item
.cchTextMax
= sizeof(buf
) / sizeof(buf
[0]);
1422 SendMessageW(tree
, TVM_GETITEMW
, 0, (LPARAM
)&item
);
1425 struct StoreInfo
*storeInfo
= (struct StoreInfo
*)item
.lParam
;
1427 if (storeInfo
->type
== StoreHandle
)
1428 store
= storeInfo
->u
.store
;
1430 store
= CertOpenSystemStoreW(0, storeInfo
->u
.name
);
1434 /* It's implicitly a system store */
1435 store
= CertOpenSystemStoreW(0, buf
);
1440 struct SelectStoreInfo
1442 PCRYPTUI_SELECTSTORE_INFO_W info
;
1446 static LRESULT CALLBACK
select_store_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wp
,
1449 struct SelectStoreInfo
*selectInfo
;
1456 selectInfo
= (struct SelectStoreInfo
*)lp
;
1457 SetWindowLongPtrW(hwnd
, DWLP_USER
, lp
);
1458 if (selectInfo
->info
->pwszTitle
)
1459 SendMessageW(hwnd
, WM_SETTEXT
, 0,
1460 (LPARAM
)selectInfo
->info
->pwszTitle
);
1461 if (selectInfo
->info
->pwszText
)
1462 SendMessageW(GetDlgItem(hwnd
, IDC_STORE_TEXT
), WM_SETTEXT
, 0,
1463 (LPARAM
)selectInfo
->info
->pwszText
);
1464 if (!(selectInfo
->info
->dwFlags
& CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE
))
1465 ShowWindow(GetDlgItem(hwnd
, IDC_SHOW_PHYSICAL_STORES
), FALSE
);
1466 enumerate_stores(hwnd
, selectInfo
->info
->pEnumData
);
1474 HWND tree
= GetDlgItem(hwnd
, IDC_STORE_LIST
);
1475 HTREEITEM selection
= (HTREEITEM
)SendMessageW(tree
,
1476 TVM_GETNEXTITEM
, TVGN_CARET
, (LPARAM
)NULL
);
1478 selectInfo
= (struct SelectStoreInfo
*)GetWindowLongPtrW(hwnd
,
1482 WCHAR title
[MAX_STRING_LEN
], error
[MAX_STRING_LEN
], *pTitle
;
1484 if (selectInfo
->info
->pwszTitle
)
1485 pTitle
= selectInfo
->info
->pwszTitle
;
1488 LoadStringW(hInstance
, IDS_SELECT_STORE_TITLE
, title
,
1489 sizeof(title
) / sizeof(title
[0]));
1492 LoadStringW(hInstance
, IDS_SELECT_STORE
, error
,
1493 sizeof(error
) / sizeof(error
[0]));
1494 MessageBoxW(hwnd
, error
, pTitle
, MB_ICONEXCLAMATION
| MB_OK
);
1498 HCERTSTORE store
= selected_item_to_store(tree
, selection
);
1500 if (!selectInfo
->info
->pfnSelectedStoreCallback
||
1501 selectInfo
->info
->pfnSelectedStoreCallback(store
, hwnd
,
1502 selectInfo
->info
->pvArg
))
1504 selectInfo
->store
= store
;
1505 free_store_info(tree
);
1506 EndDialog(hwnd
, IDOK
);
1509 CertCloseStore(store
, 0);
1515 free_store_info(GetDlgItem(hwnd
, IDC_STORE_LIST
));
1516 EndDialog(hwnd
, IDCANCEL
);
1525 /***********************************************************************
1526 * CryptUIDlgSelectStoreW (CRYPTUI.@)
1528 HCERTSTORE WINAPI
CryptUIDlgSelectStoreW(PCRYPTUI_SELECTSTORE_INFO_W info
)
1530 struct SelectStoreInfo selectInfo
= { info
, NULL
};
1532 TRACE("(%p)\n", info
);
1534 if (info
->dwSize
!= sizeof(CRYPTUI_SELECTSTORE_INFO_W
))
1536 WARN("unexpected size %d\n", info
->dwSize
);
1537 SetLastError(E_INVALIDARG
);
1540 DialogBoxParamW(hInstance
, MAKEINTRESOURCEW(IDD_SELECT_STORE
), info
->parent
,
1541 select_store_dlg_proc
, (LPARAM
)&selectInfo
);
1542 return selectInfo
.store
;
1545 /***********************************************************************
1546 * CryptUIDlgSelectStoreA (CRYPTUI.@)
1548 HCERTSTORE WINAPI
CryptUIDlgSelectStoreA(PCRYPTUI_SELECTSTORE_INFO_A info
)
1550 CRYPTUI_SELECTSTORE_INFO_W infoW
;
1554 TRACE("(%p)\n", info
);
1556 if (info
->dwSize
!= sizeof(CRYPTUI_SELECTSTORE_INFO_A
))
1558 WARN("unexpected size %d\n", info
->dwSize
);
1559 SetLastError(E_INVALIDARG
);
1562 memcpy(&infoW
, &info
, sizeof(info
));
1565 len
= MultiByteToWideChar(CP_ACP
, 0, info
->pszTitle
, -1, NULL
, 0);
1566 infoW
.pwszTitle
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1567 MultiByteToWideChar(CP_ACP
, 0, info
->pszTitle
, -1, infoW
.pwszTitle
,
1572 len
= MultiByteToWideChar(CP_ACP
, 0, info
->pszText
, -1, NULL
, 0);
1573 infoW
.pwszText
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1574 MultiByteToWideChar(CP_ACP
, 0, info
->pszText
, -1, infoW
.pwszText
, len
);
1576 ret
= CryptUIDlgSelectStoreW(&infoW
);
1577 HeapFree(GetProcessHeap(), 0, infoW
.pwszText
);
1578 HeapFree(GetProcessHeap(), 0, infoW
.pwszTitle
);
1582 /***********************************************************************
1583 * CryptUIDlgViewCertificateA (CRYPTUI.@)
1585 BOOL WINAPI
CryptUIDlgViewCertificateA(
1586 PCCRYPTUI_VIEWCERTIFICATE_STRUCTA pCertViewInfo
, BOOL
*pfPropertiesChanged
)
1588 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo
;
1589 LPWSTR title
= NULL
;
1592 TRACE("(%p, %p)\n", pCertViewInfo
, pfPropertiesChanged
);
1594 memcpy(&viewInfo
, pCertViewInfo
, sizeof(viewInfo
));
1595 if (pCertViewInfo
->szTitle
)
1597 int len
= MultiByteToWideChar(CP_ACP
, 0, pCertViewInfo
->szTitle
, -1,
1600 title
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1603 MultiByteToWideChar(CP_ACP
, 0, pCertViewInfo
->szTitle
, -1, title
,
1605 viewInfo
.szTitle
= title
;
1613 if (pCertViewInfo
->cPropSheetPages
)
1615 FIXME("ignoring additional prop sheet pages\n");
1616 viewInfo
.cPropSheetPages
= 0;
1618 ret
= CryptUIDlgViewCertificateW(&viewInfo
, pfPropertiesChanged
);
1619 HeapFree(GetProcessHeap(), 0, title
);
1624 struct ReadStringStruct
1631 static DWORD CALLBACK
read_text_callback(DWORD_PTR dwCookie
, LPBYTE buf
,
1634 struct ReadStringStruct
*string
= (struct ReadStringStruct
*)dwCookie
;
1635 LONG cch
= min(cb
/ sizeof(WCHAR
), string
->len
- string
->pos
);
1637 TRACE("(%p, %p, %d, %p)\n", string
, buf
, cb
, pcb
);
1639 memmove(buf
, string
->buf
+ string
->pos
, cch
* sizeof(WCHAR
));
1641 *pcb
= cch
* sizeof(WCHAR
);
1645 static void add_unformatted_text_to_control(HWND hwnd
, LPCWSTR text
, LONG len
)
1647 struct ReadStringStruct string
;
1648 EDITSTREAM editstream
;
1650 TRACE("(%p, %s)\n", hwnd
, debugstr_wn(text
, len
));
1655 editstream
.dwCookie
= (DWORD_PTR
)&string
;
1656 editstream
.dwError
= 0;
1657 editstream
.pfnCallback
= read_text_callback
;
1658 SendMessageW(hwnd
, EM_STREAMIN
, SF_TEXT
| SFF_SELECTION
| SF_UNICODE
,
1659 (LPARAM
)&editstream
);
1662 static void add_string_resource_to_control(HWND hwnd
, int id
)
1667 len
= LoadStringW(hInstance
, id
, (LPWSTR
)&str
, 0);
1668 add_unformatted_text_to_control(hwnd
, str
, len
);
1671 static void add_text_with_paraformat_to_control(HWND hwnd
, LPCWSTR text
,
1672 LONG len
, const PARAFORMAT2
*fmt
)
1674 add_unformatted_text_to_control(hwnd
, text
, len
);
1675 SendMessageW(hwnd
, EM_SETPARAFORMAT
, 0, (LPARAM
)fmt
);
1678 static void add_string_resource_with_paraformat_to_control(HWND hwnd
, int id
,
1679 const PARAFORMAT2
*fmt
)
1684 len
= LoadStringW(hInstance
, id
, (LPWSTR
)&str
, 0);
1685 add_text_with_paraformat_to_control(hwnd
, str
, len
, fmt
);
1688 static LPWSTR
get_cert_name_string(PCCERT_CONTEXT pCertContext
, DWORD dwType
,
1694 len
= CertGetNameStringW(pCertContext
, dwType
, dwFlags
, NULL
, NULL
, 0);
1697 buf
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1699 CertGetNameStringW(pCertContext
, dwType
, dwFlags
, NULL
, buf
, len
);
1704 static void add_cert_string_to_control(HWND hwnd
, PCCERT_CONTEXT pCertContext
,
1705 DWORD dwType
, DWORD dwFlags
)
1707 LPWSTR name
= get_cert_name_string(pCertContext
, dwType
, dwFlags
);
1711 /* Don't include NULL-terminator in output */
1712 DWORD len
= lstrlenW(name
);
1714 add_unformatted_text_to_control(hwnd
, name
, len
);
1715 HeapFree(GetProcessHeap(), 0, name
);
1719 static void add_icon_to_control(HWND hwnd
, int id
)
1722 LPRICHEDITOLE richEditOle
= NULL
;
1723 LPOLEOBJECT object
= NULL
;
1725 LPOLECACHE oleCache
= NULL
;
1726 FORMATETC formatEtc
;
1728 LPDATAOBJECT dataObject
= NULL
;
1729 HBITMAP bitmap
= NULL
;
1732 LPOLECLIENTSITE clientSite
= NULL
;
1735 TRACE("(%p, %d)\n", hwnd
, id
);
1737 SendMessageW(hwnd
, EM_GETOLEINTERFACE
, 0, (LPARAM
)&richEditOle
);
1740 hr
= OleCreateDefaultHandler(&CLSID_NULL
, NULL
, &IID_IOleObject
,
1744 hr
= IOleObject_GetUserClassID(object
, &clsid
);
1747 hr
= IOleObject_QueryInterface(object
, &IID_IOleCache
, (void**)&oleCache
);
1750 formatEtc
.cfFormat
= CF_BITMAP
;
1751 formatEtc
.ptd
= NULL
;
1752 formatEtc
.dwAspect
= DVASPECT_CONTENT
;
1753 formatEtc
.lindex
= -1;
1754 formatEtc
.tymed
= TYMED_GDI
;
1755 hr
= IOleCache_Cache(oleCache
, &formatEtc
, 0, &conn
);
1758 hr
= IOleObject_QueryInterface(object
, &IID_IDataObject
,
1759 (void**)&dataObject
);
1762 hr
= IRichEditOle_GetClientSite(richEditOle
, &clientSite
);
1765 bitmap
= LoadImageW(hInstance
, MAKEINTRESOURCEW(id
), IMAGE_BITMAP
, 0, 0,
1766 LR_DEFAULTSIZE
| LR_LOADTRANSPARENT
);
1769 rect
.left
= rect
.top
= 0;
1770 rect
.right
= GetSystemMetrics(SM_CXICON
);
1771 rect
.bottom
= GetSystemMetrics(SM_CYICON
);
1772 stgm
.tymed
= TYMED_GDI
;
1773 stgm
.u
.hBitmap
= bitmap
;
1774 stgm
.pUnkForRelease
= NULL
;
1775 hr
= IDataObject_SetData(dataObject
, &formatEtc
, &stgm
, TRUE
);
1779 reObject
.cbStruct
= sizeof(reObject
);
1780 reObject
.cp
= REO_CP_SELECTION
;
1781 reObject
.clsid
= clsid
;
1782 reObject
.poleobj
= object
;
1783 reObject
.pstg
= NULL
;
1784 reObject
.polesite
= clientSite
;
1785 reObject
.sizel
.cx
= reObject
.sizel
.cy
= 0;
1786 reObject
.dvaspect
= DVASPECT_CONTENT
;
1787 reObject
.dwFlags
= 0;
1788 reObject
.dwUser
= 0;
1790 IRichEditOle_InsertObject(richEditOle
, &reObject
);
1794 IOleClientSite_Release(clientSite
);
1796 IDataObject_Release(dataObject
);
1798 IOleCache_Release(oleCache
);
1800 IOleObject_Release(object
);
1802 IRichEditOle_Release(richEditOle
);
1805 #define MY_INDENT 200
1807 static void add_oid_text_to_control(HWND hwnd
, char *oid
)
1810 PCCRYPT_OID_INFO oidInfo
= CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY
, oid
, 0);
1813 parFmt
.cbSize
= sizeof(parFmt
);
1814 parFmt
.dwMask
= PFM_STARTINDENT
;
1815 parFmt
.dxStartIndent
= MY_INDENT
* 3;
1818 add_text_with_paraformat_to_control(hwnd
, oidInfo
->pwszName
,
1819 lstrlenW(oidInfo
->pwszName
), &parFmt
);
1820 add_unformatted_text_to_control(hwnd
, &nl
, 1);
1830 /* The following list MUST be lexicographically sorted by OID */
1831 static struct OIDToString oidMap
[] = {
1832 /* 1.3.6.1.4.1.311.10.3.1 */
1833 { szOID_KP_CTL_USAGE_SIGNING
, IDS_PURPOSE_CTL_USAGE_SIGNING
},
1834 /* 1.3.6.1.4.1.311.10.3.4 */
1835 { szOID_KP_EFS
, IDS_PURPOSE_EFS
},
1836 /* 1.3.6.1.4.1.311.10.3.4.1 */
1837 { szOID_EFS_RECOVERY
, IDS_PURPOSE_EFS_RECOVERY
},
1838 /* 1.3.6.1.4.1.311.10.3.5 */
1839 { szOID_WHQL_CRYPTO
, IDS_PURPOSE_WHQL
},
1840 /* 1.3.6.1.4.1.311.10.3.6 */
1841 { szOID_NT5_CRYPTO
, IDS_PURPOSE_NT5
},
1842 /* 1.3.6.1.4.1.311.10.3.7 */
1843 { szOID_OEM_WHQL_CRYPTO
, IDS_PURPOSE_OEM_WHQL
},
1844 /* 1.3.6.1.4.1.311.10.3.8 */
1845 { szOID_EMBEDDED_NT_CRYPTO
, IDS_PURPOSE_EMBEDDED_NT
},
1846 /* 1.3.6.1.4.1.311.10.3.9 */
1847 { szOID_ROOT_LIST_SIGNER
, IDS_PURPOSE_ROOT_LIST_SIGNER
},
1848 /* 1.3.6.1.4.1.311.10.3.10 */
1849 { szOID_KP_QUALIFIED_SUBORDINATION
, IDS_PURPOSE_QUALIFIED_SUBORDINATION
},
1850 /* 1.3.6.1.4.1.311.10.3.11 */
1851 { szOID_KP_KEY_RECOVERY
, IDS_PURPOSE_KEY_RECOVERY
},
1852 /* 1.3.6.1.4.1.311.10.3.12 */
1853 { szOID_KP_DOCUMENT_SIGNING
, IDS_PURPOSE_DOCUMENT_SIGNING
},
1854 /* 1.3.6.1.4.1.311.10.3.13 */
1855 { szOID_KP_LIFETIME_SIGNING
, IDS_PURPOSE_LIFETIME_SIGNING
},
1856 /* 1.3.6.1.4.1.311.10.5.1 */
1857 { szOID_DRM
, IDS_PURPOSE_DRM
},
1858 /* 1.3.6.1.4.1.311.10.6.1 */
1859 { szOID_LICENSES
, IDS_PURPOSE_LICENSES
},
1860 /* 1.3.6.1.4.1.311.10.6.2 */
1861 { szOID_LICENSE_SERVER
, IDS_PURPOSE_LICENSE_SERVER
},
1862 /* 1.3.6.1.4.1.311.20.2.1 */
1863 { szOID_ENROLLMENT_AGENT
, IDS_PURPOSE_ENROLLMENT_AGENT
},
1864 /* 1.3.6.1.4.1.311.20.2.2 */
1865 { szOID_KP_SMARTCARD_LOGON
, IDS_PURPOSE_SMARTCARD_LOGON
},
1866 /* 1.3.6.1.4.1.311.21.5 */
1867 { szOID_KP_CA_EXCHANGE
, IDS_PURPOSE_CA_EXCHANGE
},
1868 /* 1.3.6.1.4.1.311.21.6 */
1869 { szOID_KP_KEY_RECOVERY_AGENT
, IDS_PURPOSE_KEY_RECOVERY_AGENT
},
1870 /* 1.3.6.1.4.1.311.21.19 */
1871 { szOID_DS_EMAIL_REPLICATION
, IDS_PURPOSE_DS_EMAIL_REPLICATION
},
1872 /* 1.3.6.1.5.5.7.3.1 */
1873 { szOID_PKIX_KP_SERVER_AUTH
, IDS_PURPOSE_SERVER_AUTH
},
1874 /* 1.3.6.1.5.5.7.3.2 */
1875 { szOID_PKIX_KP_CLIENT_AUTH
, IDS_PURPOSE_CLIENT_AUTH
},
1876 /* 1.3.6.1.5.5.7.3.3 */
1877 { szOID_PKIX_KP_CODE_SIGNING
, IDS_PURPOSE_CODE_SIGNING
},
1878 /* 1.3.6.1.5.5.7.3.4 */
1879 { szOID_PKIX_KP_EMAIL_PROTECTION
, IDS_PURPOSE_EMAIL_PROTECTION
},
1880 /* 1.3.6.1.5.5.7.3.5 */
1881 { szOID_PKIX_KP_IPSEC_END_SYSTEM
, IDS_PURPOSE_IPSEC
},
1882 /* 1.3.6.1.5.5.7.3.6 */
1883 { szOID_PKIX_KP_IPSEC_TUNNEL
, IDS_PURPOSE_IPSEC
},
1884 /* 1.3.6.1.5.5.7.3.7 */
1885 { szOID_PKIX_KP_IPSEC_USER
, IDS_PURPOSE_IPSEC
},
1886 /* 1.3.6.1.5.5.7.3.8 */
1887 { szOID_PKIX_KP_TIMESTAMP_SIGNING
, IDS_PURPOSE_TIMESTAMP_SIGNING
},
1890 static struct OIDToString
*findSupportedOID(LPCSTR oid
)
1892 int indexHigh
= sizeof(oidMap
) / sizeof(oidMap
[0]) - 1, indexLow
= 0, i
;
1893 struct OIDToString
*ret
= NULL
;
1895 for (i
= (indexLow
+ indexHigh
) / 2; !ret
&& indexLow
<= indexHigh
;
1896 i
= (indexLow
+ indexHigh
) / 2)
1900 cmp
= strcmp(oid
, oidMap
[i
].oid
);
1911 static void add_local_oid_text_to_control(HWND text
, LPCSTR oid
)
1913 struct OIDToString
*entry
;
1917 parFmt
.cbSize
= sizeof(parFmt
);
1918 parFmt
.dwMask
= PFM_STARTINDENT
;
1919 parFmt
.dxStartIndent
= MY_INDENT
* 3;
1920 if ((entry
= findSupportedOID(oid
)))
1922 WCHAR
*str
, *linebreak
, *ptr
;
1923 BOOL multiline
= FALSE
;
1926 len
= LoadStringW(hInstance
, entry
->id
, (LPWSTR
)&str
, 0);
1929 if ((linebreak
= memchrW(ptr
, '\n', len
)))
1931 WCHAR copy
[MAX_STRING_LEN
];
1934 /* The source string contains a newline, which the richedit
1935 * control won't find since it's interpreted as a paragraph
1936 * break. Therefore copy up to the newline. lstrcpynW always
1937 * NULL-terminates, so pass one more than the length of the
1938 * source line so the copy includes the entire line and the
1941 lstrcpynW(copy
, ptr
, linebreak
- ptr
+ 1);
1942 add_text_with_paraformat_to_control(text
, copy
,
1943 linebreak
- ptr
, &parFmt
);
1944 ptr
= linebreak
+ 1;
1945 add_unformatted_text_to_control(text
, &nl
, 1);
1947 else if (multiline
&& *ptr
)
1949 /* Add the last line */
1950 add_text_with_paraformat_to_control(text
, ptr
,
1951 len
- (ptr
- str
), &parFmt
);
1952 add_unformatted_text_to_control(text
, &nl
, 1);
1954 } while (linebreak
);
1957 add_text_with_paraformat_to_control(text
, str
, len
, &parFmt
);
1958 add_unformatted_text_to_control(text
, &nl
, 1);
1963 WCHAR
*oidW
= HeapAlloc(GetProcessHeap(), 0,
1964 (strlen(oid
) + 1) * sizeof(WCHAR
));
1971 for (src
= oid
, dst
= oidW
; *src
; src
++, dst
++)
1974 add_text_with_paraformat_to_control(text
, oidW
, lstrlenW(oidW
),
1976 add_unformatted_text_to_control(text
, &nl
, 1);
1977 HeapFree(GetProcessHeap(), 0, oidW
);
1982 static void display_app_usages(HWND text
, PCCERT_CONTEXT cert
,
1983 BOOL
*anyUsageAdded
)
1985 static char any_app_policy
[] = szOID_ANY_APPLICATION_POLICY
;
1987 CHARFORMATW charFmt
;
1988 PCERT_EXTENSION policyExt
;
1989 if (!*anyUsageAdded
)
1993 parFmt
.cbSize
= sizeof(parFmt
);
1994 parFmt
.dwMask
= PFM_STARTINDENT
;
1995 parFmt
.dxStartIndent
= MY_INDENT
;
1996 add_string_resource_with_paraformat_to_control(text
,
1997 IDS_CERT_INFO_PURPOSES
, &parFmt
);
1998 add_unformatted_text_to_control(text
, &nl
, 1);
1999 *anyUsageAdded
= TRUE
;
2001 memset(&charFmt
, 0, sizeof(charFmt
));
2002 charFmt
.cbSize
= sizeof(charFmt
);
2003 charFmt
.dwMask
= CFM_BOLD
;
2004 charFmt
.dwEffects
= 0;
2005 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
2006 if ((policyExt
= CertFindExtension(szOID_APPLICATION_CERT_POLICIES
,
2007 cert
->pCertInfo
->cExtension
, cert
->pCertInfo
->rgExtension
)))
2009 CERT_POLICIES_INFO
*policies
;
2012 if (CryptDecodeObjectEx(X509_ASN_ENCODING
, X509_CERT_POLICIES
,
2013 policyExt
->Value
.pbData
, policyExt
->Value
.cbData
,
2014 CRYPT_DECODE_ALLOC_FLAG
, NULL
, &policies
, &size
))
2018 for (i
= 0; i
< policies
->cPolicyInfo
; i
++)
2022 for (j
= 0; j
< policies
->rgPolicyInfo
[i
].cPolicyQualifier
; j
++)
2023 add_local_oid_text_to_control(text
,
2024 policies
->rgPolicyInfo
[i
].rgPolicyQualifier
[j
].
2025 pszPolicyQualifierId
);
2027 LocalFree(policies
);
2031 add_oid_text_to_control(text
, any_app_policy
);
2034 static BOOL
display_cert_usages(HWND text
, PCCERT_CONTEXT cert
,
2035 BOOL
*anyUsageAdded
)
2039 BOOL badUsages
= FALSE
;
2041 if (CertGetEnhancedKeyUsage(cert
, 0, NULL
, &size
))
2043 CHARFORMATW charFmt
;
2044 static char any_cert_policy
[] = szOID_ANY_CERT_POLICY
;
2045 PCERT_ENHKEY_USAGE usage
= HeapAlloc(GetProcessHeap(), 0, size
);
2049 if (CertGetEnhancedKeyUsage(cert
, 0, usage
, &size
))
2053 if (!*anyUsageAdded
)
2057 parFmt
.cbSize
= sizeof(parFmt
);
2058 parFmt
.dwMask
= PFM_STARTINDENT
;
2059 parFmt
.dxStartIndent
= MY_INDENT
;
2060 add_string_resource_with_paraformat_to_control(text
,
2061 IDS_CERT_INFO_PURPOSES
, &parFmt
);
2062 add_unformatted_text_to_control(text
, &nl
, 1);
2063 *anyUsageAdded
= TRUE
;
2065 memset(&charFmt
, 0, sizeof(charFmt
));
2066 charFmt
.cbSize
= sizeof(charFmt
);
2067 charFmt
.dwMask
= CFM_BOLD
;
2068 charFmt
.dwEffects
= 0;
2069 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
,
2071 if (!usage
->cUsageIdentifier
)
2072 add_oid_text_to_control(text
, any_cert_policy
);
2074 for (i
= 0; i
< usage
->cUsageIdentifier
; i
++)
2075 add_local_oid_text_to_control(text
,
2076 usage
->rgpszUsageIdentifier
[i
]);
2080 HeapFree(GetProcessHeap(), 0, usage
);
2090 static void set_policy_text(HWND text
,
2091 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
)
2093 BOOL includeCertUsages
= FALSE
, includeAppUsages
= FALSE
;
2094 BOOL badUsages
= FALSE
, anyUsageAdded
= FALSE
;
2096 if (pCertViewInfo
->cPurposes
)
2100 for (i
= 0; i
< pCertViewInfo
->cPurposes
; i
++)
2102 if (!strcmp(pCertViewInfo
->rgszPurposes
[i
], szOID_ANY_CERT_POLICY
))
2103 includeCertUsages
= TRUE
;
2104 else if (!strcmp(pCertViewInfo
->rgszPurposes
[i
],
2105 szOID_ANY_APPLICATION_POLICY
))
2106 includeAppUsages
= TRUE
;
2112 includeAppUsages
= includeCertUsages
= TRUE
;
2113 if (includeAppUsages
)
2114 display_app_usages(text
, pCertViewInfo
->pCertContext
, &anyUsageAdded
);
2115 if (includeCertUsages
)
2116 badUsages
= display_cert_usages(text
, pCertViewInfo
->pCertContext
,
2122 parFmt
.cbSize
= sizeof(parFmt
);
2123 parFmt
.dwMask
= PFM_STARTINDENT
;
2124 parFmt
.dxStartIndent
= MY_INDENT
;
2125 add_string_resource_with_paraformat_to_control(text
,
2126 IDS_CERT_INFO_BAD_PURPOSES
, &parFmt
);
2130 static CRYPT_OBJID_BLOB
*find_policy_qualifier(CERT_POLICIES_INFO
*policies
,
2133 CRYPT_OBJID_BLOB
*ret
= NULL
;
2136 for (i
= 0; !ret
&& i
< policies
->cPolicyInfo
; i
++)
2140 for (j
= 0; !ret
&& j
< policies
->rgPolicyInfo
[i
].cPolicyQualifier
; j
++)
2141 if (!strcmp(policies
->rgPolicyInfo
[i
].rgPolicyQualifier
[j
].
2142 pszPolicyQualifierId
, policyOid
))
2143 ret
= &policies
->rgPolicyInfo
[i
].rgPolicyQualifier
[j
].
2149 static WCHAR
*get_cps_str_from_qualifier(CRYPT_OBJID_BLOB
*qualifier
)
2151 LPWSTR qualifierStr
= NULL
;
2152 CERT_NAME_VALUE
*qualifierValue
;
2155 if (CryptDecodeObjectEx(X509_ASN_ENCODING
, X509_NAME_VALUE
,
2156 qualifier
->pbData
, qualifier
->cbData
, CRYPT_DECODE_ALLOC_FLAG
, NULL
,
2157 &qualifierValue
, &size
))
2159 size
= CertRDNValueToStrW(qualifierValue
->dwValueType
,
2160 &qualifierValue
->Value
, NULL
, 0);
2161 qualifierStr
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
));
2163 CertRDNValueToStrW(qualifierValue
->dwValueType
,
2164 &qualifierValue
->Value
, qualifierStr
, size
);
2165 LocalFree(qualifierValue
);
2167 return qualifierStr
;
2170 static WCHAR
*get_user_notice_from_qualifier(CRYPT_OBJID_BLOB
*qualifier
)
2173 CERT_POLICY_QUALIFIER_USER_NOTICE
*qualifierValue
;
2176 if (CryptDecodeObjectEx(X509_ASN_ENCODING
,
2177 X509_PKIX_POLICY_QUALIFIER_USERNOTICE
,
2178 qualifier
->pbData
, qualifier
->cbData
, CRYPT_DECODE_ALLOC_FLAG
, NULL
,
2179 &qualifierValue
, &size
))
2181 str
= HeapAlloc(GetProcessHeap(), 0,
2182 (strlenW(qualifierValue
->pszDisplayText
) + 1) * sizeof(WCHAR
));
2184 strcpyW(str
, qualifierValue
->pszDisplayText
);
2185 LocalFree(qualifierValue
);
2190 struct IssuerStatement
2196 static void set_issuer_statement(HWND hwnd
,
2197 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
)
2199 PCERT_EXTENSION policyExt
;
2201 if (!(pCertViewInfo
->dwFlags
& CRYPTUI_DISABLE_ISSUERSTATEMENT
) &&
2202 (policyExt
= CertFindExtension(szOID_CERT_POLICIES
,
2203 pCertViewInfo
->pCertContext
->pCertInfo
->cExtension
,
2204 pCertViewInfo
->pCertContext
->pCertInfo
->rgExtension
)))
2206 CERT_POLICIES_INFO
*policies
;
2209 if (CryptDecodeObjectEx(X509_ASN_ENCODING
, policyExt
->pszObjId
,
2210 policyExt
->Value
.pbData
, policyExt
->Value
.cbData
,
2211 CRYPT_DECODE_ALLOC_FLAG
, NULL
, &policies
, &size
))
2213 CRYPT_OBJID_BLOB
*qualifier
;
2214 LPWSTR cps
= NULL
, userNotice
= NULL
;
2216 if ((qualifier
= find_policy_qualifier(policies
,
2217 szOID_PKIX_POLICY_QUALIFIER_CPS
)))
2218 cps
= get_cps_str_from_qualifier(qualifier
);
2219 if ((qualifier
= find_policy_qualifier(policies
,
2220 szOID_PKIX_POLICY_QUALIFIER_USERNOTICE
)))
2221 userNotice
= get_user_notice_from_qualifier(qualifier
);
2222 if (cps
|| userNotice
)
2224 struct IssuerStatement
*issuerStatement
=
2225 HeapAlloc(GetProcessHeap(), 0, sizeof(struct IssuerStatement
));
2227 if (issuerStatement
)
2229 issuerStatement
->cps
= cps
;
2230 issuerStatement
->userNotice
= userNotice
;
2231 EnableWindow(GetDlgItem(hwnd
, IDC_ISSUERSTATEMENT
), TRUE
);
2232 SetWindowLongPtrW(hwnd
, DWLP_USER
,
2233 (ULONG_PTR
)issuerStatement
);
2236 LocalFree(policies
);
2241 static void set_cert_info(HWND hwnd
,
2242 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
)
2244 CHARFORMATW charFmt
;
2246 HWND icon
= GetDlgItem(hwnd
, IDC_CERTIFICATE_ICON
);
2247 HWND text
= GetDlgItem(hwnd
, IDC_CERTIFICATE_INFO
);
2248 CRYPT_PROVIDER_SGNR
*provSigner
= WTHelperGetProvSignerFromChain(
2249 (CRYPT_PROVIDER_DATA
*)pCertViewInfo
->u
.pCryptProviderData
,
2250 pCertViewInfo
->idxSigner
, pCertViewInfo
->fCounterSigner
,
2251 pCertViewInfo
->idxCounterSigner
);
2252 CRYPT_PROVIDER_CERT
*root
=
2253 &provSigner
->pasCertChain
[provSigner
->csCertChain
- 1];
2255 if (!provSigner
->pChainContext
||
2256 (provSigner
->pChainContext
->TrustStatus
.dwErrorStatus
&
2257 CERT_TRUST_IS_PARTIAL_CHAIN
))
2258 add_icon_to_control(icon
, IDB_CERT_WARNING
);
2259 else if (!root
->fTrustedRoot
)
2260 add_icon_to_control(icon
, IDB_CERT_ERROR
);
2262 add_icon_to_control(icon
, IDB_CERT
);
2264 memset(&charFmt
, 0, sizeof(charFmt
));
2265 charFmt
.cbSize
= sizeof(charFmt
);
2266 charFmt
.dwMask
= CFM_BOLD
;
2267 charFmt
.dwEffects
= CFE_BOLD
;
2268 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
2269 /* FIXME: vertically center text */
2270 parFmt
.cbSize
= sizeof(parFmt
);
2271 parFmt
.dwMask
= PFM_STARTINDENT
;
2272 parFmt
.dxStartIndent
= MY_INDENT
;
2273 add_string_resource_with_paraformat_to_control(text
,
2274 IDS_CERTIFICATEINFORMATION
, &parFmt
);
2276 text
= GetDlgItem(hwnd
, IDC_CERTIFICATE_STATUS
);
2277 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
2278 if (provSigner
->dwError
== TRUST_E_CERT_SIGNATURE
)
2279 add_string_resource_with_paraformat_to_control(text
,
2280 IDS_CERT_INFO_BAD_SIG
, &parFmt
);
2281 else if (!provSigner
->pChainContext
||
2282 (provSigner
->pChainContext
->TrustStatus
.dwErrorStatus
&
2283 CERT_TRUST_IS_PARTIAL_CHAIN
))
2284 add_string_resource_with_paraformat_to_control(text
,
2285 IDS_CERT_INFO_PARTIAL_CHAIN
, &parFmt
);
2286 else if (!root
->fTrustedRoot
)
2288 if (provSigner
->csCertChain
== 1 && root
->fSelfSigned
)
2289 add_string_resource_with_paraformat_to_control(text
,
2290 IDS_CERT_INFO_UNTRUSTED_CA
, &parFmt
);
2292 add_string_resource_with_paraformat_to_control(text
,
2293 IDS_CERT_INFO_UNTRUSTED_ROOT
, &parFmt
);
2297 set_policy_text(text
, pCertViewInfo
);
2298 set_issuer_statement(hwnd
, pCertViewInfo
);
2302 static void set_cert_name_string(HWND hwnd
, PCCERT_CONTEXT cert
,
2303 DWORD nameFlags
, int heading
)
2306 HWND text
= GetDlgItem(hwnd
, IDC_CERTIFICATE_NAMES
);
2307 CHARFORMATW charFmt
;
2310 memset(&charFmt
, 0, sizeof(charFmt
));
2311 charFmt
.cbSize
= sizeof(charFmt
);
2312 charFmt
.dwMask
= CFM_BOLD
;
2313 charFmt
.dwEffects
= CFE_BOLD
;
2314 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
2315 parFmt
.cbSize
= sizeof(parFmt
);
2316 parFmt
.dwMask
= PFM_STARTINDENT
;
2317 parFmt
.dxStartIndent
= MY_INDENT
* 3;
2318 add_string_resource_with_paraformat_to_control(text
, heading
, &parFmt
);
2319 charFmt
.dwEffects
= 0;
2320 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
2321 add_cert_string_to_control(text
, cert
, CERT_NAME_SIMPLE_DISPLAY_TYPE
,
2323 add_unformatted_text_to_control(text
, &nl
, 1);
2324 add_unformatted_text_to_control(text
, &nl
, 1);
2325 add_unformatted_text_to_control(text
, &nl
, 1);
2329 static void add_date_string_to_control(HWND hwnd
, const FILETIME
*fileTime
)
2331 WCHAR dateFmt
[80]; /* sufficient for all versions of LOCALE_SSHORTDATE */
2335 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT
, LOCALE_SSHORTDATE
, dateFmt
,
2336 sizeof(dateFmt
) / sizeof(dateFmt
[0]));
2337 FileTimeToSystemTime(fileTime
, &sysTime
);
2338 GetDateFormatW(LOCALE_SYSTEM_DEFAULT
, 0, &sysTime
, dateFmt
, date
,
2339 sizeof(date
) / sizeof(date
[0]));
2340 add_unformatted_text_to_control(hwnd
, date
, lstrlenW(date
));
2343 static void set_cert_validity_period(HWND hwnd
, PCCERT_CONTEXT cert
)
2346 HWND text
= GetDlgItem(hwnd
, IDC_CERTIFICATE_NAMES
);
2347 CHARFORMATW charFmt
;
2350 memset(&charFmt
, 0, sizeof(charFmt
));
2351 charFmt
.cbSize
= sizeof(charFmt
);
2352 charFmt
.dwMask
= CFM_BOLD
;
2353 charFmt
.dwEffects
= CFE_BOLD
;
2354 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
2355 parFmt
.cbSize
= sizeof(parFmt
);
2356 parFmt
.dwMask
= PFM_STARTINDENT
;
2357 parFmt
.dxStartIndent
= MY_INDENT
* 3;
2358 add_string_resource_with_paraformat_to_control(text
, IDS_VALID_FROM
,
2360 charFmt
.dwEffects
= 0;
2361 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
2362 add_date_string_to_control(text
, &cert
->pCertInfo
->NotBefore
);
2363 charFmt
.dwEffects
= CFE_BOLD
;
2364 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
2365 add_string_resource_to_control(text
, IDS_VALID_TO
);
2366 charFmt
.dwEffects
= 0;
2367 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
2368 add_date_string_to_control(text
, &cert
->pCertInfo
->NotAfter
);
2369 add_unformatted_text_to_control(text
, &nl
, 1);
2372 static void set_general_info(HWND hwnd
,
2373 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
)
2375 set_cert_info(hwnd
, pCertViewInfo
);
2376 set_cert_name_string(hwnd
, pCertViewInfo
->pCertContext
, 0,
2377 IDS_SUBJECT_HEADING
);
2378 set_cert_name_string(hwnd
, pCertViewInfo
->pCertContext
,
2379 CERT_NAME_ISSUER_FLAG
, IDS_ISSUER_HEADING
);
2380 set_cert_validity_period(hwnd
, pCertViewInfo
->pCertContext
);
2383 static LRESULT CALLBACK
user_notice_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wp
,
2388 struct IssuerStatement
*issuerStatement
;
2393 text
= GetDlgItem(hwnd
, IDC_USERNOTICE
);
2394 issuerStatement
= (struct IssuerStatement
*)lp
;
2395 add_unformatted_text_to_control(text
, issuerStatement
->userNotice
,
2396 strlenW(issuerStatement
->userNotice
));
2397 if (issuerStatement
->cps
)
2398 SetWindowLongPtrW(hwnd
, DWLP_USER
, (LPARAM
)issuerStatement
->cps
);
2400 EnableWindow(GetDlgItem(hwnd
, IDC_CPS
), FALSE
);
2406 EndDialog(hwnd
, IDOK
);
2411 IBindCtx
*bctx
= NULL
;
2414 CreateBindCtx(0, &bctx
);
2415 cps
= (LPWSTR
)GetWindowLongPtrW(hwnd
, DWLP_USER
);
2416 HlinkSimpleNavigateToString(cps
, NULL
, NULL
, NULL
, bctx
, NULL
,
2417 HLNF_OPENINNEWWINDOW
, 0);
2418 IBindCtx_Release(bctx
);
2426 static void show_user_notice(HWND hwnd
, struct IssuerStatement
*issuerStatement
)
2428 DialogBoxParamW(hInstance
, MAKEINTRESOURCEW(IDD_USERNOTICE
), hwnd
,
2429 user_notice_dlg_proc
, (LPARAM
)issuerStatement
);
2432 static LRESULT CALLBACK
general_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wp
,
2435 PROPSHEETPAGEW
*page
;
2436 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
;
2438 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd
, msg
, wp
, lp
);
2443 page
= (PROPSHEETPAGEW
*)lp
;
2444 pCertViewInfo
= (PCCRYPTUI_VIEWCERTIFICATE_STRUCTW
)page
->lParam
;
2445 if (pCertViewInfo
->dwFlags
& CRYPTUI_DISABLE_ADDTOSTORE
)
2446 ShowWindow(GetDlgItem(hwnd
, IDC_ADDTOSTORE
), FALSE
);
2447 EnableWindow(GetDlgItem(hwnd
, IDC_ISSUERSTATEMENT
), FALSE
);
2448 set_general_info(hwnd
, pCertViewInfo
);
2453 case IDC_ADDTOSTORE
:
2454 CryptUIWizImport(0, hwnd
, NULL
, NULL
, NULL
);
2456 case IDC_ISSUERSTATEMENT
:
2458 struct IssuerStatement
*issuerStatement
=
2459 (struct IssuerStatement
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
2461 if (issuerStatement
)
2463 if (issuerStatement
->userNotice
)
2464 show_user_notice(hwnd
, issuerStatement
);
2465 else if (issuerStatement
->cps
)
2467 IBindCtx
*bctx
= NULL
;
2469 CreateBindCtx(0, &bctx
);
2470 HlinkSimpleNavigateToString(issuerStatement
->cps
, NULL
,
2471 NULL
, NULL
, bctx
, NULL
, HLNF_OPENINNEWWINDOW
, 0);
2472 IBindCtx_Release(bctx
);
2483 static UINT CALLBACK
general_callback_proc(HWND hwnd
, UINT msg
,
2484 PROPSHEETPAGEW
*page
)
2486 struct IssuerStatement
*issuerStatement
;
2492 (struct IssuerStatement
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
2493 if (issuerStatement
)
2495 HeapFree(GetProcessHeap(), 0, issuerStatement
->cps
);
2496 HeapFree(GetProcessHeap(), 0, issuerStatement
->userNotice
);
2497 HeapFree(GetProcessHeap(), 0, issuerStatement
);
2504 static void init_general_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
,
2505 PROPSHEETPAGEW
*page
)
2507 memset(page
, 0, sizeof(PROPSHEETPAGEW
));
2508 page
->dwSize
= sizeof(PROPSHEETPAGEW
);
2509 page
->dwFlags
= PSP_USECALLBACK
;
2510 page
->pfnCallback
= general_callback_proc
;
2511 page
->hInstance
= hInstance
;
2512 page
->u
.pszTemplate
= MAKEINTRESOURCEW(IDD_GENERAL
);
2513 page
->pfnDlgProc
= general_dlg_proc
;
2514 page
->lParam
= (LPARAM
)pCertViewInfo
;
2517 typedef WCHAR
* (*field_format_func
)(PCCERT_CONTEXT cert
);
2519 static WCHAR
*field_format_version(PCCERT_CONTEXT cert
)
2521 static const WCHAR fmt
[] = { 'V','%','d',0 };
2522 WCHAR
*buf
= HeapAlloc(GetProcessHeap(), 0, 12 * sizeof(WCHAR
));
2525 sprintfW(buf
, fmt
, cert
->pCertInfo
->dwVersion
);
2529 static WCHAR
*format_hex_string(void *pb
, DWORD cb
)
2531 WCHAR
*buf
= HeapAlloc(GetProcessHeap(), 0, (cb
* 3 + 1) * sizeof(WCHAR
));
2535 static const WCHAR fmt
[] = { '%','0','2','x',' ',0 };
2539 for (i
= 0, ptr
= buf
; i
< cb
; i
++, ptr
+= 3)
2540 sprintfW(ptr
, fmt
, ((BYTE
*)pb
)[i
]);
2545 static WCHAR
*field_format_serial_number(PCCERT_CONTEXT cert
)
2547 return format_hex_string(cert
->pCertInfo
->SerialNumber
.pbData
,
2548 cert
->pCertInfo
->SerialNumber
.cbData
);
2551 static WCHAR
*field_format_issuer(PCCERT_CONTEXT cert
)
2553 return get_cert_name_string(cert
, CERT_NAME_SIMPLE_DISPLAY_TYPE
,
2554 CERT_NAME_ISSUER_FLAG
);
2557 static WCHAR
*field_format_detailed_cert_name(PCERT_NAME_BLOB name
)
2560 DWORD len
= CertNameToStrW(X509_ASN_ENCODING
, name
,
2561 CERT_X500_NAME_STR
| CERT_NAME_STR_CRLF_FLAG
, NULL
, 0);
2565 str
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2567 CertNameToStrW(X509_ASN_ENCODING
, name
,
2568 CERT_X500_NAME_STR
| CERT_NAME_STR_CRLF_FLAG
, str
, len
);
2573 static WCHAR
*field_format_detailed_issuer(PCCERT_CONTEXT cert
, void *param
)
2575 return field_format_detailed_cert_name(&cert
->pCertInfo
->Issuer
);
2578 static WCHAR
*field_format_subject(PCCERT_CONTEXT cert
)
2580 return get_cert_name_string(cert
, CERT_NAME_SIMPLE_DISPLAY_TYPE
, 0);
2583 static WCHAR
*field_format_detailed_subject(PCCERT_CONTEXT cert
, void *param
)
2585 return field_format_detailed_cert_name(&cert
->pCertInfo
->Subject
);
2588 static WCHAR
*format_long_date(const FILETIME
*fileTime
)
2590 WCHAR dateFmt
[80]; /* long enough for LOCALE_SLONGDATE */
2595 /* FIXME: format isn't quite right, want time too */
2596 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT
, LOCALE_SLONGDATE
, dateFmt
,
2597 sizeof(dateFmt
) / sizeof(dateFmt
[0]));
2598 FileTimeToSystemTime(fileTime
, &sysTime
);
2599 len
= GetDateFormatW(LOCALE_SYSTEM_DEFAULT
, 0, &sysTime
, dateFmt
, NULL
, 0);
2602 buf
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2604 GetDateFormatW(LOCALE_SYSTEM_DEFAULT
, 0, &sysTime
, dateFmt
, buf
,
2610 static WCHAR
*field_format_from_date(PCCERT_CONTEXT cert
)
2612 return format_long_date(&cert
->pCertInfo
->NotBefore
);
2615 static WCHAR
*field_format_to_date(PCCERT_CONTEXT cert
)
2617 return format_long_date(&cert
->pCertInfo
->NotAfter
);
2620 static WCHAR
*field_format_public_key(PCCERT_CONTEXT cert
)
2622 PCCRYPT_OID_INFO oidInfo
;
2625 oidInfo
= CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY
,
2626 cert
->pCertInfo
->SubjectPublicKeyInfo
.Algorithm
.pszObjId
, 0);
2629 WCHAR fmt
[MAX_STRING_LEN
];
2631 if (LoadStringW(hInstance
, IDS_FIELD_PUBLIC_KEY_FORMAT
, fmt
,
2632 sizeof(fmt
) / sizeof(fmt
[0])))
2634 /* Allocate the output buffer. Use the number of bytes in the
2635 * public key as a conservative (high) estimate for the number of
2636 * digits in its output.
2637 * The output is of the form (in English)
2638 * "<public key algorithm> (<public key bit length> bits)".
2639 * Ordinarily having two positional parameters in a string is not a
2640 * good idea, but as this isn't a sentence fragment, it shouldn't
2641 * be word-order dependent.
2643 buf
= HeapAlloc(GetProcessHeap(), 0,
2644 (strlenW(fmt
) + strlenW(oidInfo
->pwszName
) +
2645 cert
->pCertInfo
->SubjectPublicKeyInfo
.PublicKey
.cbData
* 8)
2648 sprintfW(buf
, fmt
, oidInfo
->pwszName
,
2649 CertGetPublicKeyLength(X509_ASN_ENCODING
,
2650 &cert
->pCertInfo
->SubjectPublicKeyInfo
));
2656 static WCHAR
*field_format_detailed_public_key(PCCERT_CONTEXT cert
, void *param
)
2658 return format_hex_string(
2659 cert
->pCertInfo
->SubjectPublicKeyInfo
.PublicKey
.pbData
,
2660 cert
->pCertInfo
->SubjectPublicKeyInfo
.PublicKey
.cbData
);
2663 struct field_value_data
;
2666 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
;
2667 BOOL
*pfPropertiesChanged
;
2669 struct field_value_data
*fields
;
2672 typedef void (*add_fields_func
)(HWND hwnd
, struct detail_data
*data
);
2674 typedef WCHAR
*(*create_detailed_value_func
)(PCCERT_CONTEXT cert
, void *param
);
2676 struct field_value_data
2678 create_detailed_value_func create
;
2679 LPWSTR detailed_value
;
2683 static void add_field_value_data(struct detail_data
*data
,
2684 create_detailed_value_func create
, void *param
)
2687 data
->fields
= HeapReAlloc(GetProcessHeap(), 0, data
->fields
,
2688 (data
->cFields
+ 1) * sizeof(struct field_value_data
));
2690 data
->fields
= HeapAlloc(GetProcessHeap(), 0,
2691 sizeof(struct field_value_data
));
2694 data
->fields
[data
->cFields
].create
= create
;
2695 data
->fields
[data
->cFields
].detailed_value
= NULL
;
2696 data
->fields
[data
->cFields
].param
= param
;
2701 static void add_field_and_value_to_list(HWND hwnd
, struct detail_data
*data
,
2702 LPWSTR field
, LPWSTR value
, create_detailed_value_func create
, void *param
)
2705 int iItem
= SendMessageW(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
2707 item
.mask
= LVIF_TEXT
| LVIF_PARAM
;
2710 item
.pszText
= field
;
2711 item
.lParam
= (LPARAM
)data
;
2712 SendMessageW(hwnd
, LVM_INSERTITEMW
, 0, (LPARAM
)&item
);
2715 item
.pszText
= value
;
2717 SendMessageW(hwnd
, LVM_SETITEMTEXTW
, iItem
, (LPARAM
)&item
);
2719 add_field_value_data(data
, create
, param
);
2722 static void add_string_id_and_value_to_list(HWND hwnd
, struct detail_data
*data
,
2723 int id
, LPWSTR value
, create_detailed_value_func create
, void *param
)
2725 WCHAR buf
[MAX_STRING_LEN
];
2727 LoadStringW(hInstance
, id
, buf
, sizeof(buf
) / sizeof(buf
[0]));
2728 add_field_and_value_to_list(hwnd
, data
, buf
, value
, create
, param
);
2734 field_format_func format
;
2735 create_detailed_value_func create_detailed_value
;
2738 static void add_v1_field(HWND hwnd
, struct detail_data
*data
,
2739 const struct v1_field
*field
)
2741 WCHAR
*val
= field
->format(data
->pCertViewInfo
->pCertContext
);
2745 add_string_id_and_value_to_list(hwnd
, data
, field
->id
, val
,
2746 field
->create_detailed_value
, NULL
);
2747 HeapFree(GetProcessHeap(), 0, val
);
2751 static const struct v1_field v1_fields
[] = {
2752 { IDS_FIELD_VERSION
, field_format_version
, NULL
},
2753 { IDS_FIELD_SERIAL_NUMBER
, field_format_serial_number
, NULL
},
2754 { IDS_FIELD_ISSUER
, field_format_issuer
, field_format_detailed_issuer
},
2755 { IDS_FIELD_VALID_FROM
, field_format_from_date
, NULL
},
2756 { IDS_FIELD_VALID_TO
, field_format_to_date
, NULL
},
2757 { IDS_FIELD_SUBJECT
, field_format_subject
, field_format_detailed_subject
},
2758 { IDS_FIELD_PUBLIC_KEY
, field_format_public_key
,
2759 field_format_detailed_public_key
}
2762 static void add_v1_fields(HWND hwnd
, struct detail_data
*data
)
2765 PCCERT_CONTEXT cert
= data
->pCertViewInfo
->pCertContext
;
2767 /* The last item in v1_fields is the public key, which is not in the loop
2768 * because it's a special case.
2770 for (i
= 0; i
< sizeof(v1_fields
) / sizeof(v1_fields
[0]) - 1; i
++)
2771 add_v1_field(hwnd
, data
, &v1_fields
[i
]);
2772 if (cert
->pCertInfo
->SubjectPublicKeyInfo
.PublicKey
.cbData
)
2773 add_v1_field(hwnd
, data
, &v1_fields
[i
]);
2776 static WCHAR
*crypt_format_extension(PCERT_EXTENSION ext
, DWORD formatStrType
)
2781 if (CryptFormatObject(X509_ASN_ENCODING
, 0, formatStrType
, NULL
,
2782 ext
->pszObjId
, ext
->Value
.pbData
, ext
->Value
.cbData
, NULL
, &size
))
2784 str
= HeapAlloc(GetProcessHeap(), 0, size
);
2785 CryptFormatObject(X509_ASN_ENCODING
, 0, formatStrType
, NULL
,
2786 ext
->pszObjId
, ext
->Value
.pbData
, ext
->Value
.cbData
, str
, &size
);
2791 static WCHAR
*field_format_extension_hex_with_ascii(PCERT_EXTENSION ext
)
2795 if (ext
->Value
.cbData
)
2797 /* The output is formatted as:
2798 * <hex bytes> <ascii bytes>\n
2799 * where <hex bytes> is a string of up to 8 bytes, output as %02x,
2800 * and <ascii bytes> is the ASCII equivalent of each byte, or '.' if
2801 * the byte is not printable.
2802 * So, for example, the extension value consisting of the following
2804 * 0x30,0x14,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x03,
2805 * 0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67
2807 * 30 14 31 12 30 10 06 03 0.1.0...
2808 * 55 04 03 13 09 4a 75 61 U....Jua
2809 * 6e 20 4c 61 6e 67 n Lang
2810 * The allocation size therefore requires:
2811 * - 4 characters per character in an 8-byte line
2812 * (2 for the hex format, one for the space, one for the ASCII value)
2813 * - 3 more characters per 8-byte line (two spaces and a newline)
2814 * - 1 character for the terminating nul
2815 * FIXME: should use a fixed-width font for this
2817 DWORD lines
= (ext
->Value
.cbData
+ 7) / 8;
2819 str
= HeapAlloc(GetProcessHeap(), 0,
2820 (lines
* 8 * 4 + lines
* 3 + 1) * sizeof(WCHAR
));
2823 static const WCHAR fmt
[] = { '%','0','2','x',' ',0 };
2827 for (i
= 0, ptr
= str
; i
< ext
->Value
.cbData
; i
+= 8)
2829 /* Output as hex bytes first */
2830 for (j
= i
; j
< min(i
+ 8, ext
->Value
.cbData
); j
++, ptr
+= 3)
2831 sprintfW(ptr
, fmt
, ext
->Value
.pbData
[j
]);
2832 /* Pad the hex output with spaces for alignment */
2833 if (j
== ext
->Value
.cbData
&& j
% 8)
2835 static const WCHAR pad
[] = { ' ',' ',' ' };
2837 for (; j
% 8; j
++, ptr
+= sizeof(pad
) / sizeof(pad
[0]))
2838 memcpy(ptr
, pad
, sizeof(pad
));
2840 /* The last sprintfW included a space, so just insert one
2841 * more space between the hex bytes and the ASCII output
2844 /* Output as ASCII bytes */
2845 for (j
= i
; j
< min(i
+ 8, ext
->Value
.cbData
); j
++, ptr
++)
2847 if (isprintW(ext
->Value
.pbData
[j
]) &&
2848 !isspaceW(ext
->Value
.pbData
[j
]))
2849 *ptr
= ext
->Value
.pbData
[j
];
2861 static WCHAR
*field_format_detailed_extension(PCCERT_CONTEXT cert
, void *param
)
2863 PCERT_EXTENSION ext
= param
;
2864 LPWSTR str
= crypt_format_extension(ext
,
2865 CRYPT_FORMAT_STR_MULTI_LINE
| CRYPT_FORMAT_STR_NO_HEX
);
2868 str
= field_format_extension_hex_with_ascii(ext
);
2872 static void add_cert_extension_detail(HWND hwnd
, struct detail_data
*data
,
2873 PCERT_EXTENSION ext
)
2875 PCCRYPT_OID_INFO oidInfo
= CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY
,
2877 LPWSTR val
= crypt_format_extension(ext
, 0);
2880 add_field_and_value_to_list(hwnd
, data
, (LPWSTR
)oidInfo
->pwszName
,
2881 val
, field_format_detailed_extension
, ext
);
2884 DWORD len
= strlen(ext
->pszObjId
);
2885 LPWSTR oidW
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2891 for (i
= 0; i
<= len
; i
++)
2892 oidW
[i
] = ext
->pszObjId
[i
];
2893 add_field_and_value_to_list(hwnd
, data
, oidW
, val
,
2894 field_format_detailed_extension
, ext
);
2895 HeapFree(GetProcessHeap(), 0, oidW
);
2898 HeapFree(GetProcessHeap(), 0, val
);
2901 static void add_all_extensions(HWND hwnd
, struct detail_data
*data
)
2904 PCCERT_CONTEXT cert
= data
->pCertViewInfo
->pCertContext
;
2906 for (i
= 0; i
< cert
->pCertInfo
->cExtension
; i
++)
2907 add_cert_extension_detail(hwnd
, data
, &cert
->pCertInfo
->rgExtension
[i
]);
2910 static void add_critical_extensions(HWND hwnd
, struct detail_data
*data
)
2913 PCCERT_CONTEXT cert
= data
->pCertViewInfo
->pCertContext
;
2915 for (i
= 0; i
< cert
->pCertInfo
->cExtension
; i
++)
2916 if (cert
->pCertInfo
->rgExtension
[i
].fCritical
)
2917 add_cert_extension_detail(hwnd
, data
,
2918 &cert
->pCertInfo
->rgExtension
[i
]);
2921 typedef WCHAR
* (*prop_to_value_func
)(void *pb
, DWORD cb
);
2923 struct prop_id_to_string_id
2927 BOOL prop_is_string
;
2928 prop_to_value_func prop_to_value
;
2931 static WCHAR
*format_enhanced_key_usage_value(void *pb
, DWORD cb
)
2935 ext
.pszObjId
= (LPSTR
)X509_ENHANCED_KEY_USAGE
;
2936 ext
.fCritical
= FALSE
;
2937 ext
.Value
.pbData
= pb
;
2938 ext
.Value
.cbData
= cb
;
2939 return crypt_format_extension(&ext
, 0);
2942 /* Logically the access state should also be checked, and IDC_EDITPROPERTIES
2943 * disabled for read-only certificates, but native doesn't appear to do that.
2945 static const struct prop_id_to_string_id prop_id_map
[] = {
2946 { CERT_HASH_PROP_ID
, IDS_PROP_HASH
, FALSE
, format_hex_string
},
2947 { CERT_FRIENDLY_NAME_PROP_ID
, IDS_PROP_FRIENDLY_NAME
, TRUE
, NULL
},
2948 { CERT_DESCRIPTION_PROP_ID
, IDS_PROP_DESCRIPTION
, TRUE
, NULL
},
2949 { CERT_ENHKEY_USAGE_PROP_ID
, IDS_PROP_ENHKEY_USAGE
, FALSE
,
2950 format_enhanced_key_usage_value
},
2953 static void add_properties(HWND hwnd
, struct detail_data
*data
)
2956 PCCERT_CONTEXT cert
= data
->pCertViewInfo
->pCertContext
;
2958 for (i
= 0; i
< sizeof(prop_id_map
) / sizeof(prop_id_map
[0]); i
++)
2962 if (CertGetCertificateContextProperty(cert
, prop_id_map
[i
].prop
, NULL
,
2968 /* FIXME: MS adds a separate value for the signature hash
2971 pb
= HeapAlloc(GetProcessHeap(), 0, cb
);
2974 if (CertGetCertificateContextProperty(cert
,
2975 prop_id_map
[i
].prop
, pb
, &cb
))
2977 if (prop_id_map
[i
].prop_is_string
)
2980 /* Don't double-free pb */
2984 val
= prop_id_map
[i
].prop_to_value(pb
, cb
);
2986 HeapFree(GetProcessHeap(), 0, pb
);
2988 add_string_id_and_value_to_list(hwnd
, data
, prop_id_map
[i
].id
, val
,
2994 static void add_all_fields(HWND hwnd
, struct detail_data
*data
)
2996 add_v1_fields(hwnd
, data
);
2997 add_all_extensions(hwnd
, data
);
2998 add_properties(hwnd
, data
);
3001 struct selection_list_item
3004 add_fields_func add
;
3007 const struct selection_list_item listItems
[] = {
3008 { IDS_FIELDS_ALL
, add_all_fields
},
3009 { IDS_FIELDS_V1
, add_v1_fields
},
3010 { IDS_FIELDS_EXTENSIONS
, add_all_extensions
},
3011 { IDS_FIELDS_CRITICAL_EXTENSIONS
, add_critical_extensions
},
3012 { IDS_FIELDS_PROPERTIES
, add_properties
},
3015 static void create_show_list(HWND hwnd
, struct detail_data
*data
)
3017 HWND cb
= GetDlgItem(hwnd
, IDC_DETAIL_SELECT
);
3018 WCHAR buf
[MAX_STRING_LEN
];
3021 for (i
= 0; i
< sizeof(listItems
) / sizeof(listItems
[0]); i
++)
3025 LoadStringW(hInstance
, listItems
[i
].id
, buf
,
3026 sizeof(buf
) / sizeof(buf
[0]));
3027 index
= SendMessageW(cb
, CB_INSERTSTRING
, -1, (LPARAM
)buf
);
3028 SendMessageW(cb
, CB_SETITEMDATA
, index
, (LPARAM
)data
);
3030 SendMessageW(cb
, CB_SETCURSEL
, 0, 0);
3033 static void create_listview_columns(HWND hwnd
)
3035 HWND lv
= GetDlgItem(hwnd
, IDC_DETAIL_LIST
);
3037 WCHAR buf
[MAX_STRING_LEN
];
3040 SendMessageW(lv
, LVM_SETEXTENDEDLISTVIEWSTYLE
, 0, LVS_EX_FULLROWSELECT
);
3041 GetWindowRect(lv
, &rc
);
3042 LoadStringW(hInstance
, IDS_FIELD
, buf
, sizeof(buf
) / sizeof(buf
[0]));
3043 column
.mask
= LVCF_WIDTH
| LVCF_TEXT
;
3044 column
.cx
= (rc
.right
- rc
.left
) / 2 - 2;
3045 column
.pszText
= buf
;
3046 SendMessageW(lv
, LVM_INSERTCOLUMNW
, 0, (LPARAM
)&column
);
3047 LoadStringW(hInstance
, IDS_VALUE
, buf
, sizeof(buf
) / sizeof(buf
[0]));
3048 SendMessageW(lv
, LVM_INSERTCOLUMNW
, 1, (LPARAM
)&column
);
3051 static void set_fields_selection(HWND hwnd
, struct detail_data
*data
, int sel
)
3053 HWND list
= GetDlgItem(hwnd
, IDC_DETAIL_LIST
);
3055 if (sel
>= 0 && sel
< sizeof(listItems
) / sizeof(listItems
[0]))
3057 SendMessageW(list
, LVM_DELETEALLITEMS
, 0, 0);
3058 listItems
[sel
].add(list
, data
);
3062 static void create_cert_details_list(HWND hwnd
, struct detail_data
*data
)
3064 create_show_list(hwnd
, data
);
3065 create_listview_columns(hwnd
);
3066 set_fields_selection(hwnd
, data
, 0);
3069 static void add_purpose(HWND hwnd
, LPCSTR oid
)
3071 HWND lv
= GetDlgItem(hwnd
, IDC_CERTIFICATE_USAGES
);
3072 PCRYPT_OID_INFO info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
3073 sizeof(CRYPT_OID_INFO
));
3077 char *oidCopy
= HeapAlloc(GetProcessHeap(), 0, strlen(oid
) + 1);
3083 strcpy(oidCopy
, oid
);
3084 info
->cbSize
= sizeof(CRYPT_OID_INFO
);
3085 info
->pszOID
= oidCopy
;
3086 item
.mask
= LVIF_TEXT
| LVIF_STATE
| LVIF_PARAM
;
3087 item
.state
= INDEXTOSTATEIMAGEMASK(CheckBitmapIndexChecked
);
3088 item
.stateMask
= LVIS_STATEIMAGEMASK
;
3089 item
.iItem
= SendMessageW(lv
, LVM_GETITEMCOUNT
, 0, 0);
3091 item
.lParam
= (LPARAM
)info
;
3092 item
.pszText
= oidCopy
;
3093 SendMessageA(lv
, LVM_INSERTITEMA
, 0, (LPARAM
)&item
);
3096 HeapFree(GetProcessHeap(), 0, info
);
3100 static BOOL
is_valid_oid(LPCSTR oid
)
3104 if (oid
[0] != '0' && oid
[0] != '1' && oid
[0] != '2')
3106 else if (oid
[1] != '.')
3113 BOOL expectNum
= TRUE
;
3115 for (ptr
= oid
+ 2, ret
= TRUE
; ret
&& *ptr
; ptr
++)
3121 else if (*(ptr
+ 1) == '.')
3128 else if (!(*(ptr
+ 1)))
3138 static BOOL
is_oid_in_list(HWND hwnd
, LPCSTR oid
)
3140 return find_oid_in_list(GetDlgItem(hwnd
, IDC_CERTIFICATE_USAGES
), oid
)
3144 #define MAX_PURPOSE 255
3146 static LRESULT CALLBACK
add_purpose_dlg_proc(HWND hwnd
, UINT msg
,
3147 WPARAM wp
, LPARAM lp
)
3150 char buf
[MAX_PURPOSE
+ 1];
3155 SendMessageW(GetDlgItem(hwnd
, IDC_NEW_PURPOSE
), EM_SETLIMITTEXT
,
3157 ShowScrollBar(GetDlgItem(hwnd
, IDC_NEW_PURPOSE
), SB_VERT
, FALSE
);
3158 SetWindowLongPtrW(hwnd
, DWLP_USER
, lp
);
3164 if (LOWORD(wp
) == IDC_NEW_PURPOSE
)
3166 /* Show/hide scroll bar on description depending on how much
3169 HWND description
= GetDlgItem(hwnd
, IDC_NEW_PURPOSE
);
3170 int lines
= SendMessageW(description
, EM_GETLINECOUNT
, 0, 0);
3172 ShowScrollBar(description
, SB_VERT
, lines
> 1);
3179 SendMessageA(GetDlgItem(hwnd
, IDC_NEW_PURPOSE
), WM_GETTEXT
,
3180 sizeof(buf
) / sizeof(buf
[0]), (LPARAM
)buf
);
3183 /* An empty purpose is the same as cancelling */
3184 EndDialog(hwnd
, IDCANCEL
);
3187 else if (!is_valid_oid(buf
))
3189 WCHAR title
[MAX_STRING_LEN
], error
[MAX_STRING_LEN
];
3191 LoadStringW(hInstance
, IDS_CERTIFICATE_PURPOSE_ERROR
, error
,
3192 sizeof(error
) / sizeof(error
[0]));
3193 LoadStringW(hInstance
, IDS_CERTIFICATE_PROPERTIES
, title
,
3194 sizeof(title
) / sizeof(title
[0]));
3195 MessageBoxW(hwnd
, error
, title
, MB_ICONERROR
| MB_OK
);
3197 else if (is_oid_in_list(
3198 (HWND
)GetWindowLongPtrW(hwnd
, DWLP_USER
), buf
))
3200 WCHAR title
[MAX_STRING_LEN
], error
[MAX_STRING_LEN
];
3202 LoadStringW(hInstance
, IDS_CERTIFICATE_PURPOSE_EXISTS
,
3203 error
, sizeof(error
) / sizeof(error
[0]));
3204 LoadStringW(hInstance
, IDS_CERTIFICATE_PROPERTIES
, title
,
3205 sizeof(title
) / sizeof(title
[0]));
3206 MessageBoxW(hwnd
, error
, title
, MB_ICONEXCLAMATION
| MB_OK
);
3210 HWND parent
= (HWND
)GetWindowLongPtrW(hwnd
, DWLP_USER
);
3212 add_purpose(parent
, buf
);
3213 EndDialog(hwnd
, wp
);
3218 EndDialog(hwnd
, wp
);
3229 static WCHAR
*get_cert_property_as_string(PCCERT_CONTEXT cert
, DWORD prop
)
3234 if (CertGetCertificateContextProperty(cert
, prop
, NULL
, &cb
))
3236 name
= HeapAlloc(GetProcessHeap(), 0, cb
);
3239 if (!CertGetCertificateContextProperty(cert
, prop
, name
, &cb
))
3241 HeapFree(GetProcessHeap(), 0, name
);
3249 static void redraw_states(HWND list
, BOOL enabled
)
3251 int items
= SendMessageW(list
, LVM_GETITEMCOUNT
, 0, 0), i
;
3253 for (i
= 0; i
< items
; i
++)
3255 BOOL change
= FALSE
;
3258 state
= SendMessageW(list
, LVM_GETITEMSTATE
, i
, LVIS_STATEIMAGEMASK
);
3259 /* This reverses the INDEXTOSTATEIMAGEMASK shift. There doesn't appear
3260 * to be a handy macro for it.
3265 if (state
== CheckBitmapIndexDisabledChecked
)
3267 state
= CheckBitmapIndexChecked
;
3270 if (state
== CheckBitmapIndexDisabledUnchecked
)
3272 state
= CheckBitmapIndexUnchecked
;
3278 if (state
== CheckBitmapIndexChecked
)
3280 state
= CheckBitmapIndexDisabledChecked
;
3283 if (state
== CheckBitmapIndexUnchecked
)
3285 state
= CheckBitmapIndexDisabledUnchecked
;
3293 item
.state
= INDEXTOSTATEIMAGEMASK(state
);
3294 item
.stateMask
= LVIS_STATEIMAGEMASK
;
3295 SendMessageW(list
, LVM_SETITEMSTATE
, i
, (LPARAM
)&item
);
3301 PurposeEnableAll
= 0,
3303 PurposeEnableSelected
3306 static void select_purposes(HWND hwnd
, PurposeSelection selection
)
3308 HWND lv
= GetDlgItem(hwnd
, IDC_CERTIFICATE_USAGES
);
3312 case PurposeEnableAll
:
3313 case PurposeDisableAll
:
3314 EnableWindow(lv
, FALSE
);
3315 redraw_states(lv
, FALSE
);
3316 EnableWindow(GetDlgItem(hwnd
, IDC_ADD_PURPOSE
), FALSE
);
3318 case PurposeEnableSelected
:
3319 EnableWindow(lv
, TRUE
);
3320 redraw_states(lv
, TRUE
);
3321 EnableWindow(GetDlgItem(hwnd
, IDC_ADD_PURPOSE
), TRUE
);
3325 struct edit_cert_data
3327 PCCERT_CONTEXT cert
;
3328 BOOL
*pfPropertiesChanged
;
3329 HIMAGELIST imageList
;
3332 static void show_cert_usages(HWND hwnd
, struct edit_cert_data
*data
)
3334 PCCERT_CONTEXT cert
= data
->cert
;
3335 HWND lv
= GetDlgItem(hwnd
, IDC_CERTIFICATE_USAGES
);
3336 PCERT_ENHKEY_USAGE usage
;
3340 PurposeSelection purposeSelection
= PurposeEnableAll
;
3342 GetWindowRect(lv
, &rc
);
3343 column
.mask
= LVCF_WIDTH
;
3344 column
.cx
= rc
.right
- rc
.left
;
3345 SendMessageW(lv
, LVM_INSERTCOLUMNW
, 0, (LPARAM
)&column
);
3346 SendMessageW(lv
, LVM_SETIMAGELIST
, LVSIL_STATE
, (LPARAM
)data
->imageList
);
3348 /* Get enhanced key usage. Have to check for a property and an extension
3349 * separately, because CertGetEnhancedKeyUsage will succeed and return an
3350 * empty usage if neither is set. Unfortunately an empty usage implies
3351 * no usage is allowed, so we have to distinguish between the two cases.
3353 if (CertGetEnhancedKeyUsage(cert
, CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG
,
3356 usage
= HeapAlloc(GetProcessHeap(), 0, size
);
3357 if (!CertGetEnhancedKeyUsage(cert
,
3358 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG
, usage
, &size
))
3360 HeapFree(GetProcessHeap(), 0, usage
);
3363 else if (usage
->cUsageIdentifier
)
3364 purposeSelection
= PurposeEnableSelected
;
3366 purposeSelection
= PurposeDisableAll
;
3368 else if (CertGetEnhancedKeyUsage(cert
, CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG
,
3371 usage
= HeapAlloc(GetProcessHeap(), 0, size
);
3372 if (!CertGetEnhancedKeyUsage(cert
,
3373 CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG
, usage
, &size
))
3375 HeapFree(GetProcessHeap(), 0, usage
);
3378 else if (usage
->cUsageIdentifier
)
3379 purposeSelection
= PurposeEnableAll
;
3381 purposeSelection
= PurposeDisableAll
;
3385 purposeSelection
= PurposeEnableAll
;
3392 for (i
= 0; i
< usage
->cUsageIdentifier
; i
++)
3394 PCCRYPT_OID_INFO info
= CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY
,
3395 usage
->rgpszUsageIdentifier
[i
], CRYPT_ENHKEY_USAGE_OID_GROUP_ID
);
3398 add_known_usage(lv
, info
, CheckBitmapIndexDisabledChecked
);
3400 add_purpose(hwnd
, usage
->rgpszUsageIdentifier
[i
]);
3402 HeapFree(GetProcessHeap(), 0, usage
);
3405 add_known_usages_to_list(lv
, CheckBitmapIndexDisabledChecked
);
3406 select_purposes(hwnd
, purposeSelection
);
3407 SendMessageW(GetDlgItem(hwnd
, IDC_ENABLE_ALL_PURPOSES
+ purposeSelection
),
3411 static void set_general_cert_properties(HWND hwnd
, struct edit_cert_data
*data
)
3413 PCCERT_CONTEXT cert
= data
->cert
;
3416 if ((str
= get_cert_property_as_string(cert
, CERT_FRIENDLY_NAME_PROP_ID
)))
3418 SendMessageW(GetDlgItem(hwnd
, IDC_FRIENDLY_NAME
), WM_SETTEXT
, 0,
3420 HeapFree(GetProcessHeap(), 0, str
);
3422 if ((str
= get_cert_property_as_string(cert
, CERT_DESCRIPTION_PROP_ID
)))
3424 SendMessageW(GetDlgItem(hwnd
, IDC_DESCRIPTION
), WM_SETTEXT
, 0,
3426 HeapFree(GetProcessHeap(), 0, str
);
3428 show_cert_usages(hwnd
, data
);
3431 static void set_cert_string_property(PCCERT_CONTEXT cert
, DWORD prop
,
3434 if (str
&& strlenW(str
))
3436 CRYPT_DATA_BLOB blob
;
3438 blob
.pbData
= (BYTE
*)str
;
3439 blob
.cbData
= (strlenW(str
) + 1) * sizeof(WCHAR
);
3440 CertSetCertificateContextProperty(cert
, prop
, 0, &blob
);
3443 CertSetCertificateContextProperty(cert
, prop
, 0, NULL
);
3446 #define WM_REFRESH_VIEW WM_USER + 0
3448 static BOOL CALLBACK
refresh_propsheet_pages(HWND hwnd
, LPARAM lParam
)
3450 if ((GetClassLongW(hwnd
, GCW_ATOM
) == WC_DIALOG
))
3451 SendMessageW(hwnd
, WM_REFRESH_VIEW
, 0, 0);
3455 #define MAX_FRIENDLY_NAME 40
3456 #define MAX_DESCRIPTION 255
3458 static void apply_general_changes(HWND hwnd
)
3460 WCHAR buf
[MAX_DESCRIPTION
+ 1];
3461 struct edit_cert_data
*data
=
3462 (struct edit_cert_data
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
3464 SendMessageW(GetDlgItem(hwnd
, IDC_FRIENDLY_NAME
), WM_GETTEXT
,
3465 sizeof(buf
) / sizeof(buf
[0]), (LPARAM
)buf
);
3466 set_cert_string_property(data
->cert
, CERT_FRIENDLY_NAME_PROP_ID
, buf
);
3467 SendMessageW(GetDlgItem(hwnd
, IDC_DESCRIPTION
), WM_GETTEXT
,
3468 sizeof(buf
) / sizeof(buf
[0]), (LPARAM
)buf
);
3469 set_cert_string_property(data
->cert
, CERT_DESCRIPTION_PROP_ID
, buf
);
3470 if (IsDlgButtonChecked(hwnd
, IDC_ENABLE_ALL_PURPOSES
))
3472 /* Setting a NULL usage removes the enhanced key usage property. */
3473 CertSetEnhancedKeyUsage(data
->cert
, NULL
);
3475 else if (IsDlgButtonChecked(hwnd
, IDC_DISABLE_ALL_PURPOSES
))
3477 CERT_ENHKEY_USAGE usage
= { 0, NULL
};
3479 CertSetEnhancedKeyUsage(data
->cert
, &usage
);
3481 else if (IsDlgButtonChecked(hwnd
, IDC_ENABLE_SELECTED_PURPOSES
))
3483 HWND lv
= GetDlgItem(hwnd
, IDC_CERTIFICATE_USAGES
);
3484 CERT_ENHKEY_USAGE usage
= { 0, NULL
};
3485 int purposes
= SendMessageW(lv
, LVM_GETITEMCOUNT
, 0, 0), i
;
3488 item
.mask
= LVIF_STATE
| LVIF_PARAM
;
3490 item
.stateMask
= LVIS_STATEIMAGEMASK
;
3491 for (i
= 0; i
< purposes
; i
++)
3494 if (SendMessageW(lv
, LVM_GETITEMW
, 0, (LPARAM
)&item
))
3496 int state
= item
.state
>> 12;
3498 if (state
== CheckBitmapIndexChecked
)
3500 CRYPT_OID_INFO
*info
= (CRYPT_OID_INFO
*)item
.lParam
;
3502 if (usage
.cUsageIdentifier
)
3503 usage
.rgpszUsageIdentifier
=
3504 HeapReAlloc(GetProcessHeap(), 0,
3505 usage
.rgpszUsageIdentifier
,
3506 (usage
.cUsageIdentifier
+ 1) * sizeof(LPSTR
));
3508 usage
.rgpszUsageIdentifier
=
3509 HeapAlloc(GetProcessHeap(), 0, sizeof(LPSTR
));
3510 if (usage
.rgpszUsageIdentifier
)
3511 usage
.rgpszUsageIdentifier
[usage
.cUsageIdentifier
++] =
3512 (LPSTR
)info
->pszOID
;
3516 CertSetEnhancedKeyUsage(data
->cert
, &usage
);
3517 HeapFree(GetProcessHeap(), 0, usage
.rgpszUsageIdentifier
);
3519 EnumChildWindows(GetParent(GetParent(hwnd
)), refresh_propsheet_pages
, 0);
3520 if (data
->pfPropertiesChanged
)
3521 *data
->pfPropertiesChanged
= TRUE
;
3524 static LRESULT CALLBACK
cert_properties_general_dlg_proc(HWND hwnd
, UINT msg
,
3525 WPARAM wp
, LPARAM lp
)
3527 PROPSHEETPAGEW
*page
;
3529 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd
, msg
, wp
, lp
);
3535 HWND description
= GetDlgItem(hwnd
, IDC_DESCRIPTION
);
3536 struct detail_data
*detailData
;
3537 struct edit_cert_data
*editData
;
3539 page
= (PROPSHEETPAGEW
*)lp
;
3540 detailData
= (struct detail_data
*)page
->lParam
;
3541 SendMessageW(GetDlgItem(hwnd
, IDC_FRIENDLY_NAME
), EM_SETLIMITTEXT
,
3542 MAX_FRIENDLY_NAME
, 0);
3543 SendMessageW(description
, EM_SETLIMITTEXT
, MAX_DESCRIPTION
, 0);
3544 ShowScrollBar(description
, SB_VERT
, FALSE
);
3545 editData
= HeapAlloc(GetProcessHeap(), 0,
3546 sizeof(struct edit_cert_data
));
3549 editData
->imageList
= ImageList_Create(16, 16,
3550 ILC_COLOR4
| ILC_MASK
, 4, 0);
3551 if (editData
->imageList
)
3554 COLORREF backColor
= RGB(255, 0, 255);
3556 bmp
= LoadBitmapW(hInstance
, MAKEINTRESOURCEW(IDB_CHECKS
));
3557 ImageList_AddMasked(editData
->imageList
, bmp
, backColor
);
3559 ImageList_SetBkColor(editData
->imageList
, CLR_NONE
);
3561 editData
->cert
= detailData
->pCertViewInfo
->pCertContext
;
3562 editData
->pfPropertiesChanged
= detailData
->pfPropertiesChanged
;
3563 SetWindowLongPtrW(hwnd
, DWLP_USER
, (LPARAM
)editData
);
3564 set_general_cert_properties(hwnd
, editData
);
3570 NMHDR
*hdr
= (NMHDR
*)lp
;
3576 nm
= (NMITEMACTIVATE
*)lp
;
3577 toggle_usage(hwnd
, nm
->iItem
);
3578 SendMessageW(GetParent(hwnd
), PSM_CHANGED
, (WPARAM
)hwnd
, 0);
3581 apply_general_changes(hwnd
);
3590 SendMessageW(GetParent(hwnd
), PSM_CHANGED
, (WPARAM
)hwnd
, 0);
3591 if (LOWORD(wp
) == IDC_DESCRIPTION
)
3593 /* Show/hide scroll bar on description depending on how much
3596 HWND description
= GetDlgItem(hwnd
, IDC_DESCRIPTION
);
3597 int lines
= SendMessageW(description
, EM_GETLINECOUNT
, 0, 0);
3599 ShowScrollBar(description
, SB_VERT
, lines
> 1);
3605 case IDC_ADD_PURPOSE
:
3606 if (DialogBoxParamW(hInstance
,
3607 MAKEINTRESOURCEW(IDD_ADD_CERT_PURPOSE
), hwnd
,
3608 add_purpose_dlg_proc
, (LPARAM
)hwnd
) == IDOK
)
3609 SendMessageW(GetParent(hwnd
), PSM_CHANGED
, (WPARAM
)hwnd
, 0);
3611 case IDC_ENABLE_ALL_PURPOSES
:
3612 case IDC_DISABLE_ALL_PURPOSES
:
3613 case IDC_ENABLE_SELECTED_PURPOSES
:
3614 SendMessageW(GetParent(hwnd
), PSM_CHANGED
, (WPARAM
)hwnd
, 0);
3615 select_purposes(hwnd
, LOWORD(wp
) - IDC_ENABLE_ALL_PURPOSES
);
3625 static UINT CALLBACK
cert_properties_general_callback(HWND hwnd
, UINT msg
,
3626 PROPSHEETPAGEW
*page
)
3630 struct edit_cert_data
*data
;
3635 lv
= GetDlgItem(hwnd
, IDC_CERTIFICATE_USAGES
);
3636 cItem
= SendMessageW(lv
, LVM_GETITEMCOUNT
, 0, 0);
3637 for (i
= 0; i
< cItem
; i
++)
3641 item
.mask
= LVIF_PARAM
;
3644 if (SendMessageW(lv
, LVM_GETITEMW
, 0, (LPARAM
)&item
) && item
.lParam
)
3646 PCRYPT_OID_INFO info
= (PCRYPT_OID_INFO
)item
.lParam
;
3648 if (info
->cbSize
== sizeof(CRYPT_OID_INFO
) && !info
->dwGroupId
)
3650 HeapFree(GetProcessHeap(), 0, (LPSTR
)info
->pszOID
);
3651 HeapFree(GetProcessHeap(), 0, info
);
3655 data
= (struct edit_cert_data
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
3658 ImageList_Destroy(data
->imageList
);
3659 HeapFree(GetProcessHeap(), 0, data
);
3666 static void show_edit_cert_properties_dialog(HWND parent
,
3667 struct detail_data
*data
)
3669 PROPSHEETHEADERW hdr
;
3670 PROPSHEETPAGEW page
; /* FIXME: need to add a cross-certificate page */
3672 TRACE("(%p)\n", data
);
3674 memset(&page
, 0, sizeof(PROPSHEETPAGEW
));
3675 page
.dwSize
= sizeof(page
);
3676 page
.dwFlags
= PSP_USECALLBACK
;
3677 page
.pfnCallback
= cert_properties_general_callback
;
3678 page
.hInstance
= hInstance
;
3679 page
.u
.pszTemplate
= MAKEINTRESOURCEW(IDD_CERT_PROPERTIES_GENERAL
);
3680 page
.pfnDlgProc
= cert_properties_general_dlg_proc
;
3681 page
.lParam
= (LPARAM
)data
;
3683 memset(&hdr
, 0, sizeof(hdr
));
3684 hdr
.dwSize
= sizeof(hdr
);
3685 hdr
.hwndParent
= parent
;
3686 hdr
.dwFlags
= PSH_PROPSHEETPAGE
;
3687 hdr
.hInstance
= hInstance
;
3688 hdr
.pszCaption
= MAKEINTRESOURCEW(IDS_CERTIFICATE_PROPERTIES
);
3689 hdr
.u3
.ppsp
= &page
;
3691 PropertySheetW(&hdr
);
3694 static void free_detail_fields(struct detail_data
*data
)
3698 for (i
= 0; i
< data
->cFields
; i
++)
3699 HeapFree(GetProcessHeap(), 0, data
->fields
[i
].detailed_value
);
3700 HeapFree(GetProcessHeap(), 0, data
->fields
);
3701 data
->fields
= NULL
;
3705 static void refresh_details_view(HWND hwnd
)
3707 HWND cb
= GetDlgItem(hwnd
, IDC_DETAIL_SELECT
);
3709 struct detail_data
*data
;
3711 curSel
= SendMessageW(cb
, CB_GETCURSEL
, 0, 0);
3712 /* Actually, any index will do, since they all store the same data value */
3713 data
= (struct detail_data
*)SendMessageW(cb
, CB_GETITEMDATA
, curSel
, 0);
3714 free_detail_fields(data
);
3715 set_fields_selection(hwnd
, data
, curSel
);
3718 static LRESULT CALLBACK
detail_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wp
,
3721 PROPSHEETPAGEW
*page
;
3722 struct detail_data
*data
;
3724 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd
, msg
, wp
, lp
);
3729 page
= (PROPSHEETPAGEW
*)lp
;
3730 data
= (struct detail_data
*)page
->lParam
;
3731 create_cert_details_list(hwnd
, data
);
3732 if (!(data
->pCertViewInfo
->dwFlags
& CRYPTUI_ENABLE_EDITPROPERTIES
))
3733 EnableWindow(GetDlgItem(hwnd
, IDC_EDITPROPERTIES
), FALSE
);
3734 if (data
->pCertViewInfo
->dwFlags
& CRYPTUI_DISABLE_EXPORT
)
3735 EnableWindow(GetDlgItem(hwnd
, IDC_EXPORT
), FALSE
);
3740 HWND list
= GetDlgItem(hwnd
, IDC_DETAIL_LIST
);
3742 nm
= (NMITEMACTIVATE
*)lp
;
3743 if (nm
->hdr
.hwndFrom
== list
&& nm
->uNewState
& LVN_ITEMACTIVATE
3744 && nm
->hdr
.code
== LVN_ITEMCHANGED
)
3746 data
= (struct detail_data
*)nm
->lParam
;
3747 if (nm
->iItem
>= 0 && data
&& nm
->iItem
< data
->cFields
)
3749 WCHAR buf
[MAX_STRING_LEN
], *val
= NULL
;
3750 HWND valueCtl
= GetDlgItem(hwnd
, IDC_DETAIL_VALUE
);
3752 if (data
->fields
[nm
->iItem
].create
)
3753 val
= data
->fields
[nm
->iItem
].create(
3754 data
->pCertViewInfo
->pCertContext
,
3755 data
->fields
[nm
->iItem
].param
);
3761 item
.cchTextMax
= sizeof(buf
) / sizeof(buf
[0]);
3762 item
.mask
= LVIF_TEXT
;
3764 item
.iItem
= nm
->iItem
;
3766 res
= SendMessageW(list
, LVM_GETITEMW
, 0, (LPARAM
)&item
);
3770 /* Select all the text in the control, the next update will
3773 SendMessageW(valueCtl
, EM_SETSEL
, 0, -1);
3774 add_unformatted_text_to_control(valueCtl
, val
,
3775 val
? strlenW(val
) : 0);
3777 HeapFree(GetProcessHeap(), 0, val
);
3787 HWND cb
= GetDlgItem(hwnd
, IDC_DETAIL_SELECT
);
3788 CRYPTUI_WIZ_EXPORT_INFO info
;
3790 data
= (struct detail_data
*)SendMessageW(cb
, CB_GETITEMDATA
, 0, 0);
3791 info
.dwSize
= sizeof(info
);
3792 info
.pwszExportFileName
= NULL
;
3793 info
.dwSubjectChoice
= CRYPTUI_WIZ_EXPORT_CERT_CONTEXT
;
3794 info
.u
.pCertContext
= data
->pCertViewInfo
->pCertContext
;
3796 CryptUIWizExport(0, hwnd
, NULL
, &info
, NULL
);
3799 case IDC_EDITPROPERTIES
:
3801 HWND cb
= GetDlgItem(hwnd
, IDC_DETAIL_SELECT
);
3804 curSel
= SendMessageW(cb
, CB_GETCURSEL
, 0, 0);
3805 /* Actually, any index will do, since they all store the same
3808 data
= (struct detail_data
*)SendMessageW(cb
, CB_GETITEMDATA
,
3810 show_edit_cert_properties_dialog(GetParent(hwnd
), data
);
3813 case ((CBN_SELCHANGE
<< 16) | IDC_DETAIL_SELECT
):
3814 refresh_details_view(hwnd
);
3818 case WM_REFRESH_VIEW
:
3819 refresh_details_view(hwnd
);
3825 static UINT CALLBACK
detail_callback(HWND hwnd
, UINT msg
,
3826 PROPSHEETPAGEW
*page
)
3828 struct detail_data
*data
;
3833 data
= (struct detail_data
*)page
->lParam
;
3834 free_detail_fields(data
);
3835 HeapFree(GetProcessHeap(), 0, data
);
3841 static BOOL
init_detail_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
,
3842 BOOL
*pfPropertiesChanged
, PROPSHEETPAGEW
*page
)
3845 struct detail_data
*data
= HeapAlloc(GetProcessHeap(), 0,
3846 sizeof(struct detail_data
));
3850 data
->pCertViewInfo
= pCertViewInfo
;
3851 data
->pfPropertiesChanged
= pfPropertiesChanged
;
3853 data
->fields
= NULL
;
3854 memset(page
, 0, sizeof(PROPSHEETPAGEW
));
3855 page
->dwSize
= sizeof(PROPSHEETPAGEW
);
3856 page
->dwFlags
= PSP_USECALLBACK
;
3857 page
->pfnCallback
= detail_callback
;
3858 page
->hInstance
= hInstance
;
3859 page
->u
.pszTemplate
= MAKEINTRESOURCEW(IDD_DETAIL
);
3860 page
->pfnDlgProc
= detail_dlg_proc
;
3861 page
->lParam
= (LPARAM
)data
;
3869 struct hierarchy_data
3871 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
;
3872 HIMAGELIST imageList
;
3876 static LPARAM
index_to_lparam(struct hierarchy_data
*data
, DWORD index
)
3878 CRYPT_PROVIDER_SGNR
*provSigner
= WTHelperGetProvSignerFromChain(
3879 (CRYPT_PROVIDER_DATA
*)data
->pCertViewInfo
->u
.pCryptProviderData
,
3880 data
->pCertViewInfo
->idxSigner
, data
->pCertViewInfo
->fCounterSigner
,
3881 data
->pCertViewInfo
->idxCounterSigner
);
3883 /* Takes advantage of the fact that a pointer is 32-bit aligned, and
3884 * therefore always even.
3886 if (index
== provSigner
->csCertChain
- 1)
3887 return (LPARAM
)data
;
3888 return index
<< 1 | 1;
3891 static inline DWORD
lparam_to_index(struct hierarchy_data
*data
, LPARAM lp
)
3893 CRYPT_PROVIDER_SGNR
*provSigner
= WTHelperGetProvSignerFromChain(
3894 (CRYPT_PROVIDER_DATA
*)data
->pCertViewInfo
->u
.pCryptProviderData
,
3895 data
->pCertViewInfo
->idxSigner
, data
->pCertViewInfo
->fCounterSigner
,
3896 data
->pCertViewInfo
->idxCounterSigner
);
3899 return provSigner
->csCertChain
- 1;
3903 static struct hierarchy_data
*get_hierarchy_data_from_tree_item(HWND tree
,
3906 struct hierarchy_data
*data
= NULL
;
3907 HTREEITEM root
= NULL
;
3910 HTREEITEM parent
= (HTREEITEM
)SendMessageW(tree
, TVM_GETNEXTITEM
,
3911 TVGN_PARENT
, (LPARAM
)hItem
);
3921 item
.mask
= TVIF_PARAM
;
3923 SendMessageW(tree
, TVM_GETITEMW
, 0, (LPARAM
)&item
);
3924 data
= (struct hierarchy_data
*)item
.lParam
;
3929 static WCHAR
*get_cert_display_name(PCCERT_CONTEXT cert
)
3931 WCHAR
*name
= get_cert_property_as_string(cert
, CERT_FRIENDLY_NAME_PROP_ID
);
3934 name
= get_cert_name_string(cert
, CERT_NAME_SIMPLE_DISPLAY_TYPE
, 0);
3938 static void show_cert_chain(HWND hwnd
, struct hierarchy_data
*data
)
3940 HWND tree
= GetDlgItem(hwnd
, IDC_CERTPATH
);
3941 CRYPT_PROVIDER_SGNR
*provSigner
= WTHelperGetProvSignerFromChain(
3942 (CRYPT_PROVIDER_DATA
*)data
->pCertViewInfo
->u
.pCryptProviderData
,
3943 data
->pCertViewInfo
->idxSigner
, data
->pCertViewInfo
->fCounterSigner
,
3944 data
->pCertViewInfo
->idxCounterSigner
);
3946 HTREEITEM parent
= NULL
;
3948 SendMessageW(tree
, TVM_SETIMAGELIST
, TVSIL_NORMAL
, (LPARAM
)data
->imageList
);
3949 for (i
= provSigner
->csCertChain
; i
; i
--)
3953 name
= get_cert_display_name(provSigner
->pasCertChain
[i
- 1].pCert
);
3956 TVINSERTSTRUCTW tvis
;
3958 tvis
.hParent
= parent
;
3959 tvis
.hInsertAfter
= TVI_LAST
;
3960 tvis
.u
.item
.mask
= TVIF_TEXT
| TVIF_STATE
| TVIF_IMAGE
|
3961 TVIF_SELECTEDIMAGE
| TVIF_PARAM
;
3962 tvis
.u
.item
.pszText
= name
;
3963 tvis
.u
.item
.state
= TVIS_EXPANDED
;
3964 tvis
.u
.item
.stateMask
= TVIS_EXPANDED
;
3966 (provSigner
->pChainContext
->TrustStatus
.dwErrorStatus
&
3967 CERT_TRUST_IS_PARTIAL_CHAIN
))
3969 /* The root of the chain has a special case: if the chain is
3970 * a partial chain, the icon is a warning icon rather than an
3973 tvis
.u
.item
.iImage
= 2;
3975 else if (provSigner
->pasCertChain
[i
- 1].pChainElement
->TrustStatus
.
3977 tvis
.u
.item
.iImage
= 0;
3979 tvis
.u
.item
.iImage
= 1;
3980 tvis
.u
.item
.iSelectedImage
= tvis
.u
.item
.iImage
;
3981 tvis
.u
.item
.lParam
= index_to_lparam(data
, i
- 1);
3982 parent
= (HTREEITEM
)SendMessageW(tree
, TVM_INSERTITEMW
, 0,
3984 HeapFree(GetProcessHeap(), 0, name
);
3989 static void set_certificate_status(HWND hwnd
, CRYPT_PROVIDER_CERT
*cert
)
3991 /* Select all the text in the control, the next update will replace it */
3992 SendMessageW(hwnd
, EM_SETSEL
, 0, -1);
3993 /* Set the highest priority error messages first. */
3994 if (!(cert
->dwConfidence
& CERT_CONFIDENCE_SIG
))
3995 add_string_resource_to_control(hwnd
, IDS_CERTIFICATE_BAD_SIGNATURE
);
3996 else if (!(cert
->dwConfidence
& CERT_CONFIDENCE_TIME
))
3997 add_string_resource_to_control(hwnd
, IDS_CERTIFICATE_BAD_TIME
);
3998 else if (!(cert
->dwConfidence
& CERT_CONFIDENCE_TIMENEST
))
3999 add_string_resource_to_control(hwnd
, IDS_CERTIFICATE_BAD_TIMENEST
);
4000 else if (cert
->dwRevokedReason
)
4001 add_string_resource_to_control(hwnd
, IDS_CERTIFICATE_REVOKED
);
4003 add_string_resource_to_control(hwnd
, IDS_CERTIFICATE_VALID
);
4006 static void set_certificate_status_for_end_cert(HWND hwnd
,
4007 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
)
4009 HWND status
= GetDlgItem(hwnd
, IDC_CERTIFICATESTATUSTEXT
);
4010 CRYPT_PROVIDER_SGNR
*provSigner
= WTHelperGetProvSignerFromChain(
4011 (CRYPT_PROVIDER_DATA
*)pCertViewInfo
->u
.pCryptProviderData
,
4012 pCertViewInfo
->idxSigner
, pCertViewInfo
->fCounterSigner
,
4013 pCertViewInfo
->idxCounterSigner
);
4014 CRYPT_PROVIDER_CERT
*provCert
= WTHelperGetProvCertFromChain(provSigner
,
4015 pCertViewInfo
->idxCert
);
4017 set_certificate_status(status
, provCert
);
4020 static void show_cert_hierarchy(HWND hwnd
, struct hierarchy_data
*data
)
4022 /* Disable view certificate button until a certificate is selected */
4023 EnableWindow(GetDlgItem(hwnd
, IDC_VIEWCERTIFICATE
), FALSE
);
4024 show_cert_chain(hwnd
, data
);
4025 set_certificate_status_for_end_cert(hwnd
, data
->pCertViewInfo
);
4028 static void show_dialog_for_selected_cert(HWND hwnd
)
4030 HWND tree
= GetDlgItem(hwnd
, IDC_CERTPATH
);
4032 struct hierarchy_data
*data
;
4035 memset(&item
, 0, sizeof(item
));
4036 item
.mask
= TVIF_HANDLE
| TVIF_PARAM
;
4037 item
.hItem
= (HTREEITEM
)SendMessageW(tree
, TVM_GETNEXTITEM
, TVGN_CARET
,
4039 SendMessageW(tree
, TVM_GETITEMW
, 0, (LPARAM
)&item
);
4040 data
= get_hierarchy_data_from_tree_item(tree
, item
.hItem
);
4041 selection
= lparam_to_index(data
, item
.lParam
);
4044 CRYPT_PROVIDER_SGNR
*provSigner
;
4045 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo
;
4046 BOOL changed
= FALSE
;
4048 provSigner
= WTHelperGetProvSignerFromChain(
4049 (CRYPT_PROVIDER_DATA
*)data
->pCertViewInfo
->u
.pCryptProviderData
,
4050 data
->pCertViewInfo
->idxSigner
,
4051 data
->pCertViewInfo
->fCounterSigner
,
4052 data
->pCertViewInfo
->idxCounterSigner
);
4053 memset(&viewInfo
, 0, sizeof(viewInfo
));
4054 viewInfo
.dwSize
= sizeof(viewInfo
);
4055 viewInfo
.dwFlags
= data
->pCertViewInfo
->dwFlags
;
4056 viewInfo
.szTitle
= data
->pCertViewInfo
->szTitle
;
4057 viewInfo
.pCertContext
= provSigner
->pasCertChain
[selection
].pCert
;
4058 viewInfo
.cStores
= data
->pCertViewInfo
->cStores
;
4059 viewInfo
.rghStores
= data
->pCertViewInfo
->rghStores
;
4060 viewInfo
.cPropSheetPages
= data
->pCertViewInfo
->cPropSheetPages
;
4061 viewInfo
.rgPropSheetPages
= data
->pCertViewInfo
->rgPropSheetPages
;
4062 viewInfo
.nStartPage
= data
->pCertViewInfo
->nStartPage
;
4063 CryptUIDlgViewCertificateW(&viewInfo
, &changed
);
4066 /* Delete the contents of the tree */
4067 SendMessageW(tree
, TVM_DELETEITEM
, 0, (LPARAM
)TVI_ROOT
);
4068 /* Reinitialize the tree */
4069 show_cert_hierarchy(hwnd
, data
);
4074 static LRESULT CALLBACK
hierarchy_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wp
,
4077 PROPSHEETPAGEW
*page
;
4078 struct hierarchy_data
*data
;
4080 HWND tree
= GetDlgItem(hwnd
, IDC_CERTPATH
);
4082 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd
, msg
, wp
, lp
);
4087 page
= (PROPSHEETPAGEW
*)lp
;
4088 data
= (struct hierarchy_data
*)page
->lParam
;
4089 show_cert_hierarchy(hwnd
, data
);
4098 case TVN_SELCHANGEDW
:
4100 NMTREEVIEWW
*nm
= (NMTREEVIEWW
*)lp
;
4102 CRYPT_PROVIDER_SGNR
*provSigner
;
4104 data
= get_hierarchy_data_from_tree_item(tree
, nm
->itemNew
.hItem
);
4105 selection
= lparam_to_index(data
, nm
->itemNew
.lParam
);
4106 provSigner
= WTHelperGetProvSignerFromChain(
4107 (CRYPT_PROVIDER_DATA
*)data
->pCertViewInfo
->u
.pCryptProviderData
,
4108 data
->pCertViewInfo
->idxSigner
,
4109 data
->pCertViewInfo
->fCounterSigner
,
4110 data
->pCertViewInfo
->idxCounterSigner
);
4111 EnableWindow(GetDlgItem(hwnd
, IDC_VIEWCERTIFICATE
), selection
!= 0);
4112 set_certificate_status(GetDlgItem(hwnd
, IDC_CERTIFICATESTATUSTEXT
),
4113 &provSigner
->pasCertChain
[selection
]);
4117 show_dialog_for_selected_cert(hwnd
);
4118 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, 1);
4127 case IDC_VIEWCERTIFICATE
:
4128 show_dialog_for_selected_cert(hwnd
);
4132 case WM_REFRESH_VIEW
:
4136 /* Get hierarchy data */
4137 memset(&item
, 0, sizeof(item
));
4138 item
.mask
= TVIF_HANDLE
| TVIF_PARAM
;
4139 item
.hItem
= (HTREEITEM
)SendMessageW(tree
, TVM_GETNEXTITEM
, TVGN_ROOT
,
4141 data
= get_hierarchy_data_from_tree_item(tree
, item
.hItem
);
4142 /* Delete the contents of the tree */
4143 SendMessageW(tree
, TVM_DELETEITEM
, 0, (LPARAM
)TVI_ROOT
);
4144 /* Reinitialize the tree */
4145 show_cert_hierarchy(hwnd
, data
);
4152 static UINT CALLBACK
hierarchy_callback(HWND hwnd
, UINT msg
,
4153 PROPSHEETPAGEW
*page
)
4155 struct hierarchy_data
*data
;
4160 data
= (struct hierarchy_data
*)page
->lParam
;
4161 ImageList_Destroy(data
->imageList
);
4162 HeapFree(GetProcessHeap(), 0, data
);
4168 static BOOL
init_hierarchy_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
,
4169 PROPSHEETPAGEW
*page
)
4171 struct hierarchy_data
*data
= HeapAlloc(GetProcessHeap(), 0,
4172 sizeof(struct hierarchy_data
));
4177 data
->imageList
= ImageList_Create(16, 16, ILC_COLOR4
| ILC_MASK
, 2, 0);
4178 if (data
->imageList
)
4181 COLORREF backColor
= RGB(255, 0, 255);
4183 data
->pCertViewInfo
= pCertViewInfo
;
4184 data
->selectedCert
= 0xffffffff;
4186 bmp
= LoadBitmapW(hInstance
, MAKEINTRESOURCEW(IDB_SMALL_ICONS
));
4187 ImageList_AddMasked(data
->imageList
, bmp
, backColor
);
4189 ImageList_SetBkColor(data
->imageList
, CLR_NONE
);
4191 memset(page
, 0, sizeof(PROPSHEETPAGEW
));
4192 page
->dwSize
= sizeof(PROPSHEETPAGEW
);
4193 page
->dwFlags
= PSP_USECALLBACK
;
4194 page
->hInstance
= hInstance
;
4195 page
->u
.pszTemplate
= MAKEINTRESOURCEW(IDD_HIERARCHY
);
4196 page
->pfnDlgProc
= hierarchy_dlg_proc
;
4197 page
->lParam
= (LPARAM
)data
;
4198 page
->pfnCallback
= hierarchy_callback
;
4202 HeapFree(GetProcessHeap(), 0, data
);
4207 static int CALLBACK
cert_prop_sheet_proc(HWND hwnd
, UINT msg
, LPARAM lp
)
4212 TRACE("(%p, %08x, %08lx)\n", hwnd
, msg
, lp
);
4216 case PSCB_INITIALIZED
:
4217 /* Get cancel button's position.. */
4218 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rc
);
4219 topLeft
.x
= rc
.left
;
4221 ScreenToClient(hwnd
, &topLeft
);
4222 /* hide the cancel button.. */
4223 ShowWindow(GetDlgItem(hwnd
, IDCANCEL
), FALSE
);
4224 /* get the OK button's size.. */
4225 GetWindowRect(GetDlgItem(hwnd
, IDOK
), &rc
);
4226 /* and move the OK button to the cancel button's original position. */
4227 MoveWindow(GetDlgItem(hwnd
, IDOK
), topLeft
.x
, topLeft
.y
,
4228 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, FALSE
);
4229 GetWindowRect(GetDlgItem(hwnd
, IDOK
), &rc
);
4235 static BOOL
show_cert_dialog(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
,
4236 CRYPT_PROVIDER_CERT
*provCert
, BOOL
*pfPropertiesChanged
)
4238 static const WCHAR riched
[] = { 'r','i','c','h','e','d','2','0',0 };
4240 PROPSHEETPAGEW
*pages
;
4242 HMODULE lib
= LoadLibraryW(riched
);
4244 nPages
= pCertViewInfo
->cPropSheetPages
+ 1; /* one for the General tab */
4245 if (!(pCertViewInfo
->dwFlags
& CRYPTUI_HIDE_DETAILPAGE
))
4247 if (!(pCertViewInfo
->dwFlags
& CRYPTUI_HIDE_HIERARCHYPAGE
))
4249 pages
= HeapAlloc(GetProcessHeap(), 0, nPages
* sizeof(PROPSHEETPAGEW
));
4252 PROPSHEETHEADERW hdr
;
4253 CRYPTUI_INITDIALOG_STRUCT
*init
= NULL
;
4256 memset(&hdr
, 0, sizeof(hdr
));
4257 hdr
.dwSize
= sizeof(hdr
);
4258 hdr
.dwFlags
= PSH_NOAPPLYNOW
| PSH_PROPSHEETPAGE
| PSH_USECALLBACK
;
4259 hdr
.hInstance
= hInstance
;
4260 if (pCertViewInfo
->szTitle
)
4261 hdr
.pszCaption
= pCertViewInfo
->szTitle
;
4263 hdr
.pszCaption
= MAKEINTRESOURCEW(IDS_CERTIFICATE
);
4264 init_general_page(pCertViewInfo
, &pages
[hdr
.nPages
++]);
4265 if (!(pCertViewInfo
->dwFlags
& CRYPTUI_HIDE_DETAILPAGE
))
4267 if (init_detail_page(pCertViewInfo
, pfPropertiesChanged
,
4268 &pages
[hdr
.nPages
]))
4271 if (!(pCertViewInfo
->dwFlags
& CRYPTUI_HIDE_HIERARCHYPAGE
))
4273 if (init_hierarchy_page(pCertViewInfo
, &pages
[hdr
.nPages
]))
4276 /* Copy each additional page, and create the init dialog struct for it
4278 if (pCertViewInfo
->cPropSheetPages
)
4280 init
= HeapAlloc(GetProcessHeap(), 0,
4281 pCertViewInfo
->cPropSheetPages
*
4282 sizeof(CRYPTUI_INITDIALOG_STRUCT
));
4285 for (i
= 0; i
< pCertViewInfo
->cPropSheetPages
; i
++)
4287 memcpy(&pages
[hdr
.nPages
+ i
],
4288 &pCertViewInfo
->rgPropSheetPages
[i
],
4289 sizeof(PROPSHEETPAGEW
));
4290 init
[i
].lParam
= pCertViewInfo
->rgPropSheetPages
[i
].lParam
;
4291 init
[i
].pCertContext
= pCertViewInfo
->pCertContext
;
4292 pages
[hdr
.nPages
+ i
].lParam
= (LPARAM
)&init
[i
];
4294 if (pCertViewInfo
->nStartPage
& 0x8000)
4296 /* Start page index is relative to the number of default
4299 hdr
.u2
.nStartPage
= pCertViewInfo
->nStartPage
+ hdr
.nPages
;
4302 hdr
.u2
.nStartPage
= pCertViewInfo
->nStartPage
;
4303 hdr
.nPages
= nPages
;
4307 SetLastError(ERROR_OUTOFMEMORY
);
4311 /* Ignore the relative flag if there aren't any additional pages */
4312 hdr
.u2
.nStartPage
= pCertViewInfo
->nStartPage
& 0x7fff;
4319 hdr
.u3
.ppsp
= pages
;
4320 hdr
.pfnCallback
= cert_prop_sheet_proc
;
4321 l
= PropertySheetW(&hdr
);
4324 SetLastError(ERROR_CANCELLED
);
4328 HeapFree(GetProcessHeap(), 0, init
);
4329 HeapFree(GetProcessHeap(), 0, pages
);
4332 SetLastError(ERROR_OUTOFMEMORY
);
4337 /***********************************************************************
4338 * CryptUIDlgViewCertificateW (CRYPTUI.@)
4340 BOOL WINAPI
CryptUIDlgViewCertificateW(
4341 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
, BOOL
*pfPropertiesChanged
)
4343 static GUID generic_cert_verify
= WINTRUST_ACTION_GENERIC_CERT_VERIFY
;
4344 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo
;
4346 WINTRUST_CERT_INFO cert
;
4348 CRYPT_PROVIDER_SGNR
*signer
;
4349 CRYPT_PROVIDER_CERT
*provCert
= NULL
;
4351 TRACE("(%p, %p)\n", pCertViewInfo
, pfPropertiesChanged
);
4353 if (pCertViewInfo
->dwSize
!= sizeof(CRYPTUI_VIEWCERTIFICATE_STRUCTW
))
4355 SetLastError(ERROR_INVALID_PARAMETER
);
4358 /* Make a local copy in case we have to call WinVerifyTrust ourselves */
4359 memcpy(&viewInfo
, pCertViewInfo
, sizeof(viewInfo
));
4360 if (!viewInfo
.u
.hWVTStateData
)
4362 memset(&wvt
, 0, sizeof(wvt
));
4363 wvt
.cbStruct
= sizeof(wvt
);
4364 wvt
.dwUIChoice
= WTD_UI_NONE
;
4365 if (viewInfo
.dwFlags
&
4366 CRYPTUI_ENABLE_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT
)
4367 wvt
.fdwRevocationChecks
|= WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT
;
4368 if (viewInfo
.dwFlags
& CRYPTUI_ENABLE_REVOCATION_CHECK_END_CERT
)
4369 wvt
.fdwRevocationChecks
|= WTD_REVOCATION_CHECK_END_CERT
;
4370 if (viewInfo
.dwFlags
& CRYPTUI_ENABLE_REVOCATION_CHECK_CHAIN
)
4371 wvt
.fdwRevocationChecks
|= WTD_REVOCATION_CHECK_CHAIN
;
4372 wvt
.dwUnionChoice
= WTD_CHOICE_CERT
;
4373 memset(&cert
, 0, sizeof(cert
));
4374 cert
.cbStruct
= sizeof(cert
);
4375 cert
.psCertContext
= (CERT_CONTEXT
*)viewInfo
.pCertContext
;
4376 cert
.chStores
= viewInfo
.cStores
;
4377 cert
.pahStores
= viewInfo
.rghStores
;
4378 wvt
.u
.pCert
= &cert
;
4379 wvt
.dwStateAction
= WTD_STATEACTION_VERIFY
;
4380 WinVerifyTrust(NULL
, &generic_cert_verify
, &wvt
);
4381 viewInfo
.u
.pCryptProviderData
=
4382 WTHelperProvDataFromStateData(wvt
.hWVTStateData
);
4383 signer
= WTHelperGetProvSignerFromChain(
4384 (CRYPT_PROVIDER_DATA
*)viewInfo
.u
.pCryptProviderData
, 0, FALSE
, 0);
4385 provCert
= WTHelperGetProvCertFromChain(signer
, 0);
4390 viewInfo
.u
.pCryptProviderData
=
4391 WTHelperProvDataFromStateData(viewInfo
.u
.hWVTStateData
);
4392 signer
= WTHelperGetProvSignerFromChain(
4393 (CRYPT_PROVIDER_DATA
*)viewInfo
.u
.pCryptProviderData
,
4394 viewInfo
.idxSigner
, viewInfo
.fCounterSigner
,
4395 viewInfo
.idxCounterSigner
);
4396 provCert
= WTHelperGetProvCertFromChain(signer
, viewInfo
.idxCert
);
4401 ret
= show_cert_dialog(&viewInfo
, provCert
, pfPropertiesChanged
);
4402 if (!viewInfo
.u
.hWVTStateData
)
4404 wvt
.dwStateAction
= WTD_STATEACTION_CLOSE
;
4405 WinVerifyTrust(NULL
, &generic_cert_verify
, &wvt
);
4411 /***********************************************************************
4412 * CryptUIDlgViewContext (CRYPTUI.@)
4414 BOOL WINAPI
CryptUIDlgViewContext(DWORD dwContextType
, LPVOID pvContext
,
4415 HWND hwnd
, LPCWSTR pwszTitle
, DWORD dwFlags
, LPVOID pvReserved
)
4419 TRACE("(%d, %p, %p, %s, %08x, %p)\n", dwContextType
, pvContext
, hwnd
,
4420 debugstr_w(pwszTitle
), dwFlags
, pvReserved
);
4422 switch (dwContextType
)
4424 case CERT_STORE_CERTIFICATE_CONTEXT
:
4426 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo
;
4428 memset(&viewInfo
, 0, sizeof(viewInfo
));
4429 viewInfo
.dwSize
= sizeof(viewInfo
);
4430 viewInfo
.hwndParent
= hwnd
;
4431 viewInfo
.szTitle
= pwszTitle
;
4432 viewInfo
.pCertContext
= pvContext
;
4433 ret
= CryptUIDlgViewCertificateW(&viewInfo
, NULL
);
4437 FIXME("unimplemented for context type %d\n", dwContextType
);
4438 SetLastError(E_INVALIDARG
);
4444 /* Decodes a cert's basic constraints extension (either szOID_BASIC_CONSTRAINTS
4445 * or szOID_BASIC_CONSTRAINTS2, whichever is present) to determine if it
4446 * should be a CA. If neither extension is present, returns
4447 * defaultIfNotSpecified.
4449 static BOOL
is_ca_cert(PCCERT_CONTEXT cert
, BOOL defaultIfNotSpecified
)
4451 BOOL isCA
= defaultIfNotSpecified
;
4452 PCERT_EXTENSION ext
= CertFindExtension(szOID_BASIC_CONSTRAINTS
,
4453 cert
->pCertInfo
->cExtension
, cert
->pCertInfo
->rgExtension
);
4457 CERT_BASIC_CONSTRAINTS_INFO
*info
;
4460 if (CryptDecodeObjectEx(X509_ASN_ENCODING
, szOID_BASIC_CONSTRAINTS
,
4461 ext
->Value
.pbData
, ext
->Value
.cbData
, CRYPT_DECODE_ALLOC_FLAG
,
4462 NULL
, &info
, &size
))
4464 if (info
->SubjectType
.cbData
== 1)
4465 isCA
= info
->SubjectType
.pbData
[0] & CERT_CA_SUBJECT_FLAG
;
4471 ext
= CertFindExtension(szOID_BASIC_CONSTRAINTS2
,
4472 cert
->pCertInfo
->cExtension
, cert
->pCertInfo
->rgExtension
);
4475 CERT_BASIC_CONSTRAINTS2_INFO info
;
4476 DWORD size
= sizeof(CERT_BASIC_CONSTRAINTS2_INFO
);
4478 if (CryptDecodeObjectEx(X509_ASN_ENCODING
,
4479 szOID_BASIC_CONSTRAINTS2
, ext
->Value
.pbData
, ext
->Value
.cbData
,
4480 0, NULL
, &info
, &size
))
4487 static HCERTSTORE
choose_store_for_cert(PCCERT_CONTEXT cert
)
4491 if (is_ca_cert(cert
, TRUE
))
4494 storeName
= addressBook
;
4495 return CertOpenStore(CERT_STORE_PROV_SYSTEM_W
, 0, 0,
4496 CERT_SYSTEM_STORE_CURRENT_USER
, storeName
);
4499 static BOOL
import_cert(PCCERT_CONTEXT cert
, HCERTSTORE hDestCertStore
)
4506 SetLastError(E_INVALIDARG
);
4509 if (hDestCertStore
) store
= hDestCertStore
;
4512 if (!(store
= choose_store_for_cert(cert
)))
4514 WARN("unable to open certificate store\n");
4518 ret
= CertAddCertificateContextToStore(store
, cert
,
4519 CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES
, NULL
);
4520 if (!hDestCertStore
) CertCloseStore(store
, 0);
4524 static BOOL
import_crl(PCCRL_CONTEXT crl
, HCERTSTORE hDestCertStore
)
4531 SetLastError(E_INVALIDARG
);
4534 if (hDestCertStore
) store
= hDestCertStore
;
4537 if (!(store
= CertOpenStore(CERT_STORE_PROV_SYSTEM_W
, 0, 0,
4538 CERT_SYSTEM_STORE_CURRENT_USER
, ca
)))
4540 WARN("unable to open certificate store\n");
4544 ret
= CertAddCRLContextToStore(store
, crl
,
4545 CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES
, NULL
);
4546 if (!hDestCertStore
) CertCloseStore(store
, 0);
4550 static BOOL
import_ctl(PCCTL_CONTEXT ctl
, HCERTSTORE hDestCertStore
)
4557 SetLastError(E_INVALIDARG
);
4560 if (hDestCertStore
) store
= hDestCertStore
;
4563 static const WCHAR trust
[] = { 'T','r','u','s','t',0 };
4565 if (!(store
= CertOpenStore(CERT_STORE_PROV_SYSTEM_W
, 0, 0,
4566 CERT_SYSTEM_STORE_CURRENT_USER
, trust
)))
4568 WARN("unable to open certificate store\n");
4572 ret
= CertAddCTLContextToStore(store
, ctl
,
4573 CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES
, NULL
);
4574 if (!hDestCertStore
) CertCloseStore(store
, 0);
4578 /* Checks type, a type such as CERT_QUERY_CONTENT_CERT returned by
4579 * CryptQueryObject, against the allowed types. Returns TRUE if the
4580 * type is allowed, FALSE otherwise.
4582 static BOOL
check_context_type(DWORD dwFlags
, DWORD type
)
4587 (CRYPTUI_WIZ_IMPORT_ALLOW_CERT
| CRYPTUI_WIZ_IMPORT_ALLOW_CRL
|
4588 CRYPTUI_WIZ_IMPORT_ALLOW_CTL
))
4592 case CERT_QUERY_CONTENT_CERT
:
4593 case CERT_QUERY_CONTENT_SERIALIZED_CERT
:
4594 ret
= dwFlags
& CRYPTUI_WIZ_IMPORT_ALLOW_CERT
;
4596 case CERT_QUERY_CONTENT_CRL
:
4597 case CERT_QUERY_CONTENT_SERIALIZED_CRL
:
4598 ret
= dwFlags
& CRYPTUI_WIZ_IMPORT_ALLOW_CRL
;
4600 case CERT_QUERY_CONTENT_CTL
:
4601 case CERT_QUERY_CONTENT_SERIALIZED_CTL
:
4602 ret
= dwFlags
& CRYPTUI_WIZ_IMPORT_ALLOW_CTL
;
4605 /* The remaining types contain more than one type, so allow
4613 /* No allowed types specified, so any type is allowed */
4617 SetLastError(E_INVALIDARG
);
4622 static void import_warning(DWORD dwFlags
, HWND hwnd
, LPCWSTR szTitle
,
4625 if (!(dwFlags
& CRYPTUI_WIZ_NO_UI
))
4627 WCHAR title
[MAX_STRING_LEN
], error
[MAX_STRING_LEN
];
4634 LoadStringW(hInstance
, IDS_IMPORT_WIZARD
, title
,
4635 sizeof(title
) / sizeof(title
[0]));
4638 LoadStringW(hInstance
, warningID
, error
,
4639 sizeof(error
) / sizeof(error
[0]));
4640 MessageBoxW(hwnd
, error
, pTitle
, MB_ICONERROR
| MB_OK
);
4644 static void import_warn_type_mismatch(DWORD dwFlags
, HWND hwnd
, LPCWSTR szTitle
)
4646 import_warning(dwFlags
, hwnd
, szTitle
, IDS_IMPORT_TYPE_MISMATCH
);
4649 static BOOL
check_store_context_type(DWORD dwFlags
, HCERTSTORE store
)
4654 (CRYPTUI_WIZ_IMPORT_ALLOW_CERT
| CRYPTUI_WIZ_IMPORT_ALLOW_CRL
|
4655 CRYPTUI_WIZ_IMPORT_ALLOW_CTL
))
4657 PCCERT_CONTEXT cert
;
4662 if ((cert
= CertEnumCertificatesInStore(store
, NULL
)))
4664 CertFreeCertificateContext(cert
);
4665 if (!(dwFlags
& CRYPTUI_WIZ_IMPORT_ALLOW_CERT
))
4668 if (ret
&& (crl
= CertEnumCRLsInStore(store
, NULL
)))
4670 CertFreeCRLContext(crl
);
4671 if (!(dwFlags
& CRYPTUI_WIZ_IMPORT_ALLOW_CRL
))
4674 if (ret
&& (ctl
= CertEnumCTLsInStore(store
, NULL
)))
4676 CertFreeCTLContext(ctl
);
4677 if (!(dwFlags
& CRYPTUI_WIZ_IMPORT_ALLOW_CTL
))
4684 SetLastError(E_INVALIDARG
);
4688 static BOOL
import_store(DWORD dwFlags
, HWND hwnd
, LPCWSTR szTitle
,
4689 HCERTSTORE source
, HCERTSTORE dest
)
4693 if ((ret
= check_store_context_type(dwFlags
, source
)))
4695 PCCERT_CONTEXT cert
= NULL
;
4696 PCCRL_CONTEXT crl
= NULL
;
4697 PCCTL_CONTEXT ctl
= NULL
;
4700 cert
= CertEnumCertificatesInStore(source
, cert
);
4702 ret
= import_cert(cert
, dest
);
4703 } while (ret
&& cert
);
4705 crl
= CertEnumCRLsInStore(source
, crl
);
4707 ret
= import_crl(crl
, dest
);
4708 } while (ret
&& crl
);
4710 ctl
= CertEnumCTLsInStore(source
, ctl
);
4712 ret
= import_ctl(ctl
, dest
);
4713 } while (ret
&& ctl
);
4716 import_warn_type_mismatch(dwFlags
, hwnd
, szTitle
);
4720 static HCERTSTORE
open_store_from_file(DWORD dwFlags
, LPCWSTR fileName
,
4721 DWORD
*pContentType
)
4723 HCERTSTORE store
= NULL
;
4724 DWORD contentType
= 0, expectedContentTypeFlags
;
4727 (CRYPTUI_WIZ_IMPORT_ALLOW_CERT
| CRYPTUI_WIZ_IMPORT_ALLOW_CRL
|
4728 CRYPTUI_WIZ_IMPORT_ALLOW_CTL
))
4730 expectedContentTypeFlags
=
4731 CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE
|
4732 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED
|
4733 CERT_QUERY_CONTENT_FLAG_PFX
;
4734 if (dwFlags
& CRYPTUI_WIZ_IMPORT_ALLOW_CERT
)
4735 expectedContentTypeFlags
|=
4736 CERT_QUERY_CONTENT_FLAG_CERT
|
4737 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT
;
4738 if (dwFlags
& CRYPTUI_WIZ_IMPORT_ALLOW_CRL
)
4739 expectedContentTypeFlags
|=
4740 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL
|
4741 CERT_QUERY_CONTENT_FLAG_CRL
;
4742 if (dwFlags
& CRYPTUI_WIZ_IMPORT_ALLOW_CTL
)
4743 expectedContentTypeFlags
|=
4744 CERT_QUERY_CONTENT_FLAG_CTL
|
4745 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL
;
4748 expectedContentTypeFlags
=
4749 CERT_QUERY_CONTENT_FLAG_CERT
|
4750 CERT_QUERY_CONTENT_FLAG_CTL
|
4751 CERT_QUERY_CONTENT_FLAG_CRL
|
4752 CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE
|
4753 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT
|
4754 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL
|
4755 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL
|
4756 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED
|
4757 CERT_QUERY_CONTENT_FLAG_PFX
;
4759 CryptQueryObject(CERT_QUERY_OBJECT_FILE
, fileName
,
4760 expectedContentTypeFlags
, CERT_QUERY_FORMAT_FLAG_ALL
, 0, NULL
,
4761 &contentType
, NULL
, &store
, NULL
, NULL
);
4763 *pContentType
= contentType
;
4767 static BOOL
import_file(DWORD dwFlags
, HWND hwnd
, LPCWSTR szTitle
,
4768 LPCWSTR fileName
, HCERTSTORE dest
)
4773 if ((source
= open_store_from_file(dwFlags
, fileName
, NULL
)))
4775 ret
= import_store(dwFlags
, hwnd
, szTitle
, source
, dest
);
4776 CertCloseStore(source
, 0);
4783 struct ImportWizData
4787 LPCWSTR pwszWizardTitle
;
4788 CRYPTUI_WIZ_IMPORT_SRC_INFO importSrc
;
4792 HCERTSTORE hDestCertStore
;
4798 static LRESULT CALLBACK
import_welcome_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wp
,
4807 struct ImportWizData
*data
;
4808 PROPSHEETPAGEW
*page
= (PROPSHEETPAGEW
*)lp
;
4809 WCHAR fontFace
[MAX_STRING_LEN
];
4810 HDC hDC
= GetDC(hwnd
);
4813 data
= (struct ImportWizData
*)page
->lParam
;
4814 LoadStringW(hInstance
, IDS_WIZARD_TITLE_FONT
, fontFace
,
4815 sizeof(fontFace
) / sizeof(fontFace
[0]));
4816 height
= -MulDiv(12, GetDeviceCaps(hDC
, LOGPIXELSY
), 72);
4817 data
->titleFont
= CreateFontW(height
, 0, 0, 0, FW_BOLD
, 0, 0, 0,
4818 DEFAULT_CHARSET
, OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
,
4819 DEFAULT_QUALITY
, DEFAULT_PITCH
| FF_DONTCARE
, fontFace
);
4820 SendMessageW(GetDlgItem(hwnd
, IDC_IMPORT_TITLE
), WM_SETFONT
,
4821 (WPARAM
)data
->titleFont
, TRUE
);
4822 ReleaseDC(hwnd
, hDC
);
4827 NMHDR
*hdr
= (NMHDR
*)lp
;
4832 PostMessageW(GetParent(hwnd
), PSM_SETWIZBUTTONS
, 0, PSWIZB_NEXT
);
4842 static const WCHAR filter_cert
[] = { '*','.','c','e','r',';','*','.',
4844 static const WCHAR filter_pfx
[] = { '*','.','p','f','x',';','*','.',
4846 static const WCHAR filter_crl
[] = { '*','.','c','r','l',0 };
4847 static const WCHAR filter_ctl
[] = { '*','.','s','t','l',0 };
4848 static const WCHAR filter_serialized_store
[] = { '*','.','s','s','t',0 };
4849 static const WCHAR filter_cms
[] = { '*','.','s','p','c',';','*','.',
4851 static const WCHAR filter_all
[] = { '*','.','*',0 };
4853 struct StringToFilter
4858 } import_filters
[] = {
4859 { IDS_IMPORT_FILTER_CERT
, CRYPTUI_WIZ_IMPORT_ALLOW_CERT
, filter_cert
},
4860 { IDS_IMPORT_FILTER_PFX
, 0, filter_pfx
},
4861 { IDS_IMPORT_FILTER_CRL
, CRYPTUI_WIZ_IMPORT_ALLOW_CRL
, filter_crl
},
4862 { IDS_IMPORT_FILTER_CTL
, CRYPTUI_WIZ_IMPORT_ALLOW_CTL
, filter_ctl
},
4863 { IDS_IMPORT_FILTER_SERIALIZED_STORE
, 0, filter_serialized_store
},
4864 { IDS_IMPORT_FILTER_CMS
, 0, filter_cms
},
4865 { IDS_IMPORT_FILTER_ALL
, 0, filter_all
},
4868 static WCHAR
*make_import_file_filter(DWORD dwFlags
)
4871 int len
, totalLen
= 2;
4872 LPWSTR filter
= NULL
, str
;
4874 for (i
= 0; i
< sizeof(import_filters
) / sizeof(import_filters
[0]); i
++)
4876 if (!import_filters
[i
].allowFlags
|| !dwFlags
||
4877 (dwFlags
& import_filters
[i
].allowFlags
))
4879 len
= LoadStringW(hInstance
, import_filters
[i
].id
, (LPWSTR
)&str
, 0);
4880 totalLen
+= len
+ strlenW(import_filters
[i
].filter
) + 2;
4883 filter
= HeapAlloc(GetProcessHeap(), 0, totalLen
* sizeof(WCHAR
));
4889 for (i
= 0; i
< sizeof(import_filters
) / sizeof(import_filters
[0]); i
++)
4891 if (!import_filters
[i
].allowFlags
|| !dwFlags
||
4892 (dwFlags
& import_filters
[i
].allowFlags
))
4894 len
= LoadStringW(hInstance
, import_filters
[i
].id
,
4896 memcpy(ptr
, str
, len
* sizeof(WCHAR
));
4899 strcpyW(ptr
, import_filters
[i
].filter
);
4900 ptr
+= strlenW(import_filters
[i
].filter
) + 1;
4908 static BOOL
import_validate_filename(HWND hwnd
, struct ImportWizData
*data
,
4914 file
= CreateFileW(fileName
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
4915 OPEN_EXISTING
, 0, NULL
);
4916 if (file
!= INVALID_HANDLE_VALUE
)
4918 HCERTSTORE source
= open_store_from_file(data
->dwFlags
, fileName
,
4919 &data
->contentType
);
4923 warningID
= IDS_IMPORT_BAD_FORMAT
;
4924 else if (!check_store_context_type(data
->dwFlags
, source
))
4925 warningID
= IDS_IMPORT_TYPE_MISMATCH
;
4928 data
->importSrc
.dwSubjectChoice
=
4929 CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE
;
4930 data
->importSrc
.u
.hCertStore
= source
;
4931 data
->freeSource
= TRUE
;
4936 import_warning(data
->dwFlags
, hwnd
, data
->pwszWizardTitle
,
4943 WCHAR title
[MAX_STRING_LEN
], error
[MAX_STRING_LEN
];
4945 LPWSTR msgBuf
, fullError
;
4947 if (data
->pwszWizardTitle
)
4948 pTitle
= data
->pwszWizardTitle
;
4951 LoadStringW(hInstance
, IDS_IMPORT_WIZARD
, title
,
4952 sizeof(title
) / sizeof(title
[0]));
4955 LoadStringW(hInstance
, IDS_IMPORT_OPEN_FAILED
, error
,
4956 sizeof(error
) / sizeof(error
[0]));
4958 FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
, NULL
,
4959 GetLastError(), 0, (LPWSTR
) &msgBuf
, 0, NULL
);
4960 fullError
= HeapAlloc(GetProcessHeap(), 0,
4961 (strlenW(error
) + strlenW(fileName
) + strlenW(msgBuf
) + 3)
4965 LPWSTR ptr
= fullError
;
4967 strcpyW(ptr
, error
);
4968 ptr
+= strlenW(error
);
4969 strcpyW(ptr
, fileName
);
4970 ptr
+= strlenW(fileName
);
4973 strcpyW(ptr
, msgBuf
);
4974 MessageBoxW(hwnd
, fullError
, pTitle
, MB_ICONERROR
| MB_OK
);
4975 HeapFree(GetProcessHeap(), 0, fullError
);
4982 static LRESULT CALLBACK
import_file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wp
,
4986 struct ImportWizData
*data
;
4992 PROPSHEETPAGEW
*page
= (PROPSHEETPAGEW
*)lp
;
4994 data
= (struct ImportWizData
*)page
->lParam
;
4995 SetWindowLongPtrW(hwnd
, DWLP_USER
, (LPARAM
)data
);
4998 HWND fileNameEdit
= GetDlgItem(hwnd
, IDC_IMPORT_FILENAME
);
5000 SendMessageW(fileNameEdit
, WM_SETTEXT
, 0, (LPARAM
)data
->fileName
);
5006 NMHDR
*hdr
= (NMHDR
*)lp
;
5011 PostMessageW(GetParent(hwnd
), PSM_SETWIZBUTTONS
, 0,
5012 PSWIZB_BACK
| PSWIZB_NEXT
);
5017 HWND fileNameEdit
= GetDlgItem(hwnd
, IDC_IMPORT_FILENAME
);
5018 DWORD len
= SendMessageW(fileNameEdit
, WM_GETTEXTLENGTH
, 0, 0);
5020 data
= (struct ImportWizData
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
5023 import_warning(data
->dwFlags
, hwnd
, data
->pwszWizardTitle
,
5024 IDS_IMPORT_EMPTY_FILE
);
5025 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, 1);
5030 LPWSTR fileName
= HeapAlloc(GetProcessHeap(), 0,
5031 (len
+ 1) * sizeof(WCHAR
));
5035 SendMessageW(fileNameEdit
, WM_GETTEXT
, len
+ 1,
5037 if (!import_validate_filename(hwnd
, data
, fileName
))
5039 HeapFree(GetProcessHeap(), 0, fileName
);
5040 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, 1);
5044 data
->fileName
= fileName
;
5055 case IDC_IMPORT_BROWSE_FILE
:
5058 WCHAR fileBuf
[MAX_PATH
];
5060 data
= (struct ImportWizData
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
5061 memset(&ofn
, 0, sizeof(ofn
));
5062 ofn
.lStructSize
= sizeof(ofn
);
5063 ofn
.hwndOwner
= hwnd
;
5064 ofn
.lpstrFilter
= make_import_file_filter(data
->dwFlags
);
5065 ofn
.lpstrFile
= fileBuf
;
5066 ofn
.nMaxFile
= sizeof(fileBuf
) / sizeof(fileBuf
[0]);
5068 if (GetOpenFileNameW(&ofn
))
5069 SendMessageW(GetDlgItem(hwnd
, IDC_IMPORT_FILENAME
), WM_SETTEXT
,
5070 0, (LPARAM
)ofn
.lpstrFile
);
5071 HeapFree(GetProcessHeap(), 0, (LPWSTR
)ofn
.lpstrFilter
);
5080 static LRESULT CALLBACK
import_store_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wp
,
5084 struct ImportWizData
*data
;
5090 PROPSHEETPAGEW
*page
= (PROPSHEETPAGEW
*)lp
;
5092 data
= (struct ImportWizData
*)page
->lParam
;
5093 SetWindowLongPtrW(hwnd
, DWLP_USER
, (LPARAM
)data
);
5094 if (!data
->hDestCertStore
)
5096 SendMessageW(GetDlgItem(hwnd
, IDC_IMPORT_AUTO_STORE
), BM_CLICK
,
5098 EnableWindow(GetDlgItem(hwnd
, IDC_IMPORT_STORE
), FALSE
);
5099 EnableWindow(GetDlgItem(hwnd
, IDC_IMPORT_BROWSE_STORE
), FALSE
);
5100 EnableWindow(GetDlgItem(hwnd
, IDC_IMPORT_SPECIFY_STORE
), FALSE
);
5104 WCHAR storeTitle
[MAX_STRING_LEN
];
5106 SendMessageW(GetDlgItem(hwnd
, IDC_IMPORT_SPECIFY_STORE
), BM_CLICK
,
5108 EnableWindow(GetDlgItem(hwnd
, IDC_IMPORT_STORE
), TRUE
);
5109 EnableWindow(GetDlgItem(hwnd
, IDC_IMPORT_BROWSE_STORE
), TRUE
);
5110 EnableWindow(GetDlgItem(hwnd
, IDC_IMPORT_SPECIFY_STORE
),
5111 !(data
->dwFlags
& CRYPTUI_WIZ_IMPORT_NO_CHANGE_DEST_STORE
));
5112 LoadStringW(hInstance
, IDS_IMPORT_DEST_DETERMINED
,
5113 storeTitle
, sizeof(storeTitle
) / sizeof(storeTitle
[0]));
5114 SendMessageW(GetDlgItem(hwnd
, IDC_IMPORT_STORE
), WM_SETTEXT
,
5115 0, (LPARAM
)storeTitle
);
5121 NMHDR
*hdr
= (NMHDR
*)lp
;
5126 PostMessageW(GetParent(hwnd
), PSM_SETWIZBUTTONS
, 0,
5127 PSWIZB_BACK
| PSWIZB_NEXT
);
5132 data
= (struct ImportWizData
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
5133 if (IsDlgButtonChecked(hwnd
, IDC_IMPORT_SPECIFY_STORE
) &&
5134 !data
->hDestCertStore
)
5136 import_warning(data
->dwFlags
, hwnd
, data
->pwszWizardTitle
,
5137 IDS_IMPORT_SELECT_STORE
);
5138 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, 1);
5149 case IDC_IMPORT_AUTO_STORE
:
5150 data
= (struct ImportWizData
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
5151 data
->autoDest
= TRUE
;
5152 EnableWindow(GetDlgItem(hwnd
, IDC_IMPORT_STORE
), FALSE
);
5153 EnableWindow(GetDlgItem(hwnd
, IDC_IMPORT_BROWSE_STORE
), FALSE
);
5155 case IDC_IMPORT_SPECIFY_STORE
:
5156 data
= (struct ImportWizData
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
5157 data
->autoDest
= FALSE
;
5158 EnableWindow(GetDlgItem(hwnd
, IDC_IMPORT_STORE
), TRUE
);
5159 EnableWindow(GetDlgItem(hwnd
, IDC_IMPORT_BROWSE_STORE
), TRUE
);
5161 case IDC_IMPORT_BROWSE_STORE
:
5163 CRYPTUI_ENUM_SYSTEM_STORE_ARGS enumArgs
= {
5164 CERT_SYSTEM_STORE_CURRENT_USER
, NULL
};
5165 CRYPTUI_ENUM_DATA enumData
= { 0, NULL
, 1, &enumArgs
};
5166 CRYPTUI_SELECTSTORE_INFO_W selectInfo
;
5169 data
= (struct ImportWizData
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
5170 selectInfo
.dwSize
= sizeof(selectInfo
);
5171 selectInfo
.parent
= hwnd
;
5172 selectInfo
.dwFlags
= CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE
;
5173 selectInfo
.pwszTitle
= NULL
;
5174 selectInfo
.pEnumData
= &enumData
;
5175 selectInfo
.pfnSelectedStoreCallback
= NULL
;
5176 if ((store
= CryptUIDlgSelectStoreW(&selectInfo
)))
5178 WCHAR storeTitle
[MAX_STRING_LEN
];
5180 LoadStringW(hInstance
, IDS_IMPORT_DEST_DETERMINED
,
5181 storeTitle
, sizeof(storeTitle
) / sizeof(storeTitle
[0]));
5182 SendMessageW(GetDlgItem(hwnd
, IDC_IMPORT_STORE
), WM_SETTEXT
,
5183 0, (LPARAM
)storeTitle
);
5184 data
->hDestCertStore
= store
;
5185 data
->freeDest
= TRUE
;
5195 static void show_import_details(HWND lv
, struct ImportWizData
*data
)
5197 WCHAR text
[MAX_STRING_LEN
];
5201 item
.mask
= LVIF_TEXT
;
5202 item
.iItem
= SendMessageW(lv
, LVM_GETITEMCOUNT
, 0, 0);
5204 LoadStringW(hInstance
, IDS_IMPORT_STORE_SELECTION
, text
,
5205 sizeof(text
)/ sizeof(text
[0]));
5206 item
.pszText
= text
;
5207 SendMessageW(lv
, LVM_INSERTITEMW
, 0, (LPARAM
)&item
);
5210 LoadStringW(hInstance
, IDS_IMPORT_DEST_AUTOMATIC
, text
,
5211 sizeof(text
)/ sizeof(text
[0]));
5213 LoadStringW(hInstance
, IDS_IMPORT_DEST_DETERMINED
, text
,
5214 sizeof(text
)/ sizeof(text
[0]));
5215 SendMessageW(lv
, LVM_SETITEMTEXTW
, item
.iItem
, (LPARAM
)&item
);
5216 item
.iItem
= SendMessageW(lv
, LVM_GETITEMCOUNT
, 0, 0);
5218 LoadStringW(hInstance
, IDS_IMPORT_CONTENT
, text
,
5219 sizeof(text
)/ sizeof(text
[0]));
5220 SendMessageW(lv
, LVM_INSERTITEMW
, 0, (LPARAM
)&item
);
5221 switch (data
->contentType
)
5223 case CERT_QUERY_CONTENT_CERT
:
5224 case CERT_QUERY_CONTENT_SERIALIZED_CERT
:
5225 contentID
= IDS_IMPORT_CONTENT_CERT
;
5227 case CERT_QUERY_CONTENT_CRL
:
5228 case CERT_QUERY_CONTENT_SERIALIZED_CRL
:
5229 contentID
= IDS_IMPORT_CONTENT_CRL
;
5231 case CERT_QUERY_CONTENT_CTL
:
5232 case CERT_QUERY_CONTENT_SERIALIZED_CTL
:
5233 contentID
= IDS_IMPORT_CONTENT_CTL
;
5235 case CERT_QUERY_CONTENT_PKCS7_SIGNED
:
5236 contentID
= IDS_IMPORT_CONTENT_CMS
;
5238 case CERT_QUERY_CONTENT_FLAG_PFX
:
5239 contentID
= IDS_IMPORT_CONTENT_PFX
;
5242 contentID
= IDS_IMPORT_CONTENT_STORE
;
5245 LoadStringW(hInstance
, contentID
, text
, sizeof(text
)/ sizeof(text
[0]));
5247 SendMessageW(lv
, LVM_SETITEMTEXTW
, item
.iItem
, (LPARAM
)&item
);
5250 item
.iItem
= SendMessageW(lv
, LVM_GETITEMCOUNT
, 0, 0);
5252 LoadStringW(hInstance
, IDS_IMPORT_FILE
, text
,
5253 sizeof(text
)/ sizeof(text
[0]));
5254 SendMessageW(lv
, LVM_INSERTITEMW
, 0, (LPARAM
)&item
);
5256 item
.pszText
= data
->fileName
;
5257 SendMessageW(lv
, LVM_SETITEMTEXTW
, item
.iItem
, (LPARAM
)&item
);
5261 static BOOL
do_import(DWORD dwFlags
, HWND hwndParent
, LPCWSTR pwszWizardTitle
,
5262 PCCRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc
, HCERTSTORE hDestCertStore
)
5266 switch (pImportSrc
->dwSubjectChoice
)
5268 case CRYPTUI_WIZ_IMPORT_SUBJECT_FILE
:
5269 ret
= import_file(dwFlags
, hwndParent
, pwszWizardTitle
,
5270 pImportSrc
->u
.pwszFileName
, hDestCertStore
);
5272 case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_CONTEXT
:
5273 if ((ret
= check_context_type(dwFlags
, CERT_QUERY_CONTENT_CERT
)))
5274 ret
= import_cert(pImportSrc
->u
.pCertContext
, hDestCertStore
);
5276 import_warn_type_mismatch(dwFlags
, hwndParent
, pwszWizardTitle
);
5278 case CRYPTUI_WIZ_IMPORT_SUBJECT_CRL_CONTEXT
:
5279 if ((ret
= check_context_type(dwFlags
, CERT_QUERY_CONTENT_CRL
)))
5280 ret
= import_crl(pImportSrc
->u
.pCRLContext
, hDestCertStore
);
5282 import_warn_type_mismatch(dwFlags
, hwndParent
, pwszWizardTitle
);
5284 case CRYPTUI_WIZ_IMPORT_SUBJECT_CTL_CONTEXT
:
5285 if ((ret
= check_context_type(dwFlags
, CERT_QUERY_CONTENT_CTL
)))
5286 ret
= import_ctl(pImportSrc
->u
.pCTLContext
, hDestCertStore
);
5288 import_warn_type_mismatch(dwFlags
, hwndParent
, pwszWizardTitle
);
5290 case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE
:
5291 ret
= import_store(dwFlags
, hwndParent
, pwszWizardTitle
,
5292 pImportSrc
->u
.hCertStore
, hDestCertStore
);
5295 WARN("unknown source type: %u\n", pImportSrc
->dwSubjectChoice
);
5296 SetLastError(E_INVALIDARG
);
5302 static LRESULT CALLBACK
import_finish_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wp
,
5306 struct ImportWizData
*data
;
5312 PROPSHEETPAGEW
*page
= (PROPSHEETPAGEW
*)lp
;
5313 HWND lv
= GetDlgItem(hwnd
, IDC_IMPORT_SETTINGS
);
5317 data
= (struct ImportWizData
*)page
->lParam
;
5318 SetWindowLongPtrW(hwnd
, DWLP_USER
, (LPARAM
)data
);
5319 SendMessageW(GetDlgItem(hwnd
, IDC_IMPORT_TITLE
), WM_SETFONT
,
5320 (WPARAM
)data
->titleFont
, TRUE
);
5321 GetWindowRect(lv
, &rc
);
5322 column
.mask
= LVCF_WIDTH
;
5323 column
.cx
= (rc
.right
- rc
.left
) / 2 - 2;
5324 SendMessageW(lv
, LVM_INSERTCOLUMNW
, 0, (LPARAM
)&column
);
5325 SendMessageW(lv
, LVM_INSERTCOLUMNW
, 1, (LPARAM
)&column
);
5326 show_import_details(lv
, data
);
5331 NMHDR
*hdr
= (NMHDR
*)lp
;
5337 HWND lv
= GetDlgItem(hwnd
, IDC_IMPORT_SETTINGS
);
5339 data
= (struct ImportWizData
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
5340 SendMessageW(lv
, LVM_DELETEALLITEMS
, 0, 0);
5341 show_import_details(lv
, data
);
5342 PostMessageW(GetParent(hwnd
), PSM_SETWIZBUTTONS
, 0,
5343 PSWIZB_BACK
| PSWIZB_FINISH
);
5349 data
= (struct ImportWizData
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
5350 if ((data
->success
= do_import(data
->dwFlags
, hwnd
,
5351 data
->pwszWizardTitle
, &data
->importSrc
, data
->hDestCertStore
)))
5353 WCHAR title
[MAX_STRING_LEN
], message
[MAX_STRING_LEN
];
5356 if (data
->pwszWizardTitle
)
5357 pTitle
= data
->pwszWizardTitle
;
5360 LoadStringW(hInstance
, IDS_IMPORT_WIZARD
, title
,
5361 sizeof(title
) / sizeof(title
[0]));
5364 LoadStringW(hInstance
, IDS_IMPORT_SUCCEEDED
, message
,
5365 sizeof(message
) / sizeof(message
[0]));
5366 MessageBoxW(hwnd
, message
, pTitle
, MB_OK
);
5369 import_warning(data
->dwFlags
, hwnd
, data
->pwszWizardTitle
,
5380 static BOOL
show_import_ui(DWORD dwFlags
, HWND hwndParent
,
5381 LPCWSTR pwszWizardTitle
, PCCRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc
,
5382 HCERTSTORE hDestCertStore
)
5384 PROPSHEETHEADERW hdr
;
5385 PROPSHEETPAGEW pages
[4];
5386 struct ImportWizData data
;
5389 data
.dwFlags
= dwFlags
;
5390 data
.pwszWizardTitle
= pwszWizardTitle
;
5393 memcpy(&data
.importSrc
, pImportSrc
, sizeof(data
.importSrc
));
5394 data
.fileName
= (LPWSTR
)pImportSrc
->u
.pwszFileName
;
5398 memset(&data
.importSrc
, 0, sizeof(data
.importSrc
));
5399 data
.fileName
= NULL
;
5401 data
.freeSource
= FALSE
;
5402 data
.hDestCertStore
= hDestCertStore
;
5403 data
.freeDest
= FALSE
;
5404 data
.autoDest
= TRUE
;
5405 data
.success
= TRUE
;
5407 memset(&pages
, 0, sizeof(pages
));
5409 pages
[nPages
].dwSize
= sizeof(pages
[0]);
5410 pages
[nPages
].hInstance
= hInstance
;
5411 pages
[nPages
].u
.pszTemplate
= MAKEINTRESOURCEW(IDD_IMPORT_WELCOME
);
5412 pages
[nPages
].pfnDlgProc
= import_welcome_dlg_proc
;
5413 pages
[nPages
].dwFlags
= PSP_HIDEHEADER
;
5414 pages
[nPages
].lParam
= (LPARAM
)&data
;
5418 pImportSrc
->dwSubjectChoice
== CRYPTUI_WIZ_IMPORT_SUBJECT_FILE
)
5420 pages
[nPages
].dwSize
= sizeof(pages
[0]);
5421 pages
[nPages
].hInstance
= hInstance
;
5422 pages
[nPages
].u
.pszTemplate
= MAKEINTRESOURCEW(IDD_IMPORT_FILE
);
5423 pages
[nPages
].pfnDlgProc
= import_file_dlg_proc
;
5424 pages
[nPages
].dwFlags
= PSP_USEHEADERTITLE
| PSP_USEHEADERSUBTITLE
;
5425 pages
[nPages
].pszHeaderTitle
= MAKEINTRESOURCEW(IDS_IMPORT_FILE_TITLE
);
5426 pages
[nPages
].pszHeaderSubTitle
=
5427 MAKEINTRESOURCEW(IDS_IMPORT_FILE_SUBTITLE
);
5428 pages
[nPages
].lParam
= (LPARAM
)&data
;
5433 switch (pImportSrc
->dwSubjectChoice
)
5435 case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_CONTEXT
:
5436 data
.contentType
= CERT_QUERY_CONTENT_CERT
;
5438 case CRYPTUI_WIZ_IMPORT_SUBJECT_CRL_CONTEXT
:
5439 data
.contentType
= CERT_QUERY_CONTENT_CRL
;
5441 case CRYPTUI_WIZ_IMPORT_SUBJECT_CTL_CONTEXT
:
5442 data
.contentType
= CERT_QUERY_CONTENT_CTL
;
5444 case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE
:
5445 data
.contentType
= CERT_QUERY_CONTENT_SERIALIZED_STORE
;
5450 pages
[nPages
].dwSize
= sizeof(pages
[0]);
5451 pages
[nPages
].hInstance
= hInstance
;
5452 pages
[nPages
].u
.pszTemplate
= MAKEINTRESOURCEW(IDD_IMPORT_STORE
);
5453 pages
[nPages
].pfnDlgProc
= import_store_dlg_proc
;
5454 pages
[nPages
].dwFlags
= PSP_USEHEADERTITLE
| PSP_USEHEADERSUBTITLE
;
5455 pages
[nPages
].pszHeaderTitle
= MAKEINTRESOURCEW(IDS_IMPORT_STORE_TITLE
);
5456 pages
[nPages
].pszHeaderSubTitle
=
5457 MAKEINTRESOURCEW(IDS_IMPORT_STORE_SUBTITLE
);
5458 pages
[nPages
].lParam
= (LPARAM
)&data
;
5461 pages
[nPages
].dwSize
= sizeof(pages
[0]);
5462 pages
[nPages
].hInstance
= hInstance
;
5463 pages
[nPages
].u
.pszTemplate
= MAKEINTRESOURCEW(IDD_IMPORT_FINISH
);
5464 pages
[nPages
].pfnDlgProc
= import_finish_dlg_proc
;
5465 pages
[nPages
].dwFlags
= PSP_HIDEHEADER
;
5466 pages
[nPages
].lParam
= (LPARAM
)&data
;
5469 memset(&hdr
, 0, sizeof(hdr
));
5470 hdr
.dwSize
= sizeof(hdr
);
5471 hdr
.hwndParent
= hwndParent
;
5472 hdr
.dwFlags
= PSH_PROPSHEETPAGE
| PSH_WIZARD97_NEW
| PSH_HEADER
|
5474 hdr
.hInstance
= hInstance
;
5475 if (pwszWizardTitle
)
5476 hdr
.pszCaption
= pwszWizardTitle
;
5478 hdr
.pszCaption
= MAKEINTRESOURCEW(IDS_IMPORT_WIZARD
);
5479 hdr
.u3
.ppsp
= pages
;
5480 hdr
.nPages
= nPages
;
5481 hdr
.u4
.pszbmWatermark
= MAKEINTRESOURCEW(IDB_CERT_WATERMARK
);
5482 hdr
.u5
.pszbmHeader
= MAKEINTRESOURCEW(IDB_CERT_HEADER
);
5483 PropertySheetW(&hdr
);
5484 if (data
.fileName
!= data
.importSrc
.u
.pwszFileName
)
5485 HeapFree(GetProcessHeap(), 0, data
.fileName
);
5486 if (data
.freeSource
&&
5487 data
.importSrc
.dwSubjectChoice
== CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE
)
5488 CertCloseStore(data
.importSrc
.u
.hCertStore
, 0);
5489 DeleteObject(data
.titleFont
);
5490 return data
.success
;
5493 BOOL WINAPI
CryptUIWizImport(DWORD dwFlags
, HWND hwndParent
, LPCWSTR pwszWizardTitle
,
5494 PCCRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc
, HCERTSTORE hDestCertStore
)
5498 TRACE("(0x%08x, %p, %s, %p, %p)\n", dwFlags
, hwndParent
, debugstr_w(pwszWizardTitle
),
5499 pImportSrc
, hDestCertStore
);
5502 pImportSrc
->dwSize
!= sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO
))
5504 SetLastError(E_INVALIDARG
);
5508 if (!(dwFlags
& CRYPTUI_WIZ_NO_UI
))
5509 ret
= show_import_ui(dwFlags
, hwndParent
, pwszWizardTitle
, pImportSrc
,
5511 else if (pImportSrc
)
5512 ret
= do_import(dwFlags
, hwndParent
, pwszWizardTitle
, pImportSrc
,
5516 /* Can't have no UI without specifying source */
5517 SetLastError(E_INVALIDARG
);
5524 struct ExportWizData
5528 LPCWSTR pwszWizardTitle
;
5529 CRYPTUI_WIZ_EXPORT_INFO exportInfo
;
5530 CRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO contextInfo
;
5532 PCRYPT_KEY_PROV_INFO keyProvInfo
;
5539 static LRESULT CALLBACK
export_welcome_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wp
,
5548 struct ExportWizData
*data
;
5549 PROPSHEETPAGEW
*page
= (PROPSHEETPAGEW
*)lp
;
5550 WCHAR fontFace
[MAX_STRING_LEN
];
5551 HDC hDC
= GetDC(hwnd
);
5554 data
= (struct ExportWizData
*)page
->lParam
;
5555 LoadStringW(hInstance
, IDS_WIZARD_TITLE_FONT
, fontFace
,
5556 sizeof(fontFace
) / sizeof(fontFace
[0]));
5557 height
= -MulDiv(12, GetDeviceCaps(hDC
, LOGPIXELSY
), 72);
5558 data
->titleFont
= CreateFontW(height
, 0, 0, 0, FW_BOLD
, 0, 0, 0,
5559 DEFAULT_CHARSET
, OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
,
5560 DEFAULT_QUALITY
, DEFAULT_PITCH
| FF_DONTCARE
, fontFace
);
5561 SendMessageW(GetDlgItem(hwnd
, IDC_EXPORT_TITLE
), WM_SETFONT
,
5562 (WPARAM
)data
->titleFont
, TRUE
);
5563 ReleaseDC(hwnd
, hDC
);
5568 NMHDR
*hdr
= (NMHDR
*)lp
;
5573 PostMessageW(GetParent(hwnd
), PSM_SETWIZBUTTONS
, 0, PSWIZB_NEXT
);
5583 static PCRYPT_KEY_PROV_INFO
export_get_private_key_info(PCCERT_CONTEXT cert
)
5585 PCRYPT_KEY_PROV_INFO info
= NULL
;
5588 if (CertGetCertificateContextProperty(cert
, CERT_KEY_PROV_INFO_PROP_ID
,
5591 info
= HeapAlloc(GetProcessHeap(), 0, size
);
5594 if (!CertGetCertificateContextProperty(cert
,
5595 CERT_KEY_PROV_INFO_PROP_ID
, info
, &size
))
5597 HeapFree(GetProcessHeap(), 0, info
);
5605 static BOOL
export_acquire_private_key(PCRYPT_KEY_PROV_INFO info
,
5610 ret
= CryptAcquireContextW(phProv
, info
->pwszContainerName
,
5611 info
->pwszProvName
, info
->dwProvType
, 0);
5616 for (i
= 0; i
< info
->cProvParam
; i
++)
5617 CryptSetProvParam(*phProv
, info
->rgProvParam
[i
].dwParam
,
5618 info
->rgProvParam
[i
].pbData
, info
->rgProvParam
[i
].dwFlags
);
5623 static BOOL
export_is_key_exportable(HCRYPTPROV hProv
, DWORD keySpec
)
5628 if ((ret
= CryptGetUserKey(hProv
, keySpec
, &key
)))
5630 DWORD permissions
, size
= sizeof(permissions
);
5632 if ((ret
= CryptGetKeyParam(key
, KP_PERMISSIONS
, (BYTE
*)&permissions
,
5633 &size
, 0)) && !(permissions
& CRYPT_EXPORT
))
5635 CryptDestroyKey(key
);
5640 static LRESULT CALLBACK
export_private_key_dlg_proc(HWND hwnd
, UINT msg
,
5641 WPARAM wp
, LPARAM lp
)
5644 struct ExportWizData
*data
;
5650 PROPSHEETPAGEW
*page
= (PROPSHEETPAGEW
*)lp
;
5651 PCRYPT_KEY_PROV_INFO info
;
5652 HCRYPTPROV hProv
= 0;
5655 data
= (struct ExportWizData
*)page
->lParam
;
5656 SetWindowLongPtrW(hwnd
, DWLP_USER
, (LPARAM
)data
);
5657 /* Get enough information about a key to see whether it's exportable.
5659 if (!(info
= export_get_private_key_info(
5660 data
->exportInfo
.u
.pCertContext
)))
5661 errorID
= IDS_EXPORT_PRIVATE_KEY_UNAVAILABLE
;
5662 else if (!export_acquire_private_key(info
, &hProv
))
5663 errorID
= IDS_EXPORT_PRIVATE_KEY_UNAVAILABLE
;
5664 else if (!export_is_key_exportable(hProv
, info
->dwKeySpec
))
5665 errorID
= IDS_EXPORT_PRIVATE_KEY_NON_EXPORTABLE
;
5669 WCHAR error
[MAX_STRING_LEN
];
5671 LoadStringW(hInstance
, errorID
, error
,
5672 sizeof(error
) / sizeof(error
[0]));
5673 SendMessageW(GetDlgItem(hwnd
, IDC_EXPORT_PRIVATE_KEY_UNAVAILABLE
),
5674 WM_SETTEXT
, 0, (LPARAM
)error
);
5675 EnableWindow(GetDlgItem(hwnd
, IDC_EXPORT_PRIVATE_KEY_YES
), FALSE
);
5678 data
->keyProvInfo
= info
;
5680 CryptReleaseContext(hProv
, 0);
5681 SendMessageW(GetDlgItem(hwnd
, IDC_EXPORT_PRIVATE_KEY_NO
), BM_CLICK
,
5687 NMHDR
*hdr
= (NMHDR
*)lp
;
5692 PostMessageW(GetParent(hwnd
), PSM_SETWIZBUTTONS
, 0,
5693 PSWIZB_BACK
| PSWIZB_NEXT
);
5697 data
= (struct ExportWizData
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
5698 if (IsDlgButtonChecked(hwnd
, IDC_EXPORT_PRIVATE_KEY_NO
))
5700 data
->contextInfo
.dwExportFormat
=
5701 CRYPTUI_WIZ_EXPORT_FORMAT_DER
;
5702 data
->contextInfo
.fExportPrivateKeys
= FALSE
;
5706 data
->contextInfo
.dwExportFormat
=
5707 CRYPTUI_WIZ_EXPORT_FORMAT_PFX
;
5708 data
->contextInfo
.fExportPrivateKeys
= TRUE
;
5718 static BOOL
export_info_has_private_key(PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo
)
5722 if (pExportInfo
->dwSubjectChoice
== CRYPTUI_WIZ_EXPORT_CERT_CONTEXT
)
5726 /* If there's a CRYPT_KEY_PROV_INFO set for this cert, assume the
5727 * cert has a private key.
5729 if (CertGetCertificateContextProperty(pExportInfo
->u
.pCertContext
,
5730 CERT_KEY_PROV_INFO_PROP_ID
, NULL
, &size
))
5736 static void export_format_enable_controls(HWND hwnd
, struct ExportWizData
*data
)
5738 int defaultFormatID
;
5740 switch (data
->contextInfo
.dwExportFormat
)
5742 case CRYPTUI_WIZ_EXPORT_FORMAT_BASE64
:
5743 defaultFormatID
= IDC_EXPORT_FORMAT_BASE64
;
5745 case CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7
:
5746 defaultFormatID
= IDC_EXPORT_FORMAT_CMS
;
5748 case CRYPTUI_WIZ_EXPORT_FORMAT_PFX
:
5749 defaultFormatID
= IDC_EXPORT_FORMAT_PFX
;
5752 defaultFormatID
= IDC_EXPORT_FORMAT_DER
;
5754 SendMessageW(GetDlgItem(hwnd
, defaultFormatID
), BM_CLICK
, 0, 0);
5755 if (defaultFormatID
== IDC_EXPORT_FORMAT_PFX
)
5757 EnableWindow(GetDlgItem(hwnd
, IDC_EXPORT_FORMAT_DER
), FALSE
);
5758 EnableWindow(GetDlgItem(hwnd
, IDC_EXPORT_FORMAT_BASE64
), FALSE
);
5759 EnableWindow(GetDlgItem(hwnd
, IDC_EXPORT_FORMAT_CMS
), FALSE
);
5760 EnableWindow(GetDlgItem(hwnd
, IDC_EXPORT_FORMAT_PFX
), TRUE
);
5764 EnableWindow(GetDlgItem(hwnd
, IDC_EXPORT_FORMAT_DER
), TRUE
);
5765 EnableWindow(GetDlgItem(hwnd
, IDC_EXPORT_FORMAT_BASE64
), TRUE
);
5766 EnableWindow(GetDlgItem(hwnd
, IDC_EXPORT_FORMAT_CMS
), TRUE
);
5767 EnableWindow(GetDlgItem(hwnd
, IDC_EXPORT_FORMAT_PFX
), FALSE
);
5771 static LRESULT CALLBACK
export_format_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wp
,
5775 struct ExportWizData
*data
;
5781 PROPSHEETPAGEW
*page
= (PROPSHEETPAGEW
*)lp
;
5783 data
= (struct ExportWizData
*)page
->lParam
;
5784 SetWindowLongPtrW(hwnd
, DWLP_USER
, (LPARAM
)data
);
5785 export_format_enable_controls(hwnd
, data
);
5790 NMHDR
*hdr
= (NMHDR
*)lp
;
5795 PostMessageW(GetParent(hwnd
), PSM_SETWIZBUTTONS
, 0,
5796 PSWIZB_BACK
| PSWIZB_NEXT
);
5797 data
= (struct ExportWizData
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
5798 export_format_enable_controls(hwnd
, data
);
5803 BOOL skipPasswordPage
= TRUE
;
5805 data
= (struct ExportWizData
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
5806 if (IsDlgButtonChecked(hwnd
, IDC_EXPORT_FORMAT_DER
))
5807 data
->contextInfo
.dwExportFormat
=
5808 CRYPTUI_WIZ_EXPORT_FORMAT_DER
;
5809 else if (IsDlgButtonChecked(hwnd
, IDC_EXPORT_FORMAT_BASE64
))
5810 data
->contextInfo
.dwExportFormat
=
5811 CRYPTUI_WIZ_EXPORT_FORMAT_BASE64
;
5812 else if (IsDlgButtonChecked(hwnd
, IDC_EXPORT_FORMAT_CMS
))
5814 data
->contextInfo
.dwExportFormat
=
5815 CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7
;
5816 if (IsDlgButtonChecked(hwnd
, IDC_EXPORT_CMS_INCLUDE_CHAIN
))
5817 data
->contextInfo
.fExportChain
=
5818 CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7
;
5822 data
->contextInfo
.dwExportFormat
=
5823 CRYPTUI_WIZ_EXPORT_FORMAT_PFX
;
5824 if (IsDlgButtonChecked(hwnd
, IDC_EXPORT_PFX_INCLUDE_CHAIN
))
5825 data
->contextInfo
.fExportChain
= TRUE
;
5826 if (IsDlgButtonChecked(hwnd
, IDC_EXPORT_PFX_STRONG_ENCRYPTION
))
5827 data
->contextInfo
.fStrongEncryption
= TRUE
;
5828 if (IsDlgButtonChecked(hwnd
, IDC_EXPORT_PFX_DELETE_PRIVATE_KEY
))
5829 data
->deleteKeys
= TRUE
;
5830 skipPasswordPage
= FALSE
;
5832 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
,
5833 skipPasswordPage
? IDD_EXPORT_FILE
: 0);
5846 case IDC_EXPORT_FORMAT_DER
:
5847 case IDC_EXPORT_FORMAT_BASE64
:
5848 EnableWindow(GetDlgItem(hwnd
, IDC_EXPORT_CMS_INCLUDE_CHAIN
),
5850 EnableWindow(GetDlgItem(hwnd
, IDC_EXPORT_PFX_INCLUDE_CHAIN
),
5852 EnableWindow(GetDlgItem(hwnd
, IDC_EXPORT_PFX_STRONG_ENCRYPTION
),
5854 EnableWindow(GetDlgItem(hwnd
,
5855 IDC_EXPORT_PFX_DELETE_PRIVATE_KEY
), FALSE
);
5857 case IDC_EXPORT_FORMAT_CMS
:
5858 EnableWindow(GetDlgItem(hwnd
, IDC_EXPORT_CMS_INCLUDE_CHAIN
),
5861 case IDC_EXPORT_FORMAT_PFX
:
5862 EnableWindow(GetDlgItem(hwnd
, IDC_EXPORT_PFX_INCLUDE_CHAIN
),
5864 EnableWindow(GetDlgItem(hwnd
, IDC_EXPORT_PFX_STRONG_ENCRYPTION
),
5866 EnableWindow(GetDlgItem(hwnd
,
5867 IDC_EXPORT_PFX_DELETE_PRIVATE_KEY
), TRUE
);
5877 static void export_password_mismatch(HWND hwnd
, struct ExportWizData
*data
)
5879 WCHAR title
[MAX_STRING_LEN
], error
[MAX_STRING_LEN
];
5882 if (data
->pwszWizardTitle
)
5883 pTitle
= data
->pwszWizardTitle
;
5886 LoadStringW(hInstance
, IDS_EXPORT_WIZARD
, title
,
5887 sizeof(title
) / sizeof(title
[0]));
5890 LoadStringW(hInstance
, IDS_EXPORT_PASSWORD_MISMATCH
, error
,
5891 sizeof(error
) / sizeof(error
[0]));
5892 MessageBoxW(hwnd
, error
, pTitle
, MB_ICONERROR
| MB_OK
);
5893 SetFocus(GetDlgItem(hwnd
, IDC_EXPORT_PASSWORD
));
5896 static LRESULT CALLBACK
export_password_dlg_proc(HWND hwnd
, UINT msg
,
5897 WPARAM wp
, LPARAM lp
)
5900 struct ExportWizData
*data
;
5906 PROPSHEETPAGEW
*page
= (PROPSHEETPAGEW
*)lp
;
5908 data
= (struct ExportWizData
*)page
->lParam
;
5909 SetWindowLongPtrW(hwnd
, DWLP_USER
, (LPARAM
)data
);
5914 NMHDR
*hdr
= (NMHDR
*)lp
;
5919 PostMessageW(GetParent(hwnd
), PSM_SETWIZBUTTONS
, 0,
5920 PSWIZB_BACK
| PSWIZB_NEXT
);
5925 HWND passwordEdit
= GetDlgItem(hwnd
, IDC_EXPORT_PASSWORD
);
5926 HWND passwordConfirmEdit
= GetDlgItem(hwnd
,
5927 IDC_EXPORT_PASSWORD_CONFIRM
);
5928 DWORD passwordLen
= SendMessageW(passwordEdit
, WM_GETTEXTLENGTH
,
5930 DWORD passwordConfirmLen
= SendMessageW(passwordConfirmEdit
,
5931 WM_GETTEXTLENGTH
, 0, 0);
5933 data
= (struct ExportWizData
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
5934 if (!passwordLen
&& !passwordConfirmLen
)
5935 data
->contextInfo
.pwszPassword
= NULL
;
5936 else if (passwordLen
!= passwordConfirmLen
)
5938 export_password_mismatch(hwnd
, data
);
5939 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, 1);
5944 LPWSTR password
= HeapAlloc(GetProcessHeap(), 0,
5945 (passwordLen
+ 1) * sizeof(WCHAR
));
5946 LPWSTR passwordConfirm
= HeapAlloc(GetProcessHeap(), 0,
5947 (passwordConfirmLen
+ 1) * sizeof(WCHAR
));
5948 BOOL freePassword
= TRUE
;
5950 if (password
&& passwordConfirm
)
5952 SendMessageW(passwordEdit
, WM_GETTEXT
, passwordLen
+ 1,
5954 SendMessageW(passwordConfirmEdit
, WM_GETTEXT
,
5955 passwordConfirmLen
+ 1, (LPARAM
)passwordConfirm
);
5956 if (strcmpW(password
, passwordConfirm
))
5958 export_password_mismatch(hwnd
, data
);
5959 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, 1);
5964 data
->contextInfo
.pwszPassword
= password
;
5965 freePassword
= FALSE
;
5966 data
->freePassword
= TRUE
;
5970 HeapFree(GetProcessHeap(), 0, password
);
5971 HeapFree(GetProcessHeap(), 0, passwordConfirm
);
5982 static LPWSTR
export_append_extension(struct ExportWizData
*data
,
5985 static const WCHAR cer
[] = { '.','c','e','r',0 };
5986 static const WCHAR crl
[] = { '.','c','r','l',0 };
5987 static const WCHAR ctl
[] = { '.','c','t','l',0 };
5988 static const WCHAR p7b
[] = { '.','p','7','b',0 };
5989 static const WCHAR pfx
[] = { '.','p','f','x',0 };
5990 static const WCHAR sst
[] = { '.','s','s','t',0 };
5993 BOOL appendExtension
;
5995 switch (data
->contextInfo
.dwExportFormat
)
5997 case CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7
:
6000 case CRYPTUI_WIZ_EXPORT_FORMAT_PFX
:
6004 switch (data
->exportInfo
.dwSubjectChoice
)
6006 case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT
:
6009 case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT
:
6012 case CRYPTUI_WIZ_EXPORT_CERT_STORE
:
6019 dot
= strrchrW(fileName
, '.');
6021 appendExtension
= strcmpiW(dot
, extension
) != 0;
6023 appendExtension
= TRUE
;
6024 if (appendExtension
)
6026 fileName
= HeapReAlloc(GetProcessHeap(), 0, fileName
,
6027 (strlenW(fileName
) + strlenW(extension
) + 1) * sizeof(WCHAR
));
6029 strcatW(fileName
, extension
);
6034 static BOOL
export_validate_filename(HWND hwnd
, struct ExportWizData
*data
,
6038 BOOL tryCreate
= TRUE
, forceCreate
= FALSE
, ret
= FALSE
;
6040 file
= CreateFileW(fileName
, GENERIC_WRITE
,
6041 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, 0, NULL
);
6042 if (file
!= INVALID_HANDLE_VALUE
)
6044 WCHAR warning
[MAX_STRING_LEN
], title
[MAX_STRING_LEN
];
6047 if (data
->pwszWizardTitle
)
6048 pTitle
= data
->pwszWizardTitle
;
6051 LoadStringW(hInstance
, IDS_EXPORT_WIZARD
, title
,
6052 sizeof(title
) / sizeof(title
[0]));
6055 LoadStringW(hInstance
, IDS_EXPORT_FILE_EXISTS
, warning
,
6056 sizeof(warning
) / sizeof(warning
[0]));
6057 if (MessageBoxW(hwnd
, warning
, pTitle
, MB_YESNO
) == IDYES
)
6065 file
= CreateFileW(fileName
, GENERIC_WRITE
,
6066 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
6067 forceCreate
? CREATE_ALWAYS
: CREATE_NEW
,
6069 if (file
!= INVALID_HANDLE_VALUE
)
6076 WCHAR title
[MAX_STRING_LEN
], error
[MAX_STRING_LEN
];
6078 LPWSTR msgBuf
, fullError
;
6080 if (data
->pwszWizardTitle
)
6081 pTitle
= data
->pwszWizardTitle
;
6084 LoadStringW(hInstance
, IDS_EXPORT_WIZARD
, title
,
6085 sizeof(title
) / sizeof(title
[0]));
6088 LoadStringW(hInstance
, IDS_IMPORT_OPEN_FAILED
, error
,
6089 sizeof(error
) / sizeof(error
[0]));
6091 FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
, NULL
,
6092 GetLastError(), 0, (LPWSTR
) &msgBuf
, 0, NULL
);
6093 fullError
= HeapAlloc(GetProcessHeap(), 0,
6094 (strlenW(error
) + strlenW(fileName
) + strlenW(msgBuf
) + 3)
6098 LPWSTR ptr
= fullError
;
6100 strcpyW(ptr
, error
);
6101 ptr
+= strlenW(error
);
6102 strcpyW(ptr
, fileName
);
6103 ptr
+= strlenW(fileName
);
6106 strcpyW(ptr
, msgBuf
);
6107 MessageBoxW(hwnd
, fullError
, pTitle
, MB_ICONERROR
| MB_OK
);
6108 HeapFree(GetProcessHeap(), 0, fullError
);
6116 static const WCHAR export_filter_cert
[] = { '*','.','c','e','r',0 };
6117 static const WCHAR export_filter_crl
[] = { '*','.','c','r','l',0 };
6118 static const WCHAR export_filter_ctl
[] = { '*','.','s','t','l',0 };
6119 static const WCHAR export_filter_cms
[] = { '*','.','p','7','b',0 };
6120 static const WCHAR export_filter_pfx
[] = { '*','.','p','f','x',0 };
6121 static const WCHAR export_filter_sst
[] = { '*','.','s','s','t',0 };
6123 static WCHAR
*make_export_file_filter(DWORD exportFormat
, DWORD subjectChoice
)
6125 int baseLen
, allLen
, totalLen
= 2, baseID
;
6126 LPWSTR filter
= NULL
, baseFilter
, all
;
6129 switch (exportFormat
)
6131 case CRYPTUI_WIZ_EXPORT_FORMAT_BASE64
:
6132 baseID
= IDS_EXPORT_FILTER_BASE64_CERT
;
6133 filterStr
= export_filter_cert
;
6135 case CRYPTUI_WIZ_EXPORT_FORMAT_PFX
:
6136 baseID
= IDS_EXPORT_FILTER_PFX
;
6137 filterStr
= export_filter_pfx
;
6139 case CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7
:
6140 baseID
= IDS_EXPORT_FILTER_CMS
;
6141 filterStr
= export_filter_cms
;
6144 switch (subjectChoice
)
6146 case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT
:
6147 baseID
= IDS_EXPORT_FILTER_CRL
;
6148 filterStr
= export_filter_crl
;
6150 case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT
:
6151 baseID
= IDS_EXPORT_FILTER_CTL
;
6152 filterStr
= export_filter_ctl
;
6154 case CRYPTUI_WIZ_EXPORT_CERT_STORE
:
6155 baseID
= IDS_EXPORT_FILTER_SERIALIZED_CERT_STORE
;
6156 filterStr
= export_filter_sst
;
6159 baseID
= IDS_EXPORT_FILTER_CERT
;
6160 filterStr
= export_filter_cert
;
6164 baseLen
= LoadStringW(hInstance
, baseID
, (LPWSTR
)&baseFilter
, 0);
6165 totalLen
+= baseLen
+ strlenW(filterStr
) + 2;
6166 allLen
= LoadStringW(hInstance
, IDS_IMPORT_FILTER_ALL
, (LPWSTR
)&all
, 0);
6167 totalLen
+= allLen
+ strlenW(filter_all
) + 2;
6168 filter
= HeapAlloc(GetProcessHeap(), 0, totalLen
* sizeof(WCHAR
));
6174 memcpy(ptr
, baseFilter
, baseLen
* sizeof(WCHAR
));
6177 strcpyW(ptr
, filterStr
);
6178 ptr
+= strlenW(filterStr
) + 1;
6179 memcpy(ptr
, all
, allLen
* sizeof(WCHAR
));
6182 strcpyW(ptr
, filter_all
);
6183 ptr
+= strlenW(filter_all
) + 1;
6189 static LRESULT CALLBACK
export_file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wp
,
6193 struct ExportWizData
*data
;
6199 PROPSHEETPAGEW
*page
= (PROPSHEETPAGEW
*)lp
;
6201 data
= (struct ExportWizData
*)page
->lParam
;
6202 SetWindowLongPtrW(hwnd
, DWLP_USER
, (LPARAM
)data
);
6203 if (data
->exportInfo
.pwszExportFileName
)
6204 SendMessageW(GetDlgItem(hwnd
, IDC_EXPORT_FILENAME
), WM_SETTEXT
, 0,
6205 (LPARAM
)data
->exportInfo
.pwszExportFileName
);
6210 NMHDR
*hdr
= (NMHDR
*)lp
;
6215 data
= (struct ExportWizData
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
6216 if (data
->contextInfo
.dwExportFormat
!=
6217 CRYPTUI_WIZ_EXPORT_FORMAT_PFX
)
6219 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, IDD_EXPORT_FORMAT
);
6225 HWND fileNameEdit
= GetDlgItem(hwnd
, IDC_EXPORT_FILENAME
);
6226 DWORD len
= SendMessageW(fileNameEdit
, WM_GETTEXTLENGTH
, 0, 0);
6228 data
= (struct ExportWizData
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
6231 WCHAR title
[MAX_STRING_LEN
], error
[MAX_STRING_LEN
];
6234 if (data
->pwszWizardTitle
)
6235 pTitle
= data
->pwszWizardTitle
;
6238 LoadStringW(hInstance
, IDS_EXPORT_WIZARD
, title
,
6239 sizeof(title
) / sizeof(title
[0]));
6242 LoadStringW(hInstance
, IDS_IMPORT_EMPTY_FILE
, error
,
6243 sizeof(error
) / sizeof(error
[0]));
6244 MessageBoxW(hwnd
, error
, pTitle
, MB_ICONERROR
| MB_OK
);
6245 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, 1);
6250 LPWSTR fileName
= HeapAlloc(GetProcessHeap(), 0,
6251 (len
+ 1) * sizeof(WCHAR
));
6255 SendMessageW(fileNameEdit
, WM_GETTEXT
, len
+ 1,
6257 fileName
= export_append_extension(data
, fileName
);
6258 if (!export_validate_filename(hwnd
, data
, fileName
))
6260 HeapFree(GetProcessHeap(), 0, fileName
);
6261 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, 1);
6265 data
->fileName
= fileName
;
6271 PostMessageW(GetParent(hwnd
), PSM_SETWIZBUTTONS
, 0,
6272 PSWIZB_BACK
| PSWIZB_NEXT
);
6281 case IDC_EXPORT_BROWSE_FILE
:
6284 WCHAR fileBuf
[MAX_PATH
];
6286 data
= (struct ExportWizData
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
6287 memset(&ofn
, 0, sizeof(ofn
));
6288 ofn
.lStructSize
= sizeof(ofn
);
6289 ofn
.hwndOwner
= hwnd
;
6290 ofn
.lpstrFilter
= make_export_file_filter(
6291 data
->contextInfo
.dwExportFormat
,
6292 data
->exportInfo
.dwSubjectChoice
);
6293 ofn
.lpstrFile
= fileBuf
;
6294 ofn
.nMaxFile
= sizeof(fileBuf
) / sizeof(fileBuf
[0]);
6296 if (GetSaveFileNameW(&ofn
))
6297 SendMessageW(GetDlgItem(hwnd
, IDC_EXPORT_FILENAME
), WM_SETTEXT
,
6298 0, (LPARAM
)ofn
.lpstrFile
);
6299 HeapFree(GetProcessHeap(), 0, (LPWSTR
)ofn
.lpstrFilter
);
6308 static void show_export_details(HWND lv
, struct ExportWizData
*data
)
6310 WCHAR text
[MAX_STRING_LEN
];
6314 item
.mask
= LVIF_TEXT
;
6317 item
.iItem
= SendMessageW(lv
, LVM_GETITEMCOUNT
, 0, 0);
6319 LoadStringW(hInstance
, IDS_IMPORT_FILE
, text
,
6320 sizeof(text
)/ sizeof(text
[0]));
6321 item
.pszText
= text
;
6322 SendMessageW(lv
, LVM_INSERTITEMW
, 0, (LPARAM
)&item
);
6324 item
.pszText
= data
->fileName
;
6325 SendMessageW(lv
, LVM_SETITEMTEXTW
, item
.iItem
, (LPARAM
)&item
);
6328 item
.pszText
= text
;
6329 switch (data
->exportInfo
.dwSubjectChoice
)
6331 case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT
:
6332 case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT
:
6333 case CRYPTUI_WIZ_EXPORT_CERT_STORE
:
6334 case CRYPTUI_WIZ_EXPORT_CERT_STORE_CERTIFICATES_ONLY
:
6339 item
.iItem
= SendMessageW(lv
, LVM_GETITEMCOUNT
, 0, 0);
6341 LoadStringW(hInstance
, IDS_EXPORT_INCLUDE_CHAIN
, text
,
6342 sizeof(text
) / sizeof(text
[0]));
6343 SendMessageW(lv
, LVM_INSERTITEMW
, item
.iItem
, (LPARAM
)&item
);
6345 LoadStringW(hInstance
,
6346 data
->contextInfo
.fExportChain
? IDS_YES
: IDS_NO
, text
,
6347 sizeof(text
) / sizeof(text
[0]));
6348 SendMessageW(lv
, LVM_SETITEMTEXTW
, item
.iItem
, (LPARAM
)&item
);
6350 item
.iItem
= SendMessageW(lv
, LVM_GETITEMCOUNT
, 0, 0);
6352 LoadStringW(hInstance
, IDS_EXPORT_KEYS
, text
,
6353 sizeof(text
) / sizeof(text
[0]));
6354 SendMessageW(lv
, LVM_INSERTITEMW
, item
.iItem
, (LPARAM
)&item
);
6356 LoadStringW(hInstance
,
6357 data
->contextInfo
.fExportPrivateKeys
? IDS_YES
: IDS_NO
, text
,
6358 sizeof(text
) / sizeof(text
[0]));
6359 SendMessageW(lv
, LVM_SETITEMTEXTW
, item
.iItem
, (LPARAM
)&item
);
6363 item
.iItem
= SendMessageW(lv
, LVM_GETITEMCOUNT
, 0, 0);
6365 LoadStringW(hInstance
, IDS_EXPORT_FORMAT
, text
,
6366 sizeof(text
)/ sizeof(text
[0]));
6367 SendMessageW(lv
, LVM_INSERTITEMW
, 0, (LPARAM
)&item
);
6370 switch (data
->exportInfo
.dwSubjectChoice
)
6372 case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT
:
6373 contentID
= IDS_EXPORT_FILTER_CRL
;
6375 case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT
:
6376 contentID
= IDS_EXPORT_FILTER_CTL
;
6378 case CRYPTUI_WIZ_EXPORT_CERT_STORE
:
6379 contentID
= IDS_EXPORT_FILTER_SERIALIZED_CERT_STORE
;
6382 switch (data
->contextInfo
.dwExportFormat
)
6384 case CRYPTUI_WIZ_EXPORT_FORMAT_BASE64
:
6385 contentID
= IDS_EXPORT_FILTER_BASE64_CERT
;
6387 case CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7
:
6388 contentID
= IDS_EXPORT_FILTER_CMS
;
6390 case CRYPTUI_WIZ_EXPORT_FORMAT_PFX
:
6391 contentID
= IDS_EXPORT_FILTER_PFX
;
6394 contentID
= IDS_EXPORT_FILTER_CERT
;
6397 LoadStringW(hInstance
, contentID
, text
, sizeof(text
) / sizeof(text
[0]));
6398 SendMessageW(lv
, LVM_SETITEMTEXTW
, item
.iItem
, (LPARAM
)&item
);
6401 static inline BOOL
save_der(HANDLE file
, const BYTE
*pb
, DWORD cb
)
6405 return WriteFile(file
, pb
, cb
, &bytesWritten
, NULL
);
6408 static BOOL
save_base64(HANDLE file
, const BYTE
*pb
, DWORD cb
)
6413 if ((ret
= CryptBinaryToStringA(pb
, cb
, CRYPT_STRING_BASE64
, NULL
, &size
)))
6415 LPSTR buf
= HeapAlloc(GetProcessHeap(), 0, size
);
6419 if ((ret
= CryptBinaryToStringA(pb
, cb
, CRYPT_STRING_BASE64
, buf
,
6421 ret
= WriteFile(file
, buf
, size
, &size
, NULL
);
6422 HeapFree(GetProcessHeap(), 0, buf
);
6426 SetLastError(ERROR_OUTOFMEMORY
);
6433 static inline BOOL
save_store_as_cms(HANDLE file
, HCERTSTORE store
)
6435 return CertSaveStore(store
, PKCS_7_ASN_ENCODING
| X509_ASN_ENCODING
,
6436 CERT_STORE_SAVE_AS_PKCS7
, CERT_STORE_SAVE_TO_FILE
, file
, 0);
6439 static BOOL
save_cert_as_cms(HANDLE file
, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo
,
6443 HCERTSTORE store
= CertOpenStore(CERT_STORE_PROV_MEMORY
, 0, 0,
6444 CERT_STORE_CREATE_NEW_FLAG
, NULL
);
6450 HCERTSTORE addlStore
= CertOpenStore(CERT_STORE_PROV_COLLECTION
,
6451 0, 0, CERT_STORE_CREATE_NEW_FLAG
, NULL
);
6458 for (i
= 0; ret
&& i
< pExportInfo
->cStores
; i
++)
6459 ret
= CertAddStoreToCollection(addlStore
,
6460 pExportInfo
->rghStores
, 0, 0);
6463 PCCERT_CHAIN_CONTEXT chain
;
6465 ret
= CertGetCertificateChain(NULL
,
6466 pExportInfo
->u
.pCertContext
, NULL
, addlStore
, NULL
, 0,
6472 for (i
= 0; ret
&& i
< chain
->cChain
; i
++)
6473 for (j
= 0; ret
&& j
< chain
->rgpChain
[i
]->cElement
;
6475 ret
= CertAddCertificateContextToStore(store
,
6476 chain
->rgpChain
[i
]->rgpElement
[j
]->pCertContext
,
6477 CERT_STORE_ADD_ALWAYS
, NULL
);
6478 CertFreeCertificateChain(chain
);
6482 /* No chain could be created, just add the individual
6483 * cert to the message.
6485 ret
= CertAddCertificateContextToStore(store
,
6486 pExportInfo
->u
.pCertContext
, CERT_STORE_ADD_ALWAYS
,
6490 CertCloseStore(addlStore
, 0);
6496 ret
= CertAddCertificateContextToStore(store
,
6497 pExportInfo
->u
.pCertContext
, CERT_STORE_ADD_ALWAYS
, NULL
);
6499 ret
= save_store_as_cms(file
, store
);
6500 CertCloseStore(store
, 0);
6507 static BOOL
save_serialized_store(HANDLE file
, HCERTSTORE store
)
6509 return CertSaveStore(store
, PKCS_7_ASN_ENCODING
| X509_ASN_ENCODING
,
6510 CERT_STORE_SAVE_AS_STORE
, CERT_STORE_SAVE_TO_FILE
, file
, 0);
6513 static BOOL
save_pfx(HANDLE file
, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo
,
6514 PCCRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO pContextInfo
,
6515 PCRYPT_KEY_PROV_INFO keyProvInfo
, BOOL deleteKeys
)
6517 HCERTSTORE store
= CertOpenStore(CERT_STORE_PROV_MEMORY
, X509_ASN_ENCODING
,
6518 0, CERT_STORE_CREATE_NEW_FLAG
, NULL
);
6523 CRYPT_DATA_BLOB pfxBlob
= { 0, NULL
};
6524 PCCERT_CONTEXT cert
= NULL
;
6525 BOOL freeKeyProvInfo
= FALSE
;
6527 if (pContextInfo
->fExportChain
)
6529 HCERTCHAINENGINE engine
= NULL
;
6531 if (pExportInfo
->cStores
)
6533 CERT_CHAIN_ENGINE_CONFIG config
;
6535 memset(&config
, 0, sizeof(config
));
6536 config
.cbSize
= sizeof(config
);
6537 config
.cAdditionalStore
= pExportInfo
->cStores
;
6538 config
.rghAdditionalStore
= pExportInfo
->rghStores
;
6539 ret
= CertCreateCertificateChainEngine(&config
, &engine
);
6545 CERT_CHAIN_PARA chainPara
;
6546 PCCERT_CHAIN_CONTEXT chain
;
6548 memset(&chainPara
, 0, sizeof(chainPara
));
6549 chainPara
.cbSize
= sizeof(chainPara
);
6550 ret
= CertGetCertificateChain(engine
,
6551 pExportInfo
->u
.pCertContext
, NULL
, NULL
, &chainPara
, 0, NULL
,
6557 for (i
= 0; ret
&& i
< chain
->cChain
; i
++)
6558 for (j
= 0; ret
&& j
< chain
->rgpChain
[i
]->cElement
;
6561 if (i
== 0 && j
== 0)
6562 ret
= CertAddCertificateContextToStore(store
,
6563 chain
->rgpChain
[i
]->rgpElement
[j
]->pCertContext
,
6564 CERT_STORE_ADD_ALWAYS
, &cert
);
6566 ret
= CertAddCertificateContextToStore(store
,
6567 chain
->rgpChain
[i
]->rgpElement
[j
]->pCertContext
,
6568 CERT_STORE_ADD_ALWAYS
, NULL
);
6570 CertFreeCertificateChain(chain
);
6574 CertFreeCertificateChainEngine(engine
);
6577 ret
= CertAddCertificateContextToStore(store
,
6578 pExportInfo
->u
.pCertContext
, CERT_STORE_ADD_ALWAYS
, &cert
);
6579 /* Copy private key info to newly created cert, so it'll get exported
6580 * along with the cert.
6582 if (ret
&& pContextInfo
->fExportPrivateKeys
)
6585 ret
= CertSetCertificateContextProperty(cert
,
6586 CERT_KEY_PROV_INFO_PROP_ID
, 0, keyProvInfo
);
6589 if (!(keyProvInfo
= export_get_private_key_info(cert
)))
6593 ret
= CertSetCertificateContextProperty(cert
,
6594 CERT_KEY_PROV_INFO_PROP_ID
, 0, keyProvInfo
);
6595 freeKeyProvInfo
= TRUE
;
6602 REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY
| EXPORT_PRIVATE_KEYS
;
6604 ret
= PFXExportCertStore(store
, &pfxBlob
,
6605 pContextInfo
->pwszPassword
, exportFlags
);
6608 pfxBlob
.pbData
= HeapAlloc(GetProcessHeap(), 0, pfxBlob
.cbData
);
6611 ret
= PFXExportCertStore(store
, &pfxBlob
,
6612 pContextInfo
->pwszPassword
, exportFlags
);
6617 ret
= WriteFile(file
, pfxBlob
.pbData
, pfxBlob
.cbData
,
6618 &bytesWritten
, NULL
);
6623 SetLastError(ERROR_OUTOFMEMORY
);
6628 if (ret
&& deleteKeys
)
6632 CryptAcquireContextW(&prov
, keyProvInfo
->pwszContainerName
,
6633 keyProvInfo
->pwszProvName
, keyProvInfo
->dwProvType
,
6634 CRYPT_DELETEKEYSET
);
6636 if (freeKeyProvInfo
)
6637 HeapFree(GetProcessHeap(), 0, keyProvInfo
);
6638 CertFreeCertificateContext(cert
);
6639 CertCloseStore(store
, 0);
6644 static BOOL
do_export(HANDLE file
, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo
,
6645 PCCRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO pContextInfo
,
6646 PCRYPT_KEY_PROV_INFO keyProvInfo
, BOOL deleteKeys
)
6650 if (pContextInfo
->dwSize
!= sizeof(CRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO
))
6652 SetLastError(E_INVALIDARG
);
6655 switch (pExportInfo
->dwSubjectChoice
)
6657 case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT
:
6658 ret
= save_der(file
,
6659 pExportInfo
->u
.pCRLContext
->pbCrlEncoded
,
6660 pExportInfo
->u
.pCRLContext
->cbCrlEncoded
);
6662 case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT
:
6663 ret
= save_der(file
,
6664 pExportInfo
->u
.pCTLContext
->pbCtlEncoded
,
6665 pExportInfo
->u
.pCTLContext
->cbCtlEncoded
);
6667 case CRYPTUI_WIZ_EXPORT_CERT_STORE
:
6668 ret
= save_serialized_store(file
, pExportInfo
->u
.hCertStore
);
6670 case CRYPTUI_WIZ_EXPORT_CERT_STORE_CERTIFICATES_ONLY
:
6671 ret
= save_store_as_cms(file
, pExportInfo
->u
.hCertStore
);
6674 switch (pContextInfo
->dwExportFormat
)
6676 case CRYPTUI_WIZ_EXPORT_FORMAT_DER
:
6677 ret
= save_der(file
, pExportInfo
->u
.pCertContext
->pbCertEncoded
,
6678 pExportInfo
->u
.pCertContext
->cbCertEncoded
);
6680 case CRYPTUI_WIZ_EXPORT_FORMAT_BASE64
:
6681 ret
= save_base64(file
,
6682 pExportInfo
->u
.pCertContext
->pbCertEncoded
,
6683 pExportInfo
->u
.pCertContext
->cbCertEncoded
);
6685 case CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7
:
6686 ret
= save_cert_as_cms(file
, pExportInfo
,
6687 pContextInfo
->fExportChain
);
6689 case CRYPTUI_WIZ_EXPORT_FORMAT_PFX
:
6690 ret
= save_pfx(file
, pExportInfo
, pContextInfo
, keyProvInfo
,
6694 SetLastError(E_FAIL
);
6701 static LRESULT CALLBACK
export_finish_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wp
,
6705 struct ExportWizData
*data
;
6711 PROPSHEETPAGEW
*page
= (PROPSHEETPAGEW
*)lp
;
6712 HWND lv
= GetDlgItem(hwnd
, IDC_EXPORT_SETTINGS
);
6716 data
= (struct ExportWizData
*)page
->lParam
;
6717 SetWindowLongPtrW(hwnd
, DWLP_USER
, (LPARAM
)data
);
6718 SendMessageW(GetDlgItem(hwnd
, IDC_EXPORT_TITLE
), WM_SETFONT
,
6719 (WPARAM
)data
->titleFont
, TRUE
);
6720 GetWindowRect(lv
, &rc
);
6721 column
.mask
= LVCF_WIDTH
;
6722 column
.cx
= (rc
.right
- rc
.left
) / 2 - 2;
6723 SendMessageW(lv
, LVM_INSERTCOLUMNW
, 0, (LPARAM
)&column
);
6724 SendMessageW(lv
, LVM_INSERTCOLUMNW
, 1, (LPARAM
)&column
);
6725 show_export_details(lv
, data
);
6730 NMHDR
*hdr
= (NMHDR
*)lp
;
6736 HWND lv
= GetDlgItem(hwnd
, IDC_EXPORT_SETTINGS
);
6738 data
= (struct ExportWizData
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
6739 SendMessageW(lv
, LVM_DELETEALLITEMS
, 0, 0);
6740 show_export_details(lv
, data
);
6741 PostMessageW(GetParent(hwnd
), PSM_SETWIZBUTTONS
, 0,
6742 PSWIZB_BACK
| PSWIZB_FINISH
);
6749 WCHAR title
[MAX_STRING_LEN
], message
[MAX_STRING_LEN
];
6753 data
= (struct ExportWizData
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
6754 if ((data
->success
= do_export(data
->file
, &data
->exportInfo
,
6755 &data
->contextInfo
, data
->keyProvInfo
, data
->deleteKeys
)))
6757 messageID
= IDS_EXPORT_SUCCEEDED
;
6762 messageID
= IDS_EXPORT_FAILED
;
6763 mbFlags
= MB_OK
| MB_ICONERROR
;
6765 if (data
->pwszWizardTitle
)
6766 pTitle
= data
->pwszWizardTitle
;
6769 LoadStringW(hInstance
, IDS_EXPORT_WIZARD
, title
,
6770 sizeof(title
) / sizeof(title
[0]));
6773 LoadStringW(hInstance
, messageID
, message
,
6774 sizeof(message
) / sizeof(message
[0]));
6775 MessageBoxW(hwnd
, message
, pTitle
, mbFlags
);
6785 static BOOL
show_export_ui(DWORD dwFlags
, HWND hwndParent
,
6786 LPCWSTR pwszWizardTitle
, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo
, void *pvoid
)
6788 PROPSHEETHEADERW hdr
;
6789 PROPSHEETPAGEW pages
[6];
6790 struct ExportWizData data
;
6792 BOOL hasPrivateKey
, showFormatPage
= TRUE
;
6795 data
.dwFlags
= dwFlags
;
6796 data
.pwszWizardTitle
= pwszWizardTitle
;
6797 memset(&data
.exportInfo
, 0, sizeof(data
.exportInfo
));
6798 memcpy(&data
.exportInfo
, pExportInfo
,
6799 min(sizeof(data
.exportInfo
), pExportInfo
->dwSize
));
6800 if (pExportInfo
->dwSize
> sizeof(data
.exportInfo
))
6801 data
.exportInfo
.dwSize
= sizeof(data
.exportInfo
);
6802 data
.contextInfo
.dwSize
= sizeof(data
.contextInfo
);
6803 data
.contextInfo
.dwExportFormat
= CRYPTUI_WIZ_EXPORT_FORMAT_DER
;
6804 data
.contextInfo
.fExportChain
= FALSE
;
6805 data
.contextInfo
.fStrongEncryption
= FALSE
;
6806 data
.contextInfo
.fExportPrivateKeys
= FALSE
;
6807 data
.contextInfo
.pwszPassword
= NULL
;
6808 data
.freePassword
= FALSE
;
6809 if (pExportInfo
->dwSubjectChoice
== CRYPTUI_WIZ_EXPORT_CERT_CONTEXT
&&
6811 memcpy(&data
.contextInfo
, pvoid
,
6812 min(((PCCRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO
)pvoid
)->dwSize
,
6813 sizeof(data
.contextInfo
)));
6814 data
.keyProvInfo
= NULL
;
6815 data
.deleteKeys
= FALSE
;
6816 data
.fileName
= NULL
;
6817 data
.file
= INVALID_HANDLE_VALUE
;
6818 data
.success
= FALSE
;
6820 memset(&pages
, 0, sizeof(pages
));
6822 pages
[nPages
].dwSize
= sizeof(pages
[0]);
6823 pages
[nPages
].hInstance
= hInstance
;
6824 pages
[nPages
].u
.pszTemplate
= MAKEINTRESOURCEW(IDD_EXPORT_WELCOME
);
6825 pages
[nPages
].pfnDlgProc
= export_welcome_dlg_proc
;
6826 pages
[nPages
].dwFlags
= PSP_HIDEHEADER
;
6827 pages
[nPages
].lParam
= (LPARAM
)&data
;
6830 hasPrivateKey
= export_info_has_private_key(pExportInfo
);
6831 switch (pExportInfo
->dwSubjectChoice
)
6833 case CRYPTUI_WIZ_EXPORT_CRL_CONTEXT
:
6834 case CRYPTUI_WIZ_EXPORT_CTL_CONTEXT
:
6835 showFormatPage
= FALSE
;
6836 data
.contextInfo
.dwExportFormat
= CRYPTUI_WIZ_EXPORT_FORMAT_DER
;
6838 case CRYPTUI_WIZ_EXPORT_CERT_STORE
:
6839 showFormatPage
= FALSE
;
6840 data
.contextInfo
.dwExportFormat
=
6841 CRYPTUI_WIZ_EXPORT_FORMAT_SERIALIZED_CERT_STORE
;
6843 case CRYPTUI_WIZ_EXPORT_CERT_STORE_CERTIFICATES_ONLY
:
6844 showFormatPage
= FALSE
;
6845 data
.contextInfo
.dwExportFormat
= CRYPTUI_WIZ_EXPORT_FORMAT_PKCS7
;
6849 if (hasPrivateKey
&& showFormatPage
)
6851 pages
[nPages
].dwSize
= sizeof(pages
[0]);
6852 pages
[nPages
].hInstance
= hInstance
;
6853 pages
[nPages
].u
.pszTemplate
= MAKEINTRESOURCEW(IDD_EXPORT_PRIVATE_KEY
);
6854 pages
[nPages
].pfnDlgProc
= export_private_key_dlg_proc
;
6855 pages
[nPages
].dwFlags
= PSP_USEHEADERTITLE
| PSP_USEHEADERSUBTITLE
;
6856 pages
[nPages
].pszHeaderTitle
=
6857 MAKEINTRESOURCEW(IDS_EXPORT_PRIVATE_KEY_TITLE
);
6858 pages
[nPages
].pszHeaderSubTitle
=
6859 MAKEINTRESOURCEW(IDS_EXPORT_PRIVATE_KEY_SUBTITLE
);
6860 pages
[nPages
].lParam
= (LPARAM
)&data
;
6865 pages
[nPages
].dwSize
= sizeof(pages
[0]);
6866 pages
[nPages
].hInstance
= hInstance
;
6867 pages
[nPages
].u
.pszTemplate
= MAKEINTRESOURCEW(IDD_EXPORT_FORMAT
);
6868 pages
[nPages
].pfnDlgProc
= export_format_dlg_proc
;
6869 pages
[nPages
].dwFlags
= PSP_USEHEADERTITLE
| PSP_USEHEADERSUBTITLE
;
6870 pages
[nPages
].pszHeaderTitle
=
6871 MAKEINTRESOURCEW(IDS_EXPORT_FORMAT_TITLE
);
6872 pages
[nPages
].pszHeaderSubTitle
=
6873 MAKEINTRESOURCEW(IDS_EXPORT_FORMAT_SUBTITLE
);
6874 pages
[nPages
].lParam
= (LPARAM
)&data
;
6877 if (hasPrivateKey
&& showFormatPage
)
6879 pages
[nPages
].dwSize
= sizeof(pages
[0]);
6880 pages
[nPages
].hInstance
= hInstance
;
6881 pages
[nPages
].u
.pszTemplate
= MAKEINTRESOURCEW(IDD_EXPORT_PASSWORD
);
6882 pages
[nPages
].pfnDlgProc
= export_password_dlg_proc
;
6883 pages
[nPages
].dwFlags
= PSP_USEHEADERTITLE
| PSP_USEHEADERSUBTITLE
;
6884 pages
[nPages
].pszHeaderTitle
=
6885 MAKEINTRESOURCEW(IDS_EXPORT_PASSWORD_TITLE
);
6886 pages
[nPages
].pszHeaderSubTitle
=
6887 MAKEINTRESOURCEW(IDS_EXPORT_PASSWORD_SUBTITLE
);
6888 pages
[nPages
].lParam
= (LPARAM
)&data
;
6892 pages
[nPages
].dwSize
= sizeof(pages
[0]);
6893 pages
[nPages
].hInstance
= hInstance
;
6894 pages
[nPages
].u
.pszTemplate
= MAKEINTRESOURCEW(IDD_EXPORT_FILE
);
6895 pages
[nPages
].pfnDlgProc
= export_file_dlg_proc
;
6896 pages
[nPages
].dwFlags
= PSP_USEHEADERTITLE
| PSP_USEHEADERSUBTITLE
;
6897 pages
[nPages
].pszHeaderTitle
= MAKEINTRESOURCEW(IDS_EXPORT_FILE_TITLE
);
6898 pages
[nPages
].pszHeaderSubTitle
=
6899 MAKEINTRESOURCEW(IDS_EXPORT_FILE_SUBTITLE
);
6900 pages
[nPages
].lParam
= (LPARAM
)&data
;
6903 pages
[nPages
].dwSize
= sizeof(pages
[0]);
6904 pages
[nPages
].hInstance
= hInstance
;
6905 pages
[nPages
].u
.pszTemplate
= MAKEINTRESOURCEW(IDD_EXPORT_FINISH
);
6906 pages
[nPages
].pfnDlgProc
= export_finish_dlg_proc
;
6907 pages
[nPages
].dwFlags
= PSP_HIDEHEADER
;
6908 pages
[nPages
].lParam
= (LPARAM
)&data
;
6911 memset(&hdr
, 0, sizeof(hdr
));
6912 hdr
.dwSize
= sizeof(hdr
);
6913 hdr
.hwndParent
= hwndParent
;
6914 hdr
.dwFlags
= PSH_PROPSHEETPAGE
| PSH_WIZARD97_NEW
| PSH_HEADER
|
6916 hdr
.hInstance
= hInstance
;
6917 if (pwszWizardTitle
)
6918 hdr
.pszCaption
= pwszWizardTitle
;
6920 hdr
.pszCaption
= MAKEINTRESOURCEW(IDS_EXPORT_WIZARD
);
6921 hdr
.u3
.ppsp
= pages
;
6922 hdr
.nPages
= nPages
;
6923 hdr
.u4
.pszbmWatermark
= MAKEINTRESOURCEW(IDB_CERT_WATERMARK
);
6924 hdr
.u5
.pszbmHeader
= MAKEINTRESOURCEW(IDB_CERT_HEADER
);
6925 l
= PropertySheetW(&hdr
);
6926 DeleteObject(data
.titleFont
);
6927 if (data
.freePassword
)
6928 HeapFree(GetProcessHeap(), 0,
6929 (LPWSTR
)data
.contextInfo
.pwszPassword
);
6930 HeapFree(GetProcessHeap(), 0, data
.keyProvInfo
);
6931 CloseHandle(data
.file
);
6932 HeapFree(GetProcessHeap(), 0, data
.fileName
);
6935 SetLastError(ERROR_CANCELLED
);
6939 return data
.success
;
6942 BOOL WINAPI
CryptUIWizExport(DWORD dwFlags
, HWND hwndParent
,
6943 LPCWSTR pwszWizardTitle
, PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo
, void *pvoid
)
6947 TRACE("(%08x, %p, %s, %p, %p)\n", dwFlags
, hwndParent
,
6948 debugstr_w(pwszWizardTitle
), pExportInfo
, pvoid
);
6950 if (!(dwFlags
& CRYPTUI_WIZ_NO_UI
))
6951 ret
= show_export_ui(dwFlags
, hwndParent
, pwszWizardTitle
, pExportInfo
,
6955 HANDLE file
= CreateFileW(pExportInfo
->pwszExportFileName
,
6956 GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
6957 CREATE_ALWAYS
, 0, NULL
);
6959 if (file
!= INVALID_HANDLE_VALUE
)
6961 ret
= do_export(file
, pExportInfo
, pvoid
, NULL
, FALSE
);