xref: /aoo4110/main/uui/source/iahndl-ssl.cxx (revision b1cdbd2c)
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 
25 #include "com/sun/star/security/CertificateValidity.hpp"
26 #include "com/sun/star/security/XCertificateExtension.hpp"
27 #include "com/sun/star/security/XSanExtension.hpp"
28 #include <com/sun/star/security/ExtAltNameType.hpp>
29 #include "com/sun/star/task/XInteractionAbort.hpp"
30 #include "com/sun/star/task/XInteractionApprove.hpp"
31 #include "com/sun/star/task/XInteractionRequest.hpp"
32 #include "com/sun/star/ucb/CertificateValidationRequest.hpp"
33 #include <com/sun/star/uno/Reference.hxx>
34 
35 #include <com/sun/star/uno/Sequence.hxx>
36 #include "vos/mutex.hxx"
37 #include "tools/datetime.hxx"
38 #include "svl/zforlist.hxx"
39 #include "vcl/svapp.hxx"
40 
41 #include "ids.hrc"
42 #include "getcontinuations.hxx"
43 #include "sslwarndlg.hxx"
44 #include "unknownauthdlg.hxx"
45 
46 #include "iahndl.hxx"
47 
48 #define DESCRIPTION_1 1
49 #define DESCRIPTION_2 2
50 #define TITLE 3
51 
52 #define OID_SUBJECT_ALTERNATIVE_NAME "2.5.29.17"
53 
54 
55 using namespace com::sun::star;
56 
57 namespace {
58 
59 String
getContentPart(const String & _rRawString)60 getContentPart( const String& _rRawString )
61 {
62     // search over some parts to find a string
63     //static char* aIDs[] = { "CN", "OU", "O", "E", NULL };
64     static char const * aIDs[] = { "CN=", "OU=", "O=", "E=", NULL };// By CP
65     String sPart;
66     int i = 0;
67     while ( aIDs[i] )
68     {
69         String sPartId = String::CreateFromAscii( aIDs[i++] );
70         xub_StrLen nContStart = _rRawString.Search( sPartId );
71         if ( nContStart != STRING_NOTFOUND )
72         {
73             nContStart = nContStart + sPartId.Len();
74             xub_StrLen nContEnd
75                 = _rRawString.Search( sal_Unicode( ',' ), nContStart );
76             sPart = String( _rRawString, nContStart, nContEnd - nContStart );
77             break;
78         }
79     }
80     return sPart;
81 }
82 
83 bool
isDomainMatch(rtl::OUString hostName,uno::Sequence<::rtl::OUString> certHostNames)84 isDomainMatch(
85               rtl::OUString hostName, uno::Sequence< ::rtl::OUString > certHostNames)
86 {
87     for ( int i = 0; i < certHostNames.getLength(); i++){
88         ::rtl::OUString element = certHostNames[i];
89 
90        if (element.getLength() == 0)
91            continue;
92 
93        if (hostName.equalsIgnoreAsciiCase( element ))
94            return true;
95 
96        if ( 0 == element.indexOf( rtl::OUString::createFromAscii( "*" ) ) &&
97                  hostName.getLength() >= element.getLength()  )
98        {
99            rtl::OUString cmpStr = element.copy( 1 );
100            if ( hostName.matchIgnoreAsciiCase(
101                     cmpStr, hostName.getLength() - cmpStr.getLength()) )
102                return true;
103        }
104     }
105 
106     return false;
107 }
108 
109 rtl::OUString
getLocalizedDatTimeStr(uno::Reference<lang::XMultiServiceFactory> const & xServiceFactory,util::DateTime const & rDateTime)110 getLocalizedDatTimeStr(
111     uno::Reference< lang::XMultiServiceFactory > const & xServiceFactory,
112     util::DateTime const & rDateTime )
113 {
114     rtl::OUString aDateTimeStr;
115     Date  aDate;
116     Time  aTime;
117 
118     aDate = Date( rDateTime.Day, rDateTime.Month, rDateTime.Year );
119     aTime = Time( rDateTime.Hours, rDateTime.Minutes, rDateTime.Seconds );
120 
121     LanguageType eUILang = Application::GetSettings().GetUILanguage();
122     SvNumberFormatter *pNumberFormatter
123         = new SvNumberFormatter( xServiceFactory, eUILang );
124     String      aTmpStr;
125     Color*      pColor = NULL;
126     Date*       pNullDate = pNumberFormatter->GetNullDate();
127     sal_uInt32  nFormat
128         = pNumberFormatter->GetStandardFormat( NUMBERFORMAT_DATE, eUILang );
129 
130     pNumberFormatter->GetOutputString(
131         aDate - *pNullDate, nFormat, aTmpStr, &pColor );
132     aDateTimeStr = aTmpStr + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" "));
133 
134     nFormat = pNumberFormatter->GetStandardFormat( NUMBERFORMAT_TIME, eUILang );
135     pNumberFormatter->GetOutputString(
136         aTime.GetTimeInDays(), nFormat, aTmpStr, &pColor );
137     aDateTimeStr += aTmpStr;
138 
139     return aDateTimeStr;
140 }
141 
142 sal_Bool
executeUnknownAuthDialog(Window * pParent,uno::Reference<lang::XMultiServiceFactory> const & xServiceFactory,const uno::Reference<security::XCertificate> & rXCert)143 executeUnknownAuthDialog(
144     Window * pParent,
145     uno::Reference< lang::XMultiServiceFactory > const & xServiceFactory,
146     const uno::Reference< security::XCertificate >& rXCert)
147     SAL_THROW((uno::RuntimeException))
148 {
149     try
150     {
151         vos::OGuard aGuard(Application::GetSolarMutex());
152 
153         std::auto_ptr< ResMgr > xManager(
154             ResMgr::CreateResMgr(CREATEVERSIONRESMGR_NAME(uui)));
155         std::auto_ptr< UnknownAuthDialog > xDialog(
156             new UnknownAuthDialog( pParent,
157                                    rXCert,
158                                    xServiceFactory,
159                                    xManager.get()));
160 
161         // Get correct ressource string
162         rtl::OUString aMessage;
163 
164         std::vector< rtl::OUString > aArguments;
165         aArguments.push_back( getContentPart( rXCert->getSubjectName()) );
166 
167         if (xManager.get())
168         {
169             ResId aResId(RID_UUI_ERRHDL, *xManager.get());
170             if (ErrorResource(aResId).getString(
171                     ERRCODE_UUI_UNKNOWNAUTH_UNTRUSTED, &aMessage))
172             {
173                 aMessage = UUIInteractionHelper::replaceMessageWithArguments(
174                     aMessage, aArguments );
175                 xDialog->setDescriptionText( aMessage );
176             }
177         }
178 
179         return static_cast<sal_Bool> (xDialog->Execute());
180     }
181     catch (std::bad_alloc const &)
182     {
183         throw uno::RuntimeException(
184                   rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("out of memory")),
185                   uno::Reference< uno::XInterface >());
186     }
187 }
188 
189 sal_Bool
executeSSLWarnDialog(Window * pParent,uno::Reference<lang::XMultiServiceFactory> const & xServiceFactory,const uno::Reference<security::XCertificate> & rXCert,sal_Int32 const & failure,const rtl::OUString & hostName)190 executeSSLWarnDialog(
191     Window * pParent,
192     uno::Reference< lang::XMultiServiceFactory > const & xServiceFactory,
193     const uno::Reference< security::XCertificate >& rXCert,
194     sal_Int32 const & failure,
195     const rtl::OUString & hostName )
196     SAL_THROW((uno::RuntimeException))
197 {
198     try
199     {
200         vos::OGuard aGuard(Application::GetSolarMutex());
201 
202         std::auto_ptr< ResMgr > xManager(
203            ResMgr::CreateResMgr(CREATEVERSIONRESMGR_NAME(uui)));
204         std::auto_ptr< SSLWarnDialog > xDialog(
205            new SSLWarnDialog( pParent,
206                               rXCert,
207                               xServiceFactory,
208                               xManager.get()));
209 
210         // Get correct ressource string
211         rtl::OUString aMessage_1;
212         std::vector< rtl::OUString > aArguments_1;
213 
214         switch( failure )
215         {
216             case SSLWARN_TYPE_DOMAINMISMATCH:
217                 aArguments_1.push_back( hostName );
218                 aArguments_1.push_back(
219                     getContentPart( rXCert->getSubjectName()) );
220                 aArguments_1.push_back( hostName );
221                 break;
222             case SSLWARN_TYPE_EXPIRED:
223                 aArguments_1.push_back(
224                     getContentPart( rXCert->getSubjectName()) );
225                 aArguments_1.push_back(
226                     getLocalizedDatTimeStr( xServiceFactory,
227                                             rXCert->getNotValidAfter() ) );
228                 aArguments_1.push_back(
229                     getLocalizedDatTimeStr( xServiceFactory,
230                                             rXCert->getNotValidAfter() ) );
231                 break;
232             case SSLWARN_TYPE_INVALID:
233                 break;
234         }
235 
236         if (xManager.get())
237         {
238             ResId aResId(RID_UUI_ERRHDL, *xManager.get());
239             if (ErrorResource(aResId).getString(
240                     ERRCODE_AREA_UUI_UNKNOWNAUTH + failure + DESCRIPTION_1,
241                     &aMessage_1))
242             {
243                 aMessage_1 = UUIInteractionHelper::replaceMessageWithArguments(
244                     aMessage_1, aArguments_1 );
245                 xDialog->setDescription1Text( aMessage_1 );
246             }
247 
248             rtl::OUString aTitle;
249             ErrorResource(aResId).getString(
250                 ERRCODE_AREA_UUI_UNKNOWNAUTH + failure + TITLE, &aTitle);
251             xDialog->SetText( aTitle );
252         }
253 
254         return static_cast<sal_Bool> (xDialog->Execute());
255     }
256     catch (std::bad_alloc const &)
257     {
258         throw uno::RuntimeException(
259                   rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("out of memory")),
260                   uno::Reference< uno::XInterface >());
261     }
262 }
263 
264 void
handleCertificateValidationRequest_(Window * pParent,uno::Reference<lang::XMultiServiceFactory> const & xServiceFactory,ucb::CertificateValidationRequest const & rRequest,uno::Sequence<uno::Reference<task::XInteractionContinuation>> const & rContinuations)265 handleCertificateValidationRequest_(
266     Window * pParent,
267     uno::Reference< lang::XMultiServiceFactory > const & xServiceFactory,
268     ucb::CertificateValidationRequest const & rRequest,
269     uno::Sequence< uno::Reference< task::XInteractionContinuation > > const &
270         rContinuations)
271     SAL_THROW((uno::RuntimeException))
272 {
273     uno::Reference< task::XInteractionApprove > xApprove;
274     uno::Reference< task::XInteractionAbort > xAbort;
275     getContinuations(rContinuations, &xApprove, &xAbort);
276 
277     sal_Int32 failures = rRequest.CertificateValidity;
278     sal_Bool trustCert = sal_True;
279 
280     if ( ((failures & security::CertificateValidity::UNTRUSTED)
281              == security::CertificateValidity::UNTRUSTED ) ||
282          ((failures & security::CertificateValidity::ISSUER_UNTRUSTED)
283              == security::CertificateValidity::ISSUER_UNTRUSTED) ||
284          ((failures & security::CertificateValidity::ROOT_UNTRUSTED)
285              == security::CertificateValidity::ROOT_UNTRUSTED) )
286     {
287         trustCert = executeUnknownAuthDialog( pParent,
288                                               xServiceFactory,
289                                               rRequest.Certificate );
290     }
291 
292     uno::Sequence< uno::Reference< security::XCertificateExtension > > extensions = rRequest.Certificate->getExtensions();
293     uno::Sequence< security::CertAltNameEntry > altNames;
294     for (sal_Int32 i = 0 ; i < extensions.getLength(); i++){
295         uno::Reference< security::XCertificateExtension >element = extensions[i];
296 
297         rtl::OString aId ( (const sal_Char *)element->getExtensionId().getArray(), element->getExtensionId().getLength());
298         if (aId.equals(OID_SUBJECT_ALTERNATIVE_NAME))
299         {
300            uno::Reference< security::XSanExtension > sanExtension ( element, uno::UNO_QUERY );
301            altNames =  sanExtension->getAlternativeNames();
302            break;
303         }
304     }
305 
306     ::rtl::OUString certHostName = getContentPart( rRequest.Certificate->getSubjectName() );
307     uno::Sequence< ::rtl::OUString > certHostNames(altNames.getLength() + 1);
308 
309     certHostNames[0] = certHostName;
310 
311     for(int n = 0; n < altNames.getLength(); ++n)
312     {
313         if (altNames[n].Type ==  security::ExtAltNameType_DNS_NAME){
314            altNames[n].Value >>= certHostNames[n+1];
315         }
316     }
317 
318     if ( (!isDomainMatch(
319               rRequest.HostName,
320               certHostNames )) &&
321           trustCert )
322     {
323         trustCert = executeSSLWarnDialog( pParent,
324                                           xServiceFactory,
325                                           rRequest.Certificate,
326                                           SSLWARN_TYPE_DOMAINMISMATCH,
327                                           rRequest.HostName );
328     }
329     else
330     if ( (((failures & security::CertificateValidity::TIME_INVALID)
331               == security::CertificateValidity::TIME_INVALID) ||
332           ((failures & security::CertificateValidity::NOT_TIME_NESTED)
333               == security::CertificateValidity::NOT_TIME_NESTED)) &&
334          trustCert )
335     {
336         trustCert = executeSSLWarnDialog( pParent,
337                                           xServiceFactory,
338                                           rRequest.Certificate,
339                                           SSLWARN_TYPE_EXPIRED,
340                                           rRequest.HostName );
341     }
342     else
343     if ( (((failures & security::CertificateValidity::REVOKED)
344               == security::CertificateValidity::REVOKED) ||
345           ((failures & security::CertificateValidity::SIGNATURE_INVALID)
346               == security::CertificateValidity::SIGNATURE_INVALID) ||
347           ((failures & security::CertificateValidity::EXTENSION_INVALID)
348               == security::CertificateValidity::EXTENSION_INVALID) ||
349           ((failures & security::CertificateValidity::INVALID)
350               == security::CertificateValidity::INVALID)) &&
351          trustCert )
352     {
353         trustCert = executeSSLWarnDialog( pParent,
354                                           xServiceFactory,
355                                           rRequest.Certificate,
356                                           SSLWARN_TYPE_INVALID,
357                                           rRequest.HostName );
358     }
359 
360     if ( trustCert )
361     {
362         if (xApprove.is())
363             xApprove->select();
364     }
365     else
366     {
367         if (xAbort.is())
368             xAbort->select();
369     }
370 }
371 
372 } // namespace
373 
374 bool
handleCertificateValidationRequest(uno::Reference<task::XInteractionRequest> const & rRequest)375 UUIInteractionHelper::handleCertificateValidationRequest(
376     uno::Reference< task::XInteractionRequest > const & rRequest)
377     SAL_THROW((uno::RuntimeException))
378 {
379     uno::Any aAnyRequest(rRequest->getRequest());
380 
381     ucb::CertificateValidationRequest aCertificateValidationRequest;
382     if (aAnyRequest >>= aCertificateValidationRequest)
383     {
384         handleCertificateValidationRequest_(getParentProperty(),
385                                             m_xServiceFactory,
386                                             aCertificateValidationRequest,
387                                             rRequest->getContinuations());
388         return true;
389     }
390 
391     return false;
392 }
393 
394