summaryrefslogtreecommitdiff
path: root/protocols/Twitter
diff options
context:
space:
mode:
authorVadim Dashevskiy <watcherhd@gmail.com>2012-06-27 08:42:01 +0000
committerVadim Dashevskiy <watcherhd@gmail.com>2012-06-27 08:42:01 +0000
commit76af3716fe56e728b2cad2df2bec7bb4a5b1c8df (patch)
treeb46e5d15976e4025ce28cd3371eb69d5d7aa9a65 /protocols/Twitter
parent09da3ed6d59beb5bc9bc34eba28e2fc4502415fb (diff)
oauth re-added
git-svn-id: http://svn.miranda-ng.org/main/trunk@650 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'protocols/Twitter')
-rw-r--r--protocols/Twitter/oauth/Makefile.am8
-rw-r--r--protocols/Twitter/oauth/hash.c492
-rw-r--r--protocols/Twitter/oauth/oauth.c921
-rw-r--r--protocols/Twitter/oauth/oauth.h764
-rw-r--r--protocols/Twitter/oauth/oauth_http.c728
-rw-r--r--protocols/Twitter/oauth/sha1.c317
-rw-r--r--protocols/Twitter/oauth/xmalloc.c60
-rw-r--r--protocols/Twitter/oauth/xmalloc.h10
8 files changed, 3300 insertions, 0 deletions
diff --git a/protocols/Twitter/oauth/Makefile.am b/protocols/Twitter/oauth/Makefile.am
new file mode 100644
index 0000000000..b59c7c71df
--- /dev/null
+++ b/protocols/Twitter/oauth/Makefile.am
@@ -0,0 +1,8 @@
+ACLOCAL_AMFLAGS= -I m4
+lib_LTLIBRARIES = liboauth.la
+include_HEADERS = oauth.h
+
+liboauth_la_SOURCES=oauth.c config.h hash.c xmalloc.c xmalloc.h oauth_http.c
+liboauth_la_LDFLAGS=@LIBOAUTH_LDFLAGS@ -version-info @VERSION_INFO@
+liboauth_la_LIBADD=@HASH_LIBS@ @CURL_LIBS@
+liboauth_la_CFLAGS=@LIBOAUTH_CFLAGS@ @HASH_CFLAGS@ @CURL_CFLAGS@
diff --git a/protocols/Twitter/oauth/hash.c b/protocols/Twitter/oauth/hash.c
new file mode 100644
index 0000000000..ca00adaa8c
--- /dev/null
+++ b/protocols/Twitter/oauth/hash.c
@@ -0,0 +1,492 @@
+/*
+ * hash algorithms used in OAuth
+ *
+ * Copyright 2007-2010 Robin Gareus <robin@gareus.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if USE_BUILTIN_HASH // built-in / AVR -- TODO: check license of sha1.c
+#include <stdio.h>
+#include "oauth.h" // oauth_encode_base64
+#include "xmalloc.h"
+
+#include "sha1.c" // TODO: sha1.h ; Makefile.am: add sha1.c
+
+/* API */
+char *oauth_sign_hmac_sha1_raw (const char *m, const size_t ml, const char *k, const size_t kl) {
+ sha1nfo s;
+ sha1_initHmac(&s, (const uint8_t*) k, kl);
+ sha1_write(&s, m, ml);
+ unsigned char *digest = sha1_resultHmac(&s);
+ return oauth_encode_base64(HASH_LENGTH, digest);
+}
+
+char *oauth_sign_hmac_sha1 (const char *m, const char *k) {
+ return(oauth_sign_hmac_sha1_raw (m, strlen(m), k, strlen(k)));
+}
+
+char *oauth_body_hash_file(char *filename) {
+ FILE *F= fopen(filename, "r");
+ if (!F) return NULL;
+
+ size_t len=0;
+ char fb[BUFSIZ];
+ sha1nfo s;
+ sha1_init(&s);
+
+ while (!feof(F) && (len=fread(fb,sizeof(char),BUFSIZ, F))>0) {
+ sha1_write(&s, fb, len);
+ }
+ fclose(F);
+
+ unsigned char *dgst = xmalloc(HASH_LENGTH*sizeof(char)); // oauth_body_hash_encode frees the digest..
+ memcpy(dgst, sha1_result(&s), HASH_LENGTH);
+ return oauth_body_hash_encode(HASH_LENGTH, dgst);
+}
+
+char *oauth_body_hash_data(size_t length, const char *data) {
+ sha1nfo s;
+ sha1_init(&s);
+ for (;length--;) sha1_writebyte(&s, *data++);
+
+ unsigned char *dgst = xmalloc(HASH_LENGTH*sizeof(char)); // oauth_body_hash_encode frees the digest..
+ memcpy(dgst, sha1_result(&s), HASH_LENGTH);
+ return oauth_body_hash_encode(HASH_LENGTH, dgst);
+}
+
+char *oauth_sign_rsa_sha1 (const char *m, const char *k) {
+ /* NOT RSA/PK11 support */
+ return xstrdup("---RSA/PK11-is-not-supported-by-this-version-of-liboauth---");
+}
+
+int oauth_verify_rsa_sha1 (const char *m, const char *c, const char *sig) {
+ /* NOT RSA/PK11 support */
+ return -1; // mismatch , error
+}
+
+#elif defined (USE_NSS)
+/* use http://www.mozilla.org/projects/security/pki/nss/ for hash/sign */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "xmalloc.h"
+#include "oauth.h" // oauth base64 encode fn's.
+
+// NSS includes
+#include "pk11pub.h"
+#include "nss.h"
+#include "base64.h"
+#include "keyhi.h"
+#include "cryptohi.h"
+#include "cert.h"
+
+#if 1 // work-around compiler-warning
+ // see http://bugzilla.mozilla.org/show_bug.cgi?id=243245#c3
+ extern CERTCertificate *
+ __CERT_DecodeDERCertificate (SECItem *derSignedCert, PRBool copyDER, char *nickname);
+#endif
+
+static const char NS_CERT_HEADER[] = "-----BEGIN CERTIFICATE-----";
+static const char NS_CERT_TRAILER[] = "-----END CERTIFICATE-----";
+static const char NS_PRIV_HEADER[] = "-----BEGIN PRIVATE KEY-----";
+static const char NS_PRIV_TRAILER[] = "-----END PRIVATE KEY-----";
+
+void oauth_init_nss() {
+ static short nss_initialized = 0;
+ if (!nss_initialized) { NSS_NoDB_Init("."); nss_initialized=1;}
+}
+
+/**
+ * Removes heading & trailing strings; used only internally.
+ * similar to NSS-source/nss/lib/pkcs7/certread.c
+ *
+ * the returned string (if not NULL) needs to be freed by the caller
+ */
+char *oauth_strip_pkcs(const char *txt, const char *h, const char *t) {
+ char *start, *end, *rv;
+ size_t len;
+ if ((start=strstr(txt, h))==NULL) return NULL;
+ start+=strlen(h);
+ while (*start=='\r' || *start=='\n') start++;
+ if ((end=strstr(start, t))==NULL) return NULL;
+ end--;
+ while (*end=='\r' || *end=='\n') end--;
+ len = end-start+2;
+ rv = xmalloc(len*sizeof(char));
+ memcpy(rv,start,len);
+ rv[len-1]='\0';
+ return rv;
+}
+
+char *oauth_sign_hmac_sha1 (const char *m, const char *k) {
+ return(oauth_sign_hmac_sha1_raw (m, strlen(m), k, strlen(k)));
+}
+
+char *oauth_sign_hmac_sha1_raw (const char *m, const size_t ml, const char *k, const size_t kl) {
+ PK11SlotInfo *slot = NULL;
+ PK11SymKey *pkey = NULL;
+ PK11Context *context = NULL;
+ unsigned char digest[20]; // Is there a way to tell how large the output is?
+ unsigned int len;
+ SECStatus s;
+ SECItem keyItem, noParams;
+ char *rv=NULL;
+
+ keyItem.type = siBuffer;
+ keyItem.data = (unsigned char*) k;
+ keyItem.len = kl;
+
+ noParams.type = siBuffer;
+ noParams.data = NULL;
+ noParams.len = 0;
+
+ oauth_init_nss();
+
+ slot = PK11_GetInternalKeySlot();
+ if (!slot) goto looser;
+ pkey = PK11_ImportSymKey(slot, CKM_SHA_1_HMAC, PK11_OriginUnwrap, CKA_SIGN, &keyItem, NULL);
+ if (!pkey) goto looser;
+ context = PK11_CreateContextBySymKey(CKM_SHA_1_HMAC, CKA_SIGN, pkey, &noParams);
+ if (!context) goto looser;
+
+ s = PK11_DigestBegin(context);
+ if (s != SECSuccess) goto looser;
+ s = PK11_DigestOp(context, (unsigned char*) m, ml);
+ if (s != SECSuccess) goto looser;
+ s = PK11_DigestFinal(context, digest, &len, sizeof digest);
+ if (s != SECSuccess) goto looser;
+
+ rv=oauth_encode_base64(len, digest);
+
+looser:
+ if (context) PK11_DestroyContext(context, PR_TRUE);
+ if (pkey) PK11_FreeSymKey(pkey);
+ if (slot) PK11_FreeSlot(slot);
+ return rv;
+}
+
+char *oauth_sign_rsa_sha1 (const char *m, const char *k) {
+ PK11SlotInfo *slot = NULL;
+ SECKEYPrivateKey *pkey = NULL;
+ SECItem signature;
+ SECStatus s;
+ SECItem der;
+ char *rv=NULL;
+
+ char *key = oauth_strip_pkcs(k, NS_PRIV_HEADER, NS_PRIV_TRAILER);
+ if (!key) return NULL;
+
+ oauth_init_nss();
+
+ slot = PK11_GetInternalKeySlot();
+ if (!slot) goto looser;
+ s = ATOB_ConvertAsciiToItem(&der, key);
+ if (s != SECSuccess) goto looser;
+ s = PK11_ImportDERPrivateKeyInfoAndReturnKey(slot, &der, NULL, NULL, PR_FALSE, PR_TRUE, KU_ALL, &pkey, NULL);
+ SECITEM_FreeItem(&der, PR_FALSE);
+ if (s != SECSuccess) goto looser;
+ if (!pkey) goto looser;
+ if (pkey->keyType != rsaKey) goto looser;
+ s = SEC_SignData(&signature, (unsigned char*) m, strlen(m), pkey, SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE);
+ if (s != SECSuccess) goto looser;
+
+ rv=oauth_encode_base64(signature.len, signature.data);
+ SECITEM_FreeItem(&signature, PR_FALSE);
+
+looser:
+ if (pkey) SECKEY_DestroyPrivateKey(pkey);
+ if (slot) PK11_FreeSlot(slot);
+ free(key);
+ return rv;
+}
+
+int oauth_verify_rsa_sha1 (const char *m, const char *c, const char *sig) {
+ PK11SlotInfo *slot = NULL;
+ SECKEYPublicKey *pkey = NULL;
+ CERTCertificate *cert = NULL;
+ SECItem signature;
+ SECStatus s;
+ SECItem der;
+ int rv=0;
+
+ char *key = oauth_strip_pkcs(c, NS_CERT_HEADER, NS_CERT_TRAILER);
+ if (!key) return 0;
+
+ oauth_init_nss();
+
+ s = ATOB_ConvertAsciiToItem(&signature, (char*) sig); // XXX cast (const char*) -> (char*)
+ if (s != SECSuccess) goto looser;
+ slot = PK11_GetInternalKeySlot();
+ if (!slot) goto looser;
+ s = ATOB_ConvertAsciiToItem(&der, key);
+ if (s != SECSuccess) goto looser;
+ cert = __CERT_DecodeDERCertificate(&der, PR_TRUE, NULL);
+ SECITEM_FreeItem(&der, PR_FALSE);
+ if (!cert) goto looser;
+ pkey = CERT_ExtractPublicKey(cert);
+ if (!pkey) goto looser;
+ if (pkey->keyType != rsaKey) goto looser;
+
+ s = VFY_VerifyData((unsigned char*) m, strlen(m), pkey, &signature, SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE, NULL);
+ if (s == SECSuccess) rv=1;
+#if 0
+ else if (PR_GetError()!= SEC_ERROR_BAD_SIGNATURE) rv=-1;
+#endif
+
+looser:
+ if (pkey) SECKEY_DestroyPublicKey(pkey);
+ if (slot) PK11_FreeSlot(slot);
+ free(key);
+ return rv;
+}
+
+char *oauth_body_hash_file(char *filename) {
+ PK11SlotInfo *slot = NULL;
+ PK11Context *context = NULL;
+ unsigned char digest[20]; // Is there a way to tell how large the output is?
+ unsigned int len;
+ SECStatus s;
+ char *rv=NULL;
+ size_t bl;
+ unsigned char fb[BUFSIZ];
+
+ FILE *F= fopen(filename, "r");
+ if (!F) return NULL;
+
+ oauth_init_nss();
+
+ slot = PK11_GetInternalKeySlot();
+ if (!slot) goto looser;
+ context = PK11_CreateDigestContext(SEC_OID_SHA1);
+ if (!context) goto looser;
+
+ s = PK11_DigestBegin(context);
+ if (s != SECSuccess) goto looser;
+ while (!feof(F) && (bl=fread(fb,sizeof(char),BUFSIZ, F))>0) {
+ s = PK11_DigestOp(context, (unsigned char*) fb, bl);
+ if (s != SECSuccess) goto looser;
+ }
+ s = PK11_DigestFinal(context, digest, &len, sizeof digest);
+ if (s != SECSuccess) goto looser;
+
+ unsigned char *dgst = xmalloc(len*sizeof(char)); // oauth_body_hash_encode frees the digest..
+ memcpy(dgst, digest, len);
+ rv=oauth_body_hash_encode(len, dgst);
+
+looser:
+ fclose(F);
+ if (context) PK11_DestroyContext(context, PR_TRUE);
+ if (slot) PK11_FreeSlot(slot);
+ return rv;
+}
+
+char *oauth_body_hash_data(size_t length, const char *data) {
+ PK11SlotInfo *slot = NULL;
+ PK11Context *context = NULL;
+ unsigned char digest[20]; // Is there a way to tell how large the output is?
+ unsigned int len;
+ SECStatus s;
+ char *rv=NULL;
+
+ oauth_init_nss();
+
+ slot = PK11_GetInternalKeySlot();
+ if (!slot) goto looser;
+ context = PK11_CreateDigestContext(SEC_OID_SHA1);
+ if (!context) goto looser;
+
+ s = PK11_DigestBegin(context);
+ if (s != SECSuccess) goto looser;
+ s = PK11_DigestOp(context, (unsigned char*) data, length);
+ if (s != SECSuccess) goto looser;
+ s = PK11_DigestFinal(context, digest, &len, sizeof digest);
+ if (s != SECSuccess) goto looser;
+
+ unsigned char *dgst = xmalloc(len*sizeof(char)); // oauth_body_hash_encode frees the digest..
+ memcpy(dgst, digest, len);
+ rv=oauth_body_hash_encode(len, dgst);
+
+looser:
+ if (context) PK11_DestroyContext(context, PR_TRUE);
+ if (slot) PK11_FreeSlot(slot);
+ return rv;
+}
+
+#else
+/* use http://www.openssl.org/ for hash/sign */
+
+#ifdef _GNU_SOURCE
+/*
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "xmalloc.h"
+#include "oauth.h" // base64 encode fn's.
+#include <openssl/hmac.h>
+
+char *oauth_sign_hmac_sha1 (const char *m, const char *k) {
+ return(oauth_sign_hmac_sha1_raw (m, strlen(m), k, strlen(k)));
+}
+
+char *oauth_sign_hmac_sha1_raw (const char *m, const size_t ml, const char *k, const size_t kl) {
+ unsigned char result[EVP_MAX_MD_SIZE];
+ unsigned int resultlen = 0;
+
+ HMAC(EVP_sha1(), k, kl,
+ (unsigned char*) m, ml,
+ result, &resultlen);
+
+ return(oauth_encode_base64(resultlen, result));
+}
+
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/ssl.h>
+
+char *oauth_sign_rsa_sha1 (const char *m, const char *k) {
+ unsigned char *sig = NULL;
+ unsigned char *passphrase = NULL;
+ unsigned int len=0;
+ EVP_MD_CTX md_ctx;
+
+ EVP_PKEY *pkey;
+ BIO *in;
+ in = BIO_new_mem_buf((unsigned char*) k, strlen(k));
+ pkey = PEM_read_bio_PrivateKey(in, NULL, 0, passphrase); // generate sign
+ BIO_free(in);
+
+ if (pkey == NULL) {
+ //fprintf(stderr, "liboauth/OpenSSL: can not read private key\n");
+ return xstrdup("liboauth/OpenSSL: can not read private key");
+ }
+
+ len = EVP_PKEY_size(pkey);
+ sig = (unsigned char*)xmalloc((len+1)*sizeof(char));
+
+ EVP_SignInit(&md_ctx, EVP_sha1());
+ EVP_SignUpdate(&md_ctx, m, strlen(m));
+ if (EVP_SignFinal (&md_ctx, sig, &len, pkey)) {
+ char *tmp;
+ sig[len] = '\0';
+ tmp = oauth_encode_base64(len,sig);
+ OPENSSL_free(sig);
+ EVP_PKEY_free(pkey);
+ return tmp;
+ }
+ return xstrdup("liboauth/OpenSSL: rsa-sha1 signing failed");
+}
+
+int oauth_verify_rsa_sha1 (const char *m, const char *c, const char *s) {
+ EVP_MD_CTX md_ctx;
+ EVP_PKEY *pkey;
+ BIO *in;
+ X509 *cert = NULL;
+ unsigned char *b64d;
+ int slen, err;
+
+ in = BIO_new_mem_buf((unsigned char*)c, strlen(c));
+ cert = PEM_read_bio_X509(in, NULL, 0, NULL);
+ if (cert) {
+ pkey = (EVP_PKEY *) X509_get_pubkey(cert);
+ X509_free(cert);
+ } else {
+ pkey = PEM_read_bio_PUBKEY(in, NULL, 0, NULL);
+ }
+ BIO_free(in);
+ if (pkey == NULL) {
+ //fprintf(stderr, "could not read cert/pubkey.\n");
+ return -2;
+ }
+
+ b64d= (unsigned char*) xmalloc(sizeof(char)*strlen(s));
+ slen = oauth_decode_base64(b64d, s);
+
+ EVP_VerifyInit(&md_ctx, EVP_sha1());
+ EVP_VerifyUpdate(&md_ctx, m, strlen(m));
+ err = EVP_VerifyFinal(&md_ctx, b64d, slen, pkey);
+ EVP_MD_CTX_cleanup(&md_ctx);
+ EVP_PKEY_free(pkey);
+ free(b64d);
+ return (err);
+}
+
+
+/**
+ * http://oauth.googlecode.com/svn/spec/ext/body_hash/1.0/oauth-bodyhash.html
+ */
+char *oauth_body_hash_file(char *filename) {
+ unsigned char fb[BUFSIZ];
+ EVP_MD_CTX ctx;
+ size_t len=0;
+ unsigned char *md;
+ FILE *F= fopen(filename, "r");
+ if (!F) return NULL;
+
+ EVP_MD_CTX_init(&ctx);
+ EVP_DigestInit(&ctx,EVP_sha1());
+ while (!feof(F) && (len=fread(fb,sizeof(char),BUFSIZ, F))>0) {
+ EVP_DigestUpdate(&ctx, fb, len);
+ }
+ fclose(F);
+ len=0;
+ md=(unsigned char*) xcalloc(EVP_MD_size(EVP_sha1()),sizeof(unsigned char));
+ EVP_DigestFinal(&ctx, md,(unsigned int*) &len);
+ EVP_MD_CTX_cleanup(&ctx);
+ return oauth_body_hash_encode(len, md);
+}
+
+char *oauth_body_hash_data(size_t length, const char *data) {
+ EVP_MD_CTX ctx;
+ size_t len=0;
+ unsigned char *md;
+ md=(unsigned char*) xcalloc(EVP_MD_size(EVP_sha1()),sizeof(unsigned char));
+ EVP_MD_CTX_init(&ctx);
+ EVP_DigestInit(&ctx,EVP_sha1());
+ EVP_DigestUpdate(&ctx, data, length);
+ EVP_DigestFinal(&ctx, md,(unsigned int*) &len);
+ EVP_MD_CTX_cleanup(&ctx);
+ return oauth_body_hash_encode(len, md);
+}
+
+#endif
+
+// vi: sts=2 sw=2 ts=2
diff --git a/protocols/Twitter/oauth/oauth.c b/protocols/Twitter/oauth/oauth.c
new file mode 100644
index 0000000000..0f205572dd
--- /dev/null
+++ b/protocols/Twitter/oauth/oauth.c
@@ -0,0 +1,921 @@
+/*
+ * OAuth string functions in POSIX-C.
+ *
+ * Copyright 2007-2011 Robin Gareus <robin@gareus.org>
+ *
+ * The base64 functions are by Jan-Henrik Haukeland, <hauk@tildeslash.com>
+ * and un/escape_url() was inspired by libcurl's curl_escape under ISC-license
+ * many thanks to Daniel Stenberg <daniel@haxx.se>.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#define WIPE_MEMORY ///< overwrite sensitve data before free()ing it.
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <math.h>
+#include <ctype.h> // isxdigit
+
+#include "xmalloc.h"
+#include "oauth.h"
+
+#ifndef WIN32 // getpid() on POSIX systems
+#include <sys/types.h>
+#include <unistd.h>
+#else
+#define snprintf _snprintf
+#define strncasecmp strnicmp
+#endif
+
+/**
+ * Base64 encode one byte
+ */
+char oauth_b64_encode(unsigned char u) {
+ if(u < 26) return 'A'+u;
+ if(u < 52) return 'a'+(u-26);
+ if(u < 62) return '0'+(u-52);
+ if(u == 62) return '+';
+ return '/';
+}
+
+/**
+ * Decode a single base64 character.
+ */
+unsigned char oauth_b64_decode(char c) {
+ if(c >= 'A' && c <= 'Z') return(c - 'A');
+ if(c >= 'a' && c <= 'z') return(c - 'a' + 26);
+ if(c >= '0' && c <= '9') return(c - '0' + 52);
+ if(c == '+') return 62;
+ return 63;
+}
+
+/**
+ * Return TRUE if 'c' is a valid base64 character, otherwise FALSE
+ */
+int oauth_b64_is_base64(char c) {
+ if((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
+ (c >= '0' && c <= '9') || (c == '+') ||
+ (c == '/') || (c == '=')) {
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * Base64 encode and return size data in 'src'. The caller must free the
+ * returned string.
+ *
+ * @param size The size of the data in src
+ * @param src The data to be base64 encode
+ * @return encoded string otherwise NULL
+ */
+char *oauth_encode_base64(int size, const unsigned char *src) {
+ int i;
+ char *out, *p;
+
+ if(!src) return NULL;
+ if(!size) size= strlen((char *)src);
+ out= (char*) xcalloc(sizeof(char), size*4/3+4);
+ p= out;
+
+ for(i=0; i<size; i+=3) {
+ unsigned char b1=0, b2=0, b3=0, b4=0, b5=0, b6=0, b7=0;
+ b1= src[i];
+ if(i+1<size) b2= src[i+1];
+ if(i+2<size) b3= src[i+2];
+
+ b4= b1>>2;
+ b5= ((b1&0x3)<<4)|(b2>>4);
+ b6= ((b2&0xf)<<2)|(b3>>6);
+ b7= b3&0x3f;
+
+ *p++= oauth_b64_encode(b4);
+ *p++= oauth_b64_encode(b5);
+
+ if(i+1<size) *p++= oauth_b64_encode(b6);
+ else *p++= '=';
+
+ if(i+2<size) *p++= oauth_b64_encode(b7);
+ else *p++= '=';
+ }
+ return out;
+}
+
+/**
+ * Decode the base64 encoded string 'src' into the memory pointed to by
+ * 'dest'.
+ *
+ * @param dest Pointer to memory for holding the decoded string.
+ * Must be large enough to receive the decoded string.
+ * @param src A base64 encoded string.
+ * @return the length of the decoded string if decode
+ * succeeded otherwise 0.
+ */
+int oauth_decode_base64(unsigned char *dest, const char *src) {
+ if(src && *src) {
+ unsigned char *p= dest;
+ int k, l= strlen(src)+1;
+ unsigned char *buf= (unsigned char*) xcalloc(sizeof(unsigned char), l);
+
+ /* Ignore non base64 chars as per the POSIX standard */
+ for(k=0, l=0; src[k]; k++) {
+ if(oauth_b64_is_base64(src[k])) {
+ buf[l++]= src[k];
+ }
+ }
+
+ for(k=0; k<l; k+=4) {
+ char c1='A', c2='A', c3='A', c4='A';
+ unsigned char b1=0, b2=0, b3=0, b4=0;
+ c1= buf[k];
+
+ if(k+1<l) c2= buf[k+1];
+ if(k+2<l) c3= buf[k+2];
+ if(k+3<l) c4= buf[k+3];
+
+ b1= oauth_b64_decode(c1);
+ b2= oauth_b64_decode(c2);
+ b3= oauth_b64_decode(c3);
+ b4= oauth_b64_decode(c4);
+
+ *p++=((b1<<2)|(b2>>4) );
+
+ if(c3 != '=') *p++=(((b2&0xf)<<4)|(b3>>2) );
+ if(c4 != '=') *p++=(((b3&0x3)<<6)|b4 );
+ }
+ free(buf);
+ dest[p-dest]='\0';
+ return(p-dest);
+ }
+ return 0;
+}
+
+/**
+ * Escape 'string' according to RFC3986 and
+ * http://oauth.net/core/1.0/#encoding_parameters.
+ *
+ * @param string The data to be encoded
+ * @return encoded string otherwise NULL
+ * The caller must free the returned string.
+ */
+char *oauth_url_escape(const char *string) {
+ size_t alloc, newlen;
+ char *ns = NULL, *testing_ptr = NULL;
+ unsigned char in;
+ size_t strindex=0;
+ size_t length;
+
+ if (!string) return xstrdup("");
+
+ alloc = strlen(string)+1;
+ newlen = alloc;
+
+ ns = (char*) xmalloc(alloc);
+
+ length = alloc-1;
+ while(length--) {
+ in = *string;
+
+ switch(in){
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case 'a': case 'b': case 'c': case 'd': case 'e':
+ case 'f': case 'g': case 'h': case 'i': case 'j':
+ case 'k': case 'l': case 'm': case 'n': case 'o':
+ case 'p': case 'q': case 'r': case 's': case 't':
+ case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
+ case 'A': case 'B': case 'C': case 'D': case 'E':
+ case 'F': case 'G': case 'H': case 'I': case 'J':
+ case 'K': case 'L': case 'M': case 'N': case 'O':
+ case 'P': case 'Q': case 'R': case 'S': case 'T':
+ case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z':
+ case '_': case '~': case '.': case '-':
+ ns[strindex++]=in;
+ break;
+ default:
+ newlen += 2; /* this'll become a %XX */
+ if(newlen > alloc) {
+ alloc *= 2;
+ testing_ptr = (char*) xrealloc(ns, alloc);
+ ns = testing_ptr;
+ }
+ snprintf(&ns[strindex], 4, "%%%02X", in);
+ strindex+=3;
+ break;
+ }
+ string++;
+ }
+ ns[strindex]=0;
+ return ns;
+}
+
+#ifndef ISXDIGIT
+# define ISXDIGIT(x) (isxdigit((int) ((unsigned char)x)))
+#endif
+
+/**
+ * Parse RFC3986 encoded 'string' back to unescaped version.
+ *
+ * @param string The data to be unescaped
+ * @param olen unless NULL the length of the returned string is stored there.
+ * @return decoded string or NULL
+ * The caller must free the returned string.
+ */
+char *oauth_url_unescape(const char *string, size_t *olen) {
+ size_t alloc, strindex=0;
+ char *ns = NULL;
+ unsigned char in;
+ long hex;
+
+ if (!string) return NULL;
+ alloc = strlen(string)+1;
+ ns = (char*) xmalloc(alloc);
+
+ while(--alloc > 0) {
+ in = *string;
+ if(('%' == in) && ISXDIGIT(string[1]) && ISXDIGIT(string[2])) {
+ char hexstr[3]; // '%XX'
+ hexstr[0] = string[1];
+ hexstr[1] = string[2];
+ hexstr[2] = 0;
+ hex = strtol(hexstr, NULL, 16);
+ in = (unsigned char)hex; /* hex is always < 256 */
+ string+=2;
+ alloc-=2;
+ }
+ ns[strindex++] = in;
+ string++;
+ }
+ ns[strindex]=0;
+ if(olen) *olen = strindex;
+ return ns;
+}
+
+/**
+ * returns plaintext signature for the given key.
+ *
+ * the returned string needs to be freed by the caller
+ *
+ * @param m message to be signed
+ * @param k key used for signing
+ * @return signature string
+ */
+char *oauth_sign_plaintext (const char *m, const char *k) {
+ return(oauth_url_escape(k));
+}
+
+/**
+ * encode strings and concatenate with '&' separator.
+ * The number of strings to be concatenated must be
+ * given as first argument.
+ * all arguments thereafter must be of type (char *)
+ *
+ * @param len the number of arguments to follow this parameter
+ * @param ... string to escape and added (may be NULL)
+ *
+ * @return pointer to memory holding the concatenated
+ * strings - needs to be free(d) by the caller. or NULL
+ * in case we ran out of memory.
+ */
+char *oauth_catenc(int len, ...) {
+ va_list va;
+ int i;
+ char *rv = (char*) xmalloc(sizeof(char));
+ *rv='\0';
+ va_start(va, len);
+ for(i=0;i<len;i++) {
+ char *arg = va_arg(va, char *);
+ char *enc;
+ int len;
+ enc = oauth_url_escape(arg);
+ if(!enc) break;
+ len = strlen(enc) + 1 + ((i>0)?1:0);
+ if(rv) len+=strlen(rv);
+ rv=(char*) xrealloc(rv,len*sizeof(char));
+
+ if(i>0) strcat(rv, "&");
+ strcat(rv, enc);
+ free(enc);
+ }
+ va_end(va);
+ return(rv);
+}
+
+/**
+ * splits the given url into a parameter array.
+ * (see \ref oauth_serialize_url and \ref oauth_serialize_url_parameters for the reverse)
+ *
+ * NOTE: Request-parameters-values may include an ampersand character.
+ * However if unescaped this function will use them as parameter delimiter.
+ * If you need to make such a request, this function since version 0.3.5 allows
+ * to use the ASCII SOH (0x01) character as alias for '&' (0x26).
+ * (the motivation is convenience: SOH is /untypeable/ and much more
+ * unlikely to appear than '&' - If you plan to sign fancy URLs you
+ * should not split a query-string, but rather provide the parameter array
+ * directly to \ref oauth_serialize_url)
+ *
+ * @param url the url or query-string to parse.
+ * @param argv pointer to a (char *) array where the results are stored.
+ * The array is re-allocated to match the number of parameters and each
+ * parameter-string is allocated with strdup. - The memory needs to be freed
+ * by the caller.
+ * @param qesc use query parameter escape (vs post-param-escape) - if set
+ * to 1 all '+' are treated as spaces ' '
+ *
+ * @return number of parameter(s) in array.
+ */
+int oauth_split_post_paramters(const char *url, char ***argv, short qesc) {
+ int argc=0;
+ char *token, *tmp, *t1;
+ if (!argv) return 0;
+ if (!url) return 0;
+ t1=xstrdup(url);
+
+ // '+' represents a space, in a URL query string
+ while ((qesc&1) && (tmp=strchr(t1,'+'))) *tmp=' ';
+
+ tmp=t1;
+ while((token=strtok(tmp,"&?"))) {
+ if(!strncasecmp("oauth_signature=",token,16)) continue;
+ (*argv)=(char**) xrealloc(*argv,sizeof(char*)*(argc+1));
+ while (!(qesc&2) && (tmp=strchr(token,'\001'))) *tmp='&';
+ if (argc>0 || (qesc&4))
+ (*argv)[argc]=oauth_url_unescape(token, NULL);
+ else
+ (*argv)[argc]=xstrdup(token);
+ if (argc==0 && strstr(token, ":/")) {
+ // HTTP does not allow empty absolute paths, so the URL
+ // 'http://example.com' is equivalent to 'http://example.com/' and should
+ // be treated as such for the purposes of OAuth signing (rfc2616, section 3.2.1)
+ // see http://groups.google.com/group/oauth/browse_thread/thread/c44b6f061bfd98c?hl=en
+ char *slash=strstr(token, ":/");
+ while (slash && *(++slash) == '/') ; // skip slashes eg /xxx:[\/]*/
+#if 0
+ // skip possibly unescaped slashes in the userinfo - they're not allowed by RFC2396 but have been seen.
+ // the hostname/IP may only contain alphanumeric characters - so we're safe there.
+ if (slash && strchr(slash,'@')) slash=strchr(slash,'@');
+#endif
+ if (slash && !strchr(slash,'/')) {
+#ifdef DEBUG_OAUTH
+ fprintf(stderr, "\nliboauth: added trailing slash to URL: '%s'\n\n", token);
+#endif
+ free((*argv)[argc]);
+ (*argv)[argc]= (char*) xmalloc(sizeof(char)*(2+strlen(token)));
+ strcpy((*argv)[argc],token);
+ strcat((*argv)[argc],"/");
+ }
+ }
+ if (argc==0 && (tmp=strstr((*argv)[argc],":80/"))) {
+ memmove(tmp, tmp+3, strlen(tmp+2));
+ }
+ tmp=NULL;
+ argc++;
+ }
+
+ free(t1);
+ return argc;
+}
+
+int oauth_split_url_parameters(const char *url, char ***argv) {
+ return oauth_split_post_paramters(url, argv, 1);
+}
+
+/**
+ * build a url query string from an array.
+ *
+ * @param argc the total number of elements in the array
+ * @param start element in the array at which to start concatenating.
+ * @param argv parameter-array to concatenate.
+ * @return url string needs to be freed by the caller.
+ *
+ */
+char *oauth_serialize_url (int argc, int start, char **argv) {
+ return oauth_serialize_url_sep( argc, start, argv, "&", 0);
+}
+
+/**
+ * encode query parameters from an array.
+ *
+ * @param argc the total number of elements in the array
+ * @param start element in the array at which to start concatenating.
+ * @param argv parameter-array to concatenate.
+ * @param sep separator for parameters (usually "&")
+ * @param mod - bitwise modifiers:
+ * 1: skip all values that start with "oauth_"
+ * 2: skip all values that don't start with "oauth_"
+ * 4: add double quotation marks around values (use with sep=", " to generate HTTP Authorization header).
+ * @return url string needs to be freed by the caller.
+ */
+char *oauth_serialize_url_sep (int argc, int start, char **argv, char *sep, int mod) {
+ char *tmp, *t1;
+ int i;
+ int first=1;
+ int seplen=strlen(sep);
+ char *query = (char*) xmalloc(sizeof(char));
+ *query='\0';
+ for(i=start; i< argc; i++) {
+ int len = 0;
+ if ((mod&1)==1 && (strncmp(argv[i],"oauth_",6) == 0 || strncmp(argv[i],"x_oauth_",8) == 0) ) continue;
+ if ((mod&2)==2 && (strncmp(argv[i],"oauth_",6) != 0 && strncmp(argv[i],"x_oauth_",8) != 0) && i!=0) continue;
+
+ if (query) len+=strlen(query);
+
+ if (i==start && i==0 && strstr(argv[i], ":/")) {
+ tmp=xstrdup(argv[i]);
+#if 1 // encode white-space in the base-url
+ while ((t1=strchr(tmp,' '))) {
+# if 0
+ *t1='+';
+# else
+ size_t off = t1-tmp;
+ char *t2 = (char*) xmalloc(sizeof(char)*(3+strlen(tmp)));
+ strcpy(t2, tmp);
+ strcpy(t2+off+2, tmp+off);
+ *(t2+off)='%'; *(t2+off+1)='2'; *(t2+off+2)='0';
+ free(tmp);
+ tmp=t2;
+# endif
+#endif
+ }
+ len+=strlen(tmp);
+ } else if(!(t1=strchr(argv[i], '='))) {
+ // see http://oauth.net/core/1.0/#anchor14
+ // escape parameter names and arguments but not the '='
+ tmp=xstrdup(argv[i]);
+ tmp=(char*) xrealloc(tmp,(strlen(tmp)+2)*sizeof(char));
+ strcat(tmp,"=");
+ len+=strlen(tmp);
+ } else {
+ *t1=0;
+ tmp = oauth_url_escape(argv[i]);
+ *t1='=';
+ t1 = oauth_url_escape((t1+1));
+ tmp=(char*) xrealloc(tmp,(strlen(tmp)+strlen(t1)+2+(mod&4?2:0))*sizeof(char));
+ strcat(tmp,"=");
+ if (mod&4) strcat(tmp,"\"");
+ strcat(tmp,t1);
+ if (mod&4) strcat(tmp,"\"");
+ free(t1);
+ len+=strlen(tmp);
+ }
+ len+=seplen+1;
+ query=(char*) xrealloc(query,len*sizeof(char));
+ strcat(query, ((i==start||first)?"":sep));
+ first=0;
+ strcat(query, tmp);
+ if (i==start && i==0 && strstr(tmp, ":/")) {
+ strcat(query, "?");
+ first=1;
+ }
+ free(tmp);
+ }
+ return (query);
+}
+
+/**
+ * build a query parameter string from an array.
+ *
+ * This function is a shortcut for \ref oauth_serialize_url (argc, 1, argv).
+ * It strips the leading host/path, which is usually the first
+ * element when using oauth_split_url_parameters on an URL.
+ *
+ * @param argc the total number of elements in the array
+ * @param argv parameter-array to concatenate.
+ * @return url string needs to be freed by the caller.
+ */
+char *oauth_serialize_url_parameters (int argc, char **argv) {
+ return oauth_serialize_url(argc, 1, argv);
+}
+
+/**
+ * generate a random string between 15 and 32 chars length
+ * and return a pointer to it. The value needs to be freed by the
+ * caller
+ *
+ * @return zero terminated random string.
+ */
+#if !defined HAVE_OPENSSL_HMAC_H && !defined USE_NSS
+/* pre liboauth-0.7.2 and possible future versions that don't use OpenSSL or NSS */
+char *oauth_gen_nonce() {
+ char *nc;
+ static int rndinit = 1;
+ const char *chars = "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789_";
+ unsigned int max = strlen( chars );
+ int i, len;
+
+ if(rndinit) {srand(time(NULL)
+#ifndef WIN32 // quick windows check.
+ * getpid()
+#endif
+ ); rndinit=0;} // seed random number generator - FIXME: we can do better ;)
+
+ len=15+floor(rand()*16.0/(double)RAND_MAX);
+ nc = (char*) xmalloc((len+1)*sizeof(char));
+ for(i=0;i<len; i++) {
+ nc[i] = chars[ rand() % max ];
+ }
+ nc[i]='\0';
+ return (nc);
+}
+#else // OpenSSL or NSS random number generator
+#ifdef USE_NSS
+ void oauth_init_nss(); //decladed in hash.c
+# include "pk11pub.h"
+# define MY_RAND PK11_GenerateRandom
+# define MY_SRAND oauth_init_nss();
+#else
+# ifdef _GNU_SOURCE
+/* Note: the OpenSSL/GPL exemption stated
+ * verbosely in hash.c applies to this code as well. */
+# endif
+# include <openssl/rand.h>
+# define MY_RAND RAND_bytes
+# define MY_SRAND ;
+#endif
+char *oauth_gen_nonce() {
+ char *nc;
+ unsigned char buf;
+ const char *chars = "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789_";
+ unsigned int max = strlen(chars);
+ int i, len;
+
+ MY_SRAND
+ MY_RAND(&buf, 1);
+ len=15+(((short)buf)&0x0f);
+ nc = (char*) xmalloc((len+1)*sizeof(char));
+ for(i=0;i<len; i++) {
+ MY_RAND(&buf, 1);
+ nc[i] = chars[ ((short)buf) % max ];
+ }
+ nc[i]='\0';
+ return (nc);
+}
+#endif
+
+/**
+ * string compare function for oauth parameters.
+ *
+ * used with qsort. needed to normalize request parameters.
+ * see http://oauth.net/core/1.0/#anchor14
+ */
+int oauth_cmpstringp(const void *p1, const void *p2) {
+ char *v1,*v2;
+ char *t1,*t2;
+ int rv;
+ // TODO: this is not fast - we should escape the
+ // array elements (once) before sorting.
+ v1=oauth_url_escape(* (char * const *)p1);
+ v2=oauth_url_escape(* (char * const *)p2);
+
+ // '=' signs are not "%3D" !
+ if ((t1=strstr(v1,"%3D"))) {
+ t1[0]='\0'; t1[1]='='; t1[2]='=';
+ }
+ if ((t2=strstr(v2,"%3D"))) {
+ t2[0]='\0'; t2[1]='='; t2[2]='=';
+ }
+
+ // compare parameter names
+ rv=strcmp(v1,v2);
+ if (rv!=0) {
+ if (v1) free(v1);
+ if (v2) free(v2);
+ return rv;
+ }
+
+ // if parameter names are equal, sort by value.
+ if (t1) t1[0]='=';
+ if (t2) t2[0]='=';
+ if (t1 && t2) rv=strcmp(t1,t2);
+ else if (!t1 && !t2) rv=0;
+ else if (!t1) rv=-1;
+ else rv=1;
+
+ if (v1) free(v1);
+ if (v2) free(v2);
+ return rv;
+}
+
+/**
+ * search array for parameter key.
+ * @param argv length of array to search
+ * @param argc parameter array to search
+ * @param key key of parameter to check.
+ *
+ * @return FALSE (0) if array does not contain a parameter with given key, TRUE (1) otherwise.
+ */
+int oauth_param_exists(char **argv, int argc, char *key) {
+ int i;
+ size_t l= strlen(key);
+ for (i=0;i<argc;i++)
+ if (strlen(argv[i])>l && !strncmp(argv[i],key,l) && argv[i][l] == '=') return 1;
+ return 0;
+}
+
+/**
+ * add query parameter to array
+ *
+ * @param argcp pointer to array length int
+ * @param argvp pointer to array values
+ * @param addparam parameter to add (eg. "foo=bar")
+ */
+void oauth_add_param_to_array(int *argcp, char ***argvp, const char *addparam) {
+ (*argvp)=(char**) xrealloc(*argvp,sizeof(char*)*((*argcp)+1));
+ (*argvp)[(*argcp)++]= (char*) xstrdup(addparam);
+}
+
+/**
+ *
+ */
+void oauth_add_protocol(int *argcp, char ***argvp,
+ OAuthMethod method,
+ const char *c_key, //< consumer key - posted plain text
+ const char *t_key //< token key - posted plain text in URL
+ ){
+ char oarg[1024];
+
+ // add OAuth specific arguments
+ if (!oauth_param_exists(*argvp,*argcp,"oauth_nonce")) {
+ char *tmp;
+ snprintf(oarg, 1024, "oauth_nonce=%s", (tmp=oauth_gen_nonce()));
+ oauth_add_param_to_array(argcp, argvp, oarg);
+ free(tmp);
+ }
+
+ if (!oauth_param_exists(*argvp,*argcp,"oauth_timestamp")) {
+ snprintf(oarg, 1024, "oauth_timestamp=%li", (long int) time(NULL));
+ oauth_add_param_to_array(argcp, argvp, oarg);
+ }
+
+ if (t_key) {
+ snprintf(oarg, 1024, "oauth_token=%s", t_key);
+ oauth_add_param_to_array(argcp, argvp, oarg);
+ }
+
+ snprintf(oarg, 1024, "oauth_consumer_key=%s", c_key);
+ oauth_add_param_to_array(argcp, argvp, oarg);
+
+ snprintf(oarg, 1024, "oauth_signature_method=%s",
+ method==0?"HMAC-SHA1":method==1?"RSA-SHA1":"PLAINTEXT");
+ oauth_add_param_to_array(argcp, argvp, oarg);
+
+ if (!oauth_param_exists(*argvp,*argcp,"oauth_version")) {
+ snprintf(oarg, 1024, "oauth_version=1.0");
+ oauth_add_param_to_array(argcp, argvp, oarg);
+ }
+
+#if 0 // oauth_version 1.0 Rev A
+ if (!oauth_param_exists(argv,argc,"oauth_callback")) {
+ snprintf(oarg, 1024, "oauth_callback=oob");
+ oauth_add_param_to_array(argcp, argvp, oarg);
+ }
+#endif
+
+}
+
+char *oauth_sign_url (const char *url, char **postargs,
+ OAuthMethod method,
+ const char *c_key, //< consumer key - posted plain text
+ const char *c_secret, //< consumer secret - used as 1st part of secret-key
+ const char *t_key, //< token key - posted plain text in URL
+ const char *t_secret //< token secret - used as 2st part of secret-key
+ ) {
+ return oauth_sign_url2(url, postargs,
+ method, NULL,
+ c_key, c_secret,
+ t_key, t_secret);
+}
+
+char *oauth_sign_url2 (const char *url, char **postargs,
+ OAuthMethod method,
+ const char *http_method, //< HTTP request method
+ const char *c_key, //< consumer key - posted plain text
+ const char *c_secret, //< consumer secret - used as 1st part of secret-key
+ const char *t_key, //< token key - posted plain text in URL
+ const char *t_secret //< token secret - used as 2st part of secret-key
+ ) {
+ int argc;
+ char **argv = NULL;
+ char *rv;
+
+ if (postargs)
+ argc = oauth_split_post_paramters(url, &argv, 0);
+ else
+ argc = oauth_split_url_parameters(url, &argv);
+
+ rv=oauth_sign_array2(&argc, &argv, postargs,
+ method, http_method,
+ c_key, c_secret, t_key, t_secret);
+
+ oauth_free_array(&argc, &argv);
+ return(rv);
+}
+
+char *oauth_sign_array (int *argcp, char***argvp,
+ char **postargs,
+ OAuthMethod method,
+ const char *c_key, //< consumer key - posted plain text
+ const char *c_secret, //< consumer secret - used as 1st part of secret-key
+ const char *t_key, //< token key - posted plain text in URL
+ const char *t_secret //< token secret - used as 2st part of secret-key
+ ) {
+ return oauth_sign_array2 (argcp, argvp,
+ postargs, method,
+ NULL,
+ c_key, c_secret,
+ t_key, t_secret);
+}
+
+void oauth_sign_array2_process (int *argcp, char***argvp,
+ char **postargs,
+ OAuthMethod method,
+ const char *http_method, //< HTTP request method
+ const char *c_key, //< consumer key - posted plain text
+ const char *c_secret, //< consumer secret - used as 1st part of secret-key
+ const char *t_key, //< token key - posted plain text in URL
+ const char *t_secret //< token secret - used as 2st part of secret-key
+ ) {
+ char oarg[1024];
+ char *query;
+ char *okey, *odat, *sign;
+ char *http_request_method;
+
+ if (!http_method) {
+ http_request_method = xstrdup(postargs?"POST":"GET");
+ } else {
+ int i;
+ http_request_method = xstrdup(http_method);
+ for (i=0;i<strlen(http_request_method);i++)
+ http_request_method[i]=toupper(http_request_method[i]);
+ }
+
+ // add required OAuth protocol parameters
+ oauth_add_protocol(argcp, argvp, method, c_key, t_key);
+
+ // sort parameters
+ qsort(&(*argvp)[1], (*argcp)-1, sizeof(char *), oauth_cmpstringp);
+
+ // serialize URL - base-url
+ query= oauth_serialize_url_parameters(*argcp, *argvp);
+
+ // generate signature
+ okey = oauth_catenc(2, c_secret, t_secret);
+ odat = oauth_catenc(3, http_request_method, (*argvp)[0], query); // base-string
+ free(http_request_method);
+#ifdef DEBUG_OAUTH
+ fprintf (stderr, "\nliboauth: data to sign='%s'\n\n", odat);
+ fprintf (stderr, "\nliboauth: key='%s'\n\n", okey);
+#endif
+ switch(method) {
+ case OA_RSA:
+ sign = oauth_sign_rsa_sha1(odat,okey); // XXX okey needs to be RSA key!
+ break;
+ case OA_PLAINTEXT:
+ sign = oauth_sign_plaintext(odat,okey);
+ break;
+ default:
+ sign = oauth_sign_hmac_sha1(odat,okey);
+ }
+#ifdef WIPE_MEMORY
+ memset(okey,0, strlen(okey));
+ memset(odat,0, strlen(odat));
+#endif
+ free(odat);
+ free(okey);
+
+ // append signature to query args.
+ snprintf(oarg, 1024, "oauth_signature=%s",sign);
+ oauth_add_param_to_array(argcp, argvp, oarg);
+ free(sign);
+ if(query) free(query);
+}
+
+char *oauth_sign_array2 (int *argcp, char***argvp,
+ char **postargs,
+ OAuthMethod method,
+ const char *http_method, //< HTTP request method
+ const char *c_key, //< consumer key - posted plain text
+ const char *c_secret, //< consumer secret - used as 1st part of secret-key
+ const char *t_key, //< token key - posted plain text in URL
+ const char *t_secret //< token secret - used as 2st part of secret-key
+ ) {
+
+ char *result;
+ oauth_sign_array2_process(argcp, argvp, postargs, method, http_method, c_key, c_secret, t_key, t_secret);
+
+ // build URL params
+ result = oauth_serialize_url(*argcp, (postargs?1:0), *argvp);
+
+ if(postargs) {
+ *postargs = result;
+ result = xstrdup((*argvp)[0]);
+ }
+
+ return result;
+}
+
+
+/**
+ * free array args
+ *
+ * @param argcp pointer to array length int
+ * @param argvp pointer to array values to be free()d
+ */
+void oauth_free_array(int *argcp, char ***argvp) {
+ int i;
+ for (i=0;i<(*argcp);i++) {
+ free((*argvp)[i]);
+ }
+ if(*argvp) free(*argvp);
+}
+
+/**
+ * base64 encode digest, free it and return a URL parameter
+ * with the oauth_body_hash
+ */
+char *oauth_body_hash_encode(size_t len, unsigned char *digest) {
+ char *sign=oauth_encode_base64(len,digest);
+ char *sig_url = (char*)xmalloc(17+strlen(sign));
+ sprintf(sig_url,"oauth_body_hash=%s", sign);
+ free(sign);
+ free(digest);
+ return sig_url;
+}
+
+
+/**
+ * compare two strings in constant-time (as to not let an
+ * attacker guess how many leading chars are correct:
+ * http://rdist.root.org/2010/01/07/timing-independent-array-comparison/ )
+ *
+ * @param a string to compare
+ * @param b string to compare
+ * @param len_a length of string a
+ * @param len_b length of string b
+ *
+ * returns 0 (false) if strings are not equal, and 1 (true) if strings are equal.
+ */
+int oauth_time_independent_equals_n(const char* a, const char* b, size_t len_a, size_t len_b) {
+ int diff, i, j;
+ if (a == NULL) return (b == NULL);
+ else if (b == NULL) return 0;
+ else if (len_b == 0) return (len_a == 0);
+ diff = len_a ^ len_b;
+ j=0;
+ for (i=0; i<len_a; ++i) {
+ diff |= a[i] ^ b[j];
+ j = (j+1) % len_b;
+ }
+ return diff == 0;
+}
+int oauth_time_indepenent_equals_n(const char* a, const char* b, size_t len_a, size_t len_b) {
+ return oauth_time_independent_equals_n(a, b, len_a, len_b);
+}
+
+int oauth_time_independent_equals(const char* a, const char* b) {
+ return oauth_time_independent_equals_n (a, b, a?strlen(a):0, b?strlen(b):0);
+}
+
+int oauth_time_indepenent_equals(const char* a, const char* b) {
+ return oauth_time_independent_equals_n (a, b, a?strlen(a):0, b?strlen(b):0);
+}
+
+/**
+ * xep-0235 - TODO
+ */
+char *oauth_sign_xmpp (const char *xml,
+ OAuthMethod method,
+ const char *c_secret, //< consumer secret - used as 1st part of secret-key
+ const char *t_secret //< token secret - used as 2st part of secret-key
+ ) {
+
+ return NULL;
+}
+
+// vi: sts=2 sw=2 ts=2
diff --git a/protocols/Twitter/oauth/oauth.h b/protocols/Twitter/oauth/oauth.h
new file mode 100644
index 0000000000..4efb472fc8
--- /dev/null
+++ b/protocols/Twitter/oauth/oauth.h
@@ -0,0 +1,764 @@
+/**
+ * @brief OAuth.net implementation in POSIX-C.
+ * @file oauth.h
+ * @author Robin Gareus <robin@gareus.org>
+ *
+ * Copyright 2007-2011 Robin Gareus <robin@gareus.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+#ifndef _OAUTH_H
+#define _OAUTH_H 1
+
+#ifndef DOXYGEN_IGNORE
+// liboauth version
+#define LIBOAUTH_VERSION "0.9.6"
+#define LIBOAUTH_VERSION_MAJOR 0
+#define LIBOAUTH_VERSION_MINOR 9
+#define LIBOAUTH_VERSION_MICRO 6
+
+//interface revision number
+//http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
+#define LIBOAUTH_CUR 8
+#define LIBOAUTH_REV 3
+#define LIBOAUTH_AGE 8
+#endif
+
+#ifdef __GNUC__
+# define OA_GCC_VERSION_AT_LEAST(x,y) (__GNUC__ > x || __GNUC__ == x && __GNUC_MINOR__ >= y)
+#else
+# define OA_GCC_VERSION_AT_LEAST(x,y) 0
+#endif
+
+#ifndef attribute_deprecated
+#if OA_GCC_VERSION_AT_LEAST(3,1)
+# define attribute_deprecated __attribute__((deprecated))
+#else
+# define attribute_deprecated
+#endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \enum OAuthMethod
+ * signature method to used for signing the request.
+ */
+typedef enum {
+ OA_HMAC=0, ///< use HMAC-SHA1 request signing method
+ OA_RSA, ///< use RSA signature
+ OA_PLAINTEXT ///< use plain text signature (for testing only)
+ } OAuthMethod;
+
+/**
+ * Base64 encode and return size data in 'src'. The caller must free the
+ * returned string.
+ *
+ * @param size The size of the data in src
+ * @param src The data to be base64 encode
+ * @return encoded string otherwise NULL
+ */
+char *oauth_encode_base64(int size, const unsigned char *src);
+
+/**
+ * Decode the base64 encoded string 'src' into the memory pointed to by
+ * 'dest'.
+ *
+ * @param dest Pointer to memory for holding the decoded string.
+ * Must be large enough to receive the decoded string.
+ * @param src A base64 encoded string.
+ * @return the length of the decoded string if decode
+ * succeeded otherwise 0.
+ */
+int oauth_decode_base64(unsigned char *dest, const char *src);
+
+/**
+ * Escape 'string' according to RFC3986 and
+ * http://oauth.net/core/1.0/#encoding_parameters.
+ *
+ * @param string The data to be encoded
+ * @return encoded string otherwise NULL
+ * The caller must free the returned string.
+ */
+char *oauth_url_escape(const char *string);
+
+/**
+ * Parse RFC3986 encoded 'string' back to unescaped version.
+ *
+ * @param string The data to be unescaped
+ * @param olen unless NULL the length of the returned string is stored there.
+ * @return decoded string or NULL
+ * The caller must free the returned string.
+ */
+char *oauth_url_unescape(const char *string, size_t *olen);
+
+
+/**
+ * returns base64 encoded HMAC-SHA1 signature for
+ * given message and key.
+ * both data and key need to be urlencoded.
+ *
+ * the returned string needs to be freed by the caller
+ *
+ * @param m message to be signed
+ * @param k key used for signing
+ * @return signature string.
+ */
+char *oauth_sign_hmac_sha1 (const char *m, const char *k);
+
+/**
+ * same as \ref oauth_sign_hmac_sha1 but allows
+ * to specify length of message and key (in case they contain null chars).
+ *
+ * @param m message to be signed
+ * @param ml length of message
+ * @param k key used for signing
+ * @param kl length of key
+ * @return signature string.
+ */
+char *oauth_sign_hmac_sha1_raw (const char *m, const size_t ml, const char *k, const size_t kl);
+
+/**
+ * returns plaintext signature for the given key.
+ *
+ * the returned string needs to be freed by the caller
+ *
+ * @param m message to be signed
+ * @param k key used for signing
+ * @return signature string
+ */
+char *oauth_sign_plaintext (const char *m, const char *k);
+
+/**
+ * returns RSA-SHA1 signature for given data.
+ * the returned signature needs to be freed by the caller.
+ *
+ * @param m message to be signed
+ * @param k private-key PKCS and Base64-encoded
+ * @return base64 encoded signature string.
+ */
+char *oauth_sign_rsa_sha1 (const char *m, const char *k);
+
+/**
+ * verify RSA-SHA1 signature.
+ *
+ * returns the output of EVP_VerifyFinal() for a given message,
+ * cert/pubkey and signature.
+ *
+ * @param m message to be verified
+ * @param c public-key or x509 certificate
+ * @param s base64 encoded signature
+ * @return 1 for a correct signature, 0 for failure and -1 if some other error occurred
+ */
+int oauth_verify_rsa_sha1 (const char *m, const char *c, const char *s);
+
+/**
+ * url-escape strings and concatenate with '&' separator.
+ * The number of strings to be concatenated must be
+ * given as first argument.
+ * all arguments thereafter must be of type (char *)
+ *
+ * @param len the number of arguments to follow this parameter
+ *
+ * @return pointer to memory holding the concatenated
+ * strings - needs to be free(d) by the caller. or NULL
+ * in case we ran out of memory.
+ */
+char *oauth_catenc(int len, ...);
+
+/**
+ * splits the given url into a parameter array.
+ * (see \ref oauth_serialize_url and \ref oauth_serialize_url_parameters for the reverse)
+ * (see \ref oauth_split_post_paramters for a more generic version)
+ *
+ * @param url the url or query-string to parse; may be NULL
+ * @param argv pointer to a (char *) array where the results are stored.
+ * The array is re-allocated to match the number of parameters and each
+ * parameter-string is allocated with strdup. - The memory needs to be freed
+ * by the caller.
+ *
+ * @return number of parameter(s) in array.
+ */
+int oauth_split_url_parameters(const char *url, char ***argv);
+
+/**
+ * splits the given url into a parameter array.
+ * (see \ref oauth_serialize_url and \ref oauth_serialize_url_parameters for the reverse)
+ *
+ * @param url the url or query-string to parse.
+ * @param argv pointer to a (char *) array where the results are stored.
+ * The array is re-allocated to match the number of parameters and each
+ * parameter-string is allocated with strdup. - The memory needs to be freed
+ * by the caller.
+ * @param qesc use query parameter escape (vs post-param-escape) - if set
+ * to 1 all '+' are treated as spaces ' '
+ *
+ * @return number of parameter(s) in array.
+ */
+int oauth_split_post_paramters(const char *url, char ***argv, short qesc);
+
+/**
+ * build a url query string from an array.
+ *
+ * @param argc the total number of elements in the array
+ * @param start element in the array at which to start concatenating.
+ * @param argv parameter-array to concatenate.
+ * @return url string needs to be freed by the caller.
+ *
+ */
+char *oauth_serialize_url (int argc, int start, char **argv);
+
+/**
+ * encode query parameters from an array.
+ *
+ * @param argc the total number of elements in the array
+ * @param start element in the array at which to start concatenating.
+ * @param argv parameter-array to concatenate.
+ * @param sep separator for parameters (usually "&")
+ * @param mod - bitwise modifiers:
+ * 1: skip all values that start with "oauth_"
+ * 2: skip all values that don't start with "oauth_"
+ * 4: double quotation marks are added around values (use with sep ", " for HTTP Authorization header).
+ * @return url string needs to be freed by the caller.
+ */
+char *oauth_serialize_url_sep (int argc, int start, char **argv, char *sep, int mod);
+
+/**
+ * build a query parameter string from an array.
+ *
+ * This function is a shortcut for \ref oauth_serialize_url (argc, 1, argv).
+ * It strips the leading host/path, which is usually the first
+ * element when using oauth_split_url_parameters on an URL.
+ *
+ * @param argc the total number of elements in the array
+ * @param argv parameter-array to concatenate.
+ * @return url string needs to be freed by the caller.
+ */
+char *oauth_serialize_url_parameters (int argc, char **argv);
+
+/**
+ * generate a random string between 15 and 32 chars length
+ * and return a pointer to it. The value needs to be freed by the
+ * caller
+ *
+ * @return zero terminated random string.
+ */
+char *oauth_gen_nonce();
+
+/**
+ * string compare function for oauth parameters.
+ *
+ * used with qsort. needed to normalize request parameters.
+ * see http://oauth.net/core/1.0/#anchor14
+ */
+int oauth_cmpstringp(const void *p1, const void *p2);
+
+
+/**
+ * search array for parameter key.
+ * @param argv length of array to search
+ * @param argc parameter array to search
+ * @param key key of parameter to check.
+ *
+ * @return FALSE (0) if array does not contain a parameter with given key, TRUE (1) otherwise.
+ */
+int oauth_param_exists(char **argv, int argc, char *key);
+
+/**
+ * add query parameter to array
+ *
+ * @param argcp pointer to array length int
+ * @param argvp pointer to array values
+ * @param addparam parameter to add (eg. "foo=bar")
+ */
+void oauth_add_param_to_array(int *argcp, char ***argvp, const char *addparam);
+
+/**
+ * free array args
+ *
+ * @param argcp pointer to array length int
+ * @param argvp pointer to array values to be free()d
+ */
+void oauth_free_array(int *argcp, char ***argvp);
+
+/**
+ * compare two strings in constant-time (as to not let an
+ * attacker guess how many leading chars are correct:
+ * http://rdist.root.org/2010/01/07/timing-independent-array-comparison/ )
+ *
+ * @param a string to compare
+ * @param b string to compare
+ * @param len_a length of string a
+ * @param len_b length of string b
+ *
+ * returns 0 (false) if strings are not equal, and 1 (true) if strings are equal.
+ */
+int oauth_time_independent_equals_n(const char* a, const char* b, size_t len_a, size_t len_b);
+
+/**
+ * @deprecated Use oauth_time_independent_equals_n() instead.
+ */
+int oauth_time_indepenent_equals_n(const char* a, const char* b, size_t len_a, size_t len_b) attribute_deprecated;
+
+/**
+ * compare two strings in constant-time.
+ * wrapper to \ref oauth_time_independent_equals_n
+ * which calls strlen() for each argument.
+ *
+ * @param a string to compare
+ * @param b string to compare
+ *
+ * returns 0 (false) if strings are not equal, and 1 (true) if strings are equal.
+ */
+int oauth_time_independent_equals(const char* a, const char* b);
+
+/**
+ * @deprecated Use oauth_time_independent_equals() instead.
+ */
+int oauth_time_indepenent_equals(const char* a, const char* b) attribute_deprecated;
+
+/**
+ * calculate OAuth-signature for a given HTTP request URL, parameters and oauth-tokens.
+ *
+ * if 'postargs' is NULL a "GET" request is signed and the
+ * signed URL is returned. Else this fn will modify 'postargs'
+ * to point to memory that contains the signed POST-variables
+ * and returns the base URL.
+ *
+ * both, the return value and (if given) 'postargs' need to be freed
+ * by the caller.
+ *
+ * @param url The request URL to be signed. append all GET or POST
+ * query-parameters separated by either '?' or '&' to this parameter.
+ *
+ * @param postargs This parameter points to an area where the return value
+ * is stored. If 'postargs' is NULL, no value is stored.
+ *
+ * @param method specify the signature method to use. It is of type
+ * \ref OAuthMethod and most likely \ref OA_HMAC.
+ *
+ * @param http_method The HTTP request method to use (ie "GET", "PUT",..)
+ * If NULL is given as 'http_method' this defaults to "GET" when
+ * 'postargs' is also NULL and when postargs is not NULL "POST" is used.
+ *
+ * @param c_key consumer key
+ * @param c_secret consumer secret
+ * @param t_key token key
+ * @param t_secret token secret
+ *
+ * @return the signed url or NULL if an error occurred.
+ *
+ */
+char *oauth_sign_url2 (const char *url, char **postargs,
+ OAuthMethod method,
+ const char *http_method, //< HTTP request method
+ const char *c_key, //< consumer key - posted plain text
+ const char *c_secret, //< consumer secret - used as 1st part of secret-key
+ const char *t_key, //< token key - posted plain text in URL
+ const char *t_secret //< token secret - used as 2st part of secret-key
+ );
+
+/**
+ * @deprecated Use oauth_sign_url2() instead.
+ */
+char *oauth_sign_url (const char *url, char **postargs,
+ OAuthMethod method,
+ const char *c_key, //< consumer key - posted plain text
+ const char *c_secret, //< consumer secret - used as 1st part of secret-key
+ const char *t_key, //< token key - posted plain text in URL
+ const char *t_secret //< token secret - used as 2st part of secret-key
+ ) attribute_deprecated;
+
+
+/**
+ * the back-end behind by /ref oauth_sign_array2.
+ * however it does not serialize the signed URL again.
+ * The user needs to call /ref oauth_serialize_url (oA)
+ * and /ref oauth_free_array to do so.
+ *
+ * This allows to split parts of the URL to be used for
+ * OAuth HTTP Authorization header:
+ * see http://oauth.net/core/1.0a/#consumer_req_param
+ * the oauthtest2 example code does so.
+ *
+ *
+ * @param argcp pointer to array length int
+ * @param argvp pointer to array values
+ * (argv[0]="http://example.org:80/" argv[1]="first=QueryParamater" ..
+ * the array is modified: fi. oauth_ parameters are added)
+ * These arrays can be generated with /ref oauth_split_url_parameters
+ * or /ref oauth_split_post_paramters.
+ *
+ * @param postargs This parameter points to an area where the return value
+ * is stored. If 'postargs' is NULL, no value is stored.
+ *
+ * @param method specify the signature method to use. It is of type
+ * \ref OAuthMethod and most likely \ref OA_HMAC.
+ *
+ * @param http_method The HTTP request method to use (ie "GET", "PUT",..)
+ * If NULL is given as 'http_method' this defaults to "GET" when
+ * 'postargs' is also NULL and when postargs is not NULL "POST" is used.
+ *
+ * @param c_key consumer key
+ * @param c_secret consumer secret
+ * @param t_key token key
+ * @param t_secret token secret
+ *
+ * @return void
+ *
+ */
+void oauth_sign_array2_process (int *argcp, char***argvp,
+ char **postargs,
+ OAuthMethod method,
+ const char *http_method, //< HTTP request method
+ const char *c_key, //< consumer key - posted plain text
+ const char *c_secret, //< consumer secret - used as 1st part of secret-key
+ const char *t_key, //< token key - posted plain text in URL
+ const char *t_secret //< token secret - used as 2st part of secret-key
+ );
+
+/**
+ * same as /ref oauth_sign_url
+ * with the url already split into parameter array
+ *
+ * @param argcp pointer to array length int
+ * @param argvp pointer to array values
+ * (argv[0]="http://example.org:80/" argv[1]="first=QueryParamater" ..
+ * the array is modified: fi. oauth_ parameters are added)
+ * These arrays can be generated with /ref oauth_split_url_parameters
+ * or /ref oauth_split_post_paramters.
+ *
+ * @param postargs This parameter points to an area where the return value
+ * is stored. If 'postargs' is NULL, no value is stored.
+ *
+ * @param method specify the signature method to use. It is of type
+ * \ref OAuthMethod and most likely \ref OA_HMAC.
+ *
+ * @param http_method The HTTP request method to use (ie "GET", "PUT",..)
+ * If NULL is given as 'http_method' this defaults to "GET" when
+ * 'postargs' is also NULL and when postargs is not NULL "POST" is used.
+ *
+ * @param c_key consumer key
+ * @param c_secret consumer secret
+ * @param t_key token key
+ * @param t_secret token secret
+ *
+ * @return the signed url or NULL if an error occurred.
+ */
+char *oauth_sign_array2 (int *argcp, char***argvp,
+ char **postargs,
+ OAuthMethod method,
+ const char *http_method, //< HTTP request method
+ const char *c_key, //< consumer key - posted plain text
+ const char *c_secret, //< consumer secret - used as 1st part of secret-key
+ const char *t_key, //< token key - posted plain text in URL
+ const char *t_secret //< token secret - used as 2st part of secret-key
+ );
+
+/**
+ * @deprecated Use oauth_sign_array2() instead.
+ */
+char *oauth_sign_array (int *argcp, char***argvp,
+ char **postargs,
+ OAuthMethod method,
+ const char *c_key, //< consumer key - posted plain text
+ const char *c_secret, //< consumer secret - used as 1st part of secret-key
+ const char *t_key, //< token key - posted plain text in URL
+ const char *t_secret //< token secret - used as 2st part of secret-key
+ ) attribute_deprecated;
+
+
+/**
+ * calculate body hash (sha1sum) of given file and return
+ * a oauth_body_hash=xxxx parameter to be added to the request.
+ * The returned string needs to be freed by the calling function.
+ *
+ * see
+ * http://oauth.googlecode.com/svn/spec/ext/body_hash/1.0/oauth-bodyhash.html
+ *
+ * @param filename the filename to calculate the hash for
+ *
+ * @return URL oauth_body_hash parameter string
+ */
+char *oauth_body_hash_file(char *filename);
+
+/**
+ * calculate body hash (sha1sum) of given data and return
+ * a oauth_body_hash=xxxx parameter to be added to the request.
+ * The returned string needs to be freed by the calling function.
+ * The returned string is not yet url-escaped and suitable to be
+ * passed as argument to \ref oauth_catenc.
+ *
+ * see
+ * http://oauth.googlecode.com/svn/spec/ext/body_hash/1.0/oauth-bodyhash.html
+ *
+ * @param length length of the data parameter in bytes
+ * @param data to calculate the hash for
+ *
+ * @return URL oauth_body_hash parameter string
+ */
+char *oauth_body_hash_data(size_t length, const char *data);
+
+/**
+ * base64 encode digest, free it and return a URL parameter
+ * with the oauth_body_hash. The returned hash needs to be freed by the
+ * calling function. The returned string is not yet url-escaped and
+ * thus suitable to be passed to \ref oauth_catenc.
+ *
+ * @param len length of the digest to encode
+ * @param digest hash value to encode
+ *
+ * @return URL oauth_body_hash parameter string
+ */
+char *oauth_body_hash_encode(size_t len, unsigned char *digest);
+
+/**
+ * xep-0235 - TODO
+ */
+char *oauth_sign_xmpp (const char *xml,
+ OAuthMethod method,
+ const char *c_secret, //< consumer secret - used as 1st part of secret-key
+ const char *t_secret //< token secret - used as 2st part of secret-key
+ );
+
+/**
+ * do a HTTP GET request, wait for it to finish
+ * and return the content of the reply.
+ * (requires libcurl or a command-line HTTP client)
+ *
+ * If compiled <b>without</b> libcurl this function calls
+ * a command-line executable defined in the environment variable
+ * OAUTH_HTTP_GET_CMD - it defaults to
+ * <tt>curl -sA 'liboauth-agent/0.1' '%%u'</tt>
+ * where %%u is replaced with the URL and query parameters.
+ *
+ * bash & wget example:
+ * <tt>export OAUTH_HTTP_CMD="wget -q -U 'liboauth-agent/0.1' '%u' "</tt>
+ *
+ * WARNING: this is a tentative function. it's convenient and handy for testing
+ * or developing OAuth code. But don't rely on this function
+ * to become a stable part of this API. It does not do
+ * much error checking or handling for one thing..
+ *
+ * NOTE: \a u and \a q are just concatenated with a '?' in between,
+ * unless \a q is NULL. in which case only \a u will be used.
+ *
+ * @param u base url to get
+ * @param q query string to send along with the HTTP request or NULL.
+ * @return In case of an error NULL is returned; otherwise a pointer to the
+ * replied content from HTTP server. latter needs to be freed by caller.
+ */
+char *oauth_http_get (const char *u, const char *q);
+
+/**
+ * do a HTTP GET request, wait for it to finish
+ * and return the content of the reply.
+ *
+ * (requires libcurl)
+ *
+ * This is equivalent to /ref oauth_http_get but allows to
+ * specifiy a custom HTTP header and has
+ * has no support for commandline-curl.
+ *
+ * If liboauth is compiled <b>without</b> libcurl this function
+ * always returns NULL.
+ *
+ * @param u base url to get
+ * @param q query string to send along with the HTTP request or NULL.
+ * @param customheader specify custom HTTP header (or NULL for none)
+ * Multiple header elements can be passed separating them with "\r\n"
+ * @return In case of an error NULL is returned; otherwise a pointer to the
+ * replied content from HTTP server. latter needs to be freed by caller.
+ */
+char *oauth_http_get2 (const char *u, const char *q, const char *customheader);
+
+
+/**
+ * do a HTTP POST request, wait for it to finish
+ * and return the content of the reply.
+ * (requires libcurl or a command-line HTTP client)
+ *
+ * If compiled <b>without</b> libcurl this function calls
+ * a command-line executable defined in the environment variable
+ * OAUTH_HTTP_CMD - it defaults to
+ * <tt>curl -sA 'liboauth-agent/0.1' -d '%%p' '%%u'</tt>
+ * where %%p is replaced with the postargs and %%u is replaced with
+ * the URL.
+ *
+ * bash & wget example:
+ * <tt>export OAUTH_HTTP_CMD="wget -q -U 'liboauth-agent/0.1' --post-data='%p' '%u' "</tt>
+ *
+ * NOTE: This function uses the curl's default HTTP-POST Content-Type:
+ * application/x-www-form-urlencoded which is the only option allowed
+ * by oauth core 1.0 spec. Experimental code can use the Environment variable
+ * to transmit custom HTTP headers or parameters.
+ *
+ * WARNING: this is a tentative function. it's convenient and handy for testing
+ * or developing OAuth code. But don't rely on this function
+ * to become a stable part of this API. It does not do
+ * much error checking for one thing..
+ *
+ * @param u url to query
+ * @param p postargs to send along with the HTTP request.
+ * @return replied content from HTTP server. needs to be freed by caller.
+ */
+char *oauth_http_post (const char *u, const char *p);
+
+/**
+ * do a HTTP POST request, wait for it to finish
+ * and return the content of the reply.
+ * (requires libcurl)
+ *
+ * It's equivalent to /ref oauth_http_post, but offers
+ * the possibility to specify a custom HTTP header and
+ * has no support for commandline-curl.
+ *
+ * If liboauth is compiled <b>without</b> libcurl this function
+ * always returns NULL.
+ *
+ * @param u url to query
+ * @param p postargs to send along with the HTTP request.
+ * @param customheader specify custom HTTP header (or NULL for none)
+ * Multiple header elements can be passed separating them with "\r\n"
+ * @return replied content from HTTP server. needs to be freed by caller.
+ */
+char *oauth_http_post2 (const char *u, const char *p, const char *customheader);
+
+
+/**
+ * http post raw data from file.
+ * the returned string needs to be freed by the caller
+ * (requires libcurl)
+ *
+ * see dislaimer: /ref oauth_http_post
+ *
+ * @param u url to retrieve
+ * @param fn filename of the file to post along
+ * @param len length of the file in bytes. set to '0' for autodetection
+ * @param customheader specify custom HTTP header (or NULL for default).
+ * Multiple header elements can be passed separating them with "\r\n"
+ * @return returned HTTP reply or NULL on error
+ */
+char *oauth_post_file (const char *u, const char *fn, const size_t len, const char *customheader);
+
+/**
+ * http post raw data
+ * the returned string needs to be freed by the caller
+ * (requires libcurl)
+ *
+ * see dislaimer: /ref oauth_http_post
+ *
+ * @param u url to retrieve
+ * @param data data to post
+ * @param len length of the data in bytes.
+ * @param customheader specify custom HTTP header (or NULL for default)
+ * Multiple header elements can be passed separating them with "\r\n"
+ * @return returned HTTP reply or NULL on error
+ */
+char *oauth_post_data (const char *u, const char *data, size_t len, const char *customheader);
+
+/**
+ * http post raw data, with callback.
+ * the returned string needs to be freed by the caller
+ * (requires libcurl)
+ *
+ * Invokes the callback - in no particular order - when HTTP-request status updates occur.
+ * The callback is called with:
+ * void * callback_data: supplied on function call.
+ * int type: 0=data received, 1=data sent.
+ * size_t size: amount of data received or amount of data sent so far
+ * size_t totalsize: original amount of data to send, or amount of data received
+ *
+ * @param u url to retrieve
+ * @param data data to post along
+ * @param len length of the file in bytes. set to '0' for autodetection
+ * @param customheader specify custom HTTP header (or NULL for default)
+ * Multiple header elements can be passed separating them with "\r\n"
+ * @param callback specify the callback function
+ * @param callback_data specify data to pass to the callback function
+ * @return returned HTTP reply or NULL on error
+ */
+char *oauth_post_data_with_callback (const char *u,
+ const char *data,
+ size_t len,
+ const char *customheader,
+ void (*callback)(void*,int,size_t,size_t),
+ void *callback_data);
+
+/**
+ * http send raw data. similar to /ref oauth_http_post but provides
+ * for specifying the HTTP request method.
+ *
+ * the returned string needs to be freed by the caller
+ * (requires libcurl)
+ *
+ * see dislaimer: /ref oauth_http_post
+ *
+ * @param u url to retrieve
+ * @param data data to post
+ * @param len length of the data in bytes.
+ * @param customheader specify custom HTTP header (or NULL for default)
+ * Multiple header elements can be passed separating them with "\r\n"
+ * @param httpMethod specify http verb ("GET"/"POST"/"PUT"/"DELETE") to be used. if httpMethod is NULL, a POST is executed.
+ * @return returned HTTP reply or NULL on error
+ */
+char *oauth_send_data (const char *u,
+ const char *data,
+ size_t len,
+ const char *customheader,
+ const char *httpMethod);
+
+/**
+ * http post raw data, with callback.
+ * the returned string needs to be freed by the caller
+ * (requires libcurl)
+ *
+ * Invokes the callback - in no particular order - when HTTP-request status updates occur.
+ * The callback is called with:
+ * void * callback_data: supplied on function call.
+ * int type: 0=data received, 1=data sent.
+ * size_t size: amount of data received or amount of data sent so far
+ * size_t totalsize: original amount of data to send, or amount of data received
+ *
+ * @param u url to retrieve
+ * @param data data to post along
+ * @param len length of the file in bytes. set to '0' for autodetection
+ * @param customheader specify custom HTTP header (or NULL for default)
+ * Multiple header elements can be passed separating them with "\r\n"
+ * @param callback specify the callback function
+ * @param callback_data specify data to pass to the callback function
+ * @param httpMethod specify http verb ("GET"/"POST"/"PUT"/"DELETE") to be used.
+ * @return returned HTTP reply or NULL on error
+ */
+char *oauth_send_data_with_callback (const char *u,
+ const char *data,
+ size_t len,
+ const char *customheader,
+ void (*callback)(void*,int,size_t,size_t),
+ void *callback_data,
+ const char *httpMethod);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif
+/* vi:set ts=8 sts=2 sw=2: */
diff --git a/protocols/Twitter/oauth/oauth_http.c b/protocols/Twitter/oauth/oauth_http.c
new file mode 100644
index 0000000000..0e06b10dae
--- /dev/null
+++ b/protocols/Twitter/oauth/oauth_http.c
@@ -0,0 +1,728 @@
+/*
+ * OAuth http functions in POSIX-C.
+ *
+ * Copyright 2007, 2008, 2009, 2010 Robin Gareus <robin@gareus.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef WIN32
+# define snprintf _snprintf
+#endif
+
+#include "xmalloc.h"
+#include "oauth.h"
+
+#define OAUTH_USER_AGENT "liboauth-agent/" VERSION
+
+#ifdef HAVE_CURL /* HTTP requests via libcurl */
+#include <curl/curl.h>
+#include <sys/stat.h>
+
+# define GLOBAL_CURL_ENVIROMENT_OPTIONS \
+ if (getenv("CURLOPT_PROXYAUTH")){ \
+ curl_easy_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY); \
+ } \
+ if (getenv("CURLOPT_SSL_VERIFYPEER")){ \
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, (long) atol(getenv("CURLOPT_SSL_VERIFYPEER")) ); \
+ } \
+ if (getenv("CURLOPT_CAINFO")){ \
+ curl_easy_setopt(curl, CURLOPT_CAINFO, getenv("CURLOPT_CAINFO") ); \
+ } \
+ if (getenv("CURLOPT_FOLLOWLOCATION")){ \
+ curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, (long) atol(getenv("CURLOPT_FOLLOWLOCATION")) ); \
+ } \
+ if (getenv("CURLOPT_FAILONERROR")){ \
+ curl_easy_setopt(curl, CURLOPT_FAILONERROR, (long) atol(getenv("CURLOPT_FAILONERROR")) ); \
+ }
+
+struct MemoryStruct {
+ char *data;
+ size_t size; //< bytes remaining (r), bytes accumulated (w)
+
+ size_t start_size; //< only used with ..AndCall()
+ void (*callback)(void*,int,size_t,size_t); //< only used with ..AndCall()
+ void *callback_data; //< only used with ..AndCall()
+};
+
+static size_t
+WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data) {
+ size_t realsize = size * nmemb;
+ struct MemoryStruct *mem = (struct MemoryStruct *)data;
+
+ mem->data = (char *)xrealloc(mem->data, mem->size + realsize + 1);
+ if (mem->data) {
+ memcpy(&(mem->data[mem->size]), ptr, realsize);
+ mem->size += realsize;
+ mem->data[mem->size] = 0;
+ }
+ return realsize;
+}
+
+static size_t
+ReadMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data) {
+ struct MemoryStruct *mem = (struct MemoryStruct *)data;
+ size_t realsize = size * nmemb;
+ if (realsize > mem->size) realsize = mem->size;
+ memcpy(ptr, mem->data, realsize);
+ mem->size -= realsize;
+ mem->data += realsize;
+ return realsize;
+}
+
+static size_t
+WriteMemoryCallbackAndCall(void *ptr, size_t size, size_t nmemb, void *data) {
+ struct MemoryStruct *mem = (struct MemoryStruct *)data;
+ size_t ret=WriteMemoryCallback(ptr,size,nmemb,data);
+ mem->callback(mem->callback_data,0,mem->size,mem->size);
+ return ret;
+}
+
+static size_t
+ReadMemoryCallbackAndCall(void *ptr, size_t size, size_t nmemb, void *data) {
+ struct MemoryStruct *mem = (struct MemoryStruct *)data;
+ size_t ret=ReadMemoryCallback(ptr,size,nmemb,data);
+ mem->callback(mem->callback_data,1,mem->start_size-mem->size,mem->start_size);
+ return ret;
+}
+
+/**
+ * cURL http post function.
+ * the returned string (if not NULL) needs to be freed by the caller
+ *
+ * @param u url to retrieve
+ * @param p post parameters
+ * @param customheader specify custom HTTP header (or NULL for none)
+ * @return returned HTTP
+ */
+char *oauth_curl_post (const char *u, const char *p, const char *customheader) {
+ CURL *curl;
+ CURLcode res;
+ struct curl_slist *slist=NULL;
+
+ struct MemoryStruct chunk;
+ chunk.data=NULL;
+ chunk.size = 0;
+
+ curl = curl_easy_init();
+ if(!curl) return NULL;
+ curl_easy_setopt(curl, CURLOPT_URL, u);
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDS, p);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
+ if (customheader) {
+ slist = curl_slist_append(slist, customheader);
+ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
+ }
+ curl_easy_setopt(curl, CURLOPT_USERAGENT, OAUTH_USER_AGENT);
+#ifdef OAUTH_CURL_TIMEOUT
+ curl_easy_setopt(curl, CURLOPT_TIMEOUT, OAUTH_CURL_TIMEOUT);
+ curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
+#endif
+ GLOBAL_CURL_ENVIROMENT_OPTIONS;
+ res = curl_easy_perform(curl);
+ curl_slist_free_all(slist);
+ if (res) {
+ return NULL;
+ }
+
+ curl_easy_cleanup(curl);
+ return (chunk.data);
+}
+
+/**
+ * cURL http get function.
+ * the returned string (if not NULL) needs to be freed by the caller
+ *
+ * @param u url to retrieve
+ * @param q optional query parameters
+ * @param customheader specify custom HTTP header (or NULL for none)
+ * @return returned HTTP
+ */
+char *oauth_curl_get (const char *u, const char *q, const char *customheader) {
+ CURL *curl;
+ CURLcode res;
+ struct curl_slist *slist=NULL;
+ char *t1=NULL;
+ struct MemoryStruct chunk;
+
+ if (q) {
+ t1=(char*)xmalloc(sizeof(char)*(strlen(u)+strlen(q)+2));
+ strcpy(t1,u); strcat(t1,"?"); strcat(t1,q);
+ }
+
+ chunk.data=NULL;
+ chunk.size = 0;
+
+ curl = curl_easy_init();
+ if(!curl) return NULL;
+ curl_easy_setopt(curl, CURLOPT_URL, q?t1:u);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
+ if (customheader) {
+ slist = curl_slist_append(slist, customheader);
+ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
+ }
+#if 0 // TODO - support request methods..
+ if (0)
+ curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "HEAD");
+ else if (0)
+ curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
+#endif
+ curl_easy_setopt(curl, CURLOPT_USERAGENT, OAUTH_USER_AGENT);
+#ifdef OAUTH_CURL_TIMEOUT
+ curl_easy_setopt(curl, CURLOPT_TIMEOUT, OAUTH_CURL_TIMEOUT);
+ curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
+#endif
+ GLOBAL_CURL_ENVIROMENT_OPTIONS;
+ res = curl_easy_perform(curl);
+ curl_slist_free_all(slist);
+ if (q) free(t1);
+ curl_easy_cleanup(curl);
+
+ if (res) {
+ return NULL;
+ }
+ return (chunk.data);
+}
+
+/**
+ * cURL http post raw data from file.
+ * the returned string needs to be freed by the caller
+ *
+ * @param u url to retrieve
+ * @param fn filename of the file to post along
+ * @param len length of the file in bytes. set to '0' for autodetection
+ * @param customheader specify custom HTTP header (or NULL for default)
+ * @return returned HTTP or NULL on error
+ */
+char *oauth_curl_post_file (const char *u, const char *fn, size_t len, const char *customheader) {
+ CURL *curl;
+ CURLcode res;
+ struct curl_slist *slist=NULL;
+ struct MemoryStruct chunk;
+ FILE *f;
+
+ chunk.data=NULL;
+ chunk.size=0;
+
+ if (customheader)
+ slist = curl_slist_append(slist, customheader);
+ else
+ slist = curl_slist_append(slist, "Content-Type: image/jpeg;");
+
+ if (!len) {
+ struct stat statbuf;
+ if (stat(fn, &statbuf) == -1) return(NULL);
+ len = statbuf.st_size;
+ }
+
+ f = fopen(fn,"r");
+ if (!f) return NULL;
+
+ curl = curl_easy_init();
+ if(!curl) return NULL;
+ curl_easy_setopt(curl, CURLOPT_URL, u);
+ curl_easy_setopt(curl, CURLOPT_POST, 1);
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len);
+ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
+ curl_easy_setopt(curl, CURLOPT_READDATA, f);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
+ curl_easy_setopt(curl, CURLOPT_USERAGENT, OAUTH_USER_AGENT);
+#ifdef OAUTH_CURL_TIMEOUT
+ curl_easy_setopt(curl, CURLOPT_TIMEOUT, OAUTH_CURL_TIMEOUT);
+ curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
+#endif
+ GLOBAL_CURL_ENVIROMENT_OPTIONS;
+ res = curl_easy_perform(curl);
+ curl_slist_free_all(slist);
+ if (res) {
+ // error
+ return NULL;
+ }
+ fclose(f);
+
+ curl_easy_cleanup(curl);
+ return (chunk.data);
+}
+
+/**
+ * http send raw data, with callback.
+ * the returned string needs to be freed by the caller
+ *
+ * more documentation in oauth.h
+ *
+ * @param u url to retrieve
+ * @param data data to post along
+ * @param len length of the file in bytes. set to '0' for autodetection
+ * @param customheader specify custom HTTP header (or NULL for default)
+ * @param callback specify the callback function
+ * @param callback_data specify data to pass to the callback function
+ * @return returned HTTP reply or NULL on error
+ */
+char *oauth_curl_send_data_with_callback (const char *u, const char *data, size_t len, const char *customheader, void (*callback)(void*,int,size_t,size_t), void *callback_data, const char *httpMethod) {
+ CURL *curl;
+ CURLcode res;
+ struct curl_slist *slist=NULL;
+ struct MemoryStruct chunk;
+ struct MemoryStruct rdnfo;
+
+ chunk.data=NULL;
+ chunk.size=0;
+ chunk.start_size=0;
+ chunk.callback=callback;
+ chunk.callback_data=callback_data;
+ rdnfo.data=(char *)data;
+ rdnfo.size=len;
+ rdnfo.start_size=len;
+ rdnfo.callback=callback;
+ rdnfo.callback_data=callback_data;
+
+ if (customheader)
+ slist = curl_slist_append(slist, customheader);
+ else
+ slist = curl_slist_append(slist, "Content-Type: image/jpeg;");
+
+ curl = curl_easy_init();
+ if(!curl) return NULL;
+ curl_easy_setopt(curl, CURLOPT_URL, u);
+ curl_easy_setopt(curl, CURLOPT_POST, 1);
+ if (httpMethod) curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, httpMethod);
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len);
+ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
+ curl_easy_setopt(curl, CURLOPT_READDATA, (void *)&rdnfo);
+ if (callback)
+ curl_easy_setopt(curl, CURLOPT_READFUNCTION, ReadMemoryCallbackAndCall);
+ else
+ curl_easy_setopt(curl, CURLOPT_READFUNCTION, ReadMemoryCallback);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
+ if (callback)
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallbackAndCall);
+ else
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
+ curl_easy_setopt(curl, CURLOPT_USERAGENT, OAUTH_USER_AGENT);
+#ifdef OAUTH_CURL_TIMEOUT
+ curl_easy_setopt(curl, CURLOPT_TIMEOUT, OAUTH_CURL_TIMEOUT);
+ curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
+#endif
+ GLOBAL_CURL_ENVIROMENT_OPTIONS;
+ res = curl_easy_perform(curl);
+ curl_slist_free_all(slist);
+ if (res) {
+ // error
+ return NULL;
+ }
+
+ curl_easy_cleanup(curl);
+ return (chunk.data);
+}
+
+/**
+ * http post raw data.
+ * the returned string needs to be freed by the caller
+ *
+ * more documentation in oauth.h
+ *
+ * @param u url to retrieve
+ * @param data data to post along
+ * @param len length of the file in bytes. set to '0' for autodetection
+ * @param customheader specify custom HTTP header (or NULL for default)
+ * @return returned HTTP reply or NULL on error
+ */
+char *oauth_curl_post_data(const char *u, const char *data, size_t len, const char *customheader) {
+ return oauth_curl_send_data_with_callback(u, data, len, customheader, NULL, NULL, NULL);
+}
+
+char *oauth_curl_send_data (const char *u, const char *data, size_t len, const char *customheader, const char *httpMethod) {
+ return oauth_curl_send_data_with_callback(u, data, len, customheader, NULL, NULL, httpMethod);
+}
+
+char *oauth_curl_post_data_with_callback (const char *u, const char *data, size_t len, const char *customheader, void (*callback)(void*,int,size_t,size_t), void *callback_data) {
+ return oauth_curl_send_data_with_callback(u, data, len, customheader, callback, callback_data, NULL);
+}
+
+#endif // libcURL.
+
+
+#ifdef HAVE_SHELL_CURL /* HTTP requests via command-line curl */
+
+// command line presets and ENV variable name
+#define _OAUTH_ENV_HTTPCMD "OAUTH_HTTP_CMD"
+#define _OAUTH_ENV_HTTPGET "OAUTH_HTTP_GET_CMD"
+
+#ifdef OAUTH_CURL_TIMEOUT
+
+#define cpxstr(s) cpstr(s)
+#define cpstr(s) #s
+
+#ifndef _OAUTH_DEF_HTTPCMD
+# define _OAUTH_DEF_HTTPCMD "curl -sA '"OAUTH_USER_AGENT"' -m "cpxstr(OAUTH_CURL_TIMEOUT)" -d '%p' '%u' "
+//alternative: "wget -q -U 'liboauth-agent/0.1' --post-data='%p' '%u' "
+#endif
+
+#ifndef _OAUTH_DEF_HTTPGET
+# define _OAUTH_DEF_HTTPGET "curl -sA '"OAUTH_USER_AGENT"' -m "cpxstr(OAUTH_CURL_TIMEOUT)" '%u' "
+//alternative: "wget -q -U 'liboauth-agent/0.1' '%u' "
+#endif
+
+#else // no timeout
+
+#ifndef _OAUTH_DEF_HTTPCMD
+# define _OAUTH_DEF_HTTPCMD "curl -sA '"OAUTH_USER_AGENT"' -d '%p' '%u' "
+//alternative: "wget -q -U 'liboauth-agent/0.1' --post-data='%p' '%u' "
+#endif
+
+#ifndef _OAUTH_DEF_HTTPGET
+# define _OAUTH_DEF_HTTPGET "curl -sA '"OAUTH_USER_AGENT"' '%u' "
+//alternative: "wget -q -U 'liboauth-agent/0.1' '%u' "
+#endif
+
+#endif
+
+#include <stdio.h>
+
+/**
+ * escape URL for use in String Quotes (aka shell single quotes).
+ * the returned string needs to be free()d by the calling function
+ *
+ * WARNING: this function only escapes single-quotes (')
+ *
+ *
+ * RFC2396 defines the following
+ * reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","
+ * besides alphanum the following are allowed as unreserved:
+ * mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
+ *
+ * checking `echo '-_.!~*()'` it seems we
+ * just need to escape the tick (') itself from "'" to "'\''"
+ *
+ * In C shell, the "!" character may need a backslash before it.
+ * It depends on the characters next to it. If it is surrounded by spaces,
+ * you don't need to use a backslash.
+ * (here: we'd always need to escape it for c shell)
+ * @todo: escape '!' for c-shell curl/wget commandlines
+ *
+ * @param cmd URI string or parameter to be escaped
+ * @return escaped parameter
+ */
+char *oauth_escape_shell (const char *cmd) {
+ char *esc = xstrdup(cmd);
+ char *tmp = esc;
+ int idx;
+ while ((tmp=strchr(tmp,'\''))) {
+ idx = tmp-esc;
+ esc=(char*)xrealloc(esc,(strlen(esc)+5)*sizeof(char));
+ memmove(esc+idx+4,esc+idx+1, strlen(esc+idx));
+ esc[idx+1]='\\'; esc[idx+2]='\''; esc[idx+3]='\'';
+ tmp=esc+(idx+4);
+ }
+
+// TODO escape '!' if CSHELL ?!
+
+ return esc;
+}
+
+/**
+ * execute command via shell and return it's output.
+ * This is used to call 'curl' or 'wget'.
+ * the command is uses <em>as is</em> and needs to be propery escaped.
+ *
+ * @param cmd the commandline to execute
+ * @return stdout string that needs to be freed or NULL if there's no output
+ */
+char *oauth_exec_shell (const char *cmd) {
+#ifdef DEBUG_OAUTH
+ printf("DEBUG: executing: %s\n",cmd);
+#endif
+ FILE *in = popen (cmd, "r");
+ size_t len = 0;
+ size_t alloc = 0;
+ char *data = NULL;
+ int rcv = 1;
+ while (in && rcv > 0 && !feof(in)) {
+ alloc +=1024;
+ data = (char*)xrealloc(data, alloc * sizeof(char));
+ rcv = fread(data + (alloc-1024), sizeof(char), 1024, in);
+ len += rcv;
+ }
+ pclose(in);
+#ifdef DEBUG_OAUTH
+ printf("DEBUG: read %i bytes\n",len);
+#endif
+ data[len]=0;
+#ifdef DEBUG_OAUTH
+ if (data) printf("DEBUG: return: %s\n",data);
+ else printf("DEBUG: NULL data\n");
+#endif
+ return (data);
+}
+
+/**
+ * send POST via a command line HTTP client, wait for it to finish
+ * and return the content of the reply. requires a command-line HTTP client
+ *
+ * see \ref oauth_http_post
+ *
+ * @param u url to query
+ * @param p postargs to send along with the HTTP request.
+ * @return In case of an error NULL is returned; otherwise a pointer to the
+ * replied content from HTTP server. latter needs to be freed by caller.
+ */
+char *oauth_exec_post (const char *u, const char *p) {
+ char cmd[BUFSIZ];
+ char *t1,*t2;
+ char *cmdtpl = getenv(_OAUTH_ENV_HTTPCMD);
+ if (!cmdtpl) cmdtpl = xstrdup (_OAUTH_DEF_HTTPCMD);
+ else cmdtpl = xstrdup (cmdtpl); // clone getenv() string.
+
+ // add URL and post param - error if no '%p' or '%u' present in definition
+ t1=strstr(cmdtpl, "%p");
+ t2=strstr(cmdtpl, "%u");
+ if (!t1 || !t2) {
+ fprintf(stderr, "\nliboauth: invalid HTTP command. set the '%s' environment variable.\n\n",_OAUTH_ENV_HTTPCMD);
+ return(NULL);
+ }
+ // TODO: check if there are exactly two '%' in cmdtpl
+ *(++t1)= 's'; *(++t2)= 's';
+ if (t1>t2) {
+ t1=oauth_escape_shell(u);
+ t2=oauth_escape_shell(p);
+ } else {
+ t1=oauth_escape_shell(p);
+ t2=oauth_escape_shell(u);
+ }
+ snprintf(cmd, BUFSIZ, cmdtpl, t1, t2);
+ free(cmdtpl);
+ free(t1); free(t2);
+ return oauth_exec_shell(cmd);
+}
+
+/**
+ * send GET via a command line HTTP client
+ * and return the content of the reply..
+ * requires a command-line HTTP client.
+ *
+ * Note: u and q are just concatenated with a '?' in between unless q is NULL. in which case only u will be used.
+ *
+ * see \ref oauth_http_get
+ *
+ * @param u base url to get
+ * @param q query string to send along with the HTTP request.
+ * @return In case of an error NULL is returned; otherwise a pointer to the
+ * replied content from HTTP server. latter needs to be freed by caller.
+ */
+char *oauth_exec_get (const char *u, const char *q) {
+ char cmd[BUFSIZ];
+ char *cmdtpl, *t1, *e1;
+
+ if (!u) return (NULL);
+
+ cmdtpl = getenv(_OAUTH_ENV_HTTPGET);
+ if (!cmdtpl) cmdtpl = xstrdup (_OAUTH_DEF_HTTPGET);
+ else cmdtpl = xstrdup (cmdtpl); // clone getenv() string.
+
+ // add URL and post param - error if no '%p' or '%u' present in definition
+ t1=strstr(cmdtpl, "%u");
+ if (!t1) {
+ fprintf(stderr, "\nliboauth: invalid HTTP command. set the '%s' environment variable.\n\n",_OAUTH_ENV_HTTPGET);
+ return(NULL);
+ }
+ *(++t1)= 's';
+
+ e1 = oauth_escape_shell(u);
+ if (q) {
+ char *e2;
+ e2 = oauth_escape_shell(q);
+ t1=(char*)xmalloc(sizeof(char)*(strlen(e1)+strlen(e2)+2));
+ strcpy(t1,e1); strcat(t1,"?"); strcat(t1,e2);
+ free(e2);
+ }
+ snprintf(cmd, BUFSIZ, cmdtpl, q?t1:e1);
+ free(cmdtpl);
+ free(e1);
+ if (q) free(t1);
+ return oauth_exec_shell(cmd);
+}
+#endif // command-line curl.
+
+/* wrapper functions */
+
+/**
+ * do a HTTP GET request, wait for it to finish
+ * and return the content of the reply.
+ * (requires libcurl or a command-line HTTP client)
+ *
+ * more documentation in oauth.h
+ *
+ * @param u base url to get
+ * @param q query string to send along with the HTTP request or NULL.
+ * @return In case of an error NULL is returned; otherwise a pointer to the
+ * replied content from HTTP server. latter needs to be freed by caller.
+ */
+char *oauth_http_get (const char *u, const char *q) {
+#ifdef HAVE_CURL
+ return oauth_curl_get(u,q,NULL);
+#elif defined(HAVE_SHELL_CURL)
+ return oauth_exec_get(u,q);
+#else
+ return NULL;
+#endif
+}
+
+/**
+ * do a HTTP GET request, wait for it to finish
+ * and return the content of the reply.
+ * (requires libcurl)
+ *
+ * @param u base url to get
+ * @param q query string to send along with the HTTP request or NULL.
+ * @param customheader specify custom HTTP header (or NULL for none)
+ * @return In case of an error NULL is returned; otherwise a pointer to the
+ * replied content from HTTP server. latter needs to be freed by caller.
+ */
+char *oauth_http_get2 (const char *u, const char *q, const char *customheader) {
+#ifdef HAVE_CURL
+ return oauth_curl_get(u,q,customheader);
+#else
+ return NULL;
+#endif
+}
+
+/**
+ * do a HTTP POST request, wait for it to finish
+ * and return the content of the reply.
+ * (requires libcurl or a command-line HTTP client)
+ *
+ * more documentation in oauth.h
+ *
+ * @param u url to query
+ * @param p postargs to send along with the HTTP request.
+ * @return In case of an error NULL is returned; otherwise a pointer to the
+ * replied content from HTTP server. latter needs to be freed by caller.
+ */
+char *oauth_http_post (const char *u, const char *p) {
+#ifdef HAVE_CURL
+ return oauth_curl_post(u,p,NULL);
+#elif defined(HAVE_SHELL_CURL)
+ return oauth_exec_post(u,p);
+#else
+ return NULL;
+#endif
+}
+
+
+/**
+ * do a HTTP POST request, wait for it to finish
+ * and return the content of the reply.
+ * (requires libcurl)
+ *
+ * more documentation in oauth.h
+ *
+ * @param u url to query
+ * @param p postargs to send along with the HTTP request.
+ * @param customheader specify custom HTTP header (or NULL for none)
+ * @return In case of an error NULL is returned; otherwise a pointer to the
+ * replied content from HTTP server. latter needs to be freed by caller.
+ */
+char *oauth_http_post2 (const char *u, const char *p, const char *customheader) {
+#ifdef HAVE_CURL
+ return oauth_curl_post(u,p,customheader);
+#else
+ return NULL;
+#endif
+}
+
+/**
+ * http post raw data from file.
+ * the returned string needs to be freed by the caller
+ *
+ * more documentation in oauth.h
+ *
+ * @param u url to retrieve
+ * @param fn filename of the file to post along
+ * @param len length of the file in bytes. set to '0' for autodetection
+ * @param customheader specify custom HTTP header (or NULL for default)
+ * @return returned HTTP reply or NULL on error
+ */
+char *oauth_post_file (const char *u, const char *fn, const size_t len, const char *customheader){
+#ifdef HAVE_CURL
+ return oauth_curl_post_file (u, fn, len, customheader);
+#elif defined(HAVE_SHELL_CURL)
+ fprintf(stderr, "\nliboauth: oauth_post_file requires libcurl. libcurl is not available.\n\n");
+ return NULL;
+#else
+ return NULL;
+#endif
+}
+
+/**
+ * http post raw data.
+ * the returned string needs to be freed by the caller
+ *
+ * more documentation in oauth.h
+ *
+ * @param u url to retrieve
+ * @param data data to post along
+ * @param len length of the file in bytes. set to '0' for autodetection
+ * @param customheader specify custom HTTP header (or NULL for default)
+ * @return returned HTTP reply or NULL on error
+ */
+char *oauth_post_data (const char *u, const char *data, size_t len, const char *customheader) {
+#ifdef HAVE_CURL
+ return oauth_curl_post_data (u, data, len, customheader);
+#elif defined(HAVE_SHELL_CURL)
+ fprintf(stderr, "\nliboauth: oauth_post_file requires libcurl. libcurl is not available.\n\n");
+ return NULL;
+#else
+ return (NULL);
+#endif
+}
+
+char *oauth_send_data (const char *u, const char *data, size_t len, const char *customheader, const char *httpMethod) {
+#ifdef HAVE_CURL
+ return oauth_curl_send_data (u, data, len, customheader, httpMethod);
+#elif defined(HAVE_SHELL_CURL)
+ fprintf(stderr, "\nliboauth: oauth_send_file requires libcurl. libcurl is not available.\n\n");
+ return NULL;
+#else
+ return (NULL);
+#endif
+}
+
+char *oauth_post_data_with_callback (const char *u, const char *data, size_t len, const char *customheader, void (*callback)(void*,int,size_t,size_t), void *callback_data) {
+#ifdef HAVE_CURL
+ return oauth_curl_post_data_with_callback(u, data, len, customheader, callback, callback_data);
+#elif defined(HAVE_SHELL_CURL)
+ fprintf(stderr, "\nliboauth: oauth_post_data_with_callback requires libcurl.\n\n");
+ return NULL;
+#else
+ return (NULL);
+#endif
+}
+/* vi:set ts=8 sts=2 sw=2: */
diff --git a/protocols/Twitter/oauth/sha1.c b/protocols/Twitter/oauth/sha1.c
new file mode 100644
index 0000000000..c3189008ac
--- /dev/null
+++ b/protocols/Twitter/oauth/sha1.c
@@ -0,0 +1,317 @@
+/* This code is public-domain - it is based on libcrypt
+ * placed in the public domain by Wei Dai and other contributors.
+ */
+// gcc -Wall -DSHA1TEST -o sha1test sha1.c && ./sha1test
+
+#include <stdint.h>
+#include <string.h>
+
+/* header */
+
+#define HASH_LENGTH 20
+#define BLOCK_LENGTH 64
+
+union _buffer {
+ uint8_t b[BLOCK_LENGTH];
+ uint32_t w[BLOCK_LENGTH/4];
+};
+
+union _state {
+ uint8_t b[HASH_LENGTH];
+ uint32_t w[HASH_LENGTH/4];
+};
+
+typedef struct sha1nfo {
+ union _buffer buffer;
+ uint8_t bufferOffset;
+ union _state state;
+ uint32_t byteCount;
+ uint8_t keyBuffer[BLOCK_LENGTH];
+ uint8_t innerHash[HASH_LENGTH];
+} sha1nfo;
+
+/* public API - prototypes - TODO: doxygen*/
+
+/**
+ */
+void sha1_init(sha1nfo *s);
+/**
+ */
+void sha1_writebyte(sha1nfo *s, uint8_t data);
+/**
+ */
+void sha1_write(sha1nfo *s, const char *data, size_t len);
+/**
+ */
+uint8_t* sha1_result(sha1nfo *s);
+/**
+ */
+void sha1_initHmac(sha1nfo *s, const uint8_t* key, int keyLength);
+/**
+ */
+uint8_t* sha1_resultHmac(sha1nfo *s);
+
+
+/* code */
+#define SHA1_K0 0x5a827999
+#define SHA1_K20 0x6ed9eba1
+#define SHA1_K40 0x8f1bbcdc
+#define SHA1_K60 0xca62c1d6
+
+const uint8_t sha1InitState[] = {
+ 0x01,0x23,0x45,0x67, // H0
+ 0x89,0xab,0xcd,0xef, // H1
+ 0xfe,0xdc,0xba,0x98, // H2
+ 0x76,0x54,0x32,0x10, // H3
+ 0xf0,0xe1,0xd2,0xc3 // H4
+};
+
+void sha1_init(sha1nfo *s) {
+ memcpy(s->state.b,sha1InitState,HASH_LENGTH);
+ s->byteCount = 0;
+ s->bufferOffset = 0;
+}
+
+uint32_t sha1_rol32(uint32_t number, uint8_t bits) {
+ return ((number << bits) | (number >> (32-bits)));
+}
+
+void sha1_hashBlock(sha1nfo *s) {
+ uint8_t i;
+ uint32_t a,b,c,d,e,t;
+
+ a=s->state.w[0];
+ b=s->state.w[1];
+ c=s->state.w[2];
+ d=s->state.w[3];
+ e=s->state.w[4];
+ for (i=0; i<80; i++) {
+ if (i>=16) {
+ t = s->buffer.w[(i+13)&15] ^ s->buffer.w[(i+8)&15] ^ s->buffer.w[(i+2)&15] ^ s->buffer.w[i&15];
+ s->buffer.w[i&15] = sha1_rol32(t,1);
+ }
+ if (i<20) {
+ t = (d ^ (b & (c ^ d))) + SHA1_K0;
+ } else if (i<40) {
+ t = (b ^ c ^ d) + SHA1_K20;
+ } else if (i<60) {
+ t = ((b & c) | (d & (b | c))) + SHA1_K40;
+ } else {
+ t = (b ^ c ^ d) + SHA1_K60;
+ }
+ t+=sha1_rol32(a,5) + e + s->buffer.w[i&15];
+ e=d;
+ d=c;
+ c=sha1_rol32(b,30);
+ b=a;
+ a=t;
+ }
+ s->state.w[0] += a;
+ s->state.w[1] += b;
+ s->state.w[2] += c;
+ s->state.w[3] += d;
+ s->state.w[4] += e;
+}
+
+void sha1_addUncounted(sha1nfo *s, uint8_t data) {
+ s->buffer.b[s->bufferOffset ^ 3] = data;
+ s->bufferOffset++;
+ if (s->bufferOffset == BLOCK_LENGTH) {
+ sha1_hashBlock(s);
+ s->bufferOffset = 0;
+ }
+}
+
+void sha1_writebyte(sha1nfo *s, uint8_t data) {
+ ++s->byteCount;
+ sha1_addUncounted(s, data);
+}
+
+void sha1_write(sha1nfo *s, const char *data, size_t len) {
+ for (;len--;) sha1_writebyte(s, (uint8_t) *data++);
+}
+
+void sha1_pad(sha1nfo *s) {
+ // Implement SHA-1 padding (fips180-2 ยง5.1.1)
+
+ // Pad with 0x80 followed by 0x00 until the end of the block
+ sha1_addUncounted(s, 0x80);
+ while (s->bufferOffset != 56) sha1_addUncounted(s, 0x00);
+
+ // Append length in the last 8 bytes
+ sha1_addUncounted(s, 0); // We're only using 32 bit lengths
+ sha1_addUncounted(s, 0); // But SHA-1 supports 64 bit lengths
+ sha1_addUncounted(s, 0); // So zero pad the top bits
+ sha1_addUncounted(s, s->byteCount >> 29); // Shifting to multiply by 8
+ sha1_addUncounted(s, s->byteCount >> 21); // as SHA-1 supports bitstreams as well as
+ sha1_addUncounted(s, s->byteCount >> 13); // byte.
+ sha1_addUncounted(s, s->byteCount >> 5);
+ sha1_addUncounted(s, s->byteCount << 3);
+}
+
+uint8_t* sha1_result(sha1nfo *s) {
+ int i;
+ // Pad to complete the last block
+ sha1_pad(s);
+
+ // Swap byte order back
+ for (i=0; i<5; i++) {
+ uint32_t a,b;
+ a=s->state.w[i];
+ b=a<<24;
+ b|=(a<<8) & 0x00ff0000;
+ b|=(a>>8) & 0x0000ff00;
+ b|=a>>24;
+ s->state.w[i]=b;
+ }
+
+ // Return pointer to hash (20 characters)
+ return s->state.b;
+}
+
+#define HMAC_IPAD 0x36
+#define HMAC_OPAD 0x5c
+
+void sha1_initHmac(sha1nfo *s, const uint8_t* key, int keyLength) {
+ uint8_t i;
+ memset(s->keyBuffer, 0, BLOCK_LENGTH);
+ if (keyLength > BLOCK_LENGTH) {
+ // Hash long keys
+ sha1_init(s);
+ for (;keyLength--;) sha1_writebyte(s, *key++);
+ memcpy(s->keyBuffer, sha1_result(s), HASH_LENGTH);
+ } else {
+ // Block length keys are used as is
+ memcpy(s->keyBuffer, key, keyLength);
+ }
+ // Start inner hash
+ sha1_init(s);
+ for (i=0; i<BLOCK_LENGTH; i++) {
+ sha1_writebyte(s, s->keyBuffer[i] ^ HMAC_IPAD);
+ }
+}
+
+uint8_t* sha1_resultHmac(sha1nfo *s) {
+ uint8_t i;
+ // Complete inner hash
+ memcpy(s->innerHash,sha1_result(s),HASH_LENGTH);
+ // Calculate outer hash
+ sha1_init(s);
+ for (i=0; i<BLOCK_LENGTH; i++) sha1_writebyte(s, s->keyBuffer[i] ^ HMAC_OPAD);
+ for (i=0; i<HASH_LENGTH; i++) sha1_writebyte(s, s->innerHash[i]);
+ return sha1_result(s);
+}
+
+/* self-test */
+
+#if SHA1TEST
+#include <stdio.h>
+
+uint8_t hmacKey1[]={
+ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f
+};
+uint8_t hmacKey2[]={
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x41,0x42,0x43
+};
+uint8_t hmacKey3[]={
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
+ 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3
+};
+uint8_t hmacKey4[]={
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
+ 0xa0
+};
+
+void printHash(uint8_t* hash) {
+ int i;
+ for (i=0; i<20; i++) {
+ printf("%02x", hash[i]);
+ }
+ printf("\n");
+}
+
+
+int main (int argc, char **argv) {
+ uint32_t a;
+ sha1nfo s;
+
+ // SHA tests
+ printf("Test: FIPS 180-2 C.1 and RFC3174 7.3 TEST1\n");
+ printf("Expect:a9993e364706816aba3e25717850c26c9cd0d89d\n");
+ printf("Result:");
+ sha1_init(&s);
+ sha1_write(&s, "abc", 3);
+ printHash(sha1_result(&s));
+ printf("\n\n");
+
+ printf("Test: FIPS 180-2 C.2 and RFC3174 7.3 TEST2\n");
+ printf("Expect:84983e441c3bd26ebaae4aa1f95129e5e54670f1\n");
+ printf("Result:");
+ sha1_init(&s);
+ sha1_write(&s, "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56);
+ printHash(sha1_result(&s));
+ printf("\n\n");
+
+ printf("Test: RFC3174 7.3 TEST4\n");
+ printf("Expect:dea356a2cddd90c7a7ecedc5ebb563934f460452\n");
+ printf("Result:");
+ sha1_init(&s);
+ for (a=0; a<80; a++) sha1_write(&s, "01234567", 8);
+ printHash(sha1_result(&s));
+ printf("\n\n");
+
+ // HMAC tests
+ printf("Test: FIPS 198a A.1\n");
+ printf("Expect:4f4ca3d5d68ba7cc0a1208c9c61e9c5da0403c0a\n");
+ printf("Result:");
+ sha1_initHmac(&s, hmacKey1, 64);
+ sha1_write(&s, "Sample #1",9);
+ printHash(sha1_resultHmac(&s));
+ printf("\n\n");
+
+ printf("Test: FIPS 198a A.2\n");
+ printf("Expect:0922d3405faa3d194f82a45830737d5cc6c75d24\n");
+ printf("Result:");
+ sha1_initHmac(&s, hmacKey2, 20);
+ sha1_write(&s, "Sample #2", 9);
+ printHash(sha1_resultHmac(&s));
+ printf("\n\n");
+
+ printf("Test: FIPS 198a A.3\n");
+ printf("Expect:bcf41eab8bb2d802f3d05caf7cb092ecf8d1a3aa\n");
+ printf("Result:");
+ sha1_initHmac(&s, hmacKey3,100);
+ sha1_write(&s, "Sample #3", 9);
+ printHash(sha1_resultHmac(&s));
+ printf("\n\n");
+
+ printf("Test: FIPS 198a A.4\n");
+ printf("Expect:9ea886efe268dbecce420c7524df32e0751a2a26\n");
+ printf("Result:");
+ sha1_initHmac(&s, hmacKey4,49);
+ sha1_write(&s, "Sample #4", 9);
+ printHash(sha1_resultHmac(&s));
+ printf("\n\n");
+
+ // Long tests
+ printf("Test: FIPS 180-2 C.3 and RFC3174 7.3 TEST3\n");
+ printf("Expect:34aa973cd4c4daa4f61eeb2bdbad27316534016f\n");
+ printf("Result:");
+ sha1_init(&s);
+ for (a=0; a<1000000; a++) sha1_writebyte(&s, 'a');
+ printHash(sha1_result(&s));
+
+ return 0;
+}
+#endif /* self-test */
diff --git a/protocols/Twitter/oauth/xmalloc.c b/protocols/Twitter/oauth/xmalloc.c
new file mode 100644
index 0000000000..f831e13895
--- /dev/null
+++ b/protocols/Twitter/oauth/xmalloc.c
@@ -0,0 +1,60 @@
+/* xmalloc.c -- memory allocation including 'out of memory' checks
+ *
+ * Copyright 2010 Robin Gareus <robin@gareus.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <string.h>
+#include <stdlib.h>
+
+static void *xmalloc_fatal(size_t size) {
+ if (size==0) return NULL;
+ fprintf(stderr, "Out of memory.");
+ exit(1);
+}
+
+void *xmalloc (size_t size) {
+ void *ptr = malloc (size);
+ if (ptr == NULL) return xmalloc_fatal(size);
+ return ptr;
+}
+
+void *xcalloc (size_t nmemb, size_t size) {
+ void *ptr = calloc (nmemb, size);
+ if (ptr == NULL) return xmalloc_fatal(nmemb*size);
+ return ptr;
+}
+
+void *xrealloc (void *ptr, size_t size) {
+ void *p = realloc (ptr, size);
+ if (p == NULL) return xmalloc_fatal(size);
+ return p;
+}
+
+char *xstrdup (const char *s) {
+ void *ptr = xmalloc(strlen(s)+1);
+ strcpy (ptr, s);
+ return (char*) ptr;
+}
+
+// vi: sts=2 sw=2 ts=2
diff --git a/protocols/Twitter/oauth/xmalloc.h b/protocols/Twitter/oauth/xmalloc.h
new file mode 100644
index 0000000000..7ec9b61fdd
--- /dev/null
+++ b/protocols/Twitter/oauth/xmalloc.h
@@ -0,0 +1,10 @@
+#ifndef _OAUTH_XMALLOC_H
+#define _OAUTH_XMALLOC_H 1
+
+/* Prototypes for functions defined in xmalloc.c */
+void *xmalloc (size_t size);
+void *xcalloc (size_t nmemb, size_t size);
+void *xrealloc (void *ptr, size_t size);
+char *xstrdup (const char *s);
+
+#endif