Skip to content

Commit

Permalink
mkfs.ubifs: Add authentication support
Browse files Browse the repository at this point in the history
This adds support for authenticated UBIFS images. In authenticated
images all UBIFS nodes are hashed as described in the UBIFS
authentication whitepaper. Additionally the superblock node contains a
hash of the master node and itself is cryptographically signed in a node
following the superblock node. The signature is in PKCS #7 CMS format.

To generate an authenticated image these options are necessary:

--hash-algo=NAME     hash algorithm to use for signed images
                     (Valid options include sha1, sha256, sha512)
--auth-key=FILE      filename or PKCS #11 uri containing the authentication key
                     for signing
--auth-cert=FILE     Authentication certificate filename for signing. Unused
                     when certificate is provided via PKCS #11

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
  • Loading branch information
saschahauer authored and AgentD committed Aug 19, 2019
1 parent 3ef2627 commit a739b59
Show file tree
Hide file tree
Showing 7 changed files with 660 additions and 39 deletions.
3 changes: 2 additions & 1 deletion ubifs-utils/Makemodule.am
Expand Up @@ -19,7 +19,8 @@ mkfs_ubifs_SOURCES = \

if WITH_CRYPTO
mkfs_ubifs_SOURCES += ubifs-utils/mkfs.ubifs/crypto.c \
ubifs-utils/mkfs.ubifs/fscrypt.c
ubifs-utils/mkfs.ubifs/fscrypt.c \
ubifs-utils/mkfs.ubifs/sign.c
endif

mkfs_ubifs_LDADD = libmtd.a libubi.a $(ZLIB_LIBS) $(LZO_LIBS) $(ZSTD_LIBS) $(UUID_LIBS) $(LIBSELINUX_LIBS) $(OPENSSL_LIBS) -lm
Expand Down
12 changes: 12 additions & 0 deletions ubifs-utils/mkfs.ubifs/lpt.c
Expand Up @@ -22,6 +22,10 @@

#include "mkfs.ubifs.h"

#ifdef WITH_CRYPTO
#include <openssl/evp.h>
#endif

/**
* do_calc_lpt_geom - calculate sizes for the LPT area.
* @c: the UBIFS file-system description object
Expand Down Expand Up @@ -374,6 +378,7 @@ int create_lpt(struct ubifs_info *c)
struct ubifs_nnode *nnode = NULL;
void *buf = NULL, *p;
int *lsave = NULL;
unsigned int md_len;

pnode = malloc(sizeof(struct ubifs_pnode));
nnode = malloc(sizeof(struct ubifs_nnode));
Expand All @@ -386,6 +391,8 @@ int create_lpt(struct ubifs_info *c)
memset(pnode, 0 , sizeof(struct ubifs_pnode));
memset(nnode, 0 , sizeof(struct ubifs_nnode));

hash_digest_init();

c->lscan_lnum = c->main_first;

lnum = c->lpt_first;
Expand Down Expand Up @@ -429,6 +436,9 @@ int create_lpt(struct ubifs_info *c)
}
}
pack_pnode(c, p, pnode);

hash_digest_update(p, c->pnode_sz);

p += c->pnode_sz;
len += c->pnode_sz;
/*
Expand All @@ -439,6 +449,8 @@ int create_lpt(struct ubifs_info *c)
pnode->num += 1;
}

hash_digest_final(c->lpt_hash, &md_len);

row = c->lpt_hght - 1;
/* Add all nnodes, one level at a time */
while (1) {
Expand Down
172 changes: 136 additions & 36 deletions ubifs-utils/mkfs.ubifs/mkfs.ubifs.c
Expand Up @@ -68,6 +68,7 @@ static char *secontext;
* @lnum: LEB number
* @offs: offset
* @len: length
* @hash: hash of the node
*
* The index is recorded as a linked list which is sorted and used to create
* the bottom level of the on-flash index tree. The remaining levels of the
Expand All @@ -82,6 +83,7 @@ struct idx_entry {
int lnum;
int offs;
int len;
uint8_t hash[UBIFS_MAX_HASH_LEN];
};

/**
Expand Down Expand Up @@ -164,6 +166,12 @@ static unsigned long long creat_sqnum;

static const char *optstring = "d:r:m:o:D:yh?vVe:c:g:f:Fp:k:x:X:j:R:l:j:UQqaK:b:P:C:";

enum {
HASH_ALGO_OPTION = CHAR_MAX + 1,
AUTH_KEY_OPTION,
AUTH_CERT_OPTION,
};

static const struct option longopts[] = {
{"root", 1, NULL, 'r'},
{"min-io-size", 1, NULL, 'm'},
Expand Down Expand Up @@ -192,6 +200,9 @@ static const struct option longopts[] = {
{"key-descriptor", 1, NULL, 'b'},
{"padding", 1, NULL, 'P'},
{"cipher", 1, NULL, 'C'},
{"hash-algo", 1, NULL, HASH_ALGO_OPTION},
{"auth-key", 1, NULL, AUTH_KEY_OPTION},
{"auth-cert", 1, NULL, AUTH_CERT_OPTION},
{NULL, 0, NULL, 0}
};

Expand Down Expand Up @@ -242,6 +253,12 @@ static const char *helptext =
" (default = 4).\n"
"-C, --cipher=NAME Specify cipher to use for file level encryption\n"
" (default is \"AES-256-XTS\").\n"
" --hash-algo=NAME hash algorithm to use for signed images\n"
" (Valid options include sha1, sha256, sha512)\n"
" --auth-key=FILE filename or PKCS #11 uri containing the authentication key\n"
" for signing\n"
" --auth-cert=FILE Authentication certificate filename for signing. Unused\n"
" when certificate is provided via PKCS #11\n"
"-h, --help display this help text\n\n"
"Note, SIZE is specified in bytes, but it may also be specified in Kilobytes,\n"
"Megabytes, and Gigabytes if a KiB, MiB, or GiB suffix is used.\n\n"
Expand All @@ -261,7 +278,15 @@ static const char *helptext =
"when flashing the image and the second time when UBIFS is mounted and writes useful\n"
"data there. A proper UBI-aware flasher should skip such NAND pages, though. Note, this\n"
"flag may make the first mount very slow, because the \"free space fixup\" procedure\n"
"takes time. This feature is supported by the Linux kernel starting from version 3.0.\n";
"takes time. This feature is supported by the Linux kernel starting from version 3.0.\n"
"\n"
"mkfs.ubifs supports building signed images. For this the \"--hash-algo\",\n"
"\"--auth-key\" and \"--auth-cert\" options have to be specified.\n";

static inline uint8_t *ubifs_branch_hash(struct ubifs_branch *br)
{
return (void *)br + sizeof(*br) + c->key_len;
}

/**
* make_path - make a path name from a directory and a name.
Expand Down Expand Up @@ -753,14 +778,27 @@ static int get_options(int argc, char**argv)
}
break;
}
case 'C':
#ifdef WITH_CRYPTO
case 'C':
cipher_name = optarg;
break;
case HASH_ALGO_OPTION:
c->hash_algo_name = xstrdup(optarg);
break;
case AUTH_KEY_OPTION:
c->auth_key_filename = xstrdup(optarg);
break;
case AUTH_CERT_OPTION:
c->auth_cert_filename = xstrdup(optarg);
break;
}
#else
case 'C':
case HASH_ALGO_OPTION:
case AUTH_KEY_OPTION:
case X509_OPTION:
return err_msg("mkfs.ubifs was built without crypto support.");
#endif
break;
}
}

if (optind != argc && !output)
Expand Down Expand Up @@ -1063,9 +1101,10 @@ static void set_lprops(int lnum, int offs, int flags)
* @lnum: node LEB number
* @offs: node offset
* @len: node length
* @hash: hash of the node
*/
static int add_to_index(union ubifs_key *key, char *name, int name_len,
int lnum, int offs, int len)
int lnum, int offs, int len, const uint8_t *hash)
{
struct idx_entry *e;

Expand All @@ -1079,6 +1118,8 @@ static int add_to_index(union ubifs_key *key, char *name, int name_len,
e->lnum = lnum;
e->offs = offs;
e->len = len;
memcpy(e->hash, hash, c->hash_len);

if (!idx_list_first)
idx_list_first = e;
if (idx_list_last)
Expand Down Expand Up @@ -1137,6 +1178,7 @@ static int reserve_space(int len, int *lnum, int *offs)
static int add_node(union ubifs_key *key, char *name, int name_len, void *node, int len)
{
int err, lnum, offs, type = key_type(key);
uint8_t hash[UBIFS_MAX_HASH_LEN];

if (type == UBIFS_DENT_KEY || type == UBIFS_XENT_KEY) {
if (!name)
Expand All @@ -1156,7 +1198,9 @@ static int add_node(union ubifs_key *key, char *name, int name_len, void *node,
memcpy(leb_buf + offs, node, len);
memset(leb_buf + offs + len, 0xff, ALIGN(len, 8) - len);

add_to_index(key, name, name_len, lnum, offs, len);
ubifs_node_calc_hash(node, hash);

add_to_index(key, name, name_len, lnum, offs, len, hash);

return 0;
}
Expand Down Expand Up @@ -2298,6 +2342,7 @@ static int write_index(void)
struct ubifs_idx_node *idx;
struct ubifs_branch *br;
int child_cnt = 0, j, level, blnum, boffs, blen, blast_len, err;
uint8_t *hashes;

dbg_msg(1, "leaf node count: %zd", idx_cnt);

Expand All @@ -2321,6 +2366,9 @@ static int write_index(void)
cnt = idx_cnt / c->fanout;
if (idx_cnt % c->fanout)
cnt += 1;

hashes = xmalloc(c->hash_len * cnt);

p = idx_ptr;
blnum = head_lnum;
boffs = head_offs;
Expand All @@ -2345,8 +2393,11 @@ static int write_index(void)
br->lnum = cpu_to_le32((*p)->lnum);
br->offs = cpu_to_le32((*p)->offs);
br->len = cpu_to_le32((*p)->len);
memcpy(ubifs_branch_hash(br), (*p)->hash, c->hash_len);
}
add_idx_node(idx, child_cnt);

ubifs_node_calc_hash(idx, hashes + i * c->hash_len);
}
/* Write level 1 index nodes and above */
level = 0;
Expand Down Expand Up @@ -2423,11 +2474,18 @@ static int write_index(void)
*/
boffs += ALIGN(blen, 8);
p += pstep;

memcpy(ubifs_branch_hash(br),
hashes + bn * c->hash_len,
c->hash_len);
}
add_idx_node(idx, child_cnt);
ubifs_node_calc_hash(idx, hashes + i * c->hash_len);
}
}

memcpy(c->root_idx_hash, hashes, c->hash_len);

/* Free stuff */
for (i = 0; i < idx_cnt; i++) {
free(idx_ptr[i]->name);
Expand Down Expand Up @@ -2512,44 +2570,75 @@ static int ubifs_format_version(void)
*/
static int write_super(void)
{
struct ubifs_sb_node sup;

memset(&sup, 0, UBIFS_SB_NODE_SZ);

sup.ch.node_type = UBIFS_SB_NODE;
sup.key_hash = c->key_hash_type;
sup.min_io_size = cpu_to_le32(c->min_io_size);
sup.leb_size = cpu_to_le32(c->leb_size);
sup.leb_cnt = cpu_to_le32(c->leb_cnt);
sup.max_leb_cnt = cpu_to_le32(c->max_leb_cnt);
sup.max_bud_bytes = cpu_to_le64(c->max_bud_bytes);
sup.log_lebs = cpu_to_le32(c->log_lebs);
sup.lpt_lebs = cpu_to_le32(c->lpt_lebs);
sup.orph_lebs = cpu_to_le32(c->orph_lebs);
sup.jhead_cnt = cpu_to_le32(c->jhead_cnt);
sup.fanout = cpu_to_le32(c->fanout);
sup.lsave_cnt = cpu_to_le32(c->lsave_cnt);
sup.fmt_version = cpu_to_le32(ubifs_format_version());
sup.default_compr = cpu_to_le16(c->default_compr);
sup.rp_size = cpu_to_le64(c->rp_size);
sup.time_gran = cpu_to_le32(DEFAULT_TIME_GRAN);
uuid_generate_random(sup.uuid);
void *buf;
struct ubifs_sb_node *sup;
struct ubifs_sig_node *sig;
int err, len;

buf = xzalloc(c->leb_size);

sup = buf;
sig = buf + UBIFS_SB_NODE_SZ;

sup->ch.node_type = UBIFS_SB_NODE;
sup->key_hash = c->key_hash_type;
sup->min_io_size = cpu_to_le32(c->min_io_size);
sup->leb_size = cpu_to_le32(c->leb_size);
sup->leb_cnt = cpu_to_le32(c->leb_cnt);
sup->max_leb_cnt = cpu_to_le32(c->max_leb_cnt);
sup->max_bud_bytes = cpu_to_le64(c->max_bud_bytes);
sup->log_lebs = cpu_to_le32(c->log_lebs);
sup->lpt_lebs = cpu_to_le32(c->lpt_lebs);
sup->orph_lebs = cpu_to_le32(c->orph_lebs);
sup->jhead_cnt = cpu_to_le32(c->jhead_cnt);
sup->fanout = cpu_to_le32(c->fanout);
sup->lsave_cnt = cpu_to_le32(c->lsave_cnt);
sup->fmt_version = cpu_to_le32(ubifs_format_version());
sup->default_compr = cpu_to_le16(c->default_compr);
sup->rp_size = cpu_to_le64(c->rp_size);
sup->time_gran = cpu_to_le32(DEFAULT_TIME_GRAN);
sup->hash_algo = cpu_to_le16(c->hash_algo);
uuid_generate_random(sup->uuid);

if (verbose) {
char s[40];

uuid_unparse_upper(sup.uuid, s);
uuid_unparse_upper(sup->uuid, s);
printf("\tUUID: %s\n", s);
}
if (c->big_lpt)
sup.flags |= cpu_to_le32(UBIFS_FLG_BIGLPT);
sup->flags |= cpu_to_le32(UBIFS_FLG_BIGLPT);
if (c->space_fixup)
sup.flags |= cpu_to_le32(UBIFS_FLG_SPACE_FIXUP);
sup->flags |= cpu_to_le32(UBIFS_FLG_SPACE_FIXUP);
if (c->double_hash)
sup.flags |= cpu_to_le32(UBIFS_FLG_DOUBLE_HASH);
sup->flags |= cpu_to_le32(UBIFS_FLG_DOUBLE_HASH);
if (c->encrypted)
sup.flags |= cpu_to_le32(UBIFS_FLG_ENCRYPTION);
sup->flags |= cpu_to_le32(UBIFS_FLG_ENCRYPTION);
if (authenticated()) {
sup->flags |= cpu_to_le32(UBIFS_FLG_AUTHENTICATION);
memcpy(sup->hash_mst, c->mst_hash, c->hash_len);
}

return write_node(&sup, UBIFS_SB_NODE_SZ, UBIFS_SB_LNUM);
prepare_node(sup, UBIFS_SB_NODE_SZ);

err = sign_superblock_node(sup);
if (err)
goto out;

sig = (void *)(sup + 1);
prepare_node(sig, UBIFS_SIG_NODE_SZ + le32_to_cpu(sig->len));

len = do_pad(sig, UBIFS_SIG_NODE_SZ + le32_to_cpu(sig->len));

err = write_leb(UBIFS_SB_LNUM, UBIFS_SB_NODE_SZ + len, sup);
if (err)
goto out;

err = 0;
out:
free(buf);

return err;
}

/**
Expand Down Expand Up @@ -2592,6 +2681,11 @@ static int write_master(void)
mst.total_dark = cpu_to_le64(c->lst.total_dark);
mst.leb_cnt = cpu_to_le32(c->leb_cnt);

if (authenticated()) {
memcpy(mst.hash_root_idx, c->root_idx_hash, c->hash_len);
memcpy(mst.hash_lpt, c->lpt_hash, c->hash_len);
}

err = write_node(&mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM);
if (err)
return err;
Expand All @@ -2600,6 +2694,8 @@ static int write_master(void)
if (err)
return err;

mst_node_calc_hash(&mst, c->mst_hash);

return 0;
}

Expand Down Expand Up @@ -2864,6 +2960,10 @@ static int mkfs(void)
if (err)
goto out;

err = init_authentication();
if (err)
goto out;

err = write_data();
if (err)
goto out;
Expand All @@ -2884,11 +2984,11 @@ static int mkfs(void)
if (err)
goto out;

err = write_super();
err = write_master();
if (err)
goto out;

err = write_master();
err = write_super();
if (err)
goto out;

Expand Down

0 comments on commit a739b59

Please sign in to comment.