2 * OAuth string functions in POSIX-C.
4 * Copyright 2007-2013 Robin Gareus <robin@gareus.org>
6 * The base64 functions are by Jan-Henrik Haukeland, <hauk@tildeslash.com>
7 * and un/escape_url() was inspired by libcurl's curl_escape under ISC-license
8 * many thanks to Daniel Stenberg <daniel@haxx.se>.
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
33 #define WIPE_MEMORY ///< overwrite sensitve data before xfree()ing it.
41 #include <ctype.h> // isxdigit
46 #ifndef WIN32 // getpid() on POSIX systems
47 #include <sys/types.h>
50 #define snprintf _snprintf
51 #define strncasecmp strnicmp
55 * Base64 encode one byte
57 char oauth_b64_encode(unsigned char u) {
58 if(u < 26) return 'A'+u;
59 if(u < 52) return 'a'+(u-26);
60 if(u < 62) return '0'+(u-52);
61 if(u == 62) return '+';
66 * Decode a single base64 character.
68 unsigned char oauth_b64_decode(char c) {
69 if(c >= 'A' && c <= 'Z') return(c - 'A');
70 if(c >= 'a' && c <= 'z') return(c - 'a' + 26);
71 if(c >= '0' && c <= '9') return(c - '0' + 52);
72 if(c == '+') return 62;
77 * Return TRUE if 'c' is a valid base64 character, otherwise FALSE
79 int oauth_b64_is_base64(char c) {
80 if((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
81 (c >= '0' && c <= '9') || (c == '+') ||
82 (c == '/') || (c == '=')) {
89 * Base64 encode and return size data in 'src'. The caller must free the
92 * @param size The size of the data in src
93 * @param src The data to be base64 encode
94 * @return encoded string otherwise NULL
96 char *oauth_encode_base64(int size, const unsigned char *src) {
100 if(!src) return NULL;
101 if(!size) size= strlen((char *)src);
102 out= (char*) xcalloc(sizeof(char), size*4/3+4);
105 for(i=0; i<size; i+=3) {
106 unsigned char b1=0, b2=0, b3=0, b4=0, b5=0, b6=0, b7=0;
108 if(i+1<size) b2= src[i+1];
109 if(i+2<size) b3= src[i+2];
112 b5= ((b1&0x3)<<4)|(b2>>4);
113 b6= ((b2&0xf)<<2)|(b3>>6);
116 *p++= oauth_b64_encode(b4);
117 *p++= oauth_b64_encode(b5);
119 if(i+1<size) *p++= oauth_b64_encode(b6);
122 if(i+2<size) *p++= oauth_b64_encode(b7);
129 * Decode the base64 encoded string 'src' into the memory pointed to by
132 * @param dest Pointer to memory for holding the decoded string.
133 * Must be large enough to receive the decoded string.
134 * @param src A base64 encoded string.
135 * @return the length of the decoded string if decode
136 * succeeded otherwise 0.
138 int oauth_decode_base64(unsigned char *dest, const char *src) {
140 unsigned char *p= dest;
141 int k, l= strlen(src)+1;
142 unsigned char *buf= (unsigned char*) xcalloc(sizeof(unsigned char), l);
144 /* Ignore non base64 chars as per the POSIX standard */
145 for(k=0, l=0; src[k]; k++) {
146 if(oauth_b64_is_base64(src[k])) {
151 for(k=0; k<l; k+=4) {
152 char c1='A', c2='A', c3='A', c4='A';
153 unsigned char b1=0, b2=0, b3=0, b4=0;
156 if(k+1<l) c2= buf[k+1];
157 if(k+2<l) c3= buf[k+2];
158 if(k+3<l) c4= buf[k+3];
160 b1= oauth_b64_decode(c1);
161 b2= oauth_b64_decode(c2);
162 b3= oauth_b64_decode(c3);
163 b4= oauth_b64_decode(c4);
165 *p++=((b1<<2)|(b2>>4) );
167 if(c3 != '=') *p++=(((b2&0xf)<<4)|(b3>>2) );
168 if(c4 != '=') *p++=(((b3&0x3)<<6)|b4 );
178 * Escape 'string' according to RFC3986 and
179 * http://oauth.net/core/1.0/#encoding_parameters.
181 * @param string The data to be encoded
182 * @return encoded string otherwise NULL
183 * The caller must free the returned string.
185 char *oauth_url_escape(const char *string) {
186 size_t alloc, newlen;
187 char *ns = NULL, *testing_ptr = NULL;
192 if (!string) return xstrdup("");
194 alloc = strlen(string)+1;
197 ns = (char*) xmalloc(alloc);
204 case '0': case '1': case '2': case '3': case '4':
205 case '5': case '6': case '7': case '8': case '9':
206 case 'a': case 'b': case 'c': case 'd': case 'e':
207 case 'f': case 'g': case 'h': case 'i': case 'j':
208 case 'k': case 'l': case 'm': case 'n': case 'o':
209 case 'p': case 'q': case 'r': case 's': case 't':
210 case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
211 case 'A': case 'B': case 'C': case 'D': case 'E':
212 case 'F': case 'G': case 'H': case 'I': case 'J':
213 case 'K': case 'L': case 'M': case 'N': case 'O':
214 case 'P': case 'Q': case 'R': case 'S': case 'T':
215 case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z':
216 case '_': case '~': case '.': case '-':
220 newlen += 2; /* this'll become a %XX */
223 testing_ptr = (char*) xrealloc(ns, alloc);
226 snprintf(&ns[strindex], 4, "%%%02X", in);
237 # define ISXDIGIT(x) (isxdigit((int) ((unsigned char)x)))
241 * Parse RFC3986 encoded 'string' back to unescaped version.
243 * @param string The data to be unescaped
244 * @param olen unless NULL the length of the returned string is stored there.
245 * @return decoded string or NULL
246 * The caller must free the returned string.
248 char *oauth_url_unescape(const char *string, size_t *olen) {
249 size_t alloc, strindex=0;
254 if (!string) return NULL;
255 alloc = strlen(string)+1;
256 ns = (char*) xmalloc(alloc);
260 if(('%' == in) && ISXDIGIT(string[1]) && ISXDIGIT(string[2])) {
261 char hexstr[3]; // '%XX'
262 hexstr[0] = string[1];
263 hexstr[1] = string[2];
265 hex = strtol(hexstr, NULL, 16);
266 in = (unsigned char)hex; /* hex is always < 256 */
274 if(olen) *olen = strindex;
279 * returns plaintext signature for the given key.
281 * the returned string needs to be freed by the caller
283 * @param m message to be signed
284 * @param k key used for signing
285 * @return signature string
287 char *oauth_sign_plaintext (const char *m, const char *k) {
292 * encode strings and concatenate with '&' separator.
293 * The number of strings to be concatenated must be
294 * given as first argument.
295 * all arguments thereafter must be of type (char *)
297 * @param len the number of arguments to follow this parameter
298 * @param ... string to escape and added (may be NULL)
300 * @return pointer to memory holding the concatenated
301 * strings - needs to be xfree(d) by the caller. or NULL
302 * in case we ran out of memory.
304 char *oauth_catenc(int len, ...) {
307 char *rv = (char*) xmalloc(sizeof(char));
311 char *arg = va_arg(va, char *);
314 enc = oauth_url_escape(arg);
316 len = strlen(enc) + 1 + ((i>0)?1:0);
318 rv=(char*) xrealloc(rv,len*sizeof(char));
320 if(i>0) strcat(rv, "&");
329 * splits the given url into a parameter array.
330 * (see \ref oauth_serialize_url and \ref oauth_serialize_url_parameters for the reverse)
332 * NOTE: Request-parameters-values may include an ampersand character.
333 * However if unescaped this function will use them as parameter delimiter.
334 * If you need to make such a request, this function since version 0.3.5 allows
335 * to use the ASCII SOH (0x01) character as alias for '&' (0x26).
336 * (the motivation is convenience: SOH is /untypeable/ and much more
337 * unlikely to appear than '&' - If you plan to sign fancy URLs you
338 * should not split a query-string, but rather provide the parameter array
339 * directly to \ref oauth_serialize_url)
341 * @param url the url or query-string to parse.
342 * @param argv pointer to a (char *) array where the results are stored.
343 * The array is re-allocated to match the number of parameters and each
344 * parameter-string is allocated with strdup. - The memory needs to be freed
346 * @param qesc use query parameter escape (vs post-param-escape) - if set
347 * to 1 all '+' are treated as spaces ' '
349 * @return number of parameter(s) in array.
351 int oauth_split_post_paramters(const char *url, char ***argv, short qesc) {
353 char *token, *tmp, *t1;
358 // '+' represents a space, in a URL query string
359 while ((qesc&1) && (tmp=strchr(t1,'+'))) *tmp=' ';
362 while((token=strtok(tmp,"&?"))) {
363 if(!strncasecmp("oauth_signature=",token,16)) continue;
364 (*argv)=(char**) xrealloc(*argv,sizeof(char*)*(argc+1));
365 while (!(qesc&2) && (tmp=strchr(token,'\001'))) *tmp='&';
366 if (argc>0 || (qesc&4))
367 (*argv)[argc]=oauth_url_unescape(token, NULL);
369 (*argv)[argc]=xstrdup(token);
370 if (argc==0 && strstr(token, ":/")) {
371 // HTTP does not allow empty absolute paths, so the URL
372 // 'http://example.com' is equivalent to 'http://example.com/' and should
373 // be treated as such for the purposes of OAuth signing (rfc2616, section 3.2.1)
374 // see http://groups.google.com/group/oauth/browse_thread/thread/c44b6f061bfd98c?hl=en
375 char *slash=strstr(token, ":/");
376 while (slash && *(++slash) == '/') ; // skip slashes eg /xxx:[\/]*/
378 // skip possibly unescaped slashes in the userinfo - they're not allowed by RFC2396 but have been seen.
379 // the hostname/IP may only contain alphanumeric characters - so we're safe there.
380 if (slash && strchr(slash,'@')) slash=strchr(slash,'@');
382 if (slash && !strchr(slash,'/')) {
384 fprintf(stderr, "\nliboauth: added trailing slash to URL: '%s'\n\n", token);
386 xfree((*argv)[argc]);
387 (*argv)[argc]= (char*) xmalloc(sizeof(char)*(2+strlen(token)));
388 strcpy((*argv)[argc],token);
389 strcat((*argv)[argc],"/");
392 if (argc==0 && (tmp=strstr((*argv)[argc],":80/"))) {
393 memmove(tmp, tmp+3, strlen(tmp+2));
403 int oauth_split_url_parameters(const char *url, char ***argv) {
404 return oauth_split_post_paramters(url, argv, 1);
408 * build a url query string from an array.
410 * @param argc the total number of elements in the array
411 * @param start element in the array at which to start concatenating.
412 * @param argv parameter-array to concatenate.
413 * @return url string needs to be freed by the caller.
416 char *oauth_serialize_url (int argc, int start, char **argv) {
417 return oauth_serialize_url_sep( argc, start, argv, "&", 0);
421 * encode query parameters from an array.
423 * @param argc the total number of elements in the array
424 * @param start element in the array at which to start concatenating.
425 * @param argv parameter-array to concatenate.
426 * @param sep separator for parameters (usually "&")
427 * @param mod - bitwise modifiers:
428 * 1: skip all values that start with "oauth_"
429 * 2: skip all values that don't start with "oauth_"
430 * 4: add double quotation marks around values (use with sep=", " to generate HTTP Authorization header).
431 * @return url string needs to be freed by the caller.
433 char *oauth_serialize_url_sep (int argc, int start, char **argv, char *sep, int mod) {
437 int seplen=strlen(sep);
438 char *query = (char*) xmalloc(sizeof(char));
440 for(i=start; i< argc; i++) {
442 if ((mod&1)==1 && (strncmp(argv[i],"oauth_",6) == 0 || strncmp(argv[i],"x_oauth_",8) == 0) ) continue;
443 if ((mod&2)==2 && (strncmp(argv[i],"oauth_",6) != 0 && strncmp(argv[i],"x_oauth_",8) != 0) && i!=0) continue;
447 if (i==start && i==0 && strstr(argv[i], ":/")) {
448 tmp=xstrdup(argv[i]);
449 #if 1 // encode white-space in the base-url
450 while ((t1=strchr(tmp,' '))) {
455 char *t2 = (char*) xmalloc(sizeof(char)*(3+strlen(tmp)));
457 strcpy(t2+off+2, tmp+off);
458 *(t2+off)='%'; *(t2+off+1)='2'; *(t2+off+2)='0';
465 } else if(!(t1=strchr(argv[i], '='))) {
466 // see http://oauth.net/core/1.0/#anchor14
467 // escape parameter names and arguments but not the '='
468 tmp=xstrdup(argv[i]);
469 tmp=(char*) xrealloc(tmp,(strlen(tmp)+2)*sizeof(char));
474 tmp = oauth_url_escape(argv[i]);
476 t1 = oauth_url_escape((t1+1));
477 tmp=(char*) xrealloc(tmp,(strlen(tmp)+strlen(t1)+2+(mod&4?2:0))*sizeof(char));
479 if (mod&4) strcat(tmp,"\"");
481 if (mod&4) strcat(tmp,"\"");
486 query=(char*) xrealloc(query,len*sizeof(char));
487 strcat(query, ((i==start||first)?"":sep));
490 if (i==start && i==0 && strstr(tmp, ":/")) {
500 * build a query parameter string from an array.
502 * This function is a shortcut for \ref oauth_serialize_url (argc, 1, argv).
503 * It strips the leading host/path, which is usually the first
504 * element when using oauth_split_url_parameters on an URL.
506 * @param argc the total number of elements in the array
507 * @param argv parameter-array to concatenate.
508 * @return url string needs to be freed by the caller.
510 char *oauth_serialize_url_parameters (int argc, char **argv) {
511 return oauth_serialize_url(argc, 1, argv);
515 * generate a random string between 15 and 32 chars length
516 * and return a pointer to it. The value needs to be freed by the
519 * @return zero terminated random string.
521 #if !defined HAVE_OPENSSL_HMAC_H && !defined USE_NSS
522 /* pre liboauth-0.7.2 and possible future versions that don't use OpenSSL or NSS */
523 char *oauth_gen_nonce() {
525 static int rndinit = 1;
526 const char *chars = "abcdefghijklmnopqrstuvwxyz"
527 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789_";
528 unsigned int max = strlen( chars );
531 if(rndinit) {srand(time(NULL)
532 #ifndef WIN32 // quick windows check.
535 ); rndinit=0;} // seed random number generator - FIXME: we can do better ;)
537 len=15+floor(rand()*16.0/(double)RAND_MAX);
538 nc = (char*) xmalloc((len+1)*sizeof(char));
539 for(i=0;i<len; i++) {
540 nc[i] = chars[ rand() % max ];
545 #else // OpenSSL or NSS random number generator
547 void oauth_init_nss(); //decladed in hash.c
548 # include "pk11pub.h"
549 # define MY_RAND PK11_GenerateRandom
550 # define MY_SRAND oauth_init_nss();
553 /* Note: the OpenSSL/GPL exemption stated
554 * verbosely in hash.c applies to this code as well. */
556 # include <openssl/rand.h>
557 # define MY_RAND RAND_bytes
560 char *oauth_gen_nonce() {
563 const char *chars = "abcdefghijklmnopqrstuvwxyz"
564 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789_";
565 unsigned int max = strlen(chars);
570 len=15+(((short)buf)&0x0f);
571 nc = (char*) xmalloc((len+1)*sizeof(char));
572 for(i=0;i<len; i++) {
574 nc[i] = chars[ ((short)buf) % max ];
582 * string compare function for oauth parameters.
584 * used with qsort. needed to normalize request parameters.
585 * see http://oauth.net/core/1.0/#anchor14
587 int oauth_cmpstringp(const void *p1, const void *p2) {
591 if (!p1 || !p2) return 0;
592 // TODO: this is not fast - we should escape the
593 // array elements (once) before sorting.
594 v1=oauth_url_escape(* (char * const *)p1);
595 v2=oauth_url_escape(* (char * const *)p2);
597 // '=' signs are not "%3D" !
598 if ((t1=strstr(v1,"%3D"))) {
599 t1[0]='\0'; t1[1]='='; t1[2]='=';
601 if ((t2=strstr(v2,"%3D"))) {
602 t2[0]='\0'; t2[1]='='; t2[2]='=';
605 // compare parameter names
613 // if parameter names are equal, sort by value.
616 if (t1 && t2) rv=strcmp(t1,t2);
617 else if (!t1 && !t2) rv=0;
627 * search array for parameter key.
628 * @param argv length of array to search
629 * @param argc parameter array to search
630 * @param key key of parameter to check.
632 * @return FALSE (0) if array does not contain a parameter with given key, TRUE (1) otherwise.
634 int oauth_param_exists(char **argv, int argc, char *key) {
636 size_t l= strlen(key);
638 if (strlen(argv[i])>l && !strncmp(argv[i],key,l) && argv[i][l] == '=') return 1;
643 * add query parameter to array
645 * @param argcp pointer to array length int
646 * @param argvp pointer to array values
647 * @param addparam parameter to add (eg. "foo=bar")
649 void oauth_add_param_to_array(int *argcp, char ***argvp, const char *addparam) {
650 (*argvp)=(char**) xrealloc(*argvp,sizeof(char*)*((*argcp)+1));
651 (*argvp)[(*argcp)++]= (char*) xstrdup(addparam);
657 void oauth_add_protocol(int *argcp, char ***argvp,
659 const char *c_key, //< consumer key - posted plain text
660 const char *t_key //< token key - posted plain text in URL
664 // add OAuth specific arguments
665 if (!oauth_param_exists(*argvp,*argcp,"oauth_nonce")) {
667 snprintf(oarg, 1024, "oauth_nonce=%s", (tmp=oauth_gen_nonce()));
668 oauth_add_param_to_array(argcp, argvp, oarg);
672 if (!oauth_param_exists(*argvp,*argcp,"oauth_timestamp")) {
673 snprintf(oarg, 1024, "oauth_timestamp=%li", (long int) time(NULL));
674 oauth_add_param_to_array(argcp, argvp, oarg);
678 snprintf(oarg, 1024, "oauth_token=%s", t_key);
679 oauth_add_param_to_array(argcp, argvp, oarg);
682 snprintf(oarg, 1024, "oauth_consumer_key=%s", c_key);
683 oauth_add_param_to_array(argcp, argvp, oarg);
685 snprintf(oarg, 1024, "oauth_signature_method=%s",
686 method==0?"HMAC-SHA1":method==1?"RSA-SHA1":"PLAINTEXT");
687 oauth_add_param_to_array(argcp, argvp, oarg);
689 if (!oauth_param_exists(*argvp,*argcp,"oauth_version")) {
690 snprintf(oarg, 1024, "oauth_version=1.0");
691 oauth_add_param_to_array(argcp, argvp, oarg);
694 #if 0 // oauth_version 1.0 Rev A
695 if (!oauth_param_exists(argv,argc,"oauth_callback")) {
696 snprintf(oarg, 1024, "oauth_callback=oob");
697 oauth_add_param_to_array(argcp, argvp, oarg);
703 char *oauth_sign_url (const char *url, char **postargs,
705 const char *c_key, //< consumer key - posted plain text
706 const char *c_secret, //< consumer secret - used as 1st part of secret-key
707 const char *t_key, //< token key - posted plain text in URL
708 const char *t_secret //< token secret - used as 2st part of secret-key
710 return oauth_sign_url2(url, postargs,
716 char *oauth_sign_url2 (const char *url, char **postargs,
718 const char *http_method, //< HTTP request method
719 const char *c_key, //< consumer key - posted plain text
720 const char *c_secret, //< consumer secret - used as 1st part of secret-key
721 const char *t_key, //< token key - posted plain text in URL
722 const char *t_secret //< token secret - used as 2st part of secret-key
729 argc = oauth_split_post_paramters(url, &argv, 0);
731 argc = oauth_split_url_parameters(url, &argv);
733 rv=oauth_sign_array2(&argc, &argv, postargs,
735 c_key, c_secret, t_key, t_secret);
737 oauth_free_array(&argc, &argv);
741 char *oauth_sign_array (int *argcp, char***argvp,
744 const char *c_key, //< consumer key - posted plain text
745 const char *c_secret, //< consumer secret - used as 1st part of secret-key
746 const char *t_key, //< token key - posted plain text in URL
747 const char *t_secret //< token secret - used as 2st part of secret-key
749 return oauth_sign_array2 (argcp, argvp,
756 void oauth_sign_array2_process (int *argcp, char***argvp,
759 const char *http_method, //< HTTP request method
760 const char *c_key, //< consumer key - posted plain text
761 const char *c_secret, //< consumer secret - used as 1st part of secret-key
762 const char *t_key, //< token key - posted plain text in URL
763 const char *t_secret //< token secret - used as 2st part of secret-key
767 char *okey, *odat, *sign;
768 char *http_request_method;
771 http_request_method = xstrdup(postargs?"POST":"GET");
774 http_request_method = xstrdup(http_method);
775 for (i=0;i<strlen(http_request_method);i++)
776 http_request_method[i]=toupper(http_request_method[i]);
779 // add required OAuth protocol parameters
780 oauth_add_protocol(argcp, argvp, method, c_key, t_key);
783 qsort(&(*argvp)[1], (*argcp)-1, sizeof(char *), oauth_cmpstringp);
785 // serialize URL - base-url
786 query= oauth_serialize_url_parameters(*argcp, *argvp);
788 // prepare data to sign
789 if (method == OA_RSA) {
792 len += strlen(c_secret);
795 len += strlen(t_secret);
797 okey = (char*)xmalloc(len * sizeof(char));
800 okey = strcat(okey, c_secret);
803 okey = strcat(okey, t_secret);
806 okey = oauth_catenc(2, c_secret, t_secret);
809 odat = oauth_catenc(3, http_request_method, (*argvp)[0], query); // base-string
810 xfree(http_request_method);
813 fprintf (stderr, "\nliboauth: data to sign='%s'\n\n", odat);
814 fprintf (stderr, "\nliboauth: key='%s'\n\n", okey);
817 // generate signature
820 sign = oauth_sign_rsa_sha1(odat,okey); // XXX okey needs to be RSA key!
823 sign = oauth_sign_plaintext(odat,okey);
826 sign = oauth_sign_hmac_sha1(odat,okey);
829 memset(okey,0, strlen(okey));
830 memset(odat,0, strlen(odat));
835 // append signature to query args.
836 snprintf(oarg, 1024, "oauth_signature=%s",sign);
837 oauth_add_param_to_array(argcp, argvp, oarg);
839 if(query) xfree(query);
842 char *oauth_sign_array2 (int *argcp, char***argvp,
845 const char *http_method, //< HTTP request method
846 const char *c_key, //< consumer key - posted plain text
847 const char *c_secret, //< consumer secret - used as 1st part of secret-key
848 const char *t_key, //< token key - posted plain text in URL
849 const char *t_secret //< token secret - used as 2st part of secret-key
853 oauth_sign_array2_process(argcp, argvp, postargs, method, http_method, c_key, c_secret, t_key, t_secret);
856 result = oauth_serialize_url(*argcp, (postargs?1:0), *argvp);
860 result = xstrdup((*argvp)[0]);
870 * @param argcp pointer to array length int
871 * @param argvp pointer to array values to be xfree()d
873 void oauth_free_array(int *argcp, char ***argvp) {
875 for (i=0;i<(*argcp);i++) {
878 if(*argvp) xfree(*argvp);
882 * base64 encode digest, free it and return a URL parameter
883 * with the oauth_body_hash
885 char *oauth_body_hash_encode(size_t len, unsigned char *digest) {
886 char *sign=oauth_encode_base64(len,digest);
887 char *sig_url = (char*)xmalloc(17+strlen(sign));
888 sprintf(sig_url,"oauth_body_hash=%s", sign);
896 * compare two strings in constant-time (as to not let an
897 * attacker guess how many leading chars are correct:
898 * http://rdist.root.org/2010/01/07/timing-independent-array-comparison/ )
900 * @param a string to compare
901 * @param b string to compare
902 * @param len_a length of string a
903 * @param len_b length of string b
905 * returns 0 (false) if strings are not equal, and 1 (true) if strings are equal.
907 int oauth_time_independent_equals_n(const char* a, const char* b, size_t len_a, size_t len_b) {
909 if (a == NULL) return (b == NULL);
910 else if (b == NULL) return 0;
911 else if (len_b == 0) return (len_a == 0);
912 diff = len_a ^ len_b;
914 for (i=0; i<len_a; ++i) {
920 int oauth_time_indepenent_equals_n(const char* a, const char* b, size_t len_a, size_t len_b) {
921 return oauth_time_independent_equals_n(a, b, len_a, len_b);
924 int oauth_time_independent_equals(const char* a, const char* b) {
925 return oauth_time_independent_equals_n (a, b, a?strlen(a):0, b?strlen(b):0);
928 int oauth_time_indepenent_equals(const char* a, const char* b) {
929 return oauth_time_independent_equals_n (a, b, a?strlen(a):0, b?strlen(b):0);
935 char *oauth_sign_xmpp (const char *xml,
937 const char *c_secret, //< consumer secret - used as 1st part of secret-key
938 const char *t_secret //< token secret - used as 2st part of secret-key
944 // vi: sts=2 sw=2 ts=2