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