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
36 #include "cryptuiapi.h"
37 #include "cryptuires.h"
40 #include "wine/debug.h"
41 #include "wine/unicode.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(cryptui
);
45 static HINSTANCE hInstance
;
47 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
49 TRACE("(0x%p, %d, %p)\n", hinstDLL
, fdwReason
, lpvReserved
);
53 case DLL_WINE_PREATTACH
:
54 return FALSE
; /* prefer native version */
55 case DLL_PROCESS_ATTACH
:
57 DisableThreadLibraryCalls(hinstDLL
);
59 case DLL_PROCESS_DETACH
:
67 /***********************************************************************
68 * CryptUIDlgCertMgr (CRYPTUI.@)
70 BOOL WINAPI
CryptUIDlgCertMgr(PCCRYPTUI_CERT_MGR_STRUCT pCryptUICertMgr
)
72 FIXME("(%p): stub\n", pCryptUICertMgr
);
76 /* FIXME: real names are unknown, functions are undocumented */
77 typedef struct _CRYPTUI_ENUM_SYSTEM_STORE_ARGS
80 void *pvSystemStoreLocationPara
;
81 } CRYPTUI_ENUM_SYSTEM_STORE_ARGS
, *PCRYPTUI_ENUM_SYSTEM_STORE_ARGS
;
83 typedef struct _CRYPTUI_ENUM_DATA
88 PCRYPTUI_ENUM_SYSTEM_STORE_ARGS rgEnumArgs
;
89 } CRYPTUI_ENUM_DATA
, *PCRYPTUI_ENUM_DATA
;
91 typedef BOOL (WINAPI
*PFN_SELECTED_STORE_CB
)(HCERTSTORE store
, HWND hwnd
,
94 /* Values for dwFlags */
95 #define CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE 0x00000001
97 typedef struct _CRYPTUI_SELECTSTORE_INFO_A
104 CRYPTUI_ENUM_DATA
*pEnumData
;
105 PFN_SELECTED_STORE_CB pfnSelectedStoreCallback
;
107 } CRYPTUI_SELECTSTORE_INFO_A
, *PCRYPTUI_SELECTSTORE_INFO_A
;
109 typedef struct _CRYPTUI_SELECTSTORE_INFO_W
116 CRYPTUI_ENUM_DATA
*pEnumData
;
117 PFN_SELECTED_STORE_CB pfnSelectedStoreCallback
;
119 } CRYPTUI_SELECTSTORE_INFO_W
, *PCRYPTUI_SELECTSTORE_INFO_W
;
133 static BOOL WINAPI
enum_store_callback(const void *pvSystemStore
,
134 DWORD dwFlags
, PCERT_SYSTEM_STORE_INFO pStoreInfo
, void *pvReserved
,
137 HWND tree
= GetDlgItem(pvArg
, IDC_STORE_LIST
);
138 TVINSERTSTRUCTW tvis
;
139 LPCWSTR localizedName
;
143 tvis
.hInsertAfter
= TVI_LAST
;
144 tvis
.u
.item
.mask
= TVIF_TEXT
;
145 if ((localizedName
= CryptFindLocalizedName(pvSystemStore
)))
147 struct StoreInfo
*storeInfo
= HeapAlloc(GetProcessHeap(), 0,
148 sizeof(struct StoreInfo
));
152 storeInfo
->type
= SystemStore
;
153 storeInfo
->u
.name
= HeapAlloc(GetProcessHeap(), 0,
154 (strlenW(pvSystemStore
) + 1) * sizeof(WCHAR
));
155 if (storeInfo
->u
.name
)
157 tvis
.u
.item
.mask
|= TVIF_PARAM
;
158 tvis
.u
.item
.lParam
= (LPARAM
)storeInfo
;
159 strcpyW(storeInfo
->u
.name
, pvSystemStore
);
163 HeapFree(GetProcessHeap(), 0, storeInfo
);
169 tvis
.u
.item
.pszText
= (LPWSTR
)localizedName
;
172 tvis
.u
.item
.pszText
= (LPWSTR
)pvSystemStore
;
173 /* FIXME: need a folder icon for the store too */
175 SendMessageW(tree
, TVM_INSERTITEMW
, 0, (LPARAM
)&tvis
);
179 static void enumerate_stores(HWND hwnd
, CRYPTUI_ENUM_DATA
*pEnumData
)
182 HWND tree
= GetDlgItem(hwnd
, IDC_STORE_LIST
);
184 for (i
= 0; i
< pEnumData
->cEnumArgs
; i
++)
185 CertEnumSystemStore(pEnumData
->rgEnumArgs
[i
].dwFlags
,
186 pEnumData
->rgEnumArgs
[i
].pvSystemStoreLocationPara
,
187 hwnd
, enum_store_callback
);
188 for (i
= 0; i
< pEnumData
->cStores
; i
++)
192 if (CertGetStoreProperty(pEnumData
->rghStore
[i
],
193 CERT_STORE_LOCALIZED_NAME_PROP_ID
, NULL
, &size
))
195 LPWSTR name
= HeapAlloc(GetProcessHeap(), 0, size
);
199 if (CertGetStoreProperty(pEnumData
->rghStore
[i
],
200 CERT_STORE_LOCALIZED_NAME_PROP_ID
, name
, &size
))
202 struct StoreInfo
*storeInfo
= HeapAlloc(GetProcessHeap(),
203 0, sizeof(struct StoreInfo
));
207 TVINSERTSTRUCTW tvis
;
209 storeInfo
->type
= StoreHandle
;
210 storeInfo
->u
.store
= pEnumData
->rghStore
[i
];
212 tvis
.hInsertAfter
= TVI_LAST
;
213 tvis
.u
.item
.mask
= TVIF_TEXT
| TVIF_PARAM
;
214 tvis
.u
.item
.pszText
= name
;
215 tvis
.u
.item
.lParam
= (LPARAM
)storeInfo
;
216 SendMessageW(tree
, TVM_INSERTITEMW
, 0, (LPARAM
)&tvis
);
219 HeapFree(GetProcessHeap(), 0, name
);
225 static void free_store_info(HWND tree
)
227 HTREEITEM next
= (HTREEITEM
)SendMessageW(tree
, TVM_GETNEXTITEM
, TVGN_CHILD
,
234 memset(&item
, 0, sizeof(item
));
235 item
.mask
= TVIF_HANDLE
| TVIF_PARAM
;
237 SendMessageW(tree
, TVM_GETITEMW
, 0, (LPARAM
)&item
);
240 struct StoreInfo
*storeInfo
= (struct StoreInfo
*)item
.lParam
;
242 if (storeInfo
->type
== SystemStore
)
243 HeapFree(GetProcessHeap(), 0, storeInfo
->u
.name
);
244 HeapFree(GetProcessHeap(), 0, storeInfo
);
246 next
= (HTREEITEM
)SendMessageW(tree
, TVM_GETNEXTITEM
, TVGN_NEXT
,
251 #define MAX_STRING_LEN 512
253 static HCERTSTORE
selected_item_to_store(HWND tree
, HTREEITEM hItem
)
255 WCHAR buf
[MAX_STRING_LEN
];
259 memset(&item
, 0, sizeof(item
));
260 item
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_TEXT
;
262 item
.cchTextMax
= sizeof(buf
) / sizeof(buf
[0]);
264 SendMessageW(tree
, TVM_GETITEMW
, 0, (LPARAM
)&item
);
267 struct StoreInfo
*storeInfo
= (struct StoreInfo
*)item
.lParam
;
269 if (storeInfo
->type
== StoreHandle
)
270 store
= storeInfo
->u
.store
;
272 store
= CertOpenSystemStoreW(0, storeInfo
->u
.name
);
276 /* It's implicitly a system store */
277 store
= CertOpenSystemStoreW(0, buf
);
282 struct SelectStoreInfo
284 PCRYPTUI_SELECTSTORE_INFO_W info
;
288 static LRESULT CALLBACK
select_store_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wp
,
291 struct SelectStoreInfo
*selectInfo
;
298 selectInfo
= (struct SelectStoreInfo
*)lp
;
299 SetWindowLongPtrW(hwnd
, DWLP_USER
, lp
);
300 if (selectInfo
->info
->pwszTitle
)
301 SendMessageW(hwnd
, WM_SETTEXT
, 0,
302 (LPARAM
)selectInfo
->info
->pwszTitle
);
303 if (selectInfo
->info
->pwszText
)
304 SendMessageW(GetDlgItem(hwnd
, IDC_STORE_TEXT
), WM_SETTEXT
, 0,
305 (LPARAM
)selectInfo
->info
->pwszText
);
306 if (!(selectInfo
->info
->dwFlags
& CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE
))
307 ShowWindow(GetDlgItem(hwnd
, IDC_SHOW_PHYSICAL_STORES
), FALSE
);
308 enumerate_stores(hwnd
, selectInfo
->info
->pEnumData
);
316 HWND tree
= GetDlgItem(hwnd
, IDC_STORE_LIST
);
317 HTREEITEM selection
= (HTREEITEM
)SendMessageW(tree
,
318 TVM_GETNEXTITEM
, TVGN_CARET
, (LPARAM
)NULL
);
320 selectInfo
= (struct SelectStoreInfo
*)GetWindowLongPtrW(hwnd
,
324 WCHAR title
[MAX_STRING_LEN
], error
[MAX_STRING_LEN
], *pTitle
;
326 if (selectInfo
->info
->pwszTitle
)
327 pTitle
= selectInfo
->info
->pwszTitle
;
330 LoadStringW(hInstance
, IDS_SELECT_STORE_TITLE
, title
,
331 sizeof(title
) / sizeof(title
[0]));
334 LoadStringW(hInstance
, IDS_SELECT_STORE
, error
,
335 sizeof(error
) / sizeof(error
[0]));
336 MessageBoxW(hwnd
, error
, pTitle
, MB_ICONEXCLAMATION
| MB_OK
);
340 HCERTSTORE store
= selected_item_to_store(tree
, selection
);
342 if (!selectInfo
->info
->pfnSelectedStoreCallback
||
343 selectInfo
->info
->pfnSelectedStoreCallback(store
, hwnd
,
344 selectInfo
->info
->pvArg
))
346 selectInfo
->store
= store
;
347 free_store_info(tree
);
348 EndDialog(hwnd
, IDOK
);
351 CertCloseStore(store
, 0);
357 free_store_info(GetDlgItem(hwnd
, IDC_STORE_LIST
));
358 EndDialog(hwnd
, IDCANCEL
);
367 /***********************************************************************
368 * CryptUIDlgSelectStoreW (CRYPTUI.@)
370 HCERTSTORE WINAPI
CryptUIDlgSelectStoreW(PCRYPTUI_SELECTSTORE_INFO_W info
)
372 struct SelectStoreInfo selectInfo
= { info
, NULL
};
374 TRACE("(%p)\n", info
);
376 if (info
->dwSize
!= sizeof(CRYPTUI_SELECTSTORE_INFO_W
))
378 WARN("unexpected size %d\n", info
->dwSize
);
379 SetLastError(E_INVALIDARG
);
382 DialogBoxParamW(hInstance
, MAKEINTRESOURCEW(IDD_SELECT_STORE
), info
->parent
,
383 select_store_dlg_proc
, (LPARAM
)&selectInfo
);
384 return selectInfo
.store
;
387 /***********************************************************************
388 * CryptUIDlgSelectStoreA (CRYPTUI.@)
390 HCERTSTORE WINAPI
CryptUIDlgSelectStoreA(PCRYPTUI_SELECTSTORE_INFO_A info
)
392 CRYPTUI_SELECTSTORE_INFO_W infoW
;
396 TRACE("(%p)\n", info
);
398 if (info
->dwSize
!= sizeof(CRYPTUI_SELECTSTORE_INFO_A
))
400 WARN("unexpected size %d\n", info
->dwSize
);
401 SetLastError(E_INVALIDARG
);
404 memcpy(&infoW
, &info
, sizeof(info
));
407 len
= MultiByteToWideChar(CP_ACP
, 0, info
->pszTitle
, -1, NULL
, 0);
408 infoW
.pwszTitle
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
409 MultiByteToWideChar(CP_ACP
, 0, info
->pszTitle
, -1, infoW
.pwszTitle
,
414 len
= MultiByteToWideChar(CP_ACP
, 0, info
->pszText
, -1, NULL
, 0);
415 infoW
.pwszText
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
416 MultiByteToWideChar(CP_ACP
, 0, info
->pszText
, -1, infoW
.pwszText
, len
);
418 ret
= CryptUIDlgSelectStoreW(&infoW
);
419 HeapFree(GetProcessHeap(), 0, infoW
.pwszText
);
420 HeapFree(GetProcessHeap(), 0, infoW
.pwszTitle
);
424 /***********************************************************************
425 * CryptUIDlgViewCertificateA (CRYPTUI.@)
427 BOOL WINAPI
CryptUIDlgViewCertificateA(
428 PCCRYPTUI_VIEWCERTIFICATE_STRUCTA pCertViewInfo
, BOOL
*pfPropertiesChanged
)
430 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo
;
434 TRACE("(%p, %p)\n", pCertViewInfo
, pfPropertiesChanged
);
436 memcpy(&viewInfo
, pCertViewInfo
, sizeof(viewInfo
));
437 if (pCertViewInfo
->szTitle
)
439 int len
= MultiByteToWideChar(CP_ACP
, 0, pCertViewInfo
->szTitle
, -1,
442 title
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
445 MultiByteToWideChar(CP_ACP
, 0, pCertViewInfo
->szTitle
, -1, title
,
447 viewInfo
.szTitle
= title
;
455 if (pCertViewInfo
->cPropSheetPages
)
457 FIXME("ignoring additional prop sheet pages\n");
458 viewInfo
.cPropSheetPages
= 0;
460 ret
= CryptUIDlgViewCertificateW(&viewInfo
, pfPropertiesChanged
);
461 HeapFree(GetProcessHeap(), 0, title
);
466 struct ReadStringStruct
473 static DWORD CALLBACK
read_text_callback(DWORD_PTR dwCookie
, LPBYTE buf
,
476 struct ReadStringStruct
*string
= (struct ReadStringStruct
*)dwCookie
;
477 LONG cch
= min(cb
/ sizeof(WCHAR
), string
->len
- string
->pos
);
479 TRACE("(%p, %p, %d, %p)\n", string
, buf
, cb
, pcb
);
481 memmove(buf
, string
->buf
+ string
->pos
, cch
* sizeof(WCHAR
));
483 *pcb
= cch
* sizeof(WCHAR
);
487 static void add_unformatted_text_to_control(HWND hwnd
, LPCWSTR text
, LONG len
)
489 struct ReadStringStruct string
;
490 EDITSTREAM editstream
;
492 TRACE("(%p, %s)\n", hwnd
, debugstr_wn(text
, len
));
497 editstream
.dwCookie
= (DWORD_PTR
)&string
;
498 editstream
.dwError
= 0;
499 editstream
.pfnCallback
= read_text_callback
;
500 SendMessageW(hwnd
, EM_STREAMIN
, SF_TEXT
| SFF_SELECTION
| SF_UNICODE
,
501 (LPARAM
)&editstream
);
504 static void add_string_resource_to_control(HWND hwnd
, int id
)
509 len
= LoadStringW(hInstance
, id
, (LPWSTR
)&str
, 0);
510 add_unformatted_text_to_control(hwnd
, str
, len
);
513 static void add_text_with_paraformat_to_control(HWND hwnd
, LPCWSTR text
,
514 LONG len
, const PARAFORMAT2
*fmt
)
516 add_unformatted_text_to_control(hwnd
, text
, len
);
517 SendMessageW(hwnd
, EM_SETPARAFORMAT
, 0, (LPARAM
)fmt
);
520 static void add_string_resource_with_paraformat_to_control(HWND hwnd
, int id
,
521 const PARAFORMAT2
*fmt
)
526 len
= LoadStringW(hInstance
, id
, (LPWSTR
)&str
, 0);
527 add_text_with_paraformat_to_control(hwnd
, str
, len
, fmt
);
530 static LPWSTR
get_cert_name_string(PCCERT_CONTEXT pCertContext
, DWORD dwType
,
536 len
= CertGetNameStringW(pCertContext
, dwType
, dwFlags
, NULL
, NULL
, 0);
539 buf
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
541 CertGetNameStringW(pCertContext
, dwType
, dwFlags
, NULL
, buf
, len
);
546 static void add_cert_string_to_control(HWND hwnd
, PCCERT_CONTEXT pCertContext
,
547 DWORD dwType
, DWORD dwFlags
)
549 LPWSTR name
= get_cert_name_string(pCertContext
, dwType
, dwFlags
);
553 /* Don't include NULL-terminator in output */
554 DWORD len
= lstrlenW(name
);
556 add_unformatted_text_to_control(hwnd
, name
, len
);
557 HeapFree(GetProcessHeap(), 0, name
);
561 static void add_icon_to_control(HWND hwnd
, int id
)
564 LPRICHEDITOLE richEditOle
= NULL
;
565 LPOLEOBJECT object
= NULL
;
567 LPOLECACHE oleCache
= NULL
;
570 LPDATAOBJECT dataObject
= NULL
;
571 HBITMAP bitmap
= NULL
;
576 TRACE("(%p, %d)\n", hwnd
, id
);
578 SendMessageW(hwnd
, EM_GETOLEINTERFACE
, 0, (LPARAM
)&richEditOle
);
581 hr
= OleCreateDefaultHandler(&CLSID_NULL
, NULL
, &IID_IOleObject
,
585 hr
= IOleObject_GetUserClassID(object
, &clsid
);
588 hr
= IOleObject_QueryInterface(object
, &IID_IOleCache
, (void**)&oleCache
);
591 formatEtc
.cfFormat
= CF_BITMAP
;
592 formatEtc
.ptd
= NULL
;
593 formatEtc
.dwAspect
= DVASPECT_CONTENT
;
594 formatEtc
.lindex
= -1;
595 formatEtc
.tymed
= TYMED_GDI
;
596 hr
= IOleCache_Cache(oleCache
, &formatEtc
, 0, &conn
);
599 hr
= IOleObject_QueryInterface(object
, &IID_IDataObject
,
600 (void**)&dataObject
);
603 bitmap
= LoadImageW(hInstance
, MAKEINTRESOURCEW(id
), IMAGE_BITMAP
, 0, 0,
604 LR_DEFAULTSIZE
| LR_LOADTRANSPARENT
);
607 rect
.left
= rect
.top
= 0;
608 rect
.right
= GetSystemMetrics(SM_CXICON
);
609 rect
.bottom
= GetSystemMetrics(SM_CYICON
);
610 stgm
.tymed
= TYMED_GDI
;
611 stgm
.u
.hBitmap
= bitmap
;
612 stgm
.pUnkForRelease
= NULL
;
613 hr
= IDataObject_SetData(dataObject
, &formatEtc
, &stgm
, TRUE
);
617 reObject
.cbStruct
= sizeof(reObject
);
618 reObject
.cp
= REO_CP_SELECTION
;
619 reObject
.clsid
= clsid
;
620 reObject
.poleobj
= object
;
621 reObject
.pstg
= NULL
;
622 reObject
.polesite
= NULL
;
623 reObject
.sizel
.cx
= reObject
.sizel
.cy
= 0;
624 reObject
.dvaspect
= DVASPECT_CONTENT
;
625 reObject
.dwFlags
= 0;
628 IRichEditOle_InsertObject(richEditOle
, &reObject
);
632 IDataObject_Release(dataObject
);
634 IOleCache_Release(oleCache
);
636 IOleObject_Release(object
);
638 IRichEditOle_Release(richEditOle
);
641 #define MY_INDENT 200
643 static void add_oid_text_to_control(HWND hwnd
, char *oid
)
646 PCCRYPT_OID_INFO oidInfo
= CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY
, oid
, 0);
649 parFmt
.cbSize
= sizeof(parFmt
);
650 parFmt
.dwMask
= PFM_STARTINDENT
;
651 parFmt
.dxStartIndent
= MY_INDENT
* 3;
654 add_text_with_paraformat_to_control(hwnd
, oidInfo
->pwszName
,
655 lstrlenW(oidInfo
->pwszName
), &parFmt
);
656 add_unformatted_text_to_control(hwnd
, &nl
, 1);
666 /* The following list MUST be lexicographically sorted by OID */
667 static struct OIDToString oidMap
[] = {
668 /* 1.3.6.1.4.1.311.10.3.1 */
669 { szOID_KP_CTL_USAGE_SIGNING
, IDS_PURPOSE_CTL_USAGE_SIGNING
},
670 /* 1.3.6.1.4.1.311.10.3.4 */
671 { szOID_KP_EFS
, IDS_PURPOSE_EFS
},
672 /* 1.3.6.1.4.1.311.10.3.4.1 */
673 { szOID_EFS_RECOVERY
, IDS_PURPOSE_EFS_RECOVERY
},
674 /* 1.3.6.1.4.1.311.10.3.5 */
675 { szOID_WHQL_CRYPTO
, IDS_PURPOSE_WHQL
},
676 /* 1.3.6.1.4.1.311.10.3.6 */
677 { szOID_NT5_CRYPTO
, IDS_PURPOSE_NT5
},
678 /* 1.3.6.1.4.1.311.10.3.7 */
679 { szOID_OEM_WHQL_CRYPTO
, IDS_PURPOSE_OEM_WHQL
},
680 /* 1.3.6.1.4.1.311.10.3.8 */
681 { szOID_EMBEDDED_NT_CRYPTO
, IDS_PURPOSE_EMBEDDED_NT
},
682 /* 1.3.6.1.4.1.311.10.3.9 */
683 { szOID_ROOT_LIST_SIGNER
, IDS_PURPOSE_ROOT_LIST_SIGNER
},
684 /* 1.3.6.1.4.1.311.10.3.10 */
685 { szOID_KP_QUALIFIED_SUBORDINATION
, IDS_PURPOSE_QUALIFIED_SUBORDINATION
},
686 /* 1.3.6.1.4.1.311.10.3.11 */
687 { szOID_KP_KEY_RECOVERY
, IDS_PURPOSE_KEY_RECOVERY
},
688 /* 1.3.6.1.4.1.311.10.3.12 */
689 { szOID_KP_DOCUMENT_SIGNING
, IDS_PURPOSE_DOCUMENT_SIGNING
},
690 /* 1.3.6.1.4.1.311.10.3.13 */
691 { szOID_KP_LIFETIME_SIGNING
, IDS_PURPOSE_LIFETIME_SIGNING
},
692 /* 1.3.6.1.4.1.311.10.5.1 */
693 { szOID_DRM
, IDS_PURPOSE_DRM
},
694 /* 1.3.6.1.4.1.311.10.6.1 */
695 { szOID_LICENSES
, IDS_PURPOSE_LICENSES
},
696 /* 1.3.6.1.4.1.311.10.6.2 */
697 { szOID_LICENSE_SERVER
, IDS_PURPOSE_LICENSE_SERVER
},
698 /* 1.3.6.1.4.1.311.20.2.1 */
699 { szOID_ENROLLMENT_AGENT
, IDS_PURPOSE_ENROLLMENT_AGENT
},
700 /* 1.3.6.1.4.1.311.20.2.2 */
701 { szOID_KP_SMARTCARD_LOGON
, IDS_PURPOSE_SMARTCARD_LOGON
},
702 /* 1.3.6.1.4.1.311.21.5 */
703 { szOID_KP_CA_EXCHANGE
, IDS_PURPOSE_CA_EXCHANGE
},
704 /* 1.3.6.1.4.1.311.21.6 */
705 { szOID_KP_KEY_RECOVERY_AGENT
, IDS_PURPOSE_KEY_RECOVERY_AGENT
},
706 /* 1.3.6.1.4.1.311.21.19 */
707 { szOID_DS_EMAIL_REPLICATION
, IDS_PURPOSE_DS_EMAIL_REPLICATION
},
708 /* 1.3.6.1.5.5.7.3.1 */
709 { szOID_PKIX_KP_SERVER_AUTH
, IDS_PURPOSE_SERVER_AUTH
},
710 /* 1.3.6.1.5.5.7.3.2 */
711 { szOID_PKIX_KP_CLIENT_AUTH
, IDS_PURPOSE_CLIENT_AUTH
},
712 /* 1.3.6.1.5.5.7.3.3 */
713 { szOID_PKIX_KP_CODE_SIGNING
, IDS_PURPOSE_CODE_SIGNING
},
714 /* 1.3.6.1.5.5.7.3.4 */
715 { szOID_PKIX_KP_EMAIL_PROTECTION
, IDS_PURPOSE_EMAIL_PROTECTION
},
716 /* 1.3.6.1.5.5.7.3.5 */
717 { szOID_PKIX_KP_IPSEC_END_SYSTEM
, IDS_PURPOSE_IPSEC
},
718 /* 1.3.6.1.5.5.7.3.6 */
719 { szOID_PKIX_KP_IPSEC_TUNNEL
, IDS_PURPOSE_IPSEC
},
720 /* 1.3.6.1.5.5.7.3.7 */
721 { szOID_PKIX_KP_IPSEC_USER
, IDS_PURPOSE_IPSEC
},
722 /* 1.3.6.1.5.5.7.3.8 */
723 { szOID_PKIX_KP_TIMESTAMP_SIGNING
, IDS_PURPOSE_TIMESTAMP_SIGNING
},
726 static struct OIDToString
*findSupportedOID(LPCSTR oid
)
728 int indexHigh
= sizeof(oidMap
) / sizeof(oidMap
[0]) - 1, indexLow
= 0, i
;
729 struct OIDToString
*ret
= NULL
;
731 for (i
= (indexLow
+ indexHigh
) / 2; !ret
&& indexLow
<= indexHigh
;
732 i
= (indexLow
+ indexHigh
) / 2)
736 cmp
= strcmp(oid
, oidMap
[i
].oid
);
747 static void add_local_oid_text_to_control(HWND text
, LPCSTR oid
)
749 struct OIDToString
*entry
;
753 parFmt
.cbSize
= sizeof(parFmt
);
754 parFmt
.dwMask
= PFM_STARTINDENT
;
755 parFmt
.dxStartIndent
= MY_INDENT
* 3;
756 if ((entry
= findSupportedOID(oid
)))
758 WCHAR
*str
, *linebreak
, *ptr
;
759 BOOL multiline
= FALSE
;
762 len
= LoadStringW(hInstance
, entry
->id
, (LPWSTR
)&str
, 0);
765 if ((linebreak
= memchrW(ptr
, '\n', len
)))
767 WCHAR copy
[MAX_STRING_LEN
];
770 /* The source string contains a newline, which the richedit
771 * control won't find since it's interpreted as a paragraph
772 * break. Therefore copy up to the newline. lstrcpynW always
773 * NULL-terminates, so pass one more than the length of the
774 * source line so the copy includes the entire line and the
777 lstrcpynW(copy
, ptr
, linebreak
- ptr
+ 1);
778 add_text_with_paraformat_to_control(text
, copy
,
779 linebreak
- ptr
, &parFmt
);
781 add_unformatted_text_to_control(text
, &nl
, 1);
783 else if (multiline
&& *ptr
)
785 /* Add the last line */
786 add_text_with_paraformat_to_control(text
, ptr
,
787 len
- (ptr
- str
), &parFmt
);
788 add_unformatted_text_to_control(text
, &nl
, 1);
793 add_text_with_paraformat_to_control(text
, str
, len
, &parFmt
);
794 add_unformatted_text_to_control(text
, &nl
, 1);
799 WCHAR
*oidW
= HeapAlloc(GetProcessHeap(), 0,
800 (strlen(oid
) + 1) * sizeof(WCHAR
));
807 for (src
= oid
, dst
= oidW
; *src
; src
++, dst
++)
810 add_text_with_paraformat_to_control(text
, oidW
, lstrlenW(oidW
),
812 add_unformatted_text_to_control(text
, &nl
, 1);
813 HeapFree(GetProcessHeap(), 0, oidW
);
818 static void display_app_usages(HWND text
, PCCERT_CONTEXT cert
,
821 static char any_app_policy
[] = szOID_ANY_APPLICATION_POLICY
;
824 PCERT_EXTENSION policyExt
;
829 parFmt
.cbSize
= sizeof(parFmt
);
830 parFmt
.dwMask
= PFM_STARTINDENT
;
831 parFmt
.dxStartIndent
= MY_INDENT
;
832 add_string_resource_with_paraformat_to_control(text
,
833 IDS_CERT_INFO_PURPOSES
, &parFmt
);
834 add_unformatted_text_to_control(text
, &nl
, 1);
835 *anyUsageAdded
= TRUE
;
837 memset(&charFmt
, 0, sizeof(charFmt
));
838 charFmt
.cbSize
= sizeof(charFmt
);
839 charFmt
.dwMask
= CFM_BOLD
;
840 charFmt
.dwEffects
= 0;
841 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
842 if ((policyExt
= CertFindExtension(szOID_APPLICATION_CERT_POLICIES
,
843 cert
->pCertInfo
->cExtension
, cert
->pCertInfo
->rgExtension
)))
845 CERT_POLICIES_INFO
*policies
;
848 if (CryptDecodeObjectEx(X509_ASN_ENCODING
, X509_CERT_POLICIES
,
849 policyExt
->Value
.pbData
, policyExt
->Value
.cbData
,
850 CRYPT_DECODE_ALLOC_FLAG
, NULL
, &policies
, &size
))
854 for (i
= 0; i
< policies
->cPolicyInfo
; i
++)
858 for (j
= 0; j
< policies
->rgPolicyInfo
[i
].cPolicyQualifier
; j
++)
859 add_local_oid_text_to_control(text
,
860 policies
->rgPolicyInfo
[i
].rgPolicyQualifier
[j
].
861 pszPolicyQualifierId
);
867 add_oid_text_to_control(text
, any_app_policy
);
870 static BOOL
display_cert_usages(HWND text
, PCCERT_CONTEXT cert
,
875 BOOL badUsages
= FALSE
;
877 if (CertGetEnhancedKeyUsage(cert
, 0, NULL
, &size
))
880 static char any_cert_policy
[] = szOID_ANY_CERT_POLICY
;
881 PCERT_ENHKEY_USAGE usage
= HeapAlloc(GetProcessHeap(), 0, size
);
885 if (CertGetEnhancedKeyUsage(cert
, 0, usage
, &size
))
893 parFmt
.cbSize
= sizeof(parFmt
);
894 parFmt
.dwMask
= PFM_STARTINDENT
;
895 parFmt
.dxStartIndent
= MY_INDENT
;
896 add_string_resource_with_paraformat_to_control(text
,
897 IDS_CERT_INFO_PURPOSES
, &parFmt
);
898 add_unformatted_text_to_control(text
, &nl
, 1);
899 *anyUsageAdded
= TRUE
;
901 memset(&charFmt
, 0, sizeof(charFmt
));
902 charFmt
.cbSize
= sizeof(charFmt
);
903 charFmt
.dwMask
= CFM_BOLD
;
904 charFmt
.dwEffects
= 0;
905 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
,
907 if (!usage
->cUsageIdentifier
)
908 add_oid_text_to_control(text
, any_cert_policy
);
910 for (i
= 0; i
< usage
->cUsageIdentifier
; i
++)
911 add_local_oid_text_to_control(text
,
912 usage
->rgpszUsageIdentifier
[i
]);
916 HeapFree(GetProcessHeap(), 0, usage
);
926 static void set_policy_text(HWND text
,
927 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
)
929 BOOL includeCertUsages
= FALSE
, includeAppUsages
= FALSE
;
930 BOOL badUsages
= FALSE
, anyUsageAdded
= FALSE
;
932 if (pCertViewInfo
->cPurposes
)
936 for (i
= 0; i
< pCertViewInfo
->cPurposes
; i
++)
938 if (!strcmp(pCertViewInfo
->rgszPurposes
[i
], szOID_ANY_CERT_POLICY
))
939 includeCertUsages
= TRUE
;
940 else if (!strcmp(pCertViewInfo
->rgszPurposes
[i
],
941 szOID_ANY_APPLICATION_POLICY
))
942 includeAppUsages
= TRUE
;
948 includeAppUsages
= includeCertUsages
= TRUE
;
949 if (includeAppUsages
)
950 display_app_usages(text
, pCertViewInfo
->pCertContext
, &anyUsageAdded
);
951 if (includeCertUsages
)
952 badUsages
= display_cert_usages(text
, pCertViewInfo
->pCertContext
,
958 parFmt
.cbSize
= sizeof(parFmt
);
959 parFmt
.dwMask
= PFM_STARTINDENT
;
960 parFmt
.dxStartIndent
= MY_INDENT
;
961 add_string_resource_with_paraformat_to_control(text
,
962 IDS_CERT_INFO_BAD_PURPOSES
, &parFmt
);
966 static CRYPT_OBJID_BLOB
*find_policy_qualifier(CERT_POLICIES_INFO
*policies
,
969 CRYPT_OBJID_BLOB
*ret
= NULL
;
972 for (i
= 0; !ret
&& i
< policies
->cPolicyInfo
; i
++)
976 for (j
= 0; !ret
&& j
< policies
->rgPolicyInfo
[i
].cPolicyQualifier
; j
++)
977 if (!strcmp(policies
->rgPolicyInfo
[i
].rgPolicyQualifier
[j
].
978 pszPolicyQualifierId
, policyOid
))
979 ret
= &policies
->rgPolicyInfo
[i
].rgPolicyQualifier
[j
].
985 static WCHAR
*get_cps_str_from_qualifier(CRYPT_OBJID_BLOB
*qualifier
)
987 LPWSTR qualifierStr
= NULL
;
988 CERT_NAME_VALUE
*qualifierValue
;
991 if (CryptDecodeObjectEx(X509_ASN_ENCODING
, X509_NAME_VALUE
,
992 qualifier
->pbData
, qualifier
->cbData
, CRYPT_DECODE_ALLOC_FLAG
, NULL
,
993 &qualifierValue
, &size
))
995 size
= CertRDNValueToStrW(qualifierValue
->dwValueType
,
996 &qualifierValue
->Value
, NULL
, 0);
997 qualifierStr
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
));
999 CertRDNValueToStrW(qualifierValue
->dwValueType
,
1000 &qualifierValue
->Value
, qualifierStr
, size
);
1001 LocalFree(qualifierValue
);
1003 return qualifierStr
;
1006 static WCHAR
*get_user_notice_from_qualifier(CRYPT_OBJID_BLOB
*qualifier
)
1009 CERT_POLICY_QUALIFIER_USER_NOTICE
*qualifierValue
;
1012 if (CryptDecodeObjectEx(X509_ASN_ENCODING
,
1013 X509_PKIX_POLICY_QUALIFIER_USERNOTICE
,
1014 qualifier
->pbData
, qualifier
->cbData
, CRYPT_DECODE_ALLOC_FLAG
, NULL
,
1015 &qualifierValue
, &size
))
1017 str
= HeapAlloc(GetProcessHeap(), 0,
1018 (strlenW(qualifierValue
->pszDisplayText
) + 1) * sizeof(WCHAR
));
1020 strcpyW(str
, qualifierValue
->pszDisplayText
);
1021 LocalFree(qualifierValue
);
1026 struct IssuerStatement
1032 static void set_issuer_statement(HWND hwnd
,
1033 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
)
1035 PCERT_EXTENSION policyExt
;
1037 if (!(pCertViewInfo
->dwFlags
& CRYPTUI_DISABLE_ISSUERSTATEMENT
) &&
1038 (policyExt
= CertFindExtension(szOID_CERT_POLICIES
,
1039 pCertViewInfo
->pCertContext
->pCertInfo
->cExtension
,
1040 pCertViewInfo
->pCertContext
->pCertInfo
->rgExtension
)))
1042 CERT_POLICIES_INFO
*policies
;
1045 if (CryptDecodeObjectEx(X509_ASN_ENCODING
, policyExt
->pszObjId
,
1046 policyExt
->Value
.pbData
, policyExt
->Value
.cbData
,
1047 CRYPT_DECODE_ALLOC_FLAG
, NULL
, &policies
, &size
))
1049 CRYPT_OBJID_BLOB
*qualifier
;
1050 LPWSTR cps
= NULL
, userNotice
= NULL
;
1052 if ((qualifier
= find_policy_qualifier(policies
,
1053 szOID_PKIX_POLICY_QUALIFIER_CPS
)))
1054 cps
= get_cps_str_from_qualifier(qualifier
);
1055 if ((qualifier
= find_policy_qualifier(policies
,
1056 szOID_PKIX_POLICY_QUALIFIER_USERNOTICE
)))
1057 userNotice
= get_user_notice_from_qualifier(qualifier
);
1058 if (cps
|| userNotice
)
1060 struct IssuerStatement
*issuerStatement
=
1061 HeapAlloc(GetProcessHeap(), 0, sizeof(struct IssuerStatement
));
1063 if (issuerStatement
)
1065 issuerStatement
->cps
= cps
;
1066 issuerStatement
->userNotice
= userNotice
;
1067 EnableWindow(GetDlgItem(hwnd
, IDC_ISSUERSTATEMENT
), TRUE
);
1068 SetWindowLongPtrW(hwnd
, DWLP_USER
,
1069 (ULONG_PTR
)issuerStatement
);
1072 LocalFree(policies
);
1077 static void set_cert_info(HWND hwnd
,
1078 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
)
1080 CHARFORMATW charFmt
;
1082 HWND icon
= GetDlgItem(hwnd
, IDC_CERTIFICATE_ICON
);
1083 HWND text
= GetDlgItem(hwnd
, IDC_CERTIFICATE_INFO
);
1084 CRYPT_PROVIDER_SGNR
*provSigner
= WTHelperGetProvSignerFromChain(
1085 (CRYPT_PROVIDER_DATA
*)pCertViewInfo
->u
.pCryptProviderData
,
1086 pCertViewInfo
->idxSigner
, pCertViewInfo
->fCounterSigner
,
1087 pCertViewInfo
->idxCounterSigner
);
1088 CRYPT_PROVIDER_CERT
*root
=
1089 &provSigner
->pasCertChain
[provSigner
->csCertChain
- 1];
1091 if (!provSigner
->pChainContext
||
1092 (provSigner
->pChainContext
->TrustStatus
.dwErrorStatus
&
1093 CERT_TRUST_IS_PARTIAL_CHAIN
))
1094 add_icon_to_control(icon
, IDB_CERT_WARNING
);
1095 else if (!root
->fTrustedRoot
)
1096 add_icon_to_control(icon
, IDB_CERT_ERROR
);
1098 add_icon_to_control(icon
, IDB_CERT
);
1100 memset(&charFmt
, 0, sizeof(charFmt
));
1101 charFmt
.cbSize
= sizeof(charFmt
);
1102 charFmt
.dwMask
= CFM_BOLD
;
1103 charFmt
.dwEffects
= CFE_BOLD
;
1104 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
1105 /* FIXME: vertically center text */
1106 parFmt
.cbSize
= sizeof(parFmt
);
1107 parFmt
.dwMask
= PFM_STARTINDENT
;
1108 parFmt
.dxStartIndent
= MY_INDENT
;
1109 add_string_resource_with_paraformat_to_control(text
,
1110 IDS_CERTIFICATEINFORMATION
, &parFmt
);
1112 text
= GetDlgItem(hwnd
, IDC_CERTIFICATE_STATUS
);
1113 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
1114 if (provSigner
->dwError
== TRUST_E_CERT_SIGNATURE
)
1115 add_string_resource_with_paraformat_to_control(text
,
1116 IDS_CERT_INFO_BAD_SIG
, &parFmt
);
1117 else if (!provSigner
->pChainContext
||
1118 (provSigner
->pChainContext
->TrustStatus
.dwErrorStatus
&
1119 CERT_TRUST_IS_PARTIAL_CHAIN
))
1120 add_string_resource_with_paraformat_to_control(text
,
1121 IDS_CERT_INFO_PARTIAL_CHAIN
, &parFmt
);
1122 else if (!root
->fTrustedRoot
)
1124 if (provSigner
->csCertChain
== 1 && root
->fSelfSigned
)
1125 add_string_resource_with_paraformat_to_control(text
,
1126 IDS_CERT_INFO_UNTRUSTED_CA
, &parFmt
);
1128 add_string_resource_with_paraformat_to_control(text
,
1129 IDS_CERT_INFO_UNTRUSTED_ROOT
, &parFmt
);
1133 set_policy_text(text
, pCertViewInfo
);
1134 set_issuer_statement(hwnd
, pCertViewInfo
);
1138 static void set_cert_name_string(HWND hwnd
, PCCERT_CONTEXT cert
,
1139 DWORD nameFlags
, int heading
)
1142 HWND text
= GetDlgItem(hwnd
, IDC_CERTIFICATE_NAMES
);
1143 CHARFORMATW charFmt
;
1146 memset(&charFmt
, 0, sizeof(charFmt
));
1147 charFmt
.cbSize
= sizeof(charFmt
);
1148 charFmt
.dwMask
= CFM_BOLD
;
1149 charFmt
.dwEffects
= CFE_BOLD
;
1150 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
1151 parFmt
.cbSize
= sizeof(parFmt
);
1152 parFmt
.dwMask
= PFM_STARTINDENT
;
1153 parFmt
.dxStartIndent
= MY_INDENT
* 3;
1154 add_string_resource_with_paraformat_to_control(text
, heading
, &parFmt
);
1155 charFmt
.dwEffects
= 0;
1156 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
1157 add_cert_string_to_control(text
, cert
, CERT_NAME_SIMPLE_DISPLAY_TYPE
,
1159 add_unformatted_text_to_control(text
, &nl
, 1);
1160 add_unformatted_text_to_control(text
, &nl
, 1);
1161 add_unformatted_text_to_control(text
, &nl
, 1);
1165 static void add_date_string_to_control(HWND hwnd
, const FILETIME
*fileTime
)
1167 WCHAR dateFmt
[80]; /* sufficient for all versions of LOCALE_SSHORTDATE */
1171 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT
, LOCALE_SSHORTDATE
, dateFmt
,
1172 sizeof(dateFmt
) / sizeof(dateFmt
[0]));
1173 FileTimeToSystemTime(fileTime
, &sysTime
);
1174 GetDateFormatW(LOCALE_SYSTEM_DEFAULT
, 0, &sysTime
, dateFmt
, date
,
1175 sizeof(date
) / sizeof(date
[0]));
1176 add_unformatted_text_to_control(hwnd
, date
, lstrlenW(date
));
1179 static void set_cert_validity_period(HWND hwnd
, PCCERT_CONTEXT cert
)
1182 HWND text
= GetDlgItem(hwnd
, IDC_CERTIFICATE_NAMES
);
1183 CHARFORMATW charFmt
;
1186 memset(&charFmt
, 0, sizeof(charFmt
));
1187 charFmt
.cbSize
= sizeof(charFmt
);
1188 charFmt
.dwMask
= CFM_BOLD
;
1189 charFmt
.dwEffects
= CFE_BOLD
;
1190 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
1191 parFmt
.cbSize
= sizeof(parFmt
);
1192 parFmt
.dwMask
= PFM_STARTINDENT
;
1193 parFmt
.dxStartIndent
= MY_INDENT
* 3;
1194 add_string_resource_with_paraformat_to_control(text
, IDS_VALID_FROM
,
1196 charFmt
.dwEffects
= 0;
1197 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
1198 add_date_string_to_control(text
, &cert
->pCertInfo
->NotBefore
);
1199 charFmt
.dwEffects
= CFE_BOLD
;
1200 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
1201 add_string_resource_to_control(text
, IDS_VALID_TO
);
1202 charFmt
.dwEffects
= 0;
1203 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
1204 add_date_string_to_control(text
, &cert
->pCertInfo
->NotAfter
);
1205 add_unformatted_text_to_control(text
, &nl
, 1);
1208 static void set_general_info(HWND hwnd
,
1209 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
)
1211 set_cert_info(hwnd
, pCertViewInfo
);
1212 set_cert_name_string(hwnd
, pCertViewInfo
->pCertContext
, 0,
1213 IDS_SUBJECT_HEADING
);
1214 set_cert_name_string(hwnd
, pCertViewInfo
->pCertContext
,
1215 CERT_NAME_ISSUER_FLAG
, IDS_ISSUER_HEADING
);
1216 set_cert_validity_period(hwnd
, pCertViewInfo
->pCertContext
);
1219 static LRESULT CALLBACK
user_notice_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wp
,
1224 struct IssuerStatement
*issuerStatement
;
1229 text
= GetDlgItem(hwnd
, IDC_USERNOTICE
);
1230 issuerStatement
= (struct IssuerStatement
*)lp
;
1231 add_unformatted_text_to_control(text
, issuerStatement
->userNotice
,
1232 strlenW(issuerStatement
->userNotice
));
1233 if (issuerStatement
->cps
)
1234 SetWindowLongPtrW(hwnd
, DWLP_USER
, (LPARAM
)issuerStatement
->cps
);
1236 EnableWindow(GetDlgItem(hwnd
, IDC_CPS
), FALSE
);
1242 EndDialog(hwnd
, IDOK
);
1247 IBindCtx
*bctx
= NULL
;
1250 CreateBindCtx(0, &bctx
);
1251 cps
= (LPWSTR
)GetWindowLongPtrW(hwnd
, DWLP_USER
);
1252 HlinkSimpleNavigateToString(cps
, NULL
, NULL
, NULL
, bctx
, NULL
,
1253 HLNF_OPENINNEWWINDOW
, 0);
1254 IBindCtx_Release(bctx
);
1262 static void show_user_notice(HWND hwnd
, struct IssuerStatement
*issuerStatement
)
1264 DialogBoxParamW(hInstance
, MAKEINTRESOURCEW(IDD_USERNOTICE
), hwnd
,
1265 user_notice_dlg_proc
, (LPARAM
)issuerStatement
);
1268 static LRESULT CALLBACK
general_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wp
,
1271 PROPSHEETPAGEW
*page
;
1272 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
;
1274 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd
, msg
, wp
, lp
);
1279 page
= (PROPSHEETPAGEW
*)lp
;
1280 pCertViewInfo
= (PCCRYPTUI_VIEWCERTIFICATE_STRUCTW
)page
->lParam
;
1281 if (pCertViewInfo
->dwFlags
& CRYPTUI_DISABLE_ADDTOSTORE
)
1282 ShowWindow(GetDlgItem(hwnd
, IDC_ADDTOSTORE
), FALSE
);
1283 EnableWindow(GetDlgItem(hwnd
, IDC_ISSUERSTATEMENT
), FALSE
);
1284 set_general_info(hwnd
, pCertViewInfo
);
1289 case IDC_ADDTOSTORE
:
1290 FIXME("call CryptUIWizImport\n");
1292 case IDC_ISSUERSTATEMENT
:
1294 struct IssuerStatement
*issuerStatement
=
1295 (struct IssuerStatement
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
1297 if (issuerStatement
)
1299 if (issuerStatement
->userNotice
)
1300 show_user_notice(hwnd
, issuerStatement
);
1301 else if (issuerStatement
->cps
)
1303 IBindCtx
*bctx
= NULL
;
1305 CreateBindCtx(0, &bctx
);
1306 HlinkSimpleNavigateToString(issuerStatement
->cps
, NULL
,
1307 NULL
, NULL
, bctx
, NULL
, HLNF_OPENINNEWWINDOW
, 0);
1308 IBindCtx_Release(bctx
);
1319 static UINT CALLBACK
general_callback_proc(HWND hwnd
, UINT msg
,
1320 PROPSHEETPAGEW
*page
)
1322 struct IssuerStatement
*issuerStatement
;
1328 (struct IssuerStatement
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
1329 if (issuerStatement
)
1331 HeapFree(GetProcessHeap(), 0, issuerStatement
->cps
);
1332 HeapFree(GetProcessHeap(), 0, issuerStatement
->userNotice
);
1333 HeapFree(GetProcessHeap(), 0, issuerStatement
);
1340 static void init_general_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
,
1341 PROPSHEETPAGEW
*page
)
1343 memset(page
, 0, sizeof(PROPSHEETPAGEW
));
1344 page
->dwSize
= sizeof(PROPSHEETPAGEW
);
1345 page
->dwFlags
= PSP_USECALLBACK
;
1346 page
->pfnCallback
= general_callback_proc
;
1347 page
->hInstance
= hInstance
;
1348 page
->u
.pszTemplate
= MAKEINTRESOURCEW(IDD_GENERAL
);
1349 page
->pfnDlgProc
= general_dlg_proc
;
1350 page
->lParam
= (LPARAM
)pCertViewInfo
;
1353 typedef WCHAR
* (*field_format_func
)(PCCERT_CONTEXT cert
);
1355 static WCHAR
*field_format_version(PCCERT_CONTEXT cert
)
1357 static const WCHAR fmt
[] = { 'V','%','d',0 };
1358 WCHAR
*buf
= HeapAlloc(GetProcessHeap(), 0, 12 * sizeof(WCHAR
));
1361 sprintfW(buf
, fmt
, cert
->pCertInfo
->dwVersion
);
1365 static WCHAR
*format_hex_string(void *pb
, DWORD cb
)
1367 WCHAR
*buf
= HeapAlloc(GetProcessHeap(), 0, (cb
* 3 + 1) * sizeof(WCHAR
));
1371 static const WCHAR fmt
[] = { '%','0','2','x',' ',0 };
1375 for (i
= 0, ptr
= buf
; i
< cb
; i
++, ptr
+= 3)
1376 sprintfW(ptr
, fmt
, ((BYTE
*)pb
)[i
]);
1381 static WCHAR
*field_format_serial_number(PCCERT_CONTEXT cert
)
1383 return format_hex_string(cert
->pCertInfo
->SerialNumber
.pbData
,
1384 cert
->pCertInfo
->SerialNumber
.cbData
);
1387 static WCHAR
*field_format_issuer(PCCERT_CONTEXT cert
)
1389 return get_cert_name_string(cert
, CERT_NAME_SIMPLE_DISPLAY_TYPE
,
1390 CERT_NAME_ISSUER_FLAG
);
1393 static WCHAR
*field_format_detailed_cert_name(PCERT_NAME_BLOB name
)
1396 DWORD len
= CertNameToStrW(X509_ASN_ENCODING
, name
,
1397 CERT_X500_NAME_STR
| CERT_NAME_STR_CRLF_FLAG
, NULL
, 0);
1401 str
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1403 CertNameToStrW(X509_ASN_ENCODING
, name
,
1404 CERT_X500_NAME_STR
| CERT_NAME_STR_CRLF_FLAG
, str
, len
);
1409 static WCHAR
*field_format_detailed_issuer(PCCERT_CONTEXT cert
, void *param
)
1411 return field_format_detailed_cert_name(&cert
->pCertInfo
->Issuer
);
1414 static WCHAR
*field_format_subject(PCCERT_CONTEXT cert
)
1416 return get_cert_name_string(cert
, CERT_NAME_SIMPLE_DISPLAY_TYPE
, 0);
1419 static WCHAR
*field_format_detailed_subject(PCCERT_CONTEXT cert
, void *param
)
1421 return field_format_detailed_cert_name(&cert
->pCertInfo
->Subject
);
1424 static WCHAR
*format_long_date(const FILETIME
*fileTime
)
1426 WCHAR dateFmt
[80]; /* long enough for LOCALE_SLONGDATE */
1431 /* FIXME: format isn't quite right, want time too */
1432 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT
, LOCALE_SLONGDATE
, dateFmt
,
1433 sizeof(dateFmt
) / sizeof(dateFmt
[0]));
1434 FileTimeToSystemTime(fileTime
, &sysTime
);
1435 len
= GetDateFormatW(LOCALE_SYSTEM_DEFAULT
, 0, &sysTime
, dateFmt
, NULL
, 0);
1438 buf
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1440 GetDateFormatW(LOCALE_SYSTEM_DEFAULT
, 0, &sysTime
, dateFmt
, buf
,
1446 static WCHAR
*field_format_from_date(PCCERT_CONTEXT cert
)
1448 return format_long_date(&cert
->pCertInfo
->NotBefore
);
1451 static WCHAR
*field_format_to_date(PCCERT_CONTEXT cert
)
1453 return format_long_date(&cert
->pCertInfo
->NotAfter
);
1456 static WCHAR
*field_format_public_key(PCCERT_CONTEXT cert
)
1458 PCCRYPT_OID_INFO oidInfo
;
1461 oidInfo
= CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY
,
1462 cert
->pCertInfo
->SubjectPublicKeyInfo
.Algorithm
.pszObjId
, 0);
1465 WCHAR fmt
[MAX_STRING_LEN
];
1467 if (LoadStringW(hInstance
, IDS_FIELD_PUBLIC_KEY_FORMAT
, fmt
,
1468 sizeof(fmt
) / sizeof(fmt
[0])))
1470 /* Allocate the output buffer. Use the number of bytes in the
1471 * public key as a conservative (high) estimate for the number of
1472 * digits in its output.
1473 * The output is of the form (in English)
1474 * "<public key algorithm> (<public key bit length> bits)".
1475 * Ordinarily having two positional parameters in a string is not a
1476 * good idea, but as this isn't a sentence fragment, it shouldn't
1477 * be word-order dependent.
1479 buf
= HeapAlloc(GetProcessHeap(), 0,
1480 (strlenW(fmt
) + strlenW(oidInfo
->pwszName
) +
1481 cert
->pCertInfo
->SubjectPublicKeyInfo
.PublicKey
.cbData
* 8)
1484 sprintfW(buf
, fmt
, oidInfo
->pwszName
,
1485 CertGetPublicKeyLength(X509_ASN_ENCODING
,
1486 &cert
->pCertInfo
->SubjectPublicKeyInfo
));
1492 static WCHAR
*field_format_detailed_public_key(PCCERT_CONTEXT cert
, void *param
)
1494 return format_hex_string(
1495 cert
->pCertInfo
->SubjectPublicKeyInfo
.PublicKey
.pbData
,
1496 cert
->pCertInfo
->SubjectPublicKeyInfo
.PublicKey
.cbData
);
1499 struct field_value_data
;
1502 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
;
1503 BOOL
*pfPropertiesChanged
;
1505 struct field_value_data
*fields
;
1508 typedef void (*add_fields_func
)(HWND hwnd
, struct detail_data
*data
);
1510 typedef WCHAR
*(*create_detailed_value_func
)(PCCERT_CONTEXT cert
, void *param
);
1512 struct field_value_data
1514 create_detailed_value_func create
;
1515 LPWSTR detailed_value
;
1519 static void add_field_value_data(struct detail_data
*data
,
1520 create_detailed_value_func create
, void *param
)
1523 data
->fields
= HeapReAlloc(GetProcessHeap(), 0, data
->fields
,
1524 (data
->cFields
+ 1) * sizeof(struct field_value_data
));
1526 data
->fields
= HeapAlloc(GetProcessHeap(), 0,
1527 sizeof(struct field_value_data
));
1530 data
->fields
[data
->cFields
].create
= create
;
1531 data
->fields
[data
->cFields
].detailed_value
= NULL
;
1532 data
->fields
[data
->cFields
].param
= param
;
1537 static void add_field_and_value_to_list(HWND hwnd
, struct detail_data
*data
,
1538 LPWSTR field
, LPWSTR value
, create_detailed_value_func create
, void *param
)
1541 int iItem
= SendMessageW(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1543 item
.mask
= LVIF_TEXT
| LVIF_PARAM
;
1546 item
.pszText
= field
;
1547 item
.lParam
= (LPARAM
)data
;
1548 SendMessageW(hwnd
, LVM_INSERTITEMW
, 0, (LPARAM
)&item
);
1551 item
.pszText
= value
;
1553 SendMessageW(hwnd
, LVM_SETITEMTEXTW
, iItem
, (LPARAM
)&item
);
1555 add_field_value_data(data
, create
, param
);
1558 static void add_string_id_and_value_to_list(HWND hwnd
, struct detail_data
*data
,
1559 int id
, LPWSTR value
, create_detailed_value_func create
, void *param
)
1561 WCHAR buf
[MAX_STRING_LEN
];
1563 LoadStringW(hInstance
, id
, buf
, sizeof(buf
) / sizeof(buf
[0]));
1564 add_field_and_value_to_list(hwnd
, data
, buf
, value
, create
, param
);
1570 field_format_func format
;
1571 create_detailed_value_func create_detailed_value
;
1574 static void add_v1_field(HWND hwnd
, struct detail_data
*data
,
1575 const struct v1_field
*field
)
1577 WCHAR
*val
= field
->format(data
->pCertViewInfo
->pCertContext
);
1581 add_string_id_and_value_to_list(hwnd
, data
, field
->id
, val
,
1582 field
->create_detailed_value
, NULL
);
1583 HeapFree(GetProcessHeap(), 0, val
);
1587 static const struct v1_field v1_fields
[] = {
1588 { IDS_FIELD_VERSION
, field_format_version
, NULL
},
1589 { IDS_FIELD_SERIAL_NUMBER
, field_format_serial_number
, NULL
},
1590 { IDS_FIELD_ISSUER
, field_format_issuer
, field_format_detailed_issuer
},
1591 { IDS_FIELD_VALID_FROM
, field_format_from_date
, NULL
},
1592 { IDS_FIELD_VALID_TO
, field_format_to_date
, NULL
},
1593 { IDS_FIELD_SUBJECT
, field_format_subject
, field_format_detailed_subject
},
1594 { IDS_FIELD_PUBLIC_KEY
, field_format_public_key
,
1595 field_format_detailed_public_key
}
1598 static void add_v1_fields(HWND hwnd
, struct detail_data
*data
)
1601 PCCERT_CONTEXT cert
= data
->pCertViewInfo
->pCertContext
;
1603 /* The last item in v1_fields is the public key, which is not in the loop
1604 * because it's a special case.
1606 for (i
= 0; i
< sizeof(v1_fields
) / sizeof(v1_fields
[0]) - 1; i
++)
1607 add_v1_field(hwnd
, data
, &v1_fields
[i
]);
1608 if (cert
->pCertInfo
->SubjectPublicKeyInfo
.PublicKey
.cbData
)
1609 add_v1_field(hwnd
, data
, &v1_fields
[i
]);
1612 static WCHAR
*crypt_format_extension(PCERT_EXTENSION ext
, DWORD formatStrType
)
1617 if (CryptFormatObject(X509_ASN_ENCODING
, 0, formatStrType
, NULL
,
1618 ext
->pszObjId
, ext
->Value
.pbData
, ext
->Value
.cbData
, NULL
, &size
))
1620 str
= HeapAlloc(GetProcessHeap(), 0, size
);
1621 CryptFormatObject(X509_ASN_ENCODING
, 0, formatStrType
, NULL
,
1622 ext
->pszObjId
, ext
->Value
.pbData
, ext
->Value
.cbData
, str
, &size
);
1627 static WCHAR
*field_format_extension_hex_with_ascii(PCERT_EXTENSION ext
)
1631 if (ext
->Value
.cbData
)
1633 /* The output is formatted as:
1634 * <hex bytes> <ascii bytes>\n
1635 * where <hex bytes> is a string of up to 8 bytes, output as %02x,
1636 * and <ascii bytes> is the ASCII equivalent of each byte, or '.' if
1637 * the byte is not printable.
1638 * So, for example, the extension value consisting of the following
1640 * 0x30,0x14,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x03,
1641 * 0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67
1643 * 30 14 31 12 30 10 06 03 0.1.0...
1644 * 55 04 03 13 09 4a 75 61 U....Jua
1645 * 6e 20 4c 61 6e 67 n Lang
1646 * The allocation size therefore requires:
1647 * - 4 characters per character in an 8-byte line
1648 * (2 for the hex format, one for the space, one for the ASCII value)
1649 * - 3 more characters per 8-byte line (two spaces and a newline)
1650 * - 1 character for the terminating nul
1651 * FIXME: should use a fixed-width font for this
1653 DWORD lines
= (ext
->Value
.cbData
+ 7) / 8;
1655 str
= HeapAlloc(GetProcessHeap(), 0,
1656 (lines
* 8 * 4 + lines
* 3 + 1) * sizeof(WCHAR
));
1659 static const WCHAR fmt
[] = { '%','0','2','x',' ',0 };
1663 for (i
= 0, ptr
= str
; i
< ext
->Value
.cbData
; i
+= 8)
1665 /* Output as hex bytes first */
1666 for (j
= i
; j
< min(i
+ 8, ext
->Value
.cbData
); j
++, ptr
+= 3)
1667 sprintfW(ptr
, fmt
, ext
->Value
.pbData
[j
]);
1668 /* Pad the hex output with spaces for alignment */
1669 if (j
== ext
->Value
.cbData
&& j
% 8)
1671 static const WCHAR pad
[] = { ' ',' ',' ' };
1673 for (; j
% 8; j
++, ptr
+= sizeof(pad
) / sizeof(pad
[0]))
1674 memcpy(ptr
, pad
, sizeof(pad
));
1676 /* The last sprintfW included a space, so just insert one
1677 * more space between the hex bytes and the ASCII output
1680 /* Output as ASCII bytes */
1681 for (j
= i
; j
< min(i
+ 8, ext
->Value
.cbData
); j
++, ptr
++)
1683 if (isprintW(ext
->Value
.pbData
[j
]) &&
1684 !isspaceW(ext
->Value
.pbData
[j
]))
1685 *ptr
= ext
->Value
.pbData
[j
];
1697 static WCHAR
*field_format_detailed_extension(PCCERT_CONTEXT cert
, void *param
)
1699 PCERT_EXTENSION ext
= param
;
1700 LPWSTR str
= crypt_format_extension(ext
,
1701 CRYPT_FORMAT_STR_MULTI_LINE
| CRYPT_FORMAT_STR_NO_HEX
);
1704 str
= field_format_extension_hex_with_ascii(ext
);
1708 static void add_cert_extension_detail(HWND hwnd
, struct detail_data
*data
,
1709 PCERT_EXTENSION ext
)
1711 PCCRYPT_OID_INFO oidInfo
= CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY
,
1713 LPWSTR val
= crypt_format_extension(ext
, 0);
1716 add_field_and_value_to_list(hwnd
, data
, (LPWSTR
)oidInfo
->pwszName
,
1717 val
, field_format_detailed_extension
, ext
);
1720 DWORD len
= strlen(ext
->pszObjId
);
1721 LPWSTR oidW
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
1727 for (i
= 0; i
<= len
; i
++)
1728 oidW
[i
] = ext
->pszObjId
[i
];
1729 add_field_and_value_to_list(hwnd
, data
, oidW
, val
,
1730 field_format_detailed_extension
, ext
);
1731 HeapFree(GetProcessHeap(), 0, oidW
);
1734 HeapFree(GetProcessHeap(), 0, val
);
1737 static void add_all_extensions(HWND hwnd
, struct detail_data
*data
)
1740 PCCERT_CONTEXT cert
= data
->pCertViewInfo
->pCertContext
;
1742 for (i
= 0; i
< cert
->pCertInfo
->cExtension
; i
++)
1743 add_cert_extension_detail(hwnd
, data
, &cert
->pCertInfo
->rgExtension
[i
]);
1746 static void add_critical_extensions(HWND hwnd
, struct detail_data
*data
)
1749 PCCERT_CONTEXT cert
= data
->pCertViewInfo
->pCertContext
;
1751 for (i
= 0; i
< cert
->pCertInfo
->cExtension
; i
++)
1752 if (cert
->pCertInfo
->rgExtension
[i
].fCritical
)
1753 add_cert_extension_detail(hwnd
, data
,
1754 &cert
->pCertInfo
->rgExtension
[i
]);
1757 typedef WCHAR
* (*prop_to_value_func
)(void *pb
, DWORD cb
);
1759 struct prop_id_to_string_id
1763 BOOL prop_is_string
;
1764 prop_to_value_func prop_to_value
;
1767 static WCHAR
*format_enhanced_key_usage_value(void *pb
, DWORD cb
)
1771 ext
.pszObjId
= (LPSTR
)X509_ENHANCED_KEY_USAGE
;
1772 ext
.fCritical
= FALSE
;
1773 ext
.Value
.pbData
= pb
;
1774 ext
.Value
.cbData
= cb
;
1775 return crypt_format_extension(&ext
, 0);
1778 /* Logically the access state should also be checked, and IDC_EDITPROPERTIES
1779 * disabled for read-only certificates, but native doesn't appear to do that.
1781 static const struct prop_id_to_string_id prop_id_map
[] = {
1782 { CERT_HASH_PROP_ID
, IDS_PROP_HASH
, FALSE
, format_hex_string
},
1783 { CERT_FRIENDLY_NAME_PROP_ID
, IDS_PROP_FRIENDLY_NAME
, TRUE
, NULL
},
1784 { CERT_DESCRIPTION_PROP_ID
, IDS_PROP_DESCRIPTION
, TRUE
, NULL
},
1785 { CERT_ENHKEY_USAGE_PROP_ID
, IDS_PROP_ENHKEY_USAGE
, FALSE
,
1786 format_enhanced_key_usage_value
},
1789 static void add_properties(HWND hwnd
, struct detail_data
*data
)
1792 PCCERT_CONTEXT cert
= data
->pCertViewInfo
->pCertContext
;
1794 for (i
= 0; i
< sizeof(prop_id_map
) / sizeof(prop_id_map
[0]); i
++)
1798 if (CertGetCertificateContextProperty(cert
, prop_id_map
[i
].prop
, NULL
,
1804 /* FIXME: MS adds a separate value for the signature hash
1807 pb
= HeapAlloc(GetProcessHeap(), 0, cb
);
1810 if (CertGetCertificateContextProperty(cert
,
1811 prop_id_map
[i
].prop
, pb
, &cb
))
1813 if (prop_id_map
[i
].prop_is_string
)
1816 /* Don't double-free pb */
1820 val
= prop_id_map
[i
].prop_to_value(pb
, cb
);
1822 HeapFree(GetProcessHeap(), 0, pb
);
1824 add_string_id_and_value_to_list(hwnd
, data
, prop_id_map
[i
].id
, val
,
1830 static void add_all_fields(HWND hwnd
, struct detail_data
*data
)
1832 add_v1_fields(hwnd
, data
);
1833 add_all_extensions(hwnd
, data
);
1834 add_properties(hwnd
, data
);
1837 struct selection_list_item
1840 add_fields_func add
;
1843 const struct selection_list_item listItems
[] = {
1844 { IDS_FIELDS_ALL
, add_all_fields
},
1845 { IDS_FIELDS_V1
, add_v1_fields
},
1846 { IDS_FIELDS_EXTENSIONS
, add_all_extensions
},
1847 { IDS_FIELDS_CRITICAL_EXTENSIONS
, add_critical_extensions
},
1848 { IDS_FIELDS_PROPERTIES
, add_properties
},
1851 static void create_show_list(HWND hwnd
, struct detail_data
*data
)
1853 HWND cb
= GetDlgItem(hwnd
, IDC_DETAIL_SELECT
);
1854 WCHAR buf
[MAX_STRING_LEN
];
1857 for (i
= 0; i
< sizeof(listItems
) / sizeof(listItems
[0]); i
++)
1861 LoadStringW(hInstance
, listItems
[i
].id
, buf
,
1862 sizeof(buf
) / sizeof(buf
[0]));
1863 index
= SendMessageW(cb
, CB_INSERTSTRING
, -1, (LPARAM
)buf
);
1864 SendMessageW(cb
, CB_SETITEMDATA
, index
, (LPARAM
)data
);
1866 SendMessageW(cb
, CB_SETCURSEL
, 0, 0);
1869 static void create_listview_columns(HWND hwnd
)
1871 HWND lv
= GetDlgItem(hwnd
, IDC_DETAIL_LIST
);
1873 WCHAR buf
[MAX_STRING_LEN
];
1876 SendMessageW(lv
, LVM_SETEXTENDEDLISTVIEWSTYLE
, 0, LVS_EX_FULLROWSELECT
);
1877 GetWindowRect(lv
, &rc
);
1878 LoadStringW(hInstance
, IDS_FIELD
, buf
, sizeof(buf
) / sizeof(buf
[0]));
1879 column
.mask
= LVCF_WIDTH
| LVCF_TEXT
;
1880 column
.cx
= (rc
.right
- rc
.left
) / 2 - 2;
1881 column
.pszText
= buf
;
1882 SendMessageW(lv
, LVM_INSERTCOLUMNW
, 0, (LPARAM
)&column
);
1883 LoadStringW(hInstance
, IDS_VALUE
, buf
, sizeof(buf
) / sizeof(buf
[0]));
1884 SendMessageW(lv
, LVM_INSERTCOLUMNW
, 1, (LPARAM
)&column
);
1887 static void set_fields_selection(HWND hwnd
, struct detail_data
*data
, int sel
)
1889 HWND list
= GetDlgItem(hwnd
, IDC_DETAIL_LIST
);
1891 if (sel
>= 0 && sel
< sizeof(listItems
) / sizeof(listItems
[0]))
1893 SendMessageW(list
, LVM_DELETEALLITEMS
, 0, 0);
1894 listItems
[sel
].add(list
, data
);
1898 static void create_cert_details_list(HWND hwnd
, struct detail_data
*data
)
1900 create_show_list(hwnd
, data
);
1901 create_listview_columns(hwnd
);
1902 set_fields_selection(hwnd
, data
, 0);
1906 CheckBitmapIndexUnchecked
= 1,
1907 CheckBitmapIndexChecked
= 2,
1908 CheckBitmapIndexDisabledUnchecked
= 3,
1909 CheckBitmapIndexDisabledChecked
= 4
1912 static void add_purpose(HWND hwnd
, LPCSTR oid
)
1914 HWND lv
= GetDlgItem(hwnd
, IDC_CERTIFICATE_USAGES
);
1915 PCRYPT_OID_INFO info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
1916 sizeof(CRYPT_OID_INFO
));
1920 char *oidCopy
= HeapAlloc(GetProcessHeap(), 0, strlen(oid
) + 1);
1926 strcpy(oidCopy
, oid
);
1927 info
->cbSize
= sizeof(CRYPT_OID_INFO
);
1928 info
->pszOID
= oidCopy
;
1929 item
.mask
= LVIF_TEXT
| LVIF_STATE
| LVIF_PARAM
;
1930 item
.state
= INDEXTOSTATEIMAGEMASK(CheckBitmapIndexChecked
);
1931 item
.stateMask
= LVIS_STATEIMAGEMASK
;
1932 item
.iItem
= SendMessageW(lv
, LVM_GETITEMCOUNT
, 0, 0);
1934 item
.lParam
= (LPARAM
)info
;
1935 item
.pszText
= oidCopy
;
1936 SendMessageA(lv
, LVM_INSERTITEMA
, 0, (LPARAM
)&item
);
1939 HeapFree(GetProcessHeap(), 0, info
);
1943 static BOOL
is_valid_oid(LPCSTR oid
)
1947 if (oid
[0] != '0' && oid
[0] != '1' && oid
[0] != '2')
1949 else if (oid
[1] != '.')
1956 BOOL expectNum
= TRUE
;
1958 for (ptr
= oid
+ 2, ret
= TRUE
; ret
&& *ptr
; ptr
++)
1964 else if (*(ptr
+ 1) == '.')
1971 else if (!(*(ptr
+ 1)))
1981 static BOOL
is_oid_in_list(HWND hwnd
, LPCSTR oid
)
1983 HWND lv
= GetDlgItem(hwnd
, IDC_CERTIFICATE_USAGES
);
1984 PCCRYPT_OID_INFO oidInfo
= CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY
,
1985 (void *)oid
, CRYPT_ENHKEY_USAGE_OID_GROUP_ID
);
1990 LVFINDINFOW findInfo
;
1992 findInfo
.flags
= LVFI_PARAM
;
1993 findInfo
.lParam
= (LPARAM
)oidInfo
;
1994 if (SendMessageW(lv
, LVM_FINDITEMW
, -1, (LPARAM
)&findInfo
) != -1)
1999 LVFINDINFOA findInfo
;
2001 findInfo
.flags
= LVFI_STRING
;
2003 if (SendMessageW(lv
, LVM_FINDITEMA
, -1, (LPARAM
)&findInfo
) != -1)
2009 #define MAX_PURPOSE 255
2011 static LRESULT CALLBACK
add_purpose_dlg_proc(HWND hwnd
, UINT msg
,
2012 WPARAM wp
, LPARAM lp
)
2015 char buf
[MAX_PURPOSE
+ 1];
2020 SendMessageW(GetDlgItem(hwnd
, IDC_NEW_PURPOSE
), EM_SETLIMITTEXT
,
2022 ShowScrollBar(GetDlgItem(hwnd
, IDC_NEW_PURPOSE
), SB_VERT
, FALSE
);
2023 SetWindowLongPtrW(hwnd
, DWLP_USER
, lp
);
2029 if (LOWORD(wp
) == IDC_NEW_PURPOSE
)
2031 /* Show/hide scroll bar on description depending on how much
2034 HWND description
= GetDlgItem(hwnd
, IDC_NEW_PURPOSE
);
2035 int lines
= SendMessageW(description
, EM_GETLINECOUNT
, 0, 0);
2037 ShowScrollBar(description
, SB_VERT
, lines
> 1);
2044 SendMessageA(GetDlgItem(hwnd
, IDC_NEW_PURPOSE
), WM_GETTEXT
,
2045 sizeof(buf
) / sizeof(buf
[0]), (LPARAM
)buf
);
2048 /* An empty purpose is the same as cancelling */
2049 EndDialog(hwnd
, IDCANCEL
);
2052 else if (!is_valid_oid(buf
))
2054 WCHAR title
[MAX_STRING_LEN
], error
[MAX_STRING_LEN
];
2056 LoadStringW(hInstance
, IDS_CERTIFICATE_PURPOSE_ERROR
, error
,
2057 sizeof(error
) / sizeof(error
[0]));
2058 LoadStringW(hInstance
, IDS_CERTIFICATE_PROPERTIES
, title
,
2059 sizeof(title
) / sizeof(title
[0]));
2060 MessageBoxW(hwnd
, error
, title
, MB_ICONERROR
| MB_OK
);
2062 else if (is_oid_in_list(
2063 (HWND
)GetWindowLongPtrW(hwnd
, DWLP_USER
), buf
))
2065 WCHAR title
[MAX_STRING_LEN
], error
[MAX_STRING_LEN
];
2067 LoadStringW(hInstance
, IDS_CERTIFICATE_PURPOSE_EXISTS
,
2068 error
, sizeof(error
) / sizeof(error
[0]));
2069 LoadStringW(hInstance
, IDS_CERTIFICATE_PROPERTIES
, title
,
2070 sizeof(title
) / sizeof(title
[0]));
2071 MessageBoxW(hwnd
, error
, title
, MB_ICONEXCLAMATION
| MB_OK
);
2075 HWND parent
= (HWND
)GetWindowLongPtrW(hwnd
, DWLP_USER
);
2077 add_purpose(parent
, buf
);
2078 EndDialog(hwnd
, wp
);
2083 EndDialog(hwnd
, wp
);
2094 static WCHAR
*get_cert_property_as_string(PCCERT_CONTEXT cert
, DWORD prop
)
2099 if (CertGetCertificateContextProperty(cert
, prop
, NULL
, &cb
))
2101 name
= HeapAlloc(GetProcessHeap(), 0, cb
);
2104 if (!CertGetCertificateContextProperty(cert
, prop
, (LPBYTE
)name
,
2107 HeapFree(GetProcessHeap(), 0, name
);
2115 static void redraw_states(HWND list
, BOOL enabled
)
2117 int items
= SendMessageW(list
, LVM_GETITEMCOUNT
, 0, 0), i
;
2119 for (i
= 0; i
< items
; i
++)
2121 BOOL change
= FALSE
;
2124 state
= SendMessageW(list
, LVM_GETITEMSTATE
, i
, LVIS_STATEIMAGEMASK
);
2125 /* This reverses the INDEXTOSTATEIMAGEMASK shift. There doesn't appear
2126 * to be a handy macro for it.
2131 if (state
== CheckBitmapIndexDisabledChecked
)
2133 state
= CheckBitmapIndexChecked
;
2136 if (state
== CheckBitmapIndexDisabledUnchecked
)
2138 state
= CheckBitmapIndexUnchecked
;
2144 if (state
== CheckBitmapIndexChecked
)
2146 state
= CheckBitmapIndexDisabledChecked
;
2149 if (state
== CheckBitmapIndexUnchecked
)
2151 state
= CheckBitmapIndexDisabledUnchecked
;
2159 item
.state
= INDEXTOSTATEIMAGEMASK(state
);
2160 item
.stateMask
= LVIS_STATEIMAGEMASK
;
2161 SendMessageW(list
, LVM_SETITEMSTATE
, i
, (LPARAM
)&item
);
2167 PurposeEnableAll
= 0,
2169 PurposeEnableSelected
2172 static void select_purposes(HWND hwnd
, PurposeSelection selection
)
2174 HWND lv
= GetDlgItem(hwnd
, IDC_CERTIFICATE_USAGES
);
2178 case PurposeEnableAll
:
2179 case PurposeDisableAll
:
2180 EnableWindow(lv
, FALSE
);
2181 redraw_states(lv
, FALSE
);
2182 EnableWindow(GetDlgItem(hwnd
, IDC_ADD_PURPOSE
), FALSE
);
2184 case PurposeEnableSelected
:
2185 EnableWindow(lv
, TRUE
);
2186 redraw_states(lv
, TRUE
);
2187 EnableWindow(GetDlgItem(hwnd
, IDC_ADD_PURPOSE
), TRUE
);
2191 extern BOOL WINAPI
WTHelperGetKnownUsages(DWORD action
,
2192 PCCRYPT_OID_INFO
**usages
);
2194 static void add_known_usage(HWND lv
, PCCRYPT_OID_INFO info
)
2198 item
.mask
= LVIF_TEXT
| LVIF_STATE
| LVIF_PARAM
;
2199 item
.state
= INDEXTOSTATEIMAGEMASK(CheckBitmapIndexDisabledChecked
);
2200 item
.stateMask
= LVIS_STATEIMAGEMASK
;
2201 item
.iItem
= SendMessageW(lv
, LVM_GETITEMCOUNT
, 0, 0);
2203 item
.lParam
= (LPARAM
)info
;
2204 item
.pszText
= (LPWSTR
)info
->pwszName
;
2205 SendMessageW(lv
, LVM_INSERTITEMW
, 0, (LPARAM
)&item
);
2208 struct edit_cert_data
2210 PCCERT_CONTEXT cert
;
2211 BOOL
*pfPropertiesChanged
;
2212 HIMAGELIST imageList
;
2215 static void show_cert_usages(HWND hwnd
, struct edit_cert_data
*data
)
2217 PCCERT_CONTEXT cert
= data
->cert
;
2218 HWND lv
= GetDlgItem(hwnd
, IDC_CERTIFICATE_USAGES
);
2219 PCERT_ENHKEY_USAGE usage
;
2221 PCCRYPT_OID_INFO
*usages
;
2224 PurposeSelection purposeSelection
;
2226 GetWindowRect(lv
, &rc
);
2227 column
.mask
= LVCF_WIDTH
;
2228 column
.cx
= rc
.right
- rc
.left
;
2229 SendMessageW(lv
, LVM_INSERTCOLUMNW
, 0, (LPARAM
)&column
);
2230 SendMessageW(lv
, LVM_SETIMAGELIST
, LVSIL_STATE
, (LPARAM
)data
->imageList
);
2232 /* Get enhanced key usage. Have to check for a property and an extension
2233 * separately, because CertGetEnhancedKeyUsage will succeed and return an
2234 * empty usage if neither is set. Unfortunately an empty usage implies
2235 * no usage is allowed, so we have to distinguish between the two cases.
2237 if (CertGetEnhancedKeyUsage(cert
, CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG
,
2240 usage
= HeapAlloc(GetProcessHeap(), 0, size
);
2241 if (!CertGetEnhancedKeyUsage(cert
,
2242 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG
, usage
, &size
))
2244 HeapFree(GetProcessHeap(), 0, usage
);
2247 else if (usage
->cUsageIdentifier
)
2248 purposeSelection
= PurposeEnableSelected
;
2250 purposeSelection
= PurposeDisableAll
;
2252 else if (CertGetEnhancedKeyUsage(cert
, CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG
,
2255 usage
= HeapAlloc(GetProcessHeap(), 0, size
);
2256 if (!CertGetEnhancedKeyUsage(cert
,
2257 CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG
, usage
, &size
))
2259 HeapFree(GetProcessHeap(), 0, usage
);
2262 else if (usage
->cUsageIdentifier
)
2263 purposeSelection
= PurposeEnableAll
;
2265 purposeSelection
= PurposeDisableAll
;
2269 purposeSelection
= PurposeEnableAll
;
2276 for (i
= 0; i
< usage
->cUsageIdentifier
; i
++)
2278 PCCRYPT_OID_INFO info
= CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY
,
2279 usage
->rgpszUsageIdentifier
[i
], CRYPT_ENHKEY_USAGE_OID_GROUP_ID
);
2282 add_known_usage(lv
, info
);
2284 add_purpose(hwnd
, usage
->rgpszUsageIdentifier
[i
]);
2286 HeapFree(GetProcessHeap(), 0, usage
);
2290 if (WTHelperGetKnownUsages(1, &usages
))
2292 PCCRYPT_OID_INFO
*ptr
;
2294 for (ptr
= usages
; *ptr
; ptr
++)
2295 add_known_usage(lv
, *ptr
);
2296 WTHelperGetKnownUsages(2, &usages
);
2299 select_purposes(hwnd
, purposeSelection
);
2300 SendMessageW(GetDlgItem(hwnd
, IDC_ENABLE_ALL_PURPOSES
+ purposeSelection
),
2304 static void set_general_cert_properties(HWND hwnd
, struct edit_cert_data
*data
)
2306 PCCERT_CONTEXT cert
= data
->cert
;
2309 if ((str
= get_cert_property_as_string(cert
, CERT_FRIENDLY_NAME_PROP_ID
)))
2311 SendMessageW(GetDlgItem(hwnd
, IDC_FRIENDLY_NAME
), WM_SETTEXT
, 0,
2313 HeapFree(GetProcessHeap(), 0, str
);
2315 if ((str
= get_cert_property_as_string(cert
, CERT_DESCRIPTION_PROP_ID
)))
2317 SendMessageW(GetDlgItem(hwnd
, IDC_DESCRIPTION
), WM_SETTEXT
, 0,
2319 HeapFree(GetProcessHeap(), 0, str
);
2321 show_cert_usages(hwnd
, data
);
2324 static void toggle_usage(HWND hwnd
, int iItem
)
2328 HWND lv
= GetDlgItem(hwnd
, IDC_CERTIFICATE_USAGES
);
2330 item
.mask
= LVIF_STATE
;
2333 item
.stateMask
= LVIS_STATEIMAGEMASK
;
2334 res
= SendMessageW(lv
, LVM_GETITEMW
, 0, (LPARAM
)&item
);
2337 int state
= item
.state
>> 12;
2339 item
.state
= INDEXTOSTATEIMAGEMASK(
2340 state
== CheckBitmapIndexChecked
? CheckBitmapIndexUnchecked
:
2341 CheckBitmapIndexChecked
);
2342 SendMessageW(lv
, LVM_SETITEMSTATE
, iItem
, (LPARAM
)&item
);
2346 static void set_cert_string_property(PCCERT_CONTEXT cert
, DWORD prop
,
2349 if (str
&& strlenW(str
))
2351 CRYPT_DATA_BLOB blob
;
2353 blob
.pbData
= (BYTE
*)str
;
2354 blob
.cbData
= (strlenW(str
) + 1) * sizeof(WCHAR
);
2355 CertSetCertificateContextProperty(cert
, prop
, 0, &blob
);
2358 CertSetCertificateContextProperty(cert
, prop
, 0, NULL
);
2361 #define WM_REFRESH_VIEW WM_USER + 0
2363 static BOOL CALLBACK
refresh_propsheet_pages(HWND hwnd
, LPARAM lParam
)
2365 if ((GetClassLongW(hwnd
, GCW_ATOM
) == WC_DIALOG
))
2366 SendMessageW(hwnd
, WM_REFRESH_VIEW
, 0, 0);
2370 #define MAX_FRIENDLY_NAME 40
2371 #define MAX_DESCRIPTION 255
2373 static void apply_general_changes(HWND hwnd
)
2375 WCHAR buf
[MAX_DESCRIPTION
+ 1];
2376 struct edit_cert_data
*data
=
2377 (struct edit_cert_data
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
2379 SendMessageW(GetDlgItem(hwnd
, IDC_FRIENDLY_NAME
), WM_GETTEXT
,
2380 sizeof(buf
) / sizeof(buf
[0]), (LPARAM
)buf
);
2381 set_cert_string_property(data
->cert
, CERT_FRIENDLY_NAME_PROP_ID
, buf
);
2382 SendMessageW(GetDlgItem(hwnd
, IDC_DESCRIPTION
), WM_GETTEXT
,
2383 sizeof(buf
) / sizeof(buf
[0]), (LPARAM
)buf
);
2384 set_cert_string_property(data
->cert
, CERT_DESCRIPTION_PROP_ID
, buf
);
2385 if (IsDlgButtonChecked(hwnd
, IDC_ENABLE_ALL_PURPOSES
))
2387 /* Setting a NULL usage removes the enhanced key usage property. */
2388 CertSetEnhancedKeyUsage(data
->cert
, NULL
);
2390 else if (IsDlgButtonChecked(hwnd
, IDC_DISABLE_ALL_PURPOSES
))
2392 CERT_ENHKEY_USAGE usage
= { 0, NULL
};
2394 CertSetEnhancedKeyUsage(data
->cert
, &usage
);
2396 else if (IsDlgButtonChecked(hwnd
, IDC_ENABLE_SELECTED_PURPOSES
))
2398 HWND lv
= GetDlgItem(hwnd
, IDC_CERTIFICATE_USAGES
);
2399 CERT_ENHKEY_USAGE usage
= { 0, NULL
};
2400 int purposes
= SendMessageW(lv
, LVM_GETITEMCOUNT
, 0, 0), i
;
2403 item
.mask
= LVIF_STATE
| LVIF_PARAM
;
2405 item
.stateMask
= LVIS_STATEIMAGEMASK
;
2406 for (i
= 0; i
< purposes
; i
++)
2409 if (SendMessageW(lv
, LVM_GETITEMW
, 0, (LPARAM
)&item
))
2411 int state
= item
.state
>> 12;
2413 if (state
== CheckBitmapIndexChecked
)
2415 CRYPT_OID_INFO
*info
= (CRYPT_OID_INFO
*)item
.lParam
;
2417 if (usage
.cUsageIdentifier
)
2418 usage
.rgpszUsageIdentifier
=
2419 HeapReAlloc(GetProcessHeap(), 0,
2420 usage
.rgpszUsageIdentifier
,
2421 (usage
.cUsageIdentifier
+ 1) * sizeof(LPSTR
));
2423 usage
.rgpszUsageIdentifier
=
2424 HeapAlloc(GetProcessHeap(), 0, sizeof(LPSTR
));
2425 if (usage
.rgpszUsageIdentifier
)
2426 usage
.rgpszUsageIdentifier
[usage
.cUsageIdentifier
++] =
2427 (LPSTR
)info
->pszOID
;
2431 CertSetEnhancedKeyUsage(data
->cert
, &usage
);
2432 HeapFree(GetProcessHeap(), 0, usage
.rgpszUsageIdentifier
);
2434 EnumChildWindows(GetParent(GetParent(hwnd
)), refresh_propsheet_pages
, 0);
2435 if (data
->pfPropertiesChanged
)
2436 *data
->pfPropertiesChanged
= TRUE
;
2439 static LRESULT CALLBACK
cert_properties_general_dlg_proc(HWND hwnd
, UINT msg
,
2440 WPARAM wp
, LPARAM lp
)
2442 PROPSHEETPAGEW
*page
;
2444 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd
, msg
, wp
, lp
);
2450 HWND description
= GetDlgItem(hwnd
, IDC_DESCRIPTION
);
2451 struct detail_data
*detailData
;
2452 struct edit_cert_data
*editData
;
2454 page
= (PROPSHEETPAGEW
*)lp
;
2455 detailData
= (struct detail_data
*)page
->lParam
;
2456 SendMessageW(GetDlgItem(hwnd
, IDC_FRIENDLY_NAME
), EM_SETLIMITTEXT
,
2457 MAX_FRIENDLY_NAME
, 0);
2458 SendMessageW(description
, EM_SETLIMITTEXT
, MAX_DESCRIPTION
, 0);
2459 ShowScrollBar(description
, SB_VERT
, FALSE
);
2460 editData
= HeapAlloc(GetProcessHeap(), 0,
2461 sizeof(struct edit_cert_data
));
2464 editData
->imageList
= ImageList_Create(16, 16,
2465 ILC_COLOR4
| ILC_MASK
, 4, 0);
2466 if (editData
->imageList
)
2469 COLORREF backColor
= RGB(255, 0, 255);
2471 bmp
= LoadBitmapW(hInstance
, MAKEINTRESOURCEW(IDB_CHECKS
));
2472 ImageList_AddMasked(editData
->imageList
, bmp
, backColor
);
2474 ImageList_SetBkColor(editData
->imageList
, CLR_NONE
);
2476 editData
->cert
= detailData
->pCertViewInfo
->pCertContext
;
2477 editData
->pfPropertiesChanged
= detailData
->pfPropertiesChanged
;
2478 SetWindowLongPtrW(hwnd
, DWLP_USER
, (LPARAM
)editData
);
2479 set_general_cert_properties(hwnd
, editData
);
2485 NMHDR
*hdr
= (NMHDR
*)lp
;
2491 nm
= (NMITEMACTIVATE
*)lp
;
2492 toggle_usage(hwnd
, nm
->iItem
);
2493 SendMessageW(GetParent(hwnd
), PSM_CHANGED
, (WPARAM
)hwnd
, 0);
2496 apply_general_changes(hwnd
);
2505 SendMessageW(GetParent(hwnd
), PSM_CHANGED
, (WPARAM
)hwnd
, 0);
2506 if (LOWORD(wp
) == IDC_DESCRIPTION
)
2508 /* Show/hide scroll bar on description depending on how much
2511 HWND description
= GetDlgItem(hwnd
, IDC_DESCRIPTION
);
2512 int lines
= SendMessageW(description
, EM_GETLINECOUNT
, 0, 0);
2514 ShowScrollBar(description
, SB_VERT
, lines
> 1);
2520 case IDC_ADD_PURPOSE
:
2521 if (DialogBoxParamW(hInstance
,
2522 MAKEINTRESOURCEW(IDD_ADD_CERT_PURPOSE
), hwnd
,
2523 add_purpose_dlg_proc
, (LPARAM
)hwnd
) == IDOK
)
2524 SendMessageW(GetParent(hwnd
), PSM_CHANGED
, (WPARAM
)hwnd
, 0);
2526 case IDC_ENABLE_ALL_PURPOSES
:
2527 case IDC_DISABLE_ALL_PURPOSES
:
2528 case IDC_ENABLE_SELECTED_PURPOSES
:
2529 SendMessageW(GetParent(hwnd
), PSM_CHANGED
, (WPARAM
)hwnd
, 0);
2530 select_purposes(hwnd
, LOWORD(wp
) - IDC_ENABLE_ALL_PURPOSES
);
2540 static UINT CALLBACK
cert_properties_general_callback(HWND hwnd
, UINT msg
,
2541 PROPSHEETPAGEW
*page
)
2545 struct edit_cert_data
*data
;
2550 lv
= GetDlgItem(hwnd
, IDC_CERTIFICATE_USAGES
);
2551 cItem
= SendMessageW(lv
, LVM_GETITEMCOUNT
, 0, 0);
2552 for (i
= 0; i
< cItem
; i
++)
2556 item
.mask
= LVIF_PARAM
;
2559 if (SendMessageW(lv
, LVM_GETITEMW
, 0, (LPARAM
)&item
) && item
.lParam
)
2561 PCRYPT_OID_INFO info
= (PCRYPT_OID_INFO
)item
.lParam
;
2563 if (info
->cbSize
== sizeof(CRYPT_OID_INFO
) && !info
->dwGroupId
)
2565 HeapFree(GetProcessHeap(), 0, (LPSTR
)info
->pszOID
);
2566 HeapFree(GetProcessHeap(), 0, info
);
2570 data
= (struct edit_cert_data
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
2573 ImageList_Destroy(data
->imageList
);
2574 HeapFree(GetProcessHeap(), 0, data
);
2581 static void show_edit_cert_properties_dialog(HWND parent
,
2582 struct detail_data
*data
)
2584 PROPSHEETHEADERW hdr
;
2585 PROPSHEETPAGEW page
; /* FIXME: need to add a cross-certificate page */
2587 TRACE("(%p)\n", data
);
2589 memset(&page
, 0, sizeof(PROPSHEETPAGEW
));
2590 page
.dwSize
= sizeof(page
);
2591 page
.dwFlags
= PSP_USECALLBACK
;
2592 page
.pfnCallback
= cert_properties_general_callback
;
2593 page
.hInstance
= hInstance
;
2594 page
.u
.pszTemplate
= MAKEINTRESOURCEW(IDD_CERT_PROPERTIES_GENERAL
);
2595 page
.pfnDlgProc
= cert_properties_general_dlg_proc
;
2596 page
.lParam
= (LPARAM
)data
;
2598 memset(&hdr
, 0, sizeof(hdr
));
2599 hdr
.dwSize
= sizeof(hdr
);
2600 hdr
.hwndParent
= parent
;
2601 hdr
.dwFlags
= PSH_PROPSHEETPAGE
;
2602 hdr
.hInstance
= hInstance
;
2603 hdr
.pszCaption
= MAKEINTRESOURCEW(IDS_CERTIFICATE_PROPERTIES
);
2604 hdr
.u3
.ppsp
= &page
;
2606 PropertySheetW(&hdr
);
2609 static void free_detail_fields(struct detail_data
*data
)
2613 for (i
= 0; i
< data
->cFields
; i
++)
2614 HeapFree(GetProcessHeap(), 0, data
->fields
[i
].detailed_value
);
2615 HeapFree(GetProcessHeap(), 0, data
->fields
);
2616 data
->fields
= NULL
;
2620 static void refresh_details_view(HWND hwnd
)
2622 HWND cb
= GetDlgItem(hwnd
, IDC_DETAIL_SELECT
);
2624 struct detail_data
*data
;
2626 curSel
= SendMessageW(cb
, CB_GETCURSEL
, 0, 0);
2627 /* Actually, any index will do, since they all store the same data value */
2628 data
= (struct detail_data
*)SendMessageW(cb
, CB_GETITEMDATA
, curSel
, 0);
2629 free_detail_fields(data
);
2630 set_fields_selection(hwnd
, data
, curSel
);
2633 static LRESULT CALLBACK
detail_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wp
,
2636 PROPSHEETPAGEW
*page
;
2637 struct detail_data
*data
;
2639 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd
, msg
, wp
, lp
);
2644 page
= (PROPSHEETPAGEW
*)lp
;
2645 data
= (struct detail_data
*)page
->lParam
;
2646 create_cert_details_list(hwnd
, data
);
2647 if (!(data
->pCertViewInfo
->dwFlags
& CRYPTUI_ENABLE_EDITPROPERTIES
))
2648 EnableWindow(GetDlgItem(hwnd
, IDC_EDITPROPERTIES
), FALSE
);
2649 if (data
->pCertViewInfo
->dwFlags
& CRYPTUI_DISABLE_EXPORT
)
2650 EnableWindow(GetDlgItem(hwnd
, IDC_EXPORT
), FALSE
);
2655 HWND list
= GetDlgItem(hwnd
, IDC_DETAIL_LIST
);
2657 nm
= (NMITEMACTIVATE
*)lp
;
2658 if (nm
->hdr
.hwndFrom
== list
&& nm
->uNewState
& LVN_ITEMACTIVATE
2659 && nm
->hdr
.code
== LVN_ITEMCHANGED
)
2661 data
= (struct detail_data
*)nm
->lParam
;
2662 if (nm
->iItem
>= 0 && data
&& nm
->iItem
< data
->cFields
)
2664 WCHAR buf
[MAX_STRING_LEN
], *val
= NULL
;
2665 HWND valueCtl
= GetDlgItem(hwnd
, IDC_DETAIL_VALUE
);
2667 if (data
->fields
[nm
->iItem
].create
)
2668 val
= data
->fields
[nm
->iItem
].create(
2669 data
->pCertViewInfo
->pCertContext
,
2670 data
->fields
[nm
->iItem
].param
);
2676 item
.cchTextMax
= sizeof(buf
) / sizeof(buf
[0]);
2677 item
.mask
= LVIF_TEXT
;
2679 item
.iItem
= nm
->iItem
;
2681 res
= SendMessageW(list
, LVM_GETITEMW
, 0, (LPARAM
)&item
);
2685 /* Select all the text in the control, the next update will
2688 SendMessageW(valueCtl
, EM_SETSEL
, 0, -1);
2689 add_unformatted_text_to_control(valueCtl
, val
,
2690 val
? strlenW(val
) : 0);
2692 HeapFree(GetProcessHeap(), 0, val
);
2701 FIXME("call CryptUIWizExport\n");
2703 case IDC_EDITPROPERTIES
:
2705 HWND cb
= GetDlgItem(hwnd
, IDC_DETAIL_SELECT
);
2708 curSel
= SendMessageW(cb
, CB_GETCURSEL
, 0, 0);
2709 /* Actually, any index will do, since they all store the same
2712 data
= (struct detail_data
*)SendMessageW(cb
, CB_GETITEMDATA
,
2714 show_edit_cert_properties_dialog(GetParent(hwnd
), data
);
2717 case ((CBN_SELCHANGE
<< 16) | IDC_DETAIL_SELECT
):
2718 refresh_details_view(hwnd
);
2722 case WM_REFRESH_VIEW
:
2723 refresh_details_view(hwnd
);
2729 static UINT CALLBACK
detail_callback(HWND hwnd
, UINT msg
,
2730 PROPSHEETPAGEW
*page
)
2732 struct detail_data
*data
;
2737 data
= (struct detail_data
*)page
->lParam
;
2738 free_detail_fields(data
);
2739 HeapFree(GetProcessHeap(), 0, data
);
2745 static BOOL
init_detail_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
,
2746 BOOL
*pfPropertiesChanged
, PROPSHEETPAGEW
*page
)
2749 struct detail_data
*data
= HeapAlloc(GetProcessHeap(), 0,
2750 sizeof(struct detail_data
));
2754 data
->pCertViewInfo
= pCertViewInfo
;
2755 data
->pfPropertiesChanged
= pfPropertiesChanged
;
2757 data
->fields
= NULL
;
2758 memset(page
, 0, sizeof(PROPSHEETPAGEW
));
2759 page
->dwSize
= sizeof(PROPSHEETPAGEW
);
2760 page
->dwFlags
= PSP_USECALLBACK
;
2761 page
->pfnCallback
= detail_callback
;
2762 page
->hInstance
= hInstance
;
2763 page
->u
.pszTemplate
= MAKEINTRESOURCEW(IDD_DETAIL
);
2764 page
->pfnDlgProc
= detail_dlg_proc
;
2765 page
->lParam
= (LPARAM
)data
;
2773 struct hierarchy_data
2775 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
;
2776 HIMAGELIST imageList
;
2780 static LPARAM
index_to_lparam(struct hierarchy_data
*data
, DWORD index
)
2782 CRYPT_PROVIDER_SGNR
*provSigner
= WTHelperGetProvSignerFromChain(
2783 (CRYPT_PROVIDER_DATA
*)data
->pCertViewInfo
->u
.pCryptProviderData
,
2784 data
->pCertViewInfo
->idxSigner
, data
->pCertViewInfo
->fCounterSigner
,
2785 data
->pCertViewInfo
->idxCounterSigner
);
2787 /* Takes advantage of the fact that a pointer is 32-bit aligned, and
2788 * therefore always even.
2790 if (index
== provSigner
->csCertChain
- 1)
2791 return (LPARAM
)data
;
2792 return index
<< 1 | 1;
2795 static inline DWORD
lparam_to_index(struct hierarchy_data
*data
, LPARAM lp
)
2797 CRYPT_PROVIDER_SGNR
*provSigner
= WTHelperGetProvSignerFromChain(
2798 (CRYPT_PROVIDER_DATA
*)data
->pCertViewInfo
->u
.pCryptProviderData
,
2799 data
->pCertViewInfo
->idxSigner
, data
->pCertViewInfo
->fCounterSigner
,
2800 data
->pCertViewInfo
->idxCounterSigner
);
2803 return provSigner
->csCertChain
- 1;
2807 static struct hierarchy_data
*get_hierarchy_data_from_tree_item(HWND tree
,
2810 struct hierarchy_data
*data
= NULL
;
2811 HTREEITEM root
= NULL
;
2814 HTREEITEM parent
= (HTREEITEM
)SendMessageW(tree
, TVM_GETNEXTITEM
,
2815 TVGN_PARENT
, (LPARAM
)hItem
);
2825 item
.mask
= TVIF_PARAM
;
2827 SendMessageW(tree
, TVM_GETITEMW
, 0, (LPARAM
)&item
);
2828 data
= (struct hierarchy_data
*)item
.lParam
;
2833 static WCHAR
*get_cert_display_name(PCCERT_CONTEXT cert
)
2835 WCHAR
*name
= get_cert_property_as_string(cert
, CERT_FRIENDLY_NAME_PROP_ID
);
2838 name
= get_cert_name_string(cert
, CERT_NAME_SIMPLE_DISPLAY_TYPE
, 0);
2842 static void show_cert_chain(HWND hwnd
, struct hierarchy_data
*data
)
2844 HWND tree
= GetDlgItem(hwnd
, IDC_CERTPATH
);
2845 CRYPT_PROVIDER_SGNR
*provSigner
= WTHelperGetProvSignerFromChain(
2846 (CRYPT_PROVIDER_DATA
*)data
->pCertViewInfo
->u
.pCryptProviderData
,
2847 data
->pCertViewInfo
->idxSigner
, data
->pCertViewInfo
->fCounterSigner
,
2848 data
->pCertViewInfo
->idxCounterSigner
);
2850 HTREEITEM parent
= NULL
;
2852 SendMessageW(tree
, TVM_SETIMAGELIST
, TVSIL_NORMAL
, (LPARAM
)data
->imageList
);
2853 for (i
= provSigner
->csCertChain
; i
; i
--)
2857 name
= get_cert_display_name(provSigner
->pasCertChain
[i
- 1].pCert
);
2860 TVINSERTSTRUCTW tvis
;
2862 tvis
.hParent
= parent
;
2863 tvis
.hInsertAfter
= TVI_LAST
;
2864 tvis
.u
.item
.mask
= TVIF_TEXT
| TVIF_STATE
| TVIF_IMAGE
|
2865 TVIF_SELECTEDIMAGE
| TVIF_PARAM
;
2866 tvis
.u
.item
.pszText
= name
;
2867 tvis
.u
.item
.state
= TVIS_EXPANDED
;
2868 tvis
.u
.item
.stateMask
= TVIS_EXPANDED
;
2870 (provSigner
->pChainContext
->TrustStatus
.dwErrorStatus
&
2871 CERT_TRUST_IS_PARTIAL_CHAIN
))
2873 /* The root of the chain has a special case: if the chain is
2874 * a partial chain, the icon is a warning icon rather than an
2877 tvis
.u
.item
.iImage
= 2;
2879 else if (provSigner
->pasCertChain
[i
- 1].pChainElement
->TrustStatus
.
2881 tvis
.u
.item
.iImage
= 0;
2883 tvis
.u
.item
.iImage
= 1;
2884 tvis
.u
.item
.iSelectedImage
= tvis
.u
.item
.iImage
;
2885 tvis
.u
.item
.lParam
= index_to_lparam(data
, i
- 1);
2886 parent
= (HTREEITEM
)SendMessageW(tree
, TVM_INSERTITEMW
, 0,
2888 HeapFree(GetProcessHeap(), 0, name
);
2893 static void set_certificate_status(HWND hwnd
, CRYPT_PROVIDER_CERT
*cert
)
2895 /* Select all the text in the control, the next update will replace it */
2896 SendMessageW(hwnd
, EM_SETSEL
, 0, -1);
2897 /* Set the highest priority error messages first. */
2898 if (!(cert
->dwConfidence
& CERT_CONFIDENCE_SIG
))
2899 add_string_resource_to_control(hwnd
, IDS_CERTIFICATE_BAD_SIGNATURE
);
2900 else if (!(cert
->dwConfidence
& CERT_CONFIDENCE_TIME
))
2901 add_string_resource_to_control(hwnd
, IDS_CERTIFICATE_BAD_TIME
);
2902 else if (!(cert
->dwConfidence
& CERT_CONFIDENCE_TIMENEST
))
2903 add_string_resource_to_control(hwnd
, IDS_CERTIFICATE_BAD_TIMENEST
);
2904 else if (cert
->dwRevokedReason
)
2905 add_string_resource_to_control(hwnd
, IDS_CERTIFICATE_REVOKED
);
2907 add_string_resource_to_control(hwnd
, IDS_CERTIFICATE_VALID
);
2910 static void set_certificate_status_for_end_cert(HWND hwnd
,
2911 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
)
2913 HWND status
= GetDlgItem(hwnd
, IDC_CERTIFICATESTATUSTEXT
);
2914 CRYPT_PROVIDER_SGNR
*provSigner
= WTHelperGetProvSignerFromChain(
2915 (CRYPT_PROVIDER_DATA
*)pCertViewInfo
->u
.pCryptProviderData
,
2916 pCertViewInfo
->idxSigner
, pCertViewInfo
->fCounterSigner
,
2917 pCertViewInfo
->idxCounterSigner
);
2918 CRYPT_PROVIDER_CERT
*provCert
= WTHelperGetProvCertFromChain(provSigner
,
2919 pCertViewInfo
->idxCert
);
2921 set_certificate_status(status
, provCert
);
2924 static void show_cert_hierarchy(HWND hwnd
, struct hierarchy_data
*data
)
2926 /* Disable view certificate button until a certificate is selected */
2927 EnableWindow(GetDlgItem(hwnd
, IDC_VIEWCERTIFICATE
), FALSE
);
2928 show_cert_chain(hwnd
, data
);
2929 set_certificate_status_for_end_cert(hwnd
, data
->pCertViewInfo
);
2932 static void show_dialog_for_selected_cert(HWND hwnd
)
2934 HWND tree
= GetDlgItem(hwnd
, IDC_CERTPATH
);
2936 struct hierarchy_data
*data
;
2939 memset(&item
, 0, sizeof(item
));
2940 item
.mask
= TVIF_HANDLE
| TVIF_PARAM
;
2941 item
.hItem
= (HTREEITEM
)SendMessageW(tree
, TVM_GETNEXTITEM
, TVGN_CARET
,
2943 SendMessageW(tree
, TVM_GETITEMW
, 0, (LPARAM
)&item
);
2944 data
= get_hierarchy_data_from_tree_item(tree
, item
.hItem
);
2945 selection
= lparam_to_index(data
, item
.lParam
);
2948 CRYPT_PROVIDER_SGNR
*provSigner
;
2949 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo
;
2950 BOOL changed
= FALSE
;
2952 provSigner
= WTHelperGetProvSignerFromChain(
2953 (CRYPT_PROVIDER_DATA
*)data
->pCertViewInfo
->u
.pCryptProviderData
,
2954 data
->pCertViewInfo
->idxSigner
,
2955 data
->pCertViewInfo
->fCounterSigner
,
2956 data
->pCertViewInfo
->idxCounterSigner
);
2957 memset(&viewInfo
, 0, sizeof(viewInfo
));
2958 viewInfo
.dwSize
= sizeof(viewInfo
);
2959 viewInfo
.dwFlags
= data
->pCertViewInfo
->dwFlags
;
2960 viewInfo
.szTitle
= data
->pCertViewInfo
->szTitle
;
2961 viewInfo
.pCertContext
= provSigner
->pasCertChain
[selection
].pCert
;
2962 viewInfo
.cStores
= data
->pCertViewInfo
->cStores
;
2963 viewInfo
.rghStores
= data
->pCertViewInfo
->rghStores
;
2964 viewInfo
.cPropSheetPages
= data
->pCertViewInfo
->cPropSheetPages
;
2965 viewInfo
.rgPropSheetPages
= data
->pCertViewInfo
->rgPropSheetPages
;
2966 viewInfo
.nStartPage
= data
->pCertViewInfo
->nStartPage
;
2967 CryptUIDlgViewCertificateW(&viewInfo
, &changed
);
2970 /* Delete the contents of the tree */
2971 SendMessageW(tree
, TVM_DELETEITEM
, 0, (LPARAM
)TVI_ROOT
);
2972 /* Reinitialize the tree */
2973 show_cert_hierarchy(hwnd
, data
);
2978 static LRESULT CALLBACK
hierarchy_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wp
,
2981 PROPSHEETPAGEW
*page
;
2982 struct hierarchy_data
*data
;
2984 HWND tree
= GetDlgItem(hwnd
, IDC_CERTPATH
);
2986 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd
, msg
, wp
, lp
);
2991 page
= (PROPSHEETPAGEW
*)lp
;
2992 data
= (struct hierarchy_data
*)page
->lParam
;
2993 show_cert_hierarchy(hwnd
, data
);
3002 case TVN_SELCHANGEDW
:
3004 NMTREEVIEWW
*nm
= (NMTREEVIEWW
*)lp
;
3006 CRYPT_PROVIDER_SGNR
*provSigner
;
3008 data
= get_hierarchy_data_from_tree_item(tree
, nm
->itemNew
.hItem
);
3009 selection
= lparam_to_index(data
, nm
->itemNew
.lParam
);
3010 provSigner
= WTHelperGetProvSignerFromChain(
3011 (CRYPT_PROVIDER_DATA
*)data
->pCertViewInfo
->u
.pCryptProviderData
,
3012 data
->pCertViewInfo
->idxSigner
,
3013 data
->pCertViewInfo
->fCounterSigner
,
3014 data
->pCertViewInfo
->idxCounterSigner
);
3015 EnableWindow(GetDlgItem(hwnd
, IDC_VIEWCERTIFICATE
), selection
!= 0);
3016 set_certificate_status(GetDlgItem(hwnd
, IDC_CERTIFICATESTATUSTEXT
),
3017 &provSigner
->pasCertChain
[selection
]);
3021 show_dialog_for_selected_cert(hwnd
);
3022 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, 1);
3031 case IDC_VIEWCERTIFICATE
:
3032 show_dialog_for_selected_cert(hwnd
);
3036 case WM_REFRESH_VIEW
:
3040 /* Get hierarchy data */
3041 memset(&item
, 0, sizeof(item
));
3042 item
.mask
= TVIF_HANDLE
| TVIF_PARAM
;
3043 item
.hItem
= (HTREEITEM
)SendMessageW(tree
, TVM_GETNEXTITEM
, TVGN_ROOT
,
3045 data
= get_hierarchy_data_from_tree_item(tree
, item
.hItem
);
3046 /* Delete the contents of the tree */
3047 SendMessageW(tree
, TVM_DELETEITEM
, 0, (LPARAM
)TVI_ROOT
);
3048 /* Reinitialize the tree */
3049 show_cert_hierarchy(hwnd
, data
);
3056 static UINT CALLBACK
hierarchy_callback(HWND hwnd
, UINT msg
,
3057 PROPSHEETPAGEW
*page
)
3059 struct hierarchy_data
*data
;
3064 data
= (struct hierarchy_data
*)page
->lParam
;
3065 ImageList_Destroy(data
->imageList
);
3066 HeapFree(GetProcessHeap(), 0, data
);
3072 static BOOL
init_hierarchy_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
,
3073 PROPSHEETPAGEW
*page
)
3075 struct hierarchy_data
*data
= HeapAlloc(GetProcessHeap(), 0,
3076 sizeof(struct hierarchy_data
));
3081 data
->imageList
= ImageList_Create(16, 16, ILC_COLOR4
| ILC_MASK
, 2, 0);
3082 if (data
->imageList
)
3085 COLORREF backColor
= RGB(255, 0, 255);
3087 data
->pCertViewInfo
= pCertViewInfo
;
3088 data
->selectedCert
= 0xffffffff;
3090 bmp
= LoadBitmapW(hInstance
, MAKEINTRESOURCEW(IDB_SMALL_ICONS
));
3091 ImageList_AddMasked(data
->imageList
, bmp
, backColor
);
3093 ImageList_SetBkColor(data
->imageList
, CLR_NONE
);
3095 memset(page
, 0, sizeof(PROPSHEETPAGEW
));
3096 page
->dwSize
= sizeof(PROPSHEETPAGEW
);
3097 page
->dwFlags
= PSP_USECALLBACK
;
3098 page
->hInstance
= hInstance
;
3099 page
->u
.pszTemplate
= MAKEINTRESOURCEW(IDD_HIERARCHY
);
3100 page
->pfnDlgProc
= hierarchy_dlg_proc
;
3101 page
->lParam
= (LPARAM
)data
;
3102 page
->pfnCallback
= hierarchy_callback
;
3106 HeapFree(GetProcessHeap(), 0, data
);
3111 static int CALLBACK
cert_prop_sheet_proc(HWND hwnd
, UINT msg
, LPARAM lp
)
3116 TRACE("(%p, %08x, %08lx)\n", hwnd
, msg
, lp
);
3120 case PSCB_INITIALIZED
:
3121 /* Get cancel button's position.. */
3122 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rc
);
3123 topLeft
.x
= rc
.left
;
3125 ScreenToClient(hwnd
, &topLeft
);
3126 /* hide the cancel button.. */
3127 ShowWindow(GetDlgItem(hwnd
, IDCANCEL
), FALSE
);
3128 /* get the OK button's size.. */
3129 GetWindowRect(GetDlgItem(hwnd
, IDOK
), &rc
);
3130 /* and move the OK button to the cancel button's original position. */
3131 MoveWindow(GetDlgItem(hwnd
, IDOK
), topLeft
.x
, topLeft
.y
,
3132 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, FALSE
);
3133 GetWindowRect(GetDlgItem(hwnd
, IDOK
), &rc
);
3139 static BOOL
show_cert_dialog(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
,
3140 CRYPT_PROVIDER_CERT
*provCert
, BOOL
*pfPropertiesChanged
)
3142 static const WCHAR riched
[] = { 'r','i','c','h','e','d','2','0',0 };
3144 PROPSHEETPAGEW
*pages
;
3146 HMODULE lib
= LoadLibraryW(riched
);
3148 nPages
= pCertViewInfo
->cPropSheetPages
+ 1; /* one for the General tab */
3149 if (!(pCertViewInfo
->dwFlags
& CRYPTUI_HIDE_DETAILPAGE
))
3151 if (!(pCertViewInfo
->dwFlags
& CRYPTUI_HIDE_HIERARCHYPAGE
))
3153 pages
= HeapAlloc(GetProcessHeap(), 0, nPages
* sizeof(PROPSHEETPAGEW
));
3156 PROPSHEETHEADERW hdr
;
3157 CRYPTUI_INITDIALOG_STRUCT
*init
= NULL
;
3160 memset(&hdr
, 0, sizeof(hdr
));
3161 hdr
.dwSize
= sizeof(hdr
);
3162 hdr
.dwFlags
= PSH_NOAPPLYNOW
| PSH_PROPSHEETPAGE
| PSH_USECALLBACK
;
3163 hdr
.hInstance
= hInstance
;
3164 if (pCertViewInfo
->szTitle
)
3165 hdr
.pszCaption
= pCertViewInfo
->szTitle
;
3167 hdr
.pszCaption
= MAKEINTRESOURCEW(IDS_CERTIFICATE
);
3168 init_general_page(pCertViewInfo
, &pages
[hdr
.nPages
++]);
3169 if (!(pCertViewInfo
->dwFlags
& CRYPTUI_HIDE_DETAILPAGE
))
3171 if (init_detail_page(pCertViewInfo
, pfPropertiesChanged
,
3172 &pages
[hdr
.nPages
]))
3175 if (!(pCertViewInfo
->dwFlags
& CRYPTUI_HIDE_HIERARCHYPAGE
))
3177 if (init_hierarchy_page(pCertViewInfo
, &pages
[hdr
.nPages
]))
3180 /* Copy each additional page, and create the init dialog struct for it
3182 if (pCertViewInfo
->cPropSheetPages
)
3184 init
= HeapAlloc(GetProcessHeap(), 0,
3185 pCertViewInfo
->cPropSheetPages
*
3186 sizeof(CRYPTUI_INITDIALOG_STRUCT
));
3189 for (i
= 0; i
< pCertViewInfo
->cPropSheetPages
; i
++)
3191 memcpy(&pages
[hdr
.nPages
+ i
],
3192 &pCertViewInfo
->rgPropSheetPages
[i
],
3193 sizeof(PROPSHEETPAGEW
));
3194 init
[i
].lParam
= pCertViewInfo
->rgPropSheetPages
[i
].lParam
;
3195 init
[i
].pCertContext
= pCertViewInfo
->pCertContext
;
3196 pages
[hdr
.nPages
+ i
].lParam
= (LPARAM
)&init
[i
];
3198 if (pCertViewInfo
->nStartPage
& 0x8000)
3200 /* Start page index is relative to the number of default
3203 hdr
.u2
.nStartPage
= pCertViewInfo
->nStartPage
+ hdr
.nPages
;
3206 hdr
.u2
.nStartPage
= pCertViewInfo
->nStartPage
;
3207 hdr
.nPages
= nPages
;
3211 SetLastError(ERROR_OUTOFMEMORY
);
3215 /* Ignore the relative flag if there aren't any additional pages */
3216 hdr
.u2
.nStartPage
= pCertViewInfo
->nStartPage
& 0x7fff;
3223 hdr
.u3
.ppsp
= pages
;
3224 hdr
.pfnCallback
= cert_prop_sheet_proc
;
3225 l
= PropertySheetW(&hdr
);
3228 SetLastError(ERROR_CANCELLED
);
3232 HeapFree(GetProcessHeap(), 0, init
);
3233 HeapFree(GetProcessHeap(), 0, pages
);
3236 SetLastError(ERROR_OUTOFMEMORY
);
3241 /***********************************************************************
3242 * CryptUIDlgViewCertificateW (CRYPTUI.@)
3244 BOOL WINAPI
CryptUIDlgViewCertificateW(
3245 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
, BOOL
*pfPropertiesChanged
)
3247 static GUID generic_cert_verify
= WINTRUST_ACTION_GENERIC_CERT_VERIFY
;
3248 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo
;
3250 WINTRUST_CERT_INFO cert
;
3252 CRYPT_PROVIDER_SGNR
*signer
;
3253 CRYPT_PROVIDER_CERT
*provCert
= NULL
;
3255 TRACE("(%p, %p)\n", pCertViewInfo
, pfPropertiesChanged
);
3257 if (pCertViewInfo
->dwSize
!= sizeof(CRYPTUI_VIEWCERTIFICATE_STRUCTW
))
3259 SetLastError(ERROR_INVALID_PARAMETER
);
3262 /* Make a local copy in case we have to call WinVerifyTrust ourselves */
3263 memcpy(&viewInfo
, pCertViewInfo
, sizeof(viewInfo
));
3264 if (!viewInfo
.u
.hWVTStateData
)
3266 memset(&wvt
, 0, sizeof(wvt
));
3267 wvt
.cbStruct
= sizeof(wvt
);
3268 wvt
.dwUIChoice
= WTD_UI_NONE
;
3269 if (viewInfo
.dwFlags
&
3270 CRYPTUI_ENABLE_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT
)
3271 wvt
.fdwRevocationChecks
|= WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT
;
3272 if (viewInfo
.dwFlags
& CRYPTUI_ENABLE_REVOCATION_CHECK_END_CERT
)
3273 wvt
.fdwRevocationChecks
|= WTD_REVOCATION_CHECK_END_CERT
;
3274 if (viewInfo
.dwFlags
& CRYPTUI_ENABLE_REVOCATION_CHECK_CHAIN
)
3275 wvt
.fdwRevocationChecks
|= WTD_REVOCATION_CHECK_CHAIN
;
3276 wvt
.dwUnionChoice
= WTD_CHOICE_CERT
;
3277 memset(&cert
, 0, sizeof(cert
));
3278 cert
.cbStruct
= sizeof(cert
);
3279 cert
.psCertContext
= (CERT_CONTEXT
*)viewInfo
.pCertContext
;
3280 cert
.chStores
= viewInfo
.cStores
;
3281 cert
.pahStores
= viewInfo
.rghStores
;
3282 wvt
.u
.pCert
= &cert
;
3283 wvt
.dwStateAction
= WTD_STATEACTION_VERIFY
;
3284 WinVerifyTrust(NULL
, &generic_cert_verify
, &wvt
);
3285 viewInfo
.u
.pCryptProviderData
=
3286 WTHelperProvDataFromStateData(wvt
.hWVTStateData
);
3287 signer
= WTHelperGetProvSignerFromChain(
3288 (CRYPT_PROVIDER_DATA
*)viewInfo
.u
.pCryptProviderData
, 0, FALSE
, 0);
3289 provCert
= WTHelperGetProvCertFromChain(signer
, 0);
3294 viewInfo
.u
.pCryptProviderData
=
3295 WTHelperProvDataFromStateData(viewInfo
.u
.hWVTStateData
);
3296 signer
= WTHelperGetProvSignerFromChain(
3297 (CRYPT_PROVIDER_DATA
*)viewInfo
.u
.pCryptProviderData
,
3298 viewInfo
.idxSigner
, viewInfo
.fCounterSigner
,
3299 viewInfo
.idxCounterSigner
);
3300 provCert
= WTHelperGetProvCertFromChain(signer
, viewInfo
.idxCert
);
3305 ret
= show_cert_dialog(&viewInfo
, provCert
, pfPropertiesChanged
);
3306 if (!viewInfo
.u
.hWVTStateData
)
3308 wvt
.dwStateAction
= WTD_STATEACTION_CLOSE
;
3309 WinVerifyTrust(NULL
, &generic_cert_verify
, &wvt
);
3315 /***********************************************************************
3316 * CryptUIDlgViewContext (CRYPTUI.@)
3318 BOOL WINAPI
CryptUIDlgViewContext(DWORD dwContextType
, LPVOID pvContext
,
3319 HWND hwnd
, LPCWSTR pwszTitle
, DWORD dwFlags
, LPVOID pvReserved
)
3323 TRACE("(%d, %p, %p, %s, %08x, %p)\n", dwContextType
, pvContext
, hwnd
,
3324 debugstr_w(pwszTitle
), dwFlags
, pvReserved
);
3326 switch (dwContextType
)
3328 case CERT_STORE_CERTIFICATE_CONTEXT
:
3330 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo
;
3332 memset(&viewInfo
, 0, sizeof(viewInfo
));
3333 viewInfo
.dwSize
= sizeof(viewInfo
);
3334 viewInfo
.hwndParent
= hwnd
;
3335 viewInfo
.szTitle
= pwszTitle
;
3336 viewInfo
.pCertContext
= pvContext
;
3337 ret
= CryptUIDlgViewCertificateW(&viewInfo
, NULL
);
3341 FIXME("unimplemented for context type %d\n", dwContextType
);
3342 SetLastError(E_INVALIDARG
);
3348 static PCCERT_CONTEXT
make_cert_from_file(LPCWSTR fileName
)
3351 DWORD size
, encoding
= X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
;
3353 PCCERT_CONTEXT cert
;
3355 file
= CreateFileW(fileName
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
3356 OPEN_EXISTING
, 0, NULL
);
3357 if (file
== INVALID_HANDLE_VALUE
)
3359 WARN("can't open certificate file %s\n", debugstr_w(fileName
));
3362 if ((size
= GetFileSize(file
, NULL
)))
3364 if ((buffer
= HeapAlloc(GetProcessHeap(), 0, size
)))
3367 if (!ReadFile(file
, buffer
, size
, &read
, NULL
) || read
!= size
)
3369 WARN("can't read certificate file %s\n", debugstr_w(fileName
));
3370 HeapFree(GetProcessHeap(), 0, buffer
);
3378 WARN("empty file %s\n", debugstr_w(fileName
));
3383 cert
= CertCreateCertificateContext(encoding
, buffer
, size
);
3384 HeapFree(GetProcessHeap(), 0, buffer
);
3388 /* Decodes a cert's basic constraints extension (either szOID_BASIC_CONSTRAINTS
3389 * or szOID_BASIC_CONSTRAINTS2, whichever is present) to determine if it
3390 * should be a CA. If neither extension is present, returns
3391 * defaultIfNotSpecified.
3393 static BOOL
is_ca_cert(PCCERT_CONTEXT cert
, BOOL defaultIfNotSpecified
)
3395 BOOL isCA
= defaultIfNotSpecified
;
3396 PCERT_EXTENSION ext
= CertFindExtension(szOID_BASIC_CONSTRAINTS
,
3397 cert
->pCertInfo
->cExtension
, cert
->pCertInfo
->rgExtension
);
3401 CERT_BASIC_CONSTRAINTS_INFO
*info
;
3404 if (CryptDecodeObjectEx(X509_ASN_ENCODING
, szOID_BASIC_CONSTRAINTS
,
3405 ext
->Value
.pbData
, ext
->Value
.cbData
, CRYPT_DECODE_ALLOC_FLAG
,
3406 NULL
, (LPBYTE
)&info
, &size
))
3408 if (info
->SubjectType
.cbData
== 1)
3409 isCA
= info
->SubjectType
.pbData
[0] & CERT_CA_SUBJECT_FLAG
;
3415 ext
= CertFindExtension(szOID_BASIC_CONSTRAINTS2
,
3416 cert
->pCertInfo
->cExtension
, cert
->pCertInfo
->rgExtension
);
3419 CERT_BASIC_CONSTRAINTS2_INFO info
;
3420 DWORD size
= sizeof(CERT_BASIC_CONSTRAINTS2_INFO
);
3422 if (CryptDecodeObjectEx(X509_ASN_ENCODING
,
3423 szOID_BASIC_CONSTRAINTS2
, ext
->Value
.pbData
, ext
->Value
.cbData
,
3424 0, NULL
, &info
, &size
))
3431 static HCERTSTORE
choose_store_for_cert(PCCERT_CONTEXT cert
)
3433 static const WCHAR AddressBook
[] = { 'A','d','d','r','e','s','s',
3434 'B','o','o','k',0 };
3435 static const WCHAR CA
[] = { 'C','A',0 };
3438 if (is_ca_cert(cert
, TRUE
))
3441 storeName
= AddressBook
;
3442 return CertOpenStore(CERT_STORE_PROV_SYSTEM_W
, 0, 0,
3443 CERT_SYSTEM_STORE_CURRENT_USER
, storeName
);
3446 BOOL WINAPI
CryptUIWizImport(DWORD dwFlags
, HWND hwndParent
, LPCWSTR pwszWizardTitle
,
3447 PCCRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc
, HCERTSTORE hDestCertStore
)
3451 const CERT_CONTEXT
*cert
;
3452 BOOL freeCert
= FALSE
;
3454 TRACE("(0x%08x, %p, %s, %p, %p)\n", dwFlags
, hwndParent
, debugstr_w(pwszWizardTitle
),
3455 pImportSrc
, hDestCertStore
);
3457 if (!(dwFlags
& CRYPTUI_WIZ_NO_UI
)) FIXME("UI not implemented\n");
3460 pImportSrc
->dwSize
!= sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO
))
3462 SetLastError(E_INVALIDARG
);
3466 switch (pImportSrc
->dwSubjectChoice
)
3468 case CRYPTUI_WIZ_IMPORT_SUBJECT_FILE
:
3469 if (!(cert
= make_cert_from_file(pImportSrc
->u
.pwszFileName
)))
3471 WARN("unable to create certificate context\n");
3477 case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_CONTEXT
:
3478 cert
= pImportSrc
->u
.pCertContext
;
3481 SetLastError(E_INVALIDARG
);
3486 FIXME("source type not implemented: %u\n", pImportSrc
->dwSubjectChoice
);
3487 SetLastError(E_INVALIDARG
);
3490 if (hDestCertStore
) store
= hDestCertStore
;
3493 if (!(store
= choose_store_for_cert(cert
)))
3495 WARN("unable to open certificate store\n");
3496 CertFreeCertificateContext(cert
);
3500 ret
= CertAddCertificateContextToStore(store
, cert
, CERT_STORE_ADD_REPLACE_EXISTING
, NULL
);
3502 if (!hDestCertStore
) CertCloseStore(store
, 0);
3504 CertFreeCertificateContext(cert
);