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
This commit is contained in:
@@ -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).
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
|
||||
+52
-27
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user