[CRYPTUI] Sync with Wine Staging 3.17. CORE-15127
[reactos.git] / dll / win32 / cryptui / main.c
1 /*
2 * Copyright 2008 Juan Lang
3 *
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.
8 *
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.
13 *
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
17 */
18
19 #include "config.h"
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24 #define NONAMELESSUNION
25
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 "commdlg.h"
36 #include "commctrl.h"
37 #include "cryptuiapi.h"
38 #include "cryptuires.h"
39 #include "urlmon.h"
40 #include "hlink.h"
41 #include "winreg.h"
42 #include "wine/debug.h"
43 #include "wine/unicode.h"
44
45 WINE_DEFAULT_DEBUG_CHANNEL(cryptui);
46
47 static HINSTANCE hInstance;
48
49 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
50 {
51 TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
52
53 switch (fdwReason)
54 {
55 case DLL_WINE_PREATTACH:
56 return FALSE; /* prefer native version */
57 case DLL_PROCESS_ATTACH:
58 hInstance = hinstDLL;
59 DisableThreadLibraryCalls(hinstDLL);
60 break;
61 }
62 return TRUE;
63 }
64
65 #define MAX_STRING_LEN 512
66
67 static void add_cert_columns(HWND hwnd)
68 {
69 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
70 RECT rc;
71 WCHAR buf[MAX_STRING_LEN];
72 LVCOLUMNW column;
73
74 SendMessageW(lv, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
75 GetWindowRect(lv, &rc);
76 LoadStringW(hInstance, IDS_SUBJECT_COLUMN, buf, ARRAY_SIZE(buf));
77 column.mask = LVCF_WIDTH | LVCF_TEXT;
78 column.cx = (rc.right - rc.left) * 29 / 100 - 2;
79 column.pszText = buf;
80 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
81 LoadStringW(hInstance, IDS_ISSUER_COLUMN, buf, ARRAY_SIZE(buf));
82 SendMessageW(lv, LVM_INSERTCOLUMNW, 1, (LPARAM)&column);
83 column.cx = (rc.right - rc.left) * 16 / 100 - 2;
84 LoadStringW(hInstance, IDS_EXPIRATION_COLUMN, buf, ARRAY_SIZE(buf));
85 SendMessageW(lv, LVM_INSERTCOLUMNW, 2, (LPARAM)&column);
86 column.cx = (rc.right - rc.left) * 23 / 100 - 1;
87 LoadStringW(hInstance, IDS_FRIENDLY_NAME_COLUMN, buf, ARRAY_SIZE(buf));
88 SendMessageW(lv, LVM_INSERTCOLUMNW, 3, (LPARAM)&column);
89 }
90
91 static void add_cert_to_view(HWND lv, PCCERT_CONTEXT cert, DWORD *allocatedLen,
92 LPWSTR *str)
93 {
94 DWORD len;
95 LVITEMW item;
96 WCHAR dateFmt[80]; /* sufficient for LOCALE_SSHORTDATE */
97 WCHAR date[80];
98 SYSTEMTIME sysTime;
99 LPWSTR none;
100
101 item.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_TEXT;
102 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
103 item.iSubItem = 0;
104 item.iImage = 0;
105 item.lParam = (LPARAM)CertDuplicateCertificateContext(cert);
106 len = CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL,
107 NULL, 0);
108 if (len > *allocatedLen)
109 {
110 HeapFree(GetProcessHeap(), 0, *str);
111 *str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
112 if (*str)
113 *allocatedLen = len;
114 }
115 if (*str)
116 {
117 CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL,
118 *str, len);
119 item.pszText = *str;
120 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
121 }
122
123 item.mask = LVIF_TEXT;
124 len = CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
125 CERT_NAME_ISSUER_FLAG, NULL, NULL, 0);
126 if (len > *allocatedLen)
127 {
128 HeapFree(GetProcessHeap(), 0, *str);
129 *str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
130 if (*str)
131 *allocatedLen = len;
132 }
133 if (*str)
134 {
135 CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
136 CERT_NAME_ISSUER_FLAG, NULL, *str, len);
137 item.pszText = *str;
138 item.iSubItem = 1;
139 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
140 }
141
142 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SSHORTDATE, dateFmt, ARRAY_SIZE(dateFmt));
143 FileTimeToSystemTime(&cert->pCertInfo->NotAfter, &sysTime);
144 GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, date, ARRAY_SIZE(date));
145 item.pszText = date;
146 item.iSubItem = 2;
147 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
148
149 if (!CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID,
150 NULL, &len))
151 len = LoadStringW(hInstance, IDS_FRIENDLY_NAME_NONE, (LPWSTR)&none, 0);
152 if (len > *allocatedLen)
153 {
154 HeapFree(GetProcessHeap(), 0, *str);
155 *str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
156 if (*str)
157 *allocatedLen = len;
158 }
159 if (*str)
160 {
161 if (!CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID,
162 *str, &len))
163 item.pszText = none;
164 else
165 item.pszText = *str;
166 item.iSubItem = 3;
167 SendMessageW(lv, LVM_SETITEMTEXTW, item.iItem, (LPARAM)&item);
168 }
169 }
170
171 static LPSTR get_cert_mgr_usages(void)
172 {
173 static const WCHAR keyName[] = { 'S','o','f','t','w','a','r','e','\\','M',
174 'i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g','r','a',
175 'p','h','y','\\','U','I','\\','C','e','r','t','m','g','r','\\','P','u',
176 'r','p','o','s','e',0 };
177 LPSTR str = NULL;
178 HKEY key;
179
180 if (!RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, NULL, 0, KEY_READ,
181 NULL, &key, NULL))
182 {
183 LONG rc;
184 DWORD type, size;
185
186 rc = RegQueryValueExA(key, "Purpose", NULL, &type, NULL, &size);
187 if ((!rc || rc == ERROR_MORE_DATA) && type == REG_SZ)
188 {
189 str = HeapAlloc(GetProcessHeap(), 0, size);
190 if (str)
191 {
192 rc = RegQueryValueExA(key, "Purpose", NULL, NULL, (LPBYTE)str,
193 &size);
194 if (rc)
195 {
196 HeapFree(GetProcessHeap(), 0, str);
197 str = NULL;
198 }
199 }
200 }
201 RegCloseKey(key);
202 }
203 return str;
204 }
205
206 typedef enum {
207 PurposeFilterShowAll = 0,
208 PurposeFilterShowAdvanced = 1,
209 PurposeFilterShowOID = 2
210 } PurposeFilter;
211
212 static void initialize_purpose_selection(HWND hwnd)
213 {
214 HWND cb = GetDlgItem(hwnd, IDC_MGR_PURPOSE_SELECTION);
215 WCHAR buf[MAX_STRING_LEN];
216 LPSTR usages;
217 int index;
218
219 LoadStringW(hInstance, IDS_PURPOSE_ALL, buf, ARRAY_SIZE(buf));
220 index = SendMessageW(cb, CB_INSERTSTRING, -1, (LPARAM)buf);
221 SendMessageW(cb, CB_SETITEMDATA, index, (LPARAM)PurposeFilterShowAll);
222 LoadStringW(hInstance, IDS_PURPOSE_ADVANCED, buf, ARRAY_SIZE(buf));
223 index = SendMessageW(cb, CB_INSERTSTRING, -1, (LPARAM)buf);
224 SendMessageW(cb, CB_SETITEMDATA, index, (LPARAM)PurposeFilterShowAdvanced);
225 SendMessageW(cb, CB_SETCURSEL, 0, 0);
226 if ((usages = get_cert_mgr_usages()))
227 {
228 LPSTR ptr, comma;
229
230 for (ptr = usages, comma = strchr(ptr, ','); ptr && *ptr;
231 ptr = comma ? comma + 1 : NULL,
232 comma = ptr ? strchr(ptr, ',') : NULL)
233 {
234 PCCRYPT_OID_INFO info;
235
236 if (comma)
237 *comma = 0;
238 if ((info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, ptr, 0)))
239 {
240 index = SendMessageW(cb, CB_INSERTSTRING, 0,
241 (LPARAM)info->pwszName);
242 SendMessageW(cb, CB_SETITEMDATA, index, (LPARAM)info);
243 }
244 }
245 HeapFree(GetProcessHeap(), 0, usages);
246 }
247 }
248
249 extern BOOL WINAPI WTHelperGetKnownUsages(DWORD action,
250 PCCRYPT_OID_INFO **usages);
251
252 static CERT_ENHKEY_USAGE *add_oid_to_usage(CERT_ENHKEY_USAGE *usage, LPSTR oid)
253 {
254 if (!usage->cUsageIdentifier)
255 usage->rgpszUsageIdentifier = HeapAlloc(GetProcessHeap(), 0,
256 sizeof(LPSTR));
257 else
258 usage->rgpszUsageIdentifier = HeapReAlloc(GetProcessHeap(), 0,
259 usage->rgpszUsageIdentifier,
260 (usage->cUsageIdentifier + 1) * sizeof(LPSTR));
261 if (usage->rgpszUsageIdentifier)
262 usage->rgpszUsageIdentifier[usage->cUsageIdentifier++] = oid;
263 else
264 {
265 HeapFree(GetProcessHeap(), 0, usage);
266 usage = NULL;
267 }
268 return usage;
269 }
270
271 static CERT_ENHKEY_USAGE *convert_usages_str_to_usage(LPSTR usageStr)
272 {
273 CERT_ENHKEY_USAGE *usage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
274 sizeof(CERT_ENHKEY_USAGE));
275
276 if (usage)
277 {
278 LPSTR ptr, comma;
279
280 for (ptr = usageStr, comma = strchr(ptr, ','); usage && ptr && *ptr;
281 ptr = comma ? comma + 1 : NULL,
282 comma = ptr ? strchr(ptr, ',') : NULL)
283 {
284 if (comma)
285 *comma = 0;
286 usage = add_oid_to_usage(usage, ptr);
287 }
288 }
289 return usage;
290 }
291
292 static CERT_ENHKEY_USAGE *create_advanced_filter(void)
293 {
294 CERT_ENHKEY_USAGE *advancedUsage = HeapAlloc(GetProcessHeap(),
295 HEAP_ZERO_MEMORY, sizeof(CERT_ENHKEY_USAGE));
296
297 if (advancedUsage)
298 {
299 PCCRYPT_OID_INFO *usages;
300
301 if (WTHelperGetKnownUsages(1, &usages))
302 {
303 LPSTR disabledUsagesStr;
304
305 if ((disabledUsagesStr = get_cert_mgr_usages()))
306 {
307 CERT_ENHKEY_USAGE *disabledUsages =
308 convert_usages_str_to_usage(disabledUsagesStr);
309
310 if (disabledUsages)
311 {
312 PCCRYPT_OID_INFO *ptr;
313
314 for (ptr = usages; advancedUsage && *ptr; ptr++)
315 {
316 DWORD i;
317 BOOL disabled = FALSE;
318
319 for (i = 0; !disabled &&
320 i < disabledUsages->cUsageIdentifier; i++)
321 if (!strcmp(disabledUsages->rgpszUsageIdentifier[i],
322 (*ptr)->pszOID))
323 disabled = TRUE;
324 if (!disabled)
325 advancedUsage = add_oid_to_usage(advancedUsage,
326 (LPSTR)(*ptr)->pszOID);
327 }
328 /* The individual strings are pointers to disabledUsagesStr,
329 * so they're freed when it is.
330 */
331 HeapFree(GetProcessHeap(), 0,
332 disabledUsages->rgpszUsageIdentifier);
333 HeapFree(GetProcessHeap(), 0, disabledUsages);
334 }
335 HeapFree(GetProcessHeap(), 0, disabledUsagesStr);
336 }
337 WTHelperGetKnownUsages(2, &usages);
338 }
339 }
340 return advancedUsage;
341 }
342
343 static int CALLBACK cert_mgr_sort_by_subject(LPARAM lp1, LPARAM lp2, LPARAM lp);
344
345 static void show_store_certs(HWND hwnd, HCERTSTORE store)
346 {
347 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
348 HWND cb = GetDlgItem(hwnd, IDC_MGR_PURPOSE_SELECTION);
349 PCCERT_CONTEXT cert = NULL;
350 DWORD allocatedLen = 0;
351 LPWSTR str = NULL;
352 int index;
353 PurposeFilter filter = PurposeFilterShowAll;
354 LPCSTR oid = NULL;
355 CERT_ENHKEY_USAGE *advanced = NULL;
356
357 index = SendMessageW(cb, CB_GETCURSEL, 0, 0);
358 if (index >= 0)
359 {
360 INT_PTR data = SendMessageW(cb, CB_GETITEMDATA, index, 0);
361
362 if (!HIWORD(data))
363 filter = data;
364 else
365 {
366 PCCRYPT_OID_INFO info = (PCCRYPT_OID_INFO)data;
367
368 filter = PurposeFilterShowOID;
369 oid = info->pszOID;
370 }
371 }
372 if (filter == PurposeFilterShowAdvanced)
373 advanced = create_advanced_filter();
374 do {
375 cert = CertEnumCertificatesInStore(store, cert);
376 if (cert)
377 {
378 BOOL show = FALSE;
379
380 if (filter == PurposeFilterShowAll)
381 show = TRUE;
382 else
383 {
384 int numOIDs;
385 DWORD cbOIDs = 0;
386
387 if (CertGetValidUsages(1, &cert, &numOIDs, NULL, &cbOIDs))
388 {
389 if (numOIDs == -1)
390 {
391 /* -1 implies all usages are valid */
392 show = TRUE;
393 }
394 else
395 {
396 LPSTR *oids = HeapAlloc(GetProcessHeap(), 0, cbOIDs);
397
398 if (oids)
399 {
400 if (CertGetValidUsages(1, &cert, &numOIDs, oids,
401 &cbOIDs))
402 {
403 int i;
404
405 if (filter == PurposeFilterShowOID)
406 {
407 for (i = 0; !show && i < numOIDs; i++)
408 if (!strcmp(oids[i], oid))
409 show = TRUE;
410 }
411 else
412 {
413 for (i = 0; !show && i < numOIDs; i++)
414 {
415 DWORD j;
416
417 for (j = 0; !show &&
418 j < advanced->cUsageIdentifier; j++)
419 if (!strcmp(oids[i],
420 advanced->rgpszUsageIdentifier[j]))
421 show = TRUE;
422 }
423 }
424 }
425 HeapFree(GetProcessHeap(), 0, oids);
426 }
427 }
428 }
429 }
430 if (show)
431 add_cert_to_view(lv, cert, &allocatedLen, &str);
432 }
433 } while (cert);
434 HeapFree(GetProcessHeap(), 0, str);
435 if (advanced)
436 {
437 HeapFree(GetProcessHeap(), 0, advanced->rgpszUsageIdentifier);
438 HeapFree(GetProcessHeap(), 0, advanced);
439 }
440 SendMessageW(lv, LVM_SORTITEMSEX, (WPARAM)lv,
441 (LPARAM)cert_mgr_sort_by_subject);
442 }
443
444 static const WCHAR my[] = { 'M','y',0 };
445 static const WCHAR addressBook[] = {
446 'A','d','d','r','e','s','s','B','o','o','k',0 };
447 static const WCHAR ca[] = { 'C','A',0 };
448 static const WCHAR root[] = { 'R','o','o','t',0 };
449 static const WCHAR trustedPublisher[] = {
450 'T','r','u','s','t','e','d','P','u','b','l','i','s','h','e','r',0 };
451 static const WCHAR disallowed[] = { 'D','i','s','a','l','l','o','w','e','d',0 };
452
453 struct CertMgrStoreInfo
454 {
455 LPCWSTR name;
456 int removeWarning;
457 int removePluralWarning;
458 };
459
460 static const struct CertMgrStoreInfo defaultStoreList[] = {
461 { my, IDS_WARN_REMOVE_MY, IDS_WARN_REMOVE_PLURAL_MY },
462 { addressBook, IDS_WARN_REMOVE_ADDRESSBOOK,
463 IDS_WARN_REMOVE_PLURAL_ADDRESSBOOK },
464 { ca, IDS_WARN_REMOVE_CA, IDS_WARN_REMOVE_PLURAL_CA },
465 { root, IDS_WARN_REMOVE_ROOT, IDS_WARN_REMOVE_PLURAL_ROOT },
466 { trustedPublisher, IDS_WARN_REMOVE_TRUSTEDPUBLISHER,
467 IDS_WARN_REMOVE_PLURAL_TRUSTEDPUBLISHER },
468 { disallowed, IDS_WARN_REMOVE_DEFAULT },
469 };
470
471 static const struct CertMgrStoreInfo publisherStoreList[] = {
472 { root, IDS_WARN_REMOVE_ROOT, IDS_WARN_REMOVE_PLURAL_ROOT },
473 { trustedPublisher, IDS_WARN_REMOVE_TRUSTEDPUBLISHER,
474 IDS_WARN_REMOVE_PLURAL_TRUSTEDPUBLISHER },
475 { disallowed, IDS_WARN_REMOVE_PLURAL_DEFAULT },
476 };
477
478 struct CertMgrData
479 {
480 HIMAGELIST imageList;
481 LPCWSTR title;
482 DWORD nStores;
483 const struct CertMgrStoreInfo *stores;
484 };
485
486 static void show_cert_stores(HWND hwnd, DWORD dwFlags, struct CertMgrData *data)
487 {
488 const struct CertMgrStoreInfo *storeList;
489 int cStores, i;
490 HWND tab = GetDlgItem(hwnd, IDC_MGR_STORES);
491
492 if (dwFlags & CRYPTUI_CERT_MGR_PUBLISHER_TAB)
493 {
494 storeList = publisherStoreList;
495 cStores = ARRAY_SIZE(publisherStoreList);
496 }
497 else
498 {
499 storeList = defaultStoreList;
500 cStores = ARRAY_SIZE(defaultStoreList);
501 }
502 if (dwFlags & CRYPTUI_CERT_MGR_SINGLE_TAB_FLAG)
503 cStores = 1;
504 data->nStores = cStores;
505 data->stores = storeList;
506 for (i = 0; i < cStores; i++)
507 {
508 LPCWSTR name;
509 TCITEMW item;
510 HCERTSTORE store;
511
512 if (!(name = CryptFindLocalizedName(storeList[i].name)))
513 name = storeList[i].name;
514 store = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0,
515 CERT_SYSTEM_STORE_CURRENT_USER, storeList[i].name);
516 item.mask = TCIF_TEXT | TCIF_PARAM;
517 item.pszText = (LPWSTR)name;
518 item.lParam = (LPARAM)store;
519 SendMessageW(tab, TCM_INSERTITEMW, i, (LPARAM)&item);
520 }
521 }
522
523 static void free_certs(HWND lv)
524 {
525 LVITEMW item;
526 int items = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0), i;
527
528 for (i = 0; i < items; i++)
529 {
530 item.mask = LVIF_PARAM;
531 item.iItem = i;
532 item.iSubItem = 0;
533 SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item);
534 CertFreeCertificateContext((PCCERT_CONTEXT)item.lParam);
535 }
536 }
537
538 static HCERTSTORE cert_mgr_index_to_store(HWND tab, int index)
539 {
540 TCITEMW item;
541
542 item.mask = TCIF_PARAM;
543 SendMessageW(tab, TCM_GETITEMW, index, (LPARAM)&item);
544 return (HCERTSTORE)item.lParam;
545 }
546
547 static HCERTSTORE cert_mgr_current_store(HWND hwnd)
548 {
549 HWND tab = GetDlgItem(hwnd, IDC_MGR_STORES);
550
551 return cert_mgr_index_to_store(tab, SendMessageW(tab, TCM_GETCURSEL, 0, 0));
552 }
553
554 static void close_stores(HWND tab)
555 {
556 int i, tabs = SendMessageW(tab, TCM_GETITEMCOUNT, 0, 0);
557
558 for (i = 0; i < tabs; i++)
559 CertCloseStore(cert_mgr_index_to_store(tab, i), 0);
560 }
561
562 static void refresh_store_certs(HWND hwnd)
563 {
564 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
565
566 free_certs(lv);
567 SendMessageW(lv, LVM_DELETEALLITEMS, 0, 0);
568 show_store_certs(hwnd, cert_mgr_current_store(hwnd));
569 }
570
571 typedef enum {
572 CheckBitmapIndexUnchecked = 1,
573 CheckBitmapIndexChecked = 2,
574 CheckBitmapIndexDisabledUnchecked = 3,
575 CheckBitmapIndexDisabledChecked = 4
576 } CheckBitmapIndex;
577
578 static void add_known_usage(HWND lv, PCCRYPT_OID_INFO info,
579 CheckBitmapIndex state)
580 {
581 LVITEMW item;
582
583 item.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM;
584 item.state = INDEXTOSTATEIMAGEMASK(state);
585 item.stateMask = LVIS_STATEIMAGEMASK;
586 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
587 item.iSubItem = 0;
588 item.lParam = (LPARAM)info;
589 item.pszText = (LPWSTR)info->pwszName;
590 SendMessageW(lv, LVM_INSERTITEMW, 0, (LPARAM)&item);
591 }
592
593 static void add_known_usages_to_list(HWND lv, CheckBitmapIndex state)
594 {
595 PCCRYPT_OID_INFO *usages;
596
597 if (WTHelperGetKnownUsages(1, &usages))
598 {
599 PCCRYPT_OID_INFO *ptr;
600
601 for (ptr = usages; *ptr; ptr++)
602 add_known_usage(lv, *ptr, state);
603 WTHelperGetKnownUsages(2, &usages);
604 }
605 }
606
607 static void toggle_usage(HWND hwnd, int iItem)
608 {
609 LVITEMW item;
610 int res;
611 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
612
613 item.mask = LVIF_STATE;
614 item.iItem = iItem;
615 item.iSubItem = 0;
616 item.stateMask = LVIS_STATEIMAGEMASK;
617 res = SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item);
618 if (res)
619 {
620 int state = item.state >> 12;
621
622 item.state = INDEXTOSTATEIMAGEMASK(
623 state == CheckBitmapIndexChecked ? CheckBitmapIndexUnchecked :
624 CheckBitmapIndexChecked);
625 SendMessageW(lv, LVM_SETITEMSTATE, iItem, (LPARAM)&item);
626 }
627 }
628
629 static LONG_PTR find_oid_in_list(HWND lv, LPCSTR oid)
630 {
631 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
632 (void *)oid, CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
633 LONG_PTR ret;
634
635 if (oidInfo)
636 {
637 LVFINDINFOW findInfo;
638
639 findInfo.flags = LVFI_PARAM;
640 findInfo.lParam = (LPARAM)oidInfo;
641 ret = SendMessageW(lv, LVM_FINDITEMW, -1, (LPARAM)&findInfo);
642 }
643 else
644 {
645 LVFINDINFOA findInfo;
646
647 findInfo.flags = LVFI_STRING;
648 findInfo.psz = oid;
649 ret = SendMessageW(lv, LVM_FINDITEMA, -1, (LPARAM)&findInfo);
650 }
651 return ret;
652 }
653
654 static void save_cert_mgr_usages(HWND hwnd)
655 {
656 static const WCHAR keyName[] = { 'S','o','f','t','w','a','r','e','\\','M',
657 'i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g','r','a',
658 'p','h','y','\\','U','I','\\','C','e','r','t','m','g','r','\\','P','u',
659 'r','p','o','s','e',0 };
660 HKEY key;
661 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
662 int purposes = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0), i;
663 LVITEMW item;
664 LPSTR str = NULL;
665
666 item.mask = LVIF_STATE | LVIF_PARAM;
667 item.iSubItem = 0;
668 item.stateMask = LVIS_STATEIMAGEMASK;
669 for (i = 0; i < purposes; i++)
670 {
671 item.iItem = i;
672 if (SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item))
673 {
674 int state = item.state >> 12;
675
676 if (state == CheckBitmapIndexUnchecked)
677 {
678 CRYPT_OID_INFO *info = (CRYPT_OID_INFO *)item.lParam;
679 BOOL firstString = TRUE;
680
681 if (!str)
682 str = HeapAlloc(GetProcessHeap(), 0,
683 strlen(info->pszOID) + 1);
684 else
685 {
686 str = HeapReAlloc(GetProcessHeap(), 0, str,
687 strlen(str) + 1 + strlen(info->pszOID) + 1);
688 firstString = FALSE;
689 }
690 if (str)
691 {
692 LPSTR ptr = firstString ? str : str + strlen(str);
693
694 if (!firstString)
695 *ptr++ = ',';
696 strcpy(ptr, info->pszOID);
697 }
698 }
699 }
700 }
701 if (!RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, NULL, 0, KEY_ALL_ACCESS,
702 NULL, &key, NULL))
703 {
704 if (str)
705 RegSetValueExA(key, "Purpose", 0, REG_SZ, (const BYTE *)str,
706 strlen(str) + 1);
707 else
708 RegDeleteValueA(key, "Purpose");
709 RegCloseKey(key);
710 }
711 HeapFree(GetProcessHeap(), 0, str);
712 }
713
714 static LRESULT CALLBACK cert_mgr_advanced_dlg_proc(HWND hwnd, UINT msg,
715 WPARAM wp, LPARAM lp)
716 {
717 switch (msg)
718 {
719 case WM_INITDIALOG:
720 {
721 RECT rc;
722 LVCOLUMNW column;
723 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
724 HIMAGELIST imageList;
725 LPSTR disabledUsages;
726
727 GetWindowRect(lv, &rc);
728 column.mask = LVCF_WIDTH;
729 column.cx = rc.right - rc.left;
730 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
731 imageList = ImageList_Create(16, 16, ILC_COLOR4 | ILC_MASK, 4, 0);
732 if (imageList)
733 {
734 HBITMAP bmp;
735 COLORREF backColor = RGB(255, 0, 255);
736
737 bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_CHECKS));
738 ImageList_AddMasked(imageList, bmp, backColor);
739 DeleteObject(bmp);
740 ImageList_SetBkColor(imageList, CLR_NONE);
741 SendMessageW(lv, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)imageList);
742 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)imageList);
743 }
744 add_known_usages_to_list(lv, CheckBitmapIndexChecked);
745 if ((disabledUsages = get_cert_mgr_usages()))
746 {
747 LPSTR ptr, comma;
748
749 for (ptr = disabledUsages, comma = strchr(ptr, ','); ptr && *ptr;
750 ptr = comma ? comma + 1 : NULL,
751 comma = ptr ? strchr(ptr, ',') : NULL)
752 {
753 LONG_PTR index;
754
755 if (comma)
756 *comma = 0;
757 if ((index = find_oid_in_list(lv, ptr)) != -1)
758 toggle_usage(hwnd, index);
759 }
760 HeapFree(GetProcessHeap(), 0, disabledUsages);
761 }
762 break;
763 }
764 case WM_NOTIFY:
765 {
766 NMHDR *hdr = (NMHDR *)lp;
767 NMITEMACTIVATE *nm;
768
769 switch (hdr->code)
770 {
771 case NM_CLICK:
772 nm = (NMITEMACTIVATE *)lp;
773 toggle_usage(hwnd, nm->iItem);
774 SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
775 break;
776 }
777 break;
778 }
779 case WM_COMMAND:
780 switch (wp)
781 {
782 case IDOK:
783 save_cert_mgr_usages(hwnd);
784 ImageList_Destroy((HIMAGELIST)GetWindowLongPtrW(hwnd, DWLP_USER));
785 EndDialog(hwnd, IDOK);
786 break;
787 case IDCANCEL:
788 ImageList_Destroy((HIMAGELIST)GetWindowLongPtrW(hwnd, DWLP_USER));
789 EndDialog(hwnd, IDCANCEL);
790 break;
791 }
792 break;
793 }
794 return 0;
795 }
796
797 static void cert_mgr_clear_cert_selection(HWND hwnd)
798 {
799 WCHAR empty[] = { 0 };
800
801 EnableWindow(GetDlgItem(hwnd, IDC_MGR_EXPORT), FALSE);
802 EnableWindow(GetDlgItem(hwnd, IDC_MGR_REMOVE), FALSE);
803 EnableWindow(GetDlgItem(hwnd, IDC_MGR_VIEW), FALSE);
804 SendMessageW(GetDlgItem(hwnd, IDC_MGR_PURPOSES), WM_SETTEXT, 0,
805 (LPARAM)empty);
806 refresh_store_certs(hwnd);
807 }
808
809 static PCCERT_CONTEXT cert_mgr_index_to_cert(HWND hwnd, int index)
810 {
811 PCCERT_CONTEXT cert = NULL;
812 LVITEMW item;
813
814 item.mask = LVIF_PARAM;
815 item.iItem = index;
816 item.iSubItem = 0;
817 if (SendMessageW(GetDlgItem(hwnd, IDC_MGR_CERTS), LVM_GETITEMW, 0,
818 (LPARAM)&item))
819 cert = (PCCERT_CONTEXT)item.lParam;
820 return cert;
821 }
822
823 static void show_selected_cert(HWND hwnd, int index)
824 {
825 PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd, index);
826
827 if (cert)
828 {
829 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
830
831 memset(&viewInfo, 0, sizeof(viewInfo));
832 viewInfo.dwSize = sizeof(viewInfo);
833 viewInfo.hwndParent = hwnd;
834 viewInfo.pCertContext = cert;
835 /* FIXME: this should be modal */
836 CryptUIDlgViewCertificateW(&viewInfo, NULL);
837 }
838 }
839
840 static void cert_mgr_show_cert_usages(HWND hwnd, int index)
841 {
842 HWND text = GetDlgItem(hwnd, IDC_MGR_PURPOSES);
843 PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd, index);
844 PCERT_ENHKEY_USAGE usage;
845 DWORD size;
846
847 /* Get enhanced key usage. Have to check for a property and an extension
848 * separately, because CertGetEnhancedKeyUsage will succeed and return an
849 * empty usage if neither is set. Unfortunately an empty usage implies
850 * no usage is allowed, so we have to distinguish between the two cases.
851 */
852 if (CertGetEnhancedKeyUsage(cert, CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG,
853 NULL, &size))
854 {
855 usage = HeapAlloc(GetProcessHeap(), 0, size);
856 if (!CertGetEnhancedKeyUsage(cert,
857 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size))
858 {
859 HeapFree(GetProcessHeap(), 0, usage);
860 usage = NULL;
861 }
862 }
863 else if (CertGetEnhancedKeyUsage(cert, CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
864 NULL, &size))
865 {
866 usage = HeapAlloc(GetProcessHeap(), 0, size);
867 if (!CertGetEnhancedKeyUsage(cert,
868 CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, usage, &size))
869 {
870 HeapFree(GetProcessHeap(), 0, usage);
871 usage = NULL;
872 }
873 }
874 else
875 usage = NULL;
876 if (usage)
877 {
878 if (usage->cUsageIdentifier)
879 {
880 static const WCHAR commaSpace[] = { ',',' ',0 };
881 DWORD i, len = 1;
882 LPWSTR str, ptr;
883
884 for (i = 0; i < usage->cUsageIdentifier; i++)
885 {
886 PCCRYPT_OID_INFO info =
887 CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
888 usage->rgpszUsageIdentifier[i],
889 CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
890
891 if (info)
892 len += strlenW(info->pwszName);
893 else
894 len += strlen(usage->rgpszUsageIdentifier[i]);
895 if (i < usage->cUsageIdentifier - 1)
896 len += strlenW(commaSpace);
897 }
898 str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
899 if (str)
900 {
901 for (i = 0, ptr = str; i < usage->cUsageIdentifier; i++)
902 {
903 PCCRYPT_OID_INFO info =
904 CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
905 usage->rgpszUsageIdentifier[i],
906 CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
907
908 if (info)
909 {
910 strcpyW(ptr, info->pwszName);
911 ptr += strlenW(info->pwszName);
912 }
913 else
914 {
915 LPCSTR src = usage->rgpszUsageIdentifier[i];
916
917 for (; *src; ptr++, src++)
918 *ptr = *src;
919 *ptr = 0;
920 }
921 if (i < usage->cUsageIdentifier - 1)
922 {
923 strcpyW(ptr, commaSpace);
924 ptr += strlenW(commaSpace);
925 }
926 }
927 *ptr = 0;
928 SendMessageW(text, WM_SETTEXT, 0, (LPARAM)str);
929 HeapFree(GetProcessHeap(), 0, str);
930 }
931 HeapFree(GetProcessHeap(), 0, usage);
932 }
933 else
934 {
935 WCHAR buf[MAX_STRING_LEN];
936
937 LoadStringW(hInstance, IDS_ALLOWED_PURPOSE_NONE, buf, ARRAY_SIZE(buf));
938 SendMessageW(text, WM_SETTEXT, 0, (LPARAM)buf);
939 }
940 }
941 else
942 {
943 WCHAR buf[MAX_STRING_LEN];
944
945 LoadStringW(hInstance, IDS_ALLOWED_PURPOSE_ALL, buf, ARRAY_SIZE(buf));
946 SendMessageW(text, WM_SETTEXT, 0, (LPARAM)buf);
947 }
948 }
949
950 static void cert_mgr_do_remove(HWND hwnd)
951 {
952 int tabIndex = SendMessageW(GetDlgItem(hwnd, IDC_MGR_STORES),
953 TCM_GETCURSEL, 0, 0);
954 struct CertMgrData *data =
955 (struct CertMgrData *)GetWindowLongPtrW(hwnd, DWLP_USER);
956
957 if (tabIndex < data->nStores)
958 {
959 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
960 WCHAR warning[MAX_STRING_LEN], title[MAX_STRING_LEN];
961 LPCWSTR pTitle;
962 int warningID;
963
964 if (SendMessageW(lv, LVM_GETSELECTEDCOUNT, 0, 0) > 1)
965 warningID = data->stores[tabIndex].removePluralWarning;
966 else
967 warningID = data->stores[tabIndex].removeWarning;
968 if (data->title)
969 pTitle = data->title;
970 else
971 {
972 LoadStringW(hInstance, IDS_CERT_MGR, title, ARRAY_SIZE(title));
973 pTitle = title;
974 }
975 LoadStringW(hInstance, warningID, warning, ARRAY_SIZE(warning));
976 if (MessageBoxW(hwnd, warning, pTitle, MB_YESNO) == IDYES)
977 {
978 int selection = -1;
979
980 do {
981 selection = SendMessageW(lv, LVM_GETNEXTITEM, selection,
982 LVNI_SELECTED);
983 if (selection >= 0)
984 {
985 PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd,
986 selection);
987
988 CertDeleteCertificateFromStore(cert);
989 }
990 } while (selection >= 0);
991 cert_mgr_clear_cert_selection(hwnd);
992 }
993 }
994 }
995
996 static void cert_mgr_do_export(HWND hwnd)
997 {
998 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
999 int selectionCount = SendMessageW(lv, LVM_GETSELECTEDCOUNT, 0, 0);
1000
1001 if (selectionCount == 1)
1002 {
1003 int selection = SendMessageW(lv, LVM_GETNEXTITEM, -1,
1004 LVNI_SELECTED);
1005
1006 if (selection >= 0)
1007 {
1008 PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd, selection);
1009
1010 if (cert)
1011 {
1012 CRYPTUI_WIZ_EXPORT_INFO info;
1013
1014 info.dwSize = sizeof(info);
1015 info.pwszExportFileName = NULL;
1016 info.dwSubjectChoice = CRYPTUI_WIZ_EXPORT_CERT_CONTEXT;
1017 info.u.pCertContext = cert;
1018 info.cStores = 0;
1019 CryptUIWizExport(0, hwnd, NULL, &info, NULL);
1020 }
1021 }
1022 }
1023 else if (selectionCount > 1)
1024 {
1025 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
1026 CERT_STORE_CREATE_NEW_FLAG, NULL);
1027
1028 if (store)
1029 {
1030 CRYPTUI_WIZ_EXPORT_INFO info;
1031 int selection = -1;
1032
1033 info.dwSize = sizeof(info);
1034 info.pwszExportFileName = NULL;
1035 info.dwSubjectChoice =
1036 CRYPTUI_WIZ_EXPORT_CERT_STORE_CERTIFICATES_ONLY;
1037 info.u.hCertStore = store;
1038 info.cStores = 0;
1039 do {
1040 selection = SendMessageW(lv, LVM_GETNEXTITEM, selection,
1041 LVNI_SELECTED);
1042 if (selection >= 0)
1043 {
1044 PCCERT_CONTEXT cert = cert_mgr_index_to_cert(hwnd,
1045 selection);
1046
1047 CertAddCertificateContextToStore(store, cert,
1048 CERT_STORE_ADD_ALWAYS, NULL);
1049 }
1050 } while (selection >= 0);
1051 CryptUIWizExport(0, hwnd, NULL, &info, NULL);
1052 CertCloseStore(store, 0);
1053 }
1054 }
1055 }
1056
1057 static int cert_mgr_sort_by_text(HWND lv, int col, int index1, int index2)
1058 {
1059 LVITEMW item;
1060 WCHAR buf1[MAX_STRING_LEN];
1061 WCHAR buf2[MAX_STRING_LEN];
1062
1063 item.cchTextMax = ARRAY_SIZE(buf1);
1064 item.mask = LVIF_TEXT;
1065 item.pszText = buf1;
1066 item.iItem = index1;
1067 item.iSubItem = col;
1068 SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item);
1069 item.pszText = buf2;
1070 item.iItem = index2;
1071 SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item);
1072 return strcmpW(buf1, buf2);
1073 }
1074
1075 static int CALLBACK cert_mgr_sort_by_subject(LPARAM lp1, LPARAM lp2, LPARAM lp)
1076 {
1077 return cert_mgr_sort_by_text((HWND)lp, 0, lp1, lp2);
1078 }
1079
1080 static int CALLBACK cert_mgr_sort_by_issuer(LPARAM lp1, LPARAM lp2, LPARAM lp)
1081 {
1082 return cert_mgr_sort_by_text((HWND)lp, 1, lp1, lp2);
1083 }
1084
1085 static int CALLBACK cert_mgr_sort_by_date(LPARAM lp1, LPARAM lp2, LPARAM lp)
1086 {
1087 PCCERT_CONTEXT cert1 = (PCCERT_CONTEXT)lp1;
1088 PCCERT_CONTEXT cert2 = (PCCERT_CONTEXT)lp2;
1089 return CompareFileTime(&cert1->pCertInfo->NotAfter,
1090 &cert2->pCertInfo->NotAfter);
1091 }
1092
1093 static int CALLBACK cert_mgr_sort_by_friendly_name(LPARAM lp1, LPARAM lp2,
1094 LPARAM lp)
1095 {
1096 return cert_mgr_sort_by_text((HWND)lp, 3, lp1, lp2);
1097 }
1098
1099 static LRESULT CALLBACK cert_mgr_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
1100 LPARAM lp)
1101 {
1102 struct CertMgrData *data;
1103
1104 switch (msg)
1105 {
1106 case WM_INITDIALOG:
1107 {
1108 PCCRYPTUI_CERT_MGR_STRUCT pCryptUICertMgr =
1109 (PCCRYPTUI_CERT_MGR_STRUCT)lp;
1110 HWND tab = GetDlgItem(hwnd, IDC_MGR_STORES);
1111
1112 data = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CertMgrData));
1113 if (!data)
1114 return 0;
1115 data->imageList = ImageList_Create(16, 16, ILC_COLOR4 | ILC_MASK, 2, 0);
1116 if (data->imageList)
1117 {
1118 HBITMAP bmp;
1119 COLORREF backColor = RGB(255, 0, 255);
1120
1121 bmp = LoadBitmapW(hInstance, MAKEINTRESOURCEW(IDB_SMALL_ICONS));
1122 ImageList_AddMasked(data->imageList, bmp, backColor);
1123 DeleteObject(bmp);
1124 ImageList_SetBkColor(data->imageList, CLR_NONE);
1125 SendMessageW(GetDlgItem(hwnd, IDC_MGR_CERTS), LVM_SETIMAGELIST,
1126 LVSIL_SMALL, (LPARAM)data->imageList);
1127 }
1128 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)data);
1129 data->title = pCryptUICertMgr->pwszTitle;
1130
1131 initialize_purpose_selection(hwnd);
1132 add_cert_columns(hwnd);
1133 if (pCryptUICertMgr->pwszTitle)
1134 SendMessageW(hwnd, WM_SETTEXT, 0,
1135 (LPARAM)pCryptUICertMgr->pwszTitle);
1136 show_cert_stores(hwnd, pCryptUICertMgr->dwFlags, data);
1137 show_store_certs(hwnd, cert_mgr_index_to_store(tab, 0));
1138 break;
1139 }
1140 case WM_NOTIFY:
1141 {
1142 NMHDR *hdr = (NMHDR *)lp;
1143
1144 switch (hdr->code)
1145 {
1146 case TCN_SELCHANGE:
1147 cert_mgr_clear_cert_selection(hwnd);
1148 break;
1149 case LVN_ITEMCHANGED:
1150 {
1151 WCHAR empty[] = { 0 };
1152 NMITEMACTIVATE *nm = (NMITEMACTIVATE*)lp;
1153 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
1154 int numSelected = SendMessageW(lv, LVM_GETSELECTEDCOUNT, 0, 0);
1155
1156 EnableWindow(GetDlgItem(hwnd, IDC_MGR_EXPORT), numSelected > 0);
1157 EnableWindow(GetDlgItem(hwnd, IDC_MGR_REMOVE), numSelected > 0);
1158 EnableWindow(GetDlgItem(hwnd, IDC_MGR_VIEW), numSelected == 1);
1159 if (numSelected == 1)
1160 cert_mgr_show_cert_usages(hwnd, nm->iItem);
1161 else
1162 SendMessageW(GetDlgItem(hwnd, IDC_MGR_PURPOSES), WM_SETTEXT, 0,
1163 (LPARAM)empty);
1164 break;
1165 }
1166 case NM_DBLCLK:
1167 show_selected_cert(hwnd, ((NMITEMACTIVATE *)lp)->iItem);
1168 break;
1169 case LVN_KEYDOWN:
1170 {
1171 NMLVKEYDOWN *lvk = (NMLVKEYDOWN *)lp;
1172
1173 if (lvk->wVKey == VK_DELETE)
1174 cert_mgr_do_remove(hwnd);
1175 break;
1176 }
1177 case LVN_COLUMNCLICK:
1178 {
1179 NMLISTVIEW *nmlv = (NMLISTVIEW *)lp;
1180 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
1181
1182 /* FIXME: doesn't support swapping sort order between ascending
1183 * and descending.
1184 */
1185 switch (nmlv->iSubItem)
1186 {
1187 case 0:
1188 SendMessageW(lv, LVM_SORTITEMSEX, (WPARAM)lv,
1189 (LPARAM)cert_mgr_sort_by_subject);
1190 break;
1191 case 1:
1192 SendMessageW(lv, LVM_SORTITEMSEX, (WPARAM)lv,
1193 (LPARAM)cert_mgr_sort_by_issuer);
1194 break;
1195 case 2:
1196 SendMessageW(lv, LVM_SORTITEMS, 0,
1197 (LPARAM)cert_mgr_sort_by_date);
1198 break;
1199 case 3:
1200 SendMessageW(lv, LVM_SORTITEMSEX, (WPARAM)lv,
1201 (LPARAM)cert_mgr_sort_by_friendly_name);
1202 break;
1203 }
1204 break;
1205 }
1206 }
1207 break;
1208 }
1209 case WM_COMMAND:
1210 switch (wp)
1211 {
1212 case ((CBN_SELCHANGE << 16) | IDC_MGR_PURPOSE_SELECTION):
1213 cert_mgr_clear_cert_selection(hwnd);
1214 break;
1215 case IDC_MGR_IMPORT:
1216 if (CryptUIWizImport(0, hwnd, NULL, NULL,
1217 cert_mgr_current_store(hwnd)))
1218 refresh_store_certs(hwnd);
1219 break;
1220 case IDC_MGR_ADVANCED:
1221 if (DialogBoxW(hInstance, MAKEINTRESOURCEW(IDD_CERT_MGR_ADVANCED),
1222 hwnd, cert_mgr_advanced_dlg_proc) == IDOK)
1223 {
1224 HWND cb = GetDlgItem(hwnd, IDC_MGR_PURPOSE_SELECTION);
1225 int index, len;
1226 LPWSTR curString = NULL;
1227
1228 index = SendMessageW(cb, CB_GETCURSEL, 0, 0);
1229 if (index >= 0)
1230 {
1231 len = SendMessageW(cb, CB_GETLBTEXTLEN, index, 0);
1232 curString = HeapAlloc(GetProcessHeap(), 0,
1233 (len + 1) * sizeof(WCHAR));
1234 SendMessageW(cb, CB_GETLBTEXT, index, (LPARAM)curString);
1235 }
1236 SendMessageW(cb, CB_RESETCONTENT, 0, 0);
1237 initialize_purpose_selection(hwnd);
1238 if (curString)
1239 {
1240 index = SendMessageW(cb, CB_FINDSTRINGEXACT, -1,
1241 (LPARAM)curString);
1242 if (index >= 0)
1243 SendMessageW(cb, CB_SETCURSEL, index, 0);
1244 HeapFree(GetProcessHeap(), 0, curString);
1245 }
1246 refresh_store_certs(hwnd);
1247 }
1248 break;
1249 case IDC_MGR_VIEW:
1250 {
1251 HWND lv = GetDlgItem(hwnd, IDC_MGR_CERTS);
1252 int selection = SendMessageW(lv, LVM_GETNEXTITEM, -1,
1253 LVNI_SELECTED);
1254
1255 if (selection >= 0)
1256 show_selected_cert(hwnd, selection);
1257 break;
1258 }
1259 case IDC_MGR_EXPORT:
1260 cert_mgr_do_export(hwnd);
1261 break;
1262 case IDC_MGR_REMOVE:
1263 cert_mgr_do_remove(hwnd);
1264 break;
1265 case IDCANCEL:
1266 free_certs(GetDlgItem(hwnd, IDC_MGR_CERTS));
1267 close_stores(GetDlgItem(hwnd, IDC_MGR_STORES));
1268 data = (struct CertMgrData *)GetWindowLongPtrW(hwnd, DWLP_USER);
1269 ImageList_Destroy(data->imageList);
1270 HeapFree(GetProcessHeap(), 0, data);
1271 EndDialog(hwnd, IDCANCEL);
1272 break;
1273 }
1274 break;
1275 }
1276 return 0;
1277 }
1278
1279 /***********************************************************************
1280 * CryptUIDlgCertMgr (CRYPTUI.@)
1281 */
1282 BOOL WINAPI CryptUIDlgCertMgr(PCCRYPTUI_CERT_MGR_STRUCT pCryptUICertMgr)
1283 {
1284 TRACE("(%p)\n", pCryptUICertMgr);
1285
1286 if (pCryptUICertMgr->dwSize != sizeof(CRYPTUI_CERT_MGR_STRUCT))
1287 {
1288 WARN("unexpected size %d\n", pCryptUICertMgr->dwSize);
1289 SetLastError(E_INVALIDARG);
1290 return FALSE;
1291 }
1292 DialogBoxParamW(hInstance, MAKEINTRESOURCEW(IDD_CERT_MGR),
1293 pCryptUICertMgr->hwndParent, cert_mgr_dlg_proc, (LPARAM)pCryptUICertMgr);
1294 return TRUE;
1295 }
1296
1297 /* FIXME: real names are unknown, functions are undocumented */
1298 typedef struct _CRYPTUI_ENUM_SYSTEM_STORE_ARGS
1299 {
1300 DWORD dwFlags;
1301 void *pvSystemStoreLocationPara;
1302 } CRYPTUI_ENUM_SYSTEM_STORE_ARGS, *PCRYPTUI_ENUM_SYSTEM_STORE_ARGS;
1303
1304 typedef struct _CRYPTUI_ENUM_DATA
1305 {
1306 DWORD cStores;
1307 HCERTSTORE *rghStore;
1308 DWORD cEnumArgs;
1309 PCRYPTUI_ENUM_SYSTEM_STORE_ARGS rgEnumArgs;
1310 } CRYPTUI_ENUM_DATA, *PCRYPTUI_ENUM_DATA;
1311
1312 typedef BOOL (WINAPI *PFN_SELECTED_STORE_CB)(HCERTSTORE store, HWND hwnd,
1313 void *pvArg);
1314
1315 /* Values for dwFlags */
1316 #define CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE 0x00000001
1317
1318 typedef struct _CRYPTUI_SELECTSTORE_INFO_A
1319 {
1320 DWORD dwSize;
1321 HWND parent;
1322 DWORD dwFlags;
1323 LPSTR pszTitle;
1324 LPSTR pszText;
1325 CRYPTUI_ENUM_DATA *pEnumData;
1326 PFN_SELECTED_STORE_CB pfnSelectedStoreCallback;
1327 void *pvArg;
1328 } CRYPTUI_SELECTSTORE_INFO_A, *PCRYPTUI_SELECTSTORE_INFO_A;
1329
1330 typedef struct _CRYPTUI_SELECTSTORE_INFO_W
1331 {
1332 DWORD dwSize;
1333 HWND parent;
1334 DWORD dwFlags;
1335 LPWSTR pwszTitle;
1336 LPWSTR pwszText;
1337 CRYPTUI_ENUM_DATA *pEnumData;
1338 PFN_SELECTED_STORE_CB pfnSelectedStoreCallback;
1339 void *pvArg;
1340 } CRYPTUI_SELECTSTORE_INFO_W, *PCRYPTUI_SELECTSTORE_INFO_W;
1341
1342 struct StoreInfo
1343 {
1344 enum {
1345 StoreHandle,
1346 SystemStore
1347 } type;
1348 union {
1349 HCERTSTORE store;
1350 LPWSTR name;
1351 } DUMMYUNIONNAME;
1352 };
1353
1354 static BOOL WINAPI enum_store_callback(const void *pvSystemStore,
1355 DWORD dwFlags, PCERT_SYSTEM_STORE_INFO pStoreInfo, void *pvReserved,
1356 void *pvArg)
1357 {
1358 HWND tree = GetDlgItem(pvArg, IDC_STORE_LIST);
1359 TVINSERTSTRUCTW tvis;
1360 LPCWSTR localizedName;
1361 BOOL ret = TRUE;
1362
1363 tvis.hParent = NULL;
1364 tvis.hInsertAfter = TVI_LAST;
1365 tvis.u.item.mask = TVIF_TEXT;
1366 if ((localizedName = CryptFindLocalizedName(pvSystemStore)))
1367 {
1368 struct StoreInfo *storeInfo = HeapAlloc(GetProcessHeap(), 0,
1369 sizeof(struct StoreInfo));
1370
1371 if (storeInfo)
1372 {
1373 storeInfo->type = SystemStore;
1374 storeInfo->u.name = HeapAlloc(GetProcessHeap(), 0,
1375 (strlenW(pvSystemStore) + 1) * sizeof(WCHAR));
1376 if (storeInfo->u.name)
1377 {
1378 tvis.u.item.mask |= TVIF_PARAM;
1379 tvis.u.item.lParam = (LPARAM)storeInfo;
1380 strcpyW(storeInfo->u.name, pvSystemStore);
1381 }
1382 else
1383 {
1384 HeapFree(GetProcessHeap(), 0, storeInfo);
1385 ret = FALSE;
1386 }
1387 }
1388 else
1389 ret = FALSE;
1390 tvis.u.item.pszText = (LPWSTR)localizedName;
1391 }
1392 else
1393 tvis.u.item.pszText = (LPWSTR)pvSystemStore;
1394 /* FIXME: need a folder icon for the store too */
1395 if (ret)
1396 SendMessageW(tree, TVM_INSERTITEMW, 0, (LPARAM)&tvis);
1397 return ret;
1398 }
1399
1400 static void enumerate_stores(HWND hwnd, CRYPTUI_ENUM_DATA *pEnumData)
1401 {
1402 DWORD i;
1403 HWND tree = GetDlgItem(hwnd, IDC_STORE_LIST);
1404
1405 for (i = 0; i < pEnumData->cEnumArgs; i++)
1406 CertEnumSystemStore(pEnumData->rgEnumArgs[i].dwFlags,
1407 pEnumData->rgEnumArgs[i].pvSystemStoreLocationPara,
1408 hwnd, enum_store_callback);
1409 for (i = 0; i < pEnumData->cStores; i++)
1410 {
1411 DWORD size;
1412
1413 if (CertGetStoreProperty(pEnumData->rghStore[i],
1414 CERT_STORE_LOCALIZED_NAME_PROP_ID, NULL, &size))
1415 {
1416 LPWSTR name = HeapAlloc(GetProcessHeap(), 0, size);
1417
1418 if (name)
1419 {
1420 if (CertGetStoreProperty(pEnumData->rghStore[i],
1421 CERT_STORE_LOCALIZED_NAME_PROP_ID, name, &size))
1422 {
1423 struct StoreInfo *storeInfo = HeapAlloc(GetProcessHeap(),
1424 0, sizeof(struct StoreInfo));
1425
1426 if (storeInfo)
1427 {
1428 TVINSERTSTRUCTW tvis;
1429
1430 storeInfo->type = StoreHandle;
1431 storeInfo->u.store = pEnumData->rghStore[i];
1432 tvis.hParent = NULL;
1433 tvis.hInsertAfter = TVI_LAST;
1434 tvis.u.item.mask = TVIF_TEXT | TVIF_PARAM;
1435 tvis.u.item.pszText = name;
1436 tvis.u.item.lParam = (LPARAM)storeInfo;
1437 SendMessageW(tree, TVM_INSERTITEMW, 0, (LPARAM)&tvis);
1438 }
1439 }
1440 HeapFree(GetProcessHeap(), 0, name);
1441 }
1442 }
1443 }
1444 }
1445
1446 static void free_store_info(HWND tree)
1447 {
1448 HTREEITEM next = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM, TVGN_CHILD,
1449 0);
1450
1451 while (next)
1452 {
1453 TVITEMW item;
1454
1455 memset(&item, 0, sizeof(item));
1456 item.mask = TVIF_HANDLE | TVIF_PARAM;
1457 item.hItem = next;
1458 SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item);
1459 if (item.lParam)
1460 {
1461 struct StoreInfo *storeInfo = (struct StoreInfo *)item.lParam;
1462
1463 if (storeInfo->type == SystemStore)
1464 HeapFree(GetProcessHeap(), 0, storeInfo->u.name);
1465 HeapFree(GetProcessHeap(), 0, storeInfo);
1466 }
1467 next = (HTREEITEM)SendMessageW(tree, TVM_GETNEXTITEM, TVGN_NEXT,
1468 (LPARAM)next);
1469 }
1470 }
1471
1472 static HCERTSTORE selected_item_to_store(HWND tree, HTREEITEM hItem)
1473 {
1474 WCHAR buf[MAX_STRING_LEN];
1475 TVITEMW item;
1476 HCERTSTORE store;
1477
1478 memset(&item, 0, sizeof(item));
1479 item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_TEXT;
1480 item.hItem = hItem;
1481 item.cchTextMax = ARRAY_SIZE(buf);
1482 item.pszText = buf;
1483 SendMessageW(tree, TVM_GETITEMW, 0, (LPARAM)&item);
1484 if (item.lParam)
1485 {
1486 struct StoreInfo *storeInfo = (struct StoreInfo *)item.lParam;
1487
1488 if (storeInfo->type == StoreHandle)
1489 store = storeInfo->u.store;
1490 else
1491 store = CertOpenSystemStoreW(0, storeInfo->u.name);
1492 }
1493 else
1494 {
1495 /* It's implicitly a system store */
1496 store = CertOpenSystemStoreW(0, buf);
1497 }
1498 return store;
1499 }
1500
1501 struct SelectStoreInfo
1502 {
1503 PCRYPTUI_SELECTSTORE_INFO_W info;
1504 HCERTSTORE store;
1505 };
1506
1507 static LRESULT CALLBACK select_store_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
1508 LPARAM lp)
1509 {
1510 struct SelectStoreInfo *selectInfo;
1511 LRESULT ret = 0;
1512
1513 switch (msg)
1514 {
1515 case WM_INITDIALOG:
1516 {
1517 selectInfo = (struct SelectStoreInfo *)lp;
1518 SetWindowLongPtrW(hwnd, DWLP_USER, lp);
1519 if (selectInfo->info->pwszTitle)
1520 SendMessageW(hwnd, WM_SETTEXT, 0,
1521 (LPARAM)selectInfo->info->pwszTitle);
1522 if (selectInfo->info->pwszText)
1523 SendMessageW(GetDlgItem(hwnd, IDC_STORE_TEXT), WM_SETTEXT, 0,
1524 (LPARAM)selectInfo->info->pwszText);
1525 if (!(selectInfo->info->dwFlags & CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE))
1526 ShowWindow(GetDlgItem(hwnd, IDC_SHOW_PHYSICAL_STORES), FALSE);
1527 enumerate_stores(hwnd, selectInfo->info->pEnumData);
1528 break;
1529 }
1530 case WM_COMMAND:
1531 switch (wp)
1532 {
1533 case IDOK:
1534 {
1535 HWND tree = GetDlgItem(hwnd, IDC_STORE_LIST);
1536 HTREEITEM selection = (HTREEITEM)SendMessageW(tree,
1537 TVM_GETNEXTITEM, TVGN_CARET, 0);
1538
1539 selectInfo = (struct SelectStoreInfo *)GetWindowLongPtrW(hwnd,
1540 DWLP_USER);
1541 if (!selection)
1542 {
1543 WCHAR title[MAX_STRING_LEN], error[MAX_STRING_LEN], *pTitle;
1544
1545 if (selectInfo->info->pwszTitle)
1546 pTitle = selectInfo->info->pwszTitle;
1547 else
1548 {
1549 LoadStringW(hInstance, IDS_SELECT_STORE_TITLE, title, ARRAY_SIZE(title));
1550 pTitle = title;
1551 }
1552 LoadStringW(hInstance, IDS_SELECT_STORE, error, ARRAY_SIZE(error));
1553 MessageBoxW(hwnd, error, pTitle, MB_ICONEXCLAMATION | MB_OK);
1554 }
1555 else
1556 {
1557 HCERTSTORE store = selected_item_to_store(tree, selection);
1558
1559 if (!selectInfo->info->pfnSelectedStoreCallback ||
1560 selectInfo->info->pfnSelectedStoreCallback(store, hwnd,
1561 selectInfo->info->pvArg))
1562 {
1563 selectInfo->store = store;
1564 free_store_info(tree);
1565 EndDialog(hwnd, IDOK);
1566 }
1567 else
1568 CertCloseStore(store, 0);
1569 }
1570 ret = TRUE;
1571 break;
1572 }
1573 case IDCANCEL:
1574 free_store_info(GetDlgItem(hwnd, IDC_STORE_LIST));
1575 EndDialog(hwnd, IDCANCEL);
1576 ret = TRUE;
1577 break;
1578 }
1579 break;
1580 }
1581 return ret;
1582 }
1583
1584 /***********************************************************************
1585 * CryptUIDlgSelectStoreW (CRYPTUI.@)
1586 */
1587 HCERTSTORE WINAPI CryptUIDlgSelectStoreW(PCRYPTUI_SELECTSTORE_INFO_W info)
1588 {
1589 struct SelectStoreInfo selectInfo = { info, NULL };
1590
1591 TRACE("(%p)\n", info);
1592
1593 if (info->dwSize != sizeof(CRYPTUI_SELECTSTORE_INFO_W))
1594 {
1595 WARN("unexpected size %d\n", info->dwSize);
1596 SetLastError(E_INVALIDARG);
1597 return NULL;
1598 }
1599 DialogBoxParamW(hInstance, MAKEINTRESOURCEW(IDD_SELECT_STORE), info->parent,
1600 select_store_dlg_proc, (LPARAM)&selectInfo);
1601 return selectInfo.store;
1602 }
1603
1604 /***********************************************************************
1605 * CryptUIDlgSelectStoreA (CRYPTUI.@)
1606 */
1607 HCERTSTORE WINAPI CryptUIDlgSelectStoreA(PCRYPTUI_SELECTSTORE_INFO_A info)
1608 {
1609 CRYPTUI_SELECTSTORE_INFO_W infoW;
1610 HCERTSTORE ret;
1611 int len;
1612
1613 TRACE("(%p)\n", info);
1614
1615 if (info->dwSize != sizeof(CRYPTUI_SELECTSTORE_INFO_A))
1616 {
1617 WARN("unexpected size %d\n", info->dwSize);
1618 SetLastError(E_INVALIDARG);
1619 return NULL;
1620 }
1621 memcpy(&infoW, info, sizeof(*info));
1622 if (info->pszTitle)
1623 {
1624 len = MultiByteToWideChar(CP_ACP, 0, info->pszTitle, -1, NULL, 0);
1625 infoW.pwszTitle = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1626 MultiByteToWideChar(CP_ACP, 0, info->pszTitle, -1, infoW.pwszTitle,
1627 len);
1628 }
1629 if (info->pszText)
1630 {
1631 len = MultiByteToWideChar(CP_ACP, 0, info->pszText, -1, NULL, 0);
1632 infoW.pwszText = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1633 MultiByteToWideChar(CP_ACP, 0, info->pszText, -1, infoW.pwszText, len);
1634 }
1635 ret = CryptUIDlgSelectStoreW(&infoW);
1636 HeapFree(GetProcessHeap(), 0, infoW.pwszText);
1637 HeapFree(GetProcessHeap(), 0, infoW.pwszTitle);
1638 return ret;
1639 }
1640
1641 /***********************************************************************
1642 * CryptUIDlgViewCertificateA (CRYPTUI.@)
1643 */
1644 BOOL WINAPI CryptUIDlgViewCertificateA(
1645 PCCRYPTUI_VIEWCERTIFICATE_STRUCTA pCertViewInfo, BOOL *pfPropertiesChanged)
1646 {
1647 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo;
1648 LPWSTR title = NULL;
1649 BOOL ret;
1650
1651 TRACE("(%p, %p)\n", pCertViewInfo, pfPropertiesChanged);
1652
1653 memcpy(&viewInfo, pCertViewInfo, sizeof(viewInfo));
1654 if (pCertViewInfo->szTitle)
1655 {
1656 int len = MultiByteToWideChar(CP_ACP, 0, pCertViewInfo->szTitle, -1,
1657 NULL, 0);
1658
1659 title = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1660 if (title)
1661 {
1662 MultiByteToWideChar(CP_ACP, 0, pCertViewInfo->szTitle, -1, title,
1663 len);
1664 viewInfo.szTitle = title;
1665 }
1666 else
1667 {
1668 ret = FALSE;
1669 goto error;
1670 }
1671 }
1672 if (pCertViewInfo->cPropSheetPages)
1673 {
1674 FIXME("ignoring additional prop sheet pages\n");
1675 viewInfo.cPropSheetPages = 0;
1676 }
1677 ret = CryptUIDlgViewCertificateW(&viewInfo, pfPropertiesChanged);
1678 HeapFree(GetProcessHeap(), 0, title);
1679 error:
1680 return ret;
1681 }
1682
1683 struct ReadStringStruct
1684 {
1685 LPCWSTR buf;
1686 LONG pos;
1687 LONG len;
1688 };
1689
1690 static DWORD CALLBACK read_text_callback(DWORD_PTR dwCookie, LPBYTE buf,
1691 LONG cb, LONG *pcb)
1692 {
1693 struct ReadStringStruct *string = (struct ReadStringStruct *)dwCookie;
1694 LONG cch = min(cb / sizeof(WCHAR), string->len - string->pos);
1695
1696 TRACE("(%p, %p, %d, %p)\n", string, buf, cb, pcb);
1697
1698 memmove(buf, string->buf + string->pos, cch * sizeof(WCHAR));
1699 string->pos += cch;
1700 *pcb = cch * sizeof(WCHAR);
1701 return 0;
1702 }
1703
1704 static void add_unformatted_text_to_control(HWND hwnd, LPCWSTR text, LONG len)
1705 {
1706 struct ReadStringStruct string;
1707 EDITSTREAM editstream;
1708
1709 TRACE("(%p, %s)\n", hwnd, debugstr_wn(text, len));
1710
1711 string.buf = text;
1712 string.pos = 0;
1713 string.len = len;
1714 editstream.dwCookie = (DWORD_PTR)&string;
1715 editstream.dwError = 0;
1716 editstream.pfnCallback = read_text_callback;
1717 SendMessageW(hwnd, EM_STREAMIN, SF_TEXT | SFF_SELECTION | SF_UNICODE,
1718 (LPARAM)&editstream);
1719 }
1720
1721 static void add_string_resource_to_control(HWND hwnd, int id)
1722 {
1723 LPWSTR str;
1724 LONG len;
1725
1726 len = LoadStringW(hInstance, id, (LPWSTR)&str, 0);
1727 add_unformatted_text_to_control(hwnd, str, len);
1728 }
1729
1730 static void add_text_with_paraformat_to_control(HWND hwnd, LPCWSTR text,
1731 LONG len, const PARAFORMAT2 *fmt)
1732 {
1733 add_unformatted_text_to_control(hwnd, text, len);
1734 SendMessageW(hwnd, EM_SETPARAFORMAT, 0, (LPARAM)fmt);
1735 }
1736
1737 static void add_string_resource_with_paraformat_to_control(HWND hwnd, int id,
1738 const PARAFORMAT2 *fmt)
1739 {
1740 LPWSTR str;
1741 LONG len;
1742
1743 len = LoadStringW(hInstance, id, (LPWSTR)&str, 0);
1744 add_text_with_paraformat_to_control(hwnd, str, len, fmt);
1745 }
1746
1747 static LPWSTR get_cert_name_string(PCCERT_CONTEXT pCertContext, DWORD dwType,
1748 DWORD dwFlags)
1749 {
1750 LPWSTR buf = NULL;
1751 DWORD len;
1752
1753 len = CertGetNameStringW(pCertContext, dwType, dwFlags, NULL, NULL, 0);
1754 if (len)
1755 {
1756 buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1757 if (buf)
1758 CertGetNameStringW(pCertContext, dwType, dwFlags, NULL, buf, len);
1759 }
1760 return buf;
1761 }
1762
1763 static void add_cert_string_to_control(HWND hwnd, PCCERT_CONTEXT pCertContext,
1764 DWORD dwType, DWORD dwFlags)
1765 {
1766 LPWSTR name = get_cert_name_string(pCertContext, dwType, dwFlags);
1767
1768 if (name)
1769 {
1770 /* Don't include NULL-terminator in output */
1771 DWORD len = lstrlenW(name);
1772
1773 add_unformatted_text_to_control(hwnd, name, len);
1774 HeapFree(GetProcessHeap(), 0, name);
1775 }
1776 }
1777
1778 static void add_icon_to_control(HWND hwnd, int id)
1779 {
1780 HRESULT hr;
1781 IRichEditOle *richEditOle = NULL;
1782 IOleObject *object = NULL;
1783 CLSID clsid;
1784 LPOLECACHE oleCache = NULL;
1785 FORMATETC formatEtc;
1786 DWORD conn;
1787 IDataObject *dataObject = NULL;
1788 HBITMAP bitmap = NULL;
1789 STGMEDIUM stgm;
1790 IOleClientSite *clientSite = NULL;
1791 REOBJECT reObject;
1792
1793 TRACE("(%p, %d)\n", hwnd, id);
1794
1795 SendMessageW(hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&richEditOle);
1796 if (!richEditOle)
1797 goto end;
1798 hr = OleCreateDefaultHandler(&CLSID_NULL, NULL, &IID_IOleObject,
1799 (void**)&object);
1800 if (FAILED(hr))
1801 goto end;
1802 hr = IOleObject_GetUserClassID(object, &clsid);
1803 if (FAILED(hr))
1804 goto end;
1805 hr = IOleObject_QueryInterface(object, &IID_IOleCache, (void**)&oleCache);
1806 if (FAILED(hr))
1807 goto end;
1808 formatEtc.cfFormat = CF_BITMAP;
1809 formatEtc.ptd = NULL;
1810 formatEtc.dwAspect = DVASPECT_CONTENT;
1811 formatEtc.lindex = -1;
1812 formatEtc.tymed = TYMED_GDI;
1813 hr = IOleCache_Cache(oleCache, &formatEtc, 0, &conn);
1814 if (FAILED(hr))
1815 goto end;
1816 hr = IOleObject_QueryInterface(object, &IID_IDataObject,
1817 (void**)&dataObject);
1818 if (FAILED(hr))
1819 goto end;
1820 hr = IRichEditOle_GetClientSite(richEditOle, &clientSite);
1821 if (FAILED(hr))
1822 goto end;
1823 bitmap = LoadImageW(hInstance, MAKEINTRESOURCEW(id), IMAGE_BITMAP, 0, 0,
1824 LR_DEFAULTSIZE | LR_LOADTRANSPARENT);
1825 if (!bitmap)
1826 goto end;
1827 stgm.tymed = TYMED_GDI;
1828 stgm.u.hBitmap = bitmap;
1829 stgm.pUnkForRelease = NULL;
1830 hr = IDataObject_SetData(dataObject, &formatEtc, &stgm, TRUE);
1831 if (FAILED(hr))
1832 goto end;
1833
1834 reObject.cbStruct = sizeof(reObject);
1835 reObject.cp = REO_CP_SELECTION;
1836 reObject.clsid = clsid;
1837 reObject.poleobj = object;
1838 reObject.pstg = NULL;
1839 reObject.polesite = clientSite;
1840 reObject.sizel.cx = reObject.sizel.cy = 0;
1841 reObject.dvaspect = DVASPECT_CONTENT;
1842 reObject.dwFlags = 0;
1843 reObject.dwUser = 0;
1844
1845 IRichEditOle_InsertObject(richEditOle, &reObject);
1846
1847 end:
1848 if (clientSite)
1849 IOleClientSite_Release(clientSite);
1850 if (dataObject)
1851 IDataObject_Release(dataObject);
1852 if (oleCache)
1853 IOleCache_Release(oleCache);
1854 if (object)
1855 IOleObject_Release(object);
1856 if (richEditOle)
1857 IRichEditOle_Release(richEditOle);
1858 }
1859
1860 #define MY_INDENT 200
1861
1862 static void add_oid_text_to_control(HWND hwnd, char *oid)
1863 {
1864 WCHAR nl = '\n';
1865 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, oid, 0);
1866 PARAFORMAT2 parFmt;
1867
1868 parFmt.cbSize = sizeof(parFmt);
1869 parFmt.dwMask = PFM_STARTINDENT;
1870 parFmt.dxStartIndent = MY_INDENT * 3;
1871 if (oidInfo)
1872 {
1873 add_text_with_paraformat_to_control(hwnd, oidInfo->pwszName,
1874 lstrlenW(oidInfo->pwszName), &parFmt);
1875 add_unformatted_text_to_control(hwnd, &nl, 1);
1876 }
1877 }
1878
1879 struct OIDToString
1880 {
1881 LPCSTR oid;
1882 int id;
1883 };
1884
1885 /* The following list MUST be lexicographically sorted by OID */
1886 static struct OIDToString oidMap[] = {
1887 /* 1.3.6.1.4.1.311.10.3.1 */
1888 { szOID_KP_CTL_USAGE_SIGNING, IDS_PURPOSE_CTL_USAGE_SIGNING },
1889 /* 1.3.6.1.4.1.311.10.3.4 */
1890 { szOID_KP_EFS, IDS_PURPOSE_EFS },
1891 /* 1.3.6.1.4.1.311.10.3.4.1 */
1892 { szOID_EFS_RECOVERY, IDS_PURPOSE_EFS_RECOVERY },
1893 /* 1.3.6.1.4.1.311.10.3.5 */
1894 { szOID_WHQL_CRYPTO, IDS_PURPOSE_WHQL },
1895 /* 1.3.6.1.4.1.311.10.3.6 */
1896 { szOID_NT5_CRYPTO, IDS_PURPOSE_NT5 },
1897 /* 1.3.6.1.4.1.311.10.3.7 */
1898 { szOID_OEM_WHQL_CRYPTO, IDS_PURPOSE_OEM_WHQL },
1899 /* 1.3.6.1.4.1.311.10.3.8 */
1900 { szOID_EMBEDDED_NT_CRYPTO, IDS_PURPOSE_EMBEDDED_NT },
1901 /* 1.3.6.1.4.1.311.10.3.9 */
1902 { szOID_ROOT_LIST_SIGNER, IDS_PURPOSE_ROOT_LIST_SIGNER },
1903 /* 1.3.6.1.4.1.311.10.3.10 */
1904 { szOID_KP_QUALIFIED_SUBORDINATION, IDS_PURPOSE_QUALIFIED_SUBORDINATION },
1905 /* 1.3.6.1.4.1.311.10.3.11 */
1906 { szOID_KP_KEY_RECOVERY, IDS_PURPOSE_KEY_RECOVERY },
1907 /* 1.3.6.1.4.1.311.10.3.12 */
1908 { szOID_KP_DOCUMENT_SIGNING, IDS_PURPOSE_DOCUMENT_SIGNING },
1909 /* 1.3.6.1.4.1.311.10.3.13 */
1910 { szOID_KP_LIFETIME_SIGNING, IDS_PURPOSE_LIFETIME_SIGNING },
1911 /* 1.3.6.1.4.1.311.10.5.1 */
1912 { szOID_DRM, IDS_PURPOSE_DRM },
1913 /* 1.3.6.1.4.1.311.10.6.1 */
1914 { szOID_LICENSES, IDS_PURPOSE_LICENSES },
1915 /* 1.3.6.1.4.1.311.10.6.2 */
1916 { szOID_LICENSE_SERVER, IDS_PURPOSE_LICENSE_SERVER },
1917 /* 1.3.6.1.4.1.311.20.2.1 */
1918 { szOID_ENROLLMENT_AGENT, IDS_PURPOSE_ENROLLMENT_AGENT },
1919 /* 1.3.6.1.4.1.311.20.2.2 */
1920 { szOID_KP_SMARTCARD_LOGON, IDS_PURPOSE_SMARTCARD_LOGON },
1921 /* 1.3.6.1.4.1.311.21.5 */
1922 { szOID_KP_CA_EXCHANGE, IDS_PURPOSE_CA_EXCHANGE },
1923 /* 1.3.6.1.4.1.311.21.6 */
1924 { szOID_KP_KEY_RECOVERY_AGENT, IDS_PURPOSE_KEY_RECOVERY_AGENT },
1925 /* 1.3.6.1.4.1.311.21.19 */
1926 { szOID_DS_EMAIL_REPLICATION, IDS_PURPOSE_DS_EMAIL_REPLICATION },
1927 /* 1.3.6.1.5.5.7.3.1 */
1928 { szOID_PKIX_KP_SERVER_AUTH, IDS_PURPOSE_SERVER_AUTH },
1929 /* 1.3.6.1.5.5.7.3.2 */
1930 { szOID_PKIX_KP_CLIENT_AUTH, IDS_PURPOSE_CLIENT_AUTH },
1931 /* 1.3.6.1.5.5.7.3.3 */
1932 { szOID_PKIX_KP_CODE_SIGNING, IDS_PURPOSE_CODE_SIGNING },
1933 /* 1.3.6.1.5.5.7.3.4 */
1934 { szOID_PKIX_KP_EMAIL_PROTECTION, IDS_PURPOSE_EMAIL_PROTECTION },
1935 /* 1.3.6.1.5.5.7.3.5 */
1936 { szOID_PKIX_KP_IPSEC_END_SYSTEM, IDS_PURPOSE_IPSEC },
1937 /* 1.3.6.1.5.5.7.3.6 */
1938 { szOID_PKIX_KP_IPSEC_TUNNEL, IDS_PURPOSE_IPSEC },
1939 /* 1.3.6.1.5.5.7.3.7 */
1940 { szOID_PKIX_KP_IPSEC_USER, IDS_PURPOSE_IPSEC },
1941 /* 1.3.6.1.5.5.7.3.8 */
1942 { szOID_PKIX_KP_TIMESTAMP_SIGNING, IDS_PURPOSE_TIMESTAMP_SIGNING },
1943 };
1944
1945 static struct OIDToString *findSupportedOID(LPCSTR oid)
1946 {
1947 int indexHigh = ARRAY_SIZE(oidMap) - 1, indexLow = 0;
1948
1949 while (indexLow <= indexHigh)
1950 {
1951 int cmp, i = (indexLow + indexHigh) / 2;
1952 if (!(cmp = strcmp(oid, oidMap[i].oid)))
1953 return &oidMap[i];
1954 if (cmp > 0)
1955 indexLow = i + 1;
1956 else
1957 indexHigh = i - 1;
1958 }
1959 return NULL;
1960 }
1961
1962 static void add_local_oid_text_to_control(HWND text, LPCSTR oid)
1963 {
1964 struct OIDToString *entry;
1965 WCHAR nl = '\n';
1966 PARAFORMAT2 parFmt;
1967
1968 parFmt.cbSize = sizeof(parFmt);
1969 parFmt.dwMask = PFM_STARTINDENT;
1970 parFmt.dxStartIndent = MY_INDENT * 3;
1971 if ((entry = findSupportedOID(oid)))
1972 {
1973 WCHAR *str, *linebreak, *ptr;
1974 BOOL multiline = FALSE;
1975 int len;
1976
1977 len = LoadStringW(hInstance, entry->id, (LPWSTR)&str, 0);
1978 ptr = str;
1979 do {
1980 if ((linebreak = memchrW(ptr, '\n', len)))
1981 {
1982 WCHAR copy[MAX_STRING_LEN];
1983
1984 multiline = TRUE;
1985 /* The source string contains a newline, which the richedit
1986 * control won't find since it's interpreted as a paragraph
1987 * break. Therefore copy up to the newline. lstrcpynW always
1988 * NULL-terminates, so pass one more than the length of the
1989 * source line so the copy includes the entire line and the
1990 * NULL-terminator.
1991 */
1992 lstrcpynW(copy, ptr, linebreak - ptr + 1);
1993 add_text_with_paraformat_to_control(text, copy,
1994 linebreak - ptr, &parFmt);
1995 ptr = linebreak + 1;
1996 add_unformatted_text_to_control(text, &nl, 1);
1997 }
1998 else if (multiline && *ptr)
1999 {
2000 /* Add the last line */
2001 add_text_with_paraformat_to_control(text, ptr,
2002 len - (ptr - str), &parFmt);
2003 add_unformatted_text_to_control(text, &nl, 1);
2004 }
2005 } while (linebreak);
2006 if (!multiline)
2007 {
2008 add_text_with_paraformat_to_control(text, str, len, &parFmt);
2009 add_unformatted_text_to_control(text, &nl, 1);
2010 }
2011 }
2012 else
2013 {
2014 WCHAR *oidW = HeapAlloc(GetProcessHeap(), 0,
2015 (strlen(oid) + 1) * sizeof(WCHAR));
2016
2017 if (oidW)
2018 {
2019 LPCSTR src;
2020 WCHAR *dst;
2021
2022 for (src = oid, dst = oidW; *src; src++, dst++)
2023 *dst = *src;
2024 *dst = 0;
2025 add_text_with_paraformat_to_control(text, oidW, lstrlenW(oidW),
2026 &parFmt);
2027 add_unformatted_text_to_control(text, &nl, 1);
2028 HeapFree(GetProcessHeap(), 0, oidW);
2029 }
2030 }
2031 }
2032
2033 static void display_app_usages(HWND text, PCCERT_CONTEXT cert,
2034 BOOL *anyUsageAdded)
2035 {
2036 static char any_app_policy[] = szOID_ANY_APPLICATION_POLICY;
2037 WCHAR nl = '\n';
2038 CHARFORMATW charFmt;
2039 PCERT_EXTENSION policyExt;
2040 if (!*anyUsageAdded)
2041 {
2042 PARAFORMAT2 parFmt;
2043
2044 parFmt.cbSize = sizeof(parFmt);
2045 parFmt.dwMask = PFM_STARTINDENT;
2046 parFmt.dxStartIndent = MY_INDENT;
2047 add_string_resource_with_paraformat_to_control(text,
2048 IDS_CERT_INFO_PURPOSES, &parFmt);
2049 add_unformatted_text_to_control(text, &nl, 1);
2050 *anyUsageAdded = TRUE;
2051 }
2052 memset(&charFmt, 0, sizeof(charFmt));
2053 charFmt.cbSize = sizeof(charFmt);
2054 charFmt.dwMask = CFM_BOLD;
2055 charFmt.dwEffects = 0;
2056 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2057 if ((policyExt = CertFindExtension(szOID_APPLICATION_CERT_POLICIES,
2058 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension)))
2059 {
2060 CERT_POLICIES_INFO *policies;
2061 DWORD size;
2062
2063 if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_POLICIES,
2064 policyExt->Value.pbData, policyExt->Value.cbData,
2065 CRYPT_DECODE_ALLOC_FLAG, NULL, &policies, &size))
2066 {
2067 DWORD i;
2068
2069 for (i = 0; i < policies->cPolicyInfo; i++)
2070 {
2071 DWORD j;
2072
2073 for (j = 0; j < policies->rgPolicyInfo[i].cPolicyQualifier; j++)
2074 add_local_oid_text_to_control(text,
2075 policies->rgPolicyInfo[i].rgPolicyQualifier[j].
2076 pszPolicyQualifierId);
2077 }
2078 LocalFree(policies);
2079 }
2080 }
2081 else
2082 add_oid_text_to_control(text, any_app_policy);
2083 }
2084
2085 static BOOL display_cert_usages(HWND text, PCCERT_CONTEXT cert,
2086 BOOL *anyUsageAdded)
2087 {
2088 WCHAR nl = '\n';
2089 DWORD size;
2090 BOOL badUsages = FALSE;
2091
2092 if (CertGetEnhancedKeyUsage(cert, 0, NULL, &size))
2093 {
2094 CHARFORMATW charFmt;
2095 static char any_cert_policy[] = szOID_ANY_CERT_POLICY;
2096 PCERT_ENHKEY_USAGE usage = HeapAlloc(GetProcessHeap(), 0, size);
2097
2098 if (usage)
2099 {
2100 if (CertGetEnhancedKeyUsage(cert, 0, usage, &size))
2101 {
2102 DWORD i;
2103
2104 if (!*anyUsageAdded)
2105 {
2106 PARAFORMAT2 parFmt;
2107
2108 parFmt.cbSize = sizeof(parFmt);
2109 parFmt.dwMask = PFM_STARTINDENT;
2110 parFmt.dxStartIndent = MY_INDENT;
2111 add_string_resource_with_paraformat_to_control(text,
2112 IDS_CERT_INFO_PURPOSES, &parFmt);
2113 add_unformatted_text_to_control(text, &nl, 1);
2114 *anyUsageAdded = TRUE;
2115 }
2116 memset(&charFmt, 0, sizeof(charFmt));
2117 charFmt.cbSize = sizeof(charFmt);
2118 charFmt.dwMask = CFM_BOLD;
2119 charFmt.dwEffects = 0;
2120 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION,
2121 (LPARAM)&charFmt);
2122 if (!usage->cUsageIdentifier)
2123 add_oid_text_to_control(text, any_cert_policy);
2124 else
2125 for (i = 0; i < usage->cUsageIdentifier; i++)
2126 add_local_oid_text_to_control(text,
2127 usage->rgpszUsageIdentifier[i]);
2128 }
2129 else
2130 badUsages = TRUE;
2131 HeapFree(GetProcessHeap(), 0, usage);
2132 }
2133 else
2134 badUsages = TRUE;
2135 }
2136 else
2137 badUsages = TRUE;
2138 return badUsages;
2139 }
2140
2141 static void set_policy_text(HWND text,
2142 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
2143 {
2144 BOOL includeCertUsages = FALSE, includeAppUsages = FALSE;
2145 BOOL badUsages = FALSE, anyUsageAdded = FALSE;
2146
2147 if (pCertViewInfo->cPurposes)
2148 {
2149 DWORD i;
2150
2151 for (i = 0; i < pCertViewInfo->cPurposes; i++)
2152 {
2153 if (!strcmp(pCertViewInfo->rgszPurposes[i], szOID_ANY_CERT_POLICY))
2154 includeCertUsages = TRUE;
2155 else if (!strcmp(pCertViewInfo->rgszPurposes[i],
2156 szOID_ANY_APPLICATION_POLICY))
2157 includeAppUsages = TRUE;
2158 else
2159 badUsages = TRUE;
2160 }
2161 }
2162 else
2163 includeAppUsages = includeCertUsages = TRUE;
2164 if (includeAppUsages)
2165 display_app_usages(text, pCertViewInfo->pCertContext, &anyUsageAdded);
2166 if (includeCertUsages)
2167 badUsages = display_cert_usages(text, pCertViewInfo->pCertContext,
2168 &anyUsageAdded);
2169 if (badUsages)
2170 {
2171 PARAFORMAT2 parFmt;
2172
2173 parFmt.cbSize = sizeof(parFmt);
2174 parFmt.dwMask = PFM_STARTINDENT;
2175 parFmt.dxStartIndent = MY_INDENT;
2176 add_string_resource_with_paraformat_to_control(text,
2177 IDS_CERT_INFO_BAD_PURPOSES, &parFmt);
2178 }
2179 }
2180
2181 static CRYPT_OBJID_BLOB *find_policy_qualifier(CERT_POLICIES_INFO *policies,
2182 LPCSTR policyOid)
2183 {
2184 CRYPT_OBJID_BLOB *ret = NULL;
2185 DWORD i;
2186
2187 for (i = 0; !ret && i < policies->cPolicyInfo; i++)
2188 {
2189 DWORD j;
2190
2191 for (j = 0; !ret && j < policies->rgPolicyInfo[i].cPolicyQualifier; j++)
2192 if (!strcmp(policies->rgPolicyInfo[i].rgPolicyQualifier[j].
2193 pszPolicyQualifierId, policyOid))
2194 ret = &policies->rgPolicyInfo[i].rgPolicyQualifier[j].
2195 Qualifier;
2196 }
2197 return ret;
2198 }
2199
2200 static WCHAR *get_cps_str_from_qualifier(const CRYPT_OBJID_BLOB *qualifier)
2201 {
2202 LPWSTR qualifierStr = NULL;
2203 CERT_NAME_VALUE *qualifierValue;
2204 DWORD size;
2205
2206 if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME_VALUE,
2207 qualifier->pbData, qualifier->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL,
2208 &qualifierValue, &size))
2209 {
2210 size = CertRDNValueToStrW(qualifierValue->dwValueType,
2211 &qualifierValue->Value, NULL, 0);
2212 qualifierStr = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
2213 if (qualifierStr)
2214 CertRDNValueToStrW(qualifierValue->dwValueType,
2215 &qualifierValue->Value, qualifierStr, size);
2216 LocalFree(qualifierValue);
2217 }
2218 return qualifierStr;
2219 }
2220
2221 static WCHAR *get_user_notice_from_qualifier(const CRYPT_OBJID_BLOB *qualifier)
2222 {
2223 LPWSTR str = NULL;
2224 CERT_POLICY_QUALIFIER_USER_NOTICE *qualifierValue;
2225 DWORD size;
2226
2227 if (CryptDecodeObjectEx(X509_ASN_ENCODING,
2228 X509_PKIX_POLICY_QUALIFIER_USERNOTICE,
2229 qualifier->pbData, qualifier->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL,
2230 &qualifierValue, &size))
2231 {
2232 str = HeapAlloc(GetProcessHeap(), 0,
2233 (strlenW(qualifierValue->pszDisplayText) + 1) * sizeof(WCHAR));
2234 if (str)
2235 strcpyW(str, qualifierValue->pszDisplayText);
2236 LocalFree(qualifierValue);
2237 }
2238 return str;
2239 }
2240
2241 struct IssuerStatement
2242 {
2243 LPWSTR cps;
2244 LPWSTR userNotice;
2245 };
2246
2247 static void set_issuer_statement(HWND hwnd,
2248 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
2249 {
2250 PCERT_EXTENSION policyExt;
2251
2252 if (!(pCertViewInfo->dwFlags & CRYPTUI_DISABLE_ISSUERSTATEMENT) &&
2253 (policyExt = CertFindExtension(szOID_CERT_POLICIES,
2254 pCertViewInfo->pCertContext->pCertInfo->cExtension,
2255 pCertViewInfo->pCertContext->pCertInfo->rgExtension)))
2256 {
2257 CERT_POLICIES_INFO *policies;
2258 DWORD size;
2259
2260 if (CryptDecodeObjectEx(X509_ASN_ENCODING, policyExt->pszObjId,
2261 policyExt->Value.pbData, policyExt->Value.cbData,
2262 CRYPT_DECODE_ALLOC_FLAG, NULL, &policies, &size))
2263 {
2264 CRYPT_OBJID_BLOB *qualifier;
2265 LPWSTR cps = NULL, userNotice = NULL;
2266
2267 if ((qualifier = find_policy_qualifier(policies,
2268 szOID_PKIX_POLICY_QUALIFIER_CPS)))
2269 cps = get_cps_str_from_qualifier(qualifier);
2270 if ((qualifier = find_policy_qualifier(policies,
2271 szOID_PKIX_POLICY_QUALIFIER_USERNOTICE)))
2272 userNotice = get_user_notice_from_qualifier(qualifier);
2273 if (cps || userNotice)
2274 {
2275 struct IssuerStatement *issuerStatement =
2276 HeapAlloc(GetProcessHeap(), 0, sizeof(struct IssuerStatement));
2277
2278 if (issuerStatement)
2279 {
2280 issuerStatement->cps = cps;
2281 issuerStatement->userNotice = userNotice;
2282 EnableWindow(GetDlgItem(hwnd, IDC_ISSUERSTATEMENT), TRUE);
2283 SetWindowLongPtrW(hwnd, DWLP_USER,
2284 (ULONG_PTR)issuerStatement);
2285 }
2286 }
2287 LocalFree(policies);
2288 }
2289 }
2290 }
2291
2292 static void set_cert_info(HWND hwnd,
2293 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
2294 {
2295 CHARFORMATW charFmt;
2296 PARAFORMAT2 parFmt;
2297 HWND icon = GetDlgItem(hwnd, IDC_CERTIFICATE_ICON);
2298 HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_INFO);
2299 CRYPT_PROVIDER_SGNR *provSigner = WTHelperGetProvSignerFromChain(
2300 (CRYPT_PROVIDER_DATA *)pCertViewInfo->u.pCryptProviderData,
2301 pCertViewInfo->idxSigner, pCertViewInfo->fCounterSigner,
2302 pCertViewInfo->idxCounterSigner);
2303 CRYPT_PROVIDER_CERT *root =
2304 &provSigner->pasCertChain[provSigner->csCertChain - 1];
2305
2306 if (!provSigner->pChainContext ||
2307 (provSigner->pChainContext->TrustStatus.dwErrorStatus &
2308 CERT_TRUST_IS_PARTIAL_CHAIN))
2309 add_icon_to_control(icon, IDB_CERT_WARNING);
2310 else if (!root->fTrustedRoot)
2311 add_icon_to_control(icon, IDB_CERT_ERROR);
2312 else
2313 add_icon_to_control(icon, IDB_CERT);
2314
2315 memset(&charFmt, 0, sizeof(charFmt));
2316 charFmt.cbSize = sizeof(charFmt);
2317 charFmt.dwMask = CFM_BOLD;
2318 charFmt.dwEffects = CFE_BOLD;
2319 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2320 /* FIXME: vertically center text */
2321 parFmt.cbSize = sizeof(parFmt);
2322 parFmt.dwMask = PFM_STARTINDENT;
2323 parFmt.dxStartIndent = MY_INDENT;
2324 add_string_resource_with_paraformat_to_control(text,
2325 IDS_CERTIFICATEINFORMATION, &parFmt);
2326
2327 text = GetDlgItem(hwnd, IDC_CERTIFICATE_STATUS);
2328 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2329 if (provSigner->dwError == TRUST_E_CERT_SIGNATURE)
2330 add_string_resource_with_paraformat_to_control(text,
2331 IDS_CERT_INFO_BAD_SIG, &parFmt);
2332 else if (!provSigner->pChainContext ||
2333 (provSigner->pChainContext->TrustStatus.dwErrorStatus &
2334 CERT_TRUST_IS_PARTIAL_CHAIN))
2335 add_string_resource_with_paraformat_to_control(text,
2336 IDS_CERT_INFO_PARTIAL_CHAIN, &parFmt);
2337 else if (!root->fTrustedRoot)
2338 {
2339 if (provSigner->csCertChain == 1 && root->fSelfSigned)
2340 add_string_resource_with_paraformat_to_control(text,
2341 IDS_CERT_INFO_UNTRUSTED_CA, &parFmt);
2342 else
2343 add_string_resource_with_paraformat_to_control(text,
2344 IDS_CERT_INFO_UNTRUSTED_ROOT, &parFmt);
2345 }
2346 else
2347 {
2348 set_policy_text(text, pCertViewInfo);
2349 set_issuer_statement(hwnd, pCertViewInfo);
2350 }
2351 }
2352
2353 static void set_cert_name_string(HWND hwnd, PCCERT_CONTEXT cert,
2354 DWORD nameFlags, int heading)
2355 {
2356 WCHAR nl = '\n';
2357 HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_NAMES);
2358 CHARFORMATW charFmt;
2359 PARAFORMAT2 parFmt;
2360
2361 memset(&charFmt, 0, sizeof(charFmt));
2362 charFmt.cbSize = sizeof(charFmt);
2363 charFmt.dwMask = CFM_BOLD;
2364 charFmt.dwEffects = CFE_BOLD;
2365 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2366 parFmt.cbSize = sizeof(parFmt);
2367 parFmt.dwMask = PFM_STARTINDENT;
2368 parFmt.dxStartIndent = MY_INDENT * 3;
2369 add_string_resource_with_paraformat_to_control(text, heading, &parFmt);
2370 charFmt.dwEffects = 0;
2371 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2372 add_cert_string_to_control(text, cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
2373 nameFlags);
2374 add_unformatted_text_to_control(text, &nl, 1);
2375 add_unformatted_text_to_control(text, &nl, 1);
2376 add_unformatted_text_to_control(text, &nl, 1);
2377
2378 }
2379
2380 static void add_date_string_to_control(HWND hwnd, const FILETIME *fileTime)
2381 {
2382 WCHAR dateFmt[80]; /* sufficient for all versions of LOCALE_SSHORTDATE */
2383 WCHAR date[80];
2384 SYSTEMTIME sysTime;
2385
2386 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SSHORTDATE, dateFmt, ARRAY_SIZE(dateFmt));
2387 FileTimeToSystemTime(fileTime, &sysTime);
2388 GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, date, ARRAY_SIZE(date));
2389 add_unformatted_text_to_control(hwnd, date, lstrlenW(date));
2390 }
2391
2392 static void set_cert_validity_period(HWND hwnd, PCCERT_CONTEXT cert)
2393 {
2394 WCHAR nl = '\n';
2395 HWND text = GetDlgItem(hwnd, IDC_CERTIFICATE_NAMES);
2396 CHARFORMATW charFmt;
2397 PARAFORMAT2 parFmt;
2398
2399 memset(&charFmt, 0, sizeof(charFmt));
2400 charFmt.cbSize = sizeof(charFmt);
2401 charFmt.dwMask = CFM_BOLD;
2402 charFmt.dwEffects = CFE_BOLD;
2403 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2404 parFmt.cbSize = sizeof(parFmt);
2405 parFmt.dwMask = PFM_STARTINDENT;
2406 parFmt.dxStartIndent = MY_INDENT * 3;
2407 add_string_resource_with_paraformat_to_control(text, IDS_VALID_FROM,
2408 &parFmt);
2409 charFmt.dwEffects = 0;
2410 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2411 add_date_string_to_control(text, &cert->pCertInfo->NotBefore);
2412 charFmt.dwEffects = CFE_BOLD;
2413 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2414 add_string_resource_to_control(text, IDS_VALID_TO);
2415 charFmt.dwEffects = 0;
2416 SendMessageW(text, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFmt);
2417 add_date_string_to_control(text, &cert->pCertInfo->NotAfter);
2418 add_unformatted_text_to_control(text, &nl, 1);
2419 }
2420
2421 static void set_general_info(HWND hwnd,
2422 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo)
2423 {
2424 set_cert_info(hwnd, pCertViewInfo);
2425 set_cert_name_string(hwnd, pCertViewInfo->pCertContext, 0,
2426 IDS_SUBJECT_HEADING);
2427 set_cert_name_string(hwnd, pCertViewInfo->pCertContext,
2428 CERT_NAME_ISSUER_FLAG, IDS_ISSUER_HEADING);
2429 set_cert_validity_period(hwnd, pCertViewInfo->pCertContext);
2430 }
2431
2432 static LRESULT CALLBACK user_notice_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
2433 LPARAM lp)
2434 {
2435 LRESULT ret = 0;
2436 HWND text;
2437 struct IssuerStatement *issuerStatement;
2438
2439 switch (msg)
2440 {
2441 case WM_INITDIALOG:
2442 text = GetDlgItem(hwnd, IDC_USERNOTICE);
2443 issuerStatement = (struct IssuerStatement *)lp;
2444 add_unformatted_text_to_control(text, issuerStatement->userNotice,
2445 strlenW(issuerStatement->userNotice));
2446 if (issuerStatement->cps)
2447 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)issuerStatement->cps);
2448 else
2449 EnableWindow(GetDlgItem(hwnd, IDC_CPS), FALSE);
2450 break;
2451 case WM_COMMAND:
2452 switch (wp)
2453 {
2454 case IDOK:
2455 EndDialog(hwnd, IDOK);
2456 ret = TRUE;
2457 break;
2458 case IDC_CPS:
2459 {
2460 IBindCtx *bctx = NULL;
2461 LPWSTR cps;
2462
2463 CreateBindCtx(0, &bctx);
2464 cps = (LPWSTR)GetWindowLongPtrW(hwnd, DWLP_USER);
2465 HlinkSimpleNavigateToString(cps, NULL, NULL, NULL, bctx, NULL,
2466 HLNF_OPENINNEWWINDOW, 0);
2467 IBindCtx_Release(bctx);
2468 break;
2469 }
2470 }
2471 }
2472 return ret;
2473 }
2474
2475 static void show_user_notice(HWND hwnd, struct IssuerStatement *issuerStatement)
2476 {
2477 DialogBoxParamW(hInstance, MAKEINTRESOURCEW(IDD_USERNOTICE), hwnd,
2478 user_notice_dlg_proc, (LPARAM)issuerStatement);
2479 }
2480
2481 static LRESULT CALLBACK general_dlg_proc(HWND hwnd, UINT msg, WPARAM wp,
2482 LPARAM lp)
2483 {
2484 PROPSHEETPAGEW *page;
2485 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo;
2486
2487 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
2488
2489 switch (msg)
2490 {
2491 case WM_INITDIALOG:
2492 page = (PROPSHEETPAGEW *)lp;
2493 pCertViewInfo = (PCCRYPTUI_VIEWCERTIFICATE_STRUCTW)page->lParam;
2494 if (pCertViewInfo->dwFlags & CRYPTUI_DISABLE_ADDTOSTORE)
2495 ShowWindow(GetDlgItem(hwnd, IDC_ADDTOSTORE), FALSE);
2496 EnableWindow(GetDlgItem(hwnd, IDC_ISSUERSTATEMENT), FALSE);
2497 set_general_info(hwnd, pCertViewInfo);
2498 break;
2499 case WM_COMMAND:
2500 switch (wp)
2501 {
2502 case IDC_ADDTOSTORE:
2503 CryptUIWizImport(0, hwnd, NULL, NULL, NULL);
2504 break;
2505 case IDC_ISSUERSTATEMENT:
2506 {
2507 struct IssuerStatement *issuerStatement =
2508 (struct IssuerStatement *)GetWindowLongPtrW(hwnd, DWLP_USER);
2509
2510 if (issuerStatement)
2511 {
2512 if (issuerStatement->userNotice)
2513 show_user_notice(hwnd, issuerStatement);
2514 else if (issuerStatement->cps)
2515 {
2516 IBindCtx *bctx = NULL;
2517
2518 CreateBindCtx(0, &bctx);
2519 HlinkSimpleNavigateToString(issuerStatement->cps, NULL,
2520 NULL, NULL, bctx, NULL, HLNF_OPENINNEWWINDOW, 0);
2521 IBindCtx_Release(bctx);
2522 }
2523 }
2524 break;
2525 }
2526 }
2527 break;
2528 }
2529 return 0;
2530 }
2531
2532 static UINT CALLBACK general_callback_proc(HWND hwnd, UINT msg,
2533 PROPSHEETPAGEW *page)
2534 {
2535 struct IssuerStatement *issuerStatement;
2536
2537 switch (msg)
2538 {
2539 case PSPCB_RELEASE:
2540 issuerStatement =
2541 (struct IssuerStatement *)GetWindowLongPtrW(hwnd, DWLP_USER);
2542 if (issuerStatement)
2543 {
2544 HeapFree(GetProcessHeap(), 0, issuerStatement->cps);
2545 HeapFree(GetProcessHeap(), 0, issuerStatement->userNotice);
2546 HeapFree(GetProcessHeap(), 0, issuerStatement);
2547 }
2548 break;
2549 }
2550 return 1;
2551 }
2552
2553 static void init_general_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo,
2554 PROPSHEETPAGEW *page)
2555 {
2556 memset(page, 0, sizeof(PROPSHEETPAGEW));
2557 page->dwSize = sizeof(PROPSHEETPAGEW);
2558 page->dwFlags = PSP_USECALLBACK;
2559 page->pfnCallback = general_callback_proc;
2560 page->hInstance = hInstance;
2561 page->u.pszTemplate = MAKEINTRESOURCEW(IDD_GENERAL);
2562 page->pfnDlgProc = general_dlg_proc;
2563 page->lParam = (LPARAM)pCertViewInfo;
2564 }
2565
2566 typedef WCHAR * (*field_format_func)(PCCERT_CONTEXT cert);
2567
2568 static WCHAR *field_format_version(PCCERT_CONTEXT cert)
2569 {
2570 static const WCHAR fmt[] = { 'V','%','d',0 };
2571 WCHAR *buf = HeapAlloc(GetProcessHeap(), 0, 12 * sizeof(WCHAR));
2572
2573 if (buf)
2574 sprintfW(buf, fmt, cert->pCertInfo->dwVersion);
2575 return buf;
2576 }
2577
2578 static WCHAR *format_hex_string(void *pb, DWORD cb)
2579 {
2580 WCHAR *buf = HeapAlloc(GetProcessHeap(), 0, (cb * 3 + 1) * sizeof(WCHAR));
2581
2582 if (buf)
2583 {
2584 static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
2585 DWORD i;
2586 WCHAR *ptr;
2587
2588 for (i = 0, ptr = buf; i < cb; i++, ptr += 3)
2589 sprintfW(ptr, fmt, ((BYTE *)pb)[i]);
2590 }
2591 return buf;
2592 }
2593
2594 static WCHAR *field_format_serial_number(PCCERT_CONTEXT cert)
2595 {
2596 return format_hex_string(cert->pCertInfo->SerialNumber.pbData,
2597 cert->pCertInfo->SerialNumber.cbData);
2598 }
2599
2600 static WCHAR *field_format_issuer(PCCERT_CONTEXT cert)
2601 {
2602 return get_cert_name_string(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
2603 CERT_NAME_ISSUER_FLAG);
2604 }
2605
2606 static WCHAR *field_format_detailed_cert_name(PCERT_NAME_BLOB name)
2607 {
2608 WCHAR *str = NULL;
2609 DWORD len = CertNameToStrW(X509_ASN_ENCODING, name,
2610 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, NULL, 0);
2611
2612 if (len)
2613 {
2614 str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2615 if (str)
2616 CertNameToStrW(X509_ASN_ENCODING, name,
2617 CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG, str, len);
2618 }
2619 return str;
2620 }
2621
2622 static WCHAR *field_format_detailed_issuer(PCCERT_CONTEXT cert, void *param)
2623 {
2624 return field_format_detailed_cert_name(&cert->pCertInfo->Issuer);
2625 }
2626
2627 static WCHAR *field_format_subject(PCCERT_CONTEXT cert)
2628 {
2629 return get_cert_name_string(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0);
2630 }
2631
2632 static WCHAR *field_format_detailed_subject(PCCERT_CONTEXT cert, void *param)
2633 {
2634 return field_format_detailed_cert_name(&cert->pCertInfo->Subject);
2635 }
2636
2637 static WCHAR *format_long_date(const FILETIME *fileTime)
2638 {
2639 WCHAR dateFmt[80]; /* long enough for LOCALE_SLONGDATE */
2640 DWORD len;
2641 WCHAR *buf = NULL;
2642 SYSTEMTIME sysTime;
2643
2644 /* FIXME: format isn't quite right, want time too */
2645 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SLONGDATE, dateFmt, ARRAY_SIZE(dateFmt));
2646 FileTimeToSystemTime(fileTime, &sysTime);
2647 len = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, NULL, 0);
2648 if (len)
2649 {
2650 buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2651 if (buf)
2652 GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, buf,
2653 len);
2654 }
2655 return buf;
2656 }
2657
2658 static WCHAR *field_format_from_date(PCCERT_CONTEXT cert)
2659 {
2660 return format_long_date(&cert->pCertInfo->NotBefore);
2661 }
2662
2663 static WCHAR *field_format_to_date(PCCERT_CONTEXT cert)
2664 {
2665 return format_long_date(&cert->pCertInfo->NotAfter);
2666 }
2667
2668 static WCHAR *field_format_public_key(PCCERT_CONTEXT cert)
2669 {
2670 PCCRYPT_OID_INFO oidInfo;
2671 WCHAR *buf = NULL;
2672
2673 oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2674 cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, 0);
2675 if (oidInfo)
2676 {
2677 WCHAR fmt[MAX_STRING_LEN];
2678
2679 if (LoadStringW(hInstance, IDS_FIELD_PUBLIC_KEY_FORMAT, fmt, ARRAY_SIZE(fmt)))
2680 {
2681 DWORD len;
2682
2683 /* Allocate the output buffer. Use the number of bytes in the
2684 * public key as a conservative (high) estimate for the number of
2685 * digits in its output.
2686 * The output is of the form (in English)
2687 * "<public key algorithm> (<public key bit length> bits)".
2688 * Ordinarily having two positional parameters in a string is not a
2689 * good idea, but as this isn't a sentence fragment, it shouldn't
2690 * be word-order dependent.
2691 */
2692 len = strlenW(fmt) + strlenW(oidInfo->pwszName) +
2693 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData * 8;
2694 buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(*buf));
2695 if (buf)
2696 {
2697 DWORD_PTR args[2];
2698 args[0] = (DWORD_PTR)oidInfo->pwszName;
2699 args[1] = CertGetPublicKeyLength(X509_ASN_ENCODING,
2700 &cert->pCertInfo->SubjectPublicKeyInfo);
2701 FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
2702 fmt, 0, 0, buf, len, (__ms_va_list*)args);
2703 }
2704 }
2705 }
2706 return buf;
2707 }
2708
2709 static WCHAR *field_format_detailed_public_key(PCCERT_CONTEXT cert, void *param)
2710 {
2711 return format_hex_string(
2712 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
2713 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData);
2714 }
2715
2716 struct field_value_data;
2717 struct detail_data
2718 {
2719 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo;
2720 BOOL *pfPropertiesChanged;
2721 int cFields;
2722 struct field_value_data *fields;
2723 };
2724
2725 typedef void (*add_fields_func)(HWND hwnd, struct detail_data *data);
2726
2727 typedef WCHAR *(*create_detailed_value_func)(PCCERT_CONTEXT cert, void *param);
2728
2729 struct field_value_data
2730 {
2731 create_detailed_value_func create;
2732 LPWSTR detailed_value;
2733 void *param;
2734 };
2735
2736 static void add_field_value_data(struct detail_data *data,
2737 create_detailed_value_func create, void *param)
2738 {
2739 if (data->cFields)
2740 data->fields = HeapReAlloc(GetProcessHeap(), 0, data->fields,
2741 (data->cFields + 1) * sizeof(struct field_value_data));
2742 else
2743 data->fields = HeapAlloc(GetProcessHeap(), 0,
2744 sizeof(struct field_value_data));
2745 if (data->fields)
2746 {
2747 data->fields[data->cFields].create = create;
2748 data->fields[data->cFields].detailed_value = NULL;
2749 data->fields[data->cFields].param = param;
2750 data->cFields++;
2751 }
2752 }
2753
2754 static void add_field_and_value_to_list(HWND hwnd, struct detail_data *data,
2755 LPWSTR field, LPWSTR value, create_detailed_value_func create, void *param)
2756 {
2757 LVITEMW item;
2758 int iItem = SendMessageW(hwnd, LVM_GETITEMCOUNT, 0, 0);
2759
2760 item.mask = LVIF_TEXT | LVIF_PARAM;
2761 item.iItem = iItem;
2762 item.iSubItem = 0;
2763 item.pszText = field;
2764 item.lParam = (LPARAM)data;
2765 SendMessageW(hwnd, LVM_INSERTITEMW, 0, (LPARAM)&item);
2766 if (value)
2767 {
2768 item.pszText = value;
2769 item.iSubItem = 1;
2770 SendMessageW(hwnd, LVM_SETITEMTEXTW, iItem, (LPARAM)&item);
2771 }
2772 add_field_value_data(data, create, param);
2773 }
2774
2775 static void add_string_id_and_value_to_list(HWND hwnd, struct detail_data *data,
2776 int id, LPWSTR value, create_detailed_value_func create, void *param)
2777 {
2778 WCHAR buf[MAX_STRING_LEN];
2779
2780 LoadStringW(hInstance, id, buf, ARRAY_SIZE(buf));
2781 add_field_and_value_to_list(hwnd, data, buf, value, create, param);
2782 }
2783
2784 struct v1_field
2785 {
2786 int id;
2787 field_format_func format;
2788 create_detailed_value_func create_detailed_value;
2789 };
2790
2791 static void add_v1_field(HWND hwnd, struct detail_data *data,
2792 const struct v1_field *field)
2793 {
2794 WCHAR *val = field->format(data->pCertViewInfo->pCertContext);
2795
2796 if (val)
2797 {
2798 add_string_id_and_value_to_list(hwnd, data, field->id, val,
2799 field->create_detailed_value, NULL);
2800 HeapFree(GetProcessHeap(), 0, val);
2801 }
2802 }
2803
2804 static const struct v1_field v1_fields[] = {
2805 { IDS_FIELD_VERSION, field_format_version, NULL },
2806 { IDS_FIELD_SERIAL_NUMBER, field_format_serial_number, NULL },
2807 { IDS_FIELD_ISSUER, field_format_issuer, field_format_detailed_issuer },
2808 { IDS_FIELD_VALID_FROM, field_format_from_date, NULL },
2809 { IDS_FIELD_VALID_TO, field_format_to_date, NULL },
2810 { IDS_FIELD_SUBJECT, field_format_subject, field_format_detailed_subject },
2811 { IDS_FIELD_PUBLIC_KEY, field_format_public_key,
2812 field_format_detailed_public_key }
2813 };
2814
2815 static void add_v1_fields(HWND hwnd, struct detail_data *data)
2816 {
2817 unsigned int i;
2818 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
2819
2820 /* The last item in v1_fields is the public key, which is not in the loop
2821 * because it's a special case.
2822 */
2823 for (i = 0; i < ARRAY_SIZE(v1_fields) - 1; i++)
2824 add_v1_field(hwnd, data, &v1_fields[i]);
2825 if (cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData)
2826 add_v1_field(hwnd, data, &v1_fields[i]);
2827 }
2828
2829 static WCHAR *crypt_format_extension(const CERT_EXTENSION *ext, DWORD formatStrType)
2830 {
2831 WCHAR *str = NULL;
2832 DWORD size;
2833
2834 if (CryptFormatObject(X509_ASN_ENCODING, 0, formatStrType, NULL,
2835 ext->pszObjId, ext->Value.pbData, ext->Value.cbData, NULL, &size))
2836 {
2837 str = HeapAlloc(GetProcessHeap(), 0, size);
2838 CryptFormatObject(X509_ASN_ENCODING, 0, formatStrType, NULL,
2839 ext->pszObjId, ext->Value.pbData, ext->Value.cbData, str, &size);
2840 }
2841 return str;
2842 }
2843
2844 static WCHAR *field_format_extension_hex_with_ascii(const CERT_EXTENSION *ext)
2845 {
2846 WCHAR *str = NULL;
2847
2848 if (ext->Value.cbData)
2849 {
2850 /* The output is formatted as:
2851 * <hex bytes> <ascii bytes>\n
2852 * where <hex bytes> is a string of up to 8 bytes, output as %02x,
2853 * and <ascii bytes> is the ASCII equivalent of each byte, or '.' if
2854 * the byte is not printable.
2855 * So, for example, the extension value consisting of the following
2856 * bytes:
2857 * 0x30,0x14,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x03,
2858 * 0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67
2859 * is output as:
2860 * 30 14 31 12 30 10 06 03 0.1.0...
2861 * 55 04 03 13 09 4a 75 61 U....Jua
2862 * 6e 20 4c 61 6e 67 n Lang
2863 * The allocation size therefore requires:
2864 * - 4 characters per character in an 8-byte line
2865 * (2 for the hex format, one for the space, one for the ASCII value)
2866 * - 3 more characters per 8-byte line (two spaces and a newline)
2867 * - 1 character for the terminating nul
2868 * FIXME: should use a fixed-width font for this
2869 */
2870 DWORD lines = (ext->Value.cbData + 7) / 8;
2871
2872 str = HeapAlloc(GetProcessHeap(), 0,
2873 (lines * 8 * 4 + lines * 3 + 1) * sizeof(WCHAR));
2874 if (str)
2875 {
2876 static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
2877 DWORD i, j;
2878 WCHAR *ptr;
2879
2880 for (i = 0, ptr = str; i < ext->Value.cbData; i += 8)
2881 {
2882 /* Output as hex bytes first */
2883 for (j = i; j < min(i + 8, ext->Value.cbData); j++, ptr += 3)
2884 sprintfW(ptr, fmt, ext->Value.pbData[j]);
2885 /* Pad the hex output with spaces for alignment */
2886 if (j == ext->Value.cbData && j % 8)
2887 {
2888 static const WCHAR pad[] = { ' ',' ',' ' };
2889
2890 for (; j % 8; j++, ptr += ARRAY_SIZE(pad))
2891 memcpy(ptr, pad, sizeof(pad));
2892 }
2893 /* The last sprintfW included a space, so just insert one
2894 * more space between the hex bytes and the ASCII output
2895 */
2896 *ptr++ = ' ';
2897 /* Output as ASCII bytes */
2898 for (j = i; j < min(i + 8, ext->Value.cbData); j++, ptr++)
2899 {
2900 if (isprintW(ext->Value.pbData[j]) &&
2901 !isspaceW(ext->Value.pbData[j]))
2902 *ptr = ext->Value.pbData[j];
2903 else
2904 *ptr = '.';
2905 }
2906 *ptr++ = '\n';
2907 }
2908 *ptr++ = '\0';
2909 }
2910 }
2911 return str;
2912 }
2913
2914 static WCHAR *field_format_detailed_extension(PCCERT_CONTEXT cert, void *param)
2915 {
2916 PCERT_EXTENSION ext = param;
2917 LPWSTR str = crypt_format_extension(ext,
2918 CRYPT_FORMAT_STR_MULTI_LINE | CRYPT_FORMAT_STR_NO_HEX);
2919
2920 if (!str)
2921 str = field_format_extension_hex_with_ascii(ext);
2922 return str;
2923 }
2924
2925 static void add_cert_extension_detail(HWND hwnd, struct detail_data *data,
2926 PCERT_EXTENSION ext)
2927 {
2928 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2929 ext->pszObjId, 0);
2930 LPWSTR val = crypt_format_extension(ext, 0);
2931
2932 if (oidInfo)
2933 add_field_and_value_to_list(hwnd, data, (LPWSTR)oidInfo->pwszName,
2934 val, field_format_detailed_extension, ext);
2935 else
2936 {
2937 DWORD len = strlen(ext->pszObjId);
2938 LPWSTR oidW = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2939
2940 if (oidW)
2941 {
2942 DWORD i;
2943
2944 for (i = 0; i <= len; i++)
2945 oidW[i] = ext->pszObjId[i];
2946 add_field_and_value_to_list(hwnd, data, oidW, val,
2947 field_format_detailed_extension, ext);
2948 HeapFree(GetProcessHeap(), 0, oidW);
2949 }
2950 }
2951 HeapFree(GetProcessHeap(), 0, val);
2952 }
2953
2954 static void add_all_extensions(HWND hwnd, struct detail_data *data)
2955 {
2956 DWORD i;
2957 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
2958
2959 for (i = 0; i < cert->pCertInfo->cExtension; i++)
2960 add_cert_extension_detail(hwnd, data, &cert->pCertInfo->rgExtension[i]);
2961 }
2962
2963 static void add_critical_extensions(HWND hwnd, struct detail_data *data)
2964 {
2965 DWORD i;
2966 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
2967
2968 for (i = 0; i < cert->pCertInfo->cExtension; i++)
2969 if (cert->pCertInfo->rgExtension[i].fCritical)
2970 add_cert_extension_detail(hwnd, data,
2971 &cert->pCertInfo->rgExtension[i]);
2972 }
2973
2974 typedef WCHAR * (*prop_to_value_func)(void *pb, DWORD cb);
2975
2976 struct prop_id_to_string_id
2977 {
2978 DWORD prop;
2979 int id;
2980 BOOL prop_is_string;
2981 prop_to_value_func prop_to_value;
2982 };
2983
2984 static WCHAR *format_enhanced_key_usage_value(void *pb, DWORD cb)
2985 {
2986 CERT_EXTENSION ext;
2987
2988 ext.pszObjId = (LPSTR)X509_ENHANCED_KEY_USAGE;
2989 ext.fCritical = FALSE;
2990 ext.Value.pbData = pb;
2991 ext.Value.cbData = cb;
2992 return crypt_format_extension(&ext, 0);
2993 }
2994
2995 /* Logically the access state should also be checked, and IDC_EDITPROPERTIES
2996 * disabled for read-only certificates, but native doesn't appear to do that.
2997 */
2998 static const struct prop_id_to_string_id prop_id_map[] = {
2999 { CERT_HASH_PROP_ID, IDS_PROP_HASH, FALSE, format_hex_string },
3000 { CERT_FRIENDLY_NAME_PROP_ID, IDS_PROP_FRIENDLY_NAME, TRUE, NULL },
3001 { CERT_DESCRIPTION_PROP_ID, IDS_PROP_DESCRIPTION, TRUE, NULL },
3002 { CERT_ENHKEY_USAGE_PROP_ID, IDS_PROP_ENHKEY_USAGE, FALSE,
3003 format_enhanced_key_usage_value },
3004 };
3005
3006 static void add_properties(HWND hwnd, struct detail_data *data)
3007 {
3008 DWORD i;
3009 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
3010
3011 for (i = 0; i < ARRAY_SIZE(prop_id_map); i++)
3012 {
3013 DWORD cb;
3014
3015 if (CertGetCertificateContextProperty(cert, prop_id_map[i].prop, NULL,
3016 &cb))
3017 {
3018 BYTE *pb;
3019 WCHAR *val = NULL;
3020
3021 /* FIXME: MS adds a separate value for the signature hash
3022 * algorithm.
3023 */
3024 pb = HeapAlloc(GetProcessHeap(), 0, cb);
3025 if (pb)
3026 {
3027 if (CertGetCertificateContextProperty(cert,
3028 prop_id_map[i].prop, pb, &cb))
3029 {
3030 if (prop_id_map[i].prop_is_string)
3031 {
3032 val = (LPWSTR)pb;
3033 /* Don't double-free pb */
3034 pb = NULL;
3035 }
3036 else
3037 val = prop_id_map[i].prop_to_value(pb, cb);
3038 }
3039 HeapFree(GetProcessHeap(), 0, pb);
3040 }
3041 add_string_id_and_value_to_list(hwnd, data, prop_id_map[i].id, val,
3042 NULL, NULL);
3043 }
3044 }
3045 }
3046
3047 static void add_all_fields(HWND hwnd, struct detail_data *data)
3048 {
3049 add_v1_fields(hwnd, data);
3050 add_all_extensions(hwnd, data);
3051 add_properties(hwnd, data);
3052 }
3053
3054 struct selection_list_item
3055 {
3056 int id;
3057 add_fields_func add;
3058 };
3059
3060 static const struct selection_list_item listItems[] = {
3061 { IDS_FIELDS_ALL, add_all_fields },
3062 { IDS_FIELDS_V1, add_v1_fields },
3063 { IDS_FIELDS_EXTENSIONS, add_all_extensions },
3064 { IDS_FIELDS_CRITICAL_EXTENSIONS, add_critical_extensions },
3065 { IDS_FIELDS_PROPERTIES, add_properties },
3066 };
3067
3068 static void create_show_list(HWND hwnd, struct detail_data *data)
3069 {
3070 HWND cb = GetDlgItem(hwnd, IDC_DETAIL_SELECT);
3071 WCHAR buf[MAX_STRING_LEN];
3072 int i;
3073
3074 for (i = 0; i < ARRAY_SIZE(listItems); i++)
3075 {
3076 int index;
3077
3078 LoadStringW(hInstance, listItems[i].id, buf, ARRAY_SIZE(buf));
3079 index = SendMessageW(cb, CB_INSERTSTRING, -1, (LPARAM)buf);
3080 SendMessageW(cb, CB_SETITEMDATA, index, (LPARAM)data);
3081 }
3082 SendMessageW(cb, CB_SETCURSEL, 0, 0);
3083 }
3084
3085 static void create_listview_columns(HWND hwnd)
3086 {
3087 HWND lv = GetDlgItem(hwnd, IDC_DETAIL_LIST);
3088 RECT rc;
3089 WCHAR buf[MAX_STRING_LEN];
3090 LVCOLUMNW column;
3091
3092 SendMessageW(lv, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
3093 GetWindowRect(lv, &rc);
3094 LoadStringW(hInstance, IDS_FIELD, buf, ARRAY_SIZE(buf));
3095 column.mask = LVCF_WIDTH | LVCF_TEXT;
3096 column.cx = (rc.right - rc.left) / 2 - 2;
3097 column.pszText = buf;
3098 SendMessageW(lv, LVM_INSERTCOLUMNW, 0, (LPARAM)&column);
3099 LoadStringW(hInstance, IDS_VALUE, buf, ARRAY_SIZE(buf));
3100 SendMessageW(lv, LVM_INSERTCOLUMNW, 1, (LPARAM)&column);
3101 }
3102
3103 static void set_fields_selection(HWND hwnd, struct detail_data *data, int sel)
3104 {
3105 HWND list = GetDlgItem(hwnd, IDC_DETAIL_LIST);
3106
3107 if (sel >= 0 && sel < ARRAY_SIZE(listItems))
3108 {
3109 SendMessageW(list, LVM_DELETEALLITEMS, 0, 0);
3110 listItems[sel].add(list, data);
3111 }
3112 }
3113
3114 static void create_cert_details_list(HWND hwnd, struct detail_data *data)
3115 {
3116 create_show_list(hwnd, data);
3117 create_listview_columns(hwnd);
3118 set_fields_selection(hwnd, data, 0);
3119 }
3120
3121 static void add_purpose(HWND hwnd, LPCSTR oid)
3122 {
3123 HWND lv = GetDlgItem(hwnd, IDC_CERTIFICATE_USAGES);
3124 PCRYPT_OID_INFO info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3125 sizeof(CRYPT_OID_INFO));
3126
3127 if (info)
3128 {
3129 char *oidCopy = HeapAlloc(GetProcessHeap(), 0, strlen(oid) + 1);
3130
3131 if (oidCopy)
3132 {
3133 LVITEMA item;
3134
3135 strcpy(oidCopy, oid);
3136 info->cbSize = sizeof(CRYPT_OID_INFO);
3137 info->pszOID = oidCopy;
3138 item.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM;
3139 item.state = INDEXTOSTATEIMAGEMASK(CheckBitmapIndexChecked);
3140 item.stateMask = LVIS_STATEIMAGEMASK;
3141 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
3142 item.iSubItem = 0;
3143 item.lParam = (LPARAM)info;
3144 item.pszText = oidCopy;
3145 SendMessageA(lv, LVM_INSERTITEMA, 0, (LPARAM)&item);
3146 }
3147 else
3148 HeapFree(GetProcessHeap(), 0, info);
3149 }
3150