1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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>
28 #include <ManifestDefines.hxx>
29 #include <ManifestExport.hxx>
30 #include <sax/tools/converter.hxx>
32 #include <osl/diagnose.h>
33 #include <rtl/ustrbuf.hxx>
34 #include <comphelper/documentconstants.hxx>
35 #include <comphelper/attributelist.hxx>
37 using namespace ::com::sun::star
;
39 #if OSL_DEBUG_LEVEL > 0
40 #define THROW_WHERE SAL_WHERE
42 #define THROW_WHERE ""
45 ManifestExport::ManifestExport( uno::Reference
< xml::sax::XDocumentHandler
> xHandler
, const uno::Sequence
< uno::Sequence
< beans::PropertyValue
> >& rManList
)
47 const OUString
sFileEntryElement ( ELEMENT_FILE_ENTRY
);
48 const OUString
sManifestElement ( ELEMENT_MANIFEST
);
49 const OUString
sEncryptionDataElement( ELEMENT_ENCRYPTION_DATA
);
50 const OUString
sAlgorithmElement ( ELEMENT_ALGORITHM
);
51 const OUString
sStartKeyGenerationElement ( ELEMENT_START_KEY_GENERATION
);
52 const OUString
sKeyDerivationElement ( ELEMENT_KEY_DERIVATION
);
54 const OUString
sCdataAttribute ( ATTRIBUTE_CDATA
);
55 const OUString
sMediaTypeAttribute ( ATTRIBUTE_MEDIA_TYPE
);
56 const OUString
sVersionAttribute ( ATTRIBUTE_VERSION
);
57 const OUString
sFullPathAttribute ( ATTRIBUTE_FULL_PATH
);
58 const OUString
sSizeAttribute ( ATTRIBUTE_SIZE
);
59 const OUString
sKeySizeAttribute ( ATTRIBUTE_KEY_SIZE
);
60 const OUString
sSaltAttribute ( ATTRIBUTE_SALT
);
61 const OUString
sInitialisationVectorAttribute ( ATTRIBUTE_INITIALISATION_VECTOR
);
62 const OUString
sIterationCountAttribute ( ATTRIBUTE_ITERATION_COUNT
);
63 const OUString
sAlgorithmNameAttribute ( ATTRIBUTE_ALGORITHM_NAME
);
64 const OUString
sStartKeyGenerationNameAttribute ( ATTRIBUTE_START_KEY_GENERATION_NAME
);
65 const OUString
sKeyDerivationNameAttribute ( ATTRIBUTE_KEY_DERIVATION_NAME
);
66 const OUString
sChecksumTypeAttribute ( ATTRIBUTE_CHECKSUM_TYPE
);
67 const OUString
sChecksumAttribute ( ATTRIBUTE_CHECKSUM
);
69 const OUString
sFullPathProperty ( "FullPath" );
70 const OUString
sVersionProperty ( "Version" );
71 const OUString
sMediaTypeProperty ( "MediaType" );
72 const OUString
sIterationCountProperty ( "IterationCount" );
73 const OUString
sDerivedKeySizeProperty ( "DerivedKeySize" );
74 const OUString
sSaltProperty ( "Salt" );
75 const OUString
sInitialisationVectorProperty( "InitialisationVector" );
76 const OUString
sSizeProperty ( "Size" );
77 const OUString
sDigestProperty ( "Digest" );
78 const OUString
sEncryptionAlgProperty ( "EncryptionAlgorithm" );
79 const OUString
sStartKeyAlgProperty ( "StartKeyAlgorithm" );
80 const OUString
sDigestAlgProperty ( "DigestAlgorithm" );
82 const OUString
sWhiteSpace ( " " );
84 const OUString
sSHA256_URL ( SHA256_URL
);
85 const OUString
sSHA1_Name ( SHA1_NAME
);
87 const OUString
sSHA1_1k_Name ( SHA1_1K_NAME
);
88 const OUString
sSHA256_1k_URL ( SHA256_1K_URL
);
90 const OUString
sBlowfish_Name ( BLOWFISH_NAME
);
91 const OUString
sAES256_URL ( AES256_URL
);
93 const OUString
sPBKDF2_Name ( PBKDF2_NAME
);
95 ::comphelper::AttributeList
* pRootAttrList
= new ::comphelper::AttributeList
;
96 const uno::Sequence
< beans::PropertyValue
> *pSequence
= rManList
.getConstArray();
97 const sal_uInt32 nManLength
= rManList
.getLength();
99 // find the mediatype of the document if any
100 OUString aDocMediaType
;
101 OUString aDocVersion
;
102 for (sal_uInt32 nInd
= 0; nInd
< nManLength
; nInd
++ )
108 const beans::PropertyValue
*pValue
= pSequence
[nInd
].getConstArray();
109 for (sal_uInt32 j
= 0, nNum
= pSequence
[nInd
].getLength(); j
< nNum
; j
++, pValue
++)
111 if (pValue
->Name
.equals (sMediaTypeProperty
) )
113 pValue
->Value
>>= aMediaType
;
115 else if (pValue
->Name
.equals (sFullPathProperty
) )
117 pValue
->Value
>>= aPath
;
119 else if (pValue
->Name
.equals (sVersionProperty
) )
121 pValue
->Value
>>= aVersion
;
124 if ( !aPath
.isEmpty() && !aMediaType
.isEmpty() && !aVersion
.isEmpty() )
130 aDocMediaType
= aMediaType
;
131 aDocVersion
= aVersion
;
136 bool bProvideDTD
= false;
137 bool bAcceptNonemptyVersion
= false;
138 bool bStoreStartKeyGeneration
= false;
139 if ( !aDocMediaType
.isEmpty() )
141 if ( aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_TEXT_ASCII
142 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_TEXT_WEB_ASCII
143 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_TEXT_GLOBAL_ASCII
144 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_ASCII
145 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_ASCII
146 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_ASCII
147 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_CHART_ASCII
148 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_DATABASE_ASCII
149 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_ASCII
150 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_TEXT_TEMPLATE_ASCII
151 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_TEXT_GLOBAL_TEMPLATE_ASCII
152 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_TEMPLATE_ASCII
153 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_TEMPLATE_ASCII
154 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_TEMPLATE_ASCII
155 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_CHART_TEMPLATE_ASCII
156 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_TEMPLATE_ASCII
)
160 pRootAttrList
->AddAttribute ( ATTRIBUTE_XMLNS
,
162 MANIFEST_OASIS_NAMESPACE
);
163 bAcceptNonemptyVersion
= true;
164 if ( aDocVersion
.compareTo( ODFVER_012_TEXT
) >= 0 )
166 // this is ODF12 generation, let encrypted streams contain start-key-generation entry
167 bStoreStartKeyGeneration
= true;
168 pRootAttrList
->AddAttribute ( sVersionAttribute
, sCdataAttribute
, aDocVersion
);
173 // even if it is no SO6 format the namespace must be specified
174 // thus SO6 format is used as default one
175 pRootAttrList
->AddAttribute ( ATTRIBUTE_XMLNS
,
177 MANIFEST_NAMESPACE
);
183 uno::Reference
< xml::sax::XAttributeList
> xRootAttrList (pRootAttrList
);
185 xHandler
->startDocument();
186 uno::Reference
< xml::sax::XExtendedDocumentHandler
> xExtHandler ( xHandler
, uno::UNO_QUERY
);
187 if ( xExtHandler
.is() && bProvideDTD
)
189 OUString
aDocType ( MANIFEST_DOCTYPE
);
190 xExtHandler
->unknown ( aDocType
);
191 xHandler
->ignorableWhitespace ( sWhiteSpace
);
193 xHandler
->startElement( sManifestElement
, xRootAttrList
);
195 for (sal_uInt32 i
= 0 ; i
< nManLength
; i
++)
197 ::comphelper::AttributeList
*pAttrList
= new ::comphelper::AttributeList
;
198 const beans::PropertyValue
*pValue
= pSequence
[i
].getConstArray();
200 const uno::Any
*pVector
= NULL
, *pSalt
= NULL
, *pIterationCount
= NULL
, *pDigest
= NULL
, *pDigestAlg
= NULL
, *pEncryptAlg
= NULL
, *pStartKeyAlg
= NULL
, *pDerivedKeySize
= NULL
;
201 for (sal_uInt32 j
= 0, nNum
= pSequence
[i
].getLength(); j
< nNum
; j
++, pValue
++)
203 if (pValue
->Name
.equals (sMediaTypeProperty
) )
205 pValue
->Value
>>= aString
;
206 pAttrList
->AddAttribute ( sMediaTypeAttribute
, sCdataAttribute
, aString
);
208 else if (pValue
->Name
.equals (sVersionProperty
) )
210 pValue
->Value
>>= aString
;
211 // the version is stored only if it is not empty
212 if ( bAcceptNonemptyVersion
&& !aString
.isEmpty() )
213 pAttrList
->AddAttribute ( sVersionAttribute
, sCdataAttribute
, aString
);
215 else if (pValue
->Name
.equals (sFullPathProperty
) )
217 pValue
->Value
>>= aString
;
218 pAttrList
->AddAttribute ( sFullPathAttribute
, sCdataAttribute
, aString
);
220 else if (pValue
->Name
.equals (sSizeProperty
) )
223 pValue
->Value
>>= nSize
;
224 OUStringBuffer aBuffer
;
225 aBuffer
.append ( nSize
);
226 pAttrList
->AddAttribute ( sSizeAttribute
, sCdataAttribute
, aBuffer
.makeStringAndClear() );
228 else if (pValue
->Name
.equals (sInitialisationVectorProperty
) )
229 pVector
= &pValue
->Value
;
230 else if (pValue
->Name
.equals (sSaltProperty
) )
231 pSalt
= &pValue
->Value
;
232 else if (pValue
->Name
.equals (sIterationCountProperty
) )
233 pIterationCount
= &pValue
->Value
;
234 else if (pValue
->Name
.equals ( sDigestProperty
) )
235 pDigest
= &pValue
->Value
;
236 else if (pValue
->Name
.equals ( sDigestAlgProperty
) )
237 pDigestAlg
= &pValue
->Value
;
238 else if (pValue
->Name
.equals ( sEncryptionAlgProperty
) )
239 pEncryptAlg
= &pValue
->Value
;
240 else if (pValue
->Name
.equals ( sStartKeyAlgProperty
) )
241 pStartKeyAlg
= &pValue
->Value
;
242 else if (pValue
->Name
.equals ( sDerivedKeySizeProperty
) )
243 pDerivedKeySize
= &pValue
->Value
;
246 xHandler
->ignorableWhitespace ( sWhiteSpace
);
247 uno::Reference
< xml::sax::XAttributeList
> xAttrList ( pAttrList
);
248 xHandler
->startElement( sFileEntryElement
, xAttrList
);
249 if ( pVector
&& pSalt
&& pIterationCount
&& pDigest
&& pDigestAlg
&& pEncryptAlg
&& pStartKeyAlg
&& pDerivedKeySize
)
251 // ==== Encryption Data
252 ::comphelper::AttributeList
* pNewAttrList
= new ::comphelper::AttributeList
;
253 uno::Reference
< xml::sax::XAttributeList
> xNewAttrList (pNewAttrList
);
254 OUStringBuffer aBuffer
;
255 uno::Sequence
< sal_Int8
> aSequence
;
257 xHandler
->ignorableWhitespace ( sWhiteSpace
);
260 OUString sChecksumType
;
261 sal_Int32 nDigestAlgID
= 0;
262 *pDigestAlg
>>= nDigestAlgID
;
263 if ( nDigestAlgID
== xml::crypto::DigestID::SHA256_1K
)
264 sChecksumType
= sSHA256_1k_URL
;
265 else if ( nDigestAlgID
== xml::crypto::DigestID::SHA1_1K
)
266 sChecksumType
= sSHA1_1k_Name
;
268 throw uno::RuntimeException( THROW_WHERE
"Unexpected digest algorithm is provided!" );
270 pNewAttrList
->AddAttribute ( sChecksumTypeAttribute
, sCdataAttribute
, sChecksumType
);
271 *pDigest
>>= aSequence
;
272 ::sax::Converter::encodeBase64(aBuffer
, aSequence
);
273 pNewAttrList
->AddAttribute ( sChecksumAttribute
, sCdataAttribute
, aBuffer
.makeStringAndClear() );
275 xHandler
->startElement( sEncryptionDataElement
, xNewAttrList
);
278 pNewAttrList
= new ::comphelper::AttributeList
;
279 xNewAttrList
= pNewAttrList
;
281 sal_Int32 nEncAlgID
= 0;
282 sal_Int32 nDerivedKeySize
= 0;
283 *pEncryptAlg
>>= nEncAlgID
;
284 *pDerivedKeySize
>>= nDerivedKeySize
;
286 OUString sEncAlgName
;
287 if ( nEncAlgID
== xml::crypto::CipherID::AES_CBC_W3C_PADDING
)
289 OSL_ENSURE( nDerivedKeySize
, "Unexpected key size is provided!" );
290 if ( nDerivedKeySize
!= 32 )
291 throw uno::RuntimeException( THROW_WHERE
"Unexpected key size is provided!" );
293 sEncAlgName
= sAES256_URL
;
295 else if ( nEncAlgID
== xml::crypto::CipherID::BLOWFISH_CFB_8
)
297 sEncAlgName
= sBlowfish_Name
;
300 throw uno::RuntimeException( THROW_WHERE
"Unexpected encryption algorithm is provided!" );
302 pNewAttrList
->AddAttribute ( sAlgorithmNameAttribute
, sCdataAttribute
, sEncAlgName
);
304 *pVector
>>= aSequence
;
305 ::sax::Converter::encodeBase64(aBuffer
, aSequence
);
306 pNewAttrList
->AddAttribute ( sInitialisationVectorAttribute
, sCdataAttribute
, aBuffer
.makeStringAndClear() );
308 xHandler
->ignorableWhitespace ( sWhiteSpace
);
309 xHandler
->startElement( sAlgorithmElement
, xNewAttrList
);
310 xHandler
->ignorableWhitespace ( sWhiteSpace
);
311 xHandler
->endElement( sAlgorithmElement
);
313 // ==== Key Derivation
314 pNewAttrList
= new ::comphelper::AttributeList
;
315 xNewAttrList
= pNewAttrList
;
317 pNewAttrList
->AddAttribute ( sKeyDerivationNameAttribute
, sCdataAttribute
, sPBKDF2_Name
);
319 if ( bStoreStartKeyGeneration
)
321 aBuffer
.append( nDerivedKeySize
);
322 pNewAttrList
->AddAttribute ( sKeySizeAttribute
, sCdataAttribute
, aBuffer
.makeStringAndClear() );
325 sal_Int32 nCount
= 0;
326 *pIterationCount
>>= nCount
;
327 aBuffer
.append (nCount
);
328 pNewAttrList
->AddAttribute ( sIterationCountAttribute
, sCdataAttribute
, aBuffer
.makeStringAndClear() );
330 *pSalt
>>= aSequence
;
331 ::sax::Converter::encodeBase64(aBuffer
, aSequence
);
332 pNewAttrList
->AddAttribute ( sSaltAttribute
, sCdataAttribute
, aBuffer
.makeStringAndClear() );
334 xHandler
->ignorableWhitespace ( sWhiteSpace
);
335 xHandler
->startElement( sKeyDerivationElement
, xNewAttrList
);
336 xHandler
->ignorableWhitespace ( sWhiteSpace
);
337 xHandler
->endElement( sKeyDerivationElement
);
339 // we have to store start-key-generation element as the last one to workaround the parsing problem
340 // in OOo3.1 and older versions
341 if ( bStoreStartKeyGeneration
)
343 // ==== Start Key Generation
344 pNewAttrList
= new ::comphelper::AttributeList
;
345 xNewAttrList
= pNewAttrList
;
347 OUString sStartKeyAlg
;
348 OUString sStartKeySize
;
349 sal_Int32 nStartKeyAlgID
= 0;
350 *pStartKeyAlg
>>= nStartKeyAlgID
;
351 if ( nStartKeyAlgID
== xml::crypto::DigestID::SHA256
)
353 sStartKeyAlg
= sSHA256_URL
;
354 aBuffer
.append( (sal_Int32
)32 );
355 sStartKeySize
= aBuffer
.makeStringAndClear();
357 else if ( nStartKeyAlgID
== xml::crypto::DigestID::SHA1
)
359 sStartKeyAlg
= sSHA1_Name
;
360 aBuffer
.append( (sal_Int32
)20 );
361 sStartKeySize
= aBuffer
.makeStringAndClear();
364 throw uno::RuntimeException( THROW_WHERE
"Unexpected start key algorithm is provided!" );
366 pNewAttrList
->AddAttribute ( sStartKeyGenerationNameAttribute
, sCdataAttribute
, sStartKeyAlg
);
367 pNewAttrList
->AddAttribute ( sKeySizeAttribute
, sCdataAttribute
, sStartKeySize
);
369 xHandler
->ignorableWhitespace ( sWhiteSpace
);
370 xHandler
->startElement( sStartKeyGenerationElement
, xNewAttrList
);
371 xHandler
->ignorableWhitespace ( sWhiteSpace
);
372 xHandler
->endElement( sStartKeyGenerationElement
);
375 xHandler
->ignorableWhitespace ( sWhiteSpace
);
376 xHandler
->endElement( sEncryptionDataElement
);
378 xHandler
->ignorableWhitespace ( sWhiteSpace
);
379 xHandler
->endElement( sFileEntryElement
);
381 xHandler
->ignorableWhitespace ( sWhiteSpace
);
382 xHandler
->endElement( sManifestElement
);
383 xHandler
->endDocument();
386 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */