1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "xsecparser.hxx"
22 #include <xmlsignaturehelper.hxx>
23 #include <com/sun/star/xml/sax/SAXException.hpp>
24 #include <cppuhelper/exc_hlp.hxx>
28 namespace cssu
= com::sun::star::uno
;
29 namespace cssxc
= com::sun::star::xml::crypto
;
30 namespace cssxs
= com::sun::star::xml::sax
;
32 XSecParser::XSecParser(XMLSignatureHelper
& rXMLSignatureHelper
,
33 XSecController
* pXSecController
)
34 : m_bInX509IssuerName(false)
35 , m_bInX509SerialNumber(false)
36 , m_bInX509Certificate(false)
37 , m_bInGpgCertificate(false)
38 , m_bInGpgKeyID(false)
39 , m_bInGpgOwner(false)
40 , m_bInCertDigest(false)
41 , m_bInEncapsulatedX509Certificate(false)
42 , m_bInSigningTime(false)
43 , m_bInDigestValue(false)
44 , m_bInSignatureValue(false)
46 , m_bInDescription(false)
47 , m_bInSignatureLineId(false)
48 , m_pXSecController(pXSecController
)
49 , m_bReferenceUnresolved(false)
50 , m_nReferenceDigestID(cssxc::DigestID::SHA1
)
51 , m_rXMLSignatureHelper(rXMLSignatureHelper
)
55 OUString
XSecParser::getIdAttr(const cssu::Reference
< cssxs::XAttributeList
>& xAttribs
)
57 OUString ouIdAttr
= xAttribs
->getValueByName("id");
59 if (ouIdAttr
.isEmpty())
61 ouIdAttr
= xAttribs
->getValueByName("Id");
70 void SAL_CALL
XSecParser::startDocument( )
72 m_bInX509IssuerName
= false;
73 m_bInX509SerialNumber
= false;
74 m_bInX509Certificate
= false;
75 m_bInGpgCertificate
= false;
76 m_bInGpgKeyID
= false;
77 m_bInGpgOwner
= false;
78 m_bInSignatureValue
= false;
79 m_bInDigestValue
= false;
81 m_bInDescription
= false;
83 if (m_xNextHandler
.is())
85 m_xNextHandler
->startDocument();
89 void SAL_CALL
XSecParser::endDocument( )
91 if (m_xNextHandler
.is())
93 m_xNextHandler
->endDocument();
97 void SAL_CALL
XSecParser::startElement(
98 const OUString
& aName
,
99 const cssu::Reference
< cssxs::XAttributeList
>& xAttribs
)
103 OUString ouIdAttr
= getIdAttr(xAttribs
);
104 if (!ouIdAttr
.isEmpty())
106 m_pXSecController
->collectToVerify( ouIdAttr
);
109 if ( aName
== "Signature" )
111 m_rXMLSignatureHelper
.StartVerifySignatureElement();
112 m_pXSecController
->addSignature();
113 if (!ouIdAttr
.isEmpty())
115 m_pXSecController
->setId( ouIdAttr
);
118 else if ( aName
== "Reference" )
120 OUString ouUri
= xAttribs
->getValueByName("URI");
121 SAL_WARN_IF( ouUri
.isEmpty(), "xmlsecurity.helper", "URI is empty" );
122 if (ouUri
.startsWith("#"))
125 * remove the first character '#' from the attribute value
127 m_pXSecController
->addReference( ouUri
.copy(1), m_nReferenceDigestID
);
134 m_currentReferenceURI
= ouUri
;
135 m_bReferenceUnresolved
= true;
138 else if (aName
== "DigestMethod")
140 OUString ouAlgorithm
= xAttribs
->getValueByName("Algorithm");
142 SAL_WARN_IF( ouAlgorithm
.isEmpty(), "xmlsecurity.helper", "no Algorithm in Reference" );
143 if (!ouAlgorithm
.isEmpty())
145 SAL_WARN_IF( ouAlgorithm
!= ALGO_XMLDSIGSHA1
146 && ouAlgorithm
!= ALGO_XMLDSIGSHA256
147 && ouAlgorithm
!= ALGO_XMLDSIGSHA512
,
148 "xmlsecurity.helper", "Algorithm neither SHA1, SHA256 nor SHA512");
149 if (ouAlgorithm
== ALGO_XMLDSIGSHA1
)
150 m_nReferenceDigestID
= cssxc::DigestID::SHA1
;
151 else if (ouAlgorithm
== ALGO_XMLDSIGSHA256
)
152 m_nReferenceDigestID
= cssxc::DigestID::SHA256
;
153 else if (ouAlgorithm
== ALGO_XMLDSIGSHA512
)
154 m_nReferenceDigestID
= cssxc::DigestID::SHA512
;
156 m_nReferenceDigestID
= 0;
159 else if (aName
== "Transform")
161 if ( m_bReferenceUnresolved
)
163 OUString ouAlgorithm
= xAttribs
->getValueByName("Algorithm");
165 if (ouAlgorithm
== ALGO_C14N
)
170 m_pXSecController
->addStreamReference( m_currentReferenceURI
, false, m_nReferenceDigestID
);
171 m_bReferenceUnresolved
= false;
175 else if (aName
== "X509IssuerName")
177 m_ouX509IssuerName
.clear();
178 m_bInX509IssuerName
= true;
180 else if (aName
== "X509SerialNumber")
182 m_ouX509SerialNumber
.clear();
183 m_bInX509SerialNumber
= true;
185 else if (aName
== "X509Certificate")
187 m_ouX509Certificate
.clear();
188 m_bInX509Certificate
= true;
190 else if (aName
== "PGPData")
192 m_pXSecController
->switchGpgSignature();
194 else if (aName
== "PGPKeyID")
196 m_ouGpgKeyID
.clear();
197 m_bInGpgKeyID
= true;
199 else if (aName
== "PGPKeyPacket")
201 m_ouGpgCertificate
.clear();
202 m_bInGpgCertificate
= true;
204 else if (aName
== "loext:PGPOwner")
206 m_ouGpgOwner
.clear();
207 m_bInGpgOwner
= true;
209 else if (aName
== "SignatureValue")
211 m_ouSignatureValue
.clear();
212 m_bInSignatureValue
= true;
214 else if (aName
== "DigestValue" && !m_bInCertDigest
)
216 m_ouDigestValue
.clear();
217 m_bInDigestValue
= true;
219 else if (aName
== "xd:CertDigest")
221 m_ouCertDigest
.clear();
222 m_bInCertDigest
= true;
224 // FIXME: Existing code here in xmlsecurity uses "xd" as the namespace prefix for XAdES,
225 // while the sample document attached to tdf#76142 uses "xades". So accept either here. Of
226 // course this is idiotic and wrong, the right thing would be to use a proper way to parse
227 // XML that would handle namespaces correctly. I have no idea how substantial re-plumbing of
228 // this code that would require.
229 else if (aName
== "xd:EncapsulatedX509Certificate" || aName
== "xades:EncapsulatedX509Certificate")
231 m_ouEncapsulatedX509Certificate
.clear();
232 m_bInEncapsulatedX509Certificate
= true;
234 else if (aName
== "xd:SigningTime" || aName
== "xades:SigningTime")
237 m_bInSigningTime
= true;
239 else if ( aName
== "SignatureProperty" )
241 if (!ouIdAttr
.isEmpty())
243 m_pXSecController
->setPropertyId( ouIdAttr
);
246 else if (aName
== "dc:date")
248 if (m_ouDate
.isEmpty())
251 else if (aName
== "dc:description")
253 m_ouDescription
.clear();
254 m_bInDescription
= true;
256 else if (aName
== "loext:SignatureLineId")
258 m_ouSignatureLineId
.clear();
259 m_bInSignatureLineId
= true;
262 if (m_xNextHandler
.is())
264 m_xNextHandler
->startElement(aName
, xAttribs
);
267 catch (cssu::Exception
& )
268 {//getCaughtException MUST be the first line in the catch block
269 cssu::Any exc
= cppu::getCaughtException();
270 throw cssxs::SAXException(
271 "xmlsecurity: Exception in XSecParser::startElement",
276 throw cssxs::SAXException(
277 "xmlsecurity: unexpected exception in XSecParser::startElement", nullptr,
282 void SAL_CALL
XSecParser::endElement( const OUString
& aName
)
286 if (aName
== "DigestValue" && !m_bInCertDigest
)
288 m_bInDigestValue
= false;
290 else if ( aName
== "Reference" )
292 if ( m_bReferenceUnresolved
)
294 * it must be a octet stream
297 m_pXSecController
->addStreamReference( m_currentReferenceURI
, true, m_nReferenceDigestID
);
298 m_bReferenceUnresolved
= false;
301 m_pXSecController
->setDigestValue( m_nReferenceDigestID
, m_ouDigestValue
);
303 else if ( aName
== "SignedInfo" )
305 m_pXSecController
->setReferenceCount();
307 else if ( aName
== "SignatureValue" )
309 m_pXSecController
->setSignatureValue( m_ouSignatureValue
);
310 m_bInSignatureValue
= false;
312 else if (aName
== "X509IssuerName")
314 m_pXSecController
->setX509IssuerName( m_ouX509IssuerName
);
315 m_bInX509IssuerName
= false;
317 else if (aName
== "X509SerialNumber")
319 m_pXSecController
->setX509SerialNumber( m_ouX509SerialNumber
);
320 m_bInX509SerialNumber
= false;
322 else if (aName
== "X509Certificate")
324 m_pXSecController
->setX509Certificate( m_ouX509Certificate
);
325 m_bInX509Certificate
= false;
327 else if (aName
== "PGPKeyID")
329 m_pXSecController
->setGpgKeyID( m_ouGpgKeyID
);
330 m_bInGpgKeyID
= false;
332 else if (aName
== "PGPKeyPacket")
334 m_pXSecController
->setGpgCertificate( m_ouGpgCertificate
);
335 m_bInGpgCertificate
= false;
337 else if (aName
== "loext:PGPOwner")
339 m_pXSecController
->setGpgOwner( m_ouGpgOwner
);
340 m_bInGpgOwner
= false;
342 else if (aName
== "xd:CertDigest")
344 m_pXSecController
->setCertDigest( m_ouCertDigest
);
345 m_bInCertDigest
= false;
347 else if (aName
== "xd:EncapsulatedX509Certificate" || aName
== "xades:EncapsulatedX509Certificate")
349 m_pXSecController
->addEncapsulatedX509Certificate( m_ouEncapsulatedX509Certificate
);
350 m_bInEncapsulatedX509Certificate
= false;
352 else if (aName
== "xd:SigningTime" || aName
== "xades:SigningTime")
354 m_pXSecController
->setDate( m_ouDate
);
355 m_bInSigningTime
= false;
357 else if (aName
== "dc:date")
361 m_pXSecController
->setDate( m_ouDate
);
365 else if (aName
== "dc:description")
367 m_pXSecController
->setDescription( m_ouDescription
);
368 m_bInDescription
= false;
370 else if (aName
== "loext:SignatureLineId")
372 m_pXSecController
->setSignatureLineId( m_ouSignatureLineId
);
373 m_bInSignatureLineId
= false;
376 if (m_xNextHandler
.is())
378 m_xNextHandler
->endElement(aName
);
381 catch (cssu::Exception
& )
382 {//getCaughtException MUST be the first line in the catch block
383 cssu::Any exc
= cppu::getCaughtException();
384 throw cssxs::SAXException(
385 "xmlsecurity: Exception in XSecParser::endElement",
390 throw cssxs::SAXException(
391 "xmlsecurity: unexpected exception in XSecParser::endElement", nullptr,
396 void SAL_CALL
XSecParser::characters( const OUString
& aChars
)
398 if (m_bInX509IssuerName
)
400 m_ouX509IssuerName
+= aChars
;
402 else if (m_bInX509SerialNumber
)
404 m_ouX509SerialNumber
+= aChars
;
406 else if (m_bInX509Certificate
)
408 m_ouX509Certificate
+= aChars
;
410 else if (m_bInGpgCertificate
)
412 m_ouGpgCertificate
+= aChars
;
414 else if (m_bInGpgKeyID
)
416 m_ouGpgKeyID
+= aChars
;
418 else if (m_bInGpgOwner
)
420 m_ouGpgOwner
+= aChars
;
422 else if (m_bInSignatureValue
)
424 m_ouSignatureValue
+= aChars
;
426 else if (m_bInDigestValue
&& !m_bInCertDigest
)
428 m_ouDigestValue
+= aChars
;
434 else if (m_bInDescription
)
436 m_ouDescription
+= aChars
;
438 else if (m_bInCertDigest
)
440 m_ouCertDigest
+= aChars
;
442 else if (m_bInEncapsulatedX509Certificate
)
444 m_ouEncapsulatedX509Certificate
+= aChars
;
446 else if (m_bInSigningTime
)
450 else if (m_bInSignatureLineId
)
452 m_ouSignatureLineId
+= aChars
;
455 if (m_xNextHandler
.is())
457 m_xNextHandler
->characters(aChars
);
461 void SAL_CALL
XSecParser::ignorableWhitespace( const OUString
& aWhitespaces
)
463 if (m_xNextHandler
.is())
465 m_xNextHandler
->ignorableWhitespace( aWhitespaces
);
469 void SAL_CALL
XSecParser::processingInstruction( const OUString
& aTarget
, const OUString
& aData
)
471 if (m_xNextHandler
.is())
473 m_xNextHandler
->processingInstruction(aTarget
, aData
);
477 void SAL_CALL
XSecParser::setDocumentLocator( const cssu::Reference
< cssxs::XLocator
>& xLocator
)
479 if (m_xNextHandler
.is())
481 m_xNextHandler
->setDocumentLocator( xLocator
);
488 void SAL_CALL
XSecParser::initialize(
489 const cssu::Sequence
< cssu::Any
>& aArguments
)
491 aArguments
[0] >>= m_xNextHandler
;
494 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */