build fix
[LibreOffice.git] / xmlsecurity / source / helper / ooxmlsecexporter.cxx
blob9627021c46d54bdc50ad23b92390bf4a8a1342fb
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 #if !HAVE_BROKEN_STATIC_INITIALIZER_LIST
77 static
78 #endif
79 const std::initializer_list<OUStringLiteral> vBlacklist =
81 OUStringLiteral("/%5BContent_Types%5D.xml"),
82 OUStringLiteral("/docProps/app.xml"),
83 OUStringLiteral("/docProps/core.xml"),
84 // Don't attempt to sign other signatures for now.
85 OUStringLiteral("/_xmlsignatures")
87 // Just check the prefix, as we don't care about the content type part of the stream name.
88 return std::find_if(vBlacklist.begin(), vBlacklist.end(), [&](const OUStringLiteral& rLiteral)
90 return rStreamName.startsWith(rLiteral);
91 }) != vBlacklist.end();
94 bool OOXMLSecExporter::Impl::isOOXMLRelationBlacklist(const OUString& rRelationName)
96 #if !HAVE_BROKEN_STATIC_INITIALIZER_LIST
97 static
98 #endif
99 const std::initializer_list<OUStringLiteral> vBlacklist =
101 OUStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties"),
102 OUStringLiteral("http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties"),
103 OUStringLiteral("http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/origin")
105 return std::find(vBlacklist.begin(), vBlacklist.end(), rRelationName) != vBlacklist.end();
108 void OOXMLSecExporter::Impl::writeSignedInfo()
110 m_xDocumentHandler->startElement("SignedInfo", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
112 writeCanonicalizationMethod();
113 writeSignatureMethod();
114 writeSignedInfoReferences();
116 m_xDocumentHandler->endElement("SignedInfo");
119 void OOXMLSecExporter::Impl::writeCanonicalizationMethod()
121 rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
122 pAttributeList->AddAttribute("Algorithm", ALGO_C14N);
123 m_xDocumentHandler->startElement("CanonicalizationMethod", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
124 m_xDocumentHandler->endElement("CanonicalizationMethod");
128 void OOXMLSecExporter::Impl::writeCanonicalizationTransform()
130 rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
131 pAttributeList->AddAttribute("Algorithm", ALGO_C14N);
132 m_xDocumentHandler->startElement("Transform", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
133 m_xDocumentHandler->endElement("Transform");
137 void OOXMLSecExporter::Impl::writeSignatureMethod()
139 rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
140 pAttributeList->AddAttribute("Algorithm", ALGO_RSASHA256);
141 m_xDocumentHandler->startElement("SignatureMethod", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
142 m_xDocumentHandler->endElement("SignatureMethod");
145 void OOXMLSecExporter::Impl::writeSignedInfoReferences()
147 const SignatureReferenceInformations& rReferences = m_rInformation.vSignatureReferenceInfors;
148 for (const SignatureReferenceInformation& rReference : rReferences)
150 if (rReference.nType == SignatureReferenceType::SAMEDOCUMENT)
153 rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
154 if (rReference.ouURI != "idSignedProperties")
155 pAttributeList->AddAttribute("Type", "http://www.w3.org/2000/09/xmldsig#Object");
156 else
157 pAttributeList->AddAttribute("Type", "http://uri.etsi.org/01903#SignedProperties");
158 pAttributeList->AddAttribute("URI", "#" + rReference.ouURI);
159 m_xDocumentHandler->startElement("Reference", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
161 if (rReference.ouURI == "idSignedProperties")
163 m_xDocumentHandler->startElement("Transforms", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
164 writeCanonicalizationTransform();
165 m_xDocumentHandler->endElement("Transforms");
168 DocumentSignatureHelper::writeDigestMethod(m_xDocumentHandler);
169 m_xDocumentHandler->startElement("DigestValue", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
170 m_xDocumentHandler->characters(rReference.ouDigestValue);
171 m_xDocumentHandler->endElement("DigestValue");
172 m_xDocumentHandler->endElement("Reference");
177 void OOXMLSecExporter::Impl::writeSignatureValue()
179 m_xDocumentHandler->startElement("SignatureValue", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
180 m_xDocumentHandler->characters(m_rInformation.ouSignatureValue);
181 m_xDocumentHandler->endElement("SignatureValue");
184 void OOXMLSecExporter::Impl::writeKeyInfo()
186 m_xDocumentHandler->startElement("KeyInfo", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
187 m_xDocumentHandler->startElement("X509Data", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
188 m_xDocumentHandler->startElement("X509Certificate", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
189 m_xDocumentHandler->characters(m_rInformation.ouX509Certificate);
190 m_xDocumentHandler->endElement("X509Certificate");
191 m_xDocumentHandler->endElement("X509Data");
192 m_xDocumentHandler->endElement("KeyInfo");
195 void OOXMLSecExporter::Impl::writePackageObject()
197 rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
198 pAttributeList->AddAttribute("Id", "idPackageObject");
199 m_xDocumentHandler->startElement("Object", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
201 writeManifest();
202 writePackageObjectSignatureProperties();
204 m_xDocumentHandler->endElement("Object");
207 void OOXMLSecExporter::Impl::writeManifest()
209 m_xDocumentHandler->startElement("Manifest", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
210 const SignatureReferenceInformations& rReferences = m_rInformation.vSignatureReferenceInfors;
211 for (const SignatureReferenceInformation& rReference : rReferences)
213 if (rReference.nType != SignatureReferenceType::SAMEDOCUMENT)
215 if (OOXMLSecExporter::Impl::isOOXMLBlacklist(rReference.ouURI))
216 continue;
218 writeManifestReference(rReference);
221 m_xDocumentHandler->endElement("Manifest");
224 void OOXMLSecExporter::Impl::writeRelationshipTransform(const OUString& rURI)
226 uno::Reference<embed::XHierarchicalStorageAccess> xHierarchicalStorageAccess(m_xRootStorage, uno::UNO_QUERY);
227 uno::Reference<io::XInputStream> xRelStream(xHierarchicalStorageAccess->openStreamElementByHierarchicalName(rURI, embed::ElementModes::READ), uno::UNO_QUERY);
229 rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
230 pAttributeList->AddAttribute("Algorithm", ALGO_RELATIONSHIP);
231 m_xDocumentHandler->startElement("Transform", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
234 uno::Sequence< uno::Sequence<beans::StringPair> > aRelationsInfo = comphelper::OFOPXMLHelper::ReadRelationsInfoSequence(xRelStream, rURI, m_xComponentContext);
235 for (const uno::Sequence<beans::StringPair>& rPairs : aRelationsInfo)
237 OUString aId;
238 OUString aType;
239 for (const beans::StringPair& rPair : rPairs)
241 if (rPair.First == "Id")
242 aId = rPair.Second;
243 else if (rPair.First == "Type")
244 aType = rPair.Second;
247 if (OOXMLSecExporter::Impl::isOOXMLRelationBlacklist(aType))
248 continue;
250 rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
251 pAttributeList->AddAttribute("xmlns:mdssi", NS_MDSSI);
252 pAttributeList->AddAttribute("SourceId", aId);
253 m_xDocumentHandler->startElement("mdssi:RelationshipReference", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
254 m_xDocumentHandler->endElement("mdssi:RelationshipReference");
257 m_xDocumentHandler->endElement("Transform");
260 void OOXMLSecExporter::Impl::writePackageObjectSignatureProperties()
262 m_xDocumentHandler->startElement("SignatureProperties", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
264 rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
265 pAttributeList->AddAttribute("Id", "idSignatureTime");
266 pAttributeList->AddAttribute("Target", "#idPackageSignature");
267 m_xDocumentHandler->startElement("SignatureProperty", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
270 rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
271 pAttributeList->AddAttribute("xmlns:mdssi", NS_MDSSI);
272 m_xDocumentHandler->startElement("mdssi:SignatureTime", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
274 m_xDocumentHandler->startElement("mdssi:Format", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
275 m_xDocumentHandler->characters("YYYY-MM-DDThh:mm:ssTZD");
276 m_xDocumentHandler->endElement("mdssi:Format");
278 m_xDocumentHandler->startElement("mdssi:Value", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
279 if (!m_rInformation.ouDateTime.isEmpty())
280 m_aSignatureTimeValue = m_rInformation.ouDateTime;
281 else
283 m_aSignatureTimeValue = utl::toISO8601(m_rInformation.stDateTime);
284 // Ignore sub-seconds.
285 sal_Int32 nCommaPos = m_aSignatureTimeValue.indexOf(',');
286 if (nCommaPos != -1)
288 m_aSignatureTimeValue = m_aSignatureTimeValue.copy(0, nCommaPos);
289 m_aSignatureTimeValue += "Z";
292 m_xDocumentHandler->characters(m_aSignatureTimeValue);
293 m_xDocumentHandler->endElement("mdssi:Value");
295 m_xDocumentHandler->endElement("mdssi:SignatureTime");
296 m_xDocumentHandler->endElement("SignatureProperty");
297 m_xDocumentHandler->endElement("SignatureProperties");
300 void OOXMLSecExporter::Impl::writeManifestReference(const SignatureReferenceInformation& rReference)
302 rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
303 pAttributeList->AddAttribute("URI", rReference.ouURI);
304 m_xDocumentHandler->startElement("Reference", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
306 // Transforms
307 if (rReference.ouURI.endsWith("?ContentType=application/vnd.openxmlformats-package.relationships+xml"))
309 OUString aURI = rReference.ouURI;
310 // Ignore leading slash.
311 if (aURI.startsWith("/"))
312 aURI = aURI.copy(1);
313 // Ignore query part of the URI.
314 sal_Int32 nQueryPos = aURI.indexOf('?');
315 if (nQueryPos != -1)
316 aURI = aURI.copy(0, nQueryPos);
318 m_xDocumentHandler->startElement("Transforms", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
320 writeRelationshipTransform(aURI);
321 writeCanonicalizationTransform();
323 m_xDocumentHandler->endElement("Transforms");
326 DocumentSignatureHelper::writeDigestMethod(m_xDocumentHandler);
327 m_xDocumentHandler->startElement("DigestValue", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
328 m_xDocumentHandler->characters(rReference.ouDigestValue);
329 m_xDocumentHandler->endElement("DigestValue");
330 m_xDocumentHandler->endElement("Reference");
333 void OOXMLSecExporter::Impl::writeOfficeObject()
336 rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
337 pAttributeList->AddAttribute("Id", "idOfficeObject");
338 m_xDocumentHandler->startElement("Object", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
340 m_xDocumentHandler->startElement("SignatureProperties", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
342 rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
343 pAttributeList->AddAttribute("Id", "idOfficeV1Details");
344 pAttributeList->AddAttribute("Target", "#idPackageSignature");
345 m_xDocumentHandler->startElement("SignatureProperty", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
347 writeSignatureInfo();
348 m_xDocumentHandler->endElement("SignatureProperty");
349 m_xDocumentHandler->endElement("SignatureProperties");
350 m_xDocumentHandler->endElement("Object");
353 void OOXMLSecExporter::Impl::writeSignatureInfo()
355 rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
356 pAttributeList->AddAttribute("xmlns", "http://schemas.microsoft.com/office/2006/digsig");
357 m_xDocumentHandler->startElement("SignatureInfoV1", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
359 m_xDocumentHandler->startElement("SetupId", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
360 m_xDocumentHandler->endElement("SetupId");
361 m_xDocumentHandler->startElement("SignatureText", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
362 m_xDocumentHandler->endElement("SignatureText");
363 m_xDocumentHandler->startElement("SignatureImage", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
364 m_xDocumentHandler->endElement("SignatureImage");
365 m_xDocumentHandler->startElement("SignatureComments", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
366 m_xDocumentHandler->characters(m_rInformation.ouDescription);
367 m_xDocumentHandler->endElement("SignatureComments");
368 // Just hardcode something valid according to [MS-OFFCRYPTO].
369 m_xDocumentHandler->startElement("WindowsVersion", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
370 m_xDocumentHandler->characters("6.1");
371 m_xDocumentHandler->endElement("WindowsVersion");
372 m_xDocumentHandler->startElement("OfficeVersion", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
373 m_xDocumentHandler->characters("16.0");
374 m_xDocumentHandler->endElement("OfficeVersion");
375 m_xDocumentHandler->startElement("ApplicationVersion", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
376 m_xDocumentHandler->characters("16.0");
377 m_xDocumentHandler->endElement("ApplicationVersion");
378 m_xDocumentHandler->startElement("Monitors", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
379 m_xDocumentHandler->characters("1");
380 m_xDocumentHandler->endElement("Monitors");
381 m_xDocumentHandler->startElement("HorizontalResolution", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
382 m_xDocumentHandler->characters("1280");
383 m_xDocumentHandler->endElement("HorizontalResolution");
384 m_xDocumentHandler->startElement("VerticalResolution", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
385 m_xDocumentHandler->characters("800");
386 m_xDocumentHandler->endElement("VerticalResolution");
387 m_xDocumentHandler->startElement("ColorDepth", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
388 m_xDocumentHandler->characters("32");
389 m_xDocumentHandler->endElement("ColorDepth");
390 m_xDocumentHandler->startElement("SignatureProviderId", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
391 m_xDocumentHandler->characters("{00000000-0000-0000-0000-000000000000}");
392 m_xDocumentHandler->endElement("SignatureProviderId");
393 m_xDocumentHandler->startElement("SignatureProviderUrl", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
394 m_xDocumentHandler->endElement("SignatureProviderUrl");
395 m_xDocumentHandler->startElement("SignatureProviderDetails", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
396 m_xDocumentHandler->characters("9"); // This is what MSO 2016 writes, though [MS-OFFCRYPTO] doesn't document what the value means.
397 m_xDocumentHandler->endElement("SignatureProviderDetails");
398 m_xDocumentHandler->startElement("SignatureType", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
399 m_xDocumentHandler->characters("1");
400 m_xDocumentHandler->endElement("SignatureType");
402 m_xDocumentHandler->endElement("SignatureInfoV1");
405 void OOXMLSecExporter::Impl::writePackageSignature()
407 m_xDocumentHandler->startElement("Object", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
409 rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
410 pAttributeList->AddAttribute("xmlns:xd", NS_XD);
411 pAttributeList->AddAttribute("Target", "#idPackageSignature");
412 m_xDocumentHandler->startElement("xd:QualifyingProperties", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
415 DocumentSignatureHelper::writeSignedProperties(m_xDocumentHandler, m_rInformation, m_aSignatureTimeValue);
417 m_xDocumentHandler->endElement("xd:QualifyingProperties");
418 m_xDocumentHandler->endElement("Object");
421 OOXMLSecExporter::OOXMLSecExporter(const uno::Reference<uno::XComponentContext>& xComponentContext,
422 const uno::Reference<embed::XStorage>& xRootStorage,
423 const uno::Reference<xml::sax::XDocumentHandler>& xDocumentHandler,
424 const SignatureInformation& rInformation)
425 : m_pImpl(o3tl::make_unique<Impl>(xComponentContext, xRootStorage, xDocumentHandler, rInformation))
429 OOXMLSecExporter::~OOXMLSecExporter() = default;
431 void OOXMLSecExporter::writeSignature()
433 rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
434 pAttributeList->AddAttribute("xmlns", NS_XMLDSIG);
435 pAttributeList->AddAttribute("Id", "idPackageSignature");
436 m_pImpl->m_xDocumentHandler->startElement("Signature", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
438 m_pImpl->writeSignedInfo();
439 m_pImpl->writeSignatureValue();
440 m_pImpl->writeKeyInfo();
441 m_pImpl->writePackageObject();
442 m_pImpl->writeOfficeObject();
443 m_pImpl->writePackageSignature();
445 m_pImpl->m_xDocumentHandler->endElement("Signature");
448 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */