summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThorsten Behrens <Thorsten.Behrens@CIB.de>2017-08-18 21:34:11 +0200
committerThorsten Behrens <Thorsten.Behrens@CIB.de>2017-12-07 16:17:09 +0100
commitee0f1c7971ff06969ee3e6fd567e202377c5d616 (patch)
tree6b0a422e427b401b0ce13bf6919285f9813a3a0a
parent9895830b4f00cf54cea64e9b6db46fc627db6222 (diff)
gpg4libre: add manifest entries for gpg encryption
Change-Id: I71bd7e2c6c73d997fa1ed5bb36fdc2873daca10c
-rw-r--r--package/source/manifest/ManifestDefines.hxx13
-rw-r--r--package/source/manifest/ManifestExport.cxx175
2 files changed, 174 insertions, 14 deletions
diff --git a/package/source/manifest/ManifestDefines.hxx b/package/source/manifest/ManifestDefines.hxx
index 968aed648e6a..c68c241c7514 100644
--- a/package/source/manifest/ManifestDefines.hxx
+++ b/package/source/manifest/ManifestDefines.hxx
@@ -24,8 +24,10 @@
#define MANIFEST_NSPREFIX "manifest:"
#define ELEMENT_MANIFEST "manifest:manifest"
#define ATTRIBUTE_XMLNS "xmlns:manifest"
+#define ATTRIBUTE_XMLNS_LOEXT "xmlns:loext"
#define MANIFEST_NAMESPACE "http://openoffice.org/2001/manifest"
#define MANIFEST_OASIS_NAMESPACE "urn:oasis:names:tc:opendocument:xmlns:manifest:1.0"
+#define MANIFEST_LOEXT_NAMESPACE "urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0"
#define MANIFEST_DOCTYPE "<!DOCTYPE manifest:manifest PUBLIC \"-//OpenOffice.org//DTD Manifest 1.0//EN\" \"Manifest.dtd\">"
#define ATTRIBUTE_CDATA "CDATA"
@@ -34,6 +36,16 @@
#define ATTRIBUTE_VERSION "manifest:version"
#define ATTRIBUTE_MEDIA_TYPE "manifest:media-type"
#define ATTRIBUTE_SIZE "manifest:size"
+#define ELEMENT_MANIFEST_KEYINFO "loext:keyinfo"
+#define ELEMENT_ENCRYPTED_KEYINFO "loext:KeyInfo"
+#define ELEMENT_ENCRYPTEDKEY "loext:encrypted-key"
+#define ELEMENT_ENCRYPTIONMETHOD "loext:encryption-method"
+#define ELEMENT_PGPDATA "loext:PGPData"
+#define ELEMENT_PGPKEYID "loext:PGPKeyID"
+#define ELEMENT_PGPKEYPACKET "loext:PGPKeyPacket"
+#define ATTRIBUTE_ALGORITHM "loext:PGPAlgorithm"
+#define ELEMENT_CIPHERDATA "loext:CipherData"
+#define ELEMENT_CIPHERVALUE "loext:CipherValue"
#define ELEMENT_ENCRYPTION_DATA "manifest:encryption-data"
#define ATTRIBUTE_CHECKSUM_TYPE "manifest:checksum-type"
@@ -69,6 +81,7 @@
#define AES256_URL "http://www.w3.org/2001/04/xmlenc#aes256-cbc"
#define PBKDF2_NAME "PBKDF2"
+#define PGP_NAME "PGP"
#define PBKDF2_URL "urn:oasis:names:tc:opendocument:xmlns:manifest:1.0#pbkdf2"
#endif
diff --git a/package/source/manifest/ManifestExport.cxx b/package/source/manifest/ManifestExport.cxx
index 60a5128e945d..5cf87334ca62 100644
--- a/package/source/manifest/ManifestExport.cxx
+++ b/package/source/manifest/ManifestExport.cxx
@@ -23,6 +23,7 @@
#include <com/sun/star/xml/crypto/DigestID.hpp>
#include <com/sun/star/xml/crypto/CipherID.hpp>
#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
#include <com/sun/star/uno/RuntimeException.hpp>
#include "ManifestDefines.hxx"
@@ -66,11 +67,25 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con
const OUString sChecksumTypeAttribute ( ATTRIBUTE_CHECKSUM_TYPE );
const OUString sChecksumAttribute ( ATTRIBUTE_CHECKSUM);
+ const OUString sKeyInfoElement ( ELEMENT_ENCRYPTED_KEYINFO );
+ const OUString sManifestKeyInfoElement ( ELEMENT_MANIFEST_KEYINFO );
+ const OUString sEncryptedKeyElement ( ELEMENT_ENCRYPTEDKEY );
+ const OUString sEncryptionMethodElement ( ELEMENT_ENCRYPTIONMETHOD );
+ const OUString sPgpDataElement ( ELEMENT_PGPDATA );
+ const OUString sPgpKeyIDElement ( ELEMENT_PGPKEYID );
+ const OUString sPGPKeyPacketElement ( ELEMENT_PGPKEYPACKET );
+ const OUString sAlgorithmAttribute ( ATTRIBUTE_ALGORITHM );
+ const OUString sCipherDataElement ( ELEMENT_CIPHERDATA );
+ const OUString sCipherValueElement ( ELEMENT_CIPHERVALUE );
+ const OUString sKeyInfo ( "KeyInfo" );
+ const OUString sPgpKeyIDProperty ( "KeyId" );
+ const OUString sPgpKeyPacketProperty ( "KeyPacket" );
+ const OUString sCipherValueProperty ( "CipherValue" );
const OUString sFullPathProperty ( "FullPath" );
const OUString sVersionProperty ( "Version" );
const OUString sMediaTypeProperty ( "MediaType" );
const OUString sIterationCountProperty ( "IterationCount" );
- const OUString sDerivedKeySizeProperty ( "DerivedKeySize" );
+ const OUString sDerivedKeySizeProperty ( "DerivedKeySize" );
const OUString sSaltProperty ( "Salt" );
const OUString sInitialisationVectorProperty( "InitialisationVector" );
const OUString sSizeProperty ( "Size" );
@@ -92,6 +107,7 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con
const OUString sAES256_URL ( AES256_URL );
const OUString sPBKDF2_Name ( PBKDF2_NAME );
+ const OUString sPGP_Name ( PGP_NAME );
::comphelper::AttributeList * pRootAttrList = new ::comphelper::AttributeList;
const uno::Sequence < beans::PropertyValue > *pSequence = rManList.getConstArray();
@@ -100,6 +116,7 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con
// find the mediatype of the document if any
OUString aDocMediaType;
OUString aDocVersion;
+ sal_Int32 nRootFolderPropIndex=-1;
for (sal_uInt32 nInd = 0; nInd < nManLength ; nInd++ )
{
OUString aMediaType;
@@ -130,6 +147,7 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con
{
aDocMediaType = aMediaType;
aDocVersion = aVersion;
+ nRootFolderPropIndex = nInd;
break;
}
}
@@ -164,9 +182,14 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con
bAcceptNonemptyVersion = true;
if ( aDocVersion.compareTo( ODFVER_012_TEXT ) >= 0 )
{
- // this is ODF12 generation, let encrypted streams contain start-key-generation entry
+ // this is ODF12 or later generation, let encrypted
+ // streams contain start-key-generation entry
bStoreStartKeyGeneration = true;
pRootAttrList->AddAttribute ( sVersionAttribute, sCdataAttribute, aDocVersion );
+ // plus gpg4libre extensions - loext NS for that
+ pRootAttrList->AddAttribute ( ATTRIBUTE_XMLNS_LOEXT,
+ sCdataAttribute,
+ MANIFEST_LOEXT_NAMESPACE );
}
}
else
@@ -192,6 +215,116 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con
}
xHandler->startElement( sManifestElement, xRootAttrList );
+ const uno::Any *pKeyInfoProperty = nullptr;
+ if ( nRootFolderPropIndex >= 0 )
+ {
+ // do we have package-wide encryption info?
+ const beans::PropertyValue *pValue =
+ pSequence[nRootFolderPropIndex].getConstArray();
+ for (sal_uInt32 j = 0, nNum = pSequence[nRootFolderPropIndex].getLength(); j < nNum; j++, pValue++)
+ {
+ if (pValue->Name == sKeyInfo )
+ pKeyInfoProperty = &pValue->Value;
+ }
+
+ if ( pKeyInfoProperty )
+ {
+ // yeah, so that goes directly below the manifest:manifest
+ // element
+ ::comphelper::AttributeList * pNewAttrList = new ::comphelper::AttributeList;
+ uno::Reference < xml::sax::XAttributeList > xNewAttrList (pNewAttrList);
+ OUStringBuffer aBuffer;
+
+ xHandler->ignorableWhitespace ( sWhiteSpace );
+
+ // ==== manifest:keyinfo & children
+ xHandler->startElement( sManifestKeyInfoElement, nullptr );
+ xHandler->ignorableWhitespace ( sWhiteSpace );
+
+ uno::Sequence< uno::Sequence < beans::NamedValue > > aKeyInfoSequence;
+ *pKeyInfoProperty >>= aKeyInfoSequence;
+ const uno::Sequence < beans::NamedValue > *pKeyInfoSequence = aKeyInfoSequence.getConstArray();
+ const sal_uInt32 nKeyInfoLength = aKeyInfoSequence.getLength();
+ for (sal_uInt32 nInd = 0; nInd < nKeyInfoLength ; nInd++ )
+ {
+ uno::Sequence < sal_Int8 > aPgpKeyID;
+ uno::Sequence < sal_Int8 > aPgpKeyPacket;
+ uno::Sequence < sal_Int8 > aCipherValue;
+ const beans::NamedValue *pNValue = pKeyInfoSequence[nInd].getConstArray();
+ for (sal_uInt32 j = 0, nNum = pKeyInfoSequence[nInd].getLength(); j < nNum; j++, pNValue++)
+ {
+ if (pNValue->Name == sPgpKeyIDProperty )
+ pNValue->Value >>= aPgpKeyID;
+ else if (pNValue->Name == sPgpKeyPacketProperty )
+ pNValue->Value >>= aPgpKeyPacket;
+ else if (pNValue->Name == sCipherValueProperty )
+ pNValue->Value >>= aCipherValue;
+ }
+
+ if (aPgpKeyID.hasElements() && aCipherValue.hasElements() )
+ {
+ // ==== manifest:encrypted-key & children - one for each recipient
+ xHandler->startElement( sEncryptedKeyElement, nullptr );
+ xHandler->ignorableWhitespace ( sWhiteSpace );
+
+ // TODO: the algorithm should rather be configurable
+ pNewAttrList->AddAttribute ( sAlgorithmAttribute, sCdataAttribute,
+ "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p" );
+ xHandler->startElement( sEncryptionMethodElement, xNewAttrList );
+ xHandler->ignorableWhitespace ( sWhiteSpace );
+ xHandler->endElement( sEncryptionMethodElement );
+
+ xHandler->startElement( sKeyInfoElement, nullptr );
+ xHandler->ignorableWhitespace ( sWhiteSpace );
+
+ xHandler->startElement( sPgpDataElement, nullptr );
+ xHandler->ignorableWhitespace ( sWhiteSpace );
+
+ xHandler->startElement( sPgpKeyIDElement, nullptr );
+ ::sax::Converter::encodeBase64(aBuffer, aPgpKeyID);
+ xHandler->characters( aBuffer.makeStringAndClear() );
+ xHandler->endElement( sPgpKeyIDElement );
+ xHandler->ignorableWhitespace ( sWhiteSpace );
+
+ // key packet is optional
+ if (aPgpKeyPacket.hasElements())
+ {
+ xHandler->startElement( sPGPKeyPacketElement, nullptr );
+ ::sax::Converter::encodeBase64(aBuffer, aPgpKeyPacket);
+ xHandler->characters( aBuffer.makeStringAndClear() );
+ xHandler->endElement( sPGPKeyPacketElement );
+ xHandler->ignorableWhitespace ( sWhiteSpace );
+ }
+
+ xHandler->endElement( sPgpDataElement );
+ xHandler->ignorableWhitespace ( sWhiteSpace );
+
+ xHandler->endElement( sKeyInfoElement );
+ xHandler->ignorableWhitespace ( sWhiteSpace );
+
+ xHandler->startElement( sCipherDataElement, nullptr );
+ xHandler->ignorableWhitespace ( sWhiteSpace );
+
+ xHandler->startElement( sCipherValueElement, nullptr );
+ ::sax::Converter::encodeBase64(aBuffer, aCipherValue);
+ xHandler->characters( aBuffer.makeStringAndClear() );
+ xHandler->endElement( sCipherValueElement );
+ xHandler->ignorableWhitespace ( sWhiteSpace );
+
+ xHandler->endElement( sCipherDataElement );
+ xHandler->ignorableWhitespace ( sWhiteSpace );
+
+ xHandler->endElement( sEncryptedKeyElement );
+ xHandler->ignorableWhitespace ( sWhiteSpace );
+ }
+ }
+
+ xHandler->endElement( sManifestKeyInfoElement );
+ xHandler->ignorableWhitespace ( sWhiteSpace );
+ }
+ }
+
+ // now write individual file entries
for (sal_uInt32 i = 0 ; i < nManLength ; i++)
{
::comphelper::AttributeList *pAttrList = new ::comphelper::AttributeList;
@@ -314,22 +447,36 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con
pNewAttrList = new ::comphelper::AttributeList;
xNewAttrList = pNewAttrList;
- pNewAttrList->AddAttribute ( sKeyDerivationNameAttribute, sCdataAttribute, sPBKDF2_Name );
-
- if ( bStoreStartKeyGeneration )
+ if ( pKeyInfoProperty )
{
- aBuffer.append( nDerivedKeySize );
- pNewAttrList->AddAttribute ( sKeySizeAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );
+ pNewAttrList->AddAttribute ( sKeyDerivationNameAttribute,
+ sCdataAttribute,
+ sPGP_Name );
+ // no start-key-generation needed, our session key has
+ // max size already
+ bStoreStartKeyGeneration = false;
}
+ else
+ {
+ pNewAttrList->AddAttribute ( sKeyDerivationNameAttribute,
+ sCdataAttribute,
+ sPBKDF2_Name );
+
+ if ( bStoreStartKeyGeneration )
+ {
+ aBuffer.append( nDerivedKeySize );
+ pNewAttrList->AddAttribute ( sKeySizeAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );
+ }
- sal_Int32 nCount = 0;
- *pIterationCount >>= nCount;
- aBuffer.append (nCount);
- pNewAttrList->AddAttribute ( sIterationCountAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );
+ sal_Int32 nCount = 0;
+ *pIterationCount >>= nCount;
+ aBuffer.append (nCount);
+ pNewAttrList->AddAttribute ( sIterationCountAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );
- *pSalt >>= aSequence;
- ::sax::Converter::encodeBase64(aBuffer, aSequence);
- pNewAttrList->AddAttribute ( sSaltAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );
+ *pSalt >>= aSequence;
+ ::sax::Converter::encodeBase64(aBuffer, aSequence);
+ pNewAttrList->AddAttribute ( sSaltAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );
+ }
xHandler->ignorableWhitespace ( sWhiteSpace );
xHandler->startElement( sKeyDerivationElement , xNewAttrList);