summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2024-11-12 08:19:50 +0100
committerMiklos Vajna <vmiklos@collabora.com>2024-11-12 12:41:34 +0100
commiteabda77c9735040dd5bdb1d2ebe0b96ce316561a (patch)
tree6f9d36fc2513e3deaa5361101f03a8293c9f84fc
parent859f66b6dc37e3192161e1c5cff6afbd83f3b616 (diff)
cool#9992 lok doc sign, hash extract: digest for getCommandValues('Signature')
To be able to sign externally, we need a way to know what is the document hash that would be passed to NSS_CMSSignedData_SetDigestValue(), without actually performing the signing. Note that svl::crypto::SigningContext already gives us a way to expose the time that would be used for signing. Expose the hash in a similar way: the format is a SHA-256 hash in base64 form. This adapts both places dealing with time: vcl::PDFWriter::GetDateTime() and svl::crypto::Signing::Sign, to make sure they use the same time, otherwise the hash would potentially depend on two times, which would be hard to reproduce later when we serialize the signature we get. Change-Id: Ib039db4cdd043c8117215c31cb5bc83397693820 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176470 Reviewed-by: Miklos Vajna <vmiklos@collabora.com> Tested-by: Jenkins
-rw-r--r--include/svl/cryptosign.hxx2
-rw-r--r--include/vcl/filter/pdfdocument.hxx3
-rw-r--r--include/vcl/pdfwriter.hxx6
-rw-r--r--sfx2/qa/cppunit/view.cxx11
-rw-r--r--sfx2/source/view/lokhelper.cxx6
-rw-r--r--svl/source/crypto/cryptosign.cxx13
-rw-r--r--vcl/source/filter/ipdf/pdfdocument.cxx10
-rw-r--r--vcl/source/gdi/pdfwriter_impl.cxx16
8 files changed, 57 insertions, 10 deletions
diff --git a/include/svl/cryptosign.hxx b/include/svl/cryptosign.hxx
index a547036813c1..dce75dad8fcf 100644
--- a/include/svl/cryptosign.hxx
+++ b/include/svl/cryptosign.hxx
@@ -103,6 +103,8 @@ public:
/// If m_xCertificate is not set, the time that would be used, in milliseconds since the epoch
/// (1970-01-01 UTC).
sal_Int64 m_nSignatureTime = 0;
+ /// SHA-256 digest.
+ std::vector<unsigned char> m_aDigest;
};
}
diff --git a/include/vcl/filter/pdfdocument.hxx b/include/vcl/filter/pdfdocument.hxx
index 32850c3ddc00..d1eaf06b126e 100644
--- a/include/vcl/filter/pdfdocument.hxx
+++ b/include/vcl/filter/pdfdocument.hxx
@@ -531,7 +531,8 @@ class VCL_DLLPUBLIC PDFDocument final : public PDFObjectContainer
/// Suggest a minimal, yet free signature ID to use for the next signature.
SAL_DLLPRIVATE sal_uInt32 GetNextSignature();
/// Write the signature object as part of signing.
- SAL_DLLPRIVATE sal_Int32 WriteSignatureObject(const OUString& rDescription, bool bAdES,
+ SAL_DLLPRIVATE sal_Int32 WriteSignatureObject(svl::crypto::SigningContext& rSigningContext,
+ const OUString& rDescription, bool bAdES,
sal_uInt64& rLastByteRangeOffset,
sal_Int64& rContentOffset);
/// Write the appearance object as part of signing.
diff --git a/include/vcl/pdfwriter.hxx b/include/vcl/pdfwriter.hxx
index 2d6c517dc7ba..981d89c4831e 100644
--- a/include/vcl/pdfwriter.hxx
+++ b/include/vcl/pdfwriter.hxx
@@ -48,6 +48,10 @@ namespace tools {
class Polygon;
class PolyPolygon;
}
+namespace svl::crypto
+{
+class SigningContext;
+}
class Bitmap;
class BitmapEx;
class Gradient;
@@ -1262,7 +1266,7 @@ The following structure describes the permissions used in PDF security
static void AppendUnicodeTextString(const OUString& rString, OStringBuffer& rBuffer);
/// Get current date/time in PDF D:YYYYMMDDHHMMSS form.
- static OString GetDateTime();
+ static OString GetDateTime(svl::crypto::SigningContext* pSigningContext = nullptr);
};
}
diff --git a/sfx2/qa/cppunit/view.cxx b/sfx2/qa/cppunit/view.cxx
index 4c8e47582643..e481d7186ce0 100644
--- a/sfx2/qa/cppunit/view.cxx
+++ b/sfx2/qa/cppunit/view.cxx
@@ -24,6 +24,8 @@
#include <sfx2/lokhelper.hxx>
#include <sfx2/sfxbasemodel.hxx>
#include <tools/json_writer.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <comphelper/base64.hxx>
using namespace com::sun::star;
@@ -123,7 +125,7 @@ CPPUNIT_TEST_FIXTURE(Sfx2ViewTest, testLokHelperCommandValuesSignature)
SfxLokHelper::getCommandValues(aWriter, ".uno:Signature");
OString aJson = aWriter.finishAndGetAsOString();
- // Then make sure that we get a signature time:
+ // Then make sure that we get a signature time and a hash:
CPPUNIT_ASSERT(SfxLokHelper::supportsCommand(u"Signature"));
std::stringstream aStream{ std::string(aJson) };
boost::property_tree::ptree aTree;
@@ -133,6 +135,13 @@ CPPUNIT_TEST_FIXTURE(Sfx2ViewTest, testLokHelperCommandValuesSignature)
CPPUNIT_ASSERT(it != aTree.not_found());
auto nSignatureTime = it->second.get_value<sal_Int64>();
CPPUNIT_ASSERT(nSignatureTime != 0);
+ // Base64 encoded hash, that has the SHA-256 length:
+ it = aTree.find("digest");
+ CPPUNIT_ASSERT(it != aTree.not_found());
+ auto aDigest = OUString::fromUtf8(it->second.get_value<std::string>());
+ uno::Sequence<sal_Int8> aBytes;
+ comphelper::Base64::decode(aBytes, aDigest);
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(32), aBytes.getLength());
}
#endif
diff --git a/sfx2/source/view/lokhelper.cxx b/sfx2/source/view/lokhelper.cxx
index e37a88105d54..29efd234f91f 100644
--- a/sfx2/source/view/lokhelper.cxx
+++ b/sfx2/source/view/lokhelper.cxx
@@ -1017,6 +1017,12 @@ void SfxLokHelper::getCommandValues(tools::JsonWriter& rJsonWriter, std::string_
svl::crypto::SigningContext aSigningContext;
pObjectShell->SignDocumentContentUsingCertificate(aSigningContext);
rJsonWriter.put("signatureTime", aSigningContext.m_nSignatureTime);
+
+ uno::Sequence<sal_Int8> aDigest(reinterpret_cast<sal_Int8*>(aSigningContext.m_aDigest.data()),
+ aSigningContext.m_aDigest.size());
+ OUStringBuffer aBuffer;
+ comphelper::Base64::encode(aBuffer, aDigest);
+ rJsonWriter.put("digest", aBuffer.makeStringAndClear());
}
void SfxLokHelper::notifyUpdate(SfxViewShell const* pThisView, int nType)
diff --git a/svl/source/crypto/cryptosign.cxx b/svl/source/crypto/cryptosign.cxx
index c3a73d43290a..8a09dc0ae2ea 100644
--- a/svl/source/crypto/cryptosign.cxx
+++ b/svl/source/crypto/cryptosign.cxx
@@ -977,10 +977,19 @@ bool Signing::Sign(OStringBuffer& rCMSHexBuffer)
PRTime now = PR_Now();
- if (!m_rSigningContext.m_xCertificate.is())
+ // The context unit is milliseconds, PR_Now() unit is microseconds.
+ if (m_rSigningContext.m_nSignatureTime)
+ {
+ now = m_rSigningContext.m_nSignatureTime * 1000;
+ }
+ else
{
- // The context unit is milliseconds, PR_Now() unit is microseconds.
m_rSigningContext.m_nSignatureTime = now / 1000;
+ }
+
+ if (!m_rSigningContext.m_xCertificate.is())
+ {
+ m_rSigningContext.m_aDigest = aHashResult;
// No certificate is provided: don't actually sign -- just update the context with the
// parameters for the signing and return.
return false;
diff --git a/vcl/source/filter/ipdf/pdfdocument.cxx b/vcl/source/filter/ipdf/pdfdocument.cxx
index 3842b0c3baaa..62ce923b3ecf 100644
--- a/vcl/source/filter/ipdf/pdfdocument.cxx
+++ b/vcl/source/filter/ipdf/pdfdocument.cxx
@@ -122,7 +122,8 @@ sal_uInt32 PDFDocument::GetNextSignature()
return nRet + 1;
}
-sal_Int32 PDFDocument::WriteSignatureObject(const OUString& rDescription, bool bAdES,
+sal_Int32 PDFDocument::WriteSignatureObject(svl::crypto::SigningContext& rSigningContext,
+ const OUString& rDescription, bool bAdES,
sal_uInt64& rLastByteRangeOffset,
sal_Int64& rContentOffset)
{
@@ -146,7 +147,7 @@ sal_Int32 PDFDocument::WriteSignatureObject(const OUString& rDescription, bool b
aSigBuffer.append("/adbe.pkcs7.detached");
// Time of signing.
- aSigBuffer.append(" /M (" + vcl::PDFWriter::GetDateTime()
+ aSigBuffer.append(" /M (" + vcl::PDFWriter::GetDateTime(&rSigningContext)
+ ")"
// Byte range: we can write offset1-length1 and offset2 right now, will
@@ -863,8 +864,9 @@ bool PDFDocument::Sign(svl::crypto::SigningContext& rSigningContext, const OUStr
sal_uInt64 nSignatureLastByteRangeOffset = 0;
sal_Int64 nSignatureContentOffset = 0;
- sal_Int32 nSignatureId = WriteSignatureObject(
- rDescription, bAdES, nSignatureLastByteRangeOffset, nSignatureContentOffset);
+ sal_Int32 nSignatureId
+ = WriteSignatureObject(rSigningContext, rDescription, bAdES, nSignatureLastByteRangeOffset,
+ nSignatureContentOffset);
assert(nSignatureContentOffset > 0
&& "WriteSignatureObject guarantees a length for nSignatureContentOffset");
tools::Rectangle aSignatureRectangle;
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index 3dc4ada0e210..571f00ff2eab 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -1474,13 +1474,27 @@ void PDFWriterImpl::setupDocInfo()
m_aContext.Encryption.DocumentIdentifier = std::move(aId);
}
-OString PDFWriter::GetDateTime()
+OString PDFWriter::GetDateTime(svl::crypto::SigningContext* pSigningContext)
{
OStringBuffer aRet;
TimeValue aTVal, aGMT;
oslDateTime aDT;
osl_getSystemTime(&aGMT);
+
+ if (pSigningContext)
+ {
+ // The context unit is milliseconds, TimeValue is seconds + nanoseconds.
+ if (pSigningContext->m_nSignatureTime)
+ {
+ aGMT = std::chrono::milliseconds(pSigningContext->m_nSignatureTime);
+ }
+ else
+ {
+ pSigningContext->m_nSignatureTime = static_cast<sal_Int64>(aGMT.Seconds) * 1000 + aGMT.Nanosec / 1000000;
+ }
+ }
+
osl_getLocalTimeFromSystemTime(&aGMT, &aTVal);
osl_getDateTimeFromTimeValue(&aTVal, &aDT);