mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-02-10 18:05:41 +08:00
Fix bug 59649
This commit is contained in:
@ -7,6 +7,7 @@
|
||||
#define OOXML_SIGNATURE_INVALID 1
|
||||
#define OOXML_SIGNATURE_NOTSUPPORTED 2
|
||||
#define OOXML_SIGNATURE_BAD 3
|
||||
#define OOXML_SIGNATURE_PARTIALLY 4
|
||||
|
||||
class COOXMLSignature_private;
|
||||
class OPENSSL_DECL COOXMLSignature
|
||||
|
||||
@ -27,6 +27,7 @@ HEADERS += \
|
||||
src/XmlTransform.h
|
||||
|
||||
SOURCES += \
|
||||
src/common.h \
|
||||
src/XmlTransform.cpp \
|
||||
src/CertificateCommon.cpp \
|
||||
src/OOXMLSigner.cpp \
|
||||
|
||||
@ -1,12 +1,7 @@
|
||||
#include "./../include/OOXMLSigner.h"
|
||||
#include "../../../../OfficeUtils/src/ZipFolder.h"
|
||||
#include "./XmlTransform.h"
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
#include <time.h>
|
||||
#include "./../include/CertificateCommon.h"
|
||||
#include "./common.h"
|
||||
|
||||
class COOXMLSigner_private
|
||||
class COOXMLSigner_private : public CSignFolderFiles
|
||||
{
|
||||
public:
|
||||
ICertificate* m_certificate;
|
||||
@ -14,10 +9,6 @@ public:
|
||||
|
||||
std::wstring m_date;
|
||||
|
||||
std::map<std::wstring, std::wstring> m_content_types;
|
||||
std::vector<std::wstring> m_rels;
|
||||
std::vector<std::wstring> m_files;
|
||||
|
||||
NSStringUtils::CStringBuilderA m_signed_info;
|
||||
|
||||
std::wstring m_image_valid;
|
||||
@ -263,31 +254,7 @@ public:
|
||||
|
||||
void ParseContentTypes()
|
||||
{
|
||||
XmlUtils::CXmlNode oNode = m_pFolder->getNodeFromFile(L"/[Content_Types].xml");
|
||||
|
||||
XmlUtils::CXmlNodes nodesDefaults;
|
||||
oNode.GetNodes(L"Default", nodesDefaults);
|
||||
|
||||
XmlUtils::CXmlNodes nodesOverrides;
|
||||
oNode.GetNodes(L"Override", nodesOverrides);
|
||||
|
||||
int nCount = nodesDefaults.GetCount();
|
||||
for (int i = 0; i < nCount; ++i)
|
||||
{
|
||||
XmlUtils::CXmlNode node;
|
||||
nodesDefaults.GetAt(i, node);
|
||||
|
||||
m_content_types.insert(std::pair<std::wstring, std::wstring>(node.GetAttribute("Extension"), node.GetAttribute("ContentType")));
|
||||
}
|
||||
|
||||
nCount = nodesOverrides.GetCount();
|
||||
for (int i = 0; i < nCount; ++i)
|
||||
{
|
||||
XmlUtils::CXmlNode node;
|
||||
nodesOverrides.GetAt(i, node);
|
||||
|
||||
m_content_types.insert(std::pair<std::wstring, std::wstring>(node.GetAttribute("PartName"), node.GetAttribute("ContentType")));
|
||||
}
|
||||
Folder_ParseContentTypes(m_pFolder);
|
||||
}
|
||||
|
||||
void Parse()
|
||||
@ -295,39 +262,8 @@ public:
|
||||
// 1) Parse Content_Types.xml
|
||||
ParseContentTypes();
|
||||
|
||||
// 2) Parse files in directory
|
||||
std::vector<std::wstring> files = m_pFolder->getFiles(L"", true);
|
||||
|
||||
// 3) Check each file
|
||||
std::wstring sFolder = L"";
|
||||
for (std::vector<std::wstring>::iterator i = files.begin(); i != files.end(); i++)
|
||||
{
|
||||
std::wstring sCheckFile = *i;
|
||||
|
||||
// make cool filename
|
||||
sCheckFile = m_pFolder->getLocalFilePath(sCheckFile);
|
||||
|
||||
// check needed file
|
||||
if (0 == sCheckFile.find(L"_xmlsignatures") ||
|
||||
0 == sCheckFile.find(L"docProps") ||
|
||||
0 == sCheckFile.find(L"[Content_Types].xml") ||
|
||||
0 == sCheckFile.find(L"[trash]"))
|
||||
continue;
|
||||
|
||||
// check rels and add to needed array
|
||||
std::wstring::size_type posExt = sCheckFile.rfind(L".");
|
||||
if (std::wstring::npos == posExt)
|
||||
continue;
|
||||
|
||||
std::wstring sExt = sCheckFile.substr(posExt + 1);
|
||||
if (sExt == L"rels")
|
||||
m_rels.push_back(sCheckFile);
|
||||
else
|
||||
m_files.push_back(sCheckFile);
|
||||
}
|
||||
|
||||
std::sort(m_rels.begin(), m_rels.end());
|
||||
std::sort(m_files.begin(), m_files.end());
|
||||
// 2) Parse files & check each file in directory
|
||||
Folder_Parse(m_pFolder);
|
||||
}
|
||||
|
||||
void WriteRelsReferences(NSStringUtils::CStringBuilder& builder)
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
#include "./XmlTransform.h"
|
||||
#include "./../include/OOXMLVerifier.h"
|
||||
#include "../../../../OfficeUtils/src/ZipFolder.h"
|
||||
#include "./../include/CertificateCommon.h"
|
||||
#include "common.h"
|
||||
|
||||
class COOXMLSignature_private
|
||||
{
|
||||
@ -20,6 +18,8 @@ public:
|
||||
|
||||
XmlUtils::CXmlNode m_node; // signature file
|
||||
|
||||
std::set<std::wstring> m_arFilesInManifest;
|
||||
|
||||
class CXmlStackNamespaces
|
||||
{
|
||||
public:
|
||||
@ -139,6 +139,38 @@ public:
|
||||
RELEASEOBJECT(m_cert);
|
||||
}
|
||||
|
||||
public:
|
||||
void AddInvalidType(const int type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case OOXML_SIGNATURE_INVALID:
|
||||
case OOXML_SIGNATURE_BAD:
|
||||
case OOXML_SIGNATURE_NOTSUPPORTED:
|
||||
{
|
||||
// critical
|
||||
m_valid = type;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
switch (m_valid)
|
||||
{
|
||||
case OOXML_SIGNATURE_INVALID:
|
||||
case OOXML_SIGNATURE_BAD:
|
||||
case OOXML_SIGNATURE_NOTSUPPORTED:
|
||||
{
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
m_valid = type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public:
|
||||
int GetValid()
|
||||
{
|
||||
@ -290,6 +322,64 @@ public:
|
||||
if (OPEN_SSL_WARNING_NOVERIFY == nCertVerify)
|
||||
m_valid = OOXML_SIGNATURE_INVALID;
|
||||
}
|
||||
|
||||
// 7) Test on partically
|
||||
if (m_valid == OOXML_SIGNATURE_VALID)
|
||||
{
|
||||
CSignFolderFiles oFiles;
|
||||
oFiles.Folder_Parse(m_pFolder, true);
|
||||
|
||||
// 1) Все рельсы должны быть подписаны - иначе подпись не валидна
|
||||
for (std::vector<std::wstring>::const_iterator i = oFiles.m_rels.begin(); i != oFiles.m_rels.end(); i++)
|
||||
{
|
||||
if (m_arFilesInManifest.find(*i) == m_arFilesInManifest.end())
|
||||
{
|
||||
m_valid = OOXML_SIGNATURE_INVALID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_valid == OOXML_SIGNATURE_VALID)
|
||||
{
|
||||
// 2) Парсим все рельсы
|
||||
for (std::vector<std::wstring>::const_iterator i = oFiles.m_rels.begin(); i != oFiles.m_rels.end(); i++)
|
||||
{
|
||||
std::wstring sFile = *i;
|
||||
|
||||
CManifestFileInfo oInfo;
|
||||
oInfo.m_pFolder = m_pFolder;
|
||||
oInfo.SetFilePath(sFile);
|
||||
|
||||
std::string sXml = m_pFolder->readXml(sFile);
|
||||
COOXMLRelationships _rels(sXml, &oInfo);
|
||||
|
||||
for (std::vector<COOXMLRelationship>::const_iterator relsIter = _rels.rels.begin(); relsIter != _rels.rels.end(); relsIter++)
|
||||
{
|
||||
const COOXMLRelationship& curRel = *relsIter;
|
||||
|
||||
if (curRel.target_mode == L"Internal" && !CSignFolderFiles::CheckNeedSign(curRel.target))
|
||||
continue;
|
||||
|
||||
std::wstring sFullPath = oInfo.GetHeadPath(curRel.target);
|
||||
|
||||
// если внутренний файл отсутствует - не валидная подпись
|
||||
if (curRel.target_mode == L"Internal")
|
||||
{
|
||||
if (!m_pFolder->exists(sFullPath))
|
||||
m_valid = OOXML_SIGNATURE_INVALID;
|
||||
else
|
||||
{
|
||||
// если файл в списке, но не подписан - то подпись частичная.
|
||||
if (m_arFilesInManifest.find(sFullPath) == m_arFilesInManifest.end())
|
||||
{
|
||||
AddInvalidType(OOXML_SIGNATURE_PARTIALLY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
XmlUtils::CXmlNode GetObjectById(std::string sId)
|
||||
@ -399,6 +489,7 @@ public:
|
||||
return OOXML_SIGNATURE_INVALID;
|
||||
|
||||
sFile = sFile.substr(0, nPos);
|
||||
m_arFilesInManifest.insert(sFile);
|
||||
|
||||
if (!m_pFolder->exists(sFile))
|
||||
return OOXML_SIGNATURE_INVALID;
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include "../../../common/File.h"
|
||||
#include "../../../common/Directory.h"
|
||||
#include "../../../../OfficeUtils/src/ZipFolder.h"
|
||||
#include <set>
|
||||
|
||||
class CManifestFileInfo
|
||||
{
|
||||
@ -38,7 +39,7 @@ public:
|
||||
|
||||
void CheckAliasExist(const std::wstring& sFile)
|
||||
{
|
||||
if (!m_pFolder->exists(m_sAliasDirectory + L"/" + sFile))
|
||||
if (!m_pFolder->exists(GetHeadPath(sFile)))
|
||||
++m_nCountUnexistedFile;
|
||||
}
|
||||
|
||||
@ -46,6 +47,11 @@ public:
|
||||
{
|
||||
return (0 != m_nCountUnexistedFile) ? true : false;
|
||||
}
|
||||
|
||||
std::wstring GetHeadPath(const std::wstring& sFile)
|
||||
{
|
||||
return m_sAliasDirectory + L"/" + sFile;
|
||||
}
|
||||
};
|
||||
|
||||
class COOXMLRelationship
|
||||
@ -117,7 +123,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
COOXMLRelationships(const std::string& xml, CManifestFileInfo* pFileInfo, std::map<std::wstring, bool>* check_need = NULL)
|
||||
COOXMLRelationships(const std::string& xml, CManifestFileInfo* pFileInfo, std::set<std::wstring>* check_need = NULL)
|
||||
{
|
||||
m_pFileInfo = pFileInfo;
|
||||
XmlUtils::CXmlNode oNode;
|
||||
@ -127,11 +133,11 @@ public:
|
||||
FromXmlNode(oNode, check_need);
|
||||
}
|
||||
|
||||
COOXMLRelationships(CManifestFileInfo* pFileInfo, std::map<std::wstring, bool>* check_need = NULL)
|
||||
COOXMLRelationships(CManifestFileInfo* pFileInfo, std::set<std::wstring>* check_need = NULL)
|
||||
{
|
||||
m_pFileInfo = pFileInfo;
|
||||
|
||||
if (!m_pFileInfo || NULL != m_pFileInfo->m_pFolder)
|
||||
if (!m_pFileInfo || NULL == m_pFileInfo->m_pFolder)
|
||||
return;
|
||||
|
||||
XmlUtils::CXmlNode oNode = m_pFileInfo->m_pFolder->getNodeFromFile(m_pFileInfo->GetFilePath());
|
||||
@ -141,7 +147,7 @@ public:
|
||||
FromXmlNode(oNode, check_need);
|
||||
}
|
||||
|
||||
void FromXmlNode(XmlUtils::CXmlNode& oNode, std::map<std::wstring, bool>* check_need = NULL)
|
||||
void FromXmlNode(XmlUtils::CXmlNode& oNode, std::set<std::wstring>* check_need = NULL)
|
||||
{
|
||||
XmlUtils::CXmlNodes oNodes;
|
||||
if (!oNode.GetNodes(L"Relationship", oNodes))
|
||||
|
||||
@ -28,7 +28,7 @@ class CXmlTransformRelationship : public IXmlTransform
|
||||
{
|
||||
protected:
|
||||
CManifestFileInfo* m_pManifestFileInfo;
|
||||
std::map<std::wstring, bool> m_arIds;
|
||||
std::set<std::wstring> m_arIds;
|
||||
|
||||
public:
|
||||
CXmlTransformRelationship(CManifestFileInfo* pManifestFileInfo) : IXmlTransform()
|
||||
@ -39,23 +39,7 @@ public:
|
||||
|
||||
virtual std::string Transform(const std::string& xml)
|
||||
{
|
||||
std::map<std::wstring, bool>* checker = &m_arIds;
|
||||
|
||||
// для некоторых путей не считаем валидными добавления в rels после подписи
|
||||
if (m_pManifestFileInfo)
|
||||
{
|
||||
std::wstring& sFile = m_pManifestFileInfo->GetFilePath();
|
||||
if (0 == sFile.find(L"/word/") ||
|
||||
0 == sFile.find(L"/ppt/") ||
|
||||
0 == sFile.find(L"/xl/"))
|
||||
{
|
||||
// https://bugzilla.onlyoffice.com/show_bug.cgi?id=59649
|
||||
checker = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
COOXMLRelationships _rels(xml, m_pManifestFileInfo, checker);
|
||||
COOXMLRelationships _rels(xml, m_pManifestFileInfo, &m_arIds);
|
||||
return U_TO_UTF8(_rels.GetXml());
|
||||
}
|
||||
|
||||
@ -72,7 +56,7 @@ public:
|
||||
|
||||
std::wstring sType = _node.GetAttribute("SourceId");
|
||||
if (!sType.empty())
|
||||
m_arIds.insert(std::pair<std::wstring, bool>(sType, true));
|
||||
m_arIds.insert(sType);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
99
DesktopEditor/xmlsec/src/src/common.h
Normal file
99
DesktopEditor/xmlsec/src/src/common.h
Normal file
@ -0,0 +1,99 @@
|
||||
#pragma once
|
||||
|
||||
#include "./../include/CertificateCommon.h"
|
||||
#include "../../../../OfficeUtils/src/ZipFolder.h"
|
||||
#include "./XmlTransform.h"
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
#include <time.h>
|
||||
|
||||
class CSignFolderFiles
|
||||
{
|
||||
public:
|
||||
std::map<std::wstring, std::wstring> m_content_types;
|
||||
std::vector<std::wstring> m_rels;
|
||||
std::vector<std::wstring> m_files;
|
||||
|
||||
public:
|
||||
CSignFolderFiles() {}
|
||||
~CSignFolderFiles() {}
|
||||
|
||||
public:
|
||||
static bool CheckNeedSign(const std::wstring& sCheckFile)
|
||||
{
|
||||
if (0 == sCheckFile.find(L"_xmlsignatures") ||
|
||||
0 == sCheckFile.find(L"docProps") ||
|
||||
0 == sCheckFile.find(L"[Content_Types].xml") ||
|
||||
0 == sCheckFile.find(L"[trash]"))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Folder_Parse(IFolder* pFolder, bool bIsAddSlash = false)
|
||||
{
|
||||
// 1) Parse files in directory
|
||||
std::vector<std::wstring> files = pFolder->getFiles(L"", true);
|
||||
|
||||
// 2) Check each file
|
||||
std::wstring sFolder = L"";
|
||||
for (std::vector<std::wstring>::iterator i = files.begin(); i != files.end(); i++)
|
||||
{
|
||||
std::wstring sCheckFile = *i;
|
||||
|
||||
// make cool filename
|
||||
sCheckFile = pFolder->getLocalFilePath(sCheckFile);
|
||||
|
||||
// check needed file
|
||||
if (!CheckNeedSign(sCheckFile))
|
||||
continue;
|
||||
|
||||
// check rels and add to needed array
|
||||
std::wstring::size_type posExt = sCheckFile.rfind(L".");
|
||||
if (std::wstring::npos == posExt)
|
||||
continue;
|
||||
|
||||
std::wstring sExt = sCheckFile.substr(posExt + 1);
|
||||
|
||||
if (bIsAddSlash)
|
||||
sCheckFile = L"/" + sCheckFile;
|
||||
|
||||
if (sExt == L"rels")
|
||||
m_rels.push_back(sCheckFile);
|
||||
else
|
||||
m_files.push_back(sCheckFile);
|
||||
}
|
||||
|
||||
std::sort(m_rels.begin(), m_rels.end());
|
||||
std::sort(m_files.begin(), m_files.end());
|
||||
}
|
||||
|
||||
void Folder_ParseContentTypes(IFolder* pFolder)
|
||||
{
|
||||
XmlUtils::CXmlNode oNode = pFolder->getNodeFromFile(L"/[Content_Types].xml");
|
||||
|
||||
XmlUtils::CXmlNodes nodesDefaults;
|
||||
oNode.GetNodes(L"Default", nodesDefaults);
|
||||
|
||||
XmlUtils::CXmlNodes nodesOverrides;
|
||||
oNode.GetNodes(L"Override", nodesOverrides);
|
||||
|
||||
int nCount = nodesDefaults.GetCount();
|
||||
for (int i = 0; i < nCount; ++i)
|
||||
{
|
||||
XmlUtils::CXmlNode node;
|
||||
nodesDefaults.GetAt(i, node);
|
||||
|
||||
m_content_types.insert(std::pair<std::wstring, std::wstring>(node.GetAttribute("Extension"), node.GetAttribute("ContentType")));
|
||||
}
|
||||
|
||||
nCount = nodesOverrides.GetCount();
|
||||
for (int i = 0; i < nCount; ++i)
|
||||
{
|
||||
XmlUtils::CXmlNode node;
|
||||
nodesOverrides.GetAt(i, node);
|
||||
|
||||
m_content_types.insert(std::pair<std::wstring, std::wstring>(node.GetAttribute("PartName"), node.GetAttribute("ContentType")));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user