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 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 // --------------------------------------------------- 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 // --------------------------------------------------- 90 ManifestImport::~ManifestImport ( void ) 91 { 92 } 93 94 // --------------------------------------------------- 95 void SAL_CALL ManifestImport::startDocument( ) 96 throw( xml::sax::SAXException, uno::RuntimeException ) 97 { 98 } 99 100 // --------------------------------------------------- 101 void SAL_CALL ManifestImport::endDocument( ) 102 throw( xml::sax::SAXException, uno::RuntimeException ) 103 { 104 } 105 106 // --------------------------------------------------- 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 long 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 long 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 // --------------------------------------------------- 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 // --------------------------------------------------- 292 void SAL_CALL ManifestImport::characters( const OUString& /*aChars*/ ) 293 throw( xml::sax::SAXException, uno::RuntimeException ) 294 { 295 } 296 297 // --------------------------------------------------- 298 void SAL_CALL ManifestImport::ignorableWhitespace( const OUString& /*aWhitespaces*/ ) 299 throw( xml::sax::SAXException, uno::RuntimeException ) 300 { 301 } 302 303 // --------------------------------------------------- 304 void SAL_CALL ManifestImport::processingInstruction( const OUString& /*aTarget*/, const OUString& /*aData*/ ) 305 throw( xml::sax::SAXException, uno::RuntimeException ) 306 { 307 } 308 309 // --------------------------------------------------- 310 void SAL_CALL ManifestImport::setDocumentLocator( const uno::Reference< xml::sax::XLocator >& /*xLocator*/ ) 311 throw( xml::sax::SAXException, uno::RuntimeException ) 312 { 313 } 314 315 // --------------------------------------------------- 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 // --------------------------------------------------- 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 // --------------------------------------------------- 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