1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
10 #include "ooxmlsecexporter.hxx"
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();
61 void writePackageObject();
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",
81 // Don't attempt to sign other signatures for now.
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");
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()));
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
))
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
)
233 for (const beans::StringPair
& rPair
: rPairs
)
235 if (rPair
.First
== "Id")
237 else if (rPair
.First
== "Type")
238 aType
= rPair
.Second
;
241 if (OOXMLSecExporter::Impl::isOOXMLRelationBlacklist(aType
))
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
;
277 m_aSignatureTimeValue
= utl::toISO8601(m_rInformation
.stDateTime
);
278 // Ignore sub-seconds.
279 sal_Int32 nCommaPos
= m_aSignatureTimeValue
.indexOf(',');
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()));
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("/"))
307 // Ignore query part of the URI.
308 sal_Int32 nQueryPos
= aURI
.indexOf('?');
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: */