Index: head/sbin/geom/class/eli/geli.8 =================================================================== --- head/sbin/geom/class/eli/geli.8 +++ head/sbin/geom/class/eli/geli.8 @@ -68,6 +68,7 @@ .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 @@ 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). 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 @@ -86,7 +86,7 @@ * * 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 @@ { '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 @@ } /* 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)); Index: head/stand/geli/geliboot.c =================================================================== --- head/stand/geli/geliboot.c +++ head/stand/geli/geliboot.c @@ -121,14 +121,14 @@ 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 @@ 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)); Index: head/sys/geom/eli/g_eli.h =================================================================== --- head/sys/geom/eli/g_eli.h +++ head/sys/geom/eli/g_eli.h @@ -688,6 +688,8 @@ 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); Index: head/sys/geom/eli/g_eli.c =================================================================== --- head/sys/geom/eli/g_eli.c +++ head/sys/geom/eli/g_eli.c @@ -1086,7 +1086,7 @@ 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 @@ /* * 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) { 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 @@ -60,8 +60,8 @@ 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 @@ 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 @@ 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 @@ 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)); Index: head/sys/geom/eli/g_eli_key.c =================================================================== --- head/sys/geom/eli/g_eli_key.c +++ head/sys/geom/eli/g_eli_key.c @@ -103,52 +103,77 @@ } /* - * 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); } /*