14#include <com/sun/star/io/XTruncate.hpp>
15#include <com/sun/star/io/XStream.hpp>
16#include <com/sun/star/security/CertificateValidity.hpp>
17#include <com/sun/star/uno/SecurityException.hpp>
18#include <com/sun/star/security/DocumentSignatureInformation.hpp>
19#include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp>
20#include <com/sun/star/drawing/XShapes.hpp>
21#include <com/sun/star/frame/XModel.hpp>
22#include <com/sun/star/frame/XStorable.hpp>
23#include <com/sun/star/beans/XPropertySet.hpp>
24#include <com/sun/star/drawing/XDrawView.hpp>
42bool GetSignatureLinePage(
const uno::Reference<frame::XModel>& xModel, sal_Int32& rPage)
44 uno::Reference<drawing::XDrawView>
xController(
xModel->getCurrentController(), uno::UNO_QUERY);
50 uno::Reference<beans::XPropertySet> xPage(
xController->getCurrentPage(), uno::UNO_QUERY);
56 return xPage->getPropertyValue(
"Number") >>= rPage;
60void GetSignatureLineShape(
const uno::Reference<frame::XModel>& xModel, sal_Int32& rPage,
61 std::vector<sal_Int8>& rSignatureLineShape)
68 if (!GetSignatureLinePage(xModel, rPage))
73 uno::Reference<drawing::XShapes> xShapes(
xModel->getCurrentSelection(), uno::UNO_QUERY);
74 if (!xShapes.is() || xShapes->getCount() < 1)
79 uno::Reference<beans::XPropertySet> xShapeProps(xShapes->getByIndex(0), uno::UNO_QUERY);
80 if (!xShapeProps.is())
86 auto it =
aMap.find(
"SignatureCertificate");
94 uno::Reference<frame::XStorable> xStorable(xModel, uno::UNO_QUERY);
102 aMediaDescriptor[
"FilterName"] <<= OUString(
"draw_pdf_Export");
105 aMediaDescriptor[
"OutputStream"] <<=
xStream;
106 uno::Sequence<beans::PropertyValue> aFilterData(
108 aMediaDescriptor[
"FilterData"] <<= aFilterData;
109 xStorable->storeToURL(
"private:stream", aMediaDescriptor.getAsConstPropertyValueList());
113 rSignatureLineShape = std::vector<sal_Int8>(aStream.
GetSize());
114 aStream.
ReadBytes(rSignatureLineShape.data(), rSignatureLineShape.size());
120 std::unique_ptr<vcl::pdf::PDFiumSignature> m_pSignature;
122 std::vector<std::pair<size_t, size_t>> m_aByteRanges;
126void GetByteRangesFromPDF(
const std::unique_ptr<vcl::pdf::PDFiumSignature>& pSignature,
127 std::vector<std::pair<size_t, size_t>>& rByteRanges)
129 std::vector<int> aByteRange = pSignature->getByteRange();
130 if (aByteRange.empty())
132 SAL_WARN(
"xmlsecurity.helper",
"GetByteRangesFromPDF: no byte ranges");
136 size_t nByteRangeOffset = 0;
137 for (
size_t i = 0;
i < aByteRange.size(); ++
i)
141 nByteRangeOffset = aByteRange[
i];
146 rByteRanges.emplace_back(nByteRangeOffset, nLength);
151bool GetEOFOfSignature(
const Signature& rSignature,
size_t& rEOF)
153 if (rSignature.m_aByteRanges.size() < 2)
158 rEOF = rSignature.m_aByteRanges[1].first + rSignature.m_aByteRanges[1].second;
166int GetMDPPerm(
const std::vector<Signature>& rSignatures)
170 if (rSignatures.empty())
175 for (
const auto& rSignature : rSignatures)
177 int nPerm = rSignature.m_pSignature->getDocMDPPermission();
188bool IsCompleteSignature(
SvStream& rStream,
const Signature& rSignature,
189 const std::set<unsigned int>& rSignedEOFs,
190 const std::vector<unsigned int>& rAllEOFs)
192 size_t nSignatureEOF = 0;
193 if (!GetEOFOfSignature(rSignature, nSignatureEOF))
198 bool bFoundOwn =
false;
199 for (
const auto& rEOF : rAllEOFs)
201 if (rEOF == nSignatureEOF)
212 if (rSignedEOFs.find(rEOF) == rSignedEOFs.end())
226 rStream.
Seek(STREAM_SEEK_TO_END);
227 size_t nFileEnd = rStream.
Tell();
228 return std::find(rAllEOFs.begin(), rAllEOFs.end(), nFileEnd) != rAllEOFs.end();
238 std::vector<basegfx::B2DRectangle> m_aAnnotations;
239 bool operator==(
const PageChecksum& rChecksum)
const;
242bool PageChecksum::operator==(
const PageChecksum& rChecksum)
const
244 if (m_nPageContent != rChecksum.m_nPageContent)
249 return m_aAnnotations == rChecksum.m_aAnnotations;
253void AnalyizeSignatureStream(
SvMemoryStream& rStream, std::vector<PageChecksum>& rPageChecksums,
257 std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument
258 = pPdfium->openDocument(rStream.
GetData(), rStream.
GetSize(), OString());
264 int nPageCount = pPdfDocument->getPageCount();
265 for (
int nPage = 0; nPage < nPageCount; ++nPage)
267 std::unique_ptr<vcl::pdf::PDFiumPage> pPdfPage = pPdfDocument->openPage(nPage);
273 PageChecksum aPageChecksum;
274 aPageChecksum.m_nPageContent = pPdfPage->getChecksum(nMDPPerm);
275 for (
int i = 0;
i < pPdfPage->getAnnotationCount(); ++
i)
277 std::unique_ptr<vcl::pdf::PDFiumAnnotation> pPdfAnnotation = pPdfPage->getAnnotation(i);
280 SAL_WARN(
"xmlsecurity.helper",
"Cannot get PDFiumAnnotation");
290 aPageChecksum.m_aAnnotations.push_back(pPdfAnnotation->getRectangle());
296 rPageChecksums.push_back(aPageChecksum);
304bool IsValidSignature(
SvStream& rStream,
const Signature& rSignature,
int nMDPPerm)
306 size_t nSignatureEOF = 0;
307 if (!GetEOFOfSignature(rSignature, nSignatureEOF))
315 aSignatureStream.
WriteStream(rStream, nSignatureEOF);
317 aSignatureStream.
Seek(0);
318 std::vector<PageChecksum> aSignedPages;
319 AnalyizeSignatureStream(aSignatureStream, aSignedPages, nMDPPerm);
327 std::vector<PageChecksum> aAllPages;
328 AnalyizeSignatureStream(aFullStream, aAllPages, nMDPPerm);
332 return aSignedPages == aAllPages;
340bool ValidateSignature(
SvStream& rStream,
const Signature& rSignature,
342 const std::set<unsigned int>& rSignatureEOFs,
343 const std::vector<unsigned int>& rTrailerEnds)
345 std::vector<unsigned char> aContents = rSignature.m_pSignature->getContents();
346 if (aContents.empty())
348 SAL_WARN(
"xmlsecurity.helper",
"ValidateSignature: no contents");
352 OString aSubFilter = rSignature.m_pSignature->getSubFilter();
354 const bool bNonDetached = aSubFilter ==
"adbe.pkcs7.sha1";
355 if (aSubFilter.isEmpty()
356 || (aSubFilter !=
"adbe.pkcs7.detached" && !bNonDetached
357 && aSubFilter !=
"ETSI.CAdES.detached"))
359 if (aSubFilter.isEmpty())
360 SAL_WARN(
"xmlsecurity.helper",
"ValidateSignature: missing sub-filter");
363 "ValidateSignature: unsupported sub-filter: '" << aSubFilter <<
"'");
368 rInformation.
ouDescription = rSignature.m_pSignature->getReason();
372 rInformation.
stDateTime = rSignature.m_pSignature->getTime();
375 if (rSignature.m_aByteRanges.size() < 2)
377 SAL_WARN(
"xmlsecurity.helper",
"ValidateSignature: expected 2 byte ranges");
380 if (rSignature.m_aByteRanges[0].first != 0)
382 SAL_WARN(
"xmlsecurity.helper",
"ValidateSignature: first range start is not 0");
386 size_t nSignatureLength = aContents.size() * 2 + 2;
387 if (rSignature.m_aByteRanges[1].first
388 != (rSignature.m_aByteRanges[0].second + nSignatureLength))
391 "ValidateSignature: second range start is not the end of the signature");
395 = !IsCompleteSignature(rStream, rSignature, rSignatureEOFs, rTrailerEnds);
396 if (!IsValidSignature(rStream, rSignature, nMDPPerm))
398 SAL_WARN(
"xmlsecurity.helper",
"ValidateSignature: invalid incremental update detected");
412 const uno::Reference<io::XInputStream>& xInputStream)
414 if (!xInputStream.is())
416 SAL_WARN(
"xmlsecurity.helper",
"input stream missing");
437 std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument
438 = pPdfium->openDocument(aStream.
GetData(), aStream.
GetSize(), OString());
441 SAL_WARN(
"xmlsecurity.helper",
"failed to read the document");
445 int nSignatureCount = pPdfDocument->getSignatureCount();
446 if (nSignatureCount <= 0)
450 std::vector<Signature> aSignatures(nSignatureCount);
451 for (
int i = 0;
i < nSignatureCount; ++
i)
453 std::unique_ptr<vcl::pdf::PDFiumSignature> pSignature = pPdfDocument->getSignature(
i);
454 std::vector<std::pair<size_t, size_t>> aByteRanges;
455 GetByteRangesFromPDF(pSignature, aByteRanges);
456 aSignatures[
i] =
Signature{ std::move(pSignature), aByteRanges };
459 std::set<unsigned int> aSignatureEOFs;
460 for (
const auto& rSignature : aSignatures)
463 if (GetEOFOfSignature(rSignature, nEOF))
465 aSignatureEOFs.insert(nEOF);
469 std::vector<unsigned int> aTrailerEnds = pPdfDocument->getTrailerEnds();
473 int nMDPPerm = GetMDPPerm(aSignatures);
475 for (
size_t i = 0;
i < aSignatures.size(); ++
i)
479 if (!ValidateSignature(rStream, aSignatures[
i], aInfo, nMDPPerm, aSignatureEOFs,
482 SAL_WARN(
"xmlsecurity.helper",
"failed to determine digest match");
496uno::Sequence<security::DocumentSignatureInformation>
498 const uno::Reference<xml::crypto::XSecurityEnvironment>& xSecEnv)
const
500 uno::Sequence<security::DocumentSignatureInformation> aRet(
m_aSignatureInfos.size());
501 auto aRetRange = asNonConstRange(aRet);
506 security::DocumentSignatureInformation& rExternal = aRetRange[
i];
507 rExternal.SignatureIsValid
508 = rInternal.
nStatus == xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
512 rExternal.Signer = xSecEnv->createCertificateFromAscii(
518 if (rExternal.Signer.is())
522 rExternal.CertificateStatus = xSecEnv->verifyCertificate(rExternal.Signer, {});
524 catch (
const uno::SecurityException&)
527 rExternal.CertificateStatus = security::CertificateValidity::INVALID;
531 rExternal.CertificateStatus = security::CertificateValidity::INVALID;
540 const uno::Reference<security::XCertificate>& xCertificate)
551 const uno::Reference<io::XInputStream>& xInputStream,
bool bAdES)
557 SAL_WARN(
"xmlsecurity.helper",
"failed to read the document");
562 std::vector<sal_Int8> aSignatureLineShape;
563 GetSignatureLineShape(
xModel, nPage, aSignatureLineShape);
569 if (!aSignatureLineShape.empty())
571 aDocument.SetSignatureLine(std::move(aSignatureLineShape));
576 SAL_WARN(
"xmlsecurity.helper",
"failed to sign");
580 uno::Reference<io::XStream>
xStream(xInputStream, uno::UNO_QUERY);
584 SAL_WARN(
"xmlsecurity.helper",
"failed to write signed data");
592 sal_uInt16 nPosition)
598 SAL_WARN(
"xmlsecurity.helper",
"failed to read the document");
602 if (!
aDocument.RemoveSignature(nPosition))
604 SAL_WARN(
"xmlsecurity.helper",
"failed to remove signature");
608 uno::Reference<io::XStream>
xStream(xInputStream, uno::UNO_QUERY);
609 uno::Reference<io::XTruncate> xTruncate(
xStream, uno::UNO_QUERY);
612 SAL_WARN(
"xmlsecurity.helper",
"failed to truncate");
615 xTruncate->truncate();
619 SAL_WARN(
"xmlsecurity.helper",
"failed to write without signature");
sal_uInt64 BitmapChecksum
bool ReadAndVerifySignatureSvStream(SvStream &rStream)
css::uno::Reference< css::security::XCertificate > m_xCertificate
static bool RemoveSignature(const css::uno::Reference< css::io::XInputStream > &xInputStream, sal_uInt16 nPosition)
Remove the signature at nPosition (and all dependent signatures) from xInputStream.
bool ReadAndVerifySignature(const css::uno::Reference< css::io::XInputStream > &xInputStream)
void SetDescription(const OUString &rDescription)
Comment / reason to be used next time signing is performed.
SignatureInformations const & GetSignatureInformations() const
sal_Int32 GetNewSecurityId() const
Return the ID of the next created signature.
SignatureInformations m_aSignatureInfos
css::uno::Sequence< css::security::DocumentSignatureInformation > GetDocumentSignatureInformations(const css::uno::Reference< css::xml::crypto::XSecurityEnvironment > &xSecEnv) const
void SetX509Certificate(const css::uno::Reference< css::security::XCertificate > &xCertificate)
Certificate to be used next time signing is performed.
bool Sign(const css::uno::Reference< css::frame::XModel > &xModel, const css::uno::Reference< css::io::XInputStream > &xInputStream, bool bAdES)
Append a new signature at the end of xInputStream.
sal_uInt64 Seek(sal_uInt64 nPos)
std::size_t ReadBytes(void *pData, std::size_t nSize)
SvStream & WriteStream(SvStream &rStream)
static bool Verify(const std::vector< unsigned char > &aData, const bool bNonDetached, const std::vector< unsigned char > &aSignature, SignatureInformation &rInformation)
static std::unique_ptr< SvStream > CreateStream(const OUString &rFileName, StreamMode eOpenMode, css::uno::Reference< css::awt::XWindow > xParentWin=nullptr)
#define DBG_UNHANDLED_EXCEPTION(...)
#define SAL_WARN(area, stream)
css::uno::Sequence< css::beans::PropertyValue > InitPropertySequence(::std::initializer_list< ::std::pair< OUString, css::uno::Any > > vInit)
HashMap_OWString_Interface aMap
::std::vector< SignatureInformation > SignatureInformations
static std::shared_ptr< PDFium > & get()
Reference< XController > xController
Reference< XModel > xModel
bool operator==(const XclFontData &rLeft, const XclFontData &rRight)