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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <xsecctl.hxx>
23 #include <com/sun/star/xml/crypto/sax/ElementMarkPriority.hpp>
24 #include <com/sun/star/embed/StorageFormats.hpp>
26 #include <sal/log.hxx>
28 #include <framework/signaturecreatorimpl.hxx>
29 #include <framework/saxeventkeeperimpl.hxx>
31 namespace com::sun::star::graphic
{ class XGraphic
; }
34 using namespace css::uno
;
35 using namespace css::graphic
;
37 /* protected: for signature generation */
38 OUString
XSecController::createId()
41 rtl_createUuid( aSeq
, nullptr, true );
45 for (sal_uInt8 i
: aSeq
)
47 SAL_WNODEPRECATED_DECLARATIONS_PUSH
// sprintf (macOS 13 SDK)
48 length
+= sprintf(str
+length
, "%04x", i
);
49 SAL_WNODEPRECATED_DECLARATIONS_POP
52 return OUString::createFromAscii(str
);
55 css::uno::Reference
< css::xml::crypto::sax::XReferenceResolvedListener
> XSecController::prepareSignatureToWrite(
56 InternalSignatureInformation
& internalSignatureInfor
,
57 sal_Int32 nStorageFormat
,
58 bool bXAdESCompliantIfODF
)
60 sal_Int32 nSecurityId
= internalSignatureInfor
.signatureInfor
.nSecurityId
;
61 SignatureReferenceInformations
& vReferenceInfors
= internalSignatureInfor
.signatureInfor
.vSignatureReferenceInfors
;
63 sal_Int32 nIdOfSignatureElementCollector
;
65 nIdOfSignatureElementCollector
=
66 m_xSAXEventKeeper
->addSecurityElementCollector( css::xml::crypto::sax::ElementMarkPriority_AFTERMODIFY
, true );
68 m_xSAXEventKeeper
->setSecurityId(nIdOfSignatureElementCollector
, nSecurityId
);
70 rtl::Reference
<SignatureCreatorImpl
> xSignatureCreator(new SignatureCreatorImpl
);
72 css::uno::Sequence
<css::uno::Any
> args
74 Any(OUString::number(nSecurityId
)),
75 Any(uno::Reference
<xml::crypto::sax::XSecuritySAXEventKeeper
>(m_xSAXEventKeeper
)),
76 Any(OUString::number(nIdOfSignatureElementCollector
)),
78 //for nss, the internal module is used for signing, which needs to be improved later
79 Any(m_xSecurityContext
->getSecurityEnvironment()),
82 xSignatureCreator
->initialize(args
);
84 sal_Int32 nBlockerId
= m_xSAXEventKeeper
->addBlocker();
85 m_xSAXEventKeeper
->setSecurityId(nBlockerId
, nSecurityId
);
87 xSignatureCreator
->setBlockerId(nBlockerId
);
89 xSignatureCreator
->addSignatureCreationResultListener(this);
91 m_xSAXEventKeeper
->addReferenceResolvedListener(nIdOfSignatureElementCollector
, xSignatureCreator
);
93 int size
= vReferenceInfors
.size();
94 sal_Int32 nReferenceCount
= 0;
96 for(int i
=0; i
<size
; ++i
)
98 sal_Int32 keeperId
= internalSignatureInfor
.vKeeperIds
[i
];
102 m_xSAXEventKeeper
->setSecurityId(keeperId
, nSecurityId
);
103 m_xSAXEventKeeper
->addReferenceResolvedListener( keeperId
, xSignatureCreator
);
104 xSignatureCreator
->setReferenceId( keeperId
);
109 xSignatureCreator
->setReferenceCount( nReferenceCount
);
112 * adds all URI binding
114 for(int i
=0; i
<size
; ++i
)
116 const SignatureReferenceInformation
& refInfor
= vReferenceInfors
[i
];
118 css::uno::Reference
< css::io::XInputStream
> xInputStream
119 = getObjectInputStream( refInfor
.ouURI
);
121 if (xInputStream
.is())
122 xSignatureCreator
->setUriBinding(refInfor
.ouURI
,xInputStream
);
125 xSignatureCreator
->setKeyId(0);
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
);
131 if (nStorageFormat
!= embed::StorageFormats::OFOPXML
)
133 internalSignatureInfor
.signatureInfor
.ouSignatureId
= createId();
134 internalSignatureInfor
.signatureInfor
.ouDateTimePropertyId
= createId();
135 internalSignatureInfor
.addReference(SignatureReferenceType::SAMEDOCUMENT
, digestID
, internalSignatureInfor
.signatureInfor
.ouDateTimePropertyId
, -1, OUString() );
138 if (bXAdESCompliantIfODF
)
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, u
"http://uri.etsi.org/01903#SignedProperties"_ustr
);
146 if (!internalSignatureInfor
.signatureInfor
.ouDescription
.isEmpty())
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());
156 OUString aID
= createId();
157 internalSignatureInfor
.signatureInfor
.ouSignatureId
= aID
;
159 internalSignatureInfor
.addReference(SignatureReferenceType::SAMEDOCUMENT
, digestID
, "idPackageObject_" + aID
, -1, OUString());
161 internalSignatureInfor
.addReference(SignatureReferenceType::SAMEDOCUMENT
, digestID
, "idOfficeObject_" + aID
, -1, OUString());
163 internalSignatureInfor
.addReference(SignatureReferenceType::SAMEDOCUMENT
, digestID
, "idSignedProperties_" + aID
, -1, OUString());
168 * replace both digestValues and signatureValue to " "
170 for(int i
=0; i
<size
; ++i
)
172 SignatureReferenceInformation
& refInfor
= vReferenceInfors
[i
];
173 refInfor
.ouDigestValue
= " ";
176 internalSignatureInfor
.signatureInfor
.ouSignatureValue
= " ";
178 return xSignatureCreator
;
181 void XSecController::signAStream( sal_Int32 securityId
, const OUString
& uri
, bool isBinary
, bool bXAdESCompliantIfODF
)
183 const SignatureReferenceType type
= isBinary
? SignatureReferenceType::BINARYSTREAM
: SignatureReferenceType::XMLSTREAM
;
184 sal_Int32 digestID
= bXAdESCompliantIfODF
? css::xml::crypto::DigestID::SHA256
: css::xml::crypto::DigestID::SHA1
;
186 int index
= findSignatureInfor( securityId
);
190 InternalSignatureInformation
isi(securityId
, nullptr);
191 isi
.addReference(type
, digestID
, uri
, -1, OUString());
192 m_vInternalSignatureInformations
.push_back( isi
);
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());
203 // note: this is called when creating a new signature from scratch
204 void XSecController::setX509Certificate(
205 sal_Int32 nSecurityId
,
206 const OUString
& ouX509IssuerName
,
207 const OUString
& ouX509SerialNumber
,
208 const OUString
& ouX509Cert
,
209 const OUString
& ouX509CertDigest
,
210 svl::crypto::SignatureMethodAlgorithm eAlgorithmID
)
212 int index
= findSignatureInfor( nSecurityId
);
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
);
229 SignatureInformation
&si
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
;
241 void XSecController::setGpgCertificate(
242 sal_Int32 nSecurityId
,
243 const OUString
& ouKeyDigest
,
244 const OUString
& ouCert
,
245 const OUString
& ouOwner
)
247 int index
= findSignatureInfor( nSecurityId
);
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
);
259 SignatureInformation
&si
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
;
268 void XSecController::setDate(
269 sal_Int32 nSecurityId
,
270 const css::util::DateTime
& rDateTime
)
272 int index
= findSignatureInfor( nSecurityId
);
276 InternalSignatureInformation
isi(nSecurityId
, nullptr);
277 isi
.signatureInfor
.stDateTime
= rDateTime
;
278 m_vInternalSignatureInformations
.push_back( isi
);
282 SignatureInformation
&si
283 = m_vInternalSignatureInformations
[index
].signatureInfor
;
284 si
.stDateTime
= rDateTime
;
288 void XSecController::setDescription(sal_Int32 nSecurityId
, const OUString
& rDescription
)
290 int nIndex
= findSignatureInfor(nSecurityId
);
294 InternalSignatureInformation
aInformation(nSecurityId
, nullptr);
295 aInformation
.signatureInfor
.ouDescription
= rDescription
;
296 m_vInternalSignatureInformations
.push_back(aInformation
);
300 SignatureInformation
& rInformation
= m_vInternalSignatureInformations
[nIndex
].signatureInfor
;
301 rInformation
.ouDescription
= rDescription
;
305 void XSecController::setSignatureLineId(sal_Int32 nSecurityId
, const OUString
& rSignatureLineId
)
307 int nIndex
= findSignatureInfor(nSecurityId
);
311 InternalSignatureInformation
aInformation(nSecurityId
, nullptr);
312 aInformation
.signatureInfor
.ouSignatureLineId
= rSignatureLineId
;
313 m_vInternalSignatureInformations
.push_back(aInformation
);
317 SignatureInformation
& rInformation
= m_vInternalSignatureInformations
[nIndex
].signatureInfor
;
318 rInformation
.ouSignatureLineId
= rSignatureLineId
;
322 void XSecController::setSignatureLineValidGraphic(sal_Int32 nSecurityId
,
323 const Reference
<XGraphic
>& xValidGraphic
)
325 int nIndex
= findSignatureInfor(nSecurityId
);
329 InternalSignatureInformation
aInformation(nSecurityId
, nullptr);
330 aInformation
.signatureInfor
.aValidSignatureImage
= xValidGraphic
;
331 m_vInternalSignatureInformations
.push_back(aInformation
);
335 SignatureInformation
& rInformation
336 = m_vInternalSignatureInformations
[nIndex
].signatureInfor
;
337 rInformation
.aValidSignatureImage
= xValidGraphic
;
341 void XSecController::setSignatureLineInvalidGraphic(
342 sal_Int32 nSecurityId
, const Reference
<XGraphic
>& xInvalidGraphic
)
344 int nIndex
= findSignatureInfor(nSecurityId
);
348 InternalSignatureInformation
aInformation(nSecurityId
, nullptr);
349 aInformation
.signatureInfor
.aInvalidSignatureImage
= xInvalidGraphic
;
350 m_vInternalSignatureInformations
.push_back(aInformation
);
354 SignatureInformation
& rInformation
355 = m_vInternalSignatureInformations
[nIndex
].signatureInfor
;
356 rInformation
.aInvalidSignatureImage
= xInvalidGraphic
;
360 bool XSecController::WriteSignature(
361 const css::uno::Reference
<css::xml::sax::XDocumentHandler
>& xDocumentHandler
,
362 bool bXAdESCompliantIfODF
)
366 SAL_WARN_IF( !xDocumentHandler
.is(), "xmlsecurity.helper", "I really need a document handler!" );
369 * chain the SAXEventKeeper to the SAX chain
373 if ( m_eStatusOfSecurityComponents
== InitializationState::INITIALIZED
)
375 * if all security components are ready, add the signature
379 m_bIsSAXEventKeeperSticky
= true;
380 m_xSAXEventKeeper
->setNextHandler(xDocumentHandler
);
385 * export the signature template
387 css::uno::Reference
<css::xml::sax::XDocumentHandler
> xSEKHandler(m_xSAXEventKeeper
);
390 int sigNum
= m_vInternalSignatureInformations
.size();
392 for (i
=0; i
<sigNum
; ++i
)
394 InternalSignatureInformation
&isi
= m_vInternalSignatureInformations
[i
];
396 // Prepare the signature creator.
397 // 0 is not a documented value of embed::StorageFormats, ugh
398 isi
.xReferenceResolvedListener
= prepareSignatureToWrite( isi
, 0, bXAdESCompliantIfODF
);
400 exportSignature( xSEKHandler
, isi
.signatureInfor
, bXAdESCompliantIfODF
);
403 m_bIsSAXEventKeeperSticky
= false;
408 catch( css::uno::Exception
& )
412 m_xSAXEventKeeper
->setNextHandler( nullptr );
413 m_bIsSAXEventKeeperSticky
= false;
419 bool XSecController::WriteOOXMLSignature(const uno::Reference
<embed::XStorage
>& xRootStorage
, const uno::Reference
<xml::sax::XDocumentHandler
>& xDocumentHandler
)
423 SAL_WARN_IF(!xDocumentHandler
.is(), "xmlsecurity.helper", "empty xDocumentHandler reference");
425 // Chain the SAXEventKeeper to the SAX chain.
428 if (m_eStatusOfSecurityComponents
== InitializationState::INITIALIZED
)
430 m_bIsSAXEventKeeperSticky
= true;
431 m_xSAXEventKeeper
->setNextHandler(xDocumentHandler
);
435 // Export the signature template.
436 css::uno::Reference
<xml::sax::XDocumentHandler
> xSEKHandler(m_xSAXEventKeeper
);
438 for (InternalSignatureInformation
& rInformation
: m_vInternalSignatureInformations
)
440 // Prepare the signature creator.
441 rInformation
.xReferenceResolvedListener
= prepareSignatureToWrite(rInformation
, embed::StorageFormats::OFOPXML
, false);
443 exportOOXMLSignature(xRootStorage
, xSEKHandler
, rInformation
.signatureInfor
);
446 m_bIsSAXEventKeeperSticky
= false;
451 catch(const uno::Exception
&)
455 m_xSAXEventKeeper
->setNextHandler(nullptr);
456 m_bIsSAXEventKeeperSticky
= false;
462 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */