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 length
+= sprintf(str
+length
, "%04x", i
);
50 return OUString::createFromAscii(str
);
53 css::uno::Reference
< css::xml::crypto::sax::XReferenceResolvedListener
> XSecController::prepareSignatureToWrite(
54 InternalSignatureInformation
& internalSignatureInfor
,
55 sal_Int32 nStorageFormat
,
56 bool bXAdESCompliantIfODF
)
58 sal_Int32 nSecurityId
= internalSignatureInfor
.signatureInfor
.nSecurityId
;
59 SignatureReferenceInformations
& vReferenceInfors
= internalSignatureInfor
.signatureInfor
.vSignatureReferenceInfors
;
61 sal_Int32 nIdOfSignatureElementCollector
;
63 nIdOfSignatureElementCollector
=
64 m_xSAXEventKeeper
->addSecurityElementCollector( css::xml::crypto::sax::ElementMarkPriority_AFTERMODIFY
, true );
66 m_xSAXEventKeeper
->setSecurityId(nIdOfSignatureElementCollector
, nSecurityId
);
68 rtl::Reference
<SignatureCreatorImpl
> xSignatureCreator(new SignatureCreatorImpl
);
70 css::uno::Sequence
<css::uno::Any
> args(5);
71 args
[0] <<= OUString::number(nSecurityId
);
72 args
[1] <<= uno::Reference
<xml::crypto::sax::XSecuritySAXEventKeeper
>(static_cast<cppu::OWeakObject
*>(m_xSAXEventKeeper
.get()), uno::UNO_QUERY
);
73 args
[2] <<= OUString::number(nIdOfSignatureElementCollector
);
75 //for nss, the internal module is used for signing, which needs to be improved later
76 args
[3] <<= m_xSecurityContext
->getSecurityEnvironment();
78 args
[4] <<= m_xXMLSignature
;
79 xSignatureCreator
->initialize(args
);
81 sal_Int32 nBlockerId
= m_xSAXEventKeeper
->addBlocker();
82 m_xSAXEventKeeper
->setSecurityId(nBlockerId
, nSecurityId
);
84 xSignatureCreator
->setBlockerId(nBlockerId
);
86 xSignatureCreator
->addSignatureCreationResultListener(this);
88 m_xSAXEventKeeper
->addReferenceResolvedListener(nIdOfSignatureElementCollector
, xSignatureCreator
.get());
90 int size
= vReferenceInfors
.size();
91 sal_Int32 nReferenceCount
= 0;
93 for(int i
=0; i
<size
; ++i
)
95 sal_Int32 keeperId
= internalSignatureInfor
.vKeeperIds
[i
];
99 m_xSAXEventKeeper
->setSecurityId(keeperId
, nSecurityId
);
100 m_xSAXEventKeeper
->addReferenceResolvedListener( keeperId
, xSignatureCreator
.get());
101 xSignatureCreator
->setReferenceId( keeperId
);
106 xSignatureCreator
->setReferenceCount( nReferenceCount
);
109 * adds all URI binding
111 for(int i
=0; i
<size
; ++i
)
113 const SignatureReferenceInformation
& refInfor
= vReferenceInfors
[i
];
115 css::uno::Reference
< css::io::XInputStream
> xInputStream
116 = getObjectInputStream( refInfor
.ouURI
);
118 if (xInputStream
.is())
119 xSignatureCreator
->setUriBinding(refInfor
.ouURI
,xInputStream
);
122 xSignatureCreator
->setKeyId(0);
124 // use sha512 for gpg signing unconditionally
125 const sal_Int32 digestID
= !internalSignatureInfor
.signatureInfor
.ouGpgCertificate
.isEmpty()?
126 css::xml::crypto::DigestID::SHA512
: (bXAdESCompliantIfODF
? css::xml::crypto::DigestID::SHA256
: css::xml::crypto::DigestID::SHA1
);
128 if (nStorageFormat
!= embed::StorageFormats::OFOPXML
)
130 internalSignatureInfor
.signatureInfor
.ouSignatureId
= createId();
131 internalSignatureInfor
.signatureInfor
.ouDateTimePropertyId
= createId();
132 internalSignatureInfor
.addReference(SignatureReferenceType::SAMEDOCUMENT
, digestID
, internalSignatureInfor
.signatureInfor
.ouDateTimePropertyId
, -1, OUString() );
135 if (bXAdESCompliantIfODF
)
137 // We write a new reference, so it's possible to use the correct type URI.
138 internalSignatureInfor
.addReference(SignatureReferenceType::SAMEDOCUMENT
, digestID
, "idSignedProperties", -1, "http://uri.etsi.org/01903#SignedProperties");
142 if (!internalSignatureInfor
.signatureInfor
.ouDescription
.isEmpty())
144 // Only mention the hash of the description in the signature if it's non-empty.
145 internalSignatureInfor
.signatureInfor
.ouDescriptionPropertyId
= createId();
146 internalSignatureInfor
.addReference(SignatureReferenceType::SAMEDOCUMENT
, digestID
, internalSignatureInfor
.signatureInfor
.ouDescriptionPropertyId
, -1, OUString());
152 internalSignatureInfor
.addReference(SignatureReferenceType::SAMEDOCUMENT
, digestID
, "idPackageObject", -1, OUString());
154 internalSignatureInfor
.addReference(SignatureReferenceType::SAMEDOCUMENT
, digestID
, "idOfficeObject", -1, OUString());
156 internalSignatureInfor
.addReference(SignatureReferenceType::SAMEDOCUMENT
, digestID
, "idSignedProperties", -1, OUString());
161 * replace both digestValues and signatureValue to " "
163 for(int i
=0; i
<size
; ++i
)
165 SignatureReferenceInformation
& refInfor
= vReferenceInfors
[i
];
166 refInfor
.ouDigestValue
= " ";
169 internalSignatureInfor
.signatureInfor
.ouSignatureValue
= " ";
171 return xSignatureCreator
.get();
174 void XSecController::signAStream( sal_Int32 securityId
, const OUString
& uri
, bool isBinary
, bool bXAdESCompliantIfODF
)
176 const SignatureReferenceType type
= isBinary
? SignatureReferenceType::BINARYSTREAM
: SignatureReferenceType::XMLSTREAM
;
177 sal_Int32 digestID
= bXAdESCompliantIfODF
? css::xml::crypto::DigestID::SHA256
: css::xml::crypto::DigestID::SHA1
;
179 int index
= findSignatureInfor( securityId
);
183 InternalSignatureInformation
isi(securityId
, nullptr);
184 isi
.addReference(type
, digestID
, uri
, -1, OUString());
185 m_vInternalSignatureInformations
.push_back( isi
);
189 // use sha512 for gpg signing unconditionally
190 if (!m_vInternalSignatureInformations
[index
].signatureInfor
.ouGpgCertificate
.isEmpty())
191 digestID
= css::xml::crypto::DigestID::SHA512
;
192 m_vInternalSignatureInformations
[index
].addReference(type
, digestID
, uri
, -1, OUString());
196 // note: this is called when creating a new signature from scratch
197 void XSecController::setX509Certificate(
198 sal_Int32 nSecurityId
,
199 const OUString
& ouX509IssuerName
,
200 const OUString
& ouX509SerialNumber
,
201 const OUString
& ouX509Cert
,
202 const OUString
& ouX509CertDigest
,
203 svl::crypto::SignatureMethodAlgorithm eAlgorithmID
)
205 int index
= findSignatureInfor( nSecurityId
);
209 InternalSignatureInformation
isi(nSecurityId
, nullptr);
210 isi
.signatureInfor
.X509Datas
.clear();
211 isi
.signatureInfor
.X509Datas
.emplace_back();
212 isi
.signatureInfor
.X509Datas
.back().emplace_back();
213 isi
.signatureInfor
.X509Datas
.back().back().X509IssuerName
= ouX509IssuerName
;
214 isi
.signatureInfor
.X509Datas
.back().back().X509SerialNumber
= ouX509SerialNumber
;
215 isi
.signatureInfor
.X509Datas
.back().back().X509Certificate
= ouX509Cert
;
216 isi
.signatureInfor
.X509Datas
.back().back().CertDigest
= ouX509CertDigest
;
217 isi
.signatureInfor
.eAlgorithmID
= eAlgorithmID
;
218 m_vInternalSignatureInformations
.push_back( isi
);
222 SignatureInformation
&si
223 = m_vInternalSignatureInformations
[index
].signatureInfor
;
224 si
.X509Datas
.clear();
225 si
.X509Datas
.emplace_back();
226 si
.X509Datas
.back().emplace_back();
227 si
.X509Datas
.back().back().X509IssuerName
= ouX509IssuerName
;
228 si
.X509Datas
.back().back().X509SerialNumber
= ouX509SerialNumber
;
229 si
.X509Datas
.back().back().X509Certificate
= ouX509Cert
;
230 si
.X509Datas
.back().back().CertDigest
= ouX509CertDigest
;
234 void XSecController::setGpgCertificate(
235 sal_Int32 nSecurityId
,
236 const OUString
& ouKeyDigest
,
237 const OUString
& ouCert
,
238 const OUString
& ouOwner
)
240 int index
= findSignatureInfor( nSecurityId
);
244 InternalSignatureInformation
isi(nSecurityId
, nullptr);
245 isi
.signatureInfor
.ouGpgCertificate
= ouCert
;
246 isi
.signatureInfor
.ouGpgOwner
= ouOwner
;
247 isi
.signatureInfor
.ouGpgKeyID
= ouKeyDigest
;
248 m_vInternalSignatureInformations
.push_back( isi
);
252 SignatureInformation
&si
253 = m_vInternalSignatureInformations
[index
].signatureInfor
;
254 si
.X509Datas
.clear(); // it is a PGP signature now
255 si
.ouGpgCertificate
= ouCert
;
256 si
.ouGpgOwner
= ouOwner
;
257 si
.ouGpgKeyID
= ouKeyDigest
;
261 void XSecController::setDate(
262 sal_Int32 nSecurityId
,
263 const css::util::DateTime
& rDateTime
)
265 int index
= findSignatureInfor( nSecurityId
);
269 InternalSignatureInformation
isi(nSecurityId
, nullptr);
270 isi
.signatureInfor
.stDateTime
= rDateTime
;
271 m_vInternalSignatureInformations
.push_back( isi
);
275 SignatureInformation
&si
276 = m_vInternalSignatureInformations
[index
].signatureInfor
;
277 si
.stDateTime
= rDateTime
;
281 void XSecController::setDescription(sal_Int32 nSecurityId
, const OUString
& rDescription
)
283 int nIndex
= findSignatureInfor(nSecurityId
);
287 InternalSignatureInformation
aInformation(nSecurityId
, nullptr);
288 aInformation
.signatureInfor
.ouDescription
= rDescription
;
289 m_vInternalSignatureInformations
.push_back(aInformation
);
293 SignatureInformation
& rInformation
= m_vInternalSignatureInformations
[nIndex
].signatureInfor
;
294 rInformation
.ouDescription
= rDescription
;
298 void XSecController::setSignatureLineId(sal_Int32 nSecurityId
, const OUString
& rSignatureLineId
)
300 int nIndex
= findSignatureInfor(nSecurityId
);
304 InternalSignatureInformation
aInformation(nSecurityId
, nullptr);
305 aInformation
.signatureInfor
.ouSignatureLineId
= rSignatureLineId
;
306 m_vInternalSignatureInformations
.push_back(aInformation
);
310 SignatureInformation
& rInformation
= m_vInternalSignatureInformations
[nIndex
].signatureInfor
;
311 rInformation
.ouSignatureLineId
= rSignatureLineId
;
315 void XSecController::setSignatureLineValidGraphic(sal_Int32 nSecurityId
,
316 const Reference
<XGraphic
>& xValidGraphic
)
318 int nIndex
= findSignatureInfor(nSecurityId
);
322 InternalSignatureInformation
aInformation(nSecurityId
, nullptr);
323 aInformation
.signatureInfor
.aValidSignatureImage
= xValidGraphic
;
324 m_vInternalSignatureInformations
.push_back(aInformation
);
328 SignatureInformation
& rInformation
329 = m_vInternalSignatureInformations
[nIndex
].signatureInfor
;
330 rInformation
.aValidSignatureImage
= xValidGraphic
;
334 void XSecController::setSignatureLineInvalidGraphic(
335 sal_Int32 nSecurityId
, const Reference
<XGraphic
>& xInvalidGraphic
)
337 int nIndex
= findSignatureInfor(nSecurityId
);
341 InternalSignatureInformation
aInformation(nSecurityId
, nullptr);
342 aInformation
.signatureInfor
.aInvalidSignatureImage
= xInvalidGraphic
;
343 m_vInternalSignatureInformations
.push_back(aInformation
);
347 SignatureInformation
& rInformation
348 = m_vInternalSignatureInformations
[nIndex
].signatureInfor
;
349 rInformation
.aInvalidSignatureImage
= xInvalidGraphic
;
353 bool XSecController::WriteSignature(
354 const css::uno::Reference
<css::xml::sax::XDocumentHandler
>& xDocumentHandler
,
355 bool bXAdESCompliantIfODF
)
359 SAL_WARN_IF( !xDocumentHandler
.is(), "xmlsecurity.helper", "I really need a document handler!" );
362 * chain the SAXEventKeeper to the SAX chain
366 if ( m_eStatusOfSecurityComponents
== InitializationState::INITIALIZED
)
368 * if all security components are ready, add the signature
372 m_bIsSAXEventKeeperSticky
= true;
373 m_xSAXEventKeeper
->setNextHandler(xDocumentHandler
);
378 * export the signature template
380 css::uno::Reference
<css::xml::sax::XDocumentHandler
> xSEKHandler(static_cast<cppu::OWeakObject
*>(m_xSAXEventKeeper
.get()),css::uno::UNO_QUERY
);
383 int sigNum
= m_vInternalSignatureInformations
.size();
385 for (i
=0; i
<sigNum
; ++i
)
387 InternalSignatureInformation
&isi
= m_vInternalSignatureInformations
[i
];
389 // Prepare the signature creator.
390 // 0 is not a documented value of embed::StorageFormats, ugh
391 isi
.xReferenceResolvedListener
= prepareSignatureToWrite( isi
, 0, bXAdESCompliantIfODF
);
393 exportSignature( xSEKHandler
, isi
.signatureInfor
, bXAdESCompliantIfODF
);
396 m_bIsSAXEventKeeperSticky
= false;
401 catch( css::uno::Exception
& )
405 m_xSAXEventKeeper
->setNextHandler( nullptr );
406 m_bIsSAXEventKeeperSticky
= false;
412 bool XSecController::WriteOOXMLSignature(const uno::Reference
<embed::XStorage
>& xRootStorage
, const uno::Reference
<xml::sax::XDocumentHandler
>& xDocumentHandler
)
416 SAL_WARN_IF(!xDocumentHandler
.is(), "xmlsecurity.helper", "empty xDocumentHandler reference");
418 // Chain the SAXEventKeeper to the SAX chain.
421 if (m_eStatusOfSecurityComponents
== InitializationState::INITIALIZED
)
423 m_bIsSAXEventKeeperSticky
= true;
424 m_xSAXEventKeeper
->setNextHandler(xDocumentHandler
);
428 // Export the signature template.
429 css::uno::Reference
<xml::sax::XDocumentHandler
> xSEKHandler(static_cast<cppu::OWeakObject
*>(m_xSAXEventKeeper
.get()), uno::UNO_QUERY
);
431 for (InternalSignatureInformation
& rInformation
: m_vInternalSignatureInformations
)
433 // Prepare the signature creator.
434 rInformation
.xReferenceResolvedListener
= prepareSignatureToWrite(rInformation
, embed::StorageFormats::OFOPXML
, false);
436 exportOOXMLSignature(xRootStorage
, xSEKHandler
, rInformation
.signatureInfor
);
439 m_bIsSAXEventKeeperSticky
= false;
444 catch(const uno::Exception
&)
448 m_xSAXEventKeeper
->setNextHandler(nullptr);
449 m_bIsSAXEventKeeperSticky
= false;
455 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */