blob: 7b06ed23c966ce57f4b7e5c98efb6e47cfacb35d [file] [log] [blame]
/**************************************************************
*
* 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 <ManifestImport.hxx>
#include <ManifestDefines.hxx>
#include <sax/tools/converter.hxx>
#include <com/sun/star/xml/sax/XAttributeList.hpp>
#include <com/sun/star/xml/crypto/DigestID.hpp>
#include <com/sun/star/xml/crypto/CipherID.hpp>
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;
}