/* -*- 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/.
*/
namespace
{ /// Gets the current page of the current view from xModel and puts it to the 1-based rPage. bool GetSignatureLinePage(const uno::Reference<frame::XModel>& xModel, sal_Int32& rPage)
{
uno::Reference<drawing::XDrawView> xController(xModel->getCurrentController(), uno::UNO_QUERY); if (!xController.is())
{ returnfalse;
}
uno::Reference<beans::XPropertySet> xPage(xController->getCurrentPage(), uno::UNO_QUERY); if (!xPage.is())
{ returnfalse;
}
/// If the currently selected shape is a Draw signature line, export that to PDF. void GetSignatureLineShape(const uno::Reference<frame::XModel>& xModel, sal_Int32& rPage,
std::vector<sal_Int8>& rSignatureLineShape)
{ if (!xModel.is())
{ return;
}
if (!GetSignatureLinePage(xModel, rPage))
{ return;
}
/// Determines the last position that is covered by a signature. bool GetEOFOfSignature(const Signature& rSignature, size_t& rEOF)
{ if (rSignature.m_aByteRanges.size() < 2)
{ returnfalse;
}
/** * Get the value of the "modification detection and prevention" permission: * Valid values are 1, 2 and 3: only 3 allows annotations after signing.
*/ int GetMDPPerm(const std::vector<Signature>& rSignatures)
{ int nRet = 3;
if (rSignatures.empty())
{ return nRet;
}
for (constauto& rSignature : rSignatures)
{ int nPerm = rSignature.m_pSignature->getDocMDPPermission(); if (nPerm != 0)
{ return nPerm;
}
}
return nRet;
}
/// Checks if there are unsigned incremental updates between the signatures or after the last one. bool IsCompleteSignature(SvStream& rStream, const Signature& rSignature, const std::set<unsignedint>& rSignedEOFs, const std::vector<unsignedint>& rAllEOFs)
{
size_t nSignatureEOF = 0; if (!GetEOFOfSignature(rSignature, nSignatureEOF))
{ returnfalse;
}
bool bFoundOwn = false; for (constauto& rEOF : rAllEOFs)
{ if (rEOF == nSignatureEOF)
{
bFoundOwn = true; continue;
}
// Make sure we find the incremental update of the signature itself. if (!bFoundOwn)
{ returnfalse;
}
// No additional content after the last incremental update.
rStream.Seek(STREAM_SEEK_TO_END);
size_t nFileEnd = rStream.Tell(); return std::find(rAllEOFs.begin(), rAllEOFs.end(), nFileEnd) != rAllEOFs.end();
}
/** * Contains checksums of a PDF page, which is rendered without annotations. It also contains * the geometry of a few dangerous annotation types.
*/ struct PageChecksum
{
BitmapChecksum m_nPageContent;
std::vector<basegfx::B2DRectangle> m_aAnnotations; booloperator==(const PageChecksum& rChecksum) const;
};
/// Collects the checksum of each page of one version of the PDF. void AnalyizeSignatureStream(SvMemoryStream& rStream, std::vector<PageChecksum>& rPageChecksums, int nMDPPerm)
{ auto pPdfium = vcl::pdf::PDFiumLibrary::get();
std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument
= pPdfium->openDocument(rStream.GetData(), rStream.GetSize(), OString()); if (!pPdfDocument)
{ return;
}
int nPageCount = pPdfDocument->getPageCount(); for (int nPage = 0; nPage < nPageCount; ++nPage)
{
std::unique_ptr<vcl::pdf::PDFiumPage> pPdfPage = pPdfDocument->openPage(nPage); if (!pPdfPage)
{ return;
}
PageChecksum aPageChecksum;
aPageChecksum.m_nPageContent = pPdfPage->getChecksum(nMDPPerm); for (int i = 0; i < pPdfPage->getAnnotationCount(); ++i)
{
std::unique_ptr<vcl::pdf::PDFiumAnnotation> pPdfAnnotation = pPdfPage->getAnnotation(i); if (!pPdfAnnotation)
{
SAL_WARN("xmlsecurity.helper", "Cannot get PDFiumAnnotation"); continue;
}
vcl::pdf::PDFAnnotationSubType eType = pPdfAnnotation->getSubType(); switch (eType)
{ case vcl::pdf::PDFAnnotationSubType::Unknown: case vcl::pdf::PDFAnnotationSubType::FreeText: case vcl::pdf::PDFAnnotationSubType::Stamp: case vcl::pdf::PDFAnnotationSubType::Redact:
aPageChecksum.m_aAnnotations.push_back(pPdfAnnotation->getRectangle()); break; default: break;
}
}
rPageChecksums.push_back(aPageChecksum);
}
}
/** * Checks if incremental updates after singing performed valid modifications only. * nMDPPerm decides if annotations/commenting is OK, other changes are always not.
*/ bool IsValidSignature(SvStream& rStream, const Signature& rSignature, int nMDPPerm)
{
size_t nSignatureEOF = 0; if (!GetEOFOfSignature(rSignature, nSignatureEOF))
{ returnfalse;
}
// Fail if any page looks different after signing and at the end. Annotations/commenting doesn't // count, though. return aSignedPages == aAllPages;
}
/** * @param rInformation The actual result. * @param rDocument the parsed document to see if the signature is partial. * @return If we can determinate a result.
*/ bool ValidateSignature(SvStream& rStream, const Signature& rSignature,
SignatureInformation& rInformation, int nMDPPerm, const std::set<unsignedint>& rSignatureEOFs, const std::vector<unsignedint>& rTrailerEnds)
{
std::vector<unsignedchar> aContents = rSignature.m_pSignature->getContents(); if (aContents.empty())
{
SAL_WARN("xmlsecurity.helper", "ValidateSignature: no contents"); returnfalse;
}
// Date: used only when the time of signing is not available in the // signature.
rInformation.stDateTime = rSignature.m_pSignature->getTime();
// Detect if the byte ranges don't cover everything, but the signature itself. if (rSignature.m_aByteRanges.size() < 2)
{
SAL_WARN("xmlsecurity.helper", "ValidateSignature: expected 2 byte ranges"); returnfalse;
} if (rSignature.m_aByteRanges[0].first != 0)
{
SAL_WARN("xmlsecurity.helper", "ValidateSignature: first range start is not 0"); returnfalse;
} // Binary vs hex dump and 2 is the leading "<" and the trailing ">" around the hex string.
size_t nSignatureLength = aContents.size() * 2 + 2; if (rSignature.m_aByteRanges[1].first
!= (rSignature.m_aByteRanges[0].second + nSignatureLength))
{
SAL_WARN("xmlsecurity.helper", "ValidateSignature: second range start is not the end of the signature"); returnfalse;
}
rInformation.bPartialDocumentSignature
= !IsCompleteSignature(rStream, rSignature, rSignatureEOFs, rTrailerEnds); if (!IsValidSignature(rStream, rSignature, nMDPPerm))
{
SAL_WARN("xmlsecurity.helper", "ValidateSignature: invalid incremental update detected"); returnfalse;
}
// At this point there is no obviously missing info to validate the // signature. return svl::crypto::Signing::Verify(rStream, rSignature.m_aByteRanges, bNonDetached, aContents,
rInformation);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.