changeset 7:976121190b2d

Authentication verification almost working: signatures not computing correctly
author Adam Chlipala <adam@chlipala.net>
date Tue, 28 Dec 2010 19:57:25 -0500
parents 99496175078b
children 870d99055dd1
files include/openid.h src/c/openid.c src/ur/openid.ur src/ur/openidFfi.urs
diffstat 4 files changed, 48 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/include/openid.h	Mon Dec 27 13:18:02 2010 -0500
+++ b/include/openid.h	Tue Dec 28 19:57:25 2010 -0500
@@ -20,4 +20,4 @@
 uw_OpenidFfi_outputs uw_OpenidFfi_direct(uw_context, uw_Basis_string url, uw_OpenidFfi_inputs);
 uw_OpenidFfi_outputs uw_OpenidFfi_indirect(uw_context, uw_Basis_string fields);
 
-uw_Basis_string uw_OpenidFfi_sha256(uw_context, uw_Basis_string);
+uw_Basis_string uw_OpenidFfi_sha256(uw_context, uw_Basis_string key, uw_Basis_string data);
--- a/src/c/openid.c	Mon Dec 27 13:18:02 2010 -0500
+++ b/src/c/openid.c	Tue Dec 28 19:57:25 2010 -0500
@@ -4,6 +4,7 @@
 #include <openssl/evp.h>
 #include <openssl/buffer.h>
 #include <openssl/sha.h>
+#include <openssl/hmac.h>
 #include <curl/curl.h>
 #include <expat.h>
 
@@ -25,8 +26,6 @@
 }
 
 uw_unit uw_OpenidFfi_init(uw_context ctx) {
-  
-
   curl_global_init(CURL_GLOBAL_ALL);
 
   return uw_unit_v;
@@ -74,9 +73,6 @@
   }
 }
 
-static void XMLCALL endElement(void *userData, const XML_Char *name) {
-}
-
 typedef struct {
   XML_Parser parser;
   int any_errors;
@@ -115,7 +111,7 @@
   cd.parser = XML_ParserCreate(NULL);
   XML_SetUserData(cd.parser, &ep);
   uw_push_cleanup(ctx, (void (*)(void *))XML_ParserFree, cd.parser);
-  XML_SetElementHandler(cd.parser, startElement, endElement);
+  XML_SetStartElementHandler(cd.parser, startElement);
 
   curl_easy_setopt(c, CURLOPT_URL, id);
   curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, write_discovery_data);
@@ -215,14 +211,13 @@
         break;
       }
 
+      *colon = 0;
+
       newline = strchr(colon+1, '\n');
 
-      if (!newline) {
-        *s = 0;
+      if (!newline)
         break;
-      }
 
-      *colon = 0;
       *newline = 0;
       s = newline+1;
     }
@@ -284,28 +279,44 @@
 
 static uw_Basis_string base64(uw_context ctx, unsigned char *input, int length) {
   BIO *bmem, *b64;
-  BUF_MEM *bptr;
 
   b64 = BIO_new(BIO_f_base64());
+  BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
   bmem = BIO_new(BIO_s_mem());
-  b64 = BIO_push(b64, bmem);
+  BIO_push(b64, bmem);
   BIO_write(b64, input, length);
   (void)BIO_flush(b64);
-  BIO_get_mem_ptr(b64, &bptr);
 
-  char *buff = uw_malloc(ctx, bptr->length);
-  memcpy(buff, bptr->data, bptr->length-1);
-  buff[bptr->length-1] = 0;
+  int len = BIO_ctrl_pending(bmem);
+  char *buff = uw_malloc(ctx, len+1);
+  BIO_read(bmem, buff, len);
+  buff[len] = 0;
 
   BIO_free_all(b64);
 
   return buff;
 }
 
-uw_Basis_string uw_OpenidFfi_sha256(uw_context ctx, uw_Basis_string s) {
-  unsigned char out[SHA256_DIGEST_LENGTH];
+static void unbase64(unsigned char *input, int length, unsigned char *buffer, int bufferLength)
+{
+  BIO *b64, *bmem;
 
-  SHA256((unsigned char *)s, strlen(s), out);
+  b64 = BIO_new(BIO_f_base64());
+  BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
+  bmem = BIO_new_mem_buf(input, length);
+  BIO_push(b64, bmem);
+  BIO_read(b64, buffer, bufferLength);
 
-  return base64(ctx, out, sizeof out);
+  BIO_free_all(bmem);
 }
+
+uw_Basis_string uw_OpenidFfi_sha256(uw_context ctx, uw_Basis_string key, uw_Basis_string data) {
+  unsigned char keyBin[SHA256_DIGEST_LENGTH], out[EVP_MAX_MD_SIZE];
+  unsigned outLen;
+
+  unbase64((unsigned char *)key, strlen(key), keyBin, sizeof keyBin);
+  memset(key, sizeof key, 0);
+
+  HMAC(EVP_sha256(), keyBin, sizeof keyBin, (unsigned char *)data, strlen(data), out, &outLen);
+  return base64(ctx, out, outLen);
+}
--- a/src/ur/openid.ur	Mon Dec 27 13:18:02 2010 -0500
+++ b/src/ur/openid.ur	Tue Dec 28 19:57:25 2010 -0500
@@ -34,8 +34,8 @@
 
 fun association url =
     secret <- oneOrNoRows1 (SELECT associations.Handle, associations.Key
-                             FROM associations
-                             WHERE associations.Endpoint = {[url]});
+                            FROM associations
+                            WHERE associations.Endpoint = {[url]});
     case secret of
         Some r => return (Association r)
       | None =>
