push edc49a132052b6e245fe2c0c0797f387fa16f3c6
[wine/hacks.git] / dlls / cryptui / main.c
blob82a877f045693fa6ed5bca367d709630cc3fd433
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 ||
746 (provSigner->pChainContext->TrustStatus.dwErrorStatus &
747 CERT_TRUST_IS_PARTIAL_CHAIN))
748 add_icon_to_control(icon, IDB_CERT_WARNING);
749 else if (!root->fTrustedRoot)
750 add_icon_to_control(icon, IDB_CERT_ERROR);
751 else
752 add_icon_to_control(icon, IDB_CERT);
754 memset(&charFmt, 0, sizeof(charFmt));
755 charFmt.cbSize = sizeof(charFmt);
756 charFmt.dwMask = CFM_BOLD;
757 charFmt.dwEffects = CFE_BOLD;
758 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
759 /* FIXME: vertically center text */
760 parFmt.cbSize = sizeof(parFmt);
761 parFmt.dwMask = PFM_STARTINDENT;
762 parFmt.dxStartIndent = MY_INDENT;
763 add_string_resource_with_paraformat_to_control(text,
764 IDS_CERTIFICATEINFORMATION, &parFmt);
766 text = GetDlgItem(hwnd, IDC_CERTIFICATE_STATUS);
767 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
768 if (provSigner->dwError == TRUST_E_CERT_SIGNATURE)
769 add_string_resource_with_paraformat_to_control(text,
770 IDS_CERT_INFO_BAD_SIG, &parFmt);
771 else if (!provSigner->pChainContext ||
772 (provSigner->pChainContext->TrustStatus.dwErrorStatus &
773 CERT_TRUST_IS_PARTIAL_CHAIN))
774 add_string_resource_with_paraformat_to_control(text,
775 IDS_CERT_INFO_PARTIAL_CHAIN, &parFmt);
776 else if (!root->fTrustedRoot)
778 if (provSigner->csCertChain == 1 && root->fSelfSigned)
779 add_string_resource_with_paraformat_to_control(text,
780 IDS_CERT_INFO_UNTRUSTED_CA, &parFmt);
781 else
782 add_string_resource_with_paraformat_to_control(text,
783 IDS_CERT_INFO_UNTRUSTED_ROOT, &parFmt);
785 else
787 set_policy_text(text, pCertViewInfo);
788 set_issuer_statement(hwnd, pCertViewInfo);
792 static void set_cert_name_string(HWND hwnd, PCCERT_CONTEXT cert,
793 DWORD nameFlags, int heading)
795 WCHAR nl = '\n';
796 HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_NAMES);
797 CHARFORMATW charFmt;
798 PARAFORMAT2 parFmt;
800 memset(&charFmt, 0, sizeof(charFmt));
801 charFmt.cbSize = sizeof(charFmt);
802 charFmt.dwMask = CFM_BOLD;
803 charFmt.dwEffects = CFE_BOLD;
804 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
805 parFmt.cbSize = sizeof(parFmt);
806 parFmt.dwMask = PFM_STARTINDENT;
807 parFmt.dxStartIndent = MY_INDENT * 3;
808 add_string_resource_with_paraformat_to_control(text, heading, &parFmt);
809 charFmt.dwEffects = 0;
810 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
811 add_cert_string_to_control(text, cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
812 nameFlags);
813 add_unformatted_text_to_control(text, &nl, 1);
814 add_unformatted_text_to_control(text, &nl, 1);
815 add_unformatted_text_to_control(text, &nl, 1);
819 static void add_date_string_to_control(HWND hwnd, const FILETIME *fileTime)
821 WCHAR dateFmt[80]; /* sufficient for all versions of LOCALE_SSHORTDATE */
822 WCHAR date[80];
823 SYSTEMTIME sysTime;
825 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SSHORTDATE, dateFmt,
826 sizeof(dateFmt) / sizeof(dateFmt[0]));
827 FileTimeToSystemTime(fileTime, &sysTime);
828 GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, date,
829 sizeof(date) / sizeof(date[0]));
830 add_unformatted_text_to_control(hwnd, date, lstrlenW(date));
833 static void set_cert_validity_period(HWND hwnd, PCCERT_CONTEXT cert)
835 WCHAR nl = '\n';
836 HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_NAMES);
837 CHARFORMATW charFmt;
838 PARAFORMAT2 parFmt;
840 memset(&charFmt, 0, sizeof(charFmt));
841 charFmt.cbSize = sizeof(charFmt);
842 charFmt.dwMask = CFM_BOLD;
843 charFmt.dwEffects = CFE_BOLD;
844 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
845 parFmt.cbSize = sizeof(parFmt);
846 parFmt.dwMask = PFM_STARTINDENT;
847 parFmt.dxStartIndent = MY_INDENT * 3;
848 add_string_resource_with_paraformat_to_control(text, IDS_VALID_FROM,
849 &parFmt);
850 charFmt.dwEffects = 0;
851 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
852 add_date_string_to_control(text, &cert->pCertInfo->NotBefore);
853 charFmt.dwEffects = CFE_BOLD;
854 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
855 add_string_resource_to_control(text, IDS_VALID_TO);
856 charFmt.dwEffects = 0;
857 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
858 add_date_string_to_control(text, &cert->pCertInfo->NotAfter);
859 add_unformatted_text_to_control(text, &nl, 1);
862 static void set_general_info(HWND hwnd,
863 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
865 set_cert_info(hwnd, pCertViewInfo);
866 set_cert_name_string(hwnd, pCertViewInfo->pCertContext, 0,
867 IDS_SUBJECT_HEADING);
868 set_cert_name_string(hwnd, pCertViewInfo->pCertContext,
869 CERT_NAME_ISSUER_FLAG, IDS_ISSUER_HEADING);
870 set_cert_validity_period(hwnd, pCertViewInfo->pCertContext);
873 static LRESULT CALLBACK user_notice_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
874 LPARAM lp)
876 LRESULT ret = 0;
877 HWND text;
878 struct IssuerStatement *issuerStatement;
880 switch (msg)
882 case WM_INITDIALOG:
883 text = GetDlgItem(hwnd, IDC_USERNOTICE);
884 issuerStatement = (struct IssuerStatement *)lp;
885 add_unformatted_text_to_control(text, issuerStatement->userNotice,
886 strlenW(issuerStatement->userNotice));
887 if (issuerStatement->cps)
888 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)issuerStatement->cps);
889 else
890 EnableWindow(GetDlgItem(hwnd, IDC_CPS), FALSE);
891 break;
892 case WM_COMMAND:
893 switch (wp)
895 case IDOK:
896 EndDialog(hwnd, IDOK);
897 ret = TRUE;
898 break;
899 case IDC_CPS:
901 IBindCtx *bctx = NULL;
902 LPWSTR cps;
904 CreateBindCtx(0, &bctx);
905 cps = (LPWSTR)GetWindowLongPtrW(hwnd, DWLP_USER);
906 HlinkSimpleNavigateToString(cps, NULL, NULL, NULL, bctx, NULL,
907 HLNF_OPENINNEWWINDOW, 0);
908 IBindCtx_Release(bctx);
909 break;
913 return ret;
916 static void show_user_notice(HWND hwnd, struct IssuerStatement *issuerStatement)
918 DialogBoxParamW(hInstance, MAKEINTRESOURCEW(IDD_USERNOTICE), hwnd,
919 user_notice_dlg_proc, (LPARAM)issuerStatement);
922 static LRESULT CALLBACK general_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
923 LPARAM lp)
925 PROPSHEETPAGEW *page;
926 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo;
928 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
930 switch (msg)
932 case WM_INITDIALOG:
933 page = (PROPSHEETPAGEW *)lp;
934 pCertViewInfo = (PCCRYPTUI_VIEWCERTIFICATE_STRUCTW)page->lParam;
935 if (pCertViewInfo->dwFlags & CRYPTUI_DISABLE_ADDTOSTORE)
936 ShowWindow(GetDlgItem(hwnd, IDC_ADDTOSTORE), FALSE);
937 EnableWindow(GetDlgItem(hwnd, IDC_ISSUERSTATEMENT), FALSE);
938 set_general_info(hwnd, pCertViewInfo);
939 break;
940 case WM_COMMAND:
941 switch (wp)
943 case IDC_ADDTOSTORE:
944 FIXME("call CryptUIWizImport\n");
945 break;
946 case IDC_ISSUERSTATEMENT:
948 struct IssuerStatement *issuerStatement =
949 (struct IssuerStatement *)GetWindowLongPtrW(hwnd, DWLP_USER);
951 if (issuerStatement)
953 if (issuerStatement->userNotice)
954 show_user_notice(hwnd, issuerStatement);
955 else if (issuerStatement->cps)
957 IBindCtx *bctx = NULL;
959 CreateBindCtx(0, &bctx);
960 HlinkSimpleNavigateToString(issuerStatement->cps, NULL,
961 NULL, NULL, bctx, NULL, HLNF_OPENINNEWWINDOW, 0);
962 IBindCtx_Release(bctx);
965 break;
968 break;
970 return 0;
973 static UINT CALLBACK general_callback_proc(HWND hwnd, UINT msg,
974 PROPSHEETPAGEW *page)
976 struct IssuerStatement *issuerStatement;
978 switch (msg)
980 case PSPCB_RELEASE:
981 issuerStatement =
982 (struct IssuerStatement *)GetWindowLongPtrW(hwnd, DWLP_USER);
983 if (issuerStatement)
985 HeapFree(GetProcessHeap(), 0, issuerStatement->cps);
986 HeapFree(GetProcessHeap(), 0, issuerStatement->userNotice);
987 HeapFree(GetProcessHeap(), 0, issuerStatement);
989 break;
991 return 1;
994 static void init_general_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
995 PROPSHEETPAGEW *page)
997 memset(page, 0, sizeof(PROPSHEETPAGEW));
998 page->dwSize = sizeof(PROPSHEETPAGEW);
999 page->dwFlags = PSP_USECALLBACK;
1000 page->pfnCallback = general_callback_proc;
1001 page->hInstance = hInstance;
1002 page->u.pszTemplate = MAKEINTRESOURCEW(IDD_GENERAL);
1003 page->pfnDlgProc = general_dlg_proc;
1004 page->lParam = (LPARAM)pCertViewInfo;
1007 typedef WCHAR * (*field_format_func)(PCCERT_CONTEXT cert);
1009 static WCHAR *field_format_version(PCCERT_CONTEXT cert)
1011 static const WCHAR fmt[] = { 'V','%','d',0 };
1012 WCHAR *buf = HeapAlloc(GetProcessHeap(), 0, 12 * sizeof(WCHAR));
1014 if (buf)
1015 sprintfW(buf, fmt, cert->pCertInfo->dwVersion);
1016 return buf;
1019 static WCHAR *format_hex_string(void *pb, DWORD cb)
1021 WCHAR *buf = HeapAlloc(GetProcessHeap(), 0, (cb * 3 + 1) * sizeof(WCHAR));
1023 if (buf)
1025 static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
1026 DWORD i;
1027 WCHAR *ptr;
1029 for (i = 0, ptr = buf; i < cb; i++, ptr += 3)
1030 sprintfW(ptr, fmt, ((BYTE *)pb)[i]);
1032 return buf;
1035 static WCHAR *field_format_serial_number(PCCERT_CONTEXT cert)
1037 return format_hex_string(cert->pCertInfo->SerialNumber.pbData,
1038 cert->pCertInfo->SerialNumber.cbData);
1041 static WCHAR *field_format_issuer(PCCERT_CONTEXT cert)
1043 return get_cert_name_string(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
1044 CERT_NAME_ISSUER_FLAG);
1047 static WCHAR *field_format_detailed_cert_name(PCERT_NAME_BLOB name)
1049 WCHAR *str = NULL;
1050 DWORD len = CertNameToStrW(X509_ASN_ENCODING, name,
1051 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, NULL, 0);
1053 if (len)
1055 str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1056 if (str)
1057 CertNameToStrW(X509_ASN_ENCODING, name,
1058 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, str, len);
1060 return str;
1063 static WCHAR *field_format_detailed_issuer(PCCERT_CONTEXT cert, void *param)
1065 return field_format_detailed_cert_name(&cert->pCertInfo->Issuer);
1068 static WCHAR *field_format_subject(PCCERT_CONTEXT cert)
1070 return get_cert_name_string(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0);
1073 static WCHAR *field_format_detailed_subject(PCCERT_CONTEXT cert, void *param)
1075 return field_format_detailed_cert_name(&cert->pCertInfo->Subject);
1078 static WCHAR *format_long_date(const FILETIME *fileTime)
1080 WCHAR dateFmt[80]; /* long enough for LOCALE_SLONGDATE */
1081 DWORD len;
1082 WCHAR *buf = NULL;
1083 SYSTEMTIME sysTime;
1085 /* FIXME: format isn't quite right, want time too */
1086 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SLONGDATE, dateFmt,
1087 sizeof(dateFmt) / sizeof(dateFmt[0]));
1088 FileTimeToSystemTime(fileTime, &sysTime);
1089 len = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, NULL, 0);
1090 if (len)
1092 buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1093 if (buf)
1094 GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, buf,
1095 len);
1097 return buf;
1100 static WCHAR *field_format_from_date(PCCERT_CONTEXT cert)
1102 return format_long_date(&cert->pCertInfo->NotBefore);
1105 static WCHAR *field_format_to_date(PCCERT_CONTEXT cert)
1107 return format_long_date(&cert->pCertInfo->NotAfter);
1110 static WCHAR *field_format_public_key(PCCERT_CONTEXT cert)
1112 PCCRYPT_OID_INFO oidInfo;
1113 WCHAR *buf = NULL;
1115 oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
1116 cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, 0);
1117 if (oidInfo)
1119 WCHAR fmt[MAX_STRING_LEN];
1121 if (LoadStringW(hInstance, IDS_FIELD_PUBLIC_KEY_FORMAT, fmt,
1122 sizeof(fmt) / sizeof(fmt[0])))
1124 /* Allocate the output buffer. Use the number of bytes in the
1125 * public key as a conservative (high) estimate for the number of
1126 * digits in its output.
1127 * The output is of the form (in English)
1128 * "<public key algorithm> (<public key bit length> bits)".
1129 * Ordinarily having two positional parameters in a string is not a
1130 * good idea, but as this isn't a sentence fragment, it shouldn't
1131 * be word-order dependent.
1133 buf = HeapAlloc(GetProcessHeap(), 0,
1134 (strlenW(fmt) + strlenW(oidInfo->pwszName) +
1135 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData * 8)
1136 * sizeof(WCHAR));
1137 if (buf)
1138 sprintfW(buf, fmt, oidInfo->pwszName,
1139 CertGetPublicKeyLength(X509_ASN_ENCODING,
1140 &cert->pCertInfo->SubjectPublicKeyInfo));
1143 return buf;
1146 static WCHAR *field_format_detailed_public_key(PCCERT_CONTEXT cert, void *param)
1148 return format_hex_string(
1149 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
1150 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData);
1153 struct field_value_data;
1154 struct detail_data
1156 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo;
1157 BOOL *pfPropertiesChanged;
1158 int cFields;
1159 struct field_value_data *fields;
1162 typedef void (*add_fields_func)(HWND hwnd, struct detail_data *data);
1164 typedef WCHAR *(*create_detailed_value_func)(PCCERT_CONTEXT cert, void *param);
1166 struct field_value_data
1168 create_detailed_value_func create;
1169 LPWSTR detailed_value;
1170 void *param;
1173 static void add_field_value_data(struct detail_data *data,
1174 create_detailed_value_func create, void *param)
1176 if (data->cFields)
1177 data->fields = HeapReAlloc(GetProcessHeap(), 0, data->fields,
1178 (data->cFields + 1) * sizeof(struct field_value_data));
1179 else
1180 data->fields = HeapAlloc(GetProcessHeap(), 0,
1181 sizeof(struct field_value_data));
1182 if (data->fields)
1184 data->fields[data->cFields].create = create;
1185 data->fields[data->cFields].detailed_value = NULL;
1186 data->fields[data->cFields].param = param;
1187 data->cFields++;
1191 static void add_field_and_value_to_list(HWND hwnd, struct detail_data *data,
1192 LPWSTR field, LPWSTR value, create_detailed_value_func create, void *param)
1194 LVITEMW item;
1195 int iItem = SendMessageW(hwnd, LVM_GETITEMCOUNT, 0, 0);
1197 item.mask = LVIF_TEXT | LVIF_PARAM;
1198 item.iItem = iItem;
1199 item.iSubItem = 0;
1200 item.pszText = field;
1201 item.lParam = (LPARAM)data;
1202 SendMessageW(hwnd, LVM_INSERTITEMW, 0, (LPARAM)&item);
1203 if (value)
1205 item.pszText = value;
1206 item.iSubItem = 1;
1207 SendMessageW(hwnd, LVM_SETITEMTEXTW, iItem, (LPARAM)&item);
1209 add_field_value_data(data, create, param);
1212 static void add_string_id_and_value_to_list(HWND hwnd, struct detail_data *data,
1213 int id, LPWSTR value, create_detailed_value_func create, void *param)
1215 WCHAR buf[MAX_STRING_LEN];
1217 LoadStringW(hInstance, id, buf, sizeof(buf) / sizeof(buf[0]));
1218 add_field_and_value_to_list(hwnd, data, buf, value, create, param);
1221 struct v1_field
1223 int id;
1224 field_format_func format;
1225 create_detailed_value_func create_detailed_value;
1228 static void add_v1_field(HWND hwnd, struct detail_data *data,
1229 const struct v1_field *field)
1231 WCHAR *val = field->format(data->pCertViewInfo->pCertContext);
1233 if (val)
1235 add_string_id_and_value_to_list(hwnd, data, field->id, val,
1236 field->create_detailed_value, NULL);
1237 HeapFree(GetProcessHeap(), 0, val);
1241 static const struct v1_field v1_fields[] = {
1242 { IDS_FIELD_VERSION, field_format_version, NULL },
1243 { IDS_FIELD_SERIAL_NUMBER, field_format_serial_number, NULL },
1244 { IDS_FIELD_ISSUER, field_format_issuer, field_format_detailed_issuer },
1245 { IDS_FIELD_VALID_FROM, field_format_from_date, NULL },
1246 { IDS_FIELD_VALID_TO, field_format_to_date, NULL },
1247 { IDS_FIELD_SUBJECT, field_format_subject, field_format_detailed_subject },
1248 { IDS_FIELD_PUBLIC_KEY, field_format_public_key,
1249 field_format_detailed_public_key }
1252 static void add_v1_fields(HWND hwnd, struct detail_data *data)
1254 int i;
1255 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
1257 /* The last item in v1_fields is the public key, which is not in the loop
1258 * because it's a special case.
1260 for (i = 0; i < sizeof(v1_fields) / sizeof(v1_fields[0]) - 1; i++)
1261 add_v1_field(hwnd, data, &v1_fields[i]);
1262 if (cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData)
1263 add_v1_field(hwnd, data, &v1_fields[i]);
1266 static WCHAR *crypt_format_extension(PCERT_EXTENSION ext, DWORD formatStrType)
1268 WCHAR *str = NULL;
1269 DWORD size;
1271 if (CryptFormatObject(X509_ASN_ENCODING, 0, formatStrType, NULL,
1272 ext->pszObjId, ext->Value.pbData, ext->Value.cbData, NULL, &size))
1274 str = HeapAlloc(GetProcessHeap(), 0, size);
1275 CryptFormatObject(X509_ASN_ENCODING, 0, formatStrType, NULL,
1276 ext->pszObjId, ext->Value.pbData, ext->Value.cbData, str, &size);
1278 return str;
1281 static WCHAR *field_format_extension_hex_with_ascii(PCERT_EXTENSION ext)
1283 WCHAR *str = NULL;
1285 if (ext->Value.cbData)
1287 /* The output is formatted as:
1288 * <hex bytes> <ascii bytes>\n
1289 * where <hex bytes> is a string of up to 8 bytes, output as %02x,
1290 * and <ascii bytes> is the ASCII equivalent of each byte, or '.' if
1291 * the byte is not printable.
1292 * So, for example, the extension value consisting of the following
1293 * bytes:
1294 * 0x30,0x14,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x03,
1295 * 0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67
1296 * is output as:
1297 * 30 14 31 12 30 10 06 03 0.1.0...
1298 * 55 04 03 13 09 4a 75 61 U....Jua
1299 * 6e 20 4c 61 6e 67 n Lang
1300 * The allocation size therefore requires:
1301 * - 4 characters per character in an 8-byte line
1302 * (2 for the hex format, one for the space, one for the ASCII value)
1303 * - 3 more characters per 8-byte line (two spaces and a newline)
1304 * - 1 character for the terminating nul
1305 * FIXME: should use a fixed-width font for this
1307 DWORD lines = (ext->Value.cbData + 7) / 8;
1309 str = HeapAlloc(GetProcessHeap(), 0,
1310 (lines * 8 * 4 + lines * 3 + 1) * sizeof(WCHAR));
1311 if (str)
1313 static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
1314 DWORD i, j;
1315 WCHAR *ptr;
1317 for (i = 0, ptr = str; i < ext->Value.cbData; i += 8)
1319 /* Output as hex bytes first */
1320 for (j = i; j < min(i + 8, ext->Value.cbData); j++, ptr += 3)
1321 sprintfW(ptr, fmt, ext->Value.pbData[j]);
1322 /* Pad the hex output with spaces for alignment */
1323 if (j == ext->Value.cbData && j % 8)
1325 static const WCHAR pad[] = { ' ',' ',' ' };
1327 for (; j % 8; j++, ptr += sizeof(pad) / sizeof(pad[0]))
1328 memcpy(ptr, pad, sizeof(pad));
1330 /* The last sprintfW included a space, so just insert one
1331 * more space between the hex bytes and the ASCII output
1333 *ptr++ = ' ';
1334 /* Output as ASCII bytes */
1335 for (j = i; j < min(i + 8, ext->Value.cbData); j++, ptr++)
1337 if (isprintW(ext->Value.pbData[j]) &&
1338 !isspaceW(ext->Value.pbData[j]))
1339 *ptr = ext->Value.pbData[j];
1340 else
1341 *ptr = '.';
1343 *ptr++ = '\n';
1345 *ptr++ = '\0';
1348 return str;
1351 static WCHAR *field_format_detailed_extension(PCCERT_CONTEXT cert, void *param)
1353 PCERT_EXTENSION ext = param;
1354 LPWSTR str = crypt_format_extension(ext,
1355 CRYPT_FORMAT_STR_MULTI_LINE | CRYPT_FORMAT_STR_NO_HEX);
1357 if (!str)
1358 str = field_format_extension_hex_with_ascii(ext);
1359 return str;
1362 static void add_cert_extension_detail(HWND hwnd, struct detail_data *data,
1363 PCERT_EXTENSION ext)
1365 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
1366 ext->pszObjId, 0);
1367 LPWSTR val = crypt_format_extension(ext, 0);
1369 if (oidInfo)
1370 add_field_and_value_to_list(hwnd, data, (LPWSTR)oidInfo->pwszName,
1371 val, field_format_detailed_extension, ext);
1372 else
1374 DWORD len = strlen(ext->pszObjId);
1375 LPWSTR oidW = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1377 if (oidW)
1379 DWORD i;
1381 for (i = 0; i <= len; i++)
1382 oidW[i] = ext->pszObjId[i];
1383 add_field_and_value_to_list(hwnd, data, oidW, val,
1384 field_format_detailed_extension, ext);
1385 HeapFree(GetProcessHeap(), 0, oidW);
1388 HeapFree(GetProcessHeap(), 0, val);
1391 static void add_all_extensions(HWND hwnd, struct detail_data *data)
1393 DWORD i;
1394 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
1396 for (i = 0; i < cert->pCertInfo->cExtension; i++)
1397 add_cert_extension_detail(hwnd, data, &cert->pCertInfo->rgExtension[i]);
1400 static void add_critical_extensions(HWND hwnd, struct detail_data *data)
1402 DWORD i;
1403 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
1405 for (i = 0; i < cert->pCertInfo->cExtension; i++)
1406 if (cert->pCertInfo->rgExtension[i].fCritical)
1407 add_cert_extension_detail(hwnd, data,
1408 &cert->pCertInfo->rgExtension[i]);
1411 typedef WCHAR * (*prop_to_value_func)(void *pb, DWORD cb);
1413 struct prop_id_to_string_id
1415 DWORD prop;
1416 int id;
1417 BOOL prop_is_string;
1418 prop_to_value_func prop_to_value;
1421 static WCHAR *format_enhanced_key_usage_value(void *pb, DWORD cb)
1423 CERT_EXTENSION ext;
1425 ext.pszObjId = (LPSTR)X509_ENHANCED_KEY_USAGE;
1426 ext.fCritical = FALSE;
1427 ext.Value.pbData = pb;
1428 ext.Value.cbData = cb;
1429 return crypt_format_extension(&ext, 0);
1432 /* Logically the access state should also be checked, and IDC_EDITPROPERTIES
1433 * disabled for read-only certificates, but native doesn't appear to do that.
1435 static const struct prop_id_to_string_id prop_id_map[] = {
1436 { CERT_HASH_PROP_ID, IDS_PROP_HASH, FALSE, format_hex_string },
1437 { CERT_FRIENDLY_NAME_PROP_ID, IDS_PROP_FRIENDLY_NAME, TRUE, NULL },
1438 { CERT_DESCRIPTION_PROP_ID, IDS_PROP_DESCRIPTION, TRUE, NULL },
1439 { CERT_ENHKEY_USAGE_PROP_ID, IDS_PROP_ENHKEY_USAGE, FALSE,
1440 format_enhanced_key_usage_value },
1443 static void add_properties(HWND hwnd, struct detail_data *data)
1445 DWORD i;
1446 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
1448 for (i = 0; i < sizeof(prop_id_map) / sizeof(prop_id_map[0]); i++)
1450 DWORD cb;
1452 if (CertGetCertificateContextProperty(cert, prop_id_map[i].prop, NULL,
1453 &cb))
1455 BYTE *pb;
1456 WCHAR *val = NULL;
1458 /* FIXME: MS adds a separate value for the signature hash
1459 * algorithm.
1461 pb = HeapAlloc(GetProcessHeap(), 0, cb);
1462 if (pb)
1464 if (CertGetCertificateContextProperty(cert,
1465 prop_id_map[i].prop, pb, &cb))
1467 if (prop_id_map[i].prop_is_string)
1469 val = (LPWSTR)pb;
1470 /* Don't double-free pb */
1471 pb = NULL;
1473 else
1474 val = prop_id_map[i].prop_to_value(pb, cb);
1476 HeapFree(GetProcessHeap(), 0, pb);
1478 add_string_id_and_value_to_list(hwnd, data, prop_id_map[i].id, val,
1479 NULL, NULL);
1484 static void add_all_fields(HWND hwnd, struct detail_data *data)
1486 add_v1_fields(hwnd, data);
1487 add_all_extensions(hwnd, data);
1488 add_properties(hwnd, data);
1491 struct selection_list_item
1493 int id;
1494 add_fields_func add;
1497 const struct selection_list_item listItems[] = {
1498 { IDS_FIELDS_ALL, add_all_fields },
1499 { IDS_FIELDS_V1, add_v1_fields },
1500 { IDS_FIELDS_EXTENSIONS, add_all_extensions },
1501 { IDS_FIELDS_CRITICAL_EXTENSIONS, add_critical_extensions },
1502 { IDS_FIELDS_PROPERTIES, add_properties },
1505 static void create_show_list(HWND hwnd, struct detail_data *data)
1507 HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT);
1508 WCHAR buf[MAX_STRING_LEN];
1509 int i;
1511 for (i = 0; i < sizeof(listItems) / sizeof(listItems[0]); i++)
1513 int index;
1515 LoadStringW(hInstance, listItems[i].id, buf,
1516 sizeof(buf) / sizeof(buf[0]));
1517 index = SendMessageW(cb, CB_INSERTSTRING, -1, (LPARAM)buf);
1518 SendMessageW(cb, CB_SETITEMDATA, index, (LPARAM)data);
1520 SendMessageW(cb, CB_SETCURSEL, 0, 0);
1523 static void create_listview_columns(HWND hwnd)
1525 HWND lv = GetDlgItem(hwnd, IDC_DETAIL_LIST);
1526 RECT rc;
1527 WCHAR buf[MAX_STRING_LEN];
1528 LVCOLUMNW column;
1530 SendMessageW(lv, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
1531 GetWindowRect(lv, &rc);
1532 LoadStringW(hInstance, IDS_FIELD, buf, sizeof(buf) / sizeof(buf[0]));
1533 column.mask = LVCF_WIDTH | LVCF_TEXT;
1534 column.cx = (rc.right - rc.left) / 2 - 2;
1535 column.pszText = buf;
1536 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
1537 LoadStringW(hInstance, IDS_VALUE, buf, sizeof(buf) / sizeof(buf[0]));
1538 SendMessageW(lv, LVM_INSERTCOLUMNW, 1, (LPARAM)&column);
1541 static void set_fields_selection(HWND hwnd, struct detail_data *data, int sel)
1543 HWND list = GetDlgItem(hwnd, IDC_DETAIL_LIST);
1545 if (sel >= 0 && sel < sizeof(listItems) / sizeof(listItems[0]))
1547 SendMessageW(list, LVM_DELETEALLITEMS, 0, 0);
1548 listItems[sel].add(list, data);
1552 static void create_cert_details_list(HWND hwnd, struct detail_data *data)
1554 create_show_list(hwnd, data);
1555 create_listview_columns(hwnd);
1556 set_fields_selection(hwnd, data, 0);
1559 typedef enum {
1560 CheckBitmapIndexUnchecked = 1,
1561 CheckBitmapIndexChecked = 2,
1562 CheckBitmapIndexDisabledUnchecked = 3,
1563 CheckBitmapIndexDisabledChecked = 4
1564 } CheckBitmapIndex;
1566 static void add_purpose(HWND hwnd, LPCSTR oid)
1568 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
1569 PCRYPT_OID_INFO info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1570 sizeof(CRYPT_OID_INFO));
1572 if (info)
1574 char *oidCopy = HeapAlloc(GetProcessHeap(), 0, strlen(oid) + 1);
1576 if (oidCopy)
1578 LVITEMA item;
1580 strcpy(oidCopy, oid);
1581 info->cbSize = sizeof(CRYPT_OID_INFO);
1582 info->pszOID = oidCopy;
1583 item.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM;
1584 item.state = INDEXTOSTATEIMAGEMASK(CheckBitmapIndexChecked);
1585 item.stateMask = LVIS_STATEIMAGEMASK;
1586 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
1587 item.iSubItem = 0;
1588 item.lParam = (LPARAM)info;
1589 item.pszText = oidCopy;
1590 SendMessageA(lv, LVM_INSERTITEMA, 0, (LPARAM)&item);
1592 else
1593 HeapFree(GetProcessHeap(), 0, info);
1597 static BOOL is_valid_oid(LPCSTR oid)
1599 BOOL ret;
1601 if (oid[0] != '0' && oid[0] != '1' && oid[0] != '2')
1602 ret = FALSE;
1603 else if (oid[1] != '.')
1604 ret = FALSE;
1605 else if (!oid[2])
1606 ret = FALSE;
1607 else
1609 const char *ptr;
1610 BOOL expectNum = TRUE;
1612 for (ptr = oid + 2, ret = TRUE; ret && *ptr; ptr++)
1614 if (expectNum)
1616 if (!isdigit(*ptr))
1617 ret = FALSE;
1618 else if (*(ptr + 1) == '.')
1619 expectNum = FALSE;
1621 else
1623 if (*ptr != '.')
1624 ret = FALSE;
1625 else if (!(*(ptr + 1)))
1626 ret = FALSE;
1627 else
1628 expectNum = TRUE;
1632 return ret;
1635 static BOOL is_oid_in_list(HWND hwnd, LPCSTR oid)
1637 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
1638 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
1639 (void *)oid, CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
1640 BOOL ret = FALSE;
1642 if (oidInfo)
1644 LVFINDINFOW findInfo;
1646 findInfo.flags = LVFI_PARAM;
1647 findInfo.lParam = (LPARAM)oidInfo;
1648 if (SendMessageW(lv, LVM_FINDITEMW, -1, (LPARAM)&findInfo) != -1)
1649 ret = TRUE;
1651 else
1653 LVFINDINFOA findInfo;
1655 findInfo.flags = LVFI_STRING;
1656 findInfo.psz = oid;
1657 if (SendMessageW(lv, LVM_FINDITEMA, -1, (LPARAM)&findInfo) != -1)
1658 ret = TRUE;
1660 return ret;
1663 #define MAX_PURPOSE 255
1665 static LRESULT CALLBACK add_purpose_dlg_proc(HWND hwnd, UINT msg,
1666 WPARAM wp, LPARAM lp)
1668 LRESULT ret = 0;
1669 char buf[MAX_PURPOSE + 1];
1671 switch (msg)
1673 case WM_INITDIALOG:
1674 SendMessageW(GetDlgItem(hwnd, IDC_NEW_PURPOSE), EM_SETLIMITTEXT,
1675 MAX_PURPOSE, 0);
1676 ShowScrollBar(GetDlgItem(hwnd, IDC_NEW_PURPOSE), SB_VERT, FALSE);
1677 SetWindowLongPtrW(hwnd, DWLP_USER, lp);
1678 break;
1679 case WM_COMMAND:
1680 switch (HIWORD(wp))
1682 case EN_CHANGE:
1683 if (LOWORD(wp) == IDC_NEW_PURPOSE)
1685 /* Show/hide scroll bar on description depending on how much
1686 * text it has.
1688 HWND description = GetDlgItem(hwnd, IDC_NEW_PURPOSE);
1689 int lines = SendMessageW(description, EM_GETLINECOUNT, 0, 0);
1691 ShowScrollBar(description, SB_VERT, lines > 1);
1693 break;
1694 case BN_CLICKED:
1695 switch (LOWORD(wp))
1697 case IDOK:
1698 SendMessageA(GetDlgItem(hwnd, IDC_NEW_PURPOSE), WM_GETTEXT,
1699 sizeof(buf) / sizeof(buf[0]), (LPARAM)buf);
1700 if (!buf[0])
1702 /* An empty purpose is the same as cancelling */
1703 EndDialog(hwnd, IDCANCEL);
1704 ret = TRUE;
1706 else if (!is_valid_oid(buf))
1708 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
1710 LoadStringW(hInstance, IDS_CERTIFICATE_PURPOSE_ERROR, error,
1711 sizeof(error) / sizeof(error[0]));
1712 LoadStringW(hInstance, IDS_CERTIFICATE_PROPERTIES, title,
1713 sizeof(title) / sizeof(title[0]));
1714 MessageBoxW(hwnd, error, title, MB_ICONERROR | MB_OK);
1716 else if (is_oid_in_list(
1717 (HWND)GetWindowLongPtrW(hwnd, DWLP_USER), buf))
1719 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
1721 LoadStringW(hInstance, IDS_CERTIFICATE_PURPOSE_EXISTS,
1722 error, sizeof(error) / sizeof(error[0]));
1723 LoadStringW(hInstance, IDS_CERTIFICATE_PROPERTIES, title,
1724 sizeof(title) / sizeof(title[0]));
1725 MessageBoxW(hwnd, error, title, MB_ICONEXCLAMATION | MB_OK);
1727 else
1729 HWND parent = (HWND)GetWindowLongPtrW(hwnd, DWLP_USER);
1731 add_purpose(parent, buf);
1732 EndDialog(hwnd, wp);
1733 ret = TRUE;
1735 break;
1736 case IDCANCEL:
1737 EndDialog(hwnd, wp);
1738 ret = TRUE;
1739 break;
1741 break;
1743 break;
1745 return ret;
1748 static WCHAR *get_cert_property_as_string(PCCERT_CONTEXT cert, DWORD prop)
1750 WCHAR *name = NULL;
1751 DWORD cb;
1753 if (CertGetCertificateContextProperty(cert, prop, NULL, &cb))
1755 name = HeapAlloc(GetProcessHeap(), 0, cb);
1756 if (name)
1758 if (!CertGetCertificateContextProperty(cert, prop, (LPBYTE)name,
1759 &cb))
1761 HeapFree(GetProcessHeap(), 0, name);
1762 name = NULL;
1766 return name;
1769 static void redraw_states(HWND list, BOOL enabled)
1771 int items = SendMessageW(list, LVM_GETITEMCOUNT, 0, 0), i;
1773 for (i = 0; i < items; i++)
1775 BOOL change = FALSE;
1776 int state;
1778 state = SendMessageW(list, LVM_GETITEMSTATE, i, LVIS_STATEIMAGEMASK);
1779 /* This reverses the INDEXTOSTATEIMAGEMASK shift. There doesn't appear
1780 * to be a handy macro for it.
1782 state >>= 12;
1783 if (enabled)
1785 if (state == CheckBitmapIndexDisabledChecked)
1787 state = CheckBitmapIndexChecked;
1788 change = TRUE;
1790 if (state == CheckBitmapIndexDisabledUnchecked)
1792 state = CheckBitmapIndexUnchecked;
1793 change = TRUE;
1796 else
1798 if (state == CheckBitmapIndexChecked)
1800 state = CheckBitmapIndexDisabledChecked;
1801 change = TRUE;
1803 if (state == CheckBitmapIndexUnchecked)
1805 state = CheckBitmapIndexDisabledUnchecked;
1806 change = TRUE;
1809 if (change)
1811 LVITEMW item;
1813 item.state = INDEXTOSTATEIMAGEMASK(state);
1814 item.stateMask = LVIS_STATEIMAGEMASK;
1815 SendMessageW(list, LVM_SETITEMSTATE, i, (LPARAM)&item);
1820 typedef enum {
1821 PurposeEnableAll = 0,
1822 PurposeDisableAll,
1823 PurposeEnableSelected
1824 } PurposeSelection;
1826 static void select_purposes(HWND hwnd, PurposeSelection selection)
1828 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
1830 switch (selection)
1832 case PurposeEnableAll:
1833 case PurposeDisableAll:
1834 EnableWindow(lv, FALSE);
1835 redraw_states(lv, FALSE);
1836 EnableWindow(GetDlgItem(hwnd, IDC_ADD_PURPOSE), FALSE);
1837 break;
1838 case PurposeEnableSelected:
1839 EnableWindow(lv, TRUE);
1840 redraw_states(lv, TRUE);
1841 EnableWindow(GetDlgItem(hwnd, IDC_ADD_PURPOSE), TRUE);
1845 extern BOOL WINAPI WTHelperGetKnownUsages(DWORD action,
1846 PCCRYPT_OID_INFO **usages);
1848 static void add_known_usage(HWND lv, PCCRYPT_OID_INFO info)
1850 LVITEMW item;
1852 item.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM;
1853 item.state = INDEXTOSTATEIMAGEMASK(CheckBitmapIndexDisabledChecked);
1854 item.stateMask = LVIS_STATEIMAGEMASK;
1855 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
1856 item.iSubItem = 0;
1857 item.lParam = (LPARAM)info;
1858 item.pszText = (LPWSTR)info->pwszName;
1859 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
1862 struct edit_cert_data
1864 PCCERT_CONTEXT cert;
1865 BOOL *pfPropertiesChanged;
1866 HIMAGELIST imageList;
1869 static void show_cert_usages(HWND hwnd, struct edit_cert_data *data)
1871 PCCERT_CONTEXT cert = data->cert;
1872 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
1873 PCERT_ENHKEY_USAGE usage;
1874 DWORD size;
1875 PCCRYPT_OID_INFO *usages;
1876 RECT rc;
1877 LVCOLUMNW column;
1878 PurposeSelection purposeSelection;
1880 GetWindowRect(lv, &rc);
1881 column.mask = LVCF_WIDTH;
1882 column.cx = rc.right - rc.left;
1883 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
1884 SendMessageW(lv, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)data->imageList);
1886 /* Get enhanced key usage. Have to check for a property and an extension
1887 * separately, because CertGetEnhancedKeyUsage will succeed and return an
1888 * empty usage if neither is set. Unfortunately an empty usage implies
1889 * no usage is allowed, so we have to distinguish between the two cases.
1891 if (CertGetEnhancedKeyUsage(cert, CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG,
1892 NULL, &size))
1894 usage = HeapAlloc(GetProcessHeap(), 0, size);
1895 if (!CertGetEnhancedKeyUsage(cert,
1896 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size))
1898 HeapFree(GetProcessHeap(), 0, usage);
1899 usage = NULL;
1901 else if (usage->cUsageIdentifier)
1902 purposeSelection = PurposeEnableSelected;
1903 else
1904 purposeSelection = PurposeDisableAll;
1906 else if (CertGetEnhancedKeyUsage(cert, CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
1907 NULL, &size))
1909 usage = HeapAlloc(GetProcessHeap(), 0, size);
1910 if (!CertGetEnhancedKeyUsage(cert,
1911 CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, usage, &size))
1913 HeapFree(GetProcessHeap(), 0, usage);
1914 usage = NULL;
1916 else if (usage->cUsageIdentifier)
1917 purposeSelection = PurposeEnableAll;
1918 else
1919 purposeSelection = PurposeDisableAll;
1921 else
1923 purposeSelection = PurposeEnableAll;
1924 usage = NULL;
1926 if (usage)
1928 DWORD i;
1930 for (i = 0; i < usage->cUsageIdentifier; i++)
1932 PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
1933 usage->rgpszUsageIdentifier[i], CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
1935 if (info)
1936 add_known_usage(lv, info);
1937 else
1938 add_purpose(hwnd, usage->rgpszUsageIdentifier[i]);
1940 HeapFree(GetProcessHeap(), 0, usage);
1942 else
1944 if (WTHelperGetKnownUsages(1, &usages))
1946 PCCRYPT_OID_INFO *ptr;
1948 for (ptr = usages; *ptr; ptr++)
1949 add_known_usage(lv, *ptr);
1950 WTHelperGetKnownUsages(2, &usages);
1953 select_purposes(hwnd, purposeSelection);
1954 SendMessageW(GetDlgItem(hwnd, IDC_ENABLE_ALL_PURPOSES + purposeSelection),
1955 BM_CLICK, 0, 0);
1958 static void set_general_cert_properties(HWND hwnd, struct edit_cert_data *data)
1960 PCCERT_CONTEXT cert = data->cert;
1961 WCHAR *str;
1963 if ((str = get_cert_property_as_string(cert, CERT_FRIENDLY_NAME_PROP_ID)))
1965 SendMessageW(GetDlgItem(hwnd, IDC_FRIENDLY_NAME), WM_SETTEXT, 0,
1966 (LPARAM)str);
1967 HeapFree(GetProcessHeap(), 0, str);
1969 if ((str = get_cert_property_as_string(cert, CERT_DESCRIPTION_PROP_ID)))
1971 SendMessageW(GetDlgItem(hwnd, IDC_DESCRIPTION), WM_SETTEXT, 0,
1972 (LPARAM)str);
1973 HeapFree(GetProcessHeap(), 0, str);
1975 show_cert_usages(hwnd, data);
1978 static void toggle_usage(HWND hwnd, int iItem)
1980 LVITEMW item;
1981 int res;
1982 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
1984 item.mask = LVIF_STATE;
1985 item.iItem = iItem;
1986 item.iSubItem = 0;
1987 item.stateMask = LVIS_STATEIMAGEMASK;
1988 res = SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item);
1989 if (res)
1991 int state = item.state >> 12;
1993 item.state = INDEXTOSTATEIMAGEMASK(
1994 state == CheckBitmapIndexChecked ? CheckBitmapIndexUnchecked :
1995 CheckBitmapIndexChecked);
1996 SendMessageW(lv, LVM_SETITEMSTATE, iItem, (LPARAM)&item);
2000 static void set_cert_string_property(PCCERT_CONTEXT cert, DWORD prop,
2001 LPWSTR str)
2003 if (str && strlenW(str))
2005 CRYPT_DATA_BLOB blob;
2007 blob.pbData = (BYTE *)str;
2008 blob.cbData = (strlenW(str) + 1) * sizeof(WCHAR);
2009 CertSetCertificateContextProperty(cert, prop, 0, &blob);
2011 else
2012 CertSetCertificateContextProperty(cert, prop, 0, NULL);
2015 #define WM_REFRESH_VIEW WM_USER + 0
2017 static BOOL CALLBACK refresh_propsheet_pages(HWND hwnd, LPARAM lParam)
2019 if ((GetClassLongW(hwnd, GCW_ATOM) == WC_DIALOG))
2020 SendMessageW(hwnd, WM_REFRESH_VIEW, 0, 0);
2021 return TRUE;
2024 #define MAX_FRIENDLY_NAME 40
2025 #define MAX_DESCRIPTION 255
2027 static void apply_general_changes(HWND hwnd)
2029 WCHAR buf[MAX_DESCRIPTION + 1];
2030 struct edit_cert_data *data =
2031 (struct edit_cert_data *)GetWindowLongPtrW(hwnd, DWLP_USER);
2033 SendMessageW(GetDlgItem(hwnd, IDC_FRIENDLY_NAME), WM_GETTEXT,
2034 sizeof(buf) / sizeof(buf[0]), (LPARAM)buf);
2035 set_cert_string_property(data->cert, CERT_FRIENDLY_NAME_PROP_ID, buf);
2036 SendMessageW(GetDlgItem(hwnd, IDC_DESCRIPTION), WM_GETTEXT,
2037 sizeof(buf) / sizeof(buf[0]), (LPARAM)buf);
2038 set_cert_string_property(data->cert, CERT_DESCRIPTION_PROP_ID, buf);
2039 if (IsDlgButtonChecked(hwnd, IDC_ENABLE_ALL_PURPOSES))
2041 /* Setting a NULL usage removes the enhanced key usage property. */
2042 CertSetEnhancedKeyUsage(data->cert, NULL);
2044 else if (IsDlgButtonChecked(hwnd, IDC_DISABLE_ALL_PURPOSES))
2046 CERT_ENHKEY_USAGE usage = { 0, NULL };
2048 CertSetEnhancedKeyUsage(data->cert, &usage);
2050 else if (IsDlgButtonChecked(hwnd, IDC_ENABLE_SELECTED_PURPOSES))
2052 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
2053 CERT_ENHKEY_USAGE usage = { 0, NULL };
2054 int purposes = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0), i;
2055 LVITEMW item;
2057 item.mask = LVIF_STATE | LVIF_PARAM;
2058 item.iSubItem = 0;
2059 item.stateMask = LVIS_STATEIMAGEMASK;
2060 for (i = 0; i < purposes; i++)
2062 item.iItem = i;
2063 if (SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item))
2065 int state = item.state >> 12;
2067 if (state == CheckBitmapIndexChecked)
2069 CRYPT_OID_INFO *info = (CRYPT_OID_INFO *)item.lParam;
2071 if (usage.cUsageIdentifier)
2072 usage.rgpszUsageIdentifier =
2073 HeapReAlloc(GetProcessHeap(), 0,
2074 usage.rgpszUsageIdentifier,
2075 (usage.cUsageIdentifier + 1) * sizeof(LPSTR));
2076 else
2077 usage.rgpszUsageIdentifier =
2078 HeapAlloc(GetProcessHeap(), 0, sizeof(LPSTR));
2079 if (usage.rgpszUsageIdentifier)
2080 usage.rgpszUsageIdentifier[usage.cUsageIdentifier++] =
2081 (LPSTR)info->pszOID;
2085 CertSetEnhancedKeyUsage(data->cert, &usage);
2086 HeapFree(GetProcessHeap(), 0, usage.rgpszUsageIdentifier);
2088 EnumChildWindows(GetParent(GetParent(hwnd)), refresh_propsheet_pages, 0);
2089 if (data->pfPropertiesChanged)
2090 *data->pfPropertiesChanged = TRUE;
2093 static LRESULT CALLBACK cert_properties_general_dlg_proc(HWND hwnd, UINT msg,
2094 WPARAM wp, LPARAM lp)
2096 PROPSHEETPAGEW *page;
2098 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
2100 switch (msg)
2102 case WM_INITDIALOG:
2104 HWND description = GetDlgItem(hwnd, IDC_DESCRIPTION);
2105 struct detail_data *detailData;
2106 struct edit_cert_data *editData;
2108 page = (PROPSHEETPAGEW *)lp;
2109 detailData = (struct detail_data *)page->lParam;
2110 SendMessageW(GetDlgItem(hwnd, IDC_FRIENDLY_NAME), EM_SETLIMITTEXT,
2111 MAX_FRIENDLY_NAME, 0);
2112 SendMessageW(description, EM_SETLIMITTEXT, MAX_DESCRIPTION, 0);
2113 ShowScrollBar(description, SB_VERT, FALSE);
2114 editData = HeapAlloc(GetProcessHeap(), 0,
2115 sizeof(struct edit_cert_data));
2116 if (editData)
2118 editData->imageList = ImageList_Create(16, 16,
2119 ILC_COLOR4 | ILC_MASK, 4, 0);
2120 if (editData->imageList)
2122 HBITMAP bmp;
2123 COLORREF backColor = RGB(255, 0, 255);
2125 bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_CHECKS));
2126 ImageList_AddMasked(editData->imageList, bmp, backColor);
2127 DeleteObject(bmp);
2128 ImageList_SetBkColor(editData->imageList, CLR_NONE);
2130 editData->cert = detailData->pCertViewInfo->pCertContext;
2131 editData->pfPropertiesChanged = detailData->pfPropertiesChanged;
2132 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)editData);
2133 set_general_cert_properties(hwnd, editData);
2135 break;
2137 case WM_NOTIFY:
2139 NMHDR *hdr = (NMHDR *)lp;
2140 NMITEMACTIVATE *nm;
2142 switch (hdr->code)
2144 case NM_CLICK:
2145 nm = (NMITEMACTIVATE *)lp;
2146 toggle_usage(hwnd, nm->iItem);
2147 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
2148 break;
2149 case PSN_APPLY:
2150 apply_general_changes(hwnd);
2151 break;
2153 break;
2155 case WM_COMMAND:
2156 switch (HIWORD(wp))
2158 case EN_CHANGE:
2159 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
2160 if (LOWORD(wp) == IDC_DESCRIPTION)
2162 /* Show/hide scroll bar on description depending on how much
2163 * text it has.
2165 HWND description = GetDlgItem(hwnd, IDC_DESCRIPTION);
2166 int lines = SendMessageW(description, EM_GETLINECOUNT, 0, 0);
2168 ShowScrollBar(description, SB_VERT, lines > 1);
2170 break;
2171 case BN_CLICKED:
2172 switch (LOWORD(wp))
2174 case IDC_ADD_PURPOSE:
2175 if (DialogBoxParamW(hInstance,
2176 MAKEINTRESOURCEW(IDD_ADD_CERT_PURPOSE), hwnd,
2177 add_purpose_dlg_proc, (LPARAM)hwnd) == IDOK)
2178 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
2179 break;
2180 case IDC_ENABLE_ALL_PURPOSES:
2181 case IDC_DISABLE_ALL_PURPOSES:
2182 case IDC_ENABLE_SELECTED_PURPOSES:
2183 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
2184 select_purposes(hwnd, LOWORD(wp) - IDC_ENABLE_ALL_PURPOSES);
2185 break;
2187 break;
2189 break;
2191 return 0;
2194 static UINT CALLBACK cert_properties_general_callback(HWND hwnd, UINT msg,
2195 PROPSHEETPAGEW *page)
2197 HWND lv;
2198 int cItem, i;
2199 struct edit_cert_data *data;
2201 switch (msg)
2203 case PSPCB_RELEASE:
2204 lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
2205 cItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
2206 for (i = 0; i < cItem; i++)
2208 LVITEMW item;
2210 item.mask = LVIF_PARAM;
2211 item.iItem = i;
2212 item.iSubItem = 0;
2213 if (SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item) && item.lParam)
2215 PCRYPT_OID_INFO info = (PCRYPT_OID_INFO)item.lParam;
2217 if (info->cbSize == sizeof(CRYPT_OID_INFO) && !info->dwGroupId)
2219 HeapFree(GetProcessHeap(), 0, (LPSTR)info->pszOID);
2220 HeapFree(GetProcessHeap(), 0, info);
2224 data = (struct edit_cert_data *)GetWindowLongPtrW(hwnd, DWLP_USER);
2225 if (data)
2227 ImageList_Destroy(data->imageList);
2228 HeapFree(GetProcessHeap(), 0, data);
2230 break;
2232 return 1;
2235 static void show_edit_cert_properties_dialog(HWND parent,
2236 struct detail_data *data)
2238 PROPSHEETHEADERW hdr;
2239 PROPSHEETPAGEW page; /* FIXME: need to add a cross-certificate page */
2241 TRACE("(%p)\n", data);
2243 memset(&page, 0, sizeof(PROPSHEETPAGEW));
2244 page.dwSize = sizeof(page);
2245 page.dwFlags = PSP_USECALLBACK;
2246 page.pfnCallback = cert_properties_general_callback;
2247 page.hInstance = hInstance;
2248 page.u.pszTemplate = MAKEINTRESOURCEW(IDD_CERT_PROPERTIES_GENERAL);
2249 page.pfnDlgProc = cert_properties_general_dlg_proc;
2250 page.lParam = (LPARAM)data;
2252 memset(&hdr, 0, sizeof(hdr));
2253 hdr.dwSize = sizeof(hdr);
2254 hdr.hwndParent = parent;
2255 hdr.dwFlags = PSH_PROPSHEETPAGE;
2256 hdr.hInstance = hInstance;
2257 hdr.pszCaption = MAKEINTRESOURCEW(IDS_CERTIFICATE_PROPERTIES);
2258 hdr.u3.ppsp = &page;
2259 hdr.nPages = 1;
2260 PropertySheetW(&hdr);
2263 static void free_detail_fields(struct detail_data *data)
2265 DWORD i;
2267 for (i = 0; i < data->cFields; i++)
2268 HeapFree(GetProcessHeap(), 0, data->fields[i].detailed_value);
2269 HeapFree(GetProcessHeap(), 0, data->fields);
2270 data->fields = NULL;
2271 data->cFields = 0;
2274 static void refresh_details_view(HWND hwnd)
2276 HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT);
2277 int curSel;
2278 struct detail_data *data;
2280 curSel = SendMessageW(cb, CB_GETCURSEL, 0, 0);
2281 /* Actually, any index will do, since they all store the same data value */
2282 data = (struct detail_data *)SendMessageW(cb, CB_GETITEMDATA, curSel, 0);
2283 free_detail_fields(data);
2284 set_fields_selection(hwnd, data, curSel);
2287 static LRESULT CALLBACK detail_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
2288 LPARAM lp)
2290 PROPSHEETPAGEW *page;
2291 struct detail_data *data;
2293 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
2295 switch (msg)
2297 case WM_INITDIALOG:
2298 page = (PROPSHEETPAGEW *)lp;
2299 data = (struct detail_data *)page->lParam;
2300 create_cert_details_list(hwnd, data);
2301 if (!(data->pCertViewInfo->dwFlags & CRYPTUI_ENABLE_EDITPROPERTIES))
2302 EnableWindow(GetDlgItem(hwnd, IDC_EDITPROPERTIES), FALSE);
2303 if (data->pCertViewInfo->dwFlags & CRYPTUI_DISABLE_EXPORT)
2304 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT), FALSE);
2305 break;
2306 case WM_NOTIFY:
2308 NMITEMACTIVATE *nm;
2309 HWND list = GetDlgItem(hwnd, IDC_DETAIL_LIST);
2311 nm = (NMITEMACTIVATE*)lp;
2312 if (nm->hdr.hwndFrom == list && nm->uNewState & LVN_ITEMACTIVATE
2313 && nm->hdr.code == LVN_ITEMCHANGED)
2315 data = (struct detail_data *)nm->lParam;
2316 if (nm->iItem >= 0 && data && nm->iItem < data->cFields)
2318 WCHAR buf[MAX_STRING_LEN], *val = NULL;
2319 HWND valueCtl = GetDlgItem(hwnd, IDC_DETAIL_VALUE);
2321 if (data->fields[nm->iItem].create)
2322 val = data->fields[nm->iItem].create(
2323 data->pCertViewInfo->pCertContext,
2324 data->fields[nm->iItem].param);
2325 else
2327 LVITEMW item;
2328 int res;
2330 item.cchTextMax = sizeof(buf) / sizeof(buf[0]);
2331 item.mask = LVIF_TEXT;
2332 item.pszText = buf;
2333 item.iItem = nm->iItem;
2334 item.iSubItem = 1;
2335 res = SendMessageW(list, LVM_GETITEMW, 0, (LPARAM)&item);
2336 if (res)
2337 val = buf;
2339 /* Select all the text in the control, the next update will
2340 * replace it
2342 SendMessageW(valueCtl, EM_SETSEL, 0, -1);
2343 add_unformatted_text_to_control(valueCtl, val,
2344 val ? strlenW(val) : 0);
2345 if (val != buf)
2346 HeapFree(GetProcessHeap(), 0, val);
2349 break;
2351 case WM_COMMAND:
2352 switch (wp)
2354 case IDC_EXPORT:
2355 FIXME("call CryptUIWizExport\n");
2356 break;
2357 case IDC_EDITPROPERTIES:
2359 HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT);
2360 int curSel;
2362 curSel = SendMessageW(cb, CB_GETCURSEL, 0, 0);
2363 /* Actually, any index will do, since they all store the same
2364 * data value
2366 data = (struct detail_data *)SendMessageW(cb, CB_GETITEMDATA,
2367 curSel, 0);
2368 show_edit_cert_properties_dialog(GetParent(hwnd), data);
2369 break;
2371 case ((CBN_SELCHANGE << 16) | IDC_DETAIL_SELECT):
2372 refresh_details_view(hwnd);
2373 break;
2375 break;
2376 case WM_REFRESH_VIEW:
2377 refresh_details_view(hwnd);
2378 break;
2380 return 0;
2383 static UINT CALLBACK detail_callback(HWND hwnd, UINT msg,
2384 PROPSHEETPAGEW *page)
2386 struct detail_data *data;
2388 switch (msg)
2390 case PSPCB_RELEASE:
2391 data = (struct detail_data *)page->lParam;
2392 free_detail_fields(data);
2393 HeapFree(GetProcessHeap(), 0, data);
2394 break;
2396 return 0;
2399 static BOOL init_detail_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
2400 BOOL *pfPropertiesChanged, PROPSHEETPAGEW *page)
2402 BOOL ret;
2403 struct detail_data *data = HeapAlloc(GetProcessHeap(), 0,
2404 sizeof(struct detail_data));
2406 if (data)
2408 data->pCertViewInfo = pCertViewInfo;
2409 data->pfPropertiesChanged = pfPropertiesChanged;
2410 data->cFields = 0;
2411 data->fields = NULL;
2412 memset(page, 0, sizeof(PROPSHEETPAGEW));
2413 page->dwSize = sizeof(PROPSHEETPAGEW);
2414 page->dwFlags = PSP_USECALLBACK;
2415 page->pfnCallback = detail_callback;
2416 page->hInstance = hInstance;
2417 page->u.pszTemplate = MAKEINTRESOURCEW(IDD_DETAIL);
2418 page->pfnDlgProc = detail_dlg_proc;
2419 page->lParam = (LPARAM)data;
2420 ret = TRUE;
2422 else
2423 ret = FALSE;
2424 return ret;
2427 struct hierarchy_data
2429 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo;
2430 HIMAGELIST imageList;
2431 DWORD selectedCert;
2434 static LPARAM index_to_lparam(struct hierarchy_data *data, DWORD index)
2436 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
2437 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData,
2438 data->pCertViewInfo->idxSigner, data->pCertViewInfo->fCounterSigner,
2439 data->pCertViewInfo->idxCounterSigner);
2441 /* Takes advantage of the fact that a pointer is 32-bit aligned, and
2442 * therefore always even.
2444 if (index == provSigner->csCertChain - 1)
2445 return (LPARAM)data;
2446 return index << 1 | 1;
2449 static inline DWORD lparam_to_index(struct hierarchy_data *data, LPARAM lp)
2451 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
2452 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData,
2453 data->pCertViewInfo->idxSigner, data->pCertViewInfo->fCounterSigner,
2454 data->pCertViewInfo->idxCounterSigner);
2456 if (!(lp & 1))
2457 return provSigner->csCertChain - 1;
2458 return lp >> 1;
2461 static struct hierarchy_data *get_hierarchy_data_from_tree_item(HWND tree,
2462 HTREEITEM hItem)
2464 struct hierarchy_data *data = NULL;
2465 HTREEITEM root = NULL;
2467 do {
2468 HTREEITEM parent = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM,
2469 TVGN_PARENT, (LPARAM)hItem);
2471 if (!parent)
2472 root = hItem;
2473 hItem = parent;
2474 } while (hItem);
2475 if (root)
2477 TVITEMW item;
2479 item.mask = TVIF_PARAM;
2480 item.hItem = root;
2481 SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item);
2482 data = (struct hierarchy_data *)item.lParam;
2484 return data;
2487 static WCHAR *get_cert_display_name(PCCERT_CONTEXT cert)
2489 WCHAR *name = get_cert_property_as_string(cert, CERT_FRIENDLY_NAME_PROP_ID);
2491 if (!name)
2492 name = get_cert_name_string(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0);
2493 return name;
2496 static void show_cert_chain(HWND hwnd, struct hierarchy_data *data)
2498 HWND tree = GetDlgItem(hwnd, IDC_CERTPATH);
2499 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
2500 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData,
2501 data->pCertViewInfo->idxSigner, data->pCertViewInfo->fCounterSigner,
2502 data->pCertViewInfo->idxCounterSigner);
2503 DWORD i;
2504 HTREEITEM parent = NULL;
2506 SendMessageW(tree, TVM_SETIMAGELIST, TVSIL_NORMAL, (LPARAM)data->imageList);
2507 for (i = provSigner->csCertChain; i; i--)
2509 LPWSTR name;
2511 name = get_cert_display_name(provSigner->pasCertChain[i - 1].pCert);
2512 if (name)
2514 TVINSERTSTRUCTW tvis;
2516 tvis.hParent = parent;
2517 tvis.hInsertAfter = TVI_LAST;
2518 tvis.u.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_IMAGE |
2519 TVIF_SELECTEDIMAGE | TVIF_PARAM;
2520 tvis.u.item.pszText = name;
2521 tvis.u.item.state = TVIS_EXPANDED;
2522 tvis.u.item.stateMask = TVIS_EXPANDED;
2523 if (i == 1 &&
2524 (provSigner->pChainContext->TrustStatus.dwErrorStatus &
2525 CERT_TRUST_IS_PARTIAL_CHAIN))
2527 /* The root of the chain has a special case: if the chain is
2528 * a partial chain, the icon is a warning icon rather than an
2529 * error icon.
2531 tvis.u.item.iImage = 2;
2533 else if (provSigner->pasCertChain[i - 1].pChainElement->TrustStatus.
2534 dwErrorStatus == 0)
2535 tvis.u.item.iImage = 0;
2536 else
2537 tvis.u.item.iImage = 1;
2538 tvis.u.item.iSelectedImage = tvis.u.item.iImage;
2539 tvis.u.item.lParam = index_to_lparam(data, i - 1);
2540 parent = (HTREEITEM)SendMessageW(tree, TVM_INSERTITEMW, 0,
2541 (LPARAM)&tvis);
2542 HeapFree(GetProcessHeap(), 0, name);
2547 static void set_certificate_status(HWND hwnd, CRYPT_PROVIDER_CERT *cert)
2549 /* Select all the text in the control, the next update will replace it */
2550 SendMessageW(hwnd, EM_SETSEL, 0, -1);
2551 /* Set the highest priority error messages first. */
2552 if (!(cert->dwConfidence & CERT_CONFIDENCE_SIG))
2553 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_BAD_SIGNATURE);
2554 else if (!(cert->dwConfidence & CERT_CONFIDENCE_TIME))
2555 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_BAD_TIME);
2556 else if (!(cert->dwConfidence & CERT_CONFIDENCE_TIMENEST))
2557 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_BAD_TIMENEST);
2558 else if (cert->dwRevokedReason)
2559 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_REVOKED);
2560 else
2561 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_VALID);
2564 static void set_certificate_status_for_end_cert(HWND hwnd,
2565 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
2567 HWND status = GetDlgItem(hwnd, IDC_CERTIFICATESTATUSTEXT);
2568 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
2569 (CRYPT_PROVIDER_DATA *)pCertViewInfo->u.pCryptProviderData,
2570 pCertViewInfo->idxSigner, pCertViewInfo->fCounterSigner,
2571 pCertViewInfo->idxCounterSigner);
2572 CRYPT_PROVIDER_CERT *provCert = WTHelperGetProvCertFromChain(provSigner,
2573 pCertViewInfo->idxCert);
2575 set_certificate_status(status, provCert);
2578 static void show_cert_hierarchy(HWND hwnd, struct hierarchy_data *data)
2580 /* Disable view certificate button until a certificate is selected */
2581 EnableWindow(GetDlgItem(hwnd, IDC_VIEWCERTIFICATE), FALSE);
2582 show_cert_chain(hwnd, data);
2583 set_certificate_status_for_end_cert(hwnd, data->pCertViewInfo);
2586 static void show_dialog_for_selected_cert(HWND hwnd)
2588 HWND tree = GetDlgItem(hwnd, IDC_CERTPATH);
2589 TVITEMW item;
2590 struct hierarchy_data *data;
2591 DWORD selection;
2593 memset(&item, 0, sizeof(item));
2594 item.mask = TVIF_HANDLE | TVIF_PARAM;
2595 item.hItem = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM, TVGN_CARET,
2596 (LPARAM)NULL);
2597 SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item);
2598 data = get_hierarchy_data_from_tree_item(tree, item.hItem);
2599 selection = lparam_to_index(data, item.lParam);
2600 if (selection != 0)
2602 CRYPT_PROVIDER_SGNR *provSigner;
2603 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
2604 BOOL changed = FALSE;
2606 provSigner = WTHelperGetProvSignerFromChain(
2607 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData,
2608 data->pCertViewInfo->idxSigner,
2609 data->pCertViewInfo->fCounterSigner,
2610 data->pCertViewInfo->idxCounterSigner);
2611 memset(&viewInfo, 0, sizeof(viewInfo));
2612 viewInfo.dwSize = sizeof(viewInfo);
2613 viewInfo.dwFlags = data->pCertViewInfo->dwFlags;
2614 viewInfo.szTitle = data->pCertViewInfo->szTitle;
2615 viewInfo.pCertContext = provSigner->pasCertChain[selection].pCert;
2616 viewInfo.cStores = data->pCertViewInfo->cStores;
2617 viewInfo.rghStores = data->pCertViewInfo->rghStores;
2618 viewInfo.cPropSheetPages = data->pCertViewInfo->cPropSheetPages;
2619 viewInfo.rgPropSheetPages = data->pCertViewInfo->rgPropSheetPages;
2620 viewInfo.nStartPage = data->pCertViewInfo->nStartPage;
2621 CryptUIDlgViewCertificateW(&viewInfo, &changed);
2622 if (changed)
2624 /* Delete the contents of the tree */
2625 SendMessageW(tree, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT);
2626 /* Reinitialize the tree */
2627 show_cert_hierarchy(hwnd, data);
2632 static LRESULT CALLBACK hierarchy_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
2633 LPARAM lp)
2635 PROPSHEETPAGEW *page;
2636 struct hierarchy_data *data;
2637 LRESULT ret = 0;
2638 HWND tree = GetDlgItem(hwnd, IDC_CERTPATH);
2640 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
2642 switch (msg)
2644 case WM_INITDIALOG:
2645 page = (PROPSHEETPAGEW *)lp;
2646 data = (struct hierarchy_data *)page->lParam;
2647 show_cert_hierarchy(hwnd, data);
2648 break;
2649 case WM_NOTIFY:
2651 NMHDR *hdr;
2653 hdr = (NMHDR *)lp;
2654 switch (hdr->code)
2656 case TVN_SELCHANGEDW:
2658 NMTREEVIEWW *nm = (NMTREEVIEWW*)lp;
2659 DWORD selection;
2660 CRYPT_PROVIDER_SGNR *provSigner;
2662 data = get_hierarchy_data_from_tree_item(tree, nm->itemNew.hItem);
2663 selection = lparam_to_index(data, nm->itemNew.lParam);
2664 provSigner = WTHelperGetProvSignerFromChain(
2665 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData,
2666 data->pCertViewInfo->idxSigner,
2667 data->pCertViewInfo->fCounterSigner,
2668 data->pCertViewInfo->idxCounterSigner);
2669 EnableWindow(GetDlgItem(hwnd, IDC_VIEWCERTIFICATE), selection != 0);
2670 set_certificate_status(GetDlgItem(hwnd, IDC_CERTIFICATESTATUSTEXT),
2671 &provSigner->pasCertChain[selection]);
2672 break;
2674 case NM_DBLCLK:
2675 show_dialog_for_selected_cert(hwnd);
2676 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
2677 ret = 1;
2678 break;
2680 break;
2682 case WM_COMMAND:
2683 switch (wp)
2685 case IDC_VIEWCERTIFICATE:
2686 show_dialog_for_selected_cert(hwnd);
2687 break;
2689 break;
2690 case WM_REFRESH_VIEW:
2692 TVITEMW item;
2694 /* Get hierarchy data */
2695 memset(&item, 0, sizeof(item));
2696 item.mask = TVIF_HANDLE | TVIF_PARAM;
2697 item.hItem = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM, TVGN_ROOT,
2698 (LPARAM)NULL);
2699 data = get_hierarchy_data_from_tree_item(tree, item.hItem);
2700 /* Delete the contents of the tree */
2701 SendMessageW(tree, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT);
2702 /* Reinitialize the tree */
2703 show_cert_hierarchy(hwnd, data);
2704 break;
2707 return ret;
2710 static UINT CALLBACK hierarchy_callback(HWND hwnd, UINT msg,
2711 PROPSHEETPAGEW *page)
2713 struct hierarchy_data *data;
2715 switch (msg)
2717 case PSPCB_RELEASE:
2718 data = (struct hierarchy_data *)page->lParam;
2719 ImageList_Destroy(data->imageList);
2720 HeapFree(GetProcessHeap(), 0, data);
2721 break;
2723 return 0;
2726 static BOOL init_hierarchy_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
2727 PROPSHEETPAGEW *page)
2729 struct hierarchy_data *data = HeapAlloc(GetProcessHeap(), 0,
2730 sizeof(struct hierarchy_data));
2731 BOOL ret = FALSE;
2733 if (data)
2735 data->imageList = ImageList_Create(16, 16, ILC_COLOR4 | ILC_MASK, 2, 0);
2736 if (data->imageList)
2738 HBITMAP bmp;
2739 COLORREF backColor = RGB(255, 0, 255);
2741 data->pCertViewInfo = pCertViewInfo;
2742 data->selectedCert = 0xffffffff;
2744 bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_SMALL_ICONS));
2745 ImageList_AddMasked(data->imageList, bmp, backColor);
2746 DeleteObject(bmp);
2747 ImageList_SetBkColor(data->imageList, CLR_NONE);
2749 memset(page, 0, sizeof(PROPSHEETPAGEW));
2750 page->dwSize = sizeof(PROPSHEETPAGEW);
2751 page->dwFlags = PSP_USECALLBACK;
2752 page->hInstance = hInstance;
2753 page->u.pszTemplate = MAKEINTRESOURCEW(IDD_HIERARCHY);
2754 page->pfnDlgProc = hierarchy_dlg_proc;
2755 page->lParam = (LPARAM)data;
2756 page->pfnCallback = hierarchy_callback;
2757 ret = TRUE;
2759 else
2760 HeapFree(GetProcessHeap(), 0, data);
2762 return ret;
2765 static int CALLBACK cert_prop_sheet_proc(HWND hwnd, UINT msg, LPARAM lp)
2767 RECT rc;
2768 POINT topLeft;
2770 TRACE("(%p, %08x, %08lx)\n", hwnd, msg, lp);
2772 switch (msg)
2774 case PSCB_INITIALIZED:
2775 /* Get cancel button's position.. */
2776 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rc);
2777 topLeft.x = rc.left;
2778 topLeft.y = rc.top;
2779 ScreenToClient(hwnd, &topLeft);
2780 /* hide the cancel button.. */
2781 ShowWindow(GetDlgItem(hwnd, IDCANCEL), FALSE);
2782 /* get the OK button's size.. */
2783 GetWindowRect(GetDlgItem(hwnd, IDOK), &rc);
2784 /* and move the OK button to the cancel button's original position. */
2785 MoveWindow(GetDlgItem(hwnd, IDOK), topLeft.x, topLeft.y,
2786 rc.right - rc.left, rc.bottom - rc.top, FALSE);
2787 GetWindowRect(GetDlgItem(hwnd, IDOK), &rc);
2788 break;
2790 return 0;
2793 static BOOL show_cert_dialog(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
2794 CRYPT_PROVIDER_CERT *provCert, BOOL *pfPropertiesChanged)
2796 static const WCHAR riched[] = { 'r','i','c','h','e','d','2','0',0 };
2797 DWORD nPages;
2798 PROPSHEETPAGEW *pages;
2799 BOOL ret = FALSE;
2800 HMODULE lib = LoadLibraryW(riched);
2802 nPages = pCertViewInfo->cPropSheetPages + 1; /* one for the General tab */
2803 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_DETAILPAGE))
2804 nPages++;
2805 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_HIERARCHYPAGE))
2806 nPages++;
2807 pages = HeapAlloc(GetProcessHeap(), 0, nPages * sizeof(PROPSHEETPAGEW));
2808 if (pages)
2810 PROPSHEETHEADERW hdr;
2811 CRYPTUI_INITDIALOG_STRUCT *init = NULL;
2812 DWORD i;
2814 memset(&hdr, 0, sizeof(hdr));
2815 hdr.dwSize = sizeof(hdr);
2816 hdr.dwFlags = PSH_NOAPPLYNOW | PSH_PROPSHEETPAGE | PSH_USECALLBACK;
2817 hdr.hInstance = hInstance;
2818 if (pCertViewInfo->szTitle)
2819 hdr.pszCaption = pCertViewInfo->szTitle;
2820 else
2821 hdr.pszCaption = MAKEINTRESOURCEW(IDS_CERTIFICATE);
2822 init_general_page(pCertViewInfo, &pages[hdr.nPages++]);
2823 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_DETAILPAGE))
2825 if (init_detail_page(pCertViewInfo, pfPropertiesChanged,
2826 &pages[hdr.nPages]))
2827 hdr.nPages++;
2829 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_HIERARCHYPAGE))
2831 if (init_hierarchy_page(pCertViewInfo, &pages[hdr.nPages]))
2832 hdr.nPages++;
2834 /* Copy each additional page, and create the init dialog struct for it
2836 if (pCertViewInfo->cPropSheetPages)
2838 init = HeapAlloc(GetProcessHeap(), 0,
2839 pCertViewInfo->cPropSheetPages *
2840 sizeof(CRYPTUI_INITDIALOG_STRUCT));
2841 if (init)
2843 for (i = 0; i < pCertViewInfo->cPropSheetPages; i++)
2845 memcpy(&pages[hdr.nPages + i],
2846 &pCertViewInfo->rgPropSheetPages[i],
2847 sizeof(PROPSHEETPAGEW));
2848 init[i].lParam = pCertViewInfo->rgPropSheetPages[i].lParam;
2849 init[i].pCertContext = pCertViewInfo->pCertContext;
2850 pages[hdr.nPages + i].lParam = (LPARAM)&init[i];
2852 if (pCertViewInfo->nStartPage & 0x8000)
2854 /* Start page index is relative to the number of default
2855 * pages
2857 hdr.u2.nStartPage = pCertViewInfo->nStartPage + hdr.nPages;
2859 else
2860 hdr.u2.nStartPage = pCertViewInfo->nStartPage;
2861 hdr.nPages = nPages;
2862 ret = TRUE;
2864 else
2865 SetLastError(ERROR_OUTOFMEMORY);
2867 else
2869 /* Ignore the relative flag if there aren't any additional pages */
2870 hdr.u2.nStartPage = pCertViewInfo->nStartPage & 0x7fff;
2871 ret = TRUE;
2873 if (ret)
2875 INT_PTR l;
2877 hdr.u3.ppsp = pages;
2878 hdr.pfnCallback = cert_prop_sheet_proc;
2879 l = PropertySheetW(&hdr);
2880 if (l == 0)
2882 SetLastError(ERROR_CANCELLED);
2883 ret = FALSE;
2886 HeapFree(GetProcessHeap(), 0, init);
2887 HeapFree(GetProcessHeap(), 0, pages);
2889 else
2890 SetLastError(ERROR_OUTOFMEMORY);
2891 FreeLibrary(lib);
2892 return ret;
2895 /***********************************************************************
2896 * CryptUIDlgViewCertificateW (CRYPTUI.@)
2898 BOOL WINAPI CryptUIDlgViewCertificateW(
2899 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo, BOOL *pfPropertiesChanged)
2901 static GUID generic_cert_verify = WINTRUST_ACTION_GENERIC_CERT_VERIFY;
2902 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
2903 WINTRUST_DATA wvt;
2904 WINTRUST_CERT_INFO cert;
2905 BOOL ret = FALSE;
2906 CRYPT_PROVIDER_SGNR *signer;
2907 CRYPT_PROVIDER_CERT *provCert = NULL;
2909 TRACE("(%p, %p)\n", pCertViewInfo, pfPropertiesChanged);
2911 if (pCertViewInfo->dwSize != sizeof(CRYPTUI_VIEWCERTIFICATE_STRUCTW))
2913 SetLastError(ERROR_INVALID_PARAMETER);
2914 return FALSE;
2916 /* Make a local copy in case we have to call WinVerifyTrust ourselves */
2917 memcpy(&viewInfo, pCertViewInfo, sizeof(viewInfo));
2918 if (!viewInfo.u.hWVTStateData)
2920 memset(&wvt, 0, sizeof(wvt));
2921 wvt.cbStruct = sizeof(wvt);
2922 wvt.dwUIChoice = WTD_UI_NONE;
2923 if (viewInfo.dwFlags &
2924 CRYPTUI_ENABLE_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT)
2925 wvt.fdwRevocationChecks |= WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
2926 if (viewInfo.dwFlags & CRYPTUI_ENABLE_REVOCATION_CHECK_END_CERT)
2927 wvt.fdwRevocationChecks |= WTD_REVOCATION_CHECK_END_CERT;
2928 if (viewInfo.dwFlags & CRYPTUI_ENABLE_REVOCATION_CHECK_CHAIN)
2929 wvt.fdwRevocationChecks |= WTD_REVOCATION_CHECK_CHAIN;
2930 wvt.dwUnionChoice = WTD_CHOICE_CERT;
2931 memset(&cert, 0, sizeof(cert));
2932 cert.cbStruct = sizeof(cert);
2933 cert.psCertContext = (CERT_CONTEXT *)viewInfo.pCertContext;
2934 cert.chStores = viewInfo.cStores;
2935 cert.pahStores = viewInfo.rghStores;
2936 wvt.u.pCert = &cert;
2937 wvt.dwStateAction = WTD_STATEACTION_VERIFY;
2938 WinVerifyTrust(NULL, &generic_cert_verify, &wvt);
2939 viewInfo.u.pCryptProviderData =
2940 WTHelperProvDataFromStateData(wvt.hWVTStateData);
2941 signer = WTHelperGetProvSignerFromChain(
2942 (CRYPT_PROVIDER_DATA *)viewInfo.u.pCryptProviderData, 0, FALSE, 0);
2943 provCert = WTHelperGetProvCertFromChain(signer, 0);
2944 ret = TRUE;
2946 else
2948 viewInfo.u.pCryptProviderData =
2949 WTHelperProvDataFromStateData(viewInfo.u.hWVTStateData);
2950 signer = WTHelperGetProvSignerFromChain(
2951 (CRYPT_PROVIDER_DATA *)viewInfo.u.pCryptProviderData,
2952 viewInfo.idxSigner, viewInfo.fCounterSigner,
2953 viewInfo.idxCounterSigner);
2954 provCert = WTHelperGetProvCertFromChain(signer, viewInfo.idxCert);
2955 ret = TRUE;
2957 if (ret)
2959 ret = show_cert_dialog(&viewInfo, provCert, pfPropertiesChanged);
2960 if (!viewInfo.u.hWVTStateData)
2962 wvt.dwStateAction = WTD_STATEACTION_CLOSE;
2963 WinVerifyTrust(NULL, &generic_cert_verify, &wvt);
2966 return ret;
2969 /***********************************************************************
2970 * CryptUIDlgViewContext (CRYPTUI.@)
2972 BOOL WINAPI CryptUIDlgViewContext(DWORD dwContextType, LPVOID pvContext,
2973 HWND hwnd, LPCWSTR pwszTitle, DWORD dwFlags, LPVOID pvReserved)
2975 BOOL ret;
2977 TRACE("(%d, %p, %p, %s, %08x, %p)\n", dwContextType, pvContext, hwnd,
2978 debugstr_w(pwszTitle), dwFlags, pvReserved);
2980 switch (dwContextType)
2982 case CERT_STORE_CERTIFICATE_CONTEXT:
2984 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
2986 memset(&viewInfo, 0, sizeof(viewInfo));
2987 viewInfo.dwSize = sizeof(viewInfo);
2988 viewInfo.hwndParent = hwnd;
2989 viewInfo.szTitle = pwszTitle;
2990 viewInfo.pCertContext = pvContext;
2991 ret = CryptUIDlgViewCertificateW(&viewInfo, NULL);
2992 break;
2994 default:
2995 FIXME("unimplemented for context type %d\n", dwContextType);
2996 SetLastError(E_INVALIDARG);
2997 ret = FALSE;
2999 return ret;
3002 static PCCERT_CONTEXT make_cert_from_file(LPCWSTR fileName)
3004 HANDLE file;
3005 DWORD size, encoding = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
3006 BYTE *buffer;
3007 PCCERT_CONTEXT cert;
3009 file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
3010 OPEN_EXISTING, 0, NULL);
3011 if (file == INVALID_HANDLE_VALUE)
3013 WARN("can't open certificate file %s\n", debugstr_w(fileName));
3014 return NULL;
3016 if ((size = GetFileSize(file, NULL)))
3018 if ((buffer = HeapAlloc(GetProcessHeap(), 0, size)))
3020 DWORD read;
3021 if (!ReadFile(file, buffer, size, &read, NULL) || read != size)
3023 WARN("can't read certificate file %s\n", debugstr_w(fileName));
3024 HeapFree(GetProcessHeap(), 0, buffer);
3025 CloseHandle(file);
3026 return NULL;
3030 else
3032 WARN("empty file %s\n", debugstr_w(fileName));
3033 CloseHandle(file);
3034 return NULL;
3036 CloseHandle(file);
3037 cert = CertCreateCertificateContext(encoding, buffer, size);
3038 HeapFree(GetProcessHeap(), 0, buffer);
3039 return cert;
3042 /* Decodes a cert's basic constraints extension (either szOID_BASIC_CONSTRAINTS
3043 * or szOID_BASIC_CONSTRAINTS2, whichever is present) to determine if it
3044 * should be a CA. If neither extension is present, returns
3045 * defaultIfNotSpecified.
3047 static BOOL is_ca_cert(PCCERT_CONTEXT cert, BOOL defaultIfNotSpecified)
3049 BOOL isCA = defaultIfNotSpecified;
3050 PCERT_EXTENSION ext = CertFindExtension(szOID_BASIC_CONSTRAINTS,
3051 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
3053 if (ext)
3055 CERT_BASIC_CONSTRAINTS_INFO *info;
3056 DWORD size = 0;
3058 if (CryptDecodeObjectEx(X509_ASN_ENCODING, szOID_BASIC_CONSTRAINTS,
3059 ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG,
3060 NULL, (LPBYTE)&info, &size))
3062 if (info->SubjectType.cbData == 1)
3063 isCA = info->SubjectType.pbData[0] & CERT_CA_SUBJECT_FLAG;
3064 LocalFree(info);
3067 else
3069 ext = CertFindExtension(szOID_BASIC_CONSTRAINTS2,
3070 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
3071 if (ext)
3073 CERT_BASIC_CONSTRAINTS2_INFO info;
3074 DWORD size = sizeof(CERT_BASIC_CONSTRAINTS2_INFO);
3076 if (CryptDecodeObjectEx(X509_ASN_ENCODING,
3077 szOID_BASIC_CONSTRAINTS2, ext->Value.pbData, ext->Value.cbData,
3078 0, NULL, &info, &size))
3079 isCA = info.fCA;
3082 return isCA;
3085 static HCERTSTORE choose_store_for_cert(PCCERT_CONTEXT cert)
3087 static const WCHAR AddressBook[] = { 'A','d','d','r','e','s','s',
3088 'B','o','o','k',0 };
3089 static const WCHAR CA[] = { 'C','A',0 };
3090 LPCWSTR storeName;
3092 if (is_ca_cert(cert, TRUE))
3093 storeName = CA;
3094 else
3095 storeName = AddressBook;
3096 return CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0,
3097 CERT_SYSTEM_STORE_CURRENT_USER, storeName);
3100 BOOL WINAPI CryptUIWizImport(DWORD dwFlags, HWND hwndParent, LPCWSTR pwszWizardTitle,
3101 PCCRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc, HCERTSTORE hDestCertStore)
3103 BOOL ret;
3104 HCERTSTORE store;
3105 const CERT_CONTEXT *cert;
3106 BOOL freeCert = FALSE;
3108 TRACE("(0x%08x, %p, %s, %p, %p)\n", dwFlags, hwndParent, debugstr_w(pwszWizardTitle),
3109 pImportSrc, hDestCertStore);
3111 if (!(dwFlags & CRYPTUI_WIZ_NO_UI)) FIXME("UI not implemented\n");
3113 if (!pImportSrc ||
3114 pImportSrc->dwSize != sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO))
3116 SetLastError(E_INVALIDARG);
3117 return FALSE;
3120 switch (pImportSrc->dwSubjectChoice)
3122 case CRYPTUI_WIZ_IMPORT_SUBJECT_FILE:
3123 if (!(cert = make_cert_from_file(pImportSrc->u.pwszFileName)))
3125 WARN("unable to create certificate context\n");
3126 return FALSE;
3128 else
3129 freeCert = TRUE;
3130 break;
3131 case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_CONTEXT:
3132 cert = pImportSrc->u.pCertContext;
3133 if (!cert)
3135 SetLastError(E_INVALIDARG);
3136 return FALSE;
3138 break;
3139 default:
3140 FIXME("source type not implemented: %u\n", pImportSrc->dwSubjectChoice);
3141 SetLastError(E_INVALIDARG);
3142 return FALSE;
3144 if (hDestCertStore) store = hDestCertStore;
3145 else
3147 if (!(store = choose_store_for_cert(cert)))
3149 WARN("unable to open certificate store\n");
3150 CertFreeCertificateContext(cert);
3151 return FALSE;
3154 ret = CertAddCertificateContextToStore(store, cert, CERT_STORE_ADD_REPLACE_EXISTING, NULL);
3156 if (!hDestCertStore) CertCloseStore(store, 0);
3157 if (freeCert)
3158 CertFreeCertificateContext(cert);
3159 return ret;