/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ #include "com/sun/star/security/CertificateValidity.hpp" #include "com/sun/star/security/XCertificateExtension.hpp" #include "com/sun/star/security/XSanExtension.hpp" #include #include "com/sun/star/task/XInteractionAbort.hpp" #include "com/sun/star/task/XInteractionApprove.hpp" #include "com/sun/star/task/XInteractionRequest.hpp" #include "com/sun/star/ucb/CertificateValidationRequest.hpp" #include #include #include "vos/mutex.hxx" #include "tools/datetime.hxx" #include "svl/zforlist.hxx" #include "vcl/svapp.hxx" #include "ids.hrc" #include "getcontinuations.hxx" #include "sslwarndlg.hxx" #include "unknownauthdlg.hxx" #include "iahndl.hxx" #define DESCRIPTION_1 1 #define DESCRIPTION_2 2 #define TITLE 3 #define OID_SUBJECT_ALTERNATIVE_NAME "2.5.29.17" using namespace com::sun::star; namespace { String getContentPart( const String& _rRawString ) { // search over some parts to find a string //static char* aIDs[] = { "CN", "OU", "O", "E", NULL }; static char const * aIDs[] = { "CN=", "OU=", "O=", "E=", NULL };// By CP String sPart; int i = 0; while ( aIDs[i] ) { String sPartId = String::CreateFromAscii( aIDs[i++] ); xub_StrLen nContStart = _rRawString.Search( sPartId ); if ( nContStart != STRING_NOTFOUND ) { nContStart = nContStart + sPartId.Len(); xub_StrLen nContEnd = _rRawString.Search( sal_Unicode( ',' ), nContStart ); sPart = String( _rRawString, nContStart, nContEnd - nContStart ); break; } } return sPart; } bool isDomainMatch( rtl::OUString hostName, uno::Sequence< ::rtl::OUString > certHostNames) { for ( int i = 0; i < certHostNames.getLength(); i++){ ::rtl::OUString element = certHostNames[i]; if (element.getLength() == 0) continue; if (hostName.equalsIgnoreAsciiCase( element )) return true; if ( 0 == element.indexOf( rtl::OUString::createFromAscii( "*" ) ) && hostName.getLength() >= element.getLength() ) { rtl::OUString cmpStr = element.copy( 1 ); if ( hostName.matchIgnoreAsciiCase( cmpStr, hostName.getLength() - cmpStr.getLength()) ) return true; } } return false; } rtl::OUString getLocalizedDatTimeStr( uno::Reference< lang::XMultiServiceFactory > const & xServiceFactory, util::DateTime const & rDateTime ) { rtl::OUString aDateTimeStr; Date aDate; Time aTime; aDate = Date( rDateTime.Day, rDateTime.Month, rDateTime.Year ); aTime = Time( rDateTime.Hours, rDateTime.Minutes, rDateTime.Seconds ); LanguageType eUILang = Application::GetSettings().GetUILanguage(); SvNumberFormatter *pNumberFormatter = new SvNumberFormatter( xServiceFactory, eUILang ); String aTmpStr; Color* pColor = NULL; Date* pNullDate = pNumberFormatter->GetNullDate(); sal_uInt32 nFormat = pNumberFormatter->GetStandardFormat( NUMBERFORMAT_DATE, eUILang ); pNumberFormatter->GetOutputString( aDate - *pNullDate, nFormat, aTmpStr, &pColor ); aDateTimeStr = aTmpStr + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" ")); nFormat = pNumberFormatter->GetStandardFormat( NUMBERFORMAT_TIME, eUILang ); pNumberFormatter->GetOutputString( aTime.GetTimeInDays(), nFormat, aTmpStr, &pColor ); aDateTimeStr += aTmpStr; return aDateTimeStr; } sal_Bool executeUnknownAuthDialog( Window * pParent, uno::Reference< lang::XMultiServiceFactory > const & xServiceFactory, const uno::Reference< security::XCertificate >& rXCert) SAL_THROW((uno::RuntimeException)) { try { vos::OGuard aGuard(Application::GetSolarMutex()); std::auto_ptr< ResMgr > xManager( ResMgr::CreateResMgr(CREATEVERSIONRESMGR_NAME(uui))); std::auto_ptr< UnknownAuthDialog > xDialog( new UnknownAuthDialog( pParent, rXCert, xServiceFactory, xManager.get())); // Get correct ressource string rtl::OUString aMessage; std::vector< rtl::OUString > aArguments; aArguments.push_back( getContentPart( rXCert->getSubjectName()) ); if (xManager.get()) { ResId aResId(RID_UUI_ERRHDL, *xManager.get()); if (ErrorResource(aResId).getString( ERRCODE_UUI_UNKNOWNAUTH_UNTRUSTED, &aMessage)) { aMessage = UUIInteractionHelper::replaceMessageWithArguments( aMessage, aArguments ); xDialog->setDescriptionText( aMessage ); } } return static_cast (xDialog->Execute()); } catch (std::bad_alloc const &) { throw uno::RuntimeException( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("out of memory")), uno::Reference< uno::XInterface >()); } } 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 ) SAL_THROW((uno::RuntimeException)) { try { vos::OGuard aGuard(Application::GetSolarMutex()); std::auto_ptr< ResMgr > xManager( ResMgr::CreateResMgr(CREATEVERSIONRESMGR_NAME(uui))); std::auto_ptr< SSLWarnDialog > xDialog( new SSLWarnDialog( pParent, rXCert, xServiceFactory, xManager.get())); // Get correct ressource string rtl::OUString aMessage_1; std::vector< rtl::OUString > aArguments_1; switch( failure ) { case SSLWARN_TYPE_DOMAINMISMATCH: aArguments_1.push_back( hostName ); aArguments_1.push_back( getContentPart( rXCert->getSubjectName()) ); aArguments_1.push_back( hostName ); break; case SSLWARN_TYPE_EXPIRED: aArguments_1.push_back( getContentPart( rXCert->getSubjectName()) ); aArguments_1.push_back( getLocalizedDatTimeStr( xServiceFactory, rXCert->getNotValidAfter() ) ); aArguments_1.push_back( getLocalizedDatTimeStr( xServiceFactory, rXCert->getNotValidAfter() ) ); break; case SSLWARN_TYPE_INVALID: break; } if (xManager.get()) { ResId aResId(RID_UUI_ERRHDL, *xManager.get()); if (ErrorResource(aResId).getString( ERRCODE_AREA_UUI_UNKNOWNAUTH + failure + DESCRIPTION_1, &aMessage_1)) { aMessage_1 = UUIInteractionHelper::replaceMessageWithArguments( aMessage_1, aArguments_1 ); xDialog->setDescription1Text( aMessage_1 ); } rtl::OUString aTitle; ErrorResource(aResId).getString( ERRCODE_AREA_UUI_UNKNOWNAUTH + failure + TITLE, &aTitle); xDialog->SetText( aTitle ); } return static_cast (xDialog->Execute()); } catch (std::bad_alloc const &) { throw uno::RuntimeException( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("out of memory")), uno::Reference< uno::XInterface >()); } } void handleCertificateValidationRequest_( Window * pParent, uno::Reference< lang::XMultiServiceFactory > const & xServiceFactory, ucb::CertificateValidationRequest const & rRequest, uno::Sequence< uno::Reference< task::XInteractionContinuation > > const & rContinuations) SAL_THROW((uno::RuntimeException)) { uno::Reference< task::XInteractionApprove > xApprove; uno::Reference< task::XInteractionAbort > xAbort; getContinuations(rContinuations, &xApprove, &xAbort); sal_Int32 failures = rRequest.CertificateValidity; sal_Bool trustCert = sal_True; if ( ((failures & security::CertificateValidity::UNTRUSTED) == security::CertificateValidity::UNTRUSTED ) || ((failures & security::CertificateValidity::ISSUER_UNTRUSTED) == security::CertificateValidity::ISSUER_UNTRUSTED) || ((failures & security::CertificateValidity::ROOT_UNTRUSTED) == security::CertificateValidity::ROOT_UNTRUSTED) ) { trustCert = executeUnknownAuthDialog( pParent, xServiceFactory, rRequest.Certificate ); } uno::Sequence< uno::Reference< security::XCertificateExtension > > extensions = rRequest.Certificate->getExtensions(); uno::Sequence< security::CertAltNameEntry > altNames; for (sal_Int32 i = 0 ; i < extensions.getLength(); i++){ uno::Reference< security::XCertificateExtension >element = extensions[i]; rtl::OString aId ( (const sal_Char *)element->getExtensionId().getArray(), element->getExtensionId().getLength()); if (aId.equals(OID_SUBJECT_ALTERNATIVE_NAME)) { uno::Reference< security::XSanExtension > sanExtension ( element, uno::UNO_QUERY ); altNames = sanExtension->getAlternativeNames(); break; } } ::rtl::OUString certHostName = getContentPart( rRequest.Certificate->getSubjectName() ); uno::Sequence< ::rtl::OUString > certHostNames(altNames.getLength() + 1); certHostNames[0] = certHostName; for(int n = 0; n < altNames.getLength(); ++n) { if (altNames[n].Type == security::ExtAltNameType_DNS_NAME){ altNames[n].Value >>= certHostNames[n+1]; } } if ( (!isDomainMatch( rRequest.HostName, certHostNames )) && trustCert ) { trustCert = executeSSLWarnDialog( pParent, xServiceFactory, rRequest.Certificate, SSLWARN_TYPE_DOMAINMISMATCH, rRequest.HostName ); } else if ( (((failures & security::CertificateValidity::TIME_INVALID) == security::CertificateValidity::TIME_INVALID) || ((failures & security::CertificateValidity::NOT_TIME_NESTED) == security::CertificateValidity::NOT_TIME_NESTED)) && trustCert ) { trustCert = executeSSLWarnDialog( pParent, xServiceFactory, rRequest.Certificate, SSLWARN_TYPE_EXPIRED, rRequest.HostName ); } else if ( (((failures & security::CertificateValidity::REVOKED) == security::CertificateValidity::REVOKED) || ((failures & security::CertificateValidity::SIGNATURE_INVALID) == security::CertificateValidity::SIGNATURE_INVALID) || ((failures & security::CertificateValidity::EXTENSION_INVALID) == security::CertificateValidity::EXTENSION_INVALID) || ((failures & security::CertificateValidity::INVALID) == security::CertificateValidity::INVALID)) && trustCert ) { trustCert = executeSSLWarnDialog( pParent, xServiceFactory, rRequest.Certificate, SSLWARN_TYPE_INVALID, rRequest.HostName ); } if ( trustCert ) { if (xApprove.is()) xApprove->select(); } else { if (xAbort.is()) xAbort->select(); } } } // namespace bool UUIInteractionHelper::handleCertificateValidationRequest( uno::Reference< task::XInteractionRequest > const & rRequest) SAL_THROW((uno::RuntimeException)) { uno::Any aAnyRequest(rRequest->getRequest()); ucb::CertificateValidationRequest aCertificateValidationRequest; if (aAnyRequest >>= aCertificateValidationRequest) { handleCertificateValidationRequest_(getParentProperty(), m_xServiceFactory, aCertificateValidationRequest, rRequest->getContinuations()); return true; } return false; }