@@ -44,6 +44,8 @@
         OpenidFfi.addInput is "openid.assoc_type" "HMAC-SHA256";
         OpenidFfi.addInput is "openid.session_type" "no-encryption";
 
+        debug ("Contacting " ^ url);
+
         os <- OpenidFfi.direct url is;
         case OpenidFfi.getOutput os "error" of
             Some v => return (AssError v)
@@ -57,6 +59,8 @@
                      dml (INSERT INTO associations (Endpoint, Handle, Key, Expires)
                           VALUES ({[url]}, {[handle]}, {[key]}, {[addSeconds tm expires]}));
                      return (Association {Handle = handle, Key = key}))
+              | (None, _, _) => return (AssError "Missing assoc_handle")
+              | (_, None, _) => return (AssError "Missing mac_key")
               | _ => return (AssError "Missing fields in response from OP")
 
 fun eatFragment s =
@@ -64,7 +68,7 @@
         Some (_, s') => s'
       | _ => s
 
-datatype handle_result = HandleOk of string | HandleError of string
+datatype handle_result = HandleOk of {Endpoint : string, Key : string} | HandleError of string
 
 fun verifyHandle os id =
     ep <- discover (eatFragment id);
@@ -81,7 +85,7 @@
                 if assoc.Handle <> handle then
                     return (HandleError "Association handles don't match")
                 else
-                    return (HandleOk ep)
+                    return (HandleOk {Endpoint = ep, Key = assoc.Key})
 
 table nonces : { Endpoint : string, Nonce : string, Expires : time }
   PRIMARY KEY (Endpoint, Nonce)
@@ -92,7 +96,7 @@
       | Some (date, s) =>
         case String.split s #"Z" of
             None => None
-          | Some (time, _) => read (date ^ " " ^ time)
+          | Some (time, _) => readUtc (date ^ " " ^ time)
 
 fun verifyNonce os ep =
     case OpenidFfi.getOutput os "openid.response_nonce" of
@@ -114,11 +118,12 @@
                 if b then
                     return (Some "Duplicate nonce")
                 else
+                    debug ("Nonce expires: " ^ show exp);
                     dml (INSERT INTO nonces (Endpoint, Nonce, Expires)
                          VALUES ({[ep]}, {[nonce]}, {[exp]}));
                     return None
 
-fun verifySig os =
+fun verifySig os key =
     case OpenidFfi.getOutput os "openid.signed" of
         None => return (Some "Missing openid.signed in OP response")
       | Some signed =>
@@ -148,10 +153,11 @@
                     None => return (Some "openid.signed mentions missing field")
                   | Some nvps =>
                     let
-                        val sign' = OpenidFfi.sha256 nvps
+                        val sign' = OpenidFfi.sha256 key nvps
                     in
                         debug ("Fields: " ^ signed);
                         debug ("Nvps: " ^ nvps);
+                        debug ("Key: " ^ key);
                         debug ("His: " ^ sign);
                         debug ("Mine: " ^ sign');
                         if sign' = sign then
@@ -181,7 +187,7 @@
                          errO <- verifyHandle os id;
                          case errO of
                              HandleError s => error <xml>{[s]}</xml>
-                           | HandleOk ep =>
+                           | HandleOk {Endpoint = ep, Key = key} =>
                              errO <- verifyReturnTo os;
                              case errO of
                                  Some s => error <xml>{[s]}</xml>
@@ -190,7 +196,7 @@
                                  case errO of
                                      Some s => error <xml>{[s]}</xml>
                                    | None =>
-                                     errO <- verifySig os;
+                                     errO <- verifySig os key;
                                      case errO of
                                          Some s => error <xml>{[s]}</xml>
                                        | None => return <xml>Identity: {[id]}</xml>)
--- a/src/ur/openidFfi.urs	Mon Dec 27 13:18:02 2010 -0500
+++ b/src/ur/openidFfi.urs	Tue Dec 28 19:57:25 2010 -0500
@@ -15,4 +15,4 @@
 val direct : string -> inputs -> transaction outputs
 val indirect : queryString -> transaction outputs
 
-val sha256 : string -> string
+val sha256 : string -> string -> string