cryptui: Implement CryptUIDlgSelectStoreA on top of CryptUIDlgSelectStoreW.
[wine/wine64.git] / dlls / cryptui / main.c
blob7ae27d2f7b5c94582e1ef67fba707d30df7fb8b7
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 /***********************************************************************
122 * CryptUIDlgSelectStoreW (CRYPTUI.@)
124 HCERTSTORE WINAPI CryptUIDlgSelectStoreW(PCRYPTUI_SELECTSTORE_INFO_W info)
126 FIXME("(%p): stub\n", info);
127 return NULL;
130 /***********************************************************************
131 * CryptUIDlgSelectStoreA (CRYPTUI.@)
133 HCERTSTORE WINAPI CryptUIDlgSelectStoreA(PCRYPTUI_SELECTSTORE_INFO_A info)
135 CRYPTUI_SELECTSTORE_INFO_W infoW;
136 HCERTSTORE ret;
137 int len;
139 TRACE("(%p)\n", info);
141 if (info->dwSize != sizeof(CRYPTUI_SELECTSTORE_INFO_A))
143 WARN("unexpected size %d\n", info->dwSize);
144 SetLastError(E_INVALIDARG);
145 return NULL;
147 memcpy(&infoW, &info, sizeof(info));
148 if (info->pszTitle)
150 len = MultiByteToWideChar(CP_ACP, 0, info->pszTitle, -1, NULL, 0);
151 infoW.pwszTitle = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
152 MultiByteToWideChar(CP_ACP, 0, info->pszTitle, -1, infoW.pwszTitle,
153 len);
155 if (info->pszText)
157 len = MultiByteToWideChar(CP_ACP, 0, info->pszText, -1, NULL, 0);
158 infoW.pwszText = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
159 MultiByteToWideChar(CP_ACP, 0, info->pszText, -1, infoW.pwszText, len);
161 ret = CryptUIDlgSelectStoreW(&infoW);
162 HeapFree(GetProcessHeap(), 0, infoW.pwszText);
163 HeapFree(GetProcessHeap(), 0, infoW.pwszTitle);
164 return ret;
167 /***********************************************************************
168 * CryptUIDlgViewCertificateA (CRYPTUI.@)
170 BOOL WINAPI CryptUIDlgViewCertificateA(
171 PCCRYPTUI_VIEWCERTIFICATE_STRUCTA pCertViewInfo, BOOL *pfPropertiesChanged)
173 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
174 LPWSTR title = NULL;
175 BOOL ret;
177 TRACE("(%p, %p)\n", pCertViewInfo, pfPropertiesChanged);
179 memcpy(&viewInfo, pCertViewInfo, sizeof(viewInfo));
180 if (pCertViewInfo->szTitle)
182 int len = MultiByteToWideChar(CP_ACP, 0, pCertViewInfo->szTitle, -1,
183 NULL, 0);
185 title = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
186 if (title)
188 MultiByteToWideChar(CP_ACP, 0, pCertViewInfo->szTitle, -1, title,
189 len);
190 viewInfo.szTitle = title;
192 else
194 ret = FALSE;
195 goto error;
198 if (pCertViewInfo->cPropSheetPages)
200 FIXME("ignoring additional prop sheet pages\n");
201 viewInfo.cPropSheetPages = 0;
203 ret = CryptUIDlgViewCertificateW(&viewInfo, pfPropertiesChanged);
204 HeapFree(GetProcessHeap(), 0, title);
205 error:
206 return ret;
209 struct ReadStringStruct
211 LPCWSTR buf;
212 LONG pos;
213 LONG len;
216 static DWORD CALLBACK read_text_callback(DWORD_PTR dwCookie, LPBYTE buf,
217 LONG cb, LONG *pcb)
219 struct ReadStringStruct *string = (struct ReadStringStruct *)dwCookie;
220 LONG cch = min(cb / sizeof(WCHAR), string->len - string->pos);
222 TRACE("(%p, %p, %d, %p)\n", string, buf, cb, pcb);
224 memmove(buf, string->buf + string->pos, cch * sizeof(WCHAR));
225 string->pos += cch;
226 *pcb = cch * sizeof(WCHAR);
227 return 0;
230 static void add_unformatted_text_to_control(HWND hwnd, LPCWSTR text, LONG len)
232 struct ReadStringStruct string;
233 EDITSTREAM editstream;
235 TRACE("(%p, %s)\n", hwnd, debugstr_wn(text, len));
237 string.buf = text;
238 string.pos = 0;
239 string.len = len;
240 editstream.dwCookie = (DWORD_PTR)&string;
241 editstream.dwError = 0;
242 editstream.pfnCallback = read_text_callback;
243 SendMessageW(hwnd, EM_STREAMIN, SF_TEXT | SFF_SELECTION | SF_UNICODE,
244 (LPARAM)&editstream);
247 static void add_string_resource_to_control(HWND hwnd, int id)
249 LPWSTR str;
250 LONG len;
252 len = LoadStringW(hInstance, id, (LPWSTR)&str, 0);
253 add_unformatted_text_to_control(hwnd, str, len);
256 static void add_text_with_paraformat_to_control(HWND hwnd, LPCWSTR text,
257 LONG len, const PARAFORMAT2 *fmt)
259 add_unformatted_text_to_control(hwnd, text, len);
260 SendMessageW(hwnd, EM_SETPARAFORMAT, 0, (LPARAM)fmt);
263 static void add_string_resource_with_paraformat_to_control(HWND hwnd, int id,
264 const PARAFORMAT2 *fmt)
266 LPWSTR str;
267 LONG len;
269 len = LoadStringW(hInstance, id, (LPWSTR)&str, 0);
270 add_text_with_paraformat_to_control(hwnd, str, len, fmt);
273 static LPWSTR get_cert_name_string(PCCERT_CONTEXT pCertContext, DWORD dwType,
274 DWORD dwFlags)
276 LPWSTR buf = NULL;
277 DWORD len;
279 len = CertGetNameStringW(pCertContext, dwType, dwFlags, NULL, NULL, 0);
280 if (len)
282 buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
283 if (buf)
284 CertGetNameStringW(pCertContext, dwType, dwFlags, NULL, buf, len);
286 return buf;
289 static void add_cert_string_to_control(HWND hwnd, PCCERT_CONTEXT pCertContext,
290 DWORD dwType, DWORD dwFlags)
292 LPWSTR name = get_cert_name_string(pCertContext, dwType, dwFlags);
294 if (name)
296 /* Don't include NULL-terminator in output */
297 DWORD len = lstrlenW(name);
299 add_unformatted_text_to_control(hwnd, name, len);
300 HeapFree(GetProcessHeap(), 0, name);
304 static void add_icon_to_control(HWND hwnd, int id)
306 HRESULT hr;
307 LPRICHEDITOLE richEditOle = NULL;
308 LPOLEOBJECT object = NULL;
309 CLSID clsid;
310 LPOLECACHE oleCache = NULL;
311 FORMATETC formatEtc;
312 DWORD conn;
313 LPDATAOBJECT dataObject = NULL;
314 HBITMAP bitmap = NULL;
315 RECT rect;
316 STGMEDIUM stgm;
317 REOBJECT reObject;
319 TRACE("(%p, %d)\n", hwnd, id);
321 SendMessageW(hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&richEditOle);
322 if (!richEditOle)
323 goto end;
324 hr = OleCreateDefaultHandler(&CLSID_NULL, NULL, &IID_IOleObject,
325 (void**)&object);
326 if (FAILED(hr))
327 goto end;
328 hr = IOleObject_GetUserClassID(object, &clsid);
329 if (FAILED(hr))
330 goto end;
331 hr = IOleObject_QueryInterface(object, &IID_IOleCache, (void**)&oleCache);
332 if (FAILED(hr))
333 goto end;
334 formatEtc.cfFormat = CF_BITMAP;
335 formatEtc.ptd = NULL;
336 formatEtc.dwAspect = DVASPECT_CONTENT;
337 formatEtc.lindex = -1;
338 formatEtc.tymed = TYMED_GDI;
339 hr = IOleCache_Cache(oleCache, &formatEtc, 0, &conn);
340 if (FAILED(hr))
341 goto end;
342 hr = IOleObject_QueryInterface(object, &IID_IDataObject,
343 (void**)&dataObject);
344 if (FAILED(hr))
345 goto end;
346 bitmap = LoadImageW(hInstance, MAKEINTRESOURCEW(id), IMAGE_BITMAP, 0, 0,
347 LR_DEFAULTSIZE | LR_LOADTRANSPARENT);
348 if (!bitmap)
349 goto end;
350 rect.left = rect.top = 0;
351 rect.right = GetSystemMetrics(SM_CXICON);
352 rect.bottom = GetSystemMetrics(SM_CYICON);
353 stgm.tymed = TYMED_GDI;
354 stgm.u.hBitmap = bitmap;
355 stgm.pUnkForRelease = NULL;
356 hr = IDataObject_SetData(dataObject, &formatEtc, &stgm, TRUE);
357 if (FAILED(hr))
358 goto end;
360 reObject.cbStruct = sizeof(reObject);
361 reObject.cp = REO_CP_SELECTION;
362 reObject.clsid = clsid;
363 reObject.poleobj = object;
364 reObject.pstg = NULL;
365 reObject.polesite = NULL;
366 reObject.sizel.cx = reObject.sizel.cy = 0;
367 reObject.dvaspect = DVASPECT_CONTENT;
368 reObject.dwFlags = 0;
369 reObject.dwUser = 0;
371 IRichEditOle_InsertObject(richEditOle, &reObject);
373 end:
374 if (dataObject)
375 IDataObject_Release(dataObject);
376 if (oleCache)
377 IOleCache_Release(oleCache);
378 if (object)
379 IOleObject_Release(object);
380 if (richEditOle)
381 IRichEditOle_Release(richEditOle);
384 #define MY_INDENT 200
386 static void add_oid_text_to_control(HWND hwnd, char *oid)
388 WCHAR nl = '\n';
389 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, oid, 0);
390 PARAFORMAT2 parFmt;
392 parFmt.cbSize = sizeof(parFmt);
393 parFmt.dwMask = PFM_STARTINDENT;
394 parFmt.dxStartIndent = MY_INDENT * 3;
395 if (oidInfo)
397 add_text_with_paraformat_to_control(hwnd, oidInfo->pwszName,
398 lstrlenW(oidInfo->pwszName), &parFmt);
399 add_unformatted_text_to_control(hwnd, &nl, 1);
403 #define MAX_STRING_LEN 512
405 struct OIDToString
407 LPCSTR oid;
408 int id;
411 /* The following list MUST be lexicographically sorted by OID */
412 static struct OIDToString oidMap[] = {
413 /* 1.3.6.1.4.1.311.10.3.1 */
414 { szOID_KP_CTL_USAGE_SIGNING, IDS_PURPOSE_CTL_USAGE_SIGNING },
415 /* 1.3.6.1.4.1.311.10.3.4 */
416 { szOID_KP_EFS, IDS_PURPOSE_EFS },
417 /* 1.3.6.1.4.1.311.10.3.4.1 */
418 { szOID_EFS_RECOVERY, IDS_PURPOSE_EFS_RECOVERY },
419 /* 1.3.6.1.4.1.311.10.3.5 */
420 { szOID_WHQL_CRYPTO, IDS_PURPOSE_WHQL },
421 /* 1.3.6.1.4.1.311.10.3.6 */
422 { szOID_NT5_CRYPTO, IDS_PURPOSE_NT5 },
423 /* 1.3.6.1.4.1.311.10.3.7 */
424 { szOID_OEM_WHQL_CRYPTO, IDS_PURPOSE_OEM_WHQL },
425 /* 1.3.6.1.4.1.311.10.3.8 */
426 { szOID_EMBEDDED_NT_CRYPTO, IDS_PURPOSE_EMBEDDED_NT },
427 /* 1.3.6.1.4.1.311.10.3.9 */
428 { szOID_ROOT_LIST_SIGNER, IDS_PURPOSE_ROOT_LIST_SIGNER },
429 /* 1.3.6.1.4.1.311.10.3.10 */
430 { szOID_KP_QUALIFIED_SUBORDINATION, IDS_PURPOSE_QUALIFIED_SUBORDINATION },
431 /* 1.3.6.1.4.1.311.10.3.11 */
432 { szOID_KP_KEY_RECOVERY, IDS_PURPOSE_KEY_RECOVERY },
433 /* 1.3.6.1.4.1.311.10.3.12 */
434 { szOID_KP_DOCUMENT_SIGNING, IDS_PURPOSE_DOCUMENT_SIGNING },
435 /* 1.3.6.1.4.1.311.10.3.13 */
436 { szOID_KP_LIFETIME_SIGNING, IDS_PURPOSE_LIFETIME_SIGNING },
437 /* 1.3.6.1.4.1.311.10.5.1 */
438 { szOID_DRM, IDS_PURPOSE_DRM },
439 /* 1.3.6.1.4.1.311.10.6.1 */
440 { szOID_LICENSES, IDS_PURPOSE_LICENSES },
441 /* 1.3.6.1.4.1.311.10.6.2 */
442 { szOID_LICENSE_SERVER, IDS_PURPOSE_LICENSE_SERVER },
443 /* 1.3.6.1.4.1.311.20.2.1 */
444 { szOID_ENROLLMENT_AGENT, IDS_PURPOSE_ENROLLMENT_AGENT },
445 /* 1.3.6.1.4.1.311.20.2.2 */
446 { szOID_KP_SMARTCARD_LOGON, IDS_PURPOSE_SMARTCARD_LOGON },
447 /* 1.3.6.1.4.1.311.21.5 */
448 { szOID_KP_CA_EXCHANGE, IDS_PURPOSE_CA_EXCHANGE },
449 /* 1.3.6.1.4.1.311.21.6 */
450 { szOID_KP_KEY_RECOVERY_AGENT, IDS_PURPOSE_KEY_RECOVERY_AGENT },
451 /* 1.3.6.1.4.1.311.21.19 */
452 { szOID_DS_EMAIL_REPLICATION, IDS_PURPOSE_DS_EMAIL_REPLICATION },
453 /* 1.3.6.1.5.5.7.3.1 */
454 { szOID_PKIX_KP_SERVER_AUTH, IDS_PURPOSE_SERVER_AUTH },
455 /* 1.3.6.1.5.5.7.3.2 */
456 { szOID_PKIX_KP_CLIENT_AUTH, IDS_PURPOSE_CLIENT_AUTH },
457 /* 1.3.6.1.5.5.7.3.3 */
458 { szOID_PKIX_KP_CODE_SIGNING, IDS_PURPOSE_CODE_SIGNING },
459 /* 1.3.6.1.5.5.7.3.4 */
460 { szOID_PKIX_KP_EMAIL_PROTECTION, IDS_PURPOSE_EMAIL_PROTECTION },
461 /* 1.3.6.1.5.5.7.3.5 */
462 { szOID_PKIX_KP_IPSEC_END_SYSTEM, IDS_PURPOSE_IPSEC },
463 /* 1.3.6.1.5.5.7.3.6 */
464 { szOID_PKIX_KP_IPSEC_TUNNEL, IDS_PURPOSE_IPSEC },
465 /* 1.3.6.1.5.5.7.3.7 */
466 { szOID_PKIX_KP_IPSEC_USER, IDS_PURPOSE_IPSEC },
467 /* 1.3.6.1.5.5.7.3.8 */
468 { szOID_PKIX_KP_TIMESTAMP_SIGNING, IDS_PURPOSE_TIMESTAMP_SIGNING },
471 static struct OIDToString *findSupportedOID(LPCSTR oid)
473 int indexHigh = sizeof(oidMap) / sizeof(oidMap[0]) - 1, indexLow = 0, i;
474 struct OIDToString *ret = NULL;
476 for (i = (indexLow + indexHigh) / 2; !ret && indexLow <= indexHigh;
477 i = (indexLow + indexHigh) / 2)
479 int cmp;
481 cmp = strcmp(oid, oidMap[i].oid);
482 if (!cmp)
483 ret = &oidMap[i];
484 else if (cmp > 0)
485 indexLow = i + 1;
486 else
487 indexHigh = i - 1;
489 return ret;
492 static void add_local_oid_text_to_control(HWND text, LPCSTR oid)
494 struct OIDToString *entry;
495 WCHAR nl = '\n';
496 PARAFORMAT2 parFmt;
498 parFmt.cbSize = sizeof(parFmt);
499 parFmt.dwMask = PFM_STARTINDENT;
500 parFmt.dxStartIndent = MY_INDENT * 3;
501 if ((entry = findSupportedOID(oid)))
503 WCHAR *str, *linebreak, *ptr;
504 BOOL multiline = FALSE;
505 int len;
507 len = LoadStringW(hInstance, entry->id, (LPWSTR)&str, 0);
508 ptr = str;
509 do {
510 if ((linebreak = memchrW(ptr, '\n', len)))
512 WCHAR copy[MAX_STRING_LEN];
514 multiline = TRUE;
515 /* The source string contains a newline, which the richedit
516 * control won't find since it's interpreted as a paragraph
517 * break. Therefore copy up to the newline. lstrcpynW always
518 * NULL-terminates, so pass one more than the length of the
519 * source line so the copy includes the entire line and the
520 * NULL-terminator.
522 lstrcpynW(copy, ptr, linebreak - ptr + 1);
523 add_text_with_paraformat_to_control(text, copy,
524 linebreak - ptr, &parFmt);
525 ptr = linebreak + 1;
526 add_unformatted_text_to_control(text, &nl, 1);
528 else if (multiline && *ptr)
530 /* Add the last line */
531 add_text_with_paraformat_to_control(text, ptr,
532 len - (ptr - str), &parFmt);
533 add_unformatted_text_to_control(text, &nl, 1);
535 } while (linebreak);
536 if (!multiline)
538 add_text_with_paraformat_to_control(text, str, len, &parFmt);
539 add_unformatted_text_to_control(text, &nl, 1);
542 else
544 WCHAR *oidW = HeapAlloc(GetProcessHeap(), 0,
545 (strlen(oid) + 1) * sizeof(WCHAR));
547 if (oidW)
549 LPCSTR src;
550 WCHAR *dst;
552 for (src = oid, dst = oidW; *src; src++, dst++)
553 *dst = *src;
554 *dst = 0;
555 add_text_with_paraformat_to_control(text, oidW, lstrlenW(oidW),
556 &parFmt);
557 add_unformatted_text_to_control(text, &nl, 1);
558 HeapFree(GetProcessHeap(), 0, oidW);
563 static void display_app_usages(HWND text, PCCERT_CONTEXT cert,
564 BOOL *anyUsageAdded)
566 static char any_app_policy[] = szOID_ANY_APPLICATION_POLICY;
567 WCHAR nl = '\n';
568 CHARFORMATW charFmt;
569 PCERT_EXTENSION policyExt;
570 if (!*anyUsageAdded)
572 PARAFORMAT2 parFmt;
574 parFmt.cbSize = sizeof(parFmt);
575 parFmt.dwMask = PFM_STARTINDENT;
576 parFmt.dxStartIndent = MY_INDENT;
577 add_string_resource_with_paraformat_to_control(text,
578 IDS_CERT_INFO_PURPOSES, &parFmt);
579 add_unformatted_text_to_control(text, &nl, 1);
580 *anyUsageAdded = TRUE;
582 memset(&charFmt, 0, sizeof(charFmt));
583 charFmt.cbSize = sizeof(charFmt);
584 charFmt.dwMask = CFM_BOLD;
585 charFmt.dwEffects = 0;
586 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
587 if ((policyExt = CertFindExtension(szOID_APPLICATION_CERT_POLICIES,
588 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension)))
590 CERT_POLICIES_INFO *policies;
591 DWORD size;
593 if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_POLICIES,
594 policyExt->Value.pbData, policyExt->Value.cbData,
595 CRYPT_DECODE_ALLOC_FLAG, NULL, &policies, &size))
597 DWORD i;
599 for (i = 0; i < policies->cPolicyInfo; i++)
601 DWORD j;
603 for (j = 0; j < policies->rgPolicyInfo[i].cPolicyQualifier; j++)
604 add_local_oid_text_to_control(text,
605 policies->rgPolicyInfo[i].rgPolicyQualifier[j].
606 pszPolicyQualifierId);
608 LocalFree(policies);
611 else
612 add_oid_text_to_control(text, any_app_policy);
615 static BOOL display_cert_usages(HWND text, PCCERT_CONTEXT cert,
616 BOOL *anyUsageAdded)
618 WCHAR nl = '\n';
619 DWORD size;
620 BOOL badUsages = FALSE;
622 if (CertGetEnhancedKeyUsage(cert, 0, NULL, &size))
624 CHARFORMATW charFmt;
625 static char any_cert_policy[] = szOID_ANY_CERT_POLICY;
626 PCERT_ENHKEY_USAGE usage = HeapAlloc(GetProcessHeap(), 0, size);
628 if (usage)
630 if (CertGetEnhancedKeyUsage(cert, 0, usage, &size))
632 DWORD i;
634 if (!*anyUsageAdded)
636 PARAFORMAT2 parFmt;
638 parFmt.cbSize = sizeof(parFmt);
639 parFmt.dwMask = PFM_STARTINDENT;
640 parFmt.dxStartIndent = MY_INDENT;
641 add_string_resource_with_paraformat_to_control(text,
642 IDS_CERT_INFO_PURPOSES, &parFmt);
643 add_unformatted_text_to_control(text, &nl, 1);
644 *anyUsageAdded = TRUE;
646 memset(&charFmt, 0, sizeof(charFmt));
647 charFmt.cbSize = sizeof(charFmt);
648 charFmt.dwMask = CFM_BOLD;
649 charFmt.dwEffects = 0;
650 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION,
651 (LPARAM)&charFmt);
652 if (!usage->cUsageIdentifier)
653 add_oid_text_to_control(text, any_cert_policy);
654 else
655 for (i = 0; i < usage->cUsageIdentifier; i++)
656 add_local_oid_text_to_control(text,
657 usage->rgpszUsageIdentifier[i]);
659 else
660 badUsages = TRUE;
661 HeapFree(GetProcessHeap(), 0, usage);
663 else
664 badUsages = TRUE;
666 else
667 badUsages = TRUE;
668 return badUsages;
671 static void set_policy_text(HWND text,
672 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
674 BOOL includeCertUsages = FALSE, includeAppUsages = FALSE;
675 BOOL badUsages = FALSE, anyUsageAdded = FALSE;
677 if (pCertViewInfo->cPurposes)
679 DWORD i;
681 for (i = 0; i < pCertViewInfo->cPurposes; i++)
683 if (!strcmp(pCertViewInfo->rgszPurposes[i], szOID_ANY_CERT_POLICY))
684 includeCertUsages = TRUE;
685 else if (!strcmp(pCertViewInfo->rgszPurposes[i],
686 szOID_ANY_APPLICATION_POLICY))
687 includeAppUsages = TRUE;
688 else
689 badUsages = TRUE;
692 else
693 includeAppUsages = includeCertUsages = TRUE;
694 if (includeAppUsages)
695 display_app_usages(text, pCertViewInfo->pCertContext, &anyUsageAdded);
696 if (includeCertUsages)
697 badUsages = display_cert_usages(text, pCertViewInfo->pCertContext,
698 &anyUsageAdded);
699 if (badUsages)
701 PARAFORMAT2 parFmt;
703 parFmt.cbSize = sizeof(parFmt);
704 parFmt.dwMask = PFM_STARTINDENT;
705 parFmt.dxStartIndent = MY_INDENT;
706 add_string_resource_with_paraformat_to_control(text,
707 IDS_CERT_INFO_BAD_PURPOSES, &parFmt);
711 static CRYPT_OBJID_BLOB *find_policy_qualifier(CERT_POLICIES_INFO *policies,
712 LPCSTR policyOid)
714 CRYPT_OBJID_BLOB *ret = NULL;
715 DWORD i;
717 for (i = 0; !ret && i < policies->cPolicyInfo; i++)
719 DWORD j;
721 for (j = 0; !ret && j < policies->rgPolicyInfo[i].cPolicyQualifier; j++)
722 if (!strcmp(policies->rgPolicyInfo[i].rgPolicyQualifier[j].
723 pszPolicyQualifierId, policyOid))
724 ret = &policies->rgPolicyInfo[i].rgPolicyQualifier[j].
725 Qualifier;
727 return ret;
730 static WCHAR *get_cps_str_from_qualifier(CRYPT_OBJID_BLOB *qualifier)
732 LPWSTR qualifierStr = NULL;
733 CERT_NAME_VALUE *qualifierValue;
734 DWORD size;
736 if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME_VALUE,
737 qualifier->pbData, qualifier->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL,
738 &qualifierValue, &size))
740 size = CertRDNValueToStrW(qualifierValue->dwValueType,
741 &qualifierValue->Value, NULL, 0);
742 qualifierStr = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
743 if (qualifierStr)
744 CertRDNValueToStrW(qualifierValue->dwValueType,
745 &qualifierValue->Value, qualifierStr, size);
746 LocalFree(qualifierValue);
748 return qualifierStr;
751 static WCHAR *get_user_notice_from_qualifier(CRYPT_OBJID_BLOB *qualifier)
753 LPWSTR str = NULL;
754 CERT_POLICY_QUALIFIER_USER_NOTICE *qualifierValue;
755 DWORD size;
757 if (CryptDecodeObjectEx(X509_ASN_ENCODING,
758 X509_PKIX_POLICY_QUALIFIER_USERNOTICE,
759 qualifier->pbData, qualifier->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL,
760 &qualifierValue, &size))
762 str = HeapAlloc(GetProcessHeap(), 0,
763 (strlenW(qualifierValue->pszDisplayText) + 1) * sizeof(WCHAR));
764 if (str)
765 strcpyW(str, qualifierValue->pszDisplayText);
766 LocalFree(qualifierValue);
768 return str;
771 struct IssuerStatement
773 LPWSTR cps;
774 LPWSTR userNotice;
777 static void set_issuer_statement(HWND hwnd,
778 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
780 PCERT_EXTENSION policyExt;
782 if (!(pCertViewInfo->dwFlags & CRYPTUI_DISABLE_ISSUERSTATEMENT) &&
783 (policyExt = CertFindExtension(szOID_CERT_POLICIES,
784 pCertViewInfo->pCertContext->pCertInfo->cExtension,
785 pCertViewInfo->pCertContext->pCertInfo->rgExtension)))
787 CERT_POLICIES_INFO *policies;
788 DWORD size;
790 if (CryptDecodeObjectEx(X509_ASN_ENCODING, policyExt->pszObjId,
791 policyExt->Value.pbData, policyExt->Value.cbData,
792 CRYPT_DECODE_ALLOC_FLAG, NULL, &policies, &size))
794 CRYPT_OBJID_BLOB *qualifier;
795 LPWSTR cps = NULL, userNotice = NULL;
797 if ((qualifier = find_policy_qualifier(policies,
798 szOID_PKIX_POLICY_QUALIFIER_CPS)))
799 cps = get_cps_str_from_qualifier(qualifier);
800 if ((qualifier = find_policy_qualifier(policies,
801 szOID_PKIX_POLICY_QUALIFIER_USERNOTICE)))
802 userNotice = get_user_notice_from_qualifier(qualifier);
803 if (cps || userNotice)
805 struct IssuerStatement *issuerStatement =
806 HeapAlloc(GetProcessHeap(), 0, sizeof(struct IssuerStatement));
808 if (issuerStatement)
810 issuerStatement->cps = cps;
811 issuerStatement->userNotice = userNotice;
812 EnableWindow(GetDlgItem(hwnd, IDC_ISSUERSTATEMENT), TRUE);
813 SetWindowLongPtrW(hwnd, DWLP_USER,
814 (ULONG_PTR)issuerStatement);
817 LocalFree(policies);
822 static void set_cert_info(HWND hwnd,
823 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
825 CHARFORMATW charFmt;
826 PARAFORMAT2 parFmt;
827 HWND icon = GetDlgItem(hwnd, IDC_CERTIFICATE_ICON);
828 HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_INFO);
829 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
830 (CRYPT_PROVIDER_DATA *)pCertViewInfo->u.pCryptProviderData,
831 pCertViewInfo->idxSigner, pCertViewInfo->fCounterSigner,
832 pCertViewInfo->idxCounterSigner);
833 CRYPT_PROVIDER_CERT *root =
834 &provSigner->pasCertChain[provSigner->csCertChain - 1];
836 if (!provSigner->pChainContext ||
837 (provSigner->pChainContext->TrustStatus.dwErrorStatus &
838 CERT_TRUST_IS_PARTIAL_CHAIN))
839 add_icon_to_control(icon, IDB_CERT_WARNING);
840 else if (!root->fTrustedRoot)
841 add_icon_to_control(icon, IDB_CERT_ERROR);
842 else
843 add_icon_to_control(icon, IDB_CERT);
845 memset(&charFmt, 0, sizeof(charFmt));
846 charFmt.cbSize = sizeof(charFmt);
847 charFmt.dwMask = CFM_BOLD;
848 charFmt.dwEffects = CFE_BOLD;
849 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
850 /* FIXME: vertically center text */
851 parFmt.cbSize = sizeof(parFmt);
852 parFmt.dwMask = PFM_STARTINDENT;
853 parFmt.dxStartIndent = MY_INDENT;
854 add_string_resource_with_paraformat_to_control(text,
855 IDS_CERTIFICATEINFORMATION, &parFmt);
857 text = GetDlgItem(hwnd, IDC_CERTIFICATE_STATUS);
858 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
859 if (provSigner->dwError == TRUST_E_CERT_SIGNATURE)
860 add_string_resource_with_paraformat_to_control(text,
861 IDS_CERT_INFO_BAD_SIG, &parFmt);
862 else if (!provSigner->pChainContext ||
863 (provSigner->pChainContext->TrustStatus.dwErrorStatus &
864 CERT_TRUST_IS_PARTIAL_CHAIN))
865 add_string_resource_with_paraformat_to_control(text,
866 IDS_CERT_INFO_PARTIAL_CHAIN, &parFmt);
867 else if (!root->fTrustedRoot)
869 if (provSigner->csCertChain == 1 && root->fSelfSigned)
870 add_string_resource_with_paraformat_to_control(text,
871 IDS_CERT_INFO_UNTRUSTED_CA, &parFmt);
872 else
873 add_string_resource_with_paraformat_to_control(text,
874 IDS_CERT_INFO_UNTRUSTED_ROOT, &parFmt);
876 else
878 set_policy_text(text, pCertViewInfo);
879 set_issuer_statement(hwnd, pCertViewInfo);
883 static void set_cert_name_string(HWND hwnd, PCCERT_CONTEXT cert,
884 DWORD nameFlags, int heading)
886 WCHAR nl = '\n';
887 HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_NAMES);
888 CHARFORMATW charFmt;
889 PARAFORMAT2 parFmt;
891 memset(&charFmt, 0, sizeof(charFmt));
892 charFmt.cbSize = sizeof(charFmt);
893 charFmt.dwMask = CFM_BOLD;
894 charFmt.dwEffects = CFE_BOLD;
895 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
896 parFmt.cbSize = sizeof(parFmt);
897 parFmt.dwMask = PFM_STARTINDENT;
898 parFmt.dxStartIndent = MY_INDENT * 3;
899 add_string_resource_with_paraformat_to_control(text, heading, &parFmt);
900 charFmt.dwEffects = 0;
901 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
902 add_cert_string_to_control(text, cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
903 nameFlags);
904 add_unformatted_text_to_control(text, &nl, 1);
905 add_unformatted_text_to_control(text, &nl, 1);
906 add_unformatted_text_to_control(text, &nl, 1);
910 static void add_date_string_to_control(HWND hwnd, const FILETIME *fileTime)
912 WCHAR dateFmt[80]; /* sufficient for all versions of LOCALE_SSHORTDATE */
913 WCHAR date[80];
914 SYSTEMTIME sysTime;
916 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SSHORTDATE, dateFmt,
917 sizeof(dateFmt) / sizeof(dateFmt[0]));
918 FileTimeToSystemTime(fileTime, &sysTime);
919 GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, date,
920 sizeof(date) / sizeof(date[0]));
921 add_unformatted_text_to_control(hwnd, date, lstrlenW(date));
924 static void set_cert_validity_period(HWND hwnd, PCCERT_CONTEXT cert)
926 WCHAR nl = '\n';
927 HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_NAMES);
928 CHARFORMATW charFmt;
929 PARAFORMAT2 parFmt;
931 memset(&charFmt, 0, sizeof(charFmt));
932 charFmt.cbSize = sizeof(charFmt);
933 charFmt.dwMask = CFM_BOLD;
934 charFmt.dwEffects = CFE_BOLD;
935 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
936 parFmt.cbSize = sizeof(parFmt);
937 parFmt.dwMask = PFM_STARTINDENT;
938 parFmt.dxStartIndent = MY_INDENT * 3;
939 add_string_resource_with_paraformat_to_control(text, IDS_VALID_FROM,
940 &parFmt);
941 charFmt.dwEffects = 0;
942 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
943 add_date_string_to_control(text, &cert->pCertInfo->NotBefore);
944 charFmt.dwEffects = CFE_BOLD;
945 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
946 add_string_resource_to_control(text, IDS_VALID_TO);
947 charFmt.dwEffects = 0;
948 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
949 add_date_string_to_control(text, &cert->pCertInfo->NotAfter);
950 add_unformatted_text_to_control(text, &nl, 1);
953 static void set_general_info(HWND hwnd,
954 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
956 set_cert_info(hwnd, pCertViewInfo);
957 set_cert_name_string(hwnd, pCertViewInfo->pCertContext, 0,
958 IDS_SUBJECT_HEADING);
959 set_cert_name_string(hwnd, pCertViewInfo->pCertContext,
960 CERT_NAME_ISSUER_FLAG, IDS_ISSUER_HEADING);
961 set_cert_validity_period(hwnd, pCertViewInfo->pCertContext);
964 static LRESULT CALLBACK user_notice_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
965 LPARAM lp)
967 LRESULT ret = 0;
968 HWND text;
969 struct IssuerStatement *issuerStatement;
971 switch (msg)
973 case WM_INITDIALOG:
974 text = GetDlgItem(hwnd, IDC_USERNOTICE);
975 issuerStatement = (struct IssuerStatement *)lp;
976 add_unformatted_text_to_control(text, issuerStatement->userNotice,
977 strlenW(issuerStatement->userNotice));
978 if (issuerStatement->cps)
979 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)issuerStatement->cps);
980 else
981 EnableWindow(GetDlgItem(hwnd, IDC_CPS), FALSE);
982 break;
983 case WM_COMMAND:
984 switch (wp)
986 case IDOK:
987 EndDialog(hwnd, IDOK);
988 ret = TRUE;
989 break;
990 case IDC_CPS:
992 IBindCtx *bctx = NULL;
993 LPWSTR cps;
995 CreateBindCtx(0, &bctx);
996 cps = (LPWSTR)GetWindowLongPtrW(hwnd, DWLP_USER);
997 HlinkSimpleNavigateToString(cps, NULL, NULL, NULL, bctx, NULL,
998 HLNF_OPENINNEWWINDOW, 0);
999 IBindCtx_Release(bctx);
1000 break;
1004 return ret;
1007 static void show_user_notice(HWND hwnd, struct IssuerStatement *issuerStatement)
1009 DialogBoxParamW(hInstance, MAKEINTRESOURCEW(IDD_USERNOTICE), hwnd,
1010 user_notice_dlg_proc, (LPARAM)issuerStatement);
1013 static LRESULT CALLBACK general_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
1014 LPARAM lp)
1016 PROPSHEETPAGEW *page;
1017 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo;
1019 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
1021 switch (msg)
1023 case WM_INITDIALOG:
1024 page = (PROPSHEETPAGEW *)lp;
1025 pCertViewInfo = (PCCRYPTUI_VIEWCERTIFICATE_STRUCTW)page->lParam;
1026 if (pCertViewInfo->dwFlags & CRYPTUI_DISABLE_ADDTOSTORE)
1027 ShowWindow(GetDlgItem(hwnd, IDC_ADDTOSTORE), FALSE);
1028 EnableWindow(GetDlgItem(hwnd, IDC_ISSUERSTATEMENT), FALSE);
1029 set_general_info(hwnd, pCertViewInfo);
1030 break;
1031 case WM_COMMAND:
1032 switch (wp)
1034 case IDC_ADDTOSTORE:
1035 FIXME("call CryptUIWizImport\n");
1036 break;
1037 case IDC_ISSUERSTATEMENT:
1039 struct IssuerStatement *issuerStatement =
1040 (struct IssuerStatement *)GetWindowLongPtrW(hwnd, DWLP_USER);
1042 if (issuerStatement)
1044 if (issuerStatement->userNotice)
1045 show_user_notice(hwnd, issuerStatement);
1046 else if (issuerStatement->cps)
1048 IBindCtx *bctx = NULL;
1050 CreateBindCtx(0, &bctx);
1051 HlinkSimpleNavigateToString(issuerStatement->cps, NULL,
1052 NULL, NULL, bctx, NULL, HLNF_OPENINNEWWINDOW, 0);
1053 IBindCtx_Release(bctx);
1056 break;
1059 break;
1061 return 0;
1064 static UINT CALLBACK general_callback_proc(HWND hwnd, UINT msg,
1065 PROPSHEETPAGEW *page)
1067 struct IssuerStatement *issuerStatement;
1069 switch (msg)
1071 case PSPCB_RELEASE:
1072 issuerStatement =
1073 (struct IssuerStatement *)GetWindowLongPtrW(hwnd, DWLP_USER);
1074 if (issuerStatement)
1076 HeapFree(GetProcessHeap(), 0, issuerStatement->cps);
1077 HeapFree(GetProcessHeap(), 0, issuerStatement->userNotice);
1078 HeapFree(GetProcessHeap(), 0, issuerStatement);
1080 break;
1082 return 1;
1085 static void init_general_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
1086 PROPSHEETPAGEW *page)
1088 memset(page, 0, sizeof(PROPSHEETPAGEW));
1089 page->dwSize = sizeof(PROPSHEETPAGEW);
1090 page->dwFlags = PSP_USECALLBACK;
1091 page->pfnCallback = general_callback_proc;
1092 page->hInstance = hInstance;
1093 page->u.pszTemplate = MAKEINTRESOURCEW(IDD_GENERAL);
1094 page->pfnDlgProc = general_dlg_proc;
1095 page->lParam = (LPARAM)pCertViewInfo;
1098 typedef WCHAR * (*field_format_func)(PCCERT_CONTEXT cert);
1100 static WCHAR *field_format_version(PCCERT_CONTEXT cert)
1102 static const WCHAR fmt[] = { 'V','%','d',0 };
1103 WCHAR *buf = HeapAlloc(GetProcessHeap(), 0, 12 * sizeof(WCHAR));
1105 if (buf)
1106 sprintfW(buf, fmt, cert->pCertInfo->dwVersion);
1107 return buf;
1110 static WCHAR *format_hex_string(void *pb, DWORD cb)
1112 WCHAR *buf = HeapAlloc(GetProcessHeap(), 0, (cb * 3 + 1) * sizeof(WCHAR));
1114 if (buf)
1116 static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
1117 DWORD i;
1118 WCHAR *ptr;
1120 for (i = 0, ptr = buf; i < cb; i++, ptr += 3)
1121 sprintfW(ptr, fmt, ((BYTE *)pb)[i]);
1123 return buf;
1126 static WCHAR *field_format_serial_number(PCCERT_CONTEXT cert)
1128 return format_hex_string(cert->pCertInfo->SerialNumber.pbData,
1129 cert->pCertInfo->SerialNumber.cbData);
1132 static WCHAR *field_format_issuer(PCCERT_CONTEXT cert)
1134 return get_cert_name_string(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
1135 CERT_NAME_ISSUER_FLAG);
1138 static WCHAR *field_format_detailed_cert_name(PCERT_NAME_BLOB name)
1140 WCHAR *str = NULL;
1141 DWORD len = CertNameToStrW(X509_ASN_ENCODING, name,
1142 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, NULL, 0);
1144 if (len)
1146 str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1147 if (str)
1148 CertNameToStrW(X509_ASN_ENCODING, name,
1149 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, str, len);
1151 return str;
1154 static WCHAR *field_format_detailed_issuer(PCCERT_CONTEXT cert, void *param)
1156 return field_format_detailed_cert_name(&cert->pCertInfo->Issuer);
1159 static WCHAR *field_format_subject(PCCERT_CONTEXT cert)
1161 return get_cert_name_string(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0);
1164 static WCHAR *field_format_detailed_subject(PCCERT_CONTEXT cert, void *param)
1166 return field_format_detailed_cert_name(&cert->pCertInfo->Subject);
1169 static WCHAR *format_long_date(const FILETIME *fileTime)
1171 WCHAR dateFmt[80]; /* long enough for LOCALE_SLONGDATE */
1172 DWORD len;
1173 WCHAR *buf = NULL;
1174 SYSTEMTIME sysTime;
1176 /* FIXME: format isn't quite right, want time too */
1177 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SLONGDATE, dateFmt,
1178 sizeof(dateFmt) / sizeof(dateFmt[0]));
1179 FileTimeToSystemTime(fileTime, &sysTime);
1180 len = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, NULL, 0);
1181 if (len)
1183 buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1184 if (buf)
1185 GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, buf,
1186 len);
1188 return buf;
1191 static WCHAR *field_format_from_date(PCCERT_CONTEXT cert)
1193 return format_long_date(&cert->pCertInfo->NotBefore);
1196 static WCHAR *field_format_to_date(PCCERT_CONTEXT cert)
1198 return format_long_date(&cert->pCertInfo->NotAfter);
1201 static WCHAR *field_format_public_key(PCCERT_CONTEXT cert)
1203 PCCRYPT_OID_INFO oidInfo;
1204 WCHAR *buf = NULL;
1206 oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
1207 cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, 0);
1208 if (oidInfo)
1210 WCHAR fmt[MAX_STRING_LEN];
1212 if (LoadStringW(hInstance, IDS_FIELD_PUBLIC_KEY_FORMAT, fmt,
1213 sizeof(fmt) / sizeof(fmt[0])))
1215 /* Allocate the output buffer. Use the number of bytes in the
1216 * public key as a conservative (high) estimate for the number of
1217 * digits in its output.
1218 * The output is of the form (in English)
1219 * "<public key algorithm> (<public key bit length> bits)".
1220 * Ordinarily having two positional parameters in a string is not a
1221 * good idea, but as this isn't a sentence fragment, it shouldn't
1222 * be word-order dependent.
1224 buf = HeapAlloc(GetProcessHeap(), 0,
1225 (strlenW(fmt) + strlenW(oidInfo->pwszName) +
1226 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData * 8)
1227 * sizeof(WCHAR));
1228 if (buf)
1229 sprintfW(buf, fmt, oidInfo->pwszName,
1230 CertGetPublicKeyLength(X509_ASN_ENCODING,
1231 &cert->pCertInfo->SubjectPublicKeyInfo));
1234 return buf;
1237 static WCHAR *field_format_detailed_public_key(PCCERT_CONTEXT cert, void *param)
1239 return format_hex_string(
1240 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
1241 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData);
1244 struct field_value_data;
1245 struct detail_data
1247 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo;
1248 BOOL *pfPropertiesChanged;
1249 int cFields;
1250 struct field_value_data *fields;
1253 typedef void (*add_fields_func)(HWND hwnd, struct detail_data *data);
1255 typedef WCHAR *(*create_detailed_value_func)(PCCERT_CONTEXT cert, void *param);
1257 struct field_value_data
1259 create_detailed_value_func create;
1260 LPWSTR detailed_value;
1261 void *param;
1264 static void add_field_value_data(struct detail_data *data,
1265 create_detailed_value_func create, void *param)
1267 if (data->cFields)
1268 data->fields = HeapReAlloc(GetProcessHeap(), 0, data->fields,
1269 (data->cFields + 1) * sizeof(struct field_value_data));
1270 else
1271 data->fields = HeapAlloc(GetProcessHeap(), 0,
1272 sizeof(struct field_value_data));
1273 if (data->fields)
1275 data->fields[data->cFields].create = create;
1276 data->fields[data->cFields].detailed_value = NULL;
1277 data->fields[data->cFields].param = param;
1278 data->cFields++;
1282 static void add_field_and_value_to_list(HWND hwnd, struct detail_data *data,
1283 LPWSTR field, LPWSTR value, create_detailed_value_func create, void *param)
1285 LVITEMW item;
1286 int iItem = SendMessageW(hwnd, LVM_GETITEMCOUNT, 0, 0);
1288 item.mask = LVIF_TEXT | LVIF_PARAM;
1289 item.iItem = iItem;
1290 item.iSubItem = 0;
1291 item.pszText = field;
1292 item.lParam = (LPARAM)data;
1293 SendMessageW(hwnd, LVM_INSERTITEMW, 0, (LPARAM)&item);
1294 if (value)
1296 item.pszText = value;
1297 item.iSubItem = 1;
1298 SendMessageW(hwnd, LVM_SETITEMTEXTW, iItem, (LPARAM)&item);
1300 add_field_value_data(data, create, param);
1303 static void add_string_id_and_value_to_list(HWND hwnd, struct detail_data *data,
1304 int id, LPWSTR value, create_detailed_value_func create, void *param)
1306 WCHAR buf[MAX_STRING_LEN];
1308 LoadStringW(hInstance, id, buf, sizeof(buf) / sizeof(buf[0]));
1309 add_field_and_value_to_list(hwnd, data, buf, value, create, param);
1312 struct v1_field
1314 int id;
1315 field_format_func format;
1316 create_detailed_value_func create_detailed_value;
1319 static void add_v1_field(HWND hwnd, struct detail_data *data,
1320 const struct v1_field *field)
1322 WCHAR *val = field->format(data->pCertViewInfo->pCertContext);
1324 if (val)
1326 add_string_id_and_value_to_list(hwnd, data, field->id, val,
1327 field->create_detailed_value, NULL);
1328 HeapFree(GetProcessHeap(), 0, val);
1332 static const struct v1_field v1_fields[] = {
1333 { IDS_FIELD_VERSION, field_format_version, NULL },
1334 { IDS_FIELD_SERIAL_NUMBER, field_format_serial_number, NULL },
1335 { IDS_FIELD_ISSUER, field_format_issuer, field_format_detailed_issuer },
1336 { IDS_FIELD_VALID_FROM, field_format_from_date, NULL },
1337 { IDS_FIELD_VALID_TO, field_format_to_date, NULL },
1338 { IDS_FIELD_SUBJECT, field_format_subject, field_format_detailed_subject },
1339 { IDS_FIELD_PUBLIC_KEY, field_format_public_key,
1340 field_format_detailed_public_key }
1343 static void add_v1_fields(HWND hwnd, struct detail_data *data)
1345 int i;
1346 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
1348 /* The last item in v1_fields is the public key, which is not in the loop
1349 * because it's a special case.
1351 for (i = 0; i < sizeof(v1_fields) / sizeof(v1_fields[0]) - 1; i++)
1352 add_v1_field(hwnd, data, &v1_fields[i]);
1353 if (cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData)
1354 add_v1_field(hwnd, data, &v1_fields[i]);
1357 static WCHAR *crypt_format_extension(PCERT_EXTENSION ext, DWORD formatStrType)
1359 WCHAR *str = NULL;
1360 DWORD size;
1362 if (CryptFormatObject(X509_ASN_ENCODING, 0, formatStrType, NULL,
1363 ext->pszObjId, ext->Value.pbData, ext->Value.cbData, NULL, &size))
1365 str = HeapAlloc(GetProcessHeap(), 0, size);
1366 CryptFormatObject(X509_ASN_ENCODING, 0, formatStrType, NULL,
1367 ext->pszObjId, ext->Value.pbData, ext->Value.cbData, str, &size);
1369 return str;
1372 static WCHAR *field_format_extension_hex_with_ascii(PCERT_EXTENSION ext)
1374 WCHAR *str = NULL;
1376 if (ext->Value.cbData)
1378 /* The output is formatted as:
1379 * <hex bytes> <ascii bytes>\n
1380 * where <hex bytes> is a string of up to 8 bytes, output as %02x,
1381 * and <ascii bytes> is the ASCII equivalent of each byte, or '.' if
1382 * the byte is not printable.
1383 * So, for example, the extension value consisting of the following
1384 * bytes:
1385 * 0x30,0x14,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x03,
1386 * 0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67
1387 * is output as:
1388 * 30 14 31 12 30 10 06 03 0.1.0...
1389 * 55 04 03 13 09 4a 75 61 U....Jua
1390 * 6e 20 4c 61 6e 67 n Lang
1391 * The allocation size therefore requires:
1392 * - 4 characters per character in an 8-byte line
1393 * (2 for the hex format, one for the space, one for the ASCII value)
1394 * - 3 more characters per 8-byte line (two spaces and a newline)
1395 * - 1 character for the terminating nul
1396 * FIXME: should use a fixed-width font for this
1398 DWORD lines = (ext->Value.cbData + 7) / 8;
1400 str = HeapAlloc(GetProcessHeap(), 0,
1401 (lines * 8 * 4 + lines * 3 + 1) * sizeof(WCHAR));
1402 if (str)
1404 static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
1405 DWORD i, j;
1406 WCHAR *ptr;
1408 for (i = 0, ptr = str; i < ext->Value.cbData; i += 8)
1410 /* Output as hex bytes first */
1411 for (j = i; j < min(i + 8, ext->Value.cbData); j++, ptr += 3)
1412 sprintfW(ptr, fmt, ext->Value.pbData[j]);
1413 /* Pad the hex output with spaces for alignment */
1414 if (j == ext->Value.cbData && j % 8)
1416 static const WCHAR pad[] = { ' ',' ',' ' };
1418 for (; j % 8; j++, ptr += sizeof(pad) / sizeof(pad[0]))
1419 memcpy(ptr, pad, sizeof(pad));
1421 /* The last sprintfW included a space, so just insert one
1422 * more space between the hex bytes and the ASCII output
1424 *ptr++ = ' ';
1425 /* Output as ASCII bytes */
1426 for (j = i; j < min(i + 8, ext->Value.cbData); j++, ptr++)
1428 if (isprintW(ext->Value.pbData[j]) &&
1429 !isspaceW(ext->Value.pbData[j]))
1430 *ptr = ext->Value.pbData[j];
1431 else
1432 *ptr = '.';
1434 *ptr++ = '\n';
1436 *ptr++ = '\0';
1439 return str;
1442 static WCHAR *field_format_detailed_extension(PCCERT_CONTEXT cert, void *param)
1444 PCERT_EXTENSION ext = param;
1445 LPWSTR str = crypt_format_extension(ext,
1446 CRYPT_FORMAT_STR_MULTI_LINE | CRYPT_FORMAT_STR_NO_HEX);
1448 if (!str)
1449 str = field_format_extension_hex_with_ascii(ext);
1450 return str;
1453 static void add_cert_extension_detail(HWND hwnd, struct detail_data *data,
1454 PCERT_EXTENSION ext)
1456 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
1457 ext->pszObjId, 0);
1458 LPWSTR val = crypt_format_extension(ext, 0);
1460 if (oidInfo)
1461 add_field_and_value_to_list(hwnd, data, (LPWSTR)oidInfo->pwszName,
1462 val, field_format_detailed_extension, ext);
1463 else
1465 DWORD len = strlen(ext->pszObjId);
1466 LPWSTR oidW = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1468 if (oidW)
1470 DWORD i;
1472 for (i = 0; i <= len; i++)
1473 oidW[i] = ext->pszObjId[i];
1474 add_field_and_value_to_list(hwnd, data, oidW, val,
1475 field_format_detailed_extension, ext);
1476 HeapFree(GetProcessHeap(), 0, oidW);
1479 HeapFree(GetProcessHeap(), 0, val);
1482 static void add_all_extensions(HWND hwnd, struct detail_data *data)
1484 DWORD i;
1485 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
1487 for (i = 0; i < cert->pCertInfo->cExtension; i++)
1488 add_cert_extension_detail(hwnd, data, &cert->pCertInfo->rgExtension[i]);
1491 static void add_critical_extensions(HWND hwnd, struct detail_data *data)
1493 DWORD i;
1494 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
1496 for (i = 0; i < cert->pCertInfo->cExtension; i++)
1497 if (cert->pCertInfo->rgExtension[i].fCritical)
1498 add_cert_extension_detail(hwnd, data,
1499 &cert->pCertInfo->rgExtension[i]);
1502 typedef WCHAR * (*prop_to_value_func)(void *pb, DWORD cb);
1504 struct prop_id_to_string_id
1506 DWORD prop;
1507 int id;
1508 BOOL prop_is_string;
1509 prop_to_value_func prop_to_value;
1512 static WCHAR *format_enhanced_key_usage_value(void *pb, DWORD cb)
1514 CERT_EXTENSION ext;
1516 ext.pszObjId = (LPSTR)X509_ENHANCED_KEY_USAGE;
1517 ext.fCritical = FALSE;
1518 ext.Value.pbData = pb;
1519 ext.Value.cbData = cb;
1520 return crypt_format_extension(&ext, 0);
1523 /* Logically the access state should also be checked, and IDC_EDITPROPERTIES
1524 * disabled for read-only certificates, but native doesn't appear to do that.
1526 static const struct prop_id_to_string_id prop_id_map[] = {
1527 { CERT_HASH_PROP_ID, IDS_PROP_HASH, FALSE, format_hex_string },
1528 { CERT_FRIENDLY_NAME_PROP_ID, IDS_PROP_FRIENDLY_NAME, TRUE, NULL },
1529 { CERT_DESCRIPTION_PROP_ID, IDS_PROP_DESCRIPTION, TRUE, NULL },
1530 { CERT_ENHKEY_USAGE_PROP_ID, IDS_PROP_ENHKEY_USAGE, FALSE,
1531 format_enhanced_key_usage_value },
1534 static void add_properties(HWND hwnd, struct detail_data *data)
1536 DWORD i;
1537 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
1539 for (i = 0; i < sizeof(prop_id_map) / sizeof(prop_id_map[0]); i++)
1541 DWORD cb;
1543 if (CertGetCertificateContextProperty(cert, prop_id_map[i].prop, NULL,
1544 &cb))
1546 BYTE *pb;
1547 WCHAR *val = NULL;
1549 /* FIXME: MS adds a separate value for the signature hash
1550 * algorithm.
1552 pb = HeapAlloc(GetProcessHeap(), 0, cb);
1553 if (pb)
1555 if (CertGetCertificateContextProperty(cert,
1556 prop_id_map[i].prop, pb, &cb))
1558 if (prop_id_map[i].prop_is_string)
1560 val = (LPWSTR)pb;
1561 /* Don't double-free pb */
1562 pb = NULL;
1564 else
1565 val = prop_id_map[i].prop_to_value(pb, cb);
1567 HeapFree(GetProcessHeap(), 0, pb);
1569 add_string_id_and_value_to_list(hwnd, data, prop_id_map[i].id, val,
1570 NULL, NULL);
1575 static void add_all_fields(HWND hwnd, struct detail_data *data)
1577 add_v1_fields(hwnd, data);
1578 add_all_extensions(hwnd, data);
1579 add_properties(hwnd, data);
1582 struct selection_list_item
1584 int id;
1585 add_fields_func add;
1588 const struct selection_list_item listItems[] = {
1589 { IDS_FIELDS_ALL, add_all_fields },
1590 { IDS_FIELDS_V1, add_v1_fields },
1591 { IDS_FIELDS_EXTENSIONS, add_all_extensions },
1592 { IDS_FIELDS_CRITICAL_EXTENSIONS, add_critical_extensions },
1593 { IDS_FIELDS_PROPERTIES, add_properties },
1596 static void create_show_list(HWND hwnd, struct detail_data *data)
1598 HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT);
1599 WCHAR buf[MAX_STRING_LEN];
1600 int i;
1602 for (i = 0; i < sizeof(listItems) / sizeof(listItems[0]); i++)
1604 int index;
1606 LoadStringW(hInstance, listItems[i].id, buf,
1607 sizeof(buf) / sizeof(buf[0]));
1608 index = SendMessageW(cb, CB_INSERTSTRING, -1, (LPARAM)buf);
1609 SendMessageW(cb, CB_SETITEMDATA, index, (LPARAM)data);
1611 SendMessageW(cb, CB_SETCURSEL, 0, 0);
1614 static void create_listview_columns(HWND hwnd)
1616 HWND lv = GetDlgItem(hwnd, IDC_DETAIL_LIST);
1617 RECT rc;
1618 WCHAR buf[MAX_STRING_LEN];
1619 LVCOLUMNW column;
1621 SendMessageW(lv, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
1622 GetWindowRect(lv, &rc);
1623 LoadStringW(hInstance, IDS_FIELD, buf, sizeof(buf) / sizeof(buf[0]));
1624 column.mask = LVCF_WIDTH | LVCF_TEXT;
1625 column.cx = (rc.right - rc.left) / 2 - 2;
1626 column.pszText = buf;
1627 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
1628 LoadStringW(hInstance, IDS_VALUE, buf, sizeof(buf) / sizeof(buf[0]));
1629 SendMessageW(lv, LVM_INSERTCOLUMNW, 1, (LPARAM)&column);
1632 static void set_fields_selection(HWND hwnd, struct detail_data *data, int sel)
1634 HWND list = GetDlgItem(hwnd, IDC_DETAIL_LIST);
1636 if (sel >= 0 && sel < sizeof(listItems) / sizeof(listItems[0]))
1638 SendMessageW(list, LVM_DELETEALLITEMS, 0, 0);
1639 listItems[sel].add(list, data);
1643 static void create_cert_details_list(HWND hwnd, struct detail_data *data)
1645 create_show_list(hwnd, data);
1646 create_listview_columns(hwnd);
1647 set_fields_selection(hwnd, data, 0);
1650 typedef enum {
1651 CheckBitmapIndexUnchecked = 1,
1652 CheckBitmapIndexChecked = 2,
1653 CheckBitmapIndexDisabledUnchecked = 3,
1654 CheckBitmapIndexDisabledChecked = 4
1655 } CheckBitmapIndex;
1657 static void add_purpose(HWND hwnd, LPCSTR oid)
1659 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
1660 PCRYPT_OID_INFO info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1661 sizeof(CRYPT_OID_INFO));
1663 if (info)
1665 char *oidCopy = HeapAlloc(GetProcessHeap(), 0, strlen(oid) + 1);
1667 if (oidCopy)
1669 LVITEMA item;
1671 strcpy(oidCopy, oid);
1672 info->cbSize = sizeof(CRYPT_OID_INFO);
1673 info->pszOID = oidCopy;
1674 item.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM;
1675 item.state = INDEXTOSTATEIMAGEMASK(CheckBitmapIndexChecked);
1676 item.stateMask = LVIS_STATEIMAGEMASK;
1677 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
1678 item.iSubItem = 0;
1679 item.lParam = (LPARAM)info;
1680 item.pszText = oidCopy;
1681 SendMessageA(lv, LVM_INSERTITEMA, 0, (LPARAM)&item);
1683 else
1684 HeapFree(GetProcessHeap(), 0, info);
1688 static BOOL is_valid_oid(LPCSTR oid)
1690 BOOL ret;
1692 if (oid[0] != '0' && oid[0] != '1' && oid[0] != '2')
1693 ret = FALSE;
1694 else if (oid[1] != '.')
1695 ret = FALSE;
1696 else if (!oid[2])
1697 ret = FALSE;
1698 else
1700 const char *ptr;
1701 BOOL expectNum = TRUE;
1703 for (ptr = oid + 2, ret = TRUE; ret && *ptr; ptr++)
1705 if (expectNum)
1707 if (!isdigit(*ptr))
1708 ret = FALSE;
1709 else if (*(ptr + 1) == '.')
1710 expectNum = FALSE;
1712 else
1714 if (*ptr != '.')
1715 ret = FALSE;
1716 else if (!(*(ptr + 1)))
1717 ret = FALSE;
1718 else
1719 expectNum = TRUE;
1723 return ret;
1726 static BOOL is_oid_in_list(HWND hwnd, LPCSTR oid)
1728 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
1729 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
1730 (void *)oid, CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
1731 BOOL ret = FALSE;
1733 if (oidInfo)
1735 LVFINDINFOW findInfo;
1737 findInfo.flags = LVFI_PARAM;
1738 findInfo.lParam = (LPARAM)oidInfo;
1739 if (SendMessageW(lv, LVM_FINDITEMW, -1, (LPARAM)&findInfo) != -1)
1740 ret = TRUE;
1742 else
1744 LVFINDINFOA findInfo;
1746 findInfo.flags = LVFI_STRING;
1747 findInfo.psz = oid;
1748 if (SendMessageW(lv, LVM_FINDITEMA, -1, (LPARAM)&findInfo) != -1)
1749 ret = TRUE;
1751 return ret;
1754 #define MAX_PURPOSE 255
1756 static LRESULT CALLBACK add_purpose_dlg_proc(HWND hwnd, UINT msg,
1757 WPARAM wp, LPARAM lp)
1759 LRESULT ret = 0;
1760 char buf[MAX_PURPOSE + 1];
1762 switch (msg)
1764 case WM_INITDIALOG:
1765 SendMessageW(GetDlgItem(hwnd, IDC_NEW_PURPOSE), EM_SETLIMITTEXT,
1766 MAX_PURPOSE, 0);
1767 ShowScrollBar(GetDlgItem(hwnd, IDC_NEW_PURPOSE), SB_VERT, FALSE);
1768 SetWindowLongPtrW(hwnd, DWLP_USER, lp);
1769 break;
1770 case WM_COMMAND:
1771 switch (HIWORD(wp))
1773 case EN_CHANGE:
1774 if (LOWORD(wp) == IDC_NEW_PURPOSE)
1776 /* Show/hide scroll bar on description depending on how much
1777 * text it has.
1779 HWND description = GetDlgItem(hwnd, IDC_NEW_PURPOSE);
1780 int lines = SendMessageW(description, EM_GETLINECOUNT, 0, 0);
1782 ShowScrollBar(description, SB_VERT, lines > 1);
1784 break;
1785 case BN_CLICKED:
1786 switch (LOWORD(wp))
1788 case IDOK:
1789 SendMessageA(GetDlgItem(hwnd, IDC_NEW_PURPOSE), WM_GETTEXT,
1790 sizeof(buf) / sizeof(buf[0]), (LPARAM)buf);
1791 if (!buf[0])
1793 /* An empty purpose is the same as cancelling */
1794 EndDialog(hwnd, IDCANCEL);
1795 ret = TRUE;
1797 else if (!is_valid_oid(buf))
1799 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
1801 LoadStringW(hInstance, IDS_CERTIFICATE_PURPOSE_ERROR, error,
1802 sizeof(error) / sizeof(error[0]));
1803 LoadStringW(hInstance, IDS_CERTIFICATE_PROPERTIES, title,
1804 sizeof(title) / sizeof(title[0]));
1805 MessageBoxW(hwnd, error, title, MB_ICONERROR | MB_OK);
1807 else if (is_oid_in_list(
1808 (HWND)GetWindowLongPtrW(hwnd, DWLP_USER), buf))
1810 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
1812 LoadStringW(hInstance, IDS_CERTIFICATE_PURPOSE_EXISTS,
1813 error, sizeof(error) / sizeof(error[0]));
1814 LoadStringW(hInstance, IDS_CERTIFICATE_PROPERTIES, title,
1815 sizeof(title) / sizeof(title[0]));
1816 MessageBoxW(hwnd, error, title, MB_ICONEXCLAMATION | MB_OK);
1818 else
1820 HWND parent = (HWND)GetWindowLongPtrW(hwnd, DWLP_USER);
1822 add_purpose(parent, buf);
1823 EndDialog(hwnd, wp);
1824 ret = TRUE;
1826 break;
1827 case IDCANCEL:
1828 EndDialog(hwnd, wp);
1829 ret = TRUE;
1830 break;
1832 break;
1834 break;
1836 return ret;
1839 static WCHAR *get_cert_property_as_string(PCCERT_CONTEXT cert, DWORD prop)
1841 WCHAR *name = NULL;
1842 DWORD cb;
1844 if (CertGetCertificateContextProperty(cert, prop, NULL, &cb))
1846 name = HeapAlloc(GetProcessHeap(), 0, cb);
1847 if (name)
1849 if (!CertGetCertificateContextProperty(cert, prop, (LPBYTE)name,
1850 &cb))
1852 HeapFree(GetProcessHeap(), 0, name);
1853 name = NULL;
1857 return name;
1860 static void redraw_states(HWND list, BOOL enabled)
1862 int items = SendMessageW(list, LVM_GETITEMCOUNT, 0, 0), i;
1864 for (i = 0; i < items; i++)
1866 BOOL change = FALSE;
1867 int state;
1869 state = SendMessageW(list, LVM_GETITEMSTATE, i, LVIS_STATEIMAGEMASK);
1870 /* This reverses the INDEXTOSTATEIMAGEMASK shift. There doesn't appear
1871 * to be a handy macro for it.
1873 state >>= 12;
1874 if (enabled)
1876 if (state == CheckBitmapIndexDisabledChecked)
1878 state = CheckBitmapIndexChecked;
1879 change = TRUE;
1881 if (state == CheckBitmapIndexDisabledUnchecked)
1883 state = CheckBitmapIndexUnchecked;
1884 change = TRUE;
1887 else
1889 if (state == CheckBitmapIndexChecked)
1891 state = CheckBitmapIndexDisabledChecked;
1892 change = TRUE;
1894 if (state == CheckBitmapIndexUnchecked)
1896 state = CheckBitmapIndexDisabledUnchecked;
1897 change = TRUE;
1900 if (change)
1902 LVITEMW item;
1904 item.state = INDEXTOSTATEIMAGEMASK(state);
1905 item.stateMask = LVIS_STATEIMAGEMASK;
1906 SendMessageW(list, LVM_SETITEMSTATE, i, (LPARAM)&item);
1911 typedef enum {
1912 PurposeEnableAll = 0,
1913 PurposeDisableAll,
1914 PurposeEnableSelected
1915 } PurposeSelection;
1917 static void select_purposes(HWND hwnd, PurposeSelection selection)
1919 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
1921 switch (selection)
1923 case PurposeEnableAll:
1924 case PurposeDisableAll:
1925 EnableWindow(lv, FALSE);
1926 redraw_states(lv, FALSE);
1927 EnableWindow(GetDlgItem(hwnd, IDC_ADD_PURPOSE), FALSE);
1928 break;
1929 case PurposeEnableSelected:
1930 EnableWindow(lv, TRUE);
1931 redraw_states(lv, TRUE);
1932 EnableWindow(GetDlgItem(hwnd, IDC_ADD_PURPOSE), TRUE);
1936 extern BOOL WINAPI WTHelperGetKnownUsages(DWORD action,
1937 PCCRYPT_OID_INFO **usages);
1939 static void add_known_usage(HWND lv, PCCRYPT_OID_INFO info)
1941 LVITEMW item;
1943 item.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM;
1944 item.state = INDEXTOSTATEIMAGEMASK(CheckBitmapIndexDisabledChecked);
1945 item.stateMask = LVIS_STATEIMAGEMASK;
1946 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
1947 item.iSubItem = 0;
1948 item.lParam = (LPARAM)info;
1949 item.pszText = (LPWSTR)info->pwszName;
1950 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
1953 struct edit_cert_data
1955 PCCERT_CONTEXT cert;
1956 BOOL *pfPropertiesChanged;
1957 HIMAGELIST imageList;
1960 static void show_cert_usages(HWND hwnd, struct edit_cert_data *data)
1962 PCCERT_CONTEXT cert = data->cert;
1963 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
1964 PCERT_ENHKEY_USAGE usage;
1965 DWORD size;
1966 PCCRYPT_OID_INFO *usages;
1967 RECT rc;
1968 LVCOLUMNW column;
1969 PurposeSelection purposeSelection;
1971 GetWindowRect(lv, &rc);
1972 column.mask = LVCF_WIDTH;
1973 column.cx = rc.right - rc.left;
1974 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
1975 SendMessageW(lv, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)data->imageList);
1977 /* Get enhanced key usage. Have to check for a property and an extension
1978 * separately, because CertGetEnhancedKeyUsage will succeed and return an
1979 * empty usage if neither is set. Unfortunately an empty usage implies
1980 * no usage is allowed, so we have to distinguish between the two cases.
1982 if (CertGetEnhancedKeyUsage(cert, CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG,
1983 NULL, &size))
1985 usage = HeapAlloc(GetProcessHeap(), 0, size);
1986 if (!CertGetEnhancedKeyUsage(cert,
1987 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size))
1989 HeapFree(GetProcessHeap(), 0, usage);
1990 usage = NULL;
1992 else if (usage->cUsageIdentifier)
1993 purposeSelection = PurposeEnableSelected;
1994 else
1995 purposeSelection = PurposeDisableAll;
1997 else if (CertGetEnhancedKeyUsage(cert, CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
1998 NULL, &size))
2000 usage = HeapAlloc(GetProcessHeap(), 0, size);
2001 if (!CertGetEnhancedKeyUsage(cert,
2002 CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, usage, &size))
2004 HeapFree(GetProcessHeap(), 0, usage);
2005 usage = NULL;
2007 else if (usage->cUsageIdentifier)
2008 purposeSelection = PurposeEnableAll;
2009 else
2010 purposeSelection = PurposeDisableAll;
2012 else
2014 purposeSelection = PurposeEnableAll;
2015 usage = NULL;
2017 if (usage)
2019 DWORD i;
2021 for (i = 0; i < usage->cUsageIdentifier; i++)
2023 PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2024 usage->rgpszUsageIdentifier[i], CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
2026 if (info)
2027 add_known_usage(lv, info);
2028 else
2029 add_purpose(hwnd, usage->rgpszUsageIdentifier[i]);
2031 HeapFree(GetProcessHeap(), 0, usage);
2033 else
2035 if (WTHelperGetKnownUsages(1, &usages))
2037 PCCRYPT_OID_INFO *ptr;
2039 for (ptr = usages; *ptr; ptr++)
2040 add_known_usage(lv, *ptr);
2041 WTHelperGetKnownUsages(2, &usages);
2044 select_purposes(hwnd, purposeSelection);
2045 SendMessageW(GetDlgItem(hwnd, IDC_ENABLE_ALL_PURPOSES + purposeSelection),
2046 BM_CLICK, 0, 0);
2049 static void set_general_cert_properties(HWND hwnd, struct edit_cert_data *data)
2051 PCCERT_CONTEXT cert = data->cert;
2052 WCHAR *str;
2054 if ((str = get_cert_property_as_string(cert, CERT_FRIENDLY_NAME_PROP_ID)))
2056 SendMessageW(GetDlgItem(hwnd, IDC_FRIENDLY_NAME), WM_SETTEXT, 0,
2057 (LPARAM)str);
2058 HeapFree(GetProcessHeap(), 0, str);
2060 if ((str = get_cert_property_as_string(cert, CERT_DESCRIPTION_PROP_ID)))
2062 SendMessageW(GetDlgItem(hwnd, IDC_DESCRIPTION), WM_SETTEXT, 0,
2063 (LPARAM)str);
2064 HeapFree(GetProcessHeap(), 0, str);
2066 show_cert_usages(hwnd, data);
2069 static void toggle_usage(HWND hwnd, int iItem)
2071 LVITEMW item;
2072 int res;
2073 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
2075 item.mask = LVIF_STATE;
2076 item.iItem = iItem;
2077 item.iSubItem = 0;
2078 item.stateMask = LVIS_STATEIMAGEMASK;
2079 res = SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item);
2080 if (res)
2082 int state = item.state >> 12;
2084 item.state = INDEXTOSTATEIMAGEMASK(
2085 state == CheckBitmapIndexChecked ? CheckBitmapIndexUnchecked :
2086 CheckBitmapIndexChecked);
2087 SendMessageW(lv, LVM_SETITEMSTATE, iItem, (LPARAM)&item);
2091 static void set_cert_string_property(PCCERT_CONTEXT cert, DWORD prop,
2092 LPWSTR str)
2094 if (str && strlenW(str))
2096 CRYPT_DATA_BLOB blob;
2098 blob.pbData = (BYTE *)str;
2099 blob.cbData = (strlenW(str) + 1) * sizeof(WCHAR);
2100 CertSetCertificateContextProperty(cert, prop, 0, &blob);
2102 else
2103 CertSetCertificateContextProperty(cert, prop, 0, NULL);
2106 #define WM_REFRESH_VIEW WM_USER + 0
2108 static BOOL CALLBACK refresh_propsheet_pages(HWND hwnd, LPARAM lParam)
2110 if ((GetClassLongW(hwnd, GCW_ATOM) == WC_DIALOG))
2111 SendMessageW(hwnd, WM_REFRESH_VIEW, 0, 0);
2112 return TRUE;
2115 #define MAX_FRIENDLY_NAME 40
2116 #define MAX_DESCRIPTION 255
2118 static void apply_general_changes(HWND hwnd)
2120 WCHAR buf[MAX_DESCRIPTION + 1];
2121 struct edit_cert_data *data =
2122 (struct edit_cert_data *)GetWindowLongPtrW(hwnd, DWLP_USER);
2124 SendMessageW(GetDlgItem(hwnd, IDC_FRIENDLY_NAME), WM_GETTEXT,
2125 sizeof(buf) / sizeof(buf[0]), (LPARAM)buf);
2126 set_cert_string_property(data->cert, CERT_FRIENDLY_NAME_PROP_ID, buf);
2127 SendMessageW(GetDlgItem(hwnd, IDC_DESCRIPTION), WM_GETTEXT,
2128 sizeof(buf) / sizeof(buf[0]), (LPARAM)buf);
2129 set_cert_string_property(data->cert, CERT_DESCRIPTION_PROP_ID, buf);
2130 if (IsDlgButtonChecked(hwnd, IDC_ENABLE_ALL_PURPOSES))
2132 /* Setting a NULL usage removes the enhanced key usage property. */
2133 CertSetEnhancedKeyUsage(data->cert, NULL);
2135 else if (IsDlgButtonChecked(hwnd, IDC_DISABLE_ALL_PURPOSES))
2137 CERT_ENHKEY_USAGE usage = { 0, NULL };
2139 CertSetEnhancedKeyUsage(data->cert, &usage);
2141 else if (IsDlgButtonChecked(hwnd, IDC_ENABLE_SELECTED_PURPOSES))
2143 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
2144 CERT_ENHKEY_USAGE usage = { 0, NULL };
2145 int purposes = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0), i;
2146 LVITEMW item;
2148 item.mask = LVIF_STATE | LVIF_PARAM;
2149 item.iSubItem = 0;
2150 item.stateMask = LVIS_STATEIMAGEMASK;
2151 for (i = 0; i < purposes; i++)
2153 item.iItem = i;
2154 if (SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item))
2156 int state = item.state >> 12;
2158 if (state == CheckBitmapIndexChecked)
2160 CRYPT_OID_INFO *info = (CRYPT_OID_INFO *)item.lParam;
2162 if (usage.cUsageIdentifier)
2163 usage.rgpszUsageIdentifier =
2164 HeapReAlloc(GetProcessHeap(), 0,
2165 usage.rgpszUsageIdentifier,
2166 (usage.cUsageIdentifier + 1) * sizeof(LPSTR));
2167 else
2168 usage.rgpszUsageIdentifier =
2169 HeapAlloc(GetProcessHeap(), 0, sizeof(LPSTR));
2170 if (usage.rgpszUsageIdentifier)
2171 usage.rgpszUsageIdentifier[usage.cUsageIdentifier++] =
2172 (LPSTR)info->pszOID;
2176 CertSetEnhancedKeyUsage(data->cert, &usage);
2177 HeapFree(GetProcessHeap(), 0, usage.rgpszUsageIdentifier);
2179 EnumChildWindows(GetParent(GetParent(hwnd)), refresh_propsheet_pages, 0);
2180 if (data->pfPropertiesChanged)
2181 *data->pfPropertiesChanged = TRUE;
2184 static LRESULT CALLBACK cert_properties_general_dlg_proc(HWND hwnd, UINT msg,
2185 WPARAM wp, LPARAM lp)
2187 PROPSHEETPAGEW *page;
2189 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
2191 switch (msg)
2193 case WM_INITDIALOG:
2195 HWND description = GetDlgItem(hwnd, IDC_DESCRIPTION);
2196 struct detail_data *detailData;
2197 struct edit_cert_data *editData;
2199 page = (PROPSHEETPAGEW *)lp;
2200 detailData = (struct detail_data *)page->lParam;
2201 SendMessageW(GetDlgItem(hwnd, IDC_FRIENDLY_NAME), EM_SETLIMITTEXT,
2202 MAX_FRIENDLY_NAME, 0);
2203 SendMessageW(description, EM_SETLIMITTEXT, MAX_DESCRIPTION, 0);
2204 ShowScrollBar(description, SB_VERT, FALSE);
2205 editData = HeapAlloc(GetProcessHeap(), 0,
2206 sizeof(struct edit_cert_data));
2207 if (editData)
2209 editData->imageList = ImageList_Create(16, 16,
2210 ILC_COLOR4 | ILC_MASK, 4, 0);
2211 if (editData->imageList)
2213 HBITMAP bmp;
2214 COLORREF backColor = RGB(255, 0, 255);
2216 bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_CHECKS));
2217 ImageList_AddMasked(editData->imageList, bmp, backColor);
2218 DeleteObject(bmp);
2219 ImageList_SetBkColor(editData->imageList, CLR_NONE);
2221 editData->cert = detailData->pCertViewInfo->pCertContext;
2222 editData->pfPropertiesChanged = detailData->pfPropertiesChanged;
2223 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)editData);
2224 set_general_cert_properties(hwnd, editData);
2226 break;
2228 case WM_NOTIFY:
2230 NMHDR *hdr = (NMHDR *)lp;
2231 NMITEMACTIVATE *nm;
2233 switch (hdr->code)
2235 case NM_CLICK:
2236 nm = (NMITEMACTIVATE *)lp;
2237 toggle_usage(hwnd, nm->iItem);
2238 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
2239 break;
2240 case PSN_APPLY:
2241 apply_general_changes(hwnd);
2242 break;
2244 break;
2246 case WM_COMMAND:
2247 switch (HIWORD(wp))
2249 case EN_CHANGE:
2250 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
2251 if (LOWORD(wp) == IDC_DESCRIPTION)
2253 /* Show/hide scroll bar on description depending on how much
2254 * text it has.
2256 HWND description = GetDlgItem(hwnd, IDC_DESCRIPTION);
2257 int lines = SendMessageW(description, EM_GETLINECOUNT, 0, 0);
2259 ShowScrollBar(description, SB_VERT, lines > 1);
2261 break;
2262 case BN_CLICKED:
2263 switch (LOWORD(wp))
2265 case IDC_ADD_PURPOSE:
2266 if (DialogBoxParamW(hInstance,
2267 MAKEINTRESOURCEW(IDD_ADD_CERT_PURPOSE), hwnd,
2268 add_purpose_dlg_proc, (LPARAM)hwnd) == IDOK)
2269 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
2270 break;
2271 case IDC_ENABLE_ALL_PURPOSES:
2272 case IDC_DISABLE_ALL_PURPOSES:
2273 case IDC_ENABLE_SELECTED_PURPOSES:
2274 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
2275 select_purposes(hwnd, LOWORD(wp) - IDC_ENABLE_ALL_PURPOSES);
2276 break;
2278 break;
2280 break;
2282 return 0;
2285 static UINT CALLBACK cert_properties_general_callback(HWND hwnd, UINT msg,
2286 PROPSHEETPAGEW *page)
2288 HWND lv;
2289 int cItem, i;
2290 struct edit_cert_data *data;
2292 switch (msg)
2294 case PSPCB_RELEASE:
2295 lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
2296 cItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
2297 for (i = 0; i < cItem; i++)
2299 LVITEMW item;
2301 item.mask = LVIF_PARAM;
2302 item.iItem = i;
2303 item.iSubItem = 0;
2304 if (SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item) && item.lParam)
2306 PCRYPT_OID_INFO info = (PCRYPT_OID_INFO)item.lParam;
2308 if (info->cbSize == sizeof(CRYPT_OID_INFO) && !info->dwGroupId)
2310 HeapFree(GetProcessHeap(), 0, (LPSTR)info->pszOID);
2311 HeapFree(GetProcessHeap(), 0, info);
2315 data = (struct edit_cert_data *)GetWindowLongPtrW(hwnd, DWLP_USER);
2316 if (data)
2318 ImageList_Destroy(data->imageList);
2319 HeapFree(GetProcessHeap(), 0, data);
2321 break;
2323 return 1;
2326 static void show_edit_cert_properties_dialog(HWND parent,
2327 struct detail_data *data)
2329 PROPSHEETHEADERW hdr;
2330 PROPSHEETPAGEW page; /* FIXME: need to add a cross-certificate page */
2332 TRACE("(%p)\n", data);
2334 memset(&page, 0, sizeof(PROPSHEETPAGEW));
2335 page.dwSize = sizeof(page);
2336 page.dwFlags = PSP_USECALLBACK;
2337 page.pfnCallback = cert_properties_general_callback;
2338 page.hInstance = hInstance;
2339 page.u.pszTemplate = MAKEINTRESOURCEW(IDD_CERT_PROPERTIES_GENERAL);
2340 page.pfnDlgProc = cert_properties_general_dlg_proc;
2341 page.lParam = (LPARAM)data;
2343 memset(&hdr, 0, sizeof(hdr));
2344 hdr.dwSize = sizeof(hdr);
2345 hdr.hwndParent = parent;
2346 hdr.dwFlags = PSH_PROPSHEETPAGE;
2347 hdr.hInstance = hInstance;
2348 hdr.pszCaption = MAKEINTRESOURCEW(IDS_CERTIFICATE_PROPERTIES);
2349 hdr.u3.ppsp = &page;
2350 hdr.nPages = 1;
2351 PropertySheetW(&hdr);
2354 static void free_detail_fields(struct detail_data *data)
2356 DWORD i;
2358 for (i = 0; i < data->cFields; i++)
2359 HeapFree(GetProcessHeap(), 0, data->fields[i].detailed_value);
2360 HeapFree(GetProcessHeap(), 0, data->fields);
2361 data->fields = NULL;
2362 data->cFields = 0;
2365 static void refresh_details_view(HWND hwnd)
2367 HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT);
2368 int curSel;
2369 struct detail_data *data;
2371 curSel = SendMessageW(cb, CB_GETCURSEL, 0, 0);
2372 /* Actually, any index will do, since they all store the same data value */
2373 data = (struct detail_data *)SendMessageW(cb, CB_GETITEMDATA, curSel, 0);
2374 free_detail_fields(data);
2375 set_fields_selection(hwnd, data, curSel);
2378 static LRESULT CALLBACK detail_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
2379 LPARAM lp)
2381 PROPSHEETPAGEW *page;
2382 struct detail_data *data;
2384 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
2386 switch (msg)
2388 case WM_INITDIALOG:
2389 page = (PROPSHEETPAGEW *)lp;
2390 data = (struct detail_data *)page->lParam;
2391 create_cert_details_list(hwnd, data);
2392 if (!(data->pCertViewInfo->dwFlags & CRYPTUI_ENABLE_EDITPROPERTIES))
2393 EnableWindow(GetDlgItem(hwnd, IDC_EDITPROPERTIES), FALSE);
2394 if (data->pCertViewInfo->dwFlags & CRYPTUI_DISABLE_EXPORT)
2395 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT), FALSE);
2396 break;
2397 case WM_NOTIFY:
2399 NMITEMACTIVATE *nm;
2400 HWND list = GetDlgItem(hwnd, IDC_DETAIL_LIST);
2402 nm = (NMITEMACTIVATE*)lp;
2403 if (nm->hdr.hwndFrom == list && nm->uNewState & LVN_ITEMACTIVATE
2404 && nm->hdr.code == LVN_ITEMCHANGED)
2406 data = (struct detail_data *)nm->lParam;
2407 if (nm->iItem >= 0 && data && nm->iItem < data->cFields)
2409 WCHAR buf[MAX_STRING_LEN], *val = NULL;
2410 HWND valueCtl = GetDlgItem(hwnd, IDC_DETAIL_VALUE);
2412 if (data->fields[nm->iItem].create)
2413 val = data->fields[nm->iItem].create(
2414 data->pCertViewInfo->pCertContext,
2415 data->fields[nm->iItem].param);
2416 else
2418 LVITEMW item;
2419 int res;
2421 item.cchTextMax = sizeof(buf) / sizeof(buf[0]);
2422 item.mask = LVIF_TEXT;
2423 item.pszText = buf;
2424 item.iItem = nm->iItem;
2425 item.iSubItem = 1;
2426 res = SendMessageW(list, LVM_GETITEMW, 0, (LPARAM)&item);
2427 if (res)
2428 val = buf;
2430 /* Select all the text in the control, the next update will
2431 * replace it
2433 SendMessageW(valueCtl, EM_SETSEL, 0, -1);
2434 add_unformatted_text_to_control(valueCtl, val,
2435 val ? strlenW(val) : 0);
2436 if (val != buf)
2437 HeapFree(GetProcessHeap(), 0, val);
2440 break;
2442 case WM_COMMAND:
2443 switch (wp)
2445 case IDC_EXPORT:
2446 FIXME("call CryptUIWizExport\n");
2447 break;
2448 case IDC_EDITPROPERTIES:
2450 HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT);
2451 int curSel;
2453 curSel = SendMessageW(cb, CB_GETCURSEL, 0, 0);
2454 /* Actually, any index will do, since they all store the same
2455 * data value
2457 data = (struct detail_data *)SendMessageW(cb, CB_GETITEMDATA,
2458 curSel, 0);
2459 show_edit_cert_properties_dialog(GetParent(hwnd), data);
2460 break;
2462 case ((CBN_SELCHANGE << 16) | IDC_DETAIL_SELECT):
2463 refresh_details_view(hwnd);
2464 break;
2466 break;
2467 case WM_REFRESH_VIEW:
2468 refresh_details_view(hwnd);
2469 break;
2471 return 0;
2474 static UINT CALLBACK detail_callback(HWND hwnd, UINT msg,
2475 PROPSHEETPAGEW *page)
2477 struct detail_data *data;
2479 switch (msg)
2481 case PSPCB_RELEASE:
2482 data = (struct detail_data *)page->lParam;
2483 free_detail_fields(data);
2484 HeapFree(GetProcessHeap(), 0, data);
2485 break;
2487 return 0;
2490 static BOOL init_detail_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
2491 BOOL *pfPropertiesChanged, PROPSHEETPAGEW *page)
2493 BOOL ret;
2494 struct detail_data *data = HeapAlloc(GetProcessHeap(), 0,
2495 sizeof(struct detail_data));
2497 if (data)
2499 data->pCertViewInfo = pCertViewInfo;
2500 data->pfPropertiesChanged = pfPropertiesChanged;
2501 data->cFields = 0;
2502 data->fields = NULL;
2503 memset(page, 0, sizeof(PROPSHEETPAGEW));
2504 page->dwSize = sizeof(PROPSHEETPAGEW);
2505 page->dwFlags = PSP_USECALLBACK;
2506 page->pfnCallback = detail_callback;
2507 page->hInstance = hInstance;
2508 page->u.pszTemplate = MAKEINTRESOURCEW(IDD_DETAIL);
2509 page->pfnDlgProc = detail_dlg_proc;
2510 page->lParam = (LPARAM)data;
2511 ret = TRUE;
2513 else
2514 ret = FALSE;
2515 return ret;
2518 struct hierarchy_data
2520 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo;
2521 HIMAGELIST imageList;
2522 DWORD selectedCert;
2525 static LPARAM index_to_lparam(struct hierarchy_data *data, DWORD index)
2527 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
2528 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData,
2529 data->pCertViewInfo->idxSigner, data->pCertViewInfo->fCounterSigner,
2530 data->pCertViewInfo->idxCounterSigner);
2532 /* Takes advantage of the fact that a pointer is 32-bit aligned, and
2533 * therefore always even.
2535 if (index == provSigner->csCertChain - 1)
2536 return (LPARAM)data;
2537 return index << 1 | 1;
2540 static inline DWORD lparam_to_index(struct hierarchy_data *data, LPARAM lp)
2542 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
2543 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData,
2544 data->pCertViewInfo->idxSigner, data->pCertViewInfo->fCounterSigner,
2545 data->pCertViewInfo->idxCounterSigner);
2547 if (!(lp & 1))
2548 return provSigner->csCertChain - 1;
2549 return lp >> 1;
2552 static struct hierarchy_data *get_hierarchy_data_from_tree_item(HWND tree,
2553 HTREEITEM hItem)
2555 struct hierarchy_data *data = NULL;
2556 HTREEITEM root = NULL;
2558 do {
2559 HTREEITEM parent = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM,
2560 TVGN_PARENT, (LPARAM)hItem);
2562 if (!parent)
2563 root = hItem;
2564 hItem = parent;
2565 } while (hItem);
2566 if (root)
2568 TVITEMW item;
2570 item.mask = TVIF_PARAM;
2571 item.hItem = root;
2572 SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item);
2573 data = (struct hierarchy_data *)item.lParam;
2575 return data;
2578 static WCHAR *get_cert_display_name(PCCERT_CONTEXT cert)
2580 WCHAR *name = get_cert_property_as_string(cert, CERT_FRIENDLY_NAME_PROP_ID);
2582 if (!name)
2583 name = get_cert_name_string(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0);
2584 return name;
2587 static void show_cert_chain(HWND hwnd, struct hierarchy_data *data)
2589 HWND tree = GetDlgItem(hwnd, IDC_CERTPATH);
2590 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
2591 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData,
2592 data->pCertViewInfo->idxSigner, data->pCertViewInfo->fCounterSigner,
2593 data->pCertViewInfo->idxCounterSigner);
2594 DWORD i;
2595 HTREEITEM parent = NULL;
2597 SendMessageW(tree, TVM_SETIMAGELIST, TVSIL_NORMAL, (LPARAM)data->imageList);
2598 for (i = provSigner->csCertChain; i; i--)
2600 LPWSTR name;
2602 name = get_cert_display_name(provSigner->pasCertChain[i - 1].pCert);
2603 if (name)
2605 TVINSERTSTRUCTW tvis;
2607 tvis.hParent = parent;
2608 tvis.hInsertAfter = TVI_LAST;
2609 tvis.u.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_IMAGE |
2610 TVIF_SELECTEDIMAGE | TVIF_PARAM;
2611 tvis.u.item.pszText = name;
2612 tvis.u.item.state = TVIS_EXPANDED;
2613 tvis.u.item.stateMask = TVIS_EXPANDED;
2614 if (i == 1 &&
2615 (provSigner->pChainContext->TrustStatus.dwErrorStatus &
2616 CERT_TRUST_IS_PARTIAL_CHAIN))
2618 /* The root of the chain has a special case: if the chain is
2619 * a partial chain, the icon is a warning icon rather than an
2620 * error icon.
2622 tvis.u.item.iImage = 2;
2624 else if (provSigner->pasCertChain[i - 1].pChainElement->TrustStatus.
2625 dwErrorStatus == 0)
2626 tvis.u.item.iImage = 0;
2627 else
2628 tvis.u.item.iImage = 1;
2629 tvis.u.item.iSelectedImage = tvis.u.item.iImage;
2630 tvis.u.item.lParam = index_to_lparam(data, i - 1);
2631 parent = (HTREEITEM)SendMessageW(tree, TVM_INSERTITEMW, 0,
2632 (LPARAM)&tvis);
2633 HeapFree(GetProcessHeap(), 0, name);
2638 static void set_certificate_status(HWND hwnd, CRYPT_PROVIDER_CERT *cert)
2640 /* Select all the text in the control, the next update will replace it */
2641 SendMessageW(hwnd, EM_SETSEL, 0, -1);
2642 /* Set the highest priority error messages first. */
2643 if (!(cert->dwConfidence & CERT_CONFIDENCE_SIG))
2644 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_BAD_SIGNATURE);
2645 else if (!(cert->dwConfidence & CERT_CONFIDENCE_TIME))
2646 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_BAD_TIME);
2647 else if (!(cert->dwConfidence & CERT_CONFIDENCE_TIMENEST))
2648 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_BAD_TIMENEST);
2649 else if (cert->dwRevokedReason)
2650 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_REVOKED);
2651 else
2652 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_VALID);
2655 static void set_certificate_status_for_end_cert(HWND hwnd,
2656 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
2658 HWND status = GetDlgItem(hwnd, IDC_CERTIFICATESTATUSTEXT);
2659 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
2660 (CRYPT_PROVIDER_DATA *)pCertViewInfo->u.pCryptProviderData,
2661 pCertViewInfo->idxSigner, pCertViewInfo->fCounterSigner,
2662 pCertViewInfo->idxCounterSigner);
2663 CRYPT_PROVIDER_CERT *provCert = WTHelperGetProvCertFromChain(provSigner,
2664 pCertViewInfo->idxCert);
2666 set_certificate_status(status, provCert);
2669 static void show_cert_hierarchy(HWND hwnd, struct hierarchy_data *data)
2671 /* Disable view certificate button until a certificate is selected */
2672 EnableWindow(GetDlgItem(hwnd, IDC_VIEWCERTIFICATE), FALSE);
2673 show_cert_chain(hwnd, data);
2674 set_certificate_status_for_end_cert(hwnd, data->pCertViewInfo);
2677 static void show_dialog_for_selected_cert(HWND hwnd)
2679 HWND tree = GetDlgItem(hwnd, IDC_CERTPATH);
2680 TVITEMW item;
2681 struct hierarchy_data *data;
2682 DWORD selection;
2684 memset(&item, 0, sizeof(item));
2685 item.mask = TVIF_HANDLE | TVIF_PARAM;
2686 item.hItem = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM, TVGN_CARET,
2687 (LPARAM)NULL);
2688 SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item);
2689 data = get_hierarchy_data_from_tree_item(tree, item.hItem);
2690 selection = lparam_to_index(data, item.lParam);
2691 if (selection != 0)
2693 CRYPT_PROVIDER_SGNR *provSigner;
2694 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
2695 BOOL changed = FALSE;
2697 provSigner = WTHelperGetProvSignerFromChain(
2698 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData,
2699 data->pCertViewInfo->idxSigner,
2700 data->pCertViewInfo->fCounterSigner,
2701 data->pCertViewInfo->idxCounterSigner);
2702 memset(&viewInfo, 0, sizeof(viewInfo));
2703 viewInfo.dwSize = sizeof(viewInfo);
2704 viewInfo.dwFlags = data->pCertViewInfo->dwFlags;
2705 viewInfo.szTitle = data->pCertViewInfo->szTitle;
2706 viewInfo.pCertContext = provSigner->pasCertChain[selection].pCert;
2707 viewInfo.cStores = data->pCertViewInfo->cStores;
2708 viewInfo.rghStores = data->pCertViewInfo->rghStores;
2709 viewInfo.cPropSheetPages = data->pCertViewInfo->cPropSheetPages;
2710 viewInfo.rgPropSheetPages = data->pCertViewInfo->rgPropSheetPages;
2711 viewInfo.nStartPage = data->pCertViewInfo->nStartPage;
2712 CryptUIDlgViewCertificateW(&viewInfo, &changed);
2713 if (changed)
2715 /* Delete the contents of the tree */
2716 SendMessageW(tree, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT);
2717 /* Reinitialize the tree */
2718 show_cert_hierarchy(hwnd, data);
2723 static LRESULT CALLBACK hierarchy_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
2724 LPARAM lp)
2726 PROPSHEETPAGEW *page;
2727 struct hierarchy_data *data;
2728 LRESULT ret = 0;
2729 HWND tree = GetDlgItem(hwnd, IDC_CERTPATH);
2731 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
2733 switch (msg)
2735 case WM_INITDIALOG:
2736 page = (PROPSHEETPAGEW *)lp;
2737 data = (struct hierarchy_data *)page->lParam;
2738 show_cert_hierarchy(hwnd, data);
2739 break;
2740 case WM_NOTIFY:
2742 NMHDR *hdr;
2744 hdr = (NMHDR *)lp;
2745 switch (hdr->code)
2747 case TVN_SELCHANGEDW:
2749 NMTREEVIEWW *nm = (NMTREEVIEWW*)lp;
2750 DWORD selection;
2751 CRYPT_PROVIDER_SGNR *provSigner;
2753 data = get_hierarchy_data_from_tree_item(tree, nm->itemNew.hItem);
2754 selection = lparam_to_index(data, nm->itemNew.lParam);
2755 provSigner = WTHelperGetProvSignerFromChain(
2756 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData,
2757 data->pCertViewInfo->idxSigner,
2758 data->pCertViewInfo->fCounterSigner,
2759 data->pCertViewInfo->idxCounterSigner);
2760 EnableWindow(GetDlgItem(hwnd, IDC_VIEWCERTIFICATE), selection != 0);
2761 set_certificate_status(GetDlgItem(hwnd, IDC_CERTIFICATESTATUSTEXT),
2762 &provSigner->pasCertChain[selection]);
2763 break;
2765 case NM_DBLCLK:
2766 show_dialog_for_selected_cert(hwnd);
2767 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
2768 ret = 1;
2769 break;
2771 break;
2773 case WM_COMMAND:
2774 switch (wp)
2776 case IDC_VIEWCERTIFICATE:
2777 show_dialog_for_selected_cert(hwnd);
2778 break;
2780 break;
2781 case WM_REFRESH_VIEW:
2783 TVITEMW item;
2785 /* Get hierarchy data */
2786 memset(&item, 0, sizeof(item));
2787 item.mask = TVIF_HANDLE | TVIF_PARAM;
2788 item.hItem = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM, TVGN_ROOT,
2789 (LPARAM)NULL);
2790 data = get_hierarchy_data_from_tree_item(tree, item.hItem);
2791 /* Delete the contents of the tree */
2792 SendMessageW(tree, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT);
2793 /* Reinitialize the tree */
2794 show_cert_hierarchy(hwnd, data);
2795 break;
2798 return ret;
2801 static UINT CALLBACK hierarchy_callback(HWND hwnd, UINT msg,
2802 PROPSHEETPAGEW *page)
2804 struct hierarchy_data *data;
2806 switch (msg)
2808 case PSPCB_RELEASE:
2809 data = (struct hierarchy_data *)page->lParam;
2810 ImageList_Destroy(data->imageList);
2811 HeapFree(GetProcessHeap(), 0, data);
2812 break;
2814 return 0;
2817 static BOOL init_hierarchy_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
2818 PROPSHEETPAGEW *page)
2820 struct hierarchy_data *data = HeapAlloc(GetProcessHeap(), 0,
2821 sizeof(struct hierarchy_data));
2822 BOOL ret = FALSE;
2824 if (data)
2826 data->imageList = ImageList_Create(16, 16, ILC_COLOR4 | ILC_MASK, 2, 0);
2827 if (data->imageList)
2829 HBITMAP bmp;
2830 COLORREF backColor = RGB(255, 0, 255);
2832 data->pCertViewInfo = pCertViewInfo;
2833 data->selectedCert = 0xffffffff;
2835 bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_SMALL_ICONS));
2836 ImageList_AddMasked(data->imageList, bmp, backColor);
2837 DeleteObject(bmp);
2838 ImageList_SetBkColor(data->imageList, CLR_NONE);
2840 memset(page, 0, sizeof(PROPSHEETPAGEW));
2841 page->dwSize = sizeof(PROPSHEETPAGEW);
2842 page->dwFlags = PSP_USECALLBACK;
2843 page->hInstance = hInstance;
2844 page->u.pszTemplate = MAKEINTRESOURCEW(IDD_HIERARCHY);
2845 page->pfnDlgProc = hierarchy_dlg_proc;
2846 page->lParam = (LPARAM)data;
2847 page->pfnCallback = hierarchy_callback;
2848 ret = TRUE;
2850 else
2851 HeapFree(GetProcessHeap(), 0, data);
2853 return ret;
2856 static int CALLBACK cert_prop_sheet_proc(HWND hwnd, UINT msg, LPARAM lp)
2858 RECT rc;
2859 POINT topLeft;
2861 TRACE("(%p, %08x, %08lx)\n", hwnd, msg, lp);
2863 switch (msg)
2865 case PSCB_INITIALIZED:
2866 /* Get cancel button's position.. */
2867 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rc);
2868 topLeft.x = rc.left;
2869 topLeft.y = rc.top;
2870 ScreenToClient(hwnd, &topLeft);
2871 /* hide the cancel button.. */
2872 ShowWindow(GetDlgItem(hwnd, IDCANCEL), FALSE);
2873 /* get the OK button's size.. */
2874 GetWindowRect(GetDlgItem(hwnd, IDOK), &rc);
2875 /* and move the OK button to the cancel button's original position. */
2876 MoveWindow(GetDlgItem(hwnd, IDOK), topLeft.x, topLeft.y,
2877 rc.right - rc.left, rc.bottom - rc.top, FALSE);
2878 GetWindowRect(GetDlgItem(hwnd, IDOK), &rc);
2879 break;
2881 return 0;
2884 static BOOL show_cert_dialog(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
2885 CRYPT_PROVIDER_CERT *provCert, BOOL *pfPropertiesChanged)
2887 static const WCHAR riched[] = { 'r','i','c','h','e','d','2','0',0 };
2888 DWORD nPages;
2889 PROPSHEETPAGEW *pages;
2890 BOOL ret = FALSE;
2891 HMODULE lib = LoadLibraryW(riched);
2893 nPages = pCertViewInfo->cPropSheetPages + 1; /* one for the General tab */
2894 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_DETAILPAGE))
2895 nPages++;
2896 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_HIERARCHYPAGE))
2897 nPages++;
2898 pages = HeapAlloc(GetProcessHeap(), 0, nPages * sizeof(PROPSHEETPAGEW));
2899 if (pages)
2901 PROPSHEETHEADERW hdr;
2902 CRYPTUI_INITDIALOG_STRUCT *init = NULL;
2903 DWORD i;
2905 memset(&hdr, 0, sizeof(hdr));
2906 hdr.dwSize = sizeof(hdr);
2907 hdr.dwFlags = PSH_NOAPPLYNOW | PSH_PROPSHEETPAGE | PSH_USECALLBACK;
2908 hdr.hInstance = hInstance;
2909 if (pCertViewInfo->szTitle)
2910 hdr.pszCaption = pCertViewInfo->szTitle;
2911 else
2912 hdr.pszCaption = MAKEINTRESOURCEW(IDS_CERTIFICATE);
2913 init_general_page(pCertViewInfo, &pages[hdr.nPages++]);
2914 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_DETAILPAGE))
2916 if (init_detail_page(pCertViewInfo, pfPropertiesChanged,
2917 &pages[hdr.nPages]))
2918 hdr.nPages++;
2920 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_HIERARCHYPAGE))
2922 if (init_hierarchy_page(pCertViewInfo, &pages[hdr.nPages]))
2923 hdr.nPages++;
2925 /* Copy each additional page, and create the init dialog struct for it
2927 if (pCertViewInfo->cPropSheetPages)
2929 init = HeapAlloc(GetProcessHeap(), 0,
2930 pCertViewInfo->cPropSheetPages *
2931 sizeof(CRYPTUI_INITDIALOG_STRUCT));
2932 if (init)
2934 for (i = 0; i < pCertViewInfo->cPropSheetPages; i++)
2936 memcpy(&pages[hdr.nPages + i],
2937 &pCertViewInfo->rgPropSheetPages[i],
2938 sizeof(PROPSHEETPAGEW));
2939 init[i].lParam = pCertViewInfo->rgPropSheetPages[i].lParam;
2940 init[i].pCertContext = pCertViewInfo->pCertContext;
2941 pages[hdr.nPages + i].lParam = (LPARAM)&init[i];
2943 if (pCertViewInfo->nStartPage & 0x8000)
2945 /* Start page index is relative to the number of default
2946 * pages
2948 hdr.u2.nStartPage = pCertViewInfo->nStartPage + hdr.nPages;
2950 else
2951 hdr.u2.nStartPage = pCertViewInfo->nStartPage;
2952 hdr.nPages = nPages;
2953 ret = TRUE;
2955 else
2956 SetLastError(ERROR_OUTOFMEMORY);
2958 else
2960 /* Ignore the relative flag if there aren't any additional pages */
2961 hdr.u2.nStartPage = pCertViewInfo->nStartPage & 0x7fff;
2962 ret = TRUE;
2964 if (ret)
2966 INT_PTR l;
2968 hdr.u3.ppsp = pages;
2969 hdr.pfnCallback = cert_prop_sheet_proc;
2970 l = PropertySheetW(&hdr);
2971 if (l == 0)
2973 SetLastError(ERROR_CANCELLED);
2974 ret = FALSE;
2977 HeapFree(GetProcessHeap(), 0, init);
2978 HeapFree(GetProcessHeap(), 0, pages);
2980 else
2981 SetLastError(ERROR_OUTOFMEMORY);
2982 FreeLibrary(lib);
2983 return ret;
2986 /***********************************************************************
2987 * CryptUIDlgViewCertificateW (CRYPTUI.@)
2989 BOOL WINAPI CryptUIDlgViewCertificateW(
2990 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo, BOOL *pfPropertiesChanged)
2992 static GUID generic_cert_verify = WINTRUST_ACTION_GENERIC_CERT_VERIFY;
2993 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
2994 WINTRUST_DATA wvt;
2995 WINTRUST_CERT_INFO cert;
2996 BOOL ret = FALSE;
2997 CRYPT_PROVIDER_SGNR *signer;
2998 CRYPT_PROVIDER_CERT *provCert = NULL;
3000 TRACE("(%p, %p)\n", pCertViewInfo, pfPropertiesChanged);
3002 if (pCertViewInfo->dwSize != sizeof(CRYPTUI_VIEWCERTIFICATE_STRUCTW))
3004 SetLastError(ERROR_INVALID_PARAMETER);
3005 return FALSE;
3007 /* Make a local copy in case we have to call WinVerifyTrust ourselves */
3008 memcpy(&viewInfo, pCertViewInfo, sizeof(viewInfo));
3009 if (!viewInfo.u.hWVTStateData)
3011 memset(&wvt, 0, sizeof(wvt));
3012 wvt.cbStruct = sizeof(wvt);
3013 wvt.dwUIChoice = WTD_UI_NONE;
3014 if (viewInfo.dwFlags &
3015 CRYPTUI_ENABLE_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT)
3016 wvt.fdwRevocationChecks |= WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
3017 if (viewInfo.dwFlags & CRYPTUI_ENABLE_REVOCATION_CHECK_END_CERT)
3018 wvt.fdwRevocationChecks |= WTD_REVOCATION_CHECK_END_CERT;
3019 if (viewInfo.dwFlags & CRYPTUI_ENABLE_REVOCATION_CHECK_CHAIN)
3020 wvt.fdwRevocationChecks |= WTD_REVOCATION_CHECK_CHAIN;
3021 wvt.dwUnionChoice = WTD_CHOICE_CERT;
3022 memset(&cert, 0, sizeof(cert));
3023 cert.cbStruct = sizeof(cert);
3024 cert.psCertContext = (CERT_CONTEXT *)viewInfo.pCertContext;
3025 cert.chStores = viewInfo.cStores;
3026 cert.pahStores = viewInfo.rghStores;
3027 wvt.u.pCert = &cert;
3028 wvt.dwStateAction = WTD_STATEACTION_VERIFY;
3029 WinVerifyTrust(NULL, &generic_cert_verify, &wvt);
3030 viewInfo.u.pCryptProviderData =
3031 WTHelperProvDataFromStateData(wvt.hWVTStateData);
3032 signer = WTHelperGetProvSignerFromChain(
3033 (CRYPT_PROVIDER_DATA *)viewInfo.u.pCryptProviderData, 0, FALSE, 0);
3034 provCert = WTHelperGetProvCertFromChain(signer, 0);
3035 ret = TRUE;
3037 else
3039 viewInfo.u.pCryptProviderData =
3040 WTHelperProvDataFromStateData(viewInfo.u.hWVTStateData);
3041 signer = WTHelperGetProvSignerFromChain(
3042 (CRYPT_PROVIDER_DATA *)viewInfo.u.pCryptProviderData,
3043 viewInfo.idxSigner, viewInfo.fCounterSigner,
3044 viewInfo.idxCounterSigner);
3045 provCert = WTHelperGetProvCertFromChain(signer, viewInfo.idxCert);
3046 ret = TRUE;
3048 if (ret)
3050 ret = show_cert_dialog(&viewInfo, provCert, pfPropertiesChanged);
3051 if (!viewInfo.u.hWVTStateData)
3053 wvt.dwStateAction = WTD_STATEACTION_CLOSE;
3054 WinVerifyTrust(NULL, &generic_cert_verify, &wvt);
3057 return ret;
3060 /***********************************************************************
3061 * CryptUIDlgViewContext (CRYPTUI.@)
3063 BOOL WINAPI CryptUIDlgViewContext(DWORD dwContextType, LPVOID pvContext,
3064 HWND hwnd, LPCWSTR pwszTitle, DWORD dwFlags, LPVOID pvReserved)
3066 BOOL ret;
3068 TRACE("(%d, %p, %p, %s, %08x, %p)\n", dwContextType, pvContext, hwnd,
3069 debugstr_w(pwszTitle), dwFlags, pvReserved);
3071 switch (dwContextType)
3073 case CERT_STORE_CERTIFICATE_CONTEXT:
3075 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
3077 memset(&viewInfo, 0, sizeof(viewInfo));
3078 viewInfo.dwSize = sizeof(viewInfo);
3079 viewInfo.hwndParent = hwnd;
3080 viewInfo.szTitle = pwszTitle;
3081 viewInfo.pCertContext = pvContext;
3082 ret = CryptUIDlgViewCertificateW(&viewInfo, NULL);
3083 break;
3085 default:
3086 FIXME("unimplemented for context type %d\n", dwContextType);
3087 SetLastError(E_INVALIDARG);
3088 ret = FALSE;
3090 return ret;
3093 static PCCERT_CONTEXT make_cert_from_file(LPCWSTR fileName)
3095 HANDLE file;
3096 DWORD size, encoding = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
3097 BYTE *buffer;
3098 PCCERT_CONTEXT cert;
3100 file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
3101 OPEN_EXISTING, 0, NULL);
3102 if (file == INVALID_HANDLE_VALUE)
3104 WARN("can't open certificate file %s\n", debugstr_w(fileName));
3105 return NULL;
3107 if ((size = GetFileSize(file, NULL)))
3109 if ((buffer = HeapAlloc(GetProcessHeap(), 0, size)))
3111 DWORD read;
3112 if (!ReadFile(file, buffer, size, &read, NULL) || read != size)
3114 WARN("can't read certificate file %s\n", debugstr_w(fileName));
3115 HeapFree(GetProcessHeap(), 0, buffer);
3116 CloseHandle(file);
3117 return NULL;
3121 else
3123 WARN("empty file %s\n", debugstr_w(fileName));
3124 CloseHandle(file);
3125 return NULL;
3127 CloseHandle(file);
3128 cert = CertCreateCertificateContext(encoding, buffer, size);
3129 HeapFree(GetProcessHeap(), 0, buffer);
3130 return cert;
3133 /* Decodes a cert's basic constraints extension (either szOID_BASIC_CONSTRAINTS
3134 * or szOID_BASIC_CONSTRAINTS2, whichever is present) to determine if it
3135 * should be a CA. If neither extension is present, returns
3136 * defaultIfNotSpecified.
3138 static BOOL is_ca_cert(PCCERT_CONTEXT cert, BOOL defaultIfNotSpecified)
3140 BOOL isCA = defaultIfNotSpecified;
3141 PCERT_EXTENSION ext = CertFindExtension(szOID_BASIC_CONSTRAINTS,
3142 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
3144 if (ext)
3146 CERT_BASIC_CONSTRAINTS_INFO *info;
3147 DWORD size = 0;
3149 if (CryptDecodeObjectEx(X509_ASN_ENCODING, szOID_BASIC_CONSTRAINTS,
3150 ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG,
3151 NULL, (LPBYTE)&info, &size))
3153 if (info->SubjectType.cbData == 1)
3154 isCA = info->SubjectType.pbData[0] & CERT_CA_SUBJECT_FLAG;
3155 LocalFree(info);
3158 else
3160 ext = CertFindExtension(szOID_BASIC_CONSTRAINTS2,
3161 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
3162 if (ext)
3164 CERT_BASIC_CONSTRAINTS2_INFO info;
3165 DWORD size = sizeof(CERT_BASIC_CONSTRAINTS2_INFO);
3167 if (CryptDecodeObjectEx(X509_ASN_ENCODING,
3168 szOID_BASIC_CONSTRAINTS2, ext->Value.pbData, ext->Value.cbData,
3169 0, NULL, &info, &size))
3170 isCA = info.fCA;
3173 return isCA;
3176 static HCERTSTORE choose_store_for_cert(PCCERT_CONTEXT cert)
3178 static const WCHAR AddressBook[] = { 'A','d','d','r','e','s','s',
3179 'B','o','o','k',0 };
3180 static const WCHAR CA[] = { 'C','A',0 };
3181 LPCWSTR storeName;
3183 if (is_ca_cert(cert, TRUE))
3184 storeName = CA;
3185 else
3186 storeName = AddressBook;
3187 return CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0,
3188 CERT_SYSTEM_STORE_CURRENT_USER, storeName);
3191 BOOL WINAPI CryptUIWizImport(DWORD dwFlags, HWND hwndParent, LPCWSTR pwszWizardTitle,
3192 PCCRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc, HCERTSTORE hDestCertStore)
3194 BOOL ret;
3195 HCERTSTORE store;
3196 const CERT_CONTEXT *cert;
3197 BOOL freeCert = FALSE;
3199 TRACE("(0x%08x, %p, %s, %p, %p)\n", dwFlags, hwndParent, debugstr_w(pwszWizardTitle),
3200 pImportSrc, hDestCertStore);
3202 if (!(dwFlags & CRYPTUI_WIZ_NO_UI)) FIXME("UI not implemented\n");
3204 if (!pImportSrc ||
3205 pImportSrc->dwSize != sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO))
3207 SetLastError(E_INVALIDARG);
3208 return FALSE;
3211 switch (pImportSrc->dwSubjectChoice)
3213 case CRYPTUI_WIZ_IMPORT_SUBJECT_FILE:
3214 if (!(cert = make_cert_from_file(pImportSrc->u.pwszFileName)))
3216 WARN("unable to create certificate context\n");
3217 return FALSE;
3219 else
3220 freeCert = TRUE;
3221 break;
3222 case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_CONTEXT:
3223 cert = pImportSrc->u.pCertContext;
3224 if (!cert)
3226 SetLastError(E_INVALIDARG);
3227 return FALSE;
3229 break;
3230 default:
3231 FIXME("source type not implemented: %u\n", pImportSrc->dwSubjectChoice);
3232 SetLastError(E_INVALIDARG);
3233 return FALSE;
3235 if (hDestCertStore) store = hDestCertStore;
3236 else
3238 if (!(store = choose_store_for_cert(cert)))
3240 WARN("unable to open certificate store\n");
3241 CertFreeCertificateContext(cert);
3242 return FALSE;
3245 ret = CertAddCertificateContextToStore(store, cert, CERT_STORE_ADD_REPLACE_EXISTING, NULL);
3247 if (!hDestCertStore) CertCloseStore(store, 0);
3248 if (freeCert)
3249 CertFreeCertificateContext(cert);
3250 return ret;