Add support for creating GELI devices with older metadata version for use

with older FreeBSD versions:
- Add -V option to 'geli init' to specify version number. If no -V is given
  the most recent version is used.
- If -V is given don't allow to use features not supported by this version.
- Print version in 'geli list' output.
- Update manual page and add table describing which GELI version is
  supported by which FreeBSD version, so one can use it when preparing GELI
  device for older FreeBSD version.

Inspired by:	Garrett Cooper <yanegomi@gmail.com>
MFC after:	3 days
This commit is contained in:
Pawel Jakub Dawidek 2011-10-25 13:57:50 +00:00
parent e1d4b72a2e
commit 1f8c92e6fa
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=226733
4 changed files with 140 additions and 12 deletions

View File

@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd March 9, 2011
.Dd October 25, 2011
.Dt GELI 8
.Os
.Sh NAME
@ -60,6 +60,7 @@ utility:
.Op Fl K Ar newkeyfile
.Op Fl l Ar keylen
.Op Fl s Ar sectorsize
.Op Fl V Ar version
.Ar prov
.Nm
.Cm label - an alias for
@ -322,6 +323,15 @@ Change decrypted provider's sector size.
Increasing sector size allows to increase performance, because we need to
generate an IV and do encrypt/decrypt for every single sector - less number
of sectors means less work to do.
.It Fl V Ar version
Metadata version to use.
This option is helpful when creating provider that may be used by older
.Nm FreeBSD/GELI
versions.
Consult the
.Sx HISTORY
section to find which metadata version is supported by which FreeBSD version.
Note that using older metadata version may limit numer of features available.
.El
.It Cm attach
Attach the given provider.
@ -931,5 +941,33 @@ Support for
.Nm Camellia
block cipher is implemented by Yoshisato Yanagisawa in
.Fx 7.0 .
.Pp
Highest
.Nm GELI
metadata version supported by the given FreeBSD version:
.Pp
.Bl -column -offset indent ".Sy FreeBSD" ".Sy version"
.It Sy FreeBSD Ta Sy GELI
.It Sy version Ta Sy version
.Pp
.It Li 6.0 Ta 0
.It Li 6.1 Ta 0
.It Li 6.2 Ta 3
.It Li 6.3 Ta 3
.It Li 6.4 Ta 3
.Pp
.It Li 7.0 Ta 3
.It Li 7.1 Ta 3
.It Li 7.2 Ta 3
.It Li 7.3 Ta 3
.It Li 7.4 Ta 3
.Pp
.It Li 8.0 Ta 3
.It Li 8.1 Ta 3
.It Li 8.2 Ta 5
.Pp
.It Li 9.0 Ta 6
.El
.Pp
.Sh AUTHORS
.An Pawel Jakub Dawidek Aq pjd@FreeBSD.org

View File

