2 * The Shibboleth License, Version 1.
4 * University Corporation for Advanced Internet Development, Inc.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
11 * Redistributions of source code must retain the above copyright notice, this
12 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution, if any, must include
17 * the following acknowledgment: "This product includes software developed by
18 * the University Corporation for Advanced Internet Development
19 * <http://www.ucaid.edu>Internet2 Project. Alternately, this acknowledegement
20 * may appear in the software itself, if and wherever such third-party
21 * acknowledgments normally appear.
23 * Neither the name of Shibboleth nor the names of its contributors, nor
24 * Internet2, nor the University Corporation for Advanced Internet Development,
25 * Inc., nor UCAID may be used to endorse or promote products derived from this
26 * software without specific prior written permission. For written permission,
27 * please contact shibboleth@shibboleth.org
29 * Products derived from this software may not be called Shibboleth, Internet2,
30 * UCAID, or the University Corporation for Advanced Internet Development, nor
31 * may Shibboleth appear in their name, without prior written permission of the
32 * University Corporation for Advanced Internet Development.
35 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
36 * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
38 * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK
39 * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE.
40 * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY
41 * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT,
42 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
43 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
44 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
47 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
50 /* siterefresh.cpp - command-line tool to refresh and verify site metadata
58 #include "../shib/shib.h"
61 #include <log4cpp/Category.hh>
62 #include <xercesc/framework/URLInputSource.hpp>
63 #include <xsec/enc/XSECCryptoProvider.hpp>
64 #include <xsec/enc/XSECKeyInfoResolverDefault.hpp>
65 #include <xsec/enc/XSECCryptoException.hpp>
66 #include <xsec/enc/OpenSSL/OpenSSLCryptoX509.hpp>
67 #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.hpp>
68 #include <xsec/framework/XSECProvider.hpp>
69 #include <xsec/framework/XSECException.hpp>
70 #include <xsec/dsig/DSIGTransformC14n.hpp>
71 #include <xsec/dsig/DSIGReference.hpp>
72 #include <xsec/dsig/DSIGTransformList.hpp>
75 # define DEFAULT_SCHEMA_DIR "/shibboleth/etc/shibboleth/"
77 # define DEFAULT_SCHEMA_DIR "/opt/shibboleth/etc/shibboleth/"
82 using namespace shibboleth;
83 using namespace log4cpp;
85 void verifySignature(DOMDocument* doc, DOMElement* sigNode, const char* cert)
87 Category& log=Category::getInstance("siterefresh");
89 // Load the certificate, stripping the first and last lines.
90 string certbuf,line1,line2;
91 auto_ptr<OpenSSLCryptoX509> x509(new OpenSSLCryptoX509());
92 ifstream infile(cert);
93 getline(infile,line1);
94 while (!getline(infile,line1).fail())
99 x509->loadX509Base64Bin(certbuf.data(),certbuf.length());
101 // Load the signature.
103 DSIGSignature* sig=NULL;
106 sig=prov.newSignatureFromDOM(doc,sigNode);
111 // Verify the signature coverage.
112 DSIGReferenceList* refs=sig->getReferenceList();
113 if (sig->getSignatureMethod()==SIGNATURE_RSA && refs && refs->getSize()==1)
115 DSIGReference* ref=refs->item(0);
118 const XMLCh* URI=ref->getURI();
119 if (URI==NULL || *URI==0)
121 DSIGTransformList* tlist=ref->getTransforms();
122 for (int i=0; tlist && i<tlist->getSize(); i++)
124 if (tlist->item(i)->getTransformType()==TRANSFORM_ENVELOPED_SIGNATURE)
126 else if (tlist->item(i)->getTransformType()!=TRANSFORM_EXC_C14N)
138 log.error("detected an invalid signature profile");
139 throw InvalidCryptoException("detected an invalid signature profile");
142 sig->setSigningKey(x509->clonePublicKey());
145 log.error("detected an invalid signature value");
146 throw InvalidCryptoException("detected an invalid signature value");
149 prov.releaseSignature(sig);
154 prov.releaseSignature(sig);
159 int main(int argc,char* argv[])
162 SAMLConfig& conf=SAMLConfig::getConfig();
163 char* url_param=NULL;
164 char* cert_param=NULL;
165 char* out_param=NULL;
166 char* path=DEFAULT_SCHEMA_DIR;
168 for (int i=1; i<argc; i++)
170 if (!strcmp(argv[i],"--schema") && i+1<argc)
172 else if (!strcmp(argv[i],"--url") && i+1<argc)
174 else if (!strcmp(argv[i],"--cert") && i+1<argc)
175 cert_param=argv[++i];
176 else if (!strcmp(argv[i],"--out") && i+1<argc)
180 if (!url_param || !out_param)
182 cout << "usage: " << argv[0] << " --url <URL of metadata> --out <pathname to copy data into> [--cert <PEM Certificate> --schema <schema path>]" << endl;
186 Category::setRootPriority(ERROR);
187 conf.schema_dir=path;
191 Category& log=Category::getInstance("siterefresh");
192 saml::XML::registerSchema(shibboleth::XML::SHIB_NS,shibboleth::XML::SHIB_SCHEMA_ID);
196 // Parse the specified document.
198 static XMLCh base[]={chLatin_f, chLatin_i, chLatin_l, chLatin_e, chColon, chForwardSlash, chForwardSlash, chForwardSlash, chNull};
199 URLInputSource src(base,url_param);
200 Wrapper4InputSource dsrc(&src,false);
201 DOMDocument* doc=p.parse(dsrc);
203 // Examine the root element to be sure we know what we have.
204 DOMElement* e=doc->getDocumentElement();
205 if (XMLString::compareString(shibboleth::XML::SHIB_NS,e->getNamespaceURI()) ||
206 XMLString::compareString(shibboleth::XML::Literals::Sites,e->getLocalName()))
209 log.error("requires a valid site file: (shib:Sites as root element)");
210 throw OriginSiteMapperException("Construction requires a valid site file: (shib:Sites as root element)");
213 // If we're verifying, grab the embedded signature.
216 DOMNode* n=e->getLastChild();
217 while (n && n->getNodeType()!=DOMNode::ELEMENT_NODE)
218 n=n->getPreviousSibling();
219 if (n && !XMLString::compareString(saml::XML::XMLSIG_NS,n->getNamespaceURI()) &&
220 !XMLString::compareString(L(Signature),n->getLocalName()))
222 verifySignature(doc,static_cast<DOMElement*>(n),cert_param);
227 log.error("unable to locate a signature to verify in document");
228 throw OriginSiteMapperException("Verification implies that the document must be signed");
232 // Output the data to the specified file.
233 ofstream outfile(out_param);
238 catch (OriginSiteMapperException&)
242 catch(SAMLException& e)
244 log.errorStream() << "caught a SAML exception: " << e << CategoryStream::ENDLINE;
247 catch(XMLException& e)
249 auto_ptr<char> temp(XMLString::transcode(e.getMessage()));
250 log.errorStream() << "caught an XML exception: " << temp.get() << CategoryStream::ENDLINE;
253 catch(XSECException& e)
255 auto_ptr<char> temp(XMLString::transcode(e.getMsg()));
256 log.errorStream() << "caught an XMLSec exception: " << temp.get() << CategoryStream::ENDLINE;
258 catch(XSECCryptoException& e)
260 log.errorStream() << "caught an XMLSecCrypto exception: " << e.getMsg() << CategoryStream::ENDLINE;
264 log.errorStream() << "caught an unknown exception" << CategoryStream::ENDLINE;