/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER( update_precomp.py ): autogen include statement, do not remove #include "precompiled_package.hxx" #include #include #include #include #include #include using namespace com::sun::star::uno; using namespace com::sun::star::beans; using namespace com::sun::star; using namespace rtl; using namespace std; // helper for ignoring multiple settings of the same property #define setProperty(e,v) do{ if(!maValues[e].hasValue()) maValues[e] <<= v;} while(0) static const char* getMnfstPropName( int nManifestPropId ) { const char* pName; switch( nManifestPropId ) { case PKG_MNFST_MEDIATYPE: pName = "MediaType"; break; case PKG_MNFST_VERSION: pName = "Version"; break; case PKG_MNFST_FULLPATH: pName = "FullPath"; break; case PKG_MNFST_INIVECTOR: pName = "InitialisationVector"; break; case PKG_MNFST_SALT: pName = "Salt"; break; case PKG_MNFST_ITERATION: pName = "IterationCount"; break; case PKG_MNFST_UCOMPSIZE: pName = "Size"; break; case PKG_MNFST_DIGEST: pName = "Digest"; break; case PKG_MNFST_ENCALG: pName = "EncryptionAlgorithm"; break; case PKG_MNFST_STARTALG: pName = "StartKeyAlgorithm"; break; case PKG_MNFST_DIGESTALG: pName = "DigestAlgorithm"; break; case PKG_MNFST_DERKEYSIZE: pName = "DerivedKeySize"; break; default: pName = NULL; } return pName; } // --------------------------------------------------- ManifestImport::ManifestImport( vector < Sequence < PropertyValue > > & rNewManVector ) : rManVector ( rNewManVector ) , nDerivedKeySize( 0 ) , bIgnoreEncryptData( false ) , sCdataAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_CDATA ) ) , sMediaTypeAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_MEDIA_TYPE ) ) , sVersionAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_VERSION ) ) , sFullPathAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_FULL_PATH ) ) , sSizeAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_SIZE ) ) , sSaltAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_SALT ) ) , sInitialisationVectorAttribute(RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_INITIALISATION_VECTOR ) ) , sIterationCountAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_ITERATION_COUNT ) ) , sKeySizeAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_KEY_SIZE ) ) , sAlgorithmNameAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_ALGORITHM_NAME ) ) , sStartKeyAlgNameAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_START_KEY_GENERATION_NAME ) ) , sKeyDerivationNameAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_KEY_DERIVATION_NAME ) ) , sChecksumAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_CHECKSUM ) ) , sChecksumTypeAttribute ( RTL_CONSTASCII_USTRINGPARAM ( ATTRIBUTE_CHECKSUM_TYPE ) ) { aStack.reserve( 10 ); } // --------------------------------------------------- ManifestImport::~ManifestImport ( void ) { } // --------------------------------------------------- void SAL_CALL ManifestImport::startDocument( ) throw( xml::sax::SAXException, uno::RuntimeException ) { } // --------------------------------------------------- void SAL_CALL ManifestImport::endDocument( ) throw( xml::sax::SAXException, uno::RuntimeException ) { } // --------------------------------------------------- void SAL_CALL ManifestImport::startElement( const OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs ) throw( xml::sax::SAXException, uno::RuntimeException ) { StringHashMap aConvertedAttribs; ::rtl::OUString aConvertedName = PushNameAndNamespaces( aName, xAttribs, aConvertedAttribs ); if ( aConvertedName.equalsAscii( ELEMENT_FILE_ENTRY ) ) { setProperty( PKG_MNFST_FULLPATH, aConvertedAttribs[sFullPathAttribute]); setProperty( PKG_MNFST_MEDIATYPE, aConvertedAttribs[sMediaTypeAttribute]); const OUString& sVersion = aConvertedAttribs[sVersionAttribute]; if ( sVersion.getLength() ) setProperty( PKG_MNFST_VERSION, sVersion ); const OUString& sSize = aConvertedAttribs[sSizeAttribute]; if ( sSize.getLength() ) setProperty( PKG_MNFST_UCOMPSIZE, sSize.toInt32() ); } else if ( aStack.size() > 1 ) { ManifestStack::reverse_iterator aIter = aStack.rbegin(); aIter++; if ( aIter->m_aConvertedName.equalsAscii( ELEMENT_FILE_ENTRY ) ) { if ( aConvertedName.equalsAscii( ELEMENT_ENCRYPTION_DATA ) ) { // If this element exists, then this stream is encrypted and we need // to import the initialisation vector, salt and iteration count used nDerivedKeySize = 0; if ( !bIgnoreEncryptData ) { sal_Int32 nDigestId = 0; const OUString& rChecksumType = aConvertedAttribs[sChecksumTypeAttribute]; if( rChecksumType.equalsAscii( SHA1_1K_NAME ) || rChecksumType.equalsAscii( SHA1_1K_URL ) ) nDigestId = xml::crypto::DigestID::SHA1_1K; else if ( rChecksumType.equalsAscii( SHA256_1K_URL ) ) nDigestId = xml::crypto::DigestID::SHA256_1K; else bIgnoreEncryptData = true; if ( !bIgnoreEncryptData ) { setProperty( PKG_MNFST_DIGESTALG, nDigestId ); const OUString& sChecksumData = aConvertedAttribs[sChecksumAttribute]; uno::Sequence < sal_Int8 > aDecodeBuffer; ::sax::Converter::decodeBase64( aDecodeBuffer, sChecksumData ); setProperty( PKG_MNFST_DIGEST, aDecodeBuffer ); } } } } else if ( aIter->m_aConvertedName.equalsAscii( ELEMENT_ENCRYPTION_DATA ) ) { if ( aConvertedName.equalsAscii( ELEMENT_ALGORITHM ) ) { if ( !bIgnoreEncryptData ) { sal_Int32 nCypherId = 0; const OUString& rAlgoName = aConvertedAttribs[sAlgorithmNameAttribute]; if ( rAlgoName.equalsAscii( BLOWFISH_NAME ) || rAlgoName.equalsAscii( BLOWFISH_URL ) ) nCypherId = xml::crypto::CipherID::BLOWFISH_CFB_8; else if( rAlgoName.equalsAscii( AES256_URL ) ) { nCypherId = xml::crypto::CipherID::AES_CBC_W3C_PADDING; OSL_ENSURE( !nDerivedKeySize || nDerivedKeySize == 32, "Unexpected derived key length!" ); nDerivedKeySize = 32; } else if( rAlgoName.equalsAscii( AES192_URL ) ) { nCypherId = xml::crypto::CipherID::AES_CBC_W3C_PADDING; OSL_ENSURE( !nDerivedKeySize || nDerivedKeySize == 24, "Unexpected derived key length!" ); nDerivedKeySize = 24; } else if( rAlgoName.equalsAscii( AES128_URL ) ) { nCypherId = xml::crypto::CipherID::AES_CBC_W3C_PADDING; OSL_ENSURE( !nDerivedKeySize || nDerivedKeySize == 16, "Unexpected derived key length!" ); nDerivedKeySize = 16; } else bIgnoreEncryptData = true; if ( !bIgnoreEncryptData ) { setProperty( PKG_MNFST_ENCALG, nCypherId ); const OUString& sInitVector = aConvertedAttribs[sInitialisationVectorAttribute]; uno::Sequence < sal_Int8 > aDecodeBuffer; ::sax::Converter::decodeBase64 ( aDecodeBuffer, sInitVector ); setProperty( PKG_MNFST_INIVECTOR, aDecodeBuffer ); } } } else if ( aConvertedName.equalsAscii( ELEMENT_KEY_DERIVATION ) ) { if ( !bIgnoreEncryptData ) { const OUString& rKeyDerivString = aConvertedAttribs[sKeyDerivationNameAttribute]; if ( rKeyDerivString.equalsAscii( PBKDF2_NAME ) || rKeyDerivString.equalsAscii( PBKDF2_URL ) ) { const OUString& rSaltString = aConvertedAttribs[sSaltAttribute]; uno::Sequence < sal_Int8 > aDecodeBuffer; ::sax::Converter::decodeBase64 ( aDecodeBuffer, rSaltString ); setProperty( PKG_MNFST_SALT, aDecodeBuffer ); const OUString& rIterationCount = aConvertedAttribs[sIterationCountAttribute]; setProperty( PKG_MNFST_ITERATION, rIterationCount.toInt32() ); const OUString& rKeySize = aConvertedAttribs[sKeySizeAttribute]; if ( rKeySize.getLength() ) { const sal_Int32 nKey = rKeySize.toInt32(); OSL_ENSURE( !nDerivedKeySize || nKey == nDerivedKeySize , "Provided derived key length differs from the expected one!" ); nDerivedKeySize = nKey; } else if ( !nDerivedKeySize ) nDerivedKeySize = 16; else if ( nDerivedKeySize != 16 ) OSL_ENSURE( sal_False, "Default derived key length differs from the expected one!" ); setProperty( PKG_MNFST_DERKEYSIZE, nDerivedKeySize ); } else bIgnoreEncryptData = true; } } else if ( aConvertedName.equalsAscii( ELEMENT_START_KEY_GENERATION ) ) { const OUString& rSKeyAlg = aConvertedAttribs[sStartKeyAlgNameAttribute]; if ( rSKeyAlg.equalsAscii( SHA256_URL ) ) setProperty( PKG_MNFST_STARTALG, xml::crypto::DigestID::SHA256 ); else if ( rSKeyAlg.equalsAscii( SHA1_NAME ) || rSKeyAlg.equalsAscii( SHA1_URL ) ) setProperty( PKG_MNFST_STARTALG, xml::crypto::DigestID::SHA1 ); else bIgnoreEncryptData = true; } } } } // --------------------------------------------------- void SAL_CALL ManifestImport::endElement( const OUString& aName ) throw( xml::sax::SAXException, uno::RuntimeException ) { if( aStack.empty() ) return; const OUString aConvertedName = ConvertName( aName ); if( !aStack.rbegin()->m_aConvertedName.equals( aConvertedName ) ) return; aStack.pop_back(); if( !aConvertedName.equalsAscii( ELEMENT_FILE_ENTRY ) ) return; // create the property sequence // Put full-path property first for MBA // TODO: get rid of fullpath-first requirement const bool bHasFullPath = maValues[PKG_MNFST_FULLPATH].hasValue(); OSL_ENSURE( bHasFullPath, "Full path missing in manifest" ); int nNumProperty = bHasFullPath ? 1 : 0; PropertyValue aProperties[ PKG_SIZE_ENCR_MNFST ]; for( int i = 0; i < PKG_SIZE_ENCR_MNFST; ++i) { if(! maValues[i].hasValue() ) continue; const int nDest = (i == PKG_MNFST_FULLPATH) ? 0 : nNumProperty++; PropertyValue& rProp = aProperties[ nDest ]; rProp.Name = OUString::createFromAscii( getMnfstPropName(i)); rProp.Value = maValues[i]; maValues[i].clear(); } // add the property sequence to the vector of manifests rManVector.push_back ( PropertyValues( aProperties, nNumProperty ) ); bIgnoreEncryptData = false; } // --------------------------------------------------- void SAL_CALL ManifestImport::characters( const OUString& /*aChars*/ ) throw( xml::sax::SAXException, uno::RuntimeException ) { } // --------------------------------------------------- void SAL_CALL ManifestImport::ignorableWhitespace( const OUString& /*aWhitespaces*/ ) throw( xml::sax::SAXException, uno::RuntimeException ) { } // --------------------------------------------------- void SAL_CALL ManifestImport::processingInstruction( const OUString& /*aTarget*/, const OUString& /*aData*/ ) throw( xml::sax::SAXException, uno::RuntimeException ) { } // --------------------------------------------------- void SAL_CALL ManifestImport::setDocumentLocator( const uno::Reference< xml::sax::XLocator >& /*xLocator*/ ) throw( xml::sax::SAXException, uno::RuntimeException ) { } // --------------------------------------------------- ::rtl::OUString ManifestImport::PushNameAndNamespaces( const ::rtl::OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs, StringHashMap& o_aConvertedAttribs ) { StringHashMap aNamespaces; ::std::vector< ::std::pair< ::rtl::OUString, ::rtl::OUString > > aAttribsStrs; if ( xAttribs.is() ) { sal_Int16 nAttrCount = xAttribs.is() ? xAttribs->getLength() : 0; aAttribsStrs.reserve( nAttrCount ); for( sal_Int16 nInd = 0; nInd < nAttrCount; nInd++ ) { ::rtl::OUString aAttrName = xAttribs->getNameByIndex( nInd ); ::rtl::OUString aAttrValue = xAttribs->getValueByIndex( nInd ); if ( aAttrName.getLength() >= 5 && aAttrName.compareToAscii( "xmlns", 5 ) == 0 && ( aAttrName.getLength() == 5 || aAttrName.getStr()[5] == ( sal_Unicode )':' ) ) { // this is a namespace declaration ::rtl::OUString aNsName( ( aAttrName.getLength() == 5 ) ? ::rtl::OUString() : aAttrName.copy( 6 ) ); aNamespaces[aNsName] = aAttrValue; } else { // this is no namespace declaration aAttribsStrs.push_back( pair< ::rtl::OUString, ::rtl::OUString >( aAttrName, aAttrValue ) ); } } } ::rtl::OUString aConvertedName = ConvertNameWithNamespace( aName, aNamespaces ); if ( !aConvertedName.getLength() ) aConvertedName = ConvertName( aName ); aStack.push_back( ManifestScopeEntry( aConvertedName, aNamespaces ) ); for ( sal_uInt16 nInd = 0; nInd < aAttribsStrs.size(); nInd++ ) { // convert the attribute names on filling o_aConvertedAttribs[ConvertName( aAttribsStrs[nInd].first )] = aAttribsStrs[nInd].second; } return aConvertedName; } // --------------------------------------------------- ::rtl::OUString ManifestImport::ConvertNameWithNamespace( const ::rtl::OUString& aName, const StringHashMap& aNamespaces ) { ::rtl::OUString aNsAlias; ::rtl::OUString aPureName = aName; sal_Int32 nInd = aName.indexOf( ( sal_Unicode )':' ); if ( nInd != -1 && nInd < aName.getLength() ) { aNsAlias = aName.copy( 0, nInd ); aPureName = aName.copy( nInd + 1 ); } ::rtl::OUString aResult; StringHashMap::const_iterator aIter = aNamespaces.find( aNsAlias ); if ( aIter != aNamespaces.end() && ( aIter->second.equalsAscii( MANIFEST_NAMESPACE ) || aIter->second.equalsAscii( MANIFEST_OASIS_NAMESPACE ) ) ) { // no check for manifest.xml consistency currently since the old versions have supported inconsistent documents as well aResult = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( MANIFEST_NSPREFIX ) ); aResult += aPureName; } return aResult; } // --------------------------------------------------- ::rtl::OUString ManifestImport::ConvertName( const ::rtl::OUString& aName ) { ::rtl::OUString aConvertedName; for ( ManifestStack::reverse_iterator aIter = aStack.rbegin(); !aConvertedName.getLength() && aIter != aStack.rend(); aIter++ ) { if ( !aIter->m_aNamespaces.empty() ) aConvertedName = ConvertNameWithNamespace( aName, aIter->m_aNamespaces ); } if ( !aConvertedName.getLength() ) aConvertedName = aName; return aConvertedName; }