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 
28 #include <framework/signaturecreatorimpl.hxx>
29 #include <framework/saxeventkeeperimpl.hxx>
30 
31 namespace com::sun::star::graphic { class XGraphic; }
32 
33 using namespace css;
34 using namespace css::uno;
35 using namespace css::graphic;
36 namespace cssu = com::sun::star::uno;
37 namespace cssl = com::sun::star::lang;
38 namespace cssxc = com::sun::star::xml::crypto;
39 namespace cssxs = com::sun::star::xml::sax;
40 
41 /* protected: for signature generation */
createId()42 OUString XSecController::createId()
43 {
44     sal_uInt8 aSeq[16];
45     rtl_createUuid( aSeq, nullptr, true );
46 
47     char str[68]="ID_";
48     int length = 3;
49     for (sal_uInt8 i : aSeq)
50     {
51         length += sprintf(str+length, "%04x", i);
52     }
53 
54     return OUString::createFromAscii(str);
55 }
56 
prepareSignatureToWrite(InternalSignatureInformation & internalSignatureInfor,sal_Int32 nStorageFormat,bool bXAdESCompliantIfODF)57 cssu::Reference< cssxc::sax::XReferenceResolvedListener > XSecController::prepareSignatureToWrite(
58     InternalSignatureInformation& internalSignatureInfor,
59     sal_Int32 nStorageFormat,
60     bool bXAdESCompliantIfODF)
61 {
62     sal_Int32 nSecurityId = internalSignatureInfor.signatureInfor.nSecurityId;
63     SignatureReferenceInformations& vReferenceInfors = internalSignatureInfor.signatureInfor.vSignatureReferenceInfors;
64 
65     sal_Int32 nIdOfSignatureElementCollector;
66 
67     nIdOfSignatureElementCollector =
68         m_xSAXEventKeeper->addSecurityElementCollector( cssxc::sax::ElementMarkPriority_AFTERMODIFY, true );
69 
70     m_xSAXEventKeeper->setSecurityId(nIdOfSignatureElementCollector, nSecurityId);
71 
72     rtl::Reference<SignatureCreatorImpl> xSignatureCreator(new SignatureCreatorImpl);
73 
74     cssu::Sequence<cssu::Any> args(5);
75     args[0] <<= OUString::number(nSecurityId);
76     args[1] <<= uno::Reference<xml::crypto::sax::XSecuritySAXEventKeeper>(static_cast<cppu::OWeakObject*>(m_xSAXEventKeeper.get()), uno::UNO_QUERY);
77     args[2] <<= OUString::number(nIdOfSignatureElementCollector);
78 
79     //for nss, the internal module is used for signing, which needs to be improved later
80     args[3] <<= m_xSecurityContext->getSecurityEnvironment();
81 
82     args[4] <<= m_xXMLSignature;
83     xSignatureCreator->initialize(args);
84 
85     sal_Int32 nBlockerId = m_xSAXEventKeeper->addBlocker();
86     m_xSAXEventKeeper->setSecurityId(nBlockerId, nSecurityId);
87 
88     xSignatureCreator->setBlockerId(nBlockerId);
89 
90     xSignatureCreator->addSignatureCreationResultListener(this);
91 
92     m_xSAXEventKeeper->addReferenceResolvedListener(nIdOfSignatureElementCollector, xSignatureCreator.get());
93 
94     int size = vReferenceInfors.size();
95     sal_Int32 nReferenceCount = 0;
96 
97     for(int i=0; i<size; ++i)
98     {
99         sal_Int32 keeperId = internalSignatureInfor.vKeeperIds[i];
100 
101         if ( keeperId != -1)
102         {
103             m_xSAXEventKeeper->setSecurityId(keeperId, nSecurityId);
104             m_xSAXEventKeeper->addReferenceResolvedListener( keeperId, xSignatureCreator.get());
105             xSignatureCreator->setReferenceId( keeperId );
106             nReferenceCount++;
107         }
108     }
109 
110     xSignatureCreator->setReferenceCount( nReferenceCount );
111 
112     /*
113      * adds all URI binding
114      */
115     for(int i=0; i<size; ++i)
116     {
117         const SignatureReferenceInformation& refInfor = vReferenceInfors[i];
118 
119         cssu::Reference< css::io::XInputStream > xInputStream
120             = getObjectInputStream( refInfor.ouURI );
121 
122         if (xInputStream.is())
123             xSignatureCreator->setUriBinding(refInfor.ouURI,xInputStream);
124     }
125 
126     xSignatureCreator->setKeyId(0);
127 
128     // use sha512 for gpg signing unconditionally
129     const sal_Int32 digestID = !internalSignatureInfor.signatureInfor.ouGpgCertificate.isEmpty()?
130         cssxc::DigestID::SHA512 : (bXAdESCompliantIfODF ? cssxc::DigestID::SHA256 : cssxc::DigestID::SHA1);
131 
132     if (nStorageFormat != embed::StorageFormats::OFOPXML)
133     {
134         internalSignatureInfor.signatureInfor.ouSignatureId = createId();
135         internalSignatureInfor.signatureInfor.ouPropertyId = createId();
136         internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, internalSignatureInfor.signatureInfor.ouPropertyId, -1, OUString() );
137         size++;
138 
139         if (bXAdESCompliantIfODF)
140         {
141             // We write a new reference, so it's possible to use the correct type URI.
142             internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, "idSignedProperties", -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
155     {
156         internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, "idPackageObject", -1, OUString());
157         size++;
158         internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, "idOfficeObject", -1, OUString());
159         size++;
160         internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, "idSignedProperties", -1, OUString());
161         size++;
162     }
163 
164     /*
165      * replace both digestValues and signatureValue to " "
166      */
167     for(int i=0; i<size; ++i)
168     {
169         SignatureReferenceInformation& refInfor = vReferenceInfors[i];
170         refInfor.ouDigestValue = " ";
171     }
172 
173     internalSignatureInfor.signatureInfor.ouSignatureValue = " ";
174 
175     return xSignatureCreator.get();
176 }
177 
signAStream(sal_Int32 securityId,const OUString & uri,bool isBinary,bool bXAdESCompliantIfODF)178 void XSecController::signAStream( sal_Int32 securityId, const OUString& uri, bool isBinary, bool bXAdESCompliantIfODF)
179 {
180     const SignatureReferenceType type = isBinary ? SignatureReferenceType::BINARYSTREAM : SignatureReferenceType::XMLSTREAM;
181     sal_Int32 digestID = bXAdESCompliantIfODF ? cssxc::DigestID::SHA256 : cssxc::DigestID::SHA1;
182 
183     int index = findSignatureInfor( securityId );
184 
185     if (index == -1)
186     {
187         InternalSignatureInformation isi(securityId, nullptr);
188         isi.addReference(type, digestID, uri, -1, OUString());
189         m_vInternalSignatureInformations.push_back( isi );
190     }
191     else
192     {
193         // use sha512 for gpg signing unconditionally
194         if (!m_vInternalSignatureInformations[index].signatureInfor.ouGpgCertificate.isEmpty())
195             digestID = cssxc::DigestID::SHA512;
196         m_vInternalSignatureInformations[index].addReference(type, digestID, uri, -1, OUString());
197     }
198 }
199 
setX509Certificate(sal_Int32 nSecurityId,const OUString & ouX509IssuerName,const OUString & ouX509SerialNumber,const OUString & ouX509Cert,const OUString & ouX509CertDigest,svl::crypto::SignatureMethodAlgorithm eAlgorithmID)200 void XSecController::setX509Certificate(
201     sal_Int32 nSecurityId,
202     const OUString& ouX509IssuerName,
203     const OUString& ouX509SerialNumber,
204     const OUString& ouX509Cert,
205     const OUString& ouX509CertDigest,
206     svl::crypto::SignatureMethodAlgorithm eAlgorithmID)
207 {
208     int index = findSignatureInfor( nSecurityId );
209 
210     if ( index == -1 )
211     {
212         InternalSignatureInformation isi(nSecurityId, nullptr);
213         isi.signatureInfor.ouX509IssuerName = ouX509IssuerName;
214         isi.signatureInfor.ouX509SerialNumber = ouX509SerialNumber;
215         isi.signatureInfor.ouX509Certificate = ouX509Cert;
216         isi.signatureInfor.ouCertDigest = ouX509CertDigest;
217         isi.signatureInfor.eAlgorithmID = eAlgorithmID;
218         m_vInternalSignatureInformations.push_back( isi );
219     }
220     else
221     {
222         SignatureInformation &si
223             = m_vInternalSignatureInformations[index].signatureInfor;
224         si.ouX509IssuerName = ouX509IssuerName;
225         si.ouX509SerialNumber = ouX509SerialNumber;
226         si.ouX509Certificate = ouX509Cert;
227         si.ouCertDigest = ouX509CertDigest;
228     }
229 }
230 
setGpgCertificate(sal_Int32 nSecurityId,const OUString & ouCertDigest,const OUString & ouCert,const OUString & ouOwner)231 void XSecController::setGpgCertificate(
232         sal_Int32 nSecurityId,
233         const OUString& ouCertDigest,
234         const OUString& ouCert,
235         const OUString& ouOwner)
236 {
237     int index = findSignatureInfor( nSecurityId );
238 
239     if ( index == -1 )
240     {
241         InternalSignatureInformation isi(nSecurityId, nullptr);
242         isi.signatureInfor.ouGpgCertificate = ouCert;
243         isi.signatureInfor.ouGpgOwner = ouOwner;
244         isi.signatureInfor.ouCertDigest = ouCertDigest;
245         m_vInternalSignatureInformations.push_back( isi );
246     }
247     else
248     {
249         SignatureInformation &si
250             = m_vInternalSignatureInformations[index].signatureInfor;
251         si.ouGpgCertificate = ouCert;
252         si.ouGpgOwner = ouOwner;
253         si.ouCertDigest = ouCertDigest;
254     }
255 }
256 
setDate(sal_Int32 nSecurityId,const css::util::DateTime & rDateTime)257 void XSecController::setDate(
258     sal_Int32 nSecurityId,
259     const css::util::DateTime& rDateTime )
260 {
261     int index = findSignatureInfor( nSecurityId );
262 
263     if ( index == -1 )
264     {
265         InternalSignatureInformation isi(nSecurityId, nullptr);
266         isi.signatureInfor.stDateTime = rDateTime;
267         m_vInternalSignatureInformations.push_back( isi );
268     }
269     else
270     {
271         SignatureInformation &si
272             = m_vInternalSignatureInformations[index].signatureInfor;
273         si.stDateTime = rDateTime;
274     }
275 }
276 
setDescription(sal_Int32 nSecurityId,const OUString & rDescription)277 void XSecController::setDescription(sal_Int32 nSecurityId, const OUString& rDescription)
278 {
279     int nIndex = findSignatureInfor(nSecurityId);
280 
281     if (nIndex == -1)
282     {
283         InternalSignatureInformation aInformation(nSecurityId, nullptr);
284         aInformation.signatureInfor.ouDescription = rDescription;
285         m_vInternalSignatureInformations.push_back(aInformation);
286     }
287     else
288     {
289         SignatureInformation& rInformation = m_vInternalSignatureInformations[nIndex].signatureInfor;
290         rInformation.ouDescription = rDescription;
291     }
292 }
293 
setSignatureLineId(sal_Int32 nSecurityId,const OUString & rSignatureLineId)294 void XSecController::setSignatureLineId(sal_Int32 nSecurityId, const OUString& rSignatureLineId)
295 {
296     int nIndex = findSignatureInfor(nSecurityId);
297 
298     if (nIndex == -1)
299     {
300         InternalSignatureInformation aInformation(nSecurityId, nullptr);
301         aInformation.signatureInfor.ouSignatureLineId = rSignatureLineId;
302         m_vInternalSignatureInformations.push_back(aInformation);
303     }
304     else
305     {
306         SignatureInformation& rInformation = m_vInternalSignatureInformations[nIndex].signatureInfor;
307         rInformation.ouSignatureLineId = rSignatureLineId;
308     }
309 }
310 
setSignatureLineValidGraphic(sal_Int32 nSecurityId,const Reference<XGraphic> & xValidGraphic)311 void XSecController::setSignatureLineValidGraphic(sal_Int32 nSecurityId,
312                                                   const Reference<XGraphic>& xValidGraphic)
313 {
314     int nIndex = findSignatureInfor(nSecurityId);
315 
316     if (nIndex == -1)
317     {
318         InternalSignatureInformation aInformation(nSecurityId, nullptr);
319         aInformation.signatureInfor.aValidSignatureImage = xValidGraphic;
320         m_vInternalSignatureInformations.push_back(aInformation);
321     }
322     else
323     {
324         SignatureInformation& rInformation
325             = m_vInternalSignatureInformations[nIndex].signatureInfor;
326         rInformation.aValidSignatureImage = xValidGraphic;
327     }
328 }
329 
setSignatureLineInvalidGraphic(sal_Int32 nSecurityId,const Reference<XGraphic> & xInvalidGraphic)330 void XSecController::setSignatureLineInvalidGraphic(
331     sal_Int32 nSecurityId, const Reference<XGraphic>& xInvalidGraphic)
332 {
333     int nIndex = findSignatureInfor(nSecurityId);
334 
335     if (nIndex == -1)
336     {
337         InternalSignatureInformation aInformation(nSecurityId, nullptr);
338         aInformation.signatureInfor.aInvalidSignatureImage = xInvalidGraphic;
339         m_vInternalSignatureInformations.push_back(aInformation);
340     }
341     else
342     {
343         SignatureInformation& rInformation
344             = m_vInternalSignatureInformations[nIndex].signatureInfor;
345         rInformation.aInvalidSignatureImage = xInvalidGraphic;
346     }
347 }
348 
WriteSignature(const cssu::Reference<cssxs::XDocumentHandler> & xDocumentHandler,bool bXAdESCompliantIfODF)349 bool XSecController::WriteSignature(
350     const cssu::Reference<cssxs::XDocumentHandler>& xDocumentHandler,
351     bool bXAdESCompliantIfODF )
352 {
353     bool rc = false;
354 
355     SAL_WARN_IF( !xDocumentHandler.is(), "xmlsecurity.helper", "I really need a document handler!" );
356 
357     /*
358      * chain the SAXEventKeeper to the SAX chain
359      */
360     chainOn();
361 
362     if ( m_eStatusOfSecurityComponents == InitializationState::INITIALIZED )
363     /*
364      * if all security components are ready, add the signature
365      * stream.
366      */
367     {
368         m_bIsSAXEventKeeperSticky = true;
369         m_xSAXEventKeeper->setNextHandler(xDocumentHandler);
370 
371         try
372         {
373             /*
374              * export the signature template
375              */
376             cssu::Reference<cssxs::XDocumentHandler> xSEKHandler(static_cast<cppu::OWeakObject*>(m_xSAXEventKeeper.get()),cssu::UNO_QUERY);
377 
378             int i;
379             int sigNum = m_vInternalSignatureInformations.size();
380 
381             for (i=0; i<sigNum; ++i)
382             {
383                 InternalSignatureInformation &isi = m_vInternalSignatureInformations[i];
384 
385                 // Prepare the signature creator.
386                 // 0 is not a documented value of embed::StorageFormats, ugh
387                 isi.xReferenceResolvedListener = prepareSignatureToWrite( isi, 0, bXAdESCompliantIfODF );
388 
389                 exportSignature( xSEKHandler, isi.signatureInfor, bXAdESCompliantIfODF );
390             }
391 
392             m_bIsSAXEventKeeperSticky = false;
393             chainOff();
394 
395             rc = true;
396         }
397         catch( cssu::Exception& )
398         {
399         }
400 
401         m_xSAXEventKeeper->setNextHandler( nullptr );
402         m_bIsSAXEventKeeperSticky = false;
403     }
404 
405     return rc;
406 }
407 
WriteOOXMLSignature(const uno::Reference<embed::XStorage> & xRootStorage,const uno::Reference<xml::sax::XDocumentHandler> & xDocumentHandler)408 bool XSecController::WriteOOXMLSignature(const uno::Reference<embed::XStorage>& xRootStorage, const uno::Reference<xml::sax::XDocumentHandler>& xDocumentHandler)
409 {
410     bool bRet = false;
411 
412     SAL_WARN_IF(!xDocumentHandler.is(), "xmlsecurity.helper", "empty xDocumentHandler reference");
413 
414     // Chain the SAXEventKeeper to the SAX chain.
415     chainOn();
416 
417     if (m_eStatusOfSecurityComponents == InitializationState::INITIALIZED)
418     {
419         m_bIsSAXEventKeeperSticky = true;
420         m_xSAXEventKeeper->setNextHandler(xDocumentHandler);
421 
422         try
423         {
424             // Export the signature template.
425             cssu::Reference<xml::sax::XDocumentHandler> xSEKHandler(static_cast<cppu::OWeakObject*>(m_xSAXEventKeeper.get()), uno::UNO_QUERY);
426 
427             for (InternalSignatureInformation & rInformation : m_vInternalSignatureInformations)
428             {
429                 // Prepare the signature creator.
430                 rInformation.xReferenceResolvedListener = prepareSignatureToWrite(rInformation, embed::StorageFormats::OFOPXML, false);
431 
432                 exportOOXMLSignature(xRootStorage, xSEKHandler, rInformation.signatureInfor);
433             }
434 
435             m_bIsSAXEventKeeperSticky = false;
436             chainOff();
437 
438             bRet = true;
439         }
440         catch(const uno::Exception&)
441         {
442         }
443 
444         m_xSAXEventKeeper->setNextHandler(nullptr);
445         m_bIsSAXEventKeeperSticky = false;
446     }
447 
448     return bRet;
449 }
450 
451 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
452