summaryrefslogtreecommitdiffabout
path: root/lib
Unidiff
Diffstat (limited to 'lib') (more/less context) (ignore whitespace changes)
-rw-r--r--lib/basic_op.cc1
-rw-r--r--lib/basic_rp.cc1
-rw-r--r--lib/consumer.cc1
-rw-r--r--lib/server.cc1
4 files changed, 4 insertions, 0 deletions
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,264 +1,265 @@
1#include <time.h> 1#include <time.h>
2#include <cassert> 2#include <cassert>
3#include <openssl/sha.h> 3#include <openssl/sha.h>
4#include <openssl/hmac.h> 4#include <openssl/hmac.h>
5#include <opkele/data.h> 5#include <opkele/data.h>
6#include <opkele/basic_op.h> 6#include <opkele/basic_op.h>
7#include <opkele/exception.h> 7#include <opkele/exception.h>
8#include <opkele/util.h> 8#include <opkele/util.h>
9#include <opkele/util-internal.h>
9#include <opkele/uris.h> 10#include <opkele/uris.h>
10 11
11namespace opkele { 12namespace opkele {
12 13
13 void basic_OP::reset_vars() { 14 void basic_OP::reset_vars() {
14 assoc.reset(); 15 assoc.reset();
15 return_to.clear(); realm.clear(); 16 return_to.clear(); realm.clear();
16 claimed_id.clear(); identity.clear(); 17 claimed_id.clear(); identity.clear();
17 invalidate_handle.clear(); 18 invalidate_handle.clear();
18 } 19 }
19 20
20 bool basic_OP::has_return_to() const { 21 bool basic_OP::has_return_to() const {
21 return !return_to.empty(); 22 return !return_to.empty();
22 } 23 }
23 const string& basic_OP::get_return_to() const { 24 const string& basic_OP::get_return_to() const {
24 if(return_to.empty()) 25 if(return_to.empty())
25 throw no_return_to(OPKELE_CP_ "No return_to URL provided with request"); 26 throw no_return_to(OPKELE_CP_ "No return_to URL provided with request");
26 return return_to; 27 return return_to;
27 } 28 }
28 29
29 const string& basic_OP::get_realm() const { 30 const string& basic_OP::get_realm() const {
30 assert(!realm.empty()); 31 assert(!realm.empty());
31 return realm; 32 return realm;
32 } 33 }
33 34
34 bool basic_OP::has_identity() const { 35 bool basic_OP::has_identity() const {
35 return !identity.empty(); 36 return !identity.empty();
36 } 37 }
37 const string& basic_OP::get_claimed_id() const { 38 const string& basic_OP::get_claimed_id() const {
38 if(claimed_id.empty()) 39 if(claimed_id.empty())
39 throw non_identity(OPKELE_CP_ "attempting to retrieve claimed_id of non-identity related request"); 40 throw non_identity(OPKELE_CP_ "attempting to retrieve claimed_id of non-identity related request");
40 assert(!identity.empty()); 41 assert(!identity.empty());
41 return claimed_id; 42 return claimed_id;
42 } 43 }
43 const string& basic_OP::get_identity() const { 44 const string& basic_OP::get_identity() const {
44 if(identity.empty()) 45 if(identity.empty())
45 throw non_identity(OPKELE_CP_ "attempting to retrieve identity of non-identity related request"); 46 throw non_identity(OPKELE_CP_ "attempting to retrieve identity of non-identity related request");
46 assert(!claimed_id.empty()); 47 assert(!claimed_id.empty());
47 return identity; 48 return identity;
48 } 49 }
49 50
50 bool basic_OP::is_id_select() const { 51 bool basic_OP::is_id_select() const {
51 return identity==IDURI_SELECT20; 52 return identity==IDURI_SELECT20;
52 } 53 }
53 54
54 void basic_OP::select_identity(const string& c,const string& i) { 55 void basic_OP::select_identity(const string& c,const string& i) {
55 claimed_id = c; identity = i; 56 claimed_id = c; identity = i;
56 } 57 }
57 void basic_OP::set_claimed_id(const string& c) { 58 void basic_OP::set_claimed_id(const string& c) {
58 claimed_id = c; 59 claimed_id = c;
59 } 60 }
60 61
61 basic_openid_message& basic_OP::associate( 62 basic_openid_message& basic_OP::associate(
62 basic_openid_message& oum, 63 basic_openid_message& oum,
63 const basic_openid_message& inm) try { 64 const basic_openid_message& inm) try {
64 assert(inm.get_field("mode")=="associate"); 65 assert(inm.get_field("mode")=="associate");
65 util::dh_t dh; 66 util::dh_t dh;
66 util::bignum_t c_pub; 67 util::bignum_t c_pub;
67 unsigned char key_digest[SHA256_DIGEST_LENGTH]; 68 unsigned char key_digest[SHA256_DIGEST_LENGTH];
68 size_t d_len = 0; 69 size_t d_len = 0;
69 string sts = inm.get_field("session_type"); 70 string sts = inm.get_field("session_type");
70 string ats = inm.get_field("assoc_type"); 71 string ats = inm.get_field("assoc_type");
71 if(sts=="DH-SHA1" || sts=="DH-SHA256") { 72 if(sts=="DH-SHA1" || sts=="DH-SHA256") {
72 if(!(dh = DH_new())) 73 if(!(dh = DH_new()))
73 throw exception_openssl(OPKELE_CP_ "failed to DH_new()"); 74 throw exception_openssl(OPKELE_CP_ "failed to DH_new()");
74 c_pub = util::base64_to_bignum(inm.get_field("dh_consumer_public")); 75 c_pub = util::base64_to_bignum(inm.get_field("dh_consumer_public"));
75 try { dh->p = util::base64_to_bignum(inm.get_field("dh_modulus")); 76 try { dh->p = util::base64_to_bignum(inm.get_field("dh_modulus"));
76 }catch(failed_lookup&) { 77 }catch(failed_lookup&) {
77 dh->p = util::dec_to_bignum(data::_default_p); } 78 dh->p = util::dec_to_bignum(data::_default_p); }
78 try { dh->g = util::base64_to_bignum(inm.get_field("dh_gen")); 79 try { dh->g = util::base64_to_bignum(inm.get_field("dh_gen"));
79 }catch(failed_lookup&) { 80 }catch(failed_lookup&) {
80 dh->g = util::dec_to_bignum(data::_default_g); } 81 dh->g = util::dec_to_bignum(data::_default_g); }
81 if(!DH_generate_key(dh)) 82 if(!DH_generate_key(dh))
82 throw exception_openssl(OPKELE_CP_ "failed to DH_generate_key()"); 83 throw exception_openssl(OPKELE_CP_ "failed to DH_generate_key()");
83 vector<unsigned char> ck(DH_size(dh)+1); 84 vector<unsigned char> ck(DH_size(dh)+1);
84 unsigned char *ckptr = &(ck.front())+1; 85 unsigned char *ckptr = &(ck.front())+1;
85 int cklen = DH_compute_key(ckptr,c_pub,dh); 86 int cklen = DH_compute_key(ckptr,c_pub,dh);
86 if(cklen<0) 87 if(cklen<0)
87 throw exception_openssl(OPKELE_CP_ "failed to DH_compute_key()"); 88 throw exception_openssl(OPKELE_CP_ "failed to DH_compute_key()");
88 if(cklen && (*ckptr)&0x80) { 89 if(cklen && (*ckptr)&0x80) {
89 (*(--ckptr)) = 0; ++cklen; } 90 (*(--ckptr)) = 0; ++cklen; }
90 if(sts=="DH-SHA1") { 91 if(sts=="DH-SHA1") {
91 SHA1(ckptr,cklen,key_digest); d_len = SHA_DIGEST_LENGTH; 92 SHA1(ckptr,cklen,key_digest); d_len = SHA_DIGEST_LENGTH;
92 }else if(sts=="DH-SHA256") { 93 }else if(sts=="DH-SHA256") {
93 SHA256(ckptr,cklen,key_digest); d_len = SHA256_DIGEST_LENGTH; 94 SHA256(ckptr,cklen,key_digest); d_len = SHA256_DIGEST_LENGTH;
94 }else 95 }else
95 throw internal_error(OPKELE_CP_ "I thought I knew the session type"); 96 throw internal_error(OPKELE_CP_ "I thought I knew the session type");
96 }else 97 }else
97 throw unsupported(OPKELE_CP_ "Unsupported session_type"); 98 throw unsupported(OPKELE_CP_ "Unsupported session_type");
98 assoc_t a; 99 assoc_t a;
99 if(ats=="HMAC-SHA1") 100 if(ats=="HMAC-SHA1")
100 a = alloc_assoc(ats,SHA_DIGEST_LENGTH,false); 101 a = alloc_assoc(ats,SHA_DIGEST_LENGTH,false);
101 else if(ats=="HMAC-SHA256") 102 else if(ats=="HMAC-SHA256")
102 a = alloc_assoc(ats,SHA256_DIGEST_LENGTH,false); 103 a = alloc_assoc(ats,SHA256_DIGEST_LENGTH,false);
103 else 104 else
104 throw unsupported(OPKELE_CP_ "Unsupported assoc_type"); 105 throw unsupported(OPKELE_CP_ "Unsupported assoc_type");
105 oum.reset_fields(); 106 oum.reset_fields();
106 oum.set_field("ns",OIURI_OPENID20); 107 oum.set_field("ns",OIURI_OPENID20);
107 oum.set_field("assoc_type",a->assoc_type()); 108 oum.set_field("assoc_type",a->assoc_type());
108 oum.set_field("assoc_handle",a->handle()); 109 oum.set_field("assoc_handle",a->handle());
109 oum.set_field("expires_in",util::long_to_string(a->expires_in())); 110 oum.set_field("expires_in",util::long_to_string(a->expires_in()));
110 secret_t secret = a->secret(); 111 secret_t secret = a->secret();
111 if(sts=="DH-SHA1" || sts=="DH-SHA256") { 112 if(sts=="DH-SHA1" || sts=="DH-SHA256") {
112 if(d_len != secret.size()) 113 if(d_len != secret.size())
113 throw bad_input(OPKELE_CP_ "Association secret and session MAC are not of the same size"); 114 throw bad_input(OPKELE_CP_ "Association secret and session MAC are not of the same size");
114 oum.set_field("session_type",sts); 115 oum.set_field("session_type",sts);
115 oum.set_field("dh_server_public",util::bignum_to_base64(dh->pub_key)); 116 oum.set_field("dh_server_public",util::bignum_to_base64(dh->pub_key));
116 string b64; secret.enxor_to_base64(key_digest,b64); 117 string b64; secret.enxor_to_base64(key_digest,b64);
117 oum.set_field("enc_mac_key",b64); 118 oum.set_field("enc_mac_key",b64);
118 }else /* TODO: support cleartext over encrypted connection */ 119 }else /* TODO: support cleartext over encrypted connection */
119 throw unsupported(OPKELE_CP_ "Unsupported session type"); 120 throw unsupported(OPKELE_CP_ "Unsupported session type");
120 return oum; 121 return oum;
121 } catch(unsupported& u) { 122 } catch(unsupported& u) {
122 oum.reset_fields(); 123 oum.reset_fields();
123 oum.set_field("ns",OIURI_OPENID20); 124 oum.set_field("ns",OIURI_OPENID20);
124 oum.set_field("error",u.what()); 125 oum.set_field("error",u.what());
125 oum.set_field("error_code","unsupported-type"); 126 oum.set_field("error_code","unsupported-type");
126 oum.set_field("session_type","DH-SHA256"); 127 oum.set_field("session_type","DH-SHA256");
127 oum.set_field("assoc_type","HMAC-SHA256"); 128 oum.set_field("assoc_type","HMAC-SHA256");
128 return oum; 129 return oum;
129 } 130 }
130 131
131 void basic_OP::checkid_(const basic_openid_message& inm, 132 void basic_OP::checkid_(const basic_openid_message& inm,
132 extension_t *ext) { 133 extension_t *ext) {
133 reset_vars(); 134 reset_vars();
134 string modestr = inm.get_field("mode"); 135 string modestr = inm.get_field("mode");
135 if(modestr=="checkid_setup") 136 if(modestr=="checkid_setup")
136 mode = mode_checkid_setup; 137 mode = mode_checkid_setup;
137 else if(modestr=="checkid_immediate") 138 else if(modestr=="checkid_immediate")
138 mode = mode_checkid_immediate; 139 mode = mode_checkid_immediate;
139 else 140 else
140 throw bad_input(OPKELE_CP_ "Invalid checkid_* mode"); 141 throw bad_input(OPKELE_CP_ "Invalid checkid_* mode");
141 try { 142 try {
142 assoc = retrieve_assoc(invalidate_handle=inm.get_field("assoc_handle")); 143 assoc = retrieve_assoc(invalidate_handle=inm.get_field("assoc_handle"));
143 invalidate_handle.clear(); 144 invalidate_handle.clear();
144 }catch(failed_lookup&) { } 145 }catch(failed_lookup&) { }
145 try { 146 try {
146 openid2 = (inm.get_field("ns")==OIURI_OPENID20); 147 openid2 = (inm.get_field("ns")==OIURI_OPENID20);
147 }catch(failed_lookup&) { openid2 = false; } 148 }catch(failed_lookup&) { openid2 = false; }
148 try { 149 try {
149 return_to = inm.get_field("return_to"); 150 return_to = inm.get_field("return_to");
150 }catch(failed_lookup&) { } 151 }catch(failed_lookup&) { }
151 if(openid2) { 152 if(openid2) {
152 try { 153 try {
153 realm = inm.get_field("realm"); 154 realm = inm.get_field("realm");
154 }catch(failed_lookup&) { 155 }catch(failed_lookup&) {
155 try { 156 try {
156 realm = inm.get_field("trust_root"); 157 realm = inm.get_field("trust_root");
157 }catch(failed_lookup&) { 158 }catch(failed_lookup&) {
158 if(return_to.empty()) 159 if(return_to.empty())
159 throw bad_input(OPKELE_CP_ 160 throw bad_input(OPKELE_CP_
160 "Both realm and return_to are unset"); 161 "Both realm and return_to are unset");
161 realm = return_to; 162 realm = return_to;
162 } 163 }
163 } 164 }
164 }else{ 165 }else{
165 try { 166 try {
166 realm = inm.get_field("trust_root"); 167 realm = inm.get_field("trust_root");
167 }catch(failed_lookup&) { 168 }catch(failed_lookup&) {
168 if(return_to.empty()) 169 if(return_to.empty())
169 throw bad_input(OPKELE_CP_ 170 throw bad_input(OPKELE_CP_
170 "Both realm and return_to are unset"); 171 "Both realm and return_to are unset");
171 realm = return_to; 172 realm = return_to;
172 } 173 }
173 } 174 }
174 try { 175 try {
175 identity = inm.get_field("identity"); 176 identity = inm.get_field("identity");
176 try { 177 try {
177 claimed_id = inm.get_field("claimed_id"); 178 claimed_id = inm.get_field("claimed_id");
178 }catch(failed_lookup&) { 179 }catch(failed_lookup&) {
179 if(openid2) 180 if(openid2)
180 throw bad_input(OPKELE_CP_ 181 throw bad_input(OPKELE_CP_
181 "claimed_id and identity must be either both present or both absent"); 182 "claimed_id and identity must be either both present or both absent");
182 claimed_id = identity; 183 claimed_id = identity;
183 } 184 }
184 }catch(failed_lookup&) { 185 }catch(failed_lookup&) {
185 if(openid2 && inm.has_field("claimed_id")) 186 if(openid2 && inm.has_field("claimed_id"))
186 throw bad_input(OPKELE_CP_ 187 throw bad_input(OPKELE_CP_
187 "claimed_id and identity must be either both present or both absent"); 188 "claimed_id and identity must be either both present or both absent");
188 } 189 }
189 verify_return_to(); 190 verify_return_to();
190 if(ext) ext->op_checkid_hook(inm); 191 if(ext) ext->op_checkid_hook(inm);
191 } 192 }
192 193
193 basic_openid_message& basic_OP::id_res(basic_openid_message& om, 194 basic_openid_message& basic_OP::id_res(basic_openid_message& om,
194 extension_t *ext) { 195 extension_t *ext) {
195 assert(!return_to.empty()); 196 assert(!return_to.empty());
196 assert(!is_id_select()); 197 assert(!is_id_select());
197 if(!assoc) { 198 if(!assoc) {
198 assoc = alloc_assoc("HMAC-SHA256",SHA256_DIGEST_LENGTH,true); 199 assoc = alloc_assoc("HMAC-SHA256",SHA256_DIGEST_LENGTH,true);
199 } 200 }
200 time_t now = time(0); 201 time_t now = time(0);
201 struct tm gmt; gmtime_r(&now,&gmt); 202 struct tm gmt; gmtime_r(&now,&gmt);
202 char w3timestr[24]; 203 char w3timestr[24];
203 if(!strftime(w3timestr,sizeof(w3timestr),"%Y-%m-%dT%H:%M:%SZ",&gmt)) 204 if(!strftime(w3timestr,sizeof(w3timestr),"%Y-%m-%dT%H:%M:%SZ",&gmt))
204 throw failed_conversion(OPKELE_CP_ 205 throw failed_conversion(OPKELE_CP_
205 "Failed to build time string for nonce" ); 206 "Failed to build time string for nonce" );
206 om.set_field("ns",OIURI_OPENID20); 207 om.set_field("ns",OIURI_OPENID20);
207 om.set_field("mode","id_res"); 208 om.set_field("mode","id_res");
208 om.set_field("op_endpoint",get_op_endpoint()); 209 om.set_field("op_endpoint",get_op_endpoint());
209 string ats = "ns,mode,op_endpoint,return_to,response_nonce," 210 string ats = "ns,mode,op_endpoint,return_to,response_nonce,"
210 "assoc_handle,signed"; 211 "assoc_handle,signed";
211 if(!identity.empty()) { 212 if(!identity.empty()) {
212 om.set_field("identity",identity); 213 om.set_field("identity",identity);
213 om.set_field("claimed_id",claimed_id); 214 om.set_field("claimed_id",claimed_id);
214 ats += ",identity,claimed_id"; 215 ats += ",identity,claimed_id";
215 } 216 }
216 om.set_field("return_to",return_to); 217 om.set_field("return_to",return_to);
217 string nonce = w3timestr; 218 string nonce = w3timestr;
218 om.set_field("response_nonce",alloc_nonce(nonce)); 219 om.set_field("response_nonce",alloc_nonce(nonce));
219 if(!invalidate_handle.empty()) { 220 if(!invalidate_handle.empty()) {
220 om.set_field("invalidate_handle",invalidate_handle); 221 om.set_field("invalidate_handle",invalidate_handle);
221 ats += ",invalidate_handle"; 222 ats += ",invalidate_handle";
222 } 223 }
223 om.set_field("assoc_handle",assoc->handle()); 224 om.set_field("assoc_handle",assoc->handle());
224 om.add_to_signed(ats); 225 om.add_to_signed(ats);
225 if(ext) ext->op_id_res_hook(om); 226 if(ext) ext->op_id_res_hook(om);
226 om.set_field("sig",util::base64_signature(assoc,om)); 227 om.set_field("sig",util::base64_signature(assoc,om));
227 return om; 228 return om;
228 } 229 }
229 230
230 basic_openid_message& basic_OP::cancel(basic_openid_message& om) { 231 basic_openid_message& basic_OP::cancel(basic_openid_message& om) {
231 assert(!return_to.empty()); 232 assert(!return_to.empty());
232 om.set_field("ns",OIURI_OPENID20); 233 om.set_field("ns",OIURI_OPENID20);
233 om.set_field("mode","cancel"); 234 om.set_field("mode","cancel");
234 return om; 235 return om;
235 } 236 }
236 237
237 basic_openid_message& basic_OP::error(basic_openid_message& om, 238 basic_openid_message& basic_OP::error(basic_openid_message& om,
238 const string& err,const string& contact, 239 const string& err,const string& contact,
239 const string& reference ) { 240 const string& reference ) {
240 assert(!return_to.empty()); 241 assert(!return_to.empty());
241 om.set_field("ns",OIURI_OPENID20); 242 om.set_field("ns",OIURI_OPENID20);
242 om.set_field("mode","error"); 243 om.set_field("mode","error");
243 om.set_field("error",err); 244 om.set_field("error",err);
244 if(!contact.empty()) om.set_field("contact",contact); 245 if(!contact.empty()) om.set_field("contact",contact);
245 if(!reference.empty()) om.set_field("reference",reference); 246 if(!reference.empty()) om.set_field("reference",reference);
246 return om; 247 return om;
247 } 248 }
248 249
249 basic_openid_message& basic_OP::setup_needed( 250 basic_openid_message& basic_OP::setup_needed(
250 basic_openid_message& oum,const basic_openid_message& inm) { 251 basic_openid_message& oum,const basic_openid_message& inm) {
251 assert(mode==mode_checkid_immediate); 252 assert(mode==mode_checkid_immediate);
252 assert(!return_to.empty()); 253 assert(!return_to.empty());
253 if(openid2) { 254 if(openid2) {
254 oum.set_field("ns",OIURI_OPENID20); 255 oum.set_field("ns",OIURI_OPENID20);
255 oum.set_field("mode","setup_needed"); 256 oum.set_field("mode","setup_needed");
256 }else{ 257 }else{
257 oum.set_field("mode","id_res"); 258 oum.set_field("mode","id_res");
258 static const string setupmode = "checkid_setup"; 259 static const string setupmode = "checkid_setup";
259 oum.set_field("user_setup_url", 260 oum.set_field("user_setup_url",
260 util::change_mode_message_proxy(inm,setupmode) 261 util::change_mode_message_proxy(inm,setupmode)
261 .append_query(get_op_endpoint())); 262 .append_query(get_op_endpoint()));
262 } 263 }
263 return oum; 264 return oum;
264 } 265 }
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,264 +1,265 @@
1#include <cassert> 1#include <cassert>
2#include <openssl/sha.h> 2#include <openssl/sha.h>
3#include <openssl/hmac.h> 3#include <openssl/hmac.h>
4#include <opkele/basic_rp.h> 4#include <opkele/basic_rp.h>
5#include <opkele/exception.h> 5#include <opkele/exception.h>
6#include <opkele/uris.h> 6#include <opkele/uris.h>
7#include <opkele/data.h> 7#include <opkele/data.h>
8#include <opkele/util.h> 8#include <opkele/util.h>
9#include <opkele/util-internal.h>
9#include <opkele/curl.h> 10#include <opkele/curl.h>
10 11
11namespace opkele { 12namespace opkele {
12 13
13 static void dh_get_secret( 14 static void dh_get_secret(
14 secret_t& secret, const basic_openid_message& om, 15 secret_t& secret, const basic_openid_message& om,
15 const char *exp_assoc, const char *exp_sess, 16 const char *exp_assoc, const char *exp_sess,
16 util::dh_t& dh, 17 util::dh_t& dh,
17 size_t d_len, unsigned char *(*d_fun)(const unsigned char*,size_t,unsigned char*), 18 size_t d_len, unsigned char *(*d_fun)(const unsigned char*,size_t,unsigned char*),
18 size_t exp_s_len) try { 19 size_t exp_s_len) try {
19 if(om.get_field("assoc_type")!=exp_assoc || om.get_field("session_type")!=exp_sess) 20 if(om.get_field("assoc_type")!=exp_assoc || om.get_field("session_type")!=exp_sess)
20 throw bad_input(OPKELE_CP_ "Unexpected associate response"); 21 throw bad_input(OPKELE_CP_ "Unexpected associate response");
21 util::bignum_t s_pub = util::base64_to_bignum(om.get_field("dh_server_public")); 22 util::bignum_t s_pub = util::base64_to_bignum(om.get_field("dh_server_public"));
22 vector<unsigned char> ck(DH_size(dh)+1); 23 vector<unsigned char> ck(DH_size(dh)+1);
23 unsigned char *ckptr = &(ck.front())+1; 24 unsigned char *ckptr = &(ck.front())+1;
24 int cklen = DH_compute_key(ckptr,s_pub,dh); 25 int cklen = DH_compute_key(ckptr,s_pub,dh);
25 if(cklen<0) 26 if(cklen<0)
26 throw exception_openssl(OPKELE_CP_ "failed to DH_compute_key()"); 27 throw exception_openssl(OPKELE_CP_ "failed to DH_compute_key()");
27 if(cklen && (*ckptr)&0x80) { 28 if(cklen && (*ckptr)&0x80) {
28 (*(--ckptr))=0; ++cklen; } 29 (*(--ckptr))=0; ++cklen; }
29 assert(d_len<=SHA256_DIGEST_LENGTH); 30 assert(d_len<=SHA256_DIGEST_LENGTH);
30 unsigned char key_digest[SHA256_DIGEST_LENGTH]; 31 unsigned char key_digest[SHA256_DIGEST_LENGTH];
31 secret.enxor_from_base64((*d_fun)(ckptr,cklen,key_digest),om.get_field("enc_mac_key")); 32 secret.enxor_from_base64((*d_fun)(ckptr,cklen,key_digest),om.get_field("enc_mac_key"));
32 if(secret.size()!=exp_s_len) 33 if(secret.size()!=exp_s_len)
33 throw bad_input(OPKELE_CP_ "Secret length isn't consistent with association type"); 34 throw bad_input(OPKELE_CP_ "Secret length isn't consistent with association type");
34 }catch(opkele::failed_lookup& ofl) { 35 }catch(opkele::failed_lookup& ofl) {
35 throw bad_input(OPKELE_CP_ "Incoherent response from OP"); 36 throw bad_input(OPKELE_CP_ "Incoherent response from OP");
36 } OPKELE_RETHROW 37 } OPKELE_RETHROW
37 38
38 static void direct_request(basic_openid_message& oum,const basic_openid_message& inm,const string& OP) { 39 static void direct_request(basic_openid_message& oum,const basic_openid_message& inm,const string& OP) {
39 util::curl_pick_t curl = util::curl_pick_t::easy_init(); 40 util::curl_pick_t curl = util::curl_pick_t::easy_init();
40 if(!curl) 41 if(!curl)
41 throw exception_curl(OPKELE_CP_ "failed to initialize curl"); 42 throw exception_curl(OPKELE_CP_ "failed to initialize curl");
42 string request = inm.query_string(); 43 string request = inm.query_string();
43 CURLcode r; 44 CURLcode r;
44 (r=curl.misc_sets()) 45 (r=curl.misc_sets())
45 || (r=curl.easy_setopt(CURLOPT_URL,OP.c_str())) 46 || (r=curl.easy_setopt(CURLOPT_URL,OP.c_str()))
46 || (r=curl.easy_setopt(CURLOPT_POST,1)) 47 || (r=curl.easy_setopt(CURLOPT_POST,1))
47 || (r=curl.easy_setopt(CURLOPT_POSTFIELDS,request.data())) 48 || (r=curl.easy_setopt(CURLOPT_POSTFIELDS,request.data()))
48 || (r=curl.easy_setopt(CURLOPT_POSTFIELDSIZE,request.length())) 49 || (r=curl.easy_setopt(CURLOPT_POSTFIELDSIZE,request.length()))
49 || (r=curl.set_write()); 50 || (r=curl.set_write());
50 if(r) 51 if(r)
51 throw exception_curl(OPKELE_CP_ "failed to set curly options",r); 52 throw exception_curl(OPKELE_CP_ "failed to set curly options",r);
52 if( (r=curl.easy_perform()) ) 53 if( (r=curl.easy_perform()) )
53 throw exception_curl(OPKELE_CP_ "failed to perform curly request",r); 54 throw exception_curl(OPKELE_CP_ "failed to perform curly request",r);
54 oum.from_keyvalues(curl.response); 55 oum.from_keyvalues(curl.response);
55 } 56 }
56 57
57 58
58 assoc_t basic_RP::associate(const string& OP) { 59 assoc_t basic_RP::associate(const string& OP) {
59 util::dh_t dh = DH_new(); 60 util::dh_t dh = DH_new();
60 if(!dh) 61 if(!dh)
61 throw exception_openssl(OPKELE_CP_ "failed to DH_new()"); 62 throw exception_openssl(OPKELE_CP_ "failed to DH_new()");
62 dh->p = util::dec_to_bignum(data::_default_p); 63 dh->p = util::dec_to_bignum(data::_default_p);
63 dh->g = util::dec_to_bignum(data::_default_g); 64 dh->g = util::dec_to_bignum(data::_default_g);
64 if(!DH_generate_key(dh)) 65 if(!DH_generate_key(dh))
65 throw exception_openssl(OPKELE_CP_ "failed to DH_generate_key()"); 66 throw exception_openssl(OPKELE_CP_ "failed to DH_generate_key()");
66 openid_message_t req; 67 openid_message_t req;
67 req.set_field("ns",OIURI_OPENID20); 68 req.set_field("ns",OIURI_OPENID20);
68 req.set_field("mode","associate"); 69 req.set_field("mode","associate");
69 req.set_field("dh_modulus",util::bignum_to_base64(dh->p)); 70 req.set_field("dh_modulus",util::bignum_to_base64(dh->p));
70 req.set_field("dh_gen",util::bignum_to_base64(dh->g)); 71 req.set_field("dh_gen",util::bignum_to_base64(dh->g));
71 req.set_field("dh_consumer_public",util::bignum_to_base64(dh->pub_key)); 72 req.set_field("dh_consumer_public",util::bignum_to_base64(dh->pub_key));
72 openid_message_t res; 73 openid_message_t res;
73 req.set_field("assoc_type","HMAC-SHA256"); 74 req.set_field("assoc_type","HMAC-SHA256");
74 req.set_field("session_type","DH-SHA256"); 75 req.set_field("session_type","DH-SHA256");
75 secret_t secret; 76 secret_t secret;
76 int expires_in; 77 int expires_in;
77 try { 78 try {
78 direct_request(res,req,OP); 79 direct_request(res,req,OP);
79 dh_get_secret( secret, res, 80 dh_get_secret( secret, res,
80 "HMAC-SHA256", "DH-SHA256", 81 "HMAC-SHA256", "DH-SHA256",
81 dh, SHA256_DIGEST_LENGTH, SHA256, SHA256_DIGEST_LENGTH ); 82 dh, SHA256_DIGEST_LENGTH, SHA256, SHA256_DIGEST_LENGTH );
82 expires_in = util::string_to_long(res.get_field("expires_in")); 83 expires_in = util::string_to_long(res.get_field("expires_in"));
83 }catch(exception&) { 84 }catch(exception&) {
84 try { 85 try {
85 req.set_field("assoc_type","HMAC-SHA1"); 86 req.set_field("assoc_type","HMAC-SHA1");
86 req.set_field("session_type","DH-SHA1"); 87 req.set_field("session_type","DH-SHA1");
87 direct_request(res,req,OP); 88 direct_request(res,req,OP);
88 dh_get_secret( secret, res, 89 dh_get_secret( secret, res,
89 "HMAC-SHA1", "DH-SHA1", 90 "HMAC-SHA1", "DH-SHA1",
90 dh, SHA_DIGEST_LENGTH, SHA1, SHA_DIGEST_LENGTH ); 91 dh, SHA_DIGEST_LENGTH, SHA1, SHA_DIGEST_LENGTH );
91 expires_in = util::string_to_long(res.get_field("expires_in")); 92 expires_in = util::string_to_long(res.get_field("expires_in"));
92 }catch(bad_input&) { 93 }catch(bad_input&) {
93 throw dumb_RP(OPKELE_CP_ "OP failed to supply an association"); 94 throw dumb_RP(OPKELE_CP_ "OP failed to supply an association");
94 } 95 }
95 } 96 }
96 return store_assoc( 97 return store_assoc(
97 OP, res.get_field("assoc_handle"), 98 OP, res.get_field("assoc_handle"),
98 res.get_field("assoc_type"), secret, 99 res.get_field("assoc_type"), secret,
99 expires_in ); 100 expires_in );
100 } 101 }
101 102
102 basic_openid_message& basic_RP::checkid_( 103 basic_openid_message& basic_RP::checkid_(
103 basic_openid_message& rv, 104 basic_openid_message& rv,
104 mode_t mode, 105 mode_t mode,
105 const string& return_to,const string& realm, 106 const string& return_to,const string& realm,
106 extension_t *ext) { 107 extension_t *ext) {
107 rv.reset_fields(); 108 rv.reset_fields();
108 rv.set_field("ns",OIURI_OPENID20); 109 rv.set_field("ns",OIURI_OPENID20);
109 if(mode==mode_checkid_immediate) 110 if(mode==mode_checkid_immediate)
110 rv.set_field("mode","checkid_immediate"); 111 rv.set_field("mode","checkid_immediate");
111 else if(mode==mode_checkid_setup) 112 else if(mode==mode_checkid_setup)
112 rv.set_field("mode","checkid_setup"); 113 rv.set_field("mode","checkid_setup");
113 else 114 else
114 throw bad_input(OPKELE_CP_ "unknown checkid_* mode"); 115 throw bad_input(OPKELE_CP_ "unknown checkid_* mode");
115 if(realm.empty() && return_to.empty()) 116 if(realm.empty() && return_to.empty())
116 throw bad_input(OPKELE_CP_ "At least one of realm and return_to must be non-empty"); 117 throw bad_input(OPKELE_CP_ "At least one of realm and return_to must be non-empty");
117 if(!realm.empty()) { 118 if(!realm.empty()) {
118 rv.set_field("realm",realm); 119 rv.set_field("realm",realm);
119 rv.set_field("trust_root",realm); 120 rv.set_field("trust_root",realm);
120 } 121 }
121 if(!return_to.empty()) 122 if(!return_to.empty())
122 rv.set_field("return_to",return_to); 123 rv.set_field("return_to",return_to);
123 const openid_endpoint_t& ep = get_endpoint(); 124 const openid_endpoint_t& ep = get_endpoint();
124 rv.set_field("claimed_id",ep.claimed_id); 125 rv.set_field("claimed_id",ep.claimed_id);
125 rv.set_field("identity",ep.local_id); 126 rv.set_field("identity",ep.local_id);
126 try { 127 try {
127 rv.set_field("assoc_handle",find_assoc(ep.uri)->handle()); 128 rv.set_field("assoc_handle",find_assoc(ep.uri)->handle());
128 }catch(dumb_RP& drp) { 129 }catch(dumb_RP& drp) {
129 }catch(failed_lookup& fl) { 130 }catch(failed_lookup& fl) {
130 try { 131 try {
131 rv.set_field("assoc_handle",associate(ep.uri)->handle()); 132 rv.set_field("assoc_handle",associate(ep.uri)->handle());
132 }catch(dumb_RP& drp) { } 133 }catch(dumb_RP& drp) { }
133 } OPKELE_RETHROW 134 } OPKELE_RETHROW
134 if(ext) ext->rp_checkid_hook(rv); 135 if(ext) ext->rp_checkid_hook(rv);
135 return rv; 136 return rv;
136 } 137 }
137 138
138 class signed_part_message_proxy : public basic_openid_message { 139 class signed_part_message_proxy : public basic_openid_message {
139 public: 140 public:
140 const basic_openid_message& x; 141 const basic_openid_message& x;
141 set<string> signeds; 142 set<string> signeds;
142 143
143 signed_part_message_proxy(const basic_openid_message& xx) : x(xx) { 144 signed_part_message_proxy(const basic_openid_message& xx) : x(xx) {
144 const string& slist = x.get_field("signed"); 145 const string& slist = x.get_field("signed");
145 string::size_type p = 0; 146 string::size_type p = 0;
146 while(true) { 147 while(true) {
147 string::size_type co = slist.find(',',p); 148 string::size_type co = slist.find(',',p);
148 string f = (co==string::npos) 149 string f = (co==string::npos)
149 ?slist.substr(p):slist.substr(p,co-p); 150 ?slist.substr(p):slist.substr(p,co-p);
150 signeds.insert(f); 151 signeds.insert(f);
151 if(co==string::npos) break; 152 if(co==string::npos) break;
152 p = co+1; 153 p = co+1;
153 } 154 }
154 } 155 }
155 156
156 bool has_field(const string& n) const { 157 bool has_field(const string& n) const {
157 return signeds.find(n)!=signeds.end() && x.has_field(n); } 158 return signeds.find(n)!=signeds.end() && x.has_field(n); }
158 const string& get_field(const string& n) const { 159 const string& get_field(const string& n) const {
159 if(signeds.find(n)==signeds.end()) 160 if(signeds.find(n)==signeds.end())
160 throw failed_lookup(OPKELE_CP_ "The field isn't known to be signed"); 161 throw failed_lookup(OPKELE_CP_ "The field isn't known to be signed");
161 return x.get_field(n); } 162 return x.get_field(n); }
162 163
163 fields_iterator fields_begin() const { 164 fields_iterator fields_begin() const {
164 return signeds.begin(); } 165 return signeds.begin(); }
165 fields_iterator fields_end() const { 166 fields_iterator fields_end() const {
166 return signeds.end(); } 167 return signeds.end(); }
167 }; 168 };
168 169
169 static void parse_query(const string& u,string::size_type q, 170 static void parse_query(const string& u,string::size_type q,
170 map<string,string>& p) { 171 map<string,string>& p) {
171 if(q==string::npos) 172 if(q==string::npos)
172 return; 173 return;
173 assert(u[q]=='?'); 174 assert(u[q]=='?');
174 ++q; 175 ++q;
175 string::size_type l = u.size(); 176 string::size_type l = u.size();
176 while(q<l) { 177 while(q<l) {
177 string::size_type eq = u.find('=',q); 178 string::size_type eq = u.find('=',q);
178 string::size_type am = u.find('&',q); 179 string::size_type am = u.find('&',q);
179 if(am==string::npos) { 180 if(am==string::npos) {
180 if(eq==string::npos) { 181 if(eq==string::npos) {
181 p[""] = u.substr(q); 182 p[""] = u.substr(q);
182 }else{ 183 }else{
183 p[u.substr(q,eq-q)] = u.substr(eq+1); 184 p[u.substr(q,eq-q)] = u.substr(eq+1);
184 } 185 }
185 break; 186 break;
186 }else{ 187 }else{
187 if(eq==string::npos || eq>am) { 188 if(eq==string::npos || eq>am) {
188 p[""] = u.substr(q,eq-q); 189 p[""] = u.substr(q,eq-q);
189 }else{ 190 }else{
190 p[u.substr(q,eq-q)] = u.substr(eq+1,am-eq-1); 191 p[u.substr(q,eq-q)] = u.substr(eq+1,am-eq-1);
191 } 192 }
192 q = ++am; 193 q = ++am;
193 } 194 }
194 } 195 }
195 } 196 }
196 197
197 void basic_RP::id_res(const basic_openid_message& om,extension_t *ext) { 198 void basic_RP::id_res(const basic_openid_message& om,extension_t *ext) {
198 bool o2 = om.has_field("ns") 199 bool o2 = om.has_field("ns")
199 && om.get_field("ns")==OIURI_OPENID20; 200 && om.get_field("ns")==OIURI_OPENID20;
200 if( (!o2) && om.has_field("user_setup_url")) 201 if( (!o2) && om.has_field("user_setup_url"))
201 throw id_res_setup(OPKELE_CP_ "assertion failed, setup url provided", 202 throw id_res_setup(OPKELE_CP_ "assertion failed, setup url provided",
202 om.get_field("user_setup_url")); 203 om.get_field("user_setup_url"));
203 string m = om.get_field("mode"); 204 string m = om.get_field("mode");
204 if(o2 && m=="setup_needed") 205 if(o2 && m=="setup_needed")
205 throw id_res_setup(OPKELE_CP_ "setup needed, no setup url provided"); 206 throw id_res_setup(OPKELE_CP_ "setup needed, no setup url provided");
206 if(m=="cancel") 207 if(m=="cancel")
207 throw id_res_cancel(OPKELE_CP_ "authentication cancelled"); 208 throw id_res_cancel(OPKELE_CP_ "authentication cancelled");
208 bool go_dumb=false; 209 bool go_dumb=false;
209 try { 210 try {
210 string OP = o2 211 string OP = o2
211 ?om.get_field("op_endpoint") 212 ?om.get_field("op_endpoint")
212 :get_endpoint().uri; 213 :get_endpoint().uri;
213 assoc_t assoc = retrieve_assoc( 214 assoc_t assoc = retrieve_assoc(
214 OP,om.get_field("assoc_handle")); 215 OP,om.get_field("assoc_handle"));
215 if(om.get_field("sig")!=util::base64_signature(assoc,om)) 216 if(om.get_field("sig")!=util::base64_signature(assoc,om))
216 throw id_res_mismatch(OPKELE_CP_ "signature mismatch"); 217 throw id_res_mismatch(OPKELE_CP_ "signature mismatch");
217 }catch(dumb_RP& drp) { 218 }catch(dumb_RP& drp) {
218 go_dumb=true; 219 go_dumb=true;
219 }catch(failed_lookup& e) { 220 }catch(failed_lookup& e) {
220 go_dumb=true; 221 go_dumb=true;
221 } OPKELE_RETHROW 222 } OPKELE_RETHROW
222 if(go_dumb) { 223 if(go_dumb) {
223 try { 224 try {
224 string OP = o2 225 string OP = o2
225 ?om.get_field("op_endpoint") 226 ?om.get_field("op_endpoint")
226 :get_endpoint().uri; 227 :get_endpoint().uri;
227 check_authentication(OP,om); 228 check_authentication(OP,om);
228 }catch(failed_check_authentication& fca) { 229 }catch(failed_check_authentication& fca) {
229 throw id_res_failed(OPKELE_CP_ "failed to check_authentication()"); 230 throw id_res_failed(OPKELE_CP_ "failed to check_authentication()");
230 } OPKELE_RETHROW 231 } OPKELE_RETHROW
231 } 232 }
232 signed_part_message_proxy signeds(om); 233 signed_part_message_proxy signeds(om);
233 if(o2) { 234 if(o2) {
234 check_nonce(om.get_field("op_endpoint"), 235 check_nonce(om.get_field("op_endpoint"),
235 om.get_field("response_nonce")); 236 om.get_field("response_nonce"));
236 static const char *mustsign[] = { 237 static const char *mustsign[] = {
237 "op_endpoint", "return_to", "response_nonce", "assoc_handle", 238 "op_endpoint", "return_to", "response_nonce", "assoc_handle",
238 "claimed_id", "identity" }; 239 "claimed_id", "identity" };
239 for(size_t ms=0;ms<(sizeof(mustsign)/sizeof(*mustsign));++ms) { 240 for(size_t ms=0;ms<(sizeof(mustsign)/sizeof(*mustsign));++ms) {
240 if(om.has_field(mustsign[ms]) && !signeds.has_field(mustsign[ms])) 241 if(om.has_field(mustsign[ms]) && !signeds.has_field(mustsign[ms]))
241 throw bad_input(OPKELE_CP_ string("Field '")+mustsign[ms]+"' is not signed against the specs"); 242 throw bad_input(OPKELE_CP_ string("Field '")+mustsign[ms]+"' is not signed against the specs");
242 } 243 }
243 if( ( 244 if( (
244 (om.has_field("claimed_id")?1:0) 245 (om.has_field("claimed_id")?1:0)
245 ^ 246 ^
246 (om.has_field("identity")?1:0) 247 (om.has_field("identity")?1:0)
247 )&1 ) 248 )&1 )
248 throw bad_input(OPKELE_CP_ "claimed_id and identity must be either both present or both absent"); 249 throw bad_input(OPKELE_CP_ "claimed_id and identity must be either both present or both absent");
249 250
250 string turl = util::rfc_3986_normalize_uri(get_this_url()); 251 string turl = util::rfc_3986_normalize_uri(get_this_url());
251 util::strip_uri_fragment_part(turl); 252 util::strip_uri_fragment_part(turl);
252 string rurl = util::rfc_3986_normalize_uri(om.get_field("return_to")); 253 string rurl = util::rfc_3986_normalize_uri(om.get_field("return_to"));
253 util::strip_uri_fragment_part(rurl); 254 util::strip_uri_fragment_part(rurl);
254 string::size_type 255 string::size_type
255 tq = turl.find('?'), rq = rurl.find('?'); 256 tq = turl.find('?'), rq = rurl.find('?');
256 if( 257 if(
257 ((tq==string::npos)?turl:turl.substr(0,tq)) 258 ((tq==string::npos)?turl:turl.substr(0,tq))
258 != 259 !=
259 ((rq==string::npos)?rurl:rurl.substr(0,rq)) 260 ((rq==string::npos)?rurl:rurl.substr(0,rq))
260 ) 261 )
261 throw id_res_bad_return_to(OPKELE_CP_ "return_to url doesn't match request url"); 262 throw id_res_bad_return_to(OPKELE_CP_ "return_to url doesn't match request url");
262 map<string,string> tp; parse_query(turl,tq,tp); 263 map<string,string> tp; parse_query(turl,tq,tp);
263 map<string,string> rp; parse_query(rurl,rq,rp); 264 map<string,string> rp; parse_query(rurl,rq,rp);
264 for(map<string,string>::const_iterator rpi=rp.begin();rpi!=rp.end();++rpi) { 265 for(map<string,string>::const_iterator rpi=rp.begin();rpi!=rp.end();++rpi) {
diff --git a/lib/consumer.cc b/lib/consumer.cc
index ebda262..801496e 100644
--- a/lib/consumer.cc
+++ b/lib/consumer.cc
@@ -1,260 +1,261 @@
1#include <algorithm> 1#include <algorithm>
2#include <cassert> 2#include <cassert>
3#include <cstring> 3#include <cstring>
4#include <opkele/util.h> 4#include <opkele/util.h>
5#include <opkele/util-internal.h>
5#include <opkele/curl.h> 6#include <opkele/curl.h>
6#include <opkele/exception.h> 7#include <opkele/exception.h>
7#include <opkele/data.h> 8#include <opkele/data.h>
8#include <opkele/consumer.h> 9#include <opkele/consumer.h>
9#include <openssl/sha.h> 10#include <openssl/sha.h>
10#include <openssl/hmac.h> 11#include <openssl/hmac.h>
11#include <iostream> 12#include <iostream>
12 13
13#include "config.h" 14#include "config.h"
14 15
15#include <pcre.h> 16#include <pcre.h>
16 17
17namespace opkele { 18namespace opkele {
18 using namespace std; 19 using namespace std;
19 using util::curl_t; 20 using util::curl_t;
20 using util::curl_pick_t; 21 using util::curl_pick_t;
21 22
22 class pcre_matches_t { 23 class pcre_matches_t {
23 public: 24 public:
24 int *_ov; 25 int *_ov;
25 int _s; 26 int _s;
26 27
27 pcre_matches_t() : _ov(0), _s(0) { } 28 pcre_matches_t() : _ov(0), _s(0) { }
28 pcre_matches_t(int s) : _ov(0), _s(s) { 29 pcre_matches_t(int s) : _ov(0), _s(s) {
29 if(_s&1) ++_s; 30 if(_s&1) ++_s;
30 _s += _s>>1; 31 _s += _s>>1;
31 _ov = new int[_s]; 32 _ov = new int[_s];
32 } 33 }
33 ~pcre_matches_t() throw() { if(_ov) delete[] _ov; } 34 ~pcre_matches_t() throw() { if(_ov) delete[] _ov; }
34 35
35 int begin(int i) const { return _ov[i<<1]; } 36 int begin(int i) const { return _ov[i<<1]; }
36 int end(int i) const { return _ov[(i<<1)+1]; } 37 int end(int i) const { return _ov[(i<<1)+1]; }
37 int length(int i) const { int t=i<<1; return _ov[t+1]-_ov[t]; } 38 int length(int i) const { int t=i<<1; return _ov[t+1]-_ov[t]; }
38 }; 39 };
39 40
40 class pcre_t { 41 class pcre_t {
41 public: 42 public:
42 pcre *_p; 43 pcre *_p;
43 44
44 pcre_t() : _p(0) { } 45 pcre_t() : _p(0) { }
45 pcre_t(pcre *p) : _p(p) { } 46 pcre_t(pcre *p) : _p(p) { }
46 pcre_t(const char *re,int opts) : _p(0) { 47 pcre_t(const char *re,int opts) : _p(0) {
47 static const char *errptr; static int erroffset; 48 static const char *errptr; static int erroffset;
48 _p = pcre_compile(re,opts,&errptr,&erroffset,NULL); 49 _p = pcre_compile(re,opts,&errptr,&erroffset,NULL);
49 if(!_p) 50 if(!_p)
50 throw internal_error(OPKELE_CP_ string("Failed to compile regexp: ")+errptr); 51 throw internal_error(OPKELE_CP_ string("Failed to compile regexp: ")+errptr);
51 } 52 }
52 ~pcre_t() throw() { if(_p) (*pcre_free)(_p); } 53 ~pcre_t() throw() { if(_p) (*pcre_free)(_p); }
53 54
54 pcre_t& operator=(pcre *p) { if(_p) (*pcre_free)(_p); _p=p; return *this; } 55 pcre_t& operator=(pcre *p) { if(_p) (*pcre_free)(_p); _p=p; return *this; }
55 56
56 operator const pcre*(void) const { return _p; } 57 operator const pcre*(void) const { return _p; }
57 operator pcre*(void) { return _p; } 58 operator pcre*(void) { return _p; }
58 59
59 int exec(const string& s,pcre_matches_t& m) { 60 int exec(const string& s,pcre_matches_t& m) {
60 if(!_p) 61 if(!_p)
61 throw internal_error(OPKELE_CP_ "Trying to execute absent regexp"); 62 throw internal_error(OPKELE_CP_ "Trying to execute absent regexp");
62 return pcre_exec(_p,NULL,s.c_str(),s.length(),0,0,m._ov,m._s); 63 return pcre_exec(_p,NULL,s.c_str(),s.length(),0,0,m._ov,m._s);
63 } 64 }
64 }; 65 };
65 66
66 assoc_t consumer_t::associate(const string& server) { 67 assoc_t consumer_t::associate(const string& server) {
67 util::dh_t dh = DH_new(); 68 util::dh_t dh = DH_new();
68 if(!dh) 69 if(!dh)
69 throw exception_openssl(OPKELE_CP_ "failed to DH_new()"); 70 throw exception_openssl(OPKELE_CP_ "failed to DH_new()");
70 dh->p = util::dec_to_bignum(data::_default_p); 71 dh->p = util::dec_to_bignum(data::_default_p);
71 dh->g = util::dec_to_bignum(data::_default_g); 72 dh->g = util::dec_to_bignum(data::_default_g);
72 if(!DH_generate_key(dh)) 73 if(!DH_generate_key(dh))
73 throw exception_openssl(OPKELE_CP_ "failed to DH_generate_key()"); 74 throw exception_openssl(OPKELE_CP_ "failed to DH_generate_key()");
74 string request = 75 string request =
75 "openid.mode=associate" 76 "openid.mode=associate"
76 "&openid.assoc_type=HMAC-SHA1" 77 "&openid.assoc_type=HMAC-SHA1"
77 "&openid.session_type=DH-SHA1" 78 "&openid.session_type=DH-SHA1"
78 "&openid.dh_consumer_public="; 79 "&openid.dh_consumer_public=";
79 request += util::url_encode(util::bignum_to_base64(dh->pub_key)); 80 request += util::url_encode(util::bignum_to_base64(dh->pub_key));
80 curl_pick_t curl = curl_pick_t::easy_init(); 81 curl_pick_t curl = curl_pick_t::easy_init();
81 if(!curl) 82 if(!curl)
82 throw exception_curl(OPKELE_CP_ "failed to initialize curl"); 83 throw exception_curl(OPKELE_CP_ "failed to initialize curl");
83 CURLcode r; 84 CURLcode r;
84 (r=curl.misc_sets()) 85 (r=curl.misc_sets())
85 || (r=curl.easy_setopt(CURLOPT_URL,server.c_str())) 86 || (r=curl.easy_setopt(CURLOPT_URL,server.c_str()))
86 || (r=curl.easy_setopt(CURLOPT_POST,1)) 87 || (r=curl.easy_setopt(CURLOPT_POST,1))
87 || (r=curl.easy_setopt(CURLOPT_POSTFIELDS,request.data())) 88 || (r=curl.easy_setopt(CURLOPT_POSTFIELDS,request.data()))
88 || (r=curl.easy_setopt(CURLOPT_POSTFIELDSIZE,request.length())) 89 || (r=curl.easy_setopt(CURLOPT_POSTFIELDSIZE,request.length()))
89 || (r=curl.set_write()) 90 || (r=curl.set_write())
90 ; 91 ;
91 if(r) 92 if(r)
92 throw exception_curl(OPKELE_CP_ "failed to set curly options",r); 93 throw exception_curl(OPKELE_CP_ "failed to set curly options",r);
93 if( (r=curl.easy_perform()) ) 94 if( (r=curl.easy_perform()) )
94 throw exception_curl(OPKELE_CP_ "failed to perform curly request",r); 95 throw exception_curl(OPKELE_CP_ "failed to perform curly request",r);
95 params_t p; p.parse_keyvalues(curl.response); 96 params_t p; p.parse_keyvalues(curl.response);
96 if(p.has_param("assoc_type") && p.get_param("assoc_type")!="HMAC-SHA1") 97 if(p.has_param("assoc_type") && p.get_param("assoc_type")!="HMAC-SHA1")
97 throw bad_input(OPKELE_CP_ "unsupported assoc_type"); 98 throw bad_input(OPKELE_CP_ "unsupported assoc_type");
98 string st; 99 string st;
99 if(p.has_param("session_type")) st = p.get_param("session_type"); 100 if(p.has_param("session_type")) st = p.get_param("session_type");
100 if((!st.empty()) && st!="DH-SHA1") 101 if((!st.empty()) && st!="DH-SHA1")
101 throw bad_input(OPKELE_CP_ "unsupported session_type"); 102 throw bad_input(OPKELE_CP_ "unsupported session_type");
102 secret_t secret; 103 secret_t secret;
103 if(st.empty()) { 104 if(st.empty()) {
104 secret.from_base64(p.get_param("mac_key")); 105 secret.from_base64(p.get_param("mac_key"));
105 }else{ 106 }else{
106 util::bignum_t s_pub = util::base64_to_bignum(p.get_param("dh_server_public")); 107 util::bignum_t s_pub = util::base64_to_bignum(p.get_param("dh_server_public"));
107 vector<unsigned char> ck(DH_size(dh)+1); 108 vector<unsigned char> ck(DH_size(dh)+1);
108 unsigned char *ckptr = &(ck.front())+1; 109 unsigned char *ckptr = &(ck.front())+1;
109 int cklen = DH_compute_key(ckptr,s_pub,dh); 110 int cklen = DH_compute_key(ckptr,s_pub,dh);
110 if(cklen<0) 111 if(cklen<0)
111 throw exception_openssl(OPKELE_CP_ "failed to DH_compute_key()"); 112 throw exception_openssl(OPKELE_CP_ "failed to DH_compute_key()");
112 if(cklen && (*ckptr)&0x80) { 113 if(cklen && (*ckptr)&0x80) {
113 (*(--ckptr)) = 0; ++cklen; 114 (*(--ckptr)) = 0; ++cklen;
114 } 115 }
115 unsigned char key_sha1[SHA_DIGEST_LENGTH]; 116 unsigned char key_sha1[SHA_DIGEST_LENGTH];
116 SHA1(ckptr,cklen,key_sha1); 117 SHA1(ckptr,cklen,key_sha1);
117 secret.enxor_from_base64(key_sha1,p.get_param("enc_mac_key")); 118 secret.enxor_from_base64(key_sha1,p.get_param("enc_mac_key"));
118 } 119 }
119 int expires_in = 0; 120 int expires_in = 0;
120 if(p.has_param("expires_in")) { 121 if(p.has_param("expires_in")) {
121 expires_in = util::string_to_long(p.get_param("expires_in")); 122 expires_in = util::string_to_long(p.get_param("expires_in"));
122 }else if(p.has_param("issued") && p.has_param("expiry")) { 123 }else if(p.has_param("issued") && p.has_param("expiry")) {
123 expires_in = util::w3c_to_time(p.get_param("expiry"))-util::w3c_to_time(p.get_param("issued")); 124 expires_in = util::w3c_to_time(p.get_param("expiry"))-util::w3c_to_time(p.get_param("issued"));
124 }else 125 }else
125 throw bad_input(OPKELE_CP_ "no expiration information"); 126 throw bad_input(OPKELE_CP_ "no expiration information");
126 return store_assoc(server,p.get_param("assoc_handle"),secret,expires_in); 127 return store_assoc(server,p.get_param("assoc_handle"),secret,expires_in);
127 } 128 }
128 129
129 string consumer_t::checkid_immediate(const string& identity,const string& return_to,const string& trust_root,extension_t *ext) { 130 string consumer_t::checkid_immediate(const string& identity,const string& return_to,const string& trust_root,extension_t *ext) {
130 return checkid_(mode_checkid_immediate,identity,return_to,trust_root,ext); 131 return checkid_(mode_checkid_immediate,identity,return_to,trust_root,ext);
131 } 132 }
132 string consumer_t::checkid_setup(const string& identity,const string& return_to,const string& trust_root,extension_t *ext) { 133 string consumer_t::checkid_setup(const string& identity,const string& return_to,const string& trust_root,extension_t *ext) {
133 return checkid_(mode_checkid_setup,identity,return_to,trust_root,ext); 134 return checkid_(mode_checkid_setup,identity,return_to,trust_root,ext);
134 } 135 }
135 string consumer_t::checkid_(mode_t mode,const string& identity,const string& return_to,const string& trust_root,extension_t *ext) { 136 string consumer_t::checkid_(mode_t mode,const string& identity,const string& return_to,const string& trust_root,extension_t *ext) {
136 params_t p; 137 params_t p;
137 if(mode==mode_checkid_immediate) 138 if(mode==mode_checkid_immediate)
138 p["mode"]="checkid_immediate"; 139 p["mode"]="checkid_immediate";
139 else if(mode==mode_checkid_setup) 140 else if(mode==mode_checkid_setup)
140 p["mode"]="checkid_setup"; 141 p["mode"]="checkid_setup";
141 else 142 else
142 throw bad_input(OPKELE_CP_ "unknown checkid_* mode"); 143 throw bad_input(OPKELE_CP_ "unknown checkid_* mode");
143 string iurl = canonicalize(identity); 144 string iurl = canonicalize(identity);
144 string server, delegate; 145 string server, delegate;
145 retrieve_links(iurl,server,delegate); 146 retrieve_links(iurl,server,delegate);
146 p["identity"] = delegate.empty()?iurl:delegate; 147 p["identity"] = delegate.empty()?iurl:delegate;
147 if(!trust_root.empty()) 148 if(!trust_root.empty())
148 p["trust_root"] = trust_root; 149 p["trust_root"] = trust_root;
149 p["return_to"] = return_to; 150 p["return_to"] = return_to;
150 try { 151 try {
151 string ah = find_assoc(server)->handle(); 152 string ah = find_assoc(server)->handle();
152 p["assoc_handle"] = ah; 153 p["assoc_handle"] = ah;
153 }catch(failed_lookup& fl) { 154 }catch(failed_lookup& fl) {
154 string ah = associate(server)->handle(); 155 string ah = associate(server)->handle();
155 p["assoc_handle"] = ah; 156 p["assoc_handle"] = ah;
156 } 157 }
157 if(ext) ext->checkid_hook(p); 158 if(ext) ext->checkid_hook(p);
158 return p.append_query(server); 159 return p.append_query(server);
159 } 160 }
160 161
161 void consumer_t::id_res(const params_t& pin,const string& identity,extension_t *ext) { 162 void consumer_t::id_res(const params_t& pin,const string& identity,extension_t *ext) {
162 if(pin.has_param("openid.user_setup_url")) 163 if(pin.has_param("openid.user_setup_url"))
163 throw id_res_setup(OPKELE_CP_ "assertion failed, setup url provided",pin.get_param("openid.user_setup_url")); 164 throw id_res_setup(OPKELE_CP_ "assertion failed, setup url provided",pin.get_param("openid.user_setup_url"));
164 string server,delegate; 165 string server,delegate;
165 retrieve_links(identity.empty()?pin.get_param("openid.identity"):canonicalize(identity),server,delegate); 166 retrieve_links(identity.empty()?pin.get_param("openid.identity"):canonicalize(identity),server,delegate);
166 params_t ps; 167 params_t ps;
167 try { 168 try {
168 assoc_t assoc = retrieve_assoc(server,pin.get_param("openid.assoc_handle")); 169 assoc_t assoc = retrieve_assoc(server,pin.get_param("openid.assoc_handle"));
169 if(assoc->is_expired()) 170 if(assoc->is_expired())
170 throw id_res_expired_on_delivery(OPKELE_CP_ "retrieve_assoc() has returned expired handle"); 171 throw id_res_expired_on_delivery(OPKELE_CP_ "retrieve_assoc() has returned expired handle");
171 const string& sigenc = pin.get_param("openid.sig"); 172 const string& sigenc = pin.get_param("openid.sig");
172 vector<unsigned char> sig; 173 vector<unsigned char> sig;
173 util::decode_base64(sigenc,sig); 174 util::decode_base64(sigenc,sig);
174 const string& slist = pin.get_param("openid.signed"); 175 const string& slist = pin.get_param("openid.signed");
175 string kv; 176 string kv;
176 string::size_type p = 0; 177 string::size_type p = 0;
177 while(true) { 178 while(true) {
178 string::size_type co = slist.find(',',p); 179 string::size_type co = slist.find(',',p);
179 string f = (co==string::npos)?slist.substr(p):slist.substr(p,co-p); 180 string f = (co==string::npos)?slist.substr(p):slist.substr(p,co-p);
180 kv += f; 181 kv += f;
181 kv += ':'; 182 kv += ':';
182 f.insert(0,"openid."); 183 f.insert(0,"openid.");
183 kv += pin.get_param(f); 184 kv += pin.get_param(f);
184 kv += '\n'; 185 kv += '\n';
185 if(ext) ps[f.substr(sizeof("openid.")-1)] = pin.get_param(f); 186 if(ext) ps[f.substr(sizeof("openid.")-1)] = pin.get_param(f);
186 if(co==string::npos) 187 if(co==string::npos)
187 break; 188 break;
188 p = co+1; 189 p = co+1;
189 } 190 }
190 secret_t secret = assoc->secret(); 191 secret_t secret = assoc->secret();
191 unsigned int md_len = 0; 192 unsigned int md_len = 0;
192 unsigned char *md = HMAC( 193 unsigned char *md = HMAC(
193 EVP_sha1(), 194 EVP_sha1(),
194 &(secret.front()),secret.size(), 195 &(secret.front()),secret.size(),
195 (const unsigned char *)kv.data(),kv.length(), 196 (const unsigned char *)kv.data(),kv.length(),
196 0,&md_len); 197 0,&md_len);
197 if(sig.size()!=md_len || memcmp(&(sig.front()),md,md_len)) 198 if(sig.size()!=md_len || memcmp(&(sig.front()),md,md_len))
198 throw id_res_mismatch(OPKELE_CP_ "signature mismatch"); 199 throw id_res_mismatch(OPKELE_CP_ "signature mismatch");
199 }catch(failed_lookup& e) { 200 }catch(failed_lookup& e) {
200 const string& slist = pin.get_param("openid.signed"); 201 const string& slist = pin.get_param("openid.signed");
201 string::size_type pp = 0; 202 string::size_type pp = 0;
202 params_t p; 203 params_t p;
203 while(true) { 204 while(true) {
204 string::size_type co = slist.find(',',pp); 205 string::size_type co = slist.find(',',pp);
205 string f = "openid."; 206 string f = "openid.";
206 f += (co==string::npos)?slist.substr(pp):slist.substr(pp,co-pp); 207 f += (co==string::npos)?slist.substr(pp):slist.substr(pp,co-pp);
207 p[f] = pin.get_param(f); 208 p[f] = pin.get_param(f);
208 if(co==string::npos) 209 if(co==string::npos)
209 break; 210 break;
210 pp = co+1; 211 pp = co+1;
211 } 212 }
212 p["openid.assoc_handle"] = pin.get_param("openid.assoc_handle"); 213 p["openid.assoc_handle"] = pin.get_param("openid.assoc_handle");
213 p["openid.sig"] = pin.get_param("openid.sig"); 214 p["openid.sig"] = pin.get_param("openid.sig");
214 p["openid.signed"] = pin.get_param("openid.signed"); 215 p["openid.signed"] = pin.get_param("openid.signed");
215 try { 216 try {
216 string ih = pin.get_param("openid.invalidate_handle"); 217 string ih = pin.get_param("openid.invalidate_handle");
217 p["openid.invalidate_handle"] = ih; 218 p["openid.invalidate_handle"] = ih;
218 }catch(failed_lookup& fl) { } 219 }catch(failed_lookup& fl) { }
219 try { 220 try {
220 check_authentication(server,p); 221 check_authentication(server,p);
221 }catch(failed_check_authentication& fca) { 222 }catch(failed_check_authentication& fca) {
222 throw id_res_failed(OPKELE_CP_ "failed to check_authentication()"); 223 throw id_res_failed(OPKELE_CP_ "failed to check_authentication()");
223 } 224 }
224 } 225 }
225 if(ext) ext->id_res_hook(pin,ps); 226 if(ext) ext->id_res_hook(pin,ps);
226 } 227 }
227 228
228 void consumer_t::check_authentication(const string& server,const params_t& p) { 229 void consumer_t::check_authentication(const string& server,const params_t& p) {
229 string request = "openid.mode=check_authentication"; 230 string request = "openid.mode=check_authentication";
230 for(params_t::const_iterator i=p.begin();i!=p.end();++i) { 231 for(params_t::const_iterator i=p.begin();i!=p.end();++i) {
231 if(i->first!="openid.mode") { 232 if(i->first!="openid.mode") {
232 request += '&'; 233 request += '&';
233 request += i->first; 234 request += i->first;
234 request += '='; 235 request += '=';
235 request += util::url_encode(i->second); 236 request += util::url_encode(i->second);
236 } 237 }
237 } 238 }
238 curl_pick_t curl = curl_pick_t::easy_init(); 239 curl_pick_t curl = curl_pick_t::easy_init();
239 if(!curl) 240 if(!curl)
240 throw exception_curl(OPKELE_CP_ "failed to initialize curl"); 241 throw exception_curl(OPKELE_CP_ "failed to initialize curl");
241 CURLcode r; 242 CURLcode r;
242 (r=curl.misc_sets()) 243 (r=curl.misc_sets())
243 || (r=curl.easy_setopt(CURLOPT_URL,server.c_str())) 244 || (r=curl.easy_setopt(CURLOPT_URL,server.c_str()))
244 || (r=curl.easy_setopt(CURLOPT_POST,1)) 245 || (r=curl.easy_setopt(CURLOPT_POST,1))
245 || (r=curl.easy_setopt(CURLOPT_POSTFIELDS,request.data())) 246 || (r=curl.easy_setopt(CURLOPT_POSTFIELDS,request.data()))
246 || (r=curl.easy_setopt(CURLOPT_POSTFIELDSIZE,request.length())) 247 || (r=curl.easy_setopt(CURLOPT_POSTFIELDSIZE,request.length()))
247 || (r=curl.set_write()) 248 || (r=curl.set_write())
248 ; 249 ;
249 if(r) 250 if(r)
250 throw exception_curl(OPKELE_CP_ "failed to set curly options",r); 251 throw exception_curl(OPKELE_CP_ "failed to set curly options",r);
251 if( (r=curl.easy_perform()) ) 252 if( (r=curl.easy_perform()) )
252 throw exception_curl(OPKELE_CP_ "failed to perform curly request",r); 253 throw exception_curl(OPKELE_CP_ "failed to perform curly request",r);
253 params_t pp; pp.parse_keyvalues(curl.response); 254 params_t pp; pp.parse_keyvalues(curl.response);
254 if(pp.has_param("invalidate_handle")) 255 if(pp.has_param("invalidate_handle"))
255 invalidate_assoc(server,pp.get_param("invalidate_handle")); 256 invalidate_assoc(server,pp.get_param("invalidate_handle"));
256 if(pp.has_param("is_valid")) { 257 if(pp.has_param("is_valid")) {
257 if(pp.get_param("is_valid")=="true") 258 if(pp.get_param("is_valid")=="true")
258 return; 259 return;
259 }else if(pp.has_param("lifetime")) { 260 }else if(pp.has_param("lifetime")) {
260 if(util::string_to_long(pp.get_param("lifetime"))) 261 if(util::string_to_long(pp.get_param("lifetime")))
diff --git a/lib/server.cc b/lib/server.cc
index 776f1ae..0dea1eb 100644
--- a/lib/server.cc
+++ b/lib/server.cc
@@ -1,171 +1,172 @@
1#include <cstring> 1#include <cstring>
2#include <vector> 2#include <vector>
3#include <openssl/sha.h> 3#include <openssl/sha.h>
4#include <openssl/hmac.h> 4#include <openssl/hmac.h>
5#include <opkele/util.h> 5#include <opkele/util.h>
6#include <opkele/util-internal.h>
6#include <opkele/exception.h> 7#include <opkele/exception.h>
7#include <opkele/server.h> 8#include <opkele/server.h>
8#include <opkele/data.h> 9#include <opkele/data.h>
9 10
10namespace opkele { 11namespace opkele {
11 using namespace std; 12 using namespace std;
12 13
13 void server_t::associate(const params_t& pin,params_t& pout) { 14 void server_t::associate(const params_t& pin,params_t& pout) {
14 util::dh_t dh; 15 util::dh_t dh;
15 util::bignum_t c_pub; 16 util::bignum_t c_pub;
16 unsigned char key_sha1[SHA_DIGEST_LENGTH]; 17 unsigned char key_sha1[SHA_DIGEST_LENGTH];
17 enum { 18 enum {
18 sess_cleartext, 19 sess_cleartext,
19 sess_dh_sha1 20 sess_dh_sha1
20 } st = sess_cleartext; 21 } st = sess_cleartext;
21 if( 22 if(
22 pin.has_param("openid.session_type") 23 pin.has_param("openid.session_type")
23 && pin.get_param("openid.session_type")=="DH-SHA1" ) { 24 && pin.get_param("openid.session_type")=="DH-SHA1" ) {
24 /* TODO: fallback to cleartext in case of exceptions here? */ 25 /* TODO: fallback to cleartext in case of exceptions here? */
25 if(!(dh = DH_new())) 26 if(!(dh = DH_new()))
26 throw exception_openssl(OPKELE_CP_ "failed to DH_new()"); 27 throw exception_openssl(OPKELE_CP_ "failed to DH_new()");
27 c_pub = util::base64_to_bignum(pin.get_param("openid.dh_consumer_public")); 28 c_pub = util::base64_to_bignum(pin.get_param("openid.dh_consumer_public"));
28 if(pin.has_param("openid.dh_modulus")) 29 if(pin.has_param("openid.dh_modulus"))
29 dh->p = util::base64_to_bignum(pin.get_param("openid.dh_modulus")); 30 dh->p = util::base64_to_bignum(pin.get_param("openid.dh_modulus"));
30 else 31 else
31 dh->p = util::dec_to_bignum(data::_default_p); 32 dh->p = util::dec_to_bignum(data::_default_p);
32 if(pin.has_param("openid.dh_gen")) 33 if(pin.has_param("openid.dh_gen"))
33 dh->g = util::base64_to_bignum(pin.get_param("openid.dh_gen")); 34 dh->g = util::base64_to_bignum(pin.get_param("openid.dh_gen"));
34 else 35 else
35 dh->g = util::dec_to_bignum(data::_default_g); 36 dh->g = util::dec_to_bignum(data::_default_g);
36 if(!DH_generate_key(dh)) 37 if(!DH_generate_key(dh))
37 throw exception_openssl(OPKELE_CP_ "failed to DH_generate_key()"); 38 throw exception_openssl(OPKELE_CP_ "failed to DH_generate_key()");
38 vector<unsigned char> ck(DH_size(dh)+1); 39 vector<unsigned char> ck(DH_size(dh)+1);
39 unsigned char *ckptr = &(ck.front())+1; 40 unsigned char *ckptr = &(ck.front())+1;
40 int cklen = DH_compute_key(ckptr,c_pub,dh); 41 int cklen = DH_compute_key(ckptr,c_pub,dh);
41 if(cklen<0) 42 if(cklen<0)
42 throw exception_openssl(OPKELE_CP_ "failed to DH_compute_key()"); 43 throw exception_openssl(OPKELE_CP_ "failed to DH_compute_key()");
43 if(cklen && (*ckptr)&0x80) { 44 if(cklen && (*ckptr)&0x80) {
44 (*(--ckptr)) = 0; ++cklen; 45 (*(--ckptr)) = 0; ++cklen;
45 } 46 }
46 SHA1(ckptr,cklen,key_sha1); 47 SHA1(ckptr,cklen,key_sha1);
47 st = sess_dh_sha1; 48 st = sess_dh_sha1;
48 } 49 }
49 assoc_t assoc = alloc_assoc(mode_associate); 50 assoc_t assoc = alloc_assoc(mode_associate);
50 time_t now = time(0); 51 time_t now = time(0);
51 pout.clear(); 52 pout.clear();
52 pout["assoc_type"] = assoc->assoc_type(); 53 pout["assoc_type"] = assoc->assoc_type();
53 pout["assoc_handle"] = assoc->handle(); 54 pout["assoc_handle"] = assoc->handle();
54 /* TODO: eventually remove deprecated stuff */ 55 /* TODO: eventually remove deprecated stuff */
55 pout["issued"] = util::time_to_w3c(now); 56 pout["issued"] = util::time_to_w3c(now);
56 pout["expiry"] = util::time_to_w3c(now+assoc->expires_in()); 57 pout["expiry"] = util::time_to_w3c(now+assoc->expires_in());
57 pout["expires_in"] = util::long_to_string(assoc->expires_in()); 58 pout["expires_in"] = util::long_to_string(assoc->expires_in());
58 secret_t secret = assoc->secret(); 59 secret_t secret = assoc->secret();
59 switch(st) { 60 switch(st) {
60 case sess_dh_sha1: 61 case sess_dh_sha1:
61 pout["session_type"] = "DH-SHA1"; 62 pout["session_type"] = "DH-SHA1";
62 pout["dh_server_public"] = util::bignum_to_base64(dh->pub_key); 63 pout["dh_server_public"] = util::bignum_to_base64(dh->pub_key);
63 secret.enxor_to_base64(key_sha1,pout["enc_mac_key"]); 64 secret.enxor_to_base64(key_sha1,pout["enc_mac_key"]);
64 break; 65 break;
65 default: 66 default:
66 secret.to_base64(pout["mac_key"]); 67 secret.to_base64(pout["mac_key"]);
67 break; 68 break;
68 } 69 }
69 } 70 }
70 71
71 void server_t::checkid_immediate(const params_t& pin,string& return_to,params_t& pout,extension_t *ext) { 72 void server_t::checkid_immediate(const params_t& pin,string& return_to,params_t& pout,extension_t *ext) {
72 checkid_(mode_checkid_immediate,pin,return_to,pout,ext); 73 checkid_(mode_checkid_immediate,pin,return_to,pout,ext);
73 } 74 }
74 75
75 void server_t::checkid_setup(const params_t& pin,string& return_to,params_t& pout,extension_t *ext) { 76 void server_t::checkid_setup(const params_t& pin,string& return_to,params_t& pout,extension_t *ext) {
76 checkid_(mode_checkid_setup,pin,return_to,pout,ext); 77 checkid_(mode_checkid_setup,pin,return_to,pout,ext);
77 } 78 }
78 79
79 void server_t::checkid_(mode_t mode,const params_t& pin,string& return_to,params_t& pout,extension_t *ext) { 80 void server_t::checkid_(mode_t mode,const params_t& pin,string& return_to,params_t& pout,extension_t *ext) {
80 if(mode!=mode_checkid_immediate && mode!=mode_checkid_setup) 81 if(mode!=mode_checkid_immediate && mode!=mode_checkid_setup)
81 throw bad_input(OPKELE_CP_ "invalid checkid_* mode"); 82 throw bad_input(OPKELE_CP_ "invalid checkid_* mode");
82 pout.clear(); 83 pout.clear();
83 assoc_t assoc; 84 assoc_t assoc;
84 try { 85 try {
85 assoc = retrieve_assoc(pin.get_param("openid.assoc_handle")); 86 assoc = retrieve_assoc(pin.get_param("openid.assoc_handle"));
86 }catch(failed_lookup& fl) { 87 }catch(failed_lookup& fl) {
87 // no handle specified or no valid handle found, going dumb 88 // no handle specified or no valid handle found, going dumb
88 assoc = alloc_assoc(mode_checkid_setup); 89 assoc = alloc_assoc(mode_checkid_setup);
89 if(pin.has_param("openid.assoc_handle")) 90 if(pin.has_param("openid.assoc_handle"))
90 pout["invalidate_handle"]=pin.get_param("openid.assoc_handle"); 91 pout["invalidate_handle"]=pin.get_param("openid.assoc_handle");
91 } 92 }
92 string trust_root; 93 string trust_root;
93 try { 94 try {
94 trust_root = pin.get_param("openid.trust_root"); 95 trust_root = pin.get_param("openid.trust_root");
95 }catch(failed_lookup& fl) { } 96 }catch(failed_lookup& fl) { }
96 string identity = pin.get_param("openid.identity"); 97 string identity = pin.get_param("openid.identity");
97 return_to = pin.get_param("openid.return_to"); 98 return_to = pin.get_param("openid.return_to");
98 validate(*assoc,pin,identity,trust_root); 99 validate(*assoc,pin,identity,trust_root);
99 pout["mode"] = "id_res"; 100 pout["mode"] = "id_res";
100 pout["assoc_handle"] = assoc->handle(); 101 pout["assoc_handle"] = assoc->handle();
101 if(pin.has_param("openid.assoc_handle") && assoc->stateless()) 102 if(pin.has_param("openid.assoc_handle") && assoc->stateless())
102 pout["invalidate_handle"] = pin.get_param("openid.assoc_handle"); 103 pout["invalidate_handle"] = pin.get_param("openid.assoc_handle");
103 pout["identity"] = identity; 104 pout["identity"] = identity;
104 pout["return_to"] = return_to; 105 pout["return_to"] = return_to;
105 /* TODO: eventually remove deprecated stuff */ 106 /* TODO: eventually remove deprecated stuff */
106 time_t now = time(0); 107 time_t now = time(0);
107 pout["issued"] = util::time_to_w3c(now); 108 pout["issued"] = util::time_to_w3c(now);
108 pout["valid_to"] = util::time_to_w3c(now+120); 109 pout["valid_to"] = util::time_to_w3c(now+120);
109 pout["exipres_in"] = "120"; 110 pout["exipres_in"] = "120";
110 pout["signed"]="mode,identity,return_to"; 111 pout["signed"]="mode,identity,return_to";
111 if(ext) ext->checkid_hook(pin,pout); 112 if(ext) ext->checkid_hook(pin,pout);
112 pout["sig"] = util::base64_signature(assoc,pout); 113 pout["sig"] = util::base64_signature(assoc,pout);
113 } 114 }
114 115
115 void server_t::check_authentication(const params_t& pin,params_t& pout) { 116 void server_t::check_authentication(const params_t& pin,params_t& pout) {
116 vector<unsigned char> sig; 117 vector<unsigned char> sig;
117 const string& sigenc = pin.get_param("openid.sig"); 118 const string& sigenc = pin.get_param("openid.sig");
118 util::decode_base64(sigenc,sig); 119 util::decode_base64(sigenc,sig);
119 assoc_t assoc; 120 assoc_t assoc;
120 try { 121 try {
121 assoc = retrieve_assoc(pin.get_param("openid.assoc_handle")); 122 assoc = retrieve_assoc(pin.get_param("openid.assoc_handle"));
122 }catch(failed_lookup& fl) { 123 }catch(failed_lookup& fl) {
123 throw failed_assertion(OPKELE_CP_ "invalid handle or handle not specified"); 124 throw failed_assertion(OPKELE_CP_ "invalid handle or handle not specified");
124 } 125 }
125 if(!assoc->stateless()) 126 if(!assoc->stateless())
126 throw stateful_handle(OPKELE_CP_ "will not do check_authentication on a stateful handle"); 127 throw stateful_handle(OPKELE_CP_ "will not do check_authentication on a stateful handle");
127 const string& slist = pin.get_param("openid.signed"); 128 const string& slist = pin.get_param("openid.signed");
128 string kv; 129 string kv;
129 string::size_type p =0; 130 string::size_type p =0;
130 while(true) { 131 while(true) {
131 string::size_type co = slist.find(',',p); 132 string::size_type co = slist.find(',',p);
132 string f = (co==string::npos)?slist.substr(p):slist.substr(p,co-p); 133 string f = (co==string::npos)?slist.substr(p):slist.substr(p,co-p);
133 kv += f; 134 kv += f;
134 kv += ':'; 135 kv += ':';
135 if(f=="mode") 136 if(f=="mode")
136 kv += "id_res"; 137 kv += "id_res";
137 else { 138 else {
138 f.insert(0,"openid."); 139 f.insert(0,"openid.");
139 kv += pin.get_param(f); 140 kv += pin.get_param(f);
140 } 141 }
141 kv += '\n'; 142 kv += '\n';
142 if(co==string::npos) 143 if(co==string::npos)
143 break; 144 break;
144 p = co+1; 145 p = co+1;
145 } 146 }
146 secret_t secret = assoc->secret(); 147 secret_t secret = assoc->secret();
147 unsigned int md_len = 0; 148 unsigned int md_len = 0;
148 unsigned char *md = HMAC( 149 unsigned char *md = HMAC(
149 EVP_sha1(), 150 EVP_sha1(),
150 &(secret.front()),secret.size(), 151 &(secret.front()),secret.size(),
151 (const unsigned char *)kv.data(),kv.length(), 152 (const unsigned char *)kv.data(),kv.length(),
152 0,&md_len); 153 0,&md_len);
153 pout.clear(); 154 pout.clear();
154 if(sig.size()==md_len && !memcmp(&(sig.front()),md,md_len)) { 155 if(sig.size()==md_len && !memcmp(&(sig.front()),md,md_len)) {
155 pout["is_valid"]="true"; 156 pout["is_valid"]="true";
156 pout["lifetime"]="60"; /* TODO: eventually remove deprecated stuff */ 157 pout["lifetime"]="60"; /* TODO: eventually remove deprecated stuff */
157 }else{ 158 }else{
158 pout["is_valid"]="false"; 159 pout["is_valid"]="false";
159 pout["lifetime"]="0"; /* TODO: eventually remove deprecated stuff */ 160 pout["lifetime"]="0"; /* TODO: eventually remove deprecated stuff */
160 } 161 }
161 if(pin.has_param("openid.invalidate_handle")) { 162 if(pin.has_param("openid.invalidate_handle")) {
162 string h = pin.get_param("openid.invalidate_handle"); 163 string h = pin.get_param("openid.invalidate_handle");
163 try { 164 try {
164 assoc_t tmp = retrieve_assoc(h); 165 assoc_t tmp = retrieve_assoc(h);
165 }catch(invalid_handle& ih) { 166 }catch(invalid_handle& ih) {
166 pout["invalidate_handle"] = h; 167 pout["invalidate_handle"] = h;
167 }catch(failed_lookup& fl) { } 168 }catch(failed_lookup& fl) { }
168 } 169 }
169 } 170 }
170 171
171} 172}