From 93cbefc1746325e5c24d1592b8e8b1af075a1cef Mon Sep 17 00:00:00 2001 From: cperciva Date: Tue, 16 Sep 2014 08:40:52 +0000 Subject: Cache GELI passphrases entered at the console during the boot process, in order to improve user-friendliness when a system has multiple disks encrypted using the same passphrase. When examining a new GELI provider, the most recently used passphrase will be attempted before prompting for a passphrase; and whenever a passphrase is entered, it is cached for later reference. When the root disk is mounted, the cached passphrase is zeroed (triggered by the "mountroot" event), in order to minimize the possibility of leakage of passphrases. (After root is mounted, the "taste and prompt for passphrases on the console" code path is disabled, so there is no potential for a passphrase to be stored after the zeroing takes place.) This behaviour can be disabled by setting kern.geom.eli.boot_passcache=0. Reviewed by: pjd, dteske, allanjude MFC after: 7 days --- sys/geom/eli/g_eli.c | 45 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 7 deletions(-) (limited to 'sys/geom/eli') diff --git a/sys/geom/eli/g_eli.c b/sys/geom/eli/g_eli.c index 2c4dc2c..f545b75 100644 --- a/sys/geom/eli/g_eli.c +++ b/sys/geom/eli/g_eli.c @@ -82,6 +82,24 @@ u_int g_eli_batch = 0; SYSCTL_UINT(_kern_geom_eli, OID_AUTO, batch, CTLFLAG_RWTUN, &g_eli_batch, 0, "Use crypto operations batching"); +/* + * Passphrase cached during boot, in order to be more user-friendly if + * there are multiple providers using the same passphrase. + */ +static char cached_passphrase[256]; +static u_int g_eli_boot_passcache = 1; +TUNABLE_INT("kern.geom.eli.boot_passcache", &g_eli_boot_passcache); +SYSCTL_UINT(_kern_geom_eli, OID_AUTO, boot_passcache, CTLFLAG_RD, + &g_eli_boot_passcache, 0, + "Passphrases are cached during boot process for possible reuse"); +static void +zero_boot_passcache(void * dummy) +{ + + memset(cached_passphrase, 0, sizeof(cached_passphrase)); +} +EVENTHANDLER_DEFINE(mountroot, zero_boot_passcache, NULL, 0); + static eventhandler_tag g_eli_pre_sync = NULL; static int g_eli_destroy_geom(struct gctl_req *req, struct g_class *mp, @@ -1059,7 +1077,7 @@ g_eli_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) tries = g_eli_tries; } - for (i = 0; i < tries; i++) { + for (i = 0; i <= tries; i++) { g_eli_crypto_hmac_init(&ctx, NULL, 0); /* @@ -1083,9 +1101,19 @@ g_eli_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) /* Ask for the passphrase if defined. */ if (md.md_iterations >= 0) { - printf("Enter passphrase for %s: ", pp->name); - cngets(passphrase, sizeof(passphrase), - g_eli_visible_passphrase); + /* Try first with cached passphrase. */ + if (i == 0) { + if (!g_eli_boot_passcache) + continue; + memcpy(passphrase, cached_passphrase, + sizeof(passphrase)); + } else { + printf("Enter passphrase for %s: ", pp->name); + cngets(passphrase, sizeof(passphrase), + g_eli_visible_passphrase); + memcpy(cached_passphrase, passphrase, + sizeof(passphrase)); + } } /* @@ -1115,15 +1143,18 @@ g_eli_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) error = g_eli_mkey_decrypt(&md, key, mkey, &nkey); bzero(key, sizeof(key)); if (error == -1) { - if (i == tries - 1) { + if (i == tries) { G_ELI_DEBUG(0, "Wrong key for %s. No tries left.", pp->name); g_eli_keyfiles_clear(pp->name); return (NULL); } - G_ELI_DEBUG(0, "Wrong key for %s. Tries left: %u.", - pp->name, tries - i - 1); + if (i > 0) { + G_ELI_DEBUG(0, + "Wrong key for %s. Tries left: %u.", + pp->name, tries - i); + } /* Try again. */ continue; } else if (error > 0) { -- cgit v1.1