LibreOffice Module xmlsecurity (master) 1
certificatechooser.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#include <config_gpgme.h>
22#include <certificateviewer.hxx>
23#include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp>
24#include <com/sun/star/xml/crypto/XXMLSecurityContext.hpp>
27
28#include <com/sun/star/security/NoPasswordException.hpp>
29#include <com/sun/star/security/CertificateCharacters.hpp>
30
31#include <o3tl/safeint.hxx>
32#include <unotools/datetime.hxx>
34
35
36#include <resourcemanager.hxx>
37#include <strings.hrc>
38
39using namespace comphelper;
40using namespace css;
41
43 std::vector< css::uno::Reference< css::xml::crypto::XXMLSecurityContext > > && rxSecurityContexts,
44 UserAction eAction)
45 : GenericDialogController(_pParent, "xmlsec/ui/selectcertificatedialog.ui", "SelectCertificateDialog")
46 , meAction(eAction)
47 , m_xFTSign(m_xBuilder->weld_label("sign"))
48 , m_xFTEncrypt(m_xBuilder->weld_label("encrypt"))
49 , m_xCertLB(m_xBuilder->weld_tree_view("signatures"))
50 , m_xViewBtn(m_xBuilder->weld_button("viewcert"))
51 , m_xOKBtn(m_xBuilder->weld_button("ok"))
52 , m_xFTDescription(m_xBuilder->weld_label("description-label"))
53 , m_xDescriptionED(m_xBuilder->weld_entry("description"))
54 , m_xSearchBox(m_xBuilder->weld_entry("searchbox"))
55{
56 auto nControlWidth = m_xCertLB->get_approximate_digit_width() * 105;
57 m_xCertLB->set_size_request(nControlWidth, m_xCertLB->get_height_rows(12));
58 m_xCertLB->make_sorted();
59
60 std::vector<int> aWidths
61 {
62 o3tl::narrowing<int>(30*nControlWidth/100),
63 o3tl::narrowing<int>(30*nControlWidth/100),
64 o3tl::narrowing<int>(10*nControlWidth/100),
65 o3tl::narrowing<int>(20*nControlWidth/100)
66 };
67 m_xCertLB->set_column_fixed_widths(aWidths);
68 m_xCertLB->connect_changed( LINK( this, CertificateChooser, CertificateHighlightHdl ) );
69 m_xCertLB->connect_row_activated( LINK( this, CertificateChooser, CertificateSelectHdl ) );
70 m_xViewBtn->connect_clicked( LINK( this, CertificateChooser, ViewButtonHdl ) );
71 m_xSearchBox->connect_changed(LINK(this, CertificateChooser, SearchModifyHdl));
72
73 mxSecurityContexts = std::move(rxSecurityContexts);
74 mbInitialized = false;
75
76 // disable buttons
77 CertificateHighlightHdl(*m_xCertLB);
78}
79
81{
82}
83
85{
86 // #i48432#
87 // We can't check for personal certificates before raising this dialog,
88 // because the mozilla implementation throws a NoPassword exception,
89 // if the user pressed cancel, and also if the database does not exist!
90 // But in the later case, the is no password query, and the user is confused
91 // that nothing happens when pressing "Add..." in the SignatureDialog.
92
93 // PostUserEvent( LINK( this, CertificateChooser, Initialize ) );
94
95 // PostUserLink behavior is too slow, so do it directly before Execute().
96 // Problem: This Dialog should be visible right now, and the parent should not be accessible.
97 // Show, Update, DisableInput...
98
99 m_xDialog->show();
101 return GenericDialogController::run();
102}
103
104void CertificateChooser::HandleOneUsageBit(OUString& string, int& bits, int bit, TranslateId pResId)
105{
106 if (bits & bit)
107 {
108 if (!string.isEmpty())
109 string += ", ";
110 string += XsResId(pResId);
111 bits &= ~bit;
112 }
113}
114
116{
117 OUString result;
118
119 HandleOneUsageBit(result, bits, 0x80, STR_DIGITAL_SIGNATURE);
120 HandleOneUsageBit(result, bits, 0x40, STR_NON_REPUDIATION);
121 HandleOneUsageBit(result, bits, 0x20, STR_KEY_ENCIPHERMENT);
122 HandleOneUsageBit(result, bits, 0x10, STR_DATA_ENCIPHERMENT);
123 HandleOneUsageBit(result, bits, 0x08, STR_KEY_AGREEMENT);
124 HandleOneUsageBit(result, bits, 0x04, STR_KEY_CERT_SIGN);
125 HandleOneUsageBit(result, bits, 0x02, STR_CRL_SIGN);
126 HandleOneUsageBit(result, bits, 0x01, STR_ENCIPHER_ONLY);
127
128 // Check for mystery leftover bits
129 if (bits != 0)
130 {
131 if (!result.isEmpty())
132 result += ", ";
133 result += "0x" + OUString::number(bits, 16);
134 }
135
136 return result;
137}
138
140{
141 if (mbInitialized && !mbSearch)
142 return;
143
144 m_xCertLB->clear();
145 m_xCertLB->freeze();
146
147 SvtUserOptions aUserOpts;
148
149 SvtSysLocale aSysLocale;
150 const CharClass& rCharClass = aSysLocale.GetCharClass();
151 const OUString aSearchStr(rCharClass.uppercase(m_xSearchBox->get_text()));
152
153 switch (meAction)
154 {
155 case UserAction::Sign:
156 m_xFTSign->show();
157 m_xOKBtn->set_label(XsResId(STR_SIGN));
158 msPreferredKey = aUserOpts.GetSigningKey();
159 break;
160
162 m_xFTSign->show();
163 m_xOKBtn->set_label(XsResId(STR_SELECTSIGN));
164 msPreferredKey = aUserOpts.GetSigningKey();
165 break;
166
168 m_xFTEncrypt->show();
169 m_xFTDescription->hide();
170 m_xDescriptionED->hide();
171 m_xCertLB->set_selection_mode(SelectionMode::Multiple);
172 m_xOKBtn->set_label(XsResId(STR_ENCRYPT));
173 msPreferredKey = aUserOpts.GetEncryptionKey();
174 break;
175
176 }
177
178 uno::Sequence<uno::Reference< security::XCertificate>> xCerts;
179 for (auto& secContext : mxSecurityContexts)
180 {
181 if (!secContext.is())
182 continue;
183 auto secEnvironment = secContext->getSecurityEnvironment();
184 if (!secEnvironment.is())
185 continue;
186
187 try
188 {
189 if (xMemCerts.count(secContext))
190 {
191 xCerts = xMemCerts[secContext];
192 }
193 else
194 {
196 xCerts = secEnvironment->getPersonalCertificates();
197 else
198 xCerts = secEnvironment->getAllCertificates();
199
200 for (sal_Int32 nCert = xCerts.getLength(); nCert;)
201 {
202 uno::Reference< security::XCertificate > xCert = xCerts[ --nCert ];
203 // Check if we have a private key for this...
204 tools::Long nCertificateCharacters = secEnvironment->getCertificateCharacters(xCert);
205
206 if (!(nCertificateCharacters & security::CertificateCharacters::HAS_PRIVATE_KEY))
207 {
208 ::comphelper::removeElementAt( xCerts, nCert );
209 }
210 }
211 xMemCerts[secContext] = xCerts;
212 }
213 }
214 catch (security::NoPasswordException&)
215 {
216 }
217
218 // fill list of certificates; the first entry will be selected
219 for (const auto& xCert : std::as_const(xCerts))
220 {
221 std::shared_ptr<UserData> userData = std::make_shared<UserData>();
222 userData->xCertificate = xCert;
223 userData->xSecurityContext = secContext;
224 userData->xSecurityEnvironment = secEnvironment;
225 mvUserData.push_back(userData);
226
227 OUString sIssuer = xmlsec::GetContentPart( xCert->getIssuerName(), xCert->getCertificateKind());
228
229 // If we are searching and there is no match skip
230 if (mbSearch
231 && rCharClass.uppercase(sIssuer).indexOf(aSearchStr) < 0
232 && rCharClass.uppercase(sIssuer).indexOf(aSearchStr) < 0
233 && !aSearchStr.isEmpty())
234 continue;
235
236 m_xCertLB->append();
237 int nRow = m_xCertLB->n_children() - 1;
238 m_xCertLB->set_text(nRow, xmlsec::GetContentPart(xCert->getSubjectName(), xCert->getCertificateKind()), 0);
239 m_xCertLB->set_text(nRow, sIssuer, 1);
240 m_xCertLB->set_text(nRow, xmlsec::GetCertificateKind(xCert->getCertificateKind()), 2);
241 m_xCertLB->set_text(nRow, utl::GetDateString(xCert->getNotValidAfter()), 3);
242 m_xCertLB->set_text(nRow, UsageInClearText(xCert->getCertificateUsage()), 4);
243 OUString sId(weld::toId(userData.get()));
244 m_xCertLB->set_id(nRow, sId);
245
246#if HAVE_FEATURE_GPGME
247 // only GPG has preferred keys
248 if ( !sIssuer.isEmpty() && !msPreferredKey.isEmpty() ) {
249 if ( sIssuer == msPreferredKey )
250 {
252 m_xCertLB->select(nRow);
253 else if ( meAction == UserAction::Encrypt &&
254 aUserOpts.GetEncryptToSelf() )
255 mxEncryptToSelf = xCert;
256 }
257 }
258#endif
259 }
260 }
261
262 m_xCertLB->thaw();
263 m_xCertLB->unselect_all();
264
265 CertificateHighlightHdl(*m_xCertLB);
266 mbInitialized = true;
267}
268
269uno::Sequence<uno::Reference< css::security::XCertificate > > CertificateChooser::GetSelectedCertificates()
270{
271 std::vector< uno::Reference< css::security::XCertificate > > aRet;
273 {
274 // for encryption, multiselection is enabled
275 m_xCertLB->selected_foreach([this, &aRet](weld::TreeIter& rEntry){
276 UserData* userData = weld::fromId<UserData*>(m_xCertLB->get_id(rEntry));
277 aRet.push_back( userData->xCertificate );
278 return false;
279 });
280 }
281 else
282 {
283 uno::Reference< css::security::XCertificate > xCert;
284 int nSel = m_xCertLB->get_selected_index();
285 if (nSel != -1)
286 {
287 UserData* userData = weld::fromId<UserData*>(m_xCertLB->get_id(nSel));
288 xCert = userData->xCertificate;
289 }
290 aRet.push_back( xCert );
291 }
292
293#if HAVE_FEATURE_GPGME
294 if ( mxEncryptToSelf.is())
295 aRet.push_back( mxEncryptToSelf );
296#endif
297
299}
300
301uno::Reference<xml::crypto::XXMLSecurityContext> CertificateChooser::GetSelectedSecurityContext() const
302{
303 int nSel = m_xCertLB->get_selected_index();
304 if (nSel == -1)
305 return uno::Reference<xml::crypto::XXMLSecurityContext>();
306
307 UserData* userData = weld::fromId<UserData*>(m_xCertLB->get_id(nSel));
308 uno::Reference<xml::crypto::XXMLSecurityContext> xCert = userData->xSecurityContext;
309 return xCert;
310}
311
313{
314 return m_xDescriptionED->get_text();
315}
316
318{
319 uno::Sequence< uno::Reference<css::security::XCertificate> > xCerts =
321 return (xCerts.hasElements() && xCerts[0].is()) ?
322 UsageInClearText(xCerts[0]->getCertificateUsage()) : OUString();
323}
324
326{
327 ImplInitialize(true);
328}
329
330IMPL_LINK_NOARG(CertificateChooser, CertificateHighlightHdl, weld::TreeView&, void)
331{
332 bool bEnable = m_xCertLB->get_selected_index() != -1;
333 m_xViewBtn->set_sensitive(bEnable);
334 m_xOKBtn->set_sensitive(bEnable);
335 m_xDescriptionED->set_sensitive(bEnable);
336}
337
339{
340 m_xDialog->response(RET_OK);
341 return true;
342}
343
345{
346 ImplShowCertificateDetails();
347}
348
350{
351 int nSel = m_xCertLB->get_selected_index();
352 if (nSel == -1)
353 return;
354
355 UserData* userData = weld::fromId<UserData*>(m_xCertLB->get_id(nSel));
356
357 if (!userData->xSecurityEnvironment.is() || !userData->xCertificate.is())
358 return;
359
360 CertificateViewer aViewer(m_xDialog.get(), userData->xSecurityEnvironment, userData->xCertificate, true, this);
361 aViewer.run();
362}
363
364/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Reference< XExecutableDialog > m_xDialog
IMPL_LINK_NOARG(CertificateChooser, SearchModifyHdl, weld::Entry &, void)
static OUString UsageInClearText(int bits)
CertificateChooser(weld::Window *pParent, std::vector< css::uno::Reference< css::xml::crypto::XXMLSecurityContext > > &&rxSecurityContexts, UserAction eAction)
std::unique_ptr< weld::Button > m_xViewBtn
void ImplInitialize(bool mbSearch=false)
std::unique_ptr< weld::Entry > m_xSearchBox
static void HandleOneUsageBit(OUString &string, int &bits, int bit, TranslateId name)
virtual ~CertificateChooser() override
std::unique_ptr< weld::Label > m_xFTDescription
UserAction const meAction
std::vector< std::shared_ptr< UserData > > mvUserData
css::uno::Reference< css::security::XCertificate > mxEncryptToSelf
std::vector< css::uno::Reference< css::xml::crypto::XXMLSecurityContext > > mxSecurityContexts
std::unique_ptr< weld::Button > m_xOKBtn
css::uno::Reference< css::xml::crypto::XXMLSecurityContext > GetSelectedSecurityContext() const
std::unique_ptr< weld::Label > m_xFTEncrypt
std::unique_ptr< weld::Label > m_xFTSign
std::unordered_map< css::uno::Reference< css::xml::crypto::XXMLSecurityContext >, css::uno::Sequence< css::uno::Reference< css::security::XCertificate > > > xMemCerts
OUString GetDescription() const
Gets the description string provided when selecting the certificate.
css::uno::Sequence< css::uno::Reference< css::security::XCertificate > > GetSelectedCertificates()
std::unique_ptr< weld::Entry > m_xDescriptionED
short run() override
std::unique_ptr< weld::TreeView > m_xCertLB
OUString GetUsageText()
Returns the usage string of the selected certificate, if any.
OUString uppercase(const OUString &rStr, sal_Int32 nPos, sal_Int32 nCount) const
const CharClass & GetCharClass() const
OUString GetSigningKey() const
bool GetEncryptToSelf() const
OUString GetEncryptionKey() const
virtual short run()
std::shared_ptr< weld::Dialog > m_xDialog
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
long Long
OUString GetDateString(const css::util::DateTime &_rDT)
OUString toId(const void *pValue)
OUString XsResId(TranslateId aId)
Any result
#define bit(name)
OUString sId
RET_OK