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 /***********************************************************************
77 * CryptUIDlgViewCertificateA (CRYPTUI.@)
79 BOOL WINAPI
CryptUIDlgViewCertificateA(
80 PCCRYPTUI_VIEWCERTIFICATE_STRUCTA pCertViewInfo
, BOOL
*pfPropertiesChanged
)
82 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo
;
86 TRACE("(%p, %p)\n", pCertViewInfo
, pfPropertiesChanged
);
88 memcpy(&viewInfo
, pCertViewInfo
, sizeof(viewInfo
));
89 if (pCertViewInfo
->szTitle
)
91 int len
= MultiByteToWideChar(CP_ACP
, 0, pCertViewInfo
->szTitle
, -1,
94 title
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
97 MultiByteToWideChar(CP_ACP
, 0, pCertViewInfo
->szTitle
, -1, title
,
99 viewInfo
.szTitle
= title
;
107 if (pCertViewInfo
->cPropSheetPages
)
109 FIXME("ignoring additional prop sheet pages\n");
110 viewInfo
.cPropSheetPages
= 0;
112 ret
= CryptUIDlgViewCertificateW(&viewInfo
, pfPropertiesChanged
);
113 HeapFree(GetProcessHeap(), 0, title
);
118 struct ReadStringStruct
125 static DWORD CALLBACK
read_text_callback(DWORD_PTR dwCookie
, LPBYTE buf
,
128 struct ReadStringStruct
*string
= (struct ReadStringStruct
*)dwCookie
;
129 LONG cch
= min(cb
/ sizeof(WCHAR
), string
->len
- string
->pos
);
131 TRACE("(%p, %p, %d, %p)\n", string
, buf
, cb
, pcb
);
133 memmove(buf
, string
->buf
+ string
->pos
, cch
* sizeof(WCHAR
));
135 *pcb
= cch
* sizeof(WCHAR
);
139 static void add_unformatted_text_to_control(HWND hwnd
, LPCWSTR text
, LONG len
)
141 struct ReadStringStruct string
;
142 EDITSTREAM editstream
;
144 TRACE("(%p, %s)\n", hwnd
, debugstr_wn(text
, len
));
149 editstream
.dwCookie
= (DWORD_PTR
)&string
;
150 editstream
.dwError
= 0;
151 editstream
.pfnCallback
= read_text_callback
;
152 SendMessageW(hwnd
, EM_STREAMIN
, SF_TEXT
| SFF_SELECTION
| SF_UNICODE
,
153 (LPARAM
)&editstream
);
156 static void add_string_resource_to_control(HWND hwnd
, int id
)
161 len
= LoadStringW(hInstance
, id
, (LPWSTR
)&str
, 0);
162 add_unformatted_text_to_control(hwnd
, str
, len
);
165 static void add_text_with_paraformat_to_control(HWND hwnd
, LPCWSTR text
,
166 LONG len
, const PARAFORMAT2
*fmt
)
168 add_unformatted_text_to_control(hwnd
, text
, len
);
169 SendMessageW(hwnd
, EM_SETPARAFORMAT
, 0, (LPARAM
)fmt
);
172 static void add_string_resource_with_paraformat_to_control(HWND hwnd
, int id
,
173 const PARAFORMAT2
*fmt
)
178 len
= LoadStringW(hInstance
, id
, (LPWSTR
)&str
, 0);
179 add_text_with_paraformat_to_control(hwnd
, str
, len
, fmt
);
182 static LPWSTR
get_cert_name_string(PCCERT_CONTEXT pCertContext
, DWORD dwType
,
188 len
= CertGetNameStringW(pCertContext
, dwType
, dwFlags
, NULL
, NULL
, 0);
191 buf
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
193 CertGetNameStringW(pCertContext
, dwType
, dwFlags
, NULL
, buf
, len
);
198 static void add_cert_string_to_control(HWND hwnd
, PCCERT_CONTEXT pCertContext
,
199 DWORD dwType
, DWORD dwFlags
)
201 LPWSTR name
= get_cert_name_string(pCertContext
, dwType
, dwFlags
);
205 /* Don't include NULL-terminator in output */
206 DWORD len
= lstrlenW(name
);
208 add_unformatted_text_to_control(hwnd
, name
, len
);
209 HeapFree(GetProcessHeap(), 0, name
);
213 static void add_icon_to_control(HWND hwnd
, int id
)
216 LPRICHEDITOLE richEditOle
= NULL
;
217 LPOLEOBJECT object
= NULL
;
219 LPOLECACHE oleCache
= NULL
;
222 LPDATAOBJECT dataObject
= NULL
;
223 HBITMAP bitmap
= NULL
;
228 TRACE("(%p, %d)\n", hwnd
, id
);
230 SendMessageW(hwnd
, EM_GETOLEINTERFACE
, 0, (LPARAM
)&richEditOle
);
233 hr
= OleCreateDefaultHandler(&CLSID_NULL
, NULL
, &IID_IOleObject
,
237 hr
= IOleObject_GetUserClassID(object
, &clsid
);
240 hr
= IOleObject_QueryInterface(object
, &IID_IOleCache
, (void**)&oleCache
);
243 formatEtc
.cfFormat
= CF_BITMAP
;
244 formatEtc
.ptd
= NULL
;
245 formatEtc
.dwAspect
= DVASPECT_CONTENT
;
246 formatEtc
.lindex
= -1;
247 formatEtc
.tymed
= TYMED_GDI
;
248 hr
= IOleCache_Cache(oleCache
, &formatEtc
, 0, &conn
);
251 hr
= IOleObject_QueryInterface(object
, &IID_IDataObject
,
252 (void**)&dataObject
);
255 bitmap
= LoadImageW(hInstance
, MAKEINTRESOURCEW(id
), IMAGE_BITMAP
, 0, 0,
256 LR_DEFAULTSIZE
| LR_LOADTRANSPARENT
);
259 rect
.left
= rect
.top
= 0;
260 rect
.right
= GetSystemMetrics(SM_CXICON
);
261 rect
.bottom
= GetSystemMetrics(SM_CYICON
);
262 stgm
.tymed
= TYMED_GDI
;
263 stgm
.u
.hBitmap
= bitmap
;
264 stgm
.pUnkForRelease
= NULL
;
265 hr
= IDataObject_SetData(dataObject
, &formatEtc
, &stgm
, TRUE
);
269 reObject
.cbStruct
= sizeof(reObject
);
270 reObject
.cp
= REO_CP_SELECTION
;
271 reObject
.clsid
= clsid
;
272 reObject
.poleobj
= object
;
273 reObject
.pstg
= NULL
;
274 reObject
.polesite
= NULL
;
275 reObject
.sizel
.cx
= reObject
.sizel
.cy
= 0;
276 reObject
.dvaspect
= DVASPECT_CONTENT
;
277 reObject
.dwFlags
= 0;
280 IRichEditOle_InsertObject(richEditOle
, &reObject
);
284 IDataObject_Release(dataObject
);
286 IOleCache_Release(oleCache
);
288 IOleObject_Release(object
);
290 IRichEditOle_Release(richEditOle
);
293 #define MY_INDENT 200
295 static void add_oid_text_to_control(HWND hwnd
, char *oid
)
298 PCCRYPT_OID_INFO oidInfo
= CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY
, oid
, 0);
301 parFmt
.cbSize
= sizeof(parFmt
);
302 parFmt
.dwMask
= PFM_STARTINDENT
;
303 parFmt
.dxStartIndent
= MY_INDENT
* 3;
306 add_text_with_paraformat_to_control(hwnd
, oidInfo
->pwszName
,
307 lstrlenW(oidInfo
->pwszName
), &parFmt
);
308 add_unformatted_text_to_control(hwnd
, &nl
, 1);
312 #define MAX_STRING_LEN 512
320 /* The following list MUST be lexicographically sorted by OID */
321 static struct OIDToString oidMap
[] = {
322 /* 1.3.6.1.4.1.311.10.3.1 */
323 { szOID_KP_CTL_USAGE_SIGNING
, IDS_PURPOSE_CTL_USAGE_SIGNING
},
324 /* 1.3.6.1.4.1.311.10.3.4 */
325 { szOID_KP_EFS
, IDS_PURPOSE_EFS
},
326 /* 1.3.6.1.4.1.311.10.3.4.1 */
327 { szOID_EFS_RECOVERY
, IDS_PURPOSE_EFS_RECOVERY
},
328 /* 1.3.6.1.4.1.311.10.3.5 */
329 { szOID_WHQL_CRYPTO
, IDS_PURPOSE_WHQL
},
330 /* 1.3.6.1.4.1.311.10.3.6 */
331 { szOID_NT5_CRYPTO
, IDS_PURPOSE_NT5
},
332 /* 1.3.6.1.4.1.311.10.3.7 */
333 { szOID_OEM_WHQL_CRYPTO
, IDS_PURPOSE_OEM_WHQL
},
334 /* 1.3.6.1.4.1.311.10.3.8 */
335 { szOID_EMBEDDED_NT_CRYPTO
, IDS_PURPOSE_EMBEDDED_NT
},
336 /* 1.3.6.1.4.1.311.10.3.9 */
337 { szOID_ROOT_LIST_SIGNER
, IDS_PURPOSE_ROOT_LIST_SIGNER
},
338 /* 1.3.6.1.4.1.311.10.3.10 */
339 { szOID_KP_QUALIFIED_SUBORDINATION
, IDS_PURPOSE_QUALIFIED_SUBORDINATION
},
340 /* 1.3.6.1.4.1.311.10.3.11 */
341 { szOID_KP_KEY_RECOVERY
, IDS_PURPOSE_KEY_RECOVERY
},
342 /* 1.3.6.1.4.1.311.10.3.12 */
343 { szOID_KP_DOCUMENT_SIGNING
, IDS_PURPOSE_DOCUMENT_SIGNING
},
344 /* 1.3.6.1.4.1.311.10.3.13 */
345 { szOID_KP_LIFETIME_SIGNING
, IDS_PURPOSE_LIFETIME_SIGNING
},
346 /* 1.3.6.1.4.1.311.10.5.1 */
347 { szOID_DRM
, IDS_PURPOSE_DRM
},
348 /* 1.3.6.1.4.1.311.10.6.1 */
349 { szOID_LICENSES
, IDS_PURPOSE_LICENSES
},
350 /* 1.3.6.1.4.1.311.10.6.2 */
351 { szOID_LICENSE_SERVER
, IDS_PURPOSE_LICENSE_SERVER
},
352 /* 1.3.6.1.4.1.311.20.2.1 */
353 { szOID_ENROLLMENT_AGENT
, IDS_PURPOSE_ENROLLMENT_AGENT
},
354 /* 1.3.6.1.4.1.311.20.2.2 */
355 { szOID_KP_SMARTCARD_LOGON
, IDS_PURPOSE_SMARTCARD_LOGON
},
356 /* 1.3.6.1.4.1.311.21.5 */
357 { szOID_KP_CA_EXCHANGE
, IDS_PURPOSE_CA_EXCHANGE
},
358 /* 1.3.6.1.4.1.311.21.6 */
359 { szOID_KP_KEY_RECOVERY_AGENT
, IDS_PURPOSE_KEY_RECOVERY_AGENT
},
360 /* 1.3.6.1.4.1.311.21.19 */
361 { szOID_DS_EMAIL_REPLICATION
, IDS_PURPOSE_DS_EMAIL_REPLICATION
},
362 /* 1.3.6.1.5.5.7.3.1 */
363 { szOID_PKIX_KP_SERVER_AUTH
, IDS_PURPOSE_SERVER_AUTH
},
364 /* 1.3.6.1.5.5.7.3.2 */
365 { szOID_PKIX_KP_CLIENT_AUTH
, IDS_PURPOSE_CLIENT_AUTH
},
366 /* 1.3.6.1.5.5.7.3.3 */
367 { szOID_PKIX_KP_CODE_SIGNING
, IDS_PURPOSE_CODE_SIGNING
},
368 /* 1.3.6.1.5.5.7.3.4 */
369 { szOID_PKIX_KP_EMAIL_PROTECTION
, IDS_PURPOSE_EMAIL_PROTECTION
},
370 /* 1.3.6.1.5.5.7.3.5 */
371 { szOID_PKIX_KP_IPSEC_END_SYSTEM
, IDS_PURPOSE_IPSEC
},
372 /* 1.3.6.1.5.5.7.3.6 */
373 { szOID_PKIX_KP_IPSEC_TUNNEL
, IDS_PURPOSE_IPSEC
},
374 /* 1.3.6.1.5.5.7.3.7 */
375 { szOID_PKIX_KP_IPSEC_USER
, IDS_PURPOSE_IPSEC
},
376 /* 1.3.6.1.5.5.7.3.8 */
377 { szOID_PKIX_KP_TIMESTAMP_SIGNING
, IDS_PURPOSE_TIMESTAMP_SIGNING
},
380 static struct OIDToString
*findSupportedOID(LPCSTR oid
)
382 int indexHigh
= sizeof(oidMap
) / sizeof(oidMap
[0]) - 1, indexLow
= 0, i
;
383 struct OIDToString
*ret
= NULL
;
385 for (i
= (indexLow
+ indexHigh
) / 2; !ret
&& indexLow
<= indexHigh
;
386 i
= (indexLow
+ indexHigh
) / 2)
390 cmp
= strcmp(oid
, oidMap
[i
].oid
);
401 static void add_local_oid_text_to_control(HWND text
, LPCSTR oid
)
403 struct OIDToString
*entry
;
407 parFmt
.cbSize
= sizeof(parFmt
);
408 parFmt
.dwMask
= PFM_STARTINDENT
;
409 parFmt
.dxStartIndent
= MY_INDENT
* 3;
410 if ((entry
= findSupportedOID(oid
)))
412 WCHAR
*str
, *linebreak
, *ptr
;
413 BOOL multiline
= FALSE
;
416 len
= LoadStringW(hInstance
, entry
->id
, (LPWSTR
)&str
, 0);
419 if ((linebreak
= memchrW(ptr
, '\n', len
)))
421 WCHAR copy
[MAX_STRING_LEN
];
424 /* The source string contains a newline, which the richedit
425 * control won't find since it's interpreted as a paragraph
426 * break. Therefore copy up to the newline. lstrcpynW always
427 * NULL-terminates, so pass one more than the length of the
428 * source line so the copy includes the entire line and the
431 lstrcpynW(copy
, ptr
, linebreak
- ptr
+ 1);
432 add_text_with_paraformat_to_control(text
, copy
,
433 linebreak
- ptr
, &parFmt
);
435 add_unformatted_text_to_control(text
, &nl
, 1);
437 else if (multiline
&& *ptr
)
439 /* Add the last line */
440 add_text_with_paraformat_to_control(text
, ptr
,
441 len
- (ptr
- str
), &parFmt
);
442 add_unformatted_text_to_control(text
, &nl
, 1);
447 add_text_with_paraformat_to_control(text
, str
, len
, &parFmt
);
448 add_unformatted_text_to_control(text
, &nl
, 1);
453 WCHAR
*oidW
= HeapAlloc(GetProcessHeap(), 0,
454 (strlen(oid
) + 1) * sizeof(WCHAR
));
461 for (src
= oid
, dst
= oidW
; *src
; src
++, dst
++)
464 add_text_with_paraformat_to_control(text
, oidW
, lstrlenW(oidW
),
466 add_unformatted_text_to_control(text
, &nl
, 1);
467 HeapFree(GetProcessHeap(), 0, oidW
);
472 static void display_app_usages(HWND text
, PCCERT_CONTEXT cert
,
475 static char any_app_policy
[] = szOID_ANY_APPLICATION_POLICY
;
478 PCERT_EXTENSION policyExt
;
483 parFmt
.cbSize
= sizeof(parFmt
);
484 parFmt
.dwMask
= PFM_STARTINDENT
;
485 parFmt
.dxStartIndent
= MY_INDENT
;
486 add_string_resource_with_paraformat_to_control(text
,
487 IDS_CERT_INFO_PURPOSES
, &parFmt
);
488 add_unformatted_text_to_control(text
, &nl
, 1);
489 *anyUsageAdded
= TRUE
;
491 memset(&charFmt
, 0, sizeof(charFmt
));
492 charFmt
.cbSize
= sizeof(charFmt
);
493 charFmt
.dwMask
= CFM_BOLD
;
494 charFmt
.dwEffects
= 0;
495 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
496 if ((policyExt
= CertFindExtension(szOID_APPLICATION_CERT_POLICIES
,
497 cert
->pCertInfo
->cExtension
, cert
->pCertInfo
->rgExtension
)))
499 CERT_POLICIES_INFO
*policies
;
502 if (CryptDecodeObjectEx(X509_ASN_ENCODING
, X509_CERT_POLICIES
,
503 policyExt
->Value
.pbData
, policyExt
->Value
.cbData
,
504 CRYPT_DECODE_ALLOC_FLAG
, NULL
, &policies
, &size
))
508 for (i
= 0; i
< policies
->cPolicyInfo
; i
++)
512 for (j
= 0; j
< policies
->rgPolicyInfo
[i
].cPolicyQualifier
; j
++)
513 add_local_oid_text_to_control(text
,
514 policies
->rgPolicyInfo
[i
].rgPolicyQualifier
[j
].
515 pszPolicyQualifierId
);
521 add_oid_text_to_control(text
, any_app_policy
);
524 static BOOL
display_cert_usages(HWND text
, PCCERT_CONTEXT cert
,
529 BOOL badUsages
= FALSE
;
531 if (CertGetEnhancedKeyUsage(cert
, 0, NULL
, &size
))
534 static char any_cert_policy
[] = szOID_ANY_CERT_POLICY
;
535 PCERT_ENHKEY_USAGE usage
= HeapAlloc(GetProcessHeap(), 0, size
);
539 if (CertGetEnhancedKeyUsage(cert
, 0, usage
, &size
))
547 parFmt
.cbSize
= sizeof(parFmt
);
548 parFmt
.dwMask
= PFM_STARTINDENT
;
549 parFmt
.dxStartIndent
= MY_INDENT
;
550 add_string_resource_with_paraformat_to_control(text
,
551 IDS_CERT_INFO_PURPOSES
, &parFmt
);
552 add_unformatted_text_to_control(text
, &nl
, 1);
553 *anyUsageAdded
= TRUE
;
555 memset(&charFmt
, 0, sizeof(charFmt
));
556 charFmt
.cbSize
= sizeof(charFmt
);
557 charFmt
.dwMask
= CFM_BOLD
;
558 charFmt
.dwEffects
= 0;
559 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
,
561 if (!usage
->cUsageIdentifier
)
562 add_oid_text_to_control(text
, any_cert_policy
);
564 for (i
= 0; i
< usage
->cUsageIdentifier
; i
++)
565 add_local_oid_text_to_control(text
,
566 usage
->rgpszUsageIdentifier
[i
]);
570 HeapFree(GetProcessHeap(), 0, usage
);
580 static void set_policy_text(HWND text
,
581 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
)
583 BOOL includeCertUsages
= FALSE
, includeAppUsages
= FALSE
;
584 BOOL badUsages
= FALSE
, anyUsageAdded
= FALSE
;
586 if (pCertViewInfo
->cPurposes
)
590 for (i
= 0; i
< pCertViewInfo
->cPurposes
; i
++)
592 if (!strcmp(pCertViewInfo
->rgszPurposes
[i
], szOID_ANY_CERT_POLICY
))
593 includeCertUsages
= TRUE
;
594 else if (!strcmp(pCertViewInfo
->rgszPurposes
[i
],
595 szOID_ANY_APPLICATION_POLICY
))
596 includeAppUsages
= TRUE
;
602 includeAppUsages
= includeCertUsages
= TRUE
;
603 if (includeAppUsages
)
604 display_app_usages(text
, pCertViewInfo
->pCertContext
, &anyUsageAdded
);
605 if (includeCertUsages
)
606 badUsages
= display_cert_usages(text
, pCertViewInfo
->pCertContext
,
612 parFmt
.cbSize
= sizeof(parFmt
);
613 parFmt
.dwMask
= PFM_STARTINDENT
;
614 parFmt
.dxStartIndent
= MY_INDENT
;
615 add_string_resource_with_paraformat_to_control(text
,
616 IDS_CERT_INFO_BAD_PURPOSES
, &parFmt
);
620 static CRYPT_OBJID_BLOB
*find_policy_qualifier(CERT_POLICIES_INFO
*policies
,
623 CRYPT_OBJID_BLOB
*ret
= NULL
;
626 for (i
= 0; !ret
&& i
< policies
->cPolicyInfo
; i
++)
630 for (j
= 0; !ret
&& j
< policies
->rgPolicyInfo
[i
].cPolicyQualifier
; j
++)
631 if (!strcmp(policies
->rgPolicyInfo
[i
].rgPolicyQualifier
[j
].
632 pszPolicyQualifierId
, policyOid
))
633 ret
= &policies
->rgPolicyInfo
[i
].rgPolicyQualifier
[j
].
639 static WCHAR
*get_cps_str_from_qualifier(CRYPT_OBJID_BLOB
*qualifier
)
641 LPWSTR qualifierStr
= NULL
;
642 CERT_NAME_VALUE
*qualifierValue
;
645 if (CryptDecodeObjectEx(X509_ASN_ENCODING
, X509_NAME_VALUE
,
646 qualifier
->pbData
, qualifier
->cbData
, CRYPT_DECODE_ALLOC_FLAG
, NULL
,
647 &qualifierValue
, &size
))
649 size
= CertRDNValueToStrW(qualifierValue
->dwValueType
,
650 &qualifierValue
->Value
, NULL
, 0);
651 qualifierStr
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
));
653 CertRDNValueToStrW(qualifierValue
->dwValueType
,
654 &qualifierValue
->Value
, qualifierStr
, size
);
655 LocalFree(qualifierValue
);
660 static WCHAR
*get_user_notice_from_qualifier(CRYPT_OBJID_BLOB
*qualifier
)
663 CERT_POLICY_QUALIFIER_USER_NOTICE
*qualifierValue
;
666 if (CryptDecodeObjectEx(X509_ASN_ENCODING
,
667 X509_PKIX_POLICY_QUALIFIER_USERNOTICE
,
668 qualifier
->pbData
, qualifier
->cbData
, CRYPT_DECODE_ALLOC_FLAG
, NULL
,
669 &qualifierValue
, &size
))
671 str
= HeapAlloc(GetProcessHeap(), 0,
672 (strlenW(qualifierValue
->pszDisplayText
) + 1) * sizeof(WCHAR
));
674 strcpyW(str
, qualifierValue
->pszDisplayText
);
675 LocalFree(qualifierValue
);
680 struct IssuerStatement
686 static void set_issuer_statement(HWND hwnd
,
687 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
)
689 PCERT_EXTENSION policyExt
;
691 if (!(pCertViewInfo
->dwFlags
& CRYPTUI_DISABLE_ISSUERSTATEMENT
) &&
692 (policyExt
= CertFindExtension(szOID_CERT_POLICIES
,
693 pCertViewInfo
->pCertContext
->pCertInfo
->cExtension
,
694 pCertViewInfo
->pCertContext
->pCertInfo
->rgExtension
)))
696 CERT_POLICIES_INFO
*policies
;
699 if (CryptDecodeObjectEx(X509_ASN_ENCODING
, policyExt
->pszObjId
,
700 policyExt
->Value
.pbData
, policyExt
->Value
.cbData
,
701 CRYPT_DECODE_ALLOC_FLAG
, NULL
, &policies
, &size
))
703 CRYPT_OBJID_BLOB
*qualifier
;
704 LPWSTR cps
= NULL
, userNotice
= NULL
;
706 if ((qualifier
= find_policy_qualifier(policies
,
707 szOID_PKIX_POLICY_QUALIFIER_CPS
)))
708 cps
= get_cps_str_from_qualifier(qualifier
);
709 if ((qualifier
= find_policy_qualifier(policies
,
710 szOID_PKIX_POLICY_QUALIFIER_USERNOTICE
)))
711 userNotice
= get_user_notice_from_qualifier(qualifier
);
712 if (cps
|| userNotice
)
714 struct IssuerStatement
*issuerStatement
=
715 HeapAlloc(GetProcessHeap(), 0, sizeof(struct IssuerStatement
));
719 issuerStatement
->cps
= cps
;
720 issuerStatement
->userNotice
= userNotice
;
721 EnableWindow(GetDlgItem(hwnd
, IDC_ISSUERSTATEMENT
), TRUE
);
722 SetWindowLongPtrW(hwnd
, DWLP_USER
,
723 (ULONG_PTR
)issuerStatement
);
731 static void set_cert_info(HWND hwnd
,
732 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
)
736 HWND icon
= GetDlgItem(hwnd
, IDC_CERTIFICATE_ICON
);
737 HWND text
= GetDlgItem(hwnd
, IDC_CERTIFICATE_INFO
);
738 CRYPT_PROVIDER_SGNR
*provSigner
= WTHelperGetProvSignerFromChain(
739 (CRYPT_PROVIDER_DATA
*)pCertViewInfo
->u
.pCryptProviderData
,
740 pCertViewInfo
->idxSigner
, pCertViewInfo
->fCounterSigner
,
741 pCertViewInfo
->idxCounterSigner
);
742 CRYPT_PROVIDER_CERT
*root
=
743 &provSigner
->pasCertChain
[provSigner
->csCertChain
- 1];
745 if (provSigner
->pChainContext
->TrustStatus
.dwErrorStatus
&
746 CERT_TRUST_IS_PARTIAL_CHAIN
)
747 add_icon_to_control(icon
, IDB_CERT_WARNING
);
748 else if (!root
->fTrustedRoot
)
749 add_icon_to_control(icon
, IDB_CERT_ERROR
);
751 add_icon_to_control(icon
, IDB_CERT
);
753 memset(&charFmt
, 0, sizeof(charFmt
));
754 charFmt
.cbSize
= sizeof(charFmt
);
755 charFmt
.dwMask
= CFM_BOLD
;
756 charFmt
.dwEffects
= CFE_BOLD
;
757 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
758 /* FIXME: vertically center text */
759 parFmt
.cbSize
= sizeof(parFmt
);
760 parFmt
.dwMask
= PFM_STARTINDENT
;
761 parFmt
.dxStartIndent
= MY_INDENT
;
762 add_string_resource_with_paraformat_to_control(text
,
763 IDS_CERTIFICATEINFORMATION
, &parFmt
);
765 text
= GetDlgItem(hwnd
, IDC_CERTIFICATE_STATUS
);
766 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
767 if (provSigner
->dwError
== TRUST_E_CERT_SIGNATURE
)
768 add_string_resource_with_paraformat_to_control(text
,
769 IDS_CERT_INFO_BAD_SIG
, &parFmt
);
770 else if (provSigner
->pChainContext
->TrustStatus
.dwErrorStatus
&
771 CERT_TRUST_IS_PARTIAL_CHAIN
)
772 add_string_resource_with_paraformat_to_control(text
,
773 IDS_CERT_INFO_PARTIAL_CHAIN
, &parFmt
);
774 else if (!root
->fTrustedRoot
)
776 if (provSigner
->csCertChain
== 1 && root
->fSelfSigned
)
777 add_string_resource_with_paraformat_to_control(text
,
778 IDS_CERT_INFO_UNTRUSTED_CA
, &parFmt
);
780 add_string_resource_with_paraformat_to_control(text
,
781 IDS_CERT_INFO_UNTRUSTED_ROOT
, &parFmt
);
785 set_policy_text(text
, pCertViewInfo
);
786 set_issuer_statement(hwnd
, pCertViewInfo
);
790 static void set_cert_name_string(HWND hwnd
, PCCERT_CONTEXT cert
,
791 DWORD nameFlags
, int heading
)
794 HWND text
= GetDlgItem(hwnd
, IDC_CERTIFICATE_NAMES
);
798 memset(&charFmt
, 0, sizeof(charFmt
));
799 charFmt
.cbSize
= sizeof(charFmt
);
800 charFmt
.dwMask
= CFM_BOLD
;
801 charFmt
.dwEffects
= CFE_BOLD
;
802 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
803 parFmt
.cbSize
= sizeof(parFmt
);
804 parFmt
.dwMask
= PFM_STARTINDENT
;
805 parFmt
.dxStartIndent
= MY_INDENT
* 3;
806 add_string_resource_with_paraformat_to_control(text
, heading
, &parFmt
);
807 charFmt
.dwEffects
= 0;
808 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
809 add_cert_string_to_control(text
, cert
, CERT_NAME_SIMPLE_DISPLAY_TYPE
,
811 add_unformatted_text_to_control(text
, &nl
, 1);
812 add_unformatted_text_to_control(text
, &nl
, 1);
813 add_unformatted_text_to_control(text
, &nl
, 1);
817 static void add_date_string_to_control(HWND hwnd
, const FILETIME
*fileTime
)
819 WCHAR dateFmt
[80]; /* sufficient for all versions of LOCALE_SSHORTDATE */
823 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT
, LOCALE_SSHORTDATE
, dateFmt
,
824 sizeof(dateFmt
) / sizeof(dateFmt
[0]));
825 FileTimeToSystemTime(fileTime
, &sysTime
);
826 GetDateFormatW(LOCALE_SYSTEM_DEFAULT
, 0, &sysTime
, dateFmt
, date
,
827 sizeof(date
) / sizeof(date
[0]));
828 add_unformatted_text_to_control(hwnd
, date
, lstrlenW(date
));
831 static void set_cert_validity_period(HWND hwnd
, PCCERT_CONTEXT cert
)
834 HWND text
= GetDlgItem(hwnd
, IDC_CERTIFICATE_NAMES
);
838 memset(&charFmt
, 0, sizeof(charFmt
));
839 charFmt
.cbSize
= sizeof(charFmt
);
840 charFmt
.dwMask
= CFM_BOLD
;
841 charFmt
.dwEffects
= CFE_BOLD
;
842 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
843 parFmt
.cbSize
= sizeof(parFmt
);
844 parFmt
.dwMask
= PFM_STARTINDENT
;
845 parFmt
.dxStartIndent
= MY_INDENT
* 3;
846 add_string_resource_with_paraformat_to_control(text
, IDS_VALID_FROM
,
848 charFmt
.dwEffects
= 0;
849 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
850 add_date_string_to_control(text
, &cert
->pCertInfo
->NotBefore
);
851 charFmt
.dwEffects
= CFE_BOLD
;
852 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
853 add_string_resource_to_control(text
, IDS_VALID_TO
);
854 charFmt
.dwEffects
= 0;
855 SendMessageW(text
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&charFmt
);
856 add_date_string_to_control(text
, &cert
->pCertInfo
->NotAfter
);
857 add_unformatted_text_to_control(text
, &nl
, 1);
860 static void set_general_info(HWND hwnd
,
861 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
)
863 set_cert_info(hwnd
, pCertViewInfo
);
864 set_cert_name_string(hwnd
, pCertViewInfo
->pCertContext
, 0,
865 IDS_SUBJECT_HEADING
);
866 set_cert_name_string(hwnd
, pCertViewInfo
->pCertContext
,
867 CERT_NAME_ISSUER_FLAG
, IDS_ISSUER_HEADING
);
868 set_cert_validity_period(hwnd
, pCertViewInfo
->pCertContext
);
871 static LRESULT CALLBACK
user_notice_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wp
,
876 struct IssuerStatement
*issuerStatement
;
881 text
= GetDlgItem(hwnd
, IDC_USERNOTICE
);
882 issuerStatement
= (struct IssuerStatement
*)lp
;
883 add_unformatted_text_to_control(text
, issuerStatement
->userNotice
,
884 strlenW(issuerStatement
->userNotice
));
885 if (issuerStatement
->cps
)
886 SetWindowLongPtrW(hwnd
, DWLP_USER
, (LPARAM
)issuerStatement
->cps
);
888 EnableWindow(GetDlgItem(hwnd
, IDC_CPS
), FALSE
);
894 EndDialog(hwnd
, IDOK
);
899 IBindCtx
*bctx
= NULL
;
902 CreateBindCtx(0, &bctx
);
903 cps
= (LPWSTR
)GetWindowLongPtrW(hwnd
, DWLP_USER
);
904 HlinkSimpleNavigateToString(cps
, NULL
, NULL
, NULL
, bctx
, NULL
,
905 HLNF_OPENINNEWWINDOW
, 0);
906 IBindCtx_Release(bctx
);
914 static void show_user_notice(HWND hwnd
, struct IssuerStatement
*issuerStatement
)
916 DialogBoxParamW(hInstance
, MAKEINTRESOURCEW(IDD_USERNOTICE
), hwnd
,
917 user_notice_dlg_proc
, (LPARAM
)issuerStatement
);
920 static LRESULT CALLBACK
general_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wp
,
923 PROPSHEETPAGEW
*page
;
924 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
;
926 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd
, msg
, wp
, lp
);
931 page
= (PROPSHEETPAGEW
*)lp
;
932 pCertViewInfo
= (PCCRYPTUI_VIEWCERTIFICATE_STRUCTW
)page
->lParam
;
933 if (pCertViewInfo
->dwFlags
& CRYPTUI_DISABLE_ADDTOSTORE
)
934 ShowWindow(GetDlgItem(hwnd
, IDC_ADDTOSTORE
), FALSE
);
935 EnableWindow(GetDlgItem(hwnd
, IDC_ISSUERSTATEMENT
), FALSE
);
936 set_general_info(hwnd
, pCertViewInfo
);
942 FIXME("call CryptUIWizImport\n");
944 case IDC_ISSUERSTATEMENT
:
946 struct IssuerStatement
*issuerStatement
=
947 (struct IssuerStatement
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
951 if (issuerStatement
->userNotice
)
952 show_user_notice(hwnd
, issuerStatement
);
953 else if (issuerStatement
->cps
)
955 IBindCtx
*bctx
= NULL
;
957 CreateBindCtx(0, &bctx
);
958 HlinkSimpleNavigateToString(issuerStatement
->cps
, NULL
,
959 NULL
, NULL
, bctx
, NULL
, HLNF_OPENINNEWWINDOW
, 0);
960 IBindCtx_Release(bctx
);
971 static UINT CALLBACK
general_callback_proc(HWND hwnd
, UINT msg
,
972 PROPSHEETPAGEW
*page
)
974 struct IssuerStatement
*issuerStatement
;
980 (struct IssuerStatement
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
983 HeapFree(GetProcessHeap(), 0, issuerStatement
->cps
);
984 HeapFree(GetProcessHeap(), 0, issuerStatement
->userNotice
);
985 HeapFree(GetProcessHeap(), 0, issuerStatement
);
992 static void init_general_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
,
993 PROPSHEETPAGEW
*page
)
995 memset(page
, 0, sizeof(PROPSHEETPAGEW
));
996 page
->dwSize
= sizeof(PROPSHEETPAGEW
);
997 page
->dwFlags
= PSP_USECALLBACK
;
998 page
->pfnCallback
= general_callback_proc
;
999 page
->hInstance
= hInstance
;
1000 page
->u
.pszTemplate
= MAKEINTRESOURCEW(IDD_GENERAL
);
1001 page
->pfnDlgProc
= general_dlg_proc
;
1002 page
->lParam
= (LPARAM
)pCertViewInfo
;
1005 typedef WCHAR
* (*field_format_func
)(PCCERT_CONTEXT cert
);
1007 static WCHAR
*field_format_version(PCCERT_CONTEXT cert
)
1009 static const WCHAR fmt
[] = { 'V','%','d',0 };
1010 WCHAR
*buf
= HeapAlloc(GetProcessHeap(), 0, 12 * sizeof(WCHAR
));
1013 sprintfW(buf
, fmt
, cert
->pCertInfo
->dwVersion
);
1017 static WCHAR
*format_hex_string(void *pb
, DWORD cb
)
1019 WCHAR
*buf
= HeapAlloc(GetProcessHeap(), 0, (cb
* 3 + 1) * sizeof(WCHAR
));
1023 static const WCHAR fmt
[] = { '%','0','2','x',' ',0 };
1027 for (i
= 0, ptr
= buf
; i
< cb
; i
++, ptr
+= 3)
1028 sprintfW(ptr
, fmt
, ((BYTE
*)pb
)[i
]);
1033 static WCHAR
*field_format_serial_number(PCCERT_CONTEXT cert
)
1035 return format_hex_string(cert
->pCertInfo
->SerialNumber
.pbData
,
1036 cert
->pCertInfo
->SerialNumber
.cbData
);
1039 static WCHAR
*field_format_issuer(PCCERT_CONTEXT cert
)
1041 return get_cert_name_string(cert
, CERT_NAME_SIMPLE_DISPLAY_TYPE
,
1042 CERT_NAME_ISSUER_FLAG
);
1045 static WCHAR
*field_format_detailed_cert_name(PCERT_NAME_BLOB name
)
1048 DWORD len
= CertNameToStrW(X509_ASN_ENCODING
, name
,
1049 CERT_X500_NAME_STR
| CERT_NAME_STR_CRLF_FLAG
, NULL
, 0);
1053 str
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1055 CertNameToStrW(X509_ASN_ENCODING
, name
,
1056 CERT_X500_NAME_STR
| CERT_NAME_STR_CRLF_FLAG
, str
, len
);
1061 static WCHAR
*field_format_detailed_issuer(PCCERT_CONTEXT cert
, void *param
)
1063 return field_format_detailed_cert_name(&cert
->pCertInfo
->Issuer
);
1066 static WCHAR
*field_format_subject(PCCERT_CONTEXT cert
)
1068 return get_cert_name_string(cert
, CERT_NAME_SIMPLE_DISPLAY_TYPE
, 0);
1071 static WCHAR
*field_format_detailed_subject(PCCERT_CONTEXT cert
, void *param
)
1073 return field_format_detailed_cert_name(&cert
->pCertInfo
->Subject
);
1076 static WCHAR
*format_long_date(const FILETIME
*fileTime
)
1078 WCHAR dateFmt
[80]; /* long enough for LOCALE_SLONGDATE */
1083 /* FIXME: format isn't quite right, want time too */
1084 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT
, LOCALE_SLONGDATE
, dateFmt
,
1085 sizeof(dateFmt
) / sizeof(dateFmt
[0]));
1086 FileTimeToSystemTime(fileTime
, &sysTime
);
1087 len
= GetDateFormatW(LOCALE_SYSTEM_DEFAULT
, 0, &sysTime
, dateFmt
, NULL
, 0);
1090 buf
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1092 GetDateFormatW(LOCALE_SYSTEM_DEFAULT
, 0, &sysTime
, dateFmt
, buf
,
1098 static WCHAR
*field_format_from_date(PCCERT_CONTEXT cert
)
1100 return format_long_date(&cert
->pCertInfo
->NotBefore
);
1103 static WCHAR
*field_format_to_date(PCCERT_CONTEXT cert
)
1105 return format_long_date(&cert
->pCertInfo
->NotAfter
);
1108 static WCHAR
*field_format_public_key(PCCERT_CONTEXT cert
)
1110 PCCRYPT_OID_INFO oidInfo
;
1113 oidInfo
= CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY
,
1114 cert
->pCertInfo
->SubjectPublicKeyInfo
.Algorithm
.pszObjId
, 0);
1117 WCHAR fmt
[MAX_STRING_LEN
];
1119 if (LoadStringW(hInstance
, IDS_FIELD_PUBLIC_KEY_FORMAT
, fmt
,
1120 sizeof(fmt
) / sizeof(fmt
[0])))
1122 /* Allocate the output buffer. Use the number of bytes in the
1123 * public key as a conservative (high) estimate for the number of
1124 * digits in its output.
1125 * The output is of the form (in English)
1126 * "<public key algorithm> (<public key bit length> bits)".
1127 * Ordinarily having two positional parameters in a string is not a
1128 * good idea, but as this isn't a sentence fragment, it shouldn't
1129 * be word-order dependent.
1131 buf
= HeapAlloc(GetProcessHeap(), 0,
1132 (strlenW(fmt
) + strlenW(oidInfo
->pwszName
) +
1133 cert
->pCertInfo
->SubjectPublicKeyInfo
.PublicKey
.cbData
* 8)
1136 sprintfW(buf
, fmt
, oidInfo
->pwszName
,
1137 CertGetPublicKeyLength(X509_ASN_ENCODING
,
1138 &cert
->pCertInfo
->SubjectPublicKeyInfo
));
1144 static WCHAR
*field_format_detailed_public_key(PCCERT_CONTEXT cert
, void *param
)
1146 return format_hex_string(
1147 cert
->pCertInfo
->SubjectPublicKeyInfo
.PublicKey
.pbData
,
1148 cert
->pCertInfo
->SubjectPublicKeyInfo
.PublicKey
.cbData
);
1151 struct field_value_data
;
1154 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
;
1155 BOOL
*pfPropertiesChanged
;
1157 struct field_value_data
*fields
;
1158 HIMAGELIST imageList
;
1161 typedef void (*add_fields_func
)(HWND hwnd
, struct detail_data
*data
);
1163 typedef WCHAR
*(*create_detailed_value_func
)(PCCERT_CONTEXT cert
, void *param
);
1165 struct field_value_data
1167 create_detailed_value_func create
;
1168 LPWSTR detailed_value
;
1172 static void add_field_value_data(struct detail_data
*data
,
1173 create_detailed_value_func create
, void *param
)
1176 data
->fields
= HeapReAlloc(GetProcessHeap(), 0, data
->fields
,
1177 (data
->cFields
+ 1) * sizeof(struct field_value_data
));
1179 data
->fields
= HeapAlloc(GetProcessHeap(), 0,
1180 sizeof(struct field_value_data
));
1183 data
->fields
[data
->cFields
].create
= create
;
1184 data
->fields
[data
->cFields
].detailed_value
= NULL
;
1185 data
->fields
[data
->cFields
].param
= param
;
1190 static void add_field_and_value_to_list(HWND hwnd
, struct detail_data
*data
,
1191 LPWSTR field
, LPWSTR value
, create_detailed_value_func create
, void *param
)
1194 int iItem
= SendMessageW(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1196 item
.mask
= LVIF_TEXT
| LVIF_PARAM
;
1199 item
.pszText
= field
;
1200 item
.lParam
= (LPARAM
)data
;
1201 SendMessageW(hwnd
, LVM_INSERTITEMW
, 0, (LPARAM
)&item
);
1204 item
.pszText
= value
;
1206 SendMessageW(hwnd
, LVM_SETITEMTEXTW
, iItem
, (LPARAM
)&item
);
1208 add_field_value_data(data
, create
, param
);
1211 static void add_string_id_and_value_to_list(HWND hwnd
, struct detail_data
*data
,
1212 int id
, LPWSTR value
, create_detailed_value_func create
, void *param
)
1214 WCHAR buf
[MAX_STRING_LEN
];
1216 LoadStringW(hInstance
, id
, buf
, sizeof(buf
) / sizeof(buf
[0]));
1217 add_field_and_value_to_list(hwnd
, data
, buf
, value
, create
, param
);
1223 field_format_func format
;
1224 create_detailed_value_func create_detailed_value
;
1227 static void add_v1_field(HWND hwnd
, struct detail_data
*data
,
1228 const struct v1_field
*field
)
1230 WCHAR
*val
= field
->format(data
->pCertViewInfo
->pCertContext
);
1234 add_string_id_and_value_to_list(hwnd
, data
, field
->id
, val
,
1235 field
->create_detailed_value
, NULL
);
1236 HeapFree(GetProcessHeap(), 0, val
);
1240 static const struct v1_field v1_fields
[] = {
1241 { IDS_FIELD_VERSION
, field_format_version
, NULL
},
1242 { IDS_FIELD_SERIAL_NUMBER
, field_format_serial_number
, NULL
},
1243 { IDS_FIELD_ISSUER
, field_format_issuer
, field_format_detailed_issuer
},
1244 { IDS_FIELD_VALID_FROM
, field_format_from_date
, NULL
},
1245 { IDS_FIELD_VALID_TO
, field_format_to_date
, NULL
},
1246 { IDS_FIELD_SUBJECT
, field_format_subject
, field_format_detailed_subject
},
1247 { IDS_FIELD_PUBLIC_KEY
, field_format_public_key
,
1248 field_format_detailed_public_key
}
1251 static void add_v1_fields(HWND hwnd
, struct detail_data
*data
)
1254 PCCERT_CONTEXT cert
= data
->pCertViewInfo
->pCertContext
;
1256 /* The last item in v1_fields is the public key, which is not in the loop
1257 * because it's a special case.
1259 for (i
= 0; i
< sizeof(v1_fields
) / sizeof(v1_fields
[0]) - 1; i
++)
1260 add_v1_field(hwnd
, data
, &v1_fields
[i
]);
1261 if (cert
->pCertInfo
->SubjectPublicKeyInfo
.PublicKey
.cbData
)
1262 add_v1_field(hwnd
, data
, &v1_fields
[i
]);
1265 static WCHAR
*crypt_format_extension(PCERT_EXTENSION ext
, DWORD formatStrType
)
1270 if (CryptFormatObject(X509_ASN_ENCODING
, 0, formatStrType
, NULL
,
1271 ext
->pszObjId
, ext
->Value
.pbData
, ext
->Value
.cbData
, NULL
, &size
))
1273 str
= HeapAlloc(GetProcessHeap(), 0, size
);
1274 CryptFormatObject(X509_ASN_ENCODING
, 0, formatStrType
, NULL
,
1275 ext
->pszObjId
, ext
->Value
.pbData
, ext
->Value
.cbData
, str
, &size
);
1280 static WCHAR
*field_format_extension_hex_with_ascii(PCERT_EXTENSION ext
)
1284 if (ext
->Value
.cbData
)
1286 /* The output is formatted as:
1287 * <hex bytes> <ascii bytes>\n
1288 * where <hex bytes> is a string of up to 8 bytes, output as %02x,
1289 * and <ascii bytes> is the ASCII equivalent of each byte, or '.' if
1290 * the byte is not printable.
1291 * So, for example, the extension value consisting of the following
1293 * 0x30,0x14,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x03,
1294 * 0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67
1296 * 30 14 31 12 30 10 06 03 0.1.0...
1297 * 55 04 03 13 09 4a 75 61 U....Jua
1298 * 6e 20 4c 61 6e 67 n Lang
1299 * The allocation size therefore requires:
1300 * - 4 characters per character in an 8-byte line
1301 * (2 for the hex format, one for the space, one for the ASCII value)
1302 * - 3 more characters per 8-byte line (two spaces and a newline)
1303 * - 1 character for the terminating nul
1304 * FIXME: should use a fixed-width font for this
1306 DWORD lines
= (ext
->Value
.cbData
+ 7) / 8;
1308 str
= HeapAlloc(GetProcessHeap(), 0,
1309 (lines
* 8 * 4 + lines
* 3 + 1) * sizeof(WCHAR
));
1312 static const WCHAR fmt
[] = { '%','0','2','x',' ',0 };
1316 for (i
= 0, ptr
= str
; i
< ext
->Value
.cbData
; i
+= 8)
1318 /* Output as hex bytes first */
1319 for (j
= i
; j
< min(i
+ 8, ext
->Value
.cbData
); j
++, ptr
+= 3)
1320 sprintfW(ptr
, fmt
, ext
->Value
.pbData
[j
]);
1321 /* Pad the hex output with spaces for alignment */
1322 if (j
== ext
->Value
.cbData
&& j
% 8)
1324 static const WCHAR pad
[] = { ' ',' ',' ' };
1326 for (; j
% 8; j
++, ptr
+= sizeof(pad
) / sizeof(pad
[0]))
1327 memcpy(ptr
, pad
, sizeof(pad
));
1329 /* The last sprintfW included a space, so just insert one
1330 * more space between the hex bytes and the ASCII output
1333 /* Output as ASCII bytes */
1334 for (j
= i
; j
< min(i
+ 8, ext
->Value
.cbData
); j
++, ptr
++)
1336 if (isprintW(ext
->Value
.pbData
[j
]) &&
1337 !isspaceW(ext
->Value
.pbData
[j
]))
1338 *ptr
= ext
->Value
.pbData
[j
];
1350 static WCHAR
*field_format_detailed_extension(PCCERT_CONTEXT cert
, void *param
)
1352 PCERT_EXTENSION ext
= param
;
1353 LPWSTR str
= crypt_format_extension(ext
,
1354 CRYPT_FORMAT_STR_MULTI_LINE
| CRYPT_FORMAT_STR_NO_HEX
);
1357 str
= field_format_extension_hex_with_ascii(ext
);
1361 static void add_cert_extension_detail(HWND hwnd
, struct detail_data
*data
,
1362 PCERT_EXTENSION ext
)
1364 PCCRYPT_OID_INFO oidInfo
= CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY
,
1366 LPWSTR val
= crypt_format_extension(ext
, 0);
1369 add_field_and_value_to_list(hwnd
, data
, (LPWSTR
)oidInfo
->pwszName
,
1370 val
, field_format_detailed_extension
, ext
);
1373 DWORD len
= strlen(ext
->pszObjId
);
1374 LPWSTR oidW
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
1380 for (i
= 0; i
<= len
; i
++)
1381 oidW
[i
] = ext
->pszObjId
[i
];
1382 add_field_and_value_to_list(hwnd
, data
, oidW
, val
,
1383 field_format_detailed_extension
, ext
);
1384 HeapFree(GetProcessHeap(), 0, oidW
);
1387 HeapFree(GetProcessHeap(), 0, val
);
1390 static void add_all_extensions(HWND hwnd
, struct detail_data
*data
)
1393 PCCERT_CONTEXT cert
= data
->pCertViewInfo
->pCertContext
;
1395 for (i
= 0; i
< cert
->pCertInfo
->cExtension
; i
++)
1396 add_cert_extension_detail(hwnd
, data
, &cert
->pCertInfo
->rgExtension
[i
]);
1399 static void add_critical_extensions(HWND hwnd
, struct detail_data
*data
)
1402 PCCERT_CONTEXT cert
= data
->pCertViewInfo
->pCertContext
;
1404 for (i
= 0; i
< cert
->pCertInfo
->cExtension
; i
++)
1405 if (cert
->pCertInfo
->rgExtension
[i
].fCritical
)
1406 add_cert_extension_detail(hwnd
, data
,
1407 &cert
->pCertInfo
->rgExtension
[i
]);
1410 typedef WCHAR
* (*prop_to_value_func
)(void *pb
, DWORD cb
);
1412 struct prop_id_to_string_id
1416 BOOL prop_is_string
;
1417 prop_to_value_func prop_to_value
;
1420 static WCHAR
*format_enhanced_key_usage_value(void *pb
, DWORD cb
)
1424 ext
.pszObjId
= (LPSTR
)X509_ENHANCED_KEY_USAGE
;
1425 ext
.fCritical
= FALSE
;
1426 ext
.Value
.pbData
= pb
;
1427 ext
.Value
.cbData
= cb
;
1428 return crypt_format_extension(&ext
, 0);
1431 /* Logically the access state should also be checked, and IDC_EDITPROPERTIES
1432 * disabled for read-only certificates, but native doesn't appear to do that.
1434 static const struct prop_id_to_string_id prop_id_map
[] = {
1435 { CERT_HASH_PROP_ID
, IDS_PROP_HASH
, FALSE
, format_hex_string
},
1436 { CERT_FRIENDLY_NAME_PROP_ID
, IDS_PROP_FRIENDLY_NAME
, TRUE
, NULL
},
1437 { CERT_DESCRIPTION_PROP_ID
, IDS_PROP_DESCRIPTION
, TRUE
, NULL
},
1438 { CERT_ENHKEY_USAGE_PROP_ID
, IDS_PROP_ENHKEY_USAGE
, FALSE
,
1439 format_enhanced_key_usage_value
},
1442 static void add_properties(HWND hwnd
, struct detail_data
*data
)
1445 PCCERT_CONTEXT cert
= data
->pCertViewInfo
->pCertContext
;
1447 for (i
= 0; i
< sizeof(prop_id_map
) / sizeof(prop_id_map
[0]); i
++)
1451 if (CertGetCertificateContextProperty(cert
, prop_id_map
[i
].prop
, NULL
,
1457 /* FIXME: MS adds a separate value for the signature hash
1460 pb
= HeapAlloc(GetProcessHeap(), 0, cb
);
1463 if (CertGetCertificateContextProperty(cert
,
1464 prop_id_map
[i
].prop
, pb
, &cb
))
1466 if (prop_id_map
[i
].prop_is_string
)
1469 /* Don't double-free pb */
1473 val
= prop_id_map
[i
].prop_to_value(pb
, cb
);
1475 HeapFree(GetProcessHeap(), 0, pb
);
1477 add_string_id_and_value_to_list(hwnd
, data
, prop_id_map
[i
].id
, val
,
1483 static void add_all_fields(HWND hwnd
, struct detail_data
*data
)
1485 add_v1_fields(hwnd
, data
);
1486 add_all_extensions(hwnd
, data
);
1487 add_properties(hwnd
, data
);
1490 struct selection_list_item
1493 add_fields_func add
;
1496 const struct selection_list_item listItems
[] = {
1497 { IDS_FIELDS_ALL
, add_all_fields
},
1498 { IDS_FIELDS_V1
, add_v1_fields
},
1499 { IDS_FIELDS_EXTENSIONS
, add_all_extensions
},
1500 { IDS_FIELDS_CRITICAL_EXTENSIONS
, add_critical_extensions
},
1501 { IDS_FIELDS_PROPERTIES
, add_properties
},
1504 static void create_show_list(HWND hwnd
, struct detail_data
*data
)
1506 HWND cb
= GetDlgItem(hwnd
, IDC_DETAIL_SELECT
);
1507 WCHAR buf
[MAX_STRING_LEN
];
1510 for (i
= 0; i
< sizeof(listItems
) / sizeof(listItems
[0]); i
++)
1514 LoadStringW(hInstance
, listItems
[i
].id
, buf
,
1515 sizeof(buf
) / sizeof(buf
[0]));
1516 index
= SendMessageW(cb
, CB_INSERTSTRING
, -1, (LPARAM
)buf
);
1517 SendMessageW(cb
, CB_SETITEMDATA
, index
, (LPARAM
)data
);
1519 SendMessageW(cb
, CB_SETCURSEL
, 0, 0);
1522 static void create_listview_columns(HWND hwnd
)
1524 HWND lv
= GetDlgItem(hwnd
, IDC_DETAIL_LIST
);
1526 WCHAR buf
[MAX_STRING_LEN
];
1529 SendMessageW(lv
, LVM_SETEXTENDEDLISTVIEWSTYLE
, 0, LVS_EX_FULLROWSELECT
);
1530 GetWindowRect(lv
, &rc
);
1531 LoadStringW(hInstance
, IDS_FIELD
, buf
, sizeof(buf
) / sizeof(buf
[0]));
1532 column
.mask
= LVCF_WIDTH
| LVCF_TEXT
;
1533 column
.cx
= (rc
.right
- rc
.left
) / 2 - 2;
1534 column
.pszText
= buf
;
1535 SendMessageW(lv
, LVM_INSERTCOLUMNW
, 0, (LPARAM
)&column
);
1536 LoadStringW(hInstance
, IDS_VALUE
, buf
, sizeof(buf
) / sizeof(buf
[0]));
1537 SendMessageW(lv
, LVM_INSERTCOLUMNW
, 1, (LPARAM
)&column
);
1540 static void set_fields_selection(HWND hwnd
, struct detail_data
*data
, int sel
)
1542 HWND list
= GetDlgItem(hwnd
, IDC_DETAIL_LIST
);
1544 if (sel
>= 0 && sel
< sizeof(listItems
) / sizeof(listItems
[0]))
1546 SendMessageW(list
, LVM_DELETEALLITEMS
, 0, 0);
1547 listItems
[sel
].add(list
, data
);
1551 static void create_cert_details_list(HWND hwnd
, struct detail_data
*data
)
1553 create_show_list(hwnd
, data
);
1554 create_listview_columns(hwnd
);
1555 set_fields_selection(hwnd
, data
, 0);
1559 CheckBitmapIndexUnchecked
= 1,
1560 CheckBitmapIndexChecked
= 2,
1561 CheckBitmapIndexDisabledUnchecked
= 3,
1562 CheckBitmapIndexDisabledChecked
= 4
1565 static void add_purpose(HWND hwnd
, LPCSTR oid
)
1567 HWND lv
= GetDlgItem(hwnd
, IDC_CERTIFICATE_USAGES
);
1568 PCRYPT_OID_INFO info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
1569 sizeof(CRYPT_OID_INFO
));
1573 char *oidCopy
= HeapAlloc(GetProcessHeap(), 0, strlen(oid
) + 1);
1579 strcpy(oidCopy
, oid
);
1580 info
->cbSize
= sizeof(CRYPT_OID_INFO
);
1581 info
->pszOID
= oidCopy
;
1582 item
.mask
= LVIF_TEXT
| LVIF_STATE
| LVIF_PARAM
;
1583 item
.state
= INDEXTOSTATEIMAGEMASK(CheckBitmapIndexChecked
);
1584 item
.stateMask
= LVIS_STATEIMAGEMASK
;
1585 item
.iItem
= SendMessageW(lv
, LVM_GETITEMCOUNT
, 0, 0);
1587 item
.lParam
= (LPARAM
)info
;
1588 item
.pszText
= oidCopy
;
1589 SendMessageA(lv
, LVM_INSERTITEMA
, 0, (LPARAM
)&item
);
1592 HeapFree(GetProcessHeap(), 0, info
);
1596 static WCHAR
*get_cert_property_as_string(PCCERT_CONTEXT cert
, DWORD prop
)
1601 if (CertGetCertificateContextProperty(cert
, prop
, NULL
, &cb
))
1603 name
= HeapAlloc(GetProcessHeap(), 0, cb
);
1606 if (!CertGetCertificateContextProperty(cert
, prop
, (LPBYTE
)name
,
1609 HeapFree(GetProcessHeap(), 0, name
);
1617 static void redraw_states(HWND list
, BOOL enabled
)
1619 int items
= SendMessageW(list
, LVM_GETITEMCOUNT
, 0, 0), i
;
1621 for (i
= 0; i
< items
; i
++)
1623 BOOL change
= FALSE
;
1626 state
= SendMessageW(list
, LVM_GETITEMSTATE
, i
, LVIS_STATEIMAGEMASK
);
1627 /* This reverses the INDEXTOSTATEIMAGEMASK shift. There doesn't appear
1628 * to be a handy macro for it.
1633 if (state
== CheckBitmapIndexDisabledChecked
)
1635 state
= CheckBitmapIndexChecked
;
1638 if (state
== CheckBitmapIndexDisabledUnchecked
)
1640 state
= CheckBitmapIndexUnchecked
;
1646 if (state
== CheckBitmapIndexChecked
)
1648 state
= CheckBitmapIndexDisabledChecked
;
1651 if (state
== CheckBitmapIndexUnchecked
)
1653 state
= CheckBitmapIndexDisabledUnchecked
;
1661 item
.state
= INDEXTOSTATEIMAGEMASK(state
);
1662 item
.stateMask
= LVIS_STATEIMAGEMASK
;
1663 SendMessageW(list
, LVM_SETITEMSTATE
, i
, (LPARAM
)&item
);
1669 PurposeEnableAll
= 0,
1671 PurposeEnableSelected
1674 static void select_purposes(HWND hwnd
, PurposeSelection selection
)
1676 HWND lv
= GetDlgItem(hwnd
, IDC_CERTIFICATE_USAGES
);
1680 case PurposeEnableAll
:
1681 case PurposeDisableAll
:
1682 EnableWindow(lv
, FALSE
);
1683 redraw_states(lv
, FALSE
);
1684 EnableWindow(GetDlgItem(hwnd
, IDC_ADD_PURPOSE
), FALSE
);
1686 case PurposeEnableSelected
:
1687 EnableWindow(lv
, TRUE
);
1688 redraw_states(lv
, TRUE
);
1689 EnableWindow(GetDlgItem(hwnd
, IDC_ADD_PURPOSE
), TRUE
);
1693 extern BOOL WINAPI
WTHelperGetKnownUsages(DWORD action
,
1694 PCCRYPT_OID_INFO
**usages
);
1696 static void add_known_usage(HWND lv
, PCCRYPT_OID_INFO info
)
1700 item
.mask
= LVIF_TEXT
| LVIF_STATE
| LVIF_PARAM
;
1701 item
.state
= INDEXTOSTATEIMAGEMASK(CheckBitmapIndexDisabledChecked
);
1702 item
.stateMask
= LVIS_STATEIMAGEMASK
;
1703 item
.iItem
= SendMessageW(lv
, LVM_GETITEMCOUNT
, 0, 0);
1705 item
.lParam
= (LPARAM
)info
;
1706 item
.pszText
= (LPWSTR
)info
->pwszName
;
1707 SendMessageW(lv
, LVM_INSERTITEMW
, 0, (LPARAM
)&item
);
1710 static void show_cert_usages(HWND hwnd
, struct detail_data
*data
)
1712 PCCERT_CONTEXT cert
= data
->pCertViewInfo
->pCertContext
;
1713 HWND lv
= GetDlgItem(hwnd
, IDC_CERTIFICATE_USAGES
);
1714 PCERT_ENHKEY_USAGE usage
;
1716 PCCRYPT_OID_INFO
*usages
;
1720 GetWindowRect(lv
, &rc
);
1721 column
.mask
= LVCF_WIDTH
;
1722 column
.cx
= rc
.right
- rc
.left
;
1723 SendMessageW(lv
, LVM_INSERTCOLUMNW
, 0, (LPARAM
)&column
);
1724 SendMessageW(lv
, LVM_SETIMAGELIST
, LVSIL_STATE
, (LPARAM
)data
->imageList
);
1726 /* Get enhanced key usage. Have to check for a property and an extension
1727 * separately, because CertGetEnhancedKeyUsage will succeed and return an
1728 * empty usage if neither is set. Unfortunately an empty usage implies
1729 * no usage is allowed, so we have to distinguish between the two cases.
1731 if (CertGetEnhancedKeyUsage(cert
, CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG
,
1734 usage
= HeapAlloc(GetProcessHeap(), 0, size
);
1735 if (!CertGetEnhancedKeyUsage(cert
,
1736 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG
, usage
, &size
))
1738 HeapFree(GetProcessHeap(), 0, usage
);
1742 else if (CertGetEnhancedKeyUsage(cert
, CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG
,
1745 usage
= HeapAlloc(GetProcessHeap(), 0, size
);
1746 if (!CertGetEnhancedKeyUsage(cert
,
1747 CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG
, usage
, &size
))
1749 HeapFree(GetProcessHeap(), 0, usage
);
1759 for (i
= 0; i
< usage
->cUsageIdentifier
; i
++)
1761 PCCRYPT_OID_INFO info
= CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY
,
1762 usage
->rgpszUsageIdentifier
[i
], CRYPT_ENHKEY_USAGE_OID_GROUP_ID
);
1765 add_known_usage(lv
, info
);
1767 add_purpose(hwnd
, usage
->rgpszUsageIdentifier
[i
]);
1769 HeapFree(GetProcessHeap(), 0, usage
);
1773 if (WTHelperGetKnownUsages(1, &usages
))
1775 PCCRYPT_OID_INFO
*ptr
;
1777 for (ptr
= usages
; *ptr
; ptr
++)
1778 add_known_usage(lv
, *ptr
);
1779 WTHelperGetKnownUsages(2, &usages
);
1782 select_purposes(hwnd
, PurposeEnableAll
);
1785 static void set_general_cert_properties(HWND hwnd
, struct detail_data
*data
)
1787 PCCERT_CONTEXT cert
= data
->pCertViewInfo
->pCertContext
;
1790 if ((str
= get_cert_property_as_string(cert
, CERT_FRIENDLY_NAME_PROP_ID
)))
1792 SendMessageW(GetDlgItem(hwnd
, IDC_FRIENDLY_NAME
), WM_SETTEXT
, 0,
1794 HeapFree(GetProcessHeap(), 0, str
);
1796 if ((str
= get_cert_property_as_string(cert
, CERT_DESCRIPTION_PROP_ID
)))
1798 SendMessageW(GetDlgItem(hwnd
, IDC_DESCRIPTION
), WM_SETTEXT
, 0,
1800 HeapFree(GetProcessHeap(), 0, str
);
1802 show_cert_usages(hwnd
, data
);
1803 SendMessageW(GetDlgItem(hwnd
, IDC_ENABLE_ALL_PURPOSES
), BM_CLICK
, 0, 0);
1806 #define MAX_FRIENDLY_NAME 40
1807 #define MAX_DESCRIPTION 255
1809 static LRESULT CALLBACK
cert_properties_general_dlg_proc(HWND hwnd
, UINT msg
,
1810 WPARAM wp
, LPARAM lp
)
1812 PROPSHEETPAGEW
*page
;
1813 struct detail_data
*data
;
1815 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd
, msg
, wp
, lp
);
1821 HWND description
= GetDlgItem(hwnd
, IDC_DESCRIPTION
);
1823 page
= (PROPSHEETPAGEW
*)lp
;
1824 data
= (struct detail_data
*)page
->lParam
;
1825 SendMessageW(GetDlgItem(hwnd
, IDC_FRIENDLY_NAME
), EM_SETLIMITTEXT
,
1826 MAX_FRIENDLY_NAME
, 0);
1827 SendMessageW(description
, EM_SETLIMITTEXT
, MAX_DESCRIPTION
, 0);
1828 ShowScrollBar(description
, SB_VERT
, FALSE
);
1829 set_general_cert_properties(hwnd
, data
);
1830 SetWindowLongPtrW(hwnd
, DWLP_USER
, (LPARAM
)data
);
1837 SendMessageW(GetParent(hwnd
), PSM_CHANGED
, (WPARAM
)hwnd
, 0);
1838 if (LOWORD(wp
) == IDC_DESCRIPTION
)
1840 /* Show/hide scroll bar on description depending on how much
1843 HWND description
= GetDlgItem(hwnd
, IDC_DESCRIPTION
);
1844 int lines
= SendMessageW(description
, EM_GETLINECOUNT
, 0, 0);
1846 ShowScrollBar(description
, SB_VERT
, lines
> 1);
1852 case IDC_ENABLE_ALL_PURPOSES
:
1853 case IDC_DISABLE_ALL_PURPOSES
:
1854 case IDC_ENABLE_SELECTED_PURPOSES
:
1855 SendMessageW(GetParent(hwnd
), PSM_CHANGED
, (WPARAM
)hwnd
, 0);
1856 select_purposes(hwnd
, LOWORD(wp
) - IDC_ENABLE_ALL_PURPOSES
);
1866 static UINT CALLBACK
cert_properties_general_callback(HWND hwnd
, UINT msg
,
1867 PROPSHEETPAGEW
*page
)
1875 lv
= GetDlgItem(hwnd
, IDC_CERTIFICATE_USAGES
);
1876 cItem
= SendMessageW(lv
, LVM_GETITEMCOUNT
, 0, 0);
1877 for (i
= 0; i
< cItem
; i
++)
1881 item
.mask
= LVIF_PARAM
;
1884 if (SendMessageW(lv
, LVM_GETITEMW
, 0, (LPARAM
)&item
) && item
.lParam
)
1886 PCRYPT_OID_INFO info
= (PCRYPT_OID_INFO
)item
.lParam
;
1888 if (info
->cbSize
== sizeof(CRYPT_OID_INFO
) && !info
->dwGroupId
)
1890 HeapFree(GetProcessHeap(), 0, (LPSTR
)info
->pszOID
);
1891 HeapFree(GetProcessHeap(), 0, info
);
1900 static void show_edit_cert_properties_dialog(HWND parent
,
1901 struct detail_data
*data
)
1903 PROPSHEETHEADERW hdr
;
1904 PROPSHEETPAGEW page
; /* FIXME: need to add a cross-certificate page */
1906 TRACE("(%p)\n", data
);
1908 memset(&page
, 0, sizeof(PROPSHEETPAGEW
));
1909 page
.dwSize
= sizeof(page
);
1910 page
.dwFlags
= PSP_USECALLBACK
;
1911 page
.pfnCallback
= cert_properties_general_callback
;
1912 page
.hInstance
= hInstance
;
1913 page
.u
.pszTemplate
= MAKEINTRESOURCEW(IDD_CERT_PROPERTIES_GENERAL
);
1914 page
.pfnDlgProc
= cert_properties_general_dlg_proc
;
1915 page
.lParam
= (LPARAM
)data
;
1917 memset(&hdr
, 0, sizeof(hdr
));
1918 hdr
.dwSize
= sizeof(hdr
);
1919 hdr
.hwndParent
= parent
;
1920 hdr
.dwFlags
= PSH_PROPSHEETPAGE
;
1921 hdr
.hInstance
= hInstance
;
1922 hdr
.pszCaption
= MAKEINTRESOURCEW(IDS_CERTIFICATE_PROPERTIES
);
1923 hdr
.u3
.ppsp
= &page
;
1925 PropertySheetW(&hdr
);
1928 static void free_detail_fields(struct detail_data
*data
)
1932 for (i
= 0; i
< data
->cFields
; i
++)
1933 HeapFree(GetProcessHeap(), 0, data
->fields
[i
].detailed_value
);
1934 HeapFree(GetProcessHeap(), 0, data
->fields
);
1935 data
->fields
= NULL
;
1939 static void refresh_details_view(HWND hwnd
)
1941 HWND cb
= GetDlgItem(hwnd
, IDC_DETAIL_SELECT
);
1943 struct detail_data
*data
;
1945 curSel
= SendMessageW(cb
, CB_GETCURSEL
, 0, 0);
1946 /* Actually, any index will do, since they all store the same data value */
1947 data
= (struct detail_data
*)SendMessageW(cb
, CB_GETITEMDATA
, curSel
, 0);
1948 free_detail_fields(data
);
1949 set_fields_selection(hwnd
, data
, curSel
);
1952 static LRESULT CALLBACK
detail_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wp
,
1955 PROPSHEETPAGEW
*page
;
1956 struct detail_data
*data
;
1958 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd
, msg
, wp
, lp
);
1963 page
= (PROPSHEETPAGEW
*)lp
;
1964 data
= (struct detail_data
*)page
->lParam
;
1965 create_cert_details_list(hwnd
, data
);
1966 if (!(data
->pCertViewInfo
->dwFlags
& CRYPTUI_ENABLE_EDITPROPERTIES
))
1967 EnableWindow(GetDlgItem(hwnd
, IDC_EDITPROPERTIES
), FALSE
);
1968 if (data
->pCertViewInfo
->dwFlags
& CRYPTUI_DISABLE_EXPORT
)
1969 EnableWindow(GetDlgItem(hwnd
, IDC_EXPORT
), FALSE
);
1974 HWND list
= GetDlgItem(hwnd
, IDC_DETAIL_LIST
);
1976 nm
= (NMITEMACTIVATE
*)lp
;
1977 if (nm
->hdr
.hwndFrom
== list
&& nm
->uNewState
& LVN_ITEMACTIVATE
1978 && nm
->hdr
.code
== LVN_ITEMCHANGED
)
1980 data
= (struct detail_data
*)nm
->lParam
;
1981 if (nm
->iItem
>= 0 && data
&& nm
->iItem
< data
->cFields
)
1983 WCHAR buf
[MAX_STRING_LEN
], *val
= NULL
;
1984 HWND valueCtl
= GetDlgItem(hwnd
, IDC_DETAIL_VALUE
);
1986 if (data
->fields
[nm
->iItem
].create
)
1987 val
= data
->fields
[nm
->iItem
].create(
1988 data
->pCertViewInfo
->pCertContext
,
1989 data
->fields
[nm
->iItem
].param
);
1995 item
.cchTextMax
= sizeof(buf
) / sizeof(buf
[0]);
1996 item
.mask
= LVIF_TEXT
;
1998 item
.iItem
= nm
->iItem
;
2000 res
= SendMessageW(list
, LVM_GETITEMW
, 0, (LPARAM
)&item
);
2004 /* Select all the text in the control, the next update will
2007 SendMessageW(valueCtl
, EM_SETSEL
, 0, -1);
2008 add_unformatted_text_to_control(valueCtl
, val
,
2009 val
? strlenW(val
) : 0);
2011 HeapFree(GetProcessHeap(), 0, val
);
2020 FIXME("call CryptUIWizExport\n");
2022 case IDC_EDITPROPERTIES
:
2024 HWND cb
= GetDlgItem(hwnd
, IDC_DETAIL_SELECT
);
2027 curSel
= SendMessageW(cb
, CB_GETCURSEL
, 0, 0);
2028 /* Actually, any index will do, since they all store the same
2031 data
= (struct detail_data
*)SendMessageW(cb
, CB_GETITEMDATA
,
2033 show_edit_cert_properties_dialog(GetParent(hwnd
), data
);
2036 case ((CBN_SELCHANGE
<< 16) | IDC_DETAIL_SELECT
):
2037 refresh_details_view(hwnd
);
2045 static UINT CALLBACK
detail_callback(HWND hwnd
, UINT msg
,
2046 PROPSHEETPAGEW
*page
)
2048 struct detail_data
*data
;
2053 data
= (struct detail_data
*)page
->lParam
;
2054 free_detail_fields(data
);
2055 ImageList_Destroy(data
->imageList
);
2056 HeapFree(GetProcessHeap(), 0, data
);
2062 static BOOL
init_detail_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
,
2063 BOOL
*pfPropertiesChanged
, PROPSHEETPAGEW
*page
)
2066 struct detail_data
*data
= HeapAlloc(GetProcessHeap(), 0,
2067 sizeof(struct detail_data
));
2071 data
->pCertViewInfo
= pCertViewInfo
;
2072 data
->pfPropertiesChanged
= pfPropertiesChanged
;
2074 data
->fields
= NULL
;
2075 data
->imageList
= ImageList_Create(16, 16, ILC_COLOR4
| ILC_MASK
, 4, 0);
2076 if (data
->imageList
)
2079 COLORREF backColor
= RGB(255, 0, 255);
2081 bmp
= LoadBitmapW(hInstance
, MAKEINTRESOURCEW(IDB_CHECKS
));
2082 ImageList_AddMasked(data
->imageList
, bmp
, backColor
);
2084 ImageList_SetBkColor(data
->imageList
, CLR_NONE
);
2086 memset(page
, 0, sizeof(PROPSHEETPAGEW
));
2087 page
->dwSize
= sizeof(PROPSHEETPAGEW
);
2088 page
->dwFlags
= PSP_USECALLBACK
;
2089 page
->pfnCallback
= detail_callback
;
2090 page
->hInstance
= hInstance
;
2091 page
->u
.pszTemplate
= MAKEINTRESOURCEW(IDD_DETAIL
);
2092 page
->pfnDlgProc
= detail_dlg_proc
;
2093 page
->lParam
= (LPARAM
)data
;
2101 struct hierarchy_data
2103 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
;
2104 HIMAGELIST imageList
;
2108 static LPARAM
index_to_lparam(struct hierarchy_data
*data
, DWORD index
)
2110 CRYPT_PROVIDER_SGNR
*provSigner
= WTHelperGetProvSignerFromChain(
2111 (CRYPT_PROVIDER_DATA
*)data
->pCertViewInfo
->u
.pCryptProviderData
,
2112 data
->pCertViewInfo
->idxSigner
, data
->pCertViewInfo
->fCounterSigner
,
2113 data
->pCertViewInfo
->idxCounterSigner
);
2115 /* Takes advantage of the fact that a pointer is 32-bit aligned, and
2116 * therefore always even.
2118 if (index
== provSigner
->csCertChain
- 1)
2119 return (LPARAM
)data
;
2120 return index
<< 1 | 1;
2123 static inline DWORD
lparam_to_index(struct hierarchy_data
*data
, LPARAM lp
)
2125 CRYPT_PROVIDER_SGNR
*provSigner
= WTHelperGetProvSignerFromChain(
2126 (CRYPT_PROVIDER_DATA
*)data
->pCertViewInfo
->u
.pCryptProviderData
,
2127 data
->pCertViewInfo
->idxSigner
, data
->pCertViewInfo
->fCounterSigner
,
2128 data
->pCertViewInfo
->idxCounterSigner
);
2131 return provSigner
->csCertChain
- 1;
2135 static struct hierarchy_data
*get_hierarchy_data_from_tree_item(HWND tree
,
2138 struct hierarchy_data
*data
= NULL
;
2139 HTREEITEM root
= NULL
;
2142 HTREEITEM parent
= (HTREEITEM
)SendMessageW(tree
, TVM_GETNEXTITEM
,
2143 TVGN_PARENT
, (LPARAM
)hItem
);
2153 item
.mask
= TVIF_PARAM
;
2155 SendMessageW(tree
, TVM_GETITEMW
, 0, (LPARAM
)&item
);
2156 data
= (struct hierarchy_data
*)item
.lParam
;
2161 static WCHAR
*get_cert_display_name(PCCERT_CONTEXT cert
)
2163 WCHAR
*name
= get_cert_property_as_string(cert
, CERT_FRIENDLY_NAME_PROP_ID
);
2166 name
= get_cert_name_string(cert
, CERT_NAME_SIMPLE_DISPLAY_TYPE
, 0);
2170 static void show_cert_chain(HWND hwnd
, struct hierarchy_data
*data
)
2172 HWND tree
= GetDlgItem(hwnd
, IDC_CERTPATH
);
2173 CRYPT_PROVIDER_SGNR
*provSigner
= WTHelperGetProvSignerFromChain(
2174 (CRYPT_PROVIDER_DATA
*)data
->pCertViewInfo
->u
.pCryptProviderData
,
2175 data
->pCertViewInfo
->idxSigner
, data
->pCertViewInfo
->fCounterSigner
,
2176 data
->pCertViewInfo
->idxCounterSigner
);
2178 HTREEITEM parent
= NULL
;
2180 SendMessageW(tree
, TVM_SETIMAGELIST
, TVSIL_NORMAL
, (LPARAM
)data
->imageList
);
2181 for (i
= provSigner
->csCertChain
; i
; i
--)
2185 name
= get_cert_display_name(provSigner
->pasCertChain
[i
- 1].pCert
);
2188 TVINSERTSTRUCTW tvis
;
2190 tvis
.hParent
= parent
;
2191 tvis
.hInsertAfter
= TVI_LAST
;
2192 tvis
.u
.item
.mask
= TVIF_TEXT
| TVIF_STATE
| TVIF_IMAGE
|
2193 TVIF_SELECTEDIMAGE
| TVIF_PARAM
;
2194 tvis
.u
.item
.pszText
= name
;
2195 tvis
.u
.item
.state
= TVIS_EXPANDED
;
2196 tvis
.u
.item
.stateMask
= TVIS_EXPANDED
;
2198 (provSigner
->pChainContext
->TrustStatus
.dwErrorStatus
&
2199 CERT_TRUST_IS_PARTIAL_CHAIN
))
2201 /* The root of the chain has a special case: if the chain is
2202 * a partial chain, the icon is a warning icon rather than an
2205 tvis
.u
.item
.iImage
= 2;
2207 else if (provSigner
->pasCertChain
[i
- 1].pChainElement
->TrustStatus
.
2209 tvis
.u
.item
.iImage
= 0;
2211 tvis
.u
.item
.iImage
= 1;
2212 tvis
.u
.item
.iSelectedImage
= tvis
.u
.item
.iImage
;
2213 tvis
.u
.item
.lParam
= index_to_lparam(data
, i
- 1);
2214 parent
= (HTREEITEM
)SendMessageW(tree
, TVM_INSERTITEMW
, 0,
2216 HeapFree(GetProcessHeap(), 0, name
);
2221 static void set_certificate_status(HWND hwnd
, CRYPT_PROVIDER_CERT
*cert
)
2223 /* Select all the text in the control, the next update will replace it */
2224 SendMessageW(hwnd
, EM_SETSEL
, 0, -1);
2225 /* Set the highest priority error messages first. */
2226 if (!(cert
->dwConfidence
& CERT_CONFIDENCE_SIG
))
2227 add_string_resource_to_control(hwnd
, IDS_CERTIFICATE_BAD_SIGNATURE
);
2228 else if (!(cert
->dwConfidence
& CERT_CONFIDENCE_TIME
))
2229 add_string_resource_to_control(hwnd
, IDS_CERTIFICATE_BAD_TIME
);
2230 else if (!(cert
->dwConfidence
& CERT_CONFIDENCE_TIMENEST
))
2231 add_string_resource_to_control(hwnd
, IDS_CERTIFICATE_BAD_TIMENEST
);
2232 else if (cert
->dwRevokedReason
)
2233 add_string_resource_to_control(hwnd
, IDS_CERTIFICATE_REVOKED
);
2235 add_string_resource_to_control(hwnd
, IDS_CERTIFICATE_VALID
);
2238 static void set_certificate_status_for_end_cert(HWND hwnd
,
2239 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
)
2241 HWND status
= GetDlgItem(hwnd
, IDC_CERTIFICATESTATUSTEXT
);
2242 CRYPT_PROVIDER_SGNR
*provSigner
= WTHelperGetProvSignerFromChain(
2243 (CRYPT_PROVIDER_DATA
*)pCertViewInfo
->u
.pCryptProviderData
,
2244 pCertViewInfo
->idxSigner
, pCertViewInfo
->fCounterSigner
,
2245 pCertViewInfo
->idxCounterSigner
);
2246 CRYPT_PROVIDER_CERT
*provCert
= WTHelperGetProvCertFromChain(provSigner
,
2247 pCertViewInfo
->idxCert
);
2249 set_certificate_status(status
, provCert
);
2252 static void show_cert_hierarchy(HWND hwnd
, struct hierarchy_data
*data
)
2254 /* Disable view certificate button until a certificate is selected */
2255 EnableWindow(GetDlgItem(hwnd
, IDC_VIEWCERTIFICATE
), FALSE
);
2256 show_cert_chain(hwnd
, data
);
2257 set_certificate_status_for_end_cert(hwnd
, data
->pCertViewInfo
);
2260 static void show_dialog_for_selected_cert(HWND hwnd
)
2262 HWND tree
= GetDlgItem(hwnd
, IDC_CERTPATH
);
2264 struct hierarchy_data
*data
;
2267 memset(&item
, 0, sizeof(item
));
2268 item
.mask
= TVIF_HANDLE
| TVIF_PARAM
;
2269 item
.hItem
= (HTREEITEM
)SendMessageW(tree
, TVM_GETNEXTITEM
, TVGN_CARET
,
2271 SendMessageW(tree
, TVM_GETITEMW
, 0, (LPARAM
)&item
);
2272 data
= get_hierarchy_data_from_tree_item(tree
, item
.hItem
);
2273 selection
= lparam_to_index(data
, item
.lParam
);
2276 CRYPT_PROVIDER_SGNR
*provSigner
;
2277 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo
;
2278 BOOL changed
= FALSE
;
2280 provSigner
= WTHelperGetProvSignerFromChain(
2281 (CRYPT_PROVIDER_DATA
*)data
->pCertViewInfo
->u
.pCryptProviderData
,
2282 data
->pCertViewInfo
->idxSigner
,
2283 data
->pCertViewInfo
->fCounterSigner
,
2284 data
->pCertViewInfo
->idxCounterSigner
);
2285 memset(&viewInfo
, 0, sizeof(viewInfo
));
2286 viewInfo
.dwSize
= sizeof(viewInfo
);
2287 viewInfo
.dwFlags
= data
->pCertViewInfo
->dwFlags
;
2288 viewInfo
.szTitle
= data
->pCertViewInfo
->szTitle
;
2289 viewInfo
.pCertContext
= provSigner
->pasCertChain
[selection
].pCert
;
2290 viewInfo
.cStores
= data
->pCertViewInfo
->cStores
;
2291 viewInfo
.rghStores
= data
->pCertViewInfo
->rghStores
;
2292 viewInfo
.cPropSheetPages
= data
->pCertViewInfo
->cPropSheetPages
;
2293 viewInfo
.rgPropSheetPages
= data
->pCertViewInfo
->rgPropSheetPages
;
2294 viewInfo
.nStartPage
= data
->pCertViewInfo
->nStartPage
;
2295 CryptUIDlgViewCertificateW(&viewInfo
, &changed
);
2298 /* Delete the contents of the tree */
2299 SendMessageW(tree
, TVM_DELETEITEM
, 0, (LPARAM
)TVI_ROOT
);
2300 /* Reinitialize the tree */
2301 show_cert_hierarchy(hwnd
, data
);
2306 static LRESULT CALLBACK
hierarchy_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wp
,
2309 PROPSHEETPAGEW
*page
;
2310 struct hierarchy_data
*data
;
2313 TRACE("(%p, %08x, %08lx, %08lx)\n", hwnd
, msg
, wp
, lp
);
2318 page
= (PROPSHEETPAGEW
*)lp
;
2319 data
= (struct hierarchy_data
*)page
->lParam
;
2320 show_cert_hierarchy(hwnd
, data
);
2329 case TVN_SELCHANGEDW
:
2331 NMTREEVIEWW
*nm
= (NMTREEVIEWW
*)lp
;
2332 HWND tree
= GetDlgItem(hwnd
, IDC_CERTPATH
);
2334 CRYPT_PROVIDER_SGNR
*provSigner
;
2336 data
= get_hierarchy_data_from_tree_item(tree
, nm
->itemNew
.hItem
);
2337 selection
= lparam_to_index(data
, nm
->itemNew
.lParam
);
2338 provSigner
= WTHelperGetProvSignerFromChain(
2339 (CRYPT_PROVIDER_DATA
*)data
->pCertViewInfo
->u
.pCryptProviderData
,
2340 data
->pCertViewInfo
->idxSigner
,
2341 data
->pCertViewInfo
->fCounterSigner
,
2342 data
->pCertViewInfo
->idxCounterSigner
);
2343 EnableWindow(GetDlgItem(hwnd
, IDC_VIEWCERTIFICATE
), selection
!= 0);
2344 set_certificate_status(GetDlgItem(hwnd
, IDC_CERTIFICATESTATUSTEXT
),
2345 &provSigner
->pasCertChain
[selection
]);
2349 show_dialog_for_selected_cert(hwnd
);
2350 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, 1);
2359 case IDC_VIEWCERTIFICATE
:
2360 show_dialog_for_selected_cert(hwnd
);
2368 static UINT CALLBACK
hierarchy_callback(HWND hwnd
, UINT msg
,
2369 PROPSHEETPAGEW
*page
)
2371 struct hierarchy_data
*data
;
2376 data
= (struct hierarchy_data
*)page
->lParam
;
2377 ImageList_Destroy(data
->imageList
);
2378 HeapFree(GetProcessHeap(), 0, data
);
2384 static BOOL
init_hierarchy_page(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
,
2385 PROPSHEETPAGEW
*page
)
2387 struct hierarchy_data
*data
= HeapAlloc(GetProcessHeap(), 0,
2388 sizeof(struct hierarchy_data
));
2393 data
->imageList
= ImageList_Create(16, 16, ILC_COLOR4
| ILC_MASK
, 2, 0);
2394 if (data
->imageList
)
2397 COLORREF backColor
= RGB(255, 0, 255);
2399 data
->pCertViewInfo
= pCertViewInfo
;
2400 data
->selectedCert
= 0xffffffff;
2402 bmp
= LoadBitmapW(hInstance
, MAKEINTRESOURCEW(IDB_SMALL_ICONS
));
2403 ImageList_AddMasked(data
->imageList
, bmp
, backColor
);
2405 ImageList_SetBkColor(data
->imageList
, CLR_NONE
);
2407 memset(page
, 0, sizeof(PROPSHEETPAGEW
));
2408 page
->dwSize
= sizeof(PROPSHEETPAGEW
);
2409 page
->dwFlags
= PSP_USECALLBACK
;
2410 page
->hInstance
= hInstance
;
2411 page
->u
.pszTemplate
= MAKEINTRESOURCEW(IDD_HIERARCHY
);
2412 page
->pfnDlgProc
= hierarchy_dlg_proc
;
2413 page
->lParam
= (LPARAM
)data
;
2414 page
->pfnCallback
= hierarchy_callback
;
2418 HeapFree(GetProcessHeap(), 0, data
);
2423 static int CALLBACK
cert_prop_sheet_proc(HWND hwnd
, UINT msg
, LPARAM lp
)
2428 TRACE("(%p, %08x, %08lx)\n", hwnd
, msg
, lp
);
2432 case PSCB_INITIALIZED
:
2433 /* Get cancel button's position.. */
2434 GetWindowRect(GetDlgItem(hwnd
, IDCANCEL
), &rc
);
2435 topLeft
.x
= rc
.left
;
2437 ScreenToClient(hwnd
, &topLeft
);
2438 /* hide the cancel button.. */
2439 ShowWindow(GetDlgItem(hwnd
, IDCANCEL
), FALSE
);
2440 /* get the OK button's size.. */
2441 GetWindowRect(GetDlgItem(hwnd
, IDOK
), &rc
);
2442 /* and move the OK button to the cancel button's original position. */
2443 MoveWindow(GetDlgItem(hwnd
, IDOK
), topLeft
.x
, topLeft
.y
,
2444 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, FALSE
);
2445 GetWindowRect(GetDlgItem(hwnd
, IDOK
), &rc
);
2451 static BOOL
show_cert_dialog(PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
,
2452 CRYPT_PROVIDER_CERT
*provCert
, BOOL
*pfPropertiesChanged
)
2454 static const WCHAR riched
[] = { 'r','i','c','h','e','d','2','0',0 };
2456 PROPSHEETPAGEW
*pages
;
2458 HMODULE lib
= LoadLibraryW(riched
);
2460 nPages
= pCertViewInfo
->cPropSheetPages
+ 1; /* one for the General tab */
2461 if (!(pCertViewInfo
->dwFlags
& CRYPTUI_HIDE_DETAILPAGE
))
2463 if (!(pCertViewInfo
->dwFlags
& CRYPTUI_HIDE_HIERARCHYPAGE
))
2465 pages
= HeapAlloc(GetProcessHeap(), 0, nPages
* sizeof(PROPSHEETPAGEW
));
2468 PROPSHEETHEADERW hdr
;
2469 CRYPTUI_INITDIALOG_STRUCT
*init
= NULL
;
2472 memset(&hdr
, 0, sizeof(hdr
));
2473 hdr
.dwSize
= sizeof(hdr
);
2474 hdr
.dwFlags
= PSH_NOAPPLYNOW
| PSH_PROPSHEETPAGE
| PSH_USECALLBACK
;
2475 hdr
.hInstance
= hInstance
;
2476 if (pCertViewInfo
->szTitle
)
2477 hdr
.pszCaption
= pCertViewInfo
->szTitle
;
2479 hdr
.pszCaption
= MAKEINTRESOURCEW(IDS_CERTIFICATE
);
2480 init_general_page(pCertViewInfo
, &pages
[hdr
.nPages
++]);
2481 if (!(pCertViewInfo
->dwFlags
& CRYPTUI_HIDE_DETAILPAGE
))
2483 if (init_detail_page(pCertViewInfo
, pfPropertiesChanged
,
2484 &pages
[hdr
.nPages
]))
2487 if (!(pCertViewInfo
->dwFlags
& CRYPTUI_HIDE_HIERARCHYPAGE
))
2489 if (init_hierarchy_page(pCertViewInfo
, &pages
[hdr
.nPages
]))
2492 /* Copy each additional page, and create the init dialog struct for it
2494 if (pCertViewInfo
->cPropSheetPages
)
2496 init
= HeapAlloc(GetProcessHeap(), 0,
2497 pCertViewInfo
->cPropSheetPages
*
2498 sizeof(CRYPTUI_INITDIALOG_STRUCT
));
2501 for (i
= 0; i
< pCertViewInfo
->cPropSheetPages
; i
++)
2503 memcpy(&pages
[hdr
.nPages
+ i
],
2504 &pCertViewInfo
->rgPropSheetPages
[i
],
2505 sizeof(PROPSHEETPAGEW
));
2506 init
[i
].lParam
= pCertViewInfo
->rgPropSheetPages
[i
].lParam
;
2507 init
[i
].pCertContext
= pCertViewInfo
->pCertContext
;
2508 pages
[hdr
.nPages
+ i
].lParam
= (LPARAM
)&init
[i
];
2510 if (pCertViewInfo
->nStartPage
& 0x8000)
2512 /* Start page index is relative to the number of default
2515 hdr
.u2
.nStartPage
= pCertViewInfo
->nStartPage
+ hdr
.nPages
;
2518 hdr
.u2
.nStartPage
= pCertViewInfo
->nStartPage
;
2519 hdr
.nPages
= nPages
;
2523 SetLastError(ERROR_OUTOFMEMORY
);
2527 /* Ignore the relative flag if there aren't any additional pages */
2528 hdr
.u2
.nStartPage
= pCertViewInfo
->nStartPage
& 0x7fff;
2535 hdr
.u3
.ppsp
= pages
;
2536 hdr
.pfnCallback
= cert_prop_sheet_proc
;
2537 l
= PropertySheetW(&hdr
);
2540 SetLastError(ERROR_CANCELLED
);
2544 HeapFree(GetProcessHeap(), 0, init
);
2545 HeapFree(GetProcessHeap(), 0, pages
);
2548 SetLastError(ERROR_OUTOFMEMORY
);
2553 /***********************************************************************
2554 * CryptUIDlgViewCertificateW (CRYPTUI.@)
2556 BOOL WINAPI
CryptUIDlgViewCertificateW(
2557 PCCRYPTUI_VIEWCERTIFICATE_STRUCTW pCertViewInfo
, BOOL
*pfPropertiesChanged
)
2559 static GUID generic_cert_verify
= WINTRUST_ACTION_GENERIC_CERT_VERIFY
;
2560 CRYPTUI_VIEWCERTIFICATE_STRUCTW viewInfo
;
2562 WINTRUST_CERT_INFO cert
;
2564 CRYPT_PROVIDER_SGNR
*signer
;
2565 CRYPT_PROVIDER_CERT
*provCert
= NULL
;
2567 TRACE("(%p, %p)\n", pCertViewInfo
, pfPropertiesChanged
);
2569 if (pCertViewInfo
->dwSize
!= sizeof(CRYPTUI_VIEWCERTIFICATE_STRUCTW
))
2571 SetLastError(ERROR_INVALID_PARAMETER
);
2574 /* Make a local copy in case we have to call WinVerifyTrust ourselves */
2575 memcpy(&viewInfo
, pCertViewInfo
, sizeof(viewInfo
));
2576 if (!viewInfo
.u
.hWVTStateData
)
2578 memset(&wvt
, 0, sizeof(wvt
));
2579 wvt
.cbStruct
= sizeof(wvt
);
2580 wvt
.dwUIChoice
= WTD_UI_NONE
;
2581 if (viewInfo
.dwFlags
&
2582 CRYPTUI_ENABLE_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT
)
2583 wvt
.fdwRevocationChecks
|= WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT
;
2584 if (viewInfo
.dwFlags
& CRYPTUI_ENABLE_REVOCATION_CHECK_END_CERT
)
2585 wvt
.fdwRevocationChecks
|= WTD_REVOCATION_CHECK_END_CERT
;
2586 if (viewInfo
.dwFlags
& CRYPTUI_ENABLE_REVOCATION_CHECK_CHAIN
)
2587 wvt
.fdwRevocationChecks
|= WTD_REVOCATION_CHECK_CHAIN
;
2588 wvt
.dwUnionChoice
= WTD_CHOICE_CERT
;
2589 memset(&cert
, 0, sizeof(cert
));
2590 cert
.cbStruct
= sizeof(cert
);
2591 cert
.psCertContext
= (CERT_CONTEXT
*)viewInfo
.pCertContext
;
2592 cert
.chStores
= viewInfo
.cStores
;
2593 cert
.pahStores
= viewInfo
.rghStores
;
2594 wvt
.u
.pCert
= &cert
;
2595 wvt
.dwStateAction
= WTD_STATEACTION_VERIFY
;
2596 WinVerifyTrust(NULL
, &generic_cert_verify
, &wvt
);
2597 viewInfo
.u
.pCryptProviderData
=
2598 WTHelperProvDataFromStateData(wvt
.hWVTStateData
);
2599 signer
= WTHelperGetProvSignerFromChain(
2600 (CRYPT_PROVIDER_DATA
*)viewInfo
.u
.pCryptProviderData
, 0, FALSE
, 0);
2601 provCert
= WTHelperGetProvCertFromChain(signer
, 0);
2606 viewInfo
.u
.pCryptProviderData
=
2607 WTHelperProvDataFromStateData(viewInfo
.u
.hWVTStateData
);
2608 signer
= WTHelperGetProvSignerFromChain(
2609 (CRYPT_PROVIDER_DATA
*)viewInfo
.u
.pCryptProviderData
,
2610 viewInfo
.idxSigner
, viewInfo
.fCounterSigner
,
2611 viewInfo
.idxCounterSigner
);
2612 provCert
= WTHelperGetProvCertFromChain(signer
, viewInfo
.idxCert
);
2617 ret
= show_cert_dialog(&viewInfo
, provCert
, pfPropertiesChanged
);
2618 if (!viewInfo
.u
.hWVTStateData
)
2620 wvt
.dwStateAction
= WTD_STATEACTION_CLOSE
;
2621 WinVerifyTrust(NULL
, &generic_cert_verify
, &wvt
);
2627 static PCCERT_CONTEXT
make_cert_from_file(LPCWSTR fileName
)
2630 DWORD size
, encoding
= X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
;
2632 PCCERT_CONTEXT cert
;
2634 file
= CreateFileW(fileName
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
2635 OPEN_EXISTING
, 0, NULL
);
2636 if (file
== INVALID_HANDLE_VALUE
)
2638 WARN("can't open certificate file %s\n", debugstr_w(fileName
));
2641 if ((size
= GetFileSize(file
, NULL
)))
2643 if ((buffer
= HeapAlloc(GetProcessHeap(), 0, size
)))
2646 if (!ReadFile(file
, buffer
, size
, &read
, NULL
) || read
!= size
)
2648 WARN("can't read certificate file %s\n", debugstr_w(fileName
));
2649 HeapFree(GetProcessHeap(), 0, buffer
);
2657 WARN("empty file %s\n", debugstr_w(fileName
));
2662 cert
= CertCreateCertificateContext(encoding
, buffer
, size
);
2663 HeapFree(GetProcessHeap(), 0, buffer
);
2667 /* Decodes a cert's basic constraints extension (either szOID_BASIC_CONSTRAINTS
2668 * or szOID_BASIC_CONSTRAINTS2, whichever is present) to determine if it
2669 * should be a CA. If neither extension is present, returns
2670 * defaultIfNotSpecified.
2672 static BOOL
is_ca_cert(PCCERT_CONTEXT cert
, BOOL defaultIfNotSpecified
)
2674 BOOL isCA
= defaultIfNotSpecified
;
2675 PCERT_EXTENSION ext
= CertFindExtension(szOID_BASIC_CONSTRAINTS
,
2676 cert
->pCertInfo
->cExtension
, cert
->pCertInfo
->rgExtension
);
2680 CERT_BASIC_CONSTRAINTS_INFO
*info
;
2683 if (CryptDecodeObjectEx(X509_ASN_ENCODING
, szOID_BASIC_CONSTRAINTS
,
2684 ext
->Value
.pbData
, ext
->Value
.cbData
, CRYPT_DECODE_ALLOC_FLAG
,
2685 NULL
, (LPBYTE
)&info
, &size
))
2687 if (info
->SubjectType
.cbData
== 1)
2688 isCA
= info
->SubjectType
.pbData
[0] & CERT_CA_SUBJECT_FLAG
;
2694 ext
= CertFindExtension(szOID_BASIC_CONSTRAINTS2
,
2695 cert
->pCertInfo
->cExtension
, cert
->pCertInfo
->rgExtension
);
2698 CERT_BASIC_CONSTRAINTS2_INFO info
;
2699 DWORD size
= sizeof(CERT_BASIC_CONSTRAINTS2_INFO
);
2701 if (CryptDecodeObjectEx(X509_ASN_ENCODING
,
2702 szOID_BASIC_CONSTRAINTS2
, ext
->Value
.pbData
, ext
->Value
.cbData
,
2703 0, NULL
, &info
, &size
))
2710 static HCERTSTORE
choose_store_for_cert(PCCERT_CONTEXT cert
)
2712 static const WCHAR AddressBook
[] = { 'A','d','d','r','e','s','s',
2713 'B','o','o','k',0 };
2714 static const WCHAR CA
[] = { 'C','A',0 };
2717 if (is_ca_cert(cert
, TRUE
))
2720 storeName
= AddressBook
;
2721 return CertOpenStore(CERT_STORE_PROV_SYSTEM_W
, 0, 0,
2722 CERT_SYSTEM_STORE_CURRENT_USER
, storeName
);
2725 BOOL WINAPI
CryptUIWizImport(DWORD dwFlags
, HWND hwndParent
, LPCWSTR pwszWizardTitle
,
2726 PCCRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc
, HCERTSTORE hDestCertStore
)
2730 const CERT_CONTEXT
*cert
;
2731 BOOL freeCert
= FALSE
;
2733 TRACE("(0x%08x, %p, %s, %p, %p)\n", dwFlags
, hwndParent
, debugstr_w(pwszWizardTitle
),
2734 pImportSrc
, hDestCertStore
);
2736 if (!(dwFlags
& CRYPTUI_WIZ_NO_UI
)) FIXME("UI not implemented\n");
2739 pImportSrc
->dwSize
!= sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO
))
2741 SetLastError(E_INVALIDARG
);
2745 switch (pImportSrc
->dwSubjectChoice
)
2747 case CRYPTUI_WIZ_IMPORT_SUBJECT_FILE
:
2748 if (!(cert
= make_cert_from_file(pImportSrc
->u
.pwszFileName
)))
2750 WARN("unable to create certificate context\n");
2756 case CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_CONTEXT
:
2757 cert
= pImportSrc
->u
.pCertContext
;
2760 SetLastError(E_INVALIDARG
);
2765 FIXME("source type not implemented: %u\n", pImportSrc
->dwSubjectChoice
);
2766 SetLastError(E_INVALIDARG
);
2769 if (hDestCertStore
) store
= hDestCertStore
;
2772 if (!(store
= choose_store_for_cert(cert
)))
2774 WARN("unable to open certificate store\n");
2775 CertFreeCertificateContext(cert
);
2779 ret
= CertAddCertificateContextToStore(store
, cert
, CERT_STORE_ADD_REPLACE_EXISTING
, NULL
);
2781 if (!hDestCertStore
) CertCloseStore(store
, 0);
2783 CertFreeCertificateContext(cert
);