@ -82,7 +82,7 @@ static int eli_backup_create(struct gctl_req *req, const char *prov,
/*
* Available commands:
*
* init [-bhPv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] prov
* init [-bhPv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] [-V version] prov
* label - alias for 'init'
* attach [-dprv] [-j passfile] [-k keyfile] prov
* detach [-fl] prov ...
@ -107,29 +107,31 @@ struct g_command class_commands[] = {
{ 'a', "aalgo", "", G_TYPE_STRING },
{ 'b', "boot", NULL, G_TYPE_BOOL },
{ 'B', "backupfile", "", G_TYPE_STRING },
{ 'e', "ealgo", GELI_ENC_ALGO, G_TYPE_STRING },
{ 'e', "ealgo", "", G_TYPE_STRING },
{ 'i', "iterations", "-1", G_TYPE_NUMBER },
{ 'J', "newpassfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
{ 'K', "newkeyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
{ 'l', "keylen", "0", G_TYPE_NUMBER },
{ 'P', "nonewpassphrase", NULL, G_TYPE_BOOL },
{ 's', "sectorsize", "0", G_TYPE_NUMBER },
{ 'V', "mdversion", "-1", G_TYPE_NUMBER },
G_OPT_SENTINEL
},
"[-bPv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] [-s sectorsize] prov"
"[-bPv] [-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 },
{ 'e', "ealgo", GELI_ENC_ALGO, G_TYPE_STRING },
{ 'e', "ealgo", "", G_TYPE_STRING },
{ 'i', "iterations", "-1", G_TYPE_NUMBER },
{ 'J', "newpassfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
{ 'K', "newkeyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
{ 'l', "keylen", "0", G_TYPE_NUMBER },
{ 'P', "nonewpassphrase", NULL, G_TYPE_BOOL },
{ 's', "sectorsize", "0", G_TYPE_NUMBER },
{ 'V', "mdversion", "-1", G_TYPE_NUMBER },
G_OPT_SENTINEL
},
"- an alias for 'init'"
@ -672,7 +674,7 @@ eli_init(struct gctl_req *req)
unsigned char key[G_ELI_USERKEYLEN];
char backfile[MAXPATHLEN];
const char *str, *prov;
unsigned secsize;
unsigned int secsize, version;
off_t mediasize;
intmax_t val;
int error, nargs;
@ -693,13 +695,30 @@ eli_init(struct gctl_req *req)
bzero(&md, sizeof(md));
strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
md.md_version = G_ELI_VERSION;
val = gctl_get_intmax(req, "mdversion");
if (val == -1) {
version = G_ELI_VERSION;
} else if (val < 0 || val > G_ELI_VERSION) {
gctl_error(req,
"Invalid version specified should be between %u and %u.",
G_ELI_VERSION_00, G_ELI_VERSION);
return;
} else {
version = val;
}
md.md_version = version;
md.md_flags = 0;
if (gctl_get_int(req, "boot"))
md.md_flags |= G_ELI_FLAG_BOOT;
md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1;
str = gctl_get_ascii(req, "aalgo");
if (*str != '\0') {
if (version < G_ELI_VERSION_01) {
gctl_error(req,
"Data authentication is supported starting from version %u.",
G_ELI_VERSION_01);
return;
}
md.md_aalgo = g_eli_str2aalgo(str);
if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN &&
md.md_aalgo <= CRYPTO_ALGORITHM_MAX) {
@ -725,12 +744,32 @@ eli_init(struct gctl_req *req)
if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
str = gctl_get_ascii(req, "ealgo");
if (*str == '\0') {
if (version < G_ELI_VERSION_05)
str = "aes-cbc";
else
str = GELI_ENC_ALGO;
}
md.md_ealgo = g_eli_str2ealgo(str);
if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
gctl_error(req, "Invalid encryption algorithm.");
return;
}
if (md.md_ealgo == CRYPTO_CAMELLIA_CBC &&
version < G_ELI_VERSION_04) {
gctl_error(req,
"Camellia-CBC algorithm is supported starting from version %u.",
G_ELI_VERSION_04);
return;
}
if (md.md_ealgo == CRYPTO_AES_XTS &&
version < G_ELI_VERSION_05) {
gctl_error(req,
"AES-XTS algorithm is supported starting from version %u.",
G_ELI_VERSION_05);
return;
}
}
val = gctl_get_intmax(req, "keylen");
md.md_keylen = val;

View File

@ -713,6 +713,7 @@ g_eli_create(struct gctl_req *req, struct g_class *mp, struct g_provider *bpp,
else
gp->access = g_std_access;
sc->sc_version = md->md_version;
sc->sc_inflight = 0;
sc->sc_crypto = G_ELI_CRYPTO_UNKNOWN;
sc->sc_flags = md->md_flags;
@ -1210,6 +1211,7 @@ g_eli_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
sbuf_printf(sb, "%s<UsedKey>%u</UsedKey>\n", indent,
sc->sc_nkey);
}
sbuf_printf(sb, "%s<Version>%u</Version>\n", indent, sc->sc_version);
sbuf_printf(sb, "%s<Crypto>", indent);
switch (sc->sc_crypto) {
case G_ELI_CRYPTO_HW:

View File

@ -43,6 +43,7 @@
#include <sys/tree.h>
#include <geom/geom.h>
#else
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
@ -166,6 +167,7 @@ struct g_eli_worker {
struct g_eli_softc {
struct g_geom *sc_geom;
u_int sc_version;
u_int sc_crypto;
uint8_t sc_mkey[G_ELI_DATAIVKEYLEN];
uint8_t sc_ekey[G_ELI_DATAKEYLEN];
@ -217,14 +219,28 @@ struct g_eli_metadata {
} __packed;
#ifndef _OpenSSL_
static __inline void
eli_metadata_encode(struct g_eli_metadata *md, u_char *data)
eli_metadata_encode_v0(struct g_eli_metadata *md, u_char **datap)
{
MD5_CTX ctx;
u_char *p;
p = data;
bcopy(md->md_magic, p, sizeof(md->md_magic)); p += sizeof(md->md_magic);
le32enc(p, md->md_version); p += sizeof(md->md_version);
p = *datap;
le32enc(p, md->md_flags); p += sizeof(md->md_flags);
le16enc(p, md->md_ealgo); p += sizeof(md->md_ealgo);
le16enc(p, md->md_keylen); p += sizeof(md->md_keylen);
le64enc(p, md->md_provsize); p += sizeof(md->md_provsize);
le32enc(p, md->md_sectorsize); p += sizeof(md->md_sectorsize);
*p = md->md_keys; p += sizeof(md->md_keys);
le32enc(p, md->md_iterations); p += sizeof(md->md_iterations);
bcopy(md->md_salt, p, sizeof(md->md_salt)); p += sizeof(md->md_salt);
bcopy(md->md_mkeys, p, sizeof(md->md_mkeys)); p += sizeof(md->md_mkeys);
*datap = p;
}
static __inline void
eli_metadata_encode_v1v2v3v4v5v6(struct g_eli_metadata *md, u_char **datap)
{
u_char *p;
p = *datap;
le32enc(p, md->md_flags); p += sizeof(md->md_flags);
le16enc(p, md->md_ealgo); p += sizeof(md->md_ealgo);
le16enc(p, md->md_keylen); p += sizeof(md->md_keylen);
@ -235,6 +251,39 @@ eli_metadata_encode(struct g_eli_metadata *md, u_char *data)
le32enc(p, md->md_iterations); p += sizeof(md->md_iterations);
bcopy(md->md_salt, p, sizeof(md->md_salt)); p += sizeof(md->md_salt);
bcopy(md->md_mkeys, p, sizeof(md->md_mkeys)); p += sizeof(md->md_mkeys);
*datap = p;
}
static __inline void
eli_metadata_encode(struct g_eli_metadata *md, u_char *data)
{
MD5_CTX ctx;
u_char *p;
p = data;
bcopy(md->md_magic, p, sizeof(md->md_magic));
p += sizeof(md->md_magic);
le32enc(p, md->md_version);
p += sizeof(md->md_version);
switch (md->md_version) {
case G_ELI_VERSION_00:
eli_metadata_encode_v0(md, &p);
break;
case G_ELI_VERSION_01:
case G_ELI_VERSION_02:
case G_ELI_VERSION_03:
case G_ELI_VERSION_04:
case G_ELI_VERSION_05:
case G_ELI_VERSION_06:
eli_metadata_encode_v1v2v3v4v5v6(md, &p);
break;
default:
#ifdef _KERNEL
panic("%s: Unsupported version %u.", __func__,
(u_int)md->md_version);
#else
assert(!"Unsupported metadata version.");
#endif
}
MD5Init(&ctx);
MD5Update(&ctx, data, p - data);
MD5Final(md->md_hash, &ctx);