Bump version to 6.0-36
[LibreOffice.git] / xmlsecurity / source / helper / ooxmlsecexporter.cxx
blob9ce056d5a8687ff9969e72698608475b3b6ed7fa
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include "ooxmlsecexporter.hxx"
12 #include <algorithm>
14 #include <com/sun/star/embed/ElementModes.hpp>
15 #include <com/sun/star/embed/XHierarchicalStorageAccess.hpp>
16 #include <com/sun/star/beans/StringPair.hpp>
18 #include <comphelper/ofopxmlhelper.hxx>
19 #include <config_global.h>
20 #include <o3tl/make_unique.hxx>
21 #include <rtl/ref.hxx>
22 #include <unotools/datetime.hxx>
23 #include <xmloff/attrlist.hxx>
25 #include <documentsignaturehelper.hxx>
26 #include <xsecctl.hxx>
28 using namespace com::sun::star;
30 struct OOXMLSecExporter::Impl
32 const uno::Reference<uno::XComponentContext>& m_xComponentContext;
33 const uno::Reference<embed::XStorage>& m_xRootStorage;
34 const uno::Reference<xml::sax::XDocumentHandler>& m_xDocumentHandler;
35 const SignatureInformation& m_rInformation;
36 OUString m_aSignatureTimeValue;
38 Impl(const uno::Reference<uno::XComponentContext>& xComponentContext,
39 const uno::Reference<embed::XStorage>& xRootStorage,
40 const uno::Reference<xml::sax::XDocumentHandler>& xDocumentHandler,
41 const SignatureInformation& rInformation)
42 : m_xComponentContext(xComponentContext)
43 , m_xRootStorage(xRootStorage)
44 , m_xDocumentHandler(xDocumentHandler)
45 , m_rInformation(rInformation)
49 /// Should we intentionally not sign this stream?
50 static bool isOOXMLBlacklist(const OUString& rStreamName);
51 /// Should we intentionally not sign this relation type?
52 static bool isOOXMLRelationBlacklist(const OUString& rRelationName);
54 void writeSignedInfo();
55 void writeCanonicalizationMethod();
56 void writeCanonicalizationTransform();
57 void writeSignatureMethod();
58 void writeSignedInfoReferences();
59 void writeSignatureValue();
60 void writeKeyInfo();
61 void writePackageObject();
62 void writeManifest();
63 void writeRelationshipTransform(const OUString& rURI);
64 /// Writes <SignatureProperties> inside idPackageObject.
65 void writePackageObjectSignatureProperties();
66 /// Writes a single <Reference> inside <Manifest>.
67 void writeManifestReference(const SignatureReferenceInformation& rReference);
68 void writeOfficeObject();
69 /// Writes <SignatureInfoV1>.
70 void writeSignatureInfo();
71 void writePackageSignature();
74 bool OOXMLSecExporter::Impl::isOOXMLBlacklist(const OUString& rStreamName)
76 static const std::initializer_list<OUStringLiteral> vBlacklist =
78 "/%5BContent_Types%5D.xml",
79 "/docProps/app.xml",
80 "/docProps/core.xml",
81 // Don't attempt to sign other signatures for now.
82 "/_xmlsignatures"
84 // Just check the prefix, as we don't care about the content type part of the stream name.
85 return std::find_if(vBlacklist.begin(), vBlacklist.end(), [&](const OUStringLiteral& rLiteral)
87 return rStreamName.startsWith(rLiteral);
88 }) != vBlacklist.end();
91 bool OOXMLSecExporter::Impl::isOOXMLRelationBlacklist(const OUString& rRelationName)
93 static const std::initializer_list<OUStringLiteral> vBlacklist =
95 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties",
96 "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties",
97 "http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/origin"
99 return std::find(vBlacklist.begin(), vBlacklist.end(), rRelationName) != vBlacklist.end();
102 void OOXMLSecExporter::Impl::writeSignedInfo()
104 m_xDocumentHandler->startElement("SignedInfo", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
106 writeCanonicalizationMethod();
107 writeSignatureMethod();
108 writeSignedInfoReferences();
110 m_xDocumentHandler->endElement("SignedInfo");
113 void OOXMLSecExporter::Impl::writeCanonicalizationMethod()
115 rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
116 pAttributeList->AddAttribute("Algorithm", ALGO_C14N);
117 m_xDocumentHandler->startElement("CanonicalizationMethod", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
118 m_xDocumentHandler->endElement("CanonicalizationMethod");
122 void OOXMLSecExporter::Impl::writeCanonicalizationTransform()
124 rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
125 pAttributeList->AddAttribute("Algorithm", ALGO_C14N);
126 m_xDocumentHandler->startElement("Transform", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
127 m_xDocumentHandler->endElement("Transform");
131 void OOXMLSecExporter::Impl::writeSignatureMethod()
133 rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
134 pAttributeList->AddAttribute("Algorithm", ALGO_RSASHA256);
135 m_xDocumentHandler->startElement("SignatureMethod", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
136 m_xDocumentHandler->endElement("SignatureMethod");
139 void OOXMLSecExporter::Impl::writeSignedInfoReferences()
141 const SignatureReferenceInformations& rReferences = m_rInformation.vSignatureReferenceInfors;
142 for (const SignatureReferenceInformation& rReference : rReferences)
144 if (rReference.nType == SignatureReferenceType::SAMEDOCUMENT)
147 rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
148 if (rReference.ouURI != "idSignedProperties")
149 pAttributeList->AddAttribute("Type", "http://www.w3.org/2000/09/xmldsig#Object");
150 else
151 pAttributeList->AddAttribute("Type", "http://uri.etsi.org/01903#SignedProperties");
152 pAttributeList->AddAttribute("URI", "#" + rReference.ouURI);
153 m_xDocumentHandler->startElement("Reference", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
155 if (rReference.ouURI == "idSignedProperties")
157 m_xDocumentHandler->startElement("Transforms", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
158 writeCanonicalizationTransform();
159 m_xDocumentHandler->endElement("Transforms");
162 DocumentSignatureHelper::writeDigestMethod(m_xDocumentHandler);
163 m_xDocumentHandler->startElement("DigestValue", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
164 m_xDocumentHandler->characters(rReference.ouDigestValue);
165 m_xDocumentHandler->endElement("DigestValue");
166 m_xDocumentHandler->endElement("Reference");
171 void OOXMLSecExporter::Impl::writeSignatureValue()
173 m_xDocumentHandler->startElement("SignatureValue", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
174 m_xDocumentHandler->characters(m_rInformation.ouSignatureValue);
175 m_xDocumentHandler->endElement("SignatureValue");
178 void OOXMLSecExporter::Impl::writeKeyInfo()
180 m_xDocumentHandler->startElement("KeyInfo", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
181 m_xDocumentHandler->startElement("X509Data", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
182 m_xDocumentHandler->startElement("X509Certificate", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
183 m_xDocumentHandler->characters(m_rInformation.ouX509Certificate);
184 m_xDocumentHandler->endElement("X509Certificate");
185 m_xDocumentHandler->endElement("X509Data");
186 m_xDocumentHandler->endElement("KeyInfo");
189 void OOXMLSecExporter::Impl::writePackageObject()
191 rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
192 pAttributeList->AddAttribute("Id", "idPackageObject");
193 m_xDocumentHandler->startElement("Object", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
195 writeManifest();
196 writePackageObjectSignatureProperties();
198 m_xDocumentHandler->endElement("Object");
201 void OOXMLSecExporter::Impl::writeManifest()
203 m_xDocumentHandler->startElement("Manifest", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
204 const SignatureReferenceInformations& rReferences = m_rInformation.vSignatureReferenceInfors;
205 for (const SignatureReferenceInformation& rReference : rReferences)
207 if (rReference.nType != SignatureReferenceType::SAMEDOCUMENT)
209 if (OOXMLSecExporter::Impl::isOOXMLBlacklist(rReference.ouURI))
210 continue;
212 writeManifestReference(rReference);
215 m_xDocumentHandler->endElement("Manifest");
218 void OOXMLSecExporter::Impl::writeRelationshipTransform(const OUString& rURI)
220 uno::Reference<embed::XHierarchicalStorageAccess> xHierarchicalStorageAccess(m_xRootStorage, uno::UNO_QUERY);
221 uno::Reference<io::XInputStream> xRelStream(xHierarchicalStorageAccess->openStreamElementByHierarchicalName(rURI, embed::ElementModes::READ), uno::UNO_QUERY);
223 rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
224 pAttributeList->AddAttribute("Algorithm", ALGO_RELATIONSHIP);
225 m_xDocumentHandler->startElement("Transform", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
228 uno::Sequence< uno::Sequence<beans::StringPair> > aRelationsInfo = comphelper::OFOPXMLHelper::ReadRelationsInfoSequence(xRelStream, rURI, m_xComponentContext);
229 for (const uno::Sequence<beans::StringPair>& rPairs : aRelationsInfo)
231 OUString aId;
232 OUString aType;
233 for (const beans::StringPair& rPair : rPairs)
235 if (rPair.First == "Id")
236 aId = rPair.Second;
237 else if (rPair.First == "Type")
238 aType = rPair.Second;
241 if (OOXMLSecExporter::Impl::isOOXMLRelationBlacklist(aType))
242 continue;
244 rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
245 pAttributeList->AddAttribute("xmlns:mdssi", NS_MDSSI);
246 pAttributeList->AddAttribute("SourceId", aId);
247 m_xDocumentHandler->startElement("mdssi:RelationshipReference", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
248 m_xDocumentHandler->endElement("mdssi:RelationshipReference");
251 m_xDocumentHandler->endElement("Transform");
254 void OOXMLSecExporter::Impl::writePackageObjectSignatureProperties()
256 m_xDocumentHandler->startElement("SignatureProperties", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
258 rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
259 pAttributeList->AddAttribute("Id", "idSignatureTime");
260 pAttributeList->AddAttribute("Target", "#idPackageSignature");
261 m_xDocumentHandler->startElement("SignatureProperty", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
264 rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
265 pAttributeList->AddAttribute("xmlns:mdssi", NS_MDSSI);
266 m_xDocumentHandler->startElement("mdssi:SignatureTime", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
268 m_xDocumentHandler->startElement("mdssi:Format", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
269 m_xDocumentHandler->characters("YYYY-MM-DDThh:mm:ssTZD");
270 m_xDocumentHandler->endElement("mdssi:Format");
272 m_xDocumentHandler->startElement("mdssi:Value", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
273 if (!m_rInformation.ouDateTime.isEmpty())
274 m_aSignatureTimeValue = m_rInformation.ouDateTime;
275 else
277 m_aSignatureTimeValue = utl::toISO8601(m_rInformation.stDateTime);
278 // Ignore sub-seconds.
279 sal_Int32 nCommaPos = m_aSignatureTimeValue.indexOf(',');
280 if (nCommaPos != -1)
282 m_aSignatureTimeValue = m_aSignatureTimeValue.copy(0, nCommaPos);
283 m_aSignatureTimeValue += "Z";
286 m_xDocumentHandler->characters(m_aSignatureTimeValue);
287 m_xDocumentHandler->endElement("mdssi:Value");
289 m_xDocumentHandler->endElement("mdssi:SignatureTime");
290 m_xDocumentHandler->endElement("SignatureProperty");
291 m_xDocumentHandler->endElement("SignatureProperties");
294 void OOXMLSecExporter::Impl::writeManifestReference(const SignatureReferenceInformation& rReference)
296 rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
297 pAttributeList->AddAttribute("URI", rReference.ouURI);
298 m_xDocumentHandler->startElement("Reference", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
300 // Transforms
301 if (rReference.ouURI.endsWith("?ContentType=application/vnd.openxmlformats-package.relationships+xml"))
303 OUString aURI = rReference.ouURI;
304 // Ignore leading slash.
305 if (aURI.startsWith("/"))
306 aURI = aURI.copy(1);
307 // Ignore query part of the URI.
308 sal_Int32 nQueryPos = aURI.indexOf('?');
309 if (nQueryPos != -1)
310 aURI = aURI.copy(0, nQueryPos);
312 m_xDocumentHandler->startElement("Transforms", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
314 writeRelationshipTransform(aURI);
315 writeCanonicalizationTransform();
317 m_xDocumentHandler->endElement("Transforms");
320 DocumentSignatureHelper::writeDigestMethod(m_xDocumentHandler);
321 m_xDocumentHandler->startElement("DigestValue", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
322 m_xDocumentHandler->characters(rReference.ouDigestValue);
323 m_xDocumentHandler->endElement("DigestValue");
324 m_xDocumentHandler->endElement("Reference");
327 void OOXMLSecExporter::Impl::writeOfficeObject()
330 rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
331 pAttributeList->AddAttribute("Id", "idOfficeObject");
332 m_xDocumentHandler->startElement("Object", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
334 m_xDocumentHandler->startElement("SignatureProperties", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
336 rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
337 pAttributeList->AddAttribute("Id", "idOfficeV1Details");
338 pAttributeList->AddAttribute("Target", "#idPackageSignature");
339 m_xDocumentHandler->startElement("SignatureProperty", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
341 writeSignatureInfo();
342 m_xDocumentHandler->endElement("SignatureProperty");
343 m_xDocumentHandler->endElement("SignatureProperties");
344 m_xDocumentHandler->endElement("Object");
347 void OOXMLSecExporter::Impl::writeSignatureInfo()
349 rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
350 pAttributeList->AddAttribute("xmlns", "http://schemas.microsoft.com/office/2006/digsig");
351 m_xDocumentHandler->startElement("SignatureInfoV1", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
353 m_xDocumentHandler->startElement("SetupId", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
354 m_xDocumentHandler->characters(m_rInformation.ouSignatureLineId);
355 m_xDocumentHandler->endElement("SetupId");
356 m_xDocumentHandler->startElement("SignatureText", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
357 m_xDocumentHandler->endElement("SignatureText");
358 m_xDocumentHandler->startElement("SignatureImage", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
359 m_xDocumentHandler->endElement("SignatureImage");
360 m_xDocumentHandler->startElement("SignatureComments", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
361 m_xDocumentHandler->characters(m_rInformation.ouDescription);
362 m_xDocumentHandler->endElement("SignatureComments");
363 // Just hardcode something valid according to [MS-OFFCRYPTO].
364 m_xDocumentHandler->startElement("WindowsVersion", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
365 m_xDocumentHandler->characters("6.1");
366 m_xDocumentHandler->endElement("WindowsVersion");
367 m_xDocumentHandler->startElement("OfficeVersion", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
368 m_xDocumentHandler->characters("16.0");
369 m_xDocumentHandler->endElement("OfficeVersion");
370 m_xDocumentHandler->startElement("ApplicationVersion", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
371 m_xDocumentHandler->characters("16.0");
372 m_xDocumentHandler->endElement("ApplicationVersion");
373 m_xDocumentHandler->startElement("Monitors", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
374 m_xDocumentHandler->characters("1");
375 m_xDocumentHandler->endElement("Monitors");
376 m_xDocumentHandler->startElement("HorizontalResolution", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
377 m_xDocumentHandler->characters("1280");
378 m_xDocumentHandler->endElement("HorizontalResolution");
379 m_xDocumentHandler->startElement("VerticalResolution", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
380 m_xDocumentHandler->characters("800");
381 m_xDocumentHandler->endElement("VerticalResolution");
382 m_xDocumentHandler->startElement("ColorDepth", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
383 m_xDocumentHandler->characters("32");
384 m_xDocumentHandler->endElement("ColorDepth");
385 m_xDocumentHandler->startElement("SignatureProviderId", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
386 m_xDocumentHandler->characters("{00000000-0000-0000-0000-000000000000}");
387 m_xDocumentHandler->endElement("SignatureProviderId");
388 m_xDocumentHandler->startElement("SignatureProviderUrl", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
389 m_xDocumentHandler->endElement("SignatureProviderUrl");
390 m_xDocumentHandler->startElement("SignatureProviderDetails", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
391 m_xDocumentHandler->characters("9"); // This is what MSO 2016 writes, though [MS-OFFCRYPTO] doesn't document what the value means.
392 m_xDocumentHandler->endElement("SignatureProviderDetails");
393 m_xDocumentHandler->startElement("SignatureType", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
394 m_xDocumentHandler->characters("1");
395 m_xDocumentHandler->endElement("SignatureType");
397 m_xDocumentHandler->endElement("SignatureInfoV1");
400 void OOXMLSecExporter::Impl::writePackageSignature()
402 m_xDocumentHandler->startElement("Object", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
404 rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
405 pAttributeList->AddAttribute("xmlns:xd", NS_XD);
406 pAttributeList->AddAttribute("Target", "#idPackageSignature");
407 m_xDocumentHandler->startElement("xd:QualifyingProperties", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
410 DocumentSignatureHelper::writeSignedProperties(m_xDocumentHandler, m_rInformation, m_aSignatureTimeValue);
412 m_xDocumentHandler->endElement("xd:QualifyingProperties");
413 m_xDocumentHandler->endElement("Object");
416 OOXMLSecExporter::OOXMLSecExporter(const uno::Reference<uno::XComponentContext>& xComponentContext,
417 const uno::Reference<embed::XStorage>& xRootStorage,
418 const uno::Reference<xml::sax::XDocumentHandler>& xDocumentHandler,
419 const SignatureInformation& rInformation)
420 : m_pImpl(o3tl::make_unique<Impl>(xComponentContext, xRootStorage, xDocumentHandler, rInformation))
424 OOXMLSecExporter::~OOXMLSecExporter() = default;
426 void OOXMLSecExporter::writeSignature()
428 rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
429 pAttributeList->AddAttribute("xmlns", NS_XMLDSIG);
430 pAttributeList->AddAttribute("Id", "idPackageSignature");
431 m_pImpl->m_xDocumentHandler->startElement("Signature", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
433 m_pImpl->writeSignedInfo();
434 m_pImpl->writeSignatureValue();
435 m_pImpl->writeKeyInfo();
436 m_pImpl->writePackageObject();
437 m_pImpl->writeOfficeObject();
438 m_pImpl->writePackageSignature();
440 m_pImpl->m_xDocumentHandler->endElement("Signature");
443 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */