1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER( update_precomp.py ): autogen include statement, do not remove
25 #include "precompiled_package.hxx"
26 #include <ManifestImport.hxx>
27 #include <ManifestDefines.hxx>
28 #include <sax/tools/converter.hxx>
29
30 #include <com/sun/star/xml/sax/XAttributeList.hpp>
31 #include <com/sun/star/xml/crypto/DigestID.hpp>
32 #include <com/sun/star/xml/crypto/CipherID.hpp>
33
34 using namespace com::sun::star::uno;
35 using namespace com::sun::star::beans;
36 using namespace com::sun::star;
37 using namespace rtl;
38 using namespace std;
39
40 // helper for ignoring multiple settings of the same property
41 #define setProperty(e,v) do{ if(!maValues[e].hasValue()) maValues[e] <<= v;} while(0)
42
getMnfstPropName(int nManifestPropId)43 static const char* getMnfstPropName( int nManifestPropId )
44 {
45 const char* pName;
46 switch( nManifestPropId )
47 {
48 case PKG_MNFST_MEDIATYPE: pName = "MediaType"; break;
49 case PKG_MNFST_VERSION: pName = "Version"; break;
50 case PKG_MNFST_FULLPATH: pName = "FullPath"; break;
51 case PKG_MNFST_INIVECTOR: pName = "InitialisationVector"; break;
52 case PKG_MNFST_SALT: pName = "Salt"; break;
53 case PKG_MNFST_ITERATION: pName = "IterationCount"; break;
54 case PKG_MNFST_UCOMPSIZE: pName = "Size"; break;
55 case PKG_MNFST_DIGEST: pName = "Digest"; break;
56 case PKG_MNFST_ENCALG: pName = "EncryptionAlgorithm"; break;
57 case PKG_MNFST_STARTALG: pName = "StartKeyAlgorithm"; break;
58 case PKG_MNFST_DIGESTALG: pName = "DigestAlgorithm"; break;
59 case PKG_MNFST_DERKEYSIZE: pName = "DerivedKeySize"; break;
60 default: pName = NULL;
61 }
62 return pName;
63 }
64
65 // ---------------------------------------------------
ManifestImport(vector<Sequence<PropertyValue>> & rNewManVector)66 ManifestImport::ManifestImport( vector < Sequence < PropertyValue > > & rNewManVector )
67 : rManVector ( rNewManVector )
68 , nDerivedKeySize( 0 )
69 , bIgnoreEncryptData( false )
70
71 , sCdataAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_CDATA ) )
72 , sMediaTypeAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_MEDIA_TYPE ) )
73 , sVersionAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_VERSION ) )
74 , sFullPathAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_FULL_PATH ) )
75 , sSizeAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_SIZE ) )
76 , sSaltAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_SALT ) )
77 , sInitialisationVectorAttribute(RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_INITIALISATION_VECTOR ) )
78 , sIterationCountAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_ITERATION_COUNT ) )
79 , sKeySizeAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_KEY_SIZE ) )
80 , sAlgorithmNameAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_ALGORITHM_NAME ) )
81 , sStartKeyAlgNameAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_START_KEY_GENERATION_NAME ) )
82 , sKeyDerivationNameAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_KEY_DERIVATION_NAME ) )
83 , sChecksumAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_CHECKSUM ) )
84 , sChecksumTypeAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_CHECKSUM_TYPE ) )
85 {
86 aStack.reserve( 10 );
87 }
88
89 // ---------------------------------------------------
~ManifestImport(void)90 ManifestImport::~ManifestImport ( void )
91 {
92 }
93
94 // ---------------------------------------------------
startDocument()95 void SAL_CALL ManifestImport::startDocument( )
96 throw( xml::sax::SAXException, uno::RuntimeException )
97 {
98 }
99
100 // ---------------------------------------------------
endDocument()101 void SAL_CALL ManifestImport::endDocument( )
102 throw( xml::sax::SAXException, uno::RuntimeException )
103 {
104 }
105
106 // ---------------------------------------------------
startElement(const OUString & aName,const uno::Reference<xml::sax::XAttributeList> & xAttribs)107 void SAL_CALL ManifestImport::startElement( const OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs )
108 throw( xml::sax::SAXException, uno::RuntimeException )
109 {
110 StringHashMap aConvertedAttribs;
111 ::rtl::OUString aConvertedName = PushNameAndNamespaces( aName, xAttribs, aConvertedAttribs );
112
113 if ( aConvertedName.equalsAscii( ELEMENT_FILE_ENTRY ) )
114 {
115 setProperty( PKG_MNFST_FULLPATH, aConvertedAttribs[sFullPathAttribute]);
116 setProperty( PKG_MNFST_MEDIATYPE, aConvertedAttribs[sMediaTypeAttribute]);
117
118 const OUString& sVersion = aConvertedAttribs[sVersionAttribute];
119 if ( sVersion.getLength() )
120 setProperty( PKG_MNFST_VERSION, sVersion );
121
122 const OUString& sSize = aConvertedAttribs[sSizeAttribute];
123 if ( sSize.getLength() )
124 setProperty( PKG_MNFST_UCOMPSIZE, sSize.toInt32() );
125 }
126 else if ( aStack.size() > 1 )
127 {
128 ManifestStack::reverse_iterator aIter = aStack.rbegin();
129 aIter++;
130
131 if ( aIter->m_aConvertedName.equalsAscii( ELEMENT_FILE_ENTRY ) )
132 {
133 if ( aConvertedName.equalsAscii( ELEMENT_ENCRYPTION_DATA ) )
134 {
135 // If this element exists, then this stream is encrypted and we need
136 // to import the initialisation vector, salt and iteration count used
137 nDerivedKeySize = 0;
138 if ( !bIgnoreEncryptData )
139 {
140 sal_Int32 nDigestId = 0;
141 const OUString& rChecksumType = aConvertedAttribs[sChecksumTypeAttribute];
142 if( rChecksumType.equalsAscii( SHA1_1K_NAME )
143 || rChecksumType.equalsAscii( SHA1_1K_URL ) )
144 nDigestId = xml::crypto::DigestID::SHA1_1K;
145 else if ( rChecksumType.equalsAscii( SHA256_1K_URL ) )
146 nDigestId = xml::crypto::DigestID::SHA256_1K;
147 else
148 bIgnoreEncryptData = true;
149
150 if ( !bIgnoreEncryptData )
151 {
152 setProperty( PKG_MNFST_DIGESTALG, nDigestId );
153 const OUString& sChecksumData = aConvertedAttribs[sChecksumAttribute];
154 uno::Sequence < sal_Int8 > aDecodeBuffer;
155 ::sax::Converter::decodeBase64( aDecodeBuffer, sChecksumData );
156 setProperty( PKG_MNFST_DIGEST, aDecodeBuffer );
157 }
158 }
159 }
160 }
161 else if ( aIter->m_aConvertedName.equalsAscii( ELEMENT_ENCRYPTION_DATA ) )
162 {
163 if ( aConvertedName.equalsAscii( ELEMENT_ALGORITHM ) )
164 {
165 if ( !bIgnoreEncryptData )
166 {
167 sal_Int32 nCypherId = 0;
168 const OUString& rAlgoName = aConvertedAttribs[sAlgorithmNameAttribute];
169 if ( rAlgoName.equalsAscii( BLOWFISH_NAME )
170 || rAlgoName.equalsAscii( BLOWFISH_URL ) )
171 nCypherId = xml::crypto::CipherID::BLOWFISH_CFB_8;
172 else if( rAlgoName.equalsAscii( AES256_URL ) )
173 {
174 nCypherId = xml::crypto::CipherID::AES_CBC_W3C_PADDING;
175 OSL_ENSURE( !nDerivedKeySize || nDerivedKeySize == 32, "Unexpected derived key length!" );
176 nDerivedKeySize = 32;
177 }
178 else if( rAlgoName.equalsAscii( AES192_URL ) )
179 {
180 nCypherId = xml::crypto::CipherID::AES_CBC_W3C_PADDING;
181 OSL_ENSURE( !nDerivedKeySize || nDerivedKeySize == 24, "Unexpected derived key length!" );
182 nDerivedKeySize = 24;
183 }
184 else if( rAlgoName.equalsAscii( AES128_URL ) )
185 {
186 nCypherId = xml::crypto::CipherID::AES_CBC_W3C_PADDING;
187 OSL_ENSURE( !nDerivedKeySize || nDerivedKeySize == 16, "Unexpected derived key length!" );
188 nDerivedKeySize = 16;
189 }
190 else
191 bIgnoreEncryptData = true;
192
193 if ( !bIgnoreEncryptData )
194 {
195 setProperty( PKG_MNFST_ENCALG, nCypherId );
196 const OUString& sInitVector = aConvertedAttribs[sInitialisationVectorAttribute];
197 uno::Sequence < sal_Int8 > aDecodeBuffer;
198 ::sax::Converter::decodeBase64 ( aDecodeBuffer, sInitVector );
199 setProperty( PKG_MNFST_INIVECTOR, aDecodeBuffer );
200 }
201 }
202 }
203 else if ( aConvertedName.equalsAscii( ELEMENT_KEY_DERIVATION ) )
204 {
205 if ( !bIgnoreEncryptData )
206 {
207 const OUString& rKeyDerivString = aConvertedAttribs[sKeyDerivationNameAttribute];
208 if ( rKeyDerivString.equalsAscii( PBKDF2_NAME ) || rKeyDerivString.equalsAscii( PBKDF2_URL ) )
209 {
210 const OUString& rSaltString = aConvertedAttribs[sSaltAttribute];
211 uno::Sequence < sal_Int8 > aDecodeBuffer;
212 ::sax::Converter::decodeBase64 ( aDecodeBuffer, rSaltString );
213 setProperty( PKG_MNFST_SALT, aDecodeBuffer );
214
215 const OUString& rIterationCount = aConvertedAttribs[sIterationCountAttribute];
216 setProperty( PKG_MNFST_ITERATION, rIterationCount.toInt32() );
217
218 const OUString& rKeySize = aConvertedAttribs[sKeySizeAttribute];
219 if ( rKeySize.getLength() )
220 {
221 const sal_Int32 nKey = rKeySize.toInt32();
222 OSL_ENSURE( !nDerivedKeySize || nKey == nDerivedKeySize , "Provided derived key length differs from the expected one!" );
223 nDerivedKeySize = nKey;
224 }
225 else if ( !nDerivedKeySize )
226 nDerivedKeySize = 16;
227 else if ( nDerivedKeySize != 16 )
228 OSL_ENSURE( sal_False, "Default derived key length differs from the expected one!" );
229
230 setProperty( PKG_MNFST_DERKEYSIZE, nDerivedKeySize );
231 }
232 else
233 bIgnoreEncryptData = true;
234 }
235 }
236 else if ( aConvertedName.equalsAscii( ELEMENT_START_KEY_GENERATION ) )
237 {
238 const OUString& rSKeyAlg = aConvertedAttribs[sStartKeyAlgNameAttribute];
239 if ( rSKeyAlg.equalsAscii( SHA256_URL ) )
240 setProperty( PKG_MNFST_STARTALG, xml::crypto::DigestID::SHA256 );
241 else if ( rSKeyAlg.equalsAscii( SHA1_NAME ) || rSKeyAlg.equalsAscii( SHA1_URL ) )
242 setProperty( PKG_MNFST_STARTALG, xml::crypto::DigestID::SHA1 );
243 else
244 bIgnoreEncryptData = true;
245 }
246 }
247 }
248 }
249
250 // ---------------------------------------------------
endElement(const OUString & aName)251 void SAL_CALL ManifestImport::endElement( const OUString& aName )
252 throw( xml::sax::SAXException, uno::RuntimeException )
253 {
254 if( aStack.empty() )
255 return;
256
257 const OUString aConvertedName = ConvertName( aName );
258 if( !aStack.rbegin()->m_aConvertedName.equals( aConvertedName ) )
259 return;
260
261 aStack.pop_back();
262
263 if( !aConvertedName.equalsAscii( ELEMENT_FILE_ENTRY ) )
264 return;
265
266 // create the property sequence
267 // Put full-path property first for MBA
268 // TODO: get rid of fullpath-first requirement
269 const bool bHasFullPath = maValues[PKG_MNFST_FULLPATH].hasValue();
270 OSL_ENSURE( bHasFullPath, "Full path missing in manifest" );
271
272 int nNumProperty = bHasFullPath ? 1 : 0;
273 PropertyValue aProperties[ PKG_SIZE_ENCR_MNFST ];
274 for( int i = 0; i < PKG_SIZE_ENCR_MNFST; ++i)
275 {
276 if(! maValues[i].hasValue() )
277 continue;
278
279 const int nDest = (i == PKG_MNFST_FULLPATH) ? 0 : nNumProperty++;
280 PropertyValue& rProp = aProperties[ nDest ];
281 rProp.Name = OUString::createFromAscii( getMnfstPropName(i));
282 rProp.Value = maValues[i];
283 maValues[i].clear();
284 }
285
286 // add the property sequence to the vector of manifests
287 rManVector.push_back ( PropertyValues( aProperties, nNumProperty ) );
288 bIgnoreEncryptData = false;
289 }
290
291 // ---------------------------------------------------
characters(const OUString &)292 void SAL_CALL ManifestImport::characters( const OUString& /*aChars*/ )
293 throw( xml::sax::SAXException, uno::RuntimeException )
294 {
295 }
296
297 // ---------------------------------------------------
ignorableWhitespace(const OUString &)298 void SAL_CALL ManifestImport::ignorableWhitespace( const OUString& /*aWhitespaces*/ )
299 throw( xml::sax::SAXException, uno::RuntimeException )
300 {
301 }
302
303 // ---------------------------------------------------
processingInstruction(const OUString &,const OUString &)304 void SAL_CALL ManifestImport::processingInstruction( const OUString& /*aTarget*/, const OUString& /*aData*/ )
305 throw( xml::sax::SAXException, uno::RuntimeException )
306 {
307 }
308
309 // ---------------------------------------------------
setDocumentLocator(const uno::Reference<xml::sax::XLocator> &)310 void SAL_CALL ManifestImport::setDocumentLocator( const uno::Reference< xml::sax::XLocator >& /*xLocator*/ )
311 throw( xml::sax::SAXException, uno::RuntimeException )
312 {
313 }
314
315 // ---------------------------------------------------
PushNameAndNamespaces(const::rtl::OUString & aName,const uno::Reference<xml::sax::XAttributeList> & xAttribs,StringHashMap & o_aConvertedAttribs)316 ::rtl::OUString ManifestImport::PushNameAndNamespaces( const ::rtl::OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs, StringHashMap& o_aConvertedAttribs )
317 {
318 StringHashMap aNamespaces;
319 ::std::vector< ::std::pair< ::rtl::OUString, ::rtl::OUString > > aAttribsStrs;
320
321 if ( xAttribs.is() )
322 {
323 sal_Int16 nAttrCount = xAttribs.is() ? xAttribs->getLength() : 0;
324 aAttribsStrs.reserve( nAttrCount );
325
326 for( sal_Int16 nInd = 0; nInd < nAttrCount; nInd++ )
327 {
328 ::rtl::OUString aAttrName = xAttribs->getNameByIndex( nInd );
329 ::rtl::OUString aAttrValue = xAttribs->getValueByIndex( nInd );
330 if ( aAttrName.getLength() >= 5
331 && aAttrName.compareToAscii( "xmlns", 5 ) == 0
332 && ( aAttrName.getLength() == 5 || aAttrName.getStr()[5] == ( sal_Unicode )':' ) )
333 {
334 // this is a namespace declaration
335 ::rtl::OUString aNsName( ( aAttrName.getLength() == 5 ) ? ::rtl::OUString() : aAttrName.copy( 6 ) );
336 aNamespaces[aNsName] = aAttrValue;
337 }
338 else
339 {
340 // this is no namespace declaration
341 aAttribsStrs.push_back( pair< ::rtl::OUString, ::rtl::OUString >( aAttrName, aAttrValue ) );
342 }
343 }
344 }
345
346 ::rtl::OUString aConvertedName = ConvertNameWithNamespace( aName, aNamespaces );
347 if ( !aConvertedName.getLength() )
348 aConvertedName = ConvertName( aName );
349
350 aStack.push_back( ManifestScopeEntry( aConvertedName, aNamespaces ) );
351
352 for ( sal_uInt16 nInd = 0; nInd < aAttribsStrs.size(); nInd++ )
353 {
354 // convert the attribute names on filling
355 o_aConvertedAttribs[ConvertName( aAttribsStrs[nInd].first )] = aAttribsStrs[nInd].second;
356 }
357
358 return aConvertedName;
359 }
360
361
362 // ---------------------------------------------------
ConvertNameWithNamespace(const::rtl::OUString & aName,const StringHashMap & aNamespaces)363 ::rtl::OUString ManifestImport::ConvertNameWithNamespace( const ::rtl::OUString& aName, const StringHashMap& aNamespaces )
364 {
365 ::rtl::OUString aNsAlias;
366 ::rtl::OUString aPureName = aName;
367
368 sal_Int32 nInd = aName.indexOf( ( sal_Unicode )':' );
369 if ( nInd != -1 && nInd < aName.getLength() )
370 {
371 aNsAlias = aName.copy( 0, nInd );
372 aPureName = aName.copy( nInd + 1 );
373 }
374
375 ::rtl::OUString aResult;
376
377 StringHashMap::const_iterator aIter = aNamespaces.find( aNsAlias );
378 if ( aIter != aNamespaces.end()
379 && ( aIter->second.equalsAscii( MANIFEST_NAMESPACE )
380 || aIter->second.equalsAscii( MANIFEST_OASIS_NAMESPACE ) ) )
381 {
382 // no check for manifest.xml consistency currently since the old versions have supported inconsistent documents as well
383 aResult = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( MANIFEST_NSPREFIX ) );
384 aResult += aPureName;
385 }
386
387 return aResult;
388 }
389
390 // ---------------------------------------------------
ConvertName(const::rtl::OUString & aName)391 ::rtl::OUString ManifestImport::ConvertName( const ::rtl::OUString& aName )
392 {
393 ::rtl::OUString aConvertedName;
394 for ( ManifestStack::reverse_iterator aIter = aStack.rbegin(); !aConvertedName.getLength() && aIter != aStack.rend(); aIter++ )
395 {
396 if ( !aIter->m_aNamespaces.empty() )
397 aConvertedName = ConvertNameWithNamespace( aName, aIter->m_aNamespaces );
398 }
399
400 if ( !aConvertedName.getLength() )
401 aConvertedName = aName;
402
403 return aConvertedName;
404 }
405
406