]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
First part of zfs-crypto. CCM support with 0-filled keys
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sun, 6 Nov 2011 12:18:27 +0000 (13:18 +0100)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sun, 6 Nov 2011 12:18:27 +0000 (13:18 +0100)
grub-core/fs/zfs/zfs.c
grub-core/lib/crypto.c
include/grub/crypto.h
include/grub/zfs/dmu.h
include/grub/zfs/dsl_dir.h
include/grub/zfs/zio.h

index 9658dea0d06044aff90ce07c8b8e10648d8f0737..9da4d70e2cbd6255f97c277ec096f96e7b8c7937 100644 (file)
@@ -52,6 +52,7 @@
 #include <grub/zfs/dsl_dir.h>
 #include <grub/zfs/dsl_dataset.h>
 #include <grub/deflate.h>
+#include <grub/crypto.h>
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
@@ -124,6 +125,23 @@ static grub_dl_t my_mod;
 #define        NBBY    8
 #endif
 
+enum grub_zfs_algo
+  {
+    GRUB_ZFS_ALGO_CCM,
+    GRUB_ZFS_ALGO_GCM,
+  };
+
+struct grub_zfs_key
+{
+  grub_uint64_t algo;
+  grub_uint8_t enc_nonce[13];
+  grub_uint8_t unused[3];
+  grub_uint8_t enc_key[48];
+  grub_uint8_t unknown_purpose_nonce[13];
+  grub_uint8_t unused2[3];
+  grub_uint8_t unknown_purpose_key[48];
+};
+
 extern grub_err_t lzjb_decompress (void *, void *, grub_size_t, grub_size_t);
 
 typedef grub_err_t zfs_decomp_func_t (void *s_start, void *d_start,
@@ -161,6 +179,14 @@ struct grub_zfs_device_desc
   int original;
 };
 
+struct subvolume
+{
+  dnode_end_t mdn;
+  grub_uint64_t obj;
+  grub_uint64_t case_insensitive;
+  grub_crypto_cipher_handle_t cipher;
+};
+
 struct grub_zfs_data
 {
   /* cache for a file block of the currently zfs_open()-ed file */
@@ -176,8 +202,8 @@ struct grub_zfs_data
   grub_zfs_endian_t dnode_endian;
 
   dnode_end_t mos;
-  dnode_end_t mdn;
   dnode_end_t dnode;
+  struct subvolume subvol;
 
   struct grub_zfs_device_desc *devices_attached;
   unsigned n_devices_attached;
@@ -292,6 +318,7 @@ static zio_checksum_info_t zio_checksum_table[ZIO_CHECKSUM_FUNCTIONS] = {
   {fletcher_4, 1, 0, "fletcher4"},
   {zio_checksum_SHA256, 1, 0, "SHA256"},
   {NULL, 0, 0, "zilog2"},
+  {zio_checksum_SHA256, 1, 0, "SHA256+MAC"},
 };
 
 /*
@@ -302,7 +329,8 @@ static zio_checksum_info_t zio_checksum_table[ZIO_CHECKSUM_FUNCTIONS] = {
  */
 static grub_err_t
 zio_checksum_verify (zio_cksum_t zc, grub_uint32_t checksum,
-                    grub_zfs_endian_t endian, char *buf, grub_size_t size)
+                    grub_zfs_endian_t endian, 
+                    char *buf, grub_size_t size)
 {
   zio_eck_t *zec = (zio_eck_t *) (buf + size) - 1;
   zio_checksum_info_t *ci = &zio_checksum_table[checksum];
@@ -312,7 +340,7 @@ zio_checksum_verify (zio_cksum_t zc, grub_uint32_t checksum,
     {
       grub_dprintf ("zfs", "unknown checksum function %d\n", checksum);
       return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, 
-                        "unknown checksum function %d", checksum);
+                "unknown checksum function %d", checksum);
     }
 
   if (ci->ci_eck)
