added uuid support for EVM
authorDmitry Kasatkin <dmitry.kasatkin@intel.com>
Mon, 11 Feb 2013 11:55:32 +0000 (13:55 +0200)
committerDmitry Kasatkin <dmitry.kasatkin@intel.com>
Mon, 11 Feb 2013 14:07:30 +0000 (16:07 +0200)
Latest version of EVM uses file system UUID as part of an HMAC
calculation to prevent pasting of inode metadata from other file
systems. This patch adds support for adding file system UUID
to HMAC calculation. It is necessary to specify '-u -' or '--uuid -'
on evmctl command line.

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
README
src/evmctl.c

diff --git a/README b/README
index 7b2c001..8daeb36 100644 (file)
--- a/README
+++ b/README
@@ -3,10 +3,20 @@ ima-evm-utils - IMA/EVM signing utility
 
 Contents:
 
-   1. Key generation
-   2. Initialization
-   3. Signing
 
+   1. Key and signature formats
+   2. Key generation
+   3. Initialization
+   4. Signing
+
+
+Key and signature formats
+-------------------------
+
+EVM support (v2) in latest version of the kernel adds the file system UUID to
+the HMAC calculation. It is controlled by the CONFIG_EVM_HMAC_VERSION and
+version 2 is enabled by default. To include the UUID to the signature calculation,
+it is necessary to provide '--uuid -' or '-u -' parameter to the 'sign' command.
 
 Key generation
 --------------
@@ -61,17 +71,19 @@ Here is an example script /etc/initramfs-tools/scripts/local-top/ima.sh
 Signing
 -------
 
+Signing for using new the EVM HMAC format is done using '-u -' or '--uuid -' parameter.
+
 Sign file with EVM signature and use hash value for IMA - common case
 
-    $ evmctl sign --imahash test.txt
+    $ evmctl sign [-u -] --imahash test.txt
 
 Sign file with both IMA and EVM signatures - for immutable files
 
-    $ evmctl sign --imasig test.txt
+    $ evmctl sign [-u -] --imasig test.txt
 
 Label whole filesystem with EVM signatures
 
-    $ find / \( -fstype rootfs -o -fstype ext4 \) -exec evmctl sign --imahash '{}' \;
+    $ find / \( -fstype rootfs -o -fstype ext4 \) -exec evmctl sign [-u -] --imahash '{}' \;
 
 Label filesystem in fix mode - kernel sets correct values to IMA and EVM xattrs
 
index bac98a0..1f01176 100644 (file)
@@ -44,6 +44,7 @@
 #include <syslog.h>
 #include <attr/xattr.h>
 #include <dirent.h>
+#include <ctype.h>
 
 #include <openssl/sha.h>
 #include <openssl/rsa.h>
@@ -152,6 +153,7 @@ static int binkey;
 static char *keypass;
 static int sigfile;
 static int modsig;
+static char *uuid_str;
 
 struct command cmds[];
 static void print_usage(struct command *cmd);
@@ -309,7 +311,7 @@ static void calc_keyid(uint8_t *keyid, char *str, const unsigned char *pkey, int
 
        /* sha1[12 - 19] is exactly keyid from gpg file */
        memcpy(keyid, sha1 + 12, 8);
-       log_debug("keyid:\n");
+       log_debug("keyid: ");
        log_debug_dump(keyid, 8);
 
        id = __be64_to_cpup((__be64 *) keyid);
@@ -394,6 +396,75 @@ static int find_xattr(const char *list, int list_size, const char *xattr)
        return 0;
 }
 
+static int hex_to_bin(char ch)
+{
+       if ((ch >= '0') && (ch <= '9'))
+               return ch - '0';
+       ch = tolower(ch);
+       if ((ch >= 'a') && (ch <= 'f'))
+               return ch - 'a' + 10;
+       return -1;
+}
+
+static void pack_uuid(const char *uuid_str, char *to)
+{
+       int i;
+       for (i = 0; i < 16; ++i) {
+               *to++ = (hex_to_bin(*uuid_str) << 4) |
+                       (hex_to_bin(*(uuid_str + 1)));
+               uuid_str += 2;
+               switch (i) {
+               case 3:
+               case 5:
+               case 7:
+               case 9:
+                       uuid_str++;
+                       continue;
+               }
+       }
+}
+
+static int get_uuid(struct stat *st, char *uuid)
+{
+       uint32_t dev;
+       unsigned minor, major;
+       char path[PATH_MAX], _uuid[37];
+       FILE *fp;
+       size_t len;
+
+       if (uuid_str[0] != '-') {
+               pack_uuid(uuid_str, uuid);
+               return 0;
+       }
+
+       dev = st->st_dev;
+       major = (dev & 0xfff00) >> 8;
+       minor = (dev & 0xff) | ((dev >> 12) & 0xfff00);
+
+       log_debug("dev: %u:%u\n", major, minor);
+       sprintf(path, "blkid -s UUID -o value /dev/block/%u:%u", major, minor);
+
+       fp = popen(path, "r");
+       if (!fp) {
+               log_err("popen() failed\n");
+               return -1;
+       }
+
+       len = fread(_uuid, 1, sizeof(_uuid), fp);
+       pclose(fp);
+       if (len != sizeof(_uuid)) {
+               log_err("fread() failed\n");
+               return -1;
+       }
+
+       pack_uuid(_uuid, uuid);
+
+       log_info("uuid: ");
+       log_dump(uuid, 16);
+
+       return 0;
+}
+
 static int calc_evm_hash(const char *file, unsigned char *hash)
 {
        struct stat st;
@@ -405,6 +476,7 @@ static int calc_evm_hash(const char *file, unsigned char *hash)
        char xattr_value[1024];
        char list[1024];
        ssize_t list_size;
+       char uuid[16];
 
        fd = open(file, 0);
        if (fd < 0) {
@@ -470,6 +542,19 @@ static int calc_evm_hash(const char *file, unsigned char *hash)
                log_err("EVP_DigestUpdate() failed\n");
                return 1;
        }
+
+       if (uuid_str) {
+               err = get_uuid(&st, uuid);
+               if (err)
+                       return -1;
+
+               err = EVP_DigestUpdate(&ctx, (const unsigned char *)uuid, sizeof(uuid));
+               if (!err) {
+                       log_err("EVP_DigestUpdate() failed\n");
+                       return 1;
+               }
+       }
+
        err = EVP_DigestFinal(&ctx, hash, &mdlen);
        if (!err) {
                log_err("EVP_DigestFinal() failed\n");
@@ -1296,6 +1381,7 @@ static struct option opts[] = {
        {"pass", 1, 0, 'p'},
        {"sigfile", 0, 0, 'f'},
        {"modsig", 0, 0, 'm'},
+       {"uuid", 1, 0, 'u'},
        {}
 
 };
@@ -1308,7 +1394,7 @@ int main(int argc, char *argv[])
        g_argc = argc;
 
        while (1) {
-               c = getopt_long(argc, argv, "hvnsda:bp:f", opts, &lind);
+               c = getopt_long(argc, argv, "hvnsda:bp:fu:", opts, &lind);
                if (c == -1)
                        break;
 
@@ -1348,6 +1434,9 @@ int main(int argc, char *argv[])
                        modsig = 1;
                        xattr = 0;
                        break;
+               case 'u':
+                       uuid_str = optarg;
+                       break;
                case '?':
                        exit(1);
                        break;