summaryrefslogtreecommitdiffabout
Side-by-side diff
Diffstat (more/less context) (show whitespace changes)
-rw-r--r--include/opkele/types.h5
-rw-r--r--lib/consumer.cc2
2 files changed, 5 insertions, 2 deletions
diff --git a/include/opkele/types.h b/include/opkele/types.h
index 757c0af..8f4bf73 100644
--- a/include/opkele/types.h
+++ b/include/opkele/types.h
@@ -50,96 +50,101 @@ namespace opkele {
/**
* plainly encode to base64 representation
* @param rv reference to the return value
*/
void to_base64(string& rv) const;
/**
* decode cleartext secret from base64
* @param b64 base64-encoded representation of the secret value
*/
void from_base64(const string& b64);
};
/**
* Interface to the association.
*/
class association_t {
public:
/**
* retrieve the server with which association was established.
* @return server name
*/
virtual string server() const = 0;
/**
* retrieve the association handle.
* @return handle
*/
virtual string handle() const = 0;
/**
* retrieve the association type.
* @return association type
*/
virtual string assoc_type() const = 0;
/**
* retrieve the association secret.
* @return association secret
*/
virtual secret_t secret() const = 0;
/**
* retrieve the number of seconds the association expires in.
* @return seconds till expiration
*/
virtual int expires_in() const = 0;
/**
* check whether the association is stateless.
* @return true if stateless
*/
virtual bool stateless() const = 0;
+ /**
+ * check whether the association is expired.
+ * @return true if expired
+ */
+ virtual bool is_expired() const = 0;
};
/**
* the auto_ptr<> for association_t object type
*/
typedef auto_ptr<association_t> assoc_t;
/**
* request/response parameters map
*/
class params_t : public map<string,string> {
public:
/**
* check whether the parameter is present.
* @param n the parameter name
* @return true if yes
*/
bool has_param(const string& n) const;
/**
* retrieve the parameter (const version)
* @param n the parameter name
* @return the parameter value
* @throw failed_lookup if there is no such parameter
*/
const string& get_param(const string& n) const;
/**
* retrieve the parameter.
* @param n the parameter name
* @return the parameter value
* @throw failed_lookup if there is no such parameter
*/
string& get_param(const string& n);
/**
* parse the OpenID key/value data.
* @param kv the OpenID key/value data
*/
void parse_keyvalues(const string& kv);
/**
* sign the fields.
* @param secret the secret used for signing
* @param sig reference to the string, containing base64-encoded
* result
* @param slist the comma-separated list of fields to sign
* @param prefix the string to prepend to parameter names
*/
void sign(secret_t secret,string& sig,const string& slist,const char *prefix=0) const;
diff --git a/lib/consumer.cc b/lib/consumer.cc
index af309c1..8f66688 100644
--- a/lib/consumer.cc
+++ b/lib/consumer.cc
@@ -99,98 +99,96 @@ namespace opkele {
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) {
return checkid_(mode_checkid_setup,identity,return_to,trust_root,ext);
}
string consumer_t::checkid_(mode_t mode,const string& identity,const string& return_to,const string& trust_root,extension_t *ext) {
params_t p;
if(mode==mode_checkid_immediate)
p["mode"]="checkid_immediate";
else if(mode==mode_checkid_setup)
p["mode"]="checkid_setup";
else
throw bad_input(OPKELE_CP_ "unknown checkid_* mode");
string iurl = canonicalize(identity);
string server, delegate;
retrieve_links(iurl,server,delegate);
p["identity"] = delegate.empty()?iurl:delegate;
if(!trust_root.empty())
p["trust_root"] = trust_root;
p["return_to"] = return_to;
try {
string ah = find_assoc(server)->handle();
- if(ah->is_expired()) /* TODO: or should I throw some other exception to force programmer fix his implementation? */
- throw failed_lookup(OPKELE_CP_ "find_assoc() has returned expired handle");
p["assoc_handle"] = ah;
}catch(failed_lookup& fl) {
string ah = associate(server)->handle();
p["assoc_handle"] = ah;
}
if(ext) ext->checkid_hook(p,identity);
return p.append_query(server);
}
void consumer_t::id_res(const params_t& pin,const string& identity,extension_t *ext) {
if(pin.has_param("openid.user_setup_url"))
throw id_res_setup(OPKELE_CP_ "assertion failed, setup url provided",pin.get_param("openid.user_setup_url"));
string server,delegate;
retrieve_links(identity.empty()?pin.get_param("openid.identity"):canonicalize(identity),server,delegate);
params_t ps;
try {
assoc_t assoc = retrieve_assoc(server,pin.get_param("openid.assoc_handle"));
if(assoc->is_expired()) /* TODO: or should I throw some other exception to force programmer fix his implementation? */
throw failed_lookup(OPKELE_CP_ "retrieve_assoc() has returned expired handle");
const string& sigenc = pin.get_param("openid.sig");
vector<unsigned char> sig;
util::decode_base64(sigenc,sig);
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;
kv += ':';
f.insert(0,"openid.");
kv += pin.get_param(f);
kv += '\n';
if(ext) ps[f.substr(sizeof("openid.")-1)] = pin.get_param(f);
if(co==string::npos)
break;
p = co+1;
}
secret_t secret = assoc->secret();
unsigned int md_len = 0;
unsigned char *md = HMAC(
EVP_sha1(),
&(secret.front()),secret.size(),
(const unsigned char *)kv.data(),kv.length(),
0,&md_len);
if(sig.size()!=md_len || memcmp(&(sig.front()),md,md_len))
throw id_res_mismatch(OPKELE_CP_ "signature mismatch");
}catch(failed_lookup& e) { /* XXX: more specific? */