summaryrefslogtreecommitdiffstats
path: root/xmlsecurity/source/helper
diff options
context:
space:
mode:
Diffstat (limited to 'xmlsecurity/source/helper')
-rw-r--r--xmlsecurity/source/helper/documentsignaturehelper.cxx63
-rw-r--r--xmlsecurity/source/helper/documentsignaturemanager.cxx12
-rw-r--r--xmlsecurity/source/helper/ooxmlsecexporter.cxx23
-rw-r--r--xmlsecurity/source/helper/ooxmlsecparser.cxx22
-rw-r--r--xmlsecurity/source/helper/pdfsignaturehelper.cxx8
-rw-r--r--xmlsecurity/source/helper/xmlsignaturehelper.cxx161
-rw-r--r--xmlsecurity/source/helper/xsecctl.cxx80
-rw-r--r--xmlsecurity/source/helper/xsecparser.cxx144
-rw-r--r--xmlsecurity/source/helper/xsecsign.cxx30
-rw-r--r--xmlsecurity/source/helper/xsecverify.cxx124
10 files changed, 499 insertions, 168 deletions
diff --git a/xmlsecurity/source/helper/documentsignaturehelper.cxx b/xmlsecurity/source/helper/documentsignaturehelper.cxx
index 1dda0be4d7f5..47e788b759bb 100644
--- a/xmlsecurity/source/helper/documentsignaturehelper.cxx
+++ b/xmlsecurity/source/helper/documentsignaturehelper.cxx
@@ -512,6 +512,29 @@ void DocumentSignatureHelper::writeDigestMethod(
xDocumentHandler->endElement("DigestMethod");
}
+static void WriteXadesCert(
+ uno::Reference<xml::sax::XDocumentHandler> const& xDocumentHandler,
+ SignatureInformation::X509CertInfo const& rCertInfo)
+{
+ xDocumentHandler->startElement("xd:Cert", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ xDocumentHandler->startElement("xd:CertDigest", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ DocumentSignatureHelper::writeDigestMethod(xDocumentHandler);
+ xDocumentHandler->startElement("DigestValue", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ assert(!rCertInfo.CertDigest.isEmpty());
+ xDocumentHandler->characters(rCertInfo.CertDigest);
+ xDocumentHandler->endElement("DigestValue");
+ xDocumentHandler->endElement("xd:CertDigest");
+ xDocumentHandler->startElement("xd:IssuerSerial", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ xDocumentHandler->startElement("X509IssuerName", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ xDocumentHandler->characters(rCertInfo.X509IssuerName);
+ xDocumentHandler->endElement("X509IssuerName");
+ xDocumentHandler->startElement("X509SerialNumber", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ xDocumentHandler->characters(rCertInfo.X509SerialNumber);
+ xDocumentHandler->endElement("X509SerialNumber");
+ xDocumentHandler->endElement("xd:IssuerSerial");
+ xDocumentHandler->endElement("xd:Cert");
+}
+
void DocumentSignatureHelper::writeSignedProperties(
const uno::Reference<xml::sax::XDocumentHandler>& xDocumentHandler,
const SignatureInformation& signatureInfo,
@@ -528,26 +551,26 @@ void DocumentSignatureHelper::writeSignedProperties(
xDocumentHandler->characters(sDate);
xDocumentHandler->endElement("xd:SigningTime");
xDocumentHandler->startElement("xd:SigningCertificate", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
- xDocumentHandler->startElement("xd:Cert", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
- xDocumentHandler->startElement("xd:CertDigest", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
- writeDigestMethod(xDocumentHandler);
-
- xDocumentHandler->startElement("DigestValue", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
- // TODO: this is empty for gpg signatures currently
- //assert(!signatureInfo.ouCertDigest.isEmpty());
- xDocumentHandler->characters(signatureInfo.ouCertDigest);
- xDocumentHandler->endElement("DigestValue");
-
- xDocumentHandler->endElement("xd:CertDigest");
- xDocumentHandler->startElement("xd:IssuerSerial", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
- xDocumentHandler->startElement("X509IssuerName", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
- xDocumentHandler->characters(signatureInfo.ouX509IssuerName);
- xDocumentHandler->endElement("X509IssuerName");
- xDocumentHandler->startElement("X509SerialNumber", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
- xDocumentHandler->characters(signatureInfo.ouX509SerialNumber);
- xDocumentHandler->endElement("X509SerialNumber");
- xDocumentHandler->endElement("xd:IssuerSerial");
- xDocumentHandler->endElement("xd:Cert");
+ assert(signatureInfo.GetSigningCertificate() || !signatureInfo.ouGpgKeyID.isEmpty());
+ if (signatureInfo.GetSigningCertificate())
+ {
+ // how should this deal with multiple X509Data elements?
+ // for now, let's write all of the certificates ...
+ for (auto const& rData : signatureInfo.X509Datas)
+ {
+ for (auto const& it : rData)
+ {
+ WriteXadesCert(xDocumentHandler, it);
+ }
+ }
+ }
+ else
+ {
+ // for PGP, write empty mandatory X509IssuerName, X509SerialNumber
+ SignatureInformation::X509CertInfo temp;
+ temp.CertDigest = signatureInfo.ouGpgKeyID;
+ WriteXadesCert(xDocumentHandler, temp);
+ }
xDocumentHandler->endElement("xd:SigningCertificate");
xDocumentHandler->startElement("xd:SignaturePolicyIdentifier", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
xDocumentHandler->startElement("xd:SignaturePolicyImplied", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
diff --git a/xmlsecurity/source/helper/documentsignaturemanager.cxx b/xmlsecurity/source/helper/documentsignaturemanager.cxx
index 5da6459779f7..ce3beef82a89 100644
--- a/xmlsecurity/source/helper/documentsignaturemanager.cxx
+++ b/xmlsecurity/source/helper/documentsignaturemanager.cxx
@@ -591,6 +591,18 @@ void DocumentSignatureManager::read(bool bUseTempStream, bool bCacheLastSignatur
bCacheLastSignature);
maSignatureHelper.EndMission();
+ // this parses the XML independently from ImplVerifySignatures() - check
+ // certificates here too ...
+ for (auto const& it : maSignatureHelper.GetSignatureInformations())
+ {
+ if (!it.X509Datas.empty())
+ {
+ uno::Reference<xml::crypto::XSecurityEnvironment> const xSecEnv(
+ getSecurityEnvironment());
+ maSignatureHelper.CheckAndUpdateSignatureInformation(xSecEnv, it);
+ }
+ }
+
maCurrentSignatureInformations = maSignatureHelper.GetSignatureInformations();
}
else
diff --git a/xmlsecurity/source/helper/ooxmlsecexporter.cxx b/xmlsecurity/source/helper/ooxmlsecexporter.cxx
index 42a4df0a7792..141ae49176ed 100644
--- a/xmlsecurity/source/helper/ooxmlsecexporter.cxx
+++ b/xmlsecurity/source/helper/ooxmlsecexporter.cxx
@@ -193,12 +193,23 @@ void OOXMLSecExporter::Impl::writeSignatureValue()
void OOXMLSecExporter::Impl::writeKeyInfo()
{
- m_xDocumentHandler->startElement("KeyInfo", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
- m_xDocumentHandler->startElement("X509Data", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
- m_xDocumentHandler->startElement("X509Certificate", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
- m_xDocumentHandler->characters(m_rInformation.ouX509Certificate);
- m_xDocumentHandler->endElement("X509Certificate");
- m_xDocumentHandler->endElement("X509Data");
+ m_xDocumentHandler->startElement(
+ "KeyInfo", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ assert(m_rInformation.GetSigningCertificate());
+ for (auto const& rData : m_rInformation.X509Datas)
+ {
+ m_xDocumentHandler->startElement(
+ "X509Data", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ for (auto const& it : rData)
+ {
+ m_xDocumentHandler->startElement(
+ "X509Certificate",
+ uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ m_xDocumentHandler->characters(it.X509Certificate);
+ m_xDocumentHandler->endElement("X509Certificate");
+ }
+ m_xDocumentHandler->endElement("X509Data");
+ }
m_xDocumentHandler->endElement("KeyInfo");
}
diff --git a/xmlsecurity/source/helper/ooxmlsecparser.cxx b/xmlsecurity/source/helper/ooxmlsecparser.cxx
index 1479a2ff0006..5d1f67f7deb1 100644
--- a/xmlsecurity/source/helper/ooxmlsecparser.cxx
+++ b/xmlsecurity/source/helper/ooxmlsecparser.cxx
@@ -184,9 +184,22 @@ void SAL_CALL OOXMLSecParser::endElement(const OUString& rName)
m_pXSecController->setSignatureValue(m_aSignatureValue);
m_bInSignatureValue = false;
}
+ else if (rName == "X509Data")
+ {
+ std::vector<std::pair<OUString, OUString>> X509IssuerSerials;
+ std::vector<OUString> X509Certificates;
+ if (!m_aX509Certificate.isEmpty())
+ {
+ X509Certificates.emplace_back(m_aX509Certificate);
+ }
+ if (!m_aX509IssuerName.isEmpty() && !m_aX509SerialNumber.isEmpty())
+ {
+ X509IssuerSerials.emplace_back(m_aX509IssuerName, m_aX509SerialNumber);
+ }
+ m_pXSecController->setX509Data(X509IssuerSerials, X509Certificates);
+ }
else if (rName == "X509Certificate")
{
- m_pXSecController->setX509Certificate(m_aX509Certificate);
m_bInX509Certificate = false;
}
else if (rName == "mdssi:Value")
@@ -201,17 +214,18 @@ void SAL_CALL OOXMLSecParser::endElement(const OUString& rName)
}
else if (rName == "X509IssuerName")
{
- m_pXSecController->setX509IssuerName(m_aX509IssuerName);
m_bInX509IssuerName = false;
}
else if (rName == "X509SerialNumber")
{
- m_pXSecController->setX509SerialNumber(m_aX509SerialNumber);
m_bInX509SerialNumber = false;
}
+ else if (rName == "xd:Cert")
+ {
+ m_pXSecController->setX509CertDigest(m_aCertDigest, css::xml::crypto::DigestID::SHA1, m_aX509IssuerName, m_aX509SerialNumber);
+ }
else if (rName == "xd:CertDigest")
{
- m_pXSecController->setCertDigest(m_aCertDigest);
m_bInCertDigest = false;
}
else if (rName == "Object")
diff --git a/xmlsecurity/source/helper/pdfsignaturehelper.cxx b/xmlsecurity/source/helper/pdfsignaturehelper.cxx
index 2aea01128869..d00021c9b633 100644
--- a/xmlsecurity/source/helper/pdfsignaturehelper.cxx
+++ b/xmlsecurity/source/helper/pdfsignaturehelper.cxx
@@ -86,8 +86,12 @@ PDFSignatureHelper::GetDocumentSignatureInformations(
security::DocumentSignatureInformation& rExternal = aRet[i];
rExternal.SignatureIsValid
= rInternal.nStatus == xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
- if (!rInternal.ouX509Certificate.isEmpty())
- rExternal.Signer = xSecEnv->createCertificateFromAscii(rInternal.ouX509Certificate);
+ if (rInternal.GetSigningCertificate()
+ && !rInternal.GetSigningCertificate()->X509Certificate.isEmpty())
+ {
+ rExternal.Signer = xSecEnv->createCertificateFromAscii(
+ rInternal.GetSigningCertificate()->X509Certificate);
+ }
rExternal.PartialDocumentSignature = rInternal.bPartialDocumentSignature;
// Verify certificate.
diff --git a/xmlsecurity/source/helper/xmlsignaturehelper.cxx b/xmlsecurity/source/helper/xmlsignaturehelper.cxx
index 7df65816acee..495a230d9277 100644
--- a/xmlsecurity/source/helper/xmlsignaturehelper.cxx
+++ b/xmlsecurity/source/helper/xmlsignaturehelper.cxx
@@ -21,6 +21,7 @@
#include <xmlsignaturehelper.hxx>
#include <documentsignaturehelper.hxx>
#include <xsecctl.hxx>
+#include <biginteger.hxx>
#include <xmlsignaturehelper2.hxx>
@@ -49,6 +50,8 @@
#include <tools/diagnose_ex.h>
#include <sal/log.hxx>
+#include <boost/optional.hpp>
+
#define NS_DOCUMENTSIGNATURES "http://openoffice.org/2004/documentsignatures"
#define NS_DOCUMENTSIGNATURES_ODF_1_2 "urn:oasis:names:tc:opendocument:xmlns:digitalsignature:1.0"
#define OOXML_SIGNATURE_ORIGIN "http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/origin"
@@ -556,4 +559,162 @@ void XMLSignatureHelper::CreateAndWriteOOXMLSignature(const uno::Reference<embed
xSaxWriter->endDocument();
}
+/** check this constraint from xmldsig-core 4.5.4:
+
+ All certificates appearing in an X509Data element MUST relate to the
+ validation key by either containing it or being part of a certification
+ chain that terminates in a certificate containing the validation key.
+ */
+static auto CheckX509Data(
+ uno::Reference<xml::crypto::XSecurityEnvironment> const& xSecEnv,
+ std::vector<SignatureInformation::X509CertInfo> const& rX509CertInfos,
+ std::vector<uno::Reference<security::XCertificate>> & rCerts,
+ std::vector<SignatureInformation::X509CertInfo> & rSorted) -> bool
+{
+ assert(rCerts.empty());
+ assert(rSorted.empty());
+ if (rX509CertInfos.empty())
+ {
+ SAL_WARN("xmlsecurity.comp", "no X509Data");
+ return false;
+ }
+ std::vector<uno::Reference<security::XCertificate>> certs;
+ for (SignatureInformation::X509CertInfo const& it : rX509CertInfos)
+ {
+ if (!it.X509Certificate.isEmpty())
+ {
+ certs.emplace_back(xSecEnv->createCertificateFromAscii(it.X509Certificate));
+ }
+ else
+ {
+ certs.emplace_back(xSecEnv->getCertificate(
+ it.X509IssuerName,
+ xmlsecurity::numericStringToBigInteger(it.X509SerialNumber)));
+ }
+ if (!certs.back().is())
+ {
+ SAL_WARN("xmlsecurity.comp", "X509Data cannot be parsed");
+ return false;
+ }
+ }
+
+ // first, search one whose issuer isn't in the list, or a self-signed one
+ boost::optional<size_t> start;
+ for (size_t i = 0; i < certs.size(); ++i)
+ {
+ for (size_t j = 0; ; ++j)
+ {
+ if (j == certs.size())
+ {
+ if (start)
+ {
+ SAL_WARN("xmlsecurity.comp", "X509Data do not form a chain: certificate has no issuer but already have start of chain: " << certs[i]->getSubjectName());
+ return false;
+ }
+ start = i; // issuer isn't in the list
+ break;
+ }
+ if (xmlsecurity::EqualDistinguishedNames(certs[i]->getIssuerName(), certs[j]->getSubjectName()))
+ {
+ if (i == j) // self signed
+ {
+ if (start)
+ {
+ SAL_WARN("xmlsecurity.comp", "X509Data do not form a chain: certificate is self-signed but already have start of chain: " << certs[i]->getSubjectName());
+ return false;
+ }
+ start = i;
+ }
+ break;
+ }
+ }
+ }
+ std::vector<size_t> chain;
+ if (!start)
+ {
+ // this can only be a cycle?
+ SAL_WARN("xmlsecurity.comp", "X509Data do not form a chain: cycle detected");
+ return false;
+ }
+ chain.emplace_back(*start);
+
+ // second, check that there is a chain, no tree or cycle...
+ for (size_t i = 0; i < certs.size(); ++i)
+ {
+ assert(chain.size() == i + 1);
+ for (size_t j = 0; j < certs.size(); ++j)
+ {
+ if (chain[i] != j)
+ {
+ if (xmlsecurity::EqualDistinguishedNames(
+ certs[chain[i]]->getSubjectName(), certs[j]->getIssuerName()))
+ {
+ if (chain.size() != i + 1) // already found issuee?
+ {
+ SAL_WARN("xmlsecurity.comp", "X509Data do not form a chain: certificate issued 2 others: " << certs[chain[i]]->getSubjectName());
+ return false;
+ }
+ chain.emplace_back(j);
+ }
+ }
+ }
+ if (i == certs.size() - 1)
+ { // last one: must be a leaf
+ if (chain.size() != i + 1)
+ {
+ SAL_WARN("xmlsecurity.comp", "X509Data do not form a chain: certificate in cycle: " << certs[chain[i]]->getSubjectName());
+ return false;
+ }
+ }
+ else if (chain.size() != i + 2)
+ { // not issuer of another?
+ SAL_WARN("xmlsecurity.comp", "X509Data do not form a chain: certificate issued 0 others: " << certs[chain[i]]->getSubjectName());
+ return false;
+ }
+ }
+
+ // success
+ assert(chain.size() == rX509CertInfos.size());
+ for (auto const& it : chain)
+ {
+ rSorted.emplace_back(rX509CertInfos[it]);
+ rCerts.emplace_back(certs[it]);
+ }
+ return true;
+}
+
+std::vector<uno::Reference<security::XCertificate>>
+XMLSignatureHelper::CheckAndUpdateSignatureInformation(
+ uno::Reference<xml::crypto::XSecurityEnvironment> const& xSecEnv,
+ SignatureInformation const& rInfo)
+{
+ // if the check fails, it's not possible to determine which X509Data
+ // contained the signing certificate - the UI cannot display something
+ // useful in this case, so prevent anything misleading by clearing the
+ // X509Datas.
+
+ std::vector<uno::Reference<security::XCertificate>> certs;
+ std::vector<SignatureInformation::X509Data> datas;
+ // TODO: for now, just merge all X509Datas together for checking...
+ // (this will probably break round-trip of signature with multiple X509Data,
+ // no idea if that is a problem)
+ SignatureInformation::X509Data temp;
+ SignatureInformation::X509Data tempResult;
+ for (auto const& rData : rInfo.X509Datas)
+ {
+ for (auto const& it : rData)
+ {
+ temp.emplace_back(it);
+ }
+ }
+ if (CheckX509Data(xSecEnv, temp, certs, tempResult))
+ {
+ datas.emplace_back(tempResult);
+ }
+
+ // rInfo is a copy, update the original
+ mpXSecController->UpdateSignatureInformation(rInfo.nSecurityId, datas);
+ return certs;
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/helper/xsecctl.cxx b/xmlsecurity/source/helper/xsecctl.cxx
index 76f3208c2eed..e87c8cafee56 100644
--- a/xmlsecurity/source/helper/xsecctl.cxx
+++ b/xmlsecurity/source/helper/xsecctl.cxx
@@ -739,7 +739,7 @@ void XSecController::exportSignature(
xDocumentHandler->startElement(
"PGPKeyID",
css::uno::Reference< css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
- xDocumentHandler->characters( signatureInfo.ouCertDigest );
+ xDocumentHandler->characters(signatureInfo.ouGpgKeyID);
xDocumentHandler->endElement( "PGPKeyID" );
/* Write PGPKeyPacket element */
@@ -763,43 +763,50 @@ void XSecController::exportSignature(
}
else
{
- /* Write X509Data element */
- xDocumentHandler->startElement(
- "X509Data",
- css::uno::Reference< css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
+ assert(signatureInfo.GetSigningCertificate());
+ for (auto const& rData : signatureInfo.X509Datas)
{
- /* Write X509IssuerSerial element */
+ /* Write X509Data element */
xDocumentHandler->startElement(
- "X509IssuerSerial",
+ "X509Data",
css::uno::Reference< css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
{
- /* Write X509IssuerName element */
- xDocumentHandler->startElement(
- "X509IssuerName",
- css::uno::Reference< css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
- xDocumentHandler->characters( signatureInfo.ouX509IssuerName );
- xDocumentHandler->endElement( "X509IssuerName" );
-
- /* Write X509SerialNumber element */
- xDocumentHandler->startElement(
- "X509SerialNumber",
- css::uno::Reference< css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
- xDocumentHandler->characters( signatureInfo.ouX509SerialNumber );
- xDocumentHandler->endElement( "X509SerialNumber" );
- }
- xDocumentHandler->endElement( "X509IssuerSerial" );
-
- /* Write X509Certificate element */
- if (!signatureInfo.ouX509Certificate.isEmpty())
- {
- xDocumentHandler->startElement(
- "X509Certificate",
- css::uno::Reference< css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
- xDocumentHandler->characters( signatureInfo.ouX509Certificate );
- xDocumentHandler->endElement( "X509Certificate" );
+ for (auto const& it : rData)
+ {
+ /* Write X509IssuerSerial element */
+ xDocumentHandler->startElement(
+ "X509IssuerSerial",
+ css::uno::Reference< css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
+ {
+ /* Write X509IssuerName element */
+ xDocumentHandler->startElement(
+ "X509IssuerName",
+ css::uno::Reference< css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
+ xDocumentHandler->characters(it.X509IssuerName);
+ xDocumentHandler->endElement( "X509IssuerName" );
+
+ /* Write X509SerialNumber element */
+ xDocumentHandler->startElement(
+ "X509SerialNumber",
+ css::uno::Reference< css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
+ xDocumentHandler->characters(it.X509SerialNumber);
+ xDocumentHandler->endElement( "X509SerialNumber" );
+ }
+ xDocumentHandler->endElement( "X509IssuerSerial" );
+
+ /* Write X509Certificate element */
+ if (!it.X509Certificate.isEmpty())
+ {
+ xDocumentHandler->startElement(
+ "X509Certificate",
+ css::uno::Reference< css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
+ xDocumentHandler->characters(it.X509Certificate);
+ xDocumentHandler->endElement( "X509Certificate" );
+ }
+ }
}
+ xDocumentHandler->endElement( "X509Data" );
}
- xDocumentHandler->endElement( "X509Data" );
}
}
xDocumentHandler->endElement( "KeyInfo" );
@@ -918,6 +925,15 @@ void XSecController::exportOOXMLSignature(const uno::Reference<embed::XStorage>&
aExporter.writeSignature();
}
+void XSecController::UpdateSignatureInformation(sal_Int32 const nSecurityId,
+ std::vector<SignatureInformation::X509Data> const& rDatas)
+{
+ SignatureInformation aInf( 0 );
+ int const nIndex = findSignatureInfor(nSecurityId);
+ assert(nIndex != -1); // nothing should touch this between parsing and verify
+ m_vInternalSignatureInformations[nIndex].signatureInfor.X509Datas = rDatas;
+}
+
SignatureInformation XSecController::getSignatureInformation( sal_Int32 nSecurityId ) const
{
SignatureInformation aInf( 0 );
diff --git a/xmlsecurity/source/helper/xsecparser.cxx b/xmlsecurity/source/helper/xsecparser.cxx
index 2ce46b1e18f1..1c8bf28ab287 100644
--- a/xmlsecurity/source/helper/xsecparser.cxx
+++ b/xmlsecurity/source/helper/xsecparser.cxx
@@ -244,98 +244,79 @@ class XSecParser::DsX509CertificateContext
: public XSecParser::Context
{
private:
- OUString m_Value;
+ OUString & m_rValue;
public:
DsX509CertificateContext(XSecParser & rParser,
- std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ OUString & rValue)
: XSecParser::Context(rParser, std::move(pOldNamespaceMap))
+ , m_rValue(rValue)
{
}
- virtual void EndElement() override
- {
- m_rParser.m_pXSecController->setX509Certificate(m_Value);
- }
-
virtual void Characters(OUString const& rChars) override
{
- m_Value += rChars;
+ m_rValue += rChars;
}
};
class XSecParser::DsX509SerialNumberContext
- : public XSecParser::ReferencedContextImpl
+ : public XSecParser::Context
{
private:
- OUString m_Value;
+ OUString & m_rValue;
public:
DsX509SerialNumberContext(XSecParser & rParser,
std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
- bool const isReferenced)
- : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
- {
- }
-
- virtual void EndElement() override
+ OUString & rValue)
+ : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
+ , m_rValue(rValue)
{
- if (m_isReferenced)
- {
- m_rParser.m_pXSecController->setX509SerialNumber(m_Value);
- }
- else
- {
- SAL_INFO("xmlsecurity.helper", "ignoring unsigned X509SerialNumber");
- }
}
virtual void Characters(OUString const& rChars) override
{
- m_Value += rChars;
+ m_rValue += rChars;
}
};
class XSecParser::DsX509IssuerNameContext
- : public XSecParser::ReferencedContextImpl
+ : public XSecParser::Context
{
private:
- OUString m_Value;
+ OUString & m_rValue;
public:
DsX509IssuerNameContext(XSecParser & rParser,
std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
- bool const isReferenced)
- : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
- {
- }
-
- virtual void EndElement() override
+ OUString & rValue)
+ : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
+ , m_rValue(rValue)
{
- if (m_isReferenced)
- {
- m_rParser.m_pXSecController->setX509IssuerName(m_Value);
- }
- else
- {
- SAL_INFO("xmlsecurity.helper", "ignoring unsigned X509IssuerName");
- }
}
virtual void Characters(OUString const& rChars) override
{
- m_Value += rChars;
+ m_rValue += rChars;
}
};
class XSecParser::DsX509IssuerSerialContext
- : public XSecParser::ReferencedContextImpl
+ : public XSecParser::Context
{
+ private:
+ OUString & m_rX509IssuerName;
+ OUString & m_rX509SerialNumber;
+
public:
DsX509IssuerSerialContext(XSecParser & rParser,
std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
- bool const isReferenced)
- : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
+ OUString & rIssuerName, OUString & rSerialNumber)
+ : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
+ , m_rX509IssuerName(rIssuerName)
+ , m_rX509SerialNumber(rSerialNumber)
{
}
@@ -345,20 +326,27 @@ class XSecParser::DsX509IssuerSerialContext
{
if (nNamespace == XML_NAMESPACE_DS && rName == "X509IssuerName")
{
- return std::make_unique<DsX509IssuerNameContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
+ return std::make_unique<DsX509IssuerNameContext>(m_rParser, std::move(pOldNamespaceMap), m_rX509IssuerName);
}
if (nNamespace == XML_NAMESPACE_DS && rName == "X509SerialNumber")
{
- return std::make_unique<DsX509SerialNumberContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
+ return std::make_unique<DsX509SerialNumberContext>(m_rParser, std::move(pOldNamespaceMap), m_rX509SerialNumber);
}
// missing: ds:X509SKI, ds:X509SubjectName, ds:X509CRL
return XSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
}
};
+/// can't be sure what is supposed to happen here because the spec is clear as mud
class XSecParser::DsX509DataContext
: public XSecParser::Context
{
+ private:
+ // sigh... "No ordering is implied by the above constraints."
+ // so store the ball of mud in vectors and try to figure it out later.
+ std::vector<std::pair<OUString, OUString>> m_X509IssuerSerials;
+ std::vector<OUString> m_X509Certificates;
+
public:
DsX509DataContext(XSecParser & rParser,
std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
@@ -366,18 +354,24 @@ class XSecParser::DsX509DataContext
{
}
+ virtual void EndElement() override
+ {
+ m_rParser.m_pXSecController->setX509Data(m_X509IssuerSerials, m_X509Certificates);
+ }
+
virtual std::unique_ptr<Context> CreateChildContext(
std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
sal_uInt16 const nNamespace, OUString const& rName) override
{
if (nNamespace == XML_NAMESPACE_DS && rName == "X509IssuerSerial")
{
- // can't require KeyInfo to be signed so pass in *true*
- return std::make_unique<DsX509IssuerSerialContext>(m_rParser, std::move(pOldNamespaceMap), true);
+ m_X509IssuerSerials.emplace_back();
+ return std::make_unique<DsX509IssuerSerialContext>(m_rParser, std::move(pOldNamespaceMap), m_X509IssuerSerials.back().first, m_X509IssuerSerials.back().second);
}
if (nNamespace == XML_NAMESPACE_DS && rName == "X509Certificate")
{
- return std::make_unique<DsX509CertificateContext>(m_rParser, std::move(pOldNamespaceMap));
+ m_X509Certificates.emplace_back();
+ return std::make_unique<DsX509CertificateContext>(m_rParser, std::move(pOldNamespaceMap), m_X509Certificates.back());
}
// missing: ds:X509SKI, ds:X509SubjectName, ds:X509CRL
return XSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
@@ -969,30 +963,20 @@ class XSecParser::LoSignatureLineContext
};
class XSecParser::XadesCertDigestContext
- : public XSecParser::ReferencedContextImpl
+ : public XSecParser::Context
{
private:
- OUString m_Value;
- sal_Int32 m_nReferenceDigestID = css::xml::crypto::DigestID::SHA1;
+ OUString & m_rDigestValue;
+ sal_Int32 & m_rReferenceDigestID;
public:
XadesCertDigestContext(XSecParser & rParser,
std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
- bool const isReferenced)
- : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
- {
- }
-
- virtual void EndElement() override
+ OUString & rDigestValue, sal_Int32 & rReferenceDigestID)
+ : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
+ , m_rDigestValue(rDigestValue)
+ , m_rReferenceDigestID(rReferenceDigestID)
{
- if (m_isReferenced)
- {
- m_rParser.m_pXSecController->setCertDigest(m_Value/* FIXME , m_nReferenceDigestID*/);
- }
- else
- {
- SAL_INFO("xmlsecurity.helper", "ignoring unsigned CertDigest");
- }
}
virtual std::unique_ptr<Context> CreateChildContext(
@@ -1001,11 +985,11 @@ class XSecParser::XadesCertDigestContext
{
if (nNamespace == XML_NAMESPACE_DS && rName == "DigestMethod")
{
- return std::make_unique<DsDigestMethodContext>(m_rParser, std::move(pOldNamespaceMap), m_nReferenceDigestID);
+ return std::make_unique<DsDigestMethodContext>(m_rParser, std::move(pOldNamespaceMap), m_rReferenceDigestID);
}
if (nNamespace == XML_NAMESPACE_DS && rName == "DigestValue")
{
- return std::make_unique<DsDigestValueContext>(m_rParser, std::move(pOldNamespaceMap), m_Value);
+ return std::make_unique<DsDigestValueContext>(m_rParser, std::move(pOldNamespaceMap), m_rDigestValue);
}
return XSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
}
@@ -1014,6 +998,12 @@ class XSecParser::XadesCertDigestContext
class XSecParser::XadesCertContext
: public XSecParser::ReferencedContextImpl
{
+ private:
+ sal_Int32 m_nReferenceDigestID = css::xml::crypto::DigestID::SHA1;
+ OUString m_CertDigest;
+ OUString m_X509IssuerName;
+ OUString m_X509SerialNumber;
+
public:
XadesCertContext(XSecParser & rParser,
std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
@@ -1022,17 +1012,29 @@ class XSecParser::XadesCertContext
{
}
+ virtual void EndElement() override
+ {
+ if (m_isReferenced)
+ {
+ m_rParser.m_pXSecController->setX509CertDigest(m_CertDigest, m_nReferenceDigestID, m_X509IssuerName, m_X509SerialNumber);
+ }
+ else
+ {
+ SAL_INFO("xmlsecurity.helper", "ignoring unsigned xades:Cert");
+ }
+ }
+
virtual std::unique_ptr<Context> CreateChildContext(
std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
sal_uInt16 const nNamespace, OUString const& rName) override
{
if (nNamespace == XML_NAMESPACE_XADES132 && rName == "CertDigest")
{
- return std::make_unique<XadesCertDigestContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
+ return std::make_unique<XadesCertDigestContext>(m_rParser, std::move(pOldNamespaceMap), m_CertDigest, m_nReferenceDigestID);
}
if (nNamespace == XML_NAMESPACE_XADES132 && rName == "IssuerSerial")
{
- return std::make_unique<DsX509IssuerSerialContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
+ return std::make_unique<DsX509IssuerSerialContext>(m_rParser, std::move(pOldNamespaceMap), m_X509IssuerName, m_X509SerialNumber);
}
return XSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
}
diff --git a/xmlsecurity/source/helper/xsecsign.cxx b/xmlsecurity/source/helper/xsecsign.cxx
index 370a3e4d0e65..fd6d5c9c8f24 100644
--- a/xmlsecurity/source/helper/xsecsign.cxx
+++ b/xmlsecurity/source/helper/xsecsign.cxx
@@ -198,6 +198,7 @@ void XSecController::signAStream( sal_Int32 securityId, const OUString& uri, boo
}
}
+// note: this is called when creating a new signature from scratch
void XSecController::setX509Certificate(
sal_Int32 nSecurityId,
const OUString& ouX509IssuerName,
@@ -211,10 +212,13 @@ void XSecController::setX509Certificate(
if ( index == -1 )
{
InternalSignatureInformation isi(nSecurityId, nullptr);
- isi.signatureInfor.ouX509IssuerName = ouX509IssuerName;
- isi.signatureInfor.ouX509SerialNumber = ouX509SerialNumber;
- isi.signatureInfor.ouX509Certificate = ouX509Cert;
- isi.signatureInfor.ouCertDigest = ouX509CertDigest;
+ isi.signatureInfor.X509Datas.clear();
+ isi.signatureInfor.X509Datas.emplace_back();
+ isi.signatureInfor.X509Datas.back().emplace_back();
+ isi.signatureInfor.X509Datas.back().back().X509IssuerName = ouX509IssuerName;
+ isi.signatureInfor.X509Datas.back().back().X509SerialNumber = ouX509SerialNumber;
+ isi.signatureInfor.X509Datas.back().back().X509Certificate = ouX509Cert;
+ isi.signatureInfor.X509Datas.back().back().CertDigest = ouX509CertDigest;
isi.signatureInfor.eAlgorithmID = eAlgorithmID;
m_vInternalSignatureInformations.push_back( isi );
}
@@ -222,16 +226,19 @@ void XSecController::setX509Certificate(
{
SignatureInformation &si
= m_vInternalSignatureInformations[index].signatureInfor;
- si.ouX509IssuerName = ouX509IssuerName;
- si.ouX509SerialNumber = ouX509SerialNumber;
- si.ouX509Certificate = ouX509Cert;
- si.ouCertDigest = ouX509CertDigest;
+ si.X509Datas.clear();
+ si.X509Datas.emplace_back();
+ si.X509Datas.back().emplace_back();
+ si.X509Datas.back().back().X509IssuerName = ouX509IssuerName;
+ si.X509Datas.back().back().X509SerialNumber = ouX509SerialNumber;
+ si.X509Datas.back().back().X509Certificate = ouX509Cert;
+ si.X509Datas.back().back().CertDigest = ouX509CertDigest;
}
}
void XSecController::setGpgCertificate(
sal_Int32 nSecurityId,
- const OUString& ouCertDigest,
+ const OUString& ouKeyDigest,
const OUString& ouCert,
const OUString& ouOwner)
{
@@ -242,16 +249,17 @@ void XSecController::setGpgCertificate(
InternalSignatureInformation isi(nSecurityId, nullptr);
isi.signatureInfor.ouGpgCertificate = ouCert;
isi.signatureInfor.ouGpgOwner = ouOwner;
- isi.signatureInfor.ouCertDigest = ouCertDigest;
+ isi.signatureInfor.ouGpgKeyID = ouKeyDigest;
m_vInternalSignatureInformations.push_back( isi );
}
else
{
SignatureInformation &si
= m_vInternalSignatureInformations[index].signatureInfor;
+ si.X509Datas.clear(); // it is a PGP signature now
si.ouGpgCertificate = ouCert;
si.ouGpgOwner = ouOwner;
- si.ouCertDigest = ouCertDigest;
+ si.ouGpgKeyID = ouKeyDigest;
}
}
diff --git a/xmlsecurity/source/helper/xsecverify.cxx b/xmlsecurity/source/helper/xsecverify.cxx
index fa6f2a3d2d2e..eca94d82c768 100644
--- a/xmlsecurity/source/helper/xsecverify.cxx
+++ b/xmlsecurity/source/helper/xsecverify.cxx
@@ -22,6 +22,7 @@
#include <xsecctl.hxx>
#include "xsecparser.hxx"
#include "ooxmlsecparser.hxx"
+#include <biginteger.hxx>
#include <framework/signatureverifierimpl.hxx>
#include <framework/saxeventkeeperimpl.hxx>
#include <gpg/xmlsignature_gpgimpl.hxx>
@@ -241,7 +242,9 @@ void XSecController::setReferenceCount() const
}
}
-void XSecController::setX509IssuerName( OUString const & ouX509IssuerName )
+void XSecController::setX509Data(
+ std::vector<std::pair<OUString, OUString>> & rX509IssuerSerials,
+ std::vector<OUString> const& rX509Certificates)
{
if (m_vInternalSignatureInformations.empty())
{
@@ -249,29 +252,52 @@ void XSecController::setX509IssuerName( OUString const & ouX509IssuerName )
return;
}
InternalSignatureInformation &isi = m_vInternalSignatureInformations.back();
- isi.signatureInfor.ouX509IssuerName = ouX509IssuerName;
-}
-
-void XSecController::setX509SerialNumber( OUString const & ouX509SerialNumber )
-{
- if (m_vInternalSignatureInformations.empty())
+ SignatureInformation::X509Data data;
+ // due to the excessive flexibility of the spec it's possible that there
+ // is both a reference to a cert and the cert itself in one X509Data
+ for (OUString const& it : rX509Certificates)
{
- SAL_INFO("xmlsecurity.helper","XSecController::setX509SerialNumber: no signature");
- return;
+ try
+ {
+ data.emplace_back();
+ data.back().X509Certificate = it;
+ uno::Reference<xml::crypto::XSecurityEnvironment> const xSecEnv(m_xSecurityContext->getSecurityEnvironment());
+ uno::Reference<security::XCertificate> const xCert(xSecEnv->createCertificateFromAscii(it));
+ if (!xCert.is())
+ {
+ SAL_INFO("xmlsecurity.helper", "cannot parse X509Certificate");
+ continue; // will be handled in CheckX509Data
+ }
+ OUString const issuerName(xCert->getIssuerName());
+ OUString const serialNumber(xmlsecurity::bigIntegerToNumericString(xCert->getSerialNumber()));
+ auto const iter = std::find_if(rX509IssuerSerials.begin(), rX509IssuerSerials.end(),
+ [&](auto const& rX509IssuerSerial) {
+ return xmlsecurity::EqualDistinguishedNames(issuerName, rX509IssuerSerial.first)
+ && serialNumber == rX509IssuerSerial.second;
+ });
+ if (iter != rX509IssuerSerials.end())
+ {
+ data.back().X509IssuerName = iter->first;
+ data.back().X509SerialNumber = iter->second;
+ rX509IssuerSerials.erase(iter);
+ }
+ }
+ catch (uno::Exception const&)
+ {
+ SAL_INFO("xmlsecurity.helper", "cannot parse X509Certificate");
+ }
}
- InternalSignatureInformation &isi = m_vInternalSignatureInformations.back();
- isi.signatureInfor.ouX509SerialNumber = ouX509SerialNumber;
-}
-
-void XSecController::setX509Certificate( OUString const & ouX509Certificate )
-{
- if (m_vInternalSignatureInformations.empty())
+ // now handle any that are left...
+ for (auto const& it : rX509IssuerSerials)
{
- SAL_INFO("xmlsecurity.helper","XSecController::setX509Certificate: no signature");
- return;
+ data.emplace_back();
+ data.back().X509IssuerName = it.first;
+ data.back().X509SerialNumber = it.second;
+ }
+ if (!data.empty())
+ {
+ isi.signatureInfor.X509Datas.push_back(data);
}
- InternalSignatureInformation &isi = m_vInternalSignatureInformations.back();
- isi.signatureInfor.ouX509Certificate = ouX509Certificate;
}
void XSecController::setSignatureValue( OUString const & ouSignatureValue )
@@ -381,13 +407,67 @@ void XSecController::setSignatureBytes(const uno::Sequence<sal_Int8>& rBytes)
rInformation.signatureInfor.aSignatureBytes = rBytes;
}
-void XSecController::setCertDigest(const OUString& rCertDigest)
+void XSecController::setX509CertDigest(
+ OUString const& rCertDigest, sal_Int32 const /*TODO nReferenceDigestID*/,
+ OUString const& rX509IssuerName, OUString const& rX509SerialNumber)
{
if (m_vInternalSignatureInformations.empty())
return;
InternalSignatureInformation& rInformation = m_vInternalSignatureInformations.back();
- rInformation.signatureInfor.ouCertDigest = rCertDigest;
+ for (auto & rData : rInformation.signatureInfor.X509Datas)
+ {
+ for (auto & it : rData)
+ {
+ if (xmlsecurity::EqualDistinguishedNames(it.X509IssuerName, rX509IssuerName)
+ && it.X509SerialNumber == rX509SerialNumber)
+ {
+ it.CertDigest = rCertDigest;
+ return;
+ }
+ }
+ }
+ // fall-back: read the actual certificates
+ for (auto & rData : rInformation.signatureInfor.X509Datas)
+ {
+ for (auto & it : rData)
+ {
+ if (!it.X509Certificate.isEmpty())
+ {
+ try
+ {
+ uno::Reference<xml::crypto::XSecurityEnvironment> const xSecEnv(m_xSecurityContext->getSecurityEnvironment());
+ uno::Reference<security::XCertificate> const xCert(xSecEnv->createCertificateFromAscii(it.X509Certificate));
+ if (!xCert.is())
+ {
+ SAL_INFO("xmlsecurity.helper", "cannot parse X509Certificate");
+ }
+ else if (xmlsecurity::EqualDistinguishedNames(xCert->getIssuerName(),rX509IssuerName)
+ && xmlsecurity::bigIntegerToNumericString(xCert->getSerialNumber()) == rX509SerialNumber)
+ {
+ it.CertDigest = rCertDigest;
+ // note: testInsertCertificate_PEM_DOCX requires these!
+ it.X509SerialNumber = rX509SerialNumber;
+ it.X509IssuerName = rX509IssuerName;
+ return;
+ }
+ }
+ catch (uno::Exception const&)
+ {
+ SAL_INFO("xmlsecurity.helper", "cannot parse X509Certificate");
+ }
+ }
+ }
+ }
+ if (!rInformation.signatureInfor.ouGpgCertificate.isEmpty())
+ {
+ SAL_INFO_IF(rCertDigest != rInformation.signatureInfor.ouGpgKeyID,
+ "xmlsecurity.helper", "PGPKeyID vs CertDigest mismatch");
+ }
+ else
+ {
+ SAL_INFO("xmlsecurity.helper", "cannot find X509Data for CertDigest");
+ }
}
namespace {