cryptui: Add a (empty) hierarchy page to the cert properties dialog.
[wine/wine64.git] / dlls / cryptui / main.c
blob9d44009df672b3e44febe65d05d342f394862464
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 /***********************************************************************
77 * CryptUIDlgViewCertificateA (CRYPTUI.@)
79 BOOL WINAPI CryptUIDlgViewCertificateA(
80 PCCRYPTUI_VIEWCERTIFICATE_STRUCTA pCertViewInfo, BOOL *pfPropertiesChanged)
82 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
83 LPWSTR title = NULL;
84 BOOL ret;
86 TRACE("(%p, %p)\n", pCertViewInfo, pfPropertiesChanged);
88 memcpy(&viewInfo, pCertViewInfo, sizeof(viewInfo));
89 if (pCertViewInfo->szTitle)
91 int len = MultiByteToWideChar(CP_ACP, 0, pCertViewInfo->szTitle, -1,
92 NULL, 0);
94 title = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
95 if (title)
97 MultiByteToWideChar(CP_ACP, 0, pCertViewInfo->szTitle, -1, title,
98 len);
99 viewInfo.szTitle = title;
101 else
103 ret = FALSE;
104 goto error;
107 if (pCertViewInfo->cPropSheetPages)
109 FIXME("ignoring additional prop sheet pages\n");
110 viewInfo.cPropSheetPages = 0;
112 ret = CryptUIDlgViewCertificateW(&viewInfo, pfPropertiesChanged);
113 HeapFree(GetProcessHeap(), 0, title);
114 error:
115 return ret;
118 struct ReadStringStruct
120 LPCWSTR buf;
121 LONG pos;
122 LONG len;
125 static DWORD CALLBACK read_text_callback(DWORD_PTR dwCookie, LPBYTE buf,
126 LONG cb, LONG *pcb)
128 struct ReadStringStruct *string = (struct ReadStringStruct *)dwCookie;
129 LONG cch = min(cb / sizeof(WCHAR), string->len - string->pos);
131 TRACE("(%p, %p, %d, %p)\n", string, buf, cb, pcb);
133 memmove(buf, string->buf + string->pos, cch * sizeof(WCHAR));
134 string->pos += cch;
135 *pcb = cch * sizeof(WCHAR);
136 return 0;
139 static void add_unformatted_text_to_control(HWND hwnd, LPCWSTR text, LONG len)
141 struct ReadStringStruct string;
142 EDITSTREAM editstream;
144 TRACE("(%p, %s)\n", hwnd, debugstr_wn(text, len));
146 string.buf = text;
147 string.pos = 0;
148 string.len = len;
149 editstream.dwCookie = (DWORD_PTR)&string;
150 editstream.dwError = 0;
151 editstream.pfnCallback = read_text_callback;
152 SendMessageW(hwnd, EM_STREAMIN, SF_TEXT | SFF_SELECTION | SF_UNICODE,
153 (LPARAM)&editstream);
156 static void add_string_resource_to_control(HWND hwnd, int id)
158 LPWSTR str;
159 LONG len;
161 len = LoadStringW(hInstance, id, (LPWSTR)&str, 0);
162 add_unformatted_text_to_control(hwnd, str, len);
165 static void add_text_with_paraformat_to_control(HWND hwnd, LPCWSTR text,
166 LONG len, const PARAFORMAT2 *fmt)
168 add_unformatted_text_to_control(hwnd, text, len);
169 SendMessageW(hwnd, EM_SETPARAFORMAT, 0, (LPARAM)fmt);
172 static void add_string_resource_with_paraformat_to_control(HWND hwnd, int id,
173 const PARAFORMAT2 *fmt)
175 LPWSTR str;
176 LONG len;
178 len = LoadStringW(hInstance, id, (LPWSTR)&str, 0);
179 add_text_with_paraformat_to_control(hwnd, str, len, fmt);
182 static LPWSTR get_cert_name_string(PCCERT_CONTEXT pCertContext, DWORD dwType,
183 DWORD dwFlags)
185 LPWSTR buf = NULL;
186 DWORD len;
188 len = CertGetNameStringW(pCertContext, dwType, dwFlags, NULL, NULL, 0);
189 if (len)
191 buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
192 if (buf)
193 CertGetNameStringW(pCertContext, dwType, dwFlags, NULL, buf, len);
195 return buf;
198 static void add_cert_string_to_control(HWND hwnd, PCCERT_CONTEXT pCertContext,
199 DWORD dwType, DWORD dwFlags)
201 LPWSTR name = get_cert_name_string(pCertContext, dwType, dwFlags);
203 if (name)
205 /* Don't include NULL-terminator in output */
206 DWORD len = lstrlenW(name);
208 add_unformatted_text_to_control(hwnd, name, len);
209 HeapFree(GetProcessHeap(), 0, name);
213 static void add_icon_to_control(HWND hwnd, int id)
215 HRESULT hr;
216 LPRICHEDITOLE richEditOle = NULL;
217 LPOLEOBJECT object = NULL;
218 CLSID clsid;
219 LPOLECACHE oleCache = NULL;
220 FORMATETC formatEtc;
221 DWORD conn;
222 LPDATAOBJECT dataObject = NULL;
223 HBITMAP bitmap = NULL;
224 RECT rect;
225 STGMEDIUM stgm;
226 REOBJECT reObject;
228 TRACE("(%p, %d)\n", hwnd, id);
230 SendMessageW(hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&richEditOle);
231 if (!richEditOle)
232 goto end;
233 hr = OleCreateDefaultHandler(&CLSID_NULL, NULL, &IID_IOleObject,
234 (void**)&object);
235 if (FAILED(hr))
236 goto end;
237 hr = IOleObject_GetUserClassID(object, &clsid);
238 if (FAILED(hr))
239 goto end;
240 hr = IOleObject_QueryInterface(object, &IID_IOleCache, (void**)&oleCache);
241 if (FAILED(hr))
242 goto end;
243 formatEtc.cfFormat = CF_BITMAP;
244 formatEtc.ptd = NULL;
245 formatEtc.dwAspect = DVASPECT_CONTENT;
246 formatEtc.lindex = -1;
247 formatEtc.tymed = TYMED_GDI;
248 hr = IOleCache_Cache(oleCache, &formatEtc, 0, &conn);
249 if (FAILED(hr))
250 goto end;
251 hr = IOleObject_QueryInterface(object, &IID_IDataObject,
252 (void**)&dataObject);
253 if (FAILED(hr))
254 goto end;
255 bitmap = LoadImageW(hInstance, MAKEINTRESOURCEW(id), IMAGE_BITMAP, 0, 0,
256 LR_DEFAULTSIZE | LR_LOADTRANSPARENT);
257 if (!bitmap)
258 goto end;
259 rect.left = rect.top = 0;
260 rect.right = GetSystemMetrics(SM_CXICON);
261 rect.bottom = GetSystemMetrics(SM_CYICON);
262 stgm.tymed = TYMED_GDI;
263 stgm.u.hBitmap = bitmap;
264 stgm.pUnkForRelease = NULL;
265 hr = IDataObject_SetData(dataObject, &formatEtc, &stgm, TRUE);
266 if (FAILED(hr))
267 goto end;
269 reObject.cbStruct = sizeof(reObject);
270 reObject.cp = REO_CP_SELECTION;
271 reObject.clsid = clsid;
272 reObject.poleobj = object;
273 reObject.pstg = NULL;
274 reObject.polesite = NULL;
275 reObject.sizel.cx = reObject.sizel.cy = 0;
276 reObject.dvaspect = DVASPECT_CONTENT;
277 reObject.dwFlags = 0;
278 reObject.dwUser = 0;
280 IRichEditOle_InsertObject(richEditOle, &reObject);
282 end:
283 if (dataObject)
284 IDataObject_Release(dataObject);
285 if (oleCache)
286 IOleCache_Release(oleCache);
287 if (object)
288 IOleObject_Release(object);
289 if (richEditOle)
290 IRichEditOle_Release(richEditOle);
293 #define MY_INDENT 200
295 static void add_oid_text_to_control(HWND hwnd, char *oid)
297 WCHAR nl = '\n';
298 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, oid, 0);
299 PARAFORMAT2 parFmt;
301 parFmt.cbSize = sizeof(parFmt);
302 parFmt.dwMask = PFM_STARTINDENT;
303 parFmt.dxStartIndent = MY_INDENT * 3;
304 if (oidInfo)
306 add_text_with_paraformat_to_control(hwnd, oidInfo->pwszName,
307 lstrlenW(oidInfo->pwszName), &parFmt);
308 add_unformatted_text_to_control(hwnd, &nl, 1);
312 #define MAX_STRING_LEN 512
314 struct OIDToString
316 LPCSTR oid;
317 int id;
320 /* The following list MUST be lexicographically sorted by OID */
321 static struct OIDToString oidMap[] = {
322 /* 1.3.6.1.4.1.311.10.3.1 */
323 { szOID_KP_CTL_USAGE_SIGNING, IDS_PURPOSE_CTL_USAGE_SIGNING },
324 /* 1.3.6.1.4.1.311.10.3.4 */
325 { szOID_KP_EFS, IDS_PURPOSE_EFS },
326 /* 1.3.6.1.4.1.311.10.3.4.1 */
327 { szOID_EFS_RECOVERY, IDS_PURPOSE_EFS_RECOVERY },
328 /* 1.3.6.1.4.1.311.10.3.5 */
329 { szOID_WHQL_CRYPTO, IDS_PURPOSE_WHQL },
330 /* 1.3.6.1.4.1.311.10.3.6 */
331 { szOID_NT5_CRYPTO, IDS_PURPOSE_NT5 },
332 /* 1.3.6.1.4.1.311.10.3.7 */
333 { szOID_OEM_WHQL_CRYPTO, IDS_PURPOSE_OEM_WHQL },
334 /* 1.3.6.1.4.1.311.10.3.8 */
335 { szOID_EMBEDDED_NT_CRYPTO, IDS_PURPOSE_EMBEDDED_NT },
336 /* 1.3.6.1.4.1.311.10.3.9 */
337 { szOID_ROOT_LIST_SIGNER, IDS_PURPOSE_ROOT_LIST_SIGNER },
338 /* 1.3.6.1.4.1.311.10.3.10 */
339 { szOID_KP_QUALIFIED_SUBORDINATION, IDS_PURPOSE_QUALIFIED_SUBORDINATION },
340 /* 1.3.6.1.4.1.311.10.3.11 */
341 { szOID_KP_KEY_RECOVERY, IDS_PURPOSE_KEY_RECOVERY },
342 /* 1.3.6.1.4.1.311.10.3.12 */
343 { szOID_KP_DOCUMENT_SIGNING, IDS_PURPOSE_DOCUMENT_SIGNING },
344 /* 1.3.6.1.4.1.311.10.3.13 */
345 { szOID_KP_LIFETIME_SIGNING, IDS_PURPOSE_LIFETIME_SIGNING },
346 /* 1.3.6.1.4.1.311.10.5.1 */
347 { szOID_DRM, IDS_PURPOSE_DRM },
348 /* 1.3.6.1.4.1.311.10.6.1 */
349 { szOID_LICENSES, IDS_PURPOSE_LICENSES },
350 /* 1.3.6.1.4.1.311.10.6.2 */
351 { szOID_LICENSE_SERVER, IDS_PURPOSE_LICENSE_SERVER },
352 /* 1.3.6.1.4.1.311.20.2.1 */
353 { szOID_ENROLLMENT_AGENT, IDS_PURPOSE_ENROLLMENT_AGENT },
354 /* 1.3.6.1.4.1.311.20.2.2 */
355 { szOID_KP_SMARTCARD_LOGON, IDS_PURPOSE_SMARTCARD_LOGON },
356 /* 1.3.6.1.4.1.311.21.5 */
357 { szOID_KP_CA_EXCHANGE, IDS_PURPOSE_CA_EXCHANGE },
358 /* 1.3.6.1.4.1.311.21.6 */
359 { szOID_KP_KEY_RECOVERY_AGENT, IDS_PURPOSE_KEY_RECOVERY_AGENT },
360 /* 1.3.6.1.4.1.311.21.19 */
361 { szOID_DS_EMAIL_REPLICATION, IDS_PURPOSE_DS_EMAIL_REPLICATION },
362 /* 1.3.6.1.5.5.7.3.1 */
363 { szOID_PKIX_KP_SERVER_AUTH, IDS_PURPOSE_SERVER_AUTH },
364 /* 1.3.6.1.5.5.7.3.2 */
365 { szOID_PKIX_KP_CLIENT_AUTH, IDS_PURPOSE_CLIENT_AUTH },
366 /* 1.3.6.1.5.5.7.3.3 */
367 { szOID_PKIX_KP_CODE_SIGNING, IDS_PURPOSE_CODE_SIGNING },
368 /* 1.3.6.1.5.5.7.3.4 */
369 { szOID_PKIX_KP_EMAIL_PROTECTION, IDS_PURPOSE_EMAIL_PROTECTION },
370 /* 1.3.6.1.5.5.7.3.5 */
371 { szOID_PKIX_KP_IPSEC_END_SYSTEM, IDS_PURPOSE_IPSEC },
372 /* 1.3.6.1.5.5.7.3.6 */
373 { szOID_PKIX_KP_IPSEC_TUNNEL, IDS_PURPOSE_IPSEC },
374 /* 1.3.6.1.5.5.7.3.7 */
375 { szOID_PKIX_KP_IPSEC_USER, IDS_PURPOSE_IPSEC },
376 /* 1.3.6.1.5.5.7.3.8 */
377 { szOID_PKIX_KP_TIMESTAMP_SIGNING, IDS_PURPOSE_TIMESTAMP_SIGNING },
380 static struct OIDToString *findSupportedOID(LPCSTR oid)
382 int indexHigh = sizeof(oidMap) / sizeof(oidMap[0]) - 1, indexLow = 0, i;
383 struct OIDToString *ret = NULL;
385 for (i = (indexLow + indexHigh) / 2; !ret && indexLow <= indexHigh;
386 i = (indexLow + indexHigh) / 2)
388 int cmp;
390 cmp = strcmp(oid, oidMap[i].oid);
391 if (!cmp)
392 ret = &oidMap[i];
393 else if (cmp > 0)
394 indexLow = i + 1;
395 else
396 indexHigh = i - 1;
398 return ret;
401 static void add_local_oid_text_to_control(HWND text, LPCSTR oid)
403 struct OIDToString *entry;
404 WCHAR nl = '\n';
405 PARAFORMAT2 parFmt;
407 parFmt.cbSize = sizeof(parFmt);
408 parFmt.dwMask = PFM_STARTINDENT;
409 parFmt.dxStartIndent = MY_INDENT * 3;
410 if ((entry = findSupportedOID(oid)))
412 WCHAR *str, *linebreak, *ptr;
413 BOOL multiline = FALSE;
414 int len;
416 len = LoadStringW(hInstance, entry->id, (LPWSTR)&str, 0);
417 ptr = str;
418 do {
419 if ((linebreak = memchrW(ptr, '\n', len)))
421 WCHAR copy[MAX_STRING_LEN];
423 multiline = TRUE;
424 /* The source string contains a newline, which the richedit
425 * control won't find since it's interpreted as a paragraph
426 * break. Therefore copy up to the newline. lstrcpynW always
427 * NULL-terminates, so pass one more than the length of the
428 * source line so the copy includes the entire line and the
429 * NULL-terminator.
431 lstrcpynW(copy, ptr, linebreak - ptr + 1);
432 add_text_with_paraformat_to_control(text, copy,
433 linebreak - ptr, &parFmt);
434 ptr = linebreak + 1;
435 add_unformatted_text_to_control(text, &nl, 1);
437 else if (multiline && *ptr)
439 /* Add the last line */
440 add_text_with_paraformat_to_control(text, ptr,
441 len - (ptr - str), &parFmt);
442 add_unformatted_text_to_control(text, &nl, 1);
444 } while (linebreak);
445 if (!multiline)
447 add_text_with_paraformat_to_control(text, str, len, &parFmt);
448 add_unformatted_text_to_control(text, &nl, 1);
451 else
453 WCHAR *oidW = HeapAlloc(GetProcessHeap(), 0,
454 (strlen(oid) + 1) * sizeof(WCHAR));
456 if (oidW)
458 LPCSTR src;
459 WCHAR *dst;
461 for (src = oid, dst = oidW; *src; src++, dst++)
462 *dst = *src;
463 *dst = 0;
464 add_text_with_paraformat_to_control(text, oidW, lstrlenW(oidW),
465 &parFmt);
466 add_unformatted_text_to_control(text, &nl, 1);
467 HeapFree(GetProcessHeap(), 0, oidW);
472 static void display_app_usages(HWND text, PCCERT_CONTEXT cert,
473 BOOL *anyUsageAdded)
475 static char any_app_policy[] = szOID_ANY_APPLICATION_POLICY;
476 WCHAR nl = '\n';
477 CHARFORMATW charFmt;
478 PCERT_EXTENSION policyExt;
479 if (!*anyUsageAdded)
481 PARAFORMAT2 parFmt;
483 parFmt.cbSize = sizeof(parFmt);
484 parFmt.dwMask = PFM_STARTINDENT;
485 parFmt.dxStartIndent = MY_INDENT;
486 add_string_resource_with_paraformat_to_control(text,
487 IDS_CERT_INFO_PURPOSES, &parFmt);
488 add_unformatted_text_to_control(text, &nl, 1);
489 *anyUsageAdded = TRUE;
491 memset(&charFmt, 0, sizeof(charFmt));
492 charFmt.cbSize = sizeof(charFmt);
493 charFmt.dwMask = CFM_BOLD;
494 charFmt.dwEffects = 0;
495 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
496 if ((policyExt = CertFindExtension(szOID_APPLICATION_CERT_POLICIES,
497 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension)))
499 CERT_POLICIES_INFO *policies;
500 DWORD size;
502 if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_POLICIES,
503 policyExt->Value.pbData, policyExt->Value.cbData,
504 CRYPT_DECODE_ALLOC_FLAG, NULL, &policies, &size))
506 DWORD i;
508 for (i = 0; i < policies->cPolicyInfo; i++)
510 DWORD j;
512 for (j = 0; j < policies->rgPolicyInfo[i].cPolicyQualifier; j++)
513 add_local_oid_text_to_control(text,
514 policies->rgPolicyInfo[i].rgPolicyQualifier[j].
515 pszPolicyQualifierId);
517 LocalFree(policies);
520 else
521 add_oid_text_to_control(text, any_app_policy);
524 static BOOL display_cert_usages(HWND text, PCCERT_CONTEXT cert,
525 BOOL *anyUsageAdded)
527 WCHAR nl = '\n';
528 DWORD size;
529 BOOL badUsages = FALSE;
531 if (CertGetEnhancedKeyUsage(cert, 0, NULL, &size))
533 CHARFORMATW charFmt;
534 static char any_cert_policy[] = szOID_ANY_CERT_POLICY;
535 PCERT_ENHKEY_USAGE usage = HeapAlloc(GetProcessHeap(), 0, size);
537 if (usage)
539 if (CertGetEnhancedKeyUsage(cert, 0, usage, &size))
541 DWORD i;
543 if (!*anyUsageAdded)
545 PARAFORMAT2 parFmt;
547 parFmt.cbSize = sizeof(parFmt);
548 parFmt.dwMask = PFM_STARTINDENT;
549 parFmt.dxStartIndent = MY_INDENT;
550 add_string_resource_with_paraformat_to_control(text,
551 IDS_CERT_INFO_PURPOSES, &parFmt);
552 add_unformatted_text_to_control(text, &nl, 1);
553 *anyUsageAdded = TRUE;
555 memset(&charFmt, 0, sizeof(charFmt));
556 charFmt.cbSize = sizeof(charFmt);
557 charFmt.dwMask = CFM_BOLD;
558 charFmt.dwEffects = 0;
559 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION,
560 (LPARAM)&charFmt);
561 if (!usage->cUsageIdentifier)
562 add_oid_text_to_control(text, any_cert_policy);
563 else
564 for (i = 0; i < usage->cUsageIdentifier; i++)
565 add_local_oid_text_to_control(text,
566 usage->rgpszUsageIdentifier[i]);
568 else
569 badUsages = TRUE;
570 HeapFree(GetProcessHeap(), 0, usage);
572 else
573 badUsages = TRUE;
575 else
576 badUsages = TRUE;
577 return badUsages;
580 static void set_policy_text(HWND text,
581 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
583 BOOL includeCertUsages = FALSE, includeAppUsages = FALSE;
584 BOOL badUsages = FALSE, anyUsageAdded = FALSE;
586 if (pCertViewInfo->cPurposes)
588 DWORD i;
590 for (i = 0; i < pCertViewInfo->cPurposes; i++)
592 if (!strcmp(pCertViewInfo->rgszPurposes[i], szOID_ANY_CERT_POLICY))
593 includeCertUsages = TRUE;
594 else if (!strcmp(pCertViewInfo->rgszPurposes[i],
595 szOID_ANY_APPLICATION_POLICY))
596 includeAppUsages = TRUE;
597 else
598 badUsages = TRUE;
601 else
602 includeAppUsages = includeCertUsages = TRUE;
603 if (includeAppUsages)
604 display_app_usages(text, pCertViewInfo->pCertContext, &anyUsageAdded);
605 if (includeCertUsages)
606 badUsages = display_cert_usages(text, pCertViewInfo->pCertContext,
607 &anyUsageAdded);
608 if (badUsages)
610 PARAFORMAT2 parFmt;
612 parFmt.cbSize = sizeof(parFmt);
613 parFmt.dwMask = PFM_STARTINDENT;
614 parFmt.dxStartIndent = MY_INDENT;
615 add_string_resource_with_paraformat_to_control(text,
616 IDS_CERT_INFO_BAD_PURPOSES, &parFmt);
620 static CRYPT_OBJID_BLOB *find_policy_qualifier(CERT_POLICIES_INFO *policies,
621 LPCSTR policyOid)
623 CRYPT_OBJID_BLOB *ret = NULL;
624 DWORD i;
626 for (i = 0; !ret && i < policies->cPolicyInfo; i++)
628 DWORD j;
630 for (j = 0; !ret && j < policies->rgPolicyInfo[i].cPolicyQualifier; j++)
631 if (!strcmp(policies->rgPolicyInfo[i].rgPolicyQualifier[j].
632 pszPolicyQualifierId, policyOid))
633 ret = &policies->rgPolicyInfo[i].rgPolicyQualifier[j].
634 Qualifier;
636 return ret;
639 static WCHAR *get_cps_str_from_qualifier(CRYPT_OBJID_BLOB *qualifier)
641 LPWSTR qualifierStr = NULL;
642 CERT_NAME_VALUE *qualifierValue;
643 DWORD size;
645 if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME_VALUE,
646 qualifier->pbData, qualifier->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL,
647 &qualifierValue, &size))
649 size = CertRDNValueToStrW(qualifierValue->dwValueType,
650 &qualifierValue->Value, NULL, 0);
651 qualifierStr = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
652 if (qualifierStr)
653 CertRDNValueToStrW(qualifierValue->dwValueType,
654 &qualifierValue->Value, qualifierStr, size);
655 LocalFree(qualifierValue);
657 return qualifierStr;
660 static WCHAR *get_user_notice_from_qualifier(CRYPT_OBJID_BLOB *qualifier)
662 LPWSTR str = NULL;
663 CERT_POLICY_QUALIFIER_USER_NOTICE *qualifierValue;
664 DWORD size;
666 if (CryptDecodeObjectEx(X509_ASN_ENCODING,
667 X509_PKIX_POLICY_QUALIFIER_USERNOTICE,
668 qualifier->pbData, qualifier->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL,
669 &qualifierValue, &size))
671 str = HeapAlloc(GetProcessHeap(), 0,
672 (strlenW(qualifierValue->pszDisplayText) + 1) * sizeof(WCHAR));
673 if (str)
674 strcpyW(str, qualifierValue->pszDisplayText);
675 LocalFree(qualifierValue);
677 return str;
680 struct IssuerStatement
682 LPWSTR cps;
683 LPWSTR userNotice;
686 static void set_issuer_statement(HWND hwnd,
687 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
689 PCERT_EXTENSION policyExt;
691 if (!(pCertViewInfo->dwFlags & CRYPTUI_DISABLE_ISSUERSTATEMENT) &&
692 (policyExt = CertFindExtension(szOID_CERT_POLICIES,
693 pCertViewInfo->pCertContext->pCertInfo->cExtension,
694 pCertViewInfo->pCertContext->pCertInfo->rgExtension)))
696 CERT_POLICIES_INFO *policies;
697 DWORD size;
699 if (CryptDecodeObjectEx(X509_ASN_ENCODING, policyExt->pszObjId,
700 policyExt->Value.pbData, policyExt->Value.cbData,
701 CRYPT_DECODE_ALLOC_FLAG, NULL, &policies, &size))
703 CRYPT_OBJID_BLOB *qualifier;
704 LPWSTR cps = NULL, userNotice = NULL;
706 if ((qualifier = find_policy_qualifier(policies,
707 szOID_PKIX_POLICY_QUALIFIER_CPS)))
708 cps = get_cps_str_from_qualifier(qualifier);
709 if ((qualifier = find_policy_qualifier(policies,
710 szOID_PKIX_POLICY_QUALIFIER_USERNOTICE)))
711 userNotice = get_user_notice_from_qualifier(qualifier);
712 if (cps || userNotice)
714 struct IssuerStatement *issuerStatement =
715 HeapAlloc(GetProcessHeap(), 0, sizeof(struct IssuerStatement));
717 if (issuerStatement)
719 issuerStatement->cps = cps;
720 issuerStatement->userNotice = userNotice;
721 EnableWindow(GetDlgItem(hwnd, IDC_ISSUERSTATEMENT), TRUE);
722 SetWindowLongPtrW(hwnd, DWLP_USER,
723 (ULONG_PTR)issuerStatement);
726 LocalFree(policies);
731 static void set_cert_info(HWND hwnd,
732 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
734 CHARFORMATW charFmt;
735 PARAFORMAT2 parFmt;
736 HWND icon = GetDlgItem(hwnd, IDC_CERTIFICATE_ICON);
737 HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_INFO);
738 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
739 (CRYPT_PROVIDER_DATA *)pCertViewInfo->u.pCryptProviderData,
740 pCertViewInfo->idxSigner, pCertViewInfo->fCounterSigner,
741 pCertViewInfo->idxCounterSigner);
742 CRYPT_PROVIDER_CERT *root =
743 &provSigner->pasCertChain[provSigner->csCertChain - 1];
745 if (provSigner->pChainContext->TrustStatus.dwErrorStatus &
746 CERT_TRUST_IS_PARTIAL_CHAIN)
747 add_icon_to_control(icon, IDB_CERT_WARNING);
748 else if (!root->fTrustedRoot)
749 add_icon_to_control(icon, IDB_CERT_ERROR);
750 else
751 add_icon_to_control(icon, IDB_CERT);
753 memset(&charFmt, 0, sizeof(charFmt));
754 charFmt.cbSize = sizeof(charFmt);
755 charFmt.dwMask = CFM_BOLD;
756 charFmt.dwEffects = CFE_BOLD;
757 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
758 /* FIXME: vertically center text */
759 parFmt.cbSize = sizeof(parFmt);
760 parFmt.dwMask = PFM_STARTINDENT;
761 parFmt.dxStartIndent = MY_INDENT;
762 add_string_resource_with_paraformat_to_control(text,
763 IDS_CERTIFICATEINFORMATION, &parFmt);
765 text = GetDlgItem(hwnd, IDC_CERTIFICATE_STATUS);
766 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
767 if (provSigner->dwError == TRUST_E_CERT_SIGNATURE)
768 add_string_resource_with_paraformat_to_control(text,
769 IDS_CERT_INFO_BAD_SIG, &parFmt);
770 else if (provSigner->pChainContext->TrustStatus.dwErrorStatus &
771 CERT_TRUST_IS_PARTIAL_CHAIN)
772 add_string_resource_with_paraformat_to_control(text,
773 IDS_CERT_INFO_PARTIAL_CHAIN, &parFmt);
774 else if (!root->fTrustedRoot)
776 if (provSigner->csCertChain == 1 && root->fSelfSigned)
777 add_string_resource_with_paraformat_to_control(text,
778 IDS_CERT_INFO_UNTRUSTED_CA, &parFmt);
779 else
780 add_string_resource_with_paraformat_to_control(text,
781 IDS_CERT_INFO_UNTRUSTED_ROOT, &parFmt);
783 else
785 set_policy_text(text, pCertViewInfo);
786 set_issuer_statement(hwnd, pCertViewInfo);
790 static void set_cert_name_string(HWND hwnd, PCCERT_CONTEXT cert,
791 DWORD nameFlags, int heading)
793 WCHAR nl = '\n';
794 HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_NAMES);
795 CHARFORMATW charFmt;
796 PARAFORMAT2 parFmt;
798 memset(&charFmt, 0, sizeof(charFmt));
799 charFmt.cbSize = sizeof(charFmt);
800 charFmt.dwMask = CFM_BOLD;
801 charFmt.dwEffects = CFE_BOLD;
802 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
803 parFmt.cbSize = sizeof(parFmt);
804 parFmt.dwMask = PFM_STARTINDENT;
805 parFmt.dxStartIndent = MY_INDENT * 3;
806 add_string_resource_with_paraformat_to_control(text, heading, &parFmt);
807 charFmt.dwEffects = 0;
808 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
809 add_cert_string_to_control(text, cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
810 nameFlags);
811 add_unformatted_text_to_control(text, &nl, 1);
812 add_unformatted_text_to_control(text, &nl, 1);
813 add_unformatted_text_to_control(text, &nl, 1);
817 static void add_date_string_to_control(HWND hwnd, const FILETIME *fileTime)
819 WCHAR dateFmt[80]; /* sufficient for all versions of LOCALE_SSHORTDATE */
820 WCHAR date[80];
821 SYSTEMTIME sysTime;
823 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SSHORTDATE, dateFmt,
824 sizeof(dateFmt) / sizeof(dateFmt[0]));
825 FileTimeToSystemTime(fileTime, &sysTime);
826 GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, date,
827 sizeof(date) / sizeof(date[0]));
828 add_unformatted_text_to_control(hwnd, date, lstrlenW(date));
831 static void set_cert_validity_period(HWND hwnd, PCCERT_CONTEXT cert)
833 WCHAR nl = '\n';
834 HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_NAMES);
835 CHARFORMATW charFmt;
836 PARAFORMAT2 parFmt;
838 memset(&charFmt, 0, sizeof(charFmt));
839 charFmt.cbSize = sizeof(charFmt);
840 charFmt.dwMask = CFM_BOLD;
841 charFmt.dwEffects = CFE_BOLD;
842 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
843 parFmt.cbSize = sizeof(parFmt);
844 parFmt.dwMask = PFM_STARTINDENT;
845 parFmt.dxStartIndent = MY_INDENT * 3;
846 add_string_resource_with_paraformat_to_control(text, IDS_VALID_FROM,
847 &parFmt);
848 charFmt.dwEffects = 0;
849 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
850 add_date_string_to_control(text, &cert->pCertInfo->NotBefore);
851 charFmt.dwEffects = CFE_BOLD;
852 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
853 add_string_resource_to_control(text, IDS_VALID_TO);
854 charFmt.dwEffects = 0;
855 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
856 add_date_string_to_control(text, &cert->pCertInfo->NotAfter);
857 add_unformatted_text_to_control(text, &nl, 1);
860 static void set_general_info(HWND hwnd,
861 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
863 set_cert_info(hwnd, pCertViewInfo);
864 set_cert_name_string(hwnd, pCertViewInfo->pCertContext, 0,
865 IDS_SUBJECT_HEADING);
866 set_cert_name_string(hwnd, pCertViewInfo->pCertContext,
867 CERT_NAME_ISSUER_FLAG, IDS_ISSUER_HEADING);
868 set_cert_validity_period(hwnd, pCertViewInfo->pCertContext);
871 static LRESULT CALLBACK user_notice_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
872 LPARAM lp)
874 LRESULT ret = 0;
875 HWND text;
876 struct IssuerStatement *issuerStatement;
878 switch (msg)
880 case WM_INITDIALOG:
881 text = GetDlgItem(hwnd, IDC_USERNOTICE);
882 issuerStatement = (struct IssuerStatement *)lp;
883 add_unformatted_text_to_control(text, issuerStatement->userNotice,
884 strlenW(issuerStatement->userNotice));
885 if (issuerStatement->cps)
886 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)issuerStatement->cps);
887 else
888 EnableWindow(GetDlgItem(hwnd, IDC_CPS), FALSE);
889 break;
890 case WM_COMMAND:
891 switch (wp)
893 case IDOK:
894 EndDialog(hwnd, IDOK);
895 ret = TRUE;
896 break;
897 case IDC_CPS:
899 IBindCtx *bctx = NULL;
900 LPWSTR cps;
902 CreateBindCtx(0, &bctx);
903 cps = (LPWSTR)GetWindowLongPtrW(hwnd, DWLP_USER);
904 HlinkSimpleNavigateToString(cps, NULL, NULL, NULL, bctx, NULL,
905 HLNF_OPENINNEWWINDOW, 0);
906 IBindCtx_Release(bctx);
907 break;
911 return ret;
914 static void show_user_notice(HWND hwnd, struct IssuerStatement *issuerStatement)
916 DialogBoxParamW(hInstance, MAKEINTRESOURCEW(IDD_USERNOTICE), hwnd,
917 user_notice_dlg_proc, (LPARAM)issuerStatement);
920 static LRESULT CALLBACK general_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
921 LPARAM lp)
923 PROPSHEETPAGEW *page;
924 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo;
926 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
928 switch (msg)
930 case WM_INITDIALOG:
931 page = (PROPSHEETPAGEW *)lp;
932 pCertViewInfo = (PCCRYPTUI_VIEWCERTIFICATE_STRUCTW)page->lParam;
933 if (pCertViewInfo->dwFlags & CRYPTUI_DISABLE_ADDTOSTORE)
934 ShowWindow(GetDlgItem(hwnd, IDC_ADDTOSTORE), FALSE);
935 EnableWindow(GetDlgItem(hwnd, IDC_ISSUERSTATEMENT), FALSE);
936 set_general_info(hwnd, pCertViewInfo);
937 break;
938 case WM_COMMAND:
939 switch (wp)
941 case IDC_ADDTOSTORE:
942 FIXME("call CryptUIWizImport\n");
943 break;
944 case IDC_ISSUERSTATEMENT:
946 struct IssuerStatement *issuerStatement =
947 (struct IssuerStatement *)GetWindowLongPtrW(hwnd, DWLP_USER);
949 if (issuerStatement)
951 if (issuerStatement->userNotice)
952 show_user_notice(hwnd, issuerStatement);
953 else if (issuerStatement->cps)
955 IBindCtx *bctx = NULL;
957 CreateBindCtx(0, &bctx);
958 HlinkSimpleNavigateToString(issuerStatement->cps, NULL,
959 NULL, NULL, bctx, NULL, HLNF_OPENINNEWWINDOW, 0);
960 IBindCtx_Release(bctx);
963 break;
966 break;
968 return 0;
971 static UINT CALLBACK general_callback_proc(HWND hwnd, UINT msg,
972 PROPSHEETPAGEW *page)
974 struct IssuerStatement *issuerStatement;
976 switch (msg)
978 case PSPCB_RELEASE:
979 issuerStatement =
980 (struct IssuerStatement *)GetWindowLongPtrW(hwnd, DWLP_USER);
981 if (issuerStatement)
983 HeapFree(GetProcessHeap(), 0, issuerStatement->cps);
984 HeapFree(GetProcessHeap(), 0, issuerStatement->userNotice);
985 HeapFree(GetProcessHeap(), 0, issuerStatement);
987 break;
989 return 1;
992 static void init_general_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
993 PROPSHEETPAGEW *page)
995 memset(page, 0, sizeof(PROPSHEETPAGEW));
996 page->dwSize = sizeof(PROPSHEETPAGEW);
997 page->dwFlags = PSP_USECALLBACK;
998 page->pfnCallback = general_callback_proc;
999 page->hInstance = hInstance;
1000 page->u.pszTemplate = MAKEINTRESOURCEW(IDD_GENERAL);
1001 page->pfnDlgProc = general_dlg_proc;
1002 page->lParam = (LPARAM)pCertViewInfo;
1005 typedef WCHAR * (*field_format_func)(PCCERT_CONTEXT cert);
1007 static WCHAR *field_format_version(PCCERT_CONTEXT cert)
1009 static const WCHAR fmt[] = { 'V','%','d',0 };
1010 WCHAR *buf = HeapAlloc(GetProcessHeap(), 0, 12 * sizeof(WCHAR));
1012 if (buf)
1013 sprintfW(buf, fmt, cert->pCertInfo->dwVersion);
1014 return buf;
1017 static WCHAR *format_hex_string(void *pb, DWORD cb)
1019 WCHAR *buf = HeapAlloc(GetProcessHeap(), 0, (cb * 3 + 1) * sizeof(WCHAR));
1021 if (buf)
1023 static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
1024 DWORD i;
1025 WCHAR *ptr;
1027 for (i = 0, ptr = buf; i < cb; i++, ptr += 3)
1028 sprintfW(ptr, fmt, ((BYTE *)pb)[i]);
1030 return buf;
1033 static WCHAR *field_format_serial_number(PCCERT_CONTEXT cert)
1035 return format_hex_string(cert->pCertInfo->SerialNumber.pbData,
1036 cert->pCertInfo->SerialNumber.cbData);
1039 static WCHAR *field_format_issuer(PCCERT_CONTEXT cert)
1041 return get_cert_name_string(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
1042 CERT_NAME_ISSUER_FLAG);
1045 static WCHAR *field_format_detailed_cert_name(PCERT_NAME_BLOB name)
1047 WCHAR *str = NULL;
1048 DWORD len = CertNameToStrW(X509_ASN_ENCODING, name,
1049 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, NULL, 0);
1051 if (len)
1053 str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1054 if (str)
1055 CertNameToStrW(X509_ASN_ENCODING, name,
1056 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, str, len);
1058 return str;
1061 static WCHAR *field_format_detailed_issuer(PCCERT_CONTEXT cert, void *param)
1063 return field_format_detailed_cert_name(&cert->pCertInfo->Issuer);
1066 static WCHAR *field_format_subject(PCCERT_CONTEXT cert)
1068 return get_cert_name_string(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0);
1071 static WCHAR *field_format_detailed_subject(PCCERT_CONTEXT cert, void *param)
1073 return field_format_detailed_cert_name(&cert->pCertInfo->Subject);
1076 static WCHAR *format_long_date(const FILETIME *fileTime)
1078 WCHAR dateFmt[80]; /* long enough for LOCALE_SLONGDATE */
1079 DWORD len;
1080 WCHAR *buf = NULL;
1081 SYSTEMTIME sysTime;
1083 /* FIXME: format isn't quite right, want time too */
1084 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SLONGDATE, dateFmt,
1085 sizeof(dateFmt) / sizeof(dateFmt[0]));
1086 FileTimeToSystemTime(fileTime, &sysTime);
1087 len = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, NULL, 0);
1088 if (len)
1090 buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1091 if (buf)
1092 GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, buf,
1093 len);
1095 return buf;
1098 static WCHAR *field_format_from_date(PCCERT_CONTEXT cert)
1100 return format_long_date(&cert->pCertInfo->NotBefore);
1103 static WCHAR *field_format_to_date(PCCERT_CONTEXT cert)
1105 return format_long_date(&cert->pCertInfo->NotAfter);
1108 static WCHAR *field_format_public_key(PCCERT_CONTEXT cert)
1110 PCCRYPT_OID_INFO oidInfo;
1111 WCHAR *buf = NULL;
1113 oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
1114 cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, 0);
1115 if (oidInfo)
1117 WCHAR fmt[MAX_STRING_LEN];
1119 if (LoadStringW(hInstance, IDS_FIELD_PUBLIC_KEY_FORMAT, fmt,
1120 sizeof(fmt) / sizeof(fmt[0])))
1122 /* Allocate the output buffer. Use the number of bytes in the
1123 * public key as a conservative (high) estimate for the number of
1124 * digits in its output.
1125 * The output is of the form (in English)
1126 * "<public key algorithm> (<public key bit length> bits)".
1127 * Ordinarily having two positional parameters in a string is not a
1128 * good idea, but as this isn't a sentence fragment, it shouldn't
1129 * be word-order dependent.
1131 buf = HeapAlloc(GetProcessHeap(), 0,
1132 (strlenW(fmt) + strlenW(oidInfo->pwszName) +
1133 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData * 8)
1134 * sizeof(WCHAR));
1135 if (buf)
1136 sprintfW(buf, fmt, oidInfo->pwszName,
1137 CertGetPublicKeyLength(X509_ASN_ENCODING,
1138 &cert->pCertInfo->SubjectPublicKeyInfo));
1141 return buf;
1144 static WCHAR *field_format_detailed_public_key(PCCERT_CONTEXT cert, void *param)
1146 return format_hex_string(
1147 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
1148 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData);
1151 struct field_value_data;
1152 struct detail_data
1154 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo;
1155 BOOL *pfPropertiesChanged;
1156 int cFields;
1157 struct field_value_data *fields;
1160 typedef void (*add_fields_func)(HWND hwnd, struct detail_data *data);
1162 typedef WCHAR *(*create_detailed_value_func)(PCCERT_CONTEXT cert, void *param);
1164 struct field_value_data
1166 create_detailed_value_func create;
1167 LPWSTR detailed_value;
1168 void *param;
1171 static void add_field_value_data(struct detail_data *data,
1172 create_detailed_value_func create, void *param)
1174 if (data->cFields)
1175 data->fields = HeapReAlloc(GetProcessHeap(), 0, data->fields,
1176 (data->cFields + 1) * sizeof(struct field_value_data));
1177 else
1178 data->fields = HeapAlloc(GetProcessHeap(), 0,
1179 sizeof(struct field_value_data));
1180 if (data->fields)
1182 data->fields[data->cFields].create = create;
1183 data->fields[data->cFields].detailed_value = NULL;
1184 data->fields[data->cFields].param = param;
1185 data->cFields++;
1189 static void add_field_and_value_to_list(HWND hwnd, struct detail_data *data,
1190 LPWSTR field, LPWSTR value, create_detailed_value_func create, void *param)
1192 LVITEMW item;
1193 int iItem = SendMessageW(hwnd, LVM_GETITEMCOUNT, 0, 0);
1195 item.mask = LVIF_TEXT | LVIF_PARAM;
1196 item.iItem = iItem;
1197 item.iSubItem = 0;
1198 item.pszText = field;
1199 item.lParam = (LPARAM)data;
1200 SendMessageW(hwnd, LVM_INSERTITEMW, 0, (LPARAM)&item);
1201 if (value)
1203 item.pszText = value;
1204 item.iSubItem = 1;
1205 SendMessageW(hwnd, LVM_SETITEMTEXTW, iItem, (LPARAM)&item);
1207 add_field_value_data(data, create, param);
1210 static void add_string_id_and_value_to_list(HWND hwnd, struct detail_data *data,
1211 int id, LPWSTR value, create_detailed_value_func create, void *param)
1213 WCHAR buf[MAX_STRING_LEN];
1215 LoadStringW(hInstance, id, buf, sizeof(buf) / sizeof(buf[0]));
1216 add_field_and_value_to_list(hwnd, data, buf, value, create, param);
1219 struct v1_field
1221 int id;
1222 field_format_func format;
1223 create_detailed_value_func create_detailed_value;
1226 static void add_v1_field(HWND hwnd, struct detail_data *data,
1227 const struct v1_field *field)
1229 WCHAR *val = field->format(data->pCertViewInfo->pCertContext);
1231 if (val)
1233 add_string_id_and_value_to_list(hwnd, data, field->id, val,
1234 field->create_detailed_value, NULL);
1235 HeapFree(GetProcessHeap(), 0, val);
1239 static const struct v1_field v1_fields[] = {
1240 { IDS_FIELD_VERSION, field_format_version, NULL },
1241 { IDS_FIELD_SERIAL_NUMBER, field_format_serial_number, NULL },
1242 { IDS_FIELD_ISSUER, field_format_issuer, field_format_detailed_issuer },
1243 { IDS_FIELD_VALID_FROM, field_format_from_date, NULL },
1244 { IDS_FIELD_VALID_TO, field_format_to_date, NULL },
1245 { IDS_FIELD_SUBJECT, field_format_subject, field_format_detailed_subject },
1246 { IDS_FIELD_PUBLIC_KEY, field_format_public_key,
1247 field_format_detailed_public_key }
1250 static void add_v1_fields(HWND hwnd, struct detail_data *data)
1252 int i;
1253 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
1255 /* The last item in v1_fields is the public key, which is not in the loop
1256 * because it's a special case.
1258 for (i = 0; i < sizeof(v1_fields) / sizeof(v1_fields[0]) - 1; i++)
1259 add_v1_field(hwnd, data, &v1_fields[i]);
1260 if (cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData)
1261 add_v1_field(hwnd, data, &v1_fields[i]);
1264 static WCHAR *crypt_format_extension(PCERT_EXTENSION ext, DWORD formatStrType)
1266 WCHAR *str = NULL;
1267 DWORD size;
1269 if (CryptFormatObject(X509_ASN_ENCODING, 0, formatStrType, NULL,
1270 ext->pszObjId, ext->Value.pbData, ext->Value.cbData, NULL, &size))
1272 str = HeapAlloc(GetProcessHeap(), 0, size);
1273 CryptFormatObject(X509_ASN_ENCODING, 0, formatStrType, NULL,
1274 ext->pszObjId, ext->Value.pbData, ext->Value.cbData, str, &size);
1276 return str;
1279 static WCHAR *field_format_extension_hex_with_ascii(PCERT_EXTENSION ext)
1281 WCHAR *str = NULL;
1283 if (ext->Value.cbData)
1285 /* The output is formatted as:
1286 * <hex bytes> <ascii bytes>\n
1287 * where <hex bytes> is a string of up to 8 bytes, output as %02x,
1288 * and <ascii bytes> is the ASCII equivalent of each byte, or '.' if
1289 * the byte is not printable.
1290 * So, for example, the extension value consisting of the following
1291 * bytes:
1292 * 0x30,0x14,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x03,
1293 * 0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67
1294 * is output as:
1295 * 30 14 31 12 30 10 06 03 0.1.0...
1296 * 55 04 03 13 09 4a 75 61 U....Jua
1297 * 6e 20 4c 61 6e 67 n Lang
1298 * The allocation size therefore requires:
1299 * - 4 characters per character in an 8-byte line
1300 * (2 for the hex format, one for the space, one for the ASCII value)
1301 * - 3 more characters per 8-byte line (two spaces and a newline)
1302 * - 1 character for the terminating nul
1303 * FIXME: should use a fixed-width font for this
1305 DWORD lines = (ext->Value.cbData + 7) / 8;
1307 str = HeapAlloc(GetProcessHeap(), 0,
1308 (lines * 8 * 4 + lines * 3 + 1) * sizeof(WCHAR));
1309 if (str)
1311 static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
1312 DWORD i, j;
1313 WCHAR *ptr;
1315 for (i = 0, ptr = str; i < ext->Value.cbData; i += 8)
1317 /* Output as hex bytes first */
1318 for (j = i; j < min(i + 8, ext->Value.cbData); j++, ptr += 3)
1319 sprintfW(ptr, fmt, ext->Value.pbData[j]);
1320 /* Pad the hex output with spaces for alignment */
1321 if (j == ext->Value.cbData && j % 8)
1323 static const WCHAR pad[] = { ' ',' ',' ' };
1325 for (; j % 8; j++, ptr += sizeof(pad) / sizeof(pad[0]))
1326 memcpy(ptr, pad, sizeof(pad));
1328 /* The last sprintfW included a space, so just insert one
1329 * more space between the hex bytes and the ASCII output
1331 *ptr++ = ' ';
1332 /* Output as ASCII bytes */
1333 for (j = i; j < min(i + 8, ext->Value.cbData); j++, ptr++)
1335 if (isprintW(ext->Value.pbData[j]) &&
1336 !isspaceW(ext->Value.pbData[j]))
1337 *ptr = ext->Value.pbData[j];
1338 else
1339 *ptr = '.';
1341 *ptr++ = '\n';
1343 *ptr++ = '\0';
1346 return str;
1349 static WCHAR *field_format_detailed_extension(PCCERT_CONTEXT cert, void *param)
1351 PCERT_EXTENSION ext = param;
1352 LPWSTR str = crypt_format_extension(ext,
1353 CRYPT_FORMAT_STR_MULTI_LINE | CRYPT_FORMAT_STR_NO_HEX);
1355 if (!str)
1356 str = field_format_extension_hex_with_ascii(ext);
1357 return str;
1360 static void add_cert_extension_detail(HWND hwnd, struct detail_data *data,
1361 PCERT_EXTENSION ext)
1363 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
1364 ext->pszObjId, 0);
1365 LPWSTR val = crypt_format_extension(ext, 0);
1367 if (oidInfo)
1368 add_field_and_value_to_list(hwnd, data, (LPWSTR)oidInfo->pwszName,
1369 val, field_format_detailed_extension, ext);
1370 else
1372 DWORD len = strlen(ext->pszObjId);
1373 LPWSTR oidW = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1375 if (oidW)
1377 DWORD i;
1379 for (i = 0; i <= len; i++)
1380 oidW[i] = ext->pszObjId[i];
1381 add_field_and_value_to_list(hwnd, data, oidW, val,
1382 field_format_detailed_extension, ext);
1383 HeapFree(GetProcessHeap(), 0, oidW);
1386 HeapFree(GetProcessHeap(), 0, val);
1389 static void add_all_extensions(HWND hwnd, struct detail_data *data)
1391 DWORD i;
1392 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
1394 for (i = 0; i < cert->pCertInfo->cExtension; i++)
1395 add_cert_extension_detail(hwnd, data, &cert->pCertInfo->rgExtension[i]);
1398 static void add_critical_extensions(HWND hwnd, struct detail_data *data)
1400 DWORD i;
1401 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
1403 for (i = 0; i < cert->pCertInfo->cExtension; i++)
1404 if (cert->pCertInfo->rgExtension[i].fCritical)
1405 add_cert_extension_detail(hwnd, data,
1406 &cert->pCertInfo->rgExtension[i]);
1409 typedef WCHAR * (*prop_to_value_func)(void *pb, DWORD cb);
1411 struct prop_id_to_string_id
1413 DWORD prop;
1414 int id;
1415 BOOL prop_is_string;
1416 prop_to_value_func prop_to_value;
1419 static WCHAR *format_enhanced_key_usage_value(void *pb, DWORD cb)
1421 static const WCHAR sep[] = { ',',' ',0 };
1422 const CERT_ENHKEY_USAGE *usage = (const CERT_ENHKEY_USAGE *)pb;
1423 static WCHAR *str = NULL;
1424 DWORD i, chars = 0;
1426 for (i = 0; i < usage->cUsageIdentifier; i++)
1428 PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
1429 usage->rgpszUsageIdentifier[i], CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
1431 if (info)
1433 chars += strlenW(info->pwszName);
1434 if (i < usage->cUsageIdentifier - 1)
1435 chars += strlenW(sep);
1436 if (!str)
1438 str = HeapAlloc(GetProcessHeap(), 0,
1439 (chars + 1) * sizeof(WCHAR));
1440 if (str)
1441 *str = '\0';
1443 else
1444 str = HeapReAlloc(GetProcessHeap(), 0, str,
1445 (chars + 1) * sizeof(WCHAR));
1446 if (str)
1448 if (i < usage->cUsageIdentifier - 1)
1449 strcatW(str, sep);
1450 strcatW(str, info->pwszName);
1453 else
1455 chars += strlen(usage->rgpszUsageIdentifier[i]);
1456 if (i < usage->cUsageIdentifier - 1)
1457 chars += strlenW(sep);
1458 if (!str)
1460 str = HeapAlloc(GetProcessHeap(), 0,
1461 (chars + 1) * sizeof(WCHAR));
1462 if (str)
1463 *str = '\0';
1465 else
1466 str = HeapReAlloc(GetProcessHeap(), 0, str,
1467 (chars + 1) * sizeof(WCHAR));
1468 if (str)
1470 WCHAR *dst;
1471 const char *src;
1473 if (i < usage->cUsageIdentifier - 1)
1474 strcatW(str, sep);
1475 for (src = usage->rgpszUsageIdentifier[i],
1476 dst = str + strlenW(str); *src; src++, dst++)
1477 *dst = *src;
1478 *dst = '\0';
1482 return str;
1485 /* Logically the access state should also be checked, and IDC_EDITPROPERTIES
1486 * disabled for read-only certificates, but native doesn't appear to do that.
1488 static const struct prop_id_to_string_id prop_id_map[] = {
1489 { CERT_HASH_PROP_ID, IDS_PROP_HASH, FALSE, format_hex_string },
1490 { CERT_FRIENDLY_NAME_PROP_ID, IDS_PROP_FRIENDLY_NAME, TRUE, NULL },
1491 { CERT_DESCRIPTION_PROP_ID, IDS_PROP_DESCRIPTION, TRUE, NULL },
1492 { CERT_ENHKEY_USAGE_PROP_ID, IDS_PROP_ENHKEY_USAGE, FALSE,
1493 format_enhanced_key_usage_value },
1496 static void add_properties(HWND hwnd, struct detail_data *data)
1498 DWORD i;
1499 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
1501 for (i = 0; i < sizeof(prop_id_map) / sizeof(prop_id_map[0]); i++)
1503 DWORD cb;
1505 if (CertGetCertificateContextProperty(cert, prop_id_map[i].prop, NULL,
1506 &cb))
1508 BYTE *pb;
1509 WCHAR *val = NULL;
1511 /* FIXME: MS adds a separate value for the signature hash
1512 * algorithm.
1514 pb = HeapAlloc(GetProcessHeap(), 0, cb);
1515 if (pb)
1517 if (CertGetCertificateContextProperty(cert,
1518 prop_id_map[i].prop, pb, &cb))
1520 if (prop_id_map[i].prop_is_string)
1522 val = (LPWSTR)pb;
1523 /* Don't double-free pb */
1524 pb = NULL;
1526 else
1527 val = prop_id_map[i].prop_to_value(pb, cb);
1529 HeapFree(GetProcessHeap(), 0, pb);
1531 add_string_id_and_value_to_list(hwnd, data, prop_id_map[i].id, val,
1532 NULL, NULL);
1537 static void add_all_fields(HWND hwnd, struct detail_data *data)
1539 add_v1_fields(hwnd, data);
1540 add_all_extensions(hwnd, data);
1541 add_properties(hwnd, data);
1544 struct selection_list_item
1546 int id;
1547 add_fields_func add;
1550 const struct selection_list_item listItems[] = {
1551 { IDS_FIELDS_ALL, add_all_fields },
1552 { IDS_FIELDS_V1, add_v1_fields },
1553 { IDS_FIELDS_EXTENSIONS, add_all_extensions },
1554 { IDS_FIELDS_CRITICAL_EXTENSIONS, add_critical_extensions },
1555 { IDS_FIELDS_PROPERTIES, add_properties },
1558 static void create_show_list(HWND hwnd, struct detail_data *data)
1560 HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT);
1561 WCHAR buf[MAX_STRING_LEN];
1562 int i;
1564 for (i = 0; i < sizeof(listItems) / sizeof(listItems[0]); i++)
1566 int index;
1568 LoadStringW(hInstance, listItems[i].id, buf,
1569 sizeof(buf) / sizeof(buf[0]));
1570 index = SendMessageW(cb, CB_INSERTSTRING, -1, (LPARAM)buf);
1571 SendMessageW(cb, CB_SETITEMDATA, index, (LPARAM)data);
1573 SendMessageW(cb, CB_SETCURSEL, 0, 0);
1576 static void create_listview_columns(HWND hwnd)
1578 HWND lv = GetDlgItem(hwnd, IDC_DETAIL_LIST);
1579 RECT rc;
1580 WCHAR buf[MAX_STRING_LEN];
1581 LVCOLUMNW column;
1583 SendMessageW(lv, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
1584 GetWindowRect(lv, &rc);
1585 LoadStringW(hInstance, IDS_FIELD, buf, sizeof(buf) / sizeof(buf[0]));
1586 column.mask = LVCF_WIDTH | LVCF_TEXT;
1587 column.cx = (rc.right - rc.left) / 2 - 2;
1588 column.pszText = buf;
1589 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
1590 LoadStringW(hInstance, IDS_VALUE, buf, sizeof(buf) / sizeof(buf[0]));
1591 SendMessageW(lv, LVM_INSERTCOLUMNW, 1, (LPARAM)&column);
1594 static void set_fields_selection(HWND hwnd, struct detail_data *data, int sel)
1596 HWND list = GetDlgItem(hwnd, IDC_DETAIL_LIST);
1598 if (sel >= 0 && sel < sizeof(listItems) / sizeof(listItems[0]))
1600 SendMessageW(list, LVM_DELETEALLITEMS, 0, 0);
1601 listItems[sel].add(list, data);
1605 static void create_cert_details_list(HWND hwnd, struct detail_data *data)
1607 create_show_list(hwnd, data);
1608 create_listview_columns(hwnd);
1609 set_fields_selection(hwnd, data, 0);
1612 static void free_detail_fields(struct detail_data *data)
1614 DWORD i;
1616 for (i = 0; i < data->cFields; i++)
1617 HeapFree(GetProcessHeap(), 0, data->fields[i].detailed_value);
1618 HeapFree(GetProcessHeap(), 0, data->fields);
1619 data->fields = NULL;
1620 data->cFields = 0;
1623 static void refresh_details_view(HWND hwnd)
1625 HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT);
1626 int curSel;
1627 struct detail_data *data;
1629 curSel = SendMessageW(cb, CB_GETCURSEL, 0, 0);
1630 /* Actually, any index will do, since they all store the same data value */
1631 data = (struct detail_data *)SendMessageW(cb, CB_GETITEMDATA, curSel, 0);
1632 free_detail_fields(data);
1633 set_fields_selection(hwnd, data, curSel);
1636 static LRESULT CALLBACK detail_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
1637 LPARAM lp)
1639 PROPSHEETPAGEW *page;
1640 struct detail_data *data;
1642 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
1644 switch (msg)
1646 case WM_INITDIALOG:
1647 page = (PROPSHEETPAGEW *)lp;
1648 data = (struct detail_data *)page->lParam;
1649 create_cert_details_list(hwnd, data);
1650 if (!(data->pCertViewInfo->dwFlags & CRYPTUI_ENABLE_EDITPROPERTIES))
1651 EnableWindow(GetDlgItem(hwnd, IDC_EDITPROPERTIES), FALSE);
1652 if (data->pCertViewInfo->dwFlags & CRYPTUI_DISABLE_EXPORT)
1653 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT), FALSE);
1654 break;
1655 case WM_NOTIFY:
1657 NMITEMACTIVATE *nm;
1658 HWND list = GetDlgItem(hwnd, IDC_DETAIL_LIST);
1660 nm = (NMITEMACTIVATE*)lp;
1661 if (nm->hdr.hwndFrom == list && nm->uNewState & LVN_ITEMACTIVATE
1662 && nm->hdr.code == LVN_ITEMCHANGED)
1664 data = (struct detail_data *)nm->lParam;
1665 if (nm->iItem >= 0 && data && nm->iItem < data->cFields)
1667 WCHAR buf[MAX_STRING_LEN], *val = NULL;
1668 HWND valueCtl = GetDlgItem(hwnd, IDC_DETAIL_VALUE);
1670 if (data->fields[nm->iItem].create)
1671 val = data->fields[nm->iItem].create(
1672 data->pCertViewInfo->pCertContext,
1673 data->fields[nm->iItem].param);
1674 else
1676 LVITEMW item;
1677 int res;
1679 item.cchTextMax = sizeof(buf) / sizeof(buf[0]);
1680 item.mask = LVIF_TEXT;
1681 item.pszText = buf;
1682 item.iItem = nm->iItem;
1683 item.iSubItem = 1;
1684 res = SendMessageW(list, LVM_GETITEMW, 0, (LPARAM)&item);
1685 if (res)
1686 val = buf;
1688 /* Select all the text in the control, the next update will
1689 * replace it
1691 SendMessageW(valueCtl, EM_SETSEL, 0, -1);
1692 add_unformatted_text_to_control(valueCtl, val,
1693 val ? strlenW(val) : 0);
1694 if (val != buf)
1695 HeapFree(GetProcessHeap(), 0, val);
1698 break;
1700 case WM_COMMAND:
1701 switch (wp)
1703 case IDC_EXPORT:
1704 FIXME("call CryptUIWizExport\n");
1705 break;
1706 case IDC_EDITPROPERTIES:
1707 FIXME("show edit properties dialog\n");
1708 break;
1709 case ((CBN_SELCHANGE << 16) | IDC_DETAIL_SELECT):
1710 refresh_details_view(hwnd);
1711 break;
1713 break;
1715 return 0;
1718 static BOOL init_detail_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
1719 BOOL *pfPropertiesChanged, PROPSHEETPAGEW *page)
1721 BOOL ret;
1722 struct detail_data *data = HeapAlloc(GetProcessHeap(), 0,
1723 sizeof(struct detail_data));
1725 if (data)
1727 data->pCertViewInfo = pCertViewInfo;
1728 data->pfPropertiesChanged = pfPropertiesChanged;
1729 data->cFields = 0;
1730 data->fields = NULL;
1731 memset(page, 0, sizeof(PROPSHEETPAGEW));
1732 page->dwSize = sizeof(PROPSHEETPAGEW);
1733 page->hInstance = hInstance;
1734 page->u.pszTemplate = MAKEINTRESOURCEW(IDD_DETAIL);
1735 page->pfnDlgProc = detail_dlg_proc;
1736 page->lParam = (LPARAM)data;
1737 ret = TRUE;
1739 else
1740 ret = FALSE;
1741 return ret;
1744 struct hierarchy_data
1746 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo;
1747 DWORD selectedCert;
1750 static void show_cert_hierarchy(HWND hwnd, struct hierarchy_data *data)
1752 /* Disable view certificate button until a certificate is selected */
1753 EnableWindow(GetDlgItem(hwnd, IDC_VIEWCERTIFICATE), FALSE);
1754 FIXME("show cert chain\n");
1757 static LRESULT CALLBACK hierarchy_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
1758 LPARAM lp)
1760 PROPSHEETPAGEW *page;
1761 struct hierarchy_data *data;
1763 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
1765 switch (msg)
1767 case WM_INITDIALOG:
1768 page = (PROPSHEETPAGEW *)lp;
1769 data = (struct hierarchy_data *)page->lParam;
1770 show_cert_hierarchy(hwnd, data);
1771 break;
1773 return 0;
1776 static UINT CALLBACK hierarchy_callback(HWND hwnd, UINT msg,
1777 PROPSHEETPAGEW *page)
1779 struct hierarchy_data *data;
1781 switch (msg)
1783 case PSPCB_RELEASE:
1784 data = (struct hierarchy_data *)page->lParam;
1785 HeapFree(GetProcessHeap(), 0, data);
1786 break;
1788 return 0;
1791 static BOOL init_hierarchy_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
1792 PROPSHEETPAGEW *page)
1794 struct hierarchy_data *data = HeapAlloc(GetProcessHeap(), 0,
1795 sizeof(struct hierarchy_data));
1796 BOOL ret = FALSE;
1798 if (data)
1800 data->pCertViewInfo = pCertViewInfo;
1801 data->selectedCert = 0xffffffff;
1803 memset(page, 0, sizeof(PROPSHEETPAGEW));
1804 page->dwSize = sizeof(PROPSHEETPAGEW);
1805 page->dwFlags = PSP_USECALLBACK;
1806 page->hInstance = hInstance;
1807 page->u.pszTemplate = MAKEINTRESOURCEW(IDD_HIERARCHY);
1808 page->pfnDlgProc = hierarchy_dlg_proc;
1809 page->lParam = (LPARAM)data;
1810 page->pfnCallback = hierarchy_callback;
1811 ret = TRUE;
1813 return ret;
1816 static int CALLBACK cert_prop_sheet_proc(HWND hwnd, UINT msg, LPARAM lp)
1818 RECT rc;
1819 POINT topLeft;
1821 TRACE("(%p, %08x, %08lx)\n", hwnd, msg, lp);
1823 switch (msg)
1825 case PSCB_INITIALIZED:
1826 /* Get cancel button's position.. */
1827 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rc);
1828 topLeft.x = rc.left;
1829 topLeft.y = rc.top;
1830 ScreenToClient(hwnd, &topLeft);
1831 /* hide the cancel button.. */
1832 ShowWindow(GetDlgItem(hwnd, IDCANCEL), FALSE);
1833 /* get the OK button's size.. */
1834 GetWindowRect(GetDlgItem(hwnd, IDOK), &rc);
1835 /* and move the OK button to the cancel button's original position. */
1836 MoveWindow(GetDlgItem(hwnd, IDOK), topLeft.x, topLeft.y,
1837 rc.right - rc.left, rc.bottom - rc.top, FALSE);
1838 GetWindowRect(GetDlgItem(hwnd, IDOK), &rc);
1839 break;
1841 return 0;
1844 static BOOL show_cert_dialog(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
1845 CRYPT_PROVIDER_CERT *provCert, BOOL *pfPropertiesChanged)
1847 static const WCHAR riched[] = { 'r','i','c','h','e','d','2','0',0 };
1848 DWORD nPages;
1849 PROPSHEETPAGEW *pages;
1850 BOOL ret = FALSE;
1851 HMODULE lib = LoadLibraryW(riched);
1853 nPages = pCertViewInfo->cPropSheetPages + 1; /* one for the General tab */
1854 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_DETAILPAGE))
1855 nPages++;
1856 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_HIERARCHYPAGE))
1857 nPages++;
1858 pages = HeapAlloc(GetProcessHeap(), 0, nPages * sizeof(PROPSHEETPAGEW));
1859 if (pages)
1861 PROPSHEETHEADERW hdr;
1862 CRYPTUI_INITDIALOG_STRUCT *init = NULL;
1863 DWORD i;
1865 memset(&hdr, 0, sizeof(hdr));
1866 hdr.dwSize = sizeof(hdr);
1867 hdr.dwFlags = PSH_NOAPPLYNOW | PSH_PROPSHEETPAGE | PSH_USECALLBACK;
1868 hdr.hInstance = hInstance;
1869 if (pCertViewInfo->szTitle)
1870 hdr.pszCaption = pCertViewInfo->szTitle;
1871 else
1872 hdr.pszCaption = MAKEINTRESOURCEW(IDS_CERTIFICATE);
1873 init_general_page(pCertViewInfo, &pages[hdr.nPages++]);
1874 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_DETAILPAGE))
1876 if (init_detail_page(pCertViewInfo, pfPropertiesChanged,
1877 &pages[hdr.nPages]))
1878 hdr.nPages++;
1880 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_HIERARCHYPAGE))
1882 if (init_hierarchy_page(pCertViewInfo, &pages[hdr.nPages]))
1883 hdr.nPages++;
1885 /* Copy each additional page, and create the init dialog struct for it
1887 if (pCertViewInfo->cPropSheetPages)
1889 init = HeapAlloc(GetProcessHeap(), 0,
1890 pCertViewInfo->cPropSheetPages *
1891 sizeof(CRYPTUI_INITDIALOG_STRUCT));
1892 if (init)
1894 for (i = 0; i < pCertViewInfo->cPropSheetPages; i++)
1896 memcpy(&pages[hdr.nPages + i],
1897 &pCertViewInfo->rgPropSheetPages[i],
1898 sizeof(PROPSHEETPAGEW));
1899 init[i].lParam = pCertViewInfo->rgPropSheetPages[i].lParam;
1900 init[i].pCertContext = pCertViewInfo->pCertContext;
1901 pages[hdr.nPages + i].lParam = (LPARAM)&init[i];
1903 if (pCertViewInfo->nStartPage & 0x8000)
1905 /* Start page index is relative to the number of default
1906 * pages
1908 hdr.u2.nStartPage = pCertViewInfo->nStartPage + hdr.nPages;
1910 else
1911 hdr.u2.nStartPage = pCertViewInfo->nStartPage;
1912 hdr.nPages = nPages;
1913 ret = TRUE;
1915 else
1916 SetLastError(ERROR_OUTOFMEMORY);
1918 else
1920 /* Ignore the relative flag if there aren't any additional pages */
1921 hdr.u2.nStartPage = pCertViewInfo->nStartPage & 0x7fff;
1922 ret = TRUE;
1924 if (ret)
1926 INT_PTR l;
1928 hdr.u3.ppsp = pages;
1929 hdr.pfnCallback = cert_prop_sheet_proc;
1930 l = PropertySheetW(&hdr);
1931 if (l == 0)
1933 SetLastError(ERROR_CANCELLED);
1934 ret = FALSE;
1937 HeapFree(GetProcessHeap(), 0, init);
1938 HeapFree(GetProcessHeap(), 0, pages);
1940 else
1941 SetLastError(ERROR_OUTOFMEMORY);
1942 FreeLibrary(lib);
1943 return ret;
1946 /***********************************************************************
1947 * CryptUIDlgViewCertificateW (CRYPTUI.@)
1949 BOOL WINAPI CryptUIDlgViewCertificateW(
1950 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo, BOOL *pfPropertiesChanged)
1952 static GUID generic_cert_verify = WINTRUST_ACTION_GENERIC_CERT_VERIFY;
1953 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
1954 WINTRUST_DATA wvt;
1955 WINTRUST_CERT_INFO cert;
1956 BOOL ret = FALSE;
1957 CRYPT_PROVIDER_SGNR *signer;
1958 CRYPT_PROVIDER_CERT *provCert = NULL;
1960 TRACE("(%p, %p)\n", pCertViewInfo, pfPropertiesChanged);
1962 if (pCertViewInfo->dwSize != sizeof(CRYPTUI_VIEWCERTIFICATE_STRUCTW))
1964 SetLastError(ERROR_INVALID_PARAMETER);
1965 return FALSE;
1967 /* Make a local copy in case we have to call WinVerifyTrust ourselves */
1968 memcpy(&viewInfo, pCertViewInfo, sizeof(viewInfo));
1969 if (!viewInfo.u.hWVTStateData)
1971 memset(&wvt, 0, sizeof(wvt));
1972 wvt.cbStruct = sizeof(wvt);
1973 wvt.dwUIChoice = WTD_UI_NONE;
1974 if (viewInfo.dwFlags &
1975 CRYPTUI_ENABLE_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT)
1976 wvt.fdwRevocationChecks |= WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
1977 if (viewInfo.dwFlags & CRYPTUI_ENABLE_REVOCATION_CHECK_END_CERT)
1978 wvt.fdwRevocationChecks |= WTD_REVOCATION_CHECK_END_CERT;
1979 if (viewInfo.dwFlags & CRYPTUI_ENABLE_REVOCATION_CHECK_CHAIN)
1980 wvt.fdwRevocationChecks |= WTD_REVOCATION_CHECK_CHAIN;
1981 wvt.dwUnionChoice = WTD_CHOICE_CERT;
1982 memset(&cert, 0, sizeof(cert));
1983 cert.cbStruct = sizeof(cert);
1984 cert.psCertContext = (CERT_CONTEXT *)viewInfo.pCertContext;
1985 cert.chStores = viewInfo.cStores;
1986 cert.pahStores = viewInfo.rghStores;
1987 wvt.u.pCert = &cert;
1988 wvt.dwStateAction = WTD_STATEACTION_VERIFY;
1989 WinVerifyTrust(NULL, &generic_cert_verify, &wvt);
1990 viewInfo.u.pCryptProviderData =
1991 WTHelperProvDataFromStateData(wvt.hWVTStateData);
1992 signer = WTHelperGetProvSignerFromChain(
1993 (CRYPT_PROVIDER_DATA *)viewInfo.u.pCryptProviderData, 0, FALSE, 0);
1994 provCert = WTHelperGetProvCertFromChain(signer, 0);
1995 ret = TRUE;
1997 else
1999 viewInfo.u.pCryptProviderData =
2000 WTHelperProvDataFromStateData(viewInfo.u.hWVTStateData);
2001 signer = WTHelperGetProvSignerFromChain(
2002 (CRYPT_PROVIDER_DATA *)viewInfo.u.pCryptProviderData,
2003 viewInfo.idxSigner, viewInfo.fCounterSigner,
2004 viewInfo.idxCounterSigner);
2005 provCert = WTHelperGetProvCertFromChain(signer, viewInfo.idxCert);
2006 ret = TRUE;
2008 if (ret)
2010 ret = show_cert_dialog(&viewInfo, provCert, pfPropertiesChanged);
2011 if (!viewInfo.u.hWVTStateData)
2013 wvt.dwStateAction = WTD_STATEACTION_CLOSE;
2014 WinVerifyTrust(NULL, &generic_cert_verify, &wvt);
2017 return ret;
2020 static PCCERT_CONTEXT make_cert_from_file(LPCWSTR fileName)
2022 HANDLE file;
2023 DWORD size, encoding = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
2024 BYTE *buffer;
2025 PCCERT_CONTEXT cert;
2027 file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
2028 OPEN_EXISTING, 0, NULL);
2029 if (file == INVALID_HANDLE_VALUE)
2031 WARN("can't open certificate file %s\n", debugstr_w(fileName));
2032 return NULL;
2034 if ((size = GetFileSize(file, NULL)))
2036 if ((buffer = HeapAlloc(GetProcessHeap(), 0, size)))
2038 DWORD read;
2039 if (!ReadFile(file, buffer, size, &read, NULL) || read != size)
2041 WARN("can't read certificate file %s\n", debugstr_w(fileName));
2042 HeapFree(GetProcessHeap(), 0, buffer);
2043 CloseHandle(file);
2044 return NULL;
2048 else
2050 WARN("empty file %s\n", debugstr_w(fileName));
2051 CloseHandle(file);
2052 return NULL;
2054 CloseHandle(file);
2055 cert = CertCreateCertificateContext(encoding, buffer, size);
2056 HeapFree(GetProcessHeap(), 0, buffer);
2057 return cert;
2060 /* Decodes a cert's basic constraints extension (either szOID_BASIC_CONSTRAINTS
2061 * or szOID_BASIC_CONSTRAINTS2, whichever is present) to determine if it
2062 * should be a CA. If neither extension is present, returns
2063 * defaultIfNotSpecified.
2065 static BOOL is_ca_cert(PCCERT_CONTEXT cert, BOOL defaultIfNotSpecified)
2067 BOOL isCA = defaultIfNotSpecified;
2068 PCERT_EXTENSION ext = CertFindExtension(szOID_BASIC_CONSTRAINTS,
2069 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
2071 if (ext)
2073 CERT_BASIC_CONSTRAINTS_INFO *info;
2074 DWORD size = 0;
2076 if (CryptDecodeObjectEx(X509_ASN_ENCODING, szOID_BASIC_CONSTRAINTS,
2077 ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG,
2078 NULL, (LPBYTE)&info, &size))
2080 if (info->SubjectType.cbData == 1)
2081 isCA = info->SubjectType.pbData[0] & CERT_CA_SUBJECT_FLAG;
2082 LocalFree(info);
2085 else
2087 ext = CertFindExtension(szOID_BASIC_CONSTRAINTS2,
2088 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
2089 if (ext)
2091 CERT_BASIC_CONSTRAINTS2_INFO info;
2092 DWORD size = sizeof(CERT_BASIC_CONSTRAINTS2_INFO);
2094 if (CryptDecodeObjectEx(X509_ASN_ENCODING,
2095 szOID_BASIC_CONSTRAINTS2, ext->Value.pbData, ext->Value.cbData,
2096 0, NULL, &info, &size))
2097 isCA = info.fCA;
2100 return isCA;
2103 static HCERTSTORE choose_store_for_cert(PCCERT_CONTEXT cert)
2105 static const WCHAR AddressBook[] = { 'A','d','d','r','e','s','s',
2106 'B','o','o','k',0 };
2107 static const WCHAR CA[] = { 'C','A',0 };
2108 LPCWSTR storeName;
2110 if (is_ca_cert(cert, TRUE))
2111 storeName = CA;
2112 else
2113 storeName = AddressBook;
2114 return CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0,
2115 CERT_SYSTEM_STORE_CURRENT_USER, storeName);
2118 BOOL WINAPI CryptUIWizImport(DWORD dwFlags, HWND hwndParent, LPCWSTR pwszWizardTitle,
2119 PCCRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc, HCERTSTORE hDestCertStore)
2121 BOOL ret;
2122 HCERTSTORE store;
2123 const CERT_CONTEXT *cert;
2124 BOOL freeCert = FALSE;
2126 TRACE("(0x%08x, %p, %s, %p, %p)\n", dwFlags, hwndParent, debugstr_w(pwszWizardTitle),
2127 pImportSrc, hDestCertStore);
2129 if (!(dwFlags & CRYPTUI_WIZ_NO_UI)) FIXME("UI not implemented\n");
2131 if (!pImportSrc ||
2132 pImportSrc->dwSize != sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO))
2134 SetLastError(E_INVALIDARG);
2135 return FALSE;
2138 switch (pImportSrc->dwSubjectChoice)
2140 case CRYPTUI_WIZ_IMPORT_SUBJECT_FILE:
2141 if (!(cert = make_cert_from_file(pImportSrc->u.pwszFileName)))
2143 WARN("unable to create certificate context\n");
2144 return FALSE;
2146 else
2147 freeCert = TRUE;
2148 break;
2149 case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_CONTEXT:
2150 cert = pImportSrc->u.pCertContext;
2151 if (!cert)
2153 SetLastError(E_INVALIDARG);
2154 return FALSE;
2156 break;
2157 default:
2158 FIXME("source type not implemented: %u\n", pImportSrc->dwSubjectChoice);
2159 SetLastError(E_INVALIDARG);
2160 return FALSE;
2162 if (hDestCertStore) store = hDestCertStore;
2163 else
2165 if (!(store = choose_store_for_cert(cert)))
2167 WARN("unable to open certificate store\n");
2168 CertFreeCertificateContext(cert);
2169 return FALSE;
2172 ret = CertAddCertificateContextToStore(store, cert, CERT_STORE_ADD_REPLACE_EXISTING, NULL);
2174 if (!hDestCertStore) CertCloseStore(store, 0);
2175 if (freeCert)
2176 CertFreeCertificateContext(cert);
2177 return ret;