Hi, Matt:
I put together a patch to verify the oauth_body_hash (see attached).
However, I'm still not convinced that it helps much of anything, enough
to be actually implemented. The uglifying of the code that it brings
is annoying, and it adds nothing that supporting SSL would not either.
If you still want it, I'll build you an RPM with it for testing.
-- Pete
commit dc4e890b9051d2280a7963b5219e3ad221b54de7
Author: Pete Zaitcev <zaitcev(a)yahoo.com>
Date: Sun Jan 8 19:33:11 2012 -0700
Check the oauth_body_hash.
diff --git a/configure.ac b/configure.ac
index ad9d53d..d013936 100644
--- a/configure.ac
+++ b/configure.ac
@@ -75,6 +75,8 @@ AC_CHECK_LIB([oauth], [oauth_init_nss],
[AC_MSG_ERROR([Missing required oauth lib])])
AC_SUBST([OAUTH_LIB])
+AC_CHECK_LIB([ssl], [SSL_new], SSL_LIBS=-lssl)
+
PKG_CHECK_MODULES([HAIL],[libhail >= 0.8])
AC_SUBST([HAIL_LIBS])
AC_SUBST([HAIL_CFLAGS])
diff --git a/rest.c b/rest.c
index 1aca0af..526e8b6 100644
--- a/rest.c
+++ b/rest.c
@@ -38,6 +38,7 @@
#include <curl/curl.h>
#include <oauth.h>
+#include "base64.h"
#include "configmake.h" /* for LOCALEDIR */
#include "dirname.h"
#include "iwh.h"
@@ -1404,13 +1405,26 @@ proxy_bucket_post (void *cctx, struct MHD_Connection *conn, const
char *url,
post_iterator,ms->dict);
if (!ms->post)
return MHD_NO;
+ if (ms->body_hash_present)
+ SHA1_Init(&ms->sha1);
gc_register_finalizer_ms(ms);
}
else if (*data_size) {
+ if (ms->body_hash_present)
+ SHA1_Update(&ms->sha1,data,*data_size);
MHD_post_process(ms->post,data,*data_size);
*data_size = 0;
}
else {
+ if (ms->body_hash_present) {
+ unsigned char buf[SHA_DIGEST_LENGTH];
+ SHA1_Final(buf,&ms->sha1);
+ if (memcmp(ms->body_hash,buf,SHA_DIGEST_LENGTH)!=0) {
+ return do_resp(conn,ms,MHD_HTTP_FORBIDDEN,NULL,
+ "403 body hash mismatch\r\n");
+ }
+ }
+
int rc = MHD_HTTP_BAD_REQUEST;
key = kv_hash_lookup(ms->dict,"_key");
if (key) {
@@ -1609,13 +1623,26 @@ proxy_object_post (void *cctx, struct MHD_Connection *conn, const
char *url,
post_iterator,ms->dict);
if (!ms->post)
return MHD_NO;
+ if (ms->body_hash_present)
+ SHA1_Init(&ms->sha1);
gc_register_finalizer_ms(ms);
}
else if (*data_size) {
+ if (ms->body_hash_present)
+ SHA1_Update(&ms->sha1,data,*data_size);
MHD_post_process(ms->post,data,*data_size);
*data_size = 0;
}
else {
+ if (ms->body_hash_present) {
+ unsigned char buf[SHA_DIGEST_LENGTH];
+ SHA1_Final(buf,&ms->sha1);
+ if (memcmp(ms->body_hash,buf,SHA_DIGEST_LENGTH)!=0) {
+ return do_resp(conn,ms,MHD_HTTP_FORBIDDEN,NULL,
+ "403 body hash mismatch\r\n");
+ }
+ }
+
int rc = MHD_HTTP_BAD_REQUEST;
if (!kv_find_val(ms->dict,post_find,NULL)) {
op = kv_hash_lookup(ms->dict,"op");
@@ -2456,6 +2483,13 @@ oauth_param_find(char **argv, int argc, const char *key)
return -1;
}
+static bool
+stash_hash(unsigned char *shabuf, const char *b64hash)
+{
+ size_t len = SHA_DIGEST_LENGTH;
+ return base64_decode(b64hash, strlen(b64hash), (char *)shabuf, &len);
+}
+
static int
do_oauth (struct MHD_Connection *conn, my_state *ms,
const char *url, const char *method)
@@ -2472,6 +2506,7 @@ do_oauth (struct MHD_Connection *conn, my_state *ms,
const char *user_name;
const char *sig_method;
const char *sig_supplied, *sig_calculated;
+ const char *hash_supplied;
/*
* Don't recalculate everything in case of POST or long data piped.
@@ -2615,6 +2650,15 @@ do_oauth (struct MHD_Connection *conn, my_state *ms,
x = oauth_param_find(argv,argc,"oauth_body_hash");
if (x != -1) {
oargv[oargc++] = argv[x];
+
+ hash_supplied = oauth_param_val(argv[x]);
+ if (!hash_supplied ||
+ !stash_hash(ms->body_hash, hash_supplied)) {
+ do_resp(conn,ms,MHD_HTTP_INTERNAL_SERVER_ERROR,NULL,
+ "500 bad oauth_body_hash\r\n");
+ return 1;
+ }
+ ms->body_hash_present = true;
}
oauth_sign_array2_process(&oargc, &oargv, NULL, omethod, method,
diff --git a/state_defs.h b/state_defs.h
index 6b09c55..243791c 100644
--- a/state_defs.h
+++ b/state_defs.h
@@ -19,6 +19,7 @@
#include <stdbool.h>
#include <sys/queue.h>
#include <microhttpd.h>
+#include <openssl/sha.h>
#include "hash.h"
#include "mpipe.h"
#include "template.h"
@@ -50,6 +51,9 @@ typedef struct _my_state {
MHD_AccessHandlerCallback handler;
ms_state state;
bool authorized;
+ bool body_hash_present;
+ char *auth_hdr;
+ char *auth_user;
/* for GC library */
LIST_ENTRY(_my_state) gc_link;
/* for proxy ops */
@@ -65,6 +69,8 @@ typedef struct _my_state {
long rc;
/* for proxy puts (and logging) */
size_t size;
+ unsigned char body_hash[SHA_DIGEST_LENGTH];
+ SHA_CTX sha1;
/* for proxy puts, queries, and registrations */
struct MHD_Connection *conn;
/* for proxy queries */