cryptui: Add stubs for CryptUIDlgSelectStoreA/W.
[wine/wine64.git] / dlls / cryptui / main.c
blobd18abdf177a41e6d86da7fbef434f312e42994de
1 /*
2 * Copyright 2008 Juan Lang
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "config.h"
21 #include <stdarg.h>
23 #define COBJMACROS
24 #define NONAMELESSUNION
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winnls.h"
29 #include "winuser.h"
30 #include "softpub.h"
31 #include "wingdi.h"
32 #include "richedit.h"
33 #include "ole2.h"
34 #include "richole.h"
35 #include "commctrl.h"
36 #include "cryptuiapi.h"
37 #include "cryptuires.h"
38 #include "urlmon.h"
39 #include "hlink.h"
40 #include "wine/debug.h"
41 #include "wine/unicode.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(cryptui);
45 static HINSTANCE hInstance;
47 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
49 TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
51 switch (fdwReason)
53 case DLL_WINE_PREATTACH:
54 return FALSE; /* prefer native version */
55 case DLL_PROCESS_ATTACH:
56 hInstance = hinstDLL;
57 DisableThreadLibraryCalls(hinstDLL);
58 break;
59 case DLL_PROCESS_DETACH:
60 break;
61 default:
62 break;
64 return TRUE;
67 /***********************************************************************
68 * CryptUIDlgCertMgr (CRYPTUI.@)
70 BOOL WINAPI CryptUIDlgCertMgr(PCCRYPTUI_CERT_MGR_STRUCT pCryptUICertMgr)
72 FIXME("(%p): stub\n", pCryptUICertMgr);
73 return FALSE;
76 /* FIXME: real names are unknown, functions are undocumented */
77 struct _CRYPTUI_SELECTSTORE_INFO_A;
78 struct _CRYPTUI_SELECTSTORE_INFO_W;
80 /***********************************************************************
81 * CryptUIDlgSelectStoreA (CRYPTUI.@)
83 HCERTSTORE WINAPI CryptUIDlgSelectStoreA(struct _CRYPTUI_SELECTSTORE_INFO_A *info)
85 FIXME("(%p): stub\n", info);
86 return NULL;
89 /***********************************************************************
90 * CryptUIDlgSelectStoreW (CRYPTUI.@)
92 HCERTSTORE WINAPI CryptUIDlgSelectStoreW(struct _CRYPTUI_SELECTSTORE_INFO_W *info)
94 FIXME("(%p): stub\n", info);
95 return NULL;
98 /***********************************************************************
99 * CryptUIDlgViewCertificateA (CRYPTUI.@)
101 BOOL WINAPI CryptUIDlgViewCertificateA(
102 PCCRYPTUI_VIEWCERTIFICATE_STRUCTA pCertViewInfo, BOOL *pfPropertiesChanged)
104 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
105 LPWSTR title = NULL;
106 BOOL ret;
108 TRACE("(%p, %p)\n", pCertViewInfo, pfPropertiesChanged);
110 memcpy(&viewInfo, pCertViewInfo, sizeof(viewInfo));
111 if (pCertViewInfo->szTitle)
113 int len = MultiByteToWideChar(CP_ACP, 0, pCertViewInfo->szTitle, -1,
114 NULL, 0);
116 title = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
117 if (title)
119 MultiByteToWideChar(CP_ACP, 0, pCertViewInfo->szTitle, -1, title,
120 len);
121 viewInfo.szTitle = title;
123 else
125 ret = FALSE;
126 goto error;
129 if (pCertViewInfo->cPropSheetPages)
131 FIXME("ignoring additional prop sheet pages\n");
132 viewInfo.cPropSheetPages = 0;
134 ret = CryptUIDlgViewCertificateW(&viewInfo, pfPropertiesChanged);
135 HeapFree(GetProcessHeap(), 0, title);
136 error:
137 return ret;
140 struct ReadStringStruct
142 LPCWSTR buf;
143 LONG pos;
144 LONG len;
147 static DWORD CALLBACK read_text_callback(DWORD_PTR dwCookie, LPBYTE buf,
148 LONG cb, LONG *pcb)
150 struct ReadStringStruct *string = (struct ReadStringStruct *)dwCookie;
151 LONG cch = min(cb / sizeof(WCHAR), string->len - string->pos);
153 TRACE("(%p, %p, %d, %p)\n", string, buf, cb, pcb);
155 memmove(buf, string->buf + string->pos, cch * sizeof(WCHAR));
156 string->pos += cch;
157 *pcb = cch * sizeof(WCHAR);
158 return 0;
161 static void add_unformatted_text_to_control(HWND hwnd, LPCWSTR text, LONG len)
163 struct ReadStringStruct string;
164 EDITSTREAM editstream;
166 TRACE("(%p, %s)\n", hwnd, debugstr_wn(text, len));
168 string.buf = text;
169 string.pos = 0;
170 string.len = len;
171 editstream.dwCookie = (DWORD_PTR)&string;
172 editstream.dwError = 0;
173 editstream.pfnCallback = read_text_callback;
174 SendMessageW(hwnd, EM_STREAMIN, SF_TEXT | SFF_SELECTION | SF_UNICODE,
175 (LPARAM)&editstream);
178 static void add_string_resource_to_control(HWND hwnd, int id)
180 LPWSTR str;
181 LONG len;
183 len = LoadStringW(hInstance, id, (LPWSTR)&str, 0);
184 add_unformatted_text_to_control(hwnd, str, len);
187 static void add_text_with_paraformat_to_control(HWND hwnd, LPCWSTR text,
188 LONG len, const PARAFORMAT2 *fmt)
190 add_unformatted_text_to_control(hwnd, text, len);
191 SendMessageW(hwnd, EM_SETPARAFORMAT, 0, (LPARAM)fmt);
194 static void add_string_resource_with_paraformat_to_control(HWND hwnd, int id,
195 const PARAFORMAT2 *fmt)
197 LPWSTR str;
198 LONG len;
200 len = LoadStringW(hInstance, id, (LPWSTR)&str, 0);
201 add_text_with_paraformat_to_control(hwnd, str, len, fmt);
204 static LPWSTR get_cert_name_string(PCCERT_CONTEXT pCertContext, DWORD dwType,
205 DWORD dwFlags)
207 LPWSTR buf = NULL;
208 DWORD len;
210 len = CertGetNameStringW(pCertContext, dwType, dwFlags, NULL, NULL, 0);
211 if (len)
213 buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
214 if (buf)
215 CertGetNameStringW(pCertContext, dwType, dwFlags, NULL, buf, len);
217 return buf;
220 static void add_cert_string_to_control(HWND hwnd, PCCERT_CONTEXT pCertContext,
221 DWORD dwType, DWORD dwFlags)
223 LPWSTR name = get_cert_name_string(pCertContext, dwType, dwFlags);
225 if (name)
227 /* Don't include NULL-terminator in output */
228 DWORD len = lstrlenW(name);
230 add_unformatted_text_to_control(hwnd, name, len);
231 HeapFree(GetProcessHeap(), 0, name);
235 static void add_icon_to_control(HWND hwnd, int id)
237 HRESULT hr;
238 LPRICHEDITOLE richEditOle = NULL;
239 LPOLEOBJECT object = NULL;
240 CLSID clsid;
241 LPOLECACHE oleCache = NULL;
242 FORMATETC formatEtc;
243 DWORD conn;
244 LPDATAOBJECT dataObject = NULL;
245 HBITMAP bitmap = NULL;
246 RECT rect;
247 STGMEDIUM stgm;
248 REOBJECT reObject;
250 TRACE("(%p, %d)\n", hwnd, id);
252 SendMessageW(hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&richEditOle);
253 if (!richEditOle)
254 goto end;
255 hr = OleCreateDefaultHandler(&CLSID_NULL, NULL, &IID_IOleObject,
256 (void**)&object);
257 if (FAILED(hr))
258 goto end;
259 hr = IOleObject_GetUserClassID(object, &clsid);
260 if (FAILED(hr))
261 goto end;
262 hr = IOleObject_QueryInterface(object, &IID_IOleCache, (void**)&oleCache);
263 if (FAILED(hr))
264 goto end;
265 formatEtc.cfFormat = CF_BITMAP;
266 formatEtc.ptd = NULL;
267 formatEtc.dwAspect = DVASPECT_CONTENT;
268 formatEtc.lindex = -1;
269 formatEtc.tymed = TYMED_GDI;
270 hr = IOleCache_Cache(oleCache, &formatEtc, 0, &conn);
271 if (FAILED(hr))
272 goto end;
273 hr = IOleObject_QueryInterface(object, &IID_IDataObject,
274 (void**)&dataObject);
275 if (FAILED(hr))
276 goto end;
277 bitmap = LoadImageW(hInstance, MAKEINTRESOURCEW(id), IMAGE_BITMAP, 0, 0,
278 LR_DEFAULTSIZE | LR_LOADTRANSPARENT);
279 if (!bitmap)
280 goto end;
281 rect.left = rect.top = 0;
282 rect.right = GetSystemMetrics(SM_CXICON);
283 rect.bottom = GetSystemMetrics(SM_CYICON);
284 stgm.tymed = TYMED_GDI;
285 stgm.u.hBitmap = bitmap;
286 stgm.pUnkForRelease = NULL;
287 hr = IDataObject_SetData(dataObject, &formatEtc, &stgm, TRUE);
288 if (FAILED(hr))
289 goto end;
291 reObject.cbStruct = sizeof(reObject);
292 reObject.cp = REO_CP_SELECTION;
293 reObject.clsid = clsid;
294 reObject.poleobj = object;
295 reObject.pstg = NULL;
296 reObject.polesite = NULL;
297 reObject.sizel.cx = reObject.sizel.cy = 0;
298 reObject.dvaspect = DVASPECT_CONTENT;
299 reObject.dwFlags = 0;
300 reObject.dwUser = 0;
302 IRichEditOle_InsertObject(richEditOle, &reObject);
304 end:
305 if (dataObject)
306 IDataObject_Release(dataObject);
307 if (oleCache)
308 IOleCache_Release(oleCache);
309 if (object)
310 IOleObject_Release(object);
311 if (richEditOle)
312 IRichEditOle_Release(richEditOle);
315 #define MY_INDENT 200
317 static void add_oid_text_to_control(HWND hwnd, char *oid)
319 WCHAR nl = '\n';
320 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, oid, 0);
321 PARAFORMAT2 parFmt;
323 parFmt.cbSize = sizeof(parFmt);
324 parFmt.dwMask = PFM_STARTINDENT;
325 parFmt.dxStartIndent = MY_INDENT * 3;
326 if (oidInfo)
328 add_text_with_paraformat_to_control(hwnd, oidInfo->pwszName,
329 lstrlenW(oidInfo->pwszName), &parFmt);
330 add_unformatted_text_to_control(hwnd, &nl, 1);
334 #define MAX_STRING_LEN 512
336 struct OIDToString
338 LPCSTR oid;
339 int id;
342 /* The following list MUST be lexicographically sorted by OID */
343 static struct OIDToString oidMap[] = {
344 /* 1.3.6.1.4.1.311.10.3.1 */
345 { szOID_KP_CTL_USAGE_SIGNING, IDS_PURPOSE_CTL_USAGE_SIGNING },
346 /* 1.3.6.1.4.1.311.10.3.4 */
347 { szOID_KP_EFS, IDS_PURPOSE_EFS },
348 /* 1.3.6.1.4.1.311.10.3.4.1 */
349 { szOID_EFS_RECOVERY, IDS_PURPOSE_EFS_RECOVERY },
350 /* 1.3.6.1.4.1.311.10.3.5 */
351 { szOID_WHQL_CRYPTO, IDS_PURPOSE_WHQL },
352 /* 1.3.6.1.4.1.311.10.3.6 */
353 { szOID_NT5_CRYPTO, IDS_PURPOSE_NT5 },
354 /* 1.3.6.1.4.1.311.10.3.7 */
355 { szOID_OEM_WHQL_CRYPTO, IDS_PURPOSE_OEM_WHQL },
356 /* 1.3.6.1.4.1.311.10.3.8 */
357 { szOID_EMBEDDED_NT_CRYPTO, IDS_PURPOSE_EMBEDDED_NT },
358 /* 1.3.6.1.4.1.311.10.3.9 */
359 { szOID_ROOT_LIST_SIGNER, IDS_PURPOSE_ROOT_LIST_SIGNER },
360 /* 1.3.6.1.4.1.311.10.3.10 */
361 { szOID_KP_QUALIFIED_SUBORDINATION, IDS_PURPOSE_QUALIFIED_SUBORDINATION },
362 /* 1.3.6.1.4.1.311.10.3.11 */
363 { szOID_KP_KEY_RECOVERY, IDS_PURPOSE_KEY_RECOVERY },
364 /* 1.3.6.1.4.1.311.10.3.12 */
365 { szOID_KP_DOCUMENT_SIGNING, IDS_PURPOSE_DOCUMENT_SIGNING },
366 /* 1.3.6.1.4.1.311.10.3.13 */
367 { szOID_KP_LIFETIME_SIGNING, IDS_PURPOSE_LIFETIME_SIGNING },
368 /* 1.3.6.1.4.1.311.10.5.1 */
369 { szOID_DRM, IDS_PURPOSE_DRM },
370 /* 1.3.6.1.4.1.311.10.6.1 */
371 { szOID_LICENSES, IDS_PURPOSE_LICENSES },
372 /* 1.3.6.1.4.1.311.10.6.2 */
373 { szOID_LICENSE_SERVER, IDS_PURPOSE_LICENSE_SERVER },
374 /* 1.3.6.1.4.1.311.20.2.1 */
375 { szOID_ENROLLMENT_AGENT, IDS_PURPOSE_ENROLLMENT_AGENT },
376 /* 1.3.6.1.4.1.311.20.2.2 */
377 { szOID_KP_SMARTCARD_LOGON, IDS_PURPOSE_SMARTCARD_LOGON },
378 /* 1.3.6.1.4.1.311.21.5 */
379 { szOID_KP_CA_EXCHANGE, IDS_PURPOSE_CA_EXCHANGE },
380 /* 1.3.6.1.4.1.311.21.6 */
381 { szOID_KP_KEY_RECOVERY_AGENT, IDS_PURPOSE_KEY_RECOVERY_AGENT },
382 /* 1.3.6.1.4.1.311.21.19 */
383 { szOID_DS_EMAIL_REPLICATION, IDS_PURPOSE_DS_EMAIL_REPLICATION },
384 /* 1.3.6.1.5.5.7.3.1 */
385 { szOID_PKIX_KP_SERVER_AUTH, IDS_PURPOSE_SERVER_AUTH },
386 /* 1.3.6.1.5.5.7.3.2 */
387 { szOID_PKIX_KP_CLIENT_AUTH, IDS_PURPOSE_CLIENT_AUTH },
388 /* 1.3.6.1.5.5.7.3.3 */
389 { szOID_PKIX_KP_CODE_SIGNING, IDS_PURPOSE_CODE_SIGNING },
390 /* 1.3.6.1.5.5.7.3.4 */
391 { szOID_PKIX_KP_EMAIL_PROTECTION, IDS_PURPOSE_EMAIL_PROTECTION },
392 /* 1.3.6.1.5.5.7.3.5 */
393 { szOID_PKIX_KP_IPSEC_END_SYSTEM, IDS_PURPOSE_IPSEC },
394 /* 1.3.6.1.5.5.7.3.6 */
395 { szOID_PKIX_KP_IPSEC_TUNNEL, IDS_PURPOSE_IPSEC },
396 /* 1.3.6.1.5.5.7.3.7 */
397 { szOID_PKIX_KP_IPSEC_USER, IDS_PURPOSE_IPSEC },
398 /* 1.3.6.1.5.5.7.3.8 */
399 { szOID_PKIX_KP_TIMESTAMP_SIGNING, IDS_PURPOSE_TIMESTAMP_SIGNING },
402 static struct OIDToString *findSupportedOID(LPCSTR oid)
404 int indexHigh = sizeof(oidMap) / sizeof(oidMap[0]) - 1, indexLow = 0, i;
405 struct OIDToString *ret = NULL;
407 for (i = (indexLow + indexHigh) / 2; !ret && indexLow <= indexHigh;
408 i = (indexLow + indexHigh) / 2)
410 int cmp;
412 cmp = strcmp(oid, oidMap[i].oid);
413 if (!cmp)
414 ret = &oidMap[i];
415 else if (cmp > 0)
416 indexLow = i + 1;
417 else
418 indexHigh = i - 1;
420 return ret;
423 static void add_local_oid_text_to_control(HWND text, LPCSTR oid)
425 struct OIDToString *entry;
426 WCHAR nl = '\n';
427 PARAFORMAT2 parFmt;
429 parFmt.cbSize = sizeof(parFmt);
430 parFmt.dwMask = PFM_STARTINDENT;
431 parFmt.dxStartIndent = MY_INDENT * 3;
432 if ((entry = findSupportedOID(oid)))
434 WCHAR *str, *linebreak, *ptr;
435 BOOL multiline = FALSE;
436 int len;
438 len = LoadStringW(hInstance, entry->id, (LPWSTR)&str, 0);
439 ptr = str;
440 do {
441 if ((linebreak = memchrW(ptr, '\n', len)))
443 WCHAR copy[MAX_STRING_LEN];
445 multiline = TRUE;
446 /* The source string contains a newline, which the richedit
447 * control won't find since it's interpreted as a paragraph
448 * break. Therefore copy up to the newline. lstrcpynW always
449 * NULL-terminates, so pass one more than the length of the
450 * source line so the copy includes the entire line and the
451 * NULL-terminator.
453 lstrcpynW(copy, ptr, linebreak - ptr + 1);
454 add_text_with_paraformat_to_control(text, copy,
455 linebreak - ptr, &parFmt);
456 ptr = linebreak + 1;
457 add_unformatted_text_to_control(text, &nl, 1);
459 else if (multiline && *ptr)
461 /* Add the last line */
462 add_text_with_paraformat_to_control(text, ptr,
463 len - (ptr - str), &parFmt);
464 add_unformatted_text_to_control(text, &nl, 1);
466 } while (linebreak);
467 if (!multiline)
469 add_text_with_paraformat_to_control(text, str, len, &parFmt);
470 add_unformatted_text_to_control(text, &nl, 1);
473 else
475 WCHAR *oidW = HeapAlloc(GetProcessHeap(), 0,
476 (strlen(oid) + 1) * sizeof(WCHAR));
478 if (oidW)
480 LPCSTR src;
481 WCHAR *dst;
483 for (src = oid, dst = oidW; *src; src++, dst++)
484 *dst = *src;
485 *dst = 0;
486 add_text_with_paraformat_to_control(text, oidW, lstrlenW(oidW),
487 &parFmt);
488 add_unformatted_text_to_control(text, &nl, 1);
489 HeapFree(GetProcessHeap(), 0, oidW);
494 static void display_app_usages(HWND text, PCCERT_CONTEXT cert,
495 BOOL *anyUsageAdded)
497 static char any_app_policy[] = szOID_ANY_APPLICATION_POLICY;
498 WCHAR nl = '\n';
499 CHARFORMATW charFmt;
500 PCERT_EXTENSION policyExt;
501 if (!*anyUsageAdded)
503 PARAFORMAT2 parFmt;
505 parFmt.cbSize = sizeof(parFmt);
506 parFmt.dwMask = PFM_STARTINDENT;
507 parFmt.dxStartIndent = MY_INDENT;
508 add_string_resource_with_paraformat_to_control(text,
509 IDS_CERT_INFO_PURPOSES, &parFmt);
510 add_unformatted_text_to_control(text, &nl, 1);
511 *anyUsageAdded = TRUE;
513 memset(&charFmt, 0, sizeof(charFmt));
514 charFmt.cbSize = sizeof(charFmt);
515 charFmt.dwMask = CFM_BOLD;
516 charFmt.dwEffects = 0;
517 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
518 if ((policyExt = CertFindExtension(szOID_APPLICATION_CERT_POLICIES,
519 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension)))
521 CERT_POLICIES_INFO *policies;
522 DWORD size;
524 if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_POLICIES,
525 policyExt->Value.pbData, policyExt->Value.cbData,
526 CRYPT_DECODE_ALLOC_FLAG, NULL, &policies, &size))
528 DWORD i;
530 for (i = 0; i < policies->cPolicyInfo; i++)
532 DWORD j;
534 for (j = 0; j < policies->rgPolicyInfo[i].cPolicyQualifier; j++)
535 add_local_oid_text_to_control(text,
536 policies->rgPolicyInfo[i].rgPolicyQualifier[j].
537 pszPolicyQualifierId);
539 LocalFree(policies);
542 else
543 add_oid_text_to_control(text, any_app_policy);
546 static BOOL display_cert_usages(HWND text, PCCERT_CONTEXT cert,
547 BOOL *anyUsageAdded)
549 WCHAR nl = '\n';
550 DWORD size;
551 BOOL badUsages = FALSE;
553 if (CertGetEnhancedKeyUsage(cert, 0, NULL, &size))
555 CHARFORMATW charFmt;
556 static char any_cert_policy[] = szOID_ANY_CERT_POLICY;
557 PCERT_ENHKEY_USAGE usage = HeapAlloc(GetProcessHeap(), 0, size);
559 if (usage)
561 if (CertGetEnhancedKeyUsage(cert, 0, usage, &size))
563 DWORD i;
565 if (!*anyUsageAdded)
567 PARAFORMAT2 parFmt;
569 parFmt.cbSize = sizeof(parFmt);
570 parFmt.dwMask = PFM_STARTINDENT;
571 parFmt.dxStartIndent = MY_INDENT;
572 add_string_resource_with_paraformat_to_control(text,
573 IDS_CERT_INFO_PURPOSES, &parFmt);
574 add_unformatted_text_to_control(text, &nl, 1);
575 *anyUsageAdded = TRUE;
577 memset(&charFmt, 0, sizeof(charFmt));
578 charFmt.cbSize = sizeof(charFmt);
579 charFmt.dwMask = CFM_BOLD;
580 charFmt.dwEffects = 0;
581 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION,
582 (LPARAM)&charFmt);
583 if (!usage->cUsageIdentifier)
584 add_oid_text_to_control(text, any_cert_policy);
585 else
586 for (i = 0; i < usage->cUsageIdentifier; i++)
587 add_local_oid_text_to_control(text,
588 usage->rgpszUsageIdentifier[i]);
590 else
591 badUsages = TRUE;
592 HeapFree(GetProcessHeap(), 0, usage);
594 else
595 badUsages = TRUE;
597 else
598 badUsages = TRUE;
599 return badUsages;
602 static void set_policy_text(HWND text,
603 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
605 BOOL includeCertUsages = FALSE, includeAppUsages = FALSE;
606 BOOL badUsages = FALSE, anyUsageAdded = FALSE;
608 if (pCertViewInfo->cPurposes)
610 DWORD i;
612 for (i = 0; i < pCertViewInfo->cPurposes; i++)
614 if (!strcmp(pCertViewInfo->rgszPurposes[i], szOID_ANY_CERT_POLICY))
615 includeCertUsages = TRUE;
616 else if (!strcmp(pCertViewInfo->rgszPurposes[i],
617 szOID_ANY_APPLICATION_POLICY))
618 includeAppUsages = TRUE;
619 else
620 badUsages = TRUE;
623 else
624 includeAppUsages = includeCertUsages = TRUE;
625 if (includeAppUsages)
626 display_app_usages(text, pCertViewInfo->pCertContext, &anyUsageAdded);
627 if (includeCertUsages)
628 badUsages = display_cert_usages(text, pCertViewInfo->pCertContext,
629 &anyUsageAdded);
630 if (badUsages)
632 PARAFORMAT2 parFmt;
634 parFmt.cbSize = sizeof(parFmt);
635 parFmt.dwMask = PFM_STARTINDENT;
636 parFmt.dxStartIndent = MY_INDENT;
637 add_string_resource_with_paraformat_to_control(text,
638 IDS_CERT_INFO_BAD_PURPOSES, &parFmt);
642 static CRYPT_OBJID_BLOB *find_policy_qualifier(CERT_POLICIES_INFO *policies,
643 LPCSTR policyOid)
645 CRYPT_OBJID_BLOB *ret = NULL;
646 DWORD i;
648 for (i = 0; !ret && i < policies->cPolicyInfo; i++)
650 DWORD j;
652 for (j = 0; !ret && j < policies->rgPolicyInfo[i].cPolicyQualifier; j++)
653 if (!strcmp(policies->rgPolicyInfo[i].rgPolicyQualifier[j].
654 pszPolicyQualifierId, policyOid))
655 ret = &policies->rgPolicyInfo[i].rgPolicyQualifier[j].
656 Qualifier;
658 return ret;
661 static WCHAR *get_cps_str_from_qualifier(CRYPT_OBJID_BLOB *qualifier)
663 LPWSTR qualifierStr = NULL;
664 CERT_NAME_VALUE *qualifierValue;
665 DWORD size;
667 if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME_VALUE,
668 qualifier->pbData, qualifier->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL,
669 &qualifierValue, &size))
671 size = CertRDNValueToStrW(qualifierValue->dwValueType,
672 &qualifierValue->Value, NULL, 0);
673 qualifierStr = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
674 if (qualifierStr)
675 CertRDNValueToStrW(qualifierValue->dwValueType,
676 &qualifierValue->Value, qualifierStr, size);
677 LocalFree(qualifierValue);
679 return qualifierStr;
682 static WCHAR *get_user_notice_from_qualifier(CRYPT_OBJID_BLOB *qualifier)
684 LPWSTR str = NULL;
685 CERT_POLICY_QUALIFIER_USER_NOTICE *qualifierValue;
686 DWORD size;
688 if (CryptDecodeObjectEx(X509_ASN_ENCODING,
689 X509_PKIX_POLICY_QUALIFIER_USERNOTICE,
690 qualifier->pbData, qualifier->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL,
691 &qualifierValue, &size))
693 str = HeapAlloc(GetProcessHeap(), 0,
694 (strlenW(qualifierValue->pszDisplayText) + 1) * sizeof(WCHAR));
695 if (str)
696 strcpyW(str, qualifierValue->pszDisplayText);
697 LocalFree(qualifierValue);
699 return str;
702 struct IssuerStatement
704 LPWSTR cps;
705 LPWSTR userNotice;
708 static void set_issuer_statement(HWND hwnd,
709 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
711 PCERT_EXTENSION policyExt;
713 if (!(pCertViewInfo->dwFlags & CRYPTUI_DISABLE_ISSUERSTATEMENT) &&
714 (policyExt = CertFindExtension(szOID_CERT_POLICIES,
715 pCertViewInfo->pCertContext->pCertInfo->cExtension,
716 pCertViewInfo->pCertContext->pCertInfo->rgExtension)))
718 CERT_POLICIES_INFO *policies;
719 DWORD size;
721 if (CryptDecodeObjectEx(X509_ASN_ENCODING, policyExt->pszObjId,
722 policyExt->Value.pbData, policyExt->Value.cbData,
723 CRYPT_DECODE_ALLOC_FLAG, NULL, &policies, &size))
725 CRYPT_OBJID_BLOB *qualifier;
726 LPWSTR cps = NULL, userNotice = NULL;
728 if ((qualifier = find_policy_qualifier(policies,
729 szOID_PKIX_POLICY_QUALIFIER_CPS)))
730 cps = get_cps_str_from_qualifier(qualifier);
731 if ((qualifier = find_policy_qualifier(policies,
732 szOID_PKIX_POLICY_QUALIFIER_USERNOTICE)))
733 userNotice = get_user_notice_from_qualifier(qualifier);
734 if (cps || userNotice)
736 struct IssuerStatement *issuerStatement =
737 HeapAlloc(GetProcessHeap(), 0, sizeof(struct IssuerStatement));
739 if (issuerStatement)
741 issuerStatement->cps = cps;
742 issuerStatement->userNotice = userNotice;
743 EnableWindow(GetDlgItem(hwnd, IDC_ISSUERSTATEMENT), TRUE);
744 SetWindowLongPtrW(hwnd, DWLP_USER,
745 (ULONG_PTR)issuerStatement);
748 LocalFree(policies);
753 static void set_cert_info(HWND hwnd,
754 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
756 CHARFORMATW charFmt;
757 PARAFORMAT2 parFmt;
758 HWND icon = GetDlgItem(hwnd, IDC_CERTIFICATE_ICON);
759 HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_INFO);
760 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
761 (CRYPT_PROVIDER_DATA *)pCertViewInfo->u.pCryptProviderData,
762 pCertViewInfo->idxSigner, pCertViewInfo->fCounterSigner,
763 pCertViewInfo->idxCounterSigner);
764 CRYPT_PROVIDER_CERT *root =
765 &provSigner->pasCertChain[provSigner->csCertChain - 1];
767 if (!provSigner->pChainContext ||
768 (provSigner->pChainContext->TrustStatus.dwErrorStatus &
769 CERT_TRUST_IS_PARTIAL_CHAIN))
770 add_icon_to_control(icon, IDB_CERT_WARNING);
771 else if (!root->fTrustedRoot)
772 add_icon_to_control(icon, IDB_CERT_ERROR);
773 else
774 add_icon_to_control(icon, IDB_CERT);
776 memset(&charFmt, 0, sizeof(charFmt));
777 charFmt.cbSize = sizeof(charFmt);
778 charFmt.dwMask = CFM_BOLD;
779 charFmt.dwEffects = CFE_BOLD;
780 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
781 /* FIXME: vertically center text */
782 parFmt.cbSize = sizeof(parFmt);
783 parFmt.dwMask = PFM_STARTINDENT;
784 parFmt.dxStartIndent = MY_INDENT;
785 add_string_resource_with_paraformat_to_control(text,
786 IDS_CERTIFICATEINFORMATION, &parFmt);
788 text = GetDlgItem(hwnd, IDC_CERTIFICATE_STATUS);
789 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
790 if (provSigner->dwError == TRUST_E_CERT_SIGNATURE)
791 add_string_resource_with_paraformat_to_control(text,
792 IDS_CERT_INFO_BAD_SIG, &parFmt);
793 else if (!provSigner->pChainContext ||
794 (provSigner->pChainContext->TrustStatus.dwErrorStatus &
795 CERT_TRUST_IS_PARTIAL_CHAIN))
796 add_string_resource_with_paraformat_to_control(text,
797 IDS_CERT_INFO_PARTIAL_CHAIN, &parFmt);
798 else if (!root->fTrustedRoot)
800 if (provSigner->csCertChain == 1 && root->fSelfSigned)
801 add_string_resource_with_paraformat_to_control(text,
802 IDS_CERT_INFO_UNTRUSTED_CA, &parFmt);
803 else
804 add_string_resource_with_paraformat_to_control(text,
805 IDS_CERT_INFO_UNTRUSTED_ROOT, &parFmt);
807 else
809 set_policy_text(text, pCertViewInfo);
810 set_issuer_statement(hwnd, pCertViewInfo);
814 static void set_cert_name_string(HWND hwnd, PCCERT_CONTEXT cert,
815 DWORD nameFlags, int heading)
817 WCHAR nl = '\n';
818 HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_NAMES);
819 CHARFORMATW charFmt;
820 PARAFORMAT2 parFmt;
822 memset(&charFmt, 0, sizeof(charFmt));
823 charFmt.cbSize = sizeof(charFmt);
824 charFmt.dwMask = CFM_BOLD;
825 charFmt.dwEffects = CFE_BOLD;
826 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
827 parFmt.cbSize = sizeof(parFmt);
828 parFmt.dwMask = PFM_STARTINDENT;
829 parFmt.dxStartIndent = MY_INDENT * 3;
830 add_string_resource_with_paraformat_to_control(text, heading, &parFmt);
831 charFmt.dwEffects = 0;
832 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
833 add_cert_string_to_control(text, cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
834 nameFlags);
835 add_unformatted_text_to_control(text, &nl, 1);
836 add_unformatted_text_to_control(text, &nl, 1);
837 add_unformatted_text_to_control(text, &nl, 1);
841 static void add_date_string_to_control(HWND hwnd, const FILETIME *fileTime)
843 WCHAR dateFmt[80]; /* sufficient for all versions of LOCALE_SSHORTDATE */
844 WCHAR date[80];
845 SYSTEMTIME sysTime;
847 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SSHORTDATE, dateFmt,
848 sizeof(dateFmt) / sizeof(dateFmt[0]));
849 FileTimeToSystemTime(fileTime, &sysTime);
850 GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, date,
851 sizeof(date) / sizeof(date[0]));
852 add_unformatted_text_to_control(hwnd, date, lstrlenW(date));
855 static void set_cert_validity_period(HWND hwnd, PCCERT_CONTEXT cert)
857 WCHAR nl = '\n';
858 HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_NAMES);
859 CHARFORMATW charFmt;
860 PARAFORMAT2 parFmt;
862 memset(&charFmt, 0, sizeof(charFmt));
863 charFmt.cbSize = sizeof(charFmt);
864 charFmt.dwMask = CFM_BOLD;
865 charFmt.dwEffects = CFE_BOLD;
866 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
867 parFmt.cbSize = sizeof(parFmt);
868 parFmt.dwMask = PFM_STARTINDENT;
869 parFmt.dxStartIndent = MY_INDENT * 3;
870 add_string_resource_with_paraformat_to_control(text, IDS_VALID_FROM,
871 &parFmt);
872 charFmt.dwEffects = 0;
873 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
874 add_date_string_to_control(text, &cert->pCertInfo->NotBefore);
875 charFmt.dwEffects = CFE_BOLD;
876 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
877 add_string_resource_to_control(text, IDS_VALID_TO);
878 charFmt.dwEffects = 0;
879 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
880 add_date_string_to_control(text, &cert->pCertInfo->NotAfter);
881 add_unformatted_text_to_control(text, &nl, 1);
884 static void set_general_info(HWND hwnd,
885 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
887 set_cert_info(hwnd, pCertViewInfo);
888 set_cert_name_string(hwnd, pCertViewInfo->pCertContext, 0,
889 IDS_SUBJECT_HEADING);
890 set_cert_name_string(hwnd, pCertViewInfo->pCertContext,
891 CERT_NAME_ISSUER_FLAG, IDS_ISSUER_HEADING);
892 set_cert_validity_period(hwnd, pCertViewInfo->pCertContext);
895 static LRESULT CALLBACK user_notice_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
896 LPARAM lp)
898 LRESULT ret = 0;
899 HWND text;
900 struct IssuerStatement *issuerStatement;
902 switch (msg)
904 case WM_INITDIALOG:
905 text = GetDlgItem(hwnd, IDC_USERNOTICE);
906 issuerStatement = (struct IssuerStatement *)lp;
907 add_unformatted_text_to_control(text, issuerStatement->userNotice,
908 strlenW(issuerStatement->userNotice));
909 if (issuerStatement->cps)
910 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)issuerStatement->cps);
911 else
912 EnableWindow(GetDlgItem(hwnd, IDC_CPS), FALSE);
913 break;
914 case WM_COMMAND:
915 switch (wp)
917 case IDOK:
918 EndDialog(hwnd, IDOK);
919 ret = TRUE;
920 break;
921 case IDC_CPS:
923 IBindCtx *bctx = NULL;
924 LPWSTR cps;
926 CreateBindCtx(0, &bctx);
927 cps = (LPWSTR)GetWindowLongPtrW(hwnd, DWLP_USER);
928 HlinkSimpleNavigateToString(cps, NULL, NULL, NULL, bctx, NULL,
929 HLNF_OPENINNEWWINDOW, 0);
930 IBindCtx_Release(bctx);
931 break;
935 return ret;
938 static void show_user_notice(HWND hwnd, struct IssuerStatement *issuerStatement)
940 DialogBoxParamW(hInstance, MAKEINTRESOURCEW(IDD_USERNOTICE), hwnd,
941 user_notice_dlg_proc, (LPARAM)issuerStatement);
944 static LRESULT CALLBACK general_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
945 LPARAM lp)
947 PROPSHEETPAGEW *page;
948 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo;
950 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
952 switch (msg)
954 case WM_INITDIALOG:
955 page = (PROPSHEETPAGEW *)lp;
956 pCertViewInfo = (PCCRYPTUI_VIEWCERTIFICATE_STRUCTW)page->lParam;
957 if (pCertViewInfo->dwFlags & CRYPTUI_DISABLE_ADDTOSTORE)
958 ShowWindow(GetDlgItem(hwnd, IDC_ADDTOSTORE), FALSE);
959 EnableWindow(GetDlgItem(hwnd, IDC_ISSUERSTATEMENT), FALSE);
960 set_general_info(hwnd, pCertViewInfo);
961 break;
962 case WM_COMMAND:
963 switch (wp)
965 case IDC_ADDTOSTORE:
966 FIXME("call CryptUIWizImport\n");
967 break;
968 case IDC_ISSUERSTATEMENT:
970 struct IssuerStatement *issuerStatement =
971 (struct IssuerStatement *)GetWindowLongPtrW(hwnd, DWLP_USER);
973 if (issuerStatement)
975 if (issuerStatement->userNotice)
976 show_user_notice(hwnd, issuerStatement);
977 else if (issuerStatement->cps)
979 IBindCtx *bctx = NULL;
981 CreateBindCtx(0, &bctx);
982 HlinkSimpleNavigateToString(issuerStatement->cps, NULL,
983 NULL, NULL, bctx, NULL, HLNF_OPENINNEWWINDOW, 0);
984 IBindCtx_Release(bctx);
987 break;
990 break;
992 return 0;
995 static UINT CALLBACK general_callback_proc(HWND hwnd, UINT msg,
996 PROPSHEETPAGEW *page)
998 struct IssuerStatement *issuerStatement;
1000 switch (msg)
1002 case PSPCB_RELEASE:
1003 issuerStatement =
1004 (struct IssuerStatement *)GetWindowLongPtrW(hwnd, DWLP_USER);
1005 if (issuerStatement)
1007 HeapFree(GetProcessHeap(), 0, issuerStatement->cps);
1008 HeapFree(GetProcessHeap(), 0, issuerStatement->userNotice);
1009 HeapFree(GetProcessHeap(), 0, issuerStatement);
1011 break;
1013 return 1;
1016 static void init_general_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
1017 PROPSHEETPAGEW *page)
1019 memset(page, 0, sizeof(PROPSHEETPAGEW));
1020 page->dwSize = sizeof(PROPSHEETPAGEW);
1021 page->dwFlags = PSP_USECALLBACK;
1022 page->pfnCallback = general_callback_proc;
1023 page->hInstance = hInstance;
1024 page->u.pszTemplate = MAKEINTRESOURCEW(IDD_GENERAL);
1025 page->pfnDlgProc = general_dlg_proc;
1026 page->lParam = (LPARAM)pCertViewInfo;
1029 typedef WCHAR * (*field_format_func)(PCCERT_CONTEXT cert);
1031 static WCHAR *field_format_version(PCCERT_CONTEXT cert)
1033 static const WCHAR fmt[] = { 'V','%','d',0 };
1034 WCHAR *buf = HeapAlloc(GetProcessHeap(), 0, 12 * sizeof(WCHAR));
1036 if (buf)
1037 sprintfW(buf, fmt, cert->pCertInfo->dwVersion);
1038 return buf;
1041 static WCHAR *format_hex_string(void *pb, DWORD cb)
1043 WCHAR *buf = HeapAlloc(GetProcessHeap(), 0, (cb * 3 + 1) * sizeof(WCHAR));
1045 if (buf)
1047 static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
1048 DWORD i;
1049 WCHAR *ptr;
1051 for (i = 0, ptr = buf; i < cb; i++, ptr += 3)
1052 sprintfW(ptr, fmt, ((BYTE *)pb)[i]);
1054 return buf;
1057 static WCHAR *field_format_serial_number(PCCERT_CONTEXT cert)
1059 return format_hex_string(cert->pCertInfo->SerialNumber.pbData,
1060 cert->pCertInfo->SerialNumber.cbData);
1063 static WCHAR *field_format_issuer(PCCERT_CONTEXT cert)
1065 return get_cert_name_string(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
1066 CERT_NAME_ISSUER_FLAG);
1069 static WCHAR *field_format_detailed_cert_name(PCERT_NAME_BLOB name)
1071 WCHAR *str = NULL;
1072 DWORD len = CertNameToStrW(X509_ASN_ENCODING, name,
1073 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, NULL, 0);
1075 if (len)
1077 str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1078 if (str)
1079 CertNameToStrW(X509_ASN_ENCODING, name,
1080 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, str, len);
1082 return str;
1085 static WCHAR *field_format_detailed_issuer(PCCERT_CONTEXT cert, void *param)
1087 return field_format_detailed_cert_name(&cert->pCertInfo->Issuer);
1090 static WCHAR *field_format_subject(PCCERT_CONTEXT cert)
1092 return get_cert_name_string(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0);
1095 static WCHAR *field_format_detailed_subject(PCCERT_CONTEXT cert, void *param)
1097 return field_format_detailed_cert_name(&cert->pCertInfo->Subject);
1100 static WCHAR *format_long_date(const FILETIME *fileTime)
1102 WCHAR dateFmt[80]; /* long enough for LOCALE_SLONGDATE */
1103 DWORD len;
1104 WCHAR *buf = NULL;
1105 SYSTEMTIME sysTime;
1107 /* FIXME: format isn't quite right, want time too */
1108 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SLONGDATE, dateFmt,
1109 sizeof(dateFmt) / sizeof(dateFmt[0]));
1110 FileTimeToSystemTime(fileTime, &sysTime);
1111 len = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, NULL, 0);
1112 if (len)
1114 buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1115 if (buf)
1116 GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, buf,
1117 len);
1119 return buf;
1122 static WCHAR *field_format_from_date(PCCERT_CONTEXT cert)
1124 return format_long_date(&cert->pCertInfo->NotBefore);
1127 static WCHAR *field_format_to_date(PCCERT_CONTEXT cert)
1129 return format_long_date(&cert->pCertInfo->NotAfter);
1132 static WCHAR *field_format_public_key(PCCERT_CONTEXT cert)
1134 PCCRYPT_OID_INFO oidInfo;
1135 WCHAR *buf = NULL;
1137 oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
1138 cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, 0);
1139 if (oidInfo)
1141 WCHAR fmt[MAX_STRING_LEN];
1143 if (LoadStringW(hInstance, IDS_FIELD_PUBLIC_KEY_FORMAT, fmt,
1144 sizeof(fmt) / sizeof(fmt[0])))
1146 /* Allocate the output buffer. Use the number of bytes in the
1147 * public key as a conservative (high) estimate for the number of
1148 * digits in its output.
1149 * The output is of the form (in English)
1150 * "<public key algorithm> (<public key bit length> bits)".
1151 * Ordinarily having two positional parameters in a string is not a
1152 * good idea, but as this isn't a sentence fragment, it shouldn't
1153 * be word-order dependent.
1155 buf = HeapAlloc(GetProcessHeap(), 0,
1156 (strlenW(fmt) + strlenW(oidInfo->pwszName) +
1157 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData * 8)
1158 * sizeof(WCHAR));
1159 if (buf)
1160 sprintfW(buf, fmt, oidInfo->pwszName,
1161 CertGetPublicKeyLength(X509_ASN_ENCODING,
1162 &cert->pCertInfo->SubjectPublicKeyInfo));
1165 return buf;
1168 static WCHAR *field_format_detailed_public_key(PCCERT_CONTEXT cert, void *param)
1170 return format_hex_string(
1171 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
1172 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData);
1175 struct field_value_data;
1176 struct detail_data
1178 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo;
1179 BOOL *pfPropertiesChanged;
1180 int cFields;
1181 struct field_value_data *fields;
1184 typedef void (*add_fields_func)(HWND hwnd, struct detail_data *data);
1186 typedef WCHAR *(*create_detailed_value_func)(PCCERT_CONTEXT cert, void *param);
1188 struct field_value_data
1190 create_detailed_value_func create;
1191 LPWSTR detailed_value;
1192 void *param;
1195 static void add_field_value_data(struct detail_data *data,
1196 create_detailed_value_func create, void *param)
1198 if (data->cFields)
1199 data->fields = HeapReAlloc(GetProcessHeap(), 0, data->fields,
1200 (data->cFields + 1) * sizeof(struct field_value_data));
1201 else
1202 data->fields = HeapAlloc(GetProcessHeap(), 0,
1203 sizeof(struct field_value_data));
1204 if (data->fields)
1206 data->fields[data->cFields].create = create;
1207 data->fields[data->cFields].detailed_value = NULL;
1208 data->fields[data->cFields].param = param;
1209 data->cFields++;
1213 static void add_field_and_value_to_list(HWND hwnd, struct detail_data *data,
1214 LPWSTR field, LPWSTR value, create_detailed_value_func create, void *param)
1216 LVITEMW item;
1217 int iItem = SendMessageW(hwnd, LVM_GETITEMCOUNT, 0, 0);
1219 item.mask = LVIF_TEXT | LVIF_PARAM;
1220 item.iItem = iItem;
1221 item.iSubItem = 0;
1222 item.pszText = field;
1223 item.lParam = (LPARAM)data;
1224 SendMessageW(hwnd, LVM_INSERTITEMW, 0, (LPARAM)&item);
1225 if (value)
1227 item.pszText = value;
1228 item.iSubItem = 1;
1229 SendMessageW(hwnd, LVM_SETITEMTEXTW, iItem, (LPARAM)&item);
1231 add_field_value_data(data, create, param);
1234 static void add_string_id_and_value_to_list(HWND hwnd, struct detail_data *data,
1235 int id, LPWSTR value, create_detailed_value_func create, void *param)
1237 WCHAR buf[MAX_STRING_LEN];
1239 LoadStringW(hInstance, id, buf, sizeof(buf) / sizeof(buf[0]));
1240 add_field_and_value_to_list(hwnd, data, buf, value, create, param);
1243 struct v1_field
1245 int id;
1246 field_format_func format;
1247 create_detailed_value_func create_detailed_value;
1250 static void add_v1_field(HWND hwnd, struct detail_data *data,
1251 const struct v1_field *field)
1253 WCHAR *val = field->format(data->pCertViewInfo->pCertContext);
1255 if (val)
1257 add_string_id_and_value_to_list(hwnd, data, field->id, val,
1258 field->create_detailed_value, NULL);
1259 HeapFree(GetProcessHeap(), 0, val);
1263 static const struct v1_field v1_fields[] = {
1264 { IDS_FIELD_VERSION, field_format_version, NULL },
1265 { IDS_FIELD_SERIAL_NUMBER, field_format_serial_number, NULL },
1266 { IDS_FIELD_ISSUER, field_format_issuer, field_format_detailed_issuer },
1267 { IDS_FIELD_VALID_FROM, field_format_from_date, NULL },
1268 { IDS_FIELD_VALID_TO, field_format_to_date, NULL },
1269 { IDS_FIELD_SUBJECT, field_format_subject, field_format_detailed_subject },
1270 { IDS_FIELD_PUBLIC_KEY, field_format_public_key,
1271 field_format_detailed_public_key }
1274 static void add_v1_fields(HWND hwnd, struct detail_data *data)
1276 int i;
1277 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
1279 /* The last item in v1_fields is the public key, which is not in the loop
1280 * because it's a special case.
1282 for (i = 0; i < sizeof(v1_fields) / sizeof(v1_fields[0]) - 1; i++)
1283 add_v1_field(hwnd, data, &v1_fields[i]);
1284 if (cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData)
1285 add_v1_field(hwnd, data, &v1_fields[i]);
1288 static WCHAR *crypt_format_extension(PCERT_EXTENSION ext, DWORD formatStrType)
1290 WCHAR *str = NULL;
1291 DWORD size;
1293 if (CryptFormatObject(X509_ASN_ENCODING, 0, formatStrType, NULL,
1294 ext->pszObjId, ext->Value.pbData, ext->Value.cbData, NULL, &size))
1296 str = HeapAlloc(GetProcessHeap(), 0, size);
1297 CryptFormatObject(X509_ASN_ENCODING, 0, formatStrType, NULL,
1298 ext->pszObjId, ext->Value.pbData, ext->Value.cbData, str, &size);
1300 return str;
1303 static WCHAR *field_format_extension_hex_with_ascii(PCERT_EXTENSION ext)
1305 WCHAR *str = NULL;
1307 if (ext->Value.cbData)
1309 /* The output is formatted as:
1310 * <hex bytes> <ascii bytes>\n
1311 * where <hex bytes> is a string of up to 8 bytes, output as %02x,
1312 * and <ascii bytes> is the ASCII equivalent of each byte, or '.' if
1313 * the byte is not printable.
1314 * So, for example, the extension value consisting of the following
1315 * bytes:
1316 * 0x30,0x14,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x03,
1317 * 0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67
1318 * is output as:
1319 * 30 14 31 12 30 10 06 03 0.1.0...
1320 * 55 04 03 13 09 4a 75 61 U....Jua
1321 * 6e 20 4c 61 6e 67 n Lang
1322 * The allocation size therefore requires:
1323 * - 4 characters per character in an 8-byte line
1324 * (2 for the hex format, one for the space, one for the ASCII value)
1325 * - 3 more characters per 8-byte line (two spaces and a newline)
1326 * - 1 character for the terminating nul
1327 * FIXME: should use a fixed-width font for this
1329 DWORD lines = (ext->Value.cbData + 7) / 8;
1331 str = HeapAlloc(GetProcessHeap(), 0,
1332 (lines * 8 * 4 + lines * 3 + 1) * sizeof(WCHAR));
1333 if (str)
1335 static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
1336 DWORD i, j;
1337 WCHAR *ptr;
1339 for (i = 0, ptr = str; i < ext->Value.cbData; i += 8)
1341 /* Output as hex bytes first */
1342 for (j = i; j < min(i + 8, ext->Value.cbData); j++, ptr += 3)
1343 sprintfW(ptr, fmt, ext->Value.pbData[j]);
1344 /* Pad the hex output with spaces for alignment */
1345 if (j == ext->Value.cbData && j % 8)
1347 static const WCHAR pad[] = { ' ',' ',' ' };
1349 for (; j % 8; j++, ptr += sizeof(pad) / sizeof(pad[0]))
1350 memcpy(ptr, pad, sizeof(pad));
1352 /* The last sprintfW included a space, so just insert one
1353 * more space between the hex bytes and the ASCII output
1355 *ptr++ = ' ';
1356 /* Output as ASCII bytes */
1357 for (j = i; j < min(i + 8, ext->Value.cbData); j++, ptr++)
1359 if (isprintW(ext->Value.pbData[j]) &&
1360 !isspaceW(ext->Value.pbData[j]))
1361 *ptr = ext->Value.pbData[j];
1362 else
1363 *ptr = '.';
1365 *ptr++ = '\n';
1367 *ptr++ = '\0';
1370 return str;
1373 static WCHAR *field_format_detailed_extension(PCCERT_CONTEXT cert, void *param)
1375 PCERT_EXTENSION ext = param;
1376 LPWSTR str = crypt_format_extension(ext,
1377 CRYPT_FORMAT_STR_MULTI_LINE | CRYPT_FORMAT_STR_NO_HEX);
1379 if (!str)
1380 str = field_format_extension_hex_with_ascii(ext);
1381 return str;
1384 static void add_cert_extension_detail(HWND hwnd, struct detail_data *data,
1385 PCERT_EXTENSION ext)
1387 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
1388 ext->pszObjId, 0);
1389 LPWSTR val = crypt_format_extension(ext, 0);
1391 if (oidInfo)
1392 add_field_and_value_to_list(hwnd, data, (LPWSTR)oidInfo->pwszName,
1393 val, field_format_detailed_extension, ext);
1394 else
1396 DWORD len = strlen(ext->pszObjId);
1397 LPWSTR oidW = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1399 if (oidW)
1401 DWORD i;
1403 for (i = 0; i <= len; i++)
1404 oidW[i] = ext->pszObjId[i];
1405 add_field_and_value_to_list(hwnd, data, oidW, val,
1406 field_format_detailed_extension, ext);
1407 HeapFree(GetProcessHeap(), 0, oidW);
1410 HeapFree(GetProcessHeap(), 0, val);
1413 static void add_all_extensions(HWND hwnd, struct detail_data *data)
1415 DWORD i;
1416 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
1418 for (i = 0; i < cert->pCertInfo->cExtension; i++)
1419 add_cert_extension_detail(hwnd, data, &cert->pCertInfo->rgExtension[i]);
1422 static void add_critical_extensions(HWND hwnd, struct detail_data *data)
1424 DWORD i;
1425 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
1427 for (i = 0; i < cert->pCertInfo->cExtension; i++)
1428 if (cert->pCertInfo->rgExtension[i].fCritical)
1429 add_cert_extension_detail(hwnd, data,
1430 &cert->pCertInfo->rgExtension[i]);
1433 typedef WCHAR * (*prop_to_value_func)(void *pb, DWORD cb);
1435 struct prop_id_to_string_id
1437 DWORD prop;
1438 int id;
1439 BOOL prop_is_string;
1440 prop_to_value_func prop_to_value;
1443 static WCHAR *format_enhanced_key_usage_value(void *pb, DWORD cb)
1445 CERT_EXTENSION ext;
1447 ext.pszObjId = (LPSTR)X509_ENHANCED_KEY_USAGE;
1448 ext.fCritical = FALSE;
1449 ext.Value.pbData = pb;
1450 ext.Value.cbData = cb;
1451 return crypt_format_extension(&ext, 0);
1454 /* Logically the access state should also be checked, and IDC_EDITPROPERTIES
1455 * disabled for read-only certificates, but native doesn't appear to do that.
1457 static const struct prop_id_to_string_id prop_id_map[] = {
1458 { CERT_HASH_PROP_ID, IDS_PROP_HASH, FALSE, format_hex_string },
1459 { CERT_FRIENDLY_NAME_PROP_ID, IDS_PROP_FRIENDLY_NAME, TRUE, NULL },
1460 { CERT_DESCRIPTION_PROP_ID, IDS_PROP_DESCRIPTION, TRUE, NULL },
1461 { CERT_ENHKEY_USAGE_PROP_ID, IDS_PROP_ENHKEY_USAGE, FALSE,
1462 format_enhanced_key_usage_value },
1465 static void add_properties(HWND hwnd, struct detail_data *data)
1467 DWORD i;
1468 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
1470 for (i = 0; i < sizeof(prop_id_map) / sizeof(prop_id_map[0]); i++)
1472 DWORD cb;
1474 if (CertGetCertificateContextProperty(cert, prop_id_map[i].prop, NULL,
1475 &cb))
1477 BYTE *pb;
1478 WCHAR *val = NULL;
1480 /* FIXME: MS adds a separate value for the signature hash
1481 * algorithm.
1483 pb = HeapAlloc(GetProcessHeap(), 0, cb);
1484 if (pb)
1486 if (CertGetCertificateContextProperty(cert,
1487 prop_id_map[i].prop, pb, &cb))
1489 if (prop_id_map[i].prop_is_string)
1491 val = (LPWSTR)pb;
1492 /* Don't double-free pb */
1493 pb = NULL;
1495 else
1496 val = prop_id_map[i].prop_to_value(pb, cb);
1498 HeapFree(GetProcessHeap(), 0, pb);
1500 add_string_id_and_value_to_list(hwnd, data, prop_id_map[i].id, val,
1501 NULL, NULL);
1506 static void add_all_fields(HWND hwnd, struct detail_data *data)
1508 add_v1_fields(hwnd, data);
1509 add_all_extensions(hwnd, data);
1510 add_properties(hwnd, data);
1513 struct selection_list_item
1515 int id;
1516 add_fields_func add;
1519 const struct selection_list_item listItems[] = {
1520 { IDS_FIELDS_ALL, add_all_fields },
1521 { IDS_FIELDS_V1, add_v1_fields },
1522 { IDS_FIELDS_EXTENSIONS, add_all_extensions },
1523 { IDS_FIELDS_CRITICAL_EXTENSIONS, add_critical_extensions },
1524 { IDS_FIELDS_PROPERTIES, add_properties },
1527 static void create_show_list(HWND hwnd, struct detail_data *data)
1529 HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT);
1530 WCHAR buf[MAX_STRING_LEN];
1531 int i;
1533 for (i = 0; i < sizeof(listItems) / sizeof(listItems[0]); i++)
1535 int index;
1537 LoadStringW(hInstance, listItems[i].id, buf,
1538 sizeof(buf) / sizeof(buf[0]));
1539 index = SendMessageW(cb, CB_INSERTSTRING, -1, (LPARAM)buf);
1540 SendMessageW(cb, CB_SETITEMDATA, index, (LPARAM)data);
1542 SendMessageW(cb, CB_SETCURSEL, 0, 0);
1545 static void create_listview_columns(HWND hwnd)
1547 HWND lv = GetDlgItem(hwnd, IDC_DETAIL_LIST);
1548 RECT rc;
1549 WCHAR buf[MAX_STRING_LEN];
1550 LVCOLUMNW column;
1552 SendMessageW(lv, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
1553 GetWindowRect(lv, &rc);
1554 LoadStringW(hInstance, IDS_FIELD, buf, sizeof(buf) / sizeof(buf[0]));
1555 column.mask = LVCF_WIDTH | LVCF_TEXT;
1556 column.cx = (rc.right - rc.left) / 2 - 2;
1557 column.pszText = buf;
1558 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
1559 LoadStringW(hInstance, IDS_VALUE, buf, sizeof(buf) / sizeof(buf[0]));
1560 SendMessageW(lv, LVM_INSERTCOLUMNW, 1, (LPARAM)&column);
1563 static void set_fields_selection(HWND hwnd, struct detail_data *data, int sel)
1565 HWND list = GetDlgItem(hwnd, IDC_DETAIL_LIST);
1567 if (sel >= 0 && sel < sizeof(listItems) / sizeof(listItems[0]))
1569 SendMessageW(list, LVM_DELETEALLITEMS, 0, 0);
1570 listItems[sel].add(list, data);
1574 static void create_cert_details_list(HWND hwnd, struct detail_data *data)
1576 create_show_list(hwnd, data);
1577 create_listview_columns(hwnd);
1578 set_fields_selection(hwnd, data, 0);
1581 typedef enum {
1582 CheckBitmapIndexUnchecked = 1,
1583 CheckBitmapIndexChecked = 2,
1584 CheckBitmapIndexDisabledUnchecked = 3,
1585 CheckBitmapIndexDisabledChecked = 4
1586 } CheckBitmapIndex;
1588 static void add_purpose(HWND hwnd, LPCSTR oid)
1590 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
1591 PCRYPT_OID_INFO info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1592 sizeof(CRYPT_OID_INFO));
1594 if (info)
1596 char *oidCopy = HeapAlloc(GetProcessHeap(), 0, strlen(oid) + 1);
1598 if (oidCopy)
1600 LVITEMA item;
1602 strcpy(oidCopy, oid);
1603 info->cbSize = sizeof(CRYPT_OID_INFO);
1604 info->pszOID = oidCopy;
1605 item.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM;
1606 item.state = INDEXTOSTATEIMAGEMASK(CheckBitmapIndexChecked);
1607 item.stateMask = LVIS_STATEIMAGEMASK;
1608 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
1609 item.iSubItem = 0;
1610 item.lParam = (LPARAM)info;
1611 item.pszText = oidCopy;
1612 SendMessageA(lv, LVM_INSERTITEMA, 0, (LPARAM)&item);
1614 else
1615 HeapFree(GetProcessHeap(), 0, info);
1619 static BOOL is_valid_oid(LPCSTR oid)
1621 BOOL ret;
1623 if (oid[0] != '0' && oid[0] != '1' && oid[0] != '2')
1624 ret = FALSE;
1625 else if (oid[1] != '.')
1626 ret = FALSE;
1627 else if (!oid[2])
1628 ret = FALSE;
1629 else
1631 const char *ptr;
1632 BOOL expectNum = TRUE;
1634 for (ptr = oid + 2, ret = TRUE; ret && *ptr; ptr++)
1636 if (expectNum)
1638 if (!isdigit(*ptr))
1639 ret = FALSE;
1640 else if (*(ptr + 1) == '.')
1641 expectNum = FALSE;
1643 else
1645 if (*ptr != '.')
1646 ret = FALSE;
1647 else if (!(*(ptr + 1)))
1648 ret = FALSE;
1649 else
1650 expectNum = TRUE;
1654 return ret;
1657 static BOOL is_oid_in_list(HWND hwnd, LPCSTR oid)
1659 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
1660 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
1661 (void *)oid, CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
1662 BOOL ret = FALSE;
1664 if (oidInfo)
1666 LVFINDINFOW findInfo;
1668 findInfo.flags = LVFI_PARAM;
1669 findInfo.lParam = (LPARAM)oidInfo;
1670 if (SendMessageW(lv, LVM_FINDITEMW, -1, (LPARAM)&findInfo) != -1)
1671 ret = TRUE;
1673 else
1675 LVFINDINFOA findInfo;
1677 findInfo.flags = LVFI_STRING;
1678 findInfo.psz = oid;
1679 if (SendMessageW(lv, LVM_FINDITEMA, -1, (LPARAM)&findInfo) != -1)
1680 ret = TRUE;
1682 return ret;
1685 #define MAX_PURPOSE 255
1687 static LRESULT CALLBACK add_purpose_dlg_proc(HWND hwnd, UINT msg,
1688 WPARAM wp, LPARAM lp)
1690 LRESULT ret = 0;
1691 char buf[MAX_PURPOSE + 1];
1693 switch (msg)
1695 case WM_INITDIALOG:
1696 SendMessageW(GetDlgItem(hwnd, IDC_NEW_PURPOSE), EM_SETLIMITTEXT,
1697 MAX_PURPOSE, 0);
1698 ShowScrollBar(GetDlgItem(hwnd, IDC_NEW_PURPOSE), SB_VERT, FALSE);
1699 SetWindowLongPtrW(hwnd, DWLP_USER, lp);
1700 break;
1701 case WM_COMMAND:
1702 switch (HIWORD(wp))
1704 case EN_CHANGE:
1705 if (LOWORD(wp) == IDC_NEW_PURPOSE)
1707 /* Show/hide scroll bar on description depending on how much
1708 * text it has.
1710 HWND description = GetDlgItem(hwnd, IDC_NEW_PURPOSE);
1711 int lines = SendMessageW(description, EM_GETLINECOUNT, 0, 0);
1713 ShowScrollBar(description, SB_VERT, lines > 1);
1715 break;
1716 case BN_CLICKED:
1717 switch (LOWORD(wp))
1719 case IDOK:
1720 SendMessageA(GetDlgItem(hwnd, IDC_NEW_PURPOSE), WM_GETTEXT,
1721 sizeof(buf) / sizeof(buf[0]), (LPARAM)buf);
1722 if (!buf[0])
1724 /* An empty purpose is the same as cancelling */
1725 EndDialog(hwnd, IDCANCEL);
1726 ret = TRUE;
1728 else if (!is_valid_oid(buf))
1730 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
1732 LoadStringW(hInstance, IDS_CERTIFICATE_PURPOSE_ERROR, error,
1733 sizeof(error) / sizeof(error[0]));
1734 LoadStringW(hInstance, IDS_CERTIFICATE_PROPERTIES, title,
1735 sizeof(title) / sizeof(title[0]));
1736 MessageBoxW(hwnd, error, title, MB_ICONERROR | MB_OK);
1738 else if (is_oid_in_list(
1739 (HWND)GetWindowLongPtrW(hwnd, DWLP_USER), buf))
1741 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN];
1743 LoadStringW(hInstance, IDS_CERTIFICATE_PURPOSE_EXISTS,
1744 error, sizeof(error) / sizeof(error[0]));
1745 LoadStringW(hInstance, IDS_CERTIFICATE_PROPERTIES, title,
1746 sizeof(title) / sizeof(title[0]));
1747 MessageBoxW(hwnd, error, title, MB_ICONEXCLAMATION | MB_OK);
1749 else
1751 HWND parent = (HWND)GetWindowLongPtrW(hwnd, DWLP_USER);
1753 add_purpose(parent, buf);
1754 EndDialog(hwnd, wp);
1755 ret = TRUE;
1757 break;
1758 case IDCANCEL:
1759 EndDialog(hwnd, wp);
1760 ret = TRUE;
1761 break;
1763 break;
1765 break;
1767 return ret;
1770 static WCHAR *get_cert_property_as_string(PCCERT_CONTEXT cert, DWORD prop)
1772 WCHAR *name = NULL;
1773 DWORD cb;
1775 if (CertGetCertificateContextProperty(cert, prop, NULL, &cb))
1777 name = HeapAlloc(GetProcessHeap(), 0, cb);
1778 if (name)
1780 if (!CertGetCertificateContextProperty(cert, prop, (LPBYTE)name,
1781 &cb))
1783 HeapFree(GetProcessHeap(), 0, name);
1784 name = NULL;
1788 return name;
1791 static void redraw_states(HWND list, BOOL enabled)
1793 int items = SendMessageW(list, LVM_GETITEMCOUNT, 0, 0), i;
1795 for (i = 0; i < items; i++)
1797 BOOL change = FALSE;
1798 int state;
1800 state = SendMessageW(list, LVM_GETITEMSTATE, i, LVIS_STATEIMAGEMASK);
1801 /* This reverses the INDEXTOSTATEIMAGEMASK shift. There doesn't appear
1802 * to be a handy macro for it.
1804 state >>= 12;
1805 if (enabled)
1807 if (state == CheckBitmapIndexDisabledChecked)
1809 state = CheckBitmapIndexChecked;
1810 change = TRUE;
1812 if (state == CheckBitmapIndexDisabledUnchecked)
1814 state = CheckBitmapIndexUnchecked;
1815 change = TRUE;
1818 else
1820 if (state == CheckBitmapIndexChecked)
1822 state = CheckBitmapIndexDisabledChecked;
1823 change = TRUE;
1825 if (state == CheckBitmapIndexUnchecked)
1827 state = CheckBitmapIndexDisabledUnchecked;
1828 change = TRUE;
1831 if (change)
1833 LVITEMW item;
1835 item.state = INDEXTOSTATEIMAGEMASK(state);
1836 item.stateMask = LVIS_STATEIMAGEMASK;
1837 SendMessageW(list, LVM_SETITEMSTATE, i, (LPARAM)&item);
1842 typedef enum {
1843 PurposeEnableAll = 0,
1844 PurposeDisableAll,
1845 PurposeEnableSelected
1846 } PurposeSelection;
1848 static void select_purposes(HWND hwnd, PurposeSelection selection)
1850 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
1852 switch (selection)
1854 case PurposeEnableAll:
1855 case PurposeDisableAll:
1856 EnableWindow(lv, FALSE);
1857 redraw_states(lv, FALSE);
1858 EnableWindow(GetDlgItem(hwnd, IDC_ADD_PURPOSE), FALSE);
1859 break;
1860 case PurposeEnableSelected:
1861 EnableWindow(lv, TRUE);
1862 redraw_states(lv, TRUE);
1863 EnableWindow(GetDlgItem(hwnd, IDC_ADD_PURPOSE), TRUE);
1867 extern BOOL WINAPI WTHelperGetKnownUsages(DWORD action,
1868 PCCRYPT_OID_INFO **usages);
1870 static void add_known_usage(HWND lv, PCCRYPT_OID_INFO info)
1872 LVITEMW item;
1874 item.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM;
1875 item.state = INDEXTOSTATEIMAGEMASK(CheckBitmapIndexDisabledChecked);
1876 item.stateMask = LVIS_STATEIMAGEMASK;
1877 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
1878 item.iSubItem = 0;
1879 item.lParam = (LPARAM)info;
1880 item.pszText = (LPWSTR)info->pwszName;
1881 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
1884 struct edit_cert_data
1886 PCCERT_CONTEXT cert;
1887 BOOL *pfPropertiesChanged;
1888 HIMAGELIST imageList;
1891 static void show_cert_usages(HWND hwnd, struct edit_cert_data *data)
1893 PCCERT_CONTEXT cert = data->cert;
1894 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
1895 PCERT_ENHKEY_USAGE usage;
1896 DWORD size;
1897 PCCRYPT_OID_INFO *usages;
1898 RECT rc;
1899 LVCOLUMNW column;
1900 PurposeSelection purposeSelection;
1902 GetWindowRect(lv, &rc);
1903 column.mask = LVCF_WIDTH;
1904 column.cx = rc.right - rc.left;
1905 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
1906 SendMessageW(lv, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)data->imageList);
1908 /* Get enhanced key usage. Have to check for a property and an extension
1909 * separately, because CertGetEnhancedKeyUsage will succeed and return an
1910 * empty usage if neither is set. Unfortunately an empty usage implies
1911 * no usage is allowed, so we have to distinguish between the two cases.
1913 if (CertGetEnhancedKeyUsage(cert, CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG,
1914 NULL, &size))
1916 usage = HeapAlloc(GetProcessHeap(), 0, size);
1917 if (!CertGetEnhancedKeyUsage(cert,
1918 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size))
1920 HeapFree(GetProcessHeap(), 0, usage);
1921 usage = NULL;
1923 else if (usage->cUsageIdentifier)
1924 purposeSelection = PurposeEnableSelected;
1925 else
1926 purposeSelection = PurposeDisableAll;
1928 else if (CertGetEnhancedKeyUsage(cert, CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
1929 NULL, &size))
1931 usage = HeapAlloc(GetProcessHeap(), 0, size);
1932 if (!CertGetEnhancedKeyUsage(cert,
1933 CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, usage, &size))
1935 HeapFree(GetProcessHeap(), 0, usage);
1936 usage = NULL;
1938 else if (usage->cUsageIdentifier)
1939 purposeSelection = PurposeEnableAll;
1940 else
1941 purposeSelection = PurposeDisableAll;
1943 else
1945 purposeSelection = PurposeEnableAll;
1946 usage = NULL;
1948 if (usage)
1950 DWORD i;
1952 for (i = 0; i < usage->cUsageIdentifier; i++)
1954 PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
1955 usage->rgpszUsageIdentifier[i], CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
1957 if (info)
1958 add_known_usage(lv, info);
1959 else
1960 add_purpose(hwnd, usage->rgpszUsageIdentifier[i]);
1962 HeapFree(GetProcessHeap(), 0, usage);
1964 else
1966 if (WTHelperGetKnownUsages(1, &usages))
1968 PCCRYPT_OID_INFO *ptr;
1970 for (ptr = usages; *ptr; ptr++)
1971 add_known_usage(lv, *ptr);
1972 WTHelperGetKnownUsages(2, &usages);
1975 select_purposes(hwnd, purposeSelection);
1976 SendMessageW(GetDlgItem(hwnd, IDC_ENABLE_ALL_PURPOSES + purposeSelection),
1977 BM_CLICK, 0, 0);
1980 static void set_general_cert_properties(HWND hwnd, struct edit_cert_data *data)
1982 PCCERT_CONTEXT cert = data->cert;
1983 WCHAR *str;
1985 if ((str = get_cert_property_as_string(cert, CERT_FRIENDLY_NAME_PROP_ID)))
1987 SendMessageW(GetDlgItem(hwnd, IDC_FRIENDLY_NAME), WM_SETTEXT, 0,
1988 (LPARAM)str);
1989 HeapFree(GetProcessHeap(), 0, str);
1991 if ((str = get_cert_property_as_string(cert, CERT_DESCRIPTION_PROP_ID)))
1993 SendMessageW(GetDlgItem(hwnd, IDC_DESCRIPTION), WM_SETTEXT, 0,
1994 (LPARAM)str);
1995 HeapFree(GetProcessHeap(), 0, str);
1997 show_cert_usages(hwnd, data);
2000 static void toggle_usage(HWND hwnd, int iItem)
2002 LVITEMW item;
2003 int res;
2004 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
2006 item.mask = LVIF_STATE;
2007 item.iItem = iItem;
2008 item.iSubItem = 0;
2009 item.stateMask = LVIS_STATEIMAGEMASK;
2010 res = SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item);
2011 if (res)
2013 int state = item.state >> 12;
2015 item.state = INDEXTOSTATEIMAGEMASK(
2016 state == CheckBitmapIndexChecked ? CheckBitmapIndexUnchecked :
2017 CheckBitmapIndexChecked);
2018 SendMessageW(lv, LVM_SETITEMSTATE, iItem, (LPARAM)&item);
2022 static void set_cert_string_property(PCCERT_CONTEXT cert, DWORD prop,
2023 LPWSTR str)
2025 if (str && strlenW(str))
2027 CRYPT_DATA_BLOB blob;
2029 blob.pbData = (BYTE *)str;
2030 blob.cbData = (strlenW(str) + 1) * sizeof(WCHAR);
2031 CertSetCertificateContextProperty(cert, prop, 0, &blob);
2033 else
2034 CertSetCertificateContextProperty(cert, prop, 0, NULL);
2037 #define WM_REFRESH_VIEW WM_USER + 0
2039 static BOOL CALLBACK refresh_propsheet_pages(HWND hwnd, LPARAM lParam)
2041 if ((GetClassLongW(hwnd, GCW_ATOM) == WC_DIALOG))
2042 SendMessageW(hwnd, WM_REFRESH_VIEW, 0, 0);
2043 return TRUE;
2046 #define MAX_FRIENDLY_NAME 40
2047 #define MAX_DESCRIPTION 255
2049 static void apply_general_changes(HWND hwnd)
2051 WCHAR buf[MAX_DESCRIPTION + 1];
2052 struct edit_cert_data *data =
2053 (struct edit_cert_data *)GetWindowLongPtrW(hwnd, DWLP_USER);
2055 SendMessageW(GetDlgItem(hwnd, IDC_FRIENDLY_NAME), WM_GETTEXT,
2056 sizeof(buf) / sizeof(buf[0]), (LPARAM)buf);
2057 set_cert_string_property(data->cert, CERT_FRIENDLY_NAME_PROP_ID, buf);
2058 SendMessageW(GetDlgItem(hwnd, IDC_DESCRIPTION), WM_GETTEXT,
2059 sizeof(buf) / sizeof(buf[0]), (LPARAM)buf);
2060 set_cert_string_property(data->cert, CERT_DESCRIPTION_PROP_ID, buf);
2061 if (IsDlgButtonChecked(hwnd, IDC_ENABLE_ALL_PURPOSES))
2063 /* Setting a NULL usage removes the enhanced key usage property. */
2064 CertSetEnhancedKeyUsage(data->cert, NULL);
2066 else if (IsDlgButtonChecked(hwnd, IDC_DISABLE_ALL_PURPOSES))
2068 CERT_ENHKEY_USAGE usage = { 0, NULL };
2070 CertSetEnhancedKeyUsage(data->cert, &usage);
2072 else if (IsDlgButtonChecked(hwnd, IDC_ENABLE_SELECTED_PURPOSES))
2074 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
2075 CERT_ENHKEY_USAGE usage = { 0, NULL };
2076 int purposes = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0), i;
2077 LVITEMW item;
2079 item.mask = LVIF_STATE | LVIF_PARAM;
2080 item.iSubItem = 0;
2081 item.stateMask = LVIS_STATEIMAGEMASK;
2082 for (i = 0; i < purposes; i++)
2084 item.iItem = i;
2085 if (SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item))
2087 int state = item.state >> 12;
2089 if (state == CheckBitmapIndexChecked)
2091 CRYPT_OID_INFO *info = (CRYPT_OID_INFO *)item.lParam;
2093 if (usage.cUsageIdentifier)
2094 usage.rgpszUsageIdentifier =
2095 HeapReAlloc(GetProcessHeap(), 0,
2096 usage.rgpszUsageIdentifier,
2097 (usage.cUsageIdentifier + 1) * sizeof(LPSTR));
2098 else
2099 usage.rgpszUsageIdentifier =
2100 HeapAlloc(GetProcessHeap(), 0, sizeof(LPSTR));
2101 if (usage.rgpszUsageIdentifier)
2102 usage.rgpszUsageIdentifier[usage.cUsageIdentifier++] =
2103 (LPSTR)info->pszOID;
2107 CertSetEnhancedKeyUsage(data->cert, &usage);
2108 HeapFree(GetProcessHeap(), 0, usage.rgpszUsageIdentifier);
2110 EnumChildWindows(GetParent(GetParent(hwnd)), refresh_propsheet_pages, 0);
2111 if (data->pfPropertiesChanged)
2112 *data->pfPropertiesChanged = TRUE;
2115 static LRESULT CALLBACK cert_properties_general_dlg_proc(HWND hwnd, UINT msg,
2116 WPARAM wp, LPARAM lp)
2118 PROPSHEETPAGEW *page;
2120 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
2122 switch (msg)
2124 case WM_INITDIALOG:
2126 HWND description = GetDlgItem(hwnd, IDC_DESCRIPTION);
2127 struct detail_data *detailData;
2128 struct edit_cert_data *editData;
2130 page = (PROPSHEETPAGEW *)lp;
2131 detailData = (struct detail_data *)page->lParam;
2132 SendMessageW(GetDlgItem(hwnd, IDC_FRIENDLY_NAME), EM_SETLIMITTEXT,
2133 MAX_FRIENDLY_NAME, 0);
2134 SendMessageW(description, EM_SETLIMITTEXT, MAX_DESCRIPTION, 0);
2135 ShowScrollBar(description, SB_VERT, FALSE);
2136 editData = HeapAlloc(GetProcessHeap(), 0,
2137 sizeof(struct edit_cert_data));
2138 if (editData)
2140 editData->imageList = ImageList_Create(16, 16,
2141 ILC_COLOR4 | ILC_MASK, 4, 0);
2142 if (editData->imageList)
2144 HBITMAP bmp;
2145 COLORREF backColor = RGB(255, 0, 255);
2147 bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_CHECKS));
2148 ImageList_AddMasked(editData->imageList, bmp, backColor);
2149 DeleteObject(bmp);
2150 ImageList_SetBkColor(editData->imageList, CLR_NONE);
2152 editData->cert = detailData->pCertViewInfo->pCertContext;
2153 editData->pfPropertiesChanged = detailData->pfPropertiesChanged;
2154 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)editData);
2155 set_general_cert_properties(hwnd, editData);
2157 break;
2159 case WM_NOTIFY:
2161 NMHDR *hdr = (NMHDR *)lp;
2162 NMITEMACTIVATE *nm;
2164 switch (hdr->code)
2166 case NM_CLICK:
2167 nm = (NMITEMACTIVATE *)lp;
2168 toggle_usage(hwnd, nm->iItem);
2169 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
2170 break;
2171 case PSN_APPLY:
2172 apply_general_changes(hwnd);
2173 break;
2175 break;
2177 case WM_COMMAND:
2178 switch (HIWORD(wp))
2180 case EN_CHANGE:
2181 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
2182 if (LOWORD(wp) == IDC_DESCRIPTION)
2184 /* Show/hide scroll bar on description depending on how much
2185 * text it has.
2187 HWND description = GetDlgItem(hwnd, IDC_DESCRIPTION);
2188 int lines = SendMessageW(description, EM_GETLINECOUNT, 0, 0);
2190 ShowScrollBar(description, SB_VERT, lines > 1);
2192 break;
2193 case BN_CLICKED:
2194 switch (LOWORD(wp))
2196 case IDC_ADD_PURPOSE:
2197 if (DialogBoxParamW(hInstance,
2198 MAKEINTRESOURCEW(IDD_ADD_CERT_PURPOSE), hwnd,
2199 add_purpose_dlg_proc, (LPARAM)hwnd) == IDOK)
2200 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
2201 break;
2202 case IDC_ENABLE_ALL_PURPOSES:
2203 case IDC_DISABLE_ALL_PURPOSES:
2204 case IDC_ENABLE_SELECTED_PURPOSES:
2205 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
2206 select_purposes(hwnd, LOWORD(wp) - IDC_ENABLE_ALL_PURPOSES);
2207 break;
2209 break;
2211 break;
2213 return 0;
2216 static UINT CALLBACK cert_properties_general_callback(HWND hwnd, UINT msg,
2217 PROPSHEETPAGEW *page)
2219 HWND lv;
2220 int cItem, i;
2221 struct edit_cert_data *data;
2223 switch (msg)
2225 case PSPCB_RELEASE:
2226 lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
2227 cItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
2228 for (i = 0; i < cItem; i++)
2230 LVITEMW item;
2232 item.mask = LVIF_PARAM;
2233 item.iItem = i;
2234 item.iSubItem = 0;
2235 if (SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item) && item.lParam)
2237 PCRYPT_OID_INFO info = (PCRYPT_OID_INFO)item.lParam;
2239 if (info->cbSize == sizeof(CRYPT_OID_INFO) && !info->dwGroupId)
2241 HeapFree(GetProcessHeap(), 0, (LPSTR)info->pszOID);
2242 HeapFree(GetProcessHeap(), 0, info);
2246 data = (struct edit_cert_data *)GetWindowLongPtrW(hwnd, DWLP_USER);
2247 if (data)
2249 ImageList_Destroy(data->imageList);
2250 HeapFree(GetProcessHeap(), 0, data);
2252 break;
2254 return 1;
2257 static void show_edit_cert_properties_dialog(HWND parent,
2258 struct detail_data *data)
2260 PROPSHEETHEADERW hdr;
2261 PROPSHEETPAGEW page; /* FIXME: need to add a cross-certificate page */
2263 TRACE("(%p)\n", data);
2265 memset(&page, 0, sizeof(PROPSHEETPAGEW));
2266 page.dwSize = sizeof(page);
2267 page.dwFlags = PSP_USECALLBACK;
2268 page.pfnCallback = cert_properties_general_callback;
2269 page.hInstance = hInstance;
2270 page.u.pszTemplate = MAKEINTRESOURCEW(IDD_CERT_PROPERTIES_GENERAL);
2271 page.pfnDlgProc = cert_properties_general_dlg_proc;
2272 page.lParam = (LPARAM)data;
2274 memset(&hdr, 0, sizeof(hdr));
2275 hdr.dwSize = sizeof(hdr);
2276 hdr.hwndParent = parent;
2277 hdr.dwFlags = PSH_PROPSHEETPAGE;
2278 hdr.hInstance = hInstance;
2279 hdr.pszCaption = MAKEINTRESOURCEW(IDS_CERTIFICATE_PROPERTIES);
2280 hdr.u3.ppsp = &page;
2281 hdr.nPages = 1;
2282 PropertySheetW(&hdr);
2285 static void free_detail_fields(struct detail_data *data)
2287 DWORD i;
2289 for (i = 0; i < data->cFields; i++)
2290 HeapFree(GetProcessHeap(), 0, data->fields[i].detailed_value);
2291 HeapFree(GetProcessHeap(), 0, data->fields);
2292 data->fields = NULL;
2293 data->cFields = 0;
2296 static void refresh_details_view(HWND hwnd)
2298 HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT);
2299 int curSel;
2300 struct detail_data *data;
2302 curSel = SendMessageW(cb, CB_GETCURSEL, 0, 0);
2303 /* Actually, any index will do, since they all store the same data value */
2304 data = (struct detail_data *)SendMessageW(cb, CB_GETITEMDATA, curSel, 0);
2305 free_detail_fields(data);
2306 set_fields_selection(hwnd, data, curSel);
2309 static LRESULT CALLBACK detail_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
2310 LPARAM lp)
2312 PROPSHEETPAGEW *page;
2313 struct detail_data *data;
2315 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
2317 switch (msg)
2319 case WM_INITDIALOG:
2320 page = (PROPSHEETPAGEW *)lp;
2321 data = (struct detail_data *)page->lParam;
2322 create_cert_details_list(hwnd, data);
2323 if (!(data->pCertViewInfo->dwFlags & CRYPTUI_ENABLE_EDITPROPERTIES))
2324 EnableWindow(GetDlgItem(hwnd, IDC_EDITPROPERTIES), FALSE);
2325 if (data->pCertViewInfo->dwFlags & CRYPTUI_DISABLE_EXPORT)
2326 EnableWindow(GetDlgItem(hwnd, IDC_EXPORT), FALSE);
2327 break;
2328 case WM_NOTIFY:
2330 NMITEMACTIVATE *nm;
2331 HWND list = GetDlgItem(hwnd, IDC_DETAIL_LIST);
2333 nm = (NMITEMACTIVATE*)lp;
2334 if (nm->hdr.hwndFrom == list && nm->uNewState & LVN_ITEMACTIVATE
2335 && nm->hdr.code == LVN_ITEMCHANGED)
2337 data = (struct detail_data *)nm->lParam;
2338 if (nm->iItem >= 0 && data && nm->iItem < data->cFields)
2340 WCHAR buf[MAX_STRING_LEN], *val = NULL;
2341 HWND valueCtl = GetDlgItem(hwnd, IDC_DETAIL_VALUE);
2343 if (data->fields[nm->iItem].create)
2344 val = data->fields[nm->iItem].create(
2345 data->pCertViewInfo->pCertContext,
2346 data->fields[nm->iItem].param);
2347 else
2349 LVITEMW item;
2350 int res;
2352 item.cchTextMax = sizeof(buf) / sizeof(buf[0]);
2353 item.mask = LVIF_TEXT;
2354 item.pszText = buf;
2355 item.iItem = nm->iItem;
2356 item.iSubItem = 1;
2357 res = SendMessageW(list, LVM_GETITEMW, 0, (LPARAM)&item);
2358 if (res)
2359 val = buf;
2361 /* Select all the text in the control, the next update will
2362 * replace it
2364 SendMessageW(valueCtl, EM_SETSEL, 0, -1);
2365 add_unformatted_text_to_control(valueCtl, val,
2366 val ? strlenW(val) : 0);
2367 if (val != buf)
2368 HeapFree(GetProcessHeap(), 0, val);
2371 break;
2373 case WM_COMMAND:
2374 switch (wp)
2376 case IDC_EXPORT:
2377 FIXME("call CryptUIWizExport\n");
2378 break;
2379 case IDC_EDITPROPERTIES:
2381 HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT);
2382 int curSel;
2384 curSel = SendMessageW(cb, CB_GETCURSEL, 0, 0);
2385 /* Actually, any index will do, since they all store the same
2386 * data value
2388 data = (struct detail_data *)SendMessageW(cb, CB_GETITEMDATA,
2389 curSel, 0);
2390 show_edit_cert_properties_dialog(GetParent(hwnd), data);
2391 break;
2393 case ((CBN_SELCHANGE << 16) | IDC_DETAIL_SELECT):
2394 refresh_details_view(hwnd);
2395 break;
2397 break;
2398 case WM_REFRESH_VIEW:
2399 refresh_details_view(hwnd);
2400 break;
2402 return 0;
2405 static UINT CALLBACK detail_callback(HWND hwnd, UINT msg,
2406 PROPSHEETPAGEW *page)
2408 struct detail_data *data;
2410 switch (msg)
2412 case PSPCB_RELEASE:
2413 data = (struct detail_data *)page->lParam;
2414 free_detail_fields(data);
2415 HeapFree(GetProcessHeap(), 0, data);
2416 break;
2418 return 0;
2421 static BOOL init_detail_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
2422 BOOL *pfPropertiesChanged, PROPSHEETPAGEW *page)
2424 BOOL ret;
2425 struct detail_data *data = HeapAlloc(GetProcessHeap(), 0,
2426 sizeof(struct detail_data));
2428 if (data)
2430 data->pCertViewInfo = pCertViewInfo;
2431 data->pfPropertiesChanged = pfPropertiesChanged;
2432 data->cFields = 0;
2433 data->fields = NULL;
2434 memset(page, 0, sizeof(PROPSHEETPAGEW));
2435 page->dwSize = sizeof(PROPSHEETPAGEW);
2436 page->dwFlags = PSP_USECALLBACK;
2437 page->pfnCallback = detail_callback;
2438 page->hInstance = hInstance;
2439 page->u.pszTemplate = MAKEINTRESOURCEW(IDD_DETAIL);
2440 page->pfnDlgProc = detail_dlg_proc;
2441 page->lParam = (LPARAM)data;
2442 ret = TRUE;
2444 else
2445 ret = FALSE;
2446 return ret;
2449 struct hierarchy_data
2451 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo;
2452 HIMAGELIST imageList;
2453 DWORD selectedCert;
2456 static LPARAM index_to_lparam(struct hierarchy_data *data, DWORD index)
2458 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
2459 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData,
2460 data->pCertViewInfo->idxSigner, data->pCertViewInfo->fCounterSigner,
2461 data->pCertViewInfo->idxCounterSigner);
2463 /* Takes advantage of the fact that a pointer is 32-bit aligned, and
2464 * therefore always even.
2466 if (index == provSigner->csCertChain - 1)
2467 return (LPARAM)data;
2468 return index << 1 | 1;
2471 static inline DWORD lparam_to_index(struct hierarchy_data *data, LPARAM lp)
2473 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
2474 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData,
2475 data->pCertViewInfo->idxSigner, data->pCertViewInfo->fCounterSigner,
2476 data->pCertViewInfo->idxCounterSigner);
2478 if (!(lp & 1))
2479 return provSigner->csCertChain - 1;
2480 return lp >> 1;
2483 static struct hierarchy_data *get_hierarchy_data_from_tree_item(HWND tree,
2484 HTREEITEM hItem)
2486 struct hierarchy_data *data = NULL;
2487 HTREEITEM root = NULL;
2489 do {
2490 HTREEITEM parent = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM,
2491 TVGN_PARENT, (LPARAM)hItem);
2493 if (!parent)
2494 root = hItem;
2495 hItem = parent;
2496 } while (hItem);
2497 if (root)
2499 TVITEMW item;
2501 item.mask = TVIF_PARAM;
2502 item.hItem = root;
2503 SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item);
2504 data = (struct hierarchy_data *)item.lParam;
2506 return data;
2509 static WCHAR *get_cert_display_name(PCCERT_CONTEXT cert)
2511 WCHAR *name = get_cert_property_as_string(cert, CERT_FRIENDLY_NAME_PROP_ID);
2513 if (!name)
2514 name = get_cert_name_string(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0);
2515 return name;
2518 static void show_cert_chain(HWND hwnd, struct hierarchy_data *data)
2520 HWND tree = GetDlgItem(hwnd, IDC_CERTPATH);
2521 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
2522 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData,
2523 data->pCertViewInfo->idxSigner, data->pCertViewInfo->fCounterSigner,
2524 data->pCertViewInfo->idxCounterSigner);
2525 DWORD i;
2526 HTREEITEM parent = NULL;
2528 SendMessageW(tree, TVM_SETIMAGELIST, TVSIL_NORMAL, (LPARAM)data->imageList);
2529 for (i = provSigner->csCertChain; i; i--)
2531 LPWSTR name;
2533 name = get_cert_display_name(provSigner->pasCertChain[i - 1].pCert);
2534 if (name)
2536 TVINSERTSTRUCTW tvis;
2538 tvis.hParent = parent;
2539 tvis.hInsertAfter = TVI_LAST;
2540 tvis.u.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_IMAGE |
2541 TVIF_SELECTEDIMAGE | TVIF_PARAM;
2542 tvis.u.item.pszText = name;
2543 tvis.u.item.state = TVIS_EXPANDED;
2544 tvis.u.item.stateMask = TVIS_EXPANDED;
2545 if (i == 1 &&
2546 (provSigner->pChainContext->TrustStatus.dwErrorStatus &
2547 CERT_TRUST_IS_PARTIAL_CHAIN))
2549 /* The root of the chain has a special case: if the chain is
2550 * a partial chain, the icon is a warning icon rather than an
2551 * error icon.
2553 tvis.u.item.iImage = 2;
2555 else if (provSigner->pasCertChain[i - 1].pChainElement->TrustStatus.
2556 dwErrorStatus == 0)
2557 tvis.u.item.iImage = 0;
2558 else
2559 tvis.u.item.iImage = 1;
2560 tvis.u.item.iSelectedImage = tvis.u.item.iImage;
2561 tvis.u.item.lParam = index_to_lparam(data, i - 1);
2562 parent = (HTREEITEM)SendMessageW(tree, TVM_INSERTITEMW, 0,
2563 (LPARAM)&tvis);
2564 HeapFree(GetProcessHeap(), 0, name);
2569 static void set_certificate_status(HWND hwnd, CRYPT_PROVIDER_CERT *cert)
2571 /* Select all the text in the control, the next update will replace it */
2572 SendMessageW(hwnd, EM_SETSEL, 0, -1);
2573 /* Set the highest priority error messages first. */
2574 if (!(cert->dwConfidence & CERT_CONFIDENCE_SIG))
2575 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_BAD_SIGNATURE);
2576 else if (!(cert->dwConfidence & CERT_CONFIDENCE_TIME))
2577 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_BAD_TIME);
2578 else if (!(cert->dwConfidence & CERT_CONFIDENCE_TIMENEST))
2579 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_BAD_TIMENEST);
2580 else if (cert->dwRevokedReason)
2581 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_REVOKED);
2582 else
2583 add_string_resource_to_control(hwnd, IDS_CERTIFICATE_VALID);
2586 static void set_certificate_status_for_end_cert(HWND hwnd,
2587 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
2589 HWND status = GetDlgItem(hwnd, IDC_CERTIFICATESTATUSTEXT);
2590 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
2591 (CRYPT_PROVIDER_DATA *)pCertViewInfo->u.pCryptProviderData,
2592 pCertViewInfo->idxSigner, pCertViewInfo->fCounterSigner,
2593 pCertViewInfo->idxCounterSigner);
2594 CRYPT_PROVIDER_CERT *provCert = WTHelperGetProvCertFromChain(provSigner,
2595 pCertViewInfo->idxCert);
2597 set_certificate_status(status, provCert);
2600 static void show_cert_hierarchy(HWND hwnd, struct hierarchy_data *data)
2602 /* Disable view certificate button until a certificate is selected */
2603 EnableWindow(GetDlgItem(hwnd, IDC_VIEWCERTIFICATE), FALSE);
2604 show_cert_chain(hwnd, data);
2605 set_certificate_status_for_end_cert(hwnd, data->pCertViewInfo);
2608 static void show_dialog_for_selected_cert(HWND hwnd)
2610 HWND tree = GetDlgItem(hwnd, IDC_CERTPATH);
2611 TVITEMW item;
2612 struct hierarchy_data *data;
2613 DWORD selection;
2615 memset(&item, 0, sizeof(item));
2616 item.mask = TVIF_HANDLE | TVIF_PARAM;
2617 item.hItem = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM, TVGN_CARET,
2618 (LPARAM)NULL);
2619 SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item);
2620 data = get_hierarchy_data_from_tree_item(tree, item.hItem);
2621 selection = lparam_to_index(data, item.lParam);
2622 if (selection != 0)
2624 CRYPT_PROVIDER_SGNR *provSigner;
2625 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
2626 BOOL changed = FALSE;
2628 provSigner = WTHelperGetProvSignerFromChain(
2629 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData,
2630 data->pCertViewInfo->idxSigner,
2631 data->pCertViewInfo->fCounterSigner,
2632 data->pCertViewInfo->idxCounterSigner);
2633 memset(&viewInfo, 0, sizeof(viewInfo));
2634 viewInfo.dwSize = sizeof(viewInfo);
2635 viewInfo.dwFlags = data->pCertViewInfo->dwFlags;
2636 viewInfo.szTitle = data->pCertViewInfo->szTitle;
2637 viewInfo.pCertContext = provSigner->pasCertChain[selection].pCert;
2638 viewInfo.cStores = data->pCertViewInfo->cStores;
2639 viewInfo.rghStores = data->pCertViewInfo->rghStores;
2640 viewInfo.cPropSheetPages = data->pCertViewInfo->cPropSheetPages;
2641 viewInfo.rgPropSheetPages = data->pCertViewInfo->rgPropSheetPages;
2642 viewInfo.nStartPage = data->pCertViewInfo->nStartPage;
2643 CryptUIDlgViewCertificateW(&viewInfo, &changed);
2644 if (changed)
2646 /* Delete the contents of the tree */
2647 SendMessageW(tree, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT);
2648 /* Reinitialize the tree */
2649 show_cert_hierarchy(hwnd, data);
2654 static LRESULT CALLBACK hierarchy_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
2655 LPARAM lp)
2657 PROPSHEETPAGEW *page;
2658 struct hierarchy_data *data;
2659 LRESULT ret = 0;
2660 HWND tree = GetDlgItem(hwnd, IDC_CERTPATH);
2662 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
2664 switch (msg)
2666 case WM_INITDIALOG:
2667 page = (PROPSHEETPAGEW *)lp;
2668 data = (struct hierarchy_data *)page->lParam;
2669 show_cert_hierarchy(hwnd, data);
2670 break;
2671 case WM_NOTIFY:
2673 NMHDR *hdr;
2675 hdr = (NMHDR *)lp;
2676 switch (hdr->code)
2678 case TVN_SELCHANGEDW:
2680 NMTREEVIEWW *nm = (NMTREEVIEWW*)lp;
2681 DWORD selection;
2682 CRYPT_PROVIDER_SGNR *provSigner;
2684 data = get_hierarchy_data_from_tree_item(tree, nm->itemNew.hItem);
2685 selection = lparam_to_index(data, nm->itemNew.lParam);
2686 provSigner = WTHelperGetProvSignerFromChain(
2687 (CRYPT_PROVIDER_DATA *)data->pCertViewInfo->u.pCryptProviderData,
2688 data->pCertViewInfo->idxSigner,
2689 data->pCertViewInfo->fCounterSigner,
2690 data->pCertViewInfo->idxCounterSigner);
2691 EnableWindow(GetDlgItem(hwnd, IDC_VIEWCERTIFICATE), selection != 0);
2692 set_certificate_status(GetDlgItem(hwnd, IDC_CERTIFICATESTATUSTEXT),
2693 &provSigner->pasCertChain[selection]);
2694 break;
2696 case NM_DBLCLK:
2697 show_dialog_for_selected_cert(hwnd);
2698 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 1);
2699 ret = 1;
2700 break;
2702 break;
2704 case WM_COMMAND:
2705 switch (wp)
2707 case IDC_VIEWCERTIFICATE:
2708 show_dialog_for_selected_cert(hwnd);
2709 break;
2711 break;
2712 case WM_REFRESH_VIEW:
2714 TVITEMW item;
2716 /* Get hierarchy data */
2717 memset(&item, 0, sizeof(item));
2718 item.mask = TVIF_HANDLE | TVIF_PARAM;
2719 item.hItem = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM, TVGN_ROOT,
2720 (LPARAM)NULL);
2721 data = get_hierarchy_data_from_tree_item(tree, item.hItem);
2722 /* Delete the contents of the tree */
2723 SendMessageW(tree, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT);
2724 /* Reinitialize the tree */
2725 show_cert_hierarchy(hwnd, data);
2726 break;
2729 return ret;
2732 static UINT CALLBACK hierarchy_callback(HWND hwnd, UINT msg,
2733 PROPSHEETPAGEW *page)
2735 struct hierarchy_data *data;
2737 switch (msg)
2739 case PSPCB_RELEASE:
2740 data = (struct hierarchy_data *)page->lParam;
2741 ImageList_Destroy(data->imageList);
2742 HeapFree(GetProcessHeap(), 0, data);
2743 break;
2745 return 0;
2748 static BOOL init_hierarchy_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
2749 PROPSHEETPAGEW *page)
2751 struct hierarchy_data *data = HeapAlloc(GetProcessHeap(), 0,
2752 sizeof(struct hierarchy_data));
2753 BOOL ret = FALSE;
2755 if (data)
2757 data->imageList = ImageList_Create(16, 16, ILC_COLOR4 | ILC_MASK, 2, 0);
2758 if (data->imageList)
2760 HBITMAP bmp;
2761 COLORREF backColor = RGB(255, 0, 255);
2763 data->pCertViewInfo = pCertViewInfo;
2764 data->selectedCert = 0xffffffff;
2766 bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_SMALL_ICONS));
2767 ImageList_AddMasked(data->imageList, bmp, backColor);
2768 DeleteObject(bmp);
2769 ImageList_SetBkColor(data->imageList, CLR_NONE);
2771 memset(page, 0, sizeof(PROPSHEETPAGEW));
2772 page->dwSize = sizeof(PROPSHEETPAGEW);
2773 page->dwFlags = PSP_USECALLBACK;
2774 page->hInstance = hInstance;
2775 page->u.pszTemplate = MAKEINTRESOURCEW(IDD_HIERARCHY);
2776 page->pfnDlgProc = hierarchy_dlg_proc;
2777 page->lParam = (LPARAM)data;
2778 page->pfnCallback = hierarchy_callback;
2779 ret = TRUE;
2781 else
2782 HeapFree(GetProcessHeap(), 0, data);
2784 return ret;
2787 static int CALLBACK cert_prop_sheet_proc(HWND hwnd, UINT msg, LPARAM lp)
2789 RECT rc;
2790 POINT topLeft;
2792 TRACE("(%p, %08x, %08lx)\n", hwnd, msg, lp);
2794 switch (msg)
2796 case PSCB_INITIALIZED:
2797 /* Get cancel button's position.. */
2798 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rc);
2799 topLeft.x = rc.left;
2800 topLeft.y = rc.top;
2801 ScreenToClient(hwnd, &topLeft);
2802 /* hide the cancel button.. */
2803 ShowWindow(GetDlgItem(hwnd, IDCANCEL), FALSE);
2804 /* get the OK button's size.. */
2805 GetWindowRect(GetDlgItem(hwnd, IDOK), &rc);
2806 /* and move the OK button to the cancel button's original position. */
2807 MoveWindow(GetDlgItem(hwnd, IDOK), topLeft.x, topLeft.y,
2808 rc.right - rc.left, rc.bottom - rc.top, FALSE);
2809 GetWindowRect(GetDlgItem(hwnd, IDOK), &rc);
2810 break;
2812 return 0;
2815 static BOOL show_cert_dialog(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
2816 CRYPT_PROVIDER_CERT *provCert, BOOL *pfPropertiesChanged)
2818 static const WCHAR riched[] = { 'r','i','c','h','e','d','2','0',0 };
2819 DWORD nPages;
2820 PROPSHEETPAGEW *pages;
2821 BOOL ret = FALSE;
2822 HMODULE lib = LoadLibraryW(riched);
2824 nPages = pCertViewInfo->cPropSheetPages + 1; /* one for the General tab */
2825 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_DETAILPAGE))
2826 nPages++;
2827 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_HIERARCHYPAGE))
2828 nPages++;
2829 pages = HeapAlloc(GetProcessHeap(), 0, nPages * sizeof(PROPSHEETPAGEW));
2830 if (pages)
2832 PROPSHEETHEADERW hdr;
2833 CRYPTUI_INITDIALOG_STRUCT *init = NULL;
2834 DWORD i;
2836 memset(&hdr, 0, sizeof(hdr));
2837 hdr.dwSize = sizeof(hdr);
2838 hdr.dwFlags = PSH_NOAPPLYNOW | PSH_PROPSHEETPAGE | PSH_USECALLBACK;
2839 hdr.hInstance = hInstance;
2840 if (pCertViewInfo->szTitle)
2841 hdr.pszCaption = pCertViewInfo->szTitle;
2842 else
2843 hdr.pszCaption = MAKEINTRESOURCEW(IDS_CERTIFICATE);
2844 init_general_page(pCertViewInfo, &pages[hdr.nPages++]);
2845 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_DETAILPAGE))
2847 if (init_detail_page(pCertViewInfo, pfPropertiesChanged,
2848 &pages[hdr.nPages]))
2849 hdr.nPages++;
2851 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_HIERARCHYPAGE))
2853 if (init_hierarchy_page(pCertViewInfo, &pages[hdr.nPages]))
2854 hdr.nPages++;
2856 /* Copy each additional page, and create the init dialog struct for it
2858 if (pCertViewInfo->cPropSheetPages)
2860 init = HeapAlloc(GetProcessHeap(), 0,
2861 pCertViewInfo->cPropSheetPages *
2862 sizeof(CRYPTUI_INITDIALOG_STRUCT));
2863 if (init)
2865 for (i = 0; i < pCertViewInfo->cPropSheetPages; i++)
2867 memcpy(&pages[hdr.nPages + i],
2868 &pCertViewInfo->rgPropSheetPages[i],
2869 sizeof(PROPSHEETPAGEW));
2870 init[i].lParam = pCertViewInfo->rgPropSheetPages[i].lParam;
2871 init[i].pCertContext = pCertViewInfo->pCertContext;
2872 pages[hdr.nPages + i].lParam = (LPARAM)&init[i];
2874 if (pCertViewInfo->nStartPage & 0x8000)
2876 /* Start page index is relative to the number of default
2877 * pages
2879 hdr.u2.nStartPage = pCertViewInfo->nStartPage + hdr.nPages;
2881 else
2882 hdr.u2.nStartPage = pCertViewInfo->nStartPage;
2883 hdr.nPages = nPages;
2884 ret = TRUE;
2886 else
2887 SetLastError(ERROR_OUTOFMEMORY);
2889 else
2891 /* Ignore the relative flag if there aren't any additional pages */
2892 hdr.u2.nStartPage = pCertViewInfo->nStartPage & 0x7fff;
2893 ret = TRUE;
2895 if (ret)
2897 INT_PTR l;
2899 hdr.u3.ppsp = pages;
2900 hdr.pfnCallback = cert_prop_sheet_proc;
2901 l = PropertySheetW(&hdr);
2902 if (l == 0)
2904 SetLastError(ERROR_CANCELLED);
2905 ret = FALSE;
2908 HeapFree(GetProcessHeap(), 0, init);
2909 HeapFree(GetProcessHeap(), 0, pages);
2911 else
2912 SetLastError(ERROR_OUTOFMEMORY);
2913 FreeLibrary(lib);
2914 return ret;
2917 /***********************************************************************
2918 * CryptUIDlgViewCertificateW (CRYPTUI.@)
2920 BOOL WINAPI CryptUIDlgViewCertificateW(
2921 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo, BOOL *pfPropertiesChanged)
2923 static GUID generic_cert_verify = WINTRUST_ACTION_GENERIC_CERT_VERIFY;
2924 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
2925 WINTRUST_DATA wvt;
2926 WINTRUST_CERT_INFO cert;
2927 BOOL ret = FALSE;
2928 CRYPT_PROVIDER_SGNR *signer;
2929 CRYPT_PROVIDER_CERT *provCert = NULL;
2931 TRACE("(%p, %p)\n", pCertViewInfo, pfPropertiesChanged);
2933 if (pCertViewInfo->dwSize != sizeof(CRYPTUI_VIEWCERTIFICATE_STRUCTW))
2935 SetLastError(ERROR_INVALID_PARAMETER);
2936 return FALSE;
2938 /* Make a local copy in case we have to call WinVerifyTrust ourselves */
2939 memcpy(&viewInfo, pCertViewInfo, sizeof(viewInfo));
2940 if (!viewInfo.u.hWVTStateData)
2942 memset(&wvt, 0, sizeof(wvt));
2943 wvt.cbStruct = sizeof(wvt);
2944 wvt.dwUIChoice = WTD_UI_NONE;
2945 if (viewInfo.dwFlags &
2946 CRYPTUI_ENABLE_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT)
2947 wvt.fdwRevocationChecks |= WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
2948 if (viewInfo.dwFlags & CRYPTUI_ENABLE_REVOCATION_CHECK_END_CERT)
2949 wvt.fdwRevocationChecks |= WTD_REVOCATION_CHECK_END_CERT;
2950 if (viewInfo.dwFlags & CRYPTUI_ENABLE_REVOCATION_CHECK_CHAIN)
2951 wvt.fdwRevocationChecks |= WTD_REVOCATION_CHECK_CHAIN;
2952 wvt.dwUnionChoice = WTD_CHOICE_CERT;
2953 memset(&cert, 0, sizeof(cert));
2954 cert.cbStruct = sizeof(cert);
2955 cert.psCertContext = (CERT_CONTEXT *)viewInfo.pCertContext;
2956 cert.chStores = viewInfo.cStores;
2957 cert.pahStores = viewInfo.rghStores;
2958 wvt.u.pCert = &cert;
2959 wvt.dwStateAction = WTD_STATEACTION_VERIFY;
2960 WinVerifyTrust(NULL, &generic_cert_verify, &wvt);
2961 viewInfo.u.pCryptProviderData =
2962 WTHelperProvDataFromStateData(wvt.hWVTStateData);
2963 signer = WTHelperGetProvSignerFromChain(
2964 (CRYPT_PROVIDER_DATA *)viewInfo.u.pCryptProviderData, 0, FALSE, 0);
2965 provCert = WTHelperGetProvCertFromChain(signer, 0);
2966 ret = TRUE;
2968 else
2970 viewInfo.u.pCryptProviderData =
2971 WTHelperProvDataFromStateData(viewInfo.u.hWVTStateData);
2972 signer = WTHelperGetProvSignerFromChain(
2973 (CRYPT_PROVIDER_DATA *)viewInfo.u.pCryptProviderData,
2974 viewInfo.idxSigner, viewInfo.fCounterSigner,
2975 viewInfo.idxCounterSigner);
2976 provCert = WTHelperGetProvCertFromChain(signer, viewInfo.idxCert);
2977 ret = TRUE;
2979 if (ret)
2981 ret = show_cert_dialog(&viewInfo, provCert, pfPropertiesChanged);
2982 if (!viewInfo.u.hWVTStateData)
2984 wvt.dwStateAction = WTD_STATEACTION_CLOSE;
2985 WinVerifyTrust(NULL, &generic_cert_verify, &wvt);
2988 return ret;
2991 /***********************************************************************
2992 * CryptUIDlgViewContext (CRYPTUI.@)
2994 BOOL WINAPI CryptUIDlgViewContext(DWORD dwContextType, LPVOID pvContext,
2995 HWND hwnd, LPCWSTR pwszTitle, DWORD dwFlags, LPVOID pvReserved)
2997 BOOL ret;
2999 TRACE("(%d, %p, %p, %s, %08x, %p)\n", dwContextType, pvContext, hwnd,
3000 debugstr_w(pwszTitle), dwFlags, pvReserved);
3002 switch (dwContextType)
3004 case CERT_STORE_CERTIFICATE_CONTEXT:
3006 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
3008 memset(&viewInfo, 0, sizeof(viewInfo));
3009 viewInfo.dwSize = sizeof(viewInfo);
3010 viewInfo.hwndParent = hwnd;
3011 viewInfo.szTitle = pwszTitle;
3012 viewInfo.pCertContext = pvContext;
3013 ret = CryptUIDlgViewCertificateW(&viewInfo, NULL);
3014 break;
3016 default:
3017 FIXME("unimplemented for context type %d\n", dwContextType);
3018 SetLastError(E_INVALIDARG);
3019 ret = FALSE;
3021 return ret;
3024 static PCCERT_CONTEXT make_cert_from_file(LPCWSTR fileName)
3026 HANDLE file;
3027 DWORD size, encoding = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
3028 BYTE *buffer;
3029 PCCERT_CONTEXT cert;
3031 file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
3032 OPEN_EXISTING, 0, NULL);
3033 if (file == INVALID_HANDLE_VALUE)
3035 WARN("can't open certificate file %s\n", debugstr_w(fileName));
3036 return NULL;
3038 if ((size = GetFileSize(file, NULL)))
3040 if ((buffer = HeapAlloc(GetProcessHeap(), 0, size)))
3042 DWORD read;
3043 if (!ReadFile(file, buffer, size, &read, NULL) || read != size)
3045 WARN("can't read certificate file %s\n", debugstr_w(fileName));
3046 HeapFree(GetProcessHeap(), 0, buffer);
3047 CloseHandle(file);
3048 return NULL;
3052 else
3054 WARN("empty file %s\n", debugstr_w(fileName));
3055 CloseHandle(file);
3056 return NULL;
3058 CloseHandle(file);
3059 cert = CertCreateCertificateContext(encoding, buffer, size);
3060 HeapFree(GetProcessHeap(), 0, buffer);
3061 return cert;
3064 /* Decodes a cert's basic constraints extension (either szOID_BASIC_CONSTRAINTS
3065 * or szOID_BASIC_CONSTRAINTS2, whichever is present) to determine if it
3066 * should be a CA. If neither extension is present, returns
3067 * defaultIfNotSpecified.
3069 static BOOL is_ca_cert(PCCERT_CONTEXT cert, BOOL defaultIfNotSpecified)
3071 BOOL isCA = defaultIfNotSpecified;
3072 PCERT_EXTENSION ext = CertFindExtension(szOID_BASIC_CONSTRAINTS,
3073 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
3075 if (ext)
3077 CERT_BASIC_CONSTRAINTS_INFO *info;
3078 DWORD size = 0;
3080 if (CryptDecodeObjectEx(X509_ASN_ENCODING, szOID_BASIC_CONSTRAINTS,
3081 ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG,
3082 NULL, (LPBYTE)&info, &size))
3084 if (info->SubjectType.cbData == 1)
3085 isCA = info->SubjectType.pbData[0] & CERT_CA_SUBJECT_FLAG;
3086 LocalFree(info);
3089 else
3091 ext = CertFindExtension(szOID_BASIC_CONSTRAINTS2,
3092 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
3093 if (ext)
3095 CERT_BASIC_CONSTRAINTS2_INFO info;
3096 DWORD size = sizeof(CERT_BASIC_CONSTRAINTS2_INFO);
3098 if (CryptDecodeObjectEx(X509_ASN_ENCODING,
3099 szOID_BASIC_CONSTRAINTS2, ext->Value.pbData, ext->Value.cbData,
3100 0, NULL, &info, &size))
3101 isCA = info.fCA;
3104 return isCA;
3107 static HCERTSTORE choose_store_for_cert(PCCERT_CONTEXT cert)
3109 static const WCHAR AddressBook[] = { 'A','d','d','r','e','s','s',
3110 'B','o','o','k',0 };
3111 static const WCHAR CA[] = { 'C','A',0 };
3112 LPCWSTR storeName;
3114 if (is_ca_cert(cert, TRUE))
3115 storeName = CA;
3116 else
3117 storeName = AddressBook;
3118 return CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0,
3119 CERT_SYSTEM_STORE_CURRENT_USER, storeName);
3122 BOOL WINAPI CryptUIWizImport(DWORD dwFlags, HWND hwndParent, LPCWSTR pwszWizardTitle,
3123 PCCRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc, HCERTSTORE hDestCertStore)
3125 BOOL ret;
3126 HCERTSTORE store;
3127 const CERT_CONTEXT *cert;
3128 BOOL freeCert = FALSE;
3130 TRACE("(0x%08x, %p, %s, %p, %p)\n", dwFlags, hwndParent, debugstr_w(pwszWizardTitle),
3131 pImportSrc, hDestCertStore);
3133 if (!(dwFlags & CRYPTUI_WIZ_NO_UI)) FIXME("UI not implemented\n");
3135 if (!pImportSrc ||
3136 pImportSrc->dwSize != sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO))
3138 SetLastError(E_INVALIDARG);
3139 return FALSE;
3142 switch (pImportSrc->dwSubjectChoice)
3144 case CRYPTUI_WIZ_IMPORT_SUBJECT_FILE:
3145 if (!(cert = make_cert_from_file(pImportSrc->u.pwszFileName)))
3147 WARN("unable to create certificate context\n");
3148 return FALSE;
3150 else
3151 freeCert = TRUE;
3152 break;
3153 case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_CONTEXT:
3154 cert = pImportSrc->u.pCertContext;
3155 if (!cert)
3157 SetLastError(E_INVALIDARG);
3158 return FALSE;
3160 break;
3161 default:
3162 FIXME("source type not implemented: %u\n", pImportSrc->dwSubjectChoice);
3163 SetLastError(E_INVALIDARG);
3164 return FALSE;
3166 if (hDestCertStore) store = hDestCertStore;
3167 else
3169 if (!(store = choose_store_for_cert(cert)))
3171 WARN("unable to open certificate store\n");
3172 CertFreeCertificateContext(cert);
3173 return FALSE;
3176 ret = CertAddCertificateContextToStore(store, cert, CERT_STORE_ADD_REPLACE_EXISTING, NULL);
3178 if (!hDestCertStore) CertCloseStore(store, 0);
3179 if (freeCert)
3180 CertFreeCertificateContext(cert);
3181 return ret;