ReactOS 0.4.16-dev-737-g3368adc
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
560}
561
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:
792#ifndef __REACTOS__
794#endif
796 break;
797 case IDCANCEL:
798#ifndef __REACTOS__
800#endif
802 break;
803 }
804 break;
805 }
806 return 0;
807}
808
810{
815 (LPARAM)empty);
817}
818
820{
823
824 item.mask = LVIF_PARAM;
825 item.iItem = index;
826 item.iSubItem = 0;
828 (LPARAM)&item))
829 cert = (PCCERT_CONTEXT)item.lParam;
830 return cert;
831}
832
834{
836
837 if (cert)
838 {
840
841 memset(&viewInfo, 0, sizeof(viewInfo));
842 viewInfo.dwSize = sizeof(viewInfo);
843 viewInfo.hwndParent = hwnd;
844 viewInfo.pCertContext = cert;
845 /* FIXME: this should be modal */
847 }
848}
849
851{
853 DWORD size;
854
855 /* Get enhanced key usage. Have to check for a property and an extension
856 * separately, because CertGetEnhancedKeyUsage will succeed and return an
857 * empty usage if neither is set. Unfortunately an empty usage implies
858 * no usage is allowed, so we have to distinguish between the two cases.
859 */
861 NULL, &size))
862 {
866 {
868 usage = NULL;
869 }
870 }
872 NULL, &size))
873 {
877 {
879 usage = NULL;
880 }
881 }
882 else
883 usage = NULL;
884 if (usage)
885 {
886 if (usage->cUsageIdentifier)
887 {
888 static const WCHAR commaSpace[] = { ',',' ',0 };
889 DWORD i, len = 1;
890 LPWSTR ptr;
891
892 for (i = 0; i < usage->cUsageIdentifier; i++)
893 {
896 usage->rgpszUsageIdentifier[i],
898
899 if (info)
900 len += lstrlenW(info->pwszName);
901 else
902 len += strlen(usage->rgpszUsageIdentifier[i]);
903 if (i < usage->cUsageIdentifier - 1)
905 }
906 *str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
907 if (*str)
908 {
909 for (i = 0, ptr = *str; i < usage->cUsageIdentifier; i++)
910 {
913 usage->rgpszUsageIdentifier[i],
915
916 if (info)
917 {
918 lstrcpyW(ptr, info->pwszName);
919 ptr += lstrlenW(info->pwszName);
920 }
921 else
922 {
923 LPCSTR src = usage->rgpszUsageIdentifier[i];
924
925 for (; *src; ptr++, src++)
926 *ptr = *src;
927 *ptr = 0;
928 }
929 if (i < usage->cUsageIdentifier - 1)
930 {
933 }
934 }
935 *ptr = 0;
936 }
938 }
939 else
940 {
941 size = MAX_STRING_LEN * sizeof(WCHAR);
943 if (*str)
945 }
946 }
947 else
948 {
949 size = MAX_STRING_LEN * sizeof(WCHAR);
951 if (*str)
953 }
954}
955
957{
960 LPWSTR str = NULL;
961
963 if (str)
964 {
967 }
968}
969
971{
973 TCM_GETCURSEL, 0, 0);
974 struct CertMgrData *data =
976
977 if (tabIndex < data->nStores)
978 {
981 LPCWSTR pTitle;
982 int warningID;
983
984 if (SendMessageW(lv, LVM_GETSELECTEDCOUNT, 0, 0) > 1)
985 warningID = data->stores[tabIndex].removePluralWarning;
986 else
987 warningID = data->stores[tabIndex].removeWarning;
988 if (data->title)
989 pTitle = data->title;
990 else
991 {
993 pTitle = title;
994 }
996 if (MessageBoxW(hwnd, warning, pTitle, MB_YESNO) == IDYES)
997 {
998 int selection = -1;
999
1000 do {
1003 if (selection >= 0)
1004 {
1006 selection);
1007
1009 }
1010 } while (selection >= 0);
1012 }
1013 }
1014}
1015
1017{
1019 int selectionCount = SendMessageW(lv, LVM_GETSELECTEDCOUNT, 0, 0);
1020
1021 if (selectionCount == 1)
1022 {
1025
1026 if (selection >= 0)
1027 {
1029
1030 if (cert)
1031 {
1033
1034 info.dwSize = sizeof(info);
1035 info.pwszExportFileName = NULL;
1036 info.dwSubjectChoice = CRYPTUI_WIZ_EXPORT_CERT_CONTEXT;
1037 info.u.pCertContext = cert;
1038 info.cStores = 0;
1040 }
1041 }
1042 }
1043 else if (selectionCount > 1)
1044 {
1047
1048 if (store)
1049 {
1051 int selection = -1;
1052
1053 info.dwSize = sizeof(info);
1054 info.pwszExportFileName = NULL;
1055 info.dwSubjectChoice =
1057 info.u.hCertStore = store;
1058 info.cStores = 0;
1059 do {
1062 if (selection >= 0)
1063 {
1065 selection);
1066
1069 }
1070 } while (selection >= 0);
1072 CertCloseStore(store, 0);
1073 }
1074 }
1075}
1076
1077static int cert_mgr_sort_by_text(HWND lv, int col, int index1, int index2)
1078{
1079 LVITEMW item;
1080 WCHAR buf1[MAX_STRING_LEN];
1081 WCHAR buf2[MAX_STRING_LEN];
1082
1083 item.cchTextMax = ARRAY_SIZE(buf1);
1084 item.mask = LVIF_TEXT;
1085 item.pszText = buf1;
1086 item.iItem = index1;
1087 item.iSubItem = col;
1089 item.pszText = buf2;
1090 item.iItem = index2;
1092 return lstrcmpW(buf1, buf2);
1093}
1094
1096{
1097 return cert_mgr_sort_by_text((HWND)lp, 0, lp1, lp2);
1098}
1099
1101{
1102 return cert_mgr_sort_by_text((HWND)lp, 1, lp1, lp2);
1103}
1104
1106{
1109 return CompareFileTime(&cert1->pCertInfo->NotAfter,
1110 &cert2->pCertInfo->NotAfter);
1111}
1112
1114 LPARAM lp)
1115{
1116 return cert_mgr_sort_by_text((HWND)lp, 3, lp1, lp2);
1117}
1118
1120 LPARAM lp)
1121{
1122 struct CertMgrData *data;
1123
1124 switch (msg)
1125 {
1126 case WM_INITDIALOG:
1127 {
1128 PCCRYPTUI_CERT_MGR_STRUCT pCryptUICertMgr =
1131
1132 data = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CertMgrData));
1133 if (!data)
1134 return 0;
1135 data->imageList = ImageList_Create(16, 16, ILC_COLOR4 | ILC_MASK, 2, 0);
1136 if (data->imageList)
1137 {
1138 HBITMAP bmp;
1139 COLORREF backColor = RGB(255, 0, 255);
1140
1142 ImageList_AddMasked(data->imageList, bmp, backColor);
1144 ImageList_SetBkColor(data->imageList, CLR_NONE);
1146 LVSIL_SMALL, (LPARAM)data->imageList);
1147 }
1149 data->title = pCryptUICertMgr->pwszTitle;
1150
1153 if (pCryptUICertMgr->pwszTitle)
1155 (LPARAM)pCryptUICertMgr->pwszTitle);
1156 show_cert_stores(hwnd, pCryptUICertMgr->dwFlags, data);
1158 break;
1159 }
1160#ifdef __REACTOS__
1161 case WM_DESTROY:
1166 break;
1167#endif
1168 case WM_NOTIFY:
1169 {
1170 NMHDR *hdr = (NMHDR *)lp;
1171
1172 switch (hdr->code)
1173 {
1174 case TCN_SELCHANGE:
1176 break;
1177 case LVN_ITEMCHANGED:
1178 {
1179 NMITEMACTIVATE *nm = (NMITEMACTIVATE*)lp;
1181 int numSelected = SendMessageW(lv, LVM_GETSELECTEDCOUNT, 0, 0);
1182
1183 EnableWindow(GetDlgItem(hwnd, IDC_MGR_EXPORT), numSelected > 0);
1184 EnableWindow(GetDlgItem(hwnd, IDC_MGR_REMOVE), numSelected > 0);
1185 EnableWindow(GetDlgItem(hwnd, IDC_MGR_VIEW), numSelected == 1);
1186 if (numSelected == 1)
1188 else
1190 (LPARAM)empty);
1191 break;
1192 }
1193 case NM_DBLCLK:
1194 show_selected_cert(hwnd, ((NMITEMACTIVATE *)lp)->iItem);
1195 break;
1196 case LVN_KEYDOWN:
1197 {
1198 NMLVKEYDOWN *lvk = (NMLVKEYDOWN *)lp;
1199
1200 if (lvk->wVKey == VK_DELETE)
1202 break;
1203 }
1204 case LVN_COLUMNCLICK:
1205 {
1206 NMLISTVIEW *nmlv = (NMLISTVIEW *)lp;
1208
1209 /* FIXME: doesn't support swapping sort order between ascending
1210 * and descending.
1211 */
1212 switch (nmlv->iSubItem)
1213 {
1214 case 0:
1217 break;
1218 case 1:
1221 break;
1222 case 2:
1225 break;
1226 case 3:
1229 break;
1230 }
1231 break;
1232 }
1233 }
1234 break;
1235 }
1236 case WM_COMMAND:
1237 switch (wp)
1238 {
1241 break;
1242 case IDC_MGR_IMPORT:
1243 if (CryptUIWizImport(0, hwnd, NULL, NULL,
1246 break;
1247 case IDC_MGR_ADVANCED:
1250 {
1252 int index, len;
1253 LPWSTR curString = NULL;
1254
1256 if (index >= 0)
1257 {
1259 curString = HeapAlloc(GetProcessHeap(), 0,
1260 (len + 1) * sizeof(WCHAR));
1261 SendMessageW(cb, CB_GETLBTEXT, index, (LPARAM)curString);
1262 }
1265 if (curString)
1266 {
1268 (LPARAM)curString);
1269 if (index >= 0)
1271 HeapFree(GetProcessHeap(), 0, curString);
1272 }
1274 }
1275 break;
1276 case IDC_MGR_VIEW:
1277 {
1281
1282 if (selection >= 0)
1284 break;
1285 }
1286 case IDC_MGR_EXPORT:
1288 break;
1289 case IDC_MGR_REMOVE:
1291 break;
1292 case IDCANCEL:
1293#ifndef __REACTOS__
1297 ImageList_Destroy(data->imageList);
1299#endif
1301 break;
1302 }
1303 break;
1304 }
1305 return 0;
1306}
1307
1308/***********************************************************************
1309 * CryptUIDlgCertMgr (CRYPTUI.@)
1310 */
1312{
1313 TRACE("(%p)\n", pCryptUICertMgr);
1314
1315 if (pCryptUICertMgr->dwSize != sizeof(CRYPTUI_CERT_MGR_STRUCT))
1316 {
1317 WARN("unexpected size %d\n", pCryptUICertMgr->dwSize);
1319 return FALSE;
1320 }
1322 pCryptUICertMgr->hwndParent, cert_mgr_dlg_proc, (LPARAM)pCryptUICertMgr);
1323 return TRUE;
1324}
1325
1326/* FIXME: real names are unknown, functions are undocumented */
1328{
1332
1334{
1340
1342 void *pvArg);
1343
1344/* Values for dwFlags */
1345#define CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE 0x00000001
1346
1348{
1356 void *pvArg;
1358
1360{
1368 void *pvArg;
1370
1372{
1373 enum {
1377 union {
1381};
1382
1383static BOOL WINAPI enum_store_callback(const void *pvSystemStore,
1385 void *pvArg)
1386{
1388 TVINSERTSTRUCTW tvis;
1389 LPCWSTR localizedName;
1390 BOOL ret = TRUE;
1391
1392 tvis.hParent = NULL;
1393 tvis.hInsertAfter = TVI_LAST;
1394 tvis.u.item.mask = TVIF_TEXT;
1395 if ((localizedName = CryptFindLocalizedName(pvSystemStore)))
1396 {
1397 struct StoreInfo *storeInfo = HeapAlloc(GetProcessHeap(), 0,
1398 sizeof(struct StoreInfo));
1399
1400 if (storeInfo)
1401 {
1402 storeInfo->type = SystemStore;
1403 storeInfo->u.name = HeapAlloc(GetProcessHeap(), 0,
1404 (lstrlenW(pvSystemStore) + 1) * sizeof(WCHAR));
1405 if (storeInfo->u.name)
1406 {
1407 tvis.u.item.mask |= TVIF_PARAM;
1408 tvis.u.item.lParam = (LPARAM)storeInfo;
1409 lstrcpyW(storeInfo->u.name, pvSystemStore);
1410 }
1411 else
1412 {
1413 HeapFree(GetProcessHeap(), 0, storeInfo);
1414 ret = FALSE;
1415 }
1416 }
1417 else
1418 ret = FALSE;
1419 tvis.u.item.pszText = (LPWSTR)localizedName;
1420 }
1421 else
1422 tvis.u.item.pszText = (LPWSTR)pvSystemStore;
1423 /* FIXME: need a folder icon for the store too */
1424 if (ret)
1426 return ret;
1427}
1428
1430{
1431 DWORD i;
1433
1434 for (i = 0; i < pEnumData->cEnumArgs; i++)
1438 for (i = 0; i < pEnumData->cStores; i++)
1439 {
1440 DWORD size;
1441
1442 if (CertGetStoreProperty(pEnumData->rghStore[i],
1444 {
1446
1447 if (name)
1448 {
1449 if (CertGetStoreProperty(pEnumData->rghStore[i],
1451 {
1452 struct StoreInfo *storeInfo = HeapAlloc(GetProcessHeap(),
1453 0, sizeof(struct StoreInfo));
1454
1455 if (storeInfo)
1456 {
1457 TVINSERTSTRUCTW tvis;
1458
1459 storeInfo->type = StoreHandle;
1460 storeInfo->u.store = pEnumData->rghStore[i];
1461 tvis.hParent = NULL;
1462 tvis.hInsertAfter = TVI_LAST;
1463 tvis.u.item.mask = TVIF_TEXT | TVIF_PARAM;
1464 tvis.u.item.pszText = name;
1465 tvis.u.item.lParam = (LPARAM)storeInfo;
1467 }
1468 }
1470 }
1471 }
1472 }
1473}
1474
1476{
1478 0);
1479
1480 while (next)
1481 {
1482 TVITEMW item;
1483
1484 memset(&item, 0, sizeof(item));
1485 item.mask = TVIF_HANDLE | TVIF_PARAM;
1486 item.hItem = next;
1488 if (item.lParam)
1489 {
1490 struct StoreInfo *storeInfo = (struct StoreInfo *)item.lParam;
1491
1492 if (storeInfo->type == SystemStore)
1493 HeapFree(GetProcessHeap(), 0, storeInfo->u.name);
1494 HeapFree(GetProcessHeap(), 0, storeInfo);
1495 }
1497 (LPARAM)next);
1498 }
1499}
1500
1502{
1504 TVITEMW item;
1506
1507 memset(&item, 0, sizeof(item));
1509 item.hItem = hItem;
1510 item.cchTextMax = ARRAY_SIZE(buf);
1511 item.pszText = buf;
1513 if (item.lParam)
1514 {
1515 struct StoreInfo *storeInfo = (struct StoreInfo *)item.lParam;
1516
1517 if (storeInfo->type == StoreHandle)
1518 store = storeInfo->u.store;
1519 else
1520 store = CertOpenSystemStoreW(0, storeInfo->u.name);
1521 }
1522 else
1523 {
1524 /* It's implicitly a system store */
1526 }
1527 return store;
1528}
1529
1531{
1534};
1535
1537 LPARAM lp)
1538{
1539 struct SelectStoreInfo *selectInfo;
1540 LRESULT ret = 0;
1541
1542 switch (msg)
1543 {
1544 case WM_INITDIALOG:
1545 {
1546 selectInfo = (struct SelectStoreInfo *)lp;
1548 if (selectInfo->info->pwszTitle)
1550 (LPARAM)selectInfo->info->pwszTitle);
1551 if (selectInfo->info->pwszText)
1553 (LPARAM)selectInfo->info->pwszText);
1554 if (!(selectInfo->info->dwFlags & CRYPTUI_ENABLE_SHOW_PHYSICAL_STORE))
1556 enumerate_stores(hwnd, selectInfo->info->pEnumData);
1557 break;
1558 }
1559 case WM_COMMAND:
1560 switch (wp)
1561 {
1562 case IDOK:
1563 {
1567
1568 selectInfo = (struct SelectStoreInfo *)GetWindowLongPtrW(hwnd,
1569 DWLP_USER);
1570 if (!selection)
1571 {
1573
1574 if (selectInfo->info->pwszTitle)
1575 pTitle = selectInfo->info->pwszTitle;
1576 else
1577 {
1579 pTitle = title;
1580 }
1583 }
1584 else
1585 {
1587
1588 if (!selectInfo->info->pfnSelectedStoreCallback ||
1590 selectInfo->info->pvArg))
1591 {
1592 selectInfo->store = store;
1595 }
1596 else
1598 }
1599 ret = TRUE;
1600 break;
1601 }
1602 case IDCANCEL:
1605 ret = TRUE;
1606 break;
1607 }
1608 break;
1609 }
1610 return ret;
1611}
1612
1613/***********************************************************************
1614 * CryptUIDlgSelectStoreW (CRYPTUI.@)
1615 */
1617{
1618 struct SelectStoreInfo selectInfo = { info, NULL };
1619
1620 TRACE("(%p)\n", info);
1621
1622 if (info->dwSize != sizeof(CRYPTUI_SELECTSTORE_INFO_W))
1623 {
1624 WARN("unexpected size %d\n", info->dwSize);
1626 return NULL;
1627 }
1629 select_store_dlg_proc, (LPARAM)&selectInfo);
1630 return selectInfo.store;
1631}
1632
1633/***********************************************************************
1634 * CryptUIDlgSelectStoreA (CRYPTUI.@)
1635 */
1637{
1640 int len;
1641
1642 TRACE("(%p)\n", info);
1643
1644 if (info->dwSize != sizeof(CRYPTUI_SELECTSTORE_INFO_A))
1645 {
1646 WARN("unexpected size %d\n", info->dwSize);
1648 return NULL;
1649 }
1650 memcpy(&infoW, info, sizeof(*info));
1651 if (info->pszTitle)
1652 {
1653 len = MultiByteToWideChar(CP_ACP, 0, info->pszTitle, -1, NULL, 0);
1654 infoW.pwszTitle = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1655 MultiByteToWideChar(CP_ACP, 0, info->pszTitle, -1, infoW.pwszTitle,
1656 len);
1657 }
1658 if (info->pszText)
1659 {
1660 len = MultiByteToWideChar(CP_ACP, 0, info->pszText, -1, NULL, 0);
1661 infoW.pwszText = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1662 MultiByteToWideChar(CP_ACP, 0, info->pszText, -1, infoW.pwszText, len);
1663 }
1665 HeapFree(GetProcessHeap(), 0, infoW.pwszText);
1666 HeapFree(GetProcessHeap(), 0, infoW.pwszTitle);
1667 return ret;
1668}
1669
1670/***********************************************************************
1671 * CryptUIDlgViewCertificateA (CRYPTUI.@)
1672 */
1674 PCCRYPTUI_VIEWCERTIFICATE_STRUCTA pCertViewInfo, BOOL *pfPropertiesChanged)
1675{
1677 LPWSTR title = NULL;
1678 BOOL ret;
1679
1680 TRACE("(%p, %p)\n", pCertViewInfo, pfPropertiesChanged);
1681
1682 memcpy(&viewInfo, pCertViewInfo, sizeof(viewInfo));
1683 if (pCertViewInfo->szTitle)
1684 {
1685 int len = MultiByteToWideChar(CP_ACP, 0, pCertViewInfo->szTitle, -1,
1686 NULL, 0);
1687
1688 title = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1689 if (title)
1690 {
1691 MultiByteToWideChar(CP_ACP, 0, pCertViewInfo->szTitle, -1, title,
1692 len);
1693 viewInfo.szTitle = title;
1694 }
1695 else
1696 {
1697 ret = FALSE;
1698 goto error;
1699 }
1700 }
1701 if (pCertViewInfo->cPropSheetPages)
1702 {
1703 FIXME("ignoring additional prop sheet pages\n");
1704 viewInfo.cPropSheetPages = 0;
1705 }
1706 ret = CryptUIDlgViewCertificateW(&viewInfo, pfPropertiesChanged);
1708error:
1709 return ret;
1710}
1711
1713{
1717};
1718
1720 LONG cb, LONG *pcb)
1721{
1722 struct ReadStringStruct *string = (struct ReadStringStruct *)dwCookie;
1723 LONG cch = min(cb / sizeof(WCHAR), string->len - string->pos);
1724
1725 TRACE("(%p, %p, %d, %p)\n", string, buf, cb, pcb);
1726
1727 memmove(buf, string->buf + string->pos, cch * sizeof(WCHAR));
1728 string->pos += cch;
1729 *pcb = cch * sizeof(WCHAR);
1730 return 0;
1731}
1732
1734{
1735 struct ReadStringStruct string;
1736 EDITSTREAM editstream;
1737
1738 TRACE("(%p, %s)\n", hwnd, debugstr_wn(text, len));
1739
1740 string.buf = text;
1741 string.pos = 0;
1742 string.len = len;
1743 editstream.dwCookie = (DWORD_PTR)&string;
1744 editstream.dwError = 0;
1745 editstream.pfnCallback = read_text_callback;
1747 (LPARAM)&editstream);
1748}
1749
1751{
1752 LPWSTR str;
1753 LONG len;
1754
1755 len = LoadStringW(hInstance, id, (LPWSTR)&str, 0);
1757}
1758
1760 LONG len, const PARAFORMAT2 *fmt)
1761{
1764}
1765
1767 const PARAFORMAT2 *fmt)
1768{
1769 LPWSTR str;
1770 LONG len;
1771
1772 len = LoadStringW(hInstance, id, (LPWSTR)&str, 0);
1774}
1775
1777 DWORD dwFlags)
1778{
1779 LPWSTR buf = NULL;
1780 DWORD len;
1781
1783 if (len)
1784 {
1785 buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1786 if (buf)
1788 }
1789 return buf;
1790}
1791
1793 DWORD dwType, DWORD dwFlags)
1794{
1796
1797 if (name)
1798 {
1799 /* Don't include NULL-terminator in output */
1801
1804 }
1805}
1806
1807static void add_icon_to_control(HWND hwnd, int id)
1808{
1809 HRESULT hr;
1810 IRichEditOle *richEditOle = NULL;
1811 IOleObject *object = NULL;
1812 CLSID clsid;
1813 LPOLECACHE oleCache = NULL;
1814 FORMATETC formatEtc;
1815 DWORD conn;
1816 IDataObject *dataObject = NULL;
1818 STGMEDIUM stgm;
1819 IOleClientSite *clientSite = NULL;
1820 REOBJECT reObject;
1821
1822 TRACE("(%p, %d)\n", hwnd, id);
1823
1824 SendMessageW(hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&richEditOle);
1825 if (!richEditOle)
1826 goto end;
1828 (void**)&object);
1829 if (FAILED(hr))
1830 goto end;
1831 hr = IOleObject_GetUserClassID(object, &clsid);
1832 if (FAILED(hr))
1833 goto end;
1834 hr = IOleObject_QueryInterface(object, &IID_IOleCache, (void**)&oleCache);
1835 if (FAILED(hr))
1836 goto end;
1837 formatEtc.cfFormat = CF_BITMAP;
1838 formatEtc.ptd = NULL;
1839 formatEtc.dwAspect = DVASPECT_CONTENT;
1840 formatEtc.lindex = -1;
1841 formatEtc.tymed = TYMED_GDI;
1842 hr = IOleCache_Cache(oleCache, &formatEtc, 0, &conn);
1843 if (FAILED(hr))
1844 goto end;
1845 hr = IOleObject_QueryInterface(object, &IID_IDataObject,
1846 (void**)&dataObject);
1847 if (FAILED(hr))
1848 goto end;
1849 hr = IRichEditOle_GetClientSite(richEditOle, &clientSite);
1850 if (FAILED(hr))
1851 goto end;
1854 if (!bitmap)
1855 goto end;
1856 stgm.tymed = TYMED_GDI;
1857 stgm.u.hBitmap = bitmap;
1858 stgm.pUnkForRelease = NULL;
1859 hr = IDataObject_SetData(dataObject, &formatEtc, &stgm, TRUE);
1860 if (FAILED(hr))
1861 goto end;
1862
1863 reObject.cbStruct = sizeof(reObject);
1864 reObject.cp = REO_CP_SELECTION;
1865 reObject.clsid = clsid;
1866 reObject.poleobj = object;
1867 reObject.pstg = NULL;
1868 reObject.polesite = clientSite;
1869 reObject.sizel.cx = reObject.sizel.cy = 0;
1870 reObject.dvaspect = DVASPECT_CONTENT;
1871 reObject.dwFlags = 0;
1872 reObject.dwUser = 0;
1873
1874 IRichEditOle_InsertObject(richEditOle, &reObject);
1875
1876end:
1877 if (clientSite)
1878 IOleClientSite_Release(clientSite);
1879 if (dataObject)
1880 IDataObject_Release(dataObject);
1881 if (oleCache)
1882 IOleCache_Release(oleCache);
1883 if (object)
1884 IOleObject_Release(object);
1885 if (richEditOle)
1886 IRichEditOle_Release(richEditOle);
1887}
1888
1889#define MY_INDENT 200
1890
1891static void add_oid_text_to_control(HWND hwnd, char *oid)
1892{
1893 WCHAR nl = '\n';
1895 PARAFORMAT2 parFmt;
1896
1897 parFmt.cbSize = sizeof(parFmt);
1898 parFmt.dwMask = PFM_STARTINDENT;
1899 parFmt.dxStartIndent = MY_INDENT * 3;
1900 if (oidInfo)
1901 {
1903 lstrlenW(oidInfo->pwszName), &parFmt);
1905 }
1906}
1907
1909{
1911 int id;
1912};
1913
1914/* The following list MUST be lexicographically sorted by OID */
1915static struct OIDToString oidMap[] = {
1916 /* 1.3.6.1.4.1.311.10.3.1 */
1918 /* 1.3.6.1.4.1.311.10.3.4 */
1920 /* 1.3.6.1.4.1.311.10.3.4.1 */
1922 /* 1.3.6.1.4.1.311.10.3.5 */
1924 /* 1.3.6.1.4.1.311.10.3.6 */
1926 /* 1.3.6.1.4.1.311.10.3.7 */
1928 /* 1.3.6.1.4.1.311.10.3.8 */
1930 /* 1.3.6.1.4.1.311.10.3.9 */
1932 /* 1.3.6.1.4.1.311.10.3.10 */
1934 /* 1.3.6.1.4.1.311.10.3.11 */
1936 /* 1.3.6.1.4.1.311.10.3.12 */
1938 /* 1.3.6.1.4.1.311.10.3.13 */
1940 /* 1.3.6.1.4.1.311.10.5.1 */
1942 /* 1.3.6.1.4.1.311.10.6.1 */
1944 /* 1.3.6.1.4.1.311.10.6.2 */
1946 /* 1.3.6.1.4.1.311.20.2.1 */
1948 /* 1.3.6.1.4.1.311.20.2.2 */
1950 /* 1.3.6.1.4.1.311.21.5 */
1952 /* 1.3.6.1.4.1.311.21.6 */
1954 /* 1.3.6.1.4.1.311.21.19 */
1956 /* 1.3.6.1.5.5.7.3.1 */
1958 /* 1.3.6.1.5.5.7.3.2 */
1960 /* 1.3.6.1.5.5.7.3.3 */
1962 /* 1.3.6.1.5.5.7.3.4 */
1964 /* 1.3.6.1.5.5.7.3.5 */
1966 /* 1.3.6.1.5.5.7.3.6 */
1968 /* 1.3.6.1.5.5.7.3.7 */
1970 /* 1.3.6.1.5.5.7.3.8 */
1972};
1973
1975{
1976 int indexHigh = ARRAY_SIZE(oidMap) - 1, indexLow = 0;
1977
1978 while (indexLow <= indexHigh)
1979 {
1980 int cmp, i = (indexLow + indexHigh) / 2;
1981 if (!(cmp = strcmp(oid, oidMap[i].oid)))
1982 return &oidMap[i];
1983 if (cmp > 0)
1984 indexLow = i + 1;
1985 else
1986 indexHigh = i - 1;
1987 }
1988 return NULL;
1989}
1990
1992{
1993 struct OIDToString *entry;
1994 WCHAR nl = '\n';
1995 PARAFORMAT2 parFmt;
1996
1997 parFmt.cbSize = sizeof(parFmt);
1998 parFmt.dwMask = PFM_STARTINDENT;
1999 parFmt.dxStartIndent = MY_INDENT * 3;
2000 if ((entry = findSupportedOID(oid)))
2001 {
2002 WCHAR *str, *linebreak, *ptr;
2003 BOOL multiline = FALSE;
2004 int len;
2005
2006 len = LoadStringW(hInstance, entry->id, (LPWSTR)&str, 0);
2007 ptr = str;
2008 do {
2009 if ((linebreak = wmemchr(ptr, '\n', len)))
2010 {
2012
2013 multiline = TRUE;
2014 /* The source string contains a newline, which the richedit
2015 * control won't find since it's interpreted as a paragraph
2016 * break. Therefore copy up to the newline. lstrcpynW always
2017 * NULL-terminates, so pass one more than the length of the
2018 * source line so the copy includes the entire line and the
2019 * NULL-terminator.
2020 */
2021 lstrcpynW(copy, ptr, linebreak - ptr + 1);
2023 linebreak - ptr, &parFmt);
2024 ptr = linebreak + 1;
2026 }
2027 else if (multiline && *ptr)
2028 {
2029 /* Add the last line */
2031 len - (ptr - str), &parFmt);
2033 }
2034 } while (linebreak);
2035 if (!multiline)
2036 {
2039 }
2040 }
2041 else
2042 {
2043 WCHAR *oidW = HeapAlloc(GetProcessHeap(), 0,
2044 (strlen(oid) + 1) * sizeof(WCHAR));
2045
2046 if (oidW)
2047 {
2048 LPCSTR src;
2049 WCHAR *dst;
2050
2051 for (src = oid, dst = oidW; *src; src++, dst++)
2052 *dst = *src;
2053 *dst = 0;
2055 &parFmt);
2057 HeapFree(GetProcessHeap(), 0, oidW);
2058 }
2059 }
2060}
2061
2063 BOOL *anyUsageAdded)
2064{
2065 static char any_app_policy[] = szOID_ANY_APPLICATION_POLICY;
2066 WCHAR nl = '\n';
2067 CHARFORMATW charFmt;
2068 PCERT_EXTENSION policyExt;
2069 if (!*anyUsageAdded)
2070 {
2071 PARAFORMAT2 parFmt;
2072
2073 parFmt.cbSize = sizeof(parFmt);
2074 parFmt.dwMask = PFM_STARTINDENT;
2075 parFmt.dxStartIndent = MY_INDENT;
2077 IDS_CERT_INFO_PURPOSES, &parFmt);
2079 *anyUsageAdded = TRUE;
2080 }
2081 memset(&charFmt, 0, sizeof(charFmt));
2082 charFmt.cbSize = sizeof(charFmt);
2083 charFmt.dwMask = CFM_BOLD;
2084 charFmt.dwEffects = 0;
2087 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension)))
2088 {
2089 CERT_POLICIES_INFO *policies;
2090 DWORD size;
2091
2093 policyExt->Value.pbData, policyExt->Value.cbData,
2094 CRYPT_DECODE_ALLOC_FLAG, NULL, &policies, &size))
2095 {
2096 DWORD i;
2097
2098 for (i = 0; i < policies->cPolicyInfo; i++)
2099 {
2100 DWORD j;
2101
2102 for (j = 0; j < policies->rgPolicyInfo[i].cPolicyQualifier; j++)
2104 policies->rgPolicyInfo[i].rgPolicyQualifier[j].
2105 pszPolicyQualifierId);
2106 }
2107 LocalFree(policies);
2108 }
2109 }
2110 else
2111 add_oid_text_to_control(text, any_app_policy);
2112}
2113
2115 BOOL *anyUsageAdded)
2116{
2117 WCHAR nl = '\n';
2118 DWORD size;
2119 BOOL badUsages = FALSE;
2120
2122 {
2123 CHARFORMATW charFmt;
2124 static char any_cert_policy[] = szOID_ANY_CERT_POLICY;
2126
2127 if (usage)
2128 {
2130 {
2131 DWORD i;
2132
2133 if (!*anyUsageAdded)
2134 {
2135 PARAFORMAT2 parFmt;
2136
2137 parFmt.cbSize = sizeof(parFmt);
2138 parFmt.dwMask = PFM_STARTINDENT;
2139 parFmt.dxStartIndent = MY_INDENT;
2141 IDS_CERT_INFO_PURPOSES, &parFmt);
2143 *anyUsageAdded = TRUE;
2144 }
2145 memset(&charFmt, 0, sizeof(charFmt));
2146 charFmt.cbSize = sizeof(charFmt);
2147 charFmt.dwMask = CFM_BOLD;
2148 charFmt.dwEffects = 0;
2150 (LPARAM)&charFmt);
2151 if (!usage->cUsageIdentifier)
2152 add_oid_text_to_control(text, any_cert_policy);
2153 else
2154 for (i = 0; i < usage->cUsageIdentifier; i++)
2156 usage->rgpszUsageIdentifier[i]);
2157 }
2158 else
2159 badUsages = TRUE;
2161 }
2162 else
2163 badUsages = TRUE;
2164 }
2165 else
2166 badUsages = TRUE;
2167 return badUsages;
2168}
2169
2172{
2173 BOOL includeCertUsages = FALSE, includeAppUsages = FALSE;
2174 BOOL badUsages = FALSE, anyUsageAdded = FALSE;
2175
2176 if (pCertViewInfo->cPurposes)
2177 {
2178 DWORD i;
2179
2180 for (i = 0; i < pCertViewInfo->cPurposes; i++)
2181 {
2182 if (!strcmp(pCertViewInfo->rgszPurposes[i], szOID_ANY_CERT_POLICY))
2183 includeCertUsages = TRUE;
2184 else if (!strcmp(pCertViewInfo->rgszPurposes[i],
2186 includeAppUsages = TRUE;
2187 else
2188 badUsages = TRUE;
2189 }
2190 }
2191 else
2192 includeAppUsages = includeCertUsages = TRUE;
2193 if (includeAppUsages)
2194 display_app_usages(text, pCertViewInfo->pCertContext, &anyUsageAdded);
2195 if (includeCertUsages)
2196 badUsages = display_cert_usages(text, pCertViewInfo->pCertContext,
2197 &anyUsageAdded);
2198 if (badUsages)
2199 {
2200 PARAFORMAT2 parFmt;
2201
2202 parFmt.cbSize = sizeof(parFmt);
2203 parFmt.dwMask = PFM_STARTINDENT;
2204 parFmt.dxStartIndent = MY_INDENT;
2207 }
2208}
2209
2211 LPCSTR policyOid)
2212{
2214 DWORD i;
2215
2216 for (i = 0; !ret && i < policies->cPolicyInfo; i++)
2217 {
2218 DWORD j;
2219
2220 for (j = 0; !ret && j < policies->rgPolicyInfo[i].cPolicyQualifier; j++)
2221 if (!strcmp(policies->rgPolicyInfo[i].rgPolicyQualifier[j].
2222 pszPolicyQualifierId, policyOid))
2223 ret = &policies->rgPolicyInfo[i].rgPolicyQualifier[j].
2224 Qualifier;
2225 }
2226 return ret;
2227}
2228
2230{
2231 LPWSTR qualifierStr = NULL;
2232 CERT_NAME_VALUE *qualifierValue;
2233 DWORD size;
2234
2237 &qualifierValue, &size))
2238 {
2239 size = CertRDNValueToStrW(qualifierValue->dwValueType,
2240 &qualifierValue->Value, NULL, 0);
2241 qualifierStr = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
2242 if (qualifierStr)
2243 CertRDNValueToStrW(qualifierValue->dwValueType,
2244 &qualifierValue->Value, qualifierStr, size);
2245 LocalFree(qualifierValue);
2246 }
2247 return qualifierStr;
2248}
2249
2251{
2252 LPWSTR str = NULL;
2253 CERT_POLICY_QUALIFIER_USER_NOTICE *qualifierValue;
2254 DWORD size;
2255
2259 &qualifierValue, &size))
2260 {
2262 (lstrlenW(qualifierValue->pszDisplayText) + 1) * sizeof(WCHAR));
2263 if (str)
2264 lstrcpyW(str, qualifierValue->pszDisplayText);
2265 LocalFree(qualifierValue);
2266 }
2267 return str;
2268}
2269
2271{
2274};
2275
2278{
2279 PCERT_EXTENSION policyExt;
2280
2281 if (!(pCertViewInfo->dwFlags & CRYPTUI_DISABLE_ISSUERSTATEMENT) &&
2283 pCertViewInfo->pCertContext->pCertInfo->cExtension,
2284 pCertViewInfo->pCertContext->pCertInfo->rgExtension)))
2285 {
2286 CERT_POLICIES_INFO *policies;
2287 DWORD size;
2288
2290 policyExt->Value.pbData, policyExt->Value.cbData,
2291 CRYPT_DECODE_ALLOC_FLAG, NULL, &policies, &size))
2292 {
2294 LPWSTR cps = NULL, userNotice = NULL;
2295
2296 if ((qualifier = find_policy_qualifier(policies,
2299 if ((qualifier = find_policy_qualifier(policies,
2302 if (cps || userNotice)
2303 {
2304 struct IssuerStatement *issuerStatement =
2305 HeapAlloc(GetProcessHeap(), 0, sizeof(struct IssuerStatement));
2306
2307 if (issuerStatement)
2308 {
2309 issuerStatement->cps = cps;
2310 issuerStatement->userNotice = userNotice;
2313 (ULONG_PTR)issuerStatement);
2314 }
2315 }
2316 LocalFree(policies);
2317 }
2318 }
2319}
2320
2323{
2324 CHARFORMATW charFmt;
2325 PARAFORMAT2 parFmt;
2329 (CRYPT_PROVIDER_DATA *)pCertViewInfo->u.pCryptProviderData,
2330 pCertViewInfo->idxSigner, pCertViewInfo->fCounterSigner,
2331 pCertViewInfo->idxCounterSigner);
2333 &provSigner->pasCertChain[provSigner->csCertChain - 1];
2334
2335 if (!provSigner->pChainContext ||
2339 else if (!root->fTrustedRoot)
2341 else
2343
2344 memset(&charFmt, 0, sizeof(charFmt));
2345 charFmt.cbSize = sizeof(charFmt);
2346 charFmt.dwMask = CFM_BOLD;
2347 charFmt.dwEffects = CFE_BOLD;
2349 /* FIXME: vertically center text */
2350 parFmt.cbSize = sizeof(parFmt);
2351 parFmt.dwMask = PFM_STARTINDENT;
2352 parFmt.dxStartIndent = MY_INDENT;
2355
2358 if (provSigner->dwError == TRUST_E_CERT_SIGNATURE)
2360 IDS_CERT_INFO_BAD_SIG, &parFmt);
2361 else if (!provSigner->pChainContext ||
2366 else if (!root->fTrustedRoot)
2367 {
2368 if (provSigner->csCertChain == 1 && root->fSelfSigned)
2371 else
2374 }
2375 else
2376 {
2377 set_policy_text(text, pCertViewInfo);
2378 set_issuer_statement(hwnd, pCertViewInfo);
2379 }
2380}
2381
2383 DWORD nameFlags, int heading)
2384{
2385 WCHAR nl = '\n';
2387 CHARFORMATW charFmt;
2388 PARAFORMAT2 parFmt;
2389
2390 memset(&charFmt, 0, sizeof(charFmt));
2391 charFmt.cbSize = sizeof(charFmt);
2392 charFmt.dwMask = CFM_BOLD;
2393 charFmt.dwEffects = CFE_BOLD;
2395 parFmt.cbSize = sizeof(parFmt);
2396 parFmt.dwMask = PFM_STARTINDENT;
2397 parFmt.dxStartIndent = MY_INDENT * 3;
2399 charFmt.dwEffects = 0;
2402 nameFlags);
2406
2407}
2408
2409static void add_date_string_to_control(HWND hwnd, const FILETIME *fileTime)
2410{
2411 WCHAR dateFmt[80]; /* sufficient for all versions of LOCALE_SSHORTDATE */
2412 WCHAR date[80];
2413 SYSTEMTIME sysTime;
2414
2416 FileTimeToSystemTime(fileTime, &sysTime);
2417 GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, date, ARRAY_SIZE(date));
2419}
2420
2422{
2423 WCHAR nl = '\n';
2425 CHARFORMATW charFmt;
2426 PARAFORMAT2 parFmt;
2427
2428 memset(&charFmt, 0, sizeof(charFmt));
2429 charFmt.cbSize = sizeof(charFmt);
2430 charFmt.dwMask = CFM_BOLD;
2431 charFmt.dwEffects = CFE_BOLD;
2433 parFmt.cbSize = sizeof(parFmt);
2434 parFmt.dwMask = PFM_STARTINDENT;
2435 parFmt.dxStartIndent = MY_INDENT * 3;
2437 &parFmt);
2438 charFmt.dwEffects = 0;
2440 add_date_string_to_control(text, &cert->pCertInfo->NotBefore);
2441 charFmt.dwEffects = CFE_BOLD;
2444 charFmt.dwEffects = 0;
2446 add_date_string_to_control(text, &cert->pCertInfo->NotAfter);
2448}
2449
2452{
2453 set_cert_info(hwnd, pCertViewInfo);
2454 set_cert_name_string(hwnd, pCertViewInfo->pCertContext, 0,
2456 set_cert_name_string(hwnd, pCertViewInfo->pCertContext,
2459}
2460
2462 LPARAM lp)
2463{
2464 LRESULT ret = 0;
2465 HWND text;
2466 struct IssuerStatement *issuerStatement;
2467
2468 switch (msg)
2469 {
2470 case WM_INITDIALOG:
2472 issuerStatement = (struct IssuerStatement *)lp;
2474 lstrlenW(issuerStatement->userNotice));
2475 if (issuerStatement->cps)
2476 SetWindowLongPtrW(hwnd, DWLP_USER, (LPARAM)issuerStatement->cps);
2477 else
2479 break;
2480 case WM_COMMAND:
2481 switch (wp)
2482 {
2483 case IDOK:
2485 ret = TRUE;
2486 break;
2487 case IDC_CPS:
2488 {
2489 IBindCtx *bctx = NULL;
2490 LPWSTR cps;
2491
2492 CreateBindCtx(0, &bctx);
2495 HLNF_OPENINNEWWINDOW, 0);
2496 IBindCtx_Release(bctx);
2497 break;
2498 }
2499 }
2500 }
2501 return ret;
2502}
2503
2504static void show_user_notice(HWND hwnd, struct IssuerStatement *issuerStatement)
2505{
2507 user_notice_dlg_proc, (LPARAM)issuerStatement);
2508}
2509
2511 LPARAM lp)
2512{
2515
2516 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd, msg, wp, lp);
2517
2518 switch (msg)
2519 {
2520 case WM_INITDIALOG:
2521 page = (PROPSHEETPAGEW *)lp;
2522 pCertViewInfo = (PCCRYPTUI_VIEWCERTIFICATE_STRUCTW)page->lParam;
2523 if (pCertViewInfo->dwFlags & CRYPTUI_DISABLE_ADDTOSTORE)
2526 set_general_info(hwnd, pCertViewInfo);
2527 break;
2528 case WM_COMMAND:
2529 switch (wp)
2530 {
2531 case IDC_ADDTOSTORE:
2533 break;
2535 {
2536 struct IssuerStatement *issuerStatement =
2538
2539 if (issuerStatement)
2540 {
2541 if (issuerStatement->userNotice)
2542 show_user_notice(hwnd, issuerStatement);
2543 else if (issuerStatement->cps)
2544 {
2545 IBindCtx *bctx = NULL;
2546
2547 CreateBindCtx(0, &bctx);
2548 HlinkSimpleNavigateToString(issuerStatement->cps, NULL,
2549 NULL, NULL, bctx, NULL, HLNF_OPENINNEWWINDOW, 0);
2550 IBindCtx_Release(bctx);
2551 }
2552 }
2553 break;
2554 }
2555 }
2556 break;
2557 }
2558 return 0;
2559}
2560
2563{
2564 struct IssuerStatement *issuerStatement;
2565
2566 switch (msg)
2567 {
2568 case PSPCB_RELEASE:
2569 issuerStatement =
2571 if (issuerStatement)
2572 {
2573 HeapFree(GetProcessHeap(), 0, issuerStatement->cps);
2574 HeapFree(GetProcessHeap(), 0, issuerStatement->userNotice);
2575 HeapFree(GetProcessHeap(), 0, issuerStatement);
2576 }
2577 break;
2578 }
2579 return 1;
2580}
2581
2584{
2585 memset(page, 0, sizeof(PROPSHEETPAGEW));
2586 page->dwSize = sizeof(PROPSHEETPAGEW);
2587 page->dwFlags = PSP_USECALLBACK;
2588 page->pfnCallback = general_callback_proc;
2589 page->hInstance = hInstance;
2590 page->u.pszTemplate = MAKEINTRESOURCEW(IDD_GENERAL);
2591 page->pfnDlgProc = general_dlg_proc;
2592 page->lParam = (LPARAM)pCertViewInfo;
2593}
2594
2595typedef WCHAR * (*field_format_func)(PCCERT_CONTEXT cert);
2596
2598{
2599 static const WCHAR fmt[] = { 'V','%','d',0 };
2600 WCHAR *buf = HeapAlloc(GetProcessHeap(), 0, 12 * sizeof(WCHAR));
2601
2602 if (buf)
2603 swprintf(buf, fmt, cert->pCertInfo->dwVersion);
2604 return buf;
2605}
2606
2608{
2609 WCHAR *buf = HeapAlloc(GetProcessHeap(), 0, (cb * 3 + 1) * sizeof(WCHAR));
2610
2611 if (buf)
2612 {
2613 static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
2614 DWORD i;
2615 WCHAR *ptr;
2616
2617 for (i = 0, ptr = buf; i < cb; i++, ptr += 3)
2618 swprintf(ptr, fmt, ((BYTE *)pb)[i]);
2619 }
2620 return buf;
2621}
2622
2624{
2625 return format_hex_string(cert->pCertInfo->SerialNumber.pbData,
2626 cert->pCertInfo->SerialNumber.cbData);
2627}
2628
2630{
2633}
2634
2636{
2637 WCHAR *str = NULL;
2640
2641 if (len)
2642 {
2643 str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2644 if (str)
2647 }
2648 return str;
2649}
2650
2652{
2653 return field_format_detailed_cert_name(&cert->pCertInfo->Issuer);
2654}
2655
2657{
2659}
2660
2662{
2663 return field_format_detailed_cert_name(&cert->pCertInfo->Subject);
2664}
2665
2666static WCHAR *format_long_date(const FILETIME *fileTime)
2667{
2668 WCHAR dateFmt[80]; /* long enough for LOCALE_SLONGDATE */
2669 DWORD len;
2670 WCHAR *buf = NULL;
2671 SYSTEMTIME sysTime;
2672
2673 /* FIXME: format isn't quite right, want time too */
2675 FileTimeToSystemTime(fileTime, &sysTime);
2676 len = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, NULL, 0);
2677 if (len)
2678 {
2679 buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2680 if (buf)
2681 GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, buf,
2682 len);
2683 }
2684 return buf;
2685}
2686
2688{
2689 return format_long_date(&cert->pCertInfo->NotBefore);
2690}
2691
2693{
2694 return format_long_date(&cert->pCertInfo->NotAfter);
2695}
2696
2698{
2700 WCHAR *buf = NULL;
2701
2703 cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, 0);
2704 if (oidInfo)
2705 {
2707
2709 {
2710 DWORD len;
2711
2712 /* Allocate the output buffer. Use the number of bytes in the
2713 * public key as a conservative (high) estimate for the number of
2714 * digits in its output.
2715 * The output is of the form (in English)
2716 * "<public key algorithm> (<public key bit length> bits)".
2717 * Ordinarily having two positional parameters in a string is not a
2718 * good idea, but as this isn't a sentence fragment, it shouldn't
2719 * be word-order dependent.
2720 */
2721 len = lstrlenW(fmt) + lstrlenW(oidInfo->pwszName) +
2722 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData * 8;
2723 buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(*buf));
2724 if (buf)
2725 {
2726 DWORD_PTR args[2];
2727 args[0] = (DWORD_PTR)oidInfo->pwszName;
2729 &cert->pCertInfo->SubjectPublicKeyInfo);
2731 fmt, 0, 0, buf, len, (__ms_va_list*)args);
2732 }
2733 }
2734 }
2735 return buf;
2736}
2737
2739{
2740 return format_hex_string(
2741 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
2742 cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData);
2743}
2744
2745struct field_value_data;
2747{
2752};
2753
2755
2756typedef WCHAR *(*create_detailed_value_func)(PCCERT_CONTEXT cert, void *param);
2757
2759{
2762 void *param;
2763};
2764
2767{
2768 if (data->cFields)
2769 data->fields = HeapReAlloc(GetProcessHeap(), 0, data->fields,
2770 (data->cFields + 1) * sizeof(struct field_value_data));
2771 else
2772 data->fields = HeapAlloc(GetProcessHeap(), 0,
2773 sizeof(struct field_value_data));
2774 if (data->fields)
2775 {
2776 data->fields[data->cFields].create = create;
2777 data->fields[data->cFields].detailed_value = NULL;
2778 data->fields[data->cFields].param = param;
2779 data->cFields++;
2780 }
2781}
2782
2785{
2786 LVITEMW item;
2787 int iItem = SendMessageW(hwnd, LVM_GETITEMCOUNT, 0, 0);
2788
2789 item.mask = LVIF_TEXT | LVIF_PARAM;
2790 item.iItem = iItem;
2791 item.iSubItem = 0;
2792 item.pszText = field;
2793 item.lParam = (LPARAM)data;
2795 if (value)
2796 {
2797 item.pszText = value;
2798 item.iSubItem = 1;
2800 }
2802}
2803
2806{
2808
2811}
2812
2814{
2815 int id;
2818};
2819
2821 const struct v1_field *field)
2822{
2823 WCHAR *val = field->format(data->pCertViewInfo->pCertContext);
2824
2825 if (val)
2826 {
2828 field->create_detailed_value, NULL);
2830 }
2831}
2832
2833static const struct v1_field v1_fields[] = {
2842};
2843
2845{
2846 unsigned int i;
2847 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
2848
2849 /* The last item in v1_fields is the public key, which is not in the loop
2850 * because it's a special case.
2851 */
2852 for (i = 0; i < ARRAY_SIZE(v1_fields) - 1; i++)
2854 if (cert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData)
2856}
2857
2859{
2860 WCHAR *str = NULL;
2861 DWORD size;
2862
2863 if (CryptFormatObject(X509_ASN_ENCODING, 0, formatStrType, NULL,
2864 ext->pszObjId, ext->Value.pbData, ext->Value.cbData, NULL, &size))
2865 {
2867 CryptFormatObject(X509_ASN_ENCODING, 0, formatStrType, NULL,
2868 ext->pszObjId, ext->Value.pbData, ext->Value.cbData, str, &size);
2869 }
2870 return str;
2871}
2872
2874{
2875 WCHAR *str = NULL;
2876
2877 if (ext->Value.cbData)
2878 {
2879 /* The output is formatted as:
2880 * <hex bytes> <ascii bytes>\n
2881 * where <hex bytes> is a string of up to 8 bytes, output as %02x,
2882 * and <ascii bytes> is the ASCII equivalent of each byte, or '.' if
2883 * the byte is not printable.
2884 * So, for example, the extension value consisting of the following
2885 * bytes:
2886 * 0x30,0x14,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x03,
2887 * 0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67
2888 * is output as:
2889 * 30 14 31 12 30 10 06 03 0.1.0...
2890 * 55 04 03 13 09 4a 75 61 U....Jua
2891 * 6e 20 4c 61 6e 67 n Lang
2892 * The allocation size therefore requires:
2893 * - 4 characters per character in an 8-byte line
2894 * (2 for the hex format, one for the space, one for the ASCII value)
2895 * - 3 more characters per 8-byte line (two spaces and a newline)
2896 * - 1 character for the terminating nul
2897 * FIXME: should use a fixed-width font for this
2898 */
2899 DWORD lines = (ext->Value.cbData + 7) / 8;
2900
2902 (lines * 8 * 4 + lines * 3 + 1) * sizeof(WCHAR));
2903 if (str)
2904 {
2905 static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
2906 DWORD i, j;
2907 WCHAR *ptr;
2908
2909 for (i = 0, ptr = str; i < ext->Value.cbData; i += 8)
2910 {
2911 /* Output as hex bytes first */
2912 for (j = i; j < min(i + 8, ext->Value.cbData); j++, ptr += 3)
2913 swprintf(ptr, fmt, ext->Value.pbData[j]);
2914 /* Pad the hex output with spaces for alignment */
2915 if (j == ext->Value.cbData && j % 8)
2916 {
2917 static const WCHAR pad[] = { ' ',' ',' ' };
2918
2919 for (; j % 8; j++, ptr += ARRAY_SIZE(pad))
2920 memcpy(ptr, pad, sizeof(pad));
2921 }
2922 /* The last swprintf included a space, so just insert one
2923 * more space between the hex bytes and the ASCII output
2924 */
2925 *ptr++ = ' ';
2926 /* Output as ASCII bytes */
2927 for (j = i; j < min(i + 8, ext->Value.cbData); j++, ptr++)
2928 {
2929 if (iswprint(ext->Value.pbData[j]) &&
2930 !iswspace(ext->Value.pbData[j]))
2931 *ptr = ext->Value.pbData[j];
2932 else
2933 *ptr = '.';
2934 }
2935 *ptr++ = '\n';
2936 }
2937 *ptr++ = '\0';
2938 }
2939 }
2940 return str;
2941}
2942
2944{
2948
2949 if (!str)
2951 return str;
2952}
2953
2956{
2958 ext->pszObjId, 0);
2960
2961 if (oidInfo)
2964 else
2965 {
2966 DWORD len = strlen(ext->pszObjId);
2967 LPWSTR oidW = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2968
2969 if (oidW)
2970 {
2971 DWORD i;
2972
2973 for (i = 0; i <= len; i++)
2974 oidW[i] = ext->pszObjId[i];
2977 HeapFree(GetProcessHeap(), 0, oidW);
2978 }
2979 }
2981}
2982
2984{
2985 DWORD i;
2986 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
2987
2988 for (i = 0; i < cert->pCertInfo->cExtension; i++)
2989 add_cert_extension_detail(hwnd, data, &cert->pCertInfo->rgExtension[i]);
2990}
2991
2993{
2994 DWORD i;
2995 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
2996
2997 for (i = 0; i < cert->pCertInfo->cExtension; i++)
2998 if (cert->pCertInfo->rgExtension[i].fCritical)
3000 &cert->pCertInfo->rgExtension[i]);
3001}
3002
3003typedef WCHAR * (*prop_to_value_func)(void *pb, DWORD cb);
3004
3006{
3008 int id;
3011};
3012
3014{
3016
3017 ext.pszObjId = (LPSTR)X509_ENHANCED_KEY_USAGE;
3018 ext.fCritical = FALSE;
3019 ext.Value.pbData = pb;
3020 ext.Value.cbData = cb;
3021 return crypt_format_extension(&ext, 0);
3022}
3023
3024/* Logically the access state should also be checked, and IDC_EDITPROPERTIES
3025 * disabled for read-only certificates, but native doesn't appear to do that.
3026 */
3027static const struct prop_id_to_string_id prop_id_map[] = {
3033};
3034
3036{
3037 DWORD i;
3038 PCCERT_CONTEXT cert = data->pCertViewInfo->pCertContext;
3039
3040 for (i = 0; i < ARRAY_SIZE(prop_id_map); i++)
3041 {
3042 DWORD cb;
3043
3045 &cb))
3046 {
3047 BYTE *pb;
3048 WCHAR *val = NULL;
3049
3050 /* FIXME: MS adds a separate value for the signature hash
3051 * algorithm.
3052 */
3053 pb = HeapAlloc(GetProcessHeap(), 0, cb);
3054 if (pb)
3055 {
3057 prop_id_map[i].prop, pb, &cb))
3058 {
3060 {
3061 val = (LPWSTR)pb;
3062 /* Don't double-free pb */
3063 pb = NULL;
3064 }
3065 else
3066 val = prop_id_map[i].prop_to_value(pb, cb);
3067 }
3068 HeapFree(GetProcessHeap(), 0, pb);
3069 }
3071 NULL, NULL);
3072 }
3073 }
3074}
3075
3077{
3081}
3082
3084{
3085 int id;
3087};
3088
3089static const struct selection_list_item listItems[] = {
3095};
3096
3098{
3101 int i;
3102
3103 for (i = 0; i < ARRAY_SIZE(listItems); i++)
3104 {
3105 int index;
3106
3110 }
3112}
3113
3115{
3117 RECT rc;
3120
3122 GetWindowRect(lv, &rc);
3124 column.mask = LVCF_WIDTH | LVCF_TEXT;
3125 column.cx = (rc.right - rc.left) / 2 - 2;
3126 column.pszText = buf;
3130}
3131
3132static void set_fields_selection(HWND hwnd, struct detail_data *data, int sel)
3133{
3135
3136 if (sel >= 0 && sel < ARRAY_SIZE(listItems))
3137 {
3139 listItems[sel].add(list, data);
3140 }
3141}
3142
3144{
3148}
3149
3150static void add_purpose(HWND hwnd, LPCSTR oid)
3151{
3154 sizeof(CRYPT_OID_INFO));
3155
3156 if (info)
3157 {
3158 char *oidCopy = HeapAlloc(GetProcessHeap(), 0, strlen(oid) + 1);
3159
3160 if (oidCopy)
3161 {
3162 LVITEMA item;
3163
3164 strcpy(oidCopy, oid);
3165 info->cbSize = sizeof(CRYPT_OID_INFO);
3166 info->pszOID = oidCopy;
3169 item.stateMask = LVIS_STATEIMAGEMASK;
3170 item.iItem = SendMessageW(lv, LVM_GETITEMCOUNT, 0, 0);
3171 item.iSubItem = 0;
3172 item.lParam = (LPARAM)info;
3173 item.pszText = oidCopy;
3175 }
3176 else
3178 }
3179}
3180
3182{
3183 BOOL ret;
3184
3185 if (oid[0] != '0' && oid[0] != '1' && oid[0] != '2')
3186 ret = FALSE;
3187 else if (oid[1] != '.')
3188 ret = FALSE;
3189 else if (!oid[2])
3190 ret = FALSE;
3191 else
3192 {
3193 const char *ptr;
3194 BOOL expectNum = TRUE;
3195
3196 for (ptr = oid + 2, ret = TRUE; ret && *ptr; ptr++)
3197 {
3198 if (expectNum)
3199 {
3200 if (!isdigit(*ptr))
3201 ret = FALSE;
3202 else if (*(ptr + 1) == '.')
3203 expectNum = FALSE;
3204 }
3205 else
3206 {
3207 if (*ptr != '.')
3208 ret = FALSE;
3209 else if (!(*(ptr + 1)))
3210 ret = FALSE;
3211 else
3212 expectNum = TRUE;
3213 }
3214 }
3215 }
3216 return ret;
3217}
3218
3220{
3222 != -1;
3223}
3224
3225#define MAX_PURPOSE 255
3226
3228 WPARAM wp, LPARAM lp)
3229{
3230 LRESULT ret = 0;
3231 char buf[MAX_PURPOSE + 1];
3232
3233 switch (msg)
3234 {
3235 case WM_INITDIALOG:
3237 MAX_PURPOSE, 0);
3240 break;
3241 case WM_COMMAND:
3242 switch (HIWORD(wp))
3243 {
3244 case EN_CHANGE:
3245 if (LOWORD(wp) == IDC_NEW_PURPOSE)
3246 {
3247 /* Show/hide scroll bar on description depending on how much
3248 * text it has.
3249 */
3252
3254 }
3255 break;
3256 case BN_CLICKED:
3257 switch (LOWORD(wp))
3258 {
3259 case IDOK:
3261 (LPARAM)buf);
3262 if (!buf[0])
3263 {
3264 /* An empty purpose is the same as cancelling */
3266 ret = TRUE;
3267 }
3268 else if (!is_valid_oid(buf))
3269 {
3271
3275 }
3276 else if (is_oid_in_list(
3278 {
3280
3282 ARRAY_SIZE(error));
3285 }
3286 else
3287 {
3289
3291 EndDialog(hwnd, wp);
3292 ret = TRUE;
3293 }
3294 break;
3295 case IDCANCEL:
3296 EndDialog(hwnd, wp);
3297 ret = TRUE;
3298 break;
3299 }
3300 break;
3301 }
3302 break;
3303 }
3304 return ret;
3305}
3306
3308{
3309 WCHAR *name = NULL;
3310 DWORD cb;
3311
3313 {
3315 if (name)
3316 {
3318 {
3320 name = NULL;
3321 }
3322 }
3323 }
3324 return name;
3325}
3326
3328{
3329 int items = SendMessageW(list, LVM_GETITEMCOUNT, 0, 0), i;
3330
3331 for (i = 0; i < items; i++)
3332 {
3333 BOOL change = FALSE;
3334 int state;
3335
3337 /* This reverses the INDEXTOSTATEIMAGEMASK shift. There doesn't appear
3338 * to be a handy macro for it.
3339 */
3340 state >>= 12;
3341 if (enabled)
3342 {
3344 {
3346 change = TRUE;
3347 }
3349 {
3351 change = TRUE;
3352 }
3353 }
3354 else
3355 {
3357 {
3359 change = TRUE;
3360 }
3362 {
3364 change = TRUE;
3365 }
3366 }
3367 if (change)
3368 {
3369 LVITEMW item;
3370
3372 item.stateMask = LVIS_STATEIMAGEMASK;
3374 }
3375 }
3376}
3377
3378typedef enum {
3383
3385{
3387
3388 switch (selection)
3389 {
3390 case PurposeEnableAll:
3391 case PurposeDisableAll:
3392 EnableWindow(lv, FALSE);
3393 redraw_states(lv, FALSE);
3395 break;
3397 EnableWindow(lv, TRUE);
3398 redraw_states(lv, TRUE);
3400 }
3401}
3402
3404{
3408};
3409
3411{
3412 PCCERT_CONTEXT cert = data->cert;
3415 DWORD size;
3416 RECT rc;
3418 PurposeSelection purposeSelection = PurposeEnableAll;
3419
3420 GetWindowRect(lv, &rc);
3421 column.mask = LVCF_WIDTH;
3422 column.cx = rc.right - rc.left;
3425
3426 /* Get enhanced key usage. Have to check for a property and an extension
3427 * separately, because CertGetEnhancedKeyUsage will succeed and return an
3428 * empty usage if neither is set. Unfortunately an empty usage implies
3429 * no usage is allowed, so we have to distinguish between the two cases.
3430 */
3432 NULL, &size))
3433 {
3437 {
3439 usage = NULL;
3440 }
3441 else if (usage->cUsageIdentifier)
3442 purposeSelection = PurposeEnableSelected;
3443 else
3444 purposeSelection = PurposeDisableAll;
3445 }
3447 NULL, &size))
3448 {
3452 {
3454 usage = NULL;
3455 }
3456 else if (usage->cUsageIdentifier)
3457 purposeSelection = PurposeEnableAll;
3458 else
3459 purposeSelection = PurposeDisableAll;
3460 }
3461 else
3462 {
3463 purposeSelection = PurposeEnableAll;
3464 usage = NULL;
3465 }
3466 if (usage)
3467 {
3468 DWORD i;
3469
3470 for (i = 0; i < usage->cUsageIdentifier; i++)
3471 {
3473 usage->rgpszUsageIdentifier[i], CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
3474
3475 if (info)
3476