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