merge the formfield patch from ooo-build
[ooovba.git] / xmlsecurity / source / helper / documentsignaturehelper.cxx
blob9d19b231610dba48dcfbd51634d577aecbe612c1
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: documentsignaturehelper.cxx,v $
10 * $Revision: 1.11 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_xmlsecurity.hxx"
34 #include <xmlsecurity/documentsignaturehelper.hxx>
36 #include <com/sun/star/container/XNameAccess.hpp>
37 #include <com/sun/star/lang/XComponent.hpp>
38 #include <com/sun/star/lang/DisposedException.hpp>
39 #include <com/sun/star/embed/XStorage.hpp>
40 #include <com/sun/star/embed/ElementModes.hpp>
41 #include "com/sun/star/beans/XPropertySet.hpp"
43 #include "comphelper/documentconstants.hxx"
44 #include <tools/debug.hxx>
45 #include "rtl/uri.hxx"
47 using namespace ::com::sun::star::uno;
48 //using namespace ::com::sun::star;
49 namespace css = ::com::sun::star;
50 using rtl::OUString;
53 namespace
55 ::rtl::OUString getElement(::rtl::OUString const & version, ::sal_Int32 * index)
57 while (*index < version.getLength() && version[*index] == '0') {
58 ++*index;
60 return version.getToken(0, '.', *index);
65 // Return 1 if version1 is greater then version 2, 0 if they are equal
66 //and -1 if version1 is less version 2
67 int compareVersions(
68 ::rtl::OUString const & version1, ::rtl::OUString const & version2)
70 for (::sal_Int32 i1 = 0, i2 = 0; i1 >= 0 || i2 >= 0;) {
71 ::rtl::OUString e1(getElement(version1, &i1));
72 ::rtl::OUString e2(getElement(version2, &i2));
73 if (e1.getLength() < e2.getLength()) {
74 return -1;
75 } else if (e1.getLength() > e2.getLength()) {
76 return 1;
77 } else if (e1 < e2) {
78 return -1;
79 } else if (e1 > e2) {
80 return 1;
83 return 0;
86 //If the OOo 3.0 mode is used then we exclude
87 //'mimetype' and all content of 'META-INF'.
88 //If the argument 'bSigning' is true then the element list is created for a signing
89 //operation in which case we use the latest signing algorithm. That is all elements
90 //we find in the zip storage are added to the list. We do not support the old signatures
91 //which did not contain all files.
92 //If 'bSigning' is false, then we validate. If the user enabled validating according to OOo 3.0
93 //then mimetype and all content of META-INF must be excluded.
94 void ImplFillElementList(
95 std::vector< rtl::OUString >& rList, const Reference < css::embed::XStorage >& rxStore,
96 const ::rtl::OUString rRootStorageName, const bool bRecursive,
97 const DocumentSignatureAlgorithm mode)
99 ::rtl::OUString aMetaInfName( RTL_CONSTASCII_USTRINGPARAM( "META-INF" ) );
100 ::rtl::OUString sMimeTypeName (RTL_CONSTASCII_USTRINGPARAM("mimetype"));
101 ::rtl::OUString aSep( RTL_CONSTASCII_USTRINGPARAM( "/" ) );
103 Reference < css::container::XNameAccess > xElements( rxStore, UNO_QUERY );
104 Sequence< ::rtl::OUString > aElements = xElements->getElementNames();
105 sal_Int32 nElements = aElements.getLength();
106 const ::rtl::OUString* pNames = aElements.getConstArray();
108 for ( sal_Int32 n = 0; n < nElements; n++ )
110 if (mode != OOo3_2Document
111 && (pNames[n] == aMetaInfName
112 || pNames[n] == sMimeTypeName))
114 continue;
116 else
118 ::rtl::OUString sEncName = ::rtl::Uri::encode(
119 pNames[n], rtl_UriCharClassRelSegment,
120 rtl_UriEncodeStrict, RTL_TEXTENCODING_UTF8);
121 if (sEncName.getLength() == 0 && pNames[n].getLength() != 0)
122 throw css::uno::Exception(::rtl::OUString(
123 RTL_CONSTASCII_USTRINGPARAM("Failed to encode element name of XStorage")), 0);
125 if ( rxStore->isStreamElement( pNames[n] ) )
127 //Exclude documentsignatures.xml!
128 if (pNames[n].equals(
129 DocumentSignatureHelper::GetDocumentContentSignatureDefaultStreamName()))
130 continue;
131 ::rtl::OUString aFullName( rRootStorageName + sEncName );
132 rList.push_back(aFullName);
134 else if ( bRecursive && rxStore->isStorageElement( pNames[n] ) )
136 Reference < css::embed::XStorage > xSubStore = rxStore->openStorageElement( pNames[n], css::embed::ElementModes::READ );
137 rtl::OUString aFullRootName( rRootStorageName + sEncName + aSep );
138 ImplFillElementList(rList, xSubStore, aFullRootName, bRecursive, mode);
145 bool DocumentSignatureHelper::isODFPre_1_2(const ::rtl::OUString & sVersion)
147 //The property version exists only if the document is at least version 1.2
148 //That is, if the document has version 1.1 and sVersion is empty.
149 //The constant is defined in comphelper/documentconstants.hxx
150 if (compareVersions(sVersion, ODFVER_012_TEXT) == -1)
151 return true;
152 return false;
155 bool DocumentSignatureHelper::isOOo3_2_Signature(const SignatureInformation & sigInfo)
157 ::rtl::OUString sManifestURI(RTL_CONSTASCII_USTRINGPARAM("META-INF/manifest.xml"));
158 bool bOOo3_2 = false;
159 typedef ::std::vector< SignatureReferenceInformation >::const_iterator CIT;
160 for (CIT i = sigInfo.vSignatureReferenceInfors.begin();
161 i < sigInfo.vSignatureReferenceInfors.end(); i++)
163 if (i->ouURI.equals(sManifestURI))
165 bOOo3_2 = true;
166 break;
169 return bOOo3_2;
172 DocumentSignatureAlgorithm
173 DocumentSignatureHelper::getDocumentAlgorithm(
174 const ::rtl::OUString & sODFVersion, const SignatureInformation & sigInfo)
176 OSL_ASSERT(sODFVersion.getLength());
177 DocumentSignatureAlgorithm mode = OOo3_2Document;
178 if (!isOOo3_2_Signature(sigInfo))
180 if (isODFPre_1_2(sODFVersion))
181 mode = OOo2Document;
182 else
183 mode = OOo3_0Document;
185 return mode;
188 //The function creates a list of files which are to be signed or for which
189 //the signature is to be validated. The strings are UTF8 encoded URIs which
190 //contain '/' as path separators.
192 //The algorithm how document signatures are created and validated has
193 //changed over time. The change affects only which files within the document
194 //are changed. Document signatures created by OOo 2.x only used particular files. Since
195 //OOo 3.0 everything except "mimetype" and "META-INF" are signed. As of OOo 3.2 everything
196 //except META-INF/documentsignatures.xml is signed.
197 //Signatures are validated according to the algorithm which was then used for validation.
198 //That is, when validating a signature which was created by OOo 3.0, then mimetype and
199 //META-INF are not used.
201 //When a signature is created then we always use the latest algorithm. That is, we use
202 //that of OOo 3.2
203 std::vector< rtl::OUString >
204 DocumentSignatureHelper::CreateElementList(
205 const Reference < css::embed::XStorage >& rxStore,
206 const ::rtl::OUString /*rRootStorageName*/, DocumentSignatureMode eMode,
207 const DocumentSignatureAlgorithm mode)
209 std::vector< rtl::OUString > aElements;
210 ::rtl::OUString aSep( RTL_CONSTASCII_USTRINGPARAM( "/" ) );
212 switch ( eMode )
214 case SignatureModeDocumentContent:
216 if (mode == OOo2Document) //that is, ODF 1.0, 1.1
218 // 1) Main content
219 ImplFillElementList(aElements, rxStore, ::rtl::OUString(), false, mode);
221 // 2) Pictures...
222 rtl::OUString aSubStorageName( rtl::OUString::createFromAscii( "Pictures" ) );
225 Reference < css::embed::XStorage > xSubStore = rxStore->openStorageElement( aSubStorageName, css::embed::ElementModes::READ );
226 ImplFillElementList(aElements, xSubStore, aSubStorageName+aSep, true, mode);
228 catch(css::io::IOException& )
230 ; // Doesn't have to exist...
232 // 3) OLE....
233 aSubStorageName = rtl::OUString::createFromAscii( "ObjectReplacements" );
236 Reference < css::embed::XStorage > xSubStore = rxStore->openStorageElement( aSubStorageName, css::embed::ElementModes::READ );
237 ImplFillElementList(aElements, xSubStore, aSubStorageName+aSep, true, mode);
238 xSubStore.clear();
240 // Object folders...
241 rtl::OUString aMatchStr( rtl::OUString::createFromAscii( "Object " ) );
242 Reference < css::container::XNameAccess > xElements( rxStore, UNO_QUERY );
243 Sequence< ::rtl::OUString > aElementNames = xElements->getElementNames();
244 sal_Int32 nElements = aElementNames.getLength();
245 const ::rtl::OUString* pNames = aElementNames.getConstArray();
246 for ( sal_Int32 n = 0; n < nElements; n++ )
248 if ( ( pNames[n].match( aMatchStr ) ) && rxStore->isStorageElement( pNames[n] ) )
250 Reference < css::embed::XStorage > xTmpSubStore = rxStore->openStorageElement( pNames[n], css::embed::ElementModes::READ );
251 ImplFillElementList(aElements, xTmpSubStore, pNames[n]+aSep, true, mode);
255 catch( com::sun::star::io::IOException& )
257 ; // Doesn't have to exist...
260 else
262 // Everything except META-INF
263 ImplFillElementList(aElements, rxStore, ::rtl::OUString(), true, mode);
266 break;
267 case SignatureModeMacros:
269 // 1) Macros
270 rtl::OUString aSubStorageName( rtl::OUString::createFromAscii( "Basic" ) );
273 Reference < css::embed::XStorage > xSubStore = rxStore->openStorageElement( aSubStorageName, css::embed::ElementModes::READ );
274 ImplFillElementList(aElements, xSubStore, aSubStorageName+aSep, true, mode);
276 catch( com::sun::star::io::IOException& )
278 ; // Doesn't have to exist...
281 // 2) Dialogs
282 aSubStorageName = rtl::OUString::createFromAscii( "Dialogs") ;
285 Reference < css::embed::XStorage > xSubStore = rxStore->openStorageElement( aSubStorageName, css::embed::ElementModes::READ );
286 ImplFillElementList(aElements, xSubStore, aSubStorageName+aSep, true, mode);
288 catch( com::sun::star::io::IOException& )
290 ; // Doesn't have to exist...
292 // 3) Scripts
293 aSubStorageName = rtl::OUString::createFromAscii( "Scripts") ;
296 Reference < css::embed::XStorage > xSubStore = rxStore->openStorageElement( aSubStorageName, css::embed::ElementModes::READ );
297 ImplFillElementList(aElements, xSubStore, aSubStorageName+aSep, true, mode);
299 catch( css::io::IOException& )
301 ; // Doesn't have to exist...
304 break;
305 case SignatureModePackage:
307 // Everything except META-INF
308 ImplFillElementList(aElements, rxStore, ::rtl::OUString(), true, mode);
310 break;
313 return aElements;
316 SignatureStreamHelper DocumentSignatureHelper::OpenSignatureStream(
317 const Reference < css::embed::XStorage >& rxStore, sal_Int32 nOpenMode, DocumentSignatureMode eDocSigMode )
319 sal_Int32 nSubStorageOpenMode = css::embed::ElementModes::READ;
320 if ( nOpenMode & css::embed::ElementModes::WRITE )
321 nSubStorageOpenMode = css::embed::ElementModes::WRITE;
323 SignatureStreamHelper aHelper;
325 try
327 ::rtl::OUString aSIGStoreName( RTL_CONSTASCII_USTRINGPARAM( "META-INF" ) );
328 aHelper.xSignatureStorage = rxStore->openStorageElement( aSIGStoreName, nSubStorageOpenMode );
329 if ( aHelper.xSignatureStorage.is() )
331 ::rtl::OUString aSIGStreamName;
332 if ( eDocSigMode == SignatureModeDocumentContent )
333 aSIGStreamName = DocumentSignatureHelper::GetDocumentContentSignatureDefaultStreamName();
334 else if ( eDocSigMode == SignatureModeMacros )
335 aSIGStreamName = DocumentSignatureHelper::GetScriptingContentSignatureDefaultStreamName();
336 else
337 aSIGStreamName = DocumentSignatureHelper::GetPackageSignatureDefaultStreamName();
339 aHelper.xSignatureStream = aHelper.xSignatureStorage->openStreamElement( aSIGStreamName, nOpenMode );
342 catch(css::io::IOException& )
344 // Doesn't have to exist...
345 DBG_ASSERT( nOpenMode == css::embed::ElementModes::READ, "Error creating signature stream..." );
348 return aHelper;
351 //sElementList contains all files which are expected to be signed. Only those files must me signed,
352 //no more, no less.
353 //The DocumentSignatureAlgorithm indicates if the document was created with OOo 2.x. Then
354 //the uri s in the Reference elements in the signature, were not properly encoded.
355 // For example: <Reference URI="ObjectReplacements/Object 1">
356 bool DocumentSignatureHelper::checkIfAllFilesAreSigned(
357 const ::std::vector< ::rtl::OUString > & sElementList,
358 const SignatureInformation & sigInfo,
359 const DocumentSignatureAlgorithm alg)
361 // Can only be valid if ALL streams are signed, which means real stream count == signed stream count
362 unsigned int nRealCount = 0;
363 for ( int i = sigInfo.vSignatureReferenceInfors.size(); i; )
365 const SignatureReferenceInformation& rInf = sigInfo.vSignatureReferenceInfors[--i];
366 // There is also an extra entry of type TYPE_SAMEDOCUMENT_REFERENCE because of signature date.
367 if ( ( rInf.nType == TYPE_BINARYSTREAM_REFERENCE ) || ( rInf.nType == TYPE_XMLSTREAM_REFERENCE ) )
369 ::rtl::OUString sReferenceURI = rInf.ouURI;
370 if (alg == OOo2Document)
372 //Comparing URIs is a difficult. Therefore we kind of normalize
373 //it before comparing. We assume that our URI do not have a leading "./"
374 //and fragments at the end (...#...)
375 sReferenceURI = ::rtl::Uri::encode(
376 sReferenceURI, rtl_UriCharClassPchar,
377 rtl_UriEncodeCheckEscapes, RTL_TEXTENCODING_UTF8);
380 //find the file in the element list
381 typedef ::std::vector< ::rtl::OUString >::const_iterator CIT;
382 for (CIT aIter = sElementList.begin(); aIter < sElementList.end(); aIter++)
384 ::rtl::OUString sElementListURI = *aIter;
385 if (alg == OOo2Document)
387 sElementListURI =
388 ::rtl::Uri::encode(
389 sElementListURI, rtl_UriCharClassPchar,
390 rtl_UriEncodeCheckEscapes, RTL_TEXTENCODING_UTF8);
392 if (sElementListURI.equals(sReferenceURI))
394 nRealCount++;
395 break;
400 return sElementList.size() == nRealCount;
403 /*Compares the Uri which are obtained from CreateElementList with
404 the path obtained from the manifest.xml.
405 Returns true if both strings are equal.
407 bool DocumentSignatureHelper::equalsReferenceUriManifestPath(
408 const OUString & rUri, const OUString & rPath)
410 bool retVal = false;
411 //split up the uri and path into segments. Both are separated by '/'
412 std::vector<OUString> vUriSegments;
413 sal_Int32 nIndex = 0;
416 OUString aToken = rUri.getToken( 0, '/', nIndex );
417 vUriSegments.push_back(aToken);
419 while (nIndex >= 0);
421 std::vector<OUString> vPathSegments;
422 nIndex = 0;
425 OUString aToken = rPath.getToken( 0, '/', nIndex );
426 vPathSegments.push_back(aToken);
428 while (nIndex >= 0);
430 //Now compare each segment of the uri with its counterpart from the path
431 if (vUriSegments.size() == vPathSegments.size())
433 retVal = true;
434 typedef std::vector<OUString>::const_iterator CIT;
435 for (CIT i = vUriSegments.begin(), j = vPathSegments.begin();
436 i != vUriSegments.end(); i++, j++)
438 //Decode the uri segment, so that %20 becomes ' ', etc.
439 OUString sDecUri = ::rtl::Uri::decode(
440 *i, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8);
441 if (!sDecUri.equals(*j))
443 retVal = false;
444 break;
449 return retVal;
452 ::rtl::OUString DocumentSignatureHelper::GetDocumentContentSignatureDefaultStreamName()
454 return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "documentsignatures.xml" ) );
457 ::rtl::OUString DocumentSignatureHelper::GetScriptingContentSignatureDefaultStreamName()
459 return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "macrosignatures.xml" ) );
462 ::rtl::OUString DocumentSignatureHelper::GetPackageSignatureDefaultStreamName()
464 return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "packagesignatures.xml" ) );