1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_xmlsecurity.hxx"
26 
27 #include <xmlsecurity/certificatechooser.hxx>
28 #include <xmlsecurity/certificateviewer.hxx>
29 #include <xmlsecurity/biginteger.hxx>
30 #include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp>
31 #include <comphelper/sequence.hxx>
32 #include <comphelper/processfactory.hxx>
33 
34 #include <com/sun/star/security/NoPasswordException.hpp>
35 #include <com/sun/star/security/CertificateCharacters.hpp>
36 #include <com/sun/star/security/SerialNumberAdapter.hpp>
37 
38 #include <dialogs.hrc>
39 #include <resourcemanager.hxx>
40 #include <vcl/msgbox.hxx>
41 
42 /* HACK: disable some warnings for MS-C */
43 #ifdef _MSC_VER
44 #pragma warning (disable : 4355)	// 4355: this used in initializer-list
45 #endif
46 
47 using namespace ::com::sun::star;
48 
49 #define INVAL_SEL		0xFFFF
50 
GetSelectedEntryPos(void) const51 sal_uInt16 CertificateChooser::GetSelectedEntryPos( void ) const
52 {
53 	sal_uInt16	nSel = INVAL_SEL;
54 
55 	SvLBoxEntry* pSel = maCertLB.FirstSelected();
56 	if( pSel )
57 		nSel = (sal_uInt16) ( sal_uIntPtr ) pSel->GetUserData();
58 
59 	return (sal_uInt16) nSel;
60 }
61 
CertificateChooser(Window * _pParent,uno::Reference<uno::XComponentContext> & _rxCtx,uno::Reference<dcss::xml::crypto::XSecurityEnvironment> & _rxSecurityEnvironment,const SignatureInformations & _rCertsToIgnore)62 CertificateChooser::CertificateChooser( Window* _pParent, uno::Reference< uno::XComponentContext>& _rxCtx, uno::Reference< dcss::xml::crypto::XSecurityEnvironment >& _rxSecurityEnvironment, const SignatureInformations& _rCertsToIgnore )
63 	:ModalDialog	( _pParent, XMLSEC_RES( RID_XMLSECDLG_CERTCHOOSER ) )
64 	,maCertsToIgnore( _rCertsToIgnore )
65 	,maHintFT		( this, XMLSEC_RES( FT_HINT_SELECT ) )
66 	,maCertLB		( this, XMLSEC_RES( LB_SIGNATURES ) )
67 	,maViewBtn		( this, XMLSEC_RES( BTN_VIEWCERT ) )
68 	,maBottomSepFL	( this, XMLSEC_RES( FL_BOTTOM_SEP ) )
69 	,maOKBtn		( this, XMLSEC_RES( BTN_OK ) )
70 	,maCancelBtn	( this, XMLSEC_RES( BTN_CANCEL ) )
71 	,maHelpBtn		( this, XMLSEC_RES( BTN_HELP ) )
72 {
73 	static long nTabs[] = { 3, 0, 30*CS_LB_WIDTH/100, 60*CS_LB_WIDTH/100 };
74 	maCertLB.SetTabs( &nTabs[0] );
75 	maCertLB.InsertHeaderEntry( String( XMLSEC_RES( STR_HEADERBAR ) ) );
76 	maCertLB.SetSelectHdl( LINK( this, CertificateChooser, CertificateHighlightHdl ) );
77 	maCertLB.SetDoubleClickHdl( LINK( this, CertificateChooser, CertificateSelectHdl ) );
78 	maViewBtn.SetClickHdl( LINK( this, CertificateChooser, ViewButtonHdl ) );
79 
80 	FreeResource();
81 
82 	mxCtx = _rxCtx;
83 	mxSecurityEnvironment = _rxSecurityEnvironment;
84 	mbInitialized = sal_False;
85 
86     // disable buttons
87     CertificateHighlightHdl( NULL );
88 }
89 
~CertificateChooser()90 CertificateChooser::~CertificateChooser()
91 {
92 }
93 
Execute()94 short CertificateChooser::Execute()
95 {
96 	// #i48432#
97 	// We can't check for personal certificates before raising this dialog,
98 	// because the mozilla implementation throws a NoPassword exception,
99 	// if the user pressed cancel, and also if the database does not exist!
100 	// But in the later case, the is no password query, and the user is confused
101 	// that nothing happens when pressing "Add..." in the SignatureDialog.
102 
103 	// PostUserEvent( LINK( this, CertificateChooser, Initialize ) );
104 
105 	// PostUserLink behavior is to slow, so do it directly before Execute().
106 	// Problem: This Dialog should be visible right now, and the parent should not be accessible.
107 	// Show, Update, DIsableInput...
108 
109 	Window* pMe = this;
110 	Window* pParent = GetParent();
111 	if ( pParent )
112 		pParent->EnableInput( sal_False );
113 	pMe->Show();
114 	pMe->Update();
115 	ImplInitialize();
116 	if ( pParent )
117 		pParent->EnableInput( sal_True );
118 	return ModalDialog::Execute();
119 }
120 
121 // IMPL_LINK( CertificateChooser, Initialize, void*, EMPTYARG )
ImplInitialize()122 void CertificateChooser::ImplInitialize()
123 {
124 	if ( !mbInitialized )
125 	{
126 		try
127 		{
128 			maCerts = mxSecurityEnvironment->getPersonalCertificates();
129 		}
130 		catch (security::NoPasswordException&)
131 		{
132 		}
133 
134         uno::Reference< dcss::security::XSerialNumberAdapter> xSerialNumberAdapter =
135             ::com::sun::star::security::SerialNumberAdapter::create(mxCtx);
136 
137 		sal_Int32 nCertificates = maCerts.getLength();
138 		sal_Int32 nCertificatesToIgnore = maCertsToIgnore.size();
139 		for( sal_Int32 nCert = nCertificates; nCert; )
140 		{
141 			uno::Reference< security::XCertificate > xCert = maCerts[ --nCert ];
142 			sal_Bool bIgnoreThis = false;
143 
144 			// Do we already use that?
145 			if( nCertificatesToIgnore )
146 			{
147 				rtl::OUString aIssuerName = xCert->getIssuerName();
148 				for( sal_Int32 nSig = 0; nSig < nCertificatesToIgnore; ++nSig )
149 				{
150 					const SignatureInformation& rInf = maCertsToIgnore[ nSig ];
151 					if ( ( aIssuerName == rInf.ouX509IssuerName ) &&
152 						( xSerialNumberAdapter->toString( xCert->getSerialNumber() ) == rInf.ouX509SerialNumber ) )
153 					{
154 						bIgnoreThis = true;
155 						break;
156 					}
157 				}
158 			}
159 
160 			if ( !bIgnoreThis )
161 			{
162 				// Check if we have a private key for this...
163 				long nCertificateCharacters = mxSecurityEnvironment->getCertificateCharacters( xCert );
164 
165 				if ( !( nCertificateCharacters & security::CertificateCharacters::HAS_PRIVATE_KEY ) )
166 					bIgnoreThis = true;
167 
168 			}
169 
170 			if ( bIgnoreThis )
171 			{
172 				::comphelper::removeElementAt( maCerts, nCert );
173 				nCertificates = maCerts.getLength();
174 			}
175 		}
176 
177 		// fill list of certificates; the first entry will be selected
178 		for ( sal_Int32 nC = 0; nC < nCertificates; ++nC )
179 		{
180 			String sEntry( XmlSec::GetContentPart( maCerts[ nC ]->getSubjectName() ) );
181 			sEntry += '\t';
182 			sEntry += XmlSec::GetContentPart( maCerts[ nC ]->getIssuerName() );
183 			sEntry += '\t';
184 			sEntry += XmlSec::GetDateString( maCerts[ nC ]->getNotValidAfter() );
185 			SvLBoxEntry* pEntry = maCertLB.InsertEntry( sEntry );
186 			pEntry->SetUserData( ( void* )nC ); // missuse user data as index
187 		}
188 
189 		// enable/disable buttons
190 		CertificateHighlightHdl( NULL );
191 		mbInitialized = sal_True;
192 	}
193 }
194 
195 
GetSelectedCertificate()196 uno::Reference< dcss::security::XCertificate > CertificateChooser::GetSelectedCertificate()
197 {
198     uno::Reference< dcss::security::XCertificate > xCert;
199 	sal_uInt16	nSelected = GetSelectedEntryPos();
200     if ( nSelected < maCerts.getLength() )
201 		xCert = maCerts[ nSelected ];
202     return xCert;
203 }
204 
IMPL_LINK(CertificateChooser,CertificateHighlightHdl,void *,EMPTYARG)205 IMPL_LINK( CertificateChooser, CertificateHighlightHdl, void*, EMPTYARG )
206 {
207     sal_Bool bEnable = GetSelectedCertificate().is();
208     maViewBtn.Enable( bEnable );
209     maOKBtn.Enable( bEnable );
210     return 0;
211 }
212 
IMPL_LINK(CertificateChooser,CertificateSelectHdl,void *,EMPTYARG)213 IMPL_LINK( CertificateChooser, CertificateSelectHdl, void*, EMPTYARG )
214 {
215     EndDialog( RET_OK );
216     return 0;
217 }
218 
IMPL_LINK(CertificateChooser,ViewButtonHdl,Button *,EMPTYARG)219 IMPL_LINK( CertificateChooser, ViewButtonHdl, Button*, EMPTYARG )
220 {
221     ImplShowCertificateDetails();
222     return 0;
223 }
224 
ImplShowCertificateDetails()225 void CertificateChooser::ImplShowCertificateDetails()
226 {
227 	uno::Reference< dcss::security::XCertificate > xCert = GetSelectedCertificate();
228 	if( xCert.is() )
229 	{
230 		CertificateViewer aViewer( this, mxSecurityEnvironment, xCert, sal_True );
231 		aViewer.Execute();
232 	}
233 }
234 
235