uploaded liboauth for tizen_3.0
[platform/upstream/liboauth.git] / src / oauth.c
1 /*
2  * OAuth string functions in POSIX-C.
3  *
4  * Copyright 2007-2013 Robin Gareus <robin@gareus.org>
5  * 
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>.
9  *
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:
16  * 
17  * The above copyright notice and this permission notice shall be included in
18  * all copies or substantial portions of the Software.
19  * 
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
26  * THE SOFTWARE.
27  * 
28  */
29 #if HAVE_CONFIG_H
30 # include <config.h>
31 #endif
32
33 #define WIPE_MEMORY ///< overwrite sensitve data before xfree()ing it.
34
35 #include <stdio.h>
36 #include <stdarg.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <time.h>
40 #include <math.h>
41 #include <ctype.h> // isxdigit
42
43 #include "xmalloc.h"
44 #include "oauth.h"
45
46 #ifndef WIN32 // getpid() on POSIX systems
47 #include <sys/types.h>
48 #include <unistd.h>
49 #else
50 #define snprintf _snprintf
51 #define strncasecmp strnicmp
52 #endif
53
54 /**
55  * Base64 encode one byte
56  */
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 '+';
62   return '/';
63 }
64
65 /**
66  * Decode a single base64 character.
67  */
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;
73   return 63;
74 }
75
76 /**
77  * Return TRUE if 'c' is a valid base64 character, otherwise FALSE
78  */
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 == '=')) {
83     return 1;
84   }
85   return 0;
86 }
87
88 /**
89  * Base64 encode and return size data in 'src'. The caller must free the
90  * returned string.
91  *
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
95  */
96 char *oauth_encode_base64(int size, const unsigned char *src) {
97   int i;
98   char *out, *p;
99
100   if(!src) return NULL;
101   if(!size) size= strlen((char *)src);
102   out= (char*) xcalloc(sizeof(char), size*4/3+4);
103   p= out;
104
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;
107     b1= src[i];
108     if(i+1<size) b2= src[i+1];
109     if(i+2<size) b3= src[i+2];
110       
111     b4= b1>>2;
112     b5= ((b1&0x3)<<4)|(b2>>4);
113     b6= ((b2&0xf)<<2)|(b3>>6);
114     b7= b3&0x3f;
115       
116     *p++= oauth_b64_encode(b4);
117     *p++= oauth_b64_encode(b5);
118       
119     if(i+1<size) *p++= oauth_b64_encode(b6);
120     else *p++= '=';
121       
122     if(i+2<size) *p++= oauth_b64_encode(b7);
123     else *p++= '=';
124   }
125   return out;
126 }
127
128 /**
129  * Decode the base64 encoded string 'src' into the memory pointed to by
130  * 'dest'. 
131  *
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.
137  */
138 int oauth_decode_base64(unsigned char *dest, const char *src) {
139   if(src && *src) {
140     unsigned char *p= dest;
141     int k, l= strlen(src)+1;
142     unsigned char *buf= (unsigned char*) xcalloc(sizeof(unsigned char), l);
143
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])) {
147         buf[l++]= src[k];
148       }
149     } 
150     
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;
154       c1= buf[k];
155
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];
159       
160       b1= oauth_b64_decode(c1);
161       b2= oauth_b64_decode(c2);
162       b3= oauth_b64_decode(c3);
163       b4= oauth_b64_decode(c4);
164       
165       *p++=((b1<<2)|(b2>>4) );
166       
167       if(c3 != '=') *p++=(((b2&0xf)<<4)|(b3>>2) );
168       if(c4 != '=') *p++=(((b3&0x3)<<6)|b4 );
169     }
170     xfree(buf);
171     dest[p-dest]='\0';
172     return(p-dest);
173   }
174   return 0;
175 }
176
177 /**
178  * Escape 'string' according to RFC3986 and
179  * http://oauth.net/core/1.0/#encoding_parameters.
180  *
181  * @param string The data to be encoded
182  * @return encoded string otherwise NULL
183  * The caller must free the returned string.
184  */
185 char *oauth_url_escape(const char *string) {
186   size_t alloc, newlen;
187   char *ns = NULL, *testing_ptr = NULL;
188   unsigned char in; 
189   size_t strindex=0;
190   size_t length;
191
192   if (!string) return xstrdup("");
193
194   alloc = strlen(string)+1;
195   newlen = alloc;
196
197   ns = (char*) xmalloc(alloc);
198
199   length = alloc-1;
200   while(length--) {
201     in = *string;
202
203     switch(in){
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 '-':
217       ns[strindex++]=in;
218       break;
219     default:
220       newlen += 2; /* this'll become a %XX */
221       if(newlen > alloc) {
222         alloc *= 2;
223         testing_ptr = (char*) xrealloc(ns, alloc);
224         ns = testing_ptr;
225       }
226       snprintf(&ns[strindex], 4, "%%%02X", in);
227       strindex+=3;
228       break;
229     }
230     string++;
231   }
232   ns[strindex]=0;
233   return ns;
234 }
235
236 #ifndef ISXDIGIT
237 # define ISXDIGIT(x) (isxdigit((int) ((unsigned char)x)))
238 #endif
239
240 /**
241  * Parse RFC3986 encoded 'string' back to  unescaped version.
242  *
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.
247  */
248 char *oauth_url_unescape(const char *string, size_t *olen) {
249   size_t alloc, strindex=0;
250   char *ns = NULL;
251   unsigned char in;
252   long hex;
253
254   if (!string) return NULL;
255   alloc = strlen(string)+1;
256   ns = (char*) xmalloc(alloc);
257
258   while(--alloc > 0) {
259     in = *string;
260     if(('%' == in) && ISXDIGIT(string[1]) && ISXDIGIT(string[2])) {
261       char hexstr[3]; // '%XX'
262       hexstr[0] = string[1];
263       hexstr[1] = string[2];
264       hexstr[2] = 0;
265       hex = strtol(hexstr, NULL, 16);
266       in = (unsigned char)hex; /* hex is always < 256 */
267       string+=2;
268       alloc-=2;
269     }
270     ns[strindex++] = in;
271     string++;
272   }
273   ns[strindex]=0;
274   if(olen) *olen = strindex;
275   return ns;
276 }
277
278 /**
279  * returns plaintext signature for the given key.
280  *
281  * the returned string needs to be freed by the caller
282  *
283  * @param m message to be signed
284  * @param k key used for signing
285  * @return signature string
286  */
287 char *oauth_sign_plaintext (const char *m, const char *k) {
288   return(xstrdup(k));
289 }
290
291 /**
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 *) 
296  *
297  * @param len the number of arguments to follow this parameter
298  * @param ... string to escape and added (may be NULL)
299  *
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.
303  */
304 char *oauth_catenc(int len, ...) {
305   va_list va;
306   int i;
307   char *rv = (char*) xmalloc(sizeof(char));
308   *rv='\0';
309   va_start(va, len);
310   for(i=0;i<len;i++) {
311     char *arg = va_arg(va, char *);
312     char *enc;
313     int len;
314     enc = oauth_url_escape(arg);
315     if(!enc) break;
316     len = strlen(enc) + 1 + ((i>0)?1:0);
317     len+=strlen(rv);
318     rv=(char*) xrealloc(rv,len*sizeof(char));
319
320     if(i>0) strcat(rv, "&");
321     strcat(rv, enc);
322     xfree(enc);
323   }
324   va_end(va);
325   return(rv);
326 }
327
328 /**
329  * splits the given url into a parameter array. 
330  * (see \ref oauth_serialize_url and \ref oauth_serialize_url_parameters for the reverse)
331  *
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)
340  *
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
345  *  by the caller.
346  * @param qesc use query parameter escape (vs post-param-escape) - if set
347  *        to 1 all '+' are treated as spaces ' '
348  * 
349  * @return number of parameter(s) in array.
350  */
351 int oauth_split_post_paramters(const char *url, char ***argv, short qesc) {
352   int argc=0;
353   char *token, *tmp, *t1;
354   if (!argv) return 0;
355   if (!url) return 0;
356   t1=xstrdup(url);
357
358   // '+' represents a space, in a URL query string
359   while ((qesc&1) && (tmp=strchr(t1,'+'))) *tmp=' ';
360
361   tmp=t1;
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);
368     else
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:[\/]*/
377 #if 0
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,'@'); 
381 #endif
382       if (slash && !strchr(slash,'/')) {
383 #ifdef DEBUG_OAUTH
384         fprintf(stderr, "\nliboauth: added trailing slash to URL: '%s'\n\n", token);
385 #endif
386         xfree((*argv)[argc]);
387         (*argv)[argc]= (char*) xmalloc(sizeof(char)*(2+strlen(token))); 
388         strcpy((*argv)[argc],token);
389         strcat((*argv)[argc],"/");
390       }
391     }
392     if (argc==0 && (tmp=strstr((*argv)[argc],":80/"))) {
393         memmove(tmp, tmp+3, strlen(tmp+2));
394     }
395     tmp=NULL;
396     argc++;
397   }
398
399   xfree(t1);
400   return argc;
401 }
402
403 int oauth_split_url_parameters(const char *url, char ***argv) {
404   return oauth_split_post_paramters(url, argv, 1);
405 }
406
407 /**
408  * build a url query string from an array.
409  *
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.
414  *
415  */
416 char *oauth_serialize_url (int argc, int start, char **argv) {
417   return oauth_serialize_url_sep( argc, start, argv, "&", 0);
418 }
419
420 /**
421  * encode query parameters from an array.
422  *
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.
432  */
433 char *oauth_serialize_url_sep (int argc, int start, char **argv, char *sep, int mod) {
434   char  *tmp, *t1;
435   int i;
436   int first=1;
437   int seplen=strlen(sep);
438   char *query = (char*) xmalloc(sizeof(char)); 
439   *query='\0';
440   for(i=start; i< argc; i++) {
441     int len = 0;
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;
444
445     len+=strlen(query);
446
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,' '))) {
451 # if 0
452         *t1='+';
453 # else
454         size_t off = t1-tmp;
455         char *t2 = (char*) xmalloc(sizeof(char)*(3+strlen(tmp)));
456         strcpy(t2, tmp);
457         strcpy(t2+off+2, tmp+off);
458         *(t2+off)='%'; *(t2+off+1)='2'; *(t2+off+2)='0';
459         xfree(tmp);
460         tmp=t2;
461 # endif
462 #endif
463       }
464       len+=strlen(tmp);
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));
470       strcat(tmp,"=");
471       len+=strlen(tmp);
472     } else {
473       *t1=0;
474       tmp = oauth_url_escape(argv[i]);
475       *t1='=';
476       t1 = oauth_url_escape((t1+1));
477       tmp=(char*) xrealloc(tmp,(strlen(tmp)+strlen(t1)+2+(mod&4?2:0))*sizeof(char));
478       strcat(tmp,"=");
479       if (mod&4) strcat(tmp,"\"");
480       strcat(tmp,t1);
481       if (mod&4) strcat(tmp,"\"");
482       xfree(t1);
483       len+=strlen(tmp);
484     }
485     len+=seplen+1;
486     query=(char*) xrealloc(query,len*sizeof(char));
487     strcat(query, ((i==start||first)?"":sep));
488     first=0;
489     strcat(query, tmp);
490     if (i==start && i==0 && strstr(tmp, ":/")) {
491       strcat(query, "?");
492       first=1;
493     }
494     xfree(tmp);
495   }
496   return (query);
497 }
498
499 /**
500  * build a query parameter string from an array.
501  *
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.
505  *
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.
509  */
510 char *oauth_serialize_url_parameters (int argc, char **argv) {
511   return oauth_serialize_url(argc, 1, argv);
512 }
513
514 /**
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
517  * caller
518  *
519  * @return zero terminated random string.
520  */
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() {
524   char *nc;
525   static int rndinit = 1;
526   const char *chars = "abcdefghijklmnopqrstuvwxyz"
527     "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789_";
528   unsigned int max = strlen( chars );
529   int i, len;
530
531   if(rndinit) {srand(time(NULL) 
532 #ifndef WIN32 // quick windows check.
533     * getpid()
534 #endif
535   ); rndinit=0;} // seed random number generator - FIXME: we can do better ;)
536
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 ];
541   }
542   nc[i]='\0';
543   return (nc);
544 }
545 #else // OpenSSL or NSS random number generator
546 #ifdef USE_NSS
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();
551 #else
552 #  ifdef _GNU_SOURCE
553 /* Note: the OpenSSL/GPL exemption stated 
554  * verbosely in hash.c applies to this code as well. */
555 #  endif
556 #  include <openssl/rand.h>
557 #  define MY_RAND RAND_bytes
558 #  define MY_SRAND ;
559 #endif
560 char *oauth_gen_nonce() {
561   char *nc;
562   unsigned char buf;
563   const char *chars = "abcdefghijklmnopqrstuvwxyz"
564     "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789_";
565   unsigned int max = strlen(chars);
566   int i, len;
567
568   MY_SRAND
569   MY_RAND(&buf, 1);
570   len=15+(((short)buf)&0x0f);
571   nc = (char*) xmalloc((len+1)*sizeof(char));
572   for(i=0;i<len; i++) {
573     MY_RAND(&buf, 1);
574     nc[i] = chars[ ((short)buf) % max ];
575   }
576   nc[i]='\0';
577   return (nc);
578 }
579 #endif
580
581 /**
582  * string compare function for oauth parameters.
583  *
584  * used with qsort. needed to normalize request parameters.
585  * see http://oauth.net/core/1.0/#anchor14
586  */
587 int oauth_cmpstringp(const void *p1, const void *p2) {
588   char *v1,*v2;
589   char *t1,*t2;
590   int rv;
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);
596
597   // '=' signs are not "%3D" !
598   if ((t1=strstr(v1,"%3D"))) {
599     t1[0]='\0'; t1[1]='='; t1[2]='=';
600   }
601   if ((t2=strstr(v2,"%3D"))) {
602     t2[0]='\0'; t2[1]='='; t2[2]='=';
603   }
604
605   // compare parameter names
606   rv=strcmp(v1,v2);
607   if (rv != 0) {
608     xfree(v1);
609     xfree(v2);
610     return rv;
611   }
612
613   // if parameter names are equal, sort by value.
614   if (t1) t1[0]='='; 
615   if (t2) t2[0]='='; 
616   if (t1 && t2)        rv=strcmp(t1,t2);
617   else if (!t1 && !t2) rv=0;
618   else if (!t1)        rv=-1;
619   else                 rv=1;
620
621   xfree(v1);
622   xfree(v2);
623   return rv;
624 }
625
626 /**
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.
631  *
632  * @return FALSE (0) if array does not contain a parameter with given key, TRUE (1) otherwise.
633  */
634 int oauth_param_exists(char **argv, int argc, char *key) {
635   int i;
636   size_t l= strlen(key);
637   for (i=0;i<argc;i++)
638     if (strlen(argv[i])>l && !strncmp(argv[i],key,l) && argv[i][l] == '=') return 1;
639   return 0;
640 }
641
642 /**
643  * add query parameter to array
644  *
645  * @param argcp pointer to array length int
646  * @param argvp pointer to array values 
647  * @param addparam parameter to add (eg. "foo=bar")
648  */
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);
652 }
653
654 /**
655  *
656  */
657 void oauth_add_protocol(int *argcp, char ***argvp, 
658   OAuthMethod method, 
659   const char *c_key, //< consumer key - posted plain text
660   const char *t_key //< token key - posted plain text in URL
661  ){
662   char oarg[1024];
663
664   // add OAuth specific arguments
665   if (!oauth_param_exists(*argvp,*argcp,"oauth_nonce")) {
666     char *tmp;
667     snprintf(oarg, 1024, "oauth_nonce=%s", (tmp=oauth_gen_nonce()));
668     oauth_add_param_to_array(argcp, argvp, oarg);
669     xfree(tmp);
670   }
671
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);
675   }
676
677   if (t_key) {
678     snprintf(oarg, 1024, "oauth_token=%s", t_key);
679     oauth_add_param_to_array(argcp, argvp, oarg);
680   }
681
682   snprintf(oarg, 1024, "oauth_consumer_key=%s", c_key);
683   oauth_add_param_to_array(argcp, argvp, oarg);
684
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);
688
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);
692   }
693
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);
698   }
699 #endif
700
701 }
702
703 char *oauth_sign_url (const char *url, char **postargs, 
704   OAuthMethod method, 
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
709   ) {
710   return oauth_sign_url2(url, postargs, 
711     method, NULL,
712     c_key, c_secret,
713     t_key, t_secret);
714
715
716 char *oauth_sign_url2 (const char *url, char **postargs, 
717   OAuthMethod method, 
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
723   ) {
724   int  argc;
725   char **argv = NULL;
726   char *rv;
727
728   if (postargs)
729     argc = oauth_split_post_paramters(url, &argv, 0);
730   else
731     argc = oauth_split_url_parameters(url, &argv);
732
733   rv=oauth_sign_array2(&argc, &argv, postargs, 
734     method, http_method,
735     c_key, c_secret, t_key, t_secret);
736
737   oauth_free_array(&argc, &argv);
738   return(rv);
739 }
740
741 char *oauth_sign_array (int *argcp, char***argvp,
742   char **postargs,
743   OAuthMethod method, 
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
748   ) {
749   return oauth_sign_array2 (argcp, argvp, 
750                             postargs, method,
751                             NULL,
752                             c_key, c_secret,
753                             t_key, t_secret);
754 }
755
756 void oauth_sign_array2_process (int *argcp, char***argvp,
757   char **postargs,
758   OAuthMethod method, 
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
764   ) {
765   char oarg[1024];
766   char *query;
767   char *okey, *odat, *sign;
768   char *http_request_method;
769
770   if (!http_method) {
771     http_request_method = xstrdup(postargs?"POST":"GET");
772   } else {
773     int i;
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]);
777   }
778
779   // add required OAuth protocol parameters
780   oauth_add_protocol(argcp, argvp, method, c_key, t_key);
781
782   // sort parameters
783   qsort(&(*argvp)[1], (*argcp)-1, sizeof(char *), oauth_cmpstringp);
784
785   // serialize URL - base-url 
786   query= oauth_serialize_url_parameters(*argcp, *argvp);
787
788   // prepare data to sign
789   if (method == OA_RSA) {
790     size_t len = 1;
791     if (c_secret) {
792       len += strlen(c_secret);
793     }
794     if (t_secret) {
795       len += strlen(t_secret);
796     }
797     okey = (char*)xmalloc(len * sizeof(char));
798     *okey = '\0';
799     if (c_secret) {
800       okey = strcat(okey, c_secret);
801     }
802     if (t_secret) {
803       okey = strcat(okey, t_secret);
804     }
805   } else {
806     okey = oauth_catenc(2, c_secret, t_secret);
807   }
808
809   odat = oauth_catenc(3, http_request_method, (*argvp)[0], query); // base-string
810   xfree(http_request_method);
811
812 #ifdef DEBUG_OAUTH
813   fprintf (stderr, "\nliboauth: data to sign='%s'\n\n", odat);
814   fprintf (stderr, "\nliboauth: key='%s'\n\n", okey);
815 #endif
816
817   // generate signature
818   switch(method) {
819     case OA_RSA:
820       sign = oauth_sign_rsa_sha1(odat,okey); // XXX okey needs to be RSA key!
821       break;
822     case OA_PLAINTEXT:
823       sign = oauth_sign_plaintext(odat,okey);
824       break;
825     default:
826       sign = oauth_sign_hmac_sha1(odat,okey);
827   }
828 #ifdef WIPE_MEMORY
829   memset(okey,0, strlen(okey));
830   memset(odat,0, strlen(odat));
831 #endif
832   xfree(odat);
833   xfree(okey);
834
835   // append signature to query args.
836   snprintf(oarg, 1024, "oauth_signature=%s",sign);
837   oauth_add_param_to_array(argcp, argvp, oarg);
838   xfree(sign);
839   if(query) xfree(query);
840 }
841
842 char *oauth_sign_array2 (int *argcp, char***argvp,
843   char **postargs,
844   OAuthMethod method, 
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
850   ) {
851
852   char *result;
853   oauth_sign_array2_process(argcp, argvp, postargs, method, http_method, c_key, c_secret, t_key, t_secret);
854
855   // build URL params
856   result = oauth_serialize_url(*argcp, (postargs?1:0), *argvp);
857
858   if(postargs) { 
859     *postargs = result;
860     result = xstrdup((*argvp)[0]);
861   }
862
863   return result;
864 }
865
866
867 /**
868  * free array args
869  *
870  * @param argcp pointer to array length int
871  * @param argvp pointer to array values to be xfree()d
872  */
873 void oauth_free_array(int *argcp, char ***argvp) {
874   int i;
875   for (i=0;i<(*argcp);i++) {
876     xfree((*argvp)[i]);
877   }
878   if(*argvp) xfree(*argvp);
879 }
880
881 /**
882  * base64 encode digest, free it and return a URL parameter
883  * with the oauth_body_hash
884  */
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);
889   xfree(sign);
890   xfree(digest);
891   return sig_url;
892 }
893
894
895 /**
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/ )
899  *
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
904  *
905  * returns 0 (false) if strings are not equal, and 1 (true) if strings are equal.
906  */
907 int oauth_time_independent_equals_n(const char* a, const char* b, size_t len_a, size_t len_b) {
908   int diff, i, j;
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;
913   j=0;
914   for (i=0; i<len_a; ++i) {
915     diff |= a[i] ^ b[j];
916     j = (j+1) % len_b;
917   }
918   return diff == 0;
919 }
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);
922 }
923
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);
926 }
927
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);
930 }
931
932 /**
933  * xep-0235 - TODO
934  */
935 char *oauth_sign_xmpp (const char *xml,
936   OAuthMethod method, 
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
939   ) {
940
941   return NULL;
942 }
943
944 // vi: sts=2 sw=2 ts=2