diff options
Diffstat (limited to 'xmlsecurity/source/helper/pdfsignaturehelper.cxx')
-rw-r--r-- | xmlsecurity/source/helper/pdfsignaturehelper.cxx | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/xmlsecurity/source/helper/pdfsignaturehelper.cxx b/xmlsecurity/source/helper/pdfsignaturehelper.cxx new file mode 100644 index 000000000..b0795cb8f --- /dev/null +++ b/xmlsecurity/source/helper/pdfsignaturehelper.cxx @@ -0,0 +1,187 @@ +/* -*- 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 <pdfsignaturehelper.hxx> + +#include <memory> + +#include <com/sun/star/io/XTruncate.hpp> +#include <com/sun/star/io/XStream.hpp> +#include <com/sun/star/security/CertificateValidity.hpp> +#include <com/sun/star/uno/SecurityException.hpp> +#include <com/sun/star/security/DocumentSignatureInformation.hpp> +#include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp> + +#include <unotools/ucbstreamhelper.hxx> +#include <vcl/filter/pdfdocument.hxx> + +#include <pdfio/pdfdocument.hxx> +#include <tools/diagnose_ex.h> +#include <sal/log.hxx> + +using namespace ::com::sun::star; + +PDFSignatureHelper::PDFSignatureHelper() = default; + +bool PDFSignatureHelper::ReadAndVerifySignature( + const uno::Reference<io::XInputStream>& xInputStream) +{ + if (!xInputStream.is()) + { + SAL_WARN("xmlsecurity.helper", "input stream missing"); + return false; + } + + std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(xInputStream, true)); + vcl::filter::PDFDocument aDocument; + if (!aDocument.Read(*pStream)) + { + SAL_WARN("xmlsecurity.helper", "failed to read the document"); + return false; + } + + std::vector<vcl::filter::PDFObjectElement*> aSignatures = aDocument.GetSignatureWidgets(); + if (aSignatures.empty()) + return true; + + m_aSignatureInfos.clear(); + + int nMDPPerm = aDocument.GetMDPPerm(); + + for (size_t i = 0; i < aSignatures.size(); ++i) + { + SignatureInformation aInfo(i); + + if (!xmlsecurity::pdfio::ValidateSignature(*pStream, aSignatures[i], aInfo, aDocument, + nMDPPerm)) + SAL_WARN("xmlsecurity.helper", "failed to determine digest match"); + + m_aSignatureInfos.push_back(aInfo); + } + + return true; +} + +SignatureInformations const& PDFSignatureHelper::GetSignatureInformations() const +{ + return m_aSignatureInfos; +} + +uno::Sequence<security::DocumentSignatureInformation> +PDFSignatureHelper::GetDocumentSignatureInformations( + const uno::Reference<xml::crypto::XSecurityEnvironment>& xSecEnv) const +{ + uno::Sequence<security::DocumentSignatureInformation> aRet(m_aSignatureInfos.size()); + + for (size_t i = 0; i < m_aSignatureInfos.size(); ++i) + { + const SignatureInformation& rInternal = m_aSignatureInfos[i]; + security::DocumentSignatureInformation& rExternal = aRet[i]; + rExternal.SignatureIsValid + = rInternal.nStatus == xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED; + if (!rInternal.ouX509Certificate.isEmpty()) + rExternal.Signer = xSecEnv->createCertificateFromAscii(rInternal.ouX509Certificate); + rExternal.PartialDocumentSignature = rInternal.bPartialDocumentSignature; + + // Verify certificate. + if (rExternal.Signer.is()) + { + try + { + rExternal.CertificateStatus = xSecEnv->verifyCertificate(rExternal.Signer, {}); + } + catch (const uno::SecurityException&) + { + DBG_UNHANDLED_EXCEPTION("xmlsecurity.helper", "failed to verify certificate"); + rExternal.CertificateStatus = security::CertificateValidity::INVALID; + } + } + else + rExternal.CertificateStatus = security::CertificateValidity::INVALID; + } + + return aRet; +} + +sal_Int32 PDFSignatureHelper::GetNewSecurityId() const { return m_aSignatureInfos.size(); } + +void PDFSignatureHelper::SetX509Certificate( + const uno::Reference<security::XCertificate>& xCertificate) +{ + m_xCertificate = xCertificate; +} + +void PDFSignatureHelper::SetDescription(const OUString& rDescription) +{ + m_aDescription = rDescription; +} + +bool PDFSignatureHelper::Sign(const uno::Reference<io::XInputStream>& xInputStream, bool bAdES) +{ + std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(xInputStream, true)); + vcl::filter::PDFDocument aDocument; + if (!aDocument.Read(*pStream)) + { + SAL_WARN("xmlsecurity.helper", "failed to read the document"); + return false; + } + + if (!aDocument.Sign(m_xCertificate, m_aDescription, bAdES)) + { + SAL_WARN("xmlsecurity.helper", "failed to sign"); + return false; + } + + uno::Reference<io::XStream> xStream(xInputStream, uno::UNO_QUERY); + std::unique_ptr<SvStream> pOutStream(utl::UcbStreamHelper::CreateStream(xStream, true)); + if (!aDocument.Write(*pOutStream)) + { + SAL_WARN("xmlsecurity.helper", "failed to write signed data"); + return false; + } + + return true; +} + +bool PDFSignatureHelper::RemoveSignature(const uno::Reference<io::XInputStream>& xInputStream, + sal_uInt16 nPosition) +{ + std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(xInputStream, true)); + vcl::filter::PDFDocument aDocument; + if (!aDocument.Read(*pStream)) + { + SAL_WARN("xmlsecurity.helper", "failed to read the document"); + return false; + } + + if (!aDocument.RemoveSignature(nPosition)) + { + SAL_WARN("xmlsecurity.helper", "failed to remove signature"); + return false; + } + + uno::Reference<io::XStream> xStream(xInputStream, uno::UNO_QUERY); + uno::Reference<io::XTruncate> xTruncate(xStream, uno::UNO_QUERY); + if (!xTruncate.is()) + { + SAL_WARN("xmlsecurity.helper", "failed to truncate"); + return false; + } + xTruncate->truncate(); + std::unique_ptr<SvStream> pOutStream(utl::UcbStreamHelper::CreateStream(xStream, true)); + if (!aDocument.Write(*pOutStream)) + { + SAL_WARN("xmlsecurity.helper", "failed to write without signature"); + return false; + } + + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |