Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / xmlsecurity / source / gpg / SecurityEnvironment.cxx
blob290529bc8ae6efa14cad11d677bc11622788e8e6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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 */
10 #include "SecurityEnvironment.hxx"
11 #include "CertificateImpl.hxx"
13 #include <com/sun/star/security/CertificateCharacters.hpp>
14 #include <com/sun/star/security/CertificateValidity.hpp>
16 #include <comphelper/servicehelper.hxx>
17 #include <vector>
19 #ifdef _WIN32
20 #include <config_folders.h>
21 #include <osl/file.hxx>
22 #include <osl/process.h>
23 #include <rtl/bootstrap.hxx>
24 #include <tools/urlobj.hxx>
25 #endif
27 #include <key.h>
28 #include <keylistresult.h>
29 #include <xmlsec-wrapper.h>
31 #if defined _MSC_VER && defined __clang__
32 #pragma clang diagnostic push
33 #pragma clang diagnostic ignored "-Wundef"
34 #endif
35 #include <gpgme.h>
36 #if defined _MSC_VER && defined __clang__
37 #pragma clang diagnostic pop
38 #endif
39 #include <context.h>
41 using namespace css;
42 using namespace css::security;
43 using namespace css::uno;
44 using namespace css::lang;
46 SecurityEnvironmentGpg::SecurityEnvironmentGpg()
48 #ifdef _WIN32
49 // On Windows, gpgme expects gpgme-w32spawn.exe to be in the same directory as the current
50 // process executable. This assumption might be wrong, e.g., for bundled python, which is
51 // in instdir/program/python-core-x.y.z/bin, while gpgme-w32spawn.exe is in instdir/program.
52 // If we can't find gpgme-w32spawn.exe in the current executable location, then try to find
53 // the spawn executable, and inform gpgme about actual location using gpgme_set_global_flag.
54 [[maybe_unused]] static bool bSpawnPathInitialized = [] {
55 auto accessUrl = [](const INetURLObject& url) {
56 osl::File file(url.GetMainURL(INetURLObject::DecodeMechanism::NONE));
57 return file.open(osl_File_OpenFlag_Read) == osl::FileBase::E_None;
59 OUString sPath;
60 osl_getExecutableFile(&sPath.pData);
61 INetURLObject aPathUrl(sPath);
62 aPathUrl.setName("gpgme-w32spawn.exe");
63 if (!accessUrl(aPathUrl))
65 sPath = "$BRAND_BASE_DIR/" LIBO_LIBEXEC_FOLDER "/gpgme-w32spawn.exe";
66 rtl::Bootstrap::expandMacros(sPath);
67 aPathUrl.SetURL(sPath);
68 if (accessUrl(aPathUrl))
70 aPathUrl.removeSegment();
71 GpgME::setGlobalFlag("w32-inst-dir",
72 aPathUrl.getFSysPath(FSysStyle::Dos).toUtf8().getStr());
75 return true;
76 }();
77 #endif
78 GpgME::Error err = GpgME::checkEngine(GpgME::OpenPGP);
79 if (err)
80 throw RuntimeException("The GpgME library failed to initialize for the OpenPGP protocol.");
82 m_ctx.reset( GpgME::Context::createForProtocol(GpgME::OpenPGP) );
83 if (m_ctx == nullptr)
84 throw RuntimeException("The GpgME library failed to initialize for the OpenPGP protocol.");
85 m_ctx->setArmor(false);
88 SecurityEnvironmentGpg::~SecurityEnvironmentGpg()
92 /* XUnoTunnel */
93 sal_Int64 SAL_CALL SecurityEnvironmentGpg::getSomething( const Sequence< sal_Int8 >& aIdentifier )
95 if( isUnoTunnelId<SecurityEnvironmentGpg>(aIdentifier) ) {
96 return sal::static_int_cast<sal_Int64>(reinterpret_cast<sal_uIntPtr>(this));
98 return 0 ;
101 /* XUnoTunnel extension */
103 namespace
105 class theSecurityEnvironmentUnoTunnelId : public rtl::Static< UnoTunnelIdInit, theSecurityEnvironmentUnoTunnelId > {};
108 const Sequence< sal_Int8>& SecurityEnvironmentGpg::getUnoTunnelId() {
109 return theSecurityEnvironmentUnoTunnelId::get().getSeq();
112 OUString SecurityEnvironmentGpg::getSecurityEnvironmentInformation()
114 return OUString();
117 Sequence< Reference < XCertificate > > SecurityEnvironmentGpg::getCertificatesImpl( bool bPrivateOnly )
119 CertificateImpl* xCert;
120 std::vector< GpgME::Key > keyList;
121 std::vector< CertificateImpl* > certsList;
123 m_ctx->setKeyListMode(GPGME_KEYLIST_MODE_LOCAL);
124 GpgME::Error err = m_ctx->startKeyListing("", bPrivateOnly );
125 while (!err) {
126 GpgME::Key k = m_ctx->nextKey(err);
127 if (err)
128 break;
129 if (!k.isRevoked() && !k.isExpired() && !k.isDisabled() && !k.isInvalid()) {
130 // We can't create CertificateImpl here as CertificateImpl::setCertificate uses GpgME API
131 // which interrupts our key listing here. So first get the keys from GpgME, then create the CertificateImpls
132 keyList.push_back(k);
135 m_ctx->endKeyListing();
137 for (auto const& key : keyList) {
138 xCert = new CertificateImpl();
139 xCert->setCertificate(m_ctx.get(),key);
140 certsList.push_back(xCert);
143 Sequence< Reference< XCertificate > > xCertificateSequence(certsList.size());
144 int i = 0;
145 for (auto const& cert : certsList) {
146 xCertificateSequence[i++] = cert;
149 return xCertificateSequence;
152 Sequence< Reference < XCertificate > > SecurityEnvironmentGpg::getPersonalCertificates()
154 return getCertificatesImpl( true );
157 Sequence< Reference < XCertificate > > SecurityEnvironmentGpg::getAllCertificates()
159 return getCertificatesImpl( false );
162 Reference< XCertificate > SecurityEnvironmentGpg::getCertificate( const OUString& keyId, const Sequence< sal_Int8 >& /*serialNumber*/ )
164 CertificateImpl* xCert=nullptr;
166 //xmlChar* pSignatureValue=xmlNodeGetContent(cur);
167 OString ostr = OUStringToOString( keyId , RTL_TEXTENCODING_UTF8 );
168 const xmlChar* strKeyId = reinterpret_cast<const xmlChar*>(ostr.getStr());
169 if(xmlSecBase64Decode(strKeyId, const_cast<xmlSecByte*>(strKeyId), xmlStrlen(strKeyId)) < 0)
170 throw RuntimeException("Base64 decode failed");
172 m_ctx->setKeyListMode(GPGME_KEYLIST_MODE_LOCAL);
173 GpgME::Error err = m_ctx->startKeyListing("", false);
174 while (!err) {
175 GpgME::Key k = m_ctx->nextKey(err);
176 if (err)
177 break;
178 if (!k.isInvalid() && strcmp(k.primaryFingerprint(), reinterpret_cast<const char*>(strKeyId)) == 0) {
179 xCert = new CertificateImpl();
180 xCert->setCertificate(m_ctx.get(), k);
181 m_ctx->endKeyListing();
182 return xCert;
185 m_ctx->endKeyListing();
187 return nullptr;
190 Sequence< Reference < XCertificate > > SecurityEnvironmentGpg::buildCertificatePath( const Reference< XCertificate >& /*begin*/ )
192 return Sequence< Reference < XCertificate > >();
195 Reference< XCertificate > SecurityEnvironmentGpg::createCertificateFromRaw( const Sequence< sal_Int8 >& /*rawCertificate*/ )
197 return nullptr;
200 Reference< XCertificate > SecurityEnvironmentGpg::createCertificateFromAscii( const OUString& /*asciiCertificate*/ )
202 return nullptr;
205 sal_Int32 SecurityEnvironmentGpg::verifyCertificate( const Reference< XCertificate >& aCert,
206 const Sequence< Reference< XCertificate > >& /*intermediateCerts*/ )
208 const CertificateImpl* xCert = dynamic_cast<CertificateImpl*>(aCert.get());
209 if (xCert == nullptr) {
210 // Can't find the key locally -> unknown owner
211 return security::CertificateValidity::ISSUER_UNKNOWN;
214 const GpgME::Key* key = xCert->getCertificate();
215 if (key->ownerTrust() == GpgME::Key::OwnerTrust::Marginal ||
216 key->ownerTrust() == GpgME::Key::OwnerTrust::Full ||
217 key->ownerTrust() == GpgME::Key::OwnerTrust::Ultimate)
219 return security::CertificateValidity::VALID;
222 return security::CertificateValidity::ISSUER_UNTRUSTED;
225 sal_Int32 SecurityEnvironmentGpg::getCertificateCharacters(
226 const Reference< XCertificate >& aCert)
228 const CertificateImpl* xCert;
229 Reference< XUnoTunnel > xCertTunnel(aCert, UNO_QUERY_THROW) ;
230 xCert = reinterpret_cast<CertificateImpl*>(sal::static_int_cast<sal_uIntPtr>(xCertTunnel->getSomething(CertificateImpl::getUnoTunnelId()))) ;
231 if (xCert == nullptr)
232 throw RuntimeException();
234 // we only listed private keys anyway, up in
235 // SecurityEnvironmentGpg::getPersonalCertificates
236 return CertificateCharacters::HAS_PRIVATE_KEY;
239 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */