cryptui: Show valid policies for a cert.
[wine/wine64.git] / dlls / cryptui / main.c
blob148f91d64ed1f79f9b922763ac1ac4334a9d7b21
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 "cryptuiapi.h"
36 #include "cryptuires.h"
37 #include "wine/debug.h"
38 #include "wine/unicode.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(cryptui);
42 static HINSTANCE hInstance;
44 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
46 TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
48 switch (fdwReason)
50 case DLL_WINE_PREATTACH:
51 return FALSE; /* prefer native version */
52 case DLL_PROCESS_ATTACH:
53 hInstance = hinstDLL;
54 DisableThreadLibraryCalls(hinstDLL);
55 break;
56 case DLL_PROCESS_DETACH:
57 break;
58 default:
59 break;
61 return TRUE;
64 /***********************************************************************
65 * CryptUIDlgCertMgr (CRYPTUI.@)
67 BOOL WINAPI CryptUIDlgCertMgr(PCCRYPTUI_CERT_MGR_STRUCT pCryptUICertMgr)
69 FIXME("(%p): stub\n", pCryptUICertMgr);
70 return FALSE;
73 /***********************************************************************
74 * CryptUIDlgViewCertificateA (CRYPTUI.@)
76 BOOL WINAPI CryptUIDlgViewCertificateA(
77 PCCRYPTUI_VIEWCERTIFICATE_STRUCTA pCertViewInfo, BOOL *pfPropertiesChanged)
79 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
80 LPWSTR title = NULL;
81 BOOL ret;
83 TRACE("(%p, %p)\n", pCertViewInfo, pfPropertiesChanged);
85 memcpy(&viewInfo, pCertViewInfo, sizeof(viewInfo));
86 if (pCertViewInfo->szTitle)
88 int len = MultiByteToWideChar(CP_ACP, 0, pCertViewInfo->szTitle, -1,
89 NULL, 0);
91 title = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
92 if (title)
94 MultiByteToWideChar(CP_ACP, 0, pCertViewInfo->szTitle, -1, title,
95 len);
96 viewInfo.szTitle = title;
98 else
100 ret = FALSE;
101 goto error;
104 if (pCertViewInfo->cPropSheetPages)
106 FIXME("ignoring additional prop sheet pages\n");
107 viewInfo.cPropSheetPages = 0;
109 ret = CryptUIDlgViewCertificateW(&viewInfo, pfPropertiesChanged);
110 HeapFree(GetProcessHeap(), 0, title);
111 error:
112 return ret;
115 struct ReadStringStruct
117 LPCWSTR buf;
118 LONG pos;
119 LONG len;
122 static DWORD CALLBACK read_text_callback(DWORD_PTR dwCookie, LPBYTE buf,
123 LONG cb, LONG *pcb)
125 struct ReadStringStruct *string = (struct ReadStringStruct *)dwCookie;
126 LONG cch = min(cb / sizeof(WCHAR), string->len - string->pos);
128 TRACE("(%p, %p, %d, %p)\n", string, buf, cb, pcb);
130 memmove(buf, string->buf + string->pos, cch * sizeof(WCHAR));
131 string->pos += cch;
132 *pcb = cch * sizeof(WCHAR);
133 return 0;
136 static void add_unformatted_text_to_control(HWND hwnd, LPCWSTR text, LONG len)
138 struct ReadStringStruct string;
139 EDITSTREAM editstream;
141 TRACE("(%p, %s)\n", hwnd, debugstr_wn(text, len));
143 string.buf = text;
144 string.pos = 0;
145 string.len = len;
146 editstream.dwCookie = (DWORD_PTR)&string;
147 editstream.dwError = 0;
148 editstream.pfnCallback = read_text_callback;
149 SendMessageW(hwnd, EM_STREAMIN, SF_TEXT | SFF_SELECTION | SF_UNICODE,
150 (LPARAM)&editstream);
153 static void add_string_resource_to_control(HWND hwnd, int id)
155 LPWSTR str;
156 LONG len;
158 len = LoadStringW(hInstance, id, (LPWSTR)&str, 0);
159 add_unformatted_text_to_control(hwnd, str, len);
162 static void add_text_with_paraformat_to_control(HWND hwnd, LPCWSTR text,
163 LONG len, const PARAFORMAT2 *fmt)
165 add_unformatted_text_to_control(hwnd, text, len);
166 SendMessageW(hwnd, EM_SETPARAFORMAT, 0, (LPARAM)fmt);
169 static void add_string_resource_with_paraformat_to_control(HWND hwnd, int id,
170 const PARAFORMAT2 *fmt)
172 LPWSTR str;
173 LONG len;
175 len = LoadStringW(hInstance, id, (LPWSTR)&str, 0);
176 add_text_with_paraformat_to_control(hwnd, str, len, fmt);
179 static LPWSTR get_cert_name_string(PCCERT_CONTEXT pCertContext, DWORD dwType,
180 DWORD dwFlags)
182 LPWSTR buf = NULL;
183 DWORD len;
185 len = CertGetNameStringW(pCertContext, dwType, dwFlags, NULL, NULL, 0);
186 if (len)
188 buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
189 if (buf)
190 CertGetNameStringW(pCertContext, dwType, dwFlags, NULL, buf, len);
192 return buf;
195 static void add_cert_string_to_control(HWND hwnd, PCCERT_CONTEXT pCertContext,
196 DWORD dwType, DWORD dwFlags)
198 LPWSTR name = get_cert_name_string(pCertContext, dwType, dwFlags);
200 if (name)
202 /* Don't include NULL-terminator in output */
203 DWORD len = lstrlenW(name);
205 add_unformatted_text_to_control(hwnd, name, len);
206 HeapFree(GetProcessHeap(), 0, name);
210 static void add_icon_to_control(HWND hwnd, int id)
212 HRESULT hr;
213 LPRICHEDITOLE richEditOle = NULL;
214 LPOLEOBJECT object = NULL;
215 CLSID clsid;
216 LPOLECACHE oleCache = NULL;
217 FORMATETC formatEtc;
218 DWORD conn;
219 LPDATAOBJECT dataObject = NULL;
220 HBITMAP bitmap = NULL;
221 RECT rect;
222 STGMEDIUM stgm;
223 REOBJECT reObject;
225 TRACE("(%p, %d)\n", hwnd, id);
227 SendMessageW(hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&richEditOle);
228 if (!richEditOle)
229 goto end;
230 hr = OleCreateDefaultHandler(&CLSID_NULL, NULL, &IID_IOleObject,
231 (void**)&object);
232 if (FAILED(hr))
233 goto end;
234 hr = IOleObject_GetUserClassID(object, &clsid);
235 if (FAILED(hr))
236 goto end;
237 hr = IOleObject_QueryInterface(object, &IID_IOleCache, (void**)&oleCache);
238 if (FAILED(hr))
239 goto end;
240 formatEtc.cfFormat = CF_BITMAP;
241 formatEtc.ptd = NULL;
242 formatEtc.dwAspect = DVASPECT_CONTENT;
243 formatEtc.lindex = -1;
244 formatEtc.tymed = TYMED_GDI;
245 hr = IOleCache_Cache(oleCache, &formatEtc, 0, &conn);
246 if (FAILED(hr))
247 goto end;
248 hr = IOleObject_QueryInterface(object, &IID_IDataObject,
249 (void**)&dataObject);
250 if (FAILED(hr))
251 goto end;
252 bitmap = LoadImageW(hInstance, MAKEINTRESOURCEW(id), IMAGE_BITMAP, 0, 0,
253 LR_DEFAULTSIZE | LR_LOADTRANSPARENT);
254 if (!bitmap)
255 goto end;
256 rect.left = rect.top = 0;
257 rect.right = GetSystemMetrics(SM_CXICON);
258 rect.bottom = GetSystemMetrics(SM_CYICON);
259 stgm.tymed = TYMED_GDI;
260 stgm.u.hBitmap = bitmap;
261 stgm.pUnkForRelease = NULL;
262 hr = IDataObject_SetData(dataObject, &formatEtc, &stgm, TRUE);
263 if (FAILED(hr))
264 goto end;
266 reObject.cbStruct = sizeof(reObject);
267 reObject.cp = REO_CP_SELECTION;
268 reObject.clsid = clsid;
269 reObject.poleobj = object;
270 reObject.pstg = NULL;
271 reObject.polesite = NULL;
272 reObject.sizel.cx = reObject.sizel.cy = 0;
273 reObject.dvaspect = DVASPECT_CONTENT;
274 reObject.dwFlags = 0;
275 reObject.dwUser = 0;
277 IRichEditOle_InsertObject(richEditOle, &reObject);
279 end:
280 if (dataObject)
281 IDataObject_Release(dataObject);
282 if (oleCache)
283 IOleCache_Release(oleCache);
284 if (object)
285 IOleObject_Release(object);
286 if (richEditOle)
287 IRichEditOle_Release(richEditOle);
290 #define MY_INDENT 200
292 static void add_oid_text_to_control(HWND hwnd, char *oid)
294 WCHAR nl = '\n';
295 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, oid, 0);
296 PARAFORMAT2 parFmt;
298 parFmt.cbSize = sizeof(parFmt);
299 parFmt.dwMask = PFM_STARTINDENT;
300 parFmt.dxStartIndent = MY_INDENT * 3;
301 if (oidInfo)
303 add_text_with_paraformat_to_control(hwnd, oidInfo->pwszName,
304 lstrlenW(oidInfo->pwszName), &parFmt);
305 add_unformatted_text_to_control(hwnd, &nl, 1);
309 #define MAX_STRING_LEN 512
311 struct OIDToString
313 LPCSTR oid;
314 int id;
317 /* The following list MUST be lexicographically sorted by OID */
318 static struct OIDToString oidMap[] = {
319 /* 1.3.6.1.4.1.311.10.3.1 */
320 { szOID_KP_CTL_USAGE_SIGNING, IDS_PURPOSE_CTL_USAGE_SIGNING },
321 /* 1.3.6.1.4.1.311.10.3.4 */
322 { szOID_KP_EFS, IDS_PURPOSE_EFS },
323 /* 1.3.6.1.4.1.311.10.3.4.1 */
324 { szOID_EFS_RECOVERY, IDS_PURPOSE_EFS_RECOVERY },
325 /* 1.3.6.1.4.1.311.10.3.5 */
326 { szOID_WHQL_CRYPTO, IDS_PURPOSE_WHQL },
327 /* 1.3.6.1.4.1.311.10.3.6 */
328 { szOID_NT5_CRYPTO, IDS_PURPOSE_NT5 },
329 /* 1.3.6.1.4.1.311.10.3.7 */
330 { szOID_OEM_WHQL_CRYPTO, IDS_PURPOSE_OEM_WHQL },
331 /* 1.3.6.1.4.1.311.10.3.8 */
332 { szOID_EMBEDDED_NT_CRYPTO, IDS_PURPOSE_EMBEDDED_NT },
333 /* 1.3.6.1.4.1.311.10.3.9 */
334 { szOID_ROOT_LIST_SIGNER, IDS_PURPOSE_ROOT_LIST_SIGNER },
335 /* 1.3.6.1.4.1.311.10.3.10 */
336 { szOID_KP_QUALIFIED_SUBORDINATION, IDS_PURPOSE_QUALIFIED_SUBORDINATION },
337 /* 1.3.6.1.4.1.311.10.3.11 */
338 { szOID_KP_KEY_RECOVERY, IDS_PURPOSE_KEY_RECOVERY },
339 /* 1.3.6.1.4.1.311.10.3.12 */
340 { szOID_KP_DOCUMENT_SIGNING, IDS_PURPOSE_DOCUMENT_SIGNING },
341 /* 1.3.6.1.4.1.311.10.3.13 */
342 { szOID_KP_LIFETIME_SIGNING, IDS_PURPOSE_LIFETIME_SIGNING },
343 /* 1.3.6.1.4.1.311.10.5.1 */
344 { szOID_DRM, IDS_PURPOSE_DRM },
345 /* 1.3.6.1.4.1.311.10.6.1 */
346 { szOID_LICENSES, IDS_PURPOSE_LICENSES },
347 /* 1.3.6.1.4.1.311.10.6.2 */
348 { szOID_LICENSE_SERVER, IDS_PURPOSE_LICENSE_SERVER },
349 /* 1.3.6.1.4.1.311.20.2.1 */
350 { szOID_ENROLLMENT_AGENT, IDS_PURPOSE_ENROLLMENT_AGENT },
351 /* 1.3.6.1.4.1.311.20.2.2 */
352 { szOID_KP_SMARTCARD_LOGON, IDS_PURPOSE_SMARTCARD_LOGON },
353 /* 1.3.6.1.4.1.311.21.5 */
354 { szOID_KP_CA_EXCHANGE, IDS_PURPOSE_CA_EXCHANGE },
355 /* 1.3.6.1.4.1.311.21.6 */
356 { szOID_KP_KEY_RECOVERY_AGENT, IDS_PURPOSE_KEY_RECOVERY_AGENT },
357 /* 1.3.6.1.4.1.311.21.19 */
358 { szOID_DS_EMAIL_REPLICATION, IDS_PURPOSE_DS_EMAIL_REPLICATION },
359 /* 1.3.6.1.5.5.7.3.1 */
360 { szOID_PKIX_KP_SERVER_AUTH, IDS_PURPOSE_SERVER_AUTH },
361 /* 1.3.6.1.5.5.7.3.2 */
362 { szOID_PKIX_KP_CLIENT_AUTH, IDS_PURPOSE_CLIENT_AUTH },
363 /* 1.3.6.1.5.5.7.3.3 */
364 { szOID_PKIX_KP_CODE_SIGNING, IDS_PURPOSE_CODE_SIGNING },
365 /* 1.3.6.1.5.5.7.3.4 */
366 { szOID_PKIX_KP_EMAIL_PROTECTION, IDS_PURPOSE_EMAIL_PROTECTION },
367 /* 1.3.6.1.5.5.7.3.5 */
368 { szOID_PKIX_KP_IPSEC_END_SYSTEM, IDS_PURPOSE_IPSEC },
369 /* 1.3.6.1.5.5.7.3.6 */
370 { szOID_PKIX_KP_IPSEC_TUNNEL, IDS_PURPOSE_IPSEC },
371 /* 1.3.6.1.5.5.7.3.7 */
372 { szOID_PKIX_KP_IPSEC_USER, IDS_PURPOSE_IPSEC },
373 /* 1.3.6.1.5.5.7.3.8 */
374 { szOID_PKIX_KP_TIMESTAMP_SIGNING, IDS_PURPOSE_TIMESTAMP_SIGNING },
377 static struct OIDToString *findSupportedOID(LPCSTR oid)
379 int indexHigh = sizeof(oidMap) / sizeof(oidMap[0]) - 1, indexLow = 0, i;
380 struct OIDToString *ret = NULL;
382 for (i = (indexLow + indexHigh) / 2; !ret && indexLow <= indexHigh;
383 i = (indexLow + indexHigh) / 2)
385 int cmp;
387 cmp = strcmp(oid, oidMap[i].oid);
388 if (!cmp)
389 ret = &oidMap[i];
390 else if (cmp > 0)
391 indexLow = i + 1;
392 else
393 indexHigh = i - 1;
395 return ret;
398 static void add_local_oid_text_to_control(HWND text, LPCSTR oid)
400 struct OIDToString *entry;
401 WCHAR nl = '\n';
402 PARAFORMAT2 parFmt;
404 parFmt.cbSize = sizeof(parFmt);
405 parFmt.dwMask = PFM_STARTINDENT;
406 parFmt.dxStartIndent = MY_INDENT * 3;
407 if ((entry = findSupportedOID(oid)))
409 WCHAR *str, *linebreak, *ptr;
410 BOOL multiline = FALSE;
411 int len;
413 len = LoadStringW(hInstance, entry->id, (LPWSTR)&str, 0);
414 ptr = str;
415 do {
416 if ((linebreak = memchrW(ptr, '\n', len)))
418 WCHAR copy[MAX_STRING_LEN];
420 multiline = TRUE;
421 /* The source string contains a newline, which the richedit
422 * control won't find since it's interpreted as a paragraph
423 * break. Therefore copy up to the newline. lstrcpynW always
424 * NULL-terminates, so pass one more than the length of the
425 * source line so the copy includes the entire line and the
426 * NULL-terminator.
428 lstrcpynW(copy, ptr, linebreak - ptr + 1);
429 add_text_with_paraformat_to_control(text, copy,
430 linebreak - ptr, &parFmt);
431 ptr = linebreak + 1;
432 add_unformatted_text_to_control(text, &nl, 1);
434 else if (multiline && *ptr)
436 /* Add the last line */
437 add_text_with_paraformat_to_control(text, ptr,
438 len - (ptr - str), &parFmt);
439 add_unformatted_text_to_control(text, &nl, 1);
441 } while (linebreak);
442 if (!multiline)
444 add_text_with_paraformat_to_control(text, str, len, &parFmt);
445 add_unformatted_text_to_control(text, &nl, 1);
448 else
450 WCHAR *oidW = HeapAlloc(GetProcessHeap(), 0,
451 (strlen(oid) + 1) * sizeof(WCHAR));
453 if (oidW)
455 LPCSTR src;
456 WCHAR *dst;
458 for (src = oid, dst = oidW; *src; src++, dst++)
459 *dst = *src;
460 *dst = 0;
461 add_text_with_paraformat_to_control(text, oidW, lstrlenW(oidW),
462 &parFmt);
463 add_unformatted_text_to_control(text, &nl, 1);
464 HeapFree(GetProcessHeap(), 0, oidW);
469 static void display_app_usages(HWND text, PCCERT_CONTEXT cert,
470 BOOL *anyUsageAdded)
472 static char any_app_policy[] = szOID_ANY_APPLICATION_POLICY;
473 WCHAR nl = '\n';
474 CHARFORMATW charFmt;
475 PCERT_EXTENSION policyExt;
476 if (!*anyUsageAdded)
478 PARAFORMAT2 parFmt;
480 parFmt.cbSize = sizeof(parFmt);
481 parFmt.dwMask = PFM_STARTINDENT;
482 parFmt.dxStartIndent = MY_INDENT;
483 add_string_resource_with_paraformat_to_control(text,
484 IDS_CERT_INFO_PURPOSES, &parFmt);
485 add_unformatted_text_to_control(text, &nl, 1);
486 *anyUsageAdded = TRUE;
488 memset(&charFmt, 0, sizeof(charFmt));
489 charFmt.cbSize = sizeof(charFmt);
490 charFmt.dwMask = CFM_BOLD;
491 charFmt.dwEffects = 0;
492 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
493 if ((policyExt = CertFindExtension(szOID_APPLICATION_CERT_POLICIES,
494 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension)))
496 CERT_POLICIES_INFO *policies;
497 DWORD size;
499 if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_POLICIES,
500 policyExt->Value.pbData, policyExt->Value.cbData,
501 CRYPT_DECODE_ALLOC_FLAG, NULL, &policies, &size))
503 DWORD i;
505 for (i = 0; i < policies->cPolicyInfo; i++)
507 DWORD j;
509 for (j = 0; j < policies->rgPolicyInfo[i].cPolicyQualifier; j++)
510 add_local_oid_text_to_control(text,
511 policies->rgPolicyInfo[i].rgPolicyQualifier[j].
512 pszPolicyQualifierId);
514 LocalFree(policies);
517 else
518 add_oid_text_to_control(text, any_app_policy);
521 static BOOL display_cert_usages(HWND text, PCCERT_CONTEXT cert,
522 BOOL *anyUsageAdded)
524 WCHAR nl = '\n';
525 DWORD size;
526 BOOL badUsages = FALSE;
528 if (CertGetEnhancedKeyUsage(cert, 0, NULL, &size))
530 CHARFORMATW charFmt;
531 static char any_cert_policy[] = szOID_ANY_CERT_POLICY;
532 PCERT_ENHKEY_USAGE usage = HeapAlloc(GetProcessHeap(), 0, size);
534 if (usage)
536 if (CertGetEnhancedKeyUsage(cert, 0, usage, &size))
538 DWORD i;
540 if (!*anyUsageAdded)
542 PARAFORMAT2 parFmt;
544 parFmt.cbSize = sizeof(parFmt);
545 parFmt.dwMask = PFM_STARTINDENT;
546 parFmt.dxStartIndent = MY_INDENT;
547 add_string_resource_with_paraformat_to_control(text,
548 IDS_CERT_INFO_PURPOSES, &parFmt);
549 add_unformatted_text_to_control(text, &nl, 1);
550 *anyUsageAdded = TRUE;
552 memset(&charFmt, 0, sizeof(charFmt));
553 charFmt.cbSize = sizeof(charFmt);
554 charFmt.dwMask = CFM_BOLD;
555 charFmt.dwEffects = 0;
556 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION,
557 (LPARAM)&charFmt);
558 if (!usage->cUsageIdentifier)
559 add_oid_text_to_control(text, any_cert_policy);
560 else
561 for (i = 0; i < usage->cUsageIdentifier; i++)
562 add_local_oid_text_to_control(text,
563 usage->rgpszUsageIdentifier[i]);
565 else
566 badUsages = TRUE;
567 HeapFree(GetProcessHeap(), 0, usage);
569 else
570 badUsages = TRUE;
572 else
573 badUsages = TRUE;
574 return badUsages;
577 static void set_policy_text(HWND text,
578 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
580 BOOL includeCertUsages = FALSE, includeAppUsages = FALSE;
581 BOOL badUsages = FALSE, anyUsageAdded = FALSE;
583 if (pCertViewInfo->cPurposes)
585 DWORD i;
587 for (i = 0; i < pCertViewInfo->cPurposes; i++)
589 if (!strcmp(pCertViewInfo->rgszPurposes[i], szOID_ANY_CERT_POLICY))
590 includeCertUsages = TRUE;
591 else if (!strcmp(pCertViewInfo->rgszPurposes[i],
592 szOID_ANY_APPLICATION_POLICY))
593 includeAppUsages = TRUE;
594 else
595 badUsages = TRUE;
598 else
599 includeAppUsages = includeCertUsages = TRUE;
600 if (includeAppUsages)
601 display_app_usages(text, pCertViewInfo->pCertContext, &anyUsageAdded);
602 if (includeCertUsages)
603 badUsages = display_cert_usages(text, pCertViewInfo->pCertContext,
604 &anyUsageAdded);
605 if (badUsages)
607 PARAFORMAT2 parFmt;
609 parFmt.cbSize = sizeof(parFmt);
610 parFmt.dwMask = PFM_STARTINDENT;
611 parFmt.dxStartIndent = MY_INDENT;
612 add_string_resource_with_paraformat_to_control(text,
613 IDS_CERT_INFO_BAD_PURPOSES, &parFmt);
617 static void set_cert_info(HWND hwnd,
618 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
620 CHARFORMATW charFmt;
621 PARAFORMAT2 parFmt;
622 HWND icon = GetDlgItem(hwnd, IDC_CERTIFICATE_ICON);
623 HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_INFO);
624 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
625 (CRYPT_PROVIDER_DATA *)pCertViewInfo->u.pCryptProviderData,
626 pCertViewInfo->idxSigner, pCertViewInfo->fCounterSigner,
627 pCertViewInfo->idxCounterSigner);
628 CRYPT_PROVIDER_CERT *root =
629 &provSigner->pasCertChain[provSigner->csCertChain - 1];
631 if (provSigner->pChainContext->TrustStatus.dwErrorStatus &
632 CERT_TRUST_IS_PARTIAL_CHAIN)
633 add_icon_to_control(icon, IDB_CERT_WARNING);
634 else if (!root->fTrustedRoot)
635 add_icon_to_control(icon, IDB_CERT_ERROR);
636 else
637 add_icon_to_control(icon, IDB_CERT);
639 memset(&charFmt, 0, sizeof(charFmt));
640 charFmt.cbSize = sizeof(charFmt);
641 charFmt.dwMask = CFM_BOLD;
642 charFmt.dwEffects = CFE_BOLD;
643 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
644 /* FIXME: vertically center text */
645 parFmt.cbSize = sizeof(parFmt);
646 parFmt.dwMask = PFM_STARTINDENT;
647 parFmt.dxStartIndent = MY_INDENT;
648 add_string_resource_with_paraformat_to_control(text,
649 IDS_CERTIFICATEINFORMATION, &parFmt);
651 text = GetDlgItem(hwnd, IDC_CERTIFICATE_STATUS);
652 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
653 if (provSigner->dwError == TRUST_E_CERT_SIGNATURE)
654 add_string_resource_with_paraformat_to_control(text,
655 IDS_CERT_INFO_BAD_SIG, &parFmt);
656 else if (provSigner->pChainContext->TrustStatus.dwErrorStatus &
657 CERT_TRUST_IS_PARTIAL_CHAIN)
658 add_string_resource_with_paraformat_to_control(text,
659 IDS_CERT_INFO_PARTIAL_CHAIN, &parFmt);
660 else if (!root->fTrustedRoot)
662 if (provSigner->csCertChain == 1 && root->fSelfSigned)
663 add_string_resource_with_paraformat_to_control(text,
664 IDS_CERT_INFO_UNTRUSTED_CA, &parFmt);
665 else
666 add_string_resource_with_paraformat_to_control(text,
667 IDS_CERT_INFO_UNTRUSTED_ROOT, &parFmt);
669 else
671 set_policy_text(text, pCertViewInfo);
672 FIXME("show issuer statement\n");
676 static void set_cert_name_string(HWND hwnd, PCCERT_CONTEXT cert,
677 DWORD nameFlags, int heading)
679 WCHAR nl = '\n';
680 HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_NAMES);
681 CHARFORMATW charFmt;
682 PARAFORMAT2 parFmt;
684 memset(&charFmt, 0, sizeof(charFmt));
685 charFmt.cbSize = sizeof(charFmt);
686 charFmt.dwMask = CFM_BOLD;
687 charFmt.dwEffects = CFE_BOLD;
688 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
689 parFmt.cbSize = sizeof(parFmt);
690 parFmt.dwMask = PFM_STARTINDENT;
691 parFmt.dxStartIndent = MY_INDENT * 3;
692 add_string_resource_with_paraformat_to_control(text, heading, &parFmt);
693 charFmt.dwEffects = 0;
694 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
695 add_cert_string_to_control(text, cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
696 nameFlags);
697 add_unformatted_text_to_control(text, &nl, 1);
698 add_unformatted_text_to_control(text, &nl, 1);
699 add_unformatted_text_to_control(text, &nl, 1);
703 static void add_date_string_to_control(HWND hwnd, const FILETIME *fileTime)
705 WCHAR dateFmt[80]; /* sufficient for all versions of LOCALE_SSHORTDATE */
706 WCHAR date[80];
707 SYSTEMTIME sysTime;
709 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SSHORTDATE, dateFmt,
710 sizeof(dateFmt) / sizeof(dateFmt[0]));
711 FileTimeToSystemTime(fileTime, &sysTime);
712 GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, date,
713 sizeof(date) / sizeof(date[0]));
714 add_unformatted_text_to_control(hwnd, date, lstrlenW(date));
717 static void set_cert_validity_period(HWND hwnd, PCCERT_CONTEXT cert)
719 WCHAR nl = '\n';
720 HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_NAMES);
721 CHARFORMATW charFmt;
722 PARAFORMAT2 parFmt;
724 memset(&charFmt, 0, sizeof(charFmt));
725 charFmt.cbSize = sizeof(charFmt);
726 charFmt.dwMask = CFM_BOLD;
727 charFmt.dwEffects = CFE_BOLD;
728 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
729 parFmt.cbSize = sizeof(parFmt);
730 parFmt.dwMask = PFM_STARTINDENT;
731 parFmt.dxStartIndent = MY_INDENT * 3;
732 add_string_resource_with_paraformat_to_control(text, IDS_VALID_FROM,
733 &parFmt);
734 charFmt.dwEffects = 0;
735 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
736 add_date_string_to_control(text, &cert->pCertInfo->NotBefore);
737 charFmt.dwEffects = CFE_BOLD;
738 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
739 add_string_resource_to_control(text, IDS_VALID_TO);
740 charFmt.dwEffects = 0;
741 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
742 add_date_string_to_control(text, &cert->pCertInfo->NotAfter);
743 add_unformatted_text_to_control(text, &nl, 1);
746 static void set_general_info(HWND hwnd,
747 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
749 set_cert_info(hwnd, pCertViewInfo);
750 set_cert_name_string(hwnd, pCertViewInfo->pCertContext, 0,
751 IDS_SUBJECT_HEADING);
752 set_cert_name_string(hwnd, pCertViewInfo->pCertContext,
753 CERT_NAME_ISSUER_FLAG, IDS_ISSUER_HEADING);
754 set_cert_validity_period(hwnd, pCertViewInfo->pCertContext);
757 static LRESULT CALLBACK general_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
758 LPARAM lp)
760 PROPSHEETPAGEW *page;
761 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo;
763 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
765 switch (msg)
767 case WM_INITDIALOG:
768 page = (PROPSHEETPAGEW *)lp;
769 pCertViewInfo = (PCCRYPTUI_VIEWCERTIFICATE_STRUCTW)page->lParam;
770 if (pCertViewInfo->dwFlags & CRYPTUI_DISABLE_ADDTOSTORE)
771 ShowWindow(GetDlgItem(hwnd, IDC_ADDTOSTORE), FALSE);
772 EnableWindow(GetDlgItem(hwnd, IDC_ISSUERSTATEMENT), FALSE);
773 set_general_info(hwnd, pCertViewInfo);
774 break;
775 case WM_COMMAND:
776 switch (wp)
778 case IDC_ADDTOSTORE:
779 FIXME("call CryptUIWizImport\n");
780 break;
782 break;
784 return 0;
787 static void init_general_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
788 PROPSHEETPAGEW *page)
790 memset(page, 0, sizeof(PROPSHEETPAGEW));
791 page->dwSize = sizeof(PROPSHEETPAGEW);
792 page->hInstance = hInstance;
793 page->u.pszTemplate = MAKEINTRESOURCEW(IDD_GENERAL);
794 page->pfnDlgProc = general_dlg_proc;
795 page->lParam = (LPARAM)pCertViewInfo;
798 static int CALLBACK cert_prop_sheet_proc(HWND hwnd, UINT msg, LPARAM lp)
800 RECT rc;
801 POINT topLeft;
803 TRACE("(%p, %08x, %08lx)\n", hwnd, msg, lp);
805 switch (msg)
807 case PSCB_INITIALIZED:
808 /* Get cancel button's position.. */
809 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rc);
810 topLeft.x = rc.left;
811 topLeft.y = rc.top;
812 ScreenToClient(hwnd, &topLeft);
813 /* hide the cancel button.. */
814 ShowWindow(GetDlgItem(hwnd, IDCANCEL), FALSE);
815 /* get the OK button's size.. */
816 GetWindowRect(GetDlgItem(hwnd, IDOK), &rc);
817 /* and move the OK button to the cancel button's original position. */
818 MoveWindow(GetDlgItem(hwnd, IDOK), topLeft.x, topLeft.y,
819 rc.right - rc.left, rc.bottom - rc.top, FALSE);
820 GetWindowRect(GetDlgItem(hwnd, IDOK), &rc);
821 break;
823 return 0;
826 static BOOL show_cert_dialog(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
827 CRYPT_PROVIDER_CERT *provCert, BOOL *pfPropertiesChanged)
829 static const WCHAR riched[] = { 'r','i','c','h','e','d','2','0',0 };
830 DWORD nPages;
831 PROPSHEETPAGEW *pages;
832 BOOL ret = FALSE;
833 HMODULE lib = LoadLibraryW(riched);
835 nPages = pCertViewInfo->cPropSheetPages + 1; /* one for the General tab */
836 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_DETAILPAGE))
837 FIXME("show detail page\n");
838 if (!(pCertViewInfo->dwFlags & CRYPTUI_HIDE_HIERARCHYPAGE))
839 FIXME("show hierarchy page\n");
840 pages = HeapAlloc(GetProcessHeap(), 0, nPages * sizeof(PROPSHEETPAGEW));
841 if (pages)
843 PROPSHEETHEADERW hdr;
844 CRYPTUI_INITDIALOG_STRUCT *init = NULL;
845 DWORD i;
847 memset(&hdr, 0, sizeof(hdr));
848 hdr.dwSize = sizeof(hdr);
849 hdr.dwFlags = PSH_NOAPPLYNOW | PSH_PROPSHEETPAGE | PSH_USECALLBACK;
850 hdr.hInstance = hInstance;
851 if (pCertViewInfo->szTitle)
852 hdr.pszCaption = pCertViewInfo->szTitle;
853 else
854 hdr.pszCaption = MAKEINTRESOURCEW(IDS_CERTIFICATE);
855 init_general_page(pCertViewInfo, &pages[hdr.nPages++]);
856 /* Copy each additional page, and create the init dialog struct for it
858 if (pCertViewInfo->cPropSheetPages)
860 init = HeapAlloc(GetProcessHeap(), 0,
861 pCertViewInfo->cPropSheetPages *
862 sizeof(CRYPTUI_INITDIALOG_STRUCT));
863 if (init)
865 for (i = 0; i < pCertViewInfo->cPropSheetPages; i++)
867 memcpy(&pages[hdr.nPages + i],
868 &pCertViewInfo->rgPropSheetPages[i],
869 sizeof(PROPSHEETPAGEW));
870 init[i].lParam = pCertViewInfo->rgPropSheetPages[i].lParam;
871 init[i].pCertContext = pCertViewInfo->pCertContext;
872 pages[hdr.nPages + i].lParam = (LPARAM)&init[i];
874 if (pCertViewInfo->nStartPage & 0x8000)
876 /* Start page index is relative to the number of default
877 * pages
879 hdr.u2.nStartPage = pCertViewInfo->nStartPage + hdr.nPages;
881 else
882 hdr.u2.nStartPage = pCertViewInfo->nStartPage;
883 hdr.nPages = nPages;
884 ret = TRUE;
886 else
887 SetLastError(ERROR_OUTOFMEMORY);
889 else
891 /* Ignore the relative flag if there aren't any additional pages */
892 hdr.u2.nStartPage = pCertViewInfo->nStartPage & 0x7fff;
893 ret = TRUE;
895 if (ret)
897 INT_PTR l;
899 hdr.u3.ppsp = pages;
900 hdr.pfnCallback = cert_prop_sheet_proc;
901 l = PropertySheetW(&hdr);
902 if (l == 0)
904 SetLastError(ERROR_CANCELLED);
905 ret = FALSE;
908 HeapFree(GetProcessHeap(), 0, init);
909 HeapFree(GetProcessHeap(), 0, pages);
911 else
912 SetLastError(ERROR_OUTOFMEMORY);
913 FreeLibrary(lib);
914 return ret;
917 /***********************************************************************
918 * CryptUIDlgViewCertificateW (CRYPTUI.@)
920 BOOL WINAPI CryptUIDlgViewCertificateW(
921 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo, BOOL *pfPropertiesChanged)
923 static GUID generic_cert_verify = WINTRUST_ACTION_GENERIC_CERT_VERIFY;
924 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
925 WINTRUST_DATA wvt;
926 WINTRUST_CERT_INFO cert;
927 BOOL ret = FALSE;
928 CRYPT_PROVIDER_SGNR *signer;
929 CRYPT_PROVIDER_CERT *provCert = NULL;
931 TRACE("(%p, %p)\n", pCertViewInfo, pfPropertiesChanged);
933 if (pCertViewInfo->dwSize != sizeof(CRYPTUI_VIEWCERTIFICATE_STRUCTW))
935 SetLastError(ERROR_INVALID_PARAMETER);
936 return FALSE;
938 /* Make a local copy in case we have to call WinVerifyTrust ourselves */
939 memcpy(&viewInfo, pCertViewInfo, sizeof(viewInfo));
940 if (!viewInfo.u.hWVTStateData)
942 memset(&wvt, 0, sizeof(wvt));
943 wvt.cbStruct = sizeof(wvt);
944 wvt.dwUIChoice = WTD_UI_NONE;
945 if (viewInfo.dwFlags &
946 CRYPTUI_ENABLE_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT)
947 wvt.fdwRevocationChecks |= WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
948 if (viewInfo.dwFlags & CRYPTUI_ENABLE_REVOCATION_CHECK_END_CERT)
949 wvt.fdwRevocationChecks |= WTD_REVOCATION_CHECK_END_CERT;
950 if (viewInfo.dwFlags & CRYPTUI_ENABLE_REVOCATION_CHECK_CHAIN)
951 wvt.fdwRevocationChecks |= WTD_REVOCATION_CHECK_CHAIN;
952 wvt.dwUnionChoice = WTD_CHOICE_CERT;
953 memset(&cert, 0, sizeof(cert));
954 cert.cbStruct = sizeof(cert);
955 cert.psCertContext = (CERT_CONTEXT *)viewInfo.pCertContext;
956 cert.chStores = viewInfo.cStores;
957 cert.pahStores = viewInfo.rghStores;
958 wvt.u.pCert = &cert;
959 wvt.dwStateAction = WTD_STATEACTION_VERIFY;
960 WinVerifyTrust(NULL, &generic_cert_verify, &wvt);
961 viewInfo.u.pCryptProviderData =
962 WTHelperProvDataFromStateData(wvt.hWVTStateData);
963 signer = WTHelperGetProvSignerFromChain(
964 (CRYPT_PROVIDER_DATA *)viewInfo.u.pCryptProviderData, 0, FALSE, 0);
965 provCert = WTHelperGetProvCertFromChain(signer, 0);
966 ret = TRUE;
968 else
970 viewInfo.u.pCryptProviderData =
971 WTHelperProvDataFromStateData(viewInfo.u.hWVTStateData);
972 signer = WTHelperGetProvSignerFromChain(
973 (CRYPT_PROVIDER_DATA *)viewInfo.u.pCryptProviderData,
974 viewInfo.idxSigner, viewInfo.fCounterSigner,
975 viewInfo.idxCounterSigner);
976 provCert = WTHelperGetProvCertFromChain(signer, viewInfo.idxCert);
977 ret = TRUE;
979 if (ret)
981 ret = show_cert_dialog(&viewInfo, provCert, pfPropertiesChanged);
982 if (!viewInfo.u.hWVTStateData)
984 wvt.dwStateAction = WTD_STATEACTION_CLOSE;
985 WinVerifyTrust(NULL, &generic_cert_verify, &wvt);
988 return ret;
991 static PCCERT_CONTEXT make_cert_from_file(LPCWSTR fileName)
993 HANDLE file;
994 DWORD size, encoding = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
995 BYTE *buffer;
996 PCCERT_CONTEXT cert;
998 file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
999 OPEN_EXISTING, 0, NULL);
1000 if (file == INVALID_HANDLE_VALUE)
1002 WARN("can't open certificate file %s\n", debugstr_w(fileName));
1003 return NULL;
1005 if ((size = GetFileSize(file, NULL)))
1007 if ((buffer = HeapAlloc(GetProcessHeap(), 0, size)))
1009 DWORD read;
1010 if (!ReadFile(file, buffer, size, &read, NULL) || read != size)
1012 WARN("can't read certificate file %s\n", debugstr_w(fileName));
1013 HeapFree(GetProcessHeap(), 0, buffer);
1014 CloseHandle(file);
1015 return NULL;
1019 else
1021 WARN("empty file %s\n", debugstr_w(fileName));
1022 CloseHandle(file);
1023 return NULL;
1025 CloseHandle(file);
1026 cert = CertCreateCertificateContext(encoding, buffer, size);
1027 HeapFree(GetProcessHeap(), 0, buffer);
1028 return cert;
1031 /* Decodes a cert's basic constraints extension (either szOID_BASIC_CONSTRAINTS
1032 * or szOID_BASIC_CONSTRAINTS2, whichever is present) to determine if it
1033 * should be a CA. If neither extension is present, returns
1034 * defaultIfNotSpecified.
1036 static BOOL is_ca_cert(PCCERT_CONTEXT cert, BOOL defaultIfNotSpecified)
1038 BOOL isCA = defaultIfNotSpecified;
1039 PCERT_EXTENSION ext = CertFindExtension(szOID_BASIC_CONSTRAINTS,
1040 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
1042 if (ext)
1044 CERT_BASIC_CONSTRAINTS_INFO *info;
1045 DWORD size = 0;
1047 if (CryptDecodeObjectEx(X509_ASN_ENCODING, szOID_BASIC_CONSTRAINTS,
1048 ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG,
1049 NULL, (LPBYTE)&info, &size))
1051 if (info->SubjectType.cbData == 1)
1052 isCA = info->SubjectType.pbData[0] & CERT_CA_SUBJECT_FLAG;
1053 LocalFree(info);
1056 else
1058 ext = CertFindExtension(szOID_BASIC_CONSTRAINTS2,
1059 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
1060 if (ext)
1062 CERT_BASIC_CONSTRAINTS2_INFO info;
1063 DWORD size = sizeof(CERT_BASIC_CONSTRAINTS2_INFO);
1065 if (CryptDecodeObjectEx(X509_ASN_ENCODING,
1066 szOID_BASIC_CONSTRAINTS2, ext->Value.pbData, ext->Value.cbData,
1067 0, NULL, &info, &size))
1068 isCA = info.fCA;
1071 return isCA;
1074 static HCERTSTORE choose_store_for_cert(PCCERT_CONTEXT cert)
1076 static const WCHAR AddressBook[] = { 'A','d','d','r','e','s','s',
1077 'B','o','o','k',0 };
1078 static const WCHAR CA[] = { 'C','A',0 };
1079 LPCWSTR storeName;
1081 if (is_ca_cert(cert, TRUE))
1082 storeName = CA;
1083 else
1084 storeName = AddressBook;
1085 return CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0,
1086 CERT_SYSTEM_STORE_CURRENT_USER, storeName);
1089 BOOL WINAPI CryptUIWizImport(DWORD dwFlags, HWND hwndParent, LPCWSTR pwszWizardTitle,
1090 PCCRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc, HCERTSTORE hDestCertStore)
1092 BOOL ret;
1093 HCERTSTORE store;
1094 const CERT_CONTEXT *cert;
1095 BOOL freeCert = FALSE;
1097 TRACE("(0x%08x, %p, %s, %p, %p)\n", dwFlags, hwndParent, debugstr_w(pwszWizardTitle),
1098 pImportSrc, hDestCertStore);
1100 if (!(dwFlags & CRYPTUI_WIZ_NO_UI)) FIXME("UI not implemented\n");
1102 if (!pImportSrc ||
1103 pImportSrc->dwSize != sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO))
1105 SetLastError(E_INVALIDARG);
1106 return FALSE;
1109 switch (pImportSrc->dwSubjectChoice)
1111 case CRYPTUI_WIZ_IMPORT_SUBJECT_FILE:
1112 if (!(cert = make_cert_from_file(pImportSrc->u.pwszFileName)))
1114 WARN("unable to create certificate context\n");
1115 return FALSE;
1117 else
1118 freeCert = TRUE;
1119 break;
1120 case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_CONTEXT:
1121 cert = pImportSrc->u.pCertContext;
1122 if (!cert)
1124 SetLastError(E_INVALIDARG);
1125 return FALSE;
1127 break;
1128 default:
1129 FIXME("source type not implemented: %u\n", pImportSrc->dwSubjectChoice);
1130 SetLastError(E_INVALIDARG);
1131 return FALSE;
1133 if (hDestCertStore) store = hDestCertStore;
1134 else
1136 if (!(store = choose_store_for_cert(cert)))
1138 WARN("unable to open certificate store\n");
1139 CertFreeCertificateContext(cert);
1140 return FALSE;
1143 ret = CertAddCertificateContextToStore(store, cert, CERT_STORE_ADD_REPLACE_EXISTING, NULL);
1145 if (!hDestCertStore) CertCloseStore(store, 0);
1146 if (freeCert)
1147 CertFreeCertificateContext(cert);
1148 return ret;