00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #if HAVE_CONFIG_H
00030 # include <config.h>
00031 #endif
00032
00033 #define WIPE_MEMORY ///< overwrite sensitve data before free()ing it.
00034
00035 #include <stdio.h>
00036 #include <stdarg.h>
00037 #include <stdlib.h>
00038 #include <string.h>
00039 #include <time.h>
00040 #include <math.h>
00041 #include <ctype.h>
00042
00043 #include "oauth.h"
00044
00045 #include <vector>
00046 #include <algorithm>
00047 #include <sstream>
00048
00049
00050
00051
00052 char oauth_b64_encode(unsigned char u)
00053 {
00054 if (u < 26) return 'A' + u;
00055 if (u < 52) return 'a' + (u - 26);
00056 if (u < 62) return '0' + (u - 52);
00057 if (u == 62) return '+';
00058 return '/';
00059 }
00060
00061
00062
00063
00064 unsigned char oauth_b64_decode(char c)
00065 {
00066 if (c >= 'A' && c <= 'Z') return(c - 'A');
00067 if (c >= 'a' && c <= 'z') return(c - 'a' + 26);
00068 if (c >= '0' && c <= '9') return(c - '0' + 52);
00069 if (c == '+') return 62;
00070 return 63;
00071 }
00072
00073
00074
00075
00076 bool oauth_b64_is_base64(char c)
00077 {
00078 return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c == '+') || (c == '/') || (c == '='));
00079 }
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089 std::string oauth_encode_base64(const unsigned char *src, int size)
00090 {
00091 int i;
00092 std::stringbuf sb;
00093
00094 if (!src) return NULL;
00095 if (!size) size= strlen((char *)src);
00096
00097 for (i = 0; i < size; i += 3) {
00098 unsigned char b1 = 0, b2 = 0, b3 = 0, b4 = 0, b5 = 0, b6 = 0, b7 = 0;
00099 b1= src[i];
00100 if (i + 1 < size) b2 = src[i + 1];
00101 if (i + 2 < size) b3 = src[i + 2];
00102
00103 b4= b1 >> 2;
00104 b5= ((b1 & 0x3) << 4) | (b2 >> 4);
00105 b6= ((b2 & 0xf) << 2) | (b3 >> 6);
00106 b7= b3 & 0x3f;
00107
00108 sb.sputc(oauth_b64_encode(b4));
00109 sb.sputc(oauth_b64_encode(b5));
00110
00111 if (i + 1 < size) {
00112 sb.sputc(oauth_b64_encode(b6));
00113 } else {
00114 sb.sputc('=');
00115 }
00116
00117 if (i + 2 < size) {
00118 sb.sputc(oauth_b64_encode(b7));
00119 } else {
00120 sb.sputc('=');
00121 }
00122 }
00123 return sb.str();
00124 }
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136 std::string oauth_decode_base64(const char *src)
00137 {
00138 if (src && *src) {
00139 std::stringbuf sb;
00140
00141 int k, l= strlen(src)+1;
00142 std::vector<unsigned char> buf(l);
00143
00144
00145 for (k = 0, l = 0; src[k]; k++) {
00146 if (oauth_b64_is_base64(src[k])) {
00147 buf[l++]= src[k];
00148 }
00149 }
00150
00151 for (k = 0; k < l; k += 4) {
00152 char c1='A', c2='A', c3='A', c4='A';
00153 unsigned char b1 = 0, b2 = 0, b3 = 0, b4 = 0;
00154 c1= buf[k];
00155
00156 if (k + 1 < l) c2 = buf[k + 1];
00157 if (k + 2 < l) c3 = buf[k + 2];
00158 if (k + 3 < l) c4 = buf[k + 3];
00159
00160 b1 = oauth_b64_decode(c1);
00161 b2 = oauth_b64_decode(c2);
00162 b3 = oauth_b64_decode(c3);
00163 b4 = oauth_b64_decode(c4);
00164
00165 sb.sputc((b1 << 2) | (b2 >> 4));
00166
00167 if (c3 != '=') sb.sputc(((b2 & 0xf) << 4) | (b3 >> 2));
00168 if (c4 != '=') sb.sputc(((b3 & 0x3) << 6) | b4);
00169 }
00170
00171 return sb.str();
00172 }
00173 return 0;
00174 }
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184 std::string oauth_url_escape(const char *string)
00185 {
00186 unsigned char in;
00187 size_t length;
00188
00189 if (!string) {
00190 return std::string();
00191 }
00192
00193 length = strlen(string);
00194
00195 std::stringbuf sb;
00196
00197 while (length--) {
00198 in = *string;
00199 if (strchr("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_~.-", in)) {
00200 sb.sputc(in);
00201 } else {
00202 char tmp[10];
00203 snprintf(tmp, 4, "%%%02X", in);
00204 sb.sputc(tmp[0]);
00205 sb.sputc(tmp[1]);
00206 sb.sputc(tmp[2]);
00207 }
00208 string++;
00209 }
00210 return sb.str();
00211 }
00212
00213 #ifndef ISXDIGIT
00214 # define ISXDIGIT(x) (isxdigit((int) ((unsigned char)x)))
00215 #endif
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225 std::string oauth_url_unescape(const char *string)
00226 {
00227 size_t alloc, strindex=0;
00228 unsigned char in;
00229 long hex;
00230
00231 if (!string) return NULL;
00232
00233 alloc = strlen(string)+1;
00234 std::vector<char> ns(alloc);
00235
00236 while(--alloc > 0) {
00237 in = *string;
00238 if (('%' == in) && ISXDIGIT(string[1]) && ISXDIGIT(string[2])) {
00239 char hexstr[3];
00240 hexstr[0] = string[1];
00241 hexstr[1] = string[2];
00242 hexstr[2] = 0;
00243 hex = strtol(hexstr, NULL, 16);
00244 in = (unsigned char)hex;
00245 string += 2;
00246 alloc -= 2;
00247 }
00248 ns[strindex++] = in;
00249 string++;
00250 }
00251 ns[strindex]=0;
00252 return &ns[0];
00253 }
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264 std::string oauth_sign_plaintext (const char *m, const char *k)
00265 {
00266 return oauth_url_escape(k);
00267 }
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282 std::string oauth_catenc(int len, ...)
00283 {
00284 va_list va;
00285 std::string str;
00286 va_start(va, len);
00287 for (int i = 0; i < len; i++) {
00288 char *arg = va_arg(va, char *);
00289 std::string enc = oauth_url_escape(arg);
00290 if (i > 0) str += "&";
00291 str += enc;
00292 }
00293 va_end(va);
00294 return str;
00295 }
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320 void oauth_split_post_paramters(const char *url, std::vector<std::string> *argv, short qesc)
00321 {
00322 int argc=0;
00323 char *token, *tmp;
00324 if (!argv) return;
00325 if (!url) return;
00326 std::vector<char> t1(strlen(url) + 1);
00327 strcpy(&t1[0], url);
00328
00329
00330 while ((qesc&1) && (tmp = strchr(&t1[0],'+'))) *tmp = ' ';
00331
00332 tmp = &t1[0];
00333 while ((token = strtok(tmp,"&?"))) {
00334 if (!strncasecmp("oauth_signature=", token, 16)) continue;
00335 while (!(qesc & 2) && (tmp = strchr(token, '\001'))) *tmp = '&';
00336 argv->push_back(oauth_url_unescape(token));
00337 if (argc == 0 && strstr(token, ":/")) {
00338
00339
00340
00341
00342 char *slash = strstr(token, ":/");
00343 while (slash && *(++slash) == '/') ;
00344 #if 0
00345
00346
00347 if (slash && strchr(slash,'@')) slash=strchr(slash, '@');
00348 #endif
00349 if (slash && !strchr(slash,'/')) {
00350 #ifdef DEBUG_OAUTH
00351 fprintf(stderr, "\nliboauth: added trailing slash to URL: '%s'\n\n", token);
00352 #endif
00353 argv->push_back(std::string(token) + "/");
00354 }
00355 }
00356 if (argc == 0 && (tmp = strstr((char *)argv->at(argc).c_str(), ":80/"))) {
00357 memmove(tmp, tmp + 3, strlen(tmp + 2));
00358 }
00359 tmp = NULL;
00360 argc++;
00361 }
00362 }
00363
00364 void oauth_split_url_parameters(const char *url, std::vector<std::string> *argv)
00365 {
00366 oauth_split_post_paramters(url, argv, 1);
00367 }
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378 std::string oauth_serialize_url (std::vector<std::string> const &argv, int start)
00379 {
00380 return oauth_serialize_url_sep(argv, start, "&", 0);
00381 }
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396 std::string oauth_serialize_url_sep(std::vector<std::string> const &argv, int start, char const *sep, int mod)
00397 {
00398 int i;
00399 int first = 0;
00400 int seplen = strlen(sep);
00401 std::string query;
00402 for (i = start; i < (int)argv.size(); i++) {
00403 std::string tmp;
00404
00405 if ((mod & 1) == 1 && (strncmp(argv[i].c_str(), "oauth_", 6) == 0 || strncmp(argv[i].c_str(), "x_oauth_", 8) == 0)) continue;
00406 if ((mod & 2) == 2 && (strncmp(argv[i].c_str(), "oauth_", 6) != 0 && strncmp(argv[i].c_str(), "x_oauth_", 8) != 0) && i != 0) continue;
00407
00408 if (i == start && i == 0 && strstr(argv[i].c_str(), ":/")) {
00409 tmp = argv[i];
00410 } else {
00411 char *p = strchr((char *)argv[i].c_str(), '=');
00412 if (p) {
00413 tmp = oauth_url_escape(std::string(argv[i].c_str(), (char const *)p).c_str());
00414 std::string t2 = oauth_url_escape(p + 1);
00415 tmp += "=";
00416 if (mod & 4) tmp += "\"";
00417 tmp += t2;
00418 if (mod & 4) tmp += "\"";
00419 } else {
00420
00421
00422 tmp=argv[i];
00423 tmp += "=";
00424 }
00425 }
00426 query += ((i == start || first) ? "" : sep);
00427 query += tmp;
00428 first = 0;
00429 if (i == start && i == 0 && strstr((char *)tmp.c_str(), ":/")) {
00430 query += "?";
00431 first = 1;
00432 }
00433 }
00434 return (query);
00435 }
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448 std::string oauth_serialize_url_parameters (std::vector<std::string> const &argv)
00449 {
00450 return oauth_serialize_url(argv, 1);
00451 }
00452
00453
00454
00455
00456
00457
00458
00459
00460 std::string oauth_gen_nonce()
00461 {
00462 static const char *chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
00463 const unsigned int max = 26 + 26 + 10 + 1;
00464 char tmp[50];
00465 int i, len;
00466
00467 srand((unsigned int)time(0));
00468 len = 15 + rand() % 16;
00469 for (i = 0; i < len; i++) {
00470 tmp[i] = chars[rand() % max];
00471 }
00472 tmp[i]='\0';
00473 return &tmp[0];
00474 }
00475
00476
00477
00478
00479
00480
00481
00482 int oauth_cmpstringp(const void *p1, const void *p2)
00483 {
00484 char const *e1;
00485 char const *e2;
00486 e1 = strchr((char *)p1, '=');
00487 e2 = strchr((char *)p2, '=');
00488 if (e1 && e2) {
00489 std::string left((char const *)p1, e1);
00490 std::string right((char const *)p2, e2);
00491 return strcmp(left.c_str(), right.c_str());
00492 }
00493
00494 std::string left = oauth_url_escape((char const *)p1);
00495 std::string right = oauth_url_escape((char const *)p2);
00496 return strcmp(left.c_str(), right.c_str());
00497 }
00498
00499 bool oauth_cmpstringp_ex(std::string const &left, std::string const &right)
00500 {
00501 return oauth_cmpstringp(left.c_str(), right.c_str()) < 0;
00502 }
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512 bool oauth_param_exists(std::vector<std::string> const &argv, char const *key)
00513 {
00514 int i;
00515 size_t l = strlen(key);
00516 for (i = 0; i < (int)argv.size(); i++) {
00517 if (!strncmp(argv[i].c_str(), key, l) && argv[i][l] == '=') {
00518 return true;
00519 }
00520 }
00521 return false;
00522 }
00523
00524
00525
00526
00527 void oauth_add_protocol(
00528 std::vector<std::string> *argvp,
00529 OAuthMethod method,
00530 const char *c_key,
00531 const char *t_key
00532 )
00533 {
00534 char oarg[1024];
00535
00536
00537 if (!oauth_param_exists(*argvp,"oauth_nonce")) {
00538 std::string tmp = oauth_gen_nonce();
00539 snprintf(oarg, 1024, "oauth_nonce=%s", tmp.c_str());
00540 argvp->push_back(oarg);
00541 }
00542
00543 if (!oauth_param_exists(*argvp,"oauth_timestamp")) {
00544 long t = time(0);
00545 snprintf(oarg, 1024, "oauth_timestamp=%u", t);
00546 argvp->push_back(oarg);
00547 }
00548
00549 if (t_key) {
00550 snprintf(oarg, 1024, "oauth_token=%s", t_key);
00551 argvp->push_back(oarg);
00552 }
00553
00554 snprintf(oarg, 1024, "oauth_consumer_key=%s", c_key);
00555 argvp->push_back(oarg);
00556
00557 snprintf(oarg, 1024, "oauth_signature_method=%s", method==0?"HMAC-SHA1":method==1?"RSA-SHA1":"PLAINTEXT");
00558 argvp->push_back(oarg);
00559
00560 if (!oauth_param_exists(*argvp,"oauth_version")) {
00561 snprintf(oarg, 1024, "oauth_version=1.0");
00562 argvp->push_back(oarg);
00563 }
00564
00565 #if 0 // oauth_version 1.0 Rev A
00566 if (!oauth_param_exists(argv,argc,"oauth_callback")) {
00567 snprintf(oarg, 1024, "oauth_callback=oob");
00568 argvp->push_back(oarg);
00569 }
00570 #endif
00571
00572 }
00573
00574 std::string oauth_sign_url(
00575 const char *url,
00576 std::string *postargs,
00577 OAuthMethod method,
00578 const char *c_key,
00579 const char *c_secret,
00580 const char *t_key,
00581 const char *t_secret
00582 )
00583 {
00584 return oauth_sign_url2(url, postargs, method, NULL, c_key, c_secret, t_key, t_secret);
00585 }
00586
00587 std::string oauth_sign_url2(
00588 const char *url,
00589 std::string *postargs,
00590 OAuthMethod method,
00591 const char *http_method,
00592 const char *c_key,
00593 const char *c_secret,
00594 const char *t_key,
00595 const char *t_secret
00596 )
00597 {
00598
00599 std::vector<std::string> argv;
00600 std::string rv;
00601
00602 if (postargs) {
00603 oauth_split_post_paramters(url, &argv, 0);
00604 } else {
00605 oauth_split_url_parameters(url, &argv);
00606 }
00607
00608 rv = oauth_sign_array2(&argv, postargs, method, http_method, c_key, c_secret, t_key, t_secret);
00609
00610 return(rv);
00611 }
00612
00613 std::string oauth_sign_array (
00614 std::vector<std::string> *argvp,
00615 std::string *postargs,
00616 OAuthMethod method,
00617 const char *c_key,
00618 const char *c_secret,
00619 const char *t_key,
00620 const char *t_secret
00621 )
00622 {
00623 return oauth_sign_array2(
00624 argvp,
00625 postargs, method,
00626 NULL,
00627 c_key, c_secret,
00628 t_key, t_secret
00629 );
00630 }
00631
00632 void oauth_sign_array2_process(
00633 std::vector<std::string> *argvp,
00634 std::string *postargs,
00635 OAuthMethod method,
00636 const char *http_method,
00637 const char *c_key,
00638 const char *c_secret,
00639 const char *t_key,
00640 const char *t_secret
00641 )
00642 {
00643 char oarg[1024];
00644 std::string query;
00645 std::string sign;
00646 std::string http_request_method;
00647
00648 if (!http_method) {
00649 http_request_method = postargs ? "POST" : "GET";
00650 } else {
00651 std::vector<char> tmp(strlen(http_method) + 1);
00652 int i;
00653 for (i = 0; http_method[i]; i++) {
00654 tmp[i] = toupper(http_method[i]);
00655 }
00656 tmp[i] = 0;
00657 http_request_method = &tmp[0];
00658 }
00659
00660
00661 oauth_add_protocol(argvp, method, c_key, t_key);
00662
00663
00664
00665 std::sort(argvp->begin() + 1, argvp->end(), oauth_cmpstringp_ex);
00666
00667
00668 query= oauth_serialize_url_parameters(*argvp);
00669
00670
00671 std::string okey = oauth_catenc(2, c_secret, t_secret);
00672 std::string odat = oauth_catenc(3, http_request_method.c_str(), (*argvp)[0].c_str(), query.c_str());
00673 #ifdef DEBUG_OAUTH
00674 fprintf (stderr, "\nliboauth: data to sign='%s'\n\n", odat.c_str());
00675 fprintf (stderr, "\nliboauth: key='%s'\n\n", okey.c_str());
00676 #endif
00677 switch(method) {
00678
00679
00680
00681 case OA_PLAINTEXT:
00682 sign = oauth_sign_plaintext(odat.c_str(), okey.c_str()).c_str();
00683 break;
00684 default:
00685 sign = oauth_sign_hmac_sha1(odat.c_str(), okey.c_str());
00686 break;
00687 }
00688
00689
00690 snprintf(oarg, 1024, "oauth_signature=%s",sign.c_str());
00691 argvp->push_back(oarg);
00692 }
00693
00694 std::string oauth_sign_array2(
00695 std::vector<std::string> *argvp,
00696 std::string *postargs,
00697 OAuthMethod method,
00698 const char *http_method,
00699 const char *c_key,
00700 const char *c_secret,
00701 const char *t_key,
00702 const char *t_secret
00703 )
00704 {
00705
00706 std::string result;
00707 oauth_sign_array2_process(argvp, postargs, method, http_method, c_key, c_secret, t_key, t_secret);
00708
00709
00710 result = oauth_serialize_url(*argvp, (postargs?1:0));
00711
00712 if (postargs) {
00713 *postargs = result;
00714 result = argvp->at(0);
00715 }
00716
00717 return result;
00718 }
00719