LibreOffice Module xmlsecurity (master) 1
xsecsign.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20
21#include <xsecctl.hxx>
22
23#include <com/sun/star/xml/crypto/sax/ElementMarkPriority.hpp>
24#include <com/sun/star/embed/StorageFormats.hpp>
25#include <rtl/uuid.h>
26#include <sal/log.hxx>
27
30
31namespace com::sun::star::graphic { class XGraphic; }
32
33using namespace css;
34using namespace css::uno;
35using namespace css::graphic;
36
37/* protected: for signature generation */
39{
40 sal_uInt8 aSeq[16];
41 rtl_createUuid( aSeq, nullptr, true );
42
43 char str[68]="ID_";
44 int length = 3;
45 for (sal_uInt8 i : aSeq)
46 {
47 SAL_WNODEPRECATED_DECLARATIONS_PUSH // sprintf (macOS 13 SDK)
48 length += sprintf(str+length, "%04x", i);
50 }
51
52 return OUString::createFromAscii(str);
53}
54
55css::uno::Reference< css::xml::crypto::sax::XReferenceResolvedListener > XSecController::prepareSignatureToWrite(
56 InternalSignatureInformation& internalSignatureInfor,
57 sal_Int32 nStorageFormat,
58 bool bXAdESCompliantIfODF)
59{
60 sal_Int32 nSecurityId = internalSignatureInfor.signatureInfor.nSecurityId;
61 SignatureReferenceInformations& vReferenceInfors = internalSignatureInfor.signatureInfor.vSignatureReferenceInfors;
62
63 sal_Int32 nIdOfSignatureElementCollector;
64
65 nIdOfSignatureElementCollector =
66 m_xSAXEventKeeper->addSecurityElementCollector( css::xml::crypto::sax::ElementMarkPriority_AFTERMODIFY, true );
67
68 m_xSAXEventKeeper->setSecurityId(nIdOfSignatureElementCollector, nSecurityId);
69
71
72 css::uno::Sequence<css::uno::Any> args
73 {
74 Any(OUString::number(nSecurityId)),
75 Any(uno::Reference<xml::crypto::sax::XSecuritySAXEventKeeper>(m_xSAXEventKeeper)),
76 Any(OUString::number(nIdOfSignatureElementCollector)),
77
78 //for nss, the internal module is used for signing, which needs to be improved later
79 Any(m_xSecurityContext->getSecurityEnvironment()),
81 };
82 xSignatureCreator->initialize(args);
83
84 sal_Int32 nBlockerId = m_xSAXEventKeeper->addBlocker();
85 m_xSAXEventKeeper->setSecurityId(nBlockerId, nSecurityId);
86
87 xSignatureCreator->setBlockerId(nBlockerId);
88
89 xSignatureCreator->addSignatureCreationResultListener(this);
90
91 m_xSAXEventKeeper->addReferenceResolvedListener(nIdOfSignatureElementCollector, xSignatureCreator);
92
93 int size = vReferenceInfors.size();
94 sal_Int32 nReferenceCount = 0;
95
96 for(int i=0; i<size; ++i)
97 {
98 sal_Int32 keeperId = internalSignatureInfor.vKeeperIds[i];
99
100 if ( keeperId != -1)
101 {
102 m_xSAXEventKeeper->setSecurityId(keeperId, nSecurityId);
103 m_xSAXEventKeeper->addReferenceResolvedListener( keeperId, xSignatureCreator);
104 xSignatureCreator->setReferenceId( keeperId );
105 nReferenceCount++;
106 }
107 }
108
109 xSignatureCreator->setReferenceCount( nReferenceCount );
110
111 /*
112 * adds all URI binding
113 */
114 for(int i=0; i<size; ++i)
115 {
116 const SignatureReferenceInformation& refInfor = vReferenceInfors[i];
117
118 css::uno::Reference< css::io::XInputStream > xInputStream
119 = getObjectInputStream( refInfor.ouURI );
120
121 if (xInputStream.is())
122 xSignatureCreator->setUriBinding(refInfor.ouURI,xInputStream);
123 }
124
125 xSignatureCreator->setKeyId(0);
126
127 // use sha512 for gpg signing unconditionally
128 const sal_Int32 digestID = !internalSignatureInfor.signatureInfor.ouGpgCertificate.isEmpty()?
129 css::xml::crypto::DigestID::SHA512 : (bXAdESCompliantIfODF ? css::xml::crypto::DigestID::SHA256 : css::xml::crypto::DigestID::SHA1);
130
131 if (nStorageFormat != embed::StorageFormats::OFOPXML)
132 {
133 internalSignatureInfor.signatureInfor.ouSignatureId = createId();
134 internalSignatureInfor.signatureInfor.ouDateTimePropertyId = createId();
135 internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, internalSignatureInfor.signatureInfor.ouDateTimePropertyId, -1, OUString() );
136 size++;
137
138 if (bXAdESCompliantIfODF)
139 {
140 OUString aId = "idSignedProperties_" + internalSignatureInfor.signatureInfor.ouSignatureId;
141 // We write a new reference, so it's possible to use the correct type URI.
142 internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, aId, -1, "http://uri.etsi.org/01903#SignedProperties");
143 size++;
144 }
145
146 if (!internalSignatureInfor.signatureInfor.ouDescription.isEmpty())
147 {
148 // Only mention the hash of the description in the signature if it's non-empty.
149 internalSignatureInfor.signatureInfor.ouDescriptionPropertyId = createId();
150 internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, internalSignatureInfor.signatureInfor.ouDescriptionPropertyId, -1, OUString());
151 size++;
152 }
153 }
154 else // OOXML
155 {
156 OUString aID = createId();
157 internalSignatureInfor.signatureInfor.ouSignatureId = aID;
158
159 internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, "idPackageObject_" + aID, -1, OUString());
160 size++;
161 internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, "idOfficeObject_" + aID, -1, OUString());
162 size++;
163 internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, "idSignedProperties_" + aID, -1, OUString());
164 size++;
165 }
166
167 /*
168 * replace both digestValues and signatureValue to " "
169 */
170 for(int i=0; i<size; ++i)
171 {
172 SignatureReferenceInformation& refInfor = vReferenceInfors[i];
173 refInfor.ouDigestValue = " ";
174 }
175
176 internalSignatureInfor.signatureInfor.ouSignatureValue = " ";
177
178 return xSignatureCreator;
179}
180
181void XSecController::signAStream( sal_Int32 securityId, const OUString& uri, bool isBinary, bool bXAdESCompliantIfODF)
182{
183 const SignatureReferenceType type = isBinary ? SignatureReferenceType::BINARYSTREAM : SignatureReferenceType::XMLSTREAM;
184 sal_Int32 digestID = bXAdESCompliantIfODF ? css::xml::crypto::DigestID::SHA256 : css::xml::crypto::DigestID::SHA1;
185
186 int index = findSignatureInfor( securityId );
187
188 if (index == -1)
189 {
190 InternalSignatureInformation isi(securityId, nullptr);
191 isi.addReference(type, digestID, uri, -1, OUString());
192 m_vInternalSignatureInformations.push_back( isi );
193 }
194 else
195 {
196 // use sha512 for gpg signing unconditionally
197 if (!m_vInternalSignatureInformations[index].signatureInfor.ouGpgCertificate.isEmpty())
198 digestID = css::xml::crypto::DigestID::SHA512;
199 m_vInternalSignatureInformations[index].addReference(type, digestID, uri, -1, OUString());
200 }
201}
202
203// note: this is called when creating a new signature from scratch
205 sal_Int32 nSecurityId,
206 const OUString& ouX509IssuerName,
207 const OUString& ouX509SerialNumber,
208 const OUString& ouX509Cert,
209 const OUString& ouX509CertDigest,
211{
212 int index = findSignatureInfor( nSecurityId );
213
214 if ( index == -1 )
215 {
216 InternalSignatureInformation isi(nSecurityId, nullptr);
217 isi.signatureInfor.X509Datas.clear();
218 isi.signatureInfor.X509Datas.emplace_back();
219 isi.signatureInfor.X509Datas.back().emplace_back();
220 isi.signatureInfor.X509Datas.back().back().X509IssuerName = ouX509IssuerName;
221 isi.signatureInfor.X509Datas.back().back().X509SerialNumber = ouX509SerialNumber;
222 isi.signatureInfor.X509Datas.back().back().X509Certificate = ouX509Cert;
223 isi.signatureInfor.X509Datas.back().back().CertDigest = ouX509CertDigest;
224 isi.signatureInfor.eAlgorithmID = eAlgorithmID;
225 m_vInternalSignatureInformations.push_back( isi );
226 }
227 else
228 {
230 = m_vInternalSignatureInformations[index].signatureInfor;
231 si.X509Datas.clear();
232 si.X509Datas.emplace_back();
233 si.X509Datas.back().emplace_back();
234 si.X509Datas.back().back().X509IssuerName = ouX509IssuerName;
235 si.X509Datas.back().back().X509SerialNumber = ouX509SerialNumber;
236 si.X509Datas.back().back().X509Certificate = ouX509Cert;
237 si.X509Datas.back().back().CertDigest = ouX509CertDigest;
238 }
239}
240
242 sal_Int32 nSecurityId,
243 const OUString& ouKeyDigest,
244 const OUString& ouCert,
245 const OUString& ouOwner)
246{
247 int index = findSignatureInfor( nSecurityId );
248
249 if ( index == -1 )
250 {
251 InternalSignatureInformation isi(nSecurityId, nullptr);
252 isi.signatureInfor.ouGpgCertificate = ouCert;
253 isi.signatureInfor.ouGpgOwner = ouOwner;
254 isi.signatureInfor.ouGpgKeyID = ouKeyDigest;
255 m_vInternalSignatureInformations.push_back( isi );
256 }
257 else
258 {
260 = m_vInternalSignatureInformations[index].signatureInfor;
261 si.X509Datas.clear(); // it is a PGP signature now
262 si.ouGpgCertificate = ouCert;
263 si.ouGpgOwner = ouOwner;
264 si.ouGpgKeyID = ouKeyDigest;
265 }
266}
267
269 sal_Int32 nSecurityId,
270 const css::util::DateTime& rDateTime )
271{
272 int index = findSignatureInfor( nSecurityId );
273
274 if ( index == -1 )
275 {
276 InternalSignatureInformation isi(nSecurityId, nullptr);
277 isi.signatureInfor.stDateTime = rDateTime;
278 m_vInternalSignatureInformations.push_back( isi );
279 }
280 else
281 {
283 = m_vInternalSignatureInformations[index].signatureInfor;
284 si.stDateTime = rDateTime;
285 }
286}
287
288void XSecController::setDescription(sal_Int32 nSecurityId, const OUString& rDescription)
289{
290 int nIndex = findSignatureInfor(nSecurityId);
291
292 if (nIndex == -1)
293 {
294 InternalSignatureInformation aInformation(nSecurityId, nullptr);
295 aInformation.signatureInfor.ouDescription = rDescription;
296 m_vInternalSignatureInformations.push_back(aInformation);
297 }
298 else
299 {
300 SignatureInformation& rInformation = m_vInternalSignatureInformations[nIndex].signatureInfor;
301 rInformation.ouDescription = rDescription;
302 }
303}
304
305void XSecController::setSignatureLineId(sal_Int32 nSecurityId, const OUString& rSignatureLineId)
306{
307 int nIndex = findSignatureInfor(nSecurityId);
308
309 if (nIndex == -1)
310 {
311 InternalSignatureInformation aInformation(nSecurityId, nullptr);
312 aInformation.signatureInfor.ouSignatureLineId = rSignatureLineId;
313 m_vInternalSignatureInformations.push_back(aInformation);
314 }
315 else
316 {
317 SignatureInformation& rInformation = m_vInternalSignatureInformations[nIndex].signatureInfor;
318 rInformation.ouSignatureLineId = rSignatureLineId;
319 }
320}
321
323 const Reference<XGraphic>& xValidGraphic)
324{
325 int nIndex = findSignatureInfor(nSecurityId);
326
327 if (nIndex == -1)
328 {
329 InternalSignatureInformation aInformation(nSecurityId, nullptr);
330 aInformation.signatureInfor.aValidSignatureImage = xValidGraphic;
331 m_vInternalSignatureInformations.push_back(aInformation);
332 }
333 else
334 {
335 SignatureInformation& rInformation
337 rInformation.aValidSignatureImage = xValidGraphic;
338 }
339}
340
342 sal_Int32 nSecurityId, const Reference<XGraphic>& xInvalidGraphic)
343{
344 int nIndex = findSignatureInfor(nSecurityId);
345
346 if (nIndex == -1)
347 {
348 InternalSignatureInformation aInformation(nSecurityId, nullptr);
349 aInformation.signatureInfor.aInvalidSignatureImage = xInvalidGraphic;
350 m_vInternalSignatureInformations.push_back(aInformation);
351 }
352 else
353 {
354 SignatureInformation& rInformation
356 rInformation.aInvalidSignatureImage = xInvalidGraphic;
357 }
358}
359
361 const css::uno::Reference<css::xml::sax::XDocumentHandler>& xDocumentHandler,
362 bool bXAdESCompliantIfODF )
363{
364 bool rc = false;
365
366 SAL_WARN_IF( !xDocumentHandler.is(), "xmlsecurity.helper", "I really need a document handler!" );
367
368 /*
369 * chain the SAXEventKeeper to the SAX chain
370 */
371 chainOn();
372
374 /*
375 * if all security components are ready, add the signature
376 * stream.
377 */
378 {
380 m_xSAXEventKeeper->setNextHandler(xDocumentHandler);
381
382 try
383 {
384 /*
385 * export the signature template
386 */
387 css::uno::Reference<css::xml::sax::XDocumentHandler> xSEKHandler(m_xSAXEventKeeper);
388
389 int i;
390 int sigNum = m_vInternalSignatureInformations.size();
391
392 for (i=0; i<sigNum; ++i)
393 {
395
396 // Prepare the signature creator.
397 // 0 is not a documented value of embed::StorageFormats, ugh
398 isi.xReferenceResolvedListener = prepareSignatureToWrite( isi, 0, bXAdESCompliantIfODF );
399
400 exportSignature( xSEKHandler, isi.signatureInfor, bXAdESCompliantIfODF );
401 }
402
404 chainOff();
405
406 rc = true;
407 }
408 catch( css::uno::Exception& )
409 {
410 }
411
412 m_xSAXEventKeeper->setNextHandler( nullptr );
414 }
415
416 return rc;
417}
418
419bool XSecController::WriteOOXMLSignature(const uno::Reference<embed::XStorage>& xRootStorage, const uno::Reference<xml::sax::XDocumentHandler>& xDocumentHandler)
420{
421 bool bRet = false;
422
423 SAL_WARN_IF(!xDocumentHandler.is(), "xmlsecurity.helper", "empty xDocumentHandler reference");
424
425 // Chain the SAXEventKeeper to the SAX chain.
426 chainOn();
427
429 {
431 m_xSAXEventKeeper->setNextHandler(xDocumentHandler);
432
433 try
434 {
435 // Export the signature template.
436 css::uno::Reference<xml::sax::XDocumentHandler> xSEKHandler(m_xSAXEventKeeper);
437
439 {
440 // Prepare the signature creator.
441 rInformation.xReferenceResolvedListener = prepareSignatureToWrite(rInformation, embed::StorageFormats::OFOPXML, false);
442
443 exportOOXMLSignature(xRootStorage, xSEKHandler, rInformation.signatureInfor);
444 }
445
447 chainOff();
448
449 bRet = true;
450 }
451 catch(const uno::Exception&)
452 {
453 }
454
455 m_xSAXEventKeeper->setNextHandler(nullptr);
457 }
458
459 return bRet;
460}
461
462/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SignatureInformation signatureInfor
Definition: xsecctl.hxx:71
void addReference(SignatureReferenceType type, sal_Int32 digestID, const OUString &uri, sal_Int32 keeperId, const OUString &rType)
Definition: xsecctl.hxx:85
css::uno::Reference< css::xml::crypto::sax::XReferenceResolvedListener > xReferenceResolvedListener
Definition: xsecctl.hxx:73
::std::vector< sal_Int32 > vKeeperIds
Definition: xsecctl.hxx:75
bool m_bIsSAXEventKeeperSticky
Definition: xsecctl.hxx:199
rtl::Reference< SAXEventKeeperImpl > m_xSAXEventKeeper
Definition: xsecctl.hxx:124
bool WriteOOXMLSignature(const css::uno::Reference< css::embed::XStorage > &xRootStorage, const css::uno::Reference< css::xml::sax::XDocumentHandler > &xDocumentHandler)
Writes XML elements inside a single OOXML signature's <Signature> element.
Definition: xsecsign.cxx:419
enum XSecController::InitializationState m_eStatusOfSecurityComponents
static OUString createId()
Definition: xsecsign.cxx:38
void setX509Certificate(sal_Int32 nSecurityId, const OUString &ouX509IssuerName, const OUString &ouX509SerialNumber, const OUString &ouX509Cert, const OUString &ouX509CertDigest, svl::crypto::SignatureMethodAlgorithm eAlgorithmID)
sets data that describes the certificate.
Definition: xsecsign.cxx:204
void setSignatureLineInvalidGraphic(sal_Int32 nSecurityId, const css::uno::Reference< css::graphic::XGraphic > &xInvalidGraphic)
Definition: xsecsign.cxx:341
css::uno::Reference< css::xml::crypto::XXMLSecurityContext > m_xSecurityContext
Definition: xsecctl.hxx:134
css::uno::Reference< css::xml::crypto::XXMLSignature > m_xXMLSignature
Definition: xsecctl.hxx:129
std::vector< InternalSignatureInformation > m_vInternalSignatureInformations
Definition: xsecctl.hxx:147
void signAStream(sal_Int32 securityId, const OUString &uri, bool isBinary, bool bXAdESCompliantIfODF)
Definition: xsecsign.cxx:181
void setGpgCertificate(OUString const &ouGpgCert)
Definition: xsecverify.cxx:346
void setDescription(OUString const &rId, OUString const &rDescription)
Definition: xsecverify.cxx:390
bool WriteSignature(const css::uno::Reference< css::xml::sax::XDocumentHandler > &xDocumentHandler, bool bXAdESCompliantIfODF)
Definition: xsecsign.cxx:360
void exportOOXMLSignature(const css::uno::Reference< css::embed::XStorage > &xRootStorage, const css::uno::Reference< css::xml::sax::XDocumentHandler > &xDocumentHandler, const SignatureInformation &rInformation)
Exports an OOXML signature, called by WriteOOXMLSignature().
Definition: xsecctl.cxx:921
bool chainOn()
Definition: xsecctl.cxx:218
static void exportSignature(const css::uno::Reference< css::xml::sax::XDocumentHandler > &xDocumentHandler, const SignatureInformation &signatureInfo, bool bXAdESCompliantIfODF)
Definition: xsecctl.cxx:564
void chainOff()
Definition: xsecctl.cxx:308
void setDate(OUString const &rId, OUString const &ouDate)
Definition: xsecverify.cxx:368
void setSignatureLineValidGraphic(sal_Int32 nSecurityId, const css::uno::Reference< css::graphic::XGraphic > &xValidGraphic)
Definition: xsecsign.cxx:322
css::uno::Reference< css::xml::crypto::sax::XReferenceResolvedListener > prepareSignatureToWrite(InternalSignatureInformation &signatureInfo, sal_Int32 nStorageFormat, bool bXAdESCompliantIfODF)
Definition: xsecsign.cxx:55
css::uno::Reference< css::io::XInputStream > getObjectInputStream(const OUString &objectURL)
Definition: xsecctl.cxx:392
int findSignatureInfor(sal_Int32 nSecurityId) const
Definition: xsecctl.cxx:124
void setSignatureLineId(const OUString &rSignatureLineId)
Definition: xsecverify.cxx:514
sal_Int32 nIndex
Sequence< sal_Int8 > aSeq
#define SAL_WARN_IF(condition, area, stream)
size
int i
index
int sprintf(char(&s)[N], char const *format, T &&... arguments)
args
::std::vector< SignatureReferenceInformation > SignatureReferenceInformations
SignatureReferenceType
css::uno::Reference< css::graphic::XGraphic > aValidSignatureImage
SignatureReferenceInformations vSignatureReferenceInfors
OUString ouSignatureLineId
std::vector< X509Data > X509Datas
OUString ouDateTimePropertyId
svl::crypto::SignatureMethodAlgorithm eAlgorithmID
OUString ouDescriptionPropertyId
css::uno::Reference< css::graphic::XGraphic > aInvalidSignatureImage
css::util::DateTime stDateTime
#define SAL_WNODEPRECATED_DECLARATIONS_POP
unsigned char sal_uInt8
#define SAL_WNODEPRECATED_DECLARATIONS_PUSH
ResultType type