/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "ooxmlsecparser.hxx" #include #include #include #include #include #include #include using namespace com::sun::star; class OOXMLSecParser::Context { protected: friend class OOXMLSecParser; OOXMLSecParser & m_rParser; private: std::optional m_pOldNamespaceMap; public: Context(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap) : m_rParser(rParser) , m_pOldNamespaceMap(std::move(pOldNamespaceMap)) { } virtual ~Context() = default; virtual void StartElement( css::uno::Reference const& /*xAttrs*/) { } virtual void EndElement() { } virtual std::unique_ptr CreateChildContext( std::optional&& pOldNamespaceMap, sal_uInt16 const /*nNamespace*/, OUString const& /*rName*/); virtual void Characters(OUString const& /*rChars*/) { } }; // it's possible that an unsupported element has an Id attribute and a // ds:Reference digesting it - probably this means XSecController needs to know // about it. (For known elements, the Id attribute is only processed according // to the schema.) class OOXMLSecParser::UnknownContext : public OOXMLSecParser::Context { public: UnknownContext(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap) : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap)) { } virtual void StartElement( css::uno::Reference const& xAttrs) override { m_rParser.HandleIdAttr(xAttrs); } }; auto OOXMLSecParser::Context::CreateChildContext( std::optional&& pOldNamespaceMap, sal_uInt16 const /*nNamespace*/, OUString const& /*rName*/) -> std::unique_ptr { // default: create new base context return std::make_unique(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 OOXMLSecParser::ReferencedContextImpl : public OOXMLSecParser::Context { protected: bool m_isReferenced; public: ReferencedContextImpl(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap, bool const isReferenced) : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap)) , m_isReferenced(isReferenced) { } OUString CheckIdAttrReferenced(css::uno::Reference const& xAttrs) { OUString const id(m_rParser.HandleIdAttr(xAttrs)); if (!id.isEmpty() && m_rParser.m_pXSecController->haveReferenceForId(id)) { m_isReferenced = true; } return id; } }; class OOXMLSecParser::DsX509CertificateContext : public OOXMLSecParser::Context { private: OUString & m_rValue; public: DsX509CertificateContext(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap, OUString& rValue) : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap)) , m_rValue(rValue) { } virtual void Characters(OUString const& rChars) override { m_rValue += rChars; } }; class OOXMLSecParser::DsX509SerialNumberContext : public OOXMLSecParser::Context { private: OUString & m_rValue; public: DsX509SerialNumberContext(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap, OUString& rValue) : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap)) , m_rValue(rValue) { } virtual void Characters(OUString const& rChars) override { m_rValue += rChars; } }; class OOXMLSecParser::DsX509IssuerNameContext : public OOXMLSecParser::Context { private: OUString & m_rValue; public: DsX509IssuerNameContext(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap, OUString& rValue) : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap)) , m_rValue(rValue) { } virtual void Characters(OUString const& rChars) override { m_rValue += rChars; } }; class OOXMLSecParser::DsX509IssuerSerialContext : public OOXMLSecParser::Context { private: OUString & m_rX509IssuerName; OUString & m_rX509SerialNumber; public: DsX509IssuerSerialContext(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap, OUString& rIssuerName, OUString& rSerialNumber) : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap)) , m_rX509IssuerName(rIssuerName) , m_rX509SerialNumber(rSerialNumber) { } virtual std::unique_ptr CreateChildContext( std::optional&& pOldNamespaceMap, sal_uInt16 const nNamespace, OUString const& rName) override { if (nNamespace == XML_NAMESPACE_DS && rName == "X509IssuerName") { return std::make_unique(m_rParser, std::move(pOldNamespaceMap), m_rX509IssuerName); } if (nNamespace == XML_NAMESPACE_DS && rName == "X509SerialNumber") { return std::make_unique(m_rParser, std::move(pOldNamespaceMap), m_rX509SerialNumber); } // missing: ds:X509SKI, ds:X509SubjectName, ds:X509CRL return OOXMLSecParser::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 OOXMLSecParser::DsX509DataContext : public OOXMLSecParser::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> m_X509IssuerSerials; std::vector m_X509Certificates; public: DsX509DataContext(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap) : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap)) { } virtual void EndElement() override { m_rParser.m_pXSecController->setX509Data(m_X509IssuerSerials, m_X509Certificates); } virtual std::unique_ptr CreateChildContext( std::optional&& pOldNamespaceMap, sal_uInt16 const nNamespace, OUString const& rName) override { if (nNamespace == XML_NAMESPACE_DS && rName == "X509IssuerSerial") { m_X509IssuerSerials.emplace_back(); return std::make_unique(m_rParser, std::move(pOldNamespaceMap), m_X509IssuerSerials.back().first, m_X509IssuerSerials.back().second); } if (nNamespace == XML_NAMESPACE_DS && rName == "X509Certificate") { m_X509Certificates.emplace_back(); return std::make_unique(m_rParser, std::move(pOldNamespaceMap), m_X509Certificates.back()); } // missing: ds:X509SKI, ds:X509SubjectName, ds:X509CRL return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName); } }; class OOXMLSecParser::DsKeyInfoContext : public OOXMLSecParser::Context { public: DsKeyInfoContext(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap) : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap)) { } virtual void StartElement( css::uno::Reference const& xAttrs) override { m_rParser.HandleIdAttr(xAttrs); } virtual std::unique_ptr CreateChildContext( std::optional&& pOldNamespaceMap, sal_uInt16 const nNamespace, OUString const& rName) override { if (nNamespace == XML_NAMESPACE_DS && rName == "X509Data") { return std::make_unique(m_rParser, std::move(pOldNamespaceMap)); } // missing: ds:PGPData // missing: ds:KeyName, ds:KeyValue, ds:RetrievalMethod, ds:SPKIData, ds:MgmtData // (old code would read ds:Transform inside ds:RetrievalMethod but // presumably that was a bug) return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName); } }; class OOXMLSecParser::DsSignatureValueContext : public OOXMLSecParser::Context { private: OUString m_Value; public: DsSignatureValueContext(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap) : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap)) { } virtual void StartElement( css::uno::Reference const& xAttrs) override { m_rParser.HandleIdAttr(xAttrs); } virtual void EndElement() override { m_rParser.m_pXSecController->setSignatureValue(m_Value); } virtual void Characters(OUString const& rChars) override { m_Value += rChars; } }; class OOXMLSecParser::DsDigestValueContext : public OOXMLSecParser::Context { private: OUString & m_rValue; public: DsDigestValueContext(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap, OUString & rValue) : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap)) , m_rValue(rValue) { } virtual void StartElement( css::uno::Reference const& /*xAttrs*/) override { m_rValue.clear(); } virtual void Characters(OUString const& rChars) override { m_rValue += rChars; } }; class OOXMLSecParser::DsDigestMethodContext : public OOXMLSecParser::Context { private: sal_Int32 & m_rReferenceDigestID; public: DsDigestMethodContext(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap, sal_Int32& rReferenceDigestID) : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap)) , m_rReferenceDigestID(rReferenceDigestID) { } virtual void StartElement( css::uno::Reference const& xAttrs) override { OUString ouAlgorithm = xAttrs->getValueByName(u"Algorithm"_ustr); SAL_WARN_IF( ouAlgorithm.isEmpty(), "xmlsecurity.helper", "no Algorithm in Reference" ); if (ouAlgorithm.isEmpty()) return; SAL_WARN_IF( ouAlgorithm != ALGO_XMLDSIGSHA1 && ouAlgorithm != ALGO_XMLDSIGSHA256 && ouAlgorithm != ALGO_XMLDSIGSHA512, "xmlsecurity.helper", "Algorithm neither SHA1, SHA256 nor SHA512"); if (ouAlgorithm == ALGO_XMLDSIGSHA1) m_rReferenceDigestID = css::xml::crypto::DigestID::SHA1; else if (ouAlgorithm == ALGO_XMLDSIGSHA256) m_rReferenceDigestID = css::xml::crypto::DigestID::SHA256; else if (ouAlgorithm == ALGO_XMLDSIGSHA512) m_rReferenceDigestID = css::xml::crypto::DigestID::SHA512; else m_rReferenceDigestID = 0; } }; class OOXMLSecParser::DsTransformContext : public OOXMLSecParser::Context { private: bool & m_rIsC14N; public: DsTransformContext(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap, bool& rIsC14N) : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap)) , m_rIsC14N(rIsC14N) { } virtual void StartElement( css::uno::Reference const& xAttrs) override { OUString aAlgorithm = xAttrs->getValueByName(u"Algorithm"_ustr); if (aAlgorithm == ALGO_RELATIONSHIP) { m_rIsC14N = true; } } }; class OOXMLSecParser::DsTransformsContext : public OOXMLSecParser::Context { private: bool & m_rIsC14N; public: DsTransformsContext(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap, bool& rIsC14N) : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap)) , m_rIsC14N(rIsC14N) { } virtual std::unique_ptr CreateChildContext( std::optional&& pOldNamespaceMap, sal_uInt16 const nNamespace, OUString const& rName) override { if (nNamespace == XML_NAMESPACE_DS && rName == "Transform") { return std::make_unique(m_rParser, std::move(pOldNamespaceMap), m_rIsC14N); } return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName); } }; class OOXMLSecParser::DsReferenceContext : public OOXMLSecParser::Context { private: OUString m_URI; OUString m_Type; OUString m_DigestValue; bool m_IsC14N = false; // Relevant for ODF. The digest algorithm selected by the DigestMethod // element's Algorithm attribute. @see css::xml::crypto::DigestID. sal_Int32 m_nReferenceDigestID = css::xml::crypto::DigestID::SHA256; public: DsReferenceContext(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap) : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap)) { } virtual void StartElement( css::uno::Reference const& xAttrs) override { m_rParser.HandleIdAttr(xAttrs); m_URI = xAttrs->getValueByName(u"URI"_ustr); SAL_WARN_IF(m_URI.isEmpty(), "xmlsecurity.helper", "URI is empty"); // Remember the type of this reference. m_Type = xAttrs->getValueByName(u"Type"_ustr); } virtual void EndElement() override { if (m_URI.startsWith("#")) { /* * remove the first character '#' from the attribute value */ m_rParser.m_pXSecController->addReference(m_URI.copy(1), m_nReferenceDigestID, m_Type); } else { if (m_IsC14N) // this is determined by nested ds:Transform { m_rParser.m_pXSecController->addStreamReference(m_URI, false, m_nReferenceDigestID); } else /* * it must be an octet stream */ { m_rParser.m_pXSecController->addStreamReference(m_URI, true, m_nReferenceDigestID); } } m_rParser.m_pXSecController->setDigestValue(m_nReferenceDigestID, m_DigestValue); } virtual std::unique_ptr CreateChildContext( std::optional&& pOldNamespaceMap, sal_uInt16 const nNamespace, OUString const& rName) override { if (nNamespace == XML_NAMESPACE_DS && rName == "Transforms") { return std::make_unique(m_rParser, std::move(pOldNamespaceMap), m_IsC14N); } if (nNamespace == XML_NAMESPACE_DS && rName == "DigestMethod") { return std::make_unique(m_rParser, std::move(pOldNamespaceMap), m_nReferenceDigestID); } if (nNamespace == XML_NAMESPACE_DS && rName == "DigestValue") { return std::make_unique(m_rParser, std::move(pOldNamespaceMap), m_DigestValue); } return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName); } }; class OOXMLSecParser::DsSignatureMethodContext : public OOXMLSecParser::Context { public: DsSignatureMethodContext(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap) : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap)) { } virtual void StartElement( css::uno::Reference const& xAttrs) override { OUString ouAlgorithm = xAttrs->getValueByName(u"Algorithm"_ustr); if (ouAlgorithm == ALGO_ECDSASHA1 || ouAlgorithm == ALGO_ECDSASHA256 || ouAlgorithm == ALGO_ECDSASHA512) { m_rParser.m_pXSecController->setSignatureMethod(svl::crypto::SignatureMethodAlgorithm::ECDSA); } } }; class OOXMLSecParser::DsSignedInfoContext : public OOXMLSecParser::Context { public: DsSignedInfoContext(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap) : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap)) { } virtual void StartElement( css::uno::Reference const& xAttrs) override { m_rParser.HandleIdAttr(xAttrs); } virtual void EndElement() override { m_rParser.m_pXSecController->setReferenceCount(); } virtual std::unique_ptr CreateChildContext( std::optional&& pOldNamespaceMap, sal_uInt16 const nNamespace, OUString const& rName) override { if (nNamespace == XML_NAMESPACE_DS && rName == "SignatureMethod") { return std::make_unique(m_rParser, std::move(pOldNamespaceMap)); } if (nNamespace == XML_NAMESPACE_DS && rName == "Reference") { return std::make_unique(m_rParser, std::move(pOldNamespaceMap)); } // missing: ds:CanonicalizationMethod return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName); } }; class OOXMLSecParser::XadesCertDigestContext : public OOXMLSecParser::Context { private: OUString & m_rDigestValue; sal_Int32 & m_rReferenceDigestID; public: XadesCertDigestContext(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap, OUString& rDigestValue, sal_Int32& rReferenceDigestID) : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap)) , m_rDigestValue(rDigestValue) , m_rReferenceDigestID(rReferenceDigestID) { } virtual std::unique_ptr CreateChildContext( std::optional&& pOldNamespaceMap, sal_uInt16 const nNamespace, OUString const& rName) override { if (nNamespace == XML_NAMESPACE_DS && rName == "DigestMethod") { return std::make_unique(m_rParser, std::move(pOldNamespaceMap), m_rReferenceDigestID); } if (nNamespace == XML_NAMESPACE_DS && rName == "DigestValue") { return std::make_unique(m_rParser, std::move(pOldNamespaceMap), m_rDigestValue); } return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName); } }; class OOXMLSecParser::XadesCertContext : public OOXMLSecParser::ReferencedContextImpl { private: sal_Int32 m_nReferenceDigestID = css::xml::crypto::DigestID::SHA1; OUString m_CertDigest; OUString m_X509IssuerName; OUString m_X509SerialNumber; public: XadesCertContext(OOXMLSecParser& rParser, std::optional&& 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 CreateChildContext( std::optional&& pOldNamespaceMap, sal_uInt16 const nNamespace, OUString const& rName) override { if (nNamespace == XML_NAMESPACE_XADES132 && rName == "CertDigest") { return std::make_unique(m_rParser, std::move(pOldNamespaceMap), m_CertDigest, m_nReferenceDigestID); } if (nNamespace == XML_NAMESPACE_XADES132 && rName == "IssuerSerial") { return std::make_unique(m_rParser, std::move(pOldNamespaceMap), m_X509IssuerName, m_X509SerialNumber); } return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName); } }; class OOXMLSecParser::XadesSigningCertificateContext : public OOXMLSecParser::ReferencedContextImpl { public: XadesSigningCertificateContext(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap, bool const isReferenced) : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced) { } virtual std::unique_ptr CreateChildContext( std::optional&& pOldNamespaceMap, sal_uInt16 const nNamespace, OUString const& rName) override { if (nNamespace == XML_NAMESPACE_XADES132 && rName == "Cert") { return std::make_unique(m_rParser, std::move(pOldNamespaceMap), m_isReferenced); } return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName); } }; class OOXMLSecParser::XadesSigningTimeContext : public OOXMLSecParser::ReferencedContextImpl { private: OUString m_Value; public: XadesSigningTimeContext(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap, bool const isReferenced) : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced) { } virtual void EndElement() override { if (m_isReferenced) { m_rParser.m_pXSecController->setDate(u""_ustr, m_Value); } else { SAL_INFO("xmlsecurity.helper", "ignoring unsigned SigningTime"); } } virtual void Characters(OUString const& rChars) override { m_Value += rChars; } }; class OOXMLSecParser::XadesSignedSignaturePropertiesContext : public OOXMLSecParser::ReferencedContextImpl { public: XadesSignedSignaturePropertiesContext(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap, bool const isReferenced) : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced) { } virtual void StartElement( css::uno::Reference const& xAttrs) override { CheckIdAttrReferenced(xAttrs); } virtual std::unique_ptr CreateChildContext( std::optional&& pOldNamespaceMap, sal_uInt16 const nNamespace, OUString const& rName) override { if (nNamespace == XML_NAMESPACE_XADES132 && rName == "SigningTime") { return std::make_unique(m_rParser, std::move(pOldNamespaceMap), m_isReferenced); } if (nNamespace == XML_NAMESPACE_XADES132 && rName == "SigningCertificate") { return std::make_unique(m_rParser, std::move(pOldNamespaceMap), m_isReferenced); } // missing: xades:SignaturePolicyIdentifier, xades:SignatureProductionPlace, xades:SignerRole return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName); } }; class OOXMLSecParser::XadesSignedPropertiesContext : public OOXMLSecParser::ReferencedContextImpl { public: XadesSignedPropertiesContext(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap, bool const isReferenced) : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced) { } virtual void StartElement( css::uno::Reference const& xAttrs) override { CheckIdAttrReferenced(xAttrs); } virtual std::unique_ptr CreateChildContext( std::optional&& pOldNamespaceMap, sal_uInt16 const nNamespace, OUString const& rName) override { if (nNamespace == XML_NAMESPACE_XADES132 && rName == "SignedSignatureProperties") { return std::make_unique(m_rParser, std::move(pOldNamespaceMap), m_isReferenced); } // missing: xades:SignedDataObjectProperties return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName); } }; class OOXMLSecParser::XadesQualifyingPropertiesContext : public OOXMLSecParser::ReferencedContextImpl { public: XadesQualifyingPropertiesContext(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap, bool const isReferenced) : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced) { } virtual void StartElement( css::uno::Reference const& xAttrs) override { CheckIdAttrReferenced(xAttrs); } virtual std::unique_ptr CreateChildContext( std::optional&& pOldNamespaceMap, sal_uInt16 const nNamespace, OUString const& rName) override { if (nNamespace == XML_NAMESPACE_XADES132 && rName == "SignedProperties") { return std::make_unique(m_rParser, std::move(pOldNamespaceMap), m_isReferenced); } // missing: xades:UnsignedSignatureProperties return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName); } }; class OOXMLSecParser::MsodigsigSetupIDContext : public OOXMLSecParser::Context { private: OUString & m_rValue; public: MsodigsigSetupIDContext(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap, OUString& rValue) : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap)) , m_rValue(rValue) { } virtual void Characters(OUString const& rChars) override { m_rValue += rChars; } }; class OOXMLSecParser::MsodigsigSignatureCommentsContext : public OOXMLSecParser::Context { private: OUString & m_rValue; public: MsodigsigSignatureCommentsContext(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap, OUString& rValue) : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap)) , m_rValue(rValue) { } virtual void Characters(OUString const& rChars) override { m_rValue += rChars; } }; class OOXMLSecParser::MsodigsigSignatureInfoV1Context : public OOXMLSecParser::ReferencedContextImpl { private: OUString m_SetupID; OUString m_SignatureComments; public: MsodigsigSignatureInfoV1Context(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap, bool const isReferenced) : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced) { } virtual void StartElement( css::uno::Reference const& xAttrs) override { CheckIdAttrReferenced(xAttrs); } virtual std::unique_ptr CreateChildContext( std::optional&& pOldNamespaceMap, sal_uInt16 const nNamespace, OUString const& rName) override { if (nNamespace == XML_NAMESPACE_MSODIGSIG && rName == "SetupID") { return std::make_unique(m_rParser, std::move(pOldNamespaceMap), m_SetupID); } if (nNamespace == XML_NAMESPACE_MSODIGSIG && rName == "SignatureComments") { return std::make_unique(m_rParser, std::move(pOldNamespaceMap), m_SignatureComments); } return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName); } virtual void EndElement() override { if (m_isReferenced) { if (!m_SetupID.isEmpty()) { m_rParser.m_pXSecController->setSignatureLineId(m_SetupID); } if (!m_SignatureComments.isEmpty()) { m_rParser.m_pXSecController->setDescription(u""_ustr, m_SignatureComments); } } else { SAL_INFO("xmlsecurity.helper", "ignoring unsigned SignatureInfoV1"); } } }; class OOXMLSecParser::MdssiValueContext : public OOXMLSecParser::Context { private: OUString & m_rValue; public: MdssiValueContext(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap, OUString& rValue) : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap)) , m_rValue(rValue) { } virtual void Characters(OUString const& rChars) override { m_rValue += rChars; } }; class OOXMLSecParser::MdssiSignatureTimeContext : public OOXMLSecParser::Context { private: OUString & m_rValue; public: MdssiSignatureTimeContext(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap, OUString& rValue) : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap)) , m_rValue(rValue) { } virtual std::unique_ptr CreateChildContext( std::optional&& pOldNamespaceMap, sal_uInt16 const nNamespace, OUString const& rName) override { if (nNamespace == XML_NAMESPACE_MDSSI && rName == "Value") { return std::make_unique(m_rParser, std::move(pOldNamespaceMap), m_rValue); } return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName); } }; class OOXMLSecParser::DsSignaturePropertyContext : public OOXMLSecParser::ReferencedContextImpl { private: enum class SignatureProperty { Unknown, Date, Info }; SignatureProperty m_Property = SignatureProperty::Unknown; OUString m_Id; OUString m_Value; public: DsSignaturePropertyContext(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap, bool const isReferenced) : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced) { } virtual void StartElement( css::uno::Reference const& xAttrs) override { m_Id = CheckIdAttrReferenced(xAttrs); } virtual void EndElement() override { if (m_isReferenced) { switch (m_Property) { case SignatureProperty::Unknown: SAL_INFO("xmlsecurity.helper", "Unknown property in ds:Object ignored"); break; case SignatureProperty::Info: break; // handled by child context case SignatureProperty::Date: m_rParser.m_pXSecController->setDate(m_Id, m_Value); break; } } else { SAL_INFO("xmlsecurity.helper", "ignoring unsigned SignatureProperty"); } } virtual std::unique_ptr CreateChildContext( std::optional&& pOldNamespaceMap, sal_uInt16 const nNamespace, OUString const& rName) override { if (nNamespace == XML_NAMESPACE_MDSSI && rName == "SignatureTime") { m_Property = SignatureProperty::Date; return std::make_unique(m_rParser, std::move(pOldNamespaceMap), m_Value); } if (nNamespace == XML_NAMESPACE_MSODIGSIG && rName == "SignatureInfoV1") { return std::make_unique(m_rParser, std::move(pOldNamespaceMap), m_isReferenced); } return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName); } }; class OOXMLSecParser::DsSignaturePropertiesContext : public OOXMLSecParser::ReferencedContextImpl { public: DsSignaturePropertiesContext(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap, bool const isReferenced) : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced) { } virtual void StartElement( css::uno::Reference const& xAttrs) override { CheckIdAttrReferenced(xAttrs); } virtual std::unique_ptr CreateChildContext( std::optional&& pOldNamespaceMap, sal_uInt16 const nNamespace, OUString const& rName) override { if (nNamespace == XML_NAMESPACE_DS && rName == "SignatureProperty") { return std::make_unique(m_rParser, std::move(pOldNamespaceMap), m_isReferenced); } return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName); } }; class OOXMLSecParser::DsManifestContext : public OOXMLSecParser::ReferencedContextImpl { public: DsManifestContext(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap, bool const isReferenced) : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced) { } virtual void StartElement( css::uno::Reference const& xAttrs) override { CheckIdAttrReferenced(xAttrs); } #if 0 ??? virtual void EndElement() override { m_rParser.m_pXSecController->setReferenceCount(); } #endif virtual std::unique_ptr CreateChildContext( std::optional&& pOldNamespaceMap, sal_uInt16 const nNamespace, OUString const& rName) override { if (nNamespace == XML_NAMESPACE_DS && rName == "Reference") { return std::make_unique(m_rParser, std::move(pOldNamespaceMap)); } // missing: ds:CanonicalizationMethod return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName); } }; class OOXMLSecParser::DsObjectContext : public OOXMLSecParser::ReferencedContextImpl { enum class Mode { Default, ValidSignatureLineImage, InvalidSignatureLineImage }; Mode m_Mode = Mode::Default; OUString m_Value; public: DsObjectContext(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap) // init with "false" here - the Signature element can't be referenced by its child : OOXMLSecParser::ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), false) { } virtual void StartElement( css::uno::Reference const& xAttrs) override { OUString const id(CheckIdAttrReferenced(xAttrs)); if (id == "idValidSigLnImg") { m_Mode = Mode::ValidSignatureLineImage; } else if (id == "idInvalidSigLnImg") { m_Mode = Mode::InvalidSignatureLineImage; } } virtual void EndElement() override { switch (m_Mode) { case Mode::ValidSignatureLineImage: if (m_isReferenced) { m_rParser.m_pXSecController->setValidSignatureImage(m_Value); } else { SAL_INFO("xmlsecurity.helper", "ignoring unsigned SignatureLineValidImage"); } break; case Mode::InvalidSignatureLineImage: if (m_isReferenced) { m_rParser.m_pXSecController->setInvalidSignatureImage(m_Value); } else { SAL_INFO("xmlsecurity.helper", "ignoring unsigned SignatureLineInvalidImage"); } break; case Mode::Default: break; } } virtual void Characters(OUString const& rChars) override { m_Value += rChars; } virtual std::unique_ptr CreateChildContext( std::optional&& pOldNamespaceMap, sal_uInt16 const nNamespace, OUString const& rName) override { if (nNamespace == XML_NAMESPACE_DS && rName == "SignatureProperties") { return std::make_unique(m_rParser, std::move(pOldNamespaceMap), m_isReferenced); } if (nNamespace == XML_NAMESPACE_XADES132 && rName == "QualifyingProperties") { return std::make_unique(m_rParser, std::move(pOldNamespaceMap), m_isReferenced); } if (nNamespace == XML_NAMESPACE_DS && rName == "Manifest") { return std::make_unique(m_rParser, std::move(pOldNamespaceMap), m_isReferenced); } return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName); } }; class OOXMLSecParser::DsSignatureContext : public OOXMLSecParser::Context { public: DsSignatureContext(OOXMLSecParser& rParser, std::optional&& pOldNamespaceMap) : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap)) { } virtual void StartElement( css::uno::Reference const& xAttrs) override { OUString const ouIdAttr(m_rParser.HandleIdAttr(xAttrs)); m_rParser.m_rXMLSignatureHelper.StartVerifySignatureElement(); m_rParser.m_pXSecController->addSignature(); if (!ouIdAttr.isEmpty()) { m_rParser.m_pXSecController->setId( ouIdAttr ); } } virtual std::unique_ptr CreateChildContext( std::optional&& pOldNamespaceMap, sal_uInt16 const nNamespace, OUString const& rName) override { if (nNamespace == XML_NAMESPACE_DS && rName == "SignedInfo") { return std::make_unique(m_rParser, std::move(pOldNamespaceMap)); } if (nNamespace == XML_NAMESPACE_DS && rName == "SignatureValue") { return std::make_unique(m_rParser, std::move(pOldNamespaceMap)); } if (nNamespace == XML_NAMESPACE_DS && rName == "KeyInfo") { return std::make_unique(m_rParser, std::move(pOldNamespaceMap)); } if (nNamespace == XML_NAMESPACE_DS && rName == "Object") { return std::make_unique(m_rParser, std::move(pOldNamespaceMap)); } return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName); } }; OOXMLSecParser::OOXMLSecParser(XMLSignatureHelper& rXMLSignatureHelper, XSecController* pXSecController) : m_pNamespaceMap(SvXMLNamespaceMap()) , m_pXSecController(pXSecController) ,m_rXMLSignatureHelper(rXMLSignatureHelper) { using namespace xmloff::token; m_pNamespaceMap->Add( GetXMLToken(XML_XML), GetXMLToken(XML_N_XML), XML_NAMESPACE_XML ); m_pNamespaceMap->Add( u"_ds"_ustr, GetXMLToken(XML_N_DS), XML_NAMESPACE_DS ); m_pNamespaceMap->Add( u"_xades132"_ustr, GetXMLToken(XML_N_XADES132), XML_NAMESPACE_XADES132); m_pNamespaceMap->Add( u"_xades141"_ustr, GetXMLToken(XML_N_XADES141), XML_NAMESPACE_XADES141); m_pNamespaceMap->Add( u"_dc"_ustr, GetXMLToken(XML_N_DC), XML_NAMESPACE_DC ); m_pNamespaceMap->Add( u"_mdssi"_ustr, NS_MDSSI, XML_NAMESPACE_MDSSI ); m_pNamespaceMap->Add( u"_msodigsig"_ustr, u"http://schemas.microsoft.com/office/2006/digsig"_ustr, XML_NAMESPACE_MSODIGSIG ); m_pNamespaceMap->Add( u"_office_libo"_ustr, GetXMLToken(XML_N_LO_EXT), XML_NAMESPACE_LO_EXT); } OOXMLSecParser::~OOXMLSecParser() { } OUString OOXMLSecParser::HandleIdAttr(css::uno::Reference const& xAttrs) { OUString const aId = xAttrs->getValueByName(u"Id"_ustr); if (!aId.isEmpty()) { m_pXSecController->collectToVerify(aId); } return aId; } void SAL_CALL OOXMLSecParser::startDocument() { if (m_xNextHandler.is()) m_xNextHandler->startDocument(); } void SAL_CALL OOXMLSecParser::endDocument() { if (m_xNextHandler.is()) m_xNextHandler->endDocument(); } void SAL_CALL OOXMLSecParser::startElement(const OUString& rName, const uno::Reference& xAttribs) { assert(m_pNamespaceMap); std::optional pRewindMap( SvXMLImport::processNSAttributes(m_pNamespaceMap, nullptr, xAttribs)); OUString localName; sal_uInt16 const nPrefix(m_pNamespaceMap->GetKeyByAttrName(rName, &localName)); std::unique_ptr pContext; if (m_ContextStack.empty()) { if (nPrefix != XML_NAMESPACE_DS || localName != "Signature") { throw css::xml::sax::SAXException( u"xmlsecurity: unexpected root element"_ustr, nullptr, css::uno::Any()); } pContext.reset(new DsSignatureContext(*this, std::move(pRewindMap))); } else { pContext = m_ContextStack.top()->CreateChildContext( std::move(pRewindMap), nPrefix, localName); } m_ContextStack.push(std::move(pContext)); m_ContextStack.top()->StartElement(xAttribs); if (m_xNextHandler.is()) { m_xNextHandler->startElement(rName, xAttribs); } } void SAL_CALL OOXMLSecParser::endElement(const OUString& rName) { assert(!m_ContextStack.empty()); // this should be checked by sax parser? m_ContextStack.top()->EndElement(); if (m_xNextHandler.is()) { m_xNextHandler->endElement(rName); } if (m_ContextStack.top()->m_pOldNamespaceMap) { m_pNamespaceMap = std::move(m_ContextStack.top()->m_pOldNamespaceMap); } m_ContextStack.pop(); } void SAL_CALL OOXMLSecParser::characters(const OUString& rChars) { assert(!m_ContextStack.empty()); // this should be checked by sax parser? m_ContextStack.top()->Characters(rChars); if (m_xNextHandler.is()) m_xNextHandler->characters(rChars); } void SAL_CALL OOXMLSecParser::ignorableWhitespace(const OUString& rWhitespace) { if (m_xNextHandler.is()) m_xNextHandler->ignorableWhitespace(rWhitespace); } void SAL_CALL OOXMLSecParser::processingInstruction(const OUString& rTarget, const OUString& rData) { if (m_xNextHandler.is()) m_xNextHandler->processingInstruction(rTarget, rData); } void SAL_CALL OOXMLSecParser::setDocumentLocator(const uno::Reference& xLocator) { if (m_xNextHandler.is()) m_xNextHandler->setDocumentLocator(xLocator); } void SAL_CALL OOXMLSecParser::initialize(const uno::Sequence& rArguments) { rArguments[0] >>= m_xNextHandler; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */