Hide length of geli passphrase during boot.
Introduce additional flag to the geli which allows to restore previous behavior. Reviewed by: AllanJude@, cem@ (previous version) MFC: 1 month Relnotes: yes Differential Revision: https://reviews.freebsd.org/D11751
This commit is contained in:
parent
b92e8635f9
commit
3453dc72ad
4
UPDATING
4
UPDATING
@ -51,6 +51,10 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 12.x IS SLOW:
|
|||||||
|
|
||||||
****************************** SPECIAL WARNING: ******************************
|
****************************** SPECIAL WARNING: ******************************
|
||||||
|
|
||||||
|
20170826:
|
||||||
|
During boot the geli passphrase will be hidden. To restore previous
|
||||||
|
behavior see geli(8) configuration options.
|
||||||
|
|
||||||
20170825:
|
20170825:
|
||||||
Move PMTUD blackhole counters to TCPSTATS and remove them from bare
|
Move PMTUD blackhole counters to TCPSTATS and remove them from bare
|
||||||
sysctl values. Minor nit, but requires a rebuild of both world/kernel
|
sysctl values. Minor nit, but requires a rebuild of both world/kernel
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd August 3, 2016
|
.Dd August 26, 2017
|
||||||
.Dt GELI 8
|
.Dt GELI 8
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -51,7 +51,7 @@ utility:
|
|||||||
.Pp
|
.Pp
|
||||||
.Nm
|
.Nm
|
||||||
.Cm init
|
.Cm init
|
||||||
.Op Fl bgPTv
|
.Op Fl bdgPTv
|
||||||
.Op Fl a Ar aalgo
|
.Op Fl a Ar aalgo
|
||||||
.Op Fl B Ar backupfile
|
.Op Fl B Ar backupfile
|
||||||
.Op Fl e Ar ealgo
|
.Op Fl e Ar ealgo
|
||||||
@ -88,7 +88,7 @@ utility:
|
|||||||
.Ar prov
|
.Ar prov
|
||||||
.Nm
|
.Nm
|
||||||
.Cm configure
|
.Cm configure
|
||||||
.Op Fl bBgGtT
|
.Op Fl bBdDgGtT
|
||||||
.Ar prov ...
|
.Ar prov ...
|
||||||
.Nm
|
.Nm
|
||||||
.Cm setkey
|
.Cm setkey
|
||||||
@ -279,6 +279,9 @@ To inhibit backups, you can use
|
|||||||
.Pa none
|
.Pa none
|
||||||
as the
|
as the
|
||||||
.Ar backupfile .
|
.Ar backupfile .
|
||||||
|
.It Fl d
|
||||||
|
While booting from this encrypted root filesystem enable visibility of
|
||||||
|
passphrase length.
|
||||||
.It Fl e Ar ealgo
|
.It Fl e Ar ealgo
|
||||||
Encryption algorithm to use.
|
Encryption algorithm to use.
|
||||||
Currently supported algorithms are:
|
Currently supported algorithms are:
|
||||||
@ -490,6 +493,12 @@ For more information, see the description of the
|
|||||||
subcommand.
|
subcommand.
|
||||||
.It Fl B
|
.It Fl B
|
||||||
Remove the BOOT flag from the given providers.
|
Remove the BOOT flag from the given providers.
|
||||||
|
.It Fl d
|
||||||
|
While booting from this encrypted root filesystem enable visibility of
|
||||||
|
passphrase length.
|
||||||
|
.It Fl D
|
||||||
|
While booting from this encrypted root filesystem disable visibility of
|
||||||
|
passphrase length.
|
||||||
.It Fl g
|
.It Fl g
|
||||||
Enable booting from this encrypted root filesystem.
|
Enable booting from this encrypted root filesystem.
|
||||||
The boot loader prompts for the passphrase and loads
|
The boot loader prompts for the passphrase and loads
|
||||||
|
@ -82,7 +82,7 @@ static int eli_backup_create(struct gctl_req *req, const char *prov,
|
|||||||
/*
|
/*
|
||||||
* Available commands:
|
* Available commands:
|
||||||
*
|
*
|
||||||
* init [-bgPTv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] [-s sectorsize] [-V version] 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'
|
* label - alias for 'init'
|
||||||
* attach [-dprv] [-j passfile] [-k keyfile] prov
|
* attach [-dprv] [-j passfile] [-k keyfile] prov
|
||||||
* detach [-fl] prov ...
|
* detach [-fl] prov ...
|
||||||
@ -107,6 +107,7 @@ struct g_command class_commands[] = {
|
|||||||
{ 'a', "aalgo", "", G_TYPE_STRING },
|
{ 'a', "aalgo", "", G_TYPE_STRING },
|
||||||
{ 'b', "boot", NULL, G_TYPE_BOOL },
|
{ 'b', "boot", NULL, G_TYPE_BOOL },
|
||||||
{ 'B', "backupfile", "", G_TYPE_STRING },
|
{ 'B', "backupfile", "", G_TYPE_STRING },
|
||||||
|
{ 'd', "displaypass", NULL, G_TYPE_BOOL },
|
||||||
{ 'e', "ealgo", "", G_TYPE_STRING },
|
{ 'e', "ealgo", "", G_TYPE_STRING },
|
||||||
{ 'g', "geliboot", NULL, G_TYPE_BOOL },
|
{ 'g', "geliboot", NULL, G_TYPE_BOOL },
|
||||||
{ 'i', "iterations", "-1", G_TYPE_NUMBER },
|
{ 'i', "iterations", "-1", G_TYPE_NUMBER },
|
||||||
@ -119,13 +120,14 @@ struct g_command class_commands[] = {
|
|||||||
{ 'V', "mdversion", "-1", G_TYPE_NUMBER },
|
{ 'V', "mdversion", "-1", G_TYPE_NUMBER },
|
||||||
G_OPT_SENTINEL
|
G_OPT_SENTINEL
|
||||||
},
|
},
|
||||||
"[-bgPTv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] [-s sectorsize] [-V version] prov"
|
"[-bdgPTv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] [-s sectorsize] [-V version] prov"
|
||||||
},
|
},
|
||||||
{ "label", G_FLAG_VERBOSE, eli_main,
|
{ "label", G_FLAG_VERBOSE, eli_main,
|
||||||
{
|
{
|
||||||
{ 'a', "aalgo", "", G_TYPE_STRING },
|
{ 'a', "aalgo", "", G_TYPE_STRING },
|
||||||
{ 'b', "boot", NULL, G_TYPE_BOOL },
|
{ 'b', "boot", NULL, G_TYPE_BOOL },
|
||||||
{ 'B', "backupfile", "", G_TYPE_STRING },
|
{ 'B', "backupfile", "", G_TYPE_STRING },
|
||||||
|
{ 'd', "displaypass", NULL, G_TYPE_BOOL },
|
||||||
{ 'e', "ealgo", "", G_TYPE_STRING },
|
{ 'e', "ealgo", "", G_TYPE_STRING },
|
||||||
{ 'g', "geliboot", NULL, G_TYPE_BOOL },
|
{ 'g', "geliboot", NULL, G_TYPE_BOOL },
|
||||||
{ 'i', "iterations", "-1", G_TYPE_NUMBER },
|
{ 'i', "iterations", "-1", G_TYPE_NUMBER },
|
||||||
@ -182,13 +184,15 @@ struct g_command class_commands[] = {
|
|||||||
{
|
{
|
||||||
{ 'b', "boot", NULL, G_TYPE_BOOL },
|
{ 'b', "boot", NULL, G_TYPE_BOOL },
|
||||||
{ 'B', "noboot", NULL, G_TYPE_BOOL },
|
{ 'B', "noboot", NULL, G_TYPE_BOOL },
|
||||||
|
{ 'd', "displaypass", NULL, G_TYPE_BOOL },
|
||||||
|
{ 'D', "nodisplaypass", NULL, G_TYPE_BOOL },
|
||||||
{ 'g', "geliboot", NULL, G_TYPE_BOOL },
|
{ 'g', "geliboot", NULL, G_TYPE_BOOL },
|
||||||
{ 'G', "nogeliboot", NULL, G_TYPE_BOOL },
|
{ 'G', "nogeliboot", NULL, G_TYPE_BOOL },
|
||||||
{ 't', "trim", NULL, G_TYPE_BOOL },
|
{ 't', "trim", NULL, G_TYPE_BOOL },
|
||||||
{ 'T', "notrim", NULL, G_TYPE_BOOL },
|
{ 'T', "notrim", NULL, G_TYPE_BOOL },
|
||||||
G_OPT_SENTINEL
|
G_OPT_SENTINEL
|
||||||
},
|
},
|
||||||
"[-bBgGtT] prov ..."
|
"[-bBdDgGtT] prov ..."
|
||||||
},
|
},
|
||||||
{ "setkey", G_FLAG_VERBOSE, eli_main,
|
{ "setkey", G_FLAG_VERBOSE, eli_main,
|
||||||
{
|
{
|
||||||
@ -708,6 +712,8 @@ eli_init(struct gctl_req *req)
|
|||||||
md.md_flags |= G_ELI_FLAG_BOOT;
|
md.md_flags |= G_ELI_FLAG_BOOT;
|
||||||
if (gctl_get_int(req, "geliboot"))
|
if (gctl_get_int(req, "geliboot"))
|
||||||
md.md_flags |= G_ELI_FLAG_GELIBOOT;
|
md.md_flags |= G_ELI_FLAG_GELIBOOT;
|
||||||
|
if (gctl_get_int(req, "displaypass"))
|
||||||
|
md.md_flags |= G_ELI_FLAG_GELIDISPLAYPASS;
|
||||||
if (gctl_get_int(req, "notrim"))
|
if (gctl_get_int(req, "notrim"))
|
||||||
md.md_flags |= G_ELI_FLAG_NODELETE;
|
md.md_flags |= G_ELI_FLAG_NODELETE;
|
||||||
md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1;
|
md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1;
|
||||||
@ -912,7 +918,7 @@ eli_attach(struct gctl_req *req)
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
eli_configure_detached(struct gctl_req *req, const char *prov, int boot,
|
eli_configure_detached(struct gctl_req *req, const char *prov, int boot,
|
||||||
int geliboot, int trim)
|
int geliboot, int displaypass, int trim)
|
||||||
{
|
{
|
||||||
struct g_eli_metadata md;
|
struct g_eli_metadata md;
|
||||||
bool changed = 0;
|
bool changed = 0;
|
||||||
@ -948,6 +954,21 @@ eli_configure_detached(struct gctl_req *req, const char *prov, int boot,
|
|||||||
changed = 1;
|
changed = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (displaypass == 1 && (md.md_flags & G_ELI_FLAG_GELIDISPLAYPASS)) {
|
||||||
|
if (verbose)
|
||||||
|
printf("GELIDISPLAYPASS flag already configured for %s.\n", prov);
|
||||||
|
} else if (displaypass == 0 &&
|
||||||
|
!(md.md_flags & G_ELI_FLAG_GELIDISPLAYPASS)) {
|
||||||
|
if (verbose)
|
||||||
|
printf("GELIDISPLAYPASS flag not configured for %s.\n", prov);
|
||||||
|
} else if (displaypass >= 0) {
|
||||||
|
if (displaypass)
|
||||||
|
md.md_flags |= G_ELI_FLAG_GELIDISPLAYPASS;
|
||||||
|
else
|
||||||
|
md.md_flags &= ~G_ELI_FLAG_GELIDISPLAYPASS;
|
||||||
|
changed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (trim == 0 && (md.md_flags & G_ELI_FLAG_NODELETE)) {
|
if (trim == 0 && (md.md_flags & G_ELI_FLAG_NODELETE)) {
|
||||||
if (verbose)
|
if (verbose)
|
||||||
printf("TRIM disable flag already configured for %s.\n", prov);
|
printf("TRIM disable flag already configured for %s.\n", prov);
|
||||||
@ -971,8 +992,9 @@ static void
|
|||||||
eli_configure(struct gctl_req *req)
|
eli_configure(struct gctl_req *req)
|
||||||
{
|
{
|
||||||
const char *prov;
|
const char *prov;
|
||||||
bool boot, noboot, geliboot, nogeliboot, trim, notrim;
|
bool boot, noboot, geliboot, nogeliboot, displaypass, nodisplaypass;
|
||||||
int doboot, dogeliboot, dotrim;
|
bool trim, notrim;
|
||||||
|
int doboot, dogeliboot, dodisplaypass, dotrim;
|
||||||
int i, nargs;
|
int i, nargs;
|
||||||
|
|
||||||
nargs = gctl_get_int(req, "nargs");
|
nargs = gctl_get_int(req, "nargs");
|
||||||
@ -985,6 +1007,8 @@ eli_configure(struct gctl_req *req)
|
|||||||
noboot = gctl_get_int(req, "noboot");
|
noboot = gctl_get_int(req, "noboot");
|
||||||
geliboot = gctl_get_int(req, "geliboot");
|
geliboot = gctl_get_int(req, "geliboot");
|
||||||
nogeliboot = gctl_get_int(req, "nogeliboot");
|
nogeliboot = gctl_get_int(req, "nogeliboot");
|
||||||
|
displaypass = gctl_get_int(req, "displaypass");
|
||||||
|
nodisplaypass = gctl_get_int(req, "nodisplaypass");
|
||||||
trim = gctl_get_int(req, "trim");
|
trim = gctl_get_int(req, "trim");
|
||||||
notrim = gctl_get_int(req, "notrim");
|
notrim = gctl_get_int(req, "notrim");
|
||||||
|
|
||||||
@ -1008,6 +1032,16 @@ eli_configure(struct gctl_req *req)
|
|||||||
else if (nogeliboot)
|
else if (nogeliboot)
|
||||||
dogeliboot = 0;
|
dogeliboot = 0;
|
||||||
|
|
||||||
|
dodisplaypass = -1;
|
||||||
|
if (displaypass && nodisplaypass) {
|
||||||
|
gctl_error(req, "Options -d and -D are mutually exclusive.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (displaypass)
|
||||||
|
dodisplaypass = 1;
|
||||||
|
else if (nodisplaypass)
|
||||||
|
dodisplaypass = 0;
|
||||||
|
|
||||||
dotrim = -1;
|
dotrim = -1;
|
||||||
if (trim && notrim) {
|
if (trim && notrim) {
|
||||||
gctl_error(req, "Options -t and -T are mutually exclusive.");
|
gctl_error(req, "Options -t and -T are mutually exclusive.");
|
||||||
@ -1018,7 +1052,8 @@ eli_configure(struct gctl_req *req)
|
|||||||
else if (notrim)
|
else if (notrim)
|
||||||
dotrim = 0;
|
dotrim = 0;
|
||||||
|
|
||||||
if (doboot == -1 && dogeliboot == -1 && dotrim == -1) {
|
if (doboot == -1 && dogeliboot == -1 && dodisplaypass == -1 &&
|
||||||
|
dotrim == -1) {
|
||||||
gctl_error(req, "No option given.");
|
gctl_error(req, "No option given.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1028,8 +1063,10 @@ eli_configure(struct gctl_req *req)
|
|||||||
/* Now the rest. */
|
/* Now the rest. */
|
||||||
for (i = 0; i < nargs; i++) {
|
for (i = 0; i < nargs; i++) {
|
||||||
prov = gctl_get_ascii(req, "arg%d", i);
|
prov = gctl_get_ascii(req, "arg%d", i);
|
||||||
if (!eli_is_attached(prov))
|
if (!eli_is_attached(prov)) {
|
||||||
eli_configure_detached(req, prov, doboot, dogeliboot, dotrim);
|
eli_configure_detached(req, prov, doboot, dogeliboot,
|
||||||
|
dodisplaypass, dotrim);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,8 +220,9 @@ geli_taste(int read_func(void *vdev, void *priv, off_t off, void *buf,
|
|||||||
/*
|
/*
|
||||||
* Attempt to decrypt the device
|
* Attempt to decrypt the device
|
||||||
*/
|
*/
|
||||||
int
|
static int
|
||||||
geli_attach(struct dsk *dskp, const char *passphrase, const u_char *mkeyp)
|
geli_attach(struct geli_entry *ge, struct dsk *dskp, const char *passphrase,
|
||||||
|
const u_char *mkeyp)
|
||||||
{
|
{
|
||||||
u_char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN], *mkp;
|
u_char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN], *mkp;
|
||||||
u_int keynum;
|
u_int keynum;
|
||||||
@ -233,92 +234,83 @@ geli_attach(struct dsk *dskp, const char *passphrase, const u_char *mkeyp)
|
|||||||
explicit_bzero(mkeyp, G_ELI_DATAIVKEYLEN);
|
explicit_bzero(mkeyp, G_ELI_DATAIVKEYLEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
SLIST_FOREACH_SAFE(geli_e, &geli_head, entries, geli_e_tmp) {
|
if (mkeyp != NULL || geli_findkey(ge, dskp, mkey) == 0) {
|
||||||
if (geli_same_device(geli_e, dskp) != 0) {
|
goto found_key;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mkeyp != NULL || geli_findkey(geli_e, dskp, mkey) == 0) {
|
|
||||||
goto found_key;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_eli_crypto_hmac_init(&ctx, NULL, 0);
|
|
||||||
/*
|
|
||||||
* Prepare Derived-Key from the user passphrase.
|
|
||||||
*/
|
|
||||||
if (geli_e->md.md_iterations < 0) {
|
|
||||||
/* XXX TODO: Support loading key files. */
|
|
||||||
return (1);
|
|
||||||
} else if (geli_e->md.md_iterations == 0) {
|
|
||||||
g_eli_crypto_hmac_update(&ctx, geli_e->md.md_salt,
|
|
||||||
sizeof(geli_e->md.md_salt));
|
|
||||||
g_eli_crypto_hmac_update(&ctx, passphrase,
|
|
||||||
strlen(passphrase));
|
|
||||||
} else if (geli_e->md.md_iterations > 0) {
|
|
||||||
printf("Calculating GELI Decryption Key disk%dp%d @ %d"
|
|
||||||
" iterations...\n", dskp->unit,
|
|
||||||
(dskp->slice > 0 ? dskp->slice : dskp->part),
|
|
||||||
geli_e->md.md_iterations);
|
|
||||||
u_char dkey[G_ELI_USERKEYLEN];
|
|
||||||
|
|
||||||
pkcs5v2_genkey(dkey, sizeof(dkey), geli_e->md.md_salt,
|
|
||||||
sizeof(geli_e->md.md_salt), passphrase,
|
|
||||||
geli_e->md.md_iterations);
|
|
||||||
g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey));
|
|
||||||
explicit_bzero(dkey, sizeof(dkey));
|
|
||||||
}
|
|
||||||
|
|
||||||
g_eli_crypto_hmac_final(&ctx, key, 0);
|
|
||||||
|
|
||||||
error = g_eli_mkey_decrypt(&geli_e->md, key, mkey, &keynum);
|
|
||||||
if (error == -1) {
|
|
||||||
explicit_bzero(mkey, sizeof(mkey));
|
|
||||||
explicit_bzero(key, sizeof(key));
|
|
||||||
printf("Bad GELI key: bad password?\n");
|
|
||||||
return (error);
|
|
||||||
} else if (error != 0) {
|
|
||||||
explicit_bzero(mkey, sizeof(mkey));
|
|
||||||
explicit_bzero(key, sizeof(key));
|
|
||||||
printf("Failed to decrypt GELI master key: %d\n", error);
|
|
||||||
return (error);
|
|
||||||
} else {
|
|
||||||
/* Add key to keychain */
|
|
||||||
save_key(key);
|
|
||||||
explicit_bzero(&key, sizeof(key));
|
|
||||||
}
|
|
||||||
|
|
||||||
found_key:
|
|
||||||
/* Store the keys */
|
|
||||||
bcopy(mkey, geli_e->sc.sc_mkey, sizeof(geli_e->sc.sc_mkey));
|
|
||||||
bcopy(mkey, geli_e->sc.sc_ivkey, sizeof(geli_e->sc.sc_ivkey));
|
|
||||||
mkp = mkey + sizeof(geli_e->sc.sc_ivkey);
|
|
||||||
if ((geli_e->sc.sc_flags & G_ELI_FLAG_AUTH) == 0) {
|
|
||||||
bcopy(mkp, geli_e->sc.sc_ekey, G_ELI_DATAKEYLEN);
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* The encryption key is: ekey = HMAC_SHA512(Data-Key, 0x10)
|
|
||||||
*/
|
|
||||||
g_eli_crypto_hmac(mkp, G_ELI_MAXKEYLEN, "\x10", 1,
|
|
||||||
geli_e->sc.sc_ekey, 0);
|
|
||||||
}
|
|
||||||
explicit_bzero(mkey, sizeof(mkey));
|
|
||||||
|
|
||||||
/* Initialize the per-sector IV. */
|
|
||||||
switch (geli_e->sc.sc_ealgo) {
|
|
||||||
case CRYPTO_AES_XTS:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
SHA256_Init(&geli_e->sc.sc_ivctx);
|
|
||||||
SHA256_Update(&geli_e->sc.sc_ivctx, geli_e->sc.sc_ivkey,
|
|
||||||
sizeof(geli_e->sc.sc_ivkey));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disk not found. */
|
g_eli_crypto_hmac_init(&ctx, NULL, 0);
|
||||||
return (2);
|
/*
|
||||||
|
* Prepare Derived-Key from the user passphrase.
|
||||||
|
*/
|
||||||
|
if (geli_e->md.md_iterations < 0) {
|
||||||
|
/* XXX TODO: Support loading key files. */
|
||||||
|
return (1);
|
||||||
|
} else if (geli_e->md.md_iterations == 0) {
|
||||||
|
g_eli_crypto_hmac_update(&ctx, geli_e->md.md_salt,
|
||||||
|
sizeof(geli_e->md.md_salt));
|
||||||
|
g_eli_crypto_hmac_update(&ctx, passphrase,
|
||||||
|
strlen(passphrase));
|
||||||
|
} else if (geli_e->md.md_iterations > 0) {
|
||||||
|
printf("Calculating GELI Decryption Key disk%dp%d @ %d"
|
||||||
|
" iterations...\n", dskp->unit,
|
||||||
|
(dskp->slice > 0 ? dskp->slice : dskp->part),
|
||||||
|
geli_e->md.md_iterations);
|
||||||
|
u_char dkey[G_ELI_USERKEYLEN];
|
||||||
|
|
||||||
|
pkcs5v2_genkey(dkey, sizeof(dkey), geli_e->md.md_salt,
|
||||||
|
sizeof(geli_e->md.md_salt), passphrase,
|
||||||
|
geli_e->md.md_iterations);
|
||||||
|
g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey));
|
||||||
|
explicit_bzero(dkey, sizeof(dkey));
|
||||||
|
}
|
||||||
|
|
||||||
|
g_eli_crypto_hmac_final(&ctx, key, 0);
|
||||||
|
|
||||||
|
error = g_eli_mkey_decrypt(&geli_e->md, key, mkey, &keynum);
|
||||||
|
if (error == -1) {
|
||||||
|
explicit_bzero(mkey, sizeof(mkey));
|
||||||
|
explicit_bzero(key, sizeof(key));
|
||||||
|
printf("Bad GELI key: bad password?\n");
|
||||||
|
return (error);
|
||||||
|
} else if (error != 0) {
|
||||||
|
explicit_bzero(mkey, sizeof(mkey));
|
||||||
|
explicit_bzero(key, sizeof(key));
|
||||||
|
printf("Failed to decrypt GELI master key: %d\n", error);
|
||||||
|
return (error);
|
||||||
|
} else {
|
||||||
|
/* Add key to keychain */
|
||||||
|
save_key(key);
|
||||||
|
explicit_bzero(&key, sizeof(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
found_key:
|
||||||
|
/* Store the keys */
|
||||||
|
bcopy(mkey, geli_e->sc.sc_mkey, sizeof(geli_e->sc.sc_mkey));
|
||||||
|
bcopy(mkey, geli_e->sc.sc_ivkey, sizeof(geli_e->sc.sc_ivkey));
|
||||||
|
mkp = mkey + sizeof(geli_e->sc.sc_ivkey);
|
||||||
|
if ((geli_e->sc.sc_flags & G_ELI_FLAG_AUTH) == 0) {
|
||||||
|
bcopy(mkp, geli_e->sc.sc_ekey, G_ELI_DATAKEYLEN);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* The encryption key is: ekey = HMAC_SHA512(Data-Key, 0x10)
|
||||||
|
*/
|
||||||
|
g_eli_crypto_hmac(mkp, G_ELI_MAXKEYLEN, "\x10", 1,
|
||||||
|
geli_e->sc.sc_ekey, 0);
|
||||||
|
}
|
||||||
|
explicit_bzero(mkey, sizeof(mkey));
|
||||||
|
|
||||||
|
/* Initialize the per-sector IV. */
|
||||||
|
switch (geli_e->sc.sc_ealgo) {
|
||||||
|
case CRYPTO_AES_XTS:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SHA256_Init(&geli_e->sc.sc_ivctx);
|
||||||
|
SHA256_Update(&geli_e->sc.sc_ivctx, geli_e->sc.sc_ivkey,
|
||||||
|
sizeof(geli_e->sc.sc_ivkey));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -402,7 +394,7 @@ geli_havekey(struct dsk *dskp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (geli_findkey(geli_e, dskp, mkey) == 0) {
|
if (geli_findkey(geli_e, dskp, mkey) == 0) {
|
||||||
if (geli_attach(dskp, NULL, mkey) == 0) {
|
if (geli_attach(geli_e, dskp, NULL, mkey) == 0) {
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -417,20 +409,28 @@ geli_passphrase(char *pw, int disk, int parttype, int part, struct dsk *dskp)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* TODO: Implement GELI keyfile(s) support */
|
SLIST_FOREACH_SAFE(geli_e, &geli_head, entries, geli_e_tmp) {
|
||||||
for (i = 0; i < 3; i++) {
|
if (geli_same_device(geli_e, dskp) != 0) {
|
||||||
/* Try cached passphrase */
|
continue;
|
||||||
if (i == 0 && pw[0] != '\0') {
|
}
|
||||||
if (geli_attach(dskp, pw, NULL) == 0) {
|
|
||||||
|
/* TODO: Implement GELI keyfile(s) support */
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
/* Try cached passphrase */
|
||||||
|
if (i == 0 && pw[0] != '\0') {
|
||||||
|
if (geli_attach(geli_e, dskp, pw, NULL) == 0) {
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("GELI Passphrase for disk%d%c%d: ", disk,
|
||||||
|
parttype, part);
|
||||||
|
pwgets(pw, GELI_PW_MAXLEN,
|
||||||
|
(geli_e->md.md_flags & G_ELI_FLAG_GELIDISPLAYPASS) == 0);
|
||||||
|
printf("\n");
|
||||||
|
if (geli_attach(geli_e, dskp, pw, NULL) == 0) {
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("GELI Passphrase for disk%d%c%d: ", disk, parttype, part);
|
|
||||||
pwgets(pw, GELI_PW_MAXLEN);
|
|
||||||
printf("\n");
|
|
||||||
if (geli_attach(dskp, pw, NULL) == 0) {
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (1);
|
return (1);
|
||||||
|
@ -46,12 +46,11 @@
|
|||||||
#define GELI_MAX_KEYS 64
|
#define GELI_MAX_KEYS 64
|
||||||
#define GELI_PW_MAXLEN 256
|
#define GELI_PW_MAXLEN 256
|
||||||
|
|
||||||
extern void pwgets(char *buf, int n);
|
extern void pwgets(char *buf, int n, int hide);
|
||||||
|
|
||||||
void geli_init(void);
|
void geli_init(void);
|
||||||
int geli_taste(int read_func(void *vdev, void *priv, off_t off,
|
int geli_taste(int read_func(void *vdev, void *priv, off_t off,
|
||||||
void *buf, size_t bytes), struct dsk *dsk, daddr_t lastsector);
|
void *buf, size_t bytes), struct dsk *dsk, daddr_t lastsector);
|
||||||
int geli_attach(struct dsk *dskp, const char *passphrase, const u_char *mkeyp);
|
|
||||||
int is_geli(struct dsk *dsk);
|
int is_geli(struct dsk *dsk);
|
||||||
int geli_read(struct dsk *dsk, off_t offset, u_char *buf, size_t bytes);
|
int geli_read(struct dsk *dsk, off_t offset, u_char *buf, size_t bytes);
|
||||||
int geli_decrypt(u_int algo, u_char *data, size_t datasize,
|
int geli_decrypt(u_int algo, u_char *data, size_t datasize,
|
||||||
|
@ -39,7 +39,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
/* gets() with constrained input length, for passwords */
|
/* gets() with constrained input length, for passwords */
|
||||||
|
|
||||||
void
|
void
|
||||||
pwgets(char *buf, int n)
|
pwgets(char *buf, int n, int hide)
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
char *lp;
|
char *lp;
|
||||||
@ -55,9 +55,11 @@ pwgets(char *buf, int n)
|
|||||||
case '\177':
|
case '\177':
|
||||||
if (lp > buf) {
|
if (lp > buf) {
|
||||||
lp--;
|
lp--;
|
||||||
putchar('\b');
|
if (hide == 0) {
|
||||||
putchar(' ');
|
putchar('\b');
|
||||||
putchar('\b');
|
putchar(' ');
|
||||||
|
putchar('\b');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'u'&037:
|
case 'u'&037:
|
||||||
@ -68,7 +70,9 @@ pwgets(char *buf, int n)
|
|||||||
default:
|
default:
|
||||||
if ((n < 1) || ((lp - buf) < n - 1)) {
|
if ((n < 1) || ((lp - buf) < n - 1)) {
|
||||||
*lp++ = c;
|
*lp++ = c;
|
||||||
putchar('*');
|
if (hide == 0) {
|
||||||
|
putchar('*');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*NOTREACHED*/
|
/*NOTREACHED*/
|
||||||
|
@ -1023,7 +1023,7 @@ g_eli_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
|
|||||||
struct hmac_ctx ctx;
|
struct hmac_ctx ctx;
|
||||||
char passphrase[256];
|
char passphrase[256];
|
||||||
u_char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN];
|
u_char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN];
|
||||||
u_int i, nkey, nkeyfiles, tries;
|
u_int i, nkey, nkeyfiles, tries, showpass;
|
||||||
int error;
|
int error;
|
||||||
struct keybuf *keybuf;
|
struct keybuf *keybuf;
|
||||||
|
|
||||||
@ -1112,8 +1112,11 @@ g_eli_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
|
|||||||
sizeof(passphrase));
|
sizeof(passphrase));
|
||||||
} else {
|
} else {
|
||||||
printf("Enter passphrase for %s: ", pp->name);
|
printf("Enter passphrase for %s: ", pp->name);
|
||||||
|
showpass = g_eli_visible_passphrase;
|
||||||
|
if ((md.md_flags & G_ELI_FLAG_GELIDISPLAYPASS) != 0)
|
||||||
|
showpass = GETS_ECHOPASS;
|
||||||
cngets(passphrase, sizeof(passphrase),
|
cngets(passphrase, sizeof(passphrase),
|
||||||
g_eli_visible_passphrase);
|
showpass);
|
||||||
memcpy(cached_passphrase, passphrase,
|
memcpy(cached_passphrase, passphrase,
|
||||||
sizeof(passphrase));
|
sizeof(passphrase));
|
||||||
}
|
}
|
||||||
@ -1232,6 +1235,7 @@ g_eli_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
|
|||||||
ADD_FLAG(G_ELI_FLAG_RO, "READ-ONLY");
|
ADD_FLAG(G_ELI_FLAG_RO, "READ-ONLY");
|
||||||
ADD_FLAG(G_ELI_FLAG_NODELETE, "NODELETE");
|
ADD_FLAG(G_ELI_FLAG_NODELETE, "NODELETE");
|
||||||
ADD_FLAG(G_ELI_FLAG_GELIBOOT, "GELIBOOT");
|
ADD_FLAG(G_ELI_FLAG_GELIBOOT, "GELIBOOT");
|
||||||
|
ADD_FLAG(G_ELI_FLAG_GELIDISPLAYPASS, "GELIDISPLAYPASS");
|
||||||
#undef ADD_FLAG
|
#undef ADD_FLAG
|
||||||
}
|
}
|
||||||
sbuf_printf(sb, "</Flags>\n");
|
sbuf_printf(sb, "</Flags>\n");
|
||||||
|
@ -100,6 +100,8 @@
|
|||||||
#define G_ELI_FLAG_NODELETE 0x00000040
|
#define G_ELI_FLAG_NODELETE 0x00000040
|
||||||
/* This GELI supports GELIBoot */
|
/* This GELI supports GELIBoot */
|
||||||
#define G_ELI_FLAG_GELIBOOT 0x00000080
|
#define G_ELI_FLAG_GELIBOOT 0x00000080
|
||||||
|
/* Hide passphrase length in GELIboot. */
|
||||||
|
#define G_ELI_FLAG_GELIDISPLAYPASS 0x00000100
|
||||||
/* RUNTIME FLAGS. */
|
/* RUNTIME FLAGS. */
|
||||||
/* Provider was open for writing. */
|
/* Provider was open for writing. */
|
||||||
#define G_ELI_FLAG_WOPEN 0x00010000
|
#define G_ELI_FLAG_WOPEN 0x00010000
|
||||||
|
@ -377,6 +377,7 @@ g_eli_ctl_configure(struct gctl_req *req, struct g_class *mp)
|
|||||||
const char *prov;
|
const char *prov;
|
||||||
u_char *sector;
|
u_char *sector;
|
||||||
int *nargs, *boot, *noboot, *trim, *notrim, *geliboot, *nogeliboot;
|
int *nargs, *boot, *noboot, *trim, *notrim, *geliboot, *nogeliboot;
|
||||||
|
int *displaypass, *nodisplaypass;
|
||||||
int zero, error, changed;
|
int zero, error, changed;
|
||||||
u_int i;
|
u_int i;
|
||||||
|
|
||||||
@ -434,6 +435,19 @@ g_eli_ctl_configure(struct gctl_req *req, struct g_class *mp)
|
|||||||
if (*geliboot || *nogeliboot)
|
if (*geliboot || *nogeliboot)
|
||||||
changed = 1;
|
changed = 1;
|
||||||
|
|
||||||
|
displaypass = gctl_get_paraml(req, "displaypass", sizeof(*displaypass));
|
||||||
|
if (displaypass == NULL)
|
||||||
|
displaypass = &zero;
|
||||||
|
nodisplaypass = gctl_get_paraml(req, "nodisplaypass", sizeof(*nodisplaypass));
|
||||||
|
if (nodisplaypass == NULL)
|
||||||
|
nodisplaypass = &zero;
|
||||||
|
if (*displaypass && *nodisplaypass) {
|
||||||
|
gctl_error(req, "Options -d and -D are mutually exclusive.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (*displaypass || *nodisplaypass)
|
||||||
|
changed = 1;
|
||||||
|
|
||||||
if (!changed) {
|
if (!changed) {
|
||||||
gctl_error(req, "No option given.");
|
gctl_error(req, "No option given.");
|
||||||
return;
|
return;
|
||||||
@ -492,6 +506,17 @@ g_eli_ctl_configure(struct gctl_req *req, struct g_class *mp)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (*displaypass && (sc->sc_flags & G_ELI_FLAG_GELIDISPLAYPASS)) {
|
||||||
|
G_ELI_DEBUG(1, "GELIDISPLAYPASS flag already configured for %s.",
|
||||||
|
prov);
|
||||||
|
continue;
|
||||||
|
} else if (*nodisplaypass &&
|
||||||
|
!(sc->sc_flags & G_ELI_FLAG_GELIDISPLAYPASS)) {
|
||||||
|
G_ELI_DEBUG(1, "GELIDISPLAYPASS flag not configured for %s.",
|
||||||
|
prov);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(sc->sc_flags & G_ELI_FLAG_ONETIME)) {
|
if (!(sc->sc_flags & G_ELI_FLAG_ONETIME)) {
|
||||||
/*
|
/*
|
||||||
* ONETIME providers don't write metadata to
|
* ONETIME providers don't write metadata to
|
||||||
@ -535,6 +560,14 @@ g_eli_ctl_configure(struct gctl_req *req, struct g_class *mp)
|
|||||||
sc->sc_flags &= ~G_ELI_FLAG_GELIBOOT;
|
sc->sc_flags &= ~G_ELI_FLAG_GELIBOOT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (*displaypass) {
|
||||||
|
md.md_flags |= G_ELI_FLAG_GELIDISPLAYPASS;
|
||||||
|
sc->sc_flags |= G_ELI_FLAG_GELIDISPLAYPASS;
|
||||||
|
} else if (*nodisplaypass) {
|
||||||
|
md.md_flags &= ~G_ELI_FLAG_GELIDISPLAYPASS;
|
||||||
|
sc->sc_flags &= ~G_ELI_FLAG_GELIDISPLAYPASS;
|
||||||
|
}
|
||||||
|
|
||||||
if (sc->sc_flags & G_ELI_FLAG_ONETIME) {
|
if (sc->sc_flags & G_ELI_FLAG_ONETIME) {
|
||||||
/* There's no metadata on disk so we are done here. */
|
/* There's no metadata on disk so we are done here. */
|
||||||
continue;
|
continue;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user