Index: head/UPDATING =================================================================== --- head/UPDATING +++ head/UPDATING @@ -51,6 +51,10 @@ ****************************** SPECIAL WARNING: ****************************** +20170826: + During boot the geli passphrase will be hidden. To restore previous + behavior see geli(8) configuration options. + 20170825: Move PMTUD blackhole counters to TCPSTATS and remove them from bare sysctl values. Minor nit, but requires a rebuild of both world/kernel Index: head/sbin/geom/class/eli/geli.8 =================================================================== --- head/sbin/geom/class/eli/geli.8 +++ head/sbin/geom/class/eli/geli.8 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd August 3, 2016 +.Dd August 26, 2017 .Dt GELI 8 .Os .Sh NAME @@ -51,7 +51,7 @@ .Pp .Nm .Cm init -.Op Fl bgPTv +.Op Fl bdgPTv .Op Fl a Ar aalgo .Op Fl B Ar backupfile .Op Fl e Ar ealgo @@ -88,7 +88,7 @@ .Ar prov .Nm .Cm configure -.Op Fl bBgGtT +.Op Fl bBdDgGtT .Ar prov ... .Nm .Cm setkey @@ -279,6 +279,9 @@ .Pa none as the .Ar backupfile . +.It Fl d +While booting from this encrypted root filesystem enable visibility of +passphrase length. .It Fl e Ar ealgo Encryption algorithm to use. Currently supported algorithms are: @@ -490,6 +493,12 @@ subcommand. .It Fl B 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 Enable booting from this encrypted root filesystem. The boot loader prompts for the passphrase and loads Index: head/sbin/geom/class/eli/geom_eli.c =================================================================== --- head/sbin/geom/class/eli/geom_eli.c +++ head/sbin/geom/class/eli/geom_eli.c @@ -82,7 +82,7 @@ /* * 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' * attach [-dprv] [-j passfile] [-k keyfile] prov * detach [-fl] prov ... @@ -107,6 +107,7 @@ { 'a', "aalgo", "", G_TYPE_STRING }, { 'b', "boot", NULL, G_TYPE_BOOL }, { 'B', "backupfile", "", G_TYPE_STRING }, + { 'd', "displaypass", NULL, G_TYPE_BOOL }, { 'e', "ealgo", "", G_TYPE_STRING }, { 'g', "geliboot", NULL, G_TYPE_BOOL }, { 'i', "iterations", "-1", G_TYPE_NUMBER }, @@ -119,13 +120,14 @@ { 'V', "mdversion", "-1", G_TYPE_NUMBER }, 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, { { 'a', "aalgo", "", G_TYPE_STRING }, { 'b', "boot", NULL, G_TYPE_BOOL }, { 'B', "backupfile", "", G_TYPE_STRING }, + { 'd', "displaypass", NULL, G_TYPE_BOOL }, { 'e', "ealgo", "", G_TYPE_STRING }, { 'g', "geliboot", NULL, G_TYPE_BOOL }, { 'i', "iterations", "-1", G_TYPE_NUMBER }, @@ -182,13 +184,15 @@ { { 'b', "boot", 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', "nogeliboot", NULL, G_TYPE_BOOL }, { 't', "trim", NULL, G_TYPE_BOOL }, { 'T', "notrim", NULL, G_TYPE_BOOL }, G_OPT_SENTINEL }, - "[-bBgGtT] prov ..." + "[-bBdDgGtT] prov ..." }, { "setkey", G_FLAG_VERBOSE, eli_main, { @@ -708,6 +712,8 @@ md.md_flags |= G_ELI_FLAG_BOOT; if (gctl_get_int(req, "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")) md.md_flags |= G_ELI_FLAG_NODELETE; md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1; @@ -912,7 +918,7 @@ static void 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; bool changed = 0; @@ -948,6 +954,21 @@ 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 (verbose) printf("TRIM disable flag already configured for %s.\n", prov); @@ -971,8 +992,9 @@ eli_configure(struct gctl_req *req) { const char *prov; - bool boot, noboot, geliboot, nogeliboot, trim, notrim; - int doboot, dogeliboot, dotrim; + bool boot, noboot, geliboot, nogeliboot, displaypass, nodisplaypass; + bool trim, notrim; + int doboot, dogeliboot, dodisplaypass, dotrim; int i, nargs; nargs = gctl_get_int(req, "nargs"); @@ -985,6 +1007,8 @@ noboot = gctl_get_int(req, "noboot"); geliboot = gctl_get_int(req, "geliboot"); nogeliboot = gctl_get_int(req, "nogeliboot"); + displaypass = gctl_get_int(req, "displaypass"); + nodisplaypass = gctl_get_int(req, "nodisplaypass"); trim = gctl_get_int(req, "trim"); notrim = gctl_get_int(req, "notrim"); @@ -1008,6 +1032,16 @@ else if (nogeliboot) 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; if (trim && notrim) { gctl_error(req, "Options -t and -T are mutually exclusive."); @@ -1018,7 +1052,8 @@ else if (notrim) dotrim = 0; - if (doboot == -1 && dogeliboot == -1 && dotrim == -1) { + if (doboot == -1 && dogeliboot == -1 && dodisplaypass == -1 && + dotrim == -1) { gctl_error(req, "No option given."); return; } @@ -1028,8 +1063,10 @@ /* Now the rest. */ for (i = 0; i < nargs; i++) { prov = gctl_get_ascii(req, "arg%d", i); - if (!eli_is_attached(prov)) - eli_configure_detached(req, prov, doboot, dogeliboot, dotrim); + if (!eli_is_attached(prov)) { + eli_configure_detached(req, prov, doboot, dogeliboot, + dodisplaypass, dotrim); + } } } Index: head/sys/boot/geli/geliboot.h =================================================================== --- head/sys/boot/geli/geliboot.h +++ head/sys/boot/geli/geliboot.h @@ -46,12 +46,11 @@ #define GELI_MAX_KEYS 64 #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); int geli_taste(int read_func(void *vdev, void *priv, off_t off, 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 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, Index: head/sys/boot/geli/geliboot.c =================================================================== --- head/sys/boot/geli/geliboot.c +++ head/sys/boot/geli/geliboot.c @@ -220,8 +220,9 @@ /* * Attempt to decrypt the device */ -int -geli_attach(struct dsk *dskp, const char *passphrase, const u_char *mkeyp) +static int +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_int keynum; @@ -233,92 +234,83 @@ explicit_bzero(mkeyp, G_ELI_DATAIVKEYLEN); } - SLIST_FOREACH_SAFE(geli_e, &geli_head, entries, geli_e_tmp) { - if (geli_same_device(geli_e, dskp) != 0) { - continue; - } + if (mkeyp != NULL || geli_findkey(ge, dskp, mkey) == 0) { + goto found_key; + } - 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]; - 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)); + } - 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); - 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)); + } - 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)); + /* 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); + /* 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; } - /* Disk not found. */ - return (2); + return (0); } int @@ -402,7 +394,7 @@ } 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); } } @@ -417,19 +409,27 @@ { int i; - /* TODO: Implement GELI keyfile(s) support */ - for (i = 0; i < 3; i++) { - /* Try cached passphrase */ - if (i == 0 && pw[0] != '\0') { - if (geli_attach(dskp, pw, NULL) == 0) { + SLIST_FOREACH_SAFE(geli_e, &geli_head, entries, geli_e_tmp) { + if (geli_same_device(geli_e, dskp) != 0) { + continue; + } + + /* 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); } - } - 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); } } Index: head/sys/boot/geli/pwgets.c =================================================================== --- head/sys/boot/geli/pwgets.c +++ head/sys/boot/geli/pwgets.c @@ -39,7 +39,7 @@ /* gets() with constrained input length, for passwords */ void -pwgets(char *buf, int n) +pwgets(char *buf, int n, int hide) { int c; char *lp; @@ -55,9 +55,11 @@ case '\177': if (lp > buf) { lp--; - putchar('\b'); - putchar(' '); - putchar('\b'); + if (hide == 0) { + putchar('\b'); + putchar(' '); + putchar('\b'); + } } break; case 'u'&037: @@ -68,7 +70,9 @@ default: if ((n < 1) || ((lp - buf) < n - 1)) { *lp++ = c; - putchar('*'); + if (hide == 0) { + putchar('*'); + } } } /*NOTREACHED*/ Index: head/sys/geom/eli/g_eli.h =================================================================== --- head/sys/geom/eli/g_eli.h +++ head/sys/geom/eli/g_eli.h @@ -100,6 +100,8 @@ #define G_ELI_FLAG_NODELETE 0x00000040 /* This GELI supports GELIBoot */ #define G_ELI_FLAG_GELIBOOT 0x00000080 +/* Hide passphrase length in GELIboot. */ +#define G_ELI_FLAG_GELIDISPLAYPASS 0x00000100 /* RUNTIME FLAGS. */ /* Provider was open for writing. */ #define G_ELI_FLAG_WOPEN 0x00010000 Index: head/sys/geom/eli/g_eli.c =================================================================== --- head/sys/geom/eli/g_eli.c +++ head/sys/geom/eli/g_eli.c @@ -1023,7 +1023,7 @@ struct hmac_ctx ctx; char passphrase[256]; 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; struct keybuf *keybuf; @@ -1112,8 +1112,11 @@ sizeof(passphrase)); } else { 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), - g_eli_visible_passphrase); + showpass); memcpy(cached_passphrase, passphrase, sizeof(passphrase)); } @@ -1232,6 +1235,7 @@ ADD_FLAG(G_ELI_FLAG_RO, "READ-ONLY"); ADD_FLAG(G_ELI_FLAG_NODELETE, "NODELETE"); ADD_FLAG(G_ELI_FLAG_GELIBOOT, "GELIBOOT"); + ADD_FLAG(G_ELI_FLAG_GELIDISPLAYPASS, "GELIDISPLAYPASS"); #undef ADD_FLAG } sbuf_printf(sb, "\n"); Index: head/sys/geom/eli/g_eli_ctl.c =================================================================== --- head/sys/geom/eli/g_eli_ctl.c +++ head/sys/geom/eli/g_eli_ctl.c @@ -377,6 +377,7 @@ const char *prov; u_char *sector; int *nargs, *boot, *noboot, *trim, *notrim, *geliboot, *nogeliboot; + int *displaypass, *nodisplaypass; int zero, error, changed; u_int i; @@ -434,6 +435,19 @@ if (*geliboot || *nogeliboot) 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) { gctl_error(req, "No option given."); return; @@ -492,6 +506,17 @@ 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)) { /* * ONETIME providers don't write metadata to @@ -533,6 +558,14 @@ } else if (*nogeliboot) { md.md_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) {