You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2121 lines
91 KiB
2121 lines
91 KiB
From b970e561433f1cbeebd43c92c92c98c0468cc483 Mon Sep 17 00:00:00 2001
|
|
From: Michael Stahl <michael.stahl@allotropia.de>
|
|
Date: Fri, 19 Feb 2021 17:56:21 +0100
|
|
Subject: [PATCH 5/6] CVE-2021-25633
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
xmlsecurity: ignore elements in ds:Object that aren't signed
|
|
|
|
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111253
|
|
Tested-by: Jenkins
|
|
Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
|
|
(cherry picked from commit 2bfa00e6bf4b2a310a8b8f5060acec85b5f7a3ce)
|
|
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111909
|
|
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
|
|
(cherry picked from commit 94ce59dd02fcfcaa1eb4f195b45a9a2edbd58242)
|
|
|
|
Change-Id: I2e4411f0907b89e7ad6e0185cee8f12b600515e8
|
|
|
|
xmlsecurity: improve handling of multiple X509Data elements
|
|
|
|
Combine everything related to a certificate in a new struct X509Data.
|
|
|
|
The CertDigest is not actually written in the X509Data element but in
|
|
xades:Cert, so try to find the matching entry in
|
|
XSecController::setX509CertDigest().
|
|
|
|
There was a confusing interaction with PGP signatures, where ouGpgKeyID
|
|
was used for import, but export wrote the value from ouCertDigest
|
|
instead - this needed fixing.
|
|
|
|
The main point of this is enforcing a 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.
|
|
|
|
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111254
|
|
Tested-by: Jenkins
|
|
Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
|
|
(cherry picked from commit 9e82509b09f5fe2eb77bcdb8fd193c71923abb67)
|
|
|
|
xmlsecurity: improve handling of multiple certificates per X509Data
|
|
|
|
It turns out that an X509Data element can contain an arbitrary number of
|
|
each of its child elements.
|
|
|
|
How exactly certificates of an issuer chain may or should be distributed
|
|
across multiple X509Data elements isn't terribly obvious.
|
|
|
|
One thing that is clear is that any element that refers to or contains
|
|
one particular certificate has to be a child of the same X509Data
|
|
element, although in no particular order, so try to match the 2 such
|
|
elements that the parser supports in XSecController::setX509Data().
|
|
|
|
Presumably the only way it makes sense to have multiple signing
|
|
certificates is if they all contain the same key but are signed by
|
|
different CAs. This case isn't handled currently; CheckX509Data() will
|
|
complain there's not a single chain and validation of the certificates
|
|
will fail.
|
|
|
|
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111500
|
|
Tested-by: Jenkins
|
|
Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
|
|
(cherry picked from commit 5af5ea893bcb8a8eb472ac11133da10e5a604e66)
|
|
|
|
xmlsecurity: add EqualDistinguishedNames()
|
|
|
|
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111545
|
|
Tested-by: Jenkins
|
|
Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
|
|
(cherry picked from commit 1d3da3486d827dd5e7a3bf1c7a533f5aa9860e42)
|
|
|
|
xmlsecurity: avoid exception in DigitalSignaturesDialog::getCertificate()
|
|
|
|
Fallback to PGP if there's no X509 signing certificate because
|
|
CheckX509Data() failed prevents the dialog from popping up.
|
|
|
|
To avoid confusing the user in this situation, the dialog should
|
|
show no certificate, which is already the case.
|
|
|
|
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111664
|
|
Tested-by: Jenkins
|
|
Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
|
|
(cherry picked from commit 90b725675c2964f4a151d802d9afedd8bc2ae1a7)
|
|
|
|
xmlsecurity: fix crash in DocumentDigitalSignatures::isAuthorTrusted()
|
|
|
|
If the argument is null.
|
|
|
|
This function also should use EqualDistinguishedNames().
|
|
|
|
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111667
|
|
Tested-by: Jenkins
|
|
Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
|
|
(cherry picked from commit ca98e505cd69bf95d8ddb9387cf3f8e03ae4577d)
|
|
|
|
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111910
|
|
Tested-by: Jenkins
|
|
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
|
|
(cherry picked from commit a1cf770c2d7ca3e153e0b1f01ddcc313bc2bed7f)
|
|
|
|
Change-Id: I9633a980b0c18d58dfce24fc59396a833498a77d
|
|
---
|
|
include/svl/sigstruct.hxx | 32 +-
|
|
svl/source/crypto/cryptosign.cxx | 16 +-
|
|
sw/source/core/edit/edfcol.cxx | 3 +-
|
|
xmlsecurity/inc/biginteger.hxx | 3 +
|
|
xmlsecurity/inc/xmlsignaturehelper.hxx | 12 +
|
|
xmlsecurity/inc/xsecctl.hxx | 15 +-
|
|
.../component/documentdigitalsignatures.cxx | 54 +--
|
|
.../dialogs/digitalsignaturesdialog.cxx | 15 +-
|
|
.../source/helper/documentsignaturehelper.cxx | 63 ++--
|
|
.../helper/documentsignaturemanager.cxx | 12 +
|
|
.../source/helper/ooxmlsecexporter.cxx | 23 +-
|
|
xmlsecurity/source/helper/ooxmlsecparser.cxx | 22 +-
|
|
.../source/helper/pdfsignaturehelper.cxx | 8 +-
|
|
.../source/helper/xmlsignaturehelper.cxx | 161 +++++++++
|
|
xmlsecurity/source/helper/xsecctl.cxx | 84 +++--
|
|
xmlsecurity/source/helper/xsecparser.cxx | 334 ++++++++++++------
|
|
xmlsecurity/source/helper/xsecparser.hxx | 1 +
|
|
xmlsecurity/source/helper/xsecsign.cxx | 30 +-
|
|
xmlsecurity/source/helper/xsecverify.cxx | 143 ++++++--
|
|
.../mscrypt/x509certificate_mscryptimpl.cxx | 47 +++
|
|
.../mscrypt/xmlsignature_mscryptimpl.cxx | 2 +
|
|
.../xmlsec/nss/x509certificate_nssimpl.cxx | 25 ++
|
|
.../xmlsec/nss/xmlsignature_nssimpl.cxx | 3 +
|
|
23 files changed, 853 insertions(+), 255 deletions(-)
|
|
|
|
diff --git a/include/svl/sigstruct.hxx b/include/svl/sigstruct.hxx
|
|
index 7a0296fa9fae..f00cbce6e4b8 100644
|
|
--- a/include/svl/sigstruct.hxx
|
|
+++ b/include/svl/sigstruct.hxx
|
|
@@ -89,9 +89,30 @@ struct SignatureInformation
|
|
sal_Int32 nSecurityId;
|
|
css::xml::crypto::SecurityOperationStatus nStatus;
|
|
SignatureReferenceInformations vSignatureReferenceInfors;
|
|
- OUString ouX509IssuerName;
|
|
- OUString ouX509SerialNumber;
|
|
- OUString ouX509Certificate;
|
|
+ struct X509CertInfo
|
|
+ {
|
|
+ OUString X509IssuerName;
|
|
+ OUString X509SerialNumber;
|
|
+ OUString X509Certificate;
|
|
+ /// OOXML certificate SHA-256 digest, empty for ODF except when doing XAdES signature.
|
|
+ OUString CertDigest;
|
|
+ /// The certificate owner (aka subject).
|
|
+ OUString X509Subject;
|
|
+ };
|
|
+ typedef std::vector<X509CertInfo> X509Data;
|
|
+ // note: at parse time, it's unkown which one is the signing certificate;
|
|
+ // ImplVerifySignatures() figures it out and puts it at the back
|
|
+ std::vector<X509Data> X509Datas;
|
|
+
|
|
+ X509CertInfo const* GetSigningCertificate() const
|
|
+ {
|
|
+ if (X509Datas.empty())
|
|
+ {
|
|
+ return nullptr;
|
|
+ }
|
|
+ assert(!X509Datas.back().empty());
|
|
+ return & X509Datas.back().back();
|
|
+ }
|
|
|
|
OUString ouGpgKeyID;
|
|
OUString ouGpgCertificate;
|
|
@@ -124,8 +145,6 @@ struct SignatureInformation
|
|
OUString ouDescription;
|
|
/// The Id attribute of the <SignatureProperty> element that contains the <dc:description>.
|
|
OUString ouDescriptionPropertyId;
|
|
- /// OOXML certificate SHA-256 digest, empty for ODF except when doing XAdES signature.
|
|
- OUString ouCertDigest;
|
|
/// Valid and invalid signature line images
|
|
css::uno::Reference<css::graphic::XGraphic> aValidSignatureImage;
|
|
css::uno::Reference<css::graphic::XGraphic> aInvalidSignatureImage;
|
|
@@ -140,9 +159,6 @@ struct SignatureInformation
|
|
/// For PDF: the byte range doesn't cover the whole document.
|
|
bool bPartialDocumentSignature;
|
|
|
|
- /// The certificate owner (aka subject).
|
|
- OUString ouSubject;
|
|
-
|
|
svl::crypto::SignatureMethodAlgorithm eAlgorithmID;
|
|
|
|
SignatureInformation( sal_Int32 nId )
|
|
diff --git a/svl/source/crypto/cryptosign.cxx b/svl/source/crypto/cryptosign.cxx
|
|
index 5a3f0271c40d..1b882bb89deb 100644
|
|
--- a/svl/source/crypto/cryptosign.cxx
|
|
+++ b/svl/source/crypto/cryptosign.cxx
|
|
@@ -2097,8 +2097,12 @@ bool Signing::Verify(const std::vector<unsigned char>& aData,
|
|
aDerCert[i] = pCertificate->derCert.data[i];
|
|
OUStringBuffer aBuffer;
|
|
comphelper::Base64::encode(aBuffer, aDerCert);
|
|
- rInformation.ouX509Certificate = aBuffer.makeStringAndClear();
|
|
- rInformation.ouSubject = OUString(pCertificate->subjectName, PL_strlen(pCertificate->subjectName), RTL_TEXTENCODING_UTF8);
|
|
+ SignatureInformation::X509Data temp;
|
|
+ temp.emplace_back();
|
|
+ temp.back().X509Certificate = aBuffer.makeStringAndClear();
|
|
+ temp.back().X509Subject = OUString(pCertificate->subjectName, PL_strlen(pCertificate->subjectName), RTL_TEXTENCODING_UTF8);
|
|
+ rInformation.X509Datas.clear();
|
|
+ rInformation.X509Datas.emplace_back(temp);
|
|
}
|
|
|
|
PRTime nSigningTime;
|
|
@@ -2277,8 +2281,12 @@ bool Signing::Verify(const std::vector<unsigned char>& aData,
|
|
aDerCert[i] = pSignerCertContext->pbCertEncoded[i];
|
|
OUStringBuffer aBuffer;
|
|
comphelper::Base64::encode(aBuffer, aDerCert);
|
|
- rInformation.ouX509Certificate = aBuffer.makeStringAndClear();
|
|
- rInformation.ouSubject = GetSubjectName(pSignerCertContext);
|
|
+ SignatureInformation::X509Data temp;
|
|
+ temp.emplace_back();
|
|
+ temp.back().X509Certificate = aBuffer.makeStringAndClear();
|
|
+ temp.back().X509Subject = GetSubjectName(pSignerCertContext);
|
|
+ rInformation.X509Datas.clear();
|
|
+ rInformation.X509Datas.emplace_back(temp);
|
|
}
|
|
|
|
if (bNonDetached)
|
|
diff --git a/sw/source/core/edit/edfcol.cxx b/sw/source/core/edit/edfcol.cxx
|
|
index 2b49ee16ecc8..abbed5e40e94 100644
|
|
--- a/sw/source/core/edit/edfcol.cxx
|
|
+++ b/sw/source/core/edit/edfcol.cxx
|
|
@@ -411,7 +411,8 @@ std::pair<bool, OUString> lcl_MakeParagraphSignatureFieldText(const SignatureDes
|
|
valid = valid
|
|
&& aInfo.nStatus == xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
|
|
|
|
- msg = SwResId(STR_SIGNED_BY) + ": " + aInfo.ouSubject + ", " +
|
|
+ assert(aInfo.GetSigningCertificate()); // it was valid
|
|
+ msg = SwResId(STR_SIGNED_BY) + ": " + aInfo.GetSigningCertificate()->X509Subject + ", " +
|
|
aDescr.msDate;
|
|
msg += (!aDescr.msUsage.isEmpty() ? (" (" + aDescr.msUsage + "): ") : OUString(": "));
|
|
msg += (valid ? SwResId(STR_VALID) : SwResId(STR_INVALID));
|
|
diff --git a/xmlsecurity/inc/biginteger.hxx b/xmlsecurity/inc/biginteger.hxx
|
|
index d07ecf45d8af..8b4d8a9143b5 100644
|
|
--- a/xmlsecurity/inc/biginteger.hxx
|
|
+++ b/xmlsecurity/inc/biginteger.hxx
|
|
@@ -31,6 +31,9 @@ namespace xmlsecurity
|
|
{
|
|
XSECXMLSEC_DLLPUBLIC OUString bigIntegerToNumericString( const css::uno::Sequence< sal_Int8 >& serial );
|
|
XSECXMLSEC_DLLPUBLIC css::uno::Sequence< sal_Int8 > numericStringToBigInteger ( const OUString& serialNumber );
|
|
+
|
|
+XSECXMLSEC_DLLPUBLIC bool EqualDistinguishedNames(OUString const& rName1,
|
|
+ OUString const& rName2);
|
|
}
|
|
|
|
#endif
|
|
diff --git a/xmlsecurity/inc/xmlsignaturehelper.hxx b/xmlsecurity/inc/xmlsignaturehelper.hxx
|
|
index 0fcbd665251f..2456ddd437ec 100644
|
|
--- a/xmlsecurity/inc/xmlsignaturehelper.hxx
|
|
+++ b/xmlsecurity/inc/xmlsignaturehelper.hxx
|
|
@@ -28,6 +28,9 @@
|
|
#include "xmlsignaturehelper.hxx"
|
|
#include "xsecctl.hxx"
|
|
|
|
+#include <com/sun/star/security/XCertificate.hpp>
|
|
+#include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp>
|
|
+
|
|
class DateTime;
|
|
class UriBindingHelper;
|
|
|
|
@@ -93,6 +96,15 @@ public:
|
|
// After signing/verifying, get information about signatures
|
|
SignatureInformation GetSignatureInformation( sal_Int32 nSecurityId ) const;
|
|
SignatureInformations GetSignatureInformations() const;
|
|
+ /// ImplVerifySignature calls this to figure out which X509Data is the
|
|
+ /// signing certificate and update the internal state with the result.
|
|
+ /// @return
|
|
+ /// A sequence with the signing certificate at the back on success.
|
|
+ /// An empty sequence on failure.
|
|
+ std::vector<css::uno::Reference<css::security::XCertificate>>
|
|
+ CheckAndUpdateSignatureInformation(
|
|
+ css::uno::Reference<css::xml::crypto::XSecurityEnvironment> const& xSecEnv,
|
|
+ SignatureInformation const& rInfo);
|
|
|
|
// See XSecController for documentation
|
|
void StartMission(const css::uno::Reference<css::xml::crypto::XXMLSecurityContext>& xSecurityContext);
|
|
diff --git a/xmlsecurity/inc/xsecctl.hxx b/xmlsecurity/inc/xsecctl.hxx
|
|
index 7baa219fb13c..7ce35cea22bf 100644
|
|
--- a/xmlsecurity/inc/xsecctl.hxx
|
|
+++ b/xmlsecurity/inc/xsecctl.hxx
|
|
@@ -252,6 +252,7 @@ private:
|
|
/// Sets algorithm from <SignatureMethod Algorithm="...">.
|
|
void setSignatureMethod(svl::crypto::SignatureMethodAlgorithm eAlgorithmID);
|
|
void switchGpgSignature();
|
|
+ bool haveReferenceForId(OUString const& rId) const;
|
|
void addReference(
|
|
const OUString& ouUri,
|
|
sal_Int32 nDigestID,
|
|
@@ -262,9 +263,13 @@ private:
|
|
sal_Int32 nDigestID );
|
|
void setReferenceCount() const;
|
|
|
|
- void setX509IssuerName( OUString const & ouX509IssuerName );
|
|
- void setX509SerialNumber( OUString const & ouX509SerialNumber );
|
|
- void setX509Certificate( OUString const & ouX509Certificate );
|
|
+ void setX509Data(
|
|
+ std::vector<std::pair<OUString, OUString>> & rX509IssuerSerials,
|
|
+ std::vector<OUString> const& rX509Certificates);
|
|
+ void setX509CertDigest(
|
|
+ OUString const& rCertDigest, sal_Int32 const nReferenceDigestID,
|
|
+ OUString const& rX509IssuerName, OUString const& rX509SerialNumber);
|
|
+
|
|
void setSignatureValue( OUString const & ouSignatureValue );
|
|
void setDigestValue( sal_Int32 nDigestID, OUString const & ouDigestValue );
|
|
void setGpgKeyID( OUString const & ouKeyID );
|
|
@@ -273,7 +278,6 @@ private:
|
|
|
|
void setDate(OUString const& rId, OUString const& ouDate);
|
|
void setDescription(OUString const& rId, OUString const& rDescription);
|
|
- void setCertDigest(const OUString& rCertDigest);
|
|
void setValidSignatureImage(const OUString& rValidSigImg);
|
|
void setInvalidSignatureImage(const OUString& rInvalidSigImg);
|
|
void setSignatureLineId(const OUString& rSignatureLineId);
|
|
@@ -302,6 +306,9 @@ public:
|
|
|
|
SignatureInformation getSignatureInformation( sal_Int32 nSecurityId ) const;
|
|
SignatureInformations getSignatureInformations() const;
|
|
+ /// only verify can figure out which X509Data is the signing certificate
|
|
+ void UpdateSignatureInformation(sal_Int32 nSecurityId,
|
|
+ std::vector<SignatureInformation::X509Data> const& rDatas);
|
|
|
|
static void exportSignature(
|
|
const css::uno::Reference< css::xml::sax::XDocumentHandler >& xDocumentHandler,
|
|
diff --git a/xmlsecurity/source/component/documentdigitalsignatures.cxx b/xmlsecurity/source/component/documentdigitalsignatures.cxx
|
|
index 52cb938a8e0a..8a5bf37a0432 100644
|
|
--- a/xmlsecurity/source/component/documentdigitalsignatures.cxx
|
|
+++ b/xmlsecurity/source/component/documentdigitalsignatures.cxx
|
|
@@ -510,30 +510,36 @@ DocumentDigitalSignatures::ImplVerifySignatures(
|
|
const SignatureInformation& rInfo = aSignInfos[n];
|
|
css::security::DocumentSignatureInformation& rSigInfo = arInfos[n];
|
|
|
|
- if (rInfo.ouGpgCertificate.isEmpty()) // X.509
|
|
+ if (!rInfo.X509Datas.empty()) // X.509
|
|
{
|
|
- if (!rInfo.ouX509Certificate.isEmpty())
|
|
- rSigInfo.Signer = xSecEnv->createCertificateFromAscii(rInfo.ouX509Certificate);
|
|
- if (!rSigInfo.Signer.is())
|
|
- rSigInfo.Signer = xSecEnv->getCertificate(
|
|
- rInfo.ouX509IssuerName,
|
|
- xmlsecurity::numericStringToBigInteger(rInfo.ouX509SerialNumber));
|
|
-
|
|
- // On Windows checking the certificate path is buggy. It does name matching (issuer, subject name)
|
|
- // to find the parent certificate. It does not take into account that there can be several certificates
|
|
- // with the same subject name.
|
|
- try
|
|
+ std::vector<uno::Reference<XCertificate>> certs(
|
|
+ rSignatureHelper.CheckAndUpdateSignatureInformation(
|
|
+ xSecEnv, rInfo));
|
|
+ if (certs.empty())
|
|
{
|
|
- rSigInfo.CertificateStatus = xSecEnv->verifyCertificate(
|
|
- rSigInfo.Signer, Sequence<Reference<css::security::XCertificate>>());
|
|
+ rSigInfo.CertificateStatus = css::security::CertificateValidity::INVALID;
|
|
}
|
|
- catch (SecurityException&)
|
|
+ else
|
|
{
|
|
- OSL_FAIL("Verification of certificate failed");
|
|
- rSigInfo.CertificateStatus = css::security::CertificateValidity::INVALID;
|
|
+ rSigInfo.Signer = certs.back();
|
|
+ // get only intermediates
|
|
+ certs.pop_back();
|
|
+ // On Windows checking the certificate path is buggy. It does name matching (issuer, subject name)
|
|
+ // to find the parent certificate. It does not take into account that there can be several certificates
|
|
+ // with the same subject name.
|
|
+ try
|
|
+ {
|
|
+ rSigInfo.CertificateStatus = xSecEnv->verifyCertificate(
|
|
+ rSigInfo.Signer, comphelper::containerToSequence(certs));
|
|
+ }
|
|
+ catch (SecurityException&)
|
|
+ {
|
|
+ SAL_WARN("xmlsecurity.comp", "Verification of certificate failed");
|
|
+ rSigInfo.CertificateStatus = css::security::CertificateValidity::INVALID;
|
|
+ }
|
|
}
|
|
}
|
|
- else if (xGpgSecEnv.is()) // GPG
|
|
+ else if (!rInfo.ouGpgCertificate.isEmpty() && xGpgSecEnv.is()) // GPG
|
|
{
|
|
// TODO not ideal to retrieve cert by keyID, might
|
|
// collide, or PGPKeyID format might change - can't we
|
|
@@ -619,15 +625,19 @@ void DocumentDigitalSignatures::showCertificate(
|
|
}
|
|
|
|
sal_Bool DocumentDigitalSignatures::isAuthorTrusted(
|
|
- const Reference< css::security::XCertificate >& Author )
|
|
+ const Reference<css::security::XCertificate>& xAuthor)
|
|
{
|
|
- OUString sSerialNum = xmlsecurity::bigIntegerToNumericString( Author->getSerialNumber() );
|
|
+ if (!xAuthor.is())
|
|
+ {
|
|
+ return false;
|
|
+ }
|
|
+ OUString sSerialNum = xmlsecurity::bigIntegerToNumericString(xAuthor->getSerialNumber());
|
|
|
|
Sequence< SvtSecurityOptions::Certificate > aTrustedAuthors = SvtSecurityOptions().GetTrustedAuthors();
|
|
|
|
return std::any_of(aTrustedAuthors.begin(), aTrustedAuthors.end(),
|
|
- [&Author, &sSerialNum](const SvtSecurityOptions::Certificate& rAuthor) {
|
|
- return ( rAuthor[0] == Author->getIssuerName() )
|
|
+ [&xAuthor, &sSerialNum](const SvtSecurityOptions::Certificate& rAuthor) {
|
|
+ return xmlsecurity::EqualDistinguishedNames(rAuthor[0], xAuthor->getIssuerName())
|
|
&& ( rAuthor[1] == sSerialNum );
|
|
});
|
|
}
|
|
diff --git a/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
|
|
index ef67c7167c04..18ccaf2d2166 100644
|
|
--- a/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
|
|
+++ b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
|
|
@@ -588,7 +588,7 @@ void DigitalSignaturesDialog::ImplFillSignaturesBox()
|
|
if (!rInfo.ouGpgCertificate.isEmpty())
|
|
aType = "OpenPGP";
|
|
// XML based: XAdES or not.
|
|
- else if (!rInfo.ouCertDigest.isEmpty())
|
|
+ else if (rInfo.GetSigningCertificate() && !rInfo.GetSigningCertificate()->CertDigest.isEmpty())
|
|
aType = "XAdES";
|
|
else
|
|
aType = "XML-DSig";
|
|
@@ -700,8 +700,8 @@ uno::Reference<security::XCertificate> DigitalSignaturesDialog::getCertificate(c
|
|
uno::Reference<security::XCertificate> xCert;
|
|
|
|
//First we try to get the certificate which is embedded in the XML Signature
|
|
- if (xSecEnv.is() && !rInfo.ouX509Certificate.isEmpty())
|
|
- xCert = xSecEnv->createCertificateFromAscii(rInfo.ouX509Certificate);
|
|
+ if (xSecEnv.is() && rInfo.GetSigningCertificate() && !rInfo.GetSigningCertificate()->X509Certificate.isEmpty())
|
|
+ xCert = xSecEnv->createCertificateFromAscii(rInfo.GetSigningCertificate()->X509Certificate);
|
|
else {
|
|
//There must be an embedded certificate because we use it to get the
|
|
//issuer name. We cannot use /Signature/KeyInfo/X509Data/X509IssuerName
|
|
@@ -713,9 +713,12 @@ uno::Reference<security::XCertificate> DigitalSignaturesDialog::getCertificate(c
|
|
}
|
|
|
|
//In case there is no embedded certificate we try to get it from a local store
|
|
- if (!xCert.is() && xSecEnv.is())
|
|
- xCert = xSecEnv->getCertificate( rInfo.ouX509IssuerName, xmlsecurity::numericStringToBigInteger( rInfo.ouX509SerialNumber ) );
|
|
- if (!xCert.is() && xGpgSecEnv.is())
|
|
+ if (!xCert.is() && xSecEnv.is() && rInfo.GetSigningCertificate())
|
|
+ {
|
|
+ xCert = xSecEnv->getCertificate(rInfo.GetSigningCertificate()->X509IssuerName,
|
|
+ xmlsecurity::numericStringToBigInteger(rInfo.GetSigningCertificate()->X509SerialNumber));
|
|
+ }
|
|
+ if (!xCert.is() && xGpgSecEnv.is() && !rInfo.ouGpgKeyID.isEmpty())
|
|
xCert = xGpgSecEnv->getCertificate( rInfo.ouGpgKeyID, xmlsecurity::numericStringToBigInteger("") );
|
|
|
|
SAL_WARN_IF( !xCert.is(), "xmlsecurity.dialogs", "Certificate not found and can't be created!" );
|
|
diff --git a/xmlsecurity/source/helper/documentsignaturehelper.cxx b/xmlsecurity/source/helper/documentsignaturehelper.cxx
|
|
index 482ae6cc4126..ddff308ee52f 100644
|
|
--- a/xmlsecurity/source/helper/documentsignaturehelper.cxx
|
|
+++ b/xmlsecurity/source/helper/documentsignaturehelper.cxx
|
|
@@ -492,6 +492,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,
|
|
@@ -508,26 +531,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 a0e674c3bd1b..aa08dc5c499e 100644
|
|
--- a/xmlsecurity/source/helper/documentsignaturemanager.cxx
|
|
+++ b/xmlsecurity/source/helper/documentsignaturemanager.cxx
|
|
@@ -585,6 +585,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());
|
|
+ getSignatureHelper().CheckAndUpdateSignatureInformation(xSecEnv, it);
|
|
+ }
|
|
+ }
|
|
+
|
|
maCurrentSignatureInformations = maSignatureHelper.GetSignatureInformations();
|
|
}
|
|
else
|
|
diff --git a/xmlsecurity/source/helper/ooxmlsecexporter.cxx b/xmlsecurity/source/helper/ooxmlsecexporter.cxx
|
|
index cf87d6e1ad17..cae2ef3f5b16 100644
|
|
--- a/xmlsecurity/source/helper/ooxmlsecexporter.cxx
|
|
+++ b/xmlsecurity/source/helper/ooxmlsecexporter.cxx
|
|
@@ -194,12 +194,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 a200de60c07a..a25872fc057d 100644
|
|
--- a/xmlsecurity/source/helper/ooxmlsecparser.cxx
|
|
+++ b/xmlsecurity/source/helper/ooxmlsecparser.cxx
|
|
@@ -185,9 +185,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")
|
|
@@ -202,17 +215,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 f10f29c61840..8a90b73901db 100644
|
|
--- a/xmlsecurity/source/helper/pdfsignaturehelper.cxx
|
|
+++ b/xmlsecurity/source/helper/pdfsignaturehelper.cxx
|
|
@@ -82,8 +82,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 22c056e70da1..bcb79039e342 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>
|
|
|
|
@@ -45,6 +46,8 @@
|
|
#include <tools/diagnose_ex.h>
|
|
#include <sal/log.hxx>
|
|
|
|
+#include <optional>
|
|
+
|
|
#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"
|
|
@@ -547,4 +550,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
|
|
+ std::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 8d5ea68c768b..0901d05dbdbd 100644
|
|
--- a/xmlsecurity/source/helper/xsecctl.cxx
|
|
+++ b/xmlsecurity/source/helper/xsecctl.cxx
|
|
@@ -737,8 +737,8 @@ void XSecController::exportSignature(
|
|
/* Write keyid element */
|
|
xDocumentHandler->startElement(
|
|
"PGPKeyID",
|
|
- cssu::Reference< cssxs::XAttributeList > (new SvXMLAttributeList()));
|
|
- xDocumentHandler->characters( signatureInfo.ouCertDigest );
|
|
+ css::uno::Reference< css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
|
|
+ xDocumentHandler->characters(signatureInfo.ouGpgKeyID);
|
|
xDocumentHandler->endElement( "PGPKeyID" );
|
|
|
|
/* Write PGPKeyPacket element */
|
|
@@ -762,43 +762,50 @@ void XSecController::exportSignature(
|
|
}
|
|
else
|
|
{
|
|
- /* Write X509Data element */
|
|
- xDocumentHandler->startElement(
|
|
- "X509Data",
|
|
- cssu::Reference< cssxs::XAttributeList > (new SvXMLAttributeList()));
|
|
+ assert(signatureInfo.GetSigningCertificate());
|
|
+ for (auto const& rData : signatureInfo.X509Datas)
|
|
{
|
|
- /* Write X509IssuerSerial element */
|
|
+ /* Write X509Data element */
|
|
xDocumentHandler->startElement(
|
|
- "X509IssuerSerial",
|
|
- cssu::Reference< cssxs::XAttributeList > (new SvXMLAttributeList()));
|
|
- {
|
|
- /* Write X509IssuerName element */
|
|
- xDocumentHandler->startElement(
|
|
- "X509IssuerName",
|
|
- cssu::Reference< cssxs::XAttributeList > (new SvXMLAttributeList()));
|
|
- xDocumentHandler->characters( signatureInfo.ouX509IssuerName );
|
|
- xDocumentHandler->endElement( "X509IssuerName" );
|
|
-
|
|
- /* Write X509SerialNumber element */
|
|
- xDocumentHandler->startElement(
|
|
- "X509SerialNumber",
|
|
- cssu::Reference< cssxs::XAttributeList > (new SvXMLAttributeList()));
|
|
- xDocumentHandler->characters( signatureInfo.ouX509SerialNumber );
|
|
- xDocumentHandler->endElement( "X509SerialNumber" );
|
|
- }
|
|
- xDocumentHandler->endElement( "X509IssuerSerial" );
|
|
-
|
|
- /* Write X509Certificate element */
|
|
- if (!signatureInfo.ouX509Certificate.isEmpty())
|
|
+ "X509Data",
|
|
+ css::uno::Reference< css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
|
|
{
|
|
- xDocumentHandler->startElement(
|
|
- "X509Certificate",
|
|
- cssu::Reference< cssxs::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" );
|
|
@@ -917,6 +924,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 9cc9312b4d9f..595a02ed687d 100644
|
|
--- a/xmlsecurity/source/helper/xsecparser.cxx
|
|
+++ b/xmlsecurity/source/helper/xsecparser.cxx
|
|
@@ -99,6 +99,42 @@ auto XSecParser::Context::CreateChildContext(
|
|
return std::make_unique<UnknownContext>(m_rParser, std::move(pOldNamespaceMap));
|
|
}
|
|
|
|
+/**
|
|
+note: anything in ds:Object should be trusted *only* if there is a ds:Reference
|
|
+ to it so it is signed (exception: the xades:EncapsulatedX509Certificate).
|
|
+ ds:SignedInfo precedes all ds:Object.
|
|
+
|
|
+ There may be multiple ds:Signature for purpose of counter-signatures
|
|
+ but the way XAdES describes these, only the ds:SignatureValue element
|
|
+ would be referenced, so requiring a ds:Reference for anything in
|
|
+ ds:Object shouldn't cause issues.
|
|
+ */
|
|
+class XSecParser::ReferencedContextImpl
|
|
+ : public XSecParser::Context
|
|
+{
|
|
+ protected:
|
|
+ bool m_isReferenced;
|
|
+
|
|
+ public:
|
|
+ ReferencedContextImpl(XSecParser & rParser,
|
|
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
|
|
+ bool const isReferenced)
|
|
+ : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
|
|
+ , m_isReferenced(isReferenced)
|
|
+ {
|
|
+ }
|
|
+
|
|
+ OUString CheckIdAttrReferenced(css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs)
|
|
+ {
|
|
+ OUString const id(m_rParser.HandleIdAttr(xAttrs));
|
|
+ if (!id.isEmpty() && m_rParser.m_pXSecController->haveReferenceForId(id))
|
|
+ {
|
|
+ m_isReferenced = true;
|
|
+ }
|
|
+ return id;
|
|
+ }
|
|
+};
|
|
+
|
|
class XSecParser::LoPGPOwnerContext
|
|
: public XSecParser::Context
|
|
{
|
|
@@ -211,23 +247,20 @@ 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;
|
|
}
|
|
};
|
|
|
|
@@ -235,23 +268,20 @@ class XSecParser::DsX509SerialNumberContext
|
|
: public XSecParser::Context
|
|
{
|
|
private:
|
|
- OUString m_Value;
|
|
+ OUString & m_rValue;
|
|
|
|
public:
|
|
DsX509SerialNumberContext(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->setX509SerialNumber(m_Value);
|
|
- }
|
|
-
|
|
virtual void Characters(OUString const& rChars) override
|
|
{
|
|
- m_Value += rChars;
|
|
+ m_rValue += rChars;
|
|
}
|
|
};
|
|
|
|
@@ -259,33 +289,37 @@ class XSecParser::DsX509IssuerNameContext
|
|
: public XSecParser::Context
|
|
{
|
|
private:
|
|
- OUString m_Value;
|
|
+ OUString & m_rValue;
|
|
|
|
public:
|
|
DsX509IssuerNameContext(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->setX509IssuerName(m_Value);
|
|
- }
|
|
-
|
|
virtual void Characters(OUString const& rChars) override
|
|
{
|
|
- m_Value += rChars;
|
|
+ m_rValue += rChars;
|
|
}
|
|
};
|
|
|
|
class XSecParser::DsX509IssuerSerialContext
|
|
: public XSecParser::Context
|
|
{
|
|
+ private:
|
|
+ OUString & m_rX509IssuerName;
|
|
+ OUString & m_rX509SerialNumber;
|
|
+
|
|
public:
|
|
DsX509IssuerSerialContext(XSecParser & rParser,
|
|
- std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
|
|
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
|
|
+ OUString & rIssuerName, OUString & rSerialNumber)
|
|
: XSecParser::Context(rParser, std::move(pOldNamespaceMap))
|
|
+ , m_rX509IssuerName(rIssuerName)
|
|
+ , m_rX509SerialNumber(rSerialNumber)
|
|
{
|
|
}
|
|
|
|
@@ -295,20 +329,27 @@ class XSecParser::DsX509IssuerSerialContext
|
|
{
|
|
if (nNamespace == XML_NAMESPACE_DS && rName == "X509IssuerName")
|
|
{
|
|
- return std::make_unique<DsX509IssuerNameContext>(m_rParser, std::move(pOldNamespaceMap));
|
|
+ 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));
|
|
+ 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)
|
|
@@ -316,17 +357,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")
|
|
{
|
|
- return std::make_unique<DsX509IssuerSerialContext>(m_rParser, std::move(pOldNamespaceMap));
|
|
+ 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);
|
|
@@ -791,21 +839,29 @@ class XSecParser::XadesUnsignedPropertiesContext
|
|
};
|
|
|
|
class XSecParser::LoSignatureLineIdContext
|
|
- : public XSecParser::Context
|
|
+ : public XSecParser::ReferencedContextImpl
|
|
{
|
|
private:
|
|
OUString m_Value;
|
|
|
|
public:
|
|
LoSignatureLineIdContext(XSecParser & rParser,
|
|
- std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
|
|
- : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
|
|
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
|
|
+ bool const isReferenced)
|
|
+ : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
|
|
{
|
|
}
|
|
|
|
virtual void EndElement() override
|
|
{
|
|
- m_rParser.m_pXSecController->setSignatureLineId(m_Value);
|
|
+ if (m_isReferenced)
|
|
+ {
|
|
+ m_rParser.m_pXSecController->setSignatureLineId(m_Value);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ SAL_INFO("xmlsecurity.helper", "ignoring unsigned SignatureLineId");
|
|
+ }
|
|
}
|
|
|
|
virtual void Characters(OUString const& rChars) override
|
|
@@ -815,21 +871,29 @@ class XSecParser::LoSignatureLineIdContext
|
|
};
|
|
|
|
class XSecParser::LoSignatureLineValidImageContext
|
|
- : public XSecParser::Context
|
|
+ : public XSecParser::ReferencedContextImpl
|
|
{
|
|
private:
|
|
OUString m_Value;
|
|
|
|
public:
|
|
LoSignatureLineValidImageContext(XSecParser & rParser,
|
|
- std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
|
|
- : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
|
|
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
|
|
+ bool const isReferenced)
|
|
+ : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
|
|
{
|
|
}
|
|
|
|
virtual void EndElement() override
|
|
{
|
|
- m_rParser.m_pXSecController->setValidSignatureImage(m_Value);
|
|
+ if (m_isReferenced)
|
|
+ {
|
|
+ m_rParser.m_pXSecController->setValidSignatureImage(m_Value);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ SAL_INFO("xmlsecurity.helper", "ignoring unsigned SignatureLineValidImage");
|
|
+ }
|
|
}
|
|
|
|
virtual void Characters(OUString const& rChars) override
|
|
@@ -839,21 +903,29 @@ class XSecParser::LoSignatureLineValidImageContext
|
|
};
|
|
|
|
class XSecParser::LoSignatureLineInvalidImageContext
|
|
- : public XSecParser::Context
|
|
+ : public XSecParser::ReferencedContextImpl
|
|
{
|
|
private:
|
|
OUString m_Value;
|
|
|
|
public:
|
|
LoSignatureLineInvalidImageContext(XSecParser & rParser,
|
|
- std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
|
|
- : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
|
|
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
|
|
+ bool const isReferenced)
|
|
+ : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
|
|
{
|
|
}
|
|
|
|
virtual void EndElement() override
|
|
{
|
|
- m_rParser.m_pXSecController->setInvalidSignatureImage(m_Value);
|
|
+ if (m_isReferenced)
|
|
+ {
|
|
+ m_rParser.m_pXSecController->setInvalidSignatureImage(m_Value);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ SAL_INFO("xmlsecurity.helper", "ignoring unsigned SignatureLineInvalidImage");
|
|
+ }
|
|
}
|
|
|
|
virtual void Characters(OUString const& rChars) override
|
|
@@ -863,12 +935,13 @@ class XSecParser::LoSignatureLineInvalidImageContext
|
|
};
|
|
|
|
class XSecParser::LoSignatureLineContext
|
|
- : public XSecParser::Context
|
|
+ : public XSecParser::ReferencedContextImpl
|
|
{
|
|
public:
|
|
LoSignatureLineContext(XSecParser & rParser,
|
|
- std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
|
|
- : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
|
|
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
|
|
+ bool const isReferenced)
|
|
+ : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
|
|
{
|
|
}
|
|
|
|
@@ -878,15 +951,15 @@ class XSecParser::LoSignatureLineContext
|
|
{
|
|
if (nNamespace == XML_NAMESPACE_LO_EXT && rName == "SignatureLineId")
|
|
{
|
|
- return std::make_unique<LoSignatureLineIdContext>(m_rParser, std::move(pOldNamespaceMap));
|
|
+ return std::make_unique<LoSignatureLineIdContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
|
|
}
|
|
if (nNamespace == XML_NAMESPACE_LO_EXT && rName == "SignatureLineValidImage")
|
|
{
|
|
- return std::make_unique<LoSignatureLineValidImageContext>(m_rParser, std::move(pOldNamespaceMap));
|
|
+ return std::make_unique<LoSignatureLineValidImageContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
|
|
}
|
|
if (nNamespace == XML_NAMESPACE_LO_EXT && rName == "SignatureLineInvalidImage")
|
|
{
|
|
- return std::make_unique<LoSignatureLineInvalidImageContext>(m_rParser, std::move(pOldNamespaceMap));
|
|
+ return std::make_unique<LoSignatureLineInvalidImageContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
|
|
}
|
|
return XSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
|
|
}
|
|
@@ -896,70 +969,88 @@ class XSecParser::XadesCertDigestContext
|
|
: 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)
|
|
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
|
|
+ OUString & rDigestValue, sal_Int32 & rReferenceDigestID)
|
|
: XSecParser::Context(rParser, std::move(pOldNamespaceMap))
|
|
+ , m_rDigestValue(rDigestValue)
|
|
+ , m_rReferenceDigestID(rReferenceDigestID)
|
|
{
|
|
}
|
|
|
|
- virtual void EndElement() override
|
|
- {
|
|
- m_rParser.m_pXSecController->setCertDigest(m_Value/* FIXME , m_nReferenceDigestID*/);
|
|
- }
|
|
-
|
|
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 == "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);
|
|
}
|
|
};
|
|
|
|
class XSecParser::XadesCertContext
|
|
- : public XSecParser::Context
|
|
+ : 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)
|
|
- : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
|
|
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
|
|
+ bool const isReferenced)
|
|
+ : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
|
|
{
|
|
}
|
|
|
|
+ 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));
|
|
+ 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));
|
|
+ return std::make_unique<DsX509IssuerSerialContext>(m_rParser, std::move(pOldNamespaceMap), m_X509IssuerName, m_X509SerialNumber);
|
|
}
|
|
return XSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
|
|
}
|
|
};
|
|
|
|
class XSecParser::XadesSigningCertificateContext
|
|
- : public XSecParser::Context
|
|
+ : public XSecParser::ReferencedContextImpl
|
|
{
|
|
public:
|
|
XadesSigningCertificateContext(XSecParser & rParser,
|
|
- std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
|
|
- : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
|
|
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
|
|
+ bool const isReferenced)
|
|
+ : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
|
|
{
|
|
}
|
|
|
|
@@ -969,28 +1060,36 @@ class XSecParser::XadesSigningCertificateContext
|
|
{
|
|
if (nNamespace == XML_NAMESPACE_XADES132 && rName == "Cert")
|
|
{
|
|
- return std::make_unique<XadesCertContext>(m_rParser, std::move(pOldNamespaceMap));
|
|
+ return std::make_unique<XadesCertContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
|
|
}
|
|
return XSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
|
|
}
|
|
};
|
|
|
|
class XSecParser::XadesSigningTimeContext
|
|
- : public XSecParser::Context
|
|
+ : public XSecParser::ReferencedContextImpl
|
|
{
|
|
private:
|
|
OUString m_Value;
|
|
|
|
public:
|
|
XadesSigningTimeContext(XSecParser & rParser,
|
|
- std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
|
|
- : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
|
|
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
|
|
+ bool const isReferenced)
|
|
+ : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
|
|
{
|
|
}
|
|
|
|
virtual void EndElement() override
|
|
{
|
|
- m_rParser.m_pXSecController->setDate("", m_Value);
|
|
+ if (m_isReferenced)
|
|
+ {
|
|
+ m_rParser.m_pXSecController->setDate("", m_Value);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ SAL_INFO("xmlsecurity.helper", "ignoring unsigned SigningTime");
|
|
+ }
|
|
}
|
|
|
|
virtual void Characters(OUString const& rChars) override
|
|
@@ -1000,19 +1099,20 @@ class XSecParser::XadesSigningTimeContext
|
|
};
|
|
|
|
class XSecParser::XadesSignedSignaturePropertiesContext
|
|
- : public XSecParser::Context
|
|
+ : public XSecParser::ReferencedContextImpl
|
|
{
|
|
public:
|
|
XadesSignedSignaturePropertiesContext(XSecParser & rParser,
|
|
- std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
|
|
- : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
|
|
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
|
|
+ bool const isReferenced)
|
|
+ : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
|
|
{
|
|
}
|
|
|
|
virtual void StartElement(
|
|
css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
|
|
{
|
|
- m_rParser.HandleIdAttr(xAttrs);
|
|
+ CheckIdAttrReferenced(xAttrs);
|
|
}
|
|
|
|
virtual std::unique_ptr<Context> CreateChildContext(
|
|
@@ -1021,15 +1121,15 @@ class XSecParser::XadesSignedSignaturePropertiesContext
|
|
{
|
|
if (nNamespace == XML_NAMESPACE_XADES132 && rName == "SigningTime")
|
|
{
|
|
- return std::make_unique<XadesSigningTimeContext>(m_rParser, std::move(pOldNamespaceMap));
|
|
+ return std::make_unique<XadesSigningTimeContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
|
|
}
|
|
if (nNamespace == XML_NAMESPACE_XADES132 && rName == "SigningCertificate")
|
|
{
|
|
- return std::make_unique<XadesSigningCertificateContext>(m_rParser, std::move(pOldNamespaceMap));
|
|
+ return std::make_unique<XadesSigningCertificateContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
|
|
}
|
|
if (nNamespace == XML_NAMESPACE_LO_EXT && rName == "SignatureLine")
|
|
{
|
|
- return std::make_unique<LoSignatureLineContext>(m_rParser, std::move(pOldNamespaceMap));
|
|
+ return std::make_unique<LoSignatureLineContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
|
|
}
|
|
// missing: xades:SignaturePolicyIdentifier, xades:SignatureProductionPlace, xades:SignerRole
|
|
return XSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
|
|
@@ -1037,19 +1137,20 @@ class XSecParser::XadesSignedSignaturePropertiesContext
|
|
};
|
|
|
|
class XSecParser::XadesSignedPropertiesContext
|
|
- : public XSecParser::Context
|
|
+ : public XSecParser::ReferencedContextImpl
|
|
{
|
|
public:
|
|
XadesSignedPropertiesContext(XSecParser & rParser,
|
|
- std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
|
|
- : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
|
|
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
|
|
+ bool const isReferenced)
|
|
+ : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
|
|
{
|
|
}
|
|
|
|
virtual void StartElement(
|
|
css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
|
|
{
|
|
- m_rParser.HandleIdAttr(xAttrs);
|
|
+ CheckIdAttrReferenced(xAttrs);
|
|
}
|
|
|
|
virtual std::unique_ptr<Context> CreateChildContext(
|
|
@@ -1058,7 +1159,7 @@ class XSecParser::XadesSignedPropertiesContext
|
|
{
|
|
if (nNamespace == XML_NAMESPACE_XADES132 && rName == "SignedSignatureProperties")
|
|
{
|
|
- return std::make_unique<XadesSignedSignaturePropertiesContext>(m_rParser, std::move(pOldNamespaceMap));
|
|
+ return std::make_unique<XadesSignedSignaturePropertiesContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
|
|
}
|
|
// missing: xades:SignedDataObjectProperties
|
|
return XSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
|
|
@@ -1066,19 +1167,20 @@ class XSecParser::XadesSignedPropertiesContext
|
|
};
|
|
|
|
class XSecParser::XadesQualifyingPropertiesContext
|
|
- : public XSecParser::Context
|
|
+ : public XSecParser::ReferencedContextImpl
|
|
{
|
|
public:
|
|
XadesQualifyingPropertiesContext(XSecParser & rParser,
|
|
- std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
|
|
- : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
|
|
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
|
|
+ bool const isReferenced)
|
|
+ : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
|
|
{
|
|
}
|
|
|
|
virtual void StartElement(
|
|
css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
|
|
{
|
|
- m_rParser.HandleIdAttr(xAttrs);
|
|
+ CheckIdAttrReferenced(xAttrs);
|
|
}
|
|
|
|
virtual std::unique_ptr<Context> CreateChildContext(
|
|
@@ -1087,7 +1189,7 @@ class XSecParser::XadesQualifyingPropertiesContext
|
|
{
|
|
if (nNamespace == XML_NAMESPACE_XADES132 && rName == "SignedProperties")
|
|
{
|
|
- return std::make_unique<XadesSignedPropertiesContext>(m_rParser, std::move(pOldNamespaceMap));
|
|
+ return std::make_unique<XadesSignedPropertiesContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
|
|
}
|
|
if (nNamespace == XML_NAMESPACE_XADES132 && rName == "UnsignedProperties")
|
|
{
|
|
@@ -1140,7 +1242,7 @@ class XSecParser::DcDescriptionContext
|
|
};
|
|
|
|
class XSecParser::DsSignaturePropertyContext
|
|
- : public XSecParser::Context
|
|
+ : public XSecParser::ReferencedContextImpl
|
|
{
|
|
private:
|
|
enum class SignatureProperty { Unknown, Date, Description };
|
|
@@ -1150,30 +1252,38 @@ class XSecParser::DsSignaturePropertyContext
|
|
|
|
public:
|
|
DsSignaturePropertyContext(XSecParser & rParser,
|
|
- std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
|
|
- : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
|
|
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
|
|
+ bool const isReferenced)
|
|
+ : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
|
|
{
|
|
}
|
|
|
|
virtual void StartElement(
|
|
css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
|
|
{
|
|
- m_Id = m_rParser.HandleIdAttr(xAttrs);
|
|
+ m_Id = CheckIdAttrReferenced(xAttrs);
|
|
}
|
|
|
|
virtual void EndElement() override
|
|
{
|
|
- switch (m_Property)
|
|
+ if (m_isReferenced)
|
|
+ {
|
|
+ switch (m_Property)
|
|
+ {
|
|
+ case SignatureProperty::Unknown:
|
|
+ SAL_INFO("xmlsecurity.helper", "Unknown property in ds:Object ignored");
|
|
+ break;
|
|
+ case SignatureProperty::Date:
|
|
+ m_rParser.m_pXSecController->setDate(m_Id, m_Value);
|
|
+ break;
|
|
+ case SignatureProperty::Description:
|
|
+ m_rParser.m_pXSecController->setDescription(m_Id, m_Value);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ else
|
|
{
|
|
- case SignatureProperty::Unknown:
|
|
- SAL_INFO("xmlsecurity.helper", "Unknown property in ds:Object ignored");
|
|
- break;
|
|
- case SignatureProperty::Date:
|
|
- m_rParser.m_pXSecController->setDate(m_Id, m_Value);
|
|
- break;
|
|
- case SignatureProperty::Description:
|
|
- m_rParser.m_pXSecController->setDescription(m_Id, m_Value);
|
|
- break;
|
|
+ SAL_INFO("xmlsecurity.helper", "ignoring unsigned SignatureProperty");
|
|
}
|
|
}
|
|
|
|
@@ -1196,19 +1306,20 @@ class XSecParser::DsSignaturePropertyContext
|
|
};
|
|
|
|
class XSecParser::DsSignaturePropertiesContext
|
|
- : public XSecParser::Context
|
|
+ : public XSecParser::ReferencedContextImpl
|
|
{
|
|
public:
|
|
DsSignaturePropertiesContext(XSecParser & rParser,
|
|
- std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
|
|
- : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
|
|
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
|
|
+ bool const isReferenced)
|
|
+ : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
|
|
{
|
|
}
|
|
|
|
virtual void StartElement(
|
|
css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
|
|
{
|
|
- m_rParser.HandleIdAttr(xAttrs);
|
|
+ CheckIdAttrReferenced(xAttrs);
|
|
}
|
|
|
|
virtual std::unique_ptr<Context> CreateChildContext(
|
|
@@ -1217,26 +1328,27 @@ class XSecParser::DsSignaturePropertiesContext
|
|
{
|
|
if (nNamespace == XML_NAMESPACE_DS && rName == "SignatureProperty")
|
|
{
|
|
- return std::make_unique<DsSignaturePropertyContext>(m_rParser, std::move(pOldNamespaceMap));
|
|
+ return std::make_unique<DsSignaturePropertyContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
|
|
}
|
|
return XSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
|
|
}
|
|
};
|
|
|
|
class XSecParser::DsObjectContext
|
|
- : public XSecParser::Context
|
|
+ : public XSecParser::ReferencedContextImpl
|
|
{
|
|
public:
|
|
DsObjectContext(XSecParser & rParser,
|
|
std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
|
|
- : XSecParser::Context(rParser, std::move(pOldNamespaceMap))
|
|
+ // init with "false" here - the Signature element can't be referenced by its child
|
|
+ : XSecParser::ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), false)
|
|
{
|
|
}
|
|
|
|
virtual void StartElement(
|
|
css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
|
|
{
|
|
- m_rParser.HandleIdAttr(xAttrs);
|
|
+ CheckIdAttrReferenced(xAttrs);
|
|
}
|
|
|
|
virtual std::unique_ptr<Context> CreateChildContext(
|
|
@@ -1245,11 +1357,11 @@ class XSecParser::DsObjectContext
|
|
{
|
|
if (nNamespace == XML_NAMESPACE_DS && rName == "SignatureProperties")
|
|
{
|
|
- return std::make_unique<DsSignaturePropertiesContext>(m_rParser, std::move(pOldNamespaceMap));
|
|
+ return std::make_unique<DsSignaturePropertiesContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
|
|
}
|
|
if (nNamespace == XML_NAMESPACE_XADES132 && rName == "QualifyingProperties")
|
|
{
|
|
- return std::make_unique<XadesQualifyingPropertiesContext>(m_rParser, std::move(pOldNamespaceMap));
|
|
+ return std::make_unique<XadesQualifyingPropertiesContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
|
|
}
|
|
// missing: ds:Manifest
|
|
return XSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
|
|
diff --git a/xmlsecurity/source/helper/xsecparser.hxx b/xmlsecurity/source/helper/xsecparser.hxx
|
|
index 7a0eb08bca28..7674bf28b84d 100644
|
|
--- a/xmlsecurity/source/helper/xsecparser.hxx
|
|
+++ b/xmlsecurity/source/helper/xsecparser.hxx
|
|
@@ -56,6 +56,7 @@ public:
|
|
class Context;
|
|
private:
|
|
class UnknownContext;
|
|
+ class ReferencedContextImpl;
|
|
class LoPGPOwnerContext;
|
|
class DsPGPKeyPacketContext;
|
|
class DsPGPKeyIDContext;
|
|
diff --git a/xmlsecurity/source/helper/xsecsign.cxx b/xmlsecurity/source/helper/xsecsign.cxx
|
|
index 5ed23281f083..38a420a370aa 100644
|
|
--- a/xmlsecurity/source/helper/xsecsign.cxx
|
|
+++ b/xmlsecurity/source/helper/xsecsign.cxx
|
|
@@ -197,6 +197,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,
|
|
@@ -210,10 +211,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 );
|
|
}
|
|
@@ -221,16 +225,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)
|
|
{
|
|
@@ -241,16 +248,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 5f5840334254..1f0445c35c14 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>
|
|
@@ -147,6 +148,25 @@ void XSecController::switchGpgSignature()
|
|
#endif
|
|
}
|
|
|
|
+bool XSecController::haveReferenceForId(OUString const& rId) const
|
|
+{
|
|
+ if (m_vInternalSignatureInformations.empty())
|
|
+ {
|
|
+ SAL_INFO("xmlsecurity.helper","XSecController::haveReferenceForId: no signature");
|
|
+ return false;
|
|
+ }
|
|
+ InternalSignatureInformation const& rIsi(m_vInternalSignatureInformations.back());
|
|
+ for (SignatureReferenceInformation const& rSri : rIsi.signatureInfor.vSignatureReferenceInfors)
|
|
+ {
|
|
+ if (rSri.nType == SignatureReferenceType::SAMEDOCUMENT
|
|
+ && rSri.ouURI == rId) // ouUri has # stripped
|
|
+ {
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
void XSecController::addReference( const OUString& ouUri, sal_Int32 nDigestID, const OUString& ouType )
|
|
{
|
|
if (m_vInternalSignatureInformations.empty())
|
|
@@ -225,7 +245,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())
|
|
{
|
|
@@ -233,29 +255,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 )
|
|
@@ -365,13 +410,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 {
|
|
diff --git a/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx b/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx
|
|
index 0e619b2802f8..244cd46ac564 100644
|
|
--- a/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx
|
|
+++ b/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx
|
|
@@ -26,6 +26,7 @@
|
|
#include <cppuhelper/supportsservice.hxx>
|
|
#include "x509certificate_mscryptimpl.hxx"
|
|
#include <certificateextension_xmlsecimpl.hxx>
|
|
+#include <biginteger.hxx>
|
|
#include "sanextension_mscryptimpl.hxx"
|
|
|
|
#include "oid.hxx"
|
|
@@ -649,4 +650,50 @@ Sequence<OUString> SAL_CALL X509Certificate_MSCryptImpl::getSupportedServiceName
|
|
return { OUString() };
|
|
}
|
|
|
|
+namespace xmlsecurity {
|
|
+
|
|
+static bool EncodeDistinguishedName(OUString const& rName, CERT_NAME_BLOB & rBlob)
|
|
+{
|
|
+ LPCWSTR pszError;
|
|
+ if (!CertStrToNameW(X509_ASN_ENCODING,
|
|
+ reinterpret_cast<LPCWSTR>(rName.getStr()), CERT_X500_NAME_STR,
|
|
+ nullptr, nullptr, &rBlob.cbData, &pszError))
|
|
+ {
|
|
+ SAL_INFO("xmlsecurity.xmlsec", "CertStrToNameW failed: " << WindowsErrorString(GetLastError()) << "; " << reinterpret_cast<char16_t const*>(pszError));
|
|
+ return false;
|
|
+ }
|
|
+ rBlob.pbData = new BYTE[rBlob.cbData];
|
|
+ if (!CertStrToNameW(X509_ASN_ENCODING,
|
|
+ reinterpret_cast<LPCWSTR>(rName.getStr()), CERT_X500_NAME_STR,
|
|
+ nullptr, rBlob.pbData, &rBlob.cbData, &pszError))
|
|
+ {
|
|
+ SAL_INFO("xmlsecurity.xmlsec", "CertStrToNameW failed: " << WindowsErrorString(GetLastError()) << "; " << reinterpret_cast<char16_t const*>(pszError));
|
|
+ return false;
|
|
+ }
|
|
+ return true;
|
|
+}
|
|
+
|
|
+bool EqualDistinguishedNames(
|
|
+ OUString const& rName1, OUString const& rName2)
|
|
+{
|
|
+ CERT_NAME_BLOB blob1;
|
|
+ if (!EncodeDistinguishedName(rName1, blob1))
|
|
+ {
|
|
+ return false;
|
|
+ }
|
|
+ CERT_NAME_BLOB blob2;
|
|
+ if (!EncodeDistinguishedName(rName2, blob2))
|
|
+ {
|
|
+ delete[] blob1.pbData;
|
|
+ return false;
|
|
+ }
|
|
+ bool const ret(CertCompareCertificateName(X509_ASN_ENCODING,
|
|
+ &blob1, &blob2) == TRUE);
|
|
+ delete[] blob2.pbData;
|
|
+ delete[] blob1.pbData;
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+} // namespace xmlsecurity
|
|
+
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
|
diff --git a/xmlsecurity/source/xmlsec/mscrypt/xmlsignature_mscryptimpl.cxx b/xmlsecurity/source/xmlsec/mscrypt/xmlsignature_mscryptimpl.cxx
|
|
index a0acd81786d7..db400e6f1ed9 100644
|
|
--- a/xmlsecurity/source/xmlsec/mscrypt/xmlsignature_mscryptimpl.cxx
|
|
+++ b/xmlsecurity/source/xmlsec/mscrypt/xmlsignature_mscryptimpl.cxx
|
|
@@ -18,6 +18,7 @@
|
|
*/
|
|
|
|
#include <sal/config.h>
|
|
+#include <sal/log.hxx>
|
|
#include <rtl/uuid.h>
|
|
|
|
#include <com/sun/star/xml/crypto/SecurityOperationStatus.hpp>
|
|
@@ -250,6 +251,7 @@ SAL_CALL XMLSignature_MSCryptImpl::validate(
|
|
++nReferenceGood;
|
|
}
|
|
}
|
|
+ SAL_INFO("xmlsecurity.xmlsec", "xmlSecDSigCtxVerify status " << pDsigCtx->status << ", references good " << nReferenceGood << " of " << nReferenceCount);
|
|
|
|
if (rs == 0 && nReferenceCount == nReferenceGood)
|
|
{
|
|
diff --git a/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx b/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx
|
|
index 1a323d33f32f..d6143a81883c 100644
|
|
--- a/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx
|
|
+++ b/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx
|
|
@@ -31,6 +31,7 @@
|
|
#include <rtl/ref.hxx>
|
|
#include "x509certificate_nssimpl.hxx"
|
|
|
|
+#include <biginteger.hxx>
|
|
#include <certificateextension_xmlsecimpl.hxx>
|
|
|
|
#include "sanextension_nssimpl.hxx"
|
|
@@ -533,4 +534,28 @@ sal_Bool SAL_CALL X509Certificate_NssImpl::supportsService(const OUString& servi
|
|
/* XServiceInfo */
|
|
Sequence<OUString> SAL_CALL X509Certificate_NssImpl::getSupportedServiceNames() { return { OUString() }; }
|
|
|
|
+namespace xmlsecurity {
|
|
+
|
|
+bool EqualDistinguishedNames(
|
|
+ OUString const& rName1, OUString const& rName2)
|
|
+{
|
|
+ CERTName *const pName1(CERT_AsciiToName(OUStringToOString(rName1, RTL_TEXTENCODING_UTF8).getStr()));
|
|
+ if (pName1 == nullptr)
|
|
+ {
|
|
+ return false;
|
|
+ }
|
|
+ CERTName *const pName2(CERT_AsciiToName(OUStringToOString(rName2, RTL_TEXTENCODING_UTF8).getStr()));
|
|
+ if (pName2 == nullptr)
|
|
+ {
|
|
+ CERT_DestroyName(pName1);
|
|
+ return false;
|
|
+ }
|
|
+ bool const ret(CERT_CompareName(pName1, pName2) == SECEqual);
|
|
+ CERT_DestroyName(pName2);
|
|
+ CERT_DestroyName(pName1);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+} // namespace xmlsecurity
|
|
+
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
|
diff --git a/xmlsecurity/source/xmlsec/nss/xmlsignature_nssimpl.cxx b/xmlsecurity/source/xmlsec/nss/xmlsignature_nssimpl.cxx
|
|
index c39f6cc72f76..827580bcc7d7 100644
|
|
--- a/xmlsecurity/source/xmlsec/nss/xmlsignature_nssimpl.cxx
|
|
+++ b/xmlsecurity/source/xmlsec/nss/xmlsignature_nssimpl.cxx
|
|
@@ -26,6 +26,8 @@
|
|
#include "securityenvironment_nssimpl.hxx"
|
|
|
|
#include <xmlsec-wrapper.h>
|
|
+#include <sal/log.hxx>
|
|
+
|
|
#include <com/sun/star/xml/crypto/XXMLSignature.hpp>
|
|
#include <memory>
|
|
|
|
@@ -257,6 +259,7 @@ SAL_CALL XMLSignature_NssImpl::validate(
|
|
++nReferenceGood;
|
|
}
|
|
}
|
|
+ SAL_INFO("xmlsecurity.xmlsec", "xmlSecDSigCtxVerify status " << pDsigCtx->status << ", references good " << nReferenceGood << " of " << nReferenceCount);
|
|
|
|
if (rs == 0 && pDsigCtx->status == xmlSecDSigStatusSucceeded && nReferenceCount == nReferenceGood)
|
|
{
|
|
--
|
|
2.32.0
|
|
|