0de900cec7
The final goal of this API is to give time & hash information about the PDF signature, so once a 3rd-party produces the PKCS#7 signature, that can be added to the document and the actual PDF sign can be re-run with the same parameters. This commit continues the replacement of XCertificate with svl::crypto::SigningContext up to the point that the timestamp used in svl/ can be exposed on the LOK API. This is done by updating DocumentSignatureManager::add(), PDFSignatureHelper::SetX509Certificate(), vcl::filter::PDFDocument::Sign() and finally the svl::crypto::Signing ctor to work with the signing context instead of an XCertificate directly. Time reporting works now, so add a test for that. The digest part still needs doing. Change-Id: I83f1274cd420b67194b7caf12b1027e623d4f7fe Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176404 Reviewed-by: Miklos Vajna <vmiklos@collabora.com> Tested-by: Jenkins
219 lines
7.1 KiB
C++
219 lines
7.1 KiB
C++
/* -*- 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 <iostream>
|
|
#include <string_view>
|
|
|
|
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
|
|
#include <com/sun/star/uno/XComponentContext.hpp>
|
|
#include <com/sun/star/xml/crypto/SEInitializer.hpp>
|
|
|
|
#include <comphelper/processfactory.hxx>
|
|
#include <cppuhelper/bootstrap.hxx>
|
|
#include <osl/file.hxx>
|
|
#include <sal/log.hxx>
|
|
#include <sal/main.h>
|
|
#include <comphelper/diagnose_ex.hxx>
|
|
#include <vcl/filter/PngImageWriter.hxx>
|
|
#include <vcl/svapp.hxx>
|
|
#include <vcl/graphicfilter.hxx>
|
|
#include <vcl/filter/pdfdocument.hxx>
|
|
#include <comphelper/scopeguard.hxx>
|
|
#include <svl/sigstruct.hxx>
|
|
#include <svl/cryptosign.hxx>
|
|
|
|
#include <pdfsignaturehelper.hxx>
|
|
|
|
using namespace com::sun::star;
|
|
|
|
namespace
|
|
{
|
|
/// Does PDF to PNG conversion using pdfium.
|
|
void generatePreview(std::string_view rPdfPath, std::string_view rPngPath)
|
|
{
|
|
GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
|
|
Graphic aGraphic;
|
|
OUString aInURL;
|
|
osl::FileBase::getFileURLFromSystemPath(OUString::fromUtf8(rPdfPath), aInURL);
|
|
SvFileStream aInStream(aInURL, StreamMode::READ);
|
|
if (rFilter.ImportGraphic(aGraphic, u"", aInStream, GRFILTER_FORMAT_DONTKNOW, nullptr,
|
|
GraphicFilterImportFlags::NONE)
|
|
!= ERRCODE_NONE)
|
|
return;
|
|
|
|
BitmapEx aBitmapEx = aGraphic.GetBitmapEx();
|
|
OUString aOutURL;
|
|
osl::FileBase::getFileURLFromSystemPath(OUString::fromUtf8(rPngPath), aOutURL);
|
|
SvFileStream aOutStream(aOutURL, StreamMode::WRITE);
|
|
vcl::PngImageWriter aWriter(aOutStream);
|
|
aWriter.write(aBitmapEx);
|
|
}
|
|
|
|
int pdfVerify(int nArgc, char** pArgv)
|
|
{
|
|
if (nArgc < 2)
|
|
{
|
|
SAL_WARN("xmlsecurity.workben", "not enough parameters");
|
|
return 1;
|
|
}
|
|
|
|
// Initialize nss / mscrypto.
|
|
uno::Reference<uno::XComponentContext> xComponentContext;
|
|
try
|
|
{
|
|
xComponentContext = cppu::defaultBootstrap_InitialComponentContext();
|
|
}
|
|
catch (const uno::RuntimeException&)
|
|
{
|
|
TOOLS_WARN_EXCEPTION("xmlsecurity.workben",
|
|
"cppu::defaultBootstrap_InitialComponentContext() failed:");
|
|
return 1;
|
|
}
|
|
uno::Reference<lang::XMultiComponentFactory> xMultiComponentFactory
|
|
= xComponentContext->getServiceManager();
|
|
uno::Reference<lang::XMultiServiceFactory> xMultiServiceFactory(xMultiComponentFactory,
|
|
uno::UNO_QUERY);
|
|
comphelper::setProcessServiceFactory(xMultiServiceFactory);
|
|
|
|
InitVCL();
|
|
comphelper::ScopeGuard g([] { DeInitVCL(); });
|
|
if (nArgc > 3 && pArgv[3] == std::string_view("-p"))
|
|
{
|
|
generatePreview(pArgv[1], pArgv[2]);
|
|
return 0;
|
|
}
|
|
|
|
uno::Reference<xml::crypto::XSEInitializer> xSEInitializer;
|
|
try
|
|
{
|
|
xSEInitializer = xml::crypto::SEInitializer::create(xComponentContext);
|
|
}
|
|
catch (const uno::DeploymentException&)
|
|
{
|
|
TOOLS_WARN_EXCEPTION("xmlsecurity.workben",
|
|
"DeploymentException while creating SEInitializer:");
|
|
return 1;
|
|
}
|
|
uno::Reference<xml::crypto::XXMLSecurityContext> xSecurityContext
|
|
= xSEInitializer->createSecurityContext(OUString());
|
|
|
|
OUString aInURL;
|
|
osl::FileBase::getFileURLFromSystemPath(OUString::fromUtf8(pArgv[1]), aInURL);
|
|
OUString aOutURL;
|
|
if (nArgc > 2)
|
|
osl::FileBase::getFileURLFromSystemPath(OUString::fromUtf8(pArgv[2]), aOutURL);
|
|
|
|
bool bRemoveSignature = false;
|
|
if (nArgc > 3 && pArgv[3] == std::string_view("-r"))
|
|
bRemoveSignature = true;
|
|
|
|
SvFileStream aStream(aInURL, StreamMode::READ);
|
|
if (aOutURL.isEmpty() && !bRemoveSignature)
|
|
{
|
|
std::cerr << "verifying signatures" << std::endl;
|
|
PDFSignatureHelper aHelper;
|
|
aStream.Seek(0);
|
|
aHelper.ReadAndVerifySignatureSvStream(aStream);
|
|
if (aHelper.GetSignatureInformations().empty())
|
|
std::cerr << "found no signatures" << std::endl;
|
|
else
|
|
{
|
|
std::cerr << "found " << aHelper.GetSignatureInformations().size() << " signatures"
|
|
<< std::endl;
|
|
for (size_t i = 0; i < aHelper.GetSignatureInformations().size(); ++i)
|
|
{
|
|
const SignatureInformation& rInfo = aHelper.GetSignatureInformations()[i];
|
|
bool bSuccess
|
|
= rInfo.nStatus == xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
|
|
std::cerr << "signature #" << i << ": digest match? " << bSuccess << std::endl;
|
|
std::cerr << "signature #" << i << ": partial? " << rInfo.bPartialDocumentSignature
|
|
<< std::endl;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
vcl::filter::PDFDocument aDocument;
|
|
if (!aDocument.Read(aStream))
|
|
{
|
|
SAL_WARN("xmlsecurity.workben", "failed to read the document");
|
|
return 1;
|
|
}
|
|
|
|
if (bRemoveSignature)
|
|
{
|
|
std::cerr << "removing the last signature" << std::endl;
|
|
std::vector<vcl::filter::PDFObjectElement*> aSignatures = aDocument.GetSignatureWidgets();
|
|
if (aSignatures.empty())
|
|
{
|
|
std::cerr << "found no signatures" << std::endl;
|
|
return 1;
|
|
}
|
|
|
|
size_t nPosition = aSignatures.size() - 1;
|
|
if (!aDocument.RemoveSignature(nPosition))
|
|
{
|
|
SAL_WARN("xmlsecurity.workben", "failed to remove signature #" << nPosition);
|
|
return 1;
|
|
}
|
|
|
|
SvFileStream aOutStream(aOutURL, StreamMode::WRITE | StreamMode::TRUNC);
|
|
if (!aDocument.Write(aOutStream))
|
|
{
|
|
SAL_WARN("xmlsecurity.workben", "failed to write the document");
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
std::cerr << "adding a new signature" << std::endl;
|
|
uno::Reference<xml::crypto::XSecurityEnvironment> xSecurityEnvironment
|
|
= xSecurityContext->getSecurityEnvironment();
|
|
uno::Sequence<uno::Reference<security::XCertificate>> aCertificates
|
|
= xSecurityEnvironment->getPersonalCertificates();
|
|
if (!aCertificates.hasElements())
|
|
{
|
|
SAL_WARN("xmlsecurity.workben", "no signing certificates found");
|
|
return 1;
|
|
}
|
|
svl::crypto::SigningContext aSigningContext;
|
|
aSigningContext.m_xCertificate = aCertificates[0];
|
|
if (!aDocument.Sign(aSigningContext, u"pdfverify"_ustr, /*bAdES=*/true))
|
|
{
|
|
SAL_WARN("xmlsecurity.workben", "failed to sign");
|
|
return 1;
|
|
}
|
|
|
|
SvFileStream aOutStream(aOutURL, StreamMode::WRITE | StreamMode::TRUNC);
|
|
if (!aDocument.Write(aOutStream))
|
|
{
|
|
SAL_WARN("xmlsecurity.workben", "failed to write the document");
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
SAL_IMPLEMENT_MAIN_WITH_ARGS(nArgc, pArgv)
|
|
{
|
|
try
|
|
{
|
|
return pdfVerify(nArgc, pArgv);
|
|
}
|
|
catch (...)
|
|
{
|
|
std::cerr << "pdfverify: uncaught exception while invoking pdfVerify()" << std::endl;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|