@@ -326,10 +354,8 @@ zio_checksum_verify (zio_cksum_t zc, grub_uint32_t checksum,
   else
     ci->ci_func (buf, size, endian, &actual_cksum);
 
-  if ((actual_cksum.zc_word[0] != zc.zc_word[0]) 
-      || (actual_cksum.zc_word[1] != zc.zc_word[1]) 
-      || (actual_cksum.zc_word[2] != zc.zc_word[2]) 
-      || (actual_cksum.zc_word[3] != zc.zc_word[3]))
+  if (grub_memcmp (&actual_cksum, &zc,
+                  checksum != ZIO_CHECKSUM_SHA256_MAC ? 32 : 20) != 0)
     {
       grub_dprintf ("zfs", "checksum %s verification failed\n", ci->ci_name);
       grub_dprintf ("zfs", "actual checksum %016llx %016llx %016llx %016llx\n",
@@ -1410,16 +1436,67 @@ zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian, void *buf,
   return err;
 }
 
+static grub_err_t
+grub_ccm_decrypt (grub_crypto_cipher_handle_t cipher,
+                 grub_uint8_t *out, const grub_uint8_t *in,
+                 grub_size_t psize,
+                 void *mac_out, const void *nonce,
+                 unsigned l, unsigned m)
+{
+  grub_uint8_t iv[16];
+  grub_uint8_t mul[16];
+  grub_uint32_t mac[4];
+  unsigned i, j;
+  grub_err_t err;
+
+  grub_memcpy (iv + 1, nonce, 15 - l);
+
+  iv[0] = (l - 1) | (((m-2) / 2) << 3);
+  for (j = 0; j < l; j++)
+    iv[15 - j] = psize >> (8 * j);
+  err = grub_crypto_ecb_encrypt (cipher, mac, iv, 16);
+  if (err)
+    return err;
+
+  iv[0] = l - 1;
+
+  for (i = 0; i < (psize + 15) / 16; i++)
+    {
+      grub_size_t csize;
+      csize = 16;
+      if (csize > psize - 16 * i)
+       csize = psize - 16 * i;
+      for (j = 0; j < l; j++)
+       iv[15 - j] = (i + 1) >> (8 * j);
+      err = grub_crypto_ecb_encrypt (cipher, mul, iv, 16);
+      if (err)
+       return err;
+      grub_crypto_xor (out + 16 * i, in + 16 * i, mul, csize);
+      grub_crypto_xor (mac, mac, out + 16 * i, csize);
+      err = grub_crypto_ecb_encrypt (cipher, mac, mac, 16);
+      if (err)
+       return err;
+    }
+  for (j = 0; j < l; j++)
+    iv[15 - j] = 0;
+  err = grub_crypto_ecb_encrypt (cipher, mul, iv, 16);
+  if (err)
+    return err;
+  if (mac_out)
+    grub_crypto_xor (mac_out, mac, mul, m);
+  return GRUB_ERR_NONE;
+}
+
 /*
  * Read in a block of data, verify its checksum, decompress if needed,
  * and put the uncompressed data in buf.
  */
 static grub_err_t
-zio_read (blkptr_t * bp, grub_zfs_endian_t endian, void **buf, 
+zio_read (blkptr_t *bp, grub_zfs_endian_t endian, void **buf, 
          grub_size_t *size, struct grub_zfs_data *data)
 {
   grub_size_t lsize, psize;
-  unsigned int comp;
+  unsigned int comp, encrypted;
   char *compbuf = NULL;
   grub_err_t err;
   zio_cksum_t zc = bp->blk_cksum;
@@ -1429,6 +1506,7 @@ zio_read (blkptr_t * bp, grub_zfs_endian_t endian, void **buf,
 
   checksum = (grub_zfs_to_cpu64((bp)->blk_prop, endian) >> 40) & 0xff;
   comp = (grub_zfs_to_cpu64((bp)->blk_prop, endian)>>32) & 0xff;
+  encrypted = ((grub_zfs_to_cpu64((bp)->blk_prop, endian) >> 60) & 3);
   lsize = (BP_IS_HOLE(bp) ? 0 :
           (((grub_zfs_to_cpu64 ((bp)->blk_prop, endian) & 0xffff) + 1)
            << SPA_MINBLOCKSHIFT));
@@ -1447,7 +1525,7 @@ zio_read (blkptr_t * bp, grub_zfs_endian_t endian, void **buf,
 
   if (comp != ZIO_COMPRESS_OFF)
     {
-      compbuf = grub_malloc (psize);
+      compbuf = grub_malloc (ALIGN_UP (psize, 16));
       if (! compbuf)
        return grub_errno;
     }
@@ -1462,8 +1540,10 @@ zio_read (blkptr_t * bp, grub_zfs_endian_t endian, void **buf,
       *buf = NULL;
       return err;
     }
+  grub_memset (compbuf, 0, ALIGN_UP (psize, 16) - psize);
 
-  err = zio_checksum_verify (zc, checksum, endian, compbuf, psize);
+  err = zio_checksum_verify (zc, checksum, endian,
+                            compbuf, psize);
   if (err)
     {
       grub_dprintf ("zfs", "incorrect checksum\n");
@@ -1472,6 +1552,45 @@ zio_read (blkptr_t * bp, grub_zfs_endian_t endian, void **buf,
       return err;
     }
 
+  if (encrypted)
+    {
+      grub_uint32_t mac[4];
+      unsigned i;
+      grub_uint32_t sw[4];
+      
+      grub_memcpy (sw, &(bp)->blk_dva[encrypted], 16);
+      for (i = 0; i < 4; i++)
+       sw[i] = grub_cpu_to_be32 (grub_zfs_to_cpu32 (sw[i], endian));
+
+      if (!data->subvol.cipher)
+       {
+         grub_free (compbuf);
+         *buf = NULL;
+         return grub_error (GRUB_ERR_ACCESS_DENIED,
+                            "no decryption key available");;
+       }
+      err = grub_ccm_decrypt (data->subvol.cipher,
+                             (grub_uint8_t *) compbuf,
+                             (grub_uint8_t *) compbuf,
+                             psize, mac,
+                             sw + 1, 3, 12);
+      if (err)
+       {
+         grub_free (compbuf);
+         *buf = NULL;
+         return err;
+       }
+
+      for (i = 0; i < 3; i++)
+       if (grub_zfs_to_cpu32 (((grub_uint32_t *) &zc + 5)[i], endian)
+           != grub_be_to_cpu32 (mac[i]))
+         {
+           grub_free (compbuf);
+           *buf = NULL;
+           return grub_error (GRUB_ERR_BAD_FS, "MAC verification failed");
+         }
+    }
+
   if (comp != ZIO_COMPRESS_OFF)
     {
       *buf = grub_malloc (lsize);
@@ -1572,7 +1691,7 @@ dmu_read (dnode_end_t * dn, grub_uint64_t blkid, void **buf,
  */
 static grub_err_t
 mzap_lookup (mzap_phys_t * zapobj, grub_zfs_endian_t endian,
-            int objsize, char *name, grub_uint64_t * value,
+            int objsize, const char *name, grub_uint64_t * value,
             int case_insensitive)
 {
   int i, chunks;
@@ -1799,8 +1918,8 @@ zap_verify (zap_phys_t *zap, grub_zfs_endian_t endian)
   if (grub_zfs_to_cpu64 (zap->zap_magic, endian) != (grub_uint64_t) ZAP_MAGIC)
     return grub_error (GRUB_ERR_BAD_FS, "bad ZAP magic");
 
-  if (zap->zap_flags != 0)
-    return grub_error (GRUB_ERR_BAD_FS, "bad ZAP flags");
+  /*  if (zap->zap_flags != 0)
+      return grub_error (GRUB_ERR_BAD_FS, "bad ZAP flags");*/
 
   if (zap->zap_salt == 0)
     return grub_error (GRUB_ERR_BAD_FS, "bad ZAP salt");
@@ -1854,9 +1973,11 @@ fzap_lookup (dnode_end_t * zap_dnode, zap_phys_t * zap,
 /* XXX */
 static int
 fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
-            int NESTED_FUNC_ATTR (*hook) (const char *name, 
-                                          grub_uint64_t val), 
-            struct grub_zfs_data *data)
+             int NESTED_FUNC_ATTR (*hook) (const char *name,
+                                           const void *val_in,
+                                           grub_size_t nelem,
+                                           grub_size_t elemsize), 
+             struct grub_zfs_data *data)
 {
   zap_leaf_phys_t *l;
   void *l_in;
@@ -1918,9 +2039,9 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
       for (chunk = 0; chunk < ZAP_LEAF_NUMCHUNKS (blksft); chunk++)
          {
            char *buf;
-           struct zap_leaf_array *la;
            struct zap_leaf_entry *le;
-           grub_uint64_t val;
+           char *val;
+           grub_size_t val_length;
            le = ZAP_LEAF_ENTRY (l, blksft, chunk);
 
            /* Verify the chunk entry */
@@ -1940,24 +2061,28 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
              }
            buf[le->le_name_length] = 0;
 
-           if (le->le_int_size != 8 
-               || grub_zfs_to_cpu16 (le->le_value_length, endian) != 1)
-             continue;
+           val_length = ((int) le->le_value_length
+                         * (int) le->le_int_size);
+           val = grub_malloc (grub_zfs_to_cpu16 (val_length, endian));
+           if (zap_leaf_array_get (l, endian, blksft,
+                                   grub_zfs_to_cpu16 (le->le_value_chunk,
+                                                      endian),
+                                   val_length, val))
+             {
+               grub_free (buf);
+               grub_free (val);
+               continue;
+             }
 
-           /* get the uint64_t property value */
-           la = &ZAP_LEAF_CHUNK (l, blksft,
-                                 grub_zfs_to_cpu16 (le->le_value_chunk,
-                                                    endian)).l_array;
-           val = grub_be_to_cpu64 (la->la_array64);
-           if (hook (buf, val))
+           if (hook (buf, val, le->le_value_length, le->le_int_size))
              return 1;
            grub_free (buf);
+           grub_free (val);
          }
     }
   return 0;
 }
 
-
 /*
  * Read in the data of a zap object and find the value for a matching
  * property name.
@@ -2009,9 +2134,10 @@ zap_lookup (dnode_end_t * zap_dnode, char *name, grub_uint64_t * val,
 }
 
 static int
-zap_iterate (dnode_end_t * zap_dnode, 
-            int NESTED_FUNC_ATTR (*hook) (const char *name, grub_uint64_t val),
-            struct grub_zfs_data *data)
+zap_iterate_u64 (dnode_end_t * zap_dnode, 
+                int NESTED_FUNC_ATTR (*hook) (const char *name,
+                                              grub_uint64_t val),
+                struct grub_zfs_data *data)
 {
   grub_uint64_t block_type;
   int size;
@@ -2020,6 +2146,21 @@ zap_iterate (dnode_end_t * zap_dnode,
   int ret;
   grub_zfs_endian_t endian;
 
+  auto int NESTED_FUNC_ATTR transform (const char *name,
+                                      const void *val_in,
+                                      grub_size_t nelem,
+                                      grub_size_t elemsize);
+
+  int NESTED_FUNC_ATTR transform (const char *name,
+                                 const void *val_in,
+                                 grub_size_t nelem,
+                                 grub_size_t elemsize)
+  {
+    if (elemsize != sizeof (grub_uint64_t) || nelem != 1)
+      return 0;
+    return hook (name, grub_be_to_cpu64 (*(const grub_uint64_t *) val_in));
+  }
+
   /* Read in the first block of the zap object data. */
   size = grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec, zap_dnode->endian) << SPA_MINBLOCKSHIFT;
   err = dmu_read (zap_dnode, 0, &zapbuf, &endian, data);
@@ -2037,6 +2178,47 @@ zap_iterate (dnode_end_t * zap_dnode,
       return ret;
     }
   else if (block_type == ZBT_HEADER)
+    {
+      grub_dprintf ("zfs", "fat zap\n");
+      /* this is a fat zap */
+      ret = fzap_iterate (zap_dnode, zapbuf, transform, data);
+      grub_free (zapbuf);
+      return ret;
+    }
+  grub_error (GRUB_ERR_BAD_FS, "unknown ZAP type");
+  return 0;
+}
+
+static int
+zap_iterate (dnode_end_t * zap_dnode, 
+            int NESTED_FUNC_ATTR (*hook) (const char *name,
+                                          const void *val_in,
+                                          grub_size_t nelem,
+                                          grub_size_t elemsize),
+            struct grub_zfs_data *data)
+{
+  grub_uint64_t block_type;
+  int size;
+  void *zapbuf;
+  grub_err_t err;
+  int ret;
+  grub_zfs_endian_t endian;
+
+  /* Read in the first block of the zap object data. */
+  size = grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec, zap_dnode->endian) << SPA_MINBLOCKSHIFT;
+  err = dmu_read (zap_dnode, 0, &zapbuf, &endian, data);
+  if (err)
+    return 0;
+  block_type = grub_zfs_to_cpu64 (*((grub_uint64_t *) zapbuf), endian);
+
+  grub_dprintf ("zfs", "zap iterate\n");
+
+  if (block_type == ZBT_MICRO)
+    {
+      grub_error (GRUB_ERR_BAD_FS, "micro ZAP where FAT ZAP expected");
+      return 0;
+    }
+  if (block_type == ZBT_HEADER)
     {
       grub_dprintf ("zfs", "fat zap\n");
       /* this is a fat zap */
@@ -2124,10 +2306,10 @@ dnode_get (dnode_end_t * mdn, grub_uint64_t objnum, grub_uint8_t type,
  *
  */
 static grub_err_t
-dnode_get_path (dnode_end_t * mdn, const char *path_in, dnode_end_t * dn,
-               struct grub_zfs_data *data, int *case_insensitive)
+dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
+               struct grub_zfs_data *data)
 {
-  grub_uint64_t objnum, version, insensitivity;
+  grub_uint64_t objnum, version;
   char *cname, ch;
   grub_err_t err = GRUB_ERR_NONE;
   char *path, *path_buf;
@@ -2144,7 +2326,7 @@ dnode_get_path (dnode_end_t * mdn, const char *path_in, dnode_end_t * dn,
   dn_new->next = 0;
   dnode_path = root = dn_new;
 
-  err = dnode_get (mdn, MASTER_NODE_OBJ, DMU_OT_MASTER_NODE, 
+  err = dnode_get (&subvol->mdn, MASTER_NODE_OBJ, DMU_OT_MASTER_NODE, 
                   &(dnode_path->dn), data);
   if (err)
     {
@@ -2166,15 +2348,14 @@ dnode_get_path (dnode_end_t * mdn, const char *path_in, dnode_end_t * dn,
       return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "too new ZPL version");
     }
 
-  err = zap_lookup (&(dnode_path->dn), "casesensitivity", &insensitivity,
+  err = zap_lookup (&(dnode_path->dn), "casesensitivity",
+                   &subvol->case_insensitive,
                    data, 0);
   if (err == GRUB_ERR_FILE_NOT_FOUND)
     {
       grub_errno = GRUB_ERR_NONE;
-      insensitivity = 0;
+      subvol->case_insensitive = 0;
     }
-  if (case_insensitive)
-    *case_insensitive = insensitivity;
 
   err = zap_lookup (&(dnode_path->dn), ZFS_ROOT_OBJ, &objnum, data, 0);
   if (err)
@@ -2183,7 +2364,7 @@ dnode_get_path (dnode_end_t * mdn, const char *path_in, dnode_end_t * dn,
       return err;
     }
 
-  err = dnode_get (mdn, objnum, 0, &(dnode_path->dn), data);
+  err = dnode_get (&subvol->mdn, objnum, 0, &(dnode_path->dn), data);
   if (err)
     {
       grub_free (dn_new);
@@ -2237,7 +2418,8 @@ dnode_get_path (dnode_end_t * mdn, const char *path_in, dnode_end_t * dn,
          grub_free (path_buf);
          return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
        }
-      err = zap_lookup (&(dnode_path->dn), cname, &objnum, data, insensitivity);
+      err = zap_lookup (&(dnode_path->dn), cname, &objnum,
+                       data, subvol->case_insensitive);
       if (err)
        break;
 
@@ -2251,7 +2433,7 @@ dnode_get_path (dnode_end_t * mdn, const char *path_in, dnode_end_t * dn,
       dnode_path = dn_new;
 
       objnum = ZFS_DIRENT_OBJ (objnum);
-      err = dnode_get (mdn, objnum, 0, &(dnode_path->dn), data);
+      err = dnode_get (&subvol->mdn, objnum, 0, &(dnode_path->dn), data);
       if (err)
        break;
 
@@ -2545,15 +2727,93 @@ make_mdn (dnode_end_t * mdn, struct grub_zfs_data *data)
 }
 
 static grub_err_t
-dnode_get_fullpath (const char *fullpath, dnode_end_t * mdn,
-                   grub_uint64_t *mdnobj, dnode_end_t * dn, int *isfs,
-                   struct grub_zfs_data *data, int *case_insensitive)
+dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
+                   dnode_end_t * dn, int *isfs,
+                   struct grub_zfs_data *data)
 {
   char *fsname, *snapname;
   const char *ptr_at, *filename;
   grub_uint64_t headobj;
+  grub_uint64_t keychainobj;
   grub_err_t err;
 
+  auto int NESTED_FUNC_ATTR iterate_zap_key (const char *name,
+                                            const void *val_in,
+                                            grub_size_t nelem,
+                                            grub_size_t elemsize);
+  int NESTED_FUNC_ATTR iterate_zap_key (const char *name __attribute__ ((unused)),
+                                       const void *val_in,
+                                       grub_size_t nelem,
+                                       grub_size_t elemsize)
+  {
+    const struct grub_zfs_key *key = val_in;
+    grub_crypto_cipher_handle_t cipher;
+    grub_uint8_t wrapping_key[32], decrypted[32], mac[32];
+    unsigned keylen;
+
+    if (elemsize != 1 || nelem != sizeof (*key))
+      {
+       grub_dprintf ("zfs", "Unexpected key length %" PRIuGRUB_SIZE 
+                     " x %" PRIuGRUB_SIZE "\n", nelem, elemsize);
+       return 0;
+      }
+
+    if (grub_memcmp (key->enc_key + 32, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16)
+       == 0)
+      keylen = 16;
+    else if (grub_memcmp (key->enc_key + 40, "\0\0\0\0\0\0\0\0", 8) == 0)
+      keylen = 24;
+    else
+      keylen = 32;
+
+    grub_memset (wrapping_key, 0, sizeof (wrapping_key));
+
+    cipher = grub_crypto_cipher_open (GRUB_CIPHER_AES);
+    if (!cipher)
+      {
+       grub_errno = GRUB_ERR_NONE;
+       return 0;
+      }
+    err = grub_crypto_cipher_set_key (cipher, wrapping_key, keylen);
+    if (err)
+      {
+       grub_errno = GRUB_ERR_NONE;
+       return 0;
+      }
+
+    err = grub_ccm_decrypt (cipher, decrypted, key->unknown_purpose_key, 32,
+                           mac, key->unknown_purpose_nonce, 2, 16);
+    if (err || grub_crypto_memcmp (mac, key->unknown_purpose_key + 32, 16) != 0)
+      {
+       grub_dprintf ("zfs", "key loading failed\n");
+       grub_errno = GRUB_ERR_NONE;
+       return 0;
+      }
+
+    err = grub_ccm_decrypt (cipher, decrypted, key->enc_key, keylen, mac,
+                           key->enc_nonce, 2, 16);
+    if (err || grub_crypto_memcmp (mac, key->enc_key + keylen, 16) != 0)
+      {
+       grub_dprintf ("zfs", "key loading failed\n");
+       grub_errno = GRUB_ERR_NONE;
+       return 0;
+      }
+    subvol->cipher = grub_crypto_cipher_open (GRUB_CIPHER_AES);
+    if (!subvol->cipher)
+      {
+       grub_errno = GRUB_ERR_NONE;
+       return 0;
+      }
+    err = grub_crypto_cipher_set_key (subvol->cipher, decrypted, keylen);
+    if (err)
+      {
+       grub_errno = GRUB_ERR_NONE;
+       return 0;
+      }
+    
+    return 0;
+  }
+
   ptr_at = grub_strchr (fullpath, '@');
   if (! ptr_at)
     {
@@ -2605,29 +2865,47 @@ dnode_get_fullpath (const char *fullpath, dnode_end_t * mdn,
 
   headobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&dn->dn))->dd_head_dataset_obj, dn->endian);
 
-  grub_dprintf ("zfs", "endian = %d\n", mdn->endian);
+  grub_dprintf ("zfs", "endian = %d\n", subvol->mdn.endian);
 
-  err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, mdn, data);
+  err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, &subvol->mdn,
+                  data);
   if (err)
     {
       grub_free (fsname);
       grub_free (snapname);
       return err;
     }
-  grub_dprintf ("zfs", "endian = %d\n", mdn->endian);
+  grub_dprintf ("zfs", "endian = %d\n", subvol->mdn.endian);
+
+  keychainobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&dn->dn))->keychain, dn->endian);
+  if (keychainobj)
+    {
+      dnode_end_t keychain_dn;
+      err = dnode_get (&(data->mos), keychainobj, DMU_OT_DSL_KEYCHAIN,
+                      &keychain_dn, data);
+      if (err)
+       {
+         grub_free (fsname);
+         grub_free (snapname);
+         return err;
+       }
+      zap_iterate (&keychain_dn, iterate_zap_key, data);
+    }
+
 
   if (snapname)
     {
       grub_uint64_t snapobj;
 
-      snapobj = grub_zfs_to_cpu64 (((dsl_dataset_phys_t *) DN_BONUS (&mdn->dn))->ds_snapnames_zapobj, mdn->endian);
+      snapobj = grub_zfs_to_cpu64 (((dsl_dataset_phys_t *) DN_BONUS (&subvol->mdn.dn))->ds_snapnames_zapobj, subvol->mdn.endian);
 
       err = dnode_get (&(data->mos), snapobj, 
-                      DMU_OT_DSL_DS_SNAP_MAP, mdn, data);
+                      DMU_OT_DSL_DS_SNAP_MAP, &subvol->mdn, data);
       if (!err)
-       err = zap_lookup (mdn, snapname, &headobj, data, 0);
+       err = zap_lookup (&subvol->mdn, snapname, &headobj, data, 0);
       if (!err)
-       err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, mdn, data);
+       err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET,
+                        &subvol->mdn, data);
       if (err)
        {
          grub_free (fsname);
@@ -2636,12 +2914,11 @@ dnode_get_fullpath (const char *fullpath, dnode_end_t * mdn,
        }
     }
 
-  if (mdnobj)
-    *mdnobj = headobj;
+  subvol->obj = headobj;
 
-  make_mdn (mdn, data);
+  make_mdn (&subvol->mdn, data);
   
-  grub_dprintf ("zfs", "endian = %d\n", mdn->endian);
+  grub_dprintf ("zfs", "endian = %d\n", subvol->mdn.endian);
 
   if (*isfs)
     {
@@ -2649,7 +2926,7 @@ dnode_get_fullpath (const char *fullpath, dnode_end_t * mdn,
       grub_free (snapname);      
       return GRUB_ERR_NONE;
     }
-  err = dnode_get_path (mdn, filename, dn, data, case_insensitive);
+  err = dnode_get_path (subvol, filename, dn, data);
   grub_free (fsname);
   grub_free (snapname);
   return err;
@@ -3088,8 +3365,8 @@ grub_zfs_open (struct grub_file *file, const char *fsfilename)
   if (! data)
     return grub_errno;
 
-  err = dnode_get_fullpath (fsfilename, &(data->mdn), 0,
-                           &(data->dnode), &isfs, data, NULL);
+  err = dnode_get_fullpath (fsfilename, &(data->subvol),
+                           &(data->dnode), &isfs, data);
   if (err)
     {
       zfs_unmount (data);
@@ -3252,8 +3529,9 @@ grub_zfs_getmdnobj (grub_device_t dev, const char *fsfilename,
   if (! data)
     return grub_errno;
 
-  err = dnode_get_fullpath (fsfilename, &(data->mdn), mdnobj,
-                           &(data->dnode), &isfs, data, NULL);
+  err = dnode_get_fullpath (fsfilename, &(data->subvol),
+                           &(data->dnode), &isfs, data);
+  *mdnobj = data->subvol.obj;
   zfs_unmount (data);
   return err;
 }
@@ -3348,7 +3626,6 @@ grub_zfs_dir (grub_device_t device, const char *path,
   struct grub_zfs_data *data;
   grub_err_t err;
   int isfs;
-  int case_insensitive = 0;
   auto int NESTED_FUNC_ATTR iterate_zap (const char *name, grub_uint64_t val);
   auto int NESTED_FUNC_ATTR iterate_zap_fs (const char *name, 
                                            grub_uint64_t val);
@@ -3361,7 +3638,7 @@ grub_zfs_dir (grub_device_t device, const char *path,
     dnode_end_t dn;
     grub_memset (&info, 0, sizeof (info));
 
-    dnode_get (&(data->mdn), val, 0, &dn, data);
+    dnode_get (&(data->subvol.mdn), val, 0, &dn, data);
 
     if (dn.dn.dn_bonustype == DMU_OT_SA)
       {
@@ -3393,7 +3670,7 @@ grub_zfs_dir (grub_device_t device, const char *path,
        hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp));
        info.mtimeset = 1;
        info.mtime = grub_zfs_to_cpu64 (*(grub_uint64_t *) ((char *) sahdrp + hdrsize + SA_MTIME_OFFSET), dn.endian);
-       info.case_insensitive = case_insensitive;
+       info.case_insensitive = data->subvol.case_insensitive;
       }
     
     if (dn.dn.dn_bonustype == DMU_OT_ZNODE)
@@ -3448,8 +3725,7 @@ grub_zfs_dir (grub_device_t device, const char *path,
   data = zfs_mount (device);
   if (! data)
     return grub_errno;
-  err = dnode_get_fullpath (path, &(data->mdn), 0, &(data->dnode), &isfs, data,
-                           &case_insensitive);
+  err = dnode_get_fullpath (path, &(data->subvol), &(data->dnode), &isfs, data);
   if (err)
     {
       zfs_unmount (data);
@@ -3475,7 +3751,7 @@ grub_zfs_dir (grub_device_t device, const char *path,
          return err;
        }
 
-      zap_iterate (&dn, iterate_zap_fs, data);
+      zap_iterate_u64 (&dn, iterate_zap_fs, data);
       
       err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, &dn, data);
       if (err)
@@ -3494,7 +3770,7 @@ grub_zfs_dir (grub_device_t device, const char *path,
          return err;
        }
 
-      zap_iterate (&dn, iterate_zap_snap, data);
+      zap_iterate_u64 (&dn, iterate_zap_snap, data);
     }
   else
     {
@@ -3503,7 +3779,7 @@ grub_zfs_dir (grub_device_t device, const char *path,
          zfs_unmount (data);
          return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
        }
-      zap_iterate (&(data->dnode), iterate_zap, data);
+      zap_iterate_u64 (&(data->dnode), iterate_zap, data);
     }
   zfs_unmount (data);
   return grub_errno;
index 8876cc32695435b16b57a9ba7ed1c1560eed5333..f858be9c621cb20873e1011de6bf93f6d4076813 100644 (file)
@@ -210,9 +210,10 @@ grub_crypto_ecb_decrypt (grub_crypto_cipher_handle_t cipher,
 
 gcry_err_code_t
 grub_crypto_ecb_encrypt (grub_crypto_cipher_handle_t cipher,
-                        void *out, void *in, grub_size_t size)
+                        void *out, const void *in, grub_size_t size)
 {
-  grub_uint8_t *inptr, *outptr, *end;
+  const grub_uint8_t *inptr;
+  grub_uint8_t *outptr, *end;
   if (!cipher->cipher->encrypt)
     return GPG_ERR_NOT_SUPPORTED;
   if (size % cipher->cipher->blocksize != 0)
index 10368d99fc57832a8344ab73386784836cd46202..573893a3ed9e850abfcdda1d7ecd78c1ff179177 100644 (file)
@@ -203,7 +203,7 @@ grub_crypto_ecb_decrypt (grub_crypto_cipher_handle_t cipher,
 
 gcry_err_code_t
 grub_crypto_ecb_encrypt (grub_crypto_cipher_handle_t cipher,
-                        void *out, void *in, grub_size_t size);
+                        void *out, const void *in, grub_size_t size);
 gcry_err_code_t
 grub_crypto_cbc_encrypt (grub_crypto_cipher_handle_t cipher,
                         void *out, void *in, grub_size_t size,
@@ -251,11 +251,13 @@ extern gcry_md_spec_t _gcry_digest_spec_sha1;
 extern gcry_md_spec_t _gcry_digest_spec_sha256;
 extern gcry_md_spec_t _gcry_digest_spec_sha512;
 extern gcry_md_spec_t _gcry_digest_spec_crc32;
+extern gcry_cipher_spec_t _gcry_cipher_spec_aes;
 #define GRUB_MD_MD5 ((const gcry_md_spec_t *) &_gcry_digest_spec_md5)
 #define GRUB_MD_SHA1 ((const gcry_md_spec_t *) &_gcry_digest_spec_sha1)
 #define GRUB_MD_SHA256 ((const gcry_md_spec_t *) &_gcry_digest_spec_sha256)
 #define GRUB_MD_SHA512 ((const gcry_md_spec_t *) &_gcry_digest_spec_sha512)
 #define GRUB_MD_CRC32 ((const gcry_md_spec_t *) &_gcry_digest_spec_crc32)
+#define GRUB_CIPHER_AES ((const gcry_cipher_spec_t *) &_gcry_cipher_spec_aes)
 
 /* Implement PKCS#5 PBKDF2 as per RFC 2898.  The PRF to use is HMAC variant
    of digest supplied by MD.  Inputs are the password P of length PLEN,
index bee317e8a4e2ea1bdaa3d51053480471fe0f6062..8fc6dc5b504cf48079180b3a9899cb69a166a9cb 100644 (file)
@@ -88,6 +88,7 @@ typedef enum dmu_object_type {
        DMU_OT_SA_MASTER_NODE,          /* ZAP */
        DMU_OT_SA_ATTR_REGISTRATION,    /* ZAP */
        DMU_OT_SA_ATTR_LAYOUTS,         /* ZAP */
+       DMU_OT_DSL_KEYCHAIN = 54,
        DMU_OT_NUMTYPES
 } dmu_object_type_t;
 
index 41d77c790c1d8f2826ae245c196d063af730dcf0..6542a77feb9232d29c9734ab16762cf53c60c5fd 100644 (file)
@@ -42,7 +42,9 @@ typedef struct dsl_dir_phys {
        grub_uint64_t dd_reserved;
        grub_uint64_t dd_props_zapobj;
        grub_uint64_t dd_deleg_zapobj;  /* dataset permissions */
-       grub_uint64_t dd_pad[20]; /* pad out to 256 bytes for good measure */
+       grub_uint64_t unused[7];
+        grub_uint64_t keychain;
+       grub_uint64_t unused2[12];
 } dsl_dir_phys_t;
 
 #endif /* _SYS_DSL_DIR_H */
index 29451593f1f68504fd64f2cd87ed4225e61791e9..8b645c0630dd0422174d44866cfe6a2bbd09b66b 100644 (file)
@@ -65,6 +65,7 @@ enum zio_checksum {
        ZIO_CHECKSUM_FLETCHER_4,
        ZIO_CHECKSUM_SHA256,
        ZIO_CHECKSUM_ZILOG2,
+       ZIO_CHECKSUM_SHA256_MAC,
        ZIO_CHECKSUM_FUNCTIONS
 };