LibreOffice Module uui (master) 1
iahndl-ssl.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20
21#include <com/sun/star/security/CertificateValidity.hpp>
22#include <com/sun/star/security/XCertificateExtension.hpp>
23#include <com/sun/star/security/XSanExtension.hpp>
24#include <com/sun/star/security/ExtAltNameType.hpp>
25#include <com/sun/star/task/XInteractionAbort.hpp>
26#include <com/sun/star/task/XInteractionApprove.hpp>
27#include <com/sun/star/task/XInteractionRequest.hpp>
28#include <com/sun/star/ucb/CertificateValidationRequest.hpp>
29#include <com/sun/star/uno/Reference.hxx>
30
31#include <comphelper/lok.hxx>
33#include <com/sun/star/uno/Sequence.hxx>
34#include <o3tl/string_view.hxx>
35#include <svl/numformat.hxx>
36#include <svl/zforlist.hxx>
37#include <unotools/resmgr.hxx>
38#include <vcl/svapp.hxx>
39#include <vcl/settings.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#include <memory>
49
50#define OID_SUBJECT_ALTERNATIVE_NAME "2.5.29.17"
51
52
53using namespace com::sun::star;
54
55namespace {
56
57OUString
58getContentPart( std::u16string_view _rRawString )
59{
60 // search over some parts to find a string
61 static char const * aIDs[] = { "CN=", "OU=", "O=", "E=", nullptr };
62 OUString sPart;
63 int i = 0;
64 while ( aIDs[i] )
65 {
66 OUString sPartId = OUString::createFromAscii( aIDs[i++] );
67 size_t nContStart = _rRawString.find( sPartId );
68 if ( nContStart != std::u16string_view::npos )
69 {
70 nContStart += sPartId.getLength();
71 size_t nContEnd = _rRawString.find( ',', nContStart );
72 if ( nContEnd != std::u16string_view::npos )
73 sPart = _rRawString.substr( nContStart, nContEnd - nContStart );
74 else
75 sPart = _rRawString.substr( nContStart );
76 break;
77 }
78 }
79 return sPart;
80}
81
82bool
83isDomainMatch(
84 std::u16string_view hostName, const uno::Sequence< OUString >& certHostNames)
85{
86 for ( const OUString& element : certHostNames){
87 if (element.isEmpty())
88 continue;
89
90 if (o3tl::equalsIgnoreAsciiCase( hostName, element ))
91 return true;
92
93 if (element.startsWith("*") &&
94 sal_Int32(hostName.size()) >= element.getLength() )
95 {
96 OUString cmpStr = element.copy( 1 );
97 if ( o3tl::matchIgnoreAsciiCase(hostName,
98 cmpStr, hostName.size() - cmpStr.getLength()) )
99 return true;
100 }
101 }
102
103 return false;
104}
105
106OUString
107getLocalizedDatTimeStr(
108 uno::Reference< uno::XComponentContext> const & xContext,
109 util::DateTime const & rDateTime )
110{
111 OUString aDateTimeStr;
112 Date aDate( Date::EMPTY );
114
115 aDate = Date( rDateTime.Day, rDateTime.Month, rDateTime.Year );
116 aTime = tools::Time( rDateTime.Hours, rDateTime.Minutes, rDateTime.Seconds );
117
119 SvNumberFormatter *pNumberFormatter = new SvNumberFormatter( xContext, eUILang );
120 OUString aTmpStr;
121 const Color* pColor = nullptr;
122 const Date& rNullDate = pNumberFormatter->GetNullDate();
123 sal_uInt32 nFormat
124 = pNumberFormatter->GetStandardFormat( SvNumFormatType::DATE, eUILang );
125
126 pNumberFormatter->GetOutputString( aDate - rNullDate, nFormat, aTmpStr, &pColor );
127 aDateTimeStr = aTmpStr + " ";
128
129 nFormat = pNumberFormatter->GetStandardFormat( SvNumFormatType::TIME, eUILang );
130 pNumberFormatter->GetOutputString(
131 aTime.GetTimeInDays(), nFormat, aTmpStr, &pColor );
132 aDateTimeStr += aTmpStr;
133
134 return aDateTimeStr;
135}
136
137bool
138executeUnknownAuthDialog(
139 weld::Window * pParent,
140 uno::Reference< uno::XComponentContext > const & xContext,
141 const uno::Reference< security::XCertificate >& rXCert)
142{
143 SolarMutexGuard aGuard;
144
145 UnknownAuthDialog aDialog(pParent, rXCert, xContext);
146
147 // Get correct resource string
148 OUString aMessage;
149
150 std::vector< OUString > aArguments { getContentPart( rXCert->getSubjectName()) };
151
152 std::locale aResLocale(Translate::Create("uui"));
153
154 aMessage = Translate::get(STR_UUI_UNKNOWNAUTH_UNTRUSTED, aResLocale);
156 aMessage, aArguments );
157 aDialog.setDescriptionText( aMessage );
158
159 return static_cast<bool>(aDialog.run());
160}
161
162enum class SslWarnType {
163 DOMAINMISMATCH, EXPIRED, INVALID
164};
165
166bool
167executeSSLWarnDialog(
168 weld::Window * pParent,
169 uno::Reference< uno::XComponentContext > const & xContext,
170 const uno::Reference< security::XCertificate >& rXCert,
171 SslWarnType failure,
172 const OUString & hostName )
173{
174 SolarMutexGuard aGuard;
175
176 SSLWarnDialog aDialog(pParent, rXCert, xContext);
177
178 // Get correct resource string
179 std::vector< OUString > aArguments_1;
180 TranslateId pMessageKey;
181 TranslateId pTitleKey;
182
183 switch( failure )
184 {
185 case SslWarnType::DOMAINMISMATCH:
186 pMessageKey = STR_UUI_SSLWARN_DOMAINMISMATCH;
187 pTitleKey = STR_UUI_SSLWARN_DOMAINMISMATCH_TITLE;
188 aArguments_1.push_back( hostName );
189 aArguments_1.push_back(
190 getContentPart( rXCert->getSubjectName()) );
191 aArguments_1.push_back( hostName );
192 break;
193 case SslWarnType::EXPIRED:
194 pMessageKey = STR_UUI_SSLWARN_EXPIRED;
195 pTitleKey = STR_UUI_SSLWARN_EXPIRED_TITLE;
196 aArguments_1.push_back(
197 getContentPart( rXCert->getSubjectName()) );
198 aArguments_1.push_back(
199 getLocalizedDatTimeStr( xContext,
200 rXCert->getNotValidAfter() ) );
201 aArguments_1.push_back(
202 getLocalizedDatTimeStr( xContext,
203 rXCert->getNotValidAfter() ) );
204 break;
205 case SslWarnType::INVALID:
206 pMessageKey = STR_UUI_SSLWARN_INVALID;
207 pTitleKey = STR_UUI_SSLWARN_INVALID_TITLE;
208 break;
209 default: assert(false);
210 }
211
212 std::locale aResLocale(Translate::Create("uui"));
213
214 OUString aMessage_1 = Translate::get(pMessageKey, aResLocale);
216 aMessage_1, aArguments_1 );
217 aDialog.setDescription1Text( aMessage_1 );
218
219 OUString aTitle = Translate::get(pTitleKey, aResLocale);
220 aDialog.set_title(aTitle);
221
222 return static_cast<bool>(aDialog.run());
223}
224
225void
226handleCertificateValidationRequest_(
227 weld::Window * pParent,
228 uno::Reference< uno::XComponentContext > const & xContext,
229 ucb::CertificateValidationRequest const & rRequest,
230 uno::Sequence< uno::Reference< task::XInteractionContinuation > > const &
231 rContinuations)
232{
233 uno::Reference< task::XInteractionApprove > xApprove;
234 uno::Reference< task::XInteractionAbort > xAbort;
235 getContinuations(rContinuations, &xApprove, &xAbort);
236
237 if ( comphelper::LibreOfficeKit::isActive() && xApprove.is() )
238 {
239 xApprove->select();
240 return;
241 }
242
243 sal_Int32 failures = rRequest.CertificateValidity;
244 bool trustCert = true;
245
246 if ( ((failures & security::CertificateValidity::UNTRUSTED)
247 == security::CertificateValidity::UNTRUSTED ) ||
248 ((failures & security::CertificateValidity::ISSUER_UNTRUSTED)
249 == security::CertificateValidity::ISSUER_UNTRUSTED) ||
250 ((failures & security::CertificateValidity::ROOT_UNTRUSTED)
251 == security::CertificateValidity::ROOT_UNTRUSTED) )
252 {
253 trustCert = executeUnknownAuthDialog( pParent,
254 xContext,
255 rRequest.Certificate );
256 }
257
258 const uno::Sequence< uno::Reference< security::XCertificateExtension > > extensions = rRequest.Certificate->getExtensions();
259 uno::Reference< security::XSanExtension > sanExtension;
260 auto pExtension = std::find_if(extensions.begin(), extensions.end(),
261 [](const uno::Reference< security::XCertificateExtension >& element) {
262 OString aId ( reinterpret_cast<const char *>(element->getExtensionId().getConstArray()), element->getExtensionId().getLength());
263 return aId == OID_SUBJECT_ALTERNATIVE_NAME;
264 });
265 if (pExtension != extensions.end())
266 {
267 sanExtension = uno::Reference<security::XSanExtension>(*pExtension, uno::UNO_QUERY);
268 }
269
270 std::vector<security::CertAltNameEntry> altNames;
271 if (sanExtension.is())
272 {
273 altNames = comphelper::sequenceToContainer<std::vector<security::CertAltNameEntry>>(sanExtension->getAlternativeNames());
274 }
275
276 OUString certHostName = getContentPart( rRequest.Certificate->getSubjectName() );
277 uno::Sequence< OUString > certHostNames(altNames.size() + 1);
278 auto pcertHostNames = certHostNames.getArray();
279 pcertHostNames[0] = certHostName;
280
281 for (size_t n = 0; n < altNames.size(); ++n)
282 {
283 if (altNames[n].Type == security::ExtAltNameType_DNS_NAME)
284 {
285 altNames[n].Value >>= pcertHostNames[n+1];
286 }
287 }
288
289 if ( (!isDomainMatch(
290 rRequest.HostName,
291 certHostNames )) &&
292 trustCert )
293 {
294 trustCert = executeSSLWarnDialog( pParent,
295 xContext,
296 rRequest.Certificate,
297 SslWarnType::DOMAINMISMATCH,
298 rRequest.HostName );
299 }
300
301 else if ( (((failures & security::CertificateValidity::TIME_INVALID)
302 == security::CertificateValidity::TIME_INVALID) ||
303 ((failures & security::CertificateValidity::NOT_TIME_NESTED)
304 == security::CertificateValidity::NOT_TIME_NESTED)) &&
305 trustCert )
306 {
307 trustCert = executeSSLWarnDialog( pParent,
308 xContext,
309 rRequest.Certificate,
310 SslWarnType::EXPIRED,
311 rRequest.HostName );
312 }
313
314 else if ( (((failures & security::CertificateValidity::REVOKED)
315 == security::CertificateValidity::REVOKED) ||
316 ((failures & security::CertificateValidity::SIGNATURE_INVALID)
317 == security::CertificateValidity::SIGNATURE_INVALID) ||
318 ((failures & security::CertificateValidity::EXTENSION_INVALID)
319 == security::CertificateValidity::EXTENSION_INVALID) ||
320 ((failures & security::CertificateValidity::INVALID)
321 == security::CertificateValidity::INVALID)) &&
322 trustCert )
323 {
324 trustCert = executeSSLWarnDialog( pParent,
325 xContext,
326 rRequest.Certificate,
327 SslWarnType::INVALID,
328 rRequest.HostName );
329 }
330
331 if ( trustCert )
332 {
333 if (xApprove.is())
334 xApprove->select();
335 }
336 else
337 {
338 if (xAbort.is())
339 xAbort->select();
340 }
341}
342
343} // namespace
344
345bool
347 uno::Reference< task::XInteractionRequest > const & rRequest)
348{
349 uno::Any aAnyRequest(rRequest->getRequest());
350
351 ucb::CertificateValidationRequest aCertificateValidationRequest;
352 if (aAnyRequest >>= aCertificateValidationRequest)
353 {
354 uno::Reference<awt::XWindow> xParent = getParentXWindow();
355 handleCertificateValidationRequest_(Application::GetFrameWeld(xParent),
357 aCertificateValidationRequest,
358 rRequest->getContinuations());
359 return true;
360 }
361
362 return false;
363}
364
365/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const LanguageTag & GetUILanguageTag() const
static weld::Window * GetFrameWeld(const css::uno::Reference< css::awt::XWindow > &rWindow)
static const AllSettings & GetSettings()
LanguageType getLanguageType(bool bResolveSystem=true) const
void setDescription1Text(const OUString &rText)
Definition: sslwarndlg.hxx:41
sal_uInt32 GetStandardFormat(SvNumFormatType eType, LanguageType eLnge=LANGUAGE_DONTKNOW)
void GetOutputString(const double &fOutNumber, sal_uInt32 nFIndex, OUString &sOutString, const Color **ppColor, bool bUseStarFormat=false)
const Date & GetNullDate() const
bool handleCertificateValidationRequest(css::uno::Reference< css::task::XInteractionRequest > const &rRequest)
Definition: iahndl-ssl.cxx:346
css::uno::Reference< css::uno::XComponentContext > m_xContext
Definition: iahndl.hxx:74
static OUString replaceMessageWithArguments(const OUString &aMessage, std::vector< OUString > const &rArguments)
Definition: iahndl.cxx:222
const css::uno::Reference< css::awt::XWindow > & getParentXWindow() const
Definition: iahndl.cxx:907
void setDescriptionText(const OUString &rText)
double GetTimeInDays() const
virtual short run()
void set_title(const OUString &rTitle)
void getContinuations(css::uno::Sequence< css::uno::Reference< css::task::XInteractionContinuation > > const &rContinuations, css::uno::Reference< t1 > *pContinuation1, css::uno::Reference< t2 > *pContinuation2)
Sequence< PropertyValue > aArguments
sal_Int64 n
std::locale Create(std::string_view aPrefixName, const LanguageTag &rLocale)
OUString get(TranslateId sContextAndId, const std::locale &loc)
Type
int i
bool equalsIgnoreAsciiCase(std::u16string_view s1, std::u16string_view s2)
bool matchIgnoreAsciiCase(std::u16string_view s1, std::u16string_view s2, sal_Int32 fromIndex=0)
INVALID