capdev: fix capuse hashing, remove 'todo' panic
authorFergus Simpson <afergs@google.com>
Fri, 13 Jan 2017 19:13:28 +0000 (11:13 -0800)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 18 Jan 2017 18:27:55 +0000 (13:27 -0500)
Brings the capability device into a working state by fixing two hashing
bugs and removing a todo panic.

The first bug was in the call to capuse - the SHA256 member from a
different enum than was expected by the function was used. The same
index (1) in the expected enum was for SHA1 hashing. This meant the
produced hash was always the wrong type.

The second bug was in the usage of the return of the hashing function -
it returns a 32-byte binary representation, but it was used as a 64-byte
ASCII representation. This patch implements code to change the binary
representation into ASCII - 1 byte per nibble.

There was a todo panic that was triggered when both "from" and "to"
parameters were provided. It has been removed since it works now.

Change-Id: I24a0c546176db6d2347bf824f3803c60d4f5b0b1
Signed-off-by: Fergus Simpson <afergs@google.com>
Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/drivers/dev/capability.c

index 3c511ae..aab09a5 100644 (file)
 #include <crypto/2id.h>
 #include <crypto/2sha.h>
 
+#include <ctype.h>
+
 enum {
-       Hashlen = VB2_SHA256_BLOCK_SIZE,
+       Hashlen = VB2_MAX_DIGEST_SIZE * 2,
        Maxhash = 256,
 };
 
@@ -37,7 +39,7 @@ enum {
  */
 struct Caphash {
        struct Caphash *next;
-       char hash[Hashlen];
+       char hash[Hashlen + 1];
 };
 
 struct {
@@ -55,7 +57,7 @@ enum {
 /* caphash must be last */
 struct dirtab capdir[] = {
        {".",       {Qdir, 0, QTDIR}, 0, DMDIR | 0500},
-       {"capuse",  {Quse}, 0, 0222,},
+       {"capuse",  {Quse},           0, 0222,},
        {"caphash", {Qhash},          0, 0200,},
 };
 int ncapdir = ARRAY_SIZE(capdir);
@@ -116,19 +118,15 @@ static struct chan *capopen(struct chan *c, int omode)
        return c;
 }
 
-/*
-  static char*
-  hashstr(uint8_t *hash)
-  {
-  static char buf[2*Hashlen+1];
-  int i;
-
-  for(i = 0; i < Hashlen; i++)
-  sprint(buf+2*i, "%2.2x", hash[i]);
-  buf[2*Hashlen] = 0;
-  return buf;
-  }
-*/
+size_t __hashstr(char *buf, uint8_t *hash, size_t bytes_to_split)
+{
+       int i;
+
+       for (i = 0; i < bytes_to_split; i++)
+               snprintf(buf + 2 * i, 3, "%02x", hash[i]);
+
+       return bytes_to_split;
+}
 
 static struct Caphash *remcap(uint8_t *hash)
 {
@@ -204,7 +202,8 @@ static long capwrite(struct chan *c, void *va, long n, int64_t m)
 {
        struct Caphash *p;
        char *cp;
-       uint8_t hash[Hashlen];
+       uint8_t hash[Hashlen + 1] = {0};
+       char *hashstr = NULL;
        char *key, *from, *to;
        char err[256];
        int ret;
@@ -214,9 +213,11 @@ static long capwrite(struct chan *c, void *va, long n, int64_t m)
        case Qhash:
                if (!iseve())
                        error(EPERM, "permission denied: you must be eve");
-               if (n < Hashlen)
+               if (n < VB2_SHA256_DIGEST_SIZE * 2)
                        error(EIO, "Short read: on Qhash");
                memmove(hash, va, Hashlen);
+               for (int i = 0; i < Hashlen; i++)
+                       hash[i] = tolower(hash[i]);
                addcap(hash);
                break;
 
@@ -225,6 +226,7 @@ static long capwrite(struct chan *c, void *va, long n, int64_t m)
                cp = NULL;
                if (waserror()) {
                        kfree(cp);
+                       kfree(hashstr);
                        nexterror();
                }
                cp = kzmalloc(n + 1, 0);
@@ -237,33 +239,37 @@ static long capwrite(struct chan *c, void *va, long n, int64_t m)
                        error(EIO, "short read: Quse");
                *key++ = 0;
 
-               ret = hmac(VB2_ALG_RSA1024_SHA256, key, strlen(key),
-                          from, strlen(from), hash, sizeof(hash));
+               ret = hmac(VB2_HASH_SHA256, key, strlen(key),
+                          from, strlen(from), hash, Hashlen);
                if (ret)
                        error(EINVAL, "HMAC failed");
 
-               p = remcap(hash);
+               // Convert to ASCII text
+               hashstr = (char *)kzmalloc(sizeof(hash), MEM_WAIT);
+               ret = __hashstr(hashstr, hash, VB2_SHA256_DIGEST_SIZE);
+               if (ret != VB2_SHA256_DIGEST_SIZE)
+                       error(EINVAL, "hash is wrong length");
+
+               p = remcap((uint8_t *)hashstr);
                if (p == NULL) {
                        snprintf(err, sizeof(err), "invalid capability %s@%s", from, key);
                        error(EINVAL, err);
                }
 
+               kfree(hashstr);
+               hashstr = NULL;
+
                /* if a from user is supplied, make sure it matches */
                to = strchr(from, '@');
                if (to == NULL) {
                        to = from;
                } else {
                        *to++ = 0;
-                       panic("todo");
-                       /*
                        if (strcmp(from, current->user.name) != 0)
                                error(EINVAL, "capability must match user");
-                       */
                }
 
                /* set user id */
-               // TODO: make user a char *, not a fixed array.
-               //kstrdup(&current->user.name to);
                // In the original user names were NULL-terminated; ensure
                // that is still the case.
                if (strlen(to) > sizeof(current->user.name) - 1)
@@ -272,7 +278,6 @@ static long capwrite(struct chan *c, void *va, long n, int64_t m)
                proc_set_username(current, to);
                //up->basepri = PriNormal;
 
-
                kfree(p);
                kfree(cp);
                poperror();