summaryrefslogtreecommitdiff
path: root/fs/ubifs/master.c
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2019-05-14 10:33:22 +0200
committerRichard Weinberger <richard@nod.at>2019-07-08 19:43:52 +0200
commit817aa094842dfc3a6b98c9582d4a647827f66201 (patch)
tree68919bfade27218cdb9e66c8bcaa2f2aa32b685e /fs/ubifs/master.c
parent8ba0a2ab84b23b541a5d2ef25d759c94880e7457 (diff)
ubifs: support offline signed images
HMACs can only be generated on the system the UBIFS image is running on. To support offline signed images we add a PKCS#7 signature to the UBIFS image which can be created by mkfs.ubifs. Both the master node and the superblock need to be authenticated, during normal runtime both are protected with HMACs. For offline signature support however only a single signature is desired. We add a signature covering the superblock node directly behind it. To protect the master node a hash of the master node is added to the superblock which is used when the master node doesn't contain a HMAC. Transition to a read/write filesystem is also supported. During transition first the master node is rewritten with a HMAC (implicitly, it is written anyway as the FS is marked dirty). Afterwards the superblock is rewritten with a HMAC. Once after the image has been mounted read/write it is HMAC only, the signature is no longer required or even present on the filesystem. In an offline signed image the master node is authenticated by the superblock. In a transition to r/w we have to make sure that the master node is rewritten before the superblock node. In this case the master node gets a HMAC and its authenticity no longer depends on the superblock node. There are some cases in which the current code first writes the superblock node though, so with this patch writing of the superblock node is delayed until the master node is written. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Signed-off-by: Richard Weinberger <richard@nod.at>
Diffstat (limited to 'fs/ubifs/master.c')
-rw-r--r--fs/ubifs/master.c53
1 files changed, 47 insertions, 6 deletions
diff --git a/fs/ubifs/master.c b/fs/ubifs/master.c
index b42a768709c0..52a85c01397e 100644
--- a/fs/ubifs/master.c
+++ b/fs/ubifs/master.c
@@ -48,6 +48,39 @@ int ubifs_compare_master_node(struct ubifs_info *c, void *m1, void *m2)
return 0;
}
+/* mst_node_check_hash - Check hash of a master node
+ * @c: UBIFS file-system description object
+ * @mst: The master node
+ * @expected: The expected hash of the master node
+ *
+ * This checks the hash of a master node against a given expected hash.
+ * Note that we have two master nodes on a UBIFS image which have different
+ * sequence numbers and consequently different CRCs. To be able to match
+ * both master nodes we exclude the common node header containing the sequence
+ * number and CRC from the hash.
+ *
+ * Returns 0 if the hashes are equal, a negative error code otherwise.
+ */
+static int mst_node_check_hash(const struct ubifs_info *c,
+ const struct ubifs_mst_node *mst,
+ const u8 *expected)
+{
+ u8 calc[UBIFS_MAX_HASH_LEN];
+ const void *node = mst;
+
+ SHASH_DESC_ON_STACK(shash, c->hash_tfm);
+
+ shash->tfm = c->hash_tfm;
+
+ crypto_shash_digest(shash, node + sizeof(struct ubifs_ch),
+ UBIFS_MST_NODE_SZ - sizeof(struct ubifs_ch), calc);
+
+ if (ubifs_check_hash(c, expected, calc))
+ return -EPERM;
+
+ return 0;
+}
+
/**
* scan_for_master - search the valid master node.
* @c: UBIFS file-system description object
@@ -102,14 +135,22 @@ static int scan_for_master(struct ubifs_info *c)
if (!ubifs_authenticated(c))
return 0;
- err = ubifs_node_verify_hmac(c, c->mst_node,
- sizeof(struct ubifs_mst_node),
- offsetof(struct ubifs_mst_node, hmac));
- if (err) {
- ubifs_err(c, "Failed to verify master node HMAC");
- return -EPERM;
+ if (ubifs_hmac_zero(c, c->mst_node->hmac)) {
+ err = mst_node_check_hash(c, c->mst_node,
+ c->sup_node->hash_mst);
+ if (err)
+ ubifs_err(c, "Failed to verify master node hash");
+ } else {
+ err = ubifs_node_verify_hmac(c, c->mst_node,
+ sizeof(struct ubifs_mst_node),
+ offsetof(struct ubifs_mst_node, hmac));
+ if (err)
+ ubifs_err(c, "Failed to verify master node HMAC");
}
+ if (err)
+ return -EPERM;
+
return 0;
out: