author | Michael Krelin <hacker@klever.net> | 2008-02-16 17:49:22 (UTC) |
---|---|---|
committer | Michael Krelin <hacker@klever.net> | 2008-02-16 17:49:22 (UTC) |
commit | 21bddce2d98394865cf2ed0b144f92bbb6993bc9 (patch) (side-by-side diff) | |
tree | e30194fab08a704885ae00c711e1707dc73bed83 | |
parent | ccdfc6eacec435a59d773127762ad0b6bce07149 (diff) | |
download | libopkele-21bddce2d98394865cf2ed0b144f92bbb6993bc9.zip libopkele-21bddce2d98394865cf2ed0b144f92bbb6993bc9.tar.gz libopkele-21bddce2d98394865cf2ed0b144f92bbb6993bc9.tar.bz2 |
moved some stuff out of the now installed util.h header
Signed-off-by: Michael Krelin <hacker@klever.net>
-rw-r--r-- | include/Makefile.am | 3 | ||||
-rw-r--r-- | include/opkele/util-internal.h | 92 | ||||
-rw-r--r-- | include/opkele/util.h | 92 | ||||
-rw-r--r-- | lib/basic_op.cc | 1 | ||||
-rw-r--r-- | lib/basic_rp.cc | 1 | ||||
-rw-r--r-- | lib/consumer.cc | 1 | ||||
-rw-r--r-- | lib/server.cc | 1 | ||||
-rw-r--r-- | test/idiscover.cc | 1 |
8 files changed, 110 insertions, 82 deletions
diff --git a/include/Makefile.am b/include/Makefile.am index 9f5982c..f842bb9 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,32 +1,33 @@ NODIST_HEADERS_ = \ opkele/acconfig.h \ opkele/tr1-mem.h nobase_include_HEADERS = \ opkele/opkele-config.h \ opkele/types.h \ opkele/association.h \ opkele/exception.h \ opkele/server.h \ opkele/consumer.h \ opkele/extension.h \ opkele/sreg.h \ opkele/extension_chain.h \ opkele/xconsumer.h \ opkele/xserver.h \ opkele/uris.h \ opkele/tr1-mem.h \ opkele/basic_rp.h opkele/prequeue_rp.h \ opkele/iterator.h \ opkele/basic_op.h opkele/verify_op.h \ + opkele/util.h \ ${NODIST_HEADERS_} noinst_HEADERS = \ opkele/data.h \ opkele/curl.h opkele/expat.h opkele/tidy.h \ - opkele/util.h \ + opkele/util-internal.h \ opkele/debug.h \ opkele/discovery.h dist-hook: rm -f $(addprefix ${distdir}/,${NODIST_HEADERS_}) diff --git a/include/opkele/util-internal.h b/include/opkele/util-internal.h new file mode 100644 index 0000000..ec091ce --- a/dev/null +++ b/include/opkele/util-internal.h @@ -0,0 +1,92 @@ +#ifndef __OPKELE_UTIL_INTERNAL_H +#define __OPKELE_UTIL_INTERNAL_H + +#include <openssl/bn.h> +#include <openssl/dh.h> + +namespace opkele { + namespace util { + + /** + * Convenience class encapsulating SSL BIGNUM object for the purpose of + * automatical freeing. + */ + class bignum_t { + public: + BIGNUM *_bn; + + bignum_t() : _bn(0) { } + bignum_t(BIGNUM *bn) : _bn(bn) { } + ~bignum_t() throw() { if(_bn) BN_free(_bn); } + + bignum_t& operator=(BIGNUM *bn) { if(_bn) BN_free(_bn); _bn = bn; return *this; } + + operator const BIGNUM*(void) const { return _bn; } + operator BIGNUM*(void) { return _bn; } + }; + /** + * Convenience clas encapsulating SSL DH object for the purpose of + * automatic freeing. + */ + class dh_t { + public: + DH *_dh; + + dh_t() : _dh(0) { } + dh_t(DH *dh) : _dh(dh) { } + ~dh_t() throw() { if(_dh) DH_free(_dh); } + + dh_t& operator=(DH *dh) { if(_dh) DH_free(_dh); _dh = dh; return *this; } + + operator const DH*(void) const { return _dh; } + operator DH*(void) { return _dh; } + + DH* operator->() { return _dh; } + const DH* operator->() const { return _dh; } + }; + + /** + * Convert base64-encoded SSL BIGNUM to internal representation. + * @param b64 base64-encoded number + * @return SSL BIGNUM + * @throw failed_conversion in case of error + */ + BIGNUM *base64_to_bignum(const string& b64); + /** + * Convert decimal representation to SSL BIGNUM. + * @param dec decimal representation + * @return resulting BIGNUM + * @throw failed_conversion in case of error + */ + BIGNUM *dec_to_bignum(const string& dec); + /** + * Convert SSL BIGNUM data to base64 encoded string. + * @param bn BIGNUM + * @return base64encoded string + */ + string bignum_to_base64(const BIGNUM *bn); + + string abi_demangle(const char* mn); + + class change_mode_message_proxy : public basic_openid_message { + public: + const basic_openid_message& x; + const string& mode; + + change_mode_message_proxy(const basic_openid_message& xx,const string& m) : x(xx), mode(m) { } + + bool has_field(const string& n) const { return x.has_field(n); } + const string& get_field(const string& n) const { + return (n=="mode")?mode:x.get_field(n); } + bool has_ns(const string& uri) const {return x.has_ns(uri); } + string get_ns(const string& uri) const { return x.get_ns(uri); } + fields_iterator fields_begin() const { + return x.fields_begin(); } + fields_iterator fields_end() const { + return x.fields_end(); } + }; + + } +} + +#endif /* __OPKELE_UTIL_INTERNAL_H */ diff --git a/include/opkele/util.h b/include/opkele/util.h index bc1a0ea..60955e1 100644 --- a/include/opkele/util.h +++ b/include/opkele/util.h @@ -1,184 +1,114 @@ #ifndef __OPKELE_UTIL_H #define __OPKELE_UTIL_H #include <time.h> #include <string> #include <vector> -#include <openssl/bn.h> -#include <openssl/dh.h> #include <opkele/types.h> namespace opkele { using std::string; using std::vector; /** * @brief opkele utils namespace */ namespace util { /** - * Convenience class encapsulating SSL BIGNUM object for the purpose of - * automatical freeing. - */ - class bignum_t { - public: - BIGNUM *_bn; - - bignum_t() : _bn(0) { } - bignum_t(BIGNUM *bn) : _bn(bn) { } - ~bignum_t() throw() { if(_bn) BN_free(_bn); } - - bignum_t& operator=(BIGNUM *bn) { if(_bn) BN_free(_bn); _bn = bn; return *this; } - - operator const BIGNUM*(void) const { return _bn; } - operator BIGNUM*(void) { return _bn; } - }; - /** - * Convenience clas encapsulating SSL DH object for the purpose of - * automatic freeing. - */ - class dh_t { - public: - DH *_dh; - - dh_t() : _dh(0) { } - dh_t(DH *dh) : _dh(dh) { } - ~dh_t() throw() { if(_dh) DH_free(_dh); } - - dh_t& operator=(DH *dh) { if(_dh) DH_free(_dh); _dh = dh; return *this; } - - operator const DH*(void) const { return _dh; } - operator DH*(void) { return _dh; } - - DH* operator->() { return _dh; } - const DH* operator->() const { return _dh; } - }; - - /** - * Convert base64-encoded SSL BIGNUM to internal representation. - * @param b64 base64-encoded number - * @return SSL BIGNUM - * @throw failed_conversion in case of error - */ - BIGNUM *base64_to_bignum(const string& b64); - /** - * Convert decimal representation to SSL BIGNUM. - * @param dec decimal representation - * @return resulting BIGNUM - * @throw failed_conversion in case of error - */ - BIGNUM *dec_to_bignum(const string& dec); - /** - * Convert SSL BIGNUM data to base64 encoded string. - * @param bn BIGNUM - * @return base64encoded string - */ - string bignum_to_base64(const BIGNUM *bn); - - /** * Convert internal time representation to w3c format * @param t internal representation * @return w3c time * @throw failed_conversion in case of error */ string time_to_w3c(time_t t); /** * Convert W3C time representation to internal time_t * @param w w3c representation * @return converted time * @throw failed_conversion in case of error */ time_t w3c_to_time(const string& w); /** * Encode string to the representation suitable for using in URL. * @param str string to encode * @return encoded string * @throw failed_conversion in case of failure */ string url_encode(const string& str); /** * Make string suitable for using as x(ht)ml attribute. * @param str string to escape * @return escaped string */ string attr_escape(const string& str); /** * Convert number to string * @param l number * @return string representation * @throw failed_conversion in case of failure */ string long_to_string(long l); /** * Convert string to number * @param s string, containing the number * @return the number * @throw failed_conversion in case of failure */ long string_to_long(const string& s); /** * Encode binary data using base64. * @param data pointer to binary data * @param length length of data * @return encoded data */ string encode_base64(const void *data,size_t length); /** * Decode binary data from base64 representation. * @param data base64-encoded data * @param rv container for decoded binary */ void decode_base64(const string& data,vector<unsigned char>& rv); /** * Normalize http(s) URI according to RFC3986, section 6. URI is * expected to have scheme: in front of it. * @param uri URI * @return normalized URI * @throw not_implemented in case of non-httpi(s) URI * @throw bad_input in case of malformed URI */ string rfc_3986_normalize_uri(const string& uri); /** * Match URI against realm * @param uri URI to match * @param realm realm to match against * @return true if URI matches realm */ bool uri_matches_realm(const string& uri,const string& realm); + /** + * Strip fragment part from URI + * @param uri input/output parameter containing the URI + * @return reference to uri + */ string& strip_uri_fragment_part(string& uri); - string abi_demangle(const char* mn); - + /** + * Calculate signature and encode it using base64 + * @param assoc association being used for signing + * @param om openid message + * @return base64 representation of the signature + */ string base64_signature(const assoc_t& assoc,const basic_openid_message& om); - class change_mode_message_proxy : public basic_openid_message { - public: - const basic_openid_message& x; - const string& mode; - - change_mode_message_proxy(const basic_openid_message& xx,const string& m) : x(xx), mode(m) { } - - bool has_field(const string& n) const { return x.has_field(n); } - const string& get_field(const string& n) const { - return (n=="mode")?mode:x.get_field(n); } - bool has_ns(const string& uri) const {return x.has_ns(uri); } - string get_ns(const string& uri) const { return x.get_ns(uri); } - fields_iterator fields_begin() const { - return x.fields_begin(); } - fields_iterator fields_end() const { - return x.fields_end(); } - }; - } } #endif /* __OPKELE_UTIL_H */ diff --git a/lib/basic_op.cc b/lib/basic_op.cc index c247493..fa659ac 100644 --- a/lib/basic_op.cc +++ b/lib/basic_op.cc @@ -1,136 +1,137 @@ #include <time.h> #include <cassert> #include <openssl/sha.h> #include <openssl/hmac.h> #include <opkele/data.h> #include <opkele/basic_op.h> #include <opkele/exception.h> #include <opkele/util.h> +#include <opkele/util-internal.h> #include <opkele/uris.h> namespace opkele { void basic_OP::reset_vars() { assoc.reset(); return_to.clear(); realm.clear(); claimed_id.clear(); identity.clear(); invalidate_handle.clear(); } bool basic_OP::has_return_to() const { return !return_to.empty(); } const string& basic_OP::get_return_to() const { if(return_to.empty()) throw no_return_to(OPKELE_CP_ "No return_to URL provided with request"); return return_to; } const string& basic_OP::get_realm() const { assert(!realm.empty()); return realm; } bool basic_OP::has_identity() const { return !identity.empty(); } const string& basic_OP::get_claimed_id() const { if(claimed_id.empty()) throw non_identity(OPKELE_CP_ "attempting to retrieve claimed_id of non-identity related request"); assert(!identity.empty()); return claimed_id; } const string& basic_OP::get_identity() const { if(identity.empty()) throw non_identity(OPKELE_CP_ "attempting to retrieve identity of non-identity related request"); assert(!claimed_id.empty()); return identity; } bool basic_OP::is_id_select() const { return identity==IDURI_SELECT20; } void basic_OP::select_identity(const string& c,const string& i) { claimed_id = c; identity = i; } void basic_OP::set_claimed_id(const string& c) { claimed_id = c; } basic_openid_message& basic_OP::associate( basic_openid_message& oum, const basic_openid_message& inm) try { assert(inm.get_field("mode")=="associate"); util::dh_t dh; util::bignum_t c_pub; unsigned char key_digest[SHA256_DIGEST_LENGTH]; size_t d_len = 0; string sts = inm.get_field("session_type"); string ats = inm.get_field("assoc_type"); if(sts=="DH-SHA1" || sts=="DH-SHA256") { if(!(dh = DH_new())) throw exception_openssl(OPKELE_CP_ "failed to DH_new()"); c_pub = util::base64_to_bignum(inm.get_field("dh_consumer_public")); try { dh->p = util::base64_to_bignum(inm.get_field("dh_modulus")); }catch(failed_lookup&) { dh->p = util::dec_to_bignum(data::_default_p); } try { dh->g = util::base64_to_bignum(inm.get_field("dh_gen")); }catch(failed_lookup&) { dh->g = util::dec_to_bignum(data::_default_g); } if(!DH_generate_key(dh)) throw exception_openssl(OPKELE_CP_ "failed to DH_generate_key()"); vector<unsigned char> ck(DH_size(dh)+1); unsigned char *ckptr = &(ck.front())+1; int cklen = DH_compute_key(ckptr,c_pub,dh); if(cklen<0) throw exception_openssl(OPKELE_CP_ "failed to DH_compute_key()"); if(cklen && (*ckptr)&0x80) { (*(--ckptr)) = 0; ++cklen; } if(sts=="DH-SHA1") { SHA1(ckptr,cklen,key_digest); d_len = SHA_DIGEST_LENGTH; }else if(sts=="DH-SHA256") { SHA256(ckptr,cklen,key_digest); d_len = SHA256_DIGEST_LENGTH; }else throw internal_error(OPKELE_CP_ "I thought I knew the session type"); }else throw unsupported(OPKELE_CP_ "Unsupported session_type"); assoc_t a; if(ats=="HMAC-SHA1") a = alloc_assoc(ats,SHA_DIGEST_LENGTH,false); else if(ats=="HMAC-SHA256") a = alloc_assoc(ats,SHA256_DIGEST_LENGTH,false); else throw unsupported(OPKELE_CP_ "Unsupported assoc_type"); oum.reset_fields(); oum.set_field("ns",OIURI_OPENID20); oum.set_field("assoc_type",a->assoc_type()); oum.set_field("assoc_handle",a->handle()); oum.set_field("expires_in",util::long_to_string(a->expires_in())); secret_t secret = a->secret(); if(sts=="DH-SHA1" || sts=="DH-SHA256") { if(d_len != secret.size()) throw bad_input(OPKELE_CP_ "Association secret and session MAC are not of the same size"); oum.set_field("session_type",sts); oum.set_field("dh_server_public",util::bignum_to_base64(dh->pub_key)); string b64; secret.enxor_to_base64(key_digest,b64); oum.set_field("enc_mac_key",b64); }else /* TODO: support cleartext over encrypted connection */ throw unsupported(OPKELE_CP_ "Unsupported session type"); return oum; } catch(unsupported& u) { oum.reset_fields(); oum.set_field("ns",OIURI_OPENID20); oum.set_field("error",u.what()); oum.set_field("error_code","unsupported-type"); oum.set_field("session_type","DH-SHA256"); oum.set_field("assoc_type","HMAC-SHA256"); return oum; } void basic_OP::checkid_(const basic_openid_message& inm, extension_t *ext) { reset_vars(); string modestr = inm.get_field("mode"); if(modestr=="checkid_setup") mode = mode_checkid_setup; diff --git a/lib/basic_rp.cc b/lib/basic_rp.cc index a0ad130..e65d9fb 100644 --- a/lib/basic_rp.cc +++ b/lib/basic_rp.cc @@ -1,136 +1,137 @@ #include <cassert> #include <openssl/sha.h> #include <openssl/hmac.h> #include <opkele/basic_rp.h> #include <opkele/exception.h> #include <opkele/uris.h> #include <opkele/data.h> #include <opkele/util.h> +#include <opkele/util-internal.h> #include <opkele/curl.h> namespace opkele { static void dh_get_secret( secret_t& secret, const basic_openid_message& om, const char *exp_assoc, const char *exp_sess, util::dh_t& dh, size_t d_len, unsigned char *(*d_fun)(const unsigned char*,size_t,unsigned char*), size_t exp_s_len) try { if(om.get_field("assoc_type")!=exp_assoc || om.get_field("session_type")!=exp_sess) throw bad_input(OPKELE_CP_ "Unexpected associate response"); util::bignum_t s_pub = util::base64_to_bignum(om.get_field("dh_server_public")); vector<unsigned char> ck(DH_size(dh)+1); unsigned char *ckptr = &(ck.front())+1; int cklen = DH_compute_key(ckptr,s_pub,dh); if(cklen<0) throw exception_openssl(OPKELE_CP_ "failed to DH_compute_key()"); if(cklen && (*ckptr)&0x80) { (*(--ckptr))=0; ++cklen; } assert(d_len<=SHA256_DIGEST_LENGTH); unsigned char key_digest[SHA256_DIGEST_LENGTH]; secret.enxor_from_base64((*d_fun)(ckptr,cklen,key_digest),om.get_field("enc_mac_key")); if(secret.size()!=exp_s_len) throw bad_input(OPKELE_CP_ "Secret length isn't consistent with association type"); }catch(opkele::failed_lookup& ofl) { throw bad_input(OPKELE_CP_ "Incoherent response from OP"); } OPKELE_RETHROW static void direct_request(basic_openid_message& oum,const basic_openid_message& inm,const string& OP) { util::curl_pick_t curl = util::curl_pick_t::easy_init(); if(!curl) throw exception_curl(OPKELE_CP_ "failed to initialize curl"); string request = inm.query_string(); CURLcode r; (r=curl.misc_sets()) || (r=curl.easy_setopt(CURLOPT_URL,OP.c_str())) || (r=curl.easy_setopt(CURLOPT_POST,1)) || (r=curl.easy_setopt(CURLOPT_POSTFIELDS,request.data())) || (r=curl.easy_setopt(CURLOPT_POSTFIELDSIZE,request.length())) || (r=curl.set_write()); if(r) throw exception_curl(OPKELE_CP_ "failed to set curly options",r); if( (r=curl.easy_perform()) ) throw exception_curl(OPKELE_CP_ "failed to perform curly request",r); oum.from_keyvalues(curl.response); } assoc_t basic_RP::associate(const string& OP) { util::dh_t dh = DH_new(); if(!dh) throw exception_openssl(OPKELE_CP_ "failed to DH_new()"); dh->p = util::dec_to_bignum(data::_default_p); dh->g = util::dec_to_bignum(data::_default_g); if(!DH_generate_key(dh)) throw exception_openssl(OPKELE_CP_ "failed to DH_generate_key()"); openid_message_t req; req.set_field("ns",OIURI_OPENID20); req.set_field("mode","associate"); req.set_field("dh_modulus",util::bignum_to_base64(dh->p)); req.set_field("dh_gen",util::bignum_to_base64(dh->g)); req.set_field("dh_consumer_public",util::bignum_to_base64(dh->pub_key)); openid_message_t res; req.set_field("assoc_type","HMAC-SHA256"); req.set_field("session_type","DH-SHA256"); secret_t secret; int expires_in; try { direct_request(res,req,OP); dh_get_secret( secret, res, "HMAC-SHA256", "DH-SHA256", dh, SHA256_DIGEST_LENGTH, SHA256, SHA256_DIGEST_LENGTH ); expires_in = util::string_to_long(res.get_field("expires_in")); }catch(exception&) { try { req.set_field("assoc_type","HMAC-SHA1"); req.set_field("session_type","DH-SHA1"); direct_request(res,req,OP); dh_get_secret( secret, res, "HMAC-SHA1", "DH-SHA1", dh, SHA_DIGEST_LENGTH, SHA1, SHA_DIGEST_LENGTH ); expires_in = util::string_to_long(res.get_field("expires_in")); }catch(bad_input&) { throw dumb_RP(OPKELE_CP_ "OP failed to supply an association"); } } return store_assoc( OP, res.get_field("assoc_handle"), res.get_field("assoc_type"), secret, expires_in ); } basic_openid_message& basic_RP::checkid_( basic_openid_message& rv, mode_t mode, const string& return_to,const string& realm, extension_t *ext) { rv.reset_fields(); rv.set_field("ns",OIURI_OPENID20); if(mode==mode_checkid_immediate) rv.set_field("mode","checkid_immediate"); else if(mode==mode_checkid_setup) rv.set_field("mode","checkid_setup"); else throw bad_input(OPKELE_CP_ "unknown checkid_* mode"); if(realm.empty() && return_to.empty()) throw bad_input(OPKELE_CP_ "At least one of realm and return_to must be non-empty"); if(!realm.empty()) { rv.set_field("realm",realm); rv.set_field("trust_root",realm); } if(!return_to.empty()) rv.set_field("return_to",return_to); const openid_endpoint_t& ep = get_endpoint(); rv.set_field("claimed_id",ep.claimed_id); rv.set_field("identity",ep.local_id); try { rv.set_field("assoc_handle",find_assoc(ep.uri)->handle()); }catch(dumb_RP& drp) { }catch(failed_lookup& fl) { try { rv.set_field("assoc_handle",associate(ep.uri)->handle()); }catch(dumb_RP& drp) { } } OPKELE_RETHROW if(ext) ext->rp_checkid_hook(rv); return rv; } diff --git a/lib/consumer.cc b/lib/consumer.cc index ebda262..801496e 100644 --- a/lib/consumer.cc +++ b/lib/consumer.cc @@ -1,132 +1,133 @@ #include <algorithm> #include <cassert> #include <cstring> #include <opkele/util.h> +#include <opkele/util-internal.h> #include <opkele/curl.h> #include <opkele/exception.h> #include <opkele/data.h> #include <opkele/consumer.h> #include <openssl/sha.h> #include <openssl/hmac.h> #include <iostream> #include "config.h" #include <pcre.h> namespace opkele { using namespace std; using util::curl_t; using util::curl_pick_t; class pcre_matches_t { public: int *_ov; int _s; pcre_matches_t() : _ov(0), _s(0) { } pcre_matches_t(int s) : _ov(0), _s(s) { if(_s&1) ++_s; _s += _s>>1; _ov = new int[_s]; } ~pcre_matches_t() throw() { if(_ov) delete[] _ov; } int begin(int i) const { return _ov[i<<1]; } int end(int i) const { return _ov[(i<<1)+1]; } int length(int i) const { int t=i<<1; return _ov[t+1]-_ov[t]; } }; class pcre_t { public: pcre *_p; pcre_t() : _p(0) { } pcre_t(pcre *p) : _p(p) { } pcre_t(const char *re,int opts) : _p(0) { static const char *errptr; static int erroffset; _p = pcre_compile(re,opts,&errptr,&erroffset,NULL); if(!_p) throw internal_error(OPKELE_CP_ string("Failed to compile regexp: ")+errptr); } ~pcre_t() throw() { if(_p) (*pcre_free)(_p); } pcre_t& operator=(pcre *p) { if(_p) (*pcre_free)(_p); _p=p; return *this; } operator const pcre*(void) const { return _p; } operator pcre*(void) { return _p; } int exec(const string& s,pcre_matches_t& m) { if(!_p) throw internal_error(OPKELE_CP_ "Trying to execute absent regexp"); return pcre_exec(_p,NULL,s.c_str(),s.length(),0,0,m._ov,m._s); } }; assoc_t consumer_t::associate(const string& server) { util::dh_t dh = DH_new(); if(!dh) throw exception_openssl(OPKELE_CP_ "failed to DH_new()"); dh->p = util::dec_to_bignum(data::_default_p); dh->g = util::dec_to_bignum(data::_default_g); if(!DH_generate_key(dh)) throw exception_openssl(OPKELE_CP_ "failed to DH_generate_key()"); string request = "openid.mode=associate" "&openid.assoc_type=HMAC-SHA1" "&openid.session_type=DH-SHA1" "&openid.dh_consumer_public="; request += util::url_encode(util::bignum_to_base64(dh->pub_key)); curl_pick_t curl = curl_pick_t::easy_init(); if(!curl) throw exception_curl(OPKELE_CP_ "failed to initialize curl"); CURLcode r; (r=curl.misc_sets()) || (r=curl.easy_setopt(CURLOPT_URL,server.c_str())) || (r=curl.easy_setopt(CURLOPT_POST,1)) || (r=curl.easy_setopt(CURLOPT_POSTFIELDS,request.data())) || (r=curl.easy_setopt(CURLOPT_POSTFIELDSIZE,request.length())) || (r=curl.set_write()) ; if(r) throw exception_curl(OPKELE_CP_ "failed to set curly options",r); if( (r=curl.easy_perform()) ) throw exception_curl(OPKELE_CP_ "failed to perform curly request",r); params_t p; p.parse_keyvalues(curl.response); if(p.has_param("assoc_type") && p.get_param("assoc_type")!="HMAC-SHA1") throw bad_input(OPKELE_CP_ "unsupported assoc_type"); string st; if(p.has_param("session_type")) st = p.get_param("session_type"); if((!st.empty()) && st!="DH-SHA1") throw bad_input(OPKELE_CP_ "unsupported session_type"); secret_t secret; if(st.empty()) { secret.from_base64(p.get_param("mac_key")); }else{ util::bignum_t s_pub = util::base64_to_bignum(p.get_param("dh_server_public")); vector<unsigned char> ck(DH_size(dh)+1); unsigned char *ckptr = &(ck.front())+1; int cklen = DH_compute_key(ckptr,s_pub,dh); if(cklen<0) throw exception_openssl(OPKELE_CP_ "failed to DH_compute_key()"); if(cklen && (*ckptr)&0x80) { (*(--ckptr)) = 0; ++cklen; } unsigned char key_sha1[SHA_DIGEST_LENGTH]; SHA1(ckptr,cklen,key_sha1); secret.enxor_from_base64(key_sha1,p.get_param("enc_mac_key")); } int expires_in = 0; if(p.has_param("expires_in")) { expires_in = util::string_to_long(p.get_param("expires_in")); }else if(p.has_param("issued") && p.has_param("expiry")) { expires_in = util::w3c_to_time(p.get_param("expiry"))-util::w3c_to_time(p.get_param("issued")); }else throw bad_input(OPKELE_CP_ "no expiration information"); return store_assoc(server,p.get_param("assoc_handle"),secret,expires_in); } string consumer_t::checkid_immediate(const string& identity,const string& return_to,const string& trust_root,extension_t *ext) { return checkid_(mode_checkid_immediate,identity,return_to,trust_root,ext); } string consumer_t::checkid_setup(const string& identity,const string& return_to,const string& trust_root,extension_t *ext) { diff --git a/lib/server.cc b/lib/server.cc index 776f1ae..0dea1eb 100644 --- a/lib/server.cc +++ b/lib/server.cc @@ -1,133 +1,134 @@ #include <cstring> #include <vector> #include <openssl/sha.h> #include <openssl/hmac.h> #include <opkele/util.h> +#include <opkele/util-internal.h> #include <opkele/exception.h> #include <opkele/server.h> #include <opkele/data.h> namespace opkele { using namespace std; void server_t::associate(const params_t& pin,params_t& pout) { util::dh_t dh; util::bignum_t c_pub; unsigned char key_sha1[SHA_DIGEST_LENGTH]; enum { sess_cleartext, sess_dh_sha1 } st = sess_cleartext; if( pin.has_param("openid.session_type") && pin.get_param("openid.session_type")=="DH-SHA1" ) { /* TODO: fallback to cleartext in case of exceptions here? */ if(!(dh = DH_new())) throw exception_openssl(OPKELE_CP_ "failed to DH_new()"); c_pub = util::base64_to_bignum(pin.get_param("openid.dh_consumer_public")); if(pin.has_param("openid.dh_modulus")) dh->p = util::base64_to_bignum(pin.get_param("openid.dh_modulus")); else dh->p = util::dec_to_bignum(data::_default_p); if(pin.has_param("openid.dh_gen")) dh->g = util::base64_to_bignum(pin.get_param("openid.dh_gen")); else dh->g = util::dec_to_bignum(data::_default_g); if(!DH_generate_key(dh)) throw exception_openssl(OPKELE_CP_ "failed to DH_generate_key()"); vector<unsigned char> ck(DH_size(dh)+1); unsigned char *ckptr = &(ck.front())+1; int cklen = DH_compute_key(ckptr,c_pub,dh); if(cklen<0) throw exception_openssl(OPKELE_CP_ "failed to DH_compute_key()"); if(cklen && (*ckptr)&0x80) { (*(--ckptr)) = 0; ++cklen; } SHA1(ckptr,cklen,key_sha1); st = sess_dh_sha1; } assoc_t assoc = alloc_assoc(mode_associate); time_t now = time(0); pout.clear(); pout["assoc_type"] = assoc->assoc_type(); pout["assoc_handle"] = assoc->handle(); /* TODO: eventually remove deprecated stuff */ pout["issued"] = util::time_to_w3c(now); pout["expiry"] = util::time_to_w3c(now+assoc->expires_in()); pout["expires_in"] = util::long_to_string(assoc->expires_in()); secret_t secret = assoc->secret(); switch(st) { case sess_dh_sha1: pout["session_type"] = "DH-SHA1"; pout["dh_server_public"] = util::bignum_to_base64(dh->pub_key); secret.enxor_to_base64(key_sha1,pout["enc_mac_key"]); break; default: secret.to_base64(pout["mac_key"]); break; } } void server_t::checkid_immediate(const params_t& pin,string& return_to,params_t& pout,extension_t *ext) { checkid_(mode_checkid_immediate,pin,return_to,pout,ext); } void server_t::checkid_setup(const params_t& pin,string& return_to,params_t& pout,extension_t *ext) { checkid_(mode_checkid_setup,pin,return_to,pout,ext); } void server_t::checkid_(mode_t mode,const params_t& pin,string& return_to,params_t& pout,extension_t *ext) { if(mode!=mode_checkid_immediate && mode!=mode_checkid_setup) throw bad_input(OPKELE_CP_ "invalid checkid_* mode"); pout.clear(); assoc_t assoc; try { assoc = retrieve_assoc(pin.get_param("openid.assoc_handle")); }catch(failed_lookup& fl) { // no handle specified or no valid handle found, going dumb assoc = alloc_assoc(mode_checkid_setup); if(pin.has_param("openid.assoc_handle")) pout["invalidate_handle"]=pin.get_param("openid.assoc_handle"); } string trust_root; try { trust_root = pin.get_param("openid.trust_root"); }catch(failed_lookup& fl) { } string identity = pin.get_param("openid.identity"); return_to = pin.get_param("openid.return_to"); validate(*assoc,pin,identity,trust_root); pout["mode"] = "id_res"; pout["assoc_handle"] = assoc->handle(); if(pin.has_param("openid.assoc_handle") && assoc->stateless()) pout["invalidate_handle"] = pin.get_param("openid.assoc_handle"); pout["identity"] = identity; pout["return_to"] = return_to; /* TODO: eventually remove deprecated stuff */ time_t now = time(0); pout["issued"] = util::time_to_w3c(now); pout["valid_to"] = util::time_to_w3c(now+120); pout["exipres_in"] = "120"; pout["signed"]="mode,identity,return_to"; if(ext) ext->checkid_hook(pin,pout); pout["sig"] = util::base64_signature(assoc,pout); } void server_t::check_authentication(const params_t& pin,params_t& pout) { vector<unsigned char> sig; const string& sigenc = pin.get_param("openid.sig"); util::decode_base64(sigenc,sig); assoc_t assoc; try { assoc = retrieve_assoc(pin.get_param("openid.assoc_handle")); }catch(failed_lookup& fl) { throw failed_assertion(OPKELE_CP_ "invalid handle or handle not specified"); } if(!assoc->stateless()) throw stateful_handle(OPKELE_CP_ "will not do check_authentication on a stateful handle"); const string& slist = pin.get_param("openid.signed"); string kv; string::size_type p =0; while(true) { string::size_type co = slist.find(',',p); string f = (co==string::npos)?slist.substr(p):slist.substr(p,co-p); kv += f; diff --git a/test/idiscover.cc b/test/idiscover.cc index 44df9ce..4b1e90c 100644 --- a/test/idiscover.cc +++ b/test/idiscover.cc @@ -1,40 +1,41 @@ #include <iostream> #include <stdexcept> #include <iterator> #include <algorithm> using namespace std; #include <opkele/exception.h> #include <opkele/discovery.h> #include <opkele/util.h> +#include <opkele/util-internal.h> namespace opkele { ostream& operator<<(ostream& o,const opkele::openid_endpoint_t& oep) { o << " URI: " << oep.uri << endl << " Claimed ID: " << oep.claimed_id << endl << " Local ID: " << oep.local_id << endl; return o; } } int main(int argc,char **argv) { try { if(argc<2) throw opkele::exception(OPKELE_CP_ "Please, give me something to resolve"); for(int a=1;a<argc;++a) { cout << "==============================================================" << endl << "User-supplied ID: " << argv[a] << endl << "Endpoints:" << endl << " --" << endl; string normalized = opkele::idiscover( ostream_iterator<opkele::openid_endpoint_t>(cout," --\n") ,argv[a]); cout << "Normalized ID: " << normalized << endl; } }catch(exception& e) { cerr << "oops, caught " << opkele::util::abi_demangle(typeid(e).name()) << endl << " .what(): " << e.what() << endl; _exit(1); } _exit(0); } |