From 204d3235abbdaff64833facda5a3ce556c45d2d1 Mon Sep 17 00:00:00 2001 From: pjd Date: Sat, 11 Feb 2006 13:08:24 +0000 Subject: Teach geli how to load keyfiles before root file system is mounted. An example entries for loader.conf to make it possible: geli_da0_keyfile0_load="YES" geli_da0_keyfile0_type="da0:geli_keyfile0" geli_da0_keyfile0_name="/boot/keys/da0.key0" geli_da0_keyfile1_load="YES" geli_da0_keyfile1_type="da0:geli_keyfile1" geli_da0_keyfile1_name="/boot/keys/da0.key1" geli_da0_keyfile2_load="YES" geli_da0_keyfile2_type="da0:geli_keyfile2" geli_da0_keyfile2_name="/boot/keys/da0.key2" geli_da1s3a_keyfile0_load="YES" geli_da1s3a_keyfile0_type="da1s3a:geli_keyfile0" geli_da1s3a_keyfile0_name="/boot/keys/da1s3a.key" Thanks for jhb and kan who showed me the right direction. MFC after: 3 days --- sys/geom/eli/g_eli.c | 125 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 106 insertions(+), 19 deletions(-) (limited to 'sys/geom/eli') diff --git a/sys/geom/eli/g_eli.c b/sys/geom/eli/g_eli.c index 915f1d0..c50e6b1 100644 --- a/sys/geom/eli/g_eli.c +++ b/sys/geom/eli/g_eli.c @@ -30,6 +30,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -890,6 +891,64 @@ g_eli_destroy_geom(struct gctl_req *req __unused, return (g_eli_destroy(sc, 0)); } +static int +g_eli_keyfiles_load(struct hmac_ctx *ctx, const char *provider) +{ + u_char *keyfile, *data, *size; + char *file, name[64]; + int i; + + for (i = 0; ; i++) { + snprintf(name, sizeof(name), "%s:geli_keyfile%d", provider, i); + keyfile = preload_search_by_type(name); + if (keyfile == NULL) + return (i); /* Return number of loaded keyfiles. */ + data = preload_search_info(keyfile, MODINFO_ADDR); + if (data == NULL) { + G_ELI_DEBUG(0, "Cannot find key file data for %s.", + name); + return (0); + } + data = *(void **)data; + size = preload_search_info(keyfile, MODINFO_SIZE); + if (size == NULL) { + G_ELI_DEBUG(0, "Cannot find key file size for %s.", + name); + return (0); + } + file = preload_search_info(keyfile, MODINFO_NAME); + if (file == NULL) { + G_ELI_DEBUG(0, "Cannot find key file name for %s.", + name); + return (0); + } + G_ELI_DEBUG(1, "Loaded keyfile %s for %s (type: %s).", file, + provider, name); + g_eli_crypto_hmac_update(ctx, data, *(size_t *)size); + } +} + +static void +g_eli_keyfiles_clear(const char *provider) +{ + u_char *keyfile, *data, *size; + char name[64]; + int i; + + for (i = 0; ; i++) { + snprintf(name, sizeof(name), "%s:geli_keyfile%d", provider, i); + keyfile = preload_search_by_type(name); + if (keyfile == NULL) + return; + data = preload_search_info(keyfile, MODINFO_ADDR); + size = preload_search_info(keyfile, MODINFO_SIZE); + if (data == NULL || size == NULL) + continue; + data = *(void **)data; + bzero(data, *(size_t *)size); + } +} + /* * Tasting is only made on boot. * We detect providers which should be attached before root is mounted. @@ -902,7 +961,7 @@ g_eli_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) struct hmac_ctx ctx; char passphrase[256]; u_char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN]; - u_int nkey, i; + u_int i, nkey, nkeyfiles, tries; int error; g_trace(G_T_TOPOLOGY, "%s(%s, %s)", __func__, mp->name, pp->name); @@ -934,25 +993,52 @@ g_eli_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) G_ELI_DEBUG(0, "No valid keys on %s.", pp->name); return (NULL); } + if (md.md_iterations == -1) { + /* If there is no passphrase, we try only once. */ + tries = 1; + } else { + /* Ask for the passphrase no more than g_eli_tries times. */ + tries = g_eli_tries; + } + + for (i = 0; i < tries; i++) { + g_eli_crypto_hmac_init(&ctx, NULL, 0); + + /* + * Load all key files. + */ + nkeyfiles = g_eli_keyfiles_load(&ctx, pp->name); + + if (nkeyfiles == 0 && md.md_iterations == -1) { + /* + * No key files and no passphrase, something is + * definitely wrong here. + * geli(8) doesn't allow for such situation, so assume + * that there was really no passphrase and in that case + * key files are no properly defined in loader.conf. + */ + G_ELI_DEBUG(0, + "Found no key files in loader.conf for %s.", + pp->name); + return (NULL); + } + + /* Ask for the passphrase if defined. */ + if (md.md_iterations >= 0) { + printf("Enter passphrase for %s: ", pp->name); + gets(passphrase, sizeof(passphrase), + g_eli_visible_passphrase); + } - /* - * Ask for the passphrase no more than g_eli_tries times. - */ - for (i = 0; i < g_eli_tries; i++) { - printf("Enter passphrase for %s: ", pp->name); - gets(passphrase, sizeof(passphrase), g_eli_visible_passphrase); - KASSERT(md.md_iterations >= 0, ("md_iterations = %d for %s", - (int)md.md_iterations, pp->name)); /* * Prepare Derived-Key from the user passphrase. */ - g_eli_crypto_hmac_init(&ctx, NULL, 0); if (md.md_iterations == 0) { g_eli_crypto_hmac_update(&ctx, md.md_salt, sizeof(md.md_salt)); g_eli_crypto_hmac_update(&ctx, passphrase, strlen(passphrase)); - } else { + } else if (md.md_iterations > 0) { u_char dkey[G_ELI_USERKEYLEN]; pkcs5v2_genkey(dkey, sizeof(dkey), md.md_salt, @@ -960,6 +1046,7 @@ g_eli_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey)); bzero(dkey, sizeof(dkey)); } + g_eli_crypto_hmac_final(&ctx, key, 0); /* @@ -968,26 +1055,26 @@ 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 == g_eli_tries - 1) { - i++; - break; + if (i == tries - 1) { + 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, g_eli_tries - i - 1); + pp->name, tries - i - 1); /* Try again. */ continue; } else if (error > 0) { G_ELI_DEBUG(0, "Cannot decrypt Master Key for %s (error=%d).", pp->name, error); + g_eli_keyfiles_clear(pp->name); return (NULL); } G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name); break; } - if (i == g_eli_tries) { - G_ELI_DEBUG(0, "Wrong key for %s. No tries left.", pp->name); - return (NULL); - } /* * We have correct key, let's attach provider. -- cgit v1.1