From 31f7586d7359058c601154e0026ad983ef22ca98 Mon Sep 17 00:00:00 2001 From: Mariusz Zaborski Date: Wed, 9 May 2018 20:53:38 +0000 Subject: [PATCH] Introduce the 'n' flag for the geli attach command. If the 'n' flag is provided the provided key number will be used to decrypt device. This can be used combined with dryrun to verify if the key is set correctly. This can be also used to determine which key slot we want to change on already attached device. Reviewed by: allanjude Differential Revision: https://reviews.freebsd.org/D15309 --- sbin/geom/class/eli/geli.8 | 4 ++ sbin/geom/class/eli/geom_eli.c | 7 +-- stand/geli/geliboot.c | 6 +-- sys/geom/eli/g_eli.c | 4 +- sys/geom/eli/g_eli.h | 2 + sys/geom/eli/g_eli_ctl.c | 22 ++++++++-- sys/geom/eli/g_eli_key.c | 79 ++++++++++++++++++++++------------ 7 files changed, 85 insertions(+), 39 deletions(-) diff --git a/sbin/geom/class/eli/geli.8 b/sbin/geom/class/eli/geli.8 index 25565ee58fa5..e4a48cf625f7 100644 --- a/sbin/geom/class/eli/geli.8 +++ b/sbin/geom/class/eli/geli.8 @@ -68,6 +68,7 @@ utility: .Nm .Cm attach .Op Fl Cdprv +.Op Fl n Ar keyno .Op Fl j Ar passfile .Op Fl k Ar keyfile .Ar prov @@ -407,6 +408,9 @@ Probably a better choice is the option for the .Cm detach subcommand. +.It Fl n Ar keyno +Specifies the index number of the Master Key copy to use (could be 0 or 1). +If the index number is not provided all keys will be tested. .It Fl j Ar passfile Specifies a file which contains the passphrase component of the User Key (or part of it). diff --git a/sbin/geom/class/eli/geom_eli.c b/sbin/geom/class/eli/geom_eli.c index 69693f2d6821..f6ed6a88fb4f 100644 --- a/sbin/geom/class/eli/geom_eli.c +++ b/sbin/geom/class/eli/geom_eli.c @@ -86,7 +86,7 @@ static int eli_backup_create(struct gctl_req *req, const char *prov, * * init [-bdgPTv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] [-s sectorsize] [-V version] prov * label - alias for 'init' - * attach [-Cdprv] [-j passfile] [-k keyfile] prov + * attach [-Cdprv] [-n keyno] [-j passfile] [-k keyfile] prov * detach [-fl] prov ... * stop - alias for 'detach' * onetime [-d] [-a aalgo] [-e ealgo] [-l keylen] prov @@ -149,11 +149,12 @@ struct g_command class_commands[] = { { 'd', "detach", NULL, G_TYPE_BOOL }, { 'j', "passfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, { 'k', "keyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, + { 'n', "keyno", "-1", G_TYPE_NUMBER }, { 'p', "nopassphrase", NULL, G_TYPE_BOOL }, { 'r', "readonly", NULL, G_TYPE_BOOL }, G_OPT_SENTINEL }, - "[-Cdprv] [-j passfile] [-k keyfile] prov" + "[-Cdprv] [-n keyno] [-j passfile] [-k keyfile] prov" }, { "detach", 0, NULL, { @@ -1129,7 +1130,7 @@ eli_setkey_detached(struct gctl_req *req, const char *prov, } /* Decrypt Master Key. */ - error = g_eli_mkey_decrypt(md, key, mkey, &nkey); + error = g_eli_mkey_decrypt_any(md, key, mkey, &nkey); bzero(key, sizeof(key)); if (error != 0) { bzero(md, sizeof(*md)); diff --git a/stand/geli/geliboot.c b/stand/geli/geliboot.c index f475f4178cf7..9ae8fcaab775 100644 --- a/stand/geli/geliboot.c +++ b/stand/geli/geliboot.c @@ -121,14 +121,14 @@ geli_findkey(struct geli_entry *ge, struct dsk *dskp, u_char *mkey) int i; if (ge->keybuf_slot >= 0) { - if (g_eli_mkey_decrypt(&ge->md, saved_keys[ge->keybuf_slot], + if (g_eli_mkey_decrypt_any(&ge->md, saved_keys[ge->keybuf_slot], mkey, &keynum) == 0) { return (0); } } for (i = 0; i < nsaved_keys; i++) { - if (g_eli_mkey_decrypt(&ge->md, saved_keys[i], mkey, + if (g_eli_mkey_decrypt_any(&ge->md, saved_keys[i], mkey, &keynum) == 0) { ge->keybuf_slot = i; return (0); @@ -266,7 +266,7 @@ geli_attach(struct geli_entry *ge, struct dsk *dskp, const char *passphrase, g_eli_crypto_hmac_final(&ctx, key, 0); - error = g_eli_mkey_decrypt(&geli_e->md, key, mkey, &keynum); + error = g_eli_mkey_decrypt_any(&geli_e->md, key, mkey, &keynum); if (error == -1) { explicit_bzero(mkey, sizeof(mkey)); explicit_bzero(key, sizeof(key)); diff --git a/sys/geom/eli/g_eli.c b/sys/geom/eli/g_eli.c index d0f4f1d39fe0..17f607d6c0bf 100644 --- a/sys/geom/eli/g_eli.c +++ b/sys/geom/eli/g_eli.c @@ -1086,7 +1086,7 @@ g_eli_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) memcpy(key, keybuf->kb_ents[i].ke_data, sizeof(key)); - if (g_eli_mkey_decrypt(&md, key, + if (g_eli_mkey_decrypt_any(&md, key, mkey, &nkey) == 0 ) { explicit_bzero(key, sizeof(key)); goto have_key; @@ -1161,7 +1161,7 @@ g_eli_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) /* * Decrypt Master-Key. */ - error = g_eli_mkey_decrypt(&md, key, mkey, &nkey); + error = g_eli_mkey_decrypt_any(&md, key, mkey, &nkey); bzero(key, sizeof(key)); if (error == -1) { if (i == tries) { diff --git a/sys/geom/eli/g_eli.h b/sys/geom/eli/g_eli.h index af936eac5250..b46728570aa9 100644 --- a/sys/geom/eli/g_eli.h +++ b/sys/geom/eli/g_eli.h @@ -688,6 +688,8 @@ void g_eli_crypto_ivgen(struct g_eli_softc *sc, off_t offset, u_char *iv, void g_eli_mkey_hmac(unsigned char *mkey, const unsigned char *key); int g_eli_mkey_decrypt(const struct g_eli_metadata *md, + const unsigned char *key, unsigned char *mkey, unsigned keyp); +int g_eli_mkey_decrypt_any(const struct g_eli_metadata *md, const unsigned char *key, unsigned char *mkey, unsigned *nkeyp); int g_eli_mkey_encrypt(unsigned algo, const unsigned char *key, unsigned keylen, unsigned char *mkey); diff --git a/sys/geom/eli/g_eli_ctl.c b/sys/geom/eli/g_eli_ctl.c index e4655a178bea..75fcd9ee48fb 100644 --- a/sys/geom/eli/g_eli_ctl.c +++ b/sys/geom/eli/g_eli_ctl.c @@ -60,8 +60,8 @@ g_eli_ctl_attach(struct gctl_req *req, struct g_class *mp) const char *name; u_char *key, mkey[G_ELI_DATAIVKEYLEN]; int *nargs, *detach, *readonly, *dryrun; - int keysize, error; - u_int nkey; + int keysize, error, nkey; + intmax_t *valp; g_topology_assert(); @@ -81,6 +81,17 @@ g_eli_ctl_attach(struct gctl_req *req, struct g_class *mp) return; } + valp = gctl_get_paraml(req, "keyno", sizeof(*valp)); + if (valp == NULL) { + gctl_error(req, "No '%s' argument.", "keyno"); + return; + } + nkey = *valp; + if (nkey < -1 || nkey >= G_ELI_MAXMKEYS) { + gctl_error(req, "Invalid '%s' argument.", "keyno"); + return; + } + readonly = gctl_get_paraml(req, "readonly", sizeof(*readonly)); if (readonly == NULL) { gctl_error(req, "No '%s' argument.", "readonly"); @@ -129,7 +140,10 @@ g_eli_ctl_attach(struct gctl_req *req, struct g_class *mp) return; } - error = g_eli_mkey_decrypt(&md, key, mkey, &nkey); + if (nkey == -1) + error = g_eli_mkey_decrypt_any(&md, key, mkey, &nkey); + else + error = g_eli_mkey_decrypt(&md, key, mkey, nkey); explicit_bzero(key, keysize); if (error == -1) { explicit_bzero(&md, sizeof(md)); @@ -981,7 +995,7 @@ g_eli_ctl_resume(struct gctl_req *req, struct g_class *mp) return; } - error = g_eli_mkey_decrypt(&md, key, mkey, &nkey); + error = g_eli_mkey_decrypt_any(&md, key, mkey, &nkey); explicit_bzero(key, keysize); if (error == -1) { explicit_bzero(&md, sizeof(md)); diff --git a/sys/geom/eli/g_eli_key.c b/sys/geom/eli/g_eli_key.c index e03314fe11a9..a47a852f6ec9 100644 --- a/sys/geom/eli/g_eli_key.c +++ b/sys/geom/eli/g_eli_key.c @@ -103,54 +103,79 @@ g_eli_mkey_hmac(unsigned char *mkey, const unsigned char *key) } /* - * Find and decrypt Master Key encrypted with 'key'. - * Return decrypted Master Key number in 'nkeyp' if not NULL. + * Find and decrypt Master Key encrypted with 'key' at slot 'nkey'. * Return 0 on success, > 0 on failure, -1 on bad key. */ int g_eli_mkey_decrypt(const struct g_eli_metadata *md, const unsigned char *key, - unsigned char *mkey, unsigned *nkeyp) + unsigned char *mkey, unsigned nkey) { unsigned char tmpmkey[G_ELI_MKEYLEN]; unsigned char enckey[SHA512_MDLEN]; /* Key for encryption. */ const unsigned char *mmkey; - int bit, error, nkey; + int bit, error; - if (nkeyp != NULL) - *nkeyp = -1; + if (nkey > G_ELI_MKEYLEN) + return (-1); /* * The key for encryption is: enckey = HMAC_SHA512(Derived-Key, 1) */ g_eli_crypto_hmac(key, G_ELI_USERKEYLEN, "\x01", 1, enckey, 0); - mmkey = md->md_mkeys; - for (nkey = 0; nkey < G_ELI_MAXMKEYS; nkey++, mmkey += G_ELI_MKEYLEN) { - bit = (1 << nkey); - if (!(md->md_keys & bit)) - continue; - bcopy(mmkey, tmpmkey, G_ELI_MKEYLEN); - error = g_eli_crypto_decrypt(md->md_ealgo, tmpmkey, - G_ELI_MKEYLEN, enckey, md->md_keylen); - if (error != 0) { - explicit_bzero(tmpmkey, sizeof(tmpmkey)); - explicit_bzero(enckey, sizeof(enckey)); - return (error); - } - if (g_eli_mkey_verify(tmpmkey, key)) { - bcopy(tmpmkey, mkey, G_ELI_DATAIVKEYLEN); - explicit_bzero(tmpmkey, sizeof(tmpmkey)); - explicit_bzero(enckey, sizeof(enckey)); - if (nkeyp != NULL) - *nkeyp = nkey; - return (0); - } + mmkey = md->md_mkeys + G_ELI_MKEYLEN * nkey; + bit = (1 << nkey); + if (!(md->md_keys & bit)) + return (-1); + bcopy(mmkey, tmpmkey, G_ELI_MKEYLEN); + error = g_eli_crypto_decrypt(md->md_ealgo, tmpmkey, + G_ELI_MKEYLEN, enckey, md->md_keylen); + if (error != 0) { + explicit_bzero(tmpmkey, sizeof(tmpmkey)); + explicit_bzero(enckey, sizeof(enckey)); + return (error); + } + if (g_eli_mkey_verify(tmpmkey, key)) { + bcopy(tmpmkey, mkey, G_ELI_DATAIVKEYLEN); + explicit_bzero(tmpmkey, sizeof(tmpmkey)); + explicit_bzero(enckey, sizeof(enckey)); + return (0); } explicit_bzero(enckey, sizeof(enckey)); explicit_bzero(tmpmkey, sizeof(tmpmkey)); + return (-1); } +/* + * Find and decrypt Master Key encrypted with 'key'. + * Return decrypted Master Key number in 'nkeyp' if not NULL. + * Return 0 on success, > 0 on failure, -1 on bad key. + */ +int +g_eli_mkey_decrypt_any(const struct g_eli_metadata *md, + const unsigned char *key, unsigned char *mkey, unsigned *nkeyp) +{ + int error, nkey; + + if (nkeyp != NULL) + *nkeyp = -1; + + error = -1; + for (nkey = 0; nkey < G_ELI_MAXMKEYS; nkey++) { + error = g_eli_mkey_decrypt(md, key, mkey, nkey); + if (error == 0) { + if (nkeyp != NULL) + *nkeyp = nkey; + break; + } else if (error > 0) { + break; + } + } + + return (error); +} + /* * Encrypt the Master-Key and calculate HMAC to be able to verify it in the * future.