Line data Source code
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 : #include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp>
21 : #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
22 : #include <com/sun/star/xml/sax/XAttributeList.hpp>
23 : #include <com/sun/star/xml/crypto/DigestID.hpp>
24 : #include <com/sun/star/xml/crypto/CipherID.hpp>
25 : #include <com/sun/star/beans/PropertyValue.hpp>
26 : #include <com/sun/star/uno/RuntimeException.hpp>
27 :
28 : #include <ManifestDefines.hxx>
29 : #include <ManifestExport.hxx>
30 : #include <sax/tools/converter.hxx>
31 :
32 : #include <rtl/ustrbuf.hxx>
33 : #include <comphelper/documentconstants.hxx>
34 : #include <comphelper/attributelist.hxx>
35 :
36 : using namespace ::com::sun::star;
37 :
38 : #if OSL_DEBUG_LEVEL > 0
39 : #define THROW_WHERE SAL_WHERE
40 : #else
41 : #define THROW_WHERE ""
42 : #endif
43 :
44 416 : ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > xHandler, const uno::Sequence< uno::Sequence < beans::PropertyValue > >& rManList )
45 : {
46 416 : const OUString sFileEntryElement ( ELEMENT_FILE_ENTRY );
47 832 : const OUString sManifestElement ( ELEMENT_MANIFEST );
48 832 : const OUString sEncryptionDataElement( ELEMENT_ENCRYPTION_DATA );
49 832 : const OUString sAlgorithmElement ( ELEMENT_ALGORITHM );
50 832 : const OUString sStartKeyGenerationElement ( ELEMENT_START_KEY_GENERATION );
51 832 : const OUString sKeyDerivationElement ( ELEMENT_KEY_DERIVATION );
52 :
53 832 : const OUString sCdataAttribute ( ATTRIBUTE_CDATA );
54 832 : const OUString sMediaTypeAttribute ( ATTRIBUTE_MEDIA_TYPE );
55 832 : const OUString sVersionAttribute ( ATTRIBUTE_VERSION );
56 832 : const OUString sFullPathAttribute ( ATTRIBUTE_FULL_PATH );
57 832 : const OUString sSizeAttribute ( ATTRIBUTE_SIZE );
58 832 : const OUString sKeySizeAttribute ( ATTRIBUTE_KEY_SIZE );
59 832 : const OUString sSaltAttribute ( ATTRIBUTE_SALT );
60 832 : const OUString sInitialisationVectorAttribute ( ATTRIBUTE_INITIALISATION_VECTOR );
61 832 : const OUString sIterationCountAttribute ( ATTRIBUTE_ITERATION_COUNT );
62 832 : const OUString sAlgorithmNameAttribute ( ATTRIBUTE_ALGORITHM_NAME );
63 832 : const OUString sStartKeyGenerationNameAttribute ( ATTRIBUTE_START_KEY_GENERATION_NAME );
64 832 : const OUString sKeyDerivationNameAttribute ( ATTRIBUTE_KEY_DERIVATION_NAME );
65 832 : const OUString sChecksumTypeAttribute ( ATTRIBUTE_CHECKSUM_TYPE );
66 832 : const OUString sChecksumAttribute ( ATTRIBUTE_CHECKSUM);
67 :
68 832 : const OUString sFullPathProperty ( "FullPath" );
69 832 : const OUString sVersionProperty ( "Version" );
70 832 : const OUString sMediaTypeProperty ( "MediaType" );
71 832 : const OUString sIterationCountProperty ( "IterationCount" );
72 832 : const OUString sDerivedKeySizeProperty ( "DerivedKeySize" );
73 832 : const OUString sSaltProperty ( "Salt" );
74 832 : const OUString sInitialisationVectorProperty( "InitialisationVector" );
75 832 : const OUString sSizeProperty ( "Size" );
76 832 : const OUString sDigestProperty ( "Digest" );
77 832 : const OUString sEncryptionAlgProperty ( "EncryptionAlgorithm" );
78 832 : const OUString sStartKeyAlgProperty ( "StartKeyAlgorithm" );
79 832 : const OUString sDigestAlgProperty ( "DigestAlgorithm" );
80 :
81 832 : const OUString sWhiteSpace ( " " );
82 :
83 832 : const OUString sSHA256_URL ( SHA256_URL );
84 832 : const OUString sSHA1_Name ( SHA1_NAME );
85 :
86 832 : const OUString sSHA1_1k_Name ( SHA1_1K_NAME );
87 832 : const OUString sSHA256_1k_URL ( SHA256_1K_URL );
88 :
89 832 : const OUString sBlowfish_Name ( BLOWFISH_NAME );
90 832 : const OUString sAES256_URL ( AES256_URL );
91 :
92 832 : const OUString sPBKDF2_Name ( PBKDF2_NAME );
93 :
94 416 : ::comphelper::AttributeList * pRootAttrList = new ::comphelper::AttributeList;
95 416 : const uno::Sequence < beans::PropertyValue > *pSequence = rManList.getConstArray();
96 416 : const sal_uInt32 nManLength = rManList.getLength();
97 :
98 : // find the mediatype of the document if any
99 832 : OUString aDocMediaType;
100 832 : OUString aDocVersion;
101 416 : for (sal_uInt32 nInd = 0; nInd < nManLength ; nInd++ )
102 : {
103 416 : OUString aMediaType;
104 416 : OUString aPath;
105 416 : OUString aVersion;
106 :
107 416 : const beans::PropertyValue *pValue = pSequence[nInd].getConstArray();
108 1306 : for (sal_uInt32 j = 0, nNum = pSequence[nInd].getLength(); j < nNum; j++, pValue++)
109 : {
110 1248 : if (pValue->Name.equals (sMediaTypeProperty) )
111 : {
112 416 : pValue->Value >>= aMediaType;
113 : }
114 832 : else if (pValue->Name.equals (sFullPathProperty) )
115 : {
116 416 : pValue->Value >>= aPath;
117 : }
118 416 : else if (pValue->Name.equals (sVersionProperty) )
119 : {
120 416 : pValue->Value >>= aVersion;
121 : }
122 :
123 1248 : if ( !aPath.isEmpty() && !aMediaType.isEmpty() && !aVersion.isEmpty() )
124 358 : break;
125 : }
126 :
127 416 : if ( aPath == "/" )
128 : {
129 416 : aDocMediaType = aMediaType;
130 416 : aDocVersion = aVersion;
131 416 : break;
132 : }
133 0 : }
134 :
135 416 : bool bProvideDTD = false;
136 416 : bool bAcceptNonemptyVersion = false;
137 416 : bool bStoreStartKeyGeneration = false;
138 416 : if ( !aDocMediaType.isEmpty() )
139 : {
140 732 : if ( aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_TEXT_ASCII
141 304 : || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_TEXT_WEB_ASCII
142 304 : || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_TEXT_GLOBAL_ASCII
143 304 : || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_ASCII
144 302 : || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_ASCII
145 292 : || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_ASCII
146 192 : || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_CHART_ASCII
147 192 : || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_DATABASE_ASCII
148 8 : || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_ASCII
149 8 : || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_TEXT_TEMPLATE_ASCII
150 0 : || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_TEXT_GLOBAL_TEMPLATE_ASCII
151 0 : || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_TEMPLATE_ASCII
152 0 : || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_TEMPLATE_ASCII
153 0 : || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_TEMPLATE_ASCII
154 0 : || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_CHART_TEMPLATE_ASCII
155 366 : || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_TEMPLATE_ASCII )
156 :
157 : {
158 : // oasis format
159 : pRootAttrList->AddAttribute ( ATTRIBUTE_XMLNS,
160 : sCdataAttribute,
161 366 : MANIFEST_OASIS_NAMESPACE );
162 366 : bAcceptNonemptyVersion = true;
163 366 : if ( aDocVersion.compareTo( ODFVER_012_TEXT ) >= 0 )
164 : {
165 : // this is ODF12 generation, let encrypted streams contain start-key-generation entry
166 358 : bStoreStartKeyGeneration = true;
167 358 : pRootAttrList->AddAttribute ( sVersionAttribute, sCdataAttribute, aDocVersion );
168 : }
169 : }
170 : else
171 : {
172 : // even if it is no SO6 format the namespace must be specified
173 : // thus SO6 format is used as default one
174 : pRootAttrList->AddAttribute ( ATTRIBUTE_XMLNS,
175 : sCdataAttribute,
176 0 : MANIFEST_NAMESPACE );
177 :
178 0 : bProvideDTD = true;
179 : }
180 : }
181 :
182 832 : uno::Reference < xml::sax::XAttributeList > xRootAttrList (pRootAttrList);
183 :
184 416 : xHandler->startDocument();
185 832 : uno::Reference < xml::sax::XExtendedDocumentHandler > xExtHandler ( xHandler, uno::UNO_QUERY );
186 416 : if ( xExtHandler.is() && bProvideDTD )
187 : {
188 0 : OUString aDocType ( MANIFEST_DOCTYPE );
189 0 : xExtHandler->unknown ( aDocType );
190 0 : xHandler->ignorableWhitespace ( sWhiteSpace );
191 : }
192 416 : xHandler->startElement( sManifestElement, xRootAttrList );
193 :
194 2446 : for (sal_uInt32 i = 0 ; i < nManLength ; i++)
195 : {
196 2030 : ::comphelper::AttributeList *pAttrList = new ::comphelper::AttributeList;
197 2030 : const beans::PropertyValue *pValue = pSequence[i].getConstArray();
198 2030 : OUString aString;
199 2030 : const uno::Any *pVector = NULL, *pSalt = NULL, *pIterationCount = NULL, *pDigest = NULL, *pDigestAlg = NULL, *pEncryptAlg = NULL, *pStartKeyAlg = NULL, *pDerivedKeySize = NULL;
200 8228 : for (sal_uInt32 j = 0, nNum = pSequence[i].getLength(); j < nNum; j++, pValue++)
201 : {
202 6198 : if (pValue->Name.equals (sMediaTypeProperty) )
203 : {
204 2030 : pValue->Value >>= aString;
205 2030 : pAttrList->AddAttribute ( sMediaTypeAttribute, sCdataAttribute, aString );
206 : }
207 4168 : else if (pValue->Name.equals (sVersionProperty) )
208 : {
209 2030 : pValue->Value >>= aString;
210 : // the version is stored only if it is not empty
211 2030 : if ( bAcceptNonemptyVersion && !aString.isEmpty() )
212 362 : pAttrList->AddAttribute ( sVersionAttribute, sCdataAttribute, aString );
213 : }
214 2138 : else if (pValue->Name.equals (sFullPathProperty) )
215 : {
216 2030 : pValue->Value >>= aString;
217 2030 : pAttrList->AddAttribute ( sFullPathAttribute, sCdataAttribute, aString );
218 : }
219 108 : else if (pValue->Name.equals (sSizeProperty) )
220 : {
221 12 : sal_Int64 nSize = 0;
222 12 : pValue->Value >>= nSize;
223 12 : OUStringBuffer aBuffer;
224 12 : aBuffer.append ( nSize );
225 12 : pAttrList->AddAttribute ( sSizeAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );
226 : }
227 96 : else if (pValue->Name.equals (sInitialisationVectorProperty) )
228 12 : pVector = &pValue->Value;
229 84 : else if (pValue->Name.equals (sSaltProperty) )
230 12 : pSalt = &pValue->Value;
231 72 : else if (pValue->Name.equals (sIterationCountProperty) )
232 12 : pIterationCount = &pValue->Value;
233 60 : else if (pValue->Name.equals ( sDigestProperty ) )
234 12 : pDigest = &pValue->Value;
235 48 : else if (pValue->Name.equals ( sDigestAlgProperty ) )
236 12 : pDigestAlg = &pValue->Value;
237 36 : else if (pValue->Name.equals ( sEncryptionAlgProperty ) )
238 12 : pEncryptAlg = &pValue->Value;
239 24 : else if (pValue->Name.equals ( sStartKeyAlgProperty ) )
240 12 : pStartKeyAlg = &pValue->Value;
241 12 : else if (pValue->Name.equals ( sDerivedKeySizeProperty ) )
242 12 : pDerivedKeySize = &pValue->Value;
243 : }
244 :
245 2030 : xHandler->ignorableWhitespace ( sWhiteSpace );
246 4060 : uno::Reference < xml::sax::XAttributeList > xAttrList ( pAttrList );
247 2030 : xHandler->startElement( sFileEntryElement , xAttrList);
248 2030 : if ( pVector && pSalt && pIterationCount && pDigest && pDigestAlg && pEncryptAlg && pStartKeyAlg && pDerivedKeySize )
249 : {
250 : // ==== Encryption Data
251 12 : ::comphelper::AttributeList * pNewAttrList = new ::comphelper::AttributeList;
252 12 : uno::Reference < xml::sax::XAttributeList > xNewAttrList (pNewAttrList);
253 24 : OUStringBuffer aBuffer;
254 24 : uno::Sequence < sal_Int8 > aSequence;
255 :
256 12 : xHandler->ignorableWhitespace ( sWhiteSpace );
257 :
258 : // ==== Digest
259 24 : OUString sChecksumType;
260 12 : sal_Int32 nDigestAlgID = 0;
261 12 : *pDigestAlg >>= nDigestAlgID;
262 12 : if ( nDigestAlgID == xml::crypto::DigestID::SHA256_1K )
263 12 : sChecksumType = sSHA256_1k_URL;
264 0 : else if ( nDigestAlgID == xml::crypto::DigestID::SHA1_1K )
265 0 : sChecksumType = sSHA1_1k_Name;
266 : else
267 0 : throw uno::RuntimeException( THROW_WHERE "Unexpected digest algorithm is provided!" );
268 :
269 12 : pNewAttrList->AddAttribute ( sChecksumTypeAttribute, sCdataAttribute, sChecksumType );
270 12 : *pDigest >>= aSequence;
271 12 : ::sax::Converter::encodeBase64(aBuffer, aSequence);
272 12 : pNewAttrList->AddAttribute ( sChecksumAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );
273 :
274 12 : xHandler->startElement( sEncryptionDataElement , xNewAttrList);
275 :
276 : // ==== Algorithm
277 12 : pNewAttrList = new ::comphelper::AttributeList;
278 12 : xNewAttrList = pNewAttrList;
279 :
280 12 : sal_Int32 nEncAlgID = 0;
281 12 : sal_Int32 nDerivedKeySize = 0;
282 12 : *pEncryptAlg >>= nEncAlgID;
283 12 : *pDerivedKeySize >>= nDerivedKeySize;
284 :
285 24 : OUString sEncAlgName;
286 12 : if ( nEncAlgID == xml::crypto::CipherID::AES_CBC_W3C_PADDING )
287 : {
288 : OSL_ENSURE( nDerivedKeySize, "Unexpected key size is provided!" );
289 12 : if ( nDerivedKeySize != 32 )
290 0 : throw uno::RuntimeException( THROW_WHERE "Unexpected key size is provided!" );
291 :
292 12 : sEncAlgName = sAES256_URL;
293 : }
294 0 : else if ( nEncAlgID == xml::crypto::CipherID::BLOWFISH_CFB_8 )
295 : {
296 0 : sEncAlgName = sBlowfish_Name;
297 : }
298 : else
299 0 : throw uno::RuntimeException( THROW_WHERE "Unexpected encryption algorithm is provided!" );
300 :
301 12 : pNewAttrList->AddAttribute ( sAlgorithmNameAttribute, sCdataAttribute, sEncAlgName );
302 :
303 12 : *pVector >>= aSequence;
304 12 : ::sax::Converter::encodeBase64(aBuffer, aSequence);
305 12 : pNewAttrList->AddAttribute ( sInitialisationVectorAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );
306 :
307 12 : xHandler->ignorableWhitespace ( sWhiteSpace );
308 12 : xHandler->startElement( sAlgorithmElement , xNewAttrList);
309 12 : xHandler->ignorableWhitespace ( sWhiteSpace );
310 12 : xHandler->endElement( sAlgorithmElement );
311 :
312 : // ==== Key Derivation
313 12 : pNewAttrList = new ::comphelper::AttributeList;
314 12 : xNewAttrList = pNewAttrList;
315 :
316 12 : pNewAttrList->AddAttribute ( sKeyDerivationNameAttribute, sCdataAttribute, sPBKDF2_Name );
317 :
318 12 : if ( bStoreStartKeyGeneration )
319 : {
320 12 : aBuffer.append( nDerivedKeySize );
321 12 : pNewAttrList->AddAttribute ( sKeySizeAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );
322 : }
323 :
324 12 : sal_Int32 nCount = 0;
325 12 : *pIterationCount >>= nCount;
326 12 : aBuffer.append (nCount);
327 12 : pNewAttrList->AddAttribute ( sIterationCountAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );
328 :
329 12 : *pSalt >>= aSequence;
330 12 : ::sax::Converter::encodeBase64(aBuffer, aSequence);
331 12 : pNewAttrList->AddAttribute ( sSaltAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );
332 :
333 12 : xHandler->ignorableWhitespace ( sWhiteSpace );
334 12 : xHandler->startElement( sKeyDerivationElement , xNewAttrList);
335 12 : xHandler->ignorableWhitespace ( sWhiteSpace );
336 12 : xHandler->endElement( sKeyDerivationElement );
337 :
338 : // we have to store start-key-generation element as the last one to workaround the parsing problem
339 : // in OOo3.1 and older versions
340 12 : if ( bStoreStartKeyGeneration )
341 : {
342 : // ==== Start Key Generation
343 12 : pNewAttrList = new ::comphelper::AttributeList;
344 12 : xNewAttrList = pNewAttrList;
345 :
346 12 : OUString sStartKeyAlg;
347 24 : OUString sStartKeySize;
348 12 : sal_Int32 nStartKeyAlgID = 0;
349 12 : *pStartKeyAlg >>= nStartKeyAlgID;
350 12 : if ( nStartKeyAlgID == xml::crypto::DigestID::SHA256 )
351 : {
352 12 : sStartKeyAlg = sSHA256_URL;
353 12 : aBuffer.append( (sal_Int32)32 );
354 12 : sStartKeySize = aBuffer.makeStringAndClear();
355 : }
356 0 : else if ( nStartKeyAlgID == xml::crypto::DigestID::SHA1 )
357 : {
358 0 : sStartKeyAlg = sSHA1_Name;
359 0 : aBuffer.append( (sal_Int32)20 );
360 0 : sStartKeySize = aBuffer.makeStringAndClear();
361 : }
362 : else
363 0 : throw uno::RuntimeException( THROW_WHERE "Unexpected start key algorithm is provided!" );
364 :
365 12 : pNewAttrList->AddAttribute ( sStartKeyGenerationNameAttribute, sCdataAttribute, sStartKeyAlg );
366 12 : pNewAttrList->AddAttribute ( sKeySizeAttribute, sCdataAttribute, sStartKeySize );
367 :
368 12 : xHandler->ignorableWhitespace ( sWhiteSpace );
369 12 : xHandler->startElement( sStartKeyGenerationElement , xNewAttrList);
370 12 : xHandler->ignorableWhitespace ( sWhiteSpace );
371 24 : xHandler->endElement( sStartKeyGenerationElement );
372 : }
373 :
374 12 : xHandler->ignorableWhitespace ( sWhiteSpace );
375 24 : xHandler->endElement( sEncryptionDataElement );
376 : }
377 2030 : xHandler->ignorableWhitespace ( sWhiteSpace );
378 2030 : xHandler->endElement( sFileEntryElement );
379 2030 : }
380 416 : xHandler->ignorableWhitespace ( sWhiteSpace );
381 416 : xHandler->endElement( sManifestElement );
382 832 : xHandler->endDocument();
383 416 : }
384 :
385 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|