LibreOffice Module xmlsecurity (master) 1
SecurityEnvironment.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
11#include "CertificateImpl.hxx"
12
13#include <com/sun/star/security/CertificateCharacters.hpp>
14#include <com/sun/star/security/CertificateValidity.hpp>
15
17#include <vector>
18#include <rtl/ref.hxx>
19
20#ifdef _WIN32
21#include <config_folders.h>
22#include <osl/file.hxx>
23#include <osl/process.h>
24#include <rtl/bootstrap.hxx>
25#include <tools/urlobj.hxx>
26#endif
27
28#include <key.h>
29#include <keylistresult.h>
30#include <xmlsec-wrapper.h>
31
32#if defined _MSC_VER && defined __clang__
33#pragma clang diagnostic push
34#pragma clang diagnostic ignored "-Wundef"
35#endif
36#include <gpgme.h>
37#if defined _MSC_VER && defined __clang__
38#pragma clang diagnostic pop
39#endif
40#include <context.h>
41
42using namespace css;
43using namespace css::security;
44using namespace css::uno;
45using namespace css::lang;
46
48{
49#ifdef _WIN32
50 // On Windows, gpgme expects gpgme-w32spawn.exe to be in the same directory as the current
51 // process executable. This assumption might be wrong, e.g., for bundled python, which is
52 // in instdir/program/python-core-x.y.z/bin, while gpgme-w32spawn.exe is in instdir/program.
53 // If we can't find gpgme-w32spawn.exe in the current executable location, then try to find
54 // the spawn executable, and inform gpgme about actual location using gpgme_set_global_flag.
55 [[maybe_unused]] static bool bSpawnPathInitialized = [] {
56 auto accessUrl = [](const INetURLObject& url) {
57 osl::File file(url.GetMainURL(INetURLObject::DecodeMechanism::NONE));
58 return file.open(osl_File_OpenFlag_Read) == osl::FileBase::E_None;
59 };
60 OUString sPath;
61 osl_getExecutableFile(&sPath.pData);
62 INetURLObject aPathUrl(sPath);
63 aPathUrl.setName(u"gpgme-w32spawn.exe");
64 if (!accessUrl(aPathUrl))
65 {
66 sPath = "$BRAND_BASE_DIR/" LIBO_LIBEXEC_FOLDER "/gpgme-w32spawn.exe";
67 rtl::Bootstrap::expandMacros(sPath);
68 aPathUrl.SetURL(sPath);
69 if (accessUrl(aPathUrl))
70 {
71 aPathUrl.removeSegment();
72 GpgME::setGlobalFlag("w32-inst-dir",
73 aPathUrl.getFSysPath(FSysStyle::Dos).toUtf8().getStr());
74 }
75 }
76 return true;
77 }();
78#endif
79 GpgME::Error err = GpgME::checkEngine(GpgME::OpenPGP);
80 if (err)
81 throw RuntimeException("The GpgME library failed to initialize for the OpenPGP protocol.");
82
83 m_ctx.reset( GpgME::Context::createForProtocol(GpgME::OpenPGP) );
84 if (m_ctx == nullptr)
85 throw RuntimeException("The GpgME library failed to initialize for the OpenPGP protocol.");
86 m_ctx->setArmor(false);
87}
88
90{
91}
92
94{
95 return OUString();
96}
97
98Sequence< Reference < XCertificate > > SecurityEnvironmentGpg::getCertificatesImpl( bool bPrivateOnly )
99{
100 std::vector< GpgME::Key > keyList;
101 std::vector< rtl::Reference<CertificateImpl> > certsList;
102
103 m_ctx->setKeyListMode(GPGME_KEYLIST_MODE_LOCAL);
104 GpgME::Error err = m_ctx->startKeyListing("", bPrivateOnly );
105 while (!err) {
106 GpgME::Key k = m_ctx->nextKey(err);
107 if (err)
108 break;
109 if (!k.isRevoked() && !k.isExpired() && !k.isDisabled() && !k.isInvalid()) {
110 // We can't create CertificateImpl here as CertificateImpl::setCertificate uses GpgME API
111 // which interrupts our key listing here. So first get the keys from GpgME, then create the CertificateImpls
112 keyList.push_back(k);
113 }
114 }
115 m_ctx->endKeyListing();
116
117 for (auto const& key : keyList) {
119 xCert->setCertificate(m_ctx.get(),key);
120 certsList.push_back(xCert);
121 }
122
123 Sequence< Reference< XCertificate > > xCertificateSequence(certsList.size());
124 auto xCertificateSequenceRange = asNonConstRange(xCertificateSequence);
125 int i = 0;
126 for (const auto& cert : certsList) {
127 xCertificateSequenceRange[i++] = cert;
128 }
129
130 return xCertificateSequence;
131}
132
133Sequence< Reference < XCertificate > > SecurityEnvironmentGpg::getPersonalCertificates()
134{
135 return getCertificatesImpl( true );
136}
137
138Sequence< Reference < XCertificate > > SecurityEnvironmentGpg::getAllCertificates()
139{
140 return getCertificatesImpl( false );
141}
142
143Reference< XCertificate > SecurityEnvironmentGpg::getCertificate( const OUString& keyId, const Sequence< sal_Int8 >& /*serialNumber*/ )
144{
145 //xmlChar* pSignatureValue=xmlNodeGetContent(cur);
146 OString ostr = OUStringToOString( keyId , RTL_TEXTENCODING_UTF8 );
147 const xmlChar* strKeyId = reinterpret_cast<const xmlChar*>(ostr.getStr());
148 xmlSecSize nWritten;
149 int nRet = xmlSecBase64Decode_ex(strKeyId, const_cast<xmlSecByte*>(strKeyId), xmlStrlen(strKeyId), &nWritten);
150 if(nRet < 0)
151 throw RuntimeException("Base64 decode failed");
152
153 m_ctx->setKeyListMode(GPGME_KEYLIST_MODE_LOCAL);
154 GpgME::Error err = m_ctx->startKeyListing("", false);
155 while (!err) {
156 GpgME::Key k = m_ctx->nextKey(err);
157 if (err)
158 break;
159 if (!k.isInvalid() && strcmp(k.primaryFingerprint(), reinterpret_cast<const char*>(strKeyId)) == 0) {
161 xCert->setCertificate(m_ctx.get(), k);
162 m_ctx->endKeyListing();
163 return xCert;
164 }
165 }
166 m_ctx->endKeyListing();
167
168 return nullptr;
169}
170
171Sequence< Reference < XCertificate > > SecurityEnvironmentGpg::buildCertificatePath( const Reference< XCertificate >& /*begin*/ )
172{
173 return Sequence< Reference < XCertificate > >();
174}
175
176Reference< XCertificate > SecurityEnvironmentGpg::createCertificateFromRaw( const Sequence< sal_Int8 >& /*rawCertificate*/ )
177{
178 return nullptr;
179}
180
181Reference< XCertificate > SecurityEnvironmentGpg::createCertificateFromAscii( const OUString& /*asciiCertificate*/ )
182{
183 return nullptr;
184}
185
186sal_Int32 SecurityEnvironmentGpg::verifyCertificate( const Reference< XCertificate >& aCert,
187 const Sequence< Reference< XCertificate > >& /*intermediateCerts*/ )
188{
189 const CertificateImpl* xCert = dynamic_cast<CertificateImpl*>(aCert.get());
190 if (xCert == nullptr) {
191 // Can't find the key locally -> unknown owner
192 return security::CertificateValidity::ISSUER_UNKNOWN;
193 }
194
195 const GpgME::Key* key = xCert->getCertificate();
196 if (key->ownerTrust() == GpgME::Key::OwnerTrust::Marginal ||
197 key->ownerTrust() == GpgME::Key::OwnerTrust::Full ||
198 key->ownerTrust() == GpgME::Key::OwnerTrust::Ultimate)
199 {
200 return security::CertificateValidity::VALID;
201 }
202
203 return security::CertificateValidity::ISSUER_UNTRUSTED;
204}
205
207 const Reference< XCertificate >& aCert)
208{
209 if (dynamic_cast<CertificateImpl*>(aCert.get()) == nullptr)
210 throw RuntimeException();
211
212 // we only listed private keys anyway, up in
213 // SecurityEnvironmentGpg::getPersonalCertificates
214 return CertificateCharacters::HAS_PRIVATE_KEY;
215}
216
217/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const GpgME::Key * getCertificate() const
bool removeSegment(sal_Int32 nIndex=LAST_SEGMENT, bool bIgnoreFinalSlash=true)
bool setName(std::u16string_view rTheName, EncodeMechanism eMechanism=EncodeMechanism::WasEncoded, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8)
OUString getFSysPath(FSysStyle eStyle, sal_Unicode *pDelimiter=nullptr) const
bool SetURL(std::u16string_view rTheAbsURIRef, EncodeMechanism eMechanism=EncodeMechanism::WasEncoded, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8)
virtual OUString SAL_CALL getSecurityEnvironmentInformation() override
css::uno::Sequence< css::uno::Reference< css::security::XCertificate > > getCertificatesImpl(bool bPrivateOnly)
virtual css::uno::Reference< css::security::XCertificate > SAL_CALL createCertificateFromRaw(const css::uno::Sequence< sal_Int8 > &rawCertificate) override
std::unique_ptr< GpgME::Context > m_ctx
virtual css::uno::Sequence< css::uno::Reference< css::security::XCertificate > > SAL_CALL buildCertificatePath(const css::uno::Reference< css::security::XCertificate > &beginCert) override
virtual css::uno::Sequence< css::uno::Reference< css::security::XCertificate > > SAL_CALL getAllCertificates() override
virtual ::sal_Int32 SAL_CALL verifyCertificate(const css::uno::Reference< css::security::XCertificate > &xCert, const css::uno::Sequence< css::uno::Reference< css::security::XCertificate > > &intermediateCerts) override
virtual ::sal_Int32 SAL_CALL getCertificateCharacters(const css::uno::Reference< css::security::XCertificate > &xCert) override
virtual ~SecurityEnvironmentGpg() override
virtual css::uno::Sequence< css::uno::Reference< css::security::XCertificate > > SAL_CALL getPersonalCertificates() override
virtual css::uno::Reference< css::security::XCertificate > SAL_CALL createCertificateFromAscii(const OUString &asciiCertificate) override
virtual css::uno::Reference< css::security::XCertificate > SAL_CALL getCertificate(const OUString &keyId, const css::uno::Sequence< sal_Int8 > &serialNumber) override
We reinterpret the first parameter (originally issuerName) as keyId.
float u
err
int i
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)