cryptui: Return selected store from CryptUIDlgSelectStoreW.
[wine/wine64.git] / dlls / cryptui / main.c
blob442cd19f5656338cdafa555fe8c2a84d6299d3c6
1 /*
2 * Copyright 2008 Juan Lang
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "config.h"
21 #include <stdarg.h>
23 #define COBJMACROS
24 #define NONAMELESSUNION
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winnls.h"
29 #include "winuser.h"
30 #include "softpub.h"
31 #include "wingdi.h"
32 #include "richedit.h"
33 #include "ole2.h"
34 #include "richole.h"
35 #include "commctrl.h"
36 #include "cryptuiapi.h"
37 #include "cryptuires.h"
38 #include "urlmon.h"
39 #include "hlink.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);
51 switch (fdwReason)
53 case DLL_WINE_PREATTACH:
54 return FALSE; /* prefer native version */
55 case DLL_PROCESS_ATTACH:
56 hInstance = hinstDLL;
57 DisableThreadLibraryCalls(hinstDLL);
58 break;
59 case DLL_PROCESS_DETACH:
60 break;
61 default:
62 break;
64 return TRUE;
67 /***********************************************************************
68 * CryptUIDlgCertMgr (CRYPTUI.@)
70 BOOL WINAPI CryptUIDlgCertMgr(PCCRYPTUI_CERT_MGR_STRUCT pCryptUICertMgr)
72 FIXME("(%p): stub\n", pCryptUICertMgr);
73 return FALSE;
76 /* FIXME: real names are unknown, functions are undocumented */
77 typedef struct _CRYPTUI_ENUM_SYSTEM_STORE_ARGS
79 DWORD dwFlags;
80 void *pvSystemStoreLocationPara;
81 } CRYPTUI_ENUM_SYSTEM_STORE_ARGS, *PCRYPTUI_ENUM_SYSTEM_STORE_ARGS;
83 typedef struct _CRYPTUI_ENUM_DATA
85 DWORD cStores;
86 HCERTSTORE *rghStore;
87 DWORD cEnumArgs;
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,
92 void *pvArg);
94 /* Values for dwFlags */
95 #define CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE 0x00000001
97 typedef struct _CRYPTUI_SELECTSTORE_INFO_A
99 DWORD dwSize;
100 HWND parent;
101 DWORD dwFlags;
102 LPSTR pszTitle;
103 LPSTR pszText;
104 CRYPTUI_ENUM_DATA *pEnumData;
105 PFN_SELECTED_STORE_CB pfnSelectedStoreCallback;
106 void *pvArg;
107 } CRYPTUI_SELECTSTORE_INFO_A, *PCRYPTUI_SELECTSTORE_INFO_A;
109 typedef struct _CRYPTUI_SELECTSTORE_INFO_W
111 DWORD dwSize;
112 HWND parent;
113 DWORD dwFlags;
114 LPWSTR pwszTitle;
115 LPWSTR pwszText;
116 CRYPTUI_ENUM_DATA *pEnumData;
117 PFN_SELECTED_STORE_CB pfnSelectedStoreCallback;
118 void *pvArg;
119 } CRYPTUI_SELECTSTORE_INFO_W, *PCRYPTUI_SELECTSTORE_INFO_W;
121 struct StoreInfo
123 enum {
124 StoreHandle,
125 SystemStore
126 } type;
127 union {
128 HCERTSTORE store;
129 LPWSTR name;
130 } DUMMYUNIONNAME;
133 static BOOL WINAPI enum_store_callback(const void *pvSystemStore,
134 DWORD dwFlags, PCERT_SYSTEM_STORE_INFO pStoreInfo, void *pvReserved,
135 void *pvArg)
137 HWND tree = GetDlgItem(pvArg, IDC_STORE_LIST);
138 TVINSERTSTRUCTW tvis;
139 LPCWSTR localizedName;
140 BOOL ret = TRUE;
142 tvis.hParent = NULL;
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));
150 if (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);
161 else
163 HeapFree(GetProcessHeap(), 0, storeInfo);
164 ret = FALSE;
167 else
168 ret = FALSE;
169 tvis.u.item.pszText = (LPWSTR)localizedName;
171 else
172 tvis.u.item.pszText = (LPWSTR)pvSystemStore;
173 /* FIXME: need a folder icon for the store too */
174 if (ret)
175 SendMessageW(tree, TVM_INSERTITEMW, 0, (LPARAM)&tvis);
176 return ret;
179 static void enumerate_stores(HWND hwnd, CRYPTUI_ENUM_DATA *pEnumData)
181 DWORD i;
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++)
190 DWORD size;
192 if (CertGetStoreProperty(pEnumData->rghStore[i],
193 CERT_STORE_LOCALIZED_NAME_PROP_ID, NULL, &size))
195 LPWSTR name = HeapAlloc(GetProcessHeap(), 0, size);
197 if (name)
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));
205 if (storeInfo)
207 TVINSERTSTRUCTW tvis;
209 storeInfo->type = StoreHandle;
210 storeInfo->u.store = pEnumData->rghStore[i];
211 tvis.hParent = NULL;
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,
228 (LPARAM)NULL);
230 while (next)
232 TVITEMW item;
234 memset(&item, 0, sizeof(item));
235 item.mask = TVIF_HANDLE | TVIF_PARAM;
236 item.hItem = next;
237 SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item);
238 if (item.lParam)
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,
247 (LPARAM)next);
251 #define MAX_STRING_LEN 512
253 static HCERTSTORE selected_item_to_store(HWND tree, HTREEITEM hItem)
255 WCHAR buf[MAX_STRING_LEN];
256 TVITEMW item;
257 HCERTSTORE store;
259 memset(&item, 0, sizeof(item));
260 item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_TEXT;
261 item.hItem = hItem;
262 item.cchTextMax = sizeof(buf) / sizeof(buf[0]);
263 item.pszText = buf;
264 SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item);
265 if (item.lParam)
267 struct StoreInfo *storeInfo = (struct StoreInfo *)item.lParam;
269 if (storeInfo->type == StoreHandle)
270 store = storeInfo->u.store;
271 else
272 store = CertOpenSystemStoreW(0, storeInfo->u.name);
274 else
276 /* It's implicitly a system store */
277 store = CertOpenSystemStoreW(0, buf);
279 return store;
282 struct SelectStoreInfo
284 PCRYPTUI_SELECTSTORE_INFO_W info;
285 HCERTSTORE store;
288 static LRESULT CALLBACK select_store_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
289 LPARAM lp)
291 struct SelectStoreInfo *selectInfo;
292 LRESULT ret = 0;
294 switch (msg)
296 case WM_INITDIALOG:
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);
309 break;
311 case WM_COMMAND:
312 switch (wp)
314 case IDOK:
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,
321 DWLP_USER);
322 if (!selection)
324 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN], *pTitle;
326 if (selectInfo->info->pwszTitle)
327 pTitle = selectInfo->info->pwszTitle;
328 else
330 LoadStringW(hInstance, IDS_SELECT_STORE_TITLE, title,
331 sizeof(title) / sizeof(title[0]));
332 pTitle = title;
334 LoadStringW(hInstance, IDS_SELECT_STORE, error,
335 sizeof(error) / sizeof(error[0]));
336 MessageBoxW(hwnd, error, pTitle, MB_ICONEXCLAMATION | MB_OK);
338 else
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);
350 else
351 CertCloseStore(store, 0);
353 ret = TRUE;
354 break;
356 case IDCANCEL:
357 free_store_info(GetDlgItem(hwnd, IDC_STORE_LIST));
358 EndDialog(hwnd, IDCANCEL);
359 ret = TRUE;
360 break;
362 break;
364 return ret;
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);
380 return NULL;
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;
393 HCERTSTORE ret;
394 int len;
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);
402 return NULL;
404 memcpy(&infoW, &info, sizeof(info));
405 if (info->pszTitle)
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,
410 len);
412 if (info->pszText)
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);
421 return ret;
424 /***********************************************************************
425 * CryptUIDlgViewCertificateA (CRYPTUI.@)
427 BOOL WINAPI CryptUIDlgViewCertificateA(
428 PCCRYPTUI_VIEWCERTIFICATE_STRUCTA pCertViewInfo, BOOL *pfPropertiesChanged)
430 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
431 LPWSTR title = NULL;
432 BOOL ret;
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,
440 NULL, 0);
442 title = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
443 if (title)
445 MultiByteToWideChar(CP_ACP, 0, pCertViewInfo->szTitle, -1, title,
446 len);
447 viewInfo.szTitle = title;
449 else
451 ret = FALSE;
452 goto error;
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);
462 error:
463 return ret;
466 struct ReadStringStruct
468 LPCWSTR buf;
469 LONG pos;
470 LONG len;
473 static DWORD CALLBACK read_text_callback(DWORD_PTR dwCookie, LPBYTE buf,
474 LONG cb, LONG *pcb)
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));
482 string->pos += cch;
483 *pcb = cch * sizeof(WCHAR);
484 return 0;
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));
494 string.buf = text;
495 string.pos = 0;
496 string.len = 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)
506 LPWSTR str;
507 LONG len;
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)
523 LPWSTR str;
524 LONG len;
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,
531 DWORD dwFlags)
533 LPWSTR buf = NULL;
534 DWORD len;
536 len = CertGetNameStringW(pCertContext, dwType, dwFlags, NULL, NULL, 0);
537 if (len)
539 buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
540 if (buf)
541 CertGetNameStringW(pCertContext, dwType, dwFlags, NULL, buf, len);
543 return buf;
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);
551 if (name)
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)
563 HRESULT hr;
564 LPRICHEDITOLE richEditOle = NULL;
565 LPOLEOBJECT object = NULL;
566 CLSID clsid;
567 LPOLECACHE oleCache = NULL;
568 FORMATETC formatEtc;
569 DWORD conn;
570 LPDATAOBJECT dataObject = NULL;
571 HBITMAP bitmap = NULL;
572 RECT rect;
573 STGMEDIUM stgm;
574 REOBJECT reObject;
576 TRACE("(%p, %d)\n", hwnd, id);
578 SendMessageW(hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&richEditOle);
579 if (!richEditOle)
580 goto end;
581 hr = OleCreateDefaultHandler(&CLSID_NULL, NULL, &IID_IOleObject,
582 (void**)&object);
583 if (FAILED(hr))
584 goto end;
585 hr = IOleObject_GetUserClassID(object, &clsid);
586 if (FAILED(hr))
587 goto end;
588 hr = IOleObject_QueryInterface(object, &IID_IOleCache, (void**)&oleCache);
589 if (FAILED(hr))
590 goto end;
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);
597 if (FAILED(hr))
598 goto end;
599 hr = IOleObject_QueryInterface(object, &IID_IDataObject,
600 (void**)&dataObject);
601 if (FAILED(hr))
602 goto end;
603 bitmap = LoadImageW(hInstance, MAKEINTRESOURCEW(id), IMAGE_BITMAP, 0, 0,
604 LR_DEFAULTSIZE | LR_LOADTRANSPARENT);
605 if (!bitmap)
606 goto end;
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);
614 if (FAILED(hr))
615 goto end;
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;
626 reObject.dwUser = 0;
628 IRichEditOle_InsertObject(richEditOle, &reObject);
630 end:
631 if (dataObject)
632 IDataObject_Release(dataObject);
633 if (oleCache)
634 IOleCache_Release(oleCache);
635 if (object)
636 IOleObject_Release(object);
637 if (richEditOle)
638 IRichEditOle_Release(richEditOle);
641 #define MY_INDENT 200
643 static void add_oid_text_to_control(HWND hwnd, char *oid)
645 WCHAR nl = '\n';
646 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, oid, 0);
647 PARAFORMAT2 parFmt;
649 parFmt.cbSize = sizeof(parFmt);
650 parFmt.dwMask = PFM_STARTINDENT;
651 parFmt.dxStartIndent = MY_INDENT * 3;
652 if (oidInfo)
654 add_text_with_paraformat_to_control(hwnd, oidInfo->pwszName,
655 lstrlenW(oidInfo->pwszName), &parFmt);
656 add_unformatted_text_to_control(hwnd, &nl, 1);
660 struct OIDToString
662 LPCSTR oid;
663 int id;
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)
734 int cmp;
736 cmp = strcmp(oid, oidMap[i].oid);
737 if (!cmp)
738 ret = &oidMap[i];
739 else if (cmp > 0)
740 indexLow = i + 1;
741 else
742 indexHigh = i - 1;
744 return ret;
747 static void add_local_oid_text_to_control(HWND text, LPCSTR oid)
749 struct OIDToString *entry;
750 WCHAR nl = '\n';
751 PARAFORMAT2 parFmt;
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;
760 int len;
762 len = LoadStringW(hInstance, entry->id, (LPWSTR)&str, 0);
763 ptr = str;
764 do {
765 if ((linebreak = memchrW(ptr, '\n', len)))
767 WCHAR copy[MAX_STRING_LEN];
769 multiline = TRUE;
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
775 * NULL-terminator.
777 lstrcpynW(copy, ptr, linebreak - ptr + 1);
778 add_text_with_paraformat_to_control(text, copy,
779 linebreak - ptr, &parFmt);
780 ptr = linebreak + 1;
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);
790 } while (linebreak);
791 if (!multiline)
793 add_text_with_paraformat_to_control(text, str, len, &parFmt);
794 add_unformatted_text_to_control(text, &nl, 1);
797 else
799 WCHAR *oidW = HeapAlloc(GetProcessHeap(), 0,
800 (strlen(oid) + 1) * sizeof(WCHAR));
802 if (oidW)
804 LPCSTR src;
805 WCHAR *dst;
807 for (src = oid, dst = oidW; *src; src++, dst++)
808 *dst = *src;
809 *dst = 0;
810 add_text_with_paraformat_to_control(text, oidW, lstrlenW(oidW),
811 &parFmt);
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,
819 BOOL *anyUsageAdded)
821 static char any_app_policy[] = szOID_ANY_APPLICATION_POLICY;
822 WCHAR nl = '\n';
823 CHARFORMATW charFmt;
824 PCERT_EXTENSION policyExt;
825 if (!*anyUsageAdded)
827 PARAFORMAT2 parFmt;
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;
846 DWORD size;
848 if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_POLICIES,
849 policyExt->Value.pbData, policyExt->Value.cbData,
850 CRYPT_DECODE_ALLOC_FLAG, NULL, &policies, &size))
852 DWORD i;
854 for (i = 0; i < policies->cPolicyInfo; i++)
856 DWORD j;
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);
863 LocalFree(policies);
866 else
867 add_oid_text_to_control(text, any_app_policy);
870 static BOOL display_cert_usages(HWND text, PCCERT_CONTEXT cert,
871 BOOL *anyUsageAdded)
873 WCHAR nl = '\n';
874 DWORD size;
875 BOOL badUsages = FALSE;
877 if (CertGetEnhancedKeyUsage(cert, 0, NULL, &size))
879 CHARFORMATW charFmt;
880 static char any_cert_policy[] = szOID_ANY_CERT_POLICY;
881 PCERT_ENHKEY_USAGE usage = HeapAlloc(GetProcessHeap(), 0, size);
883 if (usage)
885 if (CertGetEnhancedKeyUsage(cert, 0, usage, &size))
887 DWORD i;
889 if (!*anyUsageAdded)
891 PARAFORMAT2 parFmt;
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,
906 (LPARAM)&charFmt);
907 if (!usage->cUsageIdentifier)
908 add_oid_text_to_control(text, any_cert_policy);
909 else
910 for (i = 0; i < usage->cUsageIdentifier; i++)
911 add_local_oid_text_to_control(text,
912 usage->rgpszUsageIdentifier[i]);
914 else
915 badUsages = TRUE;
916 HeapFree(GetProcessHeap(), 0, usage);
918 else
919 badUsages = TRUE;
921 else
922 badUsages = TRUE;
923 return badUsages;
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)
934 DWORD i;
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;
943 else
944 badUsages = TRUE;
947 else
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,
953 &anyUsageAdded);
954 if (badUsages)
956 PARAFORMAT2 parFmt;
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,
967 LPCSTR policyOid)
969 CRYPT_OBJID_BLOB *ret = NULL;
970 DWORD i;
972 for (i = 0; !ret && i < policies->cPolicyInfo; i++)
974 DWORD j;
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].
980 Qualifier;
982 return ret;
985 static WCHAR *get_cps_str_from_qualifier(CRYPT_OBJID_BLOB *qualifier)
987 LPWSTR qualifierStr = NULL;
988 CERT_NAME_VALUE *qualifierValue;
989 DWORD size;
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));
998 if (qualifierStr)
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)
1008 LPWSTR str = NULL;
1009 CERT_POLICY_QUALIFIER_USER_NOTICE *qualifierValue;
1010 DWORD size;
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));
1019 if (str)
1020 strcpyW(str, qualifierValue->pszDisplayText);
1021 LocalFree(qualifierValue);
1023 return str;
1026 struct IssuerStatement
1028 LPWSTR cps;
1029 LPWSTR userNotice;
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;
1043 DWORD size;
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;
1081 PARAFORMAT2 parFmt;
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);
1097 else
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);
1127 else
1128 add_string_resource_with_paraformat_to_control(text,
1129 IDS_CERT_INFO_UNTRUSTED_ROOT, &parFmt);
1131 else
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)
1141 WCHAR nl = '\n';
1142 HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_NAMES);
1143 CHARFORMATW charFmt;
1144 PARAFORMAT2 parFmt;
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,
1158 nameFlags);
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 */
1168 WCHAR date[80];
1169 SYSTEMTIME sysTime;
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)
1181 WCHAR nl = '\n';
1182 HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_NAMES);
1183 CHARFORMATW charFmt;
1184 PARAFORMAT2 parFmt;
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,
1195 &parFmt);
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,
1220 LPARAM lp)
1222 LRESULT ret = 0;
1223 HWND text;
1224 struct IssuerStatement *issuerStatement;
1226 switch (msg)
1228 case WM_INITDIALOG:
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);
1235 else
1236 EnableWindow(GetDlgItem(hwnd, IDC_CPS), FALSE);
1237 break;
1238 case WM_COMMAND:
1239 switch (wp)
1241 case IDOK:
1242 EndDialog(hwnd, IDOK);
1243 ret = TRUE;
1244 break;
1245 case IDC_CPS:
1247 IBindCtx *bctx = NULL;
1248 LPWSTR cps;
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);
1255 break;
1259 return ret;
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,
1269 LPARAM lp)
1271 PROPSHEETPAGEW *page;
1272 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo;
1274 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
1276 switch (msg)
1278 case WM_INITDIALOG:
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);
1285 break;
1286 case WM_COMMAND:
1287 switch (wp)
1289 case IDC_ADDTOSTORE:
1290 FIXME("call CryptUIWizImport\n");
1291 break;
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);
1311 break;
1314 break;
1316 return 0;
1319 static UINT CALLBACK general_callback_proc(HWND hwnd, UINT msg,
1320 PROPSHEETPAGEW *page)
1322 struct IssuerStatement *issuerStatement;
1324 switch (msg)
1326 case PSPCB_RELEASE:
1327 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);
1335 break;
1337 return 1;
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));
1360 if (buf)
1361 sprintfW(buf, fmt, cert->pCertInfo->dwVersion);
1362 return buf;
1365 static WCHAR *format_hex_string(void *pb, DWORD cb)
1367 WCHAR *buf = HeapAlloc(GetProcessHeap(), 0, (cb * 3 + 1) * sizeof(WCHAR));
1369 if (buf)
1371 static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
1372 DWORD i;
1373 WCHAR *ptr;
1375 for (i = 0, ptr = buf; i < cb; i++, ptr += 3)
1376 sprintfW(ptr, fmt, ((BYTE *)pb)[i]);
1378 return buf;
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)
1395 WCHAR *str = NULL;
1396 DWORD len = CertNameToStrW(X509_ASN_ENCODING, name,
1397 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, NULL, 0);
1399 if (len)
1401 str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1402 if (str)
1403 CertNameToStrW(X509_ASN_ENCODING, name,
1404 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, str, len);
1406 return str;
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 */
1427 DWORD len;
1428 WCHAR *buf = NULL;
1429 SYSTEMTIME sysTime;
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);
1436 if (len)
1438 buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1439 if (buf)
1440 GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, buf,
1441 len);
1443 return 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;
1459 WCHAR *buf = NULL;
1461 oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
1462 cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, 0);
1463 if (oidInfo)
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)
1482 * sizeof(WCHAR));
1483 if (buf)
1484 sprintfW(buf, fmt, oidInfo->pwszName,
1485 CertGetPublicKeyLength(X509_ASN_ENCODING,
1486 &cert->pCertInfo->SubjectPublicKeyInfo));
1489 return buf;
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;
1500 struct detail_data
1502 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo;
1503 BOOL *pfPropertiesChanged;
1504 int cFields;
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;
1516 void *param;
1519 static void add_field_value_data(struct detail_data *data,
1520 create_detailed_value_func create, void *param)
1522 if (data->cFields)
1523 data->fields = HeapReAlloc(GetProcessHeap(), 0, data->fields,
1524 (data->cFields + 1) * sizeof(struct field_value_data));
1525 else
1526 data->fields = HeapAlloc(GetProcessHeap(), 0,
1527 sizeof(struct field_value_data));
1528 if (data->fields)
1530 data->fields[data->cFields].create = create;
1531 data->fields[data->cFields].detailed_value = NULL;
1532 data->fields[data->cFields].param = param;
1533 data->cFields++;
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)
1540 LVITEMW item;
1541 int iItem = SendMessageW(hwnd, LVM_GETITEMCOUNT, 0, 0);
1543 item.mask = LVIF_TEXT | LVIF_PARAM;
1544 item.iItem = iItem;
1545 item.iSubItem = 0;
1546 item.pszText = field;
1547 item.lParam = (LPARAM)data;
1548 SendMessageW(hwnd, LVM_INSERTITEMW, 0, (LPARAM)&item);
1549 if (value)
1551 item.pszText = value;
1552 item.iSubItem = 1;
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);
1567 struct v1_field
1569 int id;
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);
1579 if (val)
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)
1600 int i;
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)
1614 WCHAR *str = NULL;
1615 DWORD size;
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);
1624 return str;
1627 static WCHAR *field_format_extension_hex_with_ascii(PCERT_EXTENSION ext)
1629 WCHAR *str = NULL;
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
1639 * bytes:
1640 * 0x30,0x14,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x03,
1641 * 0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67
1642 * is output as:
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));
1657 if (str)
1659 static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
1660 DWORD i, j;
1661 WCHAR *ptr;
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
1679 *ptr++ = ' ';
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];
1686 else
1687 *ptr = '.';
1689 *ptr++ = '\n';
1691 *ptr++ = '\0';
1694 return str;
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);
1703 if (!str)
1704 str = field_format_extension_hex_with_ascii(ext);
1705 return str;
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,
1712 ext->pszObjId, 0);
1713 LPWSTR val = crypt_format_extension(ext, 0);
1715 if (oidInfo)
1716 add_field_and_value_to_list(hwnd, data, (LPWSTR)oidInfo->pwszName,
1717 val, field_format_detailed_extension, ext);
1718 else
1720 DWORD len = strlen(ext->pszObjId);
1721 LPWSTR oidW = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1723 if (oidW)
1725 DWORD i;
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)
1739 DWORD i;
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)
1748 DWORD i;
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
1761 DWORD prop;
1762 int 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)
1769 CERT_EXTENSION ext;
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)
1791 DWORD i;
1792 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
1794 for (i = 0; i < sizeof(prop_id_map) / sizeof(prop_id_map[0]); i++)
1796 DWORD cb;
1798 if (CertGetCertificateContextProperty(cert, prop_id_map[i].prop, NULL,
1799 &cb))
1801 BYTE *pb;
1802 WCHAR *val = NULL;
1804 /* FIXME: MS adds a separate value for the signature hash
1805 * algorithm.
1807 pb = HeapAlloc(GetProcessHeap(), 0, cb);
1808 if (pb)
1810 if (CertGetCertificateContextProperty(cert,
1811 prop_id_map[i].prop, pb, &cb))
1813 if (prop_id_map[i].prop_is_string)
1815 val = (LPWSTR)pb;
1816 /* Don't double-free pb */
1817 pb = NULL;
1819 else
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,
1825 NULL, NULL);
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
1839 int id;
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];
1855 int i;
1857 for (i = 0; i < sizeof(listItems) / sizeof(listItems[0]); i++)
1859 int index;
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);
1872 RECT rc;
1873 WCHAR buf[MAX_STRING_LEN];
1874 LVCOLUMNW column;
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);
1905 typedef enum {
1906 CheckBitmapIndexUnchecked = 1,
1907 CheckBitmapIndexChecked = 2,
1908 CheckBitmapIndexDisabledUnchecked = 3,
1909 CheckBitmapIndexDisabledChecked = 4
1910 } CheckBitmapIndex;
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));
1918 if (info)
1920 char *oidCopy = HeapAlloc(GetProcessHeap(), 0, strlen(oid) + 1);
1922 if (oidCopy)
1924 LVITEMA item;
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);
1933 item.iSubItem = 0;
1934 item.lParam = (LPARAM)info;
1935 item.pszText = oidCopy;
1936 SendMessageA(lv, LVM_INSERTITEMA, 0, (LPARAM)&item);
1938 else
1939 HeapFree(GetProcessHeap(), 0, info);
1943 static BOOL is_valid_oid(LPCSTR oid)
1945 BOOL ret;
1947 if (oid[0] != '0' && oid[0] != '1' && oid[0] != '2')
1948 ret = FALSE;
1949 else if (oid[1] != '.')
1950 ret = FALSE;
1951 else if (!oid[2])
1952 ret = FALSE;
1953 else
1955 const char *ptr;
1956 BOOL expectNum = TRUE;
1958 for (ptr = oid + 2, ret = TRUE; ret && *ptr; ptr++)
1960 if (expectNum)
1962 if (!isdigit(*ptr))
1963 ret = FALSE;
1964 else if (*(ptr + 1) == '.')
1965 expectNum = FALSE;
1967 else
1969 if (*ptr != '.')
1970 ret = FALSE;
1971 else if (!(*(ptr + 1)))
1972 ret = FALSE;
1973 else
1974 expectNum = TRUE;
1978 return ret;
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);
1986 BOOL ret = FALSE;
1988 if (oidInfo)
1990 LVFINDINFOW findInfo;
1992 findInfo.flags = LVFI_PARAM;
1993 findInfo.lParam = (LPARAM)oidInfo;
1994 if (SendMessageW(lv, LVM_FINDITEMW, -1, (LPARAM)&findInfo) != -1)
1995 ret = TRUE;
1997 else
1999 LVFINDINFOA findInfo;
2001 findInfo.flags = LVFI_STRING;
2002 findInfo.psz = oid;
2003 if (SendMessageW(lv, LVM_FINDITEMA, -1, (LPARAM)&findInfo) != -1)
2004 ret = TRUE;
2006 return ret;
2009 #define MAX_PURPOSE 255
2011 static LRESULT CALLBACK add_purpose_dlg_proc(HWND hwnd, UINT msg,
2012 WPARAM wp, LPARAM lp)
2014 LRESULT ret = 0;
2015 char buf[MAX_PURPOSE + 1];
2017 switch (msg)
2019 case WM_INITDIALOG:
2020 SendMessageW(GetDlgItem(hwnd, IDC_NEW_PURPOSE), EM_SETLIMITTEXT,
2021 MAX_PURPOSE, 0);
2022 ShowScrollBar(GetDlgItem(hwnd, IDC_NEW_PURPOSE), SB_VERT, FALSE);
2023 SetWindowLongPtrW(hwnd, DWLP_USER, lp);
2024 break;
2025 case WM_COMMAND:
2026 switch (HIWORD(wp))
2028 case EN_CHANGE:
2029 if (LOWORD(wp) == IDC_NEW_PURPOSE)
2031 /* Show/hide scroll bar on description depending on how much
2032 * text it has.
2034 HWND description = GetDlgItem(hwnd, IDC_NEW_PURPOSE);
2035 int lines = SendMessageW(description, EM_GETLINECOUNT, 0, 0);
2037 ShowScrollBar(description, SB_VERT, lines > 1);
2039 break;
2040 case BN_CLICKED:
2041 switch (LOWORD(wp))
2043 case IDOK:
2044 SendMessageA(GetDlgItem(hwnd, IDC_NEW_PURPOSE), WM_GETTEXT,
2045 sizeof(buf) / sizeof(buf[0]), (LPARAM)buf);
2046 if (!buf[0])
2048 /* An empty purpose is the same as cancelling */
2049 EndDialog(hwnd, IDCANCEL);
2050 ret = TRUE;
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);
2073 else
2075 HWND parent = (HWND)GetWindowLongPtrW(hwnd, DWLP_USER);
2077 add_purpose(parent, buf);
2078 EndDialog(hwnd, wp);
2079 ret = TRUE;
2081 break;
2082 case IDCANCEL:
2083 EndDialog(hwnd, wp);
2084 ret = TRUE;
2085 break;
2087 break;
2089 break;
2091 return ret;
2094 static WCHAR *get_cert_property_as_string(PCCERT_CONTEXT cert, DWORD prop)
2096 WCHAR *name = NULL;
2097 DWORD cb;
2099 if (CertGetCertificateContextProperty(cert, prop, NULL, &cb))
2101 name = HeapAlloc(GetProcessHeap(), 0, cb);
2102 if (name)
2104 if (!CertGetCertificateContextProperty(cert, prop, (LPBYTE)name,
2105 &cb))
2107 HeapFree(GetProcessHeap(), 0, name);
2108 name = NULL;
2112 return 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;
2122 int state;
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.
2128 state >>= 12;
2129 if (enabled)
2131 if (state == CheckBitmapIndexDisabledChecked)
2133 state = CheckBitmapIndexChecked;
2134 change = TRUE;
2136 if (state == CheckBitmapIndexDisabledUnchecked)
2138 state = CheckBitmapIndexUnchecked;
2139 change = TRUE;
2142 else
2144 if (state == CheckBitmapIndexChecked)
2146 state = CheckBitmapIndexDisabledChecked;
2147 change = TRUE;
2149 if (state == CheckBitmapIndexUnchecked)
2151 state = CheckBitmapIndexDisabledUnchecked;
2152 change = TRUE;
2155 if (change)
2157 LVITEMW item;
2159 item.state = INDEXTOSTATEIMAGEMASK(state);
2160 item.stateMask = LVIS_STATEIMAGEMASK;
2161 SendMessageW(list, LVM_SETITEMSTATE, i, (LPARAM)&item);
2166 typedef enum {
2167 PurposeEnableAll = 0,
2168 PurposeDisableAll,
2169 PurposeEnableSelected
2170 } PurposeSelection;
2172 static void select_purposes(HWND hwnd, PurposeSelection selection)
2174 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
2176 switch (selection)
2178 case PurposeEnableAll:
2179 case PurposeDisableAll:
2180 EnableWindow(lv, FALSE);
2181 redraw_states(lv, FALSE);
2182 EnableWindow(GetDlgItem(hwnd, IDC_ADD_PURPOSE), FALSE);
2183 break;
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)
2196 LVITEMW item;
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);
2202 item.iSubItem = 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;
2220 DWORD size;
2221 PCCRYPT_OID_INFO *usages;
2222 RECT rc;
2223 LVCOLUMNW column;
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,
2238 NULL, &size))
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);
2245 usage = NULL;
2247 else if (usage->cUsageIdentifier)
2248 purposeSelection = PurposeEnableSelected;
2249 else
2250 purposeSelection = PurposeDisableAll;
2252 else if (CertGetEnhancedKeyUsage(cert, CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
2253 NULL, &size))
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);
2260 usage = NULL;
2262 else if (usage->cUsageIdentifier)
2263 purposeSelection = PurposeEnableAll;
2264 else
2265 purposeSelection = PurposeDisableAll;
2267 else
2269 purposeSelection = PurposeEnableAll;
2270 usage = NULL;
2272 if (usage)
2274 DWORD i;
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);
2281 if (info)
2282 add_known_usage(lv, info);
2283 else
2284 add_purpose(hwnd, usage->rgpszUsageIdentifier[i]);
2286 HeapFree(GetProcessHeap(), 0, usage);
2288 else
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),
2301 BM_CLICK, 0, 0);
2304 static void set_general_cert_properties(HWND hwnd, struct edit_cert_data *data)
2306 PCCERT_CONTEXT cert = data->cert;
2307 WCHAR *str;
2309 if ((str = get_cert_property_as_string(cert, CERT_FRIENDLY_NAME_PROP_ID)))
2311 SendMessageW(GetDlgItem(hwnd, IDC_FRIENDLY_NAME), WM_SETTEXT, 0,
2312 (LPARAM)str);
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,
2318 (LPARAM)str);
2319 HeapFree(GetProcessHeap(), 0, str);
2321 show_cert_usages(hwnd, data);
2324 static void toggle_usage(HWND hwnd, int iItem)
2326 LVITEMW item;
2327 int res;
2328 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
2330 item.mask = LVIF_STATE;
2331 item.iItem = iItem;
2332 item.iSubItem = 0;
2333 item.stateMask = LVIS_STATEIMAGEMASK;
2334 res = SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item);
2335 if (res)
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,
2347 LPWSTR str)
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);
2357 else
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);
2367 return TRUE;
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;
2401 LVITEMW item;
2403 item.mask = LVIF_STATE | LVIF_PARAM;
2404 item.iSubItem = 0;
2405 item.stateMask = LVIS_STATEIMAGEMASK;
2406 for (i = 0; i < purposes; i++)
2408 item.iItem = 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));
2422 else
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);
2446 switch (msg)
2448 case WM_INITDIALOG:
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));
2462 if (editData)
2464 editData->imageList = ImageList_Create(16, 16,
2465 ILC_COLOR4 | ILC_MASK, 4, 0);
2466 if (editData->imageList)
2468 HBITMAP bmp;
2469 COLORREF backColor = RGB(255, 0, 255);
2471 bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_CHECKS));
2472 ImageList_AddMasked(editData->imageList, bmp, backColor);
2473 DeleteObject(bmp);
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);
2481 break;
2483 case WM_NOTIFY:
2485 NMHDR *hdr = (NMHDR *)lp;
2486 NMITEMACTIVATE *nm;
2488 switch (hdr->code)
2490 case NM_CLICK:
2491 nm = (NMITEMACTIVATE *)lp;
2492 toggle_usage(hwnd, nm->iItem);
2493 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
2494 break;
2495 case PSN_APPLY:
2496 apply_general_changes(hwnd);
2497 break;
2499 break;
2501 case WM_COMMAND:
2502 switch (HIWORD(wp))
2504 case EN_CHANGE:
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
2509 * text it has.
2511 HWND description = GetDlgItem(hwnd, IDC_DESCRIPTION);
2512 int lines = SendMessageW(description, EM_GETLINECOUNT, 0, 0);
2514 ShowScrollBar(description, SB_VERT, lines > 1);
2516 break;
2517 case BN_CLICKED:
2518 switch (LOWORD(wp))
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);
2525 break;
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);
2531 break;
2533 break;
2535 break;
2537 return 0;
2540 static UINT CALLBACK cert_properties_general_callback(HWND hwnd, UINT msg,
2541 PROPSHEETPAGEW *page)
2543 HWND lv;
2544 int cItem, i;
2545 struct edit_cert_data *data;
2547 switch (msg)
2549 case PSPCB_RELEASE:
2550 lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
2551 cItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
2552 for (i = 0; i < cItem; i++)
2554 LVITEMW item;
2556 item.mask = LVIF_PARAM;
2557 item.iItem = i;
2558 item.iSubItem = 0;
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);
2571 if (data)
2573 ImageList_Destroy(data->imageList);
2574 HeapFree(GetProcessHeap(), 0, data);
2576 break;
2578 return 1;
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;
2605 hdr.nPages = 1;
2606 PropertySheetW(&hdr);
2609 static void free_detail_fields(struct detail_data *data)
2611 DWORD i;
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;
2617 data->cFields = 0;
2620 static void refresh_details_view(HWND hwnd)
2622 HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT);
2623 int curSel;
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,
2634 LPARAM lp)
2636 PROPSHEETPAGEW *page;
2637 struct detail_data *data;
2639 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
2641 switch (msg)
2643 case WM_INITDIALOG:
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);
2651 break;
2652 case WM_NOTIFY:
2654 NMITEMACTIVATE *nm;
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);
2671 else
2673 LVITEMW item;
2674 int res;
2676 item.cchTextMax = sizeof(buf) / sizeof(buf[0]);
2677 item.mask = LVIF_TEXT;
2678 item.pszText = buf;
2679 item.iItem = nm->iItem;
2680 item.iSubItem = 1;
2681 res = SendMessageW(list, LVM_GETITEMW, 0, (LPARAM)&item);
2682 if (res)
2683 val = buf;
2685 /* Select all the text in the control, the next update will
2686 * replace it
2688 SendMessageW(valueCtl, EM_SETSEL, 0, -1);
2689 add_unformatted_text_to_control(valueCtl, val,
2690 val ? strlenW(val) : 0);
2691 if (val != buf)
2692 HeapFree(GetProcessHeap(), 0, val);
2695 break;
2697 case WM_COMMAND:
2698 switch (wp)
2700 case IDC_EXPORT:
2701 FIXME("call CryptUIWizExport\n");
2702 break;
2703 case IDC_EDITPROPERTIES:
2705 HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT);
2706 int curSel;
2708 curSel = SendMessageW(cb, CB_GETCURSEL, 0, 0);
2709 /* Actually, any index will do, since they all store the same
2710 * data value
2712 data = (struct detail_data *)SendMessageW(cb, CB_GETITEMDATA,
2713 curSel, 0);
2714 show_edit_cert_properties_dialog(GetParent(hwnd), data);
2715 break;
2717 case ((CBN_SELCHANGE << 16) | IDC_DETAIL_SELECT):
2718 refresh_details_view(hwnd);
2719 break;
2721 break;
2722 case WM_REFRESH_VIEW:
2723 refresh_details_view(hwnd);
2724 break;
2726 return 0;
2729 static UINT CALLBACK detail_callback(HWND hwnd, UINT msg,
2730 PROPSHEETPAGEW *page)
2732 struct detail_data *data;
2734 switch (msg)
2736 case PSPCB_RELEASE:
2737 data = (struct detail_data *)page->lParam;
2738 free_detail_fields(data);
2739 HeapFree(GetProcessHeap(), 0, data);
2740 break;
2742 return 0;
2745 static BOOL init_detail_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
2746 BOOL *pfPropertiesChanged, PROPSHEETPAGEW *page)
2748 BOOL ret;
2749 struct detail_data *data = HeapAlloc(GetProcessHeap(), 0,
2750 sizeof(struct detail_data));
2752 if (data)
2754 data->pCertViewInfo = pCertViewInfo;
2755 data->pfPropertiesChanged = pfPropertiesChanged;
2756 data->cFields = 0;
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;
2766 ret = TRUE;
2768 else
2769 ret = FALSE;
2770 return ret;
2773 struct hierarchy_data
2775 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo;
2776 HIMAGELIST imageList;
2777 DWORD selectedCert;
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);
2802 if (!(lp & 1))
2803 return provSigner->csCertChain - 1;
2804 return lp >> 1;
2807 static struct hierarchy_data *get_hierarchy_data_from_tree_item(HWND tree,
2808 HTREEITEM hItem)
2810 struct hierarchy_data *data = NULL;
2811 HTREEITEM root = NULL;
2813 do {
2814 HTREEITEM parent = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM,
2815 TVGN_PARENT, (LPARAM)hItem);
2817 if (!parent)
2818 root = hItem;
2819 hItem = parent;
2820 } while (hItem);
2821 if (root)
2823 TVITEMW item;
2825 item.mask = TVIF_PARAM;
2826 item.hItem = root;
2827 SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item);
2828 data = (struct hierarchy_data *)item.lParam;
2830 return data;
2833 static WCHAR *get_cert_display_name(PCCERT_CONTEXT cert)
2835 WCHAR *name = get_cert_property_as_string(cert, CERT_FRIENDLY_NAME_PROP_ID);
2837 if (!name)
2838 name = get_cert_name_string(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0);
2839 return name;
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);
2849 DWORD i;
2850 HTREEITEM parent = NULL;
2852 SendMessageW(tree, TVM_SETIMAGELIST, TVSIL_NORMAL, (LPARAM)data->imageList);
2853 for (i = provSigner->csCertChain; i; i--)
2855 LPWSTR name;
2857 name = get_cert_display_name(provSigner->pasCertChain[i - 1].pCert);
2858 if (name)
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;
2869 if (i == 1 &&
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
2875 * error icon.
2877 tvis.u.item.iImage = 2;
2879 else if (provSigner->pasCertChain[i - 1].pChainElement->TrustStatus.
2880 dwErrorStatus == 0)
2881 tvis.u.item.iImage = 0;
2882 else
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,
2887 (LPARAM)&tvis);
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);
2906 else
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);
2935 TVITEMW item;
2936 struct hierarchy_data *data;
2937 DWORD selection;
2939 memset(&item, 0, sizeof(item));
2940 item.mask = TVIF_HANDLE | TVIF_PARAM;
2941 item.hItem = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM, TVGN_CARET,
2942 (LPARAM)NULL);
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);
2946 if (selection != 0)
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);
2968 if (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,
2979 LPARAM lp)
2981 PROPSHEETPAGEW *page;
2982 struct hierarchy_data *data;
2983 LRESULT ret = 0;
2984 HWND tree = GetDlgItem(hwnd, IDC_CERTPATH);
2986 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
2988 switch (msg)
2990 case WM_INITDIALOG:
2991 page = (PROPSHEETPAGEW *)lp;
2992 data = (struct hierarchy_data *)page->lParam;
2993 show_cert_hierarchy(hwnd, data);
2994 break;
2995 case WM_NOTIFY:
2997 NMHDR *hdr;
2999 hdr = (NMHDR *)lp;
3000 switch (hdr->code)
3002 case TVN_SELCHANGEDW:
3004 NMTREEVIEWW *nm = (NMTREEVIEWW*)lp;
3005 DWORD selection;
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]);
3018 break;
3020 case NM_DBLCLK:
3021 show_dialog_for_selected_cert(hwnd);
3022 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
3023 ret = 1;
3024 break;
3026 break;
3028 case WM_COMMAND:
3029 switch (wp)
3031 case IDC_VIEWCERTIFICATE:
3032 show_dialog_for_selected_cert(hwnd);
3033 break;
3035 break;
3036 case WM_REFRESH_VIEW:
3038 TVITEMW item;
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,
3044 (LPARAM)NULL);
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);
3050 break;
3053 return ret;
3056 static UINT CALLBACK hierarchy_callback(HWND hwnd, UINT msg,
3057 PROPSHEETPAGEW *page)
3059 struct hierarchy_data *data;
3061 switch (msg)
3063 case PSPCB_RELEASE:
3064 data = (struct hierarchy_data *)page->lParam;
3065 ImageList_Destroy(data->imageList);
3066 HeapFree(GetProcessHeap(), 0, data);
3067 break;
3069 return 0;
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));
3077 BOOL ret = FALSE;
3079 if (data)
3081 data->imageList = ImageList_Create(16, 16, ILC_COLOR4 | ILC_MASK, 2, 0);
3082 if (data->imageList)
3084 HBITMAP bmp;
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);
3092 DeleteObject(bmp);
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;
3103 ret = TRUE;
3105 else
3106 HeapFree(GetProcessHeap(), 0, data);
3108 return ret;
3111 static int CALLBACK cert_prop_sheet_proc(HWND hwnd, UINT msg, LPARAM lp)
3113 RECT rc;
3114 POINT topLeft;
3116 TRACE("(%p, %08x, %08lx)\n", hwnd, msg, lp);
3118 switch (msg)
3120 case PSCB_INITIALIZED:
3121 /* Get cancel button's position.. */
3122 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rc);
3123 topLeft.x = rc.left;
3124 topLeft.y = rc.top;
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);
3134 break;
3136 return 0;
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 };
3143 DWORD nPages;
3144 PROPSHEETPAGEW *pages;
3145 BOOL ret = FALSE;
3146 HMODULE lib = LoadLibraryW(riched);
3148 nPages = pCertViewInfo->cPropSheetPages + 1; /* one for the General tab */
3149 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_DETAILPAGE))
3150 nPages++;
3151 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_HIERARCHYPAGE))
3152 nPages++;
3153 pages = HeapAlloc(GetProcessHeap(), 0, nPages * sizeof(PROPSHEETPAGEW));
3154 if (pages)
3156 PROPSHEETHEADERW hdr;
3157 CRYPTUI_INITDIALOG_STRUCT *init = NULL;
3158 DWORD i;
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;
3166 else
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]))
3173 hdr.nPages++;
3175 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_HIERARCHYPAGE))
3177 if (init_hierarchy_page(pCertViewInfo, &pages[hdr.nPages]))
3178 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));
3187 if (init)
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
3201 * pages
3203 hdr.u2.nStartPage = pCertViewInfo->nStartPage + hdr.nPages;
3205 else
3206 hdr.u2.nStartPage = pCertViewInfo->nStartPage;
3207 hdr.nPages = nPages;
3208 ret = TRUE;
3210 else
3211 SetLastError(ERROR_OUTOFMEMORY);
3213 else
3215 /* Ignore the relative flag if there aren't any additional pages */
3216 hdr.u2.nStartPage = pCertViewInfo->nStartPage & 0x7fff;
3217 ret = TRUE;
3219 if (ret)
3221 INT_PTR l;
3223 hdr.u3.ppsp = pages;
3224 hdr.pfnCallback = cert_prop_sheet_proc;
3225 l = PropertySheetW(&hdr);
3226 if (l == 0)
3228 SetLastError(ERROR_CANCELLED);
3229 ret = FALSE;
3232 HeapFree(GetProcessHeap(), 0, init);
3233 HeapFree(GetProcessHeap(), 0, pages);
3235 else
3236 SetLastError(ERROR_OUTOFMEMORY);
3237 FreeLibrary(lib);
3238 return ret;
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;
3249 WINTRUST_DATA wvt;
3250 WINTRUST_CERT_INFO cert;
3251 BOOL ret = FALSE;
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);
3260 return FALSE;
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);
3290 ret = TRUE;
3292 else
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);
3301 ret = TRUE;
3303 if (ret)
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);
3312 return ret;
3315 /***********************************************************************
3316 * CryptUIDlgViewContext (CRYPTUI.@)
3318 BOOL WINAPI CryptUIDlgViewContext(DWORD dwContextType, LPVOID pvContext,
3319 HWND hwnd, LPCWSTR pwszTitle, DWORD dwFlags, LPVOID pvReserved)
3321 BOOL ret;
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);
3338 break;
3340 default:
3341 FIXME("unimplemented for context type %d\n", dwContextType);
3342 SetLastError(E_INVALIDARG);
3343 ret = FALSE;
3345 return ret;
3348 static PCCERT_CONTEXT make_cert_from_file(LPCWSTR fileName)
3350 HANDLE file;
3351 DWORD size, encoding = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
3352 BYTE *buffer;
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));
3360 return NULL;
3362 if ((size = GetFileSize(file, NULL)))
3364 if ((buffer = HeapAlloc(GetProcessHeap(), 0, size)))
3366 DWORD read;
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);
3371 CloseHandle(file);
3372 return NULL;
3376 else
3378 WARN("empty file %s\n", debugstr_w(fileName));
3379 CloseHandle(file);
3380 return NULL;
3382 CloseHandle(file);
3383 cert = CertCreateCertificateContext(encoding, buffer, size);
3384 HeapFree(GetProcessHeap(), 0, buffer);
3385 return cert;
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);
3399 if (ext)
3401 CERT_BASIC_CONSTRAINTS_INFO *info;
3402 DWORD size = 0;
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;
3410 LocalFree(info);
3413 else
3415 ext = CertFindExtension(szOID_BASIC_CONSTRAINTS2,
3416 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
3417 if (ext)
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))
3425 isCA = info.fCA;
3428 return isCA;
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 };
3436 LPCWSTR storeName;
3438 if (is_ca_cert(cert, TRUE))
3439 storeName = CA;
3440 else
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)
3449 BOOL ret;
3450 HCERTSTORE store;
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");
3459 if (!pImportSrc ||
3460 pImportSrc->dwSize != sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO))
3462 SetLastError(E_INVALIDARG);
3463 return FALSE;
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");
3472 return FALSE;
3474 else
3475 freeCert = TRUE;
3476 break;
3477 case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_CONTEXT:
3478 cert = pImportSrc->u.pCertContext;
3479 if (!cert)
3481 SetLastError(E_INVALIDARG);
3482 return FALSE;
3484 break;
3485 default:
3486 FIXME("source type not implemented: %u\n", pImportSrc->dwSubjectChoice);
3487 SetLastError(E_INVALIDARG);
3488 return FALSE;
3490 if (hDestCertStore) store = hDestCertStore;
3491 else
3493 if (!(store = choose_store_for_cert(cert)))
3495 WARN("unable to open certificate store\n");
3496 CertFreeCertificateContext(cert);
3497 return FALSE;
3500 ret = CertAddCertificateContextToStore(store, cert, CERT_STORE_ADD_REPLACE_EXISTING, NULL);
3502 if (!hDestCertStore) CertCloseStore(store, 0);
3503 if (freeCert)
3504 CertFreeCertificateContext(cert);
3505 return ret;