diff options
Diffstat (limited to 'xmlsecurity/source/helper/xsecparser.cxx')
-rw-r--r-- | xmlsecurity/source/helper/xsecparser.cxx | 530 |
1 files changed, 530 insertions, 0 deletions
diff --git a/xmlsecurity/source/helper/xsecparser.cxx b/xmlsecurity/source/helper/xsecparser.cxx new file mode 100644 index 000000000..9f2bbe074 --- /dev/null +++ b/xmlsecurity/source/helper/xsecparser.cxx @@ -0,0 +1,530 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "xsecparser.hxx" +#include <xsecctl.hxx> +#include <xmlsignaturehelper.hxx> +#include <com/sun/star/xml/sax/SAXException.hpp> +#include <cppuhelper/exc_hlp.hxx> +#include <sal/log.hxx> + + +XSecParser::XSecParser(XMLSignatureHelper& rXMLSignatureHelper, + XSecController* pXSecController) + : m_bInX509IssuerName(false) + , m_bInX509SerialNumber(false) + , m_bInX509Certificate(false) + , m_bInGpgCertificate(false) + , m_bInGpgKeyID(false) + , m_bInGpgOwner(false) + , m_bInCertDigest(false) + , m_bInEncapsulatedX509Certificate(false) + , m_bInSigningTime(false) + , m_bInDigestValue(false) + , m_bInSignatureValue(false) + , m_bInDate(false) + , m_bInDescription(false) + , m_bInSignatureLineId(false) + , m_bInSignatureLineValidImage(false) + , m_bInSignatureLineInvalidImage(false) + , m_pXSecController(pXSecController) + , m_bReferenceUnresolved(false) + , m_nReferenceDigestID(css::xml::crypto::DigestID::SHA1) + , m_rXMLSignatureHelper(rXMLSignatureHelper) +{ +} + +OUString XSecParser::getIdAttr(const css::uno::Reference< css::xml::sax::XAttributeList >& xAttribs ) +{ + OUString ouIdAttr = xAttribs->getValueByName("id"); + + if (ouIdAttr.isEmpty()) + { + ouIdAttr = xAttribs->getValueByName("Id"); + } + + return ouIdAttr; +} + +/* + * XDocumentHandler + */ +void SAL_CALL XSecParser::startDocument( ) +{ + m_bInX509IssuerName = false; + m_bInX509SerialNumber = false; + m_bInX509Certificate = false; + m_bInGpgCertificate = false; + m_bInGpgKeyID = false; + m_bInGpgOwner = false; + m_bInSignatureValue = false; + m_bInDigestValue = false; + m_bInDate = false; + m_bInDescription = false; + + if (m_xNextHandler.is()) + { + m_xNextHandler->startDocument(); + } +} + +void SAL_CALL XSecParser::endDocument( ) +{ + if (m_xNextHandler.is()) + { + m_xNextHandler->endDocument(); + } +} + +void SAL_CALL XSecParser::startElement( + const OUString& aName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttribs ) +{ + try + { + OUString ouIdAttr = getIdAttr(xAttribs); + if (!ouIdAttr.isEmpty()) + { + m_pXSecController->collectToVerify( ouIdAttr ); + } + + if ( aName == "Signature" ) + { + m_rXMLSignatureHelper.StartVerifySignatureElement(); + m_pXSecController->addSignature(); + if (!ouIdAttr.isEmpty()) + { + m_pXSecController->setId( ouIdAttr ); + } + } + else if (aName == "SignatureMethod") + { + OUString ouAlgorithm = xAttribs->getValueByName("Algorithm"); + if (ouAlgorithm == ALGO_ECDSASHA1 || ouAlgorithm == ALGO_ECDSASHA256 + || ouAlgorithm == ALGO_ECDSASHA512) + m_pXSecController->setSignatureMethod(svl::crypto::SignatureMethodAlgorithm::ECDSA); + } + else if ( aName == "Reference" ) + { + OUString ouUri = xAttribs->getValueByName("URI"); + SAL_WARN_IF( ouUri.isEmpty(), "xmlsecurity.helper", "URI is empty" ); + // Remember the type of this reference. + OUString ouType = xAttribs->getValueByName("Type"); + if (ouUri.startsWith("#")) + { + /* + * remove the first character '#' from the attribute value + */ + m_pXSecController->addReference( ouUri.copy(1), m_nReferenceDigestID, ouType ); + } + else + { + /* + * remember the uri + */ + m_currentReferenceURI = ouUri; + m_bReferenceUnresolved = true; + } + } + else if (aName == "DigestMethod") + { + OUString ouAlgorithm = xAttribs->getValueByName("Algorithm"); + + SAL_WARN_IF( ouAlgorithm.isEmpty(), "xmlsecurity.helper", "no Algorithm in Reference" ); + if (!ouAlgorithm.isEmpty()) + { + 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_nReferenceDigestID = css::xml::crypto::DigestID::SHA1; + else if (ouAlgorithm == ALGO_XMLDSIGSHA256) + m_nReferenceDigestID = css::xml::crypto::DigestID::SHA256; + else if (ouAlgorithm == ALGO_XMLDSIGSHA512) + m_nReferenceDigestID = css::xml::crypto::DigestID::SHA512; + else + m_nReferenceDigestID = 0; + } + } + else if (aName == "Transform") + { + if ( m_bReferenceUnresolved ) + { + OUString ouAlgorithm = xAttribs->getValueByName("Algorithm"); + + if (ouAlgorithm == ALGO_C14N) + /* + * a xml stream + */ + { + m_pXSecController->addStreamReference( m_currentReferenceURI, false, m_nReferenceDigestID ); + m_bReferenceUnresolved = false; + } + } + } + else if (aName == "X509IssuerName") + { + m_ouX509IssuerName.clear(); + m_bInX509IssuerName = true; + } + else if (aName == "X509SerialNumber") + { + m_ouX509SerialNumber.clear(); + m_bInX509SerialNumber = true; + } + else if (aName == "X509Certificate") + { + m_ouX509Certificate.clear(); + m_bInX509Certificate = true; + } + else if (aName == "PGPData") + { + m_pXSecController->switchGpgSignature(); + } + else if (aName == "PGPKeyID") + { + m_ouGpgKeyID.clear(); + m_bInGpgKeyID = true; + } + else if (aName == "PGPKeyPacket") + { + m_ouGpgCertificate.clear(); + m_bInGpgCertificate = true; + } + else if (aName == "loext:PGPOwner") + { + m_ouGpgOwner.clear(); + m_bInGpgOwner = true; + } + else if (aName == "SignatureValue") + { + m_ouSignatureValue.clear(); + m_bInSignatureValue = true; + } + else if (aName == "DigestValue" && !m_bInCertDigest) + { + m_ouDigestValue.clear(); + m_bInDigestValue = true; + } + else if (aName == "xd:CertDigest") + { + m_ouCertDigest.clear(); + m_bInCertDigest = true; + } + // FIXME: Existing code here in xmlsecurity uses "xd" as the namespace prefix for XAdES, + // while the sample document attached to tdf#76142 uses "xades". So accept either here. Of + // course this is idiotic and wrong, the right thing would be to use a proper way to parse + // XML that would handle namespaces correctly. I have no idea how substantial re-plumbing of + // this code that would require. + else if (aName == "xd:EncapsulatedX509Certificate" || aName == "xades:EncapsulatedX509Certificate") + { + m_ouEncapsulatedX509Certificate.clear(); + m_bInEncapsulatedX509Certificate = true; + } + else if (aName == "xd:SigningTime" || aName == "xades:SigningTime") + { + m_ouDate.clear(); + m_bInSigningTime = true; + } + else if ( aName == "SignatureProperty" ) + { + if (!ouIdAttr.isEmpty()) + { + m_pXSecController->setPropertyId( ouIdAttr ); + } + } + else if (aName == "dc:date") + { + if (m_ouDate.isEmpty()) + m_bInDate = true; + } + else if (aName == "dc:description") + { + m_ouDescription.clear(); + m_bInDescription = true; + } + else if (aName == "loext:SignatureLineId") + { + m_ouSignatureLineId.clear(); + m_bInSignatureLineId = true; + } + else if (aName == "loext:SignatureLineValidImage") + { + m_ouSignatureLineValidImage.clear(); + m_bInSignatureLineValidImage = true; + } + else if (aName == "loext:SignatureLineInvalidImage") + { + m_ouSignatureLineInvalidImage.clear(); + m_bInSignatureLineInvalidImage = true; + } + + if (m_xNextHandler.is()) + { + m_xNextHandler->startElement(aName, xAttribs); + } + } + catch (css::uno::Exception& ) + {//getCaughtException MUST be the first line in the catch block + css::uno::Any exc = cppu::getCaughtException(); + throw css::xml::sax::SAXException( + "xmlsecurity: Exception in XSecParser::startElement", + nullptr, exc); + } + catch (...) + { + throw css::xml::sax::SAXException( + "xmlsecurity: unexpected exception in XSecParser::startElement", nullptr, + css::uno::Any()); + } +} + +void SAL_CALL XSecParser::endElement( const OUString& aName ) +{ + try + { + if (aName == "DigestValue" && !m_bInCertDigest) + { + m_bInDigestValue = false; + } + else if ( aName == "Reference" ) + { + if ( m_bReferenceUnresolved ) + /* + * it must be an octet stream + */ + { + m_pXSecController->addStreamReference( m_currentReferenceURI, true, m_nReferenceDigestID ); + m_bReferenceUnresolved = false; + } + + m_pXSecController->setDigestValue( m_nReferenceDigestID, m_ouDigestValue ); + } + else if ( aName == "SignedInfo" ) + { + m_pXSecController->setReferenceCount(); + } + else if ( aName == "SignatureValue" ) + { + m_pXSecController->setSignatureValue( m_ouSignatureValue ); + m_bInSignatureValue = false; + } + else if (aName == "X509IssuerName") + { + m_pXSecController->setX509IssuerName( m_ouX509IssuerName ); + m_bInX509IssuerName = false; + } + else if (aName == "X509SerialNumber") + { + m_pXSecController->setX509SerialNumber( m_ouX509SerialNumber ); + m_bInX509SerialNumber = false; + } + else if (aName == "X509Certificate") + { + m_pXSecController->setX509Certificate( m_ouX509Certificate ); + m_bInX509Certificate = false; + } + else if (aName == "PGPKeyID") + { + m_pXSecController->setGpgKeyID( m_ouGpgKeyID ); + m_bInGpgKeyID = false; + } + else if (aName == "PGPKeyPacket") + { + m_pXSecController->setGpgCertificate( m_ouGpgCertificate ); + m_bInGpgCertificate = false; + } + else if (aName == "loext:PGPOwner") + { + m_pXSecController->setGpgOwner( m_ouGpgOwner ); + m_bInGpgOwner = false; + } + else if (aName == "xd:CertDigest") + { + m_pXSecController->setCertDigest( m_ouCertDigest ); + m_bInCertDigest = false; + } + else if (aName == "xd:EncapsulatedX509Certificate" || aName == "xades:EncapsulatedX509Certificate") + { + m_pXSecController->addEncapsulatedX509Certificate( m_ouEncapsulatedX509Certificate ); + m_bInEncapsulatedX509Certificate = false; + } + else if (aName == "xd:SigningTime" || aName == "xades:SigningTime") + { + m_pXSecController->setDate( m_ouDate ); + m_bInSigningTime = false; + } + else if (aName == "dc:date") + { + if (m_bInDate) + { + m_pXSecController->setDate( m_ouDate ); + m_bInDate = false; + } + } + else if (aName == "dc:description") + { + m_pXSecController->setDescription( m_ouDescription ); + m_bInDescription = false; + } + else if (aName == "loext:SignatureLineId") + { + m_pXSecController->setSignatureLineId( m_ouSignatureLineId ); + m_bInSignatureLineId = false; + } + else if (aName == "loext:SignatureLineValidImage") + { + m_pXSecController->setValidSignatureImage( m_ouSignatureLineValidImage ); + m_bInSignatureLineValidImage = false; + } + else if (aName == "loext:SignatureLineInvalidImage") + { + m_pXSecController->setInvalidSignatureImage( m_ouSignatureLineInvalidImage ); + m_bInSignatureLineInvalidImage = false; + } + + if (m_xNextHandler.is()) + { + m_xNextHandler->endElement(aName); + } + } + catch (css::uno::Exception& ) + {//getCaughtException MUST be the first line in the catch block + css::uno::Any exc = cppu::getCaughtException(); + throw css::xml::sax::SAXException( + "xmlsecurity: Exception in XSecParser::endElement", + nullptr, exc); + } + catch (...) + { + throw css::xml::sax::SAXException( + "xmlsecurity: unexpected exception in XSecParser::endElement", nullptr, + css::uno::Any()); + } +} + +void SAL_CALL XSecParser::characters( const OUString& aChars ) +{ + if (m_bInX509IssuerName) + { + m_ouX509IssuerName += aChars; + } + else if (m_bInX509SerialNumber) + { + m_ouX509SerialNumber += aChars; + } + else if (m_bInX509Certificate) + { + m_ouX509Certificate += aChars; + } + else if (m_bInGpgCertificate) + { + m_ouGpgCertificate += aChars; + } + else if (m_bInGpgKeyID) + { + m_ouGpgKeyID += aChars; + } + else if (m_bInGpgOwner) + { + m_ouGpgOwner += aChars; + } + else if (m_bInSignatureValue) + { + m_ouSignatureValue += aChars; + } + else if (m_bInDigestValue && !m_bInCertDigest) + { + m_ouDigestValue += aChars; + } + else if (m_bInDate) + { + m_ouDate += aChars; + } + else if (m_bInDescription) + { + m_ouDescription += aChars; + } + else if (m_bInCertDigest) + { + m_ouCertDigest += aChars; + } + else if (m_bInEncapsulatedX509Certificate) + { + m_ouEncapsulatedX509Certificate += aChars; + } + else if (m_bInSigningTime) + { + m_ouDate += aChars; + } + else if (m_bInSignatureLineId) + { + m_ouSignatureLineId += aChars; + } + else if (m_bInSignatureLineValidImage) + { + m_ouSignatureLineValidImage += aChars; + } + else if (m_bInSignatureLineInvalidImage) + { + m_ouSignatureLineInvalidImage += aChars; + } + + if (m_xNextHandler.is()) + { + m_xNextHandler->characters(aChars); + } +} + +void SAL_CALL XSecParser::ignorableWhitespace( const OUString& aWhitespaces ) +{ + if (m_xNextHandler.is()) + { + m_xNextHandler->ignorableWhitespace( aWhitespaces ); + } +} + +void SAL_CALL XSecParser::processingInstruction( const OUString& aTarget, const OUString& aData ) +{ + if (m_xNextHandler.is()) + { + m_xNextHandler->processingInstruction(aTarget, aData); + } +} + +void SAL_CALL XSecParser::setDocumentLocator( const css::uno::Reference< css::xml::sax::XLocator >& xLocator ) +{ + if (m_xNextHandler.is()) + { + m_xNextHandler->setDocumentLocator( xLocator ); + } +} + +/* + * XInitialization + */ +void SAL_CALL XSecParser::initialize( + const css::uno::Sequence< css::uno::Any >& aArguments ) +{ + aArguments[0] >>= m_xNextHandler; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |