Skip to content

Commit

Permalink
geli: split the initalization of HMAC
Browse files Browse the repository at this point in the history
GELI allows to read a user key from a standard input.
However if user initialize multiple providers at once, the standard
input will be empty for the second and next providers.
This caused GELI to encrypt a master key with an empty key file.

This commits initialize the HMAC with the key file, and then reuse the
finalized structure to generate different encryption keys for different
providers.

Reported by:	Nathan Dorfman
Tested by:	philip
Security:	FreeBSD-SA-23:01.geli
Security:	CVE-2023-0751
  • Loading branch information
oshogbo authored and tetlowgm committed Feb 8, 2023
1 parent 8c784bb commit 5fff096
Showing 1 changed file with 54 additions and 18 deletions.
72 changes: 54 additions & 18 deletions lib/geom/eli/geom_eli.c
Original file line number Diff line number Diff line change
Expand Up @@ -571,27 +571,35 @@ eli_genkey_passphrase(struct gctl_req *req, struct g_eli_metadata *md, bool new,
return (0);
}

static unsigned char *
eli_genkey(struct gctl_req *req, struct g_eli_metadata *md, unsigned char *key,
bool new)
static bool
eli_init_key_hmac_ctx(struct gctl_req *req, struct hmac_ctx *ctx, bool new)
{
struct hmac_ctx ctx;
bool nopassphrase;
int nfiles;
bool nopassphrase;

nopassphrase =
gctl_get_int(req, new ? "nonewpassphrase" : "nopassphrase");

g_eli_crypto_hmac_init(&ctx, NULL, 0);

nfiles = eli_genkey_files(req, new, "keyfile", &ctx, NULL, 0);
if (nfiles == -1)
return (NULL);
else if (nfiles == 0 && nopassphrase) {
g_eli_crypto_hmac_init(ctx, NULL, 0);
nfiles = eli_genkey_files(req, new, "keyfile", ctx, NULL, 0);
if (nfiles == -1) {
return (false);
} else if (nfiles == 0 && nopassphrase) {
gctl_error(req, "No key components given.");
return (NULL);
return (false);
}

return (true);
}

static unsigned char *
eli_genkey(struct gctl_req *req, const struct hmac_ctx *ctxtemplate,
struct g_eli_metadata *md, unsigned char *key, bool new)
{
struct hmac_ctx ctx;

memcpy(&ctx, ctxtemplate, sizeof(ctx));

if (eli_genkey_passphrase(req, md, new, &ctx) == -1)
return (NULL);

Expand All @@ -600,6 +608,22 @@ eli_genkey(struct gctl_req *req, struct g_eli_metadata *md, unsigned char *key,
return (key);
}

static unsigned char *
eli_genkey_single(struct gctl_req *req, struct g_eli_metadata *md,
unsigned char *key, bool new)
{
struct hmac_ctx ctx;
unsigned char *rkey;

if (!eli_init_key_hmac_ctx(req, &ctx, new)) {
return (NULL);
}
rkey = eli_genkey(req, &ctx, md, key, new);
explicit_bzero(&ctx, sizeof(ctx));

return (rkey);
}

static int
eli_metadata_read(struct gctl_req *req, const char *prov,
struct g_eli_metadata *md)
Expand Down Expand Up @@ -711,6 +735,7 @@ eli_init(struct gctl_req *req)
intmax_t val;
int error, i, nargs, nparams, param;
const int one = 1;
struct hmac_ctx ctxtemplate;

nargs = gctl_get_int(req, "nargs");
if (nargs <= 0) {
Expand Down Expand Up @@ -844,6 +869,10 @@ eli_init(struct gctl_req *req)
*/
nparams = req->narg - nargs - 1;

/* Generate HMAC context template. */
if (!eli_init_key_hmac_ctx(req, &ctxtemplate, true))
return;

/* Create new child request for each provider and issue to kernel */
for (i = 0; i < nargs; i++) {
r = gctl_get_handle();
Expand Down Expand Up @@ -885,7 +914,7 @@ eli_init(struct gctl_req *req)
arc4random_buf(md.md_mkeys, sizeof(md.md_mkeys));

/* Generate user key. */
if (eli_genkey(r, &md, key, true) == NULL) {
if (eli_genkey(r, &ctxtemplate, &md, key, true) == NULL) {
/*
* Error generating key - details added to geom request
* by eli_genkey().
Expand Down Expand Up @@ -1009,6 +1038,7 @@ eli_init(struct gctl_req *req)

/* Clear the cached metadata, including keys. */
explicit_bzero(&md, sizeof(md));
explicit_bzero(&ctxtemplate, sizeof(ctxtemplate));
}

static void
Expand All @@ -1020,6 +1050,7 @@ eli_attach(struct gctl_req *req)
off_t mediasize;
int i, nargs, nparams, param;
const int one = 1;
struct hmac_ctx ctxtemplate;

nargs = gctl_get_int(req, "nargs");
if (nargs <= 0) {
Expand All @@ -1035,6 +1066,10 @@ eli_attach(struct gctl_req *req)
*/
nparams = req->narg - nargs - 1;

/* Generate HMAC context template. */
if (!eli_init_key_hmac_ctx(req, &ctxtemplate, false))
return;

/* Create new child request for each provider and issue to kernel */
for (i = 0; i < nargs; i++) {
r = gctl_get_handle();
Expand Down Expand Up @@ -1064,7 +1099,7 @@ eli_attach(struct gctl_req *req)
goto out;
}

if (eli_genkey(r, &md, key, false) == NULL) {
if (eli_genkey(r, &ctxtemplate, &md, key, false) == NULL) {
/*
* Error generating key - details added to geom request
* by eli_genkey().
Expand Down Expand Up @@ -1098,6 +1133,7 @@ eli_attach(struct gctl_req *req)

/* Clear sensitive data from memory. */
explicit_bzero(cached_passphrase, sizeof(cached_passphrase));
explicit_bzero(&ctxtemplate, sizeof(ctxtemplate));
}

static void
Expand Down Expand Up @@ -1295,7 +1331,7 @@ eli_setkey_attached(struct gctl_req *req, struct g_eli_metadata *md)
old = md->md_iterations;

/* Generate key for Master Key encryption. */
if (eli_genkey(req, md, key, true) == NULL) {
if (eli_genkey_single(req, md, key, true) == NULL) {
explicit_bzero(key, sizeof(key));
return;
}
Expand Down Expand Up @@ -1330,7 +1366,7 @@ eli_setkey_detached(struct gctl_req *req, const char *prov,
}

/* Generate key for Master Key decryption. */
if (eli_genkey(req, md, key, false) == NULL) {
if (eli_genkey_single(req, md, key, false) == NULL) {
explicit_bzero(key, sizeof(key));
return;
}
Expand Down Expand Up @@ -1388,7 +1424,7 @@ eli_setkey_detached(struct gctl_req *req, const char *prov,
explicit_bzero(mkey, sizeof(mkey));

/* Generate key for Master Key encryption. */
if (eli_genkey(req, md, key, true) == NULL) {
if (eli_genkey_single(req, md, key, true) == NULL) {
explicit_bzero(key, sizeof(key));
explicit_bzero(md, sizeof(*md));
return;
Expand Down Expand Up @@ -1534,7 +1570,7 @@ eli_resume(struct gctl_req *req)
return;
}

if (eli_genkey(req, &md, key, false) == NULL) {
if (eli_genkey_single(req, &md, key, false) == NULL) {
explicit_bzero(key, sizeof(key));
return;
}
Expand Down

0 comments on commit 5fff096

Please sign in to comment.