From: Scott Cantor Date: Mon, 10 Sep 2007 02:40:49 +0000 (+0000) Subject: Add verify features. X-Git-Tag: 2.0-beta1~7 X-Git-Url: http://www.project-moonshot.org/gitweb/?p=shibboleth%2Fcpp-opensaml.git;a=commitdiff_plain;h=3bcd7ae2e728772e0ecaa47b083efcb15d9912a8 Add verify features. --- diff --git a/samlsign/samlsign.cpp b/samlsign/samlsign.cpp index ed8c149..d20f256 100644 --- a/samlsign/samlsign.cpp +++ b/samlsign/samlsign.cpp @@ -1,64 +1,69 @@ -/* - * Copyright 2001-2007 Internet2 - * - * Licensed 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 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* siterefresh.cpp - command-line tool to refresh and verify metadata - - Scott Cantor - 5/12/03 - - $Id:siterefresh.cpp 2252 2007-05-20 20:20:57Z cantor $ -*/ - -#if defined (_MSC_VER) || defined(__BORLANDC__) -# include "config_win32.h" -#else -# include "config.h" -#endif - -#ifdef WIN32 -# define _CRT_NONSTDC_NO_DEPRECATE 1 -# define _CRT_SECURE_NO_DEPRECATE 1 -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -using namespace xmlsignature; -using namespace xmlconstants; -using namespace xmltooling::logging; -using namespace xmltooling; -using namespace samlconstants; -using namespace opensaml::saml2md; -using namespace opensaml; -using namespace xercesc; -using namespace std; - -template T* buildPlugin(const char* path, PluginManager& mgr) -{ +/* + * Copyright 2001-2007 Internet2 + * + * Licensed 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* siterefresh.cpp - command-line tool to refresh and verify metadata + + Scott Cantor + 5/12/03 + + $Id:siterefresh.cpp 2252 2007-05-20 20:20:57Z cantor $ +*/ + +#if defined (_MSC_VER) || defined(__BORLANDC__) +# include "config_win32.h" +#else +# include "config.h" +#endif + +#ifdef WIN32 +# define _CRT_NONSTDC_NO_DEPRECATE 1 +# define _CRT_SECURE_NO_DEPRECATE 1 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace xmlsignature; +using namespace xmlconstants; +using namespace xmltooling::logging; +using namespace xmltooling; +using namespace samlconstants; +using namespace opensaml::saml2md; +using namespace opensaml; +using namespace xercesc; +using namespace std; + +template T* buildPlugin(const char* path, PluginManager& mgr) +{ ifstream in(path); DOMDocument* doc=XMLToolingConfig::getConfig().getParser().parse(in); XercesJanitor janitor(doc); @@ -68,176 +73,287 @@ template T* buildPlugin(const char* path, PluginManagergetDocumentElement()); throw XMLToolingException("Missing type in plugin configuration."); -} - -CredentialResolver* buildSimpleResolver(const char* key, const char* cert) -{ - static const XMLCh _CredentialResolver[] = UNICODE_LITERAL_18(C,r,e,d,e,n,t,i,a,l,R,e,s,o,l,v,e,r); - static const XMLCh _certificate[] = UNICODE_LITERAL_11(c,e,r,t,i,f,i,c,a,t,e); - static const XMLCh _key[] = UNICODE_LITERAL_3(k,e,y); - - DOMDocument* doc = XMLToolingConfig::getConfig().getParser().newDocument(); - XercesJanitor janitor(doc); - DOMElement* root = doc->createElementNS(NULL, _CredentialResolver); - if (key) { - auto_ptr_XMLCh widenit(key); - root->setAttributeNS(NULL, _key, widenit.get()); - } - if (cert) { - auto_ptr_XMLCh widenit(cert); - root->setAttributeNS(NULL, _certificate, widenit.get()); - } - - return XMLToolingConfig::getConfig().CredentialResolverManager.newPlugin(FILESYSTEM_CREDENTIAL_RESOLVER, root); -} - -int main(int argc,char* argv[]) -{ - bool verify=true; - char* url_param=NULL; - char* path_param=NULL; - char* key_param=NULL; - char* cert_param=NULL; - char* cr_param=NULL; - char* t_param=NULL; - char* id_param=NULL; - - // metadata lookup options - char* m_param=NULL; - char* issuer=NULL; - char* prot = NULL; - const XMLCh* protocol = NULL; - char* rname = NULL; - char* rns = NULL; - - for (int i=1; i jan(doc); - auto_ptr sourcewrapper(XMLObjectBuilder::buildOneFromElement(doc->getDocumentElement(), true)); - jan.release(); - - // Navigate to the selected node, or use the root if no ID specified. - // Then make sure it's a SignableSAMLObject. - XMLObject* source = sourcewrapper.get(); - if (id_param) { - auto_ptr_XMLCh widenit(id_param); - source = XMLHelper::getXMLObjectById(*source, widenit.get()); - if (!source) - throw XMLToolingException("Element with ID ($1) not found.", params(1,id_param)); - } - SignableObject* signable = dynamic_cast(source); - if (!signable) - throw XMLToolingException("Input is not a signable SAML object."); - - if (verify) { - } - else { - // Build a resolver to supply a credential. - auto_ptr cr( - cr_param ? buildPlugin(cr_param, xmlconf.CredentialResolverManager) : buildSimpleResolver(key_param, cert_param) - ); - cr->lock(); - CredentialCriteria cc; - cc.setUsage(CredentialCriteria::SIGNING_CREDENTIAL); - const Credential* cred = cr->resolve(&cc); - if (!cred) - throw XMLSecurityException("Unable to resolve a signing credential."); +} + +CredentialResolver* buildSimpleResolver(const char* key, const char* cert) +{ + static const XMLCh _CredentialResolver[] = UNICODE_LITERAL_18(C,r,e,d,e,n,t,i,a,l,R,e,s,o,l,v,e,r); + static const XMLCh _certificate[] = UNICODE_LITERAL_11(c,e,r,t,i,f,i,c,a,t,e); + static const XMLCh _key[] = UNICODE_LITERAL_3(k,e,y); + + DOMDocument* doc = XMLToolingConfig::getConfig().getParser().newDocument(); + XercesJanitor janitor(doc); + DOMElement* root = doc->createElementNS(NULL, _CredentialResolver); + if (key) { + auto_ptr_XMLCh widenit(key); + root->setAttributeNS(NULL, _key, widenit.get()); + } + if (cert) { + auto_ptr_XMLCh widenit(cert); + root->setAttributeNS(NULL, _certificate, widenit.get()); + } + + return XMLToolingConfig::getConfig().CredentialResolverManager.newPlugin(FILESYSTEM_CREDENTIAL_RESOLVER, root); +} + +class DummyCredentialResolver : public CredentialResolver +{ +public: + DummyCredentialResolver() {} + ~DummyCredentialResolver() {} + + Lockable* lock() {return this;} + void unlock() {} + + const Credential* resolve(const CredentialCriteria* criteria=NULL) const {return NULL;} + vector::size_type resolve( + vector& results, const CredentialCriteria* criteria=NULL + ) const {return 0;} +}; + +int main(int argc,char* argv[]) +{ + bool verify=true; + char* url_param=NULL; + char* path_param=NULL; + char* key_param=NULL; + char* cert_param=NULL; + char* cr_param=NULL; + char* t_param=NULL; + char* id_param=NULL; + + // metadata lookup options + char* m_param=NULL; + char* issuer=NULL; + char* prot = NULL; + const XMLCh* protocol = NULL; + char* rname = NULL; + char* rns = NULL; + + for (int i=1; i jan(doc); + auto_ptr sourcewrapper(XMLObjectBuilder::buildOneFromElement(doc->getDocumentElement(), true)); + jan.release(); + + // Navigate to the selected node, or use the root if no ID specified. + // Then make sure it's a SignableSAMLObject. + XMLObject* source = sourcewrapper.get(); + if (id_param) { + auto_ptr_XMLCh widenit(id_param); + source = XMLHelper::getXMLObjectById(*source, widenit.get()); + if (!source) + throw XMLToolingException("Element with ID ($1) not found.", params(1,id_param)); + } + SignableObject* signable = dynamic_cast(source); + if (!signable) + throw XMLToolingException("Input is not a signable SAML object."); + + if (verify) { + if (!signable->getSignature()) + throw SignatureException("Cannot verify unsigned object."); + + // Check the profile. + SignatureProfileValidator sigval; + sigval.validate(signable->getSignature()); + + if (cert_param || cr_param) { + // Build a resolver to supply trusted credentials. + auto_ptr cr( + cr_param ? buildPlugin(cr_param, xmlconf.CredentialResolverManager) : buildSimpleResolver(NULL, cert_param) + ); + Locker locker(cr.get()); + + // Set up criteria. + CredentialCriteria cc; + cc.setUsage(CredentialCriteria::SIGNING_CREDENTIAL); + cc.setSignature(*(signable->getSignature()), CredentialCriteria::KEYINFO_EXTRACTION_KEY); + if (issuer) + cc.setPeerName(issuer); + + // Try every credential we can find. + vector creds; + if (cr->resolve(creds, &cc)) { + bool good=false; + SignatureValidator sigValidator; + for (vector::const_iterator i = creds.begin(); i != creds.end(); ++i) { + try { + sigValidator.setCredential(*i); + sigValidator.validate(signable->getSignature()); + log.info("successful signature verification"); + good = true; + break; + } + catch (exception&) { + } + } + if (!good) + throw SignatureException("CredentialResolver did not supply a successful verification key."); + } + else { + throw SignatureException("CredentialResolver did not supply any verification keys."); + } + } + else { + // TrustEngine-based verification, so try and build the plugins. + auto_ptr trust(buildPlugin(t_param, xmlconf.TrustEngineManager)); + SignatureTrustEngine* sigtrust = dynamic_cast(trust.get()); + if (m_param && rname && issuer) { + if (!protocol) { + if (prot) + protocol = XMLString::transcode(prot); + } + if (!protocol) { + conf.term(); + cerr << "use of metadata option requires a protocol option" << endl; + return -1; + } + auto_ptr metadata(buildPlugin(m_param, conf.MetadataProviderManager)); + metadata->init(); + + Locker locker(metadata.get()); + const EntityDescriptor* entity = metadata->getEntityDescriptor(issuer); + if (!entity) + throw MetadataException("no metadata found for ($1)", params(1, issuer)); + const XMLCh* ns = rns ? XMLString::transcode(rns) : samlconstants::SAML20MD_NS; + auto_ptr_XMLCh n(rname); + QName q(ns, n.get()); + const RoleDescriptor* role = entity->getRoleDescriptor(q, protocol); + if (!role) + throw MetadataException("compatible role $1 not found for ($2)", params(2, q.toString().c_str(), issuer)); - // Attach new signature. + MetadataCredentialCriteria mcc(*role); + if (sigtrust->validate(*signable->getSignature(), *metadata.get(), &mcc)) + log.info("successful signature verification"); + else + throw SignatureException("Unable to verify signature with TrustEngine and supplied metadata."); + } + else { + // Set up criteria. + CredentialCriteria cc; + cc.setUsage(CredentialCriteria::SIGNING_CREDENTIAL); + cc.setSignature(*(signable->getSignature()), CredentialCriteria::KEYINFO_EXTRACTION_KEY); + if (issuer) + cc.setPeerName(issuer); + DummyCredentialResolver dummy; + if (sigtrust->validate(*signable->getSignature(), dummy, &cc)) + log.info("successful signature verification"); + else + throw SignatureException("Unable to verify signature with TrustEngine (no metadata supplied)."); + } + } + } + else { + // Build a resolver to supply a credential. + auto_ptr cr( + cr_param ? buildPlugin(cr_param, xmlconf.CredentialResolverManager) : buildSimpleResolver(key_param, cert_param) + ); + Locker locker(cr.get()); + CredentialCriteria cc; + cc.setUsage(CredentialCriteria::SIGNING_CREDENTIAL); + const Credential* cred = cr->resolve(&cc); + if (!cred) + throw XMLSecurityException("Unable to resolve a signing credential."); + + // Attach new signature. Signature* sig = SignatureBuilder::buildSignature(); signable->setSignature(sig); // Sign response while re-marshalling. vector sigs(1,sig); XMLHelper::serialize(signable->marshall((DOMDocument*)NULL,&sigs,cred), cout); - } - } - catch(exception& e) { - log.errorStream() << "caught an exception: " << e.what() << CategoryStream::ENDLINE; - ret=-10; - } - catch(XMLException& e) { - auto_ptr_char temp(e.getMessage()); - log.errorStream() << "caught a Xerces exception: " << temp.get() << CategoryStream::ENDLINE; - ret=-20; - } - - conf.term(); - return ret; -} + } + } + catch(exception& e) { + log.errorStream() << "caught an exception: " << e.what() << CategoryStream::ENDLINE; + ret=-10; + } + catch(XMLException& e) { + auto_ptr_char temp(e.getMessage()); + log.errorStream() << "caught a Xerces exception: " << temp.get() << CategoryStream::ENDLINE; + ret=-20; + } + + conf.term(); + return ret; +}