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"
41 #include "wine/debug.h"
42 #include "wine/unicode.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(cryptui
);
46 static HINSTANCE hInstance
;
48 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
50 TRACE("(0x%p, %d, %p)\n", hinstDLL
, fdwReason
, lpvReserved
);
54 case DLL_WINE_PREATTACH
:
55 return FALSE
; /* prefer native version */
56 case DLL_PROCESS_ATTACH
:
58 DisableThreadLibraryCalls(hinstDLL
);
60 case DLL_PROCESS_DETACH
:
68 /***********************************************************************
69 * CryptUIDlgCertMgr (CRYPTUI.@)
71 BOOL WINAPI
CryptUIDlgCertMgr(PCCRYPTUI_CERT_MGR_STRUCT pCryptUICertMgr
)
73 FIXME("(%p): stub\n", pCryptUICertMgr
);
77 /* FIXME: real names are unknown, functions are undocumented */
78 typedef struct _CRYPTUI_ENUM_SYSTEM_STORE_ARGS
81 void *pvSystemStoreLocationPara
;
82 } CRYPTUI_ENUM_SYSTEM_STORE_ARGS
, *PCRYPTUI_ENUM_SYSTEM_STORE_ARGS
;
84 typedef struct _CRYPTUI_ENUM_DATA
89 PCRYPTUI_ENUM_SYSTEM_STORE_ARGS rgEnumArgs
;
90 } CRYPTUI_ENUM_DATA
, *PCRYPTUI_ENUM_DATA
;
92 typedef BOOL (WINAPI
*PFN_SELECTED_STORE_CB
)(HCERTSTORE store
, HWND hwnd
,
95 /* Values for dwFlags */
96 #define CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE 0x00000001
98 typedef struct _CRYPTUI_SELECTSTORE_INFO_A
105 CRYPTUI_ENUM_DATA
*pEnumData
;
106 PFN_SELECTED_STORE_CB pfnSelectedStoreCallback
;
108 } CRYPTUI_SELECTSTORE_INFO_A
, *PCRYPTUI_SELECTSTORE_INFO_A
;
110 typedef struct _CRYPTUI_SELECTSTORE_INFO_W
117 CRYPTUI_ENUM_DATA
*pEnumData
;
118 PFN_SELECTED_STORE_CB pfnSelectedStoreCallback
;
120 } CRYPTUI_SELECTSTORE_INFO_W
, *PCRYPTUI_SELECTSTORE_INFO_W
;
134 static BOOL WINAPI
enum_store_callback(const void *pvSystemStore
,
135 DWORD dwFlags
, PCERT_SYSTEM_STORE_INFO pStoreInfo
, void *pvReserved
,
138 HWND tree
= GetDlgItem(pvArg
, IDC_STORE_LIST
);
139 TVINSERTSTRUCTW tvis
;
140 LPCWSTR localizedName
;
144 tvis
.hInsertAfter
= TVI_LAST
;
145 tvis
.u
.item
.mask
= TVIF_TEXT
;
146 if ((localizedName
= CryptFindLocalizedName(pvSystemStore
)))
148 struct StoreInfo
*storeInfo
= HeapAlloc(GetProcessHeap(), 0,
149 sizeof(struct StoreInfo
));
153 storeInfo
->type
= SystemStore
;
154 storeInfo
->u
.name
= HeapAlloc(GetProcessHeap(), 0,
155 (strlenW(pvSystemStore
) + 1) * sizeof(WCHAR
));
156 if (storeInfo
->u
.name
)
158 tvis
.u
.item
.mask
|= TVIF_PARAM
;
159 tvis
.u
.item
.lParam
= (LPARAM
)storeInfo
;
160 strcpyW(storeInfo
->u
.name
, pvSystemStore
);
164 HeapFree(GetProcessHeap(), 0, storeInfo
);
170 tvis
.u
.item
.pszText
= (LPWSTR
)localizedName
;
173 tvis
.u
.item
.pszText
= (LPWSTR
)pvSystemStore
;
174 /* FIXME: need a folder icon for the store too */
176 SendMessageW(tree
, TVM_INSERTITEMW
, 0, (LPARAM
)&tvis
);
180 static void enumerate_stores(HWND hwnd
, CRYPTUI_ENUM_DATA
*pEnumData
)
183 HWND tree
= GetDlgItem(hwnd
, IDC_STORE_LIST
);
185 for (i
= 0; i
< pEnumData
->cEnumArgs
; i
++)
186 CertEnumSystemStore(pEnumData
->rgEnumArgs
[i
].dwFlags
,
187 pEnumData
->rgEnumArgs
[i
].pvSystemStoreLocationPara
,
188 hwnd
, enum_store_callback
);
189 for (i
= 0; i
< pEnumData
->cStores
; i
++)
193 if (CertGetStoreProperty(pEnumData
->rghStore
[i
],
194 CERT_STORE_LOCALIZED_NAME_PROP_ID
, NULL
, &size
))
196 LPWSTR name
= HeapAlloc(GetProcessHeap(), 0, size
);
200 if (CertGetStoreProperty(pEnumData
->rghStore
[i
],
201 CERT_STORE_LOCALIZED_NAME_PROP_ID
, name
, &size
))
203 struct StoreInfo
*storeInfo
= HeapAlloc(GetProcessHeap(),
204 0, sizeof(struct StoreInfo
));
208 TVINSERTSTRUCTW tvis
;
210 storeInfo
->type
= StoreHandle
;
211 storeInfo
->u
.store
= pEnumData
->rghStore
[i
];
213 tvis
.hInsertAfter
= TVI_LAST
;
214 tvis
.u
.item
.mask
= TVIF_TEXT
| TVIF_PARAM
;
215 tvis
.u
.item
.pszText
= name
;
216 tvis
.u
.item
.lParam
= (LPARAM
)storeInfo
;
217 SendMessageW(tree
, TVM_INSERTITEMW
, 0, (LPARAM
)&tvis
);
220 HeapFree(GetProcessHeap(), 0, name
);
226 static void free_store_info(HWND tree
)
228 HTREEITEM next
= (HTREEITEM
)SendMessageW(tree
, TVM_GETNEXTITEM
, TVGN_CHILD
,
235 memset(&item
, 0, sizeof(item
));
236 item
.mask
= TVIF_HANDLE
| TVIF_PARAM
;
238 SendMessageW(tree
, TVM_GETITEMW
, 0, (LPARAM
)&item
);
241 struct StoreInfo
*storeInfo
= (struct StoreInfo
*)item
.lParam
;
243 if (storeInfo
->type
== SystemStore
)
244 HeapFree(GetProcessHeap(), 0, storeInfo
->u
.name
);
245 HeapFree(GetProcessHeap(), 0, storeInfo
);
247 next
= (HTREEITEM
)SendMessageW(tree
, TVM_GETNEXTITEM
, TVGN_NEXT
,
252 #define MAX_STRING_LEN 512
254 static HCERTSTORE
selected_item_to_store(HWND tree
, HTREEITEM hItem
)
256 WCHAR buf
[MAX_STRING_LEN
];
260 memset(&item
, 0, sizeof(item
));
261 item
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_TEXT
;
263 item
.cchTextMax
= sizeof(buf
) / sizeof(buf
[0]);
265 SendMessageW(tree
, TVM_GETITEMW
, 0, (LPARAM
)&item
);
268 struct StoreInfo
*storeInfo
= (struct StoreInfo
*)item
.lParam
;
270 if (storeInfo
->type
== StoreHandle
)
271 store
= storeInfo
->u
.store
;
273 store
= CertOpenSystemStoreW(0, storeInfo
->u
.name
);
277 /* It's implicitly a system store */
278 store
= CertOpenSystemStoreW(0, buf
);
283 struct SelectStoreInfo
285 PCRYPTUI_SELECTSTORE_INFO_W info
;
289 static LRESULT CALLBACK
select_store_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wp
,
292 struct SelectStoreInfo
*selectInfo
;
299 selectInfo
= (struct SelectStoreInfo
*)lp
;
300 SetWindowLongPtrW(hwnd
, DWLP_USER
, lp
);
301 if (selectInfo
->info
->pwszTitle
)
302 SendMessageW(hwnd
, WM_SETTEXT
, 0,
303 (LPARAM
)selectInfo
->info
->pwszTitle
);
304 if (selectInfo
->info
->pwszText
)
305 SendMessageW(GetDlgItem(hwnd
, IDC_STORE_TEXT
), WM_SETTEXT
, 0,
306 (LPARAM
)selectInfo
->info
->pwszText
);
307 if (!(selectInfo
->info
->dwFlags
& CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE
))
308 ShowWindow(GetDlgItem(hwnd
, IDC_SHOW_PHYSICAL_STORES
), FALSE
);
309 enumerate_stores(hwnd
, selectInfo
->info
->pEnumData
);
317 HWND tree
= GetDlgItem(hwnd
, IDC_STORE_LIST
);
318 HTREEITEM selection
= (HTREEITEM
)SendMessageW(tree
,
319 TVM_GETNEXTITEM
, TVGN_CARET
, (LPARAM
)NULL
);
321 selectInfo
= (struct SelectStoreInfo
*)GetWindowLongPtrW(hwnd
,
325 WCHAR title
[MAX_STRING_LEN
], error
[MAX_STRING_LEN
], *pTitle
;
327 if (selectInfo
->info
->pwszTitle
)
328 pTitle
= selectInfo
->info
->pwszTitle
;
331 LoadStringW(hInstance
, IDS_SELECT_STORE_TITLE
, title
,
332 sizeof(title
) / sizeof(title
[0]));
335 LoadStringW(hInstance
, IDS_SELECT_STORE
, error
,
336 sizeof(error
) / sizeof(error
[0]));
337 MessageBoxW(hwnd
, error
, pTitle
, MB_ICONEXCLAMATION
| MB_OK
);
341 HCERTSTORE store
= selected_item_to_store(tree
, selection
);
343 if (!selectInfo
->info
->pfnSelectedStoreCallback
||
344 selectInfo
->info
->pfnSelectedStoreCallback(store
, hwnd
,
345 selectInfo
->info
->pvArg
))
347 selectInfo
->store
= store
;
348 free_store_info(tree
);
349 EndDialog(hwnd
, IDOK
);
352 CertCloseStore(store
, 0);
358 free_store_info(GetDlgItem(hwnd
, IDC_STORE_LIST
));
359 EndDialog(hwnd
, IDCANCEL
);
368 /***********************************************************************
369 * CryptUIDlgSelectStoreW (CRYPTUI.@)
371 HCERTSTORE WINAPI
CryptUIDlgSelectStoreW(PCRYPTUI_SELECTSTORE_INFO_W info
)
373 struct SelectStoreInfo selectInfo
= { info
, NULL
};
375 TRACE("(%p)\n", info
);
377 if (info
->dwSize
!= sizeof(CRYPTUI_SELECTSTORE_INFO_W
))
379 WARN("unexpected size %d\n", info
->dwSize
);
380 SetLastError(E_INVALIDARG
);
383 DialogBoxParamW(hInstance
, MAKEINTRESOURCEW(IDD_SELECT_STORE
), info
->parent
,
384 select_store_dlg_proc
, (LPARAM
)&selectInfo
);
385 return selectInfo
.store
;
388 /***********************************************************************
389 * CryptUIDlgSelectStoreA (CRYPTUI.@)
391 HCERTSTORE WINAPI
CryptUIDlgSelectStoreA(PCRYPTUI_SELECTSTORE_INFO_A info
)
393 CRYPTUI_SELECTSTORE_INFO_W infoW
;
397 TRACE("(%p)\n", info
);
399 if (info
->dwSize
!= sizeof(CRYPTUI_SELECTSTORE_INFO_A
))
401 WARN("unexpected size %d\n", info
->dwSize
);
402 SetLastError(E_INVALIDARG
);
405 memcpy(&infoW
, &info
, sizeof(info
));
408 len
= MultiByteToWideChar(CP_ACP
, 0, info
->pszTitle
, -1, NULL
, 0);
409 infoW
.pwszTitle
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
410 MultiByteToWideChar(CP_ACP
, 0, info
->pszTitle
, -1, infoW
.pwszTitle
,
415 len
= MultiByteToWideChar(CP_ACP
, 0, info
->pszText
, -1, NULL
, 0);
416 infoW
.pwszText
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
417 MultiByteToWideChar(CP_ACP
, 0, info
->pszText
, -1, infoW
.pwszText
, len
);
419 ret
= CryptUIDlgSelectStoreW(&infoW
);
420 HeapFree(GetProcessHeap(), 0, infoW
.pwszText
);
421 HeapFree(GetProcessHeap(), 0, infoW
.pwszTitle
);
425 /***********************************************************************
426 * CryptUIDlgViewCertificateA (CRYPTUI.@)
428 BOOL WINAPI
CryptUIDlgViewCertificateA(
429 PCCRYPTUI_VIEWCERTIFICATE_STRUCTA pCertViewInfo
, BOOL
*pfPropertiesChanged
)
431 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo
;
435 TRACE("(%p, %p)\n", pCertViewInfo
, pfPropertiesChanged
);
437 memcpy(&viewInfo
, pCertViewInfo
, sizeof(viewInfo
));
438 if (pCertViewInfo
->szTitle
)
440 int len
= MultiByteToWideChar(CP_ACP
, 0, pCertViewInfo
->szTitle
, -1,
443 title
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
446 MultiByteToWideChar(CP_ACP
, 0, pCertViewInfo
->szTitle
, -1, title
,
448 viewInfo
.szTitle
= title
;
456 if (pCertViewInfo
->cPropSheetPages
)
458 FIXME("ignoring additional prop sheet pages\n");
459 viewInfo
.cPropSheetPages
= 0;
461 ret
= CryptUIDlgViewCertificateW(&viewInfo
, pfPropertiesChanged
);
462 HeapFree(GetProcessHeap(), 0, title
);
467 struct ReadStringStruct
474 static DWORD CALLBACK
read_text_callback(DWORD_PTR dwCookie
, LPBYTE buf
,
477 struct ReadStringStruct
*string
= (struct ReadStringStruct
*)dwCookie
;
478 LONG cch
= min(cb
/ sizeof(WCHAR
), string
->len
- string
->pos
);
480 TRACE("(%p, %p, %d, %p)\n", string
, buf
, cb
, pcb
);
482 memmove(buf
, string
->buf
+ string
->pos
, cch
* sizeof(WCHAR
));
484 *pcb
= cch
* sizeof(WCHAR
);
488 static void add_unformatted_text_to_control(HWND hwnd
, LPCWSTR text
, LONG len
)
490 struct ReadStringStruct string
;
491 EDITSTREAM editstream
;
493 TRACE("(%p, %s)\n", hwnd
, debugstr_wn(text
, len
));
498 editstream
.dwCookie
= (DWORD_PTR
)&string
;
499 editstream
.dwError
= 0;
500 editstream
.pfnCallback
= read_text_callback
;
501 SendMessageW(hwnd
, EM_STREAMIN
, SF_TEXT
| SFF_SELECTION
| SF_UNICODE
,
502 (LPARAM
)&editstream
);
505 static void add_string_resource_to_control(HWND hwnd
, int id
)
510 len
= LoadStringW(hInstance
, id
, (LPWSTR
)&str
, 0);
511 add_unformatted_text_to_control(hwnd
, str
, len
);
514 static void add_text_with_paraformat_to_control(HWND hwnd
, LPCWSTR text
,
515 LONG len
, const PARAFORMAT2
*fmt
)
517 add_unformatted_text_to_control(hwnd
, text
, len
);
518 SendMessageW(hwnd
, EM_SETPARAFORMAT
, 0, (LPARAM
)fmt
);
521 static void add_string_resource_with_paraformat_to_control(HWND hwnd
, int id
,
522 const PARAFORMAT2
*fmt
)
527 len
= LoadStringW(hInstance
, id
, (LPWSTR
)&str
, 0);
528 add_text_with_paraformat_to_control(hwnd
, str
, len
, fmt
);
531 static LPWSTR
get_cert_name_string(PCCERT_CONTEXT pCertContext
, DWORD dwType
,
537 len
= CertGetNameStringW(pCertContext
, dwType
, dwFlags
, NULL
, NULL
, 0);
540 buf
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
542 CertGetNameStringW(pCertContext
, dwType
, dwFlags
, NULL
, buf
, len
);
547 static void add_cert_string_to_control(HWND hwnd
, PCCERT_CONTEXT pCertContext
,
548 DWORD dwType
, DWORD dwFlags
)
550 LPWSTR name
= get_cert_name_string(pCertContext
, dwType
, dwFlags
);
554 /* Don't include NULL-terminator in output */
555 DWORD len
= lstrlenW(name
);
557 add_unformatted_text_to_control(hwnd
, name
, len
);
558 HeapFree(GetProcessHeap(), 0, name
);
562 static void add_icon_to_control(HWND hwnd
, int id
)
565 LPRICHEDITOLE richEditOle
= NULL
;
566 LPOLEOBJECT object
= NULL
;
568 LPOLECACHE oleCache
= NULL
;
571 LPDATAOBJECT dataObject
= NULL
;
572 HBITMAP bitmap
= NULL
;
577 TRACE("(%p, %d)\n", hwnd
, id
);
579 SendMessageW(hwnd
, EM_GETOLEINTERFACE
, 0, (LPARAM
)&richEditOle
);
582 hr
= OleCreateDefaultHandler(&CLSID_NULL
, NULL
, &IID_IOleObject
,
586 hr
= IOleObject_GetUserClassID(object
, &clsid
);
589 hr
= IOleObject_QueryInterface(object
, &IID_IOleCache
, (void**)&oleCache
);
592 formatEtc
.cfFormat
= CF_BITMAP
;
593 formatEtc
.ptd
= NULL
;
594 formatEtc
.dwAspect
= DVASPECT_CONTENT
;
595 formatEtc
.lindex
= -1;
596 formatEtc
.tymed
= TYMED_GDI
;
597 hr
= IOleCache_Cache(oleCache
, &formatEtc
, 0, &conn
);
600 hr
= IOleObject_QueryInterface(object
, &IID_IDataObject
,
601 (void**)&dataObject
);
604 bitmap
= LoadImageW(hInstance
, MAKEINTRESOURCEW(id
), IMAGE_BITMAP
, 0, 0,
605 LR_DEFAULTSIZE
| LR_LOADTRANSPARENT
);
608 rect
.left
= rect
.top
= 0;
609 rect
.right
= GetSystemMetrics(SM_CXICON
);
610 rect
.bottom
= GetSystemMetrics(SM_CYICON
);
611 stgm
.tymed
= TYMED_GDI
;
612 stgm
.u
.hBitmap
= bitmap
;
613 stgm
.pUnkForRelease
= NULL
;
614 hr
= IDataObject_SetData(dataObject
, &formatEtc
, &stgm
, TRUE
);
618 reObject
.cbStruct
= sizeof(reObject
);
619 reObject
.cp
= REO_CP_SELECTION
;
620 reObject
.clsid
= clsid
;
621 reObject
.poleobj
= object
;
622 reObject
.pstg
= NULL
;
623 reObject
.polesite
= NULL
;
624 reObject
.sizel
.cx
= reObject
.sizel
.cy
= 0;
625 reObject
.dvaspect
= DVASPECT_CONTENT
;
626 reObject
.dwFlags
= 0;
629 IRichEditOle_InsertObject(richEditOle
, &reObject
);
633 IDataObject_Release(dataObject
);
635 IOleCache_Release(oleCache
);
637 IOleObject_Release(object
);
639 IRichEditOle_Release(richEditOle
);
642 #define MY_INDENT 200
644 static void add_oid_text_to_control(HWND hwnd
, char *oid
)
647 PCCRYPT_OID_INFO oidInfo
= CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY
, oid
, 0);
650 parFmt
.cbSize
= sizeof(parFmt
);
651 parFmt
.dwMask
= PFM_STARTINDENT
;
652 parFmt
.dxStartIndent
= MY_INDENT
* 3;
655 add_text_with_paraformat_to_control(hwnd
, oidInfo
->pwszName
,
656 lstrlenW(oidInfo
->pwszName
), &parFmt
);
657 add_unformatted_text_to_control(hwnd
, &nl
, 1);
667 /* The following list MUST be lexicographically sorted by OID */
668 static struct OIDToString oidMap
[] = {
669 /* 1.3.6.1.4.1.311.10.3.1 */
670 { szOID_KP_CTL_USAGE_SIGNING
, IDS_PURPOSE_CTL_USAGE_SIGNING
},
671 /* 1.3.6.1.4.1.311.10.3.4 */
672 { szOID_KP_EFS
, IDS_PURPOSE_EFS
},
673 /* 1.3.6.1.4.1.311.10.3.4.1 */
674 { szOID_EFS_RECOVERY
, IDS_PURPOSE_EFS_RECOVERY
},
675 /* 1.3.6.1.4.1.311.10.3.5 */
676 { szOID_WHQL_CRYPTO
, IDS_PURPOSE_WHQL
},
677 /* 1.3.6.1.4.1.311.10.3.6 */
678 { szOID_NT5_CRYPTO
, IDS_PURPOSE_NT5
},
679 /* 1.3.6.1.4.1.311.10.3.7 */
680 { szOID_OEM_WHQL_CRYPTO
, IDS_PURPOSE_OEM_WHQL
},
681 /* 1.3.6.1.4.1.311.10.3.8 */
682 { szOID_EMBEDDED_NT_CRYPTO
, IDS_PURPOSE_EMBEDDED_NT
},
683 /* 1.3.6.1.4.1.311.10.3.9 */
684 { szOID_ROOT_LIST_SIGNER
, IDS_PURPOSE_ROOT_LIST_SIGNER
},
685 /* 1.3.6.1.4.1.311.10.3.10 */
686 { szOID_KP_QUALIFIED_SUBORDINATION
, IDS_PURPOSE_QUALIFIED_SUBORDINATION
},
687 /* 1.3.6.1.4.1.311.10.3.11 */
688 { szOID_KP_KEY_RECOVERY
, IDS_PURPOSE_KEY_RECOVERY
},
689 /* 1.3.6.1.4.1.311.10.3.12 */
690 { szOID_KP_DOCUMENT_SIGNING
, IDS_PURPOSE_DOCUMENT_SIGNING
},
691 /* 1.3.6.1.4.1.311.10.3.13 */
692 { szOID_KP_LIFETIME_SIGNING
, IDS_PURPOSE_LIFETIME_SIGNING
},
693 /* 1.3.6.1.4.1.311.10.5.1 */
694 { szOID_DRM
, IDS_PURPOSE_DRM
},
695 /* 1.3.6.1.4.1.311.10.6.1 */
696 { szOID_LICENSES
, IDS_PURPOSE_LICENSES
},
697 /* 1.3.6.1.4.1.311.10.6.2 */
698 { szOID_LICENSE_SERVER
, IDS_PURPOSE_LICENSE_SERVER
},
699 /* 1.3.6.1.4.1.311.20.2.1 */
700 { szOID_ENROLLMENT_AGENT
, IDS_PURPOSE_ENROLLMENT_AGENT
},
701 /* 1.3.6.1.4.1.311.20.2.2 */
702 { szOID_KP_SMARTCARD_LOGON
, IDS_PURPOSE_SMARTCARD_LOGON
},
703 /* 1.3.6.1.4.1.311.21.5 */
704 { szOID_KP_CA_EXCHANGE
, IDS_PURPOSE_CA_EXCHANGE
},
705 /* 1.3.6.1.4.1.311.21.6 */
706 { szOID_KP_KEY_RECOVERY_AGENT
, IDS_PURPOSE_KEY_RECOVERY_AGENT
},
707 /* 1.3.6.1.4.1.311.21.19 */
708 { szOID_DS_EMAIL_REPLICATION
, IDS_PURPOSE_DS_EMAIL_REPLICATION
},
709 /* 1.3.6.1.5.5.7.3.1 */
710 { szOID_PKIX_KP_SERVER_AUTH
, IDS_PURPOSE_SERVER_AUTH
},
711 /* 1.3.6.1.5.5.7.3.2 */
712 { szOID_PKIX_KP_CLIENT_AUTH
, IDS_PURPOSE_CLIENT_AUTH
},
713 /* 1.3.6.1.5.5.7.3.3 */
714 { szOID_PKIX_KP_CODE_SIGNING
, IDS_PURPOSE_CODE_SIGNING
},
715 /* 1.3.6.1.5.5.7.3.4 */
716 { szOID_PKIX_KP_EMAIL_PROTECTION
, IDS_PURPOSE_EMAIL_PROTECTION
},
717 /* 1.3.6.1.5.5.7.3.5 */
718 { szOID_PKIX_KP_IPSEC_END_SYSTEM
, IDS_PURPOSE_IPSEC
},
719 /* 1.3.6.1.5.5.7.3.6 */
720 { szOID_PKIX_KP_IPSEC_TUNNEL
, IDS_PURPOSE_IPSEC
},
721 /* 1.3.6.1.5.5.7.3.7 */
722 { szOID_PKIX_KP_IPSEC_USER
, IDS_PURPOSE_IPSEC
},
723 /* 1.3.6.1.5.5.7.3.8 */
724 { szOID_PKIX_KP_TIMESTAMP_SIGNING
, IDS_PURPOSE_TIMESTAMP_SIGNING
},
727 static struct OIDToString
*findSupportedOID(LPCSTR oid
)
729 int indexHigh
= sizeof(oidMap
) / sizeof(oidMap
[0]) - 1, indexLow
= 0, i
;
730 struct OIDToString
*ret
= NULL
;
732 for (i
= (indexLow
+ indexHigh
) / 2; !ret
&& indexLow
<= indexHigh
;
733 i
= (indexLow
+ indexHigh
) / 2)
737 cmp
= strcmp(oid
, oidMap
[i
].oid
);
748 static void add_local_oid_text_to_control(HWND text
, LPCSTR oid
)
750 struct OIDToString
*entry
;
754 parFmt
.cbSize
= sizeof(parFmt
);
755 parFmt
.dwMask
= PFM_STARTINDENT
;
756 parFmt
.dxStartIndent
= MY_INDENT
* 3;
757 if ((entry
= findSupportedOID(oid
)))
759 WCHAR
*str
, *linebreak
, *ptr
;
760 BOOL multiline
= FALSE
;
763 len
= LoadStringW(hInstance
, entry
->id
, (LPWSTR
)&str
, 0);
766 if ((linebreak
= memchrW(ptr
, '\n', len
)))
768 WCHAR copy
[MAX_STRING_LEN
];
771 /* The source string contains a newline, which the richedit
772 * control won't find since it's interpreted as a paragraph
773 * break. Therefore copy up to the newline. lstrcpynW always
774 * NULL-terminates, so pass one more than the length of the
775 * source line so the copy includes the entire line and the
778 lstrcpynW(copy
, ptr
, linebreak
- ptr
+ 1);
779 add_text_with_paraformat_to_control(text
, copy
,
780 linebreak
- ptr
, &parFmt
);
782 add_unformatted_text_to_control(text
, &nl
, 1);
784 else if (multiline
&& *ptr
)
786 /* Add the last line */
787 add_text_with_paraformat_to_control(text
, ptr
,
788 len
- (ptr
- str
), &parFmt
);
789 add_unformatted_text_to_control(text
, &nl
, 1);
794 add_text_with_paraformat_to_control(text
, str
, len
, &parFmt
);
795 add_unformatted_text_to_control(text
, &nl
, 1);
800 WCHAR
*oidW
= HeapAlloc(GetProcessHeap(), 0,
801 (strlen(oid
) + 1) * sizeof(WCHAR
));
808 for (src
= oid
, dst
= oidW
; *src
; src
++, dst
++)
811 add_text_with_paraformat_to_control(text
, oidW
, lstrlenW(oidW
),
813 add_unformatted_text_to_control(text
, &nl
, 1);
814 HeapFree(GetProcessHeap(), 0, oidW
);
819 static void display_app_usages(HWND text
, PCCERT_CONTEXT cert
,
822 static char any_app_policy
[] = szOID_ANY_APPLICATION_POLICY
;
825 PCERT_EXTENSION policyExt
;
830 parFmt
.cbSize
= sizeof(parFmt
);
831 parFmt
.dwMask
= PFM_STARTINDENT
;
832 parFmt
.dxStartIndent
= MY_INDENT
;
833 add_string_resource_with_paraformat_to_control(text
,
834 IDS_CERT_INFO_PURPOSES
, &parFmt
);
835 add_unformatted_text_to_control(text
, &nl
, 1);
836 *anyUsageAdded
= TRUE
;
838 memset(&charFmt
, 0, sizeof(charFmt
));
839 charFmt
.cbSize
= sizeof(charFmt
);
840 charFmt
.dwMask
= CFM_BOLD
;
841 charFmt
.dwEffects
= 0;
842 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
843 if ((policyExt
= CertFindExtension(szOID_APPLICATION_CERT_POLICIES
,
844 cert
->pCertInfo
->cExtension
, cert
->pCertInfo
->rgExtension
)))
846 CERT_POLICIES_INFO
*policies
;
849 if (CryptDecodeObjectEx(X509_ASN_ENCODING
, X509_CERT_POLICIES
,
850 policyExt
->Value
.pbData
, policyExt
->Value
.cbData
,
851 CRYPT_DECODE_ALLOC_FLAG
, NULL
, &policies
, &size
))
855 for (i
= 0; i
< policies
->cPolicyInfo
; i
++)
859 for (j
= 0; j
< policies
->rgPolicyInfo
[i
].cPolicyQualifier
; j
++)
860 add_local_oid_text_to_control(text
,
861 policies
->rgPolicyInfo
[i
].rgPolicyQualifier
[j
].
862 pszPolicyQualifierId
);
868 add_oid_text_to_control(text
, any_app_policy
);
871 static BOOL
display_cert_usages(HWND text
, PCCERT_CONTEXT cert
,
876 BOOL badUsages
= FALSE
;
878 if (CertGetEnhancedKeyUsage(cert
, 0, NULL
, &size
))
881 static char any_cert_policy
[] = szOID_ANY_CERT_POLICY
;
882 PCERT_ENHKEY_USAGE usage
= HeapAlloc(GetProcessHeap(), 0, size
);
886 if (CertGetEnhancedKeyUsage(cert
, 0, usage
, &size
))
894 parFmt
.cbSize
= sizeof(parFmt
);
895 parFmt
.dwMask
= PFM_STARTINDENT
;
896 parFmt
.dxStartIndent
= MY_INDENT
;
897 add_string_resource_with_paraformat_to_control(text
,
898 IDS_CERT_INFO_PURPOSES
, &parFmt
);
899 add_unformatted_text_to_control(text
, &nl
, 1);
900 *anyUsageAdded
= TRUE
;
902 memset(&charFmt
, 0, sizeof(charFmt
));
903 charFmt
.cbSize
= sizeof(charFmt
);
904 charFmt
.dwMask
= CFM_BOLD
;
905 charFmt
.dwEffects
= 0;
906 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
,
908 if (!usage
->cUsageIdentifier
)
909 add_oid_text_to_control(text
, any_cert_policy
);
911 for (i
= 0; i
< usage
->cUsageIdentifier
; i
++)
912 add_local_oid_text_to_control(text
,
913 usage
->rgpszUsageIdentifier
[i
]);
917 HeapFree(GetProcessHeap(), 0, usage
);
927 static void set_policy_text(HWND text
,
928 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
)
930 BOOL includeCertUsages
= FALSE
, includeAppUsages
= FALSE
;
931 BOOL badUsages
= FALSE
, anyUsageAdded
= FALSE
;
933 if (pCertViewInfo
->cPurposes
)
937 for (i
= 0; i
< pCertViewInfo
->cPurposes
; i
++)
939 if (!strcmp(pCertViewInfo
->rgszPurposes
[i
], szOID_ANY_CERT_POLICY
))
940 includeCertUsages
= TRUE
;
941 else if (!strcmp(pCertViewInfo
->rgszPurposes
[i
],
942 szOID_ANY_APPLICATION_POLICY
))
943 includeAppUsages
= TRUE
;
949 includeAppUsages
= includeCertUsages
= TRUE
;
950 if (includeAppUsages
)
951 display_app_usages(text
, pCertViewInfo
->pCertContext
, &anyUsageAdded
);
952 if (includeCertUsages
)
953 badUsages
= display_cert_usages(text
, pCertViewInfo
->pCertContext
,
959 parFmt
.cbSize
= sizeof(parFmt
);
960 parFmt
.dwMask
= PFM_STARTINDENT
;
961 parFmt
.dxStartIndent
= MY_INDENT
;
962 add_string_resource_with_paraformat_to_control(text
,
963 IDS_CERT_INFO_BAD_PURPOSES
, &parFmt
);
967 static CRYPT_OBJID_BLOB
*find_policy_qualifier(CERT_POLICIES_INFO
*policies
,
970 CRYPT_OBJID_BLOB
*ret
= NULL
;
973 for (i
= 0; !ret
&& i
< policies
->cPolicyInfo
; i
++)
977 for (j
= 0; !ret
&& j
< policies
->rgPolicyInfo
[i
].cPolicyQualifier
; j
++)
978 if (!strcmp(policies
->rgPolicyInfo
[i
].rgPolicyQualifier
[j
].
979 pszPolicyQualifierId
, policyOid
))
980 ret
= &policies
->rgPolicyInfo
[i
].rgPolicyQualifier
[j
].
986 static WCHAR
*get_cps_str_from_qualifier(CRYPT_OBJID_BLOB
*qualifier
)
988 LPWSTR qualifierStr
= NULL
;
989 CERT_NAME_VALUE
*qualifierValue
;
992 if (CryptDecodeObjectEx(X509_ASN_ENCODING
, X509_NAME_VALUE
,
993 qualifier
->pbData
, qualifier
->cbData
, CRYPT_DECODE_ALLOC_FLAG
, NULL
,
994 &qualifierValue
, &size
))
996 size
= CertRDNValueToStrW(qualifierValue
->dwValueType
,
997 &qualifierValue
->Value
, NULL
, 0);
998 qualifierStr
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
));
1000 CertRDNValueToStrW(qualifierValue
->dwValueType
,
1001 &qualifierValue
->Value
, qualifierStr
, size
);
1002 LocalFree(qualifierValue
);
1004 return qualifierStr
;
1007 static WCHAR
*get_user_notice_from_qualifier(CRYPT_OBJID_BLOB
*qualifier
)
1010 CERT_POLICY_QUALIFIER_USER_NOTICE
*qualifierValue
;
1013 if (CryptDecodeObjectEx(X509_ASN_ENCODING
,
1014 X509_PKIX_POLICY_QUALIFIER_USERNOTICE
,
1015 qualifier
->pbData
, qualifier
->cbData
, CRYPT_DECODE_ALLOC_FLAG
, NULL
,
1016 &qualifierValue
, &size
))
1018 str
= HeapAlloc(GetProcessHeap(), 0,
1019 (strlenW(qualifierValue
->pszDisplayText
) + 1) * sizeof(WCHAR
));
1021 strcpyW(str
, qualifierValue
->pszDisplayText
);
1022 LocalFree(qualifierValue
);
1027 struct IssuerStatement
1033 static void set_issuer_statement(HWND hwnd
,
1034 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
)
1036 PCERT_EXTENSION policyExt
;
1038 if (!(pCertViewInfo
->dwFlags
& CRYPTUI_DISABLE_ISSUERSTATEMENT
) &&
1039 (policyExt
= CertFindExtension(szOID_CERT_POLICIES
,
1040 pCertViewInfo
->pCertContext
->pCertInfo
->cExtension
,
1041 pCertViewInfo
->pCertContext
->pCertInfo
->rgExtension
)))
1043 CERT_POLICIES_INFO
*policies
;
1046 if (CryptDecodeObjectEx(X509_ASN_ENCODING
, policyExt
->pszObjId
,
1047 policyExt
->Value
.pbData
, policyExt
->Value
.cbData
,
1048 CRYPT_DECODE_ALLOC_FLAG
, NULL
, &policies
, &size
))
1050 CRYPT_OBJID_BLOB
*qualifier
;
1051 LPWSTR cps
= NULL
, userNotice
= NULL
;
1053 if ((qualifier
= find_policy_qualifier(policies
,
1054 szOID_PKIX_POLICY_QUALIFIER_CPS
)))
1055 cps
= get_cps_str_from_qualifier(qualifier
);
1056 if ((qualifier
= find_policy_qualifier(policies
,
1057 szOID_PKIX_POLICY_QUALIFIER_USERNOTICE
)))
1058 userNotice
= get_user_notice_from_qualifier(qualifier
);
1059 if (cps
|| userNotice
)
1061 struct IssuerStatement
*issuerStatement
=
1062 HeapAlloc(GetProcessHeap(), 0, sizeof(struct IssuerStatement
));
1064 if (issuerStatement
)
1066 issuerStatement
->cps
= cps
;
1067 issuerStatement
->userNotice
= userNotice
;
1068 EnableWindow(GetDlgItem(hwnd
, IDC_ISSUERSTATEMENT
), TRUE
);
1069 SetWindowLongPtrW(hwnd
, DWLP_USER
,
1070 (ULONG_PTR
)issuerStatement
);
1073 LocalFree(policies
);
1078 static void set_cert_info(HWND hwnd
,
1079 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
)
1081 CHARFORMATW charFmt
;
1083 HWND icon
= GetDlgItem(hwnd
, IDC_CERTIFICATE_ICON
);
1084 HWND text
= GetDlgItem(hwnd
, IDC_CERTIFICATE_INFO
);
1085 CRYPT_PROVIDER_SGNR
*provSigner
= WTHelperGetProvSignerFromChain(
1086 (CRYPT_PROVIDER_DATA
*)pCertViewInfo
->u
.pCryptProviderData
,
1087 pCertViewInfo
->idxSigner
, pCertViewInfo
->fCounterSigner
,
1088 pCertViewInfo
->idxCounterSigner
);
1089 CRYPT_PROVIDER_CERT
*root
=
1090 &provSigner
->pasCertChain
[provSigner
->csCertChain
- 1];
1092 if (!provSigner
->pChainContext
||
1093 (provSigner
->pChainContext
->TrustStatus
.dwErrorStatus
&
1094 CERT_TRUST_IS_PARTIAL_CHAIN
))
1095 add_icon_to_control(icon
, IDB_CERT_WARNING
);
1096 else if (!root
->fTrustedRoot
)
1097 add_icon_to_control(icon
, IDB_CERT_ERROR
);
1099 add_icon_to_control(icon
, IDB_CERT
);
1101 memset(&charFmt
, 0, sizeof(charFmt
));
1102 charFmt
.cbSize
= sizeof(charFmt
);
1103 charFmt
.dwMask
= CFM_BOLD
;
1104 charFmt
.dwEffects
= CFE_BOLD
;
1105 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
1106 /* FIXME: vertically center text */
1107 parFmt
.cbSize
= sizeof(parFmt
);
1108 parFmt
.dwMask
= PFM_STARTINDENT
;
1109 parFmt
.dxStartIndent
= MY_INDENT
;
1110 add_string_resource_with_paraformat_to_control(text
,
1111 IDS_CERTIFICATEINFORMATION
, &parFmt
);
1113 text
= GetDlgItem(hwnd
, IDC_CERTIFICATE_STATUS
);
1114 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
1115 if (provSigner
->dwError
== TRUST_E_CERT_SIGNATURE
)
1116 add_string_resource_with_paraformat_to_control(text
,
1117 IDS_CERT_INFO_BAD_SIG
, &parFmt
);
1118 else if (!provSigner
->pChainContext
||
1119 (provSigner
->pChainContext
->TrustStatus
.dwErrorStatus
&
1120 CERT_TRUST_IS_PARTIAL_CHAIN
))
1121 add_string_resource_with_paraformat_to_control(text
,
1122 IDS_CERT_INFO_PARTIAL_CHAIN
, &parFmt
);
1123 else if (!root
->fTrustedRoot
)
1125 if (provSigner
->csCertChain
== 1 && root
->fSelfSigned
)
1126 add_string_resource_with_paraformat_to_control(text
,
1127 IDS_CERT_INFO_UNTRUSTED_CA
, &parFmt
);
1129 add_string_resource_with_paraformat_to_control(text
,
1130 IDS_CERT_INFO_UNTRUSTED_ROOT
, &parFmt
);
1134 set_policy_text(text
, pCertViewInfo
);
1135 set_issuer_statement(hwnd
, pCertViewInfo
);
1139 static void set_cert_name_string(HWND hwnd
, PCCERT_CONTEXT cert
,
1140 DWORD nameFlags
, int heading
)
1143 HWND text
= GetDlgItem(hwnd
, IDC_CERTIFICATE_NAMES
);
1144 CHARFORMATW charFmt
;
1147 memset(&charFmt
, 0, sizeof(charFmt
));
1148 charFmt
.cbSize
= sizeof(charFmt
);
1149 charFmt
.dwMask
= CFM_BOLD
;
1150 charFmt
.dwEffects
= CFE_BOLD
;
1151 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
1152 parFmt
.cbSize
= sizeof(parFmt
);
1153 parFmt
.dwMask
= PFM_STARTINDENT
;
1154 parFmt
.dxStartIndent
= MY_INDENT
* 3;
1155 add_string_resource_with_paraformat_to_control(text
, heading
, &parFmt
);
1156 charFmt
.dwEffects
= 0;
1157 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
1158 add_cert_string_to_control(text
, cert
, CERT_NAME_SIMPLE_DISPLAY_TYPE
,
1160 add_unformatted_text_to_control(text
, &nl
, 1);
1161 add_unformatted_text_to_control(text
, &nl
, 1);
1162 add_unformatted_text_to_control(text
, &nl
, 1);
1166 static void add_date_string_to_control(HWND hwnd
, const FILETIME
*fileTime
)
1168 WCHAR dateFmt
[80]; /* sufficient for all versions of LOCALE_SSHORTDATE */
1172 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT
, LOCALE_SSHORTDATE
, dateFmt
,
1173 sizeof(dateFmt
) / sizeof(dateFmt
[0]));
1174 FileTimeToSystemTime(fileTime
, &sysTime
);
1175 GetDateFormatW(LOCALE_SYSTEM_DEFAULT
, 0, &sysTime
, dateFmt
, date
,
1176 sizeof(date
) / sizeof(date
[0]));
1177 add_unformatted_text_to_control(hwnd
, date
, lstrlenW(date
));
1180 static void set_cert_validity_period(HWND hwnd
, PCCERT_CONTEXT cert
)
1183 HWND text
= GetDlgItem(hwnd
, IDC_CERTIFICATE_NAMES
);
1184 CHARFORMATW charFmt
;
1187 memset(&charFmt
, 0, sizeof(charFmt
));
1188 charFmt
.cbSize
= sizeof(charFmt
);
1189 charFmt
.dwMask
= CFM_BOLD
;
1190 charFmt
.dwEffects
= CFE_BOLD
;
1191 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
1192 parFmt
.cbSize
= sizeof(parFmt
);
1193 parFmt
.dwMask
= PFM_STARTINDENT
;
1194 parFmt
.dxStartIndent
= MY_INDENT
* 3;
1195 add_string_resource_with_paraformat_to_control(text
, IDS_VALID_FROM
,
1197 charFmt
.dwEffects
= 0;
1198 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
1199 add_date_string_to_control(text
, &cert
->pCertInfo
->NotBefore
);
1200 charFmt
.dwEffects
= CFE_BOLD
;
1201 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
1202 add_string_resource_to_control(text
, IDS_VALID_TO
);
1203 charFmt
.dwEffects
= 0;
1204 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
1205 add_date_string_to_control(text
, &cert
->pCertInfo
->NotAfter
);
1206 add_unformatted_text_to_control(text
, &nl
, 1);
1209 static void set_general_info(HWND hwnd
,
1210 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
)
1212 set_cert_info(hwnd
, pCertViewInfo
);
1213 set_cert_name_string(hwnd
, pCertViewInfo
->pCertContext
, 0,
1214 IDS_SUBJECT_HEADING
);
1215 set_cert_name_string(hwnd
, pCertViewInfo
->pCertContext
,
1216 CERT_NAME_ISSUER_FLAG
, IDS_ISSUER_HEADING
);
1217 set_cert_validity_period(hwnd
, pCertViewInfo
->pCertContext
);
1220 static LRESULT CALLBACK
user_notice_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wp
,
1225 struct IssuerStatement
*issuerStatement
;
1230 text
= GetDlgItem(hwnd
, IDC_USERNOTICE
);
1231 issuerStatement
= (struct IssuerStatement
*)lp
;
1232 add_unformatted_text_to_control(text
, issuerStatement
->userNotice
,
1233 strlenW(issuerStatement
->userNotice
));
1234 if (issuerStatement
->cps
)
1235 SetWindowLongPtrW(hwnd
, DWLP_USER
, (LPARAM
)issuerStatement
->cps
);
1237 EnableWindow(GetDlgItem(hwnd
, IDC_CPS
), FALSE
);
1243 EndDialog(hwnd
, IDOK
);
1248 IBindCtx
*bctx
= NULL
;
1251 CreateBindCtx(0, &bctx
);
1252 cps
= (LPWSTR
)GetWindowLongPtrW(hwnd
, DWLP_USER
);
1253 HlinkSimpleNavigateToString(cps
, NULL
, NULL
, NULL
, bctx
, NULL
,
1254 HLNF_OPENINNEWWINDOW
, 0);
1255 IBindCtx_Release(bctx
);
1263 static void show_user_notice(HWND hwnd
, struct IssuerStatement
*issuerStatement
)
1265 DialogBoxParamW(hInstance
, MAKEINTRESOURCEW(IDD_USERNOTICE
), hwnd
,
1266 user_notice_dlg_proc
, (LPARAM
)issuerStatement
);
1269 static LRESULT CALLBACK
general_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wp
,
1272 PROPSHEETPAGEW
*page
;
1273 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
;
1275 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd
, msg
, wp
, lp
);
1280 page
= (PROPSHEETPAGEW
*)lp
;
1281 pCertViewInfo
= (PCCRYPTUI_VIEWCERTIFICATE_STRUCTW
)page
->lParam
;
1282 if (pCertViewInfo
->dwFlags
& CRYPTUI_DISABLE_ADDTOSTORE
)
1283 ShowWindow(GetDlgItem(hwnd
, IDC_ADDTOSTORE
), FALSE
);
1284 EnableWindow(GetDlgItem(hwnd
, IDC_ISSUERSTATEMENT
), FALSE
);
1285 set_general_info(hwnd
, pCertViewInfo
);
1290 case IDC_ADDTOSTORE
:
1291 FIXME("call CryptUIWizImport\n");
1293 case IDC_ISSUERSTATEMENT
:
1295 struct IssuerStatement
*issuerStatement
=
1296 (struct IssuerStatement
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
1298 if (issuerStatement
)
1300 if (issuerStatement
->userNotice
)
1301 show_user_notice(hwnd
, issuerStatement
);
1302 else if (issuerStatement
->cps
)
1304 IBindCtx
*bctx
= NULL
;
1306 CreateBindCtx(0, &bctx
);
1307 HlinkSimpleNavigateToString(issuerStatement
->cps
, NULL
,
1308 NULL
, NULL
, bctx
, NULL
, HLNF_OPENINNEWWINDOW
, 0);
1309 IBindCtx_Release(bctx
);
1320 static UINT CALLBACK
general_callback_proc(HWND hwnd
, UINT msg
,
1321 PROPSHEETPAGEW
*page
)
1323 struct IssuerStatement
*issuerStatement
;
1329 (struct IssuerStatement
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
1330 if (issuerStatement
)
1332 HeapFree(GetProcessHeap(), 0, issuerStatement
->cps
);
1333 HeapFree(GetProcessHeap(), 0, issuerStatement
->userNotice
);
1334 HeapFree(GetProcessHeap(), 0, issuerStatement
);
1341 static void init_general_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
,
1342 PROPSHEETPAGEW
*page
)
1344 memset(page
, 0, sizeof(PROPSHEETPAGEW
));
1345 page
->dwSize
= sizeof(PROPSHEETPAGEW
);
1346 page
->dwFlags
= PSP_USECALLBACK
;
1347 page
->pfnCallback
= general_callback_proc
;
1348 page
->hInstance
= hInstance
;
1349 page
->u
.pszTemplate
= MAKEINTRESOURCEW(IDD_GENERAL
);
1350 page
->pfnDlgProc
= general_dlg_proc
;
1351 page
->lParam
= (LPARAM
)pCertViewInfo
;
1354 typedef WCHAR
* (*field_format_func
)(PCCERT_CONTEXT cert
);
1356 static WCHAR
*field_format_version(PCCERT_CONTEXT cert
)
1358 static const WCHAR fmt
[] = { 'V','%','d',0 };
1359 WCHAR
*buf
= HeapAlloc(GetProcessHeap(), 0, 12 * sizeof(WCHAR
));
1362 sprintfW(buf
, fmt
, cert
->pCertInfo
->dwVersion
);
1366 static WCHAR
*format_hex_string(void *pb
, DWORD cb
)
1368 WCHAR
*buf
= HeapAlloc(GetProcessHeap(), 0, (cb
* 3 + 1) * sizeof(WCHAR
));
1372 static const WCHAR fmt
[] = { '%','0','2','x',' ',0 };
1376 for (i
= 0, ptr
= buf
; i
< cb
; i
++, ptr
+= 3)
1377 sprintfW(ptr
, fmt
, ((BYTE
*)pb
)[i
]);
1382 static WCHAR
*field_format_serial_number(PCCERT_CONTEXT cert
)
1384 return format_hex_string(cert
->pCertInfo
->SerialNumber
.pbData
,
1385 cert
->pCertInfo
->SerialNumber
.cbData
);
1388 static WCHAR
*field_format_issuer(PCCERT_CONTEXT cert
)
1390 return get_cert_name_string(cert
, CERT_NAME_SIMPLE_DISPLAY_TYPE
,
1391 CERT_NAME_ISSUER_FLAG
);
1394 static WCHAR
*field_format_detailed_cert_name(PCERT_NAME_BLOB name
)
1397 DWORD len
= CertNameToStrW(X509_ASN_ENCODING
, name
,
1398 CERT_X500_NAME_STR
| CERT_NAME_STR_CRLF_FLAG
, NULL
, 0);
1402 str
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1404 CertNameToStrW(X509_ASN_ENCODING
, name
,
1405 CERT_X500_NAME_STR
| CERT_NAME_STR_CRLF_FLAG
, str
, len
);
1410 static WCHAR
*field_format_detailed_issuer(PCCERT_CONTEXT cert
, void *param
)
1412 return field_format_detailed_cert_name(&cert
->pCertInfo
->Issuer
);
1415 static WCHAR
*field_format_subject(PCCERT_CONTEXT cert
)
1417 return get_cert_name_string(cert
, CERT_NAME_SIMPLE_DISPLAY_TYPE
, 0);
1420 static WCHAR
*field_format_detailed_subject(PCCERT_CONTEXT cert
, void *param
)
1422 return field_format_detailed_cert_name(&cert
->pCertInfo
->Subject
);
1425 static WCHAR
*format_long_date(const FILETIME
*fileTime
)
1427 WCHAR dateFmt
[80]; /* long enough for LOCALE_SLONGDATE */
1432 /* FIXME: format isn't quite right, want time too */
1433 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT
, LOCALE_SLONGDATE
, dateFmt
,
1434 sizeof(dateFmt
) / sizeof(dateFmt
[0]));
1435 FileTimeToSystemTime(fileTime
, &sysTime
);
1436 len
= GetDateFormatW(LOCALE_SYSTEM_DEFAULT
, 0, &sysTime
, dateFmt
, NULL
, 0);
1439 buf
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1441 GetDateFormatW(LOCALE_SYSTEM_DEFAULT
, 0, &sysTime
, dateFmt
, buf
,
1447 static WCHAR
*field_format_from_date(PCCERT_CONTEXT cert
)
1449 return format_long_date(&cert
->pCertInfo
->NotBefore
);
1452 static WCHAR
*field_format_to_date(PCCERT_CONTEXT cert
)
1454 return format_long_date(&cert
->pCertInfo
->NotAfter
);
1457 static WCHAR
*field_format_public_key(PCCERT_CONTEXT cert
)
1459 PCCRYPT_OID_INFO oidInfo
;
1462 oidInfo
= CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY
,
1463 cert
->pCertInfo
->SubjectPublicKeyInfo
.Algorithm
.pszObjId
, 0);
1466 WCHAR fmt
[MAX_STRING_LEN
];
1468 if (LoadStringW(hInstance
, IDS_FIELD_PUBLIC_KEY_FORMAT
, fmt
,
1469 sizeof(fmt
) / sizeof(fmt
[0])))
1471 /* Allocate the output buffer. Use the number of bytes in the
1472 * public key as a conservative (high) estimate for the number of
1473 * digits in its output.
1474 * The output is of the form (in English)
1475 * "<public key algorithm> (<public key bit length> bits)".
1476 * Ordinarily having two positional parameters in a string is not a
1477 * good idea, but as this isn't a sentence fragment, it shouldn't
1478 * be word-order dependent.
1480 buf
= HeapAlloc(GetProcessHeap(), 0,
1481 (strlenW(fmt
) + strlenW(oidInfo
->pwszName
) +
1482 cert
->pCertInfo
->SubjectPublicKeyInfo
.PublicKey
.cbData
* 8)
1485 sprintfW(buf
, fmt
, oidInfo
->pwszName
,
1486 CertGetPublicKeyLength(X509_ASN_ENCODING
,
1487 &cert
->pCertInfo
->SubjectPublicKeyInfo
));
1493 static WCHAR
*field_format_detailed_public_key(PCCERT_CONTEXT cert
, void *param
)
1495 return format_hex_string(
1496 cert
->pCertInfo
->SubjectPublicKeyInfo
.PublicKey
.pbData
,
1497 cert
->pCertInfo
->SubjectPublicKeyInfo
.PublicKey
.cbData
);
1500 struct field_value_data
;
1503 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
;
1504 BOOL
*pfPropertiesChanged
;
1506 struct field_value_data
*fields
;
1509 typedef void (*add_fields_func
)(HWND hwnd
, struct detail_data
*data
);
1511 typedef WCHAR
*(*create_detailed_value_func
)(PCCERT_CONTEXT cert
, void *param
);
1513 struct field_value_data
1515 create_detailed_value_func create
;
1516 LPWSTR detailed_value
;
1520 static void add_field_value_data(struct detail_data
*data
,
1521 create_detailed_value_func create
, void *param
)
1524 data
->fields
= HeapReAlloc(GetProcessHeap(), 0, data
->fields
,
1525 (data
->cFields
+ 1) * sizeof(struct field_value_data
));
1527 data
->fields
= HeapAlloc(GetProcessHeap(), 0,
1528 sizeof(struct field_value_data
));
1531 data
->fields
[data
->cFields
].create
= create
;
1532 data
->fields
[data
->cFields
].detailed_value
= NULL
;
1533 data
->fields
[data
->cFields
].param
= param
;
1538 static void add_field_and_value_to_list(HWND hwnd
, struct detail_data
*data
,
1539 LPWSTR field
, LPWSTR value
, create_detailed_value_func create
, void *param
)
1542 int iItem
= SendMessageW(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1544 item
.mask
= LVIF_TEXT
| LVIF_PARAM
;
1547 item
.pszText
= field
;
1548 item
.lParam
= (LPARAM
)data
;
1549 SendMessageW(hwnd
, LVM_INSERTITEMW
, 0, (LPARAM
)&item
);
1552 item
.pszText
= value
;
1554 SendMessageW(hwnd
, LVM_SETITEMTEXTW
, iItem
, (LPARAM
)&item
);
1556 add_field_value_data(data
, create
, param
);
1559 static void add_string_id_and_value_to_list(HWND hwnd
, struct detail_data
*data
,
1560 int id
, LPWSTR value
, create_detailed_value_func create
, void *param
)
1562 WCHAR buf
[MAX_STRING_LEN
];
1564 LoadStringW(hInstance
, id
, buf
, sizeof(buf
) / sizeof(buf
[0]));
1565 add_field_and_value_to_list(hwnd
, data
, buf
, value
, create
, param
);
1571 field_format_func format
;
1572 create_detailed_value_func create_detailed_value
;
1575 static void add_v1_field(HWND hwnd
, struct detail_data
*data
,
1576 const struct v1_field
*field
)
1578 WCHAR
*val
= field
->format(data
->pCertViewInfo
->pCertContext
);
1582 add_string_id_and_value_to_list(hwnd
, data
, field
->id
, val
,
1583 field
->create_detailed_value
, NULL
);
1584 HeapFree(GetProcessHeap(), 0, val
);
1588 static const struct v1_field v1_fields
[] = {
1589 { IDS_FIELD_VERSION
, field_format_version
, NULL
},
1590 { IDS_FIELD_SERIAL_NUMBER
, field_format_serial_number
, NULL
},
1591 { IDS_FIELD_ISSUER
, field_format_issuer
, field_format_detailed_issuer
},
1592 { IDS_FIELD_VALID_FROM
, field_format_from_date
, NULL
},
1593 { IDS_FIELD_VALID_TO
, field_format_to_date
, NULL
},
1594 { IDS_FIELD_SUBJECT
, field_format_subject
, field_format_detailed_subject
},
1595 { IDS_FIELD_PUBLIC_KEY
, field_format_public_key
,
1596 field_format_detailed_public_key
}
1599 static void add_v1_fields(HWND hwnd
, struct detail_data
*data
)
1602 PCCERT_CONTEXT cert
= data
->pCertViewInfo
->pCertContext
;
1604 /* The last item in v1_fields is the public key, which is not in the loop
1605 * because it's a special case.
1607 for (i
= 0; i
< sizeof(v1_fields
) / sizeof(v1_fields
[0]) - 1; i
++)
1608 add_v1_field(hwnd
, data
, &v1_fields
[i
]);
1609 if (cert
->pCertInfo
->SubjectPublicKeyInfo
.PublicKey
.cbData
)
1610 add_v1_field(hwnd
, data
, &v1_fields
[i
]);
1613 static WCHAR
*crypt_format_extension(PCERT_EXTENSION ext
, DWORD formatStrType
)
1618 if (CryptFormatObject(X509_ASN_ENCODING
, 0, formatStrType
, NULL
,
1619 ext
->pszObjId
, ext
->Value
.pbData
, ext
->Value
.cbData
, NULL
, &size
))
1621 str
= HeapAlloc(GetProcessHeap(), 0, size
);
1622 CryptFormatObject(X509_ASN_ENCODING
, 0, formatStrType
, NULL
,
1623 ext
->pszObjId
, ext
->Value
.pbData
, ext
->Value
.cbData
, str
, &size
);
1628 static WCHAR
*field_format_extension_hex_with_ascii(PCERT_EXTENSION ext
)
1632 if (ext
->Value
.cbData
)
1634 /* The output is formatted as:
1635 * <hex bytes> <ascii bytes>\n
1636 * where <hex bytes> is a string of up to 8 bytes, output as %02x,
1637 * and <ascii bytes> is the ASCII equivalent of each byte, or '.' if
1638 * the byte is not printable.
1639 * So, for example, the extension value consisting of the following
1641 * 0x30,0x14,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x03,
1642 * 0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67
1644 * 30 14 31 12 30 10 06 03 0.1.0...
1645 * 55 04 03 13 09 4a 75 61 U....Jua
1646 * 6e 20 4c 61 6e 67 n Lang
1647 * The allocation size therefore requires:
1648 * - 4 characters per character in an 8-byte line
1649 * (2 for the hex format, one for the space, one for the ASCII value)
1650 * - 3 more characters per 8-byte line (two spaces and a newline)
1651 * - 1 character for the terminating nul
1652 * FIXME: should use a fixed-width font for this
1654 DWORD lines
= (ext
->Value
.cbData
+ 7) / 8;
1656 str
= HeapAlloc(GetProcessHeap(), 0,
1657 (lines
* 8 * 4 + lines
* 3 + 1) * sizeof(WCHAR
));
1660 static const WCHAR fmt
[] = { '%','0','2','x',' ',0 };
1664 for (i
= 0, ptr
= str
; i
< ext
->Value
.cbData
; i
+= 8)
1666 /* Output as hex bytes first */
1667 for (j
= i
; j
< min(i
+ 8, ext
->Value
.cbData
); j
++, ptr
+= 3)
1668 sprintfW(ptr
, fmt
, ext
->Value
.pbData
[j
]);
1669 /* Pad the hex output with spaces for alignment */
1670 if (j
== ext
->Value
.cbData
&& j
% 8)
1672 static const WCHAR pad
[] = { ' ',' ',' ' };
1674 for (; j
% 8; j
++, ptr
+= sizeof(pad
) / sizeof(pad
[0]))
1675 memcpy(ptr
, pad
, sizeof(pad
));
1677 /* The last sprintfW included a space, so just insert one
1678 * more space between the hex bytes and the ASCII output
1681 /* Output as ASCII bytes */
1682 for (j
= i
; j
< min(i
+ 8, ext
->Value
.cbData
); j
++, ptr
++)
1684 if (isprintW(ext
->Value
.pbData
[j
]) &&
1685 !isspaceW(ext
->Value
.pbData
[j
]))
1686 *ptr
= ext
->Value
.pbData
[j
];
1698 static WCHAR
*field_format_detailed_extension(PCCERT_CONTEXT cert
, void *param
)
1700 PCERT_EXTENSION ext
= param
;
1701 LPWSTR str
= crypt_format_extension(ext
,
1702 CRYPT_FORMAT_STR_MULTI_LINE
| CRYPT_FORMAT_STR_NO_HEX
);
1705 str
= field_format_extension_hex_with_ascii(ext
);
1709 static void add_cert_extension_detail(HWND hwnd
, struct detail_data
*data
,
1710 PCERT_EXTENSION ext
)
1712 PCCRYPT_OID_INFO oidInfo
= CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY
,
1714 LPWSTR val
= crypt_format_extension(ext
, 0);
1717 add_field_and_value_to_list(hwnd
, data
, (LPWSTR
)oidInfo
->pwszName
,
1718 val
, field_format_detailed_extension
, ext
);
1721 DWORD len
= strlen(ext
->pszObjId
);
1722 LPWSTR oidW
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
1728 for (i
= 0; i
<= len
; i
++)
1729 oidW
[i
] = ext
->pszObjId
[i
];
1730 add_field_and_value_to_list(hwnd
, data
, oidW
, val
,
1731 field_format_detailed_extension
, ext
);
1732 HeapFree(GetProcessHeap(), 0, oidW
);
1735 HeapFree(GetProcessHeap(), 0, val
);
1738 static void add_all_extensions(HWND hwnd
, struct detail_data
*data
)
1741 PCCERT_CONTEXT cert
= data
->pCertViewInfo
->pCertContext
;
1743 for (i
= 0; i
< cert
->pCertInfo
->cExtension
; i
++)
1744 add_cert_extension_detail(hwnd
, data
, &cert
->pCertInfo
->rgExtension
[i
]);
1747 static void add_critical_extensions(HWND hwnd
, struct detail_data
*data
)
1750 PCCERT_CONTEXT cert
= data
->pCertViewInfo
->pCertContext
;
1752 for (i
= 0; i
< cert
->pCertInfo
->cExtension
; i
++)
1753 if (cert
->pCertInfo
->rgExtension
[i
].fCritical
)
1754 add_cert_extension_detail(hwnd
, data
,
1755 &cert
->pCertInfo
->rgExtension
[i
]);
1758 typedef WCHAR
* (*prop_to_value_func
)(void *pb
, DWORD cb
);
1760 struct prop_id_to_string_id
1764 BOOL prop_is_string
;
1765 prop_to_value_func prop_to_value
;
1768 static WCHAR
*format_enhanced_key_usage_value(void *pb
, DWORD cb
)
1772 ext
.pszObjId
= (LPSTR
)X509_ENHANCED_KEY_USAGE
;
1773 ext
.fCritical
= FALSE
;
1774 ext
.Value
.pbData
= pb
;
1775 ext
.Value
.cbData
= cb
;
1776 return crypt_format_extension(&ext
, 0);
1779 /* Logically the access state should also be checked, and IDC_EDITPROPERTIES
1780 * disabled for read-only certificates, but native doesn't appear to do that.
1782 static const struct prop_id_to_string_id prop_id_map
[] = {
1783 { CERT_HASH_PROP_ID
, IDS_PROP_HASH
, FALSE
, format_hex_string
},
1784 { CERT_FRIENDLY_NAME_PROP_ID
, IDS_PROP_FRIENDLY_NAME
, TRUE
, NULL
},
1785 { CERT_DESCRIPTION_PROP_ID
, IDS_PROP_DESCRIPTION
, TRUE
, NULL
},
1786 { CERT_ENHKEY_USAGE_PROP_ID
, IDS_PROP_ENHKEY_USAGE
, FALSE
,
1787 format_enhanced_key_usage_value
},
1790 static void add_properties(HWND hwnd
, struct detail_data
*data
)
1793 PCCERT_CONTEXT cert
= data
->pCertViewInfo
->pCertContext
;
1795 for (i
= 0; i
< sizeof(prop_id_map
) / sizeof(prop_id_map
[0]); i
++)
1799 if (CertGetCertificateContextProperty(cert
, prop_id_map
[i
].prop
, NULL
,
1805 /* FIXME: MS adds a separate value for the signature hash
1808 pb
= HeapAlloc(GetProcessHeap(), 0, cb
);
1811 if (CertGetCertificateContextProperty(cert
,
1812 prop_id_map
[i
].prop
, pb
, &cb
))
1814 if (prop_id_map
[i
].prop_is_string
)
1817 /* Don't double-free pb */
1821 val
= prop_id_map
[i
].prop_to_value(pb
, cb
);
1823 HeapFree(GetProcessHeap(), 0, pb
);
1825 add_string_id_and_value_to_list(hwnd
, data
, prop_id_map
[i
].id
, val
,
1831 static void add_all_fields(HWND hwnd
, struct detail_data
*data
)
1833 add_v1_fields(hwnd
, data
);
1834 add_all_extensions(hwnd
, data
);
1835 add_properties(hwnd
, data
);
1838 struct selection_list_item
1841 add_fields_func add
;
1844 const struct selection_list_item listItems
[] = {
1845 { IDS_FIELDS_ALL
, add_all_fields
},
1846 { IDS_FIELDS_V1
, add_v1_fields
},
1847 { IDS_FIELDS_EXTENSIONS
, add_all_extensions
},
1848 { IDS_FIELDS_CRITICAL_EXTENSIONS
, add_critical_extensions
},
1849 { IDS_FIELDS_PROPERTIES
, add_properties
},
1852 static void create_show_list(HWND hwnd
, struct detail_data
*data
)
1854 HWND cb
= GetDlgItem(hwnd
, IDC_DETAIL_SELECT
);
1855 WCHAR buf
[MAX_STRING_LEN
];
1858 for (i
= 0; i
< sizeof(listItems
) / sizeof(listItems
[0]); i
++)
1862 LoadStringW(hInstance
, listItems
[i
].id
, buf
,
1863 sizeof(buf
) / sizeof(buf
[0]));
1864 index
= SendMessageW(cb
, CB_INSERTSTRING
, -1, (LPARAM
)buf
);
1865 SendMessageW(cb
, CB_SETITEMDATA
, index
, (LPARAM
)data
);
1867 SendMessageW(cb
, CB_SETCURSEL
, 0, 0);
1870 static void create_listview_columns(HWND hwnd
)
1872 HWND lv
= GetDlgItem(hwnd
, IDC_DETAIL_LIST
);
1874 WCHAR buf
[MAX_STRING_LEN
];
1877 SendMessageW(lv
, LVM_SETEXTENDEDLISTVIEWSTYLE
, 0, LVS_EX_FULLROWSELECT
);
1878 GetWindowRect(lv
, &rc
);
1879 LoadStringW(hInstance
, IDS_FIELD
, buf
, sizeof(buf
) / sizeof(buf
[0]));
1880 column
.mask
= LVCF_WIDTH
| LVCF_TEXT
;
1881 column
.cx
= (rc
.right
- rc
.left
) / 2 - 2;
1882 column
.pszText
= buf
;
1883 SendMessageW(lv
, LVM_INSERTCOLUMNW
, 0, (LPARAM
)&column
);
1884 LoadStringW(hInstance
, IDS_VALUE
, buf
, sizeof(buf
) / sizeof(buf
[0]));
1885 SendMessageW(lv
, LVM_INSERTCOLUMNW
, 1, (LPARAM
)&column
);
1888 static void set_fields_selection(HWND hwnd
, struct detail_data
*data
, int sel
)
1890 HWND list
= GetDlgItem(hwnd
, IDC_DETAIL_LIST
);
1892 if (sel
>= 0 && sel
< sizeof(listItems
) / sizeof(listItems
[0]))
1894 SendMessageW(list
, LVM_DELETEALLITEMS
, 0, 0);
1895 listItems
[sel
].add(list
, data
);
1899 static void create_cert_details_list(HWND hwnd
, struct detail_data
*data
)
1901 create_show_list(hwnd
, data
);
1902 create_listview_columns(hwnd
);
1903 set_fields_selection(hwnd
, data
, 0);
1907 CheckBitmapIndexUnchecked
= 1,
1908 CheckBitmapIndexChecked
= 2,
1909 CheckBitmapIndexDisabledUnchecked
= 3,
1910 CheckBitmapIndexDisabledChecked
= 4
1913 static void add_purpose(HWND hwnd
, LPCSTR oid
)
1915 HWND lv
= GetDlgItem(hwnd
, IDC_CERTIFICATE_USAGES
);
1916 PCRYPT_OID_INFO info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
1917 sizeof(CRYPT_OID_INFO
));
1921 char *oidCopy
= HeapAlloc(GetProcessHeap(), 0, strlen(oid
) + 1);
1927 strcpy(oidCopy
, oid
);
1928 info
->cbSize
= sizeof(CRYPT_OID_INFO
);
1929 info
->pszOID
= oidCopy
;
1930 item
.mask
= LVIF_TEXT
| LVIF_STATE
| LVIF_PARAM
;
1931 item
.state
= INDEXTOSTATEIMAGEMASK(CheckBitmapIndexChecked
);
1932 item
.stateMask
= LVIS_STATEIMAGEMASK
;
1933 item
.iItem
= SendMessageW(lv
, LVM_GETITEMCOUNT
, 0, 0);
1935 item
.lParam
= (LPARAM
)info
;
1936 item
.pszText
= oidCopy
;
1937 SendMessageA(lv
, LVM_INSERTITEMA
, 0, (LPARAM
)&item
);
1940 HeapFree(GetProcessHeap(), 0, info
);
1944 static BOOL
is_valid_oid(LPCSTR oid
)
1948 if (oid
[0] != '0' && oid
[0] != '1' && oid
[0] != '2')
1950 else if (oid
[1] != '.')
1957 BOOL expectNum
= TRUE
;
1959 for (ptr
= oid
+ 2, ret
= TRUE
; ret
&& *ptr
; ptr
++)
1965 else if (*(ptr
+ 1) == '.')
1972 else if (!(*(ptr
+ 1)))
1982 static BOOL
is_oid_in_list(HWND hwnd
, LPCSTR oid
)
1984 HWND lv
= GetDlgItem(hwnd
, IDC_CERTIFICATE_USAGES
);
1985 PCCRYPT_OID_INFO oidInfo
= CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY
,
1986 (void *)oid
, CRYPT_ENHKEY_USAGE_OID_GROUP_ID
);
1991 LVFINDINFOW findInfo
;
1993 findInfo
.flags
= LVFI_PARAM
;
1994 findInfo
.lParam
= (LPARAM
)oidInfo
;
1995 if (SendMessageW(lv
, LVM_FINDITEMW
, -1, (LPARAM
)&findInfo
) != -1)
2000 LVFINDINFOA findInfo
;
2002 findInfo
.flags
= LVFI_STRING
;
2004 if (SendMessageW(lv
, LVM_FINDITEMA
, -1, (LPARAM
)&findInfo
) != -1)
2010 #define MAX_PURPOSE 255
2012 static LRESULT CALLBACK
add_purpose_dlg_proc(HWND hwnd
, UINT msg
,
2013 WPARAM wp
, LPARAM lp
)
2016 char buf
[MAX_PURPOSE
+ 1];
2021 SendMessageW(GetDlgItem(hwnd
, IDC_NEW_PURPOSE
), EM_SETLIMITTEXT
,
2023 ShowScrollBar(GetDlgItem(hwnd
, IDC_NEW_PURPOSE
), SB_VERT
, FALSE
);
2024 SetWindowLongPtrW(hwnd
, DWLP_USER
, lp
);
2030 if (LOWORD(wp
) == IDC_NEW_PURPOSE
)
2032 /* Show/hide scroll bar on description depending on how much
2035 HWND description
= GetDlgItem(hwnd
, IDC_NEW_PURPOSE
);
2036 int lines
= SendMessageW(description
, EM_GETLINECOUNT
, 0, 0);
2038 ShowScrollBar(description
, SB_VERT
, lines
> 1);
2045 SendMessageA(GetDlgItem(hwnd
, IDC_NEW_PURPOSE
), WM_GETTEXT
,
2046 sizeof(buf
) / sizeof(buf
[0]), (LPARAM
)buf
);
2049 /* An empty purpose is the same as cancelling */
2050 EndDialog(hwnd
, IDCANCEL
);
2053 else if (!is_valid_oid(buf
))
2055 WCHAR title
[MAX_STRING_LEN
], error
[MAX_STRING_LEN
];
2057 LoadStringW(hInstance
, IDS_CERTIFICATE_PURPOSE_ERROR
, error
,
2058 sizeof(error
) / sizeof(error
[0]));
2059 LoadStringW(hInstance
, IDS_CERTIFICATE_PROPERTIES
, title
,
2060 sizeof(title
) / sizeof(title
[0]));
2061 MessageBoxW(hwnd
, error
, title
, MB_ICONERROR
| MB_OK
);
2063 else if (is_oid_in_list(
2064 (HWND
)GetWindowLongPtrW(hwnd
, DWLP_USER
), buf
))
2066 WCHAR title
[MAX_STRING_LEN
], error
[MAX_STRING_LEN
];
2068 LoadStringW(hInstance
, IDS_CERTIFICATE_PURPOSE_EXISTS
,
2069 error
, sizeof(error
) / sizeof(error
[0]));
2070 LoadStringW(hInstance
, IDS_CERTIFICATE_PROPERTIES
, title
,
2071 sizeof(title
) / sizeof(title
[0]));
2072 MessageBoxW(hwnd
, error
, title
, MB_ICONEXCLAMATION
| MB_OK
);
2076 HWND parent
= (HWND
)GetWindowLongPtrW(hwnd
, DWLP_USER
);
2078 add_purpose(parent
, buf
);
2079 EndDialog(hwnd
, wp
);
2084 EndDialog(hwnd
, wp
);
2095 static WCHAR
*get_cert_property_as_string(PCCERT_CONTEXT cert
, DWORD prop
)
2100 if (CertGetCertificateContextProperty(cert
, prop
, NULL
, &cb
))
2102 name
= HeapAlloc(GetProcessHeap(), 0, cb
);
2105 if (!CertGetCertificateContextProperty(cert
, prop
, (LPBYTE
)name
,
2108 HeapFree(GetProcessHeap(), 0, name
);
2116 static void redraw_states(HWND list
, BOOL enabled
)
2118 int items
= SendMessageW(list
, LVM_GETITEMCOUNT
, 0, 0), i
;
2120 for (i
= 0; i
< items
; i
++)
2122 BOOL change
= FALSE
;
2125 state
= SendMessageW(list
, LVM_GETITEMSTATE
, i
, LVIS_STATEIMAGEMASK
);
2126 /* This reverses the INDEXTOSTATEIMAGEMASK shift. There doesn't appear
2127 * to be a handy macro for it.
2132 if (state
== CheckBitmapIndexDisabledChecked
)
2134 state
= CheckBitmapIndexChecked
;
2137 if (state
== CheckBitmapIndexDisabledUnchecked
)
2139 state
= CheckBitmapIndexUnchecked
;
2145 if (state
== CheckBitmapIndexChecked
)
2147 state
= CheckBitmapIndexDisabledChecked
;
2150 if (state
== CheckBitmapIndexUnchecked
)
2152 state
= CheckBitmapIndexDisabledUnchecked
;
2160 item
.state
= INDEXTOSTATEIMAGEMASK(state
);
2161 item
.stateMask
= LVIS_STATEIMAGEMASK
;
2162 SendMessageW(list
, LVM_SETITEMSTATE
, i
, (LPARAM
)&item
);
2168 PurposeEnableAll
= 0,
2170 PurposeEnableSelected
2173 static void select_purposes(HWND hwnd
, PurposeSelection selection
)
2175 HWND lv
= GetDlgItem(hwnd
, IDC_CERTIFICATE_USAGES
);
2179 case PurposeEnableAll
:
2180 case PurposeDisableAll
:
2181 EnableWindow(lv
, FALSE
);
2182 redraw_states(lv
, FALSE
);
2183 EnableWindow(GetDlgItem(hwnd
, IDC_ADD_PURPOSE
), FALSE
);
2185 case PurposeEnableSelected
:
2186 EnableWindow(lv
, TRUE
);
2187 redraw_states(lv
, TRUE
);
2188 EnableWindow(GetDlgItem(hwnd
, IDC_ADD_PURPOSE
), TRUE
);
2192 extern BOOL WINAPI
WTHelperGetKnownUsages(DWORD action
,
2193 PCCRYPT_OID_INFO
**usages
);
2195 static void add_known_usage(HWND lv
, PCCRYPT_OID_INFO info
)
2199 item
.mask
= LVIF_TEXT
| LVIF_STATE
| LVIF_PARAM
;
2200 item
.state
= INDEXTOSTATEIMAGEMASK(CheckBitmapIndexDisabledChecked
);
2201 item
.stateMask
= LVIS_STATEIMAGEMASK
;
2202 item
.iItem
= SendMessageW(lv
, LVM_GETITEMCOUNT
, 0, 0);
2204 item
.lParam
= (LPARAM
)info
;
2205 item
.pszText
= (LPWSTR
)info
->pwszName
;
2206 SendMessageW(lv
, LVM_INSERTITEMW
, 0, (LPARAM
)&item
);
2209 struct edit_cert_data
2211 PCCERT_CONTEXT cert
;
2212 BOOL
*pfPropertiesChanged
;
2213 HIMAGELIST imageList
;
2216 static void show_cert_usages(HWND hwnd
, struct edit_cert_data
*data
)
2218 PCCERT_CONTEXT cert
= data
->cert
;
2219 HWND lv
= GetDlgItem(hwnd
, IDC_CERTIFICATE_USAGES
);
2220 PCERT_ENHKEY_USAGE usage
;
2222 PCCRYPT_OID_INFO
*usages
;
2225 PurposeSelection purposeSelection
;
2227 GetWindowRect(lv
, &rc
);
2228 column
.mask
= LVCF_WIDTH
;
2229 column
.cx
= rc
.right
- rc
.left
;
2230 SendMessageW(lv
, LVM_INSERTCOLUMNW
, 0, (LPARAM
)&column
);
2231 SendMessageW(lv
, LVM_SETIMAGELIST
, LVSIL_STATE
, (LPARAM
)data
->imageList
);
2233 /* Get enhanced key usage. Have to check for a property and an extension
2234 * separately, because CertGetEnhancedKeyUsage will succeed and return an
2235 * empty usage if neither is set. Unfortunately an empty usage implies
2236 * no usage is allowed, so we have to distinguish between the two cases.
2238 if (CertGetEnhancedKeyUsage(cert
, CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG
,
2241 usage
= HeapAlloc(GetProcessHeap(), 0, size
);
2242 if (!CertGetEnhancedKeyUsage(cert
,
2243 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG
, usage
, &size
))
2245 HeapFree(GetProcessHeap(), 0, usage
);
2248 else if (usage
->cUsageIdentifier
)
2249 purposeSelection
= PurposeEnableSelected
;
2251 purposeSelection
= PurposeDisableAll
;
2253 else if (CertGetEnhancedKeyUsage(cert
, CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG
,
2256 usage
= HeapAlloc(GetProcessHeap(), 0, size
);
2257 if (!CertGetEnhancedKeyUsage(cert
,
2258 CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG
, usage
, &size
))
2260 HeapFree(GetProcessHeap(), 0, usage
);
2263 else if (usage
->cUsageIdentifier
)
2264 purposeSelection
= PurposeEnableAll
;
2266 purposeSelection
= PurposeDisableAll
;
2270 purposeSelection
= PurposeEnableAll
;
2277 for (i
= 0; i
< usage
->cUsageIdentifier
; i
++)
2279 PCCRYPT_OID_INFO info
= CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY
,
2280 usage
->rgpszUsageIdentifier
[i
], CRYPT_ENHKEY_USAGE_OID_GROUP_ID
);
2283 add_known_usage(lv
, info
);
2285 add_purpose(hwnd
, usage
->rgpszUsageIdentifier
[i
]);
2287 HeapFree(GetProcessHeap(), 0, usage
);
2291 if (WTHelperGetKnownUsages(1, &usages
))
2293 PCCRYPT_OID_INFO
*ptr
;
2295 for (ptr
= usages
; *ptr
; ptr
++)
2296 add_known_usage(lv
, *ptr
);
2297 WTHelperGetKnownUsages(2, &usages
);
2300 select_purposes(hwnd
, purposeSelection
);
2301 SendMessageW(GetDlgItem(hwnd
, IDC_ENABLE_ALL_PURPOSES
+ purposeSelection
),
2305 static void set_general_cert_properties(HWND hwnd
, struct edit_cert_data
*data
)
2307 PCCERT_CONTEXT cert
= data
->cert
;
2310 if ((str
= get_cert_property_as_string(cert
, CERT_FRIENDLY_NAME_PROP_ID
)))
2312 SendMessageW(GetDlgItem(hwnd
, IDC_FRIENDLY_NAME
), WM_SETTEXT
, 0,
2314 HeapFree(GetProcessHeap(), 0, str
);
2316 if ((str
= get_cert_property_as_string(cert
, CERT_DESCRIPTION_PROP_ID
)))
2318 SendMessageW(GetDlgItem(hwnd
, IDC_DESCRIPTION
), WM_SETTEXT
, 0,
2320 HeapFree(GetProcessHeap(), 0, str
);
2322 show_cert_usages(hwnd
, data
);
2325 static void toggle_usage(HWND hwnd
, int iItem
)
2329 HWND lv
= GetDlgItem(hwnd
, IDC_CERTIFICATE_USAGES
);
2331 item
.mask
= LVIF_STATE
;
2334 item
.stateMask
= LVIS_STATEIMAGEMASK
;
2335 res
= SendMessageW(lv
, LVM_GETITEMW
, 0, (LPARAM
)&item
);
2338 int state
= item
.state
>> 12;
2340 item
.state
= INDEXTOSTATEIMAGEMASK(
2341 state
== CheckBitmapIndexChecked
? CheckBitmapIndexUnchecked
:
2342 CheckBitmapIndexChecked
);
2343 SendMessageW(lv
, LVM_SETITEMSTATE
, iItem
, (LPARAM
)&item
);
2347 static void set_cert_string_property(PCCERT_CONTEXT cert
, DWORD prop
,
2350 if (str
&& strlenW(str
))
2352 CRYPT_DATA_BLOB blob
;
2354 blob
.pbData
= (BYTE
*)str
;
2355 blob
.cbData
= (strlenW(str
) + 1) * sizeof(WCHAR
);
2356 CertSetCertificateContextProperty(cert
, prop
, 0, &blob
);
2359 CertSetCertificateContextProperty(cert
, prop
, 0, NULL
);
2362 #define WM_REFRESH_VIEW WM_USER + 0
2364 static BOOL CALLBACK
refresh_propsheet_pages(HWND hwnd
, LPARAM lParam
)
2366 if ((GetClassLongW(hwnd
, GCW_ATOM
) == WC_DIALOG
))
2367 SendMessageW(hwnd
, WM_REFRESH_VIEW
, 0, 0);
2371 #define MAX_FRIENDLY_NAME 40
2372 #define MAX_DESCRIPTION 255
2374 static void apply_general_changes(HWND hwnd
)
2376 WCHAR buf
[MAX_DESCRIPTION
+ 1];
2377 struct edit_cert_data
*data
=
2378 (struct edit_cert_data
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
2380 SendMessageW(GetDlgItem(hwnd
, IDC_FRIENDLY_NAME
), WM_GETTEXT
,
2381 sizeof(buf
) / sizeof(buf
[0]), (LPARAM
)buf
);
2382 set_cert_string_property(data
->cert
, CERT_FRIENDLY_NAME_PROP_ID
, buf
);
2383 SendMessageW(GetDlgItem(hwnd
, IDC_DESCRIPTION
), WM_GETTEXT
,
2384 sizeof(buf
) / sizeof(buf
[0]), (LPARAM
)buf
);
2385 set_cert_string_property(data
->cert
, CERT_DESCRIPTION_PROP_ID
, buf
);
2386 if (IsDlgButtonChecked(hwnd
, IDC_ENABLE_ALL_PURPOSES
))
2388 /* Setting a NULL usage removes the enhanced key usage property. */
2389 CertSetEnhancedKeyUsage(data
->cert
, NULL
);
2391 else if (IsDlgButtonChecked(hwnd
, IDC_DISABLE_ALL_PURPOSES
))
2393 CERT_ENHKEY_USAGE usage
= { 0, NULL
};
2395 CertSetEnhancedKeyUsage(data
->cert
, &usage
);
2397 else if (IsDlgButtonChecked(hwnd
, IDC_ENABLE_SELECTED_PURPOSES
))
2399 HWND lv
= GetDlgItem(hwnd
, IDC_CERTIFICATE_USAGES
);
2400 CERT_ENHKEY_USAGE usage
= { 0, NULL
};
2401 int purposes
= SendMessageW(lv
, LVM_GETITEMCOUNT
, 0, 0), i
;
2404 item
.mask
= LVIF_STATE
| LVIF_PARAM
;
2406 item
.stateMask
= LVIS_STATEIMAGEMASK
;
2407 for (i
= 0; i
< purposes
; i
++)
2410 if (SendMessageW(lv
, LVM_GETITEMW
, 0, (LPARAM
)&item
))
2412 int state
= item
.state
>> 12;
2414 if (state
== CheckBitmapIndexChecked
)
2416 CRYPT_OID_INFO
*info
= (CRYPT_OID_INFO
*)item
.lParam
;
2418 if (usage
.cUsageIdentifier
)
2419 usage
.rgpszUsageIdentifier
=
2420 HeapReAlloc(GetProcessHeap(), 0,
2421 usage
.rgpszUsageIdentifier
,
2422 (usage
.cUsageIdentifier
+ 1) * sizeof(LPSTR
));
2424 usage
.rgpszUsageIdentifier
=
2425 HeapAlloc(GetProcessHeap(), 0, sizeof(LPSTR
));
2426 if (usage
.rgpszUsageIdentifier
)
2427 usage
.rgpszUsageIdentifier
[usage
.cUsageIdentifier
++] =
2428 (LPSTR
)info
->pszOID
;
2432 CertSetEnhancedKeyUsage(data
->cert
, &usage
);
2433 HeapFree(GetProcessHeap(), 0, usage
.rgpszUsageIdentifier
);
2435 EnumChildWindows(GetParent(GetParent(hwnd
)), refresh_propsheet_pages
, 0);
2436 if (data
->pfPropertiesChanged
)
2437 *data
->pfPropertiesChanged
= TRUE
;
2440 static LRESULT CALLBACK
cert_properties_general_dlg_proc(HWND hwnd
, UINT msg
,
2441 WPARAM wp
, LPARAM lp
)
2443 PROPSHEETPAGEW
*page
;
2445 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd
, msg
, wp
, lp
);
2451 HWND description
= GetDlgItem(hwnd
, IDC_DESCRIPTION
);
2452 struct detail_data
*detailData
;
2453 struct edit_cert_data
*editData
;
2455 page
= (PROPSHEETPAGEW
*)lp
;
2456 detailData
= (struct detail_data
*)page
->lParam
;
2457 SendMessageW(GetDlgItem(hwnd
, IDC_FRIENDLY_NAME
), EM_SETLIMITTEXT
,
2458 MAX_FRIENDLY_NAME
, 0);
2459 SendMessageW(description
, EM_SETLIMITTEXT
, MAX_DESCRIPTION
, 0);
2460 ShowScrollBar(description
, SB_VERT
, FALSE
);
2461 editData
= HeapAlloc(GetProcessHeap(), 0,
2462 sizeof(struct edit_cert_data
));
2465 editData
->imageList
= ImageList_Create(16, 16,
2466 ILC_COLOR4
| ILC_MASK
, 4, 0);
2467 if (editData
->imageList
)
2470 COLORREF backColor
= RGB(255, 0, 255);
2472 bmp
= LoadBitmapW(hInstance
, MAKEINTRESOURCEW(IDB_CHECKS
));
2473 ImageList_AddMasked(editData
->imageList
, bmp
, backColor
);
2475 ImageList_SetBkColor(editData
->imageList
, CLR_NONE
);
2477 editData
->cert
= detailData
->pCertViewInfo
->pCertContext
;
2478 editData
->pfPropertiesChanged
= detailData
->pfPropertiesChanged
;
2479 SetWindowLongPtrW(hwnd
, DWLP_USER
, (LPARAM
)editData
);
2480 set_general_cert_properties(hwnd
, editData
);
2486 NMHDR
*hdr
= (NMHDR
*)lp
;
2492 nm
= (NMITEMACTIVATE
*)lp
;
2493 toggle_usage(hwnd
, nm
->iItem
);
2494 SendMessageW(GetParent(hwnd
), PSM_CHANGED
, (WPARAM
)hwnd
, 0);
2497 apply_general_changes(hwnd
);
2506 SendMessageW(GetParent(hwnd
), PSM_CHANGED
, (WPARAM
)hwnd
, 0);
2507 if (LOWORD(wp
) == IDC_DESCRIPTION
)
2509 /* Show/hide scroll bar on description depending on how much
2512 HWND description
= GetDlgItem(hwnd
, IDC_DESCRIPTION
);
2513 int lines
= SendMessageW(description
, EM_GETLINECOUNT
, 0, 0);
2515 ShowScrollBar(description
, SB_VERT
, lines
> 1);
2521 case IDC_ADD_PURPOSE
:
2522 if (DialogBoxParamW(hInstance
,
2523 MAKEINTRESOURCEW(IDD_ADD_CERT_PURPOSE
), hwnd
,
2524 add_purpose_dlg_proc
, (LPARAM
)hwnd
) == IDOK
)
2525 SendMessageW(GetParent(hwnd
), PSM_CHANGED
, (WPARAM
)hwnd
, 0);
2527 case IDC_ENABLE_ALL_PURPOSES
:
2528 case IDC_DISABLE_ALL_PURPOSES
:
2529 case IDC_ENABLE_SELECTED_PURPOSES
:
2530 SendMessageW(GetParent(hwnd
), PSM_CHANGED
, (WPARAM
)hwnd
, 0);
2531 select_purposes(hwnd
, LOWORD(wp
) - IDC_ENABLE_ALL_PURPOSES
);
2541 static UINT CALLBACK
cert_properties_general_callback(HWND hwnd
, UINT msg
,
2542 PROPSHEETPAGEW
*page
)
2546 struct edit_cert_data
*data
;
2551 lv
= GetDlgItem(hwnd
, IDC_CERTIFICATE_USAGES
);
2552 cItem
= SendMessageW(lv
, LVM_GETITEMCOUNT
, 0, 0);
2553 for (i
= 0; i
< cItem
; i
++)
2557 item
.mask
= LVIF_PARAM
;
2560 if (SendMessageW(lv
, LVM_GETITEMW
, 0, (LPARAM
)&item
) && item
.lParam
)
2562 PCRYPT_OID_INFO info
= (PCRYPT_OID_INFO
)item
.lParam
;
2564 if (info
->cbSize
== sizeof(CRYPT_OID_INFO
) && !info
->dwGroupId
)
2566 HeapFree(GetProcessHeap(), 0, (LPSTR
)info
->pszOID
);
2567 HeapFree(GetProcessHeap(), 0, info
);
2571 data
= (struct edit_cert_data
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
2574 ImageList_Destroy(data
->imageList
);
2575 HeapFree(GetProcessHeap(), 0, data
);
2582 static void show_edit_cert_properties_dialog(HWND parent
,
2583 struct detail_data
*data
)
2585 PROPSHEETHEADERW hdr
;
2586 PROPSHEETPAGEW page
; /* FIXME: need to add a cross-certificate page */
2588 TRACE("(%p)\n", data
);
2590 memset(&page
, 0, sizeof(PROPSHEETPAGEW
));
2591 page
.dwSize
= sizeof(page
);
2592 page
.dwFlags
= PSP_USECALLBACK
;
2593 page
.pfnCallback
= cert_properties_general_callback
;
2594 page
.hInstance
= hInstance
;
2595 page
.u
.pszTemplate
= MAKEINTRESOURCEW(IDD_CERT_PROPERTIES_GENERAL
);
2596 page
.pfnDlgProc
= cert_properties_general_dlg_proc
;
2597 page
.lParam
= (LPARAM
)data
;
2599 memset(&hdr
, 0, sizeof(hdr
));
2600 hdr
.dwSize
= sizeof(hdr
);
2601 hdr
.hwndParent
= parent
;
2602 hdr
.dwFlags
= PSH_PROPSHEETPAGE
;
2603 hdr
.hInstance
= hInstance
;
2604 hdr
.pszCaption
= MAKEINTRESOURCEW(IDS_CERTIFICATE_PROPERTIES
);
2605 hdr
.u3
.ppsp
= &page
;
2607 PropertySheetW(&hdr
);
2610 static void free_detail_fields(struct detail_data
*data
)
2614 for (i
= 0; i
< data
->cFields
; i
++)
2615 HeapFree(GetProcessHeap(), 0, data
->fields
[i
].detailed_value
);
2616 HeapFree(GetProcessHeap(), 0, data
->fields
);
2617 data
->fields
= NULL
;
2621 static void refresh_details_view(HWND hwnd
)
2623 HWND cb
= GetDlgItem(hwnd
, IDC_DETAIL_SELECT
);
2625 struct detail_data
*data
;
2627 curSel
= SendMessageW(cb
, CB_GETCURSEL
, 0, 0);
2628 /* Actually, any index will do, since they all store the same data value */
2629 data
= (struct detail_data
*)SendMessageW(cb
, CB_GETITEMDATA
, curSel
, 0);
2630 free_detail_fields(data
);
2631 set_fields_selection(hwnd
, data
, curSel
);
2634 static LRESULT CALLBACK
detail_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wp
,
2637 PROPSHEETPAGEW
*page
;
2638 struct detail_data
*data
;
2640 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd
, msg
, wp
, lp
);
2645 page
= (PROPSHEETPAGEW
*)lp
;
2646 data
= (struct detail_data
*)page
->lParam
;
2647 create_cert_details_list(hwnd
, data
);
2648 if (!(data
->pCertViewInfo
->dwFlags
& CRYPTUI_ENABLE_EDITPROPERTIES
))
2649 EnableWindow(GetDlgItem(hwnd
, IDC_EDITPROPERTIES
), FALSE
);
2650 if (data
->pCertViewInfo
->dwFlags
& CRYPTUI_DISABLE_EXPORT
)
2651 EnableWindow(GetDlgItem(hwnd
, IDC_EXPORT
), FALSE
);
2656 HWND list
= GetDlgItem(hwnd
, IDC_DETAIL_LIST
);
2658 nm
= (NMITEMACTIVATE
*)lp
;
2659 if (nm
->hdr
.hwndFrom
== list
&& nm
->uNewState
& LVN_ITEMACTIVATE
2660 && nm
->hdr
.code
== LVN_ITEMCHANGED
)
2662 data
= (struct detail_data
*)nm
->lParam
;
2663 if (nm
->iItem
>= 0 && data
&& nm
->iItem
< data
->cFields
)
2665 WCHAR buf
[MAX_STRING_LEN
], *val
= NULL
;
2666 HWND valueCtl
= GetDlgItem(hwnd
, IDC_DETAIL_VALUE
);
2668 if (data
->fields
[nm
->iItem
].create
)
2669 val
= data
->fields
[nm
->iItem
].create(
2670 data
->pCertViewInfo
->pCertContext
,
2671 data
->fields
[nm
->iItem
].param
);
2677 item
.cchTextMax
= sizeof(buf
) / sizeof(buf
[0]);
2678 item
.mask
= LVIF_TEXT
;
2680 item
.iItem
= nm
->iItem
;
2682 res
= SendMessageW(list
, LVM_GETITEMW
, 0, (LPARAM
)&item
);
2686 /* Select all the text in the control, the next update will
2689 SendMessageW(valueCtl
, EM_SETSEL
, 0, -1);
2690 add_unformatted_text_to_control(valueCtl
, val
,
2691 val
? strlenW(val
) : 0);
2693 HeapFree(GetProcessHeap(), 0, val
);
2702 FIXME("call CryptUIWizExport\n");
2704 case IDC_EDITPROPERTIES
:
2706 HWND cb
= GetDlgItem(hwnd
, IDC_DETAIL_SELECT
);
2709 curSel
= SendMessageW(cb
, CB_GETCURSEL
, 0, 0);
2710 /* Actually, any index will do, since they all store the same
2713 data
= (struct detail_data
*)SendMessageW(cb
, CB_GETITEMDATA
,
2715 show_edit_cert_properties_dialog(GetParent(hwnd
), data
);
2718 case ((CBN_SELCHANGE
<< 16) | IDC_DETAIL_SELECT
):
2719 refresh_details_view(hwnd
);
2723 case WM_REFRESH_VIEW
:
2724 refresh_details_view(hwnd
);
2730 static UINT CALLBACK
detail_callback(HWND hwnd
, UINT msg
,
2731 PROPSHEETPAGEW
*page
)
2733 struct detail_data
*data
;
2738 data
= (struct detail_data
*)page
->lParam
;
2739 free_detail_fields(data
);
2740 HeapFree(GetProcessHeap(), 0, data
);
2746 static BOOL
init_detail_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
,
2747 BOOL
*pfPropertiesChanged
, PROPSHEETPAGEW
*page
)
2750 struct detail_data
*data
= HeapAlloc(GetProcessHeap(), 0,
2751 sizeof(struct detail_data
));
2755 data
->pCertViewInfo
= pCertViewInfo
;
2756 data
->pfPropertiesChanged
= pfPropertiesChanged
;
2758 data
->fields
= NULL
;
2759 memset(page
, 0, sizeof(PROPSHEETPAGEW
));
2760 page
->dwSize
= sizeof(PROPSHEETPAGEW
);
2761 page
->dwFlags
= PSP_USECALLBACK
;
2762 page
->pfnCallback
= detail_callback
;
2763 page
->hInstance
= hInstance
;
2764 page
->u
.pszTemplate
= MAKEINTRESOURCEW(IDD_DETAIL
);
2765 page
->pfnDlgProc
= detail_dlg_proc
;
2766 page
->lParam
= (LPARAM
)data
;
2774 struct hierarchy_data
2776 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
;
2777 HIMAGELIST imageList
;
2781 static LPARAM
index_to_lparam(struct hierarchy_data
*data
, DWORD index
)
2783 CRYPT_PROVIDER_SGNR
*provSigner
= WTHelperGetProvSignerFromChain(
2784 (CRYPT_PROVIDER_DATA
*)data
->pCertViewInfo
->u
.pCryptProviderData
,
2785 data
->pCertViewInfo
->idxSigner
, data
->pCertViewInfo
->fCounterSigner
,
2786 data
->pCertViewInfo
->idxCounterSigner
);
2788 /* Takes advantage of the fact that a pointer is 32-bit aligned, and
2789 * therefore always even.
2791 if (index
== provSigner
->csCertChain
- 1)
2792 return (LPARAM
)data
;
2793 return index
<< 1 | 1;
2796 static inline DWORD
lparam_to_index(struct hierarchy_data
*data
, LPARAM lp
)
2798 CRYPT_PROVIDER_SGNR
*provSigner
= WTHelperGetProvSignerFromChain(
2799 (CRYPT_PROVIDER_DATA
*)data
->pCertViewInfo
->u
.pCryptProviderData
,
2800 data
->pCertViewInfo
->idxSigner
, data
->pCertViewInfo
->fCounterSigner
,
2801 data
->pCertViewInfo
->idxCounterSigner
);
2804 return provSigner
->csCertChain
- 1;
2808 static struct hierarchy_data
*get_hierarchy_data_from_tree_item(HWND tree
,
2811 struct hierarchy_data
*data
= NULL
;
2812 HTREEITEM root
= NULL
;
2815 HTREEITEM parent
= (HTREEITEM
)SendMessageW(tree
, TVM_GETNEXTITEM
,
2816 TVGN_PARENT
, (LPARAM
)hItem
);
2826 item
.mask
= TVIF_PARAM
;
2828 SendMessageW(tree
, TVM_GETITEMW
, 0, (LPARAM
)&item
);
2829 data
= (struct hierarchy_data
*)item
.lParam
;
2834 static WCHAR
*get_cert_display_name(PCCERT_CONTEXT cert
)
2836 WCHAR
*name
= get_cert_property_as_string(cert
, CERT_FRIENDLY_NAME_PROP_ID
);
2839 name
= get_cert_name_string(cert
, CERT_NAME_SIMPLE_DISPLAY_TYPE
, 0);
2843 static void show_cert_chain(HWND hwnd
, struct hierarchy_data
*data
)
2845 HWND tree
= GetDlgItem(hwnd
, IDC_CERTPATH
);
2846 CRYPT_PROVIDER_SGNR
*provSigner
= WTHelperGetProvSignerFromChain(
2847 (CRYPT_PROVIDER_DATA
*)data
->pCertViewInfo
->u
.pCryptProviderData
,
2848 data
->pCertViewInfo
->idxSigner
, data
->pCertViewInfo
->fCounterSigner
,
2849 data
->pCertViewInfo
->idxCounterSigner
);
2851 HTREEITEM parent
= NULL
;
2853 SendMessageW(tree
, TVM_SETIMAGELIST
, TVSIL_NORMAL
, (LPARAM
)data
->imageList
);
2854 for (i
= provSigner
->csCertChain
; i
; i
--)
2858 name
= get_cert_display_name(provSigner
->pasCertChain
[i
- 1].pCert
);
2861 TVINSERTSTRUCTW tvis
;
2863 tvis
.hParent
= parent
;
2864 tvis
.hInsertAfter
= TVI_LAST
;
2865 tvis
.u
.item
.mask
= TVIF_TEXT
| TVIF_STATE
| TVIF_IMAGE
|
2866 TVIF_SELECTEDIMAGE
| TVIF_PARAM
;
2867 tvis
.u
.item
.pszText
= name
;
2868 tvis
.u
.item
.state
= TVIS_EXPANDED
;
2869 tvis
.u
.item
.stateMask
= TVIS_EXPANDED
;
2871 (provSigner
->pChainContext
->TrustStatus
.dwErrorStatus
&
2872 CERT_TRUST_IS_PARTIAL_CHAIN
))
2874 /* The root of the chain has a special case: if the chain is
2875 * a partial chain, the icon is a warning icon rather than an
2878 tvis
.u
.item
.iImage
= 2;
2880 else if (provSigner
->pasCertChain
[i
- 1].pChainElement
->TrustStatus
.
2882 tvis
.u
.item
.iImage
= 0;
2884 tvis
.u
.item
.iImage
= 1;
2885 tvis
.u
.item
.iSelectedImage
= tvis
.u
.item
.iImage
;
2886 tvis
.u
.item
.lParam
= index_to_lparam(data
, i
- 1);
2887 parent
= (HTREEITEM
)SendMessageW(tree
, TVM_INSERTITEMW
, 0,
2889 HeapFree(GetProcessHeap(), 0, name
);
2894 static void set_certificate_status(HWND hwnd
, CRYPT_PROVIDER_CERT
*cert
)
2896 /* Select all the text in the control, the next update will replace it */
2897 SendMessageW(hwnd
, EM_SETSEL
, 0, -1);
2898 /* Set the highest priority error messages first. */
2899 if (!(cert
->dwConfidence
& CERT_CONFIDENCE_SIG
))
2900 add_string_resource_to_control(hwnd
, IDS_CERTIFICATE_BAD_SIGNATURE
);
2901 else if (!(cert
->dwConfidence
& CERT_CONFIDENCE_TIME
))
2902 add_string_resource_to_control(hwnd
, IDS_CERTIFICATE_BAD_TIME
);
2903 else if (!(cert
->dwConfidence
& CERT_CONFIDENCE_TIMENEST
))
2904 add_string_resource_to_control(hwnd
, IDS_CERTIFICATE_BAD_TIMENEST
);
2905 else if (cert
->dwRevokedReason
)
2906 add_string_resource_to_control(hwnd
, IDS_CERTIFICATE_REVOKED
);
2908 add_string_resource_to_control(hwnd
, IDS_CERTIFICATE_VALID
);
2911 static void set_certificate_status_for_end_cert(HWND hwnd
,
2912 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
)
2914 HWND status
= GetDlgItem(hwnd
, IDC_CERTIFICATESTATUSTEXT
);
2915 CRYPT_PROVIDER_SGNR
*provSigner
= WTHelperGetProvSignerFromChain(
2916 (CRYPT_PROVIDER_DATA
*)pCertViewInfo
->u
.pCryptProviderData
,
2917 pCertViewInfo
->idxSigner
, pCertViewInfo
->fCounterSigner
,
2918 pCertViewInfo
->idxCounterSigner
);
2919 CRYPT_PROVIDER_CERT
*provCert
= WTHelperGetProvCertFromChain(provSigner
,
2920 pCertViewInfo
->idxCert
);
2922 set_certificate_status(status
, provCert
);
2925 static void show_cert_hierarchy(HWND hwnd
, struct hierarchy_data
*data
)
2927 /* Disable view certificate button until a certificate is selected */
2928 EnableWindow(GetDlgItem(hwnd
, IDC_VIEWCERTIFICATE
), FALSE
);
2929 show_cert_chain(hwnd
, data
);
2930 set_certificate_status_for_end_cert(hwnd
, data
->pCertViewInfo
);
2933 static void show_dialog_for_selected_cert(HWND hwnd
)
2935 HWND tree
= GetDlgItem(hwnd
, IDC_CERTPATH
);
2937 struct hierarchy_data
*data
;
2940 memset(&item
, 0, sizeof(item
));
2941 item
.mask
= TVIF_HANDLE
| TVIF_PARAM
;
2942 item
.hItem
= (HTREEITEM
)SendMessageW(tree
, TVM_GETNEXTITEM
, TVGN_CARET
,
2944 SendMessageW(tree
, TVM_GETITEMW
, 0, (LPARAM
)&item
);
2945 data
= get_hierarchy_data_from_tree_item(tree
, item
.hItem
);
2946 selection
= lparam_to_index(data
, item
.lParam
);
2949 CRYPT_PROVIDER_SGNR
*provSigner
;
2950 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo
;
2951 BOOL changed
= FALSE
;
2953 provSigner
= WTHelperGetProvSignerFromChain(
2954 (CRYPT_PROVIDER_DATA
*)data
->pCertViewInfo
->u
.pCryptProviderData
,
2955 data
->pCertViewInfo
->idxSigner
,
2956 data
->pCertViewInfo
->fCounterSigner
,
2957 data
->pCertViewInfo
->idxCounterSigner
);
2958 memset(&viewInfo
, 0, sizeof(viewInfo
));
2959 viewInfo
.dwSize
= sizeof(viewInfo
);
2960 viewInfo
.dwFlags
= data
->pCertViewInfo
->dwFlags
;
2961 viewInfo
.szTitle
= data
->pCertViewInfo
->szTitle
;
2962 viewInfo
.pCertContext
= provSigner
->pasCertChain
[selection
].pCert
;
2963 viewInfo
.cStores
= data
->pCertViewInfo
->cStores
;
2964 viewInfo
.rghStores
= data
->pCertViewInfo
->rghStores
;
2965 viewInfo
.cPropSheetPages
= data
->pCertViewInfo
->cPropSheetPages
;
2966 viewInfo
.rgPropSheetPages
= data
->pCertViewInfo
->rgPropSheetPages
;
2967 viewInfo
.nStartPage
= data
->pCertViewInfo
->nStartPage
;
2968 CryptUIDlgViewCertificateW(&viewInfo
, &changed
);
2971 /* Delete the contents of the tree */
2972 SendMessageW(tree
, TVM_DELETEITEM
, 0, (LPARAM
)TVI_ROOT
);
2973 /* Reinitialize the tree */
2974 show_cert_hierarchy(hwnd
, data
);
2979 static LRESULT CALLBACK
hierarchy_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wp
,
2982 PROPSHEETPAGEW
*page
;
2983 struct hierarchy_data
*data
;
2985 HWND tree
= GetDlgItem(hwnd
, IDC_CERTPATH
);
2987 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd
, msg
, wp
, lp
);
2992 page
= (PROPSHEETPAGEW
*)lp
;
2993 data
= (struct hierarchy_data
*)page
->lParam
;
2994 show_cert_hierarchy(hwnd
, data
);
3003 case TVN_SELCHANGEDW
:
3005 NMTREEVIEWW
*nm
= (NMTREEVIEWW
*)lp
;
3007 CRYPT_PROVIDER_SGNR
*provSigner
;
3009 data
= get_hierarchy_data_from_tree_item(tree
, nm
->itemNew
.hItem
);
3010 selection
= lparam_to_index(data
, nm
->itemNew
.lParam
);
3011 provSigner
= WTHelperGetProvSignerFromChain(
3012 (CRYPT_PROVIDER_DATA
*)data
->pCertViewInfo
->u
.pCryptProviderData
,
3013 data
->pCertViewInfo
->idxSigner
,
3014 data
->pCertViewInfo
->fCounterSigner
,
3015 data
->pCertViewInfo
->idxCounterSigner
);
3016 EnableWindow(GetDlgItem(hwnd
, IDC_VIEWCERTIFICATE
), selection
!= 0);
3017 set_certificate_status(GetDlgItem(hwnd
, IDC_CERTIFICATESTATUSTEXT
),
3018 &provSigner
->pasCertChain
[selection
]);
3022 show_dialog_for_selected_cert(hwnd
);
3023 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, 1);
3032 case IDC_VIEWCERTIFICATE
:
3033 show_dialog_for_selected_cert(hwnd
);
3037 case WM_REFRESH_VIEW
:
3041 /* Get hierarchy data */
3042 memset(&item
, 0, sizeof(item
));
3043 item
.mask
= TVIF_HANDLE
| TVIF_PARAM
;
3044 item
.hItem
= (HTREEITEM
)SendMessageW(tree
, TVM_GETNEXTITEM
, TVGN_ROOT
,
3046 data
= get_hierarchy_data_from_tree_item(tree
, item
.hItem
);
3047 /* Delete the contents of the tree */
3048 SendMessageW(tree
, TVM_DELETEITEM
, 0, (LPARAM
)TVI_ROOT
);
3049 /* Reinitialize the tree */
3050 show_cert_hierarchy(hwnd
, data
);
3057 static UINT CALLBACK
hierarchy_callback(HWND hwnd
, UINT msg
,
3058 PROPSHEETPAGEW
*page
)
3060 struct hierarchy_data
*data
;
3065 data
= (struct hierarchy_data
*)page
->lParam
;
3066 ImageList_Destroy(data
->imageList
);
3067 HeapFree(GetProcessHeap(), 0, data
);
3073 static BOOL
init_hierarchy_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
,
3074 PROPSHEETPAGEW
*page
)
3076 struct hierarchy_data
*data
= HeapAlloc(GetProcessHeap(), 0,
3077 sizeof(struct hierarchy_data
));
3082 data
->imageList
= ImageList_Create(16, 16, ILC_COLOR4
| ILC_MASK
, 2, 0);
3083 if (data
->imageList
)
3086 COLORREF backColor
= RGB(255, 0, 255);
3088 data
->pCertViewInfo
= pCertViewInfo
;
3089 data
->selectedCert
= 0xffffffff;
3091 bmp
= LoadBitmapW(hInstance
, MAKEINTRESOURCEW(IDB_SMALL_ICONS
));
3092 ImageList_AddMasked(data
->imageList
, bmp
, backColor
);
3094 ImageList_SetBkColor(data
->imageList
, CLR_NONE
);
3096 memset(page
, 0, sizeof(PROPSHEETPAGEW
));
3097 page
->dwSize
= sizeof(PROPSHEETPAGEW
);
3098 page
->dwFlags
= PSP_USECALLBACK
;
3099 page
->hInstance
= hInstance
;
3100 page
->u
.pszTemplate
= MAKEINTRESOURCEW(IDD_HIERARCHY
);
3101 page
->pfnDlgProc
= hierarchy_dlg_proc
;
3102 page
->lParam
= (LPARAM
)data
;
3103 page
->pfnCallback
= hierarchy_callback
;
3107 HeapFree(GetProcessHeap(), 0, data
);
3112 static int CALLBACK
cert_prop_sheet_proc(HWND hwnd
, UINT msg
, LPARAM lp
)
3117 TRACE("(%p, %08x, %08lx)\n", hwnd
, msg
, lp
);
3121 case PSCB_INITIALIZED
:
3122 /* Get cancel button's position.. */
3123 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rc
);
3124 topLeft
.x
= rc
.left
;
3126 ScreenToClient(hwnd
, &topLeft
);
3127 /* hide the cancel button.. */
3128 ShowWindow(GetDlgItem(hwnd
, IDCANCEL
), FALSE
);
3129 /* get the OK button's size.. */
3130 GetWindowRect(GetDlgItem(hwnd
, IDOK
), &rc
);
3131 /* and move the OK button to the cancel button's original position. */
3132 MoveWindow(GetDlgItem(hwnd
, IDOK
), topLeft
.x
, topLeft
.y
,
3133 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, FALSE
);
3134 GetWindowRect(GetDlgItem(hwnd
, IDOK
), &rc
);
3140 static BOOL
show_cert_dialog(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
,
3141 CRYPT_PROVIDER_CERT
*provCert
, BOOL
*pfPropertiesChanged
)
3143 static const WCHAR riched
[] = { 'r','i','c','h','e','d','2','0',0 };
3145 PROPSHEETPAGEW
*pages
;
3147 HMODULE lib
= LoadLibraryW(riched
);
3149 nPages
= pCertViewInfo
->cPropSheetPages
+ 1; /* one for the General tab */
3150 if (!(pCertViewInfo
->dwFlags
& CRYPTUI_HIDE_DETAILPAGE
))
3152 if (!(pCertViewInfo
->dwFlags
& CRYPTUI_HIDE_HIERARCHYPAGE
))
3154 pages
= HeapAlloc(GetProcessHeap(), 0, nPages
* sizeof(PROPSHEETPAGEW
));
3157 PROPSHEETHEADERW hdr
;
3158 CRYPTUI_INITDIALOG_STRUCT
*init
= NULL
;
3161 memset(&hdr
, 0, sizeof(hdr
));
3162 hdr
.dwSize
= sizeof(hdr
);
3163 hdr
.dwFlags
= PSH_NOAPPLYNOW
| PSH_PROPSHEETPAGE
| PSH_USECALLBACK
;
3164 hdr
.hInstance
= hInstance
;
3165 if (pCertViewInfo
->szTitle
)
3166 hdr
.pszCaption
= pCertViewInfo
->szTitle
;
3168 hdr
.pszCaption
= MAKEINTRESOURCEW(IDS_CERTIFICATE
);
3169 init_general_page(pCertViewInfo
, &pages
[hdr
.nPages
++]);
3170 if (!(pCertViewInfo
->dwFlags
& CRYPTUI_HIDE_DETAILPAGE
))
3172 if (init_detail_page(pCertViewInfo
, pfPropertiesChanged
,
3173 &pages
[hdr
.nPages
]))
3176 if (!(pCertViewInfo
->dwFlags
& CRYPTUI_HIDE_HIERARCHYPAGE
))
3178 if (init_hierarchy_page(pCertViewInfo
, &pages
[hdr
.nPages
]))
3181 /* Copy each additional page, and create the init dialog struct for it
3183 if (pCertViewInfo
->cPropSheetPages
)
3185 init
= HeapAlloc(GetProcessHeap(), 0,
3186 pCertViewInfo
->cPropSheetPages
*
3187 sizeof(CRYPTUI_INITDIALOG_STRUCT
));
3190 for (i
= 0; i
< pCertViewInfo
->cPropSheetPages
; i
++)
3192 memcpy(&pages
[hdr
.nPages
+ i
],
3193 &pCertViewInfo
->rgPropSheetPages
[i
],
3194 sizeof(PROPSHEETPAGEW
));
3195 init
[i
].lParam
= pCertViewInfo
->rgPropSheetPages
[i
].lParam
;
3196 init
[i
].pCertContext
= pCertViewInfo
->pCertContext
;
3197 pages
[hdr
.nPages
+ i
].lParam
= (LPARAM
)&init
[i
];
3199 if (pCertViewInfo
->nStartPage
& 0x8000)
3201 /* Start page index is relative to the number of default
3204 hdr
.u2
.nStartPage
= pCertViewInfo
->nStartPage
+ hdr
.nPages
;
3207 hdr
.u2
.nStartPage
= pCertViewInfo
->nStartPage
;
3208 hdr
.nPages
= nPages
;
3212 SetLastError(ERROR_OUTOFMEMORY
);
3216 /* Ignore the relative flag if there aren't any additional pages */
3217 hdr
.u2
.nStartPage
= pCertViewInfo
->nStartPage
& 0x7fff;
3224 hdr
.u3
.ppsp
= pages
;
3225 hdr
.pfnCallback
= cert_prop_sheet_proc
;
3226 l
= PropertySheetW(&hdr
);
3229 SetLastError(ERROR_CANCELLED
);
3233 HeapFree(GetProcessHeap(), 0, init
);
3234 HeapFree(GetProcessHeap(), 0, pages
);
3237 SetLastError(ERROR_OUTOFMEMORY
);
3242 /***********************************************************************
3243 * CryptUIDlgViewCertificateW (CRYPTUI.@)
3245 BOOL WINAPI
CryptUIDlgViewCertificateW(
3246 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
, BOOL
*pfPropertiesChanged
)
3248 static GUID generic_cert_verify
= WINTRUST_ACTION_GENERIC_CERT_VERIFY
;
3249 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo
;
3251 WINTRUST_CERT_INFO cert
;
3253 CRYPT_PROVIDER_SGNR
*signer
;
3254 CRYPT_PROVIDER_CERT
*provCert
= NULL
;
3256 TRACE("(%p, %p)\n", pCertViewInfo
, pfPropertiesChanged
);
3258 if (pCertViewInfo
->dwSize
!= sizeof(CRYPTUI_VIEWCERTIFICATE_STRUCTW
))
3260 SetLastError(ERROR_INVALID_PARAMETER
);
3263 /* Make a local copy in case we have to call WinVerifyTrust ourselves */
3264 memcpy(&viewInfo
, pCertViewInfo
, sizeof(viewInfo
));
3265 if (!viewInfo
.u
.hWVTStateData
)
3267 memset(&wvt
, 0, sizeof(wvt
));
3268 wvt
.cbStruct
= sizeof(wvt
);
3269 wvt
.dwUIChoice
= WTD_UI_NONE
;
3270 if (viewInfo
.dwFlags
&
3271 CRYPTUI_ENABLE_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT
)
3272 wvt
.fdwRevocationChecks
|= WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT
;
3273 if (viewInfo
.dwFlags
& CRYPTUI_ENABLE_REVOCATION_CHECK_END_CERT
)
3274 wvt
.fdwRevocationChecks
|= WTD_REVOCATION_CHECK_END_CERT
;
3275 if (viewInfo
.dwFlags
& CRYPTUI_ENABLE_REVOCATION_CHECK_CHAIN
)
3276 wvt
.fdwRevocationChecks
|= WTD_REVOCATION_CHECK_CHAIN
;
3277 wvt
.dwUnionChoice
= WTD_CHOICE_CERT
;
3278 memset(&cert
, 0, sizeof(cert
));
3279 cert
.cbStruct
= sizeof(cert
);
3280 cert
.psCertContext
= (CERT_CONTEXT
*)viewInfo
.pCertContext
;
3281 cert
.chStores
= viewInfo
.cStores
;
3282 cert
.pahStores
= viewInfo
.rghStores
;
3283 wvt
.u
.pCert
= &cert
;
3284 wvt
.dwStateAction
= WTD_STATEACTION_VERIFY
;
3285 WinVerifyTrust(NULL
, &generic_cert_verify
, &wvt
);
3286 viewInfo
.u
.pCryptProviderData
=
3287 WTHelperProvDataFromStateData(wvt
.hWVTStateData
);
3288 signer
= WTHelperGetProvSignerFromChain(
3289 (CRYPT_PROVIDER_DATA
*)viewInfo
.u
.pCryptProviderData
, 0, FALSE
, 0);
3290 provCert
= WTHelperGetProvCertFromChain(signer
, 0);
3295 viewInfo
.u
.pCryptProviderData
=
3296 WTHelperProvDataFromStateData(viewInfo
.u
.hWVTStateData
);
3297 signer
= WTHelperGetProvSignerFromChain(
3298 (CRYPT_PROVIDER_DATA
*)viewInfo
.u
.pCryptProviderData
,
3299 viewInfo
.idxSigner
, viewInfo
.fCounterSigner
,
3300 viewInfo
.idxCounterSigner
);
3301 provCert
= WTHelperGetProvCertFromChain(signer
, viewInfo
.idxCert
);
3306 ret
= show_cert_dialog(&viewInfo
, provCert
, pfPropertiesChanged
);
3307 if (!viewInfo
.u
.hWVTStateData
)
3309 wvt
.dwStateAction
= WTD_STATEACTION_CLOSE
;
3310 WinVerifyTrust(NULL
, &generic_cert_verify
, &wvt
);
3316 /***********************************************************************
3317 * CryptUIDlgViewContext (CRYPTUI.@)
3319 BOOL WINAPI
CryptUIDlgViewContext(DWORD dwContextType
, LPVOID pvContext
,
3320 HWND hwnd
, LPCWSTR pwszTitle
, DWORD dwFlags
, LPVOID pvReserved
)
3324 TRACE("(%d, %p, %p, %s, %08x, %p)\n", dwContextType
, pvContext
, hwnd
,
3325 debugstr_w(pwszTitle
), dwFlags
, pvReserved
);
3327 switch (dwContextType
)
3329 case CERT_STORE_CERTIFICATE_CONTEXT
:
3331 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo
;
3333 memset(&viewInfo
, 0, sizeof(viewInfo
));
3334 viewInfo
.dwSize
= sizeof(viewInfo
);
3335 viewInfo
.hwndParent
= hwnd
;
3336 viewInfo
.szTitle
= pwszTitle
;
3337 viewInfo
.pCertContext
= pvContext
;
3338 ret
= CryptUIDlgViewCertificateW(&viewInfo
, NULL
);
3342 FIXME("unimplemented for context type %d\n", dwContextType
);
3343 SetLastError(E_INVALIDARG
);
3349 /* Decodes a cert's basic constraints extension (either szOID_BASIC_CONSTRAINTS
3350 * or szOID_BASIC_CONSTRAINTS2, whichever is present) to determine if it
3351 * should be a CA. If neither extension is present, returns
3352 * defaultIfNotSpecified.
3354 static BOOL
is_ca_cert(PCCERT_CONTEXT cert
, BOOL defaultIfNotSpecified
)
3356 BOOL isCA
= defaultIfNotSpecified
;
3357 PCERT_EXTENSION ext
= CertFindExtension(szOID_BASIC_CONSTRAINTS
,
3358 cert
->pCertInfo
->cExtension
, cert
->pCertInfo
->rgExtension
);
3362 CERT_BASIC_CONSTRAINTS_INFO
*info
;
3365 if (CryptDecodeObjectEx(X509_ASN_ENCODING
, szOID_BASIC_CONSTRAINTS
,
3366 ext
->Value
.pbData
, ext
->Value
.cbData
, CRYPT_DECODE_ALLOC_FLAG
,
3367 NULL
, (LPBYTE
)&info
, &size
))
3369 if (info
->SubjectType
.cbData
== 1)
3370 isCA
= info
->SubjectType
.pbData
[0] & CERT_CA_SUBJECT_FLAG
;
3376 ext
= CertFindExtension(szOID_BASIC_CONSTRAINTS2
,
3377 cert
->pCertInfo
->cExtension
, cert
->pCertInfo
->rgExtension
);
3380 CERT_BASIC_CONSTRAINTS2_INFO info
;
3381 DWORD size
= sizeof(CERT_BASIC_CONSTRAINTS2_INFO
);
3383 if (CryptDecodeObjectEx(X509_ASN_ENCODING
,
3384 szOID_BASIC_CONSTRAINTS2
, ext
->Value
.pbData
, ext
->Value
.cbData
,
3385 0, NULL
, &info
, &size
))
3392 static HCERTSTORE
choose_store_for_cert(PCCERT_CONTEXT cert
)
3394 static const WCHAR AddressBook
[] = { 'A','d','d','r','e','s','s',
3395 'B','o','o','k',0 };
3396 static const WCHAR CA
[] = { 'C','A',0 };
3399 if (is_ca_cert(cert
, TRUE
))
3402 storeName
= AddressBook
;
3403 return CertOpenStore(CERT_STORE_PROV_SYSTEM_W
, 0, 0,
3404 CERT_SYSTEM_STORE_CURRENT_USER
, storeName
);
3407 static BOOL
import_cert(PCCERT_CONTEXT cert
, HCERTSTORE hDestCertStore
)
3414 SetLastError(E_INVALIDARG
);
3417 if (hDestCertStore
) store
= hDestCertStore
;
3420 if (!(store
= choose_store_for_cert(cert
)))
3422 WARN("unable to open certificate store\n");
3426 ret
= CertAddCertificateContextToStore(store
, cert
,
3427 CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES
, NULL
);
3428 if (!hDestCertStore
) CertCloseStore(store
, 0);
3432 static BOOL
import_crl(PCCRL_CONTEXT crl
, HCERTSTORE hDestCertStore
)
3439 SetLastError(E_INVALIDARG
);
3442 if (hDestCertStore
) store
= hDestCertStore
;
3445 static const WCHAR ca
[] = { 'C','A',0 };
3447 if (!(store
= CertOpenStore(CERT_STORE_PROV_SYSTEM_W
, 0, 0,
3448 CERT_SYSTEM_STORE_CURRENT_USER
, ca
)))
3450 WARN("unable to open certificate store\n");
3454 ret
= CertAddCRLContextToStore(store
, crl
,
3455 CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES
, NULL
);
3456 if (!hDestCertStore
) CertCloseStore(store
, 0);
3460 static BOOL
import_ctl(PCCTL_CONTEXT ctl
, HCERTSTORE hDestCertStore
)
3467 SetLastError(E_INVALIDARG
);
3470 if (hDestCertStore
) store
= hDestCertStore
;
3473 static const WCHAR trust
[] = { 'T','r','u','s','t',0 };
3475 if (!(store
= CertOpenStore(CERT_STORE_PROV_SYSTEM_W
, 0, 0,
3476 CERT_SYSTEM_STORE_CURRENT_USER
, trust
)))
3478 WARN("unable to open certificate store\n");
3482 ret
= CertAddCTLContextToStore(store
, ctl
,
3483 CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES
, NULL
);
3484 if (!hDestCertStore
) CertCloseStore(store
, 0);
3488 /* Checks type, a type such as CERT_QUERY_CONTENT_CERT returned by
3489 * CryptQueryObject, against the allowed types. Returns TRUE if the
3490 * type is allowed, FALSE otherwise.
3492 static BOOL
check_context_type(DWORD dwFlags
, DWORD type
)
3497 (CRYPTUI_WIZ_IMPORT_ALLOW_CERT
| CRYPTUI_WIZ_IMPORT_ALLOW_CRL
|
3498 CRYPTUI_WIZ_IMPORT_ALLOW_CTL
))
3502 case CERT_QUERY_CONTENT_CERT
:
3503 case CERT_QUERY_CONTENT_SERIALIZED_CERT
:
3504 ret
= dwFlags
& CRYPTUI_WIZ_IMPORT_ALLOW_CERT
;
3506 case CERT_QUERY_CONTENT_CRL
:
3507 case CERT_QUERY_CONTENT_SERIALIZED_CRL
:
3508 ret
= dwFlags
& CRYPTUI_WIZ_IMPORT_ALLOW_CRL
;
3510 case CERT_QUERY_CONTENT_CTL
:
3511 case CERT_QUERY_CONTENT_SERIALIZED_CTL
:
3512 ret
= dwFlags
& CRYPTUI_WIZ_IMPORT_ALLOW_CTL
;
3515 /* The remaining types contain more than one type, so allow
3523 /* No allowed types specified, so any type is allowed */
3527 SetLastError(E_INVALIDARG
);
3532 static void import_warning(DWORD dwFlags
, HWND hwnd
, LPCWSTR szTitle
,
3535 if (!(dwFlags
& CRYPTUI_WIZ_NO_UI
))
3537 WCHAR title
[MAX_STRING_LEN
], error
[MAX_STRING_LEN
];
3544 LoadStringW(hInstance
, IDS_IMPORT_WIZARD
, title
,
3545 sizeof(title
) / sizeof(title
[0]));
3548 LoadStringW(hInstance
, warningID
, error
,
3549 sizeof(error
) / sizeof(error
[0]));
3550 MessageBoxW(hwnd
, error
, pTitle
, MB_ICONERROR
| MB_OK
);
3554 static void import_warn_type_mismatch(DWORD dwFlags
, HWND hwnd
, LPCWSTR szTitle
)
3556 import_warning(dwFlags
, hwnd
, szTitle
, IDS_IMPORT_TYPE_MISMATCH
);
3559 static BOOL
check_store_context_type(DWORD dwFlags
, HCERTSTORE store
)
3564 (CRYPTUI_WIZ_IMPORT_ALLOW_CERT
| CRYPTUI_WIZ_IMPORT_ALLOW_CRL
|
3565 CRYPTUI_WIZ_IMPORT_ALLOW_CTL
))
3567 PCCERT_CONTEXT cert
;
3572 if ((cert
= CertEnumCertificatesInStore(store
, NULL
)))
3574 CertFreeCertificateContext(cert
);
3575 if (!(dwFlags
& CRYPTUI_WIZ_IMPORT_ALLOW_CERT
))
3578 if (ret
&& (crl
= CertEnumCRLsInStore(store
, NULL
)))
3580 CertFreeCRLContext(crl
);
3581 if (!(dwFlags
& CRYPTUI_WIZ_IMPORT_ALLOW_CRL
))
3584 if (ret
&& (ctl
= CertEnumCTLsInStore(store
, NULL
)))
3586 CertFreeCTLContext(ctl
);
3587 if (!(dwFlags
& CRYPTUI_WIZ_IMPORT_ALLOW_CTL
))
3594 SetLastError(E_INVALIDARG
);
3598 static BOOL
import_store(DWORD dwFlags
, HWND hwnd
, LPCWSTR szTitle
,
3599 HCERTSTORE source
, HCERTSTORE dest
)
3603 if ((ret
= check_store_context_type(dwFlags
, source
)))
3605 PCCERT_CONTEXT cert
= NULL
;
3606 PCCRL_CONTEXT crl
= NULL
;
3607 PCCTL_CONTEXT ctl
= NULL
;
3610 cert
= CertEnumCertificatesInStore(source
, cert
);
3612 ret
= import_cert(cert
, dest
);
3613 } while (ret
&& cert
);
3615 crl
= CertEnumCRLsInStore(source
, crl
);
3617 ret
= import_crl(crl
, dest
);
3618 } while (ret
&& crl
);
3620 ctl
= CertEnumCTLsInStore(source
, ctl
);
3622 ret
= import_ctl(ctl
, dest
);
3623 } while (ret
&& ctl
);
3626 import_warn_type_mismatch(dwFlags
, hwnd
, szTitle
);
3630 static HCERTSTORE
open_store_from_file(DWORD dwFlags
, LPCWSTR fileName
)
3632 HCERTSTORE store
= NULL
;
3633 DWORD contentType
, expectedContentTypeFlags
;
3636 (CRYPTUI_WIZ_IMPORT_ALLOW_CERT
| CRYPTUI_WIZ_IMPORT_ALLOW_CRL
|
3637 CRYPTUI_WIZ_IMPORT_ALLOW_CTL
))
3639 expectedContentTypeFlags
=
3640 CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE
|
3641 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED
|
3642 CERT_QUERY_CONTENT_FLAG_PFX
;
3643 if (dwFlags
& CRYPTUI_WIZ_IMPORT_ALLOW_CERT
)
3644 expectedContentTypeFlags
|=
3645 CERT_QUERY_CONTENT_FLAG_CERT
|
3646 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT
;
3647 if (dwFlags
& CRYPTUI_WIZ_IMPORT_ALLOW_CRL
)
3648 expectedContentTypeFlags
|=
3649 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL
|
3650 CERT_QUERY_CONTENT_FLAG_CRL
;
3651 if (dwFlags
& CRYPTUI_WIZ_IMPORT_ALLOW_CTL
)
3652 expectedContentTypeFlags
|=
3653 CERT_QUERY_CONTENT_FLAG_CTL
|
3654 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL
;
3657 expectedContentTypeFlags
=
3658 CERT_QUERY_CONTENT_FLAG_CERT
|
3659 CERT_QUERY_CONTENT_FLAG_CTL
|
3660 CERT_QUERY_CONTENT_FLAG_CRL
|
3661 CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE
|
3662 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT
|
3663 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL
|
3664 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL
|
3665 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED
|
3666 CERT_QUERY_CONTENT_FLAG_PFX
;
3668 CryptQueryObject(CERT_QUERY_OBJECT_FILE
, fileName
,
3669 expectedContentTypeFlags
, CERT_QUERY_FORMAT_FLAG_ALL
, 0, NULL
,
3670 &contentType
, NULL
, &store
, NULL
, NULL
);
3674 static BOOL
import_file(DWORD dwFlags
, HWND hwnd
, LPCWSTR szTitle
,
3675 LPCWSTR fileName
, HCERTSTORE dest
)
3680 if ((source
= open_store_from_file(dwFlags
, fileName
)))
3682 ret
= import_store(dwFlags
, hwnd
, szTitle
, source
, dest
);
3683 CertCloseStore(source
, 0);
3690 static LRESULT CALLBACK
import_welcome_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wp
,
3699 NMHDR
*hdr
= (NMHDR
*)lp
;
3704 PostMessageW(GetParent(hwnd
), PSM_SETWIZBUTTONS
, 0, PSWIZB_NEXT
);
3714 static const WCHAR filter_cert
[] = { '*','.','c','e','r',';','*','.',
3716 static const WCHAR filter_pfx
[] = { '*','.','p','f','x',';','*','.',
3718 static const WCHAR filter_crl
[] = { '*','.','c','r','l',0 };
3719 static const WCHAR filter_ctl
[] = { '*','.','s','t','l',0 };
3720 static const WCHAR filter_serialized_store
[] = { '*','.','s','s','t',0 };
3721 static const WCHAR filter_cms
[] = { '*','.','s','p','c',';','*','.',
3723 static const WCHAR filter_all
[] = { '*','.','*',0 };
3725 struct StringToFilter
3730 } import_filters
[] = {
3731 { IDS_IMPORT_FILTER_CERT
, CRYPTUI_WIZ_IMPORT_ALLOW_CERT
, filter_cert
},
3732 { IDS_IMPORT_FILTER_PFX
, 0, filter_pfx
},
3733 { IDS_IMPORT_FILTER_CRL
, CRYPTUI_WIZ_IMPORT_ALLOW_CRL
, filter_crl
},
3734 { IDS_IMPORT_FILTER_CTL
, CRYPTUI_WIZ_IMPORT_ALLOW_CTL
, filter_ctl
},
3735 { IDS_IMPORT_FILTER_SERIALIZED_STORE
, 0, filter_serialized_store
},
3736 { IDS_IMPORT_FILTER_CMS
, 0, filter_cms
},
3737 { IDS_IMPORT_FILTER_ALL
, 0, filter_all
},
3740 static WCHAR
*make_import_file_filter(DWORD dwFlags
)
3743 int len
, totalLen
= 2;
3744 LPWSTR filter
= NULL
, str
;
3746 for (i
= 0; i
< sizeof(import_filters
) / sizeof(import_filters
[0]); i
++)
3748 if (!import_filters
[i
].allowFlags
|| !dwFlags
||
3749 (dwFlags
& import_filters
[i
].allowFlags
))
3751 len
= LoadStringW(hInstance
, import_filters
[i
].id
, (LPWSTR
)&str
, 0);
3752 totalLen
+= len
+ strlenW(import_filters
[i
].filter
) + 2;
3755 filter
= HeapAlloc(GetProcessHeap(), 0, totalLen
* sizeof(WCHAR
));
3761 for (i
= 0; i
< sizeof(import_filters
) / sizeof(import_filters
[0]); i
++)
3763 if (!import_filters
[i
].allowFlags
|| !dwFlags
||
3764 (dwFlags
& import_filters
[i
].allowFlags
))
3766 len
= LoadStringW(hInstance
, import_filters
[i
].id
,
3768 memcpy(ptr
, str
, len
* sizeof(WCHAR
));
3771 strcpyW(ptr
, import_filters
[i
].filter
);
3772 ptr
+= strlenW(import_filters
[i
].filter
) + 1;
3780 struct ImportWizData
3783 LPCWSTR pwszWizardTitle
;
3784 CRYPTUI_WIZ_IMPORT_SRC_INFO importSrc
;
3786 HCERTSTORE hDestCertStore
;
3791 static BOOL
import_validate_filename(HWND hwnd
, struct ImportWizData
*data
,
3797 file
= CreateFileW(fileName
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
3798 OPEN_EXISTING
, 0, NULL
);
3799 if (file
!= INVALID_HANDLE_VALUE
)
3801 HCERTSTORE source
= open_store_from_file(data
->dwFlags
, fileName
);
3805 warningID
= IDS_IMPORT_BAD_FORMAT
;
3806 else if (!check_store_context_type(data
->dwFlags
, source
))
3807 warningID
= IDS_IMPORT_TYPE_MISMATCH
;
3810 data
->importSrc
.dwSubjectChoice
=
3811 CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE
;
3812 data
->importSrc
.u
.hCertStore
= source
;
3813 data
->freeSource
= TRUE
;
3818 import_warning(data
->dwFlags
, hwnd
, data
->pwszWizardTitle
,
3825 WCHAR title
[MAX_STRING_LEN
], error
[MAX_STRING_LEN
];
3827 LPWSTR msgBuf
, fullError
;
3829 if (data
->pwszWizardTitle
)
3830 pTitle
= data
->pwszWizardTitle
;
3833 LoadStringW(hInstance
, IDS_IMPORT_WIZARD
, title
,
3834 sizeof(title
) / sizeof(title
[0]));
3837 LoadStringW(hInstance
, IDS_IMPORT_OPEN_FAILED
, error
,
3838 sizeof(error
) / sizeof(error
[0]));
3840 FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
, NULL
,
3841 GetLastError(), 0, (LPWSTR
) &msgBuf
, 0, NULL
);
3842 fullError
= HeapAlloc(GetProcessHeap(), 0,
3843 (strlenW(error
) + strlenW(fileName
) + strlenW(msgBuf
) + 3)
3847 LPWSTR ptr
= fullError
;
3849 strcpyW(ptr
, error
);
3850 ptr
+= strlenW(error
);
3851 strcpyW(ptr
, fileName
);
3852 ptr
+= strlenW(fileName
);
3855 strcpyW(ptr
, msgBuf
);
3856 MessageBoxW(hwnd
, fullError
, pTitle
, MB_ICONERROR
| MB_OK
);
3857 HeapFree(GetProcessHeap(), 0, fullError
);
3864 static LRESULT CALLBACK
import_file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wp
,
3868 struct ImportWizData
*data
;
3874 PROPSHEETPAGEW
*page
= (PROPSHEETPAGEW
*)lp
;
3876 data
= (struct ImportWizData
*)page
->lParam
;
3877 SetWindowLongPtrW(hwnd
, DWLP_USER
, (LPARAM
)data
);
3882 NMHDR
*hdr
= (NMHDR
*)lp
;
3887 PostMessageW(GetParent(hwnd
), PSM_SETWIZBUTTONS
, 0,
3888 PSWIZB_BACK
| PSWIZB_NEXT
);
3893 HWND fileNameEdit
= GetDlgItem(hwnd
, IDC_IMPORT_FILENAME
);
3894 DWORD len
= SendMessageW(fileNameEdit
, WM_GETTEXTLENGTH
, 0, 0);
3896 data
= (struct ImportWizData
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
3899 import_warning(data
->dwFlags
, hwnd
, data
->pwszWizardTitle
,
3900 IDS_IMPORT_EMPTY_FILE
);
3901 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, 1);
3906 LPWSTR fileName
= HeapAlloc(GetProcessHeap(), 0,
3907 (len
+ 1) * sizeof(WCHAR
));
3911 SendMessageW(fileNameEdit
, WM_GETTEXT
, len
+ 1,
3913 if (!import_validate_filename(hwnd
, data
, fileName
))
3915 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, 1);
3918 HeapFree(GetProcessHeap(), 0, fileName
);
3929 case IDC_IMPORT_BROWSE_FILE
:
3932 WCHAR fileBuf
[MAX_PATH
];
3934 data
= (struct ImportWizData
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
3935 memset(&ofn
, 0, sizeof(ofn
));
3936 ofn
.lStructSize
= sizeof(ofn
);
3937 ofn
.hwndOwner
= hwnd
;
3938 ofn
.lpstrFilter
= make_import_file_filter(data
->dwFlags
);
3939 ofn
.lpstrFile
= fileBuf
;
3940 ofn
.nMaxFile
= sizeof(fileBuf
) / sizeof(fileBuf
[0]);
3942 if (GetOpenFileNameW(&ofn
))
3943 SendMessageW(GetDlgItem(hwnd
, IDC_IMPORT_FILENAME
), WM_SETTEXT
,
3944 0, (LPARAM
)ofn
.lpstrFile
);
3945 HeapFree(GetProcessHeap(), 0, (LPWSTR
)ofn
.lpstrFilter
);
3954 static LRESULT CALLBACK
import_store_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wp
,
3958 struct ImportWizData
*data
;
3964 PROPSHEETPAGEW
*page
= (PROPSHEETPAGEW
*)lp
;
3966 data
= (struct ImportWizData
*)page
->lParam
;
3967 SetWindowLongPtrW(hwnd
, DWLP_USER
, (LPARAM
)data
);
3968 SendMessageW(GetDlgItem(hwnd
, IDC_IMPORT_AUTO_STORE
), BM_CLICK
, 0, 0);
3969 if (data
->dwFlags
& CRYPTUI_WIZ_IMPORT_NO_CHANGE_DEST_STORE
)
3970 EnableWindow(GetDlgItem(hwnd
, IDC_IMPORT_SPECIFY_STORE
), FALSE
);
3971 EnableWindow(GetDlgItem(hwnd
, IDC_IMPORT_STORE
), FALSE
);
3972 EnableWindow(GetDlgItem(hwnd
, IDC_IMPORT_BROWSE_STORE
), FALSE
);
3977 NMHDR
*hdr
= (NMHDR
*)lp
;
3982 PostMessageW(GetParent(hwnd
), PSM_SETWIZBUTTONS
, 0,
3983 PSWIZB_BACK
| PSWIZB_NEXT
);
3988 data
= (struct ImportWizData
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
3989 if (IsDlgButtonChecked(hwnd
, IDC_IMPORT_SPECIFY_STORE
) &&
3990 !data
->hDestCertStore
)
3992 import_warning(data
->dwFlags
, hwnd
, data
->pwszWizardTitle
,
3993 IDS_IMPORT_SELECT_STORE
);
3994 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, 1);
4005 case IDC_IMPORT_AUTO_STORE
:
4006 data
= (struct ImportWizData
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
4007 data
->autoDest
= TRUE
;
4008 EnableWindow(GetDlgItem(hwnd
, IDC_IMPORT_STORE
), FALSE
);
4009 EnableWindow(GetDlgItem(hwnd
, IDC_IMPORT_BROWSE_STORE
), FALSE
);
4011 case IDC_IMPORT_SPECIFY_STORE
:
4012 data
= (struct ImportWizData
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
4013 data
->autoDest
= FALSE
;
4014 EnableWindow(GetDlgItem(hwnd
, IDC_IMPORT_STORE
), TRUE
);
4015 EnableWindow(GetDlgItem(hwnd
, IDC_IMPORT_BROWSE_STORE
), TRUE
);
4017 case IDC_IMPORT_BROWSE_STORE
:
4019 CRYPTUI_ENUM_SYSTEM_STORE_ARGS enumArgs
= {
4020 CERT_SYSTEM_STORE_CURRENT_USER
, NULL
};
4021 CRYPTUI_ENUM_DATA enumData
= { 0, NULL
, 1, &enumArgs
};
4022 CRYPTUI_SELECTSTORE_INFO_W selectInfo
;
4025 data
= (struct ImportWizData
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
4026 selectInfo
.dwSize
= sizeof(selectInfo
);
4027 selectInfo
.parent
= hwnd
;
4028 selectInfo
.dwFlags
= CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE
;
4029 selectInfo
.pwszTitle
= selectInfo
.pwszTitle
= NULL
;
4030 selectInfo
.pEnumData
= &enumData
;
4031 selectInfo
.pfnSelectedStoreCallback
= NULL
;
4032 if ((store
= CryptUIDlgSelectStoreW(&selectInfo
)))
4034 WCHAR storeTitle
[MAX_STRING_LEN
];
4036 LoadStringW(hInstance
, IDS_IMPORT_DEST_DETERMINED
,
4037 storeTitle
, sizeof(storeTitle
) / sizeof(storeTitle
[0]));
4038 SendMessageW(GetDlgItem(hwnd
, IDC_IMPORT_STORE
), WM_SETTEXT
,
4039 0, (LPARAM
)storeTitle
);
4040 data
->hDestCertStore
= store
;
4041 data
->freeDest
= TRUE
;
4051 static LRESULT CALLBACK
import_finish_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wp
,
4060 NMHDR
*hdr
= (NMHDR
*)lp
;
4065 PostMessageW(GetParent(hwnd
), PSM_SETWIZBUTTONS
, 0,
4066 PSWIZB_BACK
| PSWIZB_FINISH
);
4076 static BOOL
show_import_ui(DWORD dwFlags
, HWND hwndParent
,
4077 LPCWSTR pwszWizardTitle
, PCCRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc
,
4078 HCERTSTORE hDestCertStore
)
4080 PROPSHEETHEADERW hdr
;
4081 PROPSHEETPAGEW pages
[4];
4082 struct ImportWizData data
;
4087 data
.dwFlags
= dwFlags
;
4088 data
.pwszWizardTitle
= pwszWizardTitle
;
4090 memcpy(&data
.importSrc
, pImportSrc
, sizeof(data
.importSrc
));
4092 memset(&data
.importSrc
, 0, sizeof(data
.importSrc
));
4093 data
.freeSource
= FALSE
;
4094 data
.hDestCertStore
= hDestCertStore
;
4095 data
.freeDest
= FALSE
;
4096 data
.autoDest
= TRUE
;
4098 memset(&pages
, 0, sizeof(pages
));
4100 pages
[nPages
].dwSize
= sizeof(pages
[0]);
4101 pages
[nPages
].hInstance
= hInstance
;
4102 pages
[nPages
].u
.pszTemplate
= MAKEINTRESOURCEW(IDD_IMPORT_WELCOME
);
4103 pages
[nPages
].pfnDlgProc
= import_welcome_dlg_proc
;
4104 pages
[nPages
].dwFlags
= PSP_HIDEHEADER
;
4108 pImportSrc
->dwSubjectChoice
== CRYPTUI_WIZ_IMPORT_SUBJECT_FILE
)
4110 pages
[nPages
].dwSize
= sizeof(pages
[0]);
4111 pages
[nPages
].hInstance
= hInstance
;
4112 pages
[nPages
].u
.pszTemplate
= MAKEINTRESOURCEW(IDD_IMPORT_FILE
);
4113 pages
[nPages
].pfnDlgProc
= import_file_dlg_proc
;
4114 pages
[nPages
].dwFlags
= PSP_USEHEADERTITLE
| PSP_USEHEADERSUBTITLE
;
4115 pages
[nPages
].pszHeaderTitle
= MAKEINTRESOURCEW(IDS_IMPORT_FILE_TITLE
);
4116 pages
[nPages
].pszHeaderSubTitle
=
4117 MAKEINTRESOURCEW(IDS_IMPORT_FILE_SUBTITLE
);
4118 pages
[nPages
].lParam
= (LPARAM
)&data
;
4122 pages
[nPages
].dwSize
= sizeof(pages
[0]);
4123 pages
[nPages
].hInstance
= hInstance
;
4124 pages
[nPages
].u
.pszTemplate
= MAKEINTRESOURCEW(IDD_IMPORT_STORE
);
4125 pages
[nPages
].pfnDlgProc
= import_store_dlg_proc
;
4126 pages
[nPages
].dwFlags
= PSP_USEHEADERTITLE
| PSP_USEHEADERSUBTITLE
;
4127 pages
[nPages
].pszHeaderTitle
= MAKEINTRESOURCEW(IDS_IMPORT_STORE_TITLE
);
4128 pages
[nPages
].pszHeaderSubTitle
=
4129 MAKEINTRESOURCEW(IDS_IMPORT_STORE_SUBTITLE
);
4130 pages
[nPages
].lParam
= (LPARAM
)&data
;
4133 pages
[nPages
].dwSize
= sizeof(pages
[0]);
4134 pages
[nPages
].hInstance
= hInstance
;
4135 pages
[nPages
].u
.pszTemplate
= MAKEINTRESOURCEW(IDD_IMPORT_FINISH
);
4136 pages
[nPages
].pfnDlgProc
= import_finish_dlg_proc
;
4137 pages
[nPages
].dwFlags
= PSP_HIDEHEADER
;
4140 memset(&hdr
, 0, sizeof(hdr
));
4141 hdr
.dwSize
= sizeof(hdr
);
4142 hdr
.hwndParent
= hwndParent
;
4143 hdr
.dwFlags
= PSH_PROPSHEETPAGE
| PSH_WIZARD97_OLD
| PSH_HEADER
;
4144 hdr
.hInstance
= hInstance
;
4145 if (pwszWizardTitle
)
4146 hdr
.pszCaption
= pwszWizardTitle
;
4148 hdr
.pszCaption
= MAKEINTRESOURCEW(IDS_IMPORT_WIZARD
);
4149 hdr
.u3
.ppsp
= pages
;
4150 hdr
.nPages
= nPages
;
4151 PropertySheetW(&hdr
);
4152 if (data
.freeSource
&&
4153 data
.importSrc
.dwSubjectChoice
== CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE
)
4154 CertCloseStore(data
.importSrc
.u
.hCertStore
, 0);
4158 BOOL WINAPI
CryptUIWizImport(DWORD dwFlags
, HWND hwndParent
, LPCWSTR pwszWizardTitle
,
4159 PCCRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc
, HCERTSTORE hDestCertStore
)
4163 TRACE("(0x%08x, %p, %s, %p, %p)\n", dwFlags
, hwndParent
, debugstr_w(pwszWizardTitle
),
4164 pImportSrc
, hDestCertStore
);
4167 pImportSrc
->dwSize
!= sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO
))
4169 SetLastError(E_INVALIDARG
);
4173 if (!(dwFlags
& CRYPTUI_WIZ_NO_UI
))
4174 ret
= show_import_ui(dwFlags
, hwndParent
, pwszWizardTitle
, pImportSrc
,
4176 else if (pImportSrc
)
4178 switch (pImportSrc
->dwSubjectChoice
)
4180 case CRYPTUI_WIZ_IMPORT_SUBJECT_FILE
:
4181 ret
= import_file(dwFlags
, hwndParent
, pwszWizardTitle
,
4182 pImportSrc
->u
.pwszFileName
, hDestCertStore
);
4184 case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_CONTEXT
:
4185 if ((ret
= check_context_type(dwFlags
, CERT_QUERY_CONTENT_CERT
)))
4186 ret
= import_cert(pImportSrc
->u
.pCertContext
, hDestCertStore
);
4188 import_warn_type_mismatch(dwFlags
, hwndParent
, pwszWizardTitle
);
4190 case CRYPTUI_WIZ_IMPORT_SUBJECT_CRL_CONTEXT
:
4191 if ((ret
= check_context_type(dwFlags
, CERT_QUERY_CONTENT_CRL
)))
4192 ret
= import_crl(pImportSrc
->u
.pCRLContext
, hDestCertStore
);
4194 import_warn_type_mismatch(dwFlags
, hwndParent
, pwszWizardTitle
);
4196 case CRYPTUI_WIZ_IMPORT_SUBJECT_CTL_CONTEXT
:
4197 if ((ret
= check_context_type(dwFlags
, CERT_QUERY_CONTENT_CTL
)))
4198 ret
= import_ctl(pImportSrc
->u
.pCTLContext
, hDestCertStore
);
4200 import_warn_type_mismatch(dwFlags
, hwndParent
, pwszWizardTitle
);
4202 case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE
:
4203 ret
= import_store(dwFlags
, hwndParent
, pwszWizardTitle
,
4204 pImportSrc
->u
.hCertStore
, hDestCertStore
);
4207 WARN("unknown source type: %u\n", pImportSrc
->dwSubjectChoice
);
4208 SetLastError(E_INVALIDARG
);
4214 /* Can't have no UI without specifying source */
4215 SetLastError(E_INVALIDARG
);