summaryrefslogtreecommitdiffabout
path: root/lib/util.cc
Unidiff
Diffstat (limited to 'lib/util.cc') (more/less context) (show whitespace changes)
-rw-r--r--lib/util.cc71
1 files changed, 69 insertions, 2 deletions
diff --git a/lib/util.cc b/lib/util.cc
index a9b9bed..54d6535 100644
--- a/lib/util.cc
+++ b/lib/util.cc
@@ -1,37 +1,43 @@
1#include <errno.h> 1#include <errno.h>
2#include <cassert> 2#include <cassert>
3#include <cctype> 3#include <cctype>
4#include <cstring> 4#include <cstring>
5#include <vector> 5#include <vector>
6#include <string> 6#include <string>
7#include <stack> 7#include <stack>
8#include <openssl/bio.h> 8#include <openssl/bio.h>
9#include <openssl/evp.h> 9#include <openssl/evp.h>
10#include <openssl/hmac.h>
10#include <curl/curl.h> 11#include <curl/curl.h>
11#include "opkele/util.h" 12#include "opkele/util.h"
12#include "opkele/exception.h" 13#include "opkele/exception.h"
13 14
15#include <config.h>
16#ifdef HAVE_DEMANGLE
17# include <cxxabi.h>
18#endif
19
14namespace opkele { 20namespace opkele {
15 using namespace std; 21 using namespace std;
16 22
17 namespace util { 23 namespace util {
18 24
19 /* 25 /*
20 * base64 26 * base64
21 */ 27 */
22 string encode_base64(const void *data,size_t length) { 28 string encode_base64(const void *data,size_t length) {
23 BIO *b64 = 0, *bmem = 0; 29 BIO *b64 = 0, *bmem = 0;
24 try { 30 try {
25 b64 = BIO_new(BIO_f_base64()); 31 b64 = BIO_new(BIO_f_base64());
26 if(!b64) 32 if(!b64)
27 throw exception_openssl(OPKELE_CP_ "failed to BIO_new() base64 encoder"); 33 throw exception_openssl(OPKELE_CP_ "failed to BIO_new() base64 encoder");
28 BIO_set_flags(b64,BIO_FLAGS_BASE64_NO_NL); 34 BIO_set_flags(b64,BIO_FLAGS_BASE64_NO_NL);
29 bmem = BIO_new(BIO_s_mem()); 35 bmem = BIO_new(BIO_s_mem());
30 BIO_set_flags(b64,BIO_CLOSE); 36 BIO_set_flags(b64,BIO_CLOSE);
31 if(!bmem) 37 if(!bmem)
32 throw exception_openssl(OPKELE_CP_ "failed to BIO_new() memory buffer"); 38 throw exception_openssl(OPKELE_CP_ "failed to BIO_new() memory buffer");
33 BIO_push(b64,bmem); 39 BIO_push(b64,bmem);
34 if(((size_t)BIO_write(b64,data,length))!=length) 40 if(((size_t)BIO_write(b64,data,length))!=length)
35 throw exception_openssl(OPKELE_CP_ "failed to BIO_write()"); 41 throw exception_openssl(OPKELE_CP_ "failed to BIO_write()");
36 if(BIO_flush(b64)!=1) 42 if(BIO_flush(b64)!=1)
37 throw exception_openssl(OPKELE_CP_ "failed to BIO_flush()"); 43 throw exception_openssl(OPKELE_CP_ "failed to BIO_flush()");
@@ -184,50 +190,49 @@ namespace opkele {
184 */ 190 */
185 string rfc_3986_normalize_uri(const string& uri) { 191 string rfc_3986_normalize_uri(const string& uri) {
186 static const char *whitespace = " \t\r\n"; 192 static const char *whitespace = " \t\r\n";
187 string rv; 193 string rv;
188 string::size_type ns = uri.find_first_not_of(whitespace); 194 string::size_type ns = uri.find_first_not_of(whitespace);
189 if(ns==string::npos) 195 if(ns==string::npos)
190 throw bad_input(OPKELE_CP_ "Can't normalize empty URI"); 196 throw bad_input(OPKELE_CP_ "Can't normalize empty URI");
191 string::size_type colon = uri.find(':',ns); 197 string::size_type colon = uri.find(':',ns);
192 if(colon==string::npos) 198 if(colon==string::npos)
193 throw bad_input(OPKELE_CP_ "No scheme specified in URI"); 199 throw bad_input(OPKELE_CP_ "No scheme specified in URI");
194 transform( 200 transform(
195 uri.begin()+ns, uri.begin()+colon+1, 201 uri.begin()+ns, uri.begin()+colon+1,
196 back_inserter(rv), ::tolower ); 202 back_inserter(rv), ::tolower );
197 bool s; 203 bool s;
198 string::size_type ul = uri.find_last_not_of(whitespace)+1; 204 string::size_type ul = uri.find_last_not_of(whitespace)+1;
199 if(ul <= (colon+3)) 205 if(ul <= (colon+3))
200 throw bad_input(OPKELE_CP_ "Unexpected end of URI being normalized encountered"); 206 throw bad_input(OPKELE_CP_ "Unexpected end of URI being normalized encountered");
201 if(uri[colon+1]!='/' || uri[colon+2]!='/') 207 if(uri[colon+1]!='/' || uri[colon+2]!='/')
202 throw bad_input(OPKELE_CP_ "Unexpected input in URI being normalized after scheme component"); 208 throw bad_input(OPKELE_CP_ "Unexpected input in URI being normalized after scheme component");
203 if(rv=="http:") 209 if(rv=="http:")
204 s = false; 210 s = false;
205 else if(rv=="https:") 211 else if(rv=="https:")
206 s = true; 212 s = true;
207 else{ 213 else{
208 /* TODO: support more schemes. 214 /* TODO: support more schemes. e.g. xri. How do we normalize
209 * e.g. xri. How do we normalize
210 * xri? 215 * xri?
211 */ 216 */
212 rv.append(uri,colon+1,ul-colon-1); 217 rv.append(uri,colon+1,ul-colon-1);
213 return rv; 218 return rv;
214 } 219 }
215 rv += "//"; 220 rv += "//";
216 string::size_type interesting = uri.find_first_of(":/#?",colon+3); 221 string::size_type interesting = uri.find_first_of(":/#?",colon+3);
217 if(interesting==string::npos) { 222 if(interesting==string::npos) {
218 transform( 223 transform(
219 uri.begin()+colon+3,uri.begin()+ul, 224 uri.begin()+colon+3,uri.begin()+ul,
220 back_inserter(rv), ::tolower ); 225 back_inserter(rv), ::tolower );
221 rv += '/'; return rv; 226 rv += '/'; return rv;
222 } 227 }
223 transform( 228 transform(
224 uri.begin()+colon+3,uri.begin()+interesting, 229 uri.begin()+colon+3,uri.begin()+interesting,
225 back_inserter(rv), ::tolower ); 230 back_inserter(rv), ::tolower );
226 bool qf = false; 231 bool qf = false;
227 char ic = uri[interesting]; 232 char ic = uri[interesting];
228 if(ic==':') { 233 if(ic==':') {
229 string::size_type ni = uri.find_first_of("/#?%",interesting+1); 234 string::size_type ni = uri.find_first_of("/#?%",interesting+1);
230 const char *nptr = uri.data()+interesting+1; 235 const char *nptr = uri.data()+interesting+1;
231 char *eptr = 0; 236 char *eptr = 0;
232 long port = strtol(nptr,&eptr,10); 237 long port = strtol(nptr,&eptr,10);
233 if( (port>0) && (port<65535) && port!=(s?443:80) ) { 238 if( (port>0) && (port<65535) && port!=(s?443:80) ) {
@@ -290,27 +295,89 @@ namespace opkele {
290 } 295 }
291 if(c=='/' && (n>=ul || strchr("?#",uri[n])) ) { 296 if(c=='/' && (n>=ul || strchr("?#",uri[n])) ) {
292 rv += '/'; 297 rv += '/';
293 if(n<ul) 298 if(n<ul)
294 qf = true; 299 qf = true;
295 }else if(strchr("?#",c)) { 300 }else if(strchr("?#",c)) {
296 if(psegs.size()==1 && psegs.top()==rv.length()) 301 if(psegs.size()==1 && psegs.top()==rv.length())
297 rv += '/'; 302 rv += '/';
298 if(pseg.empty()) 303 if(pseg.empty())
299 rv += c; 304 rv += c;
300 qf = true; 305 qf = true;
301 } 306 }
302 pseg.clear(); 307 pseg.clear();
303 }else{ 308 }else{
304 pseg += c; 309 pseg += c;
305 } 310 }
306 } 311 }
307 if(!pseg.empty()) { 312 if(!pseg.empty()) {
308 if(!qf) rv += '/'; 313 if(!qf) rv += '/';
309 rv += pseg; 314 rv += pseg;
310 } 315 }
311 return rv; 316 return rv;
312 } 317 }
313 318
319 string& strip_uri_fragment_part(string& u) {
320 string::size_type q = u.find('?'), f = u.find('#');
321 if(q==string::npos) {
322 if(f!=string::npos)
323 u.erase(f);
324 }else{
325 if(f!=string::npos) {
326 if(f<q)
327 u.erase(f,q-f);
328 else
329 u.erase(f);
330 }
331 }
332 return u;
333 }
334
335 string abi_demangle(const char *mn) {
336#ifndef HAVE_DEMANGLE
337 return mn;
338#else /* !HAVE_DEMANGLE */
339 int dstat;
340 char *demangled = abi::__cxa_demangle(mn,0,0,&dstat);
341 if(dstat)
342 return mn;
343 string rv = demangled;
344 free(demangled);
345 return rv;
346#endif /* !HAVE_DEMANGLE */
347 }
348
349 string base64_signature(const assoc_t& assoc,const basic_openid_message& om) {
350 const string& slist = om.get_field("signed");
351 string kv;
352 string::size_type p=0;
353 while(true) {
354 string::size_type co = slist.find(',',p);
355 string f = (co==string::npos)
356 ?slist.substr(p):slist.substr(p,co-p);
357 kv += f;
358 kv += ':';
359 kv += om.get_field(f);
360 kv += '\n';
361 if(co==string::npos) break;
362 p = co+1;
363 }
364 const secret_t& secret = assoc->secret();
365 const EVP_MD *evpmd;
366 const string& at = assoc->assoc_type();
367 if(at=="HMAC-SHA256")
368 evpmd = EVP_sha256();
369 else if(at=="HMAC-SHA1")
370 evpmd = EVP_sha1();
371 else
372 throw unsupported(OPKELE_CP_ "unknown association type");
373 unsigned int md_len = 0;
374 unsigned char *md = HMAC(evpmd,
375 &(secret.front()),secret.size(),
376 (const unsigned char*)kv.data(),kv.length(),
377 0,&md_len);
378 return encode_base64(md,md_len);
379 }
380
314 } 381 }
315 382
316} 383}