ReactOS 0.4.15-dev-6669-g8227c5d
main.c
Go to the documentation of this file.
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 <stdarg.h>
20#include <wchar.h>
21
22#define COBJMACROS
23#define NONAMELESSUNION
24
25#include "windef.h"
26#include "winbase.h"
27#include "winnls.h"
28#include "winuser.h"
29#include "softpub.h"
30#include "wingdi.h"
31#include "richedit.h"
32#include "ole2.h"
33#include "richole.h"
34#include "commdlg.h"
35#include "commctrl.h"
36#include "cryptuiapi.h"
37#include "cryptuires.h"
38#include "urlmon.h"
39#include "hlink.h"
40#include "winreg.h"
41#include "wine/debug.h"
42
44
46
47static const WCHAR empty[] = {0};
48
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 */
58 hInstance = hinstDLL;
60 break;
61 }
62 return TRUE;
63}
64
65static WCHAR *strdupAtoW( const char *str )
66{
67 DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
68 WCHAR *ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
69 if (ret) MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
70 return ret;
71}
72
73#define MAX_STRING_LEN 512
74
76{
78 RECT rc;
81
83 GetWindowRect(lv, &rc);
86 column.cx = (rc.right - rc.left) * 29 / 100 - 2;
87 column.pszText = buf;
91 column.cx = (rc.right - rc.left) * 16 / 100 - 2;
94 column.cx = (rc.right - rc.left) * 23 / 100 - 1;
97}
98
99static void add_cert_to_view(HWND lv, PCCERT_CONTEXT cert, DWORD *allocatedLen,
100 LPWSTR *str)
101{
102 DWORD len;
104 WCHAR dateFmt[80]; /* sufficient for LOCALE_SSHORTDATE */
105 WCHAR date[80];
106 SYSTEMTIME sysTime;
107 LPWSTR none;
108
110 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
111 item.iSubItem = 0;
112 item.iImage = 0;
115 NULL, 0);
116 if (len > *allocatedLen)
117 {
119 *str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
120 if (*str)
121 *allocatedLen = len;
122 }
123 if (*str)
124 {
126 *str, len);
127 item.pszText = *str;
129 }
130
131 item.mask = LVIF_TEXT;
134 if (len > *allocatedLen)
135 {
137 *str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
138 if (*str)
139 *allocatedLen = len;
140 }
141 if (*str)
142 {
145 item.pszText = *str;
146 item.iSubItem = 1;
148 }
149
151 FileTimeToSystemTime(&cert->pCertInfo->NotAfter, &sysTime);
152 GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, date, ARRAY_SIZE(date));
153 item.pszText = date;
154 item.iSubItem = 2;
156
158 NULL, &len))
160 if (len > *allocatedLen)
161 {
163 *str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
164 if (*str)
165 *allocatedLen = len;
166 }
167 if (*str)
168 {
170 *str, &len))
171 item.pszText = none;
172 else
173 item.pszText = *str;
174 item.iSubItem = 3;
176 }
177}
178
180{
181 static const WCHAR keyName[] = { 'S','o','f','t','w','a','r','e','\\','M',
182 'i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g','r','a',
183 'p','h','y','\\','U','I','\\','C','e','r','t','m','g','r','\\','P','u',
184 'r','p','o','s','e',0 };
185 LPSTR str = NULL;
186 HKEY key;
187
188 if (!RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, NULL, 0, KEY_READ,
189 NULL, &key, NULL))
190 {
191 LONG rc;
192 DWORD type, size;
193
194 rc = RegQueryValueExA(key, "Purpose", NULL, &type, NULL, &size);
195 if ((!rc || rc == ERROR_MORE_DATA) && type == REG_SZ)
196 {
198 if (str)
199 {
200 rc = RegQueryValueExA(key, "Purpose", NULL, NULL, (LPBYTE)str,
201 &size);
202 if (rc)
203 {
205 str = NULL;
206 }
207 }
208 }
210 }
211 return str;
212}
213
214typedef enum {
219
221{
225 int index;
226
234 if ((usages = get_cert_mgr_usages()))
235 {
236 LPSTR ptr, comma;
237
238 for (ptr = usages, comma = strchr(ptr, ','); ptr && *ptr;
239 ptr = comma ? comma + 1 : NULL,
240 comma = ptr ? strchr(ptr, ',') : NULL)
241 {
243
244 if (comma)
245 *comma = 0;
247 {
249 (LPARAM)info->pwszName);
251 }
252 }
254 }
255}
256
259
261{
262 if (!usage->cUsageIdentifier)
264 sizeof(LPSTR));
265 else
266 usage->rgpszUsageIdentifier = HeapReAlloc(GetProcessHeap(), 0,
267 usage->rgpszUsageIdentifier,
268 (usage->cUsageIdentifier + 1) * sizeof(LPSTR));
269 if (usage->rgpszUsageIdentifier)
270 usage->rgpszUsageIdentifier[usage->cUsageIdentifier++] = oid;
271 else
272 {
274 usage = NULL;
275 }
276 return usage;
277}
278
280{
282 sizeof(CERT_ENHKEY_USAGE));
283
284 if (usage)
285 {
286 LPSTR ptr, comma;
287
288 for (ptr = usageStr, comma = strchr(ptr, ','); usage && ptr && *ptr;
289 ptr = comma ? comma + 1 : NULL,
290 comma = ptr ? strchr(ptr, ',') : NULL)
291 {
292 if (comma)
293 *comma = 0;
295 }
296 }
297 return usage;
298}
299
301{
302 CERT_ENHKEY_USAGE *advancedUsage = HeapAlloc(GetProcessHeap(),
304
305 if (advancedUsage)
306 {
308
310 {
311 LPSTR disabledUsagesStr;
312
313 if ((disabledUsagesStr = get_cert_mgr_usages()))
314 {
315 CERT_ENHKEY_USAGE *disabledUsages =
316 convert_usages_str_to_usage(disabledUsagesStr);
317
318 if (disabledUsages)
319 {
321
322 for (ptr = usages; advancedUsage && *ptr; ptr++)
323 {
324 DWORD i;
325 BOOL disabled = FALSE;
326
327 for (i = 0; !disabled &&
328 i < disabledUsages->cUsageIdentifier; i++)
329 if (!strcmp(disabledUsages->rgpszUsageIdentifier[i],
330 (*ptr)->pszOID))
331 disabled = TRUE;
332 if (!disabled)
333 advancedUsage = add_oid_to_usage(advancedUsage,
334 (LPSTR)(*ptr)->pszOID);
335 }
336 /* The individual strings are pointers to disabledUsagesStr,
337 * so they're freed when it is.
338 */
340 disabledUsages->rgpszUsageIdentifier);
341 HeapFree(GetProcessHeap(), 0, disabledUsages);
342 }
343 HeapFree(GetProcessHeap(), 0, disabledUsagesStr);
344 }
346 }
347 }
348 return advancedUsage;
349}
350
351static int CALLBACK cert_mgr_sort_by_subject(LPARAM lp1, LPARAM lp2, LPARAM lp);
352
354{
358 DWORD allocatedLen = 0;
359 LPWSTR str = NULL;
360 int index;
362 LPCSTR oid = NULL;
363 CERT_ENHKEY_USAGE *advanced = NULL;
364
366 if (index >= 0)
367 {
369
370 if (!HIWORD(data))
371 filter = data;
372 else
373 {
375
377 oid = info->pszOID;
378 }
379 }
381 advanced = create_advanced_filter();
382 do {
384 if (cert)
385 {
386 BOOL show = FALSE;
387
389 show = TRUE;
390 else
391 {
392 int numOIDs;
393 DWORD cbOIDs = 0;
394
395 if (CertGetValidUsages(1, &cert, &numOIDs, NULL, &cbOIDs))
396 {
397 if (numOIDs == -1)
398 {
399 /* -1 implies all usages are valid */
400 show = TRUE;
401 }
402 else
403 {
404 LPSTR *oids = HeapAlloc(GetProcessHeap(), 0, cbOIDs);
405
406 if (oids)
407 {
408 if (CertGetValidUsages(1, &cert, &numOIDs, oids,
409 &cbOIDs))
410 {
411 int i;
412
414 {
415 for (i = 0; !show && i < numOIDs; i++)
416 if (!strcmp(oids[i], oid))
417 show = TRUE;
418 }
419 else
420 {
421 for (i = 0; !show && i < numOIDs; i++)
422 {
423 DWORD j;
424
425 for (j = 0; !show &&
426 j < advanced->cUsageIdentifier; j++)
427 if (!strcmp(oids[i],
428 advanced->rgpszUsageIdentifier[j]))
429 show = TRUE;
430 }
431 }
432 }
433 HeapFree(GetProcessHeap(), 0, oids);
434 }
435 }
436 }
437 }
438 if (show)
439 add_cert_to_view(lv, cert, &allocatedLen, &str);
440 }
441 } while (cert);
443 if (advanced)
444 {
446 HeapFree(GetProcessHeap(), 0, advanced);
447 }
450}
451
452static const WCHAR my[] = { 'M','y',0 };
453static const WCHAR addressBook[] = {
454 'A','d','d','r','e','s','s','B','o','o','k',0 };
455static const WCHAR ca[] = { 'C','A',0 };
456static const WCHAR root[] = { 'R','o','o','t',0 };
457static const WCHAR trustedPublisher[] = {
458 'T','r','u','s','t','e','d','P','u','b','l','i','s','h','e','r',0 };
459static const WCHAR disallowed[] = { 'D','i','s','a','l','l','o','w','e','d',0 };
460
462{
466};
467
468static const struct CertMgrStoreInfo defaultStoreList[] = {
477};
478
479static const struct CertMgrStoreInfo publisherStoreList[] = {
484};
485
487{
492};
493
495{
496 const struct CertMgrStoreInfo *storeList;
497 int cStores, i;
499
501 {
502 storeList = publisherStoreList;
504 }
505 else
506 {
507 storeList = defaultStoreList;
508 cStores = ARRAY_SIZE(defaultStoreList);
509 }
511 cStores = 1;
512 data->nStores = cStores;
513 data->stores = storeList;
514 for (i = 0; i < cStores; i++)
515 {
518 HCERTSTORE store;
519
520 if (!(name = CryptFindLocalizedName(storeList[i].name)))
521 name = storeList[i].name;
524 item.mask = TCIF_TEXT | TCIF_PARAM;
525 item.pszText = (LPWSTR)name;
526 item.lParam = (LPARAM)store;
528 }
529}
530
531static void free_certs(HWND lv)
532{
534 int items = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0), i;
535
536 for (i = 0; i < items; i++)
537 {
538 item.mask = LVIF_PARAM;
539 item.iItem = i;
540 item.iSubItem = 0;
543 }
544}
545
547{
549
550 item.mask = TCIF_PARAM;
552 return (HCERTSTORE)item.lParam;
553}
554
556{
558
559 return cert_mgr_index_to_store(tab, SendMessageW(tab, TCM_GETCURSEL, 0, 0));
560}
561
562static void close_stores(HWND tab)
563{
564 int i, tabs = SendMessageW(tab, TCM_GETITEMCOUNT, 0, 0);
565
566 for (i = 0; i < tabs; i++)
568}
569
571{
573
574 free_certs(lv);
577}
578
579typedef enum {
585
588{
590
593 item.stateMask = LVIS_STATEIMAGEMASK;
594 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
595 item.iSubItem = 0;
596 item.lParam = (LPARAM)info;
597 item.pszText = (LPWSTR)info->pwszName;
599}
600
602{
604
606 {
608
609 for (ptr = usages; *ptr; ptr++)
612 }
613}
614
615static void toggle_usage(HWND hwnd, int iItem)
616{
618 int res;
620
621 item.mask = LVIF_STATE;
622 item.iItem = iItem;
623 item.iSubItem = 0;
624 item.stateMask = LVIS_STATEIMAGEMASK;
626 if (res)
627 {
628 int state = item.state >> 12;
629
634 }
635}
636
638{
642
643 if (oidInfo)
644 {
645 LVFINDINFOW findInfo;
646
647 findInfo.flags = LVFI_PARAM;
648 findInfo.lParam = (LPARAM)oidInfo;
649 ret = SendMessageW(lv, LVM_FINDITEMW, -1, (LPARAM)&findInfo);
650 }
651 else
652 {
653 LVFINDINFOA findInfo;
654
655 findInfo.flags = LVFI_STRING;
656 findInfo.psz = oid;
657 ret = SendMessageW(lv, LVM_FINDITEMA, -1, (LPARAM)&findInfo);
658 }
659 return ret;
660}
661
663{
664 static const WCHAR keyName[] = { 'S','o','f','t','w','a','r','e','\\','M',
665 'i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g','r','a',
666 'p','h','y','\\','U','I','\\','C','e','r','t','m','g','r','\\','P','u',
667 'r','p','o','s','e',0 };
668 HKEY key;
670 int purposes = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0), i;
672 LPSTR str = NULL;
673
674 item.mask = LVIF_STATE | LVIF_PARAM;
675 item.iSubItem = 0;
676 item.stateMask = LVIS_STATEIMAGEMASK;
677 for (i = 0; i < purposes; i++)
678 {
679 item.iItem = i;
680 if (SendMessageW(lv, LVM_GETITEMW, 0, (LPARAM)&item))
681 {
682 int state = item.state >> 12;
683
685 {
687 BOOL firstString = TRUE;
688
689 if (!str)
691 strlen(info->pszOID) + 1);
692 else
693 {
695 strlen(str) + 1 + strlen(info->pszOID) + 1);
696 firstString = FALSE;
697 }
698 if (str)
699 {
700 LPSTR ptr = firstString ? str : str + strlen(str);
701
702 if (!firstString)
703 *ptr++ = ',';
704 strcpy(ptr, info->pszOID);
705 }
706 }
707 }
708 }
710 NULL, &key, NULL))
711 {
712 if (str)
713 RegSetValueExA(key, "Purpose", 0, REG_SZ, (const BYTE *)str,
714 strlen(str) + 1);
715 else
716 RegDeleteValueA(key, "Purpose");
718 }
720}
721
723 WPARAM wp, LPARAM lp)
724{
725 switch (msg)
726 {
727 case WM_INITDIALOG:
728 {
729 RECT rc;
732 HIMAGELIST imageList;
733 LPSTR disabledUsages;
734
735 GetWindowRect(lv, &rc);
736 column.mask = LVCF_WIDTH;
737 column.cx = rc.right - rc.left;
739 imageList = ImageList_Create(16, 16, ILC_COLOR4 | ILC_MASK, 4, 0);
740 if (imageList)
741 {
742 HBITMAP bmp;
743 COLORREF backColor = RGB(255, 0, 255);
744
746 ImageList_AddMasked(imageList, bmp, backColor);
748 ImageList_SetBkColor(imageList, CLR_NONE);
751 }
753 if ((disabledUsages = get_cert_mgr_usages()))
754 {
755 LPSTR ptr, comma;
756
757 for (ptr = disabledUsages, comma = strchr(ptr, ','); ptr && *ptr;
758 ptr = comma ? comma + 1 : NULL,
759 comma = ptr ? strchr(ptr, ',') : NULL)
760 {
762
763 if (comma)
764 *comma = 0;
765 if ((index = find_oid_in_list(lv, ptr)) != -1)
767 }
768 HeapFree(GetProcessHeap(), 0, disabledUsages);
769 }
770 break;
771 }
772 case WM_NOTIFY:
773 {
774 NMHDR *hdr = (NMHDR *)lp;
775 NMITEMACTIVATE *nm;
776
777 switch (hdr->code)
778 {
779 case NM_CLICK:
780 nm = (NMITEMACTIVATE *)lp;
781 toggle_usage(hwnd, nm->iItem);
783 break;
784 }
785 break;
786 }
787 case WM_COMMAND:
788 switch (wp)
789 {
790 case IDOK:
794 break;
795 case IDCANCEL:
798 break;
799 }
800 break;
801 }
802 return 0;
803}
804
806{
811 (LPARAM)empty);
813}
814
816{
819
820 item.mask = LVIF_PARAM;
821 item.iItem = index;
822 item.iSubItem = 0;
824 (LPARAM)&item))
825 cert = (PCCERT_CONTEXT)item.lParam;
826 return cert;
827}
828
830{
832
833 if (cert)
834 {
836
837 memset(&viewInfo, 0, sizeof(viewInfo));
838 viewInfo.dwSize = sizeof(viewInfo);
839 viewInfo.hwndParent = hwnd;
840 viewInfo.pCertContext = cert;
841 /* FIXME: this should be modal */
843 }
844}
845
847{
849 DWORD size;
850
851 /* Get enhanced key usage. Have to check for a property and an extension
852 * separately, because CertGetEnhancedKeyUsage will succeed and return an
853 * empty usage if neither is set. Unfortunately an empty usage implies
854 * no usage is allowed, so we have to distinguish between the two cases.
855 */
857 NULL, &size))
858 {
862 {
864 usage = NULL;
865 }
866 }
868 NULL, &size))
869 {
873 {
875 usage = NULL;
876 }
877 }
878 else
879 usage = NULL;
880 if (usage)
881 {
882 if (usage->cUsageIdentifier)
883 {
884 static const WCHAR commaSpace[] = { ',',' ',0 };
885 DWORD i, len = 1;
886 LPWSTR ptr;
887
888 for (i = 0; i < usage->cUsageIdentifier; i++)
889 {
892 usage->rgpszUsageIdentifier[i],
894
895 if (info)
896 len += lstrlenW(info->pwszName);
897 else
898 len += strlen(usage->rgpszUsageIdentifier[i]);
899 if (i < usage->cUsageIdentifier - 1)
901 }
902 *str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
903 if (*str)
904 {
905 for (i = 0, ptr = *str; i < usage->cUsageIdentifier; i++)
906 {
909 usage->rgpszUsageIdentifier[i],
911
912 if (info)
913 {
914 lstrcpyW(ptr, info->pwszName);
915 ptr += lstrlenW(info->pwszName);
916 }
917 else
918 {
919 LPCSTR src = usage->rgpszUsageIdentifier[i];
920
921 for (; *src; ptr++, src++)
922 *ptr = *src;
923 *ptr = 0;
924 }
925 if (i < usage->cUsageIdentifier - 1)
926 {
929 }
930 }
931 *ptr = 0;
932 }
934 }
935 else
936 {
937 size = MAX_STRING_LEN * sizeof(WCHAR);
939 if (*str)
941 }
942 }
943 else
944 {
945 size = MAX_STRING_LEN * sizeof(WCHAR);
947 if (*str)
949 }
950}
951
953{
956 LPWSTR str = NULL;
957
959 if (str)
960 {
963 }
964}
965
967{
969 TCM_GETCURSEL, 0, 0);
970 struct CertMgrData *data =
972
973 if (tabIndex < data->nStores)
974 {
977 LPCWSTR pTitle;
978 int warningID;
979
980 if (SendMessageW(lv, LVM_GETSELECTEDCOUNT, 0, 0) > 1)
981 warningID = data->stores[tabIndex].removePluralWarning;
982 else
983 warningID = data->stores[tabIndex].removeWarning;
984 if (data->title)
985 pTitle = data->title;
986 else
987 {
989 pTitle = title;
990 }
992 if (MessageBoxW(hwnd, warning, pTitle, MB_YESNO) == IDYES)
993 {
994 int selection = -1;
995
996 do {
999 if (selection >= 0)
1000 {
1002 selection);
1003
1005 }
1006 } while (selection >= 0);
1008 }
1009 }
1010}
1011
1013{
1015 int selectionCount = SendMessageW(lv, LVM_GETSELECTEDCOUNT, 0, 0);
1016
1017 if (selectionCount == 1)
1018 {
1021
1022 if (selection >= 0)
1023 {
1025
1026 if (cert)
1027 {
1029
1030 info.dwSize = sizeof(info);
1031 info.pwszExportFileName = NULL;
1032 info.dwSubjectChoice = CRYPTUI_WIZ_EXPORT_CERT_CONTEXT;
1033 info.u.pCertContext = cert;
1034 info.cStores = 0;
1036 }
1037 }
1038 }
1039 else if (selectionCount > 1)
1040 {
1043
1044 if (store)
1045 {
1047 int selection = -1;
1048
1049 info.dwSize = sizeof(info);
1050 info.pwszExportFileName = NULL;
1051 info.dwSubjectChoice =
1053 info.u.hCertStore = store;
1054 info.cStores = 0;
1055 do {
1058 if (selection >= 0)
1059 {
1061 selection);
1062
1065 }
1066 } while (selection >= 0);
1068 CertCloseStore(store, 0);
1069 }
1070 }
1071}
1072
1073static int cert_mgr_sort_by_text(HWND lv, int col, int index1, int index2)
1074{
1075 LVITEMW item;
1076 WCHAR buf1[MAX_STRING_LEN];
1077 WCHAR buf2[MAX_STRING_LEN];
1078
1079 item.cchTextMax = ARRAY_SIZE(buf1);
1080 item.mask = LVIF_TEXT;
1081 item.pszText = buf1;
1082 item.iItem = index1;
1083 item.iSubItem = col;
1085 item.pszText = buf2;
1086 item.iItem = index2;
1088 return lstrcmpW(buf1, buf2);
1089}
1090
1092{
1093 return cert_mgr_sort_by_text((HWND)lp, 0, lp1, lp2);
1094}
1095
1097{
1098 return cert_mgr_sort_by_text((HWND)lp, 1, lp1, lp2);
1099}
1100
1102{
1105 return CompareFileTime(&cert1->pCertInfo->NotAfter,
1106 &cert2->pCertInfo->NotAfter);
1107}
1108
1110 LPARAM lp)
1111{
1112 return cert_mgr_sort_by_text((HWND)lp, 3, lp1, lp2);
1113}
1114
1116 LPARAM lp)
1117{
1118 struct CertMgrData *data;
1119
1120 switch (msg)
1121 {
1122 case WM_INITDIALOG:
1123 {
1124 PCCRYPTUI_CERT_MGR_STRUCT pCryptUICertMgr =
1127
1128 data = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CertMgrData));
1129 if (!data)
1130 return 0;
1131 data->imageList = ImageList_Create(16, 16, ILC_COLOR4 | ILC_MASK, 2, 0);
1132 if (data->imageList)
1133 {
1134 HBITMAP bmp;
1135 COLORREF backColor = RGB(255, 0, 255);
1136
1138 ImageList_AddMasked(data->imageList, bmp, backColor);
1140 ImageList_SetBkColor(data->imageList, CLR_NONE);
1142 LVSIL_SMALL, (LPARAM)data->imageList);
1143 }
1145 data->title = pCryptUICertMgr->pwszTitle;
1146
1149 if (pCryptUICertMgr->pwszTitle)
1151 (LPARAM)pCryptUICertMgr->pwszTitle);
1152 show_cert_stores(hwnd, pCryptUICertMgr->dwFlags, data);
1154 break;
1155 }
1156 case WM_NOTIFY:
1157 {
1158 NMHDR *hdr = (NMHDR *)lp;
1159
1160 switch (hdr->code)
1161 {
1162 case TCN_SELCHANGE:
1164 break;
1165 case LVN_ITEMCHANGED:
1166 {
1167 NMITEMACTIVATE *nm = (NMITEMACTIVATE*)lp;
1169 int numSelected = SendMessageW(lv, LVM_GETSELECTEDCOUNT, 0, 0);
1170
1171 EnableWindow(GetDlgItem(hwnd, IDC_MGR_EXPORT), numSelected > 0);
1172 EnableWindow(GetDlgItem(hwnd, IDC_MGR_REMOVE), numSelected > 0);
1173 EnableWindow(GetDlgItem(hwnd, IDC_MGR_VIEW), numSelected == 1);
1174 if (numSelected == 1)
1176 else
1178 (LPARAM)empty);
1179 break;
1180 }
1181 case NM_DBLCLK:
1182 show_selected_cert(hwnd, ((NMITEMACTIVATE *)lp)->iItem);
1183 break;
1184 case LVN_KEYDOWN:
1185 {
1186 NMLVKEYDOWN *lvk = (NMLVKEYDOWN *)lp;
1187
1188 if (lvk->wVKey == VK_DELETE)
1190 break;
1191 }
1192 case LVN_COLUMNCLICK:
1193 {
1194 NMLISTVIEW *nmlv = (NMLISTVIEW *)lp;
1196
1197 /* FIXME: doesn't support swapping sort order between ascending
1198 * and descending.
1199 */
1200 switch (nmlv->iSubItem)
1201 {
1202 case 0:
1205 break;
1206 case 1:
1209 break;
1210 case 2:
1213 break;
1214 case 3:
1217 break;
1218 }
1219 break;
1220 }
1221 }
1222 break;
1223 }
1224 case WM_COMMAND:
1225 switch (wp)
1226 {
1229 break;
1230 case IDC_MGR_IMPORT:
1231 if (CryptUIWizImport(0, hwnd, NULL, NULL,
1234 break;
1235 case IDC_MGR_ADVANCED:
1238 {
1240 int index, len;
1241 LPWSTR curString = NULL;
1242
1244 if (index >= 0)
1245 {
1247 curString = HeapAlloc(GetProcessHeap(), 0,
1248 (len + 1) * sizeof(WCHAR));
1249 SendMessageW(cb, CB_GETLBTEXT, index, (LPARAM)curString);
1250 }
1253 if (curString)
1254 {
1256 (LPARAM)curString);
1257 if (index >= 0)
1259 HeapFree(GetProcessHeap(), 0, curString);
1260 }
1262 }
1263 break;
1264 case IDC_MGR_VIEW:
1265 {
1269
1270 if (selection >= 0)
1272 break;
1273 }
1274 case IDC_MGR_EXPORT:
1276 break;
1277 case IDC_MGR_REMOVE:
1279 break;
1280 case IDCANCEL:
1284 ImageList_Destroy(data->imageList);
1287 break;
1288 }
1289 break;
1290 }
1291 return 0;
1292}
1293
1294/***********************************************************************
1295 * CryptUIDlgCertMgr (CRYPTUI.@)
1296 */
1298{
1299 TRACE("(%p)\n", pCryptUICertMgr);
1300
1301 if (pCryptUICertMgr->dwSize != sizeof(CRYPTUI_CERT_MGR_STRUCT))
1302 {
1303 WARN("unexpected size %d\n", pCryptUICertMgr->dwSize);
1305 return FALSE;
1306 }
1308 pCryptUICertMgr->hwndParent, cert_mgr_dlg_proc, (LPARAM)pCryptUICertMgr);
1309 return TRUE;
1310}
1311
1312/* FIXME: real names are unknown, functions are undocumented */
1314{
1318
1320{
1326
1328 void *pvArg);
1329
1330/* Values for dwFlags */
1331#define CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE 0x00000001
1332
1334{
1342 void *pvArg;
1344
1346{
1354 void *pvArg;
1356
1358{
1359 enum {
1363 union {
1367};
1368
1369static BOOL WINAPI enum_store_callback(const void *pvSystemStore,
1371 void *pvArg)
1372{
1374 TVINSERTSTRUCTW tvis;
1375 LPCWSTR localizedName;
1376 BOOL ret = TRUE;
1377
1378 tvis.hParent = NULL;
1379 tvis.hInsertAfter = TVI_LAST;
1380 tvis.u.item.mask = TVIF_TEXT;
1381 if ((localizedName = CryptFindLocalizedName(pvSystemStore)))
1382 {
1383 struct StoreInfo *storeInfo = HeapAlloc(GetProcessHeap(), 0,
1384 sizeof(struct StoreInfo));
1385
1386 if (storeInfo)
1387 {
1388 storeInfo->type = SystemStore;
1389 storeInfo->u.name = HeapAlloc(GetProcessHeap(), 0,
1390 (lstrlenW(pvSystemStore) + 1) * sizeof(WCHAR));
1391 if (storeInfo->u.name)
1392 {
1393 tvis.u.item.mask |= TVIF_PARAM;
1394 tvis.u.item.lParam = (LPARAM)storeInfo;
1395 lstrcpyW(storeInfo->u.name, pvSystemStore);
1396 }
1397 else
1398 {
1399 HeapFree(GetProcessHeap(), 0, storeInfo);
1400 ret = FALSE;
1401 }
1402 }
1403 else
1404 ret = FALSE;
1405 tvis.u.item.pszText = (LPWSTR)localizedName;
1406 }
1407 else
1408 tvis.u.item.pszText = (LPWSTR)pvSystemStore;
1409 /* FIXME: need a folder icon for the store too */
1410 if (ret)
1412 return ret;
1413}
1414
1416{
1417 DWORD i;
1419
1420 for (i = 0; i < pEnumData->cEnumArgs; i++)
1424 for (i = 0; i < pEnumData->cStores; i++)
1425 {
1426 DWORD size;
1427
1428 if (CertGetStoreProperty(pEnumData->rghStore[i],
1430 {
1432
1433 if (name)
1434 {
1435 if (CertGetStoreProperty(pEnumData->rghStore[i],
1437 {
1438 struct StoreInfo *storeInfo = HeapAlloc(GetProcessHeap(),
1439 0, sizeof(struct StoreInfo));
1440
1441 if (storeInfo)
1442 {
1443 TVINSERTSTRUCTW tvis;
1444
1445 storeInfo->type = StoreHandle;
1446 storeInfo->u.store = pEnumData->rghStore[i];
1447 tvis.hParent = NULL;
1448 tvis.hInsertAfter = TVI_LAST;
1449 tvis.u.item.mask = TVIF_TEXT | TVIF_PARAM;
1450 tvis.u.item.pszText = name;
1451 tvis.u.item.lParam = (LPARAM)storeInfo;
1453 }
1454 }
1456 }
1457 }
1458 }
1459}
1460
1462{
1464 0);
1465
1466 while (next)
1467 {
1468 TVITEMW item;
1469
1470 memset(&item, 0, sizeof(item));
1471 item.mask = TVIF_HANDLE | TVIF_PARAM;
1472 item.hItem = next;
1474 if (item.lParam)
1475 {
1476 struct StoreInfo *storeInfo = (struct StoreInfo *)item.lParam;
1477
1478 if (storeInfo->type == SystemStore)
1479 HeapFree(GetProcessHeap(), 0, storeInfo->u.name);
1480 HeapFree(GetProcessHeap(), 0, storeInfo);
1481 }
1483 (LPARAM)next);
1484 }
1485}
1486
1488{
1490 TVITEMW item;
1492
1493 memset(&item, 0, sizeof(item));
1495 item.hItem = hItem;
1496 item.cchTextMax = ARRAY_SIZE(buf);
1497 item.pszText = buf;
1499 if (item.lParam)
1500 {
1501 struct StoreInfo *storeInfo = (struct StoreInfo *)item.lParam;
1502
1503 if (storeInfo->type == StoreHandle)
1504 store = storeInfo->u.store;
1505 else
1506 store = CertOpenSystemStoreW(0, storeInfo->u.name);
1507 }
1508 else
1509 {
1510 /* It's implicitly a system store */
1512 }
1513 return store;
1514}
1515
1517{
1520};
1521
1523 LPARAM lp)
1524{
1525 struct SelectStoreInfo *selectInfo;
1526 LRESULT ret = 0;
1527
1528 switch (msg)
1529 {
1530 case WM_INITDIALOG:
1531 {
1532 selectInfo = (struct SelectStoreInfo *)lp;
1534 if (selectInfo->info->pwszTitle)
1536 (LPARAM)selectInfo->info->pwszTitle);
1537 if (selectInfo->info->pwszText)
1539 (LPARAM)selectInfo->info->pwszText);
1540 if (!(selectInfo->info->dwFlags & CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE))
1542 enumerate_stores(hwnd, selectInfo->info->pEnumData);
1543 break;
1544 }
1545 case WM_COMMAND:
1546 switch (wp)
1547 {
1548 case IDOK:
1549 {
1553
1554 selectInfo = (struct SelectStoreInfo *)GetWindowLongPtrW(hwnd,
1555 DWLP_USER);
1556 if (!selection)
1557 {
1559
1560 if (selectInfo->info->pwszTitle)
1561 pTitle = selectInfo->info->pwszTitle;
1562 else
1563 {
1565 pTitle = title;
1566 }
1569 }
1570 else
1571 {
1573
1574 if (!selectInfo->info->pfnSelectedStoreCallback ||
1576 selectInfo->info->pvArg))
1577 {
1578 selectInfo->store = store;
1581 }
1582 else
1584 }
1585 ret = TRUE;
1586 break;
1587 }
1588 case IDCANCEL:
1591 ret = TRUE;
1592 break;
1593 }
1594 break;
1595 }
1596 return ret;
1597}
1598
1599/***********************************************************************
1600 * CryptUIDlgSelectStoreW (CRYPTUI.@)
1601 */
1603{
1604 struct SelectStoreInfo selectInfo = { info, NULL };
1605
1606 TRACE("(%p)\n", info);
1607
1608 if (info->dwSize != sizeof(CRYPTUI_SELECTSTORE_INFO_W))
1609 {
1610 WARN("unexpected size %d\n", info->dwSize);
1612 return NULL;
1613 }
1615 select_store_dlg_proc, (LPARAM)&selectInfo);
1616 return selectInfo.store;
1617}
1618
1619/***********************************************************************
1620 * CryptUIDlgSelectStoreA (CRYPTUI.@)
1621 */
1623{
1626 int len;
1627
1628 TRACE("(%p)\n", info);
1629
1630 if (info->dwSize != sizeof(CRYPTUI_SELECTSTORE_INFO_A))
1631 {
1632 WARN("unexpected size %d\n", info->dwSize);
1634 return NULL;
1635 }
1636 memcpy(&infoW, info, sizeof(*info));
1637 if (info->pszTitle)
1638 {
1639 len = MultiByteToWideChar(CP_ACP, 0, info->pszTitle, -1, NULL, 0);
1640 infoW.pwszTitle = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1641 MultiByteToWideChar(CP_ACP, 0, info->pszTitle, -1, infoW.pwszTitle,
1642 len);
1643 }
1644 if (info->pszText)
1645 {
1646 len = MultiByteToWideChar(CP_ACP, 0, info->pszText, -1, NULL, 0);
1647 infoW.pwszText = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1648 MultiByteToWideChar(CP_ACP, 0, info->pszText, -1, infoW.pwszText, len);
1649 }
1651 HeapFree(GetProcessHeap(), 0, infoW.pwszText);
1652 HeapFree(GetProcessHeap(), 0, infoW.pwszTitle);
1653 return ret;
1654}
1655
1656/***********************************************************************
1657 * CryptUIDlgViewCertificateA (CRYPTUI.@)
1658 */
1660 PCCRYPTUI_VIEWCERTIFICATE_STRUCTA pCertViewInfo, BOOL *pfPropertiesChanged)
1661{
1663 LPWSTR title = NULL;
1664 BOOL ret;
1665
1666 TRACE("(%p, %p)\n", pCertViewInfo, pfPropertiesChanged);
1667
1668 memcpy(&viewInfo, pCertViewInfo, sizeof(viewInfo));
1669 if (pCertViewInfo->szTitle)
1670 {
1671 int len = MultiByteToWideChar(CP_ACP, 0, pCertViewInfo->szTitle, -1,
1672 NULL, 0);
1673
1674 title = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1675 if (title)
1676 {
1677 MultiByteToWideChar(CP_ACP, 0, pCertViewInfo->szTitle, -1, title,
1678 len);
1679 viewInfo.szTitle = title;
1680 }
1681 else
1682 {
1683 ret = FALSE;
1684 goto error;
1685 }
1686 }
1687 if (pCertViewInfo->cPropSheetPages)
1688 {
1689 FIXME("ignoring additional prop sheet pages\n");
1690 viewInfo.cPropSheetPages = 0;
1691 }
1692 ret = CryptUIDlgViewCertificateW(&viewInfo, pfPropertiesChanged);
1694error:
1695 return ret;
1696}
1697
1699{
1703};
1704
1706 LONG cb, LONG *pcb)
1707{
1708 struct ReadStringStruct *string = (struct ReadStringStruct *)dwCookie;
1709 LONG cch = min(cb / sizeof(WCHAR), string->len - string->pos);
1710
1711 TRACE("(%p, %p, %d, %p)\n", string, buf, cb, pcb);
1712
1713 memmove(buf, string->buf + string->pos, cch * sizeof(WCHAR));
1714 string->pos += cch;
1715 *pcb = cch * sizeof(WCHAR);
1716 return 0;
1717}
1718
1720{
1721 struct ReadStringStruct string;
1722 EDITSTREAM editstream;
1723
1724 TRACE("(%p, %s)\n", hwnd, debugstr_wn(text, len));
1725
1726 string.buf = text;
1727 string.pos = 0;
1728 string.len = len;
1729 editstream.dwCookie = (DWORD_PTR)&string;
1730 editstream.dwError = 0;
1731 editstream.pfnCallback = read_text_callback;
1733 (LPARAM)&editstream);
1734}
1735
1737{
1738 LPWSTR str;
1739 LONG len;
1740
1741 len = LoadStringW(hInstance, id, (LPWSTR)&str, 0);
1743}
1744
1746 LONG len, const PARAFORMAT2 *fmt)
1747{
1750}
1751
1753 const PARAFORMAT2 *fmt)
1754{
1755 LPWSTR str;
1756 LONG len;
1757
1758 len = LoadStringW(hInstance, id, (LPWSTR)&str, 0);
1760}
1761
1763 DWORD dwFlags)
1764{
1765 LPWSTR buf = NULL;
1766 DWORD len;
1767
1769 if (len)
1770 {
1771 buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1772 if (buf)
1774 }
1775 return buf;
1776}
1777
1779 DWORD dwType, DWORD dwFlags)
1780{
1782
1783 if (name)
1784 {
1785 /* Don't include NULL-terminator in output */
1787
1790 }
1791}
1792
1793static void add_icon_to_control(HWND hwnd, int id)
1794{
1795 HRESULT hr;
1796 IRichEditOle *richEditOle = NULL;
1797 IOleObject *object = NULL;
1798 CLSID clsid;
1799 LPOLECACHE oleCache = NULL;
1800 FORMATETC formatEtc;
1801 DWORD conn;
1802 IDataObject *dataObject = NULL;
1804 STGMEDIUM stgm;
1805 IOleClientSite *clientSite = NULL;
1806 REOBJECT reObject;
1807
1808 TRACE("(%p, %d)\n", hwnd, id);
1809
1810 SendMessageW(hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&richEditOle);
1811 if (!richEditOle)
1812 goto end;
1814 (void**)&object);
1815 if (FAILED(hr))
1816 goto end;
1817 hr = IOleObject_GetUserClassID(object, &clsid);
1818 if (FAILED(hr))
1819 goto end;
1820 hr = IOleObject_QueryInterface(object, &IID_IOleCache, (void**)&oleCache);
1821 if (FAILED(hr))
1822 goto end;
1823 formatEtc.cfFormat = CF_BITMAP;
1824 formatEtc.ptd = NULL;
1825 formatEtc.dwAspect = DVASPECT_CONTENT;
1826 formatEtc.lindex = -1;
1827 formatEtc.tymed = TYMED_GDI;
1828 hr = IOleCache_Cache(oleCache, &formatEtc, 0, &conn);
1829 if (FAILED(hr))
1830 goto end;
1831 hr = IOleObject_QueryInterface(object, &IID_IDataObject,
1832 (void**)&dataObject);
1833 if (FAILED(hr))
1834 goto end;
1835 hr = IRichEditOle_GetClientSite(richEditOle, &clientSite);
1836 if (FAILED(hr))
1837 goto end;
1840 if (!bitmap)
1841 goto end;
1842 stgm.tymed = TYMED_GDI;
1843 stgm.u.hBitmap = bitmap;
1844 stgm.pUnkForRelease = NULL;
1845 hr = IDataObject_SetData(dataObject, &formatEtc, &stgm, TRUE);
1846 if (FAILED(hr))
1847 goto end;
1848
1849 reObject.cbStruct = sizeof(reObject);
1850 reObject.cp = REO_CP_SELECTION;
1851 reObject.clsid = clsid;
1852 reObject.poleobj = object;
1853 reObject.pstg = NULL;
1854 reObject.polesite = clientSite;
1855 reObject.sizel.cx = reObject.sizel.cy = 0;
1856 reObject.dvaspect = DVASPECT_CONTENT;
1857 reObject.dwFlags = 0;
1858 reObject.dwUser = 0;
1859
1860 IRichEditOle_InsertObject(richEditOle, &reObject);
1861
1862end:
1863 if (clientSite)
1864 IOleClientSite_Release(clientSite);
1865 if (dataObject)
1866 IDataObject_Release(dataObject);
1867 if (oleCache)
1868 IOleCache_Release(oleCache);
1869 if (object)
1870 IOleObject_Release(object);
1871 if (richEditOle)
1872 IRichEditOle_Release(richEditOle);
1873}
1874
1875#define MY_INDENT 200
1876
1877static void add_oid_text_to_control(HWND hwnd, char *oid)
1878{
1879 WCHAR nl = '\n';
1881 PARAFORMAT2 parFmt;
1882
1883 parFmt.cbSize = sizeof(parFmt);
1884 parFmt.dwMask = PFM_STARTINDENT;
1885 parFmt.dxStartIndent = MY_INDENT * 3;
1886 if (oidInfo)
1887 {
1889 lstrlenW(oidInfo->pwszName), &parFmt);
1891 }
1892}
1893
1895{
1897 int id;
1898};
1899
1900/* The following list MUST be lexicographically sorted by OID */
1901static struct OIDToString oidMap[] = {
1902 /* 1.3.6.1.4.1.311.10.3.1 */
1904 /* 1.3.6.1.4.1.311.10.3.4 */
1906 /* 1.3.6.1.4.1.311.10.3.4.1 */
1908 /* 1.3.6.1.4.1.311.10.3.5 */
1910 /* 1.3.6.1.4.1.311.10.3.6 */
1912 /* 1.3.6.1.4.1.311.10.3.7 */
1914 /* 1.3.6.1.4.1.311.10.3.8 */
1916 /* 1.3.6.1.4.1.311.10.3.9 */
1918 /* 1.3.6.1.4.1.311.10.3.10 */
1920 /* 1.3.6.1.4.1.311.10.3.11 */
1922 /* 1.3.6.1.4.1.311.10.3.12 */
1924 /* 1.3.6.1.4.1.311.10.3.13 */
1926 /* 1.3.6.1.4.1.311.10.5.1 */
1928 /* 1.3.6.1.4.1.311.10.6.1 */
1930 /* 1.3.6.1.4.1.311.10.6.2 */
1932 /* 1.3.6.1.4.1.311.20.2.1 */
1934 /* 1.3.6.1.4.1.311.20.2.2 */
1936 /* 1.3.6.1.4.1.311.21.5 */
1938 /* 1.3.6.1.4.1.311.21.6 */
1940 /* 1.3.6.1.4.1.311.21.19 */
1942 /* 1.3.6.1.5.5.7.3.1 */
1944 /* 1.3.6.1.5.5.7.3.2 */
1946 /* 1.3.6.1.5.5.7.3.3 */
1948 /* 1.3.6.1.5.5.7.3.4 */
1950 /* 1.3.6.1.5.5.7.3.5 */
1952 /* 1.3.6.1.5.5.7.3.6 */
1954 /* 1.3.6.1.5.5.7.3.7 */
1956 /* 1.3.6.1.5.5.7.3.8 */
1958};
1959
1961{
1962 int indexHigh = ARRAY_SIZE(oidMap) - 1, indexLow = 0;
1963
1964 while (indexLow <= indexHigh)
1965 {
1966 int cmp, i = (indexLow + indexHigh) / 2;
1967 if (!(cmp = strcmp(oid, oidMap[i].oid)))
1968 return &oidMap[i];
1969 if (cmp > 0)
1970 indexLow = i + 1;
1971 else
1972 indexHigh = i - 1;
1973 }
1974 return NULL;
1975}
1976
1978{
1979 struct OIDToString *entry;
1980 WCHAR nl = '\n';
1981 PARAFORMAT2 parFmt;
1982
1983 parFmt.cbSize = sizeof(parFmt);
1984 parFmt.dwMask = PFM_STARTINDENT;
1985 parFmt.dxStartIndent = MY_INDENT * 3;
1986 if ((entry = findSupportedOID(oid)))
1987 {
1988 WCHAR *str, *linebreak, *ptr;
1989 BOOL multiline = FALSE;
1990 int len;
1991
1992 len = LoadStringW(hInstance, entry->id, (LPWSTR)&str, 0);
1993 ptr = str;
1994 do {
1995 if ((linebreak = wmemchr(ptr, '\n', len)))
1996 {
1998
1999 multiline = TRUE;
2000 /* The source string contains a newline, which the richedit
2001 * control won't find since it's interpreted as a paragraph
2002 * break. Therefore copy up to the newline. lstrcpynW always
2003 * NULL-terminates, so pass one more than the length of the
2004 * source line so the copy includes the entire line and the
2005 * NULL-terminator.
2006 */
2007 lstrcpynW(copy, ptr, linebreak - ptr + 1);
2009 linebreak - ptr, &parFmt);
2010 ptr = linebreak + 1;
2012 }
2013 else if (multiline && *ptr)
2014 {
2015 /* Add the last line */
2017 len - (ptr - str), &parFmt);
2019 }
2020 } while (linebreak);
2021 if (!multiline)
2022 {
2025 }
2026 }
2027 else
2028 {
2029 WCHAR *oidW = HeapAlloc(GetProcessHeap(), 0,
2030 (strlen(oid) + 1) * sizeof(WCHAR));
2031
2032 if (oidW)
2033 {
2034 LPCSTR src;
2035 WCHAR *dst;
2036
2037 for (src = oid, dst = oidW; *src; src++, dst++)
2038 *dst = *src;
2039 *dst = 0;
2041 &parFmt);
2043 HeapFree(GetProcessHeap(), 0, oidW);
2044 }
2045 }
2046}
2047
2049 BOOL *anyUsageAdded)
2050{
2051 static char any_app_policy[] = szOID_ANY_APPLICATION_POLICY;
2052 WCHAR nl = '\n';
2053 CHARFORMATW charFmt;
2054 PCERT_EXTENSION policyExt;
2055 if (!*anyUsageAdded)
2056 {
2057 PARAFORMAT2 parFmt;
2058
2059 parFmt.cbSize = sizeof(parFmt);
2060 parFmt.dwMask = PFM_STARTINDENT;
2061 parFmt.dxStartIndent = MY_INDENT;
2063 IDS_CERT_INFO_PURPOSES, &parFmt);
2065 *anyUsageAdded = TRUE;
2066 }
2067 memset(&charFmt, 0, sizeof(charFmt));
2068 charFmt.cbSize = sizeof(charFmt);
2069 charFmt.dwMask = CFM_BOLD;
2070 charFmt.dwEffects = 0;
2073 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension)))
2074 {
2075 CERT_POLICIES_INFO *policies;
2076 DWORD size;
2077
2079 policyExt->Value.pbData, policyExt->Value.cbData,
2080 CRYPT_DECODE_ALLOC_FLAG, NULL, &policies, &size))
2081 {
2082 DWORD i;
2083
2084 for (i = 0; i < policies->cPolicyInfo; i++)
2085 {
2086 DWORD j;
2087
2088 for (j = 0; j < policies->rgPolicyInfo[i].cPolicyQualifier; j++)
2090 policies->rgPolicyInfo[i].rgPolicyQualifier[j].
2091 pszPolicyQualifierId);
2092 }
2093 LocalFree(policies);
2094 }
2095 }
2096 else
2097 add_oid_text_to_control(text, any_app_policy);
2098}
2099
2101 BOOL *anyUsageAdded)
2102{
2103 WCHAR nl = '\n';
2104 DWORD size;
2105 BOOL badUsages = FALSE;
2106
2108 {
2109 CHARFORMATW charFmt;
2110 static char any_cert_policy[] = szOID_ANY_CERT_POLICY;
2112
2113 if (usage)
2114 {
2116 {
2117 DWORD i;
2118
2119 if (!*anyUsageAdded)
2120 {
2121 PARAFORMAT2 parFmt;
2122
2123 parFmt.cbSize = sizeof(parFmt);
2124 parFmt.dwMask = PFM_STARTINDENT;
2125 parFmt.dxStartIndent = MY_INDENT;
2127 IDS_CERT_INFO_PURPOSES, &parFmt);
2129 *anyUsageAdded = TRUE;
2130 }
2131 memset(&charFmt, 0, sizeof(charFmt));
2132 charFmt.cbSize = sizeof(charFmt);
2133 charFmt.dwMask = CFM_BOLD;
2134 charFmt.dwEffects = 0;
2136 (LPARAM)&charFmt);
2137 if (!usage->cUsageIdentifier)
2138 add_oid_text_to_control(text, any_cert_policy);
2139 else
2140 for (i = 0; i < usage->cUsageIdentifier; i++)
2142 usage->rgpszUsageIdentifier[i]);
2143 }
2144 else
2145 badUsages = TRUE;
2147 }
2148 else
2149 badUsages = TRUE;
2150 }
2151 else
2152 badUsages = TRUE;
2153 return badUsages;
2154}
2155
2158{
2159 BOOL includeCertUsages = FALSE, includeAppUsages = FALSE;
2160 BOOL badUsages = FALSE, anyUsageAdded = FALSE;
2161
2162 if (pCertViewInfo->cPurposes)
2163 {
2164 DWORD i;
2165
2166 for (i = 0; i < pCertViewInfo->cPurposes; i++)
2167 {
2168 if (!strcmp(pCertViewInfo->rgszPurposes[i], szOID_ANY_CERT_POLICY))
2169 includeCertUsages = TRUE;
2170 else if (!strcmp(pCertViewInfo->rgszPurposes[i],
2172 includeAppUsages = TRUE;
2173 else
2174 badUsages = TRUE;
2175 }
2176 }
2177 else
2178 includeAppUsages = includeCertUsages = TRUE;
2179 if (includeAppUsages)
2180 display_app_usages(text, pCertViewInfo->pCertContext, &anyUsageAdded);
2181 if (includeCertUsages)
2182 badUsages = display_cert_usages(text, pCertViewInfo->pCertContext,
2183 &anyUsageAdded);
2184 if (badUsages)
2185 {
2186 PARAFORMAT2 parFmt;
2187
2188 parFmt.cbSize = sizeof(parFmt);
2189 parFmt.dwMask = PFM_STARTINDENT;
2190 parFmt.dxStartIndent = MY_INDENT;
2193 }
2194}
2195
2197 LPCSTR policyOid)
2198{
2200 DWORD i;
2201
2202 for (i = 0; !ret && i < policies->cPolicyInfo; i++)
2203 {
2204 DWORD j;
2205
2206 for (j = 0; !ret && j < policies->rgPolicyInfo[i].cPolicyQualifier; j++)
2207 if (!strcmp(policies->rgPolicyInfo[i].rgPolicyQualifier[j].
2208 pszPolicyQualifierId, policyOid))
2209 ret = &policies->rgPolicyInfo[i].rgPolicyQualifier[j].
2210 Qualifier;
2211 }
2212 return ret;
2213}
2214
2216{
2217 LPWSTR qualifierStr = NULL;
2218 CERT_NAME_VALUE *qualifierValue;
2219 DWORD size;
2220
2223 &qualifierValue, &size))
2224 {
2225 size = CertRDNValueToStrW(qualifierValue->dwValueType,
2226 &qualifierValue->Value, NULL, 0);
2227 qualifierStr = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
2228 if (qualifierStr)
2229 CertRDNValueToStrW(qualifierValue->dwValueType,
2230 &qualifierValue->Value, qualifierStr, size);
2231 LocalFree(qualifierValue);
2232 }
2233 return qualifierStr;
2234}
2235
2237{
2238 LPWSTR str = NULL;
2239 CERT_POLICY_QUALIFIER_USER_NOTICE *qualifierValue;
2240 DWORD size;
2241
2245 &qualifierValue, &size))
2246 {
2248 (lstrlenW(qualifierValue->pszDisplayText) + 1) * sizeof(WCHAR));
2249 if (str)
2250 lstrcpyW(str, qualifierValue->pszDisplayText);
2251 LocalFree(qualifierValue);
2252 }
2253 return str;
2254}
2255
2257{
2260};
2261
2264{
2265 PCERT_EXTENSION policyExt;
2266
2267 if (!(pCertViewInfo->dwFlags & CRYPTUI_DISABLE_ISSUERSTATEMENT) &&
2269 pCertViewInfo->pCertContext->pCertInfo->cExtension,
2270 pCertViewInfo->pCertContext->pCertInfo->rgExtension)))
2271 {
2272 CERT_POLICIES_INFO *policies;
2273 DWORD size;
2274
2276 policyExt->Value.pbData, policyExt->Value.cbData,
2277 CRYPT_DECODE_ALLOC_FLAG, NULL, &policies, &size))
2278 {
2280 LPWSTR cps = NULL, userNotice = NULL;
2281
2282 if ((qualifier = find_policy_qualifier(policies,
2285 if ((qualifier = find_policy_qualifier(policies,
2288 if (cps || userNotice)
2289 {
2290 struct IssuerStatement *issuerStatement =
2291 HeapAlloc(GetProcessHeap(), 0, sizeof(struct IssuerStatement));
2292
2293 if (issuerStatement)
2294 {
2295 issuerStatement->cps = cps;
2296 issuerStatement->userNotice = userNotice;
2299 (ULONG_PTR)issuerStatement);
2300 }
2301 }
2302 LocalFree(policies);
2303 }
2304 }
2305}
2306
2309{
2310 CHARFORMATW charFmt;
2311 PARAFORMAT2 parFmt;
2315 (CRYPT_PROVIDER_DATA *)pCertViewInfo->u.pCryptProviderData,
2316 pCertViewInfo->idxSigner, pCertViewInfo->fCounterSigner,
2317 pCertViewInfo->idxCounterSigner);
2319 &provSigner->pasCertChain[provSigner->csCertChain - 1];
2320
2321 if (!provSigner->pChainContext ||
2325 else if (!root->fTrustedRoot)
2327 else
2329
2330 memset(&charFmt, 0, sizeof(charFmt));
2331 charFmt.cbSize = sizeof(charFmt);
2332 charFmt.dwMask = CFM_BOLD;
2333 charFmt.dwEffects = CFE_BOLD;
2335 /* FIXME: vertically center text */
2336 parFmt.cbSize = sizeof(parFmt);
2337 parFmt.dwMask = PFM_STARTINDENT;
2338 parFmt.dxStartIndent = MY_INDENT;
2341
2344 if (provSigner->dwError == TRUST_E_CERT_SIGNATURE)
2346 IDS_CERT_INFO_BAD_SIG, &parFmt);
2347 else if (!provSigner->pChainContext ||
2352 else if (!root->fTrustedRoot)
2353 {
2354 if (provSigner->csCertChain == 1 && root->fSelfSigned)
2357 else
2360 }
2361 else
2362 {
2363 set_policy_text(text, pCertViewInfo);
2364 set_issuer_statement(hwnd, pCertViewInfo);
2365 }
2366}
2367
2369 DWORD nameFlags, int heading)
2370{
2371 WCHAR nl = '\n';
2373 CHARFORMATW charFmt;
2374 PARAFORMAT2 parFmt;
2375
2376 memset(&charFmt, 0, sizeof(charFmt));
2377 charFmt.cbSize = sizeof(charFmt);
2378 charFmt.dwMask = CFM_BOLD;
2379 charFmt.dwEffects = CFE_BOLD;
2381 parFmt.cbSize = sizeof(parFmt);
2382 parFmt.dwMask = PFM_STARTINDENT;
2383 parFmt.dxStartIndent = MY_INDENT * 3;
2385 charFmt.dwEffects = 0;
2388 nameFlags);
2392
2393}
2394
2395static void add_date_string_to_control(HWND hwnd, const FILETIME *fileTime)
2396{
2397 WCHAR dateFmt[80]; /* sufficient for all versions of LOCALE_SSHORTDATE */
2398 WCHAR date[80];
2399 SYSTEMTIME sysTime;
2400
2402 FileTimeToSystemTime(fileTime, &sysTime);
2403 GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, date, ARRAY_SIZE(date));
2405}
2406
2408{
2409 WCHAR nl = '\n';
2411 CHARFORMATW charFmt;
2412 PARAFORMAT2 parFmt;
2413
2414 memset(&charFmt, 0, sizeof(charFmt));
2415 charFmt.cbSize = sizeof(charFmt);
2416 charFmt.dwMask = CFM_BOLD;
2417 charFmt.dwEffects = CFE_BOLD;
2419 parFmt.cbSize = sizeof(parFmt);
2420 parFmt.dwMask = PFM_STARTINDENT;
2421 parFmt.dxStartIndent = MY_INDENT * 3;
2423 &parFmt);
2424 charFmt.dwEffects = 0;
2426 add_date_string_to_control(text, &cert->pCertInfo->NotBefore);
2427 charFmt.dwEffects = CFE_BOLD;
2430 charFmt.dwEffects = 0;
2432 add_date_string_to_control(text, &cert->pCertInfo->NotAfter);
2434}
2435
2438{
2439 set_cert_info(hwnd, pCertViewInfo);
2440 set_cert_name_string(hwnd, pCertViewInfo->pCertContext, 0,
2442 set_cert_name_string(hwnd, pCertViewInfo->pCertContext,
2445}
2446
2448 LPARAM lp)
2449{
2450 LRESULT ret = 0;
2451 HWND text;
2452 struct IssuerStatement *issuerStatement;
2453
2454 switch (msg)
2455 {
2456 case WM_INITDIALOG:
2458 issuerStatement = (struct IssuerStatement *)lp;
2460 lstrlenW(issuerStatement->userNotice));
2461 if (issuerStatement->cps)
2462 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)issuerStatement->cps);
2463 else
2465 break;
2466 case WM_COMMAND:
2467 switch (wp)
2468 {
2469 case IDOK:
2471 ret = TRUE;
2472 break;
2473 case IDC_CPS:
2474 {
2475 IBindCtx *bctx = NULL;
2476 LPWSTR cps;
2477
2478 CreateBindCtx(0, &bctx);
2481 HLNF_OPENINNEWWINDOW, 0);
2482 IBindCtx_Release(bctx);
2483 break;
2484 }
2485 }
2486 }
2487 return ret;
2488}
2489
2490static void show_user_notice(HWND hwnd, struct IssuerStatement *issuerStatement)
2491{
2493 user_notice_dlg_proc, (LPARAM)issuerStatement);
2494}
2495
2497 LPARAM lp)
2498{
2501
2502 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
2503
2504 switch (msg)
2505 {
2506 case WM_INITDIALOG:
2507 page = (PROPSHEETPAGEW *)lp;
2508 pCertViewInfo = (PCCRYPTUI_VIEWCERTIFICATE_STRUCTW)page->lParam;
2509 if (pCertViewInfo->dwFlags & CRYPTUI_DISABLE_ADDTOSTORE)
2512 set_general_info(hwnd, pCertViewInfo);
2513 break;
2514 case WM_COMMAND:
2515 switch (wp)
2516 {
2517 case IDC_ADDTOSTORE:
2519 break;
2521 {
2522 struct IssuerStatement *issuerStatement =
2524
2525 if (issuerStatement)
2526 {
2527 if (issuerStatement->userNotice)
2528 show_user_notice(hwnd, issuerStatement);
2529 else if (issuerStatement->cps)
2530 {
2531 IBindCtx *bctx = NULL;
2532
2533 CreateBindCtx(0, &bctx);
2534 HlinkSimpleNavigateToString(issuerStatement->cps, NULL,
2535 NULL, NULL, bctx, NULL, HLNF_OPENINNEWWINDOW, 0);
2536 IBindCtx_Release(bctx);
2537 }
2538 }
2539 break;
2540 }
2541 }
2542 break;
2543 }
2544 return 0;
2545}
2546
2549{
2550 struct IssuerStatement *issuerStatement;
2551
2552 switch (msg)
2553 {
2554 case PSPCB_RELEASE:
2555 issuerStatement =
2557 if (issuerStatement)
2558 {
2559 HeapFree(GetProcessHeap(), 0, issuerStatement->cps);
2560 HeapFree(GetProcessHeap(), 0, issuerStatement->userNotice);
2561 HeapFree(GetProcessHeap(), 0, issuerStatement);
2562 }
2563 break;
2564 }
2565 return 1;
2566}
2567
2570{
2571 memset(page, 0, sizeof(PROPSHEETPAGEW));
2572 page->dwSize = sizeof(PROPSHEETPAGEW);
2573 page->dwFlags = PSP_USECALLBACK;
2574 page->pfnCallback = general_callback_proc;
2575 page->hInstance = hInstance;
2576 page->u.pszTemplate = MAKEINTRESOURCEW(IDD_GENERAL);
2577 page->pfnDlgProc = general_dlg_proc;
2578 page->lParam = (LPARAM)pCertViewInfo;
2579}
2580
2581typedef WCHAR * (*field_format_func)(PCCERT_CONTEXT cert);
2582
2584{
2585 static const WCHAR fmt[] = { 'V','%','d',0 };
2586 WCHAR *buf = HeapAlloc(GetProcessHeap(), 0, 12 * sizeof(WCHAR));
2587
2588 if (buf)
2589 swprintf(buf, fmt, cert->pCertInfo->dwVersion);
2590 return buf;
2591}
2592
2594{
2595 WCHAR *buf = HeapAlloc(GetProcessHeap(), 0, (cb * 3 + 1) * sizeof(WCHAR));
2596
2597 if (buf)
2598 {
2599 static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
2600 DWORD i;
2601 WCHAR *ptr;
2602
2603 for (i = 0, ptr = buf; i < cb; i++, ptr += 3)
2604 swprintf(ptr, fmt, ((BYTE *)pb)[i]);
2605 }
2606 return buf;
2607}
2608
2610{
2611 return format_hex_string(cert->pCertInfo->SerialNumber.pbData,
2612 cert->pCertInfo->SerialNumber.cbData);
2613}
2614
2616{
2619}
2620
2622{
2623 WCHAR *str = NULL;
2626
2627 if (len)
2628 {
2629 str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2630 if (str)
2633 }
2634 return str;
2635}
2636
2638{
2639 return field_format_detailed_cert_name(&cert->pCertInfo->Issuer);
2640}
2641
2643{
2645}
2646
2648{
2649 return field_format_detailed_cert_name(&cert->pCertInfo->Subject);
2650}
2651
2652static WCHAR *format_long_date(const FILETIME *fileTime)
2653{
2654 WCHAR dateFmt[80]; /* long enough for LOCALE_SLONGDATE */
2655 DWORD len;
2656 WCHAR *buf = NULL;
2657 SYSTEMTIME sysTime;
2658
2659 /* FIXME: format isn't quite right, want time too */
2661 FileTimeToSystemTime(fileTime, &sysTime);
2662 len = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, NULL, 0);
2663 if (len)
2664 {
2665 buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2666 if (buf)
2667 GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, buf,
2668 len);
2669 }
2670 return buf;
2671}
2672
2674{
2675 return format_long_date(&cert->pCertInfo->NotBefore);
2676}
2677
2679{
2680 return format_long_date(&cert->pCertInfo->NotAfter);
2681}
2682
2684{
2686 WCHAR *buf = NULL;
2687
2689 cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, 0);
2690 if (oidInfo)
2691 {
2693
2695 {
2696 DWORD len;
2697
2698 /* Allocate the output buffer. Use the number of bytes in the
2699 * public key as a conservative (high) estimate for the number of
2700 * digits in its output.
2701 * The output is of the form (in English)
2702 * "<public key algorithm> (<public key bit length> bits)".
2703 * Ordinarily having two positional parameters in a string is not a
2704 * good idea, but as this isn't a sentence fragment, it shouldn't
2705 * be word-order dependent.
2706 */
2707 len = lstrlenW(fmt) + lstrlenW(oidInfo->pwszName) +
2708 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData * 8;
2709 buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(*buf));
2710 if (buf)
2711 {
2712 DWORD_PTR args[2];
2713 args[0] = (DWORD_PTR)oidInfo->pwszName;
2715 &cert->pCertInfo->SubjectPublicKeyInfo);
2717 fmt, 0, 0, buf, len, (__ms_va_list*)args);
2718 }
2719 }
2720 }
2721 return buf;
2722}
2723
2725{
2726 return format_hex_string(
2727 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
2728 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData);
2729}
2730
2731struct field_value_data;
2733{
2738};
2739
2741
2742typedef WCHAR *(*create_detailed_value_func)(PCCERT_CONTEXT cert, void *param);
2743
2745{
2748 void *param;
2749};
2750
2753{
2754 if (data->cFields)
2755 data->fields = HeapReAlloc(GetProcessHeap(), 0, data->fields,
2756 (data->cFields + 1) * sizeof(struct field_value_data));
2757 else
2758 data->fields = HeapAlloc(GetProcessHeap(), 0,
2759 sizeof(struct field_value_data));
2760 if (data->fields)
2761 {
2762 data->fields[data->cFields].create = create;
2763 data->fields[data->cFields].detailed_value = NULL;
2764 data->fields[data->cFields].param = param;
2765 data->cFields++;
2766 }
2767}
2768
2771{
2772 LVITEMW item;
2773 int iItem = SendMessageW(hwnd, LVM_GETITEMCOUNT, 0, 0);
2774
2775 item.mask = LVIF_TEXT | LVIF_PARAM;
2776 item.iItem = iItem;
2777 item.iSubItem = 0;
2778 item.pszText = field;
2779 item.lParam = (LPARAM)data;
2781 if (value)
2782 {
2783 item.pszText = value;
2784 item.iSubItem = 1;
2786 }
2788}
2789
2792{
2794
2797}
2798
2800{
2801 int id;
2804};
2805
2807 const struct v1_field *field)
2808{
2809 WCHAR *val = field->format(data->pCertViewInfo->pCertContext);
2810
2811 if (val)
2812 {
2814 field->create_detailed_value, NULL);
2816 }
2817}
2818
2819static const struct v1_field v1_fields[] = {
2828};
2829
2831{
2832 unsigned int i;
2833 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
2834
2835 /* The last item in v1_fields is the public key, which is not in the loop
2836 * because it's a special case.
2837 */
2838 for (i = 0; i < ARRAY_SIZE(v1_fields) - 1; i++)
2840 if (cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData)
2842}
2843
2845{
2846 WCHAR *str = NULL;
2847 DWORD size;
2848
2849 if (CryptFormatObject(X509_ASN_ENCODING, 0, formatStrType, NULL,
2850 ext->pszObjId, ext->Value.pbData, ext->Value.cbData, NULL, &size))
2851 {
2853 CryptFormatObject(X509_ASN_ENCODING, 0, formatStrType, NULL,
2854 ext->pszObjId, ext->Value.pbData, ext->Value.cbData, str, &size);
2855 }
2856 return str;
2857}
2858
2860{
2861 WCHAR *str = NULL;
2862
2863 if (ext->Value.cbData)
2864 {
2865 /* The output is formatted as:
2866 * <hex bytes> <ascii bytes>\n
2867 * where <hex bytes> is a string of up to 8 bytes, output as %02x,
2868 * and <ascii bytes> is the ASCII equivalent of each byte, or '.' if
2869 * the byte is not printable.
2870 * So, for example, the extension value consisting of the following
2871 * bytes:
2872 * 0x30,0x14,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x03,
2873 * 0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67
2874 * is output as:
2875 * 30 14 31 12 30 10 06 03 0.1.0...
2876 * 55 04 03 13 09 4a 75 61 U....Jua
2877 * 6e 20 4c 61 6e 67 n Lang
2878 * The allocation size therefore requires:
2879 * - 4 characters per character in an 8-byte line
2880 * (2 for the hex format, one for the space, one for the ASCII value)
2881 * - 3 more characters per 8-byte line (two spaces and a newline)
2882 * - 1 character for the terminating nul
2883 * FIXME: should use a fixed-width font for this
2884 */
2885 DWORD lines = (ext->Value.cbData + 7) / 8;
2886
2888 (lines * 8 * 4 + lines * 3 + 1) * sizeof(WCHAR));
2889 if (str)
2890 {
2891 static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
2892 DWORD i, j;
2893 WCHAR *ptr;
2894
2895 for (i = 0, ptr = str; i < ext->Value.cbData; i += 8)
2896 {
2897 /* Output as hex bytes first */
2898 for (j = i; j < min(i + 8, ext->Value.cbData); j++, ptr += 3)
2899 swprintf(ptr, fmt, ext->Value.pbData[j]);
2900 /* Pad the hex output with spaces for alignment */
2901 if (j == ext->Value.cbData && j % 8)
2902 {
2903 static const WCHAR pad[] = { ' ',' ',' ' };
2904
2905 for (; j % 8; j++, ptr += ARRAY_SIZE(pad))
2906 memcpy(ptr, pad, sizeof(pad));
2907 }
2908 /* The last swprintf included a space, so just insert one
2909 * more space between the hex bytes and the ASCII output
2910 */
2911 *ptr++ = ' ';
2912 /* Output as ASCII bytes */
2913 for (j = i; j < min(i + 8, ext->Value.cbData); j++, ptr++)
2914 {
2915 if (iswprint(ext->Value.pbData[j]) &&
2916 !iswspace(ext->Value.pbData[j]))
2917 *ptr = ext->Value.pbData[j];
2918 else
2919 *ptr = '.';
2920 }
2921 *ptr++ = '\n';
2922 }
2923 *ptr++ = '\0';
2924 }
2925 }
2926 return str;
2927}
2928
2930{
2934
2935 if (!str)
2937 return str;
2938}
2939
2942{
2944 ext->pszObjId, 0);
2946
2947 if (oidInfo)
2950 else
2951 {
2952 DWORD len = strlen(ext->pszObjId);
2953 LPWSTR oidW = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2954
2955 if (oidW)
2956 {
2957 DWORD i;
2958
2959 for (i = 0; i <= len; i++)
2960 oidW[i] = ext->pszObjId[i];
2963 HeapFree(GetProcessHeap(), 0, oidW);
2964 }
2965 }
2967}
2968
2970{
2971 DWORD i;
2972 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
2973
2974 for (i = 0; i < cert->pCertInfo->cExtension; i++)
2975 add_cert_extension_detail(hwnd, data, &cert->pCertInfo->rgExtension[i]);
2976}
2977
2979{
2980 DWORD i;
2981 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
2982
2983 for (i = 0; i < cert->pCertInfo->cExtension; i++)
2984 if (cert->pCertInfo->rgExtension[i].fCritical)
2986 &cert->pCertInfo->rgExtension[i]);
2987}
2988
2989typedef WCHAR * (*prop_to_value_func)(void *pb, DWORD cb);
2990
2992{
2994 int id;
2997};
2998
3000{
3002
3003 ext.pszObjId = (LPSTR)X509_ENHANCED_KEY_USAGE;
3004 ext.fCritical = FALSE;
3005 ext.Value.pbData = pb;
3006 ext.Value.cbData = cb;
3007 return crypt_format_extension(&ext, 0);
3008}
3009
3010/* Logically the access state should also be checked, and IDC_EDITPROPERTIES
3011 * disabled for read-only certificates, but native doesn't appear to do that.
3012 */
3013static const struct prop_id_to_string_id prop_id_map[] = {
3019};
3020
3022{
3023 DWORD i;
3024 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
3025
3026 for (i = 0; i < ARRAY_SIZE(prop_id_map); i++)
3027 {
3028 DWORD cb;
3029
3031 &cb))
3032 {
3033 BYTE *pb;
3034 WCHAR *val = NULL;
3035
3036 /* FIXME: MS adds a separate value for the signature hash
3037 * algorithm.
3038 */
3039 pb = HeapAlloc(GetProcessHeap(), 0, cb);
3040 if (pb)
3041 {
3043 prop_id_map[i].prop, pb, &cb))
3044 {
3046 {
3047 val = (LPWSTR)pb;
3048 /* Don't double-free pb */
3049 pb = NULL;
3050 }
3051 else
3052 val = prop_id_map[i].prop_to_value(pb, cb);
3053 }
3054 HeapFree(GetProcessHeap(), 0, pb);
3055 }
3057 NULL, NULL);
3058 }
3059 }
3060}
3061
3063{
3067}
3068
3070{
3071 int id;
3073};
3074
3075static const struct selection_list_item listItems[] = {
3081};
3082
3084{
3087 int i;
3088
3089 for (i = 0; i < ARRAY_SIZE(listItems); i++)
3090 {
3091 int index;
3092
3096 }
3098}
3099
3101{
3103 RECT rc;
3106
3108 GetWindowRect(lv, &rc);
3110 column.mask = LVCF_WIDTH | LVCF_TEXT;
3111 column.cx = (rc.right - rc.left) / 2 - 2;
3112 column.pszText = buf;
3116}
3117
3118static void set_fields_selection(HWND hwnd, struct detail_data *data, int sel)
3119{
3121
3122 if (sel >= 0 && sel < ARRAY_SIZE(listItems))
3123 {
3125 listItems[sel].add(list, data);
3126 }
3127}
3128
3130{
3134}
3135
3136static void add_purpose(HWND hwnd, LPCSTR oid)
3137{
3140 sizeof(CRYPT_OID_INFO));
3141
3142 if (info)
3143 {
3144 char *oidCopy = HeapAlloc(GetProcessHeap(), 0, strlen(oid) + 1);
3145
3146 if (oidCopy)
3147 {
3148 LVITEMA item;
3149
3150 strcpy(oidCopy, oid);
3151 info->cbSize = sizeof(CRYPT_OID_INFO);
3152 info->pszOID = oidCopy;
3155 item.stateMask = LVIS_STATEIMAGEMASK;
3156 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
3157 item.iSubItem = 0;
3158 item.lParam = (LPARAM)info;
3159 item.pszText = oidCopy;
3161 }
3162 else
3164 }
3165}
3166
3168{
3169 BOOL ret;
3170
3171 if (oid[0] != '0' && oid[0] != '1' && oid[0] != '2')
3172 ret = FALSE;
3173 else if (oid[1] != '.')
3174 ret = FALSE;
3175 else if (!oid[2])
3176 ret = FALSE;
3177 else
3178 {
3179 const char *ptr;
3180 BOOL expectNum = TRUE;
3181
3182 for (ptr = oid + 2, ret = TRUE; ret && *ptr; ptr++)
3183 {
3184 if (expectNum)
3185 {
3186 if (!isdigit(*ptr))
3187 ret = FALSE;
3188 else if (*(ptr + 1) == '.')
3189 expectNum = FALSE;
3190 }
3191 else
3192 {
3193 if (*ptr != '.')
3194 ret = FALSE;
3195 else if (!(*(ptr + 1)))
3196 ret = FALSE;
3197 else
3198 expectNum = TRUE;
3199 }
3200 }
3201 }
3202 return ret;
3203}
3204
3206{
3208 != -1;
3209}
3210
3211#define MAX_PURPOSE 255
3212
3214 WPARAM wp, LPARAM lp)
3215{
3216 LRESULT ret = 0;
3217 char buf[MAX_PURPOSE + 1];
3218
3219 switch (msg)
3220 {
3221 case WM_INITDIALOG:
3223 MAX_PURPOSE, 0);
3226 break;
3227 case WM_COMMAND:
3228 switch (HIWORD(wp))
3229 {
3230 case EN_CHANGE:
3231 if (LOWORD(wp) == IDC_NEW_PURPOSE)
3232 {
3233 /* Show/hide scroll bar on description depending on how much
3234 * text it has.
3235 */
3238
3240 }
3241 break;
3242 case BN_CLICKED:
3243 switch (LOWORD(wp))
3244 {
3245 case IDOK:
3247 (LPARAM)buf);
3248 if (!buf[0])
3249 {
3250 /* An empty purpose is the same as cancelling */
3252 ret = TRUE;
3253 }
3254 else if (!is_valid_oid(buf))
3255 {
3257
3261 }
3262 else if (is_oid_in_list(
3264 {
3266
3268 ARRAY_SIZE(error));
3271 }
3272 else
3273 {
3275
3277 EndDialog(hwnd, wp);
3278 ret = TRUE;
3279 }
3280 break;
3281 case IDCANCEL:
3282 EndDialog(hwnd, wp);
3283 ret = TRUE;
3284 break;
3285 }
3286 break;
3287 }
3288 break;
3289 }
3290 return ret;
3291}
3292
3294{
3295 WCHAR *name = NULL;
3296 DWORD cb;
3297
3299 {
3301 if (name)
3302 {
3304 {
3306 name = NULL;
3307 }
3308 }
3309 }
3310 return name;
3311}
3312
3314{
3315 int items = SendMessageW(list, LVM_GETITEMCOUNT, 0, 0), i;
3316
3317 for (i = 0; i < items; i++)
3318 {
3319 BOOL change = FALSE;
3320 int state;
3321
3323 /* This reverses the INDEXTOSTATEIMAGEMASK shift. There doesn't appear
3324 * to be a handy macro for it.
3325 */
3326 state >>= 12;
3327 if (enabled)
3328 {
3330 {
3332 change = TRUE;
3333 }
3335 {
3337 change = TRUE;
3338 }
3339 }
3340 else
3341 {
3343 {
3345 change = TRUE;
3346 }
3348 {
3350 change = TRUE;
3351 }
3352 }
3353 if (change)
3354 {
3355 LVITEMW item;
3356
3358 item.stateMask = LVIS_STATEIMAGEMASK;
3360 }
3361 }
3362}
3363
3364typedef enum {
3369
3371{
3373
3374 switch (selection)
3375 {
3376 case PurposeEnableAll:
3377 case PurposeDisableAll:
3378 EnableWindow(lv, FALSE);
3379 redraw_states(lv, FALSE);
3381 break;
3383 EnableWindow(lv, TRUE);
3384 redraw_states(lv, TRUE);
3386 }
3387}
3388
3390{
3394};
3395
3397{
3398 PCCERT_CONTEXT cert = data->cert;
3401 DWORD size;
3402 RECT rc;
3404 PurposeSelection purposeSelection = PurposeEnableAll;
3405
3406 GetWindowRect(lv, &rc);
3407 column.mask = LVCF_WIDTH;
3408 column.cx = rc.right - rc.left;
3411
3412 /* Get enhanced key usage. Have to check for a property and an extension
3413 * separately, because CertGetEnhancedKeyUsage will succeed and return an
3414 * empty usage if neither is set. Unfortunately an empty usage implies
3415 * no usage is allowed, so we have to distinguish between the two cases.
3416 */
3418 NULL, &size))
3419 {
3423 {
3425 usage = NULL;
3426 }
3427 else if (usage->cUsageIdentifier)
3428 purposeSelection = PurposeEnableSelected;
3429 else
3430 purposeSelection = PurposeDisableAll;
3431 }
3433 NULL, &size))
3434 {
3438 {
3440 usage = NULL;
3441 }
3442 else if (usage->cUsageIdentifier)
3443 purposeSelection = PurposeEnableAll;
3444 else
3445 purposeSelection = PurposeDisableAll;
3446 }
3447 else
3448 {
3449 purposeSelection = PurposeEnableAll;
3450 usage = NULL;
3451 }
3452 if (usage)
3453 {
3454 DWORD i;
3455
3456 for (i = 0; i < usage->cUsageIdentifier; i++)
3457 {
3459 usage->rgpszUsageIdentifier[i], CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
3460
3461 if (info)
3463 else
3464 add_purpose(hwnd, usage->rgpszUsageIdentifier[i]);
3465 }
3467 }
3468 else
3470 select_purposes(hwnd, purposeSelection);
3472 BM_CLICK, 0, 0);
3473}
3474
3476{
3477 PCCERT_CONTEXT cert = data->cert;
3478 WCHAR *str;
3479
3480