1 /**
2 * Licensed to the University Corporation for Advanced Internet
3 * Development, Inc. (UCAID) under one or more contributor license
4 * agreements. See the NOTICE file distributed with this work for
5 * additional information regarding copyright ownership.
6 *
7 * UCAID licenses this file to you under the Apache License,
8 * Version 2.0 (the "License"); you may not use this file except
9 * in compliance with the License. You may obtain a copy of the
10 * License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
17 * either express or implied. See the License for the specific
18 * language governing permissions and limitations under the License.
19 */
20
21 /**
22 * XMLSecSignatureImpl.cpp
23 *
24 * Signature class for XMLSec-based signature-handling.
25 */
26
27 #include "internal.h"
28 #include "exceptions.h"
29 #include "logging.h"
30 #include "impl/UnknownElement.h"
31 #include "security/Credential.h"
32 #include "signature/ContentReference.h"
33 #include "signature/KeyInfo.h"
34 #include "signature/Signature.h"
35 #include "util/NDC.h"
36 #include "util/XMLConstants.h"
37 #include "util/XMLHelper.h"
38
39 #include <xercesc/framework/MemBufInputSource.hpp>
40 #include <xercesc/framework/Wrapper4InputSource.hpp>
41 #include <xercesc/util/XMLUniDefs.hpp>
42 #include <xsec/dsig/DSIGKeyInfoX509.hpp>
43 #include <xsec/dsig/DSIGReference.hpp>
44 #include <xsec/enc/XSECCryptoException.hpp>
45 #include <xsec/framework/XSECAlgorithmHandler.hpp>
46 #include <xsec/framework/XSECAlgorithmMapper.hpp>
47 #include <xsec/framework/XSECException.hpp>
48 #include <xsec/transformers/TXFMSB.hpp>
49 #include <xsec/transformers/TXFMChain.hpp>
50 #include <xsec/transformers/TXFMOutputFile.hpp>
51
52 using namespace xmlsignature;
53 using namespace xmltooling::logging;
54 using namespace xmltooling;
55 using namespace xercesc;
56 using namespace std;
57 using xmlconstants::XMLSIG_NS;
58 using xmlconstants::XMLSIG_PREFIX;
59
60 namespace xmlsignature {
61
62 #if defined (_MSC_VER)
63 #pragma warning( push )
64 #pragma warning( disable : 4250 4251 )
65 #endif
66
67 class XMLTOOL_DLLLOCAL XMLSecSignatureImpl : public UnknownElementImpl, public virtual Signature
68 {
69 public:
XMLSecSignatureImpl()70 XMLSecSignatureImpl() : AbstractXMLObject(XMLSIG_NS, Signature::LOCAL_NAME, XMLSIG_PREFIX),
71 UnknownElementImpl(XMLSIG_NS, Signature::LOCAL_NAME, XMLSIG_PREFIX),
72 m_signature(nullptr), m_c14n(nullptr), m_sm(nullptr), m_key(nullptr), m_keyInfo(nullptr), m_reference(nullptr) {}
73 virtual ~XMLSecSignatureImpl();
74
75 void releaseDOM() const;
releaseChildrenDOM(bool propagateRelease=true) const76 void releaseChildrenDOM(bool propagateRelease=true) const {
77 if (m_keyInfo) {
78 m_keyInfo->releaseDOM();
79 if (propagateRelease)
80 m_keyInfo->releaseChildrenDOM();
81 }
82 }
83 XMLObject* clone() const;
84 Signature* cloneSignature() const;
85
86 DOMElement* marshall(DOMDocument* document=nullptr, const vector<Signature*>* sigs=nullptr, const Credential* credential=nullptr) const;
87 DOMElement* marshall(DOMElement* parentElement, const vector<Signature*>* sigs=nullptr, const Credential* credential=nullptr) const;
88 XMLObject* unmarshall(DOMElement* element, bool bindDocument=false);
89
90 // Getters
getCanonicalizationMethod() const91 const XMLCh* getCanonicalizationMethod() const {
92 if (m_signature)
93 return m_signature->getCanonicalizationMethod();
94 return m_c14n ? m_c14n : DSIGConstants::s_unicodeStrURIEXC_C14N_NOC;
95 }
getSignatureAlgorithm() const96 const XMLCh* getSignatureAlgorithm() const {
97 if (!m_sm && m_signature) {
98 m_sm = XMLString::replicate(m_signature->getAlgorithmURI());
99 }
100 return m_sm;
101 }
102
getKeyInfo() const103 KeyInfo* getKeyInfo() const { return m_keyInfo; }
getContentReference() const104 ContentReference* getContentReference() const { return m_reference; }
getXMLSignature() const105 DSIGSignature* getXMLSignature() const { return m_signature; }
106
107 // Setters
setCanonicalizationMethod(const XMLCh * c14n)108 void setCanonicalizationMethod(const XMLCh* c14n) { m_c14n = prepareForAssignment(m_c14n,c14n); }
setSignatureAlgorithm(const XMLCh * sm)109 void setSignatureAlgorithm(const XMLCh* sm) { m_sm = prepareForAssignment(m_sm,sm); }
setSigningKey(XSECCryptoKey * signingKey)110 void setSigningKey(XSECCryptoKey* signingKey) {
111 delete m_key;
112 m_key=signingKey;
113 }
setKeyInfo(KeyInfo * keyInfo)114 void setKeyInfo(KeyInfo* keyInfo) {
115 prepareForAssignment(m_keyInfo, keyInfo);
116 m_keyInfo=keyInfo;
117 }
setContentReference(ContentReference * reference)118 void setContentReference(ContentReference* reference) {
119 delete m_reference;
120 m_reference=reference;
121 }
122
123 void sign(const Credential* credential=nullptr);
124
125 private:
126 mutable DSIGSignature* m_signature;
127 XMLCh* m_c14n;
128 mutable XMLCh* m_sm;
129 XSECCryptoKey* m_key;
130 mutable KeyInfo* m_keyInfo;
131 ContentReference* m_reference;
132 };
133
134 #if defined (_MSC_VER)
135 #pragma warning( pop )
136 #endif
137 };
138
ContentReference()139 ContentReference::ContentReference()
140 {
141 }
142
~ContentReference()143 ContentReference::~ContentReference()
144 {
145 }
146
Signature()147 Signature::Signature()
148 {
149 }
150
~Signature()151 Signature::~Signature()
152 {
153 }
154
~XMLSecSignatureImpl()155 XMLSecSignatureImpl::~XMLSecSignatureImpl()
156 {
157 // Release the associated signature.
158 if (m_signature)
159 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseSignature(m_signature);
160
161 XMLString::release(&m_c14n);
162 XMLString::release(&m_sm);
163 delete m_key;
164 delete m_keyInfo;
165 delete m_reference;
166 }
167
releaseDOM() const168 void XMLSecSignatureImpl::releaseDOM() const
169 {
170 if (getDOM()) {
171 // This should save off the DOM
172 UnknownElementImpl::releaseDOM();
173
174 // Release the associated signature.
175 if (m_signature) {
176 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseSignature(m_signature);
177 m_signature=nullptr;
178 }
179 }
180 }
181
clone() const182 XMLObject* XMLSecSignatureImpl::clone() const
183 {
184 return cloneSignature();
185 }
186
cloneSignature() const187 Signature* XMLSecSignatureImpl::cloneSignature() const
188 {
189 XMLSecSignatureImpl* ret=new XMLSecSignatureImpl();
190
191 ret->m_c14n=XMLString::replicate(m_c14n);
192 ret->m_sm=XMLString::replicate(m_sm);
193 if (m_key)
194 ret->m_key=m_key->clone();
195 if (m_keyInfo)
196 ret->m_keyInfo=m_keyInfo->cloneKeyInfo();
197
198 // If there's no XML locally, serialize this object into the new one, otherwise just copy it over.
199 if (m_xml.empty())
200 serialize(ret->m_xml);
201 else
202 ret->m_xml=m_xml;
203
204 return ret;
205 }
206
sign(const Credential * credential)207 void XMLSecSignatureImpl::sign(const Credential* credential)
208 {
209 Category& log=Category::getInstance(XMLTOOLING_LOGCAT ".Signature");
210 log.debug("applying signature");
211
212 if (!m_signature)
213 throw SignatureException("Only a marshalled Signature object can be signed.");
214 else if (!m_reference)
215 throw SignatureException("No ContentReference object set for signature creation.");
216
217 const XSECCryptoKey* key = credential ? credential->getPrivateKey() : m_key;
218 if (!key)
219 throw SignatureException("No signing key available for signature creation.");
220
221 try {
222 log.debug("creating signature reference(s)");
223 DSIGReferenceList* refs = m_signature->getReferenceList();
224 while (refs && refs->getSize())
225 delete refs->removeReference(0);
226 m_reference->createReferences(m_signature);
227
228 log.debug("computing signature");
229 m_signature->setSigningKey(key->clone());
230 m_signature->sign();
231 }
232 catch(const XSECException& e) {
233 auto_ptr_char temp(e.getMsg());
234 throw SignatureException(string("Caught an XMLSecurity exception while signing: ") + temp.get());
235 }
236 catch(const XSECCryptoException& e) {
237 throw SignatureException(string("Caught an XMLSecurity exception while signing: ") + e.getMsg());
238 }
239 }
240
marshall(DOMDocument * document,const vector<Signature * > * sigs,const Credential * credential) const241 DOMElement* XMLSecSignatureImpl::marshall(DOMDocument* document, const vector<Signature*>* sigs, const Credential* credential) const
242 {
243 #ifdef _DEBUG
244 xmltooling::NDC ndc("marshall");
245 #endif
246
247 Category& log=Category::getInstance(XMLTOOLING_LOGCAT ".Signature");
248 log.debug("marshalling ds:Signature");
249
250 DOMElement* cachedDOM=getDOM();
251 if (cachedDOM) {
252 if (!document || document==cachedDOM->getOwnerDocument()) {
253 log.debug("Signature has a usable cached DOM, reusing it");
254 if (document)
255 setDocumentElement(cachedDOM->getOwnerDocument(),cachedDOM);
256 releaseParentDOM(true);
257 return cachedDOM;
258 }
259
260 // We have a DOM but it doesn't match the document we were given. This both sucks and blows.
261 // Without an adoptNode option to maintain the child pointers, we have to either import the
262 // DOM while somehow reassigning all the nested references (which amounts to a complete
263 // *unmarshall* operation), or we just release the existing DOM and hope that we can get
264 // it back. This depends on all objects being able to preserve their DOM at all costs.
265 releaseChildrenDOM(true);
266 releaseDOM();
267 }
268
269 // If we get here, we didn't have a usable DOM.
270 bool bindDocument=false;
271 if (m_xml.empty()) {
272 // Fresh signature, so we just create an empty one.
273 log.debug("creating empty Signature element");
274 if (!document) {
275 document=DOMImplementationRegistry::getDOMImplementation(nullptr)->createDocument();
276 bindDocument=true;
277 }
278 DSIGSignature* temp=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newSignature();
279 temp->setDSIGNSPrefix(XMLSIG_PREFIX);
280 const XMLCh* alg = getSignatureAlgorithm();
281 if (!alg) {
282 #ifdef XSEC_OPENSSL_HAVE_SHA2
283 alg = DSIGConstants::s_unicodeStrURIRSA_SHA256;
284 #else
285 alg = DSIGConstants::s_unicodeStrURIRSA_SHA1;
286 #endif
287 }
288 cachedDOM=temp->createBlankSignature(document, getCanonicalizationMethod(), alg);
289 m_signature = temp;
290 }
291 else {
292 // We need to reparse the XML we saved off into a new DOM.
293 MemBufInputSource src(reinterpret_cast<const XMLByte*>(m_xml.c_str()),m_xml.length(),"XMLSecSignatureImpl");
294 Wrapper4InputSource dsrc(&src,false);
295 log.debug("parsing Signature XML back into DOM tree");
296 DOMDocument* internalDoc=XMLToolingConfig::getConfig().getParser().parse(dsrc);
297 if (document) {
298 // The caller insists on using his own document, so we now have to import the thing
299 // into it. Then we're just dumping the one we built.
300 log.debug("reimporting new DOM into caller-supplied document");
301 try {
302 cachedDOM=static_cast<DOMElement*>(document->importNode(internalDoc->getDocumentElement(), true));
303 }
304 catch (XMLException& ex) {
305 internalDoc->release();
306 auto_ptr_char temp(ex.getMessage());
307 throw XMLParserException(
308 string("Error importing DOM into caller-supplied document: ") + (temp.get() ? temp.get() : "no message")
309 );
310 }
311 internalDoc->release();
312 }
313 else {
314 // We just bind the document we built to the object as the result.
315 cachedDOM=static_cast<DOMElement*>(internalDoc->getDocumentElement());
316 document=internalDoc;
317 bindDocument=true;
318 }
319
320 // Now reload the signature from the DOM.
321 try {
322 m_signature=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newSignatureFromDOM(
323 document, cachedDOM
324 );
325 m_signature->load();
326 }
327 catch(const XSECException& e) {
328 if (bindDocument)
329 document->release();
330 auto_ptr_char temp(e.getMsg());
331 throw MarshallingException(string("Caught an XMLSecurity exception while loading signature: ") + temp.get());
332 }
333 catch(const XSECCryptoException& e) {
334 if (bindDocument)
335 document->release();
336 throw MarshallingException(string("Caught an XMLSecurity exception while loading signature: ") + e.getMsg());
337 }
338 }
339
340 // Marshall KeyInfo data.
341 if (credential) {
342 delete m_keyInfo;
343 m_keyInfo = nullptr;
344 m_keyInfo = credential->getKeyInfo();
345 }
346 if (m_keyInfo && (!m_signature->getKeyInfoList() || m_signature->getKeyInfoList()->isEmpty())) {
347 m_keyInfo->marshall(cachedDOM);
348 }
349
350 // Recache the DOM and clear the serialized copy.
351 setDocumentElement(document, cachedDOM);
352 log.debug("caching DOM for Signature (document is %sbound)", bindDocument ? "" : "not ");
353 setDOM(cachedDOM, bindDocument);
354 releaseParentDOM(true);
355 m_xml.erase();
356 return cachedDOM;
357 }
358
marshall(DOMElement * parentElement,const vector<Signature * > * sigs,const Credential * credential) const359 DOMElement* XMLSecSignatureImpl::marshall(DOMElement* parentElement, const vector<Signature*>* sigs, const Credential* credential) const
360 {
361 #ifdef _DEBUG
362 xmltooling::NDC ndc("marshall");
363 #endif
364
365 Category& log=Category::getInstance(XMLTOOLING_LOGCAT ".Signature");
366 log.debug("marshalling ds:Signature");
367
368 DOMElement* cachedDOM=getDOM();
369 if (cachedDOM) {
370 if (parentElement->getOwnerDocument()==cachedDOM->getOwnerDocument()) {
371 log.debug("Signature has a usable cached DOM, reusing it");
372 if (parentElement!=cachedDOM->getParentNode()) {
373 parentElement->appendChild(cachedDOM);
374 releaseParentDOM(true);
375 }
376 return cachedDOM;
377 }
378
379 // We have a DOM but it doesn't match the document we were given. This both sucks and blows.
380 // Without an adoptNode option to maintain the child pointers, we have to either import the
381 // DOM while somehow reassigning all the nested references (which amounts to a complete
382 // *unmarshall* operation), or we just release the existing DOM and hope that we can get
383 // it back. This depends on all objects being able to preserve their DOM at all costs.
384 releaseChildrenDOM(true);
385 releaseDOM();
386 }
387
388 // If we get here, we didn't have a usable DOM.
389 if (m_xml.empty()) {
390 // Fresh signature, so we just create an empty one.
391 log.debug("creating empty Signature element");
392 DSIGSignature* temp=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newSignature();
393 temp->setDSIGNSPrefix(XMLSIG_PREFIX);
394 const XMLCh* alg = getSignatureAlgorithm();
395 if (!alg)
396 alg = DSIGConstants::s_unicodeStrURIRSA_SHA1;
397 cachedDOM=temp->createBlankSignature(parentElement->getOwnerDocument(), getCanonicalizationMethod(), alg);
398 m_signature = temp;
399 }
400 else {
401 MemBufInputSource src(reinterpret_cast<const XMLByte*>(m_xml.c_str()),m_xml.length(),"XMLSecSignatureImpl");
402 Wrapper4InputSource dsrc(&src,false);
403 log.debug("parsing XML back into DOM tree");
404 DOMDocument* internalDoc=XMLToolingConfig::getConfig().getParser().parse(dsrc);
405
406 log.debug("reimporting new DOM into caller-supplied document");
407 try {
408 cachedDOM=static_cast<DOMElement*>(parentElement->getOwnerDocument()->importNode(internalDoc->getDocumentElement(),true));
409 }
410 catch (const XMLException& ex) {
411 internalDoc->release();
412 auto_ptr_char temp(ex.getMessage());
413 throw XMLParserException(
414 string("Error importing DOM into caller-supplied document: ") + (temp.get() ? temp.get() : "no message")
415 );
416 }
417 internalDoc->release();
418
419 // Now reload the signature from the DOM.
420 try {
421 m_signature=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newSignatureFromDOM(
422 parentElement->getOwnerDocument(), cachedDOM
423 );
424 m_signature->load();
425 }
426 catch(const XSECException& e) {
427 auto_ptr_char temp(e.getMsg());
428 throw MarshallingException(string("Caught an XMLSecurity exception while loading signature: ") + temp.get());
429 }
430 catch(const XSECCryptoException& e) {
431 throw MarshallingException(string("Caught an XMLSecurity exception while loading signature: ") + e.getMsg());
432 }
433 }
434
435 // Marshall KeyInfo data.
436 if (credential) {
437 delete m_keyInfo;
438 m_keyInfo = nullptr;
439 m_keyInfo = credential->getKeyInfo();
440 }
441 if (m_keyInfo && (!m_signature->getKeyInfoList() || m_signature->getKeyInfoList()->isEmpty())) {
442 m_keyInfo->marshall(cachedDOM);
443 }
444
445 // Recache the DOM and clear the serialized copy.
446 parentElement->appendChild(cachedDOM);
447 log.debug("caching DOM for Signature");
448 setDOM(cachedDOM, false);
449 releaseParentDOM(true);
450 m_xml.erase();
451 return cachedDOM;
452 }
453
unmarshall(DOMElement * element,bool bindDocument)454 XMLObject* XMLSecSignatureImpl::unmarshall(DOMElement* element, bool bindDocument)
455 {
456 Category::getInstance(XMLTOOLING_LOGCAT ".Signature").debug("unmarshalling ds:Signature");
457
458 try {
459 m_signature=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newSignatureFromDOM(
460 element->getOwnerDocument(), element
461 );
462 m_signature->load();
463 }
464 catch(const XSECException& e) {
465 auto_ptr_char temp(e.getMsg());
466 throw UnmarshallingException(string("Caught an XMLSecurity exception while loading signature: ") + temp.get());
467 }
468 catch(const XSECCryptoException& e) {
469 throw UnmarshallingException(string("Caught an XMLSecurity exception while loading signature: ") + e.getMsg());
470 }
471
472 setDOM(element, bindDocument);
473 return this;
474 }
475
476 #ifdef HAVE_COVARIANT_RETURNS
477 Signature*
478 #else
479 XMLObject*
480 #endif
buildObject(const XMLCh * nsURI,const XMLCh * localName,const XMLCh * prefix,const xmltooling::QName * schemaType) const481 SignatureBuilder::buildObject(
482 const XMLCh* nsURI, const XMLCh* localName, const XMLCh* prefix, const xmltooling::QName* schemaType
483 ) const
484 {
485 if (!XMLString::equals(nsURI,XMLSIG_NS) || !XMLString::equals(localName,Signature::LOCAL_NAME))
486 throw XMLObjectException("XMLSecSignatureBuilder requires standard Signature element name.");
487 return buildObject();
488 }
489
490 #ifdef HAVE_COVARIANT_RETURNS
491 Signature*
492 #else
493 XMLObject*
494 #endif
buildObject() const495 SignatureBuilder::buildObject() const
496 {
497 return new XMLSecSignatureImpl();
498 }
499
buildSignature()500 Signature* SignatureBuilder::buildSignature() {
501 const SignatureBuilder* b = dynamic_cast<const SignatureBuilder*>(
502 XMLObjectBuilder::getBuilder(xmltooling::QName(xmlconstants::XMLSIG_NS,Signature::LOCAL_NAME))
503 );
504 if (b) {
505 #ifdef HAVE_COVARIANT_RETURNS
506 return b->buildObject();
507 #else
508 return dynamic_cast<Signature*>(b->buildObject());
509 #endif
510 }
511 throw XMLObjectException("Unable to obtain typed builder for Signature.");
512 }
513
514 const XMLCh Signature::LOCAL_NAME[] = UNICODE_LITERAL_9(S,i,g,n,a,t,u,r,e);
515
516 // Raw signature methods.
517
createRawSignature(const XSECCryptoKey * key,const XMLCh * sigAlgorithm,const char * in,unsigned int in_len,char * out,unsigned int out_len)518 unsigned int Signature::createRawSignature(
519 const XSECCryptoKey* key, const XMLCh* sigAlgorithm, const char* in, unsigned int in_len, char* out, unsigned int out_len
520 )
521 {
522 try {
523 const XSECAlgorithmHandler* handler = XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(sigAlgorithm);
524 if (!handler) {
525 auto_ptr_char alg(sigAlgorithm);
526 throw SignatureException("Unsupported signature algorithm ($1).", params(1,alg.get()));
527 }
528
529 // Move input into a safeBuffer to source the transform chain.
530 safeBuffer sb,sbout;
531 sb.sbStrncpyIn(in,in_len);
532 TXFMSB* sbt = new TXFMSB(nullptr);
533 sbt->setInput(sb, in_len);
534 TXFMChain tx(sbt);
535
536 // Sign the chain.
537 unsigned int siglen = handler->signToSafeBuffer(&tx, sigAlgorithm, key, out_len-1, sbout);
538 if (siglen >= out_len)
539 throw SignatureException("Signature size exceeded output buffer size.");
540
541 // Push all non-whitespace into buffer.
542 unsigned int ret_len = 0;
543 const char* source = sbout.rawCharBuffer();
544 while (siglen--) {
545 if (isspace(*source))
546 ++source;
547 else {
548 *out++ = *source++;
549 ++ret_len;
550 }
551 }
552 *out = 0;
553 return ret_len;
554 }
555 catch(const XSECException& e) {
556 auto_ptr_char temp(e.getMsg());
557 throw SignatureException(string("Caught an XMLSecurity exception while creating raw signature: ") + temp.get());
558 }
559 catch(const XSECCryptoException& e) {
560 throw SignatureException(string("Caught an XMLSecurity exception while creating raw signature: ") + e.getMsg());
561 }
562 }
563
verifyRawSignature(const XSECCryptoKey * key,const XMLCh * sigAlgorithm,const char * signature,const char * in,unsigned int in_len)564 bool Signature::verifyRawSignature(
565 const XSECCryptoKey* key, const XMLCh* sigAlgorithm, const char* signature, const char* in, unsigned int in_len
566 )
567 {
568 try {
569 const XSECAlgorithmHandler* handler = XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(sigAlgorithm);
570 if (!handler) {
571 auto_ptr_char alg(sigAlgorithm);
572 throw SignatureException("Unsupported signature algorithm ($1).", params(1,alg.get()));
573 }
574
575 // Move input into a safeBuffer to source the transform chain.
576 safeBuffer sb;
577 sb.sbStrncpyIn(in,in_len);
578 TXFMSB* sbt = new TXFMSB(nullptr);
579 sbt->setInput(sb, in_len);
580 TXFMChain tx(sbt);
581
582 // Verify the chain.
583 return handler->verifyBase64Signature(&tx, sigAlgorithm, signature, 0, key);
584 }
585 catch(const XSECException& e) {
586 auto_ptr_char temp(e.getMsg());
587 throw SignatureException(string("Caught an XMLSecurity exception while verifying raw signature: ") + temp.get());
588 }
589 catch(const XSECCryptoException& e) {
590 throw SignatureException(string("Caught an XMLSecurity exception while verifying raw signature: ") + e.getMsg());
591 }
592 }
593