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