All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/15][RFC] Encrypted logical volumes for LVM2
@ 2009-01-21 11:19 Milan Broz
  2009-01-21 11:19 ` [PATCH 01/15] Support crypt segment in libdevmapper tree Milan Broz
  0 siblings, 1 reply; 16+ messages in thread
From: Milan Broz @ 2009-01-21 11:19 UTC (permalink / raw)
  To: lvm-devel

This patch series implements encrypted volume handling in LVM2.

Not all functions are finished but it should provide basic
design overview for review and discussion.

(I know that patches are big, but I see no better alternative
for posting...)

Milan

Basic idea is provide standard encrypted volume management in LVM2
but keep key management (and userspace crypto handling) outside lvm core.

Then we can support simple key management (equivalent to
cryptsetup/luks) but also library for connecting to some
infrastructure. The metadata format is still the same.

This patches implements these subsystems, needed for
correct operation:
(see particular patches for description, this is just short overview)

	- new "crypt" and "crypt-keystore" lv segments
	(crypt is equivalent to linear segment, just with
	encrypted areas, crypt-keystore is area which
	include special metadata interpreted by particular
	driver - e.g. LUKS metadata area)

	- key handlers interface, for now
		"simple" handler
		"luks1" handler

	- internal master key cache (lvm need temporarily store
	master key used in dm-crypt maping table for various
	mapping table operations)
	
	- encrypted LVs & cryptostore LVs manipulation code
	
	- lvcreate support, lvconvert to allow importing
	already prepared encrypted volumes

	- some helper functions (like password entry etc.)
	(is linking to other library worth to replace these?)

Key management inside lvm

For manipulating with volume inside kernel device-mapper, lvm needs
to know master key and cipher parameters.

Crypt store says which method (crytpto store type) is used to obtain
these attributes, key handler implement these methods
(resp. should provide interface to proper tools for key management).

Examples of Key handlers:

  - The simple one is "plain" handler, where the used cipher is stored
in LVM metadata directly and driver asks user for master key.

 - Second one (not yet implemented) is "hashed" where the key is
hashed value of user entered password.
(equivalent of crypsetup in non-luks mode).

 - More sophisticated is use some key management system, and simple
 example is support for "LUKS".
 (here equivalent of cryptsetup-luks keystore)
 
 - For enterprise segment, it need implement key handler which will
 communicate with an infrastructure to obtain encryption parameters and key.

 ...

So the key handlers should be separated from basic lvm core,
I expect that it should be dynamically loaded library [RFC].
(library loading is not yet implemented in patchset, but
code should be already separate modules)


Metadata representation:

 - everything new is in crypt and crypt-keystore segment, so
  even old code should read partial metadata properly,
  just ignoring these segments.

 - new "crypt" segment has the same format as linear,
   just it adds "crypto_store" attribute, which is name
   of special LV withing the VG.
   Only one area is allowed in this segment (the same like linear)
   (it uses "areas" instead of "stripes" in segment metadata)

 - special cryptostore LV containing "crypt-keystore" segment.
   Here is stored information how to obtian crypt attributes
   needed for encrypted LV activation

     - crypostore LV can be shared between encrypted segments

     - the special name "cryptostoreN" is now reserved

     - it defines some basic metadata atttributes
       (handler name, cipher, key_size, key_hash)
       which are retained (if present) even if particular key handler
       is not loaded.
       (Basically this concept allows manipulation with metadata 
       in some rescue mode, but without specialized key handlers loaded.)

 - encrypted LV can consist of several encrypted segments, In normal
   situation all segments will use the same cryptostore.
   But it should support  online reencryption in future (in this situation
   it temporary  uses different crypto stores for segments).

 - cryptostore LV is special, invisible LV with only crypt-keystore segments.
   To simplify code, if the last lv segment referencing this LV is removed,
   cryptostore LV is removed too.

Best to see a METADATA example:

 vg {	... # no change here
	logical_volumes {

		# simple encrypted volume
		tst {
			id = "ONqIFB-p2vX-rQ2V-B9Yg-0kPB-uKbh-NWIssL"
			status = ["READ", "WRITE", "VISIBLE"]
			flags = []
			segment_count = 1

			segment1 {
				start_extent = 0
				extent_count = 4        # 16 Megabytes

				type = "crypt"
				crypto_store = "cryptostore1"

				areas = [
					"pv2", 12
				]
			}
		}

		# imported LUKS1 volume
		luks1 {
			id = "G0NURa-cD93-6VnU-zHGP-Affz-Hu8Q-3MU1vt"
			status = ["READ", "WRITE", "VISIBLE"]
			flags = []
			segment_count = 1

			segment1 {
				start_extent = 0
				extent_count = 3        # 12 Megabytes

				type = "crypt"
				crypto_store = "cryptostore2"

				areas = [
					"pv0", 4
				]
			}
		}

		# plain cryptostore
		cryptostore1 {
			id = "5WYknM-Vhti-pGqU-yIN7-UgY1-I3KW-Hnmb08"
			status = ["READ"]
			flags = []
			allocation_policy = "normal"
			segment_count = 1

			segment1 {
				start_extent = 0
				extent_count = 0        # 0 Kilobytes

				type = "crypt-keystore"
				handler = "plain"
				cipher = "aes-xts-plain"
				key_size = 256  # 32 Bytes
			}
		}

		# LUKS1 cryptostore
		cryptostore2 {
			id = "qbo213-gxbu-NeI3-n63K-vnOT-JtNB-RXmOUk"
			status = ["READ"]
			flags = []
			allocation_policy = "normal"
			segment_count = 1

			segment1 {
				start_extent = 0
				extent_count = 1        # 4 Megabytes

				type = "crypt-keystore"
				handler = "luks1"

				# LUKS keyslots live here
				areas = [
					"pv0", 3
				]
			}
		}
	}
}


This is the (huge) patchset statistic :-)

Milan Broz (15):
  Support crypt segment in libdevmapper tree.
  Add lvm-crypto header file with basic crypto struct definintions:
  Add master key cache to LVM.
  Add simple password helpers.
  Add key store handlers machinery.
  Prepare source for recognising crypt segment.
  Add "crypt" and "crypt-keystore" segment implementation.
  Add crypto_store to LV segment allocation functions.
  Add encrypted LV manipulation functions.
  Cache key from crypt mapping table if segment is active.
  Add lvcreate crypto LV implementation.
  Add lvconcert crypt implementation.
  Add --keyfile option.
  Add *testing* LUKS1 keystore implementation.
  Add simple test for crypto volumes.

 configure                        |  131 ++++++++++-
 configure.in                     |   51 ++++
 include/.symlinks                |    1 +
 lib/Makefile.in                  |   14 +
 lib/activate/activate.c          |   47 ++++
 lib/activate/activate.h          |    5 +
 lib/activate/dev_manager.c       |   59 +++++
 lib/activate/dev_manager.h       |    4 +
 lib/commands/toolcontext.c       |   37 +++
 lib/crypt/crypt.c                |  372 ++++++++++++++++++++++++++++
 lib/crypt/key_handlers.c         |   88 +++++++
 lib/crypt/key_luks.c             |  495 ++++++++++++++++++++++++++++++++++++++
 lib/crypt/lvm-crypto.h           |  126 ++++++++++
 lib/crypt/masterkey.c            |  152 ++++++++++++
 lib/crypt/password.c             |  127 ++++++++++
 lib/crypt/pbkdf2.c               |  199 +++++++++++++++
 lib/crypt/pbkdf2.h               |   36 +++
 lib/format1/format1.c            |    1 +
 lib/format1/import-extents.c     |    4 +-
 lib/format_pool/format_pool.c    |    1 +
 lib/format_pool/import_export.c  |    4 +-
 lib/format_text/import_vsn1.c    |    3 +-
 lib/metadata/crypt_manip.c       |  266 ++++++++++++++++++++
 lib/metadata/lv_alloc.h          |    3 +-
 lib/metadata/lv_manip.c          |   29 ++-
 lib/metadata/merge.c             |   32 +++-
 lib/metadata/metadata-exported.h |   20 ++
 lib/metadata/metadata.c          |    2 +
 lib/metadata/segtype.h           |    6 +
 lib/misc/configure.h.in          |    6 +
 libdm/.exported_symbols          |    1 +
 libdm/libdevmapper.h             |    4 +
 libdm/libdm-deptree.c            |   31 +++-
 test/t-crypto-usage.sh           |   54 ++++
 tools/args.h                     |    5 +
 tools/commands.h                 |   30 ++-
 tools/lvchange.c                 |    7 +
 tools/lvconvert.c                |  125 ++++++++++
 tools/lvcreate.c                 |  167 +++++++++++++-
 tools/toollib.c                  |    6 +
 tools/vgchange.c                 |    7 +
 41 files changed, 2723 insertions(+), 35 deletions(-)
 create mode 100644 lib/crypt/crypt.c
 create mode 100644 lib/crypt/key_handlers.c
 create mode 100644 lib/crypt/key_luks.c
 create mode 100644 lib/crypt/lvm-crypto.h
 create mode 100644 lib/crypt/masterkey.c
 create mode 100644 lib/crypt/password.c
 create mode 100644 lib/crypt/pbkdf2.c
 create mode 100644 lib/crypt/pbkdf2.h
 create mode 100644 lib/metadata/crypt_manip.c
 create mode 100755 test/t-crypto-usage.sh



^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 01/15] Support crypt segment in libdevmapper tree.
  2009-01-21 11:19 [PATCH 00/15][RFC] Encrypted logical volumes for LVM2 Milan Broz
@ 2009-01-21 11:19 ` Milan Broz
  2009-01-21 11:19   ` [PATCH 02/15] Add lvm-crypto header file with basic crypto struct definintions: Milan Broz
  0 siblings, 1 reply; 16+ messages in thread
From: Milan Broz @ 2009-01-21 11:19 UTC (permalink / raw)
  To: lvm-devel

 - it can support multiple segments, but note that
to work properly, correct IV (initialization vector)
offset parameter must be set properly.

Both cipher and key must be supplied in correct dm-crypt format,

Signed-off-by: Milan Broz <mbroz@redhat.com>
---
 libdm/.exported_symbols |    1 +
 libdm/libdevmapper.h    |    4 ++++
 libdm/libdm-deptree.c   |   31 ++++++++++++++++++++++++++++---
 3 files changed, 33 insertions(+), 3 deletions(-)

diff --git a/libdm/.exported_symbols b/libdm/.exported_symbols
index a6e04f8..f8dba1b 100644
--- a/libdm/.exported_symbols
+++ b/libdm/.exported_symbols
@@ -66,6 +66,7 @@ dm_tree_node_add_error_target
 dm_tree_node_add_zero_target
 dm_tree_node_add_linear_target
 dm_tree_node_add_striped_target
+dm_tree_node_add_crypt_target
 dm_tree_node_add_mirror_target
 dm_tree_node_add_mirror_target_log
 dm_tree_node_add_target_area
diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h
index 93aecbb..775b4ec 100644
--- a/libdm/libdevmapper.h
+++ b/libdm/libdevmapper.h
@@ -373,6 +373,10 @@ int dm_tree_node_add_linear_target(struct dm_tree_node *node,
 int dm_tree_node_add_striped_target(struct dm_tree_node *node,
 				       uint64_t size,
 				       uint32_t stripe_size);
+int dm_tree_node_add_crypt_target(struct dm_tree_node *node,
+				  uint64_t size,
+				  const char *cipher,
+				  const char *key);
 int dm_tree_node_add_mirror_target(struct dm_tree_node *node,
 				      uint64_t size);
  
diff --git a/libdm/libdm-deptree.c b/libdm/libdm-deptree.c
index 11428ca..310b30e 100644
--- a/libdm/libdm-deptree.c
+++ b/libdm/libdm-deptree.c
@@ -28,7 +28,8 @@
 
 /* Supported segment types */
 enum {
-	SEG_ERROR, 
+	SEG_CRYPT,
+	SEG_ERROR,
 	SEG_LINEAR,
 	SEG_MIRRORED,
 	SEG_SNAPSHOT,
@@ -43,6 +44,7 @@ struct {
 	unsigned type;
 	const char *target;
 } dm_segtypes[] = {
+	{ SEG_CRYPT, "crypt" },
 	{ SEG_ERROR, "error" },
 	{ SEG_LINEAR, "linear" },
 	{ SEG_MIRRORED, "mirror" },
@@ -69,8 +71,8 @@ struct load_segment {
 
 	uint64_t size;
 
-	unsigned area_count;		/* Linear + Striped + Mirrored */
-	struct dm_list areas;		/* Linear + Striped + Mirrored */
+	unsigned area_count;		/* Linear + Striped + Mirrored + Crypt */
+	struct dm_list areas;		/* Linear + Striped + Mirrored + Crypt */
 
 	uint32_t stripe_size;		/* Striped */
 
@@ -85,6 +87,9 @@ struct load_segment {
 	unsigned mirror_area_count;	/* Mirror */
 	uint32_t flags;			/* Mirror log */
 	char *uuid;			/* Clustered mirror log */
+
+	const char *cipher;		/* Crypt */
+	const char *key;		/* Crypt */
 };
 
 /* Per-device properties */
@@ -1323,6 +1328,9 @@ static int _emit_segment_line(struct dm_task *dmt, struct load_segment *seg, uin
 	case SEG_STRIPED:
 		EMIT_PARAMS(pos, "%u %u", seg->area_count, seg->stripe_size);
 		break;
+	case SEG_CRYPT:
+		EMIT_PARAMS(pos, "%s %s %" PRIu64, seg->cipher, seg->key, *seg_start);
+		break;
 	}
 
 	switch(seg->type) {
@@ -1331,6 +1339,7 @@ static int _emit_segment_line(struct dm_task *dmt, struct load_segment *seg, uin
 	case SEG_SNAPSHOT_ORIGIN:
 	case SEG_ZERO:
 		break;
+	case SEG_CRYPT:
 	case SEG_LINEAR:
 	case SEG_MIRRORED:
 	case SEG_STRIPED:
@@ -1664,6 +1673,22 @@ int dm_tree_node_add_striped_target(struct dm_tree_node *node,
 	return 1;
 }
 
+int dm_tree_node_add_crypt_target(struct dm_tree_node *node,
+				  uint64_t size,
+				  const char *cipher,
+				  const char *key)
+{
+	struct load_segment *seg;
+
+	if (!(seg = _add_segment(node, SEG_CRYPT, size)))
+		return_0;
+
+	seg->cipher = cipher;
+	seg->key = key;
+
+	return 1;
+}
+
 int dm_tree_node_add_mirror_target_log(struct dm_tree_node *node,
 					  uint32_t region_size,
 					  unsigned clustered, 
-- 
1.5.6.5



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 02/15] Add lvm-crypto header file with basic crypto struct definintions:
  2009-01-21 11:19 ` [PATCH 01/15] Support crypt segment in libdevmapper tree Milan Broz
@ 2009-01-21 11:19   ` Milan Broz
  2009-01-21 11:19     ` [PATCH 03/15] Add master key cache to LVM Milan Broz
  0 siblings, 1 reply; 16+ messages in thread
From: Milan Broz @ 2009-01-21 11:19 UTC (permalink / raw)
  To: lvm-devel

 - crypto_store_type it the crypto equivalent for segment type,
 it says how the crypto attributes are retrieved.
 In future there will be separate libraries
 which can provide various key stores.

 - crypto_store represents particular crypto store.
 Every crypt lv_segment must be linked to some crypto_store.
 Basically it says "how the cipher attributes and key" can
 be obtained for this segment.
 crypto_store can be shared by several LV segments.

 crypto_store can have special areas on disk (where it stores
 key material in some obfuscatted form - e.g. LUKS slots).

 If there is no area on disk, the cipher & key parameters
 can be stored directly in metadata (or provided through
 other interface - depends on crypto_store_type.)

 There are hardcoded attributes, which are mainly for
 supporting basic crypto segment operations
 (compatible mappings created by cryptsetup in non-luks mode)
 (see following patches).

 The keystore is identified by UUID (~= LV UUID)
 (Becuse crypto_store is represented by special LV,
  it is real LV UUID internally.)

Signed-off-by: Milan Broz <mbroz@redhat.com>
---
 include/.symlinks                |    1 +
 lib/crypt/lvm-crypto.h           |   65 ++++++++++++++++++++++++++++++++++++++
 lib/format1/format1.c            |    1 +
 lib/format_pool/format_pool.c    |    1 +
 lib/format_text/import_vsn1.c    |    1 +
 lib/metadata/metadata-exported.h |    5 +++
 lib/metadata/metadata.c          |    2 +
 7 files changed, 76 insertions(+), 0 deletions(-)
 create mode 100644 lib/crypt/lvm-crypto.h

diff --git a/include/.symlinks b/include/.symlinks
index 1a4bd93..4033e18 100644
--- a/include/.symlinks
+++ b/include/.symlinks
@@ -4,6 +4,7 @@
 ../lib/activate/activate.h
 ../lib/activate/targets.h
 ../lib/cache/lvmcache.h
+../lib/crypt/lvm-crypto.h
 ../lib/commands/errors.h
 ../lib/commands/toolcontext.h
 ../lib/config/config.h
diff --git a/lib/crypt/lvm-crypto.h b/lib/crypt/lvm-crypto.h
new file mode 100644
index 0000000..7ce3941
--- /dev/null
+++ b/lib/crypt/lvm-crypto.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _LVM_CRYPTO_H
+#define _LVM_CRYPTO_H
+
+#include "device.h"
+#include "uuid.h"
+
+/*
+ * Crypto config & key store
+ */
+struct crypto_store_type {
+	struct dm_list list;
+
+	const char *name;		/* cs type: plain/hashed/luks1 etc. */
+	uint32_t flags;			/* CS_IGNORE_* flags */
+	struct crypto_store_ops *ops;
+};
+
+struct crypto_store {
+	struct dm_list list;
+
+	int ref;			/* reference counter */
+	struct crypto_store_type *type;
+	struct dm_pool *mem;
+
+	struct id id;			/* ID, the same as LV id*/
+	const char *name;		/* Name used in crypt segments */
+	const char *type_name;		/* used if keystore type is unknown */
+
+	const char *cipher;		/* Cipher in dm-crypt form */
+	const char *keyhash;		/* Key hashing algorithm */
+	uint32_t key_size;		/* Master Key size in bits */
+
+	struct dm_list dev_areas;	/* disk areas maintained */
+};
+
+struct crypto_area_list {
+	struct dm_list list;
+	struct device_area area;
+};
+
+struct crypto_store_ops {
+	int (*scan) (struct device_area *da);
+	int (*master_key_retrieve) (struct crypto_store *cs,
+				    const char *name,
+				    char *buffer, unsigned buffer_len);
+	// int (*backup) (struct crypto_store *cs, ...);
+	// int (*restore) (struct crypto_store *cs, ...);
+	// FIXME: key management, area formatting functions, etc
+};
+
+#endif
diff --git a/lib/format1/format1.c b/lib/format1/format1.c
index 8ab9363..a9ed088 100644
--- a/lib/format1/format1.c
+++ b/lib/format1/format1.c
@@ -130,6 +130,7 @@ static struct volume_group *_build_vg(struct format_instance *fid,
 	vg->seqno = 0;
 	dm_list_init(&vg->pvs);
 	dm_list_init(&vg->lvs);
+	dm_list_init(&vg->crypto_stores);
 	dm_list_init(&vg->tags);
 
 	if (!_check_vgs(pvs))
diff --git a/lib/format_pool/format_pool.c b/lib/format_pool/format_pool.c
index 0f72bd3..53c995f 100644
--- a/lib/format_pool/format_pool.c
+++ b/lib/format_pool/format_pool.c
@@ -124,6 +124,7 @@ static struct volume_group *_build_vg_from_pds(struct format_instance
 	vg->system_id = NULL;
 	dm_list_init(&vg->pvs);
 	dm_list_init(&vg->lvs);
+	dm_list_init(&vg->crypto_stores);
 	dm_list_init(&vg->tags);
 
 	if (!import_pool_vg(vg, smem, pds))
diff --git a/lib/format_text/import_vsn1.c b/lib/format_text/import_vsn1.c
index b7d06af..b610501 100644
--- a/lib/format_text/import_vsn1.c
+++ b/lib/format_text/import_vsn1.c
@@ -768,6 +768,7 @@ static struct volume_group *_read_vg(struct format_instance *fid,
 
 	dm_list_init(&vg->lvs);
 	dm_list_init(&vg->tags);
+	dm_list_init(&vg->crypto_stores);
 
 	/* Optional tags */
 	if ((cn = find_config_node(vgn, "tags")) &&
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index 40ece6f..16c216a 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -22,6 +22,7 @@
 #define _LVM_METADATA_EXPORTED_H
 
 #include "uuid.h"
+#include "lvm-crypto.h"
 
 struct physical_volume;
 typedef struct physical_volume pv_t;
@@ -231,6 +232,8 @@ struct volume_group {
 	uint32_t snapshot_count;
 	struct dm_list lvs;
 
+	struct dm_list crypto_stores;
+
 	struct dm_list tags;
 };
 
@@ -271,6 +274,8 @@ struct lv_segment {
 	uint32_t extents_copied;
 	struct logical_volume *log_lv;
 
+	struct crypto_store *crypto_store;
+
 	struct dm_list tags;
 
 	struct lv_segment_area *areas;
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index a49c4d8..cb5dcbd 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -546,6 +546,7 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
 
 	vg->snapshot_count = 0;
 
+	dm_list_init(&vg->crypto_stores);
 	dm_list_init(&vg->tags);
 
 	if (!(vg->fid = cmd->fmt->ops->create_instance(cmd->fmt, vg_name,
@@ -1617,6 +1618,7 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd,
 	}
 	dm_list_init(&vg->pvs);
 	dm_list_init(&vg->lvs);
+	dm_list_init(&vg->crypto_stores);
 	dm_list_init(&vg->tags);
 	vg->cmd = cmd;
 	if (!(vg->name = dm_pool_strdup(cmd->mem, orphan_vgname))) {
-- 
1.5.6.5



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 03/15] Add master key cache to LVM.
  2009-01-21 11:19   ` [PATCH 02/15] Add lvm-crypto header file with basic crypto struct definintions: Milan Broz
@ 2009-01-21 11:19     ` Milan Broz
  2009-01-21 11:19       ` [PATCH 04/15] Add simple password helpers Milan Broz
  0 siblings, 1 reply; 16+ messages in thread
From: Milan Broz @ 2009-01-21 11:19 UTC (permalink / raw)
  To: lvm-devel

Master key is key used directly in crypt segment mapping table.

Because LVM performs various magic with mapping table,
we need ask user (for providing master key unlocking information)
only once and during the lvm operation cache the master key.

Master key cache provides such temporary store area.

Key is stored directly in dm-crypt format in hash table,
key for hash table is crypt_store UUID.

The memory for storing key is allocated using dm_malloc
and must be always wiped before releasing.

Master key interface provides these functions:
 - init/destroy the whole cache
 - insert/remove key from cache using its ID
 - query for key

Also this patch provides two helper functions:
lvm_masterkeys_verify - verifies that key is in expected format & length
lvm_masterkeys_retrieve - calls the retrieve function
                          in crypto store if key is not already cached

Signed-off-by: Milan Broz <mbroz@redhat.com>
---
 lib/Makefile.in            |    1 +
 lib/commands/toolcontext.c |   21 ++++++
 lib/crypt/lvm-crypto.h     |   22 +++++++
 lib/crypt/masterkey.c      |  149 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 193 insertions(+), 0 deletions(-)
 create mode 100644 lib/crypt/masterkey.c

diff --git a/lib/Makefile.in b/lib/Makefile.in
index 54092cd..9705580 100644
--- a/lib/Makefile.in
+++ b/lib/Makefile.in
@@ -37,6 +37,7 @@ SOURCES =\
 	cache/lvmcache.c \
 	commands/toolcontext.c \
 	config/config.c \
+	crypt/masterkey.c \
 	datastruct/btree.c \
 	datastruct/str_list.c \
 	device/dev-cache.c \
diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c
index 0a98325..26a4c83 100644
--- a/lib/commands/toolcontext.c
+++ b/lib/commands/toolcontext.c
@@ -997,6 +997,22 @@ static void _init_globals(struct cmd_context *cmd)
 
 }
 
+static int _init_crypto(struct cmd_context *cmd)
+{
+#ifdef CRYPT_INTERNAL
+	if (!lvm_masterkeys_init())
+		return 0;
+#endif
+	return 1;
+}
+
+static void _destroy_crypto(struct cmd_context *cmd)
+{
+#ifdef CRYPT_INTERNAL
+	lvm_masterkeys_destroy();
+#endif
+}
+
 /* Entry point */
 struct cmd_context *create_toolcontext(unsigned is_long_lived)
 {
@@ -1092,6 +1108,9 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived)
 	if (!_init_backup(cmd))
 		goto error;
 
+	if (!_init_crypto(cmd))
+		goto error;
+
 	_init_rand(cmd);
 
 	_init_globals(cmd);
@@ -1164,6 +1183,7 @@ int refresh_toolcontext(struct cmd_context *cmd)
 	dev_cache_exit();
 	_destroy_tags(cmd);
 	_destroy_tag_configs(cmd);
+	_destroy_crypto(cmd);
 
 	cmd->config_valid = 0;
 
@@ -1228,6 +1248,7 @@ void destroy_toolcontext(struct cmd_context *cmd)
 	dev_cache_exit();
 	_destroy_tags(cmd);
 	_destroy_tag_configs(cmd);
+	_destroy_crypto(cmd);
 	dm_pool_destroy(cmd->libmem);
 	dm_free(cmd);
 
diff --git a/lib/crypt/lvm-crypto.h b/lib/crypt/lvm-crypto.h
index 7ce3941..9690779 100644
--- a/lib/crypt/lvm-crypto.h
+++ b/lib/crypt/lvm-crypto.h
@@ -19,6 +19,15 @@
 #include "uuid.h"
 
 /*
+ * Master key is stored in *text* hexa string, in direct dm-crypt format
+ */
+typedef const char *masterkey_t;
+
+#define cs_handler_name(cs)     ((cs)->type ? (cs)->type->name : (cs)->type_name)
+
+#define cs_key_bytes(cs)        ((cs)->key_size ? ((cs)->key_size * 2 / 8) : 4095)
+
+/*
  * Crypto config & key store
  */
 struct crypto_store_type {
@@ -62,4 +71,17 @@ struct crypto_store_ops {
 	// FIXME: key management, area formatting functions, etc
 };
 
+/*
+ * Master Key cache
+ */
+int lvm_masterkeys_init(void);
+void lvm_masterkeys_destroy(void);
+
+int lvm_masterkeys_insert(const struct id *id, masterkey_t key);
+void lvm_masterkeys_remove(const struct id *id);
+masterkey_t lvm_masterkeys_query(const struct id *id);
+
+int lvm_masterkeys_verify(struct crypto_store *cs, const char *key);
+int lvm_masterkeys_retrieve(const char *for_text, struct crypto_store *cs);
+
 #endif
diff --git a/lib/crypt/masterkey.c b/lib/crypt/masterkey.c
new file mode 100644
index 0000000..6efefcd
--- /dev/null
+++ b/lib/crypt/masterkey.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ * Store for master keys used for dm-crypt mapping
+ */
+#include "lib.h"
+#include "lvm-crypto.h"
+
+static struct dm_hash_table *_key_hash = NULL;
+
+static void _masterkeys_destroy_entry(char *mk)
+{
+	/*
+	 * Safely clean memory
+	 */
+	memset(mk, 0, strlen(mk));
+	dm_free(mk);
+}
+
+void lvm_masterkeys_remove(const struct id *id)
+{
+	char *mk = (char *)lvm_masterkeys_query(id);
+
+	dm_hash_remove_binary(_key_hash, (const char *)id, ID_LEN);
+	_masterkeys_destroy_entry(mk);
+}
+
+int lvm_masterkeys_insert(const struct id *id, masterkey_t key)
+{
+	/*
+	 * Hash key for master key is id of cryptostore
+	 * Key is stored as text hexa string (direct dm-crypt format)
+	 */
+	return dm_hash_insert_binary(_key_hash, (const char *)id,
+				     ID_LEN, (void *)key) ? 1 : 0;
+}
+
+masterkey_t lvm_masterkeys_query(const struct id *id)
+{
+	return dm_hash_lookup_binary(_key_hash, (const char *)id, ID_LEN);
+}
+
+int lvm_masterkeys_verify(struct crypto_store *cs, const char *key)
+{
+	int i, len = strlen(key);
+
+	if (len != cs_key_bytes(cs))
+		return 0;
+
+	// FIXME: really stupid
+	for (i = 0; i < len; i++) {
+		if (key[i] >= '0' && key[i] <= '9')
+			continue;
+		if (key[i] >= 'a' && key[i] <= 'f')
+			continue;
+		if (key[i] >= 'A' && key[i] <= 'F')
+			continue;
+		return 0;
+	}
+
+	return 1;
+}
+
+int lvm_masterkeys_retrieve(const char *for_text, struct crypto_store *cs)
+{
+	char *password;
+	int r = 0;
+
+	// FIXME: allow several tries, set in lvm.conf
+	// FIXME: if the volume is activated, retrieve Master Key through dm table
+
+	/*
+	 * Driver for keystore is not loaded, do not try to read key.
+	 */
+	if (!cs->type || !cs->type->ops || !cs->type->ops->master_key_retrieve) {
+		log_error("Cannot retrieve password%s%s, "
+			  "key store handler type %s is not installed.",
+			  for_text ? " for " : "", for_text ?: "",
+			  cs_handler_name(cs));
+		return 0;
+	}
+
+	/*
+	 * Master Key is already cached
+	 */
+	if (lvm_masterkeys_query(&cs->id))
+		return 1;
+
+	/*
+	 * Buffer for hexa encoding
+	 */
+	if (!(password = dm_malloc(cs_key_bytes(cs) + 1)))
+		return_0;
+
+	r = cs->type->ops->master_key_retrieve(cs, for_text, password, cs_key_bytes(cs));
+
+	// FIXME: if the retrieve function fails, it should not ask during the same
+	//	  operation for the same volume again
+	if (!r)
+		goto out;
+
+	password[cs_key_bytes(cs)] = '\0';
+	if (!lvm_masterkeys_verify(cs, password)) {
+		log_error("Key is not in expected format.");
+		goto out;
+	}
+
+	return lvm_masterkeys_insert(&cs->id, password);
+out:
+	memset(password, 0, cs_key_bytes(cs));
+	dm_free(password);
+	return 0;
+}
+
+int lvm_masterkeys_init()
+{
+	//FIXME: clear keys?
+	if (_key_hash)
+		return 1;
+
+	log_debug("Initializing master key cache.");
+
+	if (!(_key_hash = dm_hash_create(128)))
+		return 0;
+
+	return 1;
+}
+
+void lvm_masterkeys_destroy()
+{
+	if (_key_hash) {
+		log_debug("Destroying master key cache (%u).", dm_hash_get_num_entries(_key_hash));
+		dm_hash_iter(_key_hash, (dm_hash_iterate_fn) _masterkeys_destroy_entry);
+		dm_hash_destroy(_key_hash);
+		_key_hash = NULL;
+	}
+}
-- 
1.5.6.5



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 04/15] Add simple password helpers.
  2009-01-21 11:19     ` [PATCH 03/15] Add master key cache to LVM Milan Broz
@ 2009-01-21 11:19       ` Milan Broz
  2009-01-21 11:19         ` [PATCH 05/15] Add key store handlers machinery Milan Broz
  0 siblings, 1 reply; 16+ messages in thread
From: Milan Broz @ 2009-01-21 11:19 UTC (permalink / raw)
  To: lvm-devel

These enable to read password from
	- terminal
	- standard input
	- file

(Key store handlers will use this.)

(Alternative is use some exported funtion provided
by some crypto library but I think we should
not rely here on external library.)

Signed-off-by: Milan Broz <mbroz@redhat.com>
---
 lib/Makefile.in        |    1 +
 lib/crypt/lvm-crypto.h |    6 ++
 lib/crypt/masterkey.c  |    3 +
 lib/crypt/password.c   |  127 ++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 137 insertions(+), 0 deletions(-)
 create mode 100644 lib/crypt/password.c

diff --git a/lib/Makefile.in b/lib/Makefile.in
index 9705580..d7b2bf2 100644
--- a/lib/Makefile.in
+++ b/lib/Makefile.in
@@ -38,6 +38,7 @@ SOURCES =\
 	commands/toolcontext.c \
 	config/config.c \
 	crypt/masterkey.c \
+	crypt/password.c \
 	datastruct/btree.c \
 	datastruct/str_list.c \
 	device/dev-cache.c \
diff --git a/lib/crypt/lvm-crypto.h b/lib/crypt/lvm-crypto.h
index 9690779..1a7825d 100644
--- a/lib/crypt/lvm-crypto.h
+++ b/lib/crypt/lvm-crypto.h
@@ -84,4 +84,10 @@ masterkey_t lvm_masterkeys_query(const struct id *id);
 int lvm_masterkeys_verify(struct crypto_store *cs, const char *key);
 int lvm_masterkeys_retrieve(const char *for_text, struct crypto_store *cs);
 
+/*
+ * Crypto Helper functions
+ */
+int lvm_set_password_dev(const char *password_file);
+int lvm_read_password(char *message, char *pass, size_t len);
+
 #endif
diff --git a/lib/crypt/masterkey.c b/lib/crypt/masterkey.c
index 6efefcd..c3870ca 100644
--- a/lib/crypt/masterkey.c
+++ b/lib/crypt/masterkey.c
@@ -126,6 +126,7 @@ out:
 
 int lvm_masterkeys_init()
 {
+	(void)lvm_set_password_dev(NULL);
 	//FIXME: clear keys?
 	if (_key_hash)
 		return 1;
@@ -140,6 +141,8 @@ int lvm_masterkeys_init()
 
 void lvm_masterkeys_destroy()
 {
+	(void)lvm_set_password_dev(NULL);
+
 	if (_key_hash) {
 		log_debug("Destroying master key cache (%u).", dm_hash_get_num_entries(_key_hash));
 		dm_hash_iter(_key_hash, (dm_hash_iterate_fn) _masterkeys_destroy_entry);
diff --git a/lib/crypt/password.c b/lib/crypt/password.c
new file mode 100644
index 0000000..a7f5a46
--- /dev/null
+++ b/lib/crypt/password.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ * Various password read helpers
+ */
+#include <fcntl.h>
+#include <termios.h>
+#include "lib.h"
+#include "lvm-crypto.h"
+
+/*
+ * File name where to read password form
+ */
+static char _password_dev_name[PATH_MAX+1];
+
+static int lvm_read_password_from_stdin(char *pass, size_t maxlen)
+{
+	int ret, fd = 0;
+
+	ret = read(fd, pass, maxlen);
+
+	if (ret > 0 && ret < maxlen)
+		pass[ret-1] = 0;
+
+	return ret;
+}
+
+static int lvm_read_password_from_tty(char *message, char *pass,
+				      size_t maxlen)
+{
+	struct termios term_orig, term_noecho;
+	int fd, ret = 0;
+
+	// FIXME: add timeout option
+	// FIXME: fail if not on compatible termial
+	// FIXME: support alternative imput (file)
+
+	if ((fd = open("/dev/tty", O_RDWR)) == -1)
+		return 0;
+
+	/*
+	 * Switch echo off
+	 */
+	if (tcgetattr(fd, &term_orig))
+		goto out_err;
+	memcpy(&term_noecho, &term_orig, sizeof(term_noecho));
+	term_noecho.c_lflag &= ~ECHO;
+	if (tcsetattr(fd, TCSAFLUSH, &term_noecho))
+		goto out_err;
+
+	if (message)
+		(void)write(fd, message, strlen(message));
+
+	ret = read(fd, pass, maxlen);
+
+	if (ret > 0 && ret < maxlen)
+		pass[ret-1] = 0;
+
+	(void)write(fd, "\n", 1);
+
+	(void)tcsetattr(fd, TCSAFLUSH, &term_orig);
+
+out_err:
+	(void)close(fd);
+
+	if (!ret)
+		log_error("Unable to get password from terminal.");
+
+	return ret;
+}
+
+static int lvm_read_password_from_file(const char *password_file,
+				      char *pass, size_t len)
+{
+	struct device *dev;
+	int r = 1;
+
+	if (!(dev = dev_create_file(password_file, NULL, NULL, 1)))
+		return 0;
+
+	if (!dev_open(dev)) {
+		log_error("Cannot open key file: %s", password_file);
+		return 0;
+	}
+
+	if (!dev_read(dev, 0, len, pass))
+		r = 0;
+
+	if (!dev_close(dev))
+		stack;
+
+	return r;
+}
+
+int lvm_set_password_dev(const char *password_file)
+{
+	if (!password_file)
+		memset(_password_dev_name, 0, sizeof(_password_dev_name));
+	else
+		strncpy(_password_dev_name, password_file, PATH_MAX);
+
+	//FIXME: verify file path?
+
+	return 1;
+}
+
+int lvm_read_password(char *message, char *pass, size_t len)
+{
+	if(!_password_dev_name[0])
+		return lvm_read_password_from_tty(message, pass, len);
+	else if(!strcmp(_password_dev_name, "-"))
+		return lvm_read_password_from_stdin(pass, len);
+
+	return lvm_read_password_from_file(_password_dev_name, pass, len);
+}
-- 
1.5.6.5



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 05/15] Add key store handlers machinery.
  2009-01-21 11:19       ` [PATCH 04/15] Add simple password helpers Milan Broz
@ 2009-01-21 11:19         ` Milan Broz
  2009-01-21 11:19           ` [PATCH 06/15] Prepare source for recognising crypt segment Milan Broz
  0 siblings, 1 reply; 16+ messages in thread
From: Milan Broz @ 2009-01-21 11:19 UTC (permalink / raw)
  To: lvm-devel

This code should load various drivers for manipulating
with key for volumes.

Here will be interface between LVM (for volume management)
and key management (and related security code).

Currently it only maintains the list of key handlers
and provides search for key handler in this list.

Also implements manadatory key handler "simple".
 - it stores cipher & keysize in LVM metadata directly
 - asks for Master Key (no processig here)

This is direct interface to dm-crypt mapping, and
it does not require any cryptography code in userspace.

Signed-off-by: Milan Broz <mbroz@redhat.com>
---
 lib/Makefile.in            |    1 +
 lib/commands/toolcontext.c |    3 ++
 lib/crypt/key_handlers.c   |   85 ++++++++++++++++++++++++++++++++++++++++++++
 lib/crypt/lvm-crypto.h     |   25 ++++++++++++-
 4 files changed, 112 insertions(+), 2 deletions(-)
 create mode 100644 lib/crypt/key_handlers.c

diff --git a/lib/Makefile.in b/lib/Makefile.in
index d7b2bf2..41395ed 100644
--- a/lib/Makefile.in
+++ b/lib/Makefile.in
@@ -37,6 +37,7 @@ SOURCES =\
 	cache/lvmcache.c \
 	commands/toolcontext.c \
 	config/config.c \
+	crypt/key_handlers.c \
 	crypt/masterkey.c \
 	crypt/password.c \
 	datastruct/btree.c \
diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c
index 26a4c83..f9a0b13 100644
--- a/lib/commands/toolcontext.c
+++ b/lib/commands/toolcontext.c
@@ -1002,6 +1002,8 @@ static int _init_crypto(struct cmd_context *cmd)
 #ifdef CRYPT_INTERNAL
 	if (!lvm_masterkeys_init())
 		return 0;
+	if (!lvm_keystore_handlers_init())
+		return 0;
 #endif
 	return 1;
 }
@@ -1010,6 +1012,7 @@ static void _destroy_crypto(struct cmd_context *cmd)
 {
 #ifdef CRYPT_INTERNAL
 	lvm_masterkeys_destroy();
+	lvm_keystore_handlers_destroy();
 #endif
 }
 
diff --git a/lib/crypt/key_handlers.c b/lib/crypt/key_handlers.c
new file mode 100644
index 0000000..678a260
--- /dev/null
+++ b/lib/crypt/key_handlers.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "lib.h"
+#include "lvm-crypto.h"
+
+/*
+ * Global Key Store handlers list
+ */
+static struct dm_list _keystore_handlers;
+
+/*
+ * Plain handler (mandatory)
+ */
+static int plain_retrieve(struct crypto_store *cs, const char *for_text,
+			  char *buffer, unsigned buffer_len)
+{
+	char prompt[4096];
+	unsigned len;
+
+	dm_snprintf(prompt, sizeof(prompt), "Enter master key%s%s [%u]: ",
+		    for_text ? " for " : "", for_text ?: "", buffer_len);
+	len = lvm_read_password(prompt, buffer, buffer_len);
+	if (len != buffer_len) {
+		log_error("Incorrect key length (need %u bytes, received %u)",
+			  buffer_len, len);
+		return 0;
+	}
+
+	return 1;
+}
+
+static struct crypto_store_ops _plain_ops = {
+	.master_key_retrieve = plain_retrieve,
+};
+
+static struct crypto_store_type _plain_csh = {
+	.name = "plain",
+	.flags = CS_IGNORE_KEYHASH,
+	.ops = &_plain_ops,
+};
+
+/*
+ * Key Store registration helpers
+ */
+int lvm_keystore_handlers_init()
+{
+	dm_list_init(&_keystore_handlers);
+
+	// FIXME: here should be library loading
+	dm_list_add(&_keystore_handlers, &_plain_csh.list);
+
+	return 1;
+}
+
+void lvm_keystore_handlers_destroy()
+{
+	dm_list_init(&_keystore_handlers);
+}
+
+struct crypto_store_type *lvm_get_keystore_handler(const char *name)
+{
+	struct crypto_store_type *csh;
+
+	if (!name)
+		return_NULL;
+
+	dm_list_iterate_items(csh, &_keystore_handlers)
+		if (!strcmp(name, csh->name))
+			return csh;
+
+	log_debug("Not supported %s handler for crypto store.", name);
+	return NULL;
+}
diff --git a/lib/crypt/lvm-crypto.h b/lib/crypt/lvm-crypto.h
index 1a7825d..3ebddce 100644
--- a/lib/crypt/lvm-crypto.h
+++ b/lib/crypt/lvm-crypto.h
@@ -23,9 +23,23 @@
  */
 typedef const char *masterkey_t;
 
-#define cs_handler_name(cs)     ((cs)->type ? (cs)->type->name : (cs)->type_name)
+/*
+ * Flags says if attribute is stored in keystore area and not in LVM metadata.
+ * By default, all generic attributes in LVM metadata must be retained
+ * (for example when some keystore handler is not loaded in rescue mode).
+ */
+#define CS_IGNORE_CIPHER	0x00000001U
+#define CS_IGNORE_KEYLEN	0x00000002U
+#define CS_IGNORE_KEYHASH	0x00000004U
+
+#define cs_flags(cs)		((cs)->type ? (cs)->type->flags : 0)
+#define cs_handler_name(cs)	((cs)->type ? (cs)->type->name : (cs)->type_name)
+
+#define cs_store_cipher(cs)	(cs_flags(cs) & CS_IGNORE_CIPHER ? 0 : 1)
+#define cs_store_keylen(cs)	(cs_flags(cs) & CS_IGNORE_KEYLEN ? 0 : 1)
+#define cs_store_keyhash(cs)	(cs_flags(cs) & CS_IGNORE_KEYHASH ? 0 : 1)
 
-#define cs_key_bytes(cs)        ((cs)->key_size ? ((cs)->key_size * 2 / 8) : 4095)
+#define cs_key_bytes(cs)	((cs)->key_size ? ((cs)->key_size * 2 / 8) : 4095)
 
 /*
  * Crypto config & key store
@@ -85,6 +99,13 @@ int lvm_masterkeys_verify(struct crypto_store *cs, const char *key);
 int lvm_masterkeys_retrieve(const char *for_text, struct crypto_store *cs);
 
 /*
+ * Key Store handlers manipulation
+ */
+int lvm_keystore_handlers_init(void);
+void lvm_keystore_handlers_destroy(void);
+struct crypto_store_type *lvm_get_keystore_handler(const char *name);
+
+/*
  * Crypto Helper functions
  */
 int lvm_set_password_dev(const char *password_file);
-- 
1.5.6.5



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 06/15] Prepare source for recognising crypt segment.
  2009-01-21 11:19         ` [PATCH 05/15] Add key store handlers machinery Milan Broz
@ 2009-01-21 11:19           ` Milan Broz
  2009-01-21 11:19             ` [PATCH 07/15] Add "crypt" and "crypt-keystore" segment implementation Milan Broz
  0 siblings, 1 reply; 16+ messages in thread
From: Milan Broz @ 2009-01-21 11:19 UTC (permalink / raw)
  To: lvm-devel

 - modify autoconf script to define CRYPTO
   (supporting currently only --with-crypto=none/internal)
   and add CRYPT_INTERNAL define

 - prepare empty segtype constructors
   for segtype "crypt" (encrypted area)
   for segtype "crypt-keystore" (crypto metadata area)

 - define new encrypted segment flag and prepare
   macros to work with it.

Signed-off-by: Milan Broz <mbroz@redhat.com>
---
 configure                  |   39 +++++++++++++++++++++++++++++++++++++--
 configure.in               |   21 +++++++++++++++++++++
 lib/Makefile.in            |    4 ++++
 lib/commands/toolcontext.c |   13 +++++++++++++
 lib/crypt/crypt.c          |   44 ++++++++++++++++++++++++++++++++++++++++++++
 lib/metadata/segtype.h     |    6 ++++++
 lib/misc/configure.h.in    |    3 +++
 7 files changed, 128 insertions(+), 2 deletions(-)
 create mode 100644 lib/crypt/crypt.c

diff --git a/configure b/configure
index 8095090..e4a8f82 100755
--- a/configure
+++ b/configure
@@ -699,6 +699,7 @@ CLUSTER
 CLVMD
 CMDLIB
 COPTIMISE_FLAG
+CRYPTO
 DEBUG
 DEVMAPPER
 DMEVENTD
@@ -1360,6 +1361,8 @@ Optional Packages:
                           TYPE=internal
   --with-mirrors=TYPE     Mirror support: internal/shared/none
                           TYPE=internal
+  --with-crypto=TYPE      Crypto support: internal/none
+                          TYPE=internal
   --with-clvmd=TYPE       Build cluster LVM Daemon: cman/gulm/none/all
                           TYPE=none
   --with-optimisation=OPT C optimisation flag [OPT=-O2]
@@ -8663,6 +8666,36 @@ _ACEOF
 fi
 
 ################################################################################
+{ echo "$as_me:$LINENO: checking whether to include crypto support" >&5
+echo $ECHO_N "checking whether to include crypto support... $ECHO_C" >&6; }
+
+# Check whether --with-crypto was given.
+if test "${with_crypto+set}" = set; then
+  withval=$with_crypto;  CRYPTO="$withval"
+else
+   CRYPTO="internal"
+fi
+
+{ echo "$as_me:$LINENO: result: $CRYPTO" >&5
+echo "${ECHO_T}$CRYPTO" >&6; }
+
+if [ "x$CRYPTO" != xnone -a "x$CRYPTO" != xinternal ];
+ then  { { echo "$as_me:$LINENO: error: --with-crypto parameter invalid
+" >&5
+echo "$as_me: error: --with-crypto parameter invalid
+" >&2;}
+   { (exit 1); exit 1; }; }
+fi;
+
+if test x$CRYPTO = xinternal; then
+
+cat >>confdefs.h <<\_ACEOF
+#define CRYPT_INTERNAL 1
+_ACEOF
+
+fi
+
+################################################################################
 { echo "$as_me:$LINENO: checking whether to enable readline" >&5
 echo $ECHO_N "checking whether to enable readline... $ECHO_C" >&6; }
 # Check whether --enable-readline was given.
@@ -11719,6 +11752,7 @@ LVM_VERSION="\"`cat VERSION 2>/dev/null || echo Unknown`\""
 
 
 
+
 ################################################################################
 ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile doc/Makefile include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/snapshot/Makefile libdm/Makefile libdm/libdevmapper.pc man/Makefile po/Makefile scripts/clvmd_init_red_hat scripts/Makefile test/Makefile test/api/Makefile tools/Makefile tools/version.h"
 
@@ -12450,6 +12484,7 @@ CLUSTER!$CLUSTER$ac_delim
 CLVMD!$CLVMD$ac_delim
 CMDLIB!$CMDLIB$ac_delim
 COPTIMISE_FLAG!$COPTIMISE_FLAG$ac_delim
+CRYPTO!$CRYPTO$ac_delim
 DEBUG!$DEBUG$ac_delim
 DEVMAPPER!$DEVMAPPER$ac_delim
 DMEVENTD!$DMEVENTD$ac_delim
@@ -12461,7 +12496,6 @@ DM_IOCTLS!$DM_IOCTLS$ac_delim
 DM_LIB_VERSION!$DM_LIB_VERSION$ac_delim
 DM_LIB_PATCHLEVEL!$DM_LIB_PATCHLEVEL$ac_delim
 FSADM!$FSADM$ac_delim
-GROUP!$GROUP$ac_delim
 _ACEOF
 
   if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then
@@ -12503,6 +12537,7 @@ _ACEOF
 ac_delim='%!_!# '
 for ac_last_try in false false false false false :; do
   cat >conf$$subs.sed <<_ACEOF
+GROUP!$GROUP$ac_delim
 HAVE_LIBDL!$HAVE_LIBDL$ac_delim
 HAVE_REALTIME!$HAVE_REALTIME$ac_delim
 HAVE_SELINUX!$HAVE_SELINUX$ac_delim
@@ -12534,7 +12569,7 @@ usrsbindir!$usrsbindir$ac_delim
 LTLIBOBJS!$LTLIBOBJS$ac_delim
 _ACEOF
 
-  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 29; then
+  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 30; then
     break
   elif $ac_last_try; then
     { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
diff --git a/configure.in b/configure.in
index 5d28c2c..a5e9236 100644
--- a/configure.in
+++ b/configure.in
@@ -306,6 +306,26 @@ if test x$MIRRORS = xinternal; then
 fi
 
 ################################################################################
+dnl -- crypt inclusion type
+AC_MSG_CHECKING(whether to include crypto support)
+AC_ARG_WITH(crypto,
+  [  --with-crypto=TYPE      Crypto support: internal/none
+                          [TYPE=internal] ],
+  [ CRYPTO="$withval" ],
+  [ CRYPTO="internal" ])
+AC_MSG_RESULT($CRYPTO)
+
+if [[ "x$CRYPTO" != xnone -a "x$CRYPTO" != xinternal ]];
+ then  AC_MSG_ERROR(
+--with-crypto parameter invalid
+)
+fi;
+
+if test x$CRYPTO = xinternal; then
+	AC_DEFINE([CRYPT_INTERNAL], 1, [Define to 1 to include built-in support for crypto.])
+fi
+
+################################################################################
 dnl -- Disable readline
 AC_MSG_CHECKING(whether to enable readline)
 AC_ARG_ENABLE([readline],
@@ -734,6 +754,7 @@ AC_SUBST(CLUSTER)
 AC_SUBST(CLVMD)
 AC_SUBST(CMDLIB)
 AC_SUBST(COPTIMISE_FLAG)
+AC_SUBST(CRYPTO)
 AC_SUBST(CSCOPE_CMD)
 AC_SUBST(DEBUG)
 AC_SUBST(DEVMAPPER)
diff --git a/lib/Makefile.in b/lib/Makefile.in
index 41395ed..7971395 100644
--- a/lib/Makefile.in
+++ b/lib/Makefile.in
@@ -126,6 +126,10 @@ ifeq ("@MIRRORS@", "internal")
   SOURCES += mirror/mirrored.c
 endif
 
+ifeq ("@CRYPTO@", "internal")
+  SOURCES += crypt/crypt.c
+endif
+
 ifeq ("@DEVMAPPER@", "yes")
   SOURCES +=\
 	activate/dev_manager.c \
diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c
index f9a0b13..af7643b 100644
--- a/lib/commands/toolcontext.c
+++ b/lib/commands/toolcontext.c
@@ -846,6 +846,19 @@ static int _init_segtypes(struct cmd_context *cmd)
 	dm_list_add(&cmd->segtypes, &segtype->list);
 #endif
 
+#ifdef CRYPT_INTERNAL
+	if (!(segtype = init_crypt_segtype(cmd)))
+		return 0;
+	segtype->library = NULL;
+	dm_list_add(&cmd->segtypes, &segtype->list);
+
+	/* Keystore must be supported if crypt segment is present */
+	if (!(segtype = init_keystore_segtype(cmd)))
+		return 0;
+	segtype->library = NULL;
+	dm_list_add(&cmd->segtypes, &segtype->list);
+#endif
+
 #ifdef HAVE_LIBDL
 	/* Load any formats in shared libs unless static */
 	if (!is_static() &&
diff --git a/lib/crypt/crypt.c b/lib/crypt/crypt.c
new file mode 100644
index 0000000..c6658c8
--- /dev/null
+++ b/lib/crypt/crypt.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "lib.h"
+#include "segtype.h"
+#include "display.h"
+#include "text_export.h"
+#include "text_import.h"
+#include "str_list.h"
+#include "targets.h"
+#include "activate.h"
+#include "pv_alloc.h"
+#include "metadata.h"
+#include "toolcontext.h"
+#include "lvm-crypto.h"
+
+/*
+ * "crypt" segment - using real crypt target directly
+ */
+struct segment_type *init_crypt_segtype(struct cmd_context *cmd)
+{
+	return NULL;
+}
+
+/*
+ * "crypt-keystore" segment - area for storing keys, need specific handler
+ * (e.g. LUKS metadata space)
+ */
+
+struct segment_type *init_keystore_segtype(struct cmd_context *cmd)
+{
+	return NULL;
+}
diff --git a/lib/metadata/segtype.h b/lib/metadata/segtype.h
index ad274a3..15f4b5b 100644
--- a/lib/metadata/segtype.h
+++ b/lib/metadata/segtype.h
@@ -33,6 +33,7 @@ struct dev_manager;
 #define SEG_VIRTUAL		0x00000020U
 #define SEG_CANNOT_BE_ZEROED	0x00000040U
 #define SEG_MONITORED		0x00000080U
+#define SEG_AREAS_ENCRYPTED	0x00000100U
 
 #define seg_is_mirrored(seg)	((seg)->segtype->flags & SEG_AREAS_MIRRORED ? 1 : 0)
 #define seg_is_striped(seg)	((seg)->segtype->flags & SEG_AREAS_STRIPED ? 1 : 0)
@@ -41,10 +42,14 @@ struct dev_manager;
 #define seg_can_split(seg)	((seg)->segtype->flags & SEG_CAN_SPLIT ? 1 : 0)
 #define seg_cannot_be_zeroed(seg) ((seg)->segtype->flags & SEG_CANNOT_BE_ZEROED ? 1 : 0)
 #define seg_monitored(seg)	((seg)->segtype->flags & SEG_MONITORED ? 1 : 0)
+#define seg_is_encrypted(seg)	((seg)->segtype->flags & SEG_AREAS_ENCRYPTED ? 1 : 0)
+#define seg_is_keystore(seg)	(seg_is_encrypted(seg) && seg_cannot_be_zeroed(seg))
 
 #define segtype_is_striped(segtype)	((segtype)->flags & SEG_AREAS_STRIPED ? 1 : 0)
 #define segtype_is_mirrored(segtype)	((segtype)->flags & SEG_AREAS_MIRRORED ? 1 : 0)
 #define segtype_is_virtual(segtype)	((segtype)->flags & SEG_VIRTUAL ? 1 : 0)
+#define segtype_is_encrypted(segtype)	((segtype)->flags & SEG_AREAS_ENCRYPTED ? 1 : 0)
+#define segtype_is_keystore(segtype)	(segtype_is_encrypted(segtype) && segtype_cannot_be_zeroed(segtype))
 
 struct segment_type {
 	struct dm_list list;
@@ -106,6 +111,7 @@ struct segment_type *init_mirrored_segtype(struct cmd_context *cmd);
 #endif
 
 #ifdef CRYPT_INTERNAL
+struct segment_type *init_keystore_segtype(struct cmd_context *cmd);
 struct segment_type *init_crypt_segtype(struct cmd_context *cmd);
 #endif
 
diff --git a/lib/misc/configure.h.in b/lib/misc/configure.h.in
index ccab9f5..d171445 100644
--- a/lib/misc/configure.h.in
+++ b/lib/misc/configure.h.in
@@ -11,6 +11,9 @@
    */
 #undef CRAY_STACKSEG_END
 
+/* Define to 1 to include built-in support for crypto. */
+#undef CRYPT_INTERNAL
+
 /* Define to 1 if using `alloca.c'. */
 #undef C_ALLOCA
 
-- 
1.5.6.5



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 07/15] Add "crypt" and "crypt-keystore" segment implementation.
  2009-01-21 11:19           ` [PATCH 06/15] Prepare source for recognising crypt segment Milan Broz
@ 2009-01-21 11:19             ` Milan Broz
  2009-01-21 11:19               ` [PATCH 08/15] Add crypto_store to LV segment allocation functions Milan Broz
  0 siblings, 1 reply; 16+ messages in thread
From: Milan Broz @ 2009-01-21 11:19 UTC (permalink / raw)
  To: lvm-devel

The "crypt" segment is direct equivalent to "linear"
segment, except it is encrypted of course.

For segment are defined the same flags to easily
re-use all lvm functions already using linear segment type.

It also implements merging of crypto segments.

New flag SEG_AREAS_ENCRYPTED is used to distinguish
between linear and encrypted segment.

The "crypt" segment must have assigned crypto_store
(for validation code enforcing this see following patch).

METADATA example:

	segment1 {
		start_extent = 0
		extent_count = 4        # 16 Megabytes

		type = "crypt"
		crypto_store = "cryptostore3"

		areas = [
			"pv2", 0
		]
	}

(crypto_store references special LV by its name in the same VG)

The "crypt-keystore" segment describes special part of disk,
which is never activated with any logical volume, except
for key management operation.
(Activation is currently simply ignored).

(Following code implements crypto store as special LV,
only "crypt-keystore" segments can be included in this
special LV.)

Keystore segment should always include only physical areas
(but the restriction is not hardcoded).

Currently only one area for crypto segment and one "crypt-keystore"
segment per special LV is supported.

METADATA examples:
 - "plain" handler, no areas

		segment1 {
			start_extent = 0
			extent_count = 0        # 0 Kilobytes

			type = "crypt-keystore"
			handler = "plain"
			cipher = "aes-xts-plain"
			key_size = 256  # 32 Bytes
		}

 - "luks1" handler using keyslots on disk
   (cipher, key_size, etc. are stored in this area too)

		segment1 {
			start_extent = 0
			extent_count = 1        # 4 Megabytes

			type = "crypt-keystore"
			handler = "luks1"

			areas = [
				"pv0", 3
			]
		}

For unknown handler it retains these attributes:
	cipher, key_size, key_hash

Signed-off-by: Milan Broz <mbroz@redhat.com>
---
 lib/Makefile.in                  |    1 +
 lib/crypt/crypt.c                |  332 +++++++++++++++++++++++++++++++++++++-
 lib/crypt/lvm-crypto.h           |    7 +
 lib/metadata/crypt_manip.c       |  118 ++++++++++++++
 lib/metadata/metadata-exported.h |    9 +
 5 files changed, 465 insertions(+), 2 deletions(-)
 create mode 100644 lib/metadata/crypt_manip.c

diff --git a/lib/Makefile.in b/lib/Makefile.in
index 7971395..7167f04 100644
--- a/lib/Makefile.in
+++ b/lib/Makefile.in
@@ -69,6 +69,7 @@ SOURCES =\
 	locking/locking.c \
 	locking/no_locking.c \
 	log/log.c \
+	metadata/crypt_manip.c \
 	metadata/lv_manip.c \
 	metadata/merge.c \
 	metadata/metadata.c \
diff --git a/lib/crypt/crypt.c b/lib/crypt/crypt.c
index c6658c8..6dae88f 100644
--- a/lib/crypt/crypt.c
+++ b/lib/crypt/crypt.c
@@ -25,20 +25,348 @@
 #include "toolcontext.h"
 #include "lvm-crypto.h"
 
+static const char *_crypt_name(const struct lv_segment *seg)
+{
+	return seg->segtype->name;
+}
+
+static void _crypt_display(const struct lv_segment *seg)
+{
+	log_print("  Key Handler\t\t%s", cs_handler_name(seg->crypto_store));
+	display_stripe(seg, 0, "  ");
+	log_print(" ");
+}
+
+static int _crypt_text_import_area_count(struct config_node *sn, uint32_t *area_count)
+{
+	/*
+	 * Crypt can support multiple segments, but only one area per segment.
+	 */
+	*area_count = 1;
+
+	return 1;
+}
+
+static int _keystore_text_import_area_count(struct config_node *sn, uint32_t *area_count)
+{
+	/*
+	 * Crypt key store can use area on disk, simply check if it is in metadata
+	 */
+	if (find_config_node(sn, "areas"))
+		*area_count = 1;
+	else
+		*area_count = 0;
+
+	return 1;
+}
+
+static int _crypt_text_import(struct lv_segment *seg, const struct config_node *sn,
+			struct dm_hash_table *pv_hash)
+{
+	struct config_node *cn;
+	char *cs_name = NULL;
+
+	if (!get_config_str(sn, "crypto_store", &cs_name)) {
+		log_error("Couldn't find crypto_store for %s.", sn->key);
+		return 0;
+	}
+
+	if (!seg_assign_cryptostore(seg, cs_name, NULL)) {
+		log_error("Crypto store %s is not defined.", cs_name);
+		return 0;
+	}
+	seg->crypto_store->ref++;
+
+	if (!(cn = find_config_node(sn, "areas"))) {
+		log_error("Couldn't find areas array for segment "
+			  "'%s'.", sn->key);
+		return 0;
+	}
+
+	return text_import_areas(seg, sn, cn, pv_hash, 0);
+}
+
+static int _keystore_text_import(struct lv_segment *seg, const struct config_node *sn,
+			struct dm_hash_table *pv_hash)
+{
+	struct crypto_store *cs;
+	struct crypto_store_type *cst;
+	struct config_node *cn;
+	char *cs_handler = NULL, *cipher = NULL, *keyhash = NULL;
+
+	if (!get_config_str(sn, "handler", &cs_handler)) {
+		log_error("Missing handler specification for crypto store.");
+		return 0;
+	}
+
+	cst = lvm_get_keystore_handler(cs_handler);
+
+	if (!seg_assign_cryptostore(seg, seg->lv->name, cst)) {
+		log_error("Crypto store %s cannot be created.", seg->lv->name);
+		return 0;
+	}
+
+	/*
+	 * Now is the crypto store in seg surely allocated
+	 */
+	cs = seg->crypto_store;
+
+	/*
+	 * If we have no handler, store type_name
+	 * (to allow export metadata for not loaded keyhandler)
+	 */
+	if (!cst) {
+		if (!(cs->type_name = dm_pool_strdup(cs->mem, cs_handler)))
+			return_0;
+		log_debug("Unknown crypto store type %s, LVs using it cannot "
+			 "be activated.", cs_handler);
+	}
+
+	cs->id = seg->lv->lvid.id[1];
+
+	if (cs_store_cipher(cs)) {
+		if (!get_config_str(sn, "cipher", &cipher) && cst) {
+			log_error("Missing cipher specification for %s.", cs_handler);
+			return 0;
+		}
+
+		if (cipher && !(cs->cipher = dm_pool_strdup(cs->mem, cipher)))
+			return_0;
+	}
+
+	if (cs_store_keyhash(cs)) {
+		if (!get_config_str(sn, "key_hash", &keyhash) && cst) {
+			log_error("Missing key hash specification for %s.", cs_handler);
+			return 0;
+		}
+
+		if (keyhash && !(cs->keyhash = dm_pool_strdup(cs->mem, keyhash)))
+			return_0;
+	}
+
+	if (cs_store_keylen(cs))
+		if (!get_config_uint32(sn, "key_size", &cs->key_size) && cst) {
+			log_error("Missing key length specification for %s.", cs_handler);
+			return 0;
+		}
+
+	if (seg->area_count == 0)
+		return 1;
+
+	if (!(cn = find_config_node(sn, "areas"))) {
+		log_error("Couldn't find areas array for segment '%s'.", sn->key);
+		return 0;
+	}
+
+	if (!text_import_areas(seg, sn, cn, pv_hash, 0))
+		return 0;
+
+	if (!seg_assign_crypto_store_areas(seg)) {
+		log_error("Couldn't convert LV areas to crypto store areas.");
+		return 0;
+	}
+
+	return 1;
+}
+
+static int _crypt_text_export(const struct lv_segment *seg, struct formatter *f)
+{
+	if (seg->crypto_store)
+		outf(f, "crypto_store = \"%s\"", seg->crypto_store->name);
+
+	return out_areas(f, seg, "area");
+}
+
+static int _keystore_text_export(const struct lv_segment *seg, struct formatter *f)
+{
+	struct crypto_store *cs = seg->crypto_store;
+
+	outf(f, "handler = \"%s\"", cs_handler_name(cs));
+
+	/*
+	 * For unknown keystore, default is retain all previously read attributes
+	 */
+	if (cs_store_cipher(cs) && cs->cipher)
+		outf(f, "cipher = \"%s\"", cs->cipher);
+
+	if (cs_store_keylen(cs) && cs->key_size)
+		outf(f, "key_size = %u\t# %u Bytes", cs->key_size, cs->key_size / 8);
+
+	if (cs_store_keyhash(cs) && cs->keyhash)
+		outf(f, "key_hash = \"%s\"", cs->keyhash);
+
+	return seg->area_count ? out_areas(f, seg, "area") : 1;
+}
+
+static int _crypt_merge_segments(struct lv_segment *seg1, struct lv_segment *seg2)
+{
+	/*
+	 * Check if segments are compatible
+	 * Area count is always 1.
+	 */
+	if ((seg_type(seg1, 0) != AREA_PV) ||
+	    (seg_type(seg2, 0) != AREA_PV))
+		return 0;
+
+	if (seg1->crypto_store != seg2->crypto_store)
+		return 0;
+
+	if (!str_list_lists_equal(&seg1->tags, &seg2->tags))
+		return 0;
+
+	if ((seg_pv(seg1, 0) != seg_pv(seg2, 0)) ||
+	    (seg_pe(seg1, 0) + seg1->area_len != seg_pe(seg2, 0)))
+		return 0;
+
+	/*
+	 * Merge segments
+	 */
+	seg1->len += seg2->len;
+	seg1->area_len += seg2->area_len;
+
+	merge_pv_segments(seg_pvseg(seg1, 0), seg_pvseg(seg2, 0));
+
+	return 1;
+}
+
+#ifdef DEVMAPPER_SUPPORT
+static int _crypt_add_target_line(struct dev_manager *dm,
+				struct dm_pool *mem __attribute((unused)),
+				struct cmd_context *cmd __attribute((unused)),
+				void **target_state __attribute((unused)),
+				struct lv_segment *seg,
+				struct dm_tree_node *node, uint64_t len,
+				uint32_t *pvmove_mirror_count __attribute((unused)))
+{
+	struct crypto_store *cs = seg->crypto_store;
+
+	/*
+	 * Caller must ensure that master key is already in cache
+	 */
+	if(!dm_tree_node_add_crypt_target(node, len, cs->cipher, lvm_masterkeys_query(&cs->id)))
+		return_0;
+
+	return add_areas_line(dm, seg, node, 0u, seg->area_count);
+}
+
+static int _keystore_add_target_line(struct dev_manager *dm,
+				struct dm_pool *mem __attribute((unused)),
+				struct cmd_context *cmd __attribute((unused)),
+				void **target_state __attribute((unused)),
+				struct lv_segment *seg,
+				struct dm_tree_node *node, uint64_t len,
+				uint32_t *pvmove_mirror_count __attribute((unused)))
+{
+	/*
+	 * FIXME: allow activation only for Key Management operations here
+	 *
+	if (!dm_tree_node_add_linear_target(node, len))
+		return_0;
+
+	return add_areas_line(dm, seg, node, 0u, seg->area_count);
+	 */
+
+	return 0;
+}
+
+static int _crypt_target_present(const struct lv_segment *seg __attribute((unused)),
+				   unsigned *attributes __attribute((unused)))
+{
+	static int _crypt_checked = 0;
+	static int _crypt_present = 0;
+
+	if (!_crypt_checked)
+		_crypt_present = target_present("crypt", 0);
+
+	_crypt_checked = 1;
+
+	return _crypt_present;
+}
+#endif
+
+static int _crypt_modules_needed(struct dm_pool *mem,
+				const struct lv_segment *seg __attribute((unused)),
+				struct dm_list *modules)
+{
+	if (!str_list_add(mem, modules, "crypt")) {
+		log_error("crypt module string list allocation failed");
+		return 0;
+	}
+
+	return 1;
+}
+
+static void _crypt_destroy(const struct segment_type *segtype)
+{
+	dm_free((void *)segtype);
+}
+
 /*
  * "crypt" segment - using real crypt target directly
  */
+static struct segtype_handler _crypt_ops = {
+	.name			= _crypt_name,
+	.display		= _crypt_display,
+	.text_import_area_count	= _crypt_text_import_area_count,
+	.text_import		= _crypt_text_import,
+	.text_export		= _crypt_text_export,
+	.merge_segments		= _crypt_merge_segments,
+#ifdef DEVMAPPER_SUPPORT
+	.add_target_line	= _crypt_add_target_line,
+	.target_present		= _crypt_target_present,
+#endif
+	.modules_needed		= _crypt_modules_needed,
+	.destroy		= _crypt_destroy,
+};
+
 struct segment_type *init_crypt_segtype(struct cmd_context *cmd)
 {
-	return NULL;
+	struct segment_type *segtype = dm_malloc(sizeof(*segtype));
+
+	if (!segtype)
+		return_NULL;
+
+	segtype->cmd = cmd;
+	segtype->ops = &_crypt_ops;
+	segtype->name = "crypt";
+	segtype->private = NULL;
+	segtype->flags = SEG_AREAS_STRIPED |SEG_AREAS_ENCRYPTED | SEG_CAN_SPLIT;
+
+	log_very_verbose("Initialised segtype: %s", segtype->name);
+
+	return segtype;
 }
 
 /*
  * "crypt-keystore" segment - area for storing keys, need specific handler
  * (e.g. LUKS metadata space)
  */
+static struct segtype_handler _keystore_ops = {
+	.name			= _crypt_name,
+	.display		= _crypt_display,
+	.text_import_area_count	= _keystore_text_import_area_count,
+	.text_import		= _keystore_text_import,
+	.text_export		= _keystore_text_export,
+#ifdef DEVMAPPER_SUPPORT
+	.add_target_line 	= _keystore_add_target_line,
+#endif
+	.destroy		= _crypt_destroy,
+};
 
 struct segment_type *init_keystore_segtype(struct cmd_context *cmd)
 {
-	return NULL;
+	struct segment_type *segtype = dm_malloc(sizeof(*segtype));
+
+	if (!segtype)
+		return_NULL;
+
+	segtype->cmd = cmd;
+	segtype->ops = &_keystore_ops;
+	segtype->name = "crypt-keystore";
+	segtype->private = NULL;
+	segtype->flags = SEG_AREAS_STRIPED | SEG_AREAS_ENCRYPTED | SEG_CANNOT_BE_ZEROED;
+
+	log_very_verbose("Initialised segtype: %s", segtype->name);
+
+	return segtype;
 }
diff --git a/lib/crypt/lvm-crypto.h b/lib/crypt/lvm-crypto.h
index 3ebddce..6ed2d91 100644
--- a/lib/crypt/lvm-crypto.h
+++ b/lib/crypt/lvm-crypto.h
@@ -23,6 +23,9 @@
  */
 typedef const char *masterkey_t;
 
+struct lv_segment;
+struct logical_volume;
+
 /*
  * Flags says if attribute is stored in keystore area and not in LVM metadata.
  * By default, all generic attributes in LVM metadata must be retained
@@ -111,4 +114,8 @@ struct crypto_store_type *lvm_get_keystore_handler(const char *name);
 int lvm_set_password_dev(const char *password_file);
 int lvm_read_password(char *message, char *pass, size_t len);
 
+struct device_area *first_crypto_area(struct crypto_store *cs);
+int seg_assign_crypto_store_areas(struct lv_segment *seg);
+int seg_assign_cryptostore(struct lv_segment *seg, const char *name,
+                           struct crypto_store_type *cst);
 #endif
diff --git a/lib/metadata/crypt_manip.c b/lib/metadata/crypt_manip.c
new file mode 100644
index 0000000..59e40b9
--- /dev/null
+++ b/lib/metadata/crypt_manip.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "lib.h"
+#include "metadata.h"
+#include "toolcontext.h"
+#include "lv_alloc.h"
+#include "segtype.h"
+#include "activate.h"
+
+struct crypto_store *alloc_cryptostore(struct dm_pool *mem, const char *name,
+				       struct crypto_store_type *cst)
+{
+	struct crypto_store *cs;
+
+	cs = dm_pool_zalloc(mem, sizeof(struct crypto_store));
+	if (!cs)
+		return_NULL;
+
+	cs->mem = mem;
+	cs->type = cst;
+	if (!(cs->name = dm_pool_strdup(cs->mem, name)))
+		return_NULL;
+
+	dm_list_init(&cs->dev_areas);
+
+	return cs;
+}
+
+/*
+ * Crypto area helpers
+ */
+struct device_area *first_crypto_area(struct crypto_store *cs)
+{
+	struct crypto_area_list *da = NULL;
+
+	dm_list_iterate_items(da, &cs->dev_areas)
+		break;
+
+	return da ? &da->area : NULL;
+}
+
+int seg_assign_crypto_store_areas(struct lv_segment *seg)
+{
+	struct crypto_area_list *cal;
+
+	if (seg->area_count == 0)
+		return 1;
+
+	if (seg->area_count > 1)
+		return 0;
+
+	if (!(cal = dm_pool_zalloc(seg->crypto_store->mem, sizeof(*cal))))
+		return_0;
+
+	cal->area.dev = seg_dev(seg, 0);
+	cal->area.start = seg_pv(seg, 0)->pe_start +
+			  seg->lv->vg->extent_size * seg_pe(seg, 0);
+	cal->area.start <<= SECTOR_SHIFT;
+	cal->area.size = seg->lv->vg->extent_size * seg_pvseg(seg, 0)->len;
+
+	dm_list_add(&seg->crypto_store->dev_areas, &cal->list);
+
+	return 1;
+}
+
+/*
+ * We cannot guarantee that LV segment is read after cryptostore LV
+ * Code can allocate empty cryptostore, which get set up later
+ * vg_validate must check against unconfigured cryptostores.
+ */
+int seg_assign_cryptostore(struct lv_segment *seg, const char *name,
+			   struct crypto_store_type *cst)
+{
+	struct volume_group *vg = seg->lv->vg;
+	struct crypto_store *cs;
+
+	if (!(cs = find_crypto_store_in_vg(vg, name))) {
+		if (!(cs = alloc_cryptostore(vg->cmd->mem, name, cst)))
+			return_0;
+
+		dm_list_add(&vg->crypto_stores, &cs->list);
+	}
+
+	// FIXME: remove this test
+	if (seg->crypto_store && seg->crypto_store != cs)
+		log_error("Internal error: cryptostore mismatch.");
+
+	if (cst)
+		cs->type = cst;
+
+	seg->crypto_store = cs;
+
+	return 1;
+}
+
+struct crypto_store *find_crypto_store_in_vg(struct volume_group *vg,
+					     const char *cs_name)
+{
+	struct crypto_store *cs;
+
+	dm_list_iterate_items(cs, &vg->crypto_stores)
+		if (!strcmp(cs->name, cs_name))
+			return cs;
+
+	return NULL;
+}
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index 16c216a..2aa5a1b 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -476,6 +476,9 @@ struct logical_volume *find_lv(const struct volume_group *vg,
 			       const char *lv_name);
 struct physical_volume *find_pv_by_name(struct cmd_context *cmd,
 					const char *pv_name);
+/* Find crypto store in VG */
+struct crypto_store *find_crypto_store_in_vg(struct volume_group *vg,
+					     const char *cs_name);
 
 /* Find LV segment containing given LE */
 struct lv_segment *first_seg(const struct logical_volume *lv);
@@ -567,6 +570,12 @@ char *generate_lv_name(struct volume_group *vg, const char *format,
 		       char *buffer, size_t len);
 
 /*
+ * Crypto functions
+ */
+struct crypto_store *alloc_cryptostore(struct dm_pool *mem, const char *name,
+				       struct crypto_store_type *cst);
+
+/*
 * Begin skeleton for external LVM library
 */
 struct device *pv_dev(const pv_t *pv);
-- 
1.5.6.5



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 08/15] Add crypto_store to LV segment allocation functions.
  2009-01-21 11:19             ` [PATCH 07/15] Add "crypt" and "crypt-keystore" segment implementation Milan Broz
@ 2009-01-21 11:19               ` Milan Broz
  2009-01-21 11:19                 ` [PATCH 09/15] Add encrypted LV manipulation functions Milan Broz
  0 siblings, 1 reply; 16+ messages in thread
From: Milan Broz @ 2009-01-21 11:19 UTC (permalink / raw)
  To: lvm-devel

Also by default inherit crypto store from first segment
when allocating new crypt segment.

Signed-off-by: Milan Broz <mbroz@redhat.com>
---
 lib/format1/import-extents.c    |    4 ++--
 lib/format_pool/import_export.c |    4 ++--
 lib/format_text/import_vsn1.c   |    2 +-
 lib/metadata/lv_alloc.h         |    3 ++-
 lib/metadata/lv_manip.c         |   24 ++++++++++++++++--------
 lib/metadata/merge.c            |    2 +-
 6 files changed, 24 insertions(+), 15 deletions(-)

diff --git a/lib/format1/import-extents.c b/lib/format1/import-extents.c
index ded0a8e..937c5bf 100644
--- a/lib/format1/import-extents.c
+++ b/lib/format1/import-extents.c
@@ -219,7 +219,7 @@ static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm)
 		len = _area_length(lvm, le);
 
 		if (!(seg = alloc_lv_segment(cmd->mem, segtype, lvm->lv, le,
-					     len, 0, 0, NULL, 1, len, 0, 0, 0))) {
+					     len, 0, 0, NULL, 1, len, 0, 0, 0, NULL))) {
 			log_error("Failed to allocate linear segment.");
 			return 0;
 		}
@@ -293,7 +293,7 @@ static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
 					     lvm->stripes * area_len,
 					     0, lvm->stripe_size, NULL,
 					     lvm->stripes,
-					     area_len, 0, 0, 0))) {
+					     area_len, 0, 0, 0, NULL))) {
 			log_error("Failed to allocate striped segment.");
 			return 0;
 		}
diff --git a/lib/format_pool/import_export.c b/lib/format_pool/import_export.c
index 4d2163d..a5198de 100644
--- a/lib/format_pool/import_export.c
+++ b/lib/format_pool/import_export.c
@@ -220,7 +220,7 @@ static int _add_stripe_seg(struct dm_pool *mem,
 	if (!(seg = alloc_lv_segment(mem, segtype, lv, *le_cur,
 				     area_len * usp->num_devs, 0,
 				     usp->striping, NULL, usp->num_devs,
-				     area_len, 0, 0, 0))) {
+				     area_len, 0, 0, 0, NULL))) {
 		log_error("Unable to allocate striped lv_segment structure");
 		return 0;
 	}
@@ -257,7 +257,7 @@ static int _add_linear_seg(struct dm_pool *mem,
 		if (!(seg = alloc_lv_segment(mem, segtype, lv, *le_cur,
 					     area_len, 0, usp->striping,
 					     NULL, 1, area_len,
-					     POOL_PE_SIZE, 0, 0))) {
+					     POOL_PE_SIZE, 0, 0, NULL))) {
 			log_error("Unable to allocate linear lv_segment "
 				  "structure");
 			return 0;
diff --git a/lib/format_text/import_vsn1.c b/lib/format_text/import_vsn1.c
index b610501..1de6fbc 100644
--- a/lib/format_text/import_vsn1.c
+++ b/lib/format_text/import_vsn1.c
@@ -336,7 +336,7 @@ static int _read_segment(struct dm_pool *mem, struct volume_group *vg,
 
 	if (!(seg = alloc_lv_segment(mem, segtype, lv, start_extent,
 				     extent_count, 0, 0, NULL, area_count,
-				     extent_count, 0, 0, 0))) {
+				     extent_count, 0, 0, 0, NULL))) {
 		log_error("Segment allocation failed");
 		return 0;
 	}
diff --git a/lib/metadata/lv_alloc.h b/lib/metadata/lv_alloc.h
index f94f503..e21fb08 100644
--- a/lib/metadata/lv_alloc.h
+++ b/lib/metadata/lv_alloc.h
@@ -26,7 +26,8 @@ struct lv_segment *alloc_lv_segment(struct dm_pool *mem,
 				    uint32_t area_len,
 				    uint32_t chunk_size,
 				    uint32_t region_size,
-				    uint32_t extents_copied);
+				    uint32_t extents_copied,
+				    struct crypto_store *crypto_store);
 
 struct lv_segment *alloc_snapshot_seg(struct logical_volume *lv,
 				      uint32_t status, uint32_t old_le_count);
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index 2661e0c..2c3fdf5 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -173,7 +173,8 @@ struct lv_segment *alloc_lv_segment(struct dm_pool *mem,
 				    uint32_t area_len,
 				    uint32_t chunk_size,
 				    uint32_t region_size,
-				    uint32_t extents_copied)
+				    uint32_t extents_copied,
+				    struct crypto_store *crypto_store)
 {
 	struct lv_segment *seg;
 	uint32_t areas_sz = area_count * sizeof(*seg->areas);
@@ -203,6 +204,7 @@ struct lv_segment *alloc_lv_segment(struct dm_pool *mem,
 	seg->region_size = region_size;
 	seg->extents_copied = extents_copied;
 	seg->log_lv = log_lv;
+	seg->crypto_store = crypto_store;
 	dm_list_init(&seg->tags);
 
 	if (log_lv && !attach_mirror_log(seg, log_lv))
@@ -226,7 +228,7 @@ struct lv_segment *alloc_snapshot_seg(struct logical_volume *lv,
 	if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv, old_le_count,
 				     lv->le_count - old_le_count, status, 0,
 				     NULL, 0, lv->le_count - old_le_count,
-				     0, 0, 0))) {
+				     0, 0, 0, NULL))) {
 		log_error("Couldn't allocate new snapshot segment.");
 		return NULL;
 	}
@@ -655,16 +657,21 @@ static int _setup_alloced_segment(struct logical_volume *lv, uint32_t status,
 {
 	uint32_t s, extents, area_multiple;
 	struct lv_segment *seg;
+	struct crypto_store *cs = NULL;
 
 	area_multiple = calc_area_multiple(segtype, area_count);
 
+	/* Inherit crypto_store from first segment */
+	if (segtype_is_encrypted(segtype) && first_seg(lv))
+		cs = first_seg(lv)->crypto_store;
+
 	/* log_lv gets set up elsehere */
 	if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv,
 				     lv->le_count,
 				     aa[0].len * area_multiple,
 				     status, stripe_size, NULL,
 				     area_count,
-				     aa[0].len, 0u, region_size, 0u))) {
+				     aa[0].len, 0u, region_size, 0u, cs))) {
 		log_error("Couldn't allocate new LV segment.");
 		return 0;
 	}
@@ -673,6 +680,7 @@ static int _setup_alloced_segment(struct logical_volume *lv, uint32_t status,
 		if (!set_lv_segment_area_pv(seg, s, aa[s].pv, aa[s].pe))
 			return_0;
 
+
 	dm_list_add(&lv->segments, &seg->list);
 
 	extents = aa[0].len * area_multiple;
@@ -1260,7 +1268,7 @@ int lv_add_virtual_segment(struct logical_volume *lv, uint32_t status,
 
 	if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv,
 				     lv->le_count, extents, status, 0,
-				     NULL, 0, extents, 0, 0, 0))) {
+				     NULL, 0, extents, 0, 0, 0, NULL))) {
 		log_error("Couldn't allocate new zero segment.");
 		return 0;
 	}
@@ -1393,7 +1401,7 @@ static struct lv_segment *_convert_seg_to_mirror(struct lv_segment *seg,
 					log_lv,
 					seg->area_count, seg->area_len,
 					seg->chunk_size, region_size,
-					seg->extents_copied))) {
+					seg->extents_copied, NULL))) {
 		log_error("Couldn't allocate converted LV segment");
 		return NULL;
 	}
@@ -1534,7 +1542,7 @@ int lv_add_log_segment(struct alloc_handle *ah, struct logical_volume *log_lv)
 				     get_segtype_from_string(log_lv->vg->cmd,
 							     "striped"),
 				     log_lv, 0, ah->log_area.len, MIRROR_LOG,
-				     0, NULL, 1, ah->log_area.len, 0, 0, 0))) {
+				     0, NULL, 1, ah->log_area.len, 0, 0, 0, NULL))) {
 		log_error("Couldn't allocate new mirror log segment.");
 		return 0;
 	}
@@ -2447,7 +2455,7 @@ struct logical_volume *insert_layer_for_lv(struct cmd_context *cmd,
 	if (!(mapseg = alloc_lv_segment(cmd->mem, segtype,
 					lv_where, 0, layer_lv->le_count,
 					status, 0, NULL, 1, layer_lv->le_count,
-					0, 0, 0)))
+					0, 0, 0, NULL)))
 		return_NULL;
 
 	/* map the new segment to the original underlying are */
@@ -2490,7 +2498,7 @@ static int _extend_layer_lv_for_segment(struct logical_volume *layer_lv,
 	if (!(mapseg = alloc_lv_segment(layer_lv->vg->cmd->mem, segtype,
 					layer_lv, layer_lv->le_count,
 					seg->area_len, status, 0,
-					NULL, 1, seg->area_len, 0, 0, 0)))
+					NULL, 1, seg->area_len, 0, 0, 0, NULL)))
 		return_0;
 
 	/* map the new segment to the original underlying are */
diff --git a/lib/metadata/merge.c b/lib/metadata/merge.c
index 66e9ce0..f1d8b9a 100644
--- a/lib/metadata/merge.c
+++ b/lib/metadata/merge.c
@@ -274,7 +274,7 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
 					   seg->log_lv,
 					   seg->area_count, seg->area_len,
 					   seg->chunk_size, seg->region_size,
-					   seg->extents_copied))) {
+					   seg->extents_copied, seg->crypto_store))) {
 		log_error("Couldn't allocate cloned LV segment.");
 		return 0;
 	}
-- 
1.5.6.5



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 09/15] Add encrypted LV manipulation functions.
  2009-01-21 11:19               ` [PATCH 08/15] Add crypto_store to LV segment allocation functions Milan Broz
@ 2009-01-21 11:19                 ` Milan Broz
  2009-01-21 11:19                   ` [PATCH 10/15] Cache key from crypt mapping table if segment is active Milan Broz
  0 siblings, 1 reply; 16+ messages in thread
From: Milan Broz @ 2009-01-21 11:19 UTC (permalink / raw)
  To: lvm-devel

 - add vg_validate code which checks that all
   - crypt segments has referenced crypto_store
   - cryptostores have special LV in this VG
   - existing crypto_store LVs are referenced

 - add reserved LV name "cryptostoreN" used for cryptostore LV

 - retrieve segment master key before activate and preload commands
 (and skip the table loading if we have no key for crypt segments)

 - add cryptostore LV add/remove functions.

crypto_store has reference counter
(increased during segment loading or new crypt segment allocation)

If the last segment is removed, automatically remove special
crypto_store LV too.

Signed-off-by: Milan Broz <mbroz@redhat.com>
---
 lib/activate/activate.c          |    6 ++
 lib/crypt/lvm-crypto.h           |    2 +
 lib/metadata/crypt_manip.c       |  142 ++++++++++++++++++++++++++++++++++++++
 lib/metadata/lv_manip.c          |    5 ++
 lib/metadata/merge.c             |   30 ++++++++
 lib/metadata/metadata-exported.h |    6 ++
 tools/toollib.c                  |    6 ++
 7 files changed, 197 insertions(+), 0 deletions(-)

diff --git a/lib/activate/activate.c b/lib/activate/activate.c
index 2bc1db7..0f13cbd 100644
--- a/lib/activate/activate.c
+++ b/lib/activate/activate.c
@@ -863,6 +863,9 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
 
 	/* If VG was precommitted, preload devices for the LV */
 	if ((lv_pre->vg->status & PRECOMMITTED)) {
+		if (!lv_retrieve_password(lv))
+			return 0;
+
 		if (!_lv_preload(lv_pre)) {
 			/* FIXME Revert preloading */
 			return_0;
@@ -1047,6 +1050,9 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
 	if (exclusive)
 		lv->status |= ACTIVATE_EXCL;
 
+	if (!lv_retrieve_password(lv))
+		return 0;
+
 	memlock_inc();
 	r = _lv_activate_lv(lv);
 	memlock_dec();
diff --git a/lib/crypt/lvm-crypto.h b/lib/crypt/lvm-crypto.h
index 6ed2d91..42004b7 100644
--- a/lib/crypt/lvm-crypto.h
+++ b/lib/crypt/lvm-crypto.h
@@ -118,4 +118,6 @@ struct device_area *first_crypto_area(struct crypto_store *cs);
 int seg_assign_crypto_store_areas(struct lv_segment *seg);
 int seg_assign_cryptostore(struct lv_segment *seg, const char *name,
                            struct crypto_store_type *cst);
+int lv_retrieve_password(struct logical_volume *lv);
+
 #endif
diff --git a/lib/metadata/crypt_manip.c b/lib/metadata/crypt_manip.c
index 59e40b9..ff5c3e2 100644
--- a/lib/metadata/crypt_manip.c
+++ b/lib/metadata/crypt_manip.c
@@ -105,6 +105,67 @@ int seg_assign_cryptostore(struct lv_segment *seg, const char *name,
 	return 1;
 }
 
+
+/*
+ * Set cryptostore for all LV segments
+ */
+int lv_add_cryptostore(struct logical_volume *lv, struct crypto_store *cs)
+{
+	struct lv_segment *seg;
+
+	if (!find_crypto_store_in_vg(lv->vg, cs->name))
+		return_0;
+
+	dm_list_iterate_items(seg, &lv->segments) {
+		seg->crypto_store = cs;
+		seg->crypto_store->ref++;
+	}
+
+	return 1;
+}
+
+static int remove_cryptostore(struct crypto_store *cs, struct logical_volume *lv)
+{
+	struct lv_list *lvl;
+
+	lvl = find_lv_in_vg(lv->vg, cs->name);
+
+	/*
+	 * Explicit cryptostore LV remove (lv_remove_single() do the job)
+	 * But do not allow removing of used cryptostore
+	 */
+	if (lv == lvl->lv)
+		return cs->ref ? 0 : 1;
+
+	if (--cs->ref)
+		return 1;
+
+	log_verbose("Removing unused cryptostore %s", cs->name);
+	dm_list_del(&cs->list);
+
+	if (!lv_remove(lvl->lv)) {
+		log_error("Error cryptostore logical volume \"%s\"", lvl->lv->name);
+		return 0;
+	}
+
+	return 1;
+}
+
+/*
+ * Try to remove cryptostores in all LV segments
+ */
+int lv_remove_cryptostores(struct logical_volume *lv)
+{
+	struct lv_segment *seg;
+
+	dm_list_iterate_items(seg, &lv->segments)
+		if (seg->crypto_store &&
+		    !remove_cryptostore(seg->crypto_store, lv))
+			return 0;
+
+	return 1;
+}
+
 struct crypto_store *find_crypto_store_in_vg(struct volume_group *vg,
 					     const char *cs_name)
 {
@@ -116,3 +177,84 @@ struct crypto_store *find_crypto_store_in_vg(struct volume_group *vg,
 
 	return NULL;
 }
+
+/*
+ * Allocate new cryptostore. If seg is specified use it,
+ * otherwise alloc new virtual segment.
+ *
+ * Caller must set paramaters if required (like cipher).
+ */
+struct crypto_store *vg_add_cryptostore(struct volume_group *vg,
+					struct lv_segment *seg,
+					const char *handler_name)
+{
+	struct crypto_store *cs;
+	struct crypto_store_type *cst;
+	struct segment_type *cs_segtype;
+	struct logical_volume *cs_lv;
+
+	if (!(cs_segtype = get_segtype_from_string(vg->cmd, "crypt-keystore"))) {
+		log_error("Failed to initialize crypt-keystore segment.");
+		return NULL;
+	}
+
+	if (!(cs_lv = lv_create_empty("cryptostore%d", NULL,
+				      LVM_READ, vg->alloc, 0, vg))) {
+		log_error("Failed to create cryptstore LV.");
+		return NULL;
+	}
+
+	if (seg) {
+		/* We have physical key store area */
+		dm_list_add(&cs_lv->segments, &seg->list);
+		seg->lv = cs_lv;
+		seg->segtype = cs_segtype;
+		cs_lv->le_count = 1;
+	} else {
+		/* Need to allocate virtual segment*/
+		if (!lv_add_virtual_segment(cs_lv, LVM_READ, 0, cs_segtype))
+			return_NULL;
+
+		seg = first_seg(cs_lv);
+	}
+
+	if (!(cst = lvm_get_keystore_handler(handler_name)))
+		return_0;
+
+	if (!(cs = alloc_cryptostore(vg->cmd->mem, cs_lv->name, cst)))
+		return_0;
+
+	cs->id = cs_lv->lvid.id[1];
+	seg->crypto_store = cs;
+	if (!seg_assign_crypto_store_areas(seg))
+		return_0;
+
+	dm_list_add(&vg->crypto_stores, &cs->list);
+
+	return cs;
+}
+
+static int _seg_retrieve_masterkey(struct lv_segment *seg)
+{
+	/*
+	 * Master Key is already cached
+	 */
+	if (lvm_masterkeys_query(&seg->crypto_store->id))
+		return 1;
+
+	return lvm_masterkeys_retrieve(seg->lv->name, seg->crypto_store);
+}
+
+int lv_retrieve_password(struct logical_volume *lv)
+{
+	struct lv_segment *seg;
+
+	dm_list_iterate_items(seg, &lv->segments) {
+		if (seg_is_encrypted(seg) &&
+		    !seg_is_keystore(seg) &&
+		    !_seg_retrieve_masterkey(seg))
+			return 0;
+	}
+
+	return 1;
+}
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index 2c3fdf5..0cdda57 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -2056,6 +2056,11 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
 			return_0;
 	}
 
+	if (!lv_remove_cryptostores(lv)) {
+		log_error("Error removing cryptostores for logical volume \"%s\"", lv->name);
+		return 0;
+	}
+
 	log_verbose("Releasing logical volume \"%s\"", lv->name);
 	if (!lv_remove(lv)) {
 		log_error("Error releasing logical volume \"%s\"", lv->name);
diff --git a/lib/metadata/merge.c b/lib/metadata/merge.c
index f1d8b9a..403bfbe 100644
--- a/lib/metadata/merge.c
+++ b/lib/metadata/merge.c
@@ -129,6 +129,36 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
 			}
 		}
 
+		if (seg_is_encrypted(seg)) {
+			if (!seg->crypto_store) {
+				log_error("LV %s: segment %u is encrypted but have "
+					  "no assigned crypto store",
+					  lv->name, seg_count);
+				r = 0;
+			} else if (!find_crypto_store_in_vg(lv->vg,
+							    seg->crypto_store->name)) {
+				log_error("LV %s: segment %u is encrypted but have "
+					  "assigned nonexisting crypto store %s",
+					  lv->name, seg_count, seg->crypto_store->name);
+				r = 0;
+			}
+			if (seg->area_count > 1) {
+				log_error("LV %s: encrypted segment %u have %u areas, "
+					  "but only one area is supported.",
+					  lv->name, seg_count, seg->area_count);
+				r = 0;
+			}
+		}
+
+		if (seg_is_keystore(seg)) {
+			if (!seg->crypto_store->ref) {
+				log_error("LV %s: segment %u is keystore and "
+					  "is not referenced by any other LV.",
+					  lv->name, seg_count);
+				r = 0;
+			}
+		}
+
 		for (s = 0; s < seg->area_count; s++) {
 			if (seg_type(seg, s) == AREA_UNASSIGNED) {
 				log_error("LV %s: segment %u has unassigned "
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index 2aa5a1b..9835308 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -575,6 +575,12 @@ char *generate_lv_name(struct volume_group *vg, const char *format,
 struct crypto_store *alloc_cryptostore(struct dm_pool *mem, const char *name,
 				       struct crypto_store_type *cst);
 
+struct crypto_store *vg_add_cryptostore(struct volume_group *vg,
+					struct lv_segment *seg,
+					const char *handler_name);
+int lv_remove_cryptostores(struct logical_volume *lv);
+int lv_add_cryptostore(struct logical_volume *lv, struct crypto_store *cs);
+
 /*
 * Begin skeleton for external LVM library
 */
diff --git a/tools/toollib.c b/tools/toollib.c
index a0494a1..bada05e 100644
--- a/tools/toollib.c
+++ b/tools/toollib.c
@@ -1160,6 +1160,12 @@ int apply_lvname_restrictions(const char *name)
 		return 0;
 	}
 
+	if (!strncmp(name, "cryptostore", 11)) {
+		log_error("Names starting \"cryptostore\" are reserved. "
+			  "Please choose a different LV name.");
+		return 0;
+	}
+
 	if (strstr(name, "_mlog")) {
 		log_error("Names including \"_mlog\" are reserved. "
 			  "Please choose a different LV name.");
-- 
1.5.6.5



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 10/15] Cache key from crypt mapping table if segment is active.
  2009-01-21 11:19                 ` [PATCH 09/15] Add encrypted LV manipulation functions Milan Broz
@ 2009-01-21 11:19                   ` Milan Broz
  2009-01-21 11:19                     ` [PATCH 11/15] Add lvcreate crypto LV implementation Milan Broz
  0 siblings, 1 reply; 16+ messages in thread
From: Milan Broz @ 2009-01-21 11:19 UTC (permalink / raw)
  To: lvm-devel

For some online operations (like lvresize) we need preload
new table, thus we need master key.

But the key is already in mapping table, do not ask
user and try to retrieve master key from mapping table first.

Signed-off-by: Milan Broz <mbroz@redhat.com>
---
 lib/activate/activate.c    |   41 ++++++++++++++++++++++++++++++
 lib/activate/activate.h    |    5 +++
 lib/activate/dev_manager.c |   59 ++++++++++++++++++++++++++++++++++++++++++++
 lib/activate/dev_manager.h |    4 +++
 lib/metadata/crypt_manip.c |    6 ++++
 5 files changed, 115 insertions(+), 0 deletions(-)

diff --git a/lib/activate/activate.c b/lib/activate/activate.c
index 0f13cbd..0b17be8 100644
--- a/lib/activate/activate.c
+++ b/lib/activate/activate.c
@@ -1117,6 +1117,47 @@ int pv_uses_vg(struct physical_volume *pv,
 	return dev_manager_device_uses_vg(pv->dev, vg);
 }
 
+/*
+ * Retrieve key for lv segment from dm table and cache it
+ */
+int lv_seg_cache_key(struct lv_segment *seg)
+{
+	char *key;
+	struct dev_manager *dm;
+	struct logical_volume *lv = seg->lv;
+	struct crypto_store *cs = seg->crypto_store;
+	int r;
+
+	if (!(key = dm_malloc(cs_key_bytes(cs) + 1)))
+		return_0;
+
+	if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) {
+		dm_free(key);
+		return_0;
+	}
+
+	if (!(r = dev_manager_crypt_key(dm, seg, key, cs_key_bytes(cs) + 1)))
+		stack;
+
+	dev_manager_destroy(dm);
+
+	if (!r)
+		goto out;
+
+	if (!lvm_masterkeys_verify(cs, key)) {
+		log_error("Internal error: Key in mapping table "
+			  "is not in expected format.");
+		goto out;
+	}
+
+	return lvm_masterkeys_insert(&cs->id, key);
+out:
+	memset(key, 0, cs_key_bytes(cs));
+	dm_free(key);
+	return 0;
+}
+
+
 void activation_release(void)
 {
 	dev_manager_release();
diff --git a/lib/activate/activate.h b/lib/activate/activate.h
index c5bd4b6..cc096a2 100644
--- a/lib/activate/activate.h
+++ b/lib/activate/activate.h
@@ -107,4 +107,9 @@ int pv_uses_vg(struct physical_volume *pv,
  */
 int device_is_usable(dev_t dev);
 
+/*
+ * Retrieve key for lv segment from dm table and cache it
+ */
+int lv_seg_cache_key(struct lv_segment *seg);
+
 #endif
diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c
index ef827ad..9be77f3 100644
--- a/lib/activate/dev_manager.c
+++ b/lib/activate/dev_manager.c
@@ -1272,3 +1272,62 @@ out:
 	dm_tree_free(dtree);
 	return r;
 }
+
+int dev_manager_crypt_key(struct dev_manager *dm, struct lv_segment *seg,
+			  char *buffer, int buffer_len)
+{
+	struct logical_volume *lv = seg->lv;
+	const char *dlid;
+	int r = 0;
+	struct dm_task *dmt;
+	struct dm_info info;
+	void *next = NULL;
+	uint64_t req_start, start, length;
+	char *type = NULL;
+	char *params = NULL;
+	char *key_start, *key_end;
+
+	// FIXME: secure pool operation & deallocate
+
+	/*
+	 * Build a name for the top layer.
+	 */
+	if (!(dlid = build_dlid(dm, lv->lvid.s, NULL)))
+		return_0;
+
+	if (!(dmt = _setup_task(NULL, dlid, 0, DM_DEVICE_TABLE, 0, 0)))
+		return_0;
+
+	if (!dm_task_no_open_count(dmt))
+		log_error("Failed to disable open_count");
+
+	if (!dm_task_run(dmt))
+		goto_out;
+
+	if (!dm_task_get_info(dmt, &info) || !info.exists)
+		goto_out;
+
+	req_start = seg->le * seg->lv->vg->extent_size;
+
+	do {
+		next = dm_get_next_target(dmt, next, &start, &length,
+					  &type, &params);
+		if (req_start == start) {
+			if (!(key_start = strchr(params, ' ')))
+				break;
+			key_start++;
+			if (!(key_end = strchr(key_start, ' ')))
+				break;
+			if (key_end - key_start > buffer_len)
+				break;
+			strncpy(buffer, key_start, buffer_len);
+			buffer[buffer_len - 1] = '\0';
+			r = 1;
+			break;
+		}
+	} while (next);
+
+out:
+	dm_task_destroy(dmt);
+	return r;
+}
diff --git a/lib/activate/dev_manager.h b/lib/activate/dev_manager.h
index 7a76453..ac7cec9 100644
--- a/lib/activate/dev_manager.h
+++ b/lib/activate/dev_manager.h
@@ -17,6 +17,7 @@
 #define _LVM_DEV_MANAGER_H
 
 struct logical_volume;
+struct lv_segment;
 struct volume_group;
 struct cmd_context;
 struct dev_manager;
@@ -57,6 +58,9 @@ int dev_manager_deactivate(struct dev_manager *dm, struct logical_volume *lv);
 int dev_manager_lv_mknodes(const struct logical_volume *lv);
 int dev_manager_lv_rmnodes(const struct logical_volume *lv);
 
+int dev_manager_crypt_key(struct dev_manager *dm, struct lv_segment *seg,
+			  char *buffer, int buffer_len);
+
 /*
  * Put the desired changes into effect.
  */
diff --git a/lib/metadata/crypt_manip.c b/lib/metadata/crypt_manip.c
index ff5c3e2..4b45a07 100644
--- a/lib/metadata/crypt_manip.c
+++ b/lib/metadata/crypt_manip.c
@@ -242,6 +242,12 @@ static int _seg_retrieve_masterkey(struct lv_segment *seg)
 	if (lvm_masterkeys_query(&seg->crypto_store->id))
 		return 1;
 
+	/*
+	 * Try to retrieve key from dm table
+	 */
+	if (lv_is_active(seg->lv) && lv_seg_cache_key(seg))
+		return 1;
+
 	return lvm_masterkeys_retrieve(seg->lv->name, seg->crypto_store);
 }
 
-- 
1.5.6.5



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 11/15] Add lvcreate crypto LV implementation.
  2009-01-21 11:19                   ` [PATCH 10/15] Cache key from crypt mapping table if segment is active Milan Broz
@ 2009-01-21 11:19                     ` Milan Broz
  2009-01-21 11:19                       ` [PATCH 12/15] Add lvconcert crypt implementation Milan Broz
  0 siblings, 1 reply; 16+ messages in thread
From: Milan Broz @ 2009-01-21 11:19 UTC (permalink / raw)
  To: lvm-devel

lcvreate now support two modes for creating encrypted LVs:

1) specify encryption directly
	--crypt KeyStoreType --cipher Cipher --keysize KeySize

e.g.

lvcreate -n LV -l 4 --crypt plain --cipher aes-xts-plain --keysize 256 VG

2) use another LV as template (IOW reuse its cryptostore)
	--crypt TemplateLogicalVolume[Path]

e.g.

lvcreate -n LV2 -l 4 --crypt LV VG

Signed-off-by: Milan Broz <mbroz@redhat.com>
---
 tools/args.h     |    4 ++
 tools/commands.h |    9 ++-
 tools/lvcreate.c |  160 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 168 insertions(+), 5 deletions(-)

diff --git a/tools/args.h b/tools/args.h
index 8f026fc..a1347ea 100644
--- a/tools/args.h
+++ b/tools/args.h
@@ -57,6 +57,10 @@ arg(nameprefixes_ARG, '\0', "nameprefixes", NULL, 0)
 arg(unquoted_ARG, '\0', "unquoted", NULL, 0)
 arg(rows_ARG, '\0', "rows", NULL, 0)
 
+arg(crypt_ARG, '\0', "crypt", string_arg, 0)
+arg(cipher_ARG, '\0', "cipher", string_arg, 0)
+arg(keysize_ARG, '\0', "keysize", int_arg, 0)
+
 /* Allow some variations */
 arg(resizable_ARG, '\0', "resizable", yes_no_arg, 0)
 arg(allocation_ARG, '\0', "allocation", yes_no_arg, 0)
diff --git a/tools/commands.h b/tools/commands.h
index 58c6156..aa5814c 100644
--- a/tools/commands.h
+++ b/tools/commands.h
@@ -132,6 +132,8 @@ xx(lvcreate,
    "\t -L|--size LogicalVolumeSize[kKmMgGtTpPeE]}\n"
    "\t[-M|--persistent {y|n}] [--major major] [--minor minor]\n"
    "\t[-m|--mirrors Mirrors [--nosync] [{--mirrorlog {disk|core}|--corelog}]]\n"
+   "\t[--crypt KeyStoreType --cipher Cipher --keysize KeySize]\n"
+   "\t[--crypt TemplateLogicalVolume[Path]]\n"
    "\t[-n|--name LogicalVolumeName]\n"
    "\t[-p|--permission {r|rw}]\n"
    "\t[-r|--readahead ReadAheadSectors|auto|none]\n"
@@ -163,9 +165,10 @@ xx(lvcreate,
    "\t[--version]\n"
    "\tOriginalLogicalVolume[Path] [PhysicalVolumePath...]\n\n",
 
-   addtag_ARG, alloc_ARG, autobackup_ARG, chunksize_ARG, contiguous_ARG,
-   corelog_ARG, extents_ARG, major_ARG, minor_ARG, mirrorlog_ARG, mirrors_ARG,
-   name_ARG, nosync_ARG, permission_ARG, persistent_ARG, readahead_ARG,
+   addtag_ARG, alloc_ARG, autobackup_ARG, chunksize_ARG, cipher_ARG,
+   contiguous_ARG, corelog_ARG, crypt_ARG, extents_ARG, keysize_ARG,
+   major_ARG, minor_ARG, mirrorlog_ARG, mirrors_ARG, name_ARG,
+   nosync_ARG, permission_ARG, persistent_ARG, readahead_ARG,
    regionsize_ARG, size_ARG, snapshot_ARG, stripes_ARG, stripesize_ARG,
    test_ARG, type_ARG, zero_ARG)
 
diff --git a/tools/lvcreate.c b/tools/lvcreate.c
index f17f876..e0f59be 100644
--- a/tools/lvcreate.c
+++ b/tools/lvcreate.c
@@ -26,6 +26,7 @@ struct lvcreate_params {
 	int minor;
 	int corelog;
 	int nosync;
+	int crypt;
 
 	char *origin;
 	const char *vg_name;
@@ -38,6 +39,12 @@ struct lvcreate_params {
 
 	uint32_t mirrors;
 
+	const char *crypt_handler;
+	const char *cipher;
+	uint32_t keysize;
+	struct crypto_store *cryptostore;
+	const char *crypt_template;
+
 	const struct segment_type *segtype;
 
 	/* size */
@@ -327,6 +334,46 @@ static int _read_mirror_params(struct lvcreate_params *lp,
 	return 1;
 }
 
+static int _read_crypt_params(struct lvcreate_params *lp,
+			      struct cmd_context *cmd)
+{
+	char *ptr;
+
+	if (!arg_count(cmd, crypt_ARG))
+		return 1;
+
+	if (arg_count(cmd, cipher_ARG)) {
+		/*
+		 * Explicit cipher specification
+		*/
+		lp->crypt_handler = arg_value(cmd, crypt_ARG);
+			if (!lvm_get_keystore_handler(lp->crypt_handler))
+			return 0;
+
+		// FIXME: validate this somehow
+		lp->cipher = arg_value(cmd, cipher_ARG);
+		lp->keysize = arg_uint_value(cmd, keysize_ARG, 1);
+	} else {
+		/*
+		* Template LV specified - use its cryptstore
+		*/
+		lp->crypt_template = arg_value(cmd, crypt_ARG);
+		lp->crypt = 2;
+
+		if ((ptr = strrchr(lp->crypt_template, '/')))
+			lp->crypt_template = ptr + 1;
+
+		if (!validate_name(lp->crypt_template)) {
+			log_error("Logical volume crypto template "
+				  "\"%s\" is invalid",
+				  lp->lv_name);
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
 static int _lvcreate_params(struct lvcreate_params *lp, struct cmd_context *cmd,
 			    int argc, char **argv)
 {
@@ -346,6 +393,9 @@ static int _lvcreate_params(struct lvcreate_params *lp, struct cmd_context *cmd,
 	if (arg_count(cmd, stripes_ARG) && lp->stripes == 1)
 		log_print("Redundant stripes argument: default is 1");
 
+	if (arg_count(cmd, crypt_ARG))
+		lp->crypt = 1;
+
 	if (arg_count(cmd, snapshot_ARG) || seg_is_snapshot(lp))
 		lp->snapshot = 1;
 
@@ -365,6 +415,12 @@ static int _lvcreate_params(struct lvcreate_params *lp, struct cmd_context *cmd,
 		}
 	}
 
+	if (!lp->crypt && (arg_count(cmd, cipher_ARG) ||
+			   arg_count(cmd, keysize_ARG))) {
+		log_error("--cipher and --keysize requires --crypt too");
+		return 0;
+	}
+
 	if (lp->snapshot) {
 		if (arg_count(cmd, zero_ARG)) {
 			log_error("-Z is incompatible with snapshots");
@@ -429,7 +485,8 @@ static int _lvcreate_params(struct lvcreate_params *lp, struct cmd_context *cmd,
 	if (!_lvcreate_name_params(lp, cmd, &argc, &argv) ||
 	    !_read_size_params(lp, cmd) ||
 	    !_read_stripe_params(lp, cmd) ||
-	    !_read_mirror_params(lp, cmd))
+	    !_read_mirror_params(lp, cmd) ||
+	    !_read_crypt_params(lp, cmd))
 		return_0;
 
 	/*
@@ -511,6 +568,66 @@ static int _lvcreate_params(struct lvcreate_params *lp, struct cmd_context *cmd,
 	return 1;
 }
 
+static int _lvcreate_cryptostore(struct cmd_context *cmd, struct volume_group *vg,
+				 struct lvcreate_params *lp)
+{
+	struct lv_segment *seg;
+	struct lv_list *lvl;
+
+	if (!(lp->segtype = get_segtype_from_string(cmd, "crypt"))) {
+		log_error("Failed to initialize crypt segment.");
+		return 0;
+	}
+
+	if (lp->crypt_template) {
+		/*
+		 * We have template LV, reuse its cryptostore
+		 */
+		lvl = find_lv_in_vg(vg, lp->crypt_template);
+		if (!lvl) {
+			log_error("Template LV %s not found.", lp->crypt_template);
+			return 0;
+		}
+
+		seg = first_seg(lvl->lv);
+
+		if (!seg || !seg->crypto_store) {
+			log_error("Template LV %s have no assigned cryptostore.",
+				  lp->crypt_template);
+			return 0;
+		}
+
+		if (!seg->crypto_store->type) {
+			log_error("Cannot use LV %s as template, "
+				  "key handler is not loaded.", lp->crypt_template);
+			return 0;
+		}
+
+		if (!lv_retrieve_password(lvl->lv)) {
+			log_error("Cannot use LV %s as template, "
+				  "master key is invalid.", lp->crypt_template);
+			return 0;
+		}
+
+		lp->cryptostore = seg->crypto_store;
+		lp->crypt_handler = seg->crypto_store->type->name;
+	} else {
+		/*
+		 * New cryptostore.is needed
+		 * FIXME: only cryptostores without physical segments supported now
+		 */
+		if (!(lp->cryptostore = vg_add_cryptostore(vg, NULL, lp->crypt_handler))) {
+			log_error("Failed to create cryptstore LV.");
+			return 0;
+		}
+
+		lp->cryptostore->cipher = lp->cipher;
+		lp->cryptostore->key_size = lp->keysize;
+	}
+
+	return 1;
+}
+
 static int _lvcreate(struct cmd_context *cmd, struct volume_group *vg,
 		     struct lvcreate_params *lp)
 {
@@ -634,6 +751,31 @@ static int _lvcreate(struct cmd_context *cmd, struct volume_group *vg,
 
 	status |= lp->permission | VISIBLE_LV;
 
+	if (lp->crypt) {
+		if (!(vg->fid->fmt->features & FMT_SEGMENTS)) {
+			log_error("Metadata does not support encryption.");
+			return 0;
+		}
+
+		if (vg_is_clustered(vg)) {
+			log_error("Clustered encrypted volumes are not yet supported.");
+			return 0;
+		}
+
+		if (lp->snapshot || lp->mirrors > 1) {
+			log_error("Combination of encryption and snapshots "
+				  "is not yet supported.");
+			return 0;
+		}
+
+		if (lp->stripes > 1) {
+			log_error("Striping is incompatible with encryption volume..");
+			return 0;
+		}
+
+		//FIXME: validate used cipher
+	}
+
 	if (lp->snapshot) {
 		if (!activation()) {
 			log_error("Can't create snapshot without using "
@@ -711,6 +853,9 @@ static int _lvcreate(struct cmd_context *cmd, struct volume_group *vg,
 	if (!archive(vg))
 		return 0;
 
+	if (lp->crypt && !_lvcreate_cryptostore(cmd, vg, lp))
+		return 0;
+
 	if (lp->lv_name)
 		lv_name = lp->lv_name;
 	else {
@@ -771,6 +916,16 @@ static int _lvcreate(struct cmd_context *cmd, struct volume_group *vg,
 		       1, lp->extents, NULL, 0u, 0u, pvh, lp->alloc))
 		return_0;
 
+	if (lp->crypt) {
+		if (!lv_add_cryptostore(lv, lp->cryptostore)) {
+			log_error("Cannot assign crypto store.");
+			stack;
+			goto revert_new_lv;
+		}
+		if (!lv_retrieve_password(lv))
+			goto revert_new_lv;
+	}
+
 	if (lp->mirrors > 1) {
 		if (!lv_add_mirrors(cmd, lv, lp->mirrors - 1, lp->stripes,
 				    adjusted_mirror_region_size(
@@ -878,7 +1033,8 @@ deactivate_and_revert_new_lv:
 
 revert_new_lv:
 	/* FIXME Better to revert to backup of metadata? */
-	if (!lv_remove(lv) || !vg_write(vg) || (backup(vg), !vg_commit(vg)))
+	if (!lv_remove_cryptostores(lv) || !lv_remove(lv) ||
+	    !vg_write(vg) || (backup(vg), !vg_commit(vg)))
 		log_error("Manual intervention may be required to remove "
 			  "abandoned LV(s) before retrying.");
 	return 0;
-- 
1.5.6.5



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 12/15] Add lvconcert crypt implementation.
  2009-01-21 11:19                     ` [PATCH 11/15] Add lvcreate crypto LV implementation Milan Broz
@ 2009-01-21 11:19                       ` Milan Broz
  2009-01-21 11:19                         ` [PATCH 13/15] Add --keyfile option Milan Broz
  0 siblings, 1 reply; 16+ messages in thread
From: Milan Broz @ 2009-01-21 11:19 UTC (permalink / raw)
  To: lvm-devel

lvconvert --crypt KeyStoreType LogicalVolume[Path]

If the defined key handler contains support
for conversion (it implements scan function),
it converts linear volume into encrypted using
the first extent as keystore area.

Note, that there is currently not yet implemented
key management interface, so you lost access
to keystore for key management operation
after conversion.

You can activate volume using only keys defined
in the moment when conversion happened.

[basically this allows using LUKS keystore only now]

Signed-off-by: Milan Broz <mbroz@redhat.com>
---
 tools/commands.h  |    8 +++-
 tools/lvconvert.c |  125 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 131 insertions(+), 2 deletions(-)

diff --git a/tools/commands.h b/tools/commands.h
index aa5814c..deb300b 100644
--- a/tools/commands.h
+++ b/tools/commands.h
@@ -112,9 +112,13 @@ xx(lvconvert,
    "\t[-v|--verbose]\n"
    "\t[-Z|--zero {y|n}]\n"
    "\t[--version]" "\n"
-   "\tOriginalLogicalVolume[Path] SnapshotLogicalVolume[Path]\n",
+   "\tOriginalLogicalVolume[Path] SnapshotLogicalVolume[Path]\n\n"
 
-   alloc_ARG, background_ARG, chunksize_ARG, corelog_ARG, interval_ARG,
+   "lvconvert "
+   "[--crypt KeyStoreType]\n"
+   "\tLogicalVolume[Path]]\n",
+
+   alloc_ARG, background_ARG, chunksize_ARG, corelog_ARG, crypt_ARG, interval_ARG,
    mirrorlog_ARG, mirrors_ARG, regionsize_ARG, snapshot_ARG, test_ARG, zero_ARG)
 
 xx(lvcreate,
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index d1260f5..6723f5a 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -15,10 +15,12 @@
 #include "tools.h"
 #include "polldaemon.h"
 #include "lv_alloc.h"
+#include "metadata.h"
 
 struct lvconvert_params {
 	int snapshot;
 	int zero;
+	int crypt;
 
 	const char *origin;
 	const char *lv_name;
@@ -33,6 +35,9 @@ struct lvconvert_params {
 	uint32_t mirrors;
 	sign_t mirrors_sign;
 
+	const char *crypt_handler;
+	struct crypto_store_type *cs_type;
+
 	struct segment_type *segtype;
 
 	alloc_policy_t alloc;
@@ -123,6 +128,17 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
 	if (arg_count(cmd, snapshot_ARG))
 		lp->snapshot = 1;
 
+	if (arg_count(cmd, crypt_ARG)) {
+		if (arg_count(cmd, snapshot_ARG) ||
+		    arg_count(cmd, mirrorlog_ARG) ||
+		    arg_count(cmd, mirrors_ARG)) {
+			log_error("--crypt argument cannot be mixed "
+				  "with mirrors of snapshots args");
+			return 0;
+		}
+		lp->crypt = 1;
+	}
+
 	if (arg_count(cmd, mirrors_ARG)) {
 		lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0);
 		lp->mirrors_sign = arg_sign_value(cmd, mirrors_ARG, 0);
@@ -159,6 +175,22 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
 						 SEG_CANNOT_BE_ZEROED) ?
 						"n" : "y"), "n");
 
+	} else if (lp->crypt) { /* Convert to encrypted LV */
+
+		lp->crypt_handler = arg_str_value(cmd, crypt_ARG, NULL);
+		if (!(lp->cs_type = lvm_get_keystore_handler(lp->crypt_handler))) {
+			log_error("Unsuported crypt handler %s", lp->crypt_handler);
+			return 0;
+		}
+
+		if (!lp->cs_type->ops->scan) {
+			log_error("Key handler %s does not support conversion.",
+				  lp->cs_type->name);
+			return 0;
+		}
+
+		if (!(lp->segtype = get_segtype_from_string(cmd, "crypt")))
+			return_0;
 	} else {	/* Mirrors */
 		if (arg_count(cmd, chunksize_ARG)) {
 			log_error("--chunksize is only available with "
@@ -385,6 +417,15 @@ static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * l
 	struct logical_volume *original_lv;
 
 	seg = first_seg(lv);
+
+	if (seg_is_encrypted(seg)) {
+		log_error("Logical volume %s is encrypted, this operation is "
+			  "not supported because will store unencrypted data "
+			  "directly in new mirror log.",
+			  lv->name);
+		return 0;
+	}
+
 	existing_mirrors = lv_mirror_count(lv);
 
 	/* If called with no argument, try collapsing the resync layers */
@@ -685,6 +726,85 @@ static int lvconvert_snapshot(struct cmd_context *cmd,
 	return 1;
 }
 
+static int lvconvert_crypt(struct cmd_context *cmd,
+			   struct logical_volume *lv,
+			   struct lvconvert_params *lp)
+{
+	struct lv_segment *seg, *cs_seg;
+	struct crypto_store *cs;
+
+	/*
+	 * Conversion is supporetd only if keystore is in first extent. 
+	 */
+
+	dm_list_iterate_items(seg, &lv->segments) {
+		if (seg_is_encrypted(seg)) {
+			log_error("Logical volume %s already contains encrypted "
+				  "segments.", lv->name);
+			return 0;
+		}
+		if (!seg_is_striped(seg) || seg->area_count > 1) {
+			log_error("Only plain linear volumes can be converted "
+				  "(no mirrors, stripes).");
+			return 0;
+		}
+	}
+
+	if (!deactivate_lv(cmd, lv)) {
+		log_error("Couldn't deactivate LV %s.", lv->name);
+		return 0;
+	}
+
+	/* Split keystore area */
+	if (!lv_split_segment(lv, 1)) {
+		log_error("Cannot split keystore from LV.");
+		return 0;
+	}
+
+	/*
+	 * Detach segment from LV
+	 */
+	cs_seg = first_seg(lv);
+	dm_list_del(&cs_seg->list);
+	dm_list_iterate_items(seg, &lv->segments) {
+		seg->segtype = lp->segtype;
+		seg->le--;
+	}
+	lv->le_count--;
+
+	if (!(cs = vg_add_cryptostore(lv->vg, cs_seg, lp->crypt_handler))) {
+		log_error("Failed to create cryptstore LV.");
+		return 0;
+	}
+
+	/*
+	 * Scan if the segment really contains compatible keystore header
+	 */
+	if (!cs->type->ops->scan(first_crypto_area(cs))) {
+		log_error("There is no compatible keystore area on LV %s.",
+			  lv->name);
+		return 0;
+	}
+
+	/*
+	 * Attach segment to cryptostore LV
+	 */
+	if (!lv_add_cryptostore(lv, cs)) {
+		log_error("Cannot change cryptostore to %s", lv->name);
+		return 0;
+	}
+
+	if (!vg_write(lv->vg))
+		return_0;
+
+	if (!vg_commit(lv->vg))
+		return_0;
+
+	log_print("Logical volume %s was imported as encrypted.", lv->name);
+
+	return 1;
+}
+
 static int lvconvert_single(struct cmd_context *cmd, struct logical_volume *lv,
 			    void *handle)
 {
@@ -721,6 +841,11 @@ static int lvconvert_single(struct cmd_context *cmd, struct logical_volume *lv,
 			return ECMD_FAILED;
 		if (!lvconvert_snapshot(cmd, lv, lp))
 			return ECMD_FAILED;
+	} else if (lp->crypt) {
+		if (!archive(lv->vg))
+			return ECMD_FAILED;
+		if (!lvconvert_crypt(cmd, lv, lp))
+			return ECMD_FAILED;
 	} else if (arg_count(cmd, mirrors_ARG) || (lv->status & MIRRORED)) {
 		if (!archive(lv->vg))
 			return ECMD_FAILED;
-- 
1.5.6.5



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 13/15] Add --keyfile option.
  2009-01-21 11:19                       ` [PATCH 12/15] Add lvconcert crypt implementation Milan Broz
@ 2009-01-21 11:19                         ` Milan Broz
  2009-01-21 11:19                           ` [PATCH 14/15] Add *testing* LUKS1 keystore implementation Milan Broz
  0 siblings, 1 reply; 16+ messages in thread
From: Milan Broz @ 2009-01-21 11:19 UTC (permalink / raw)
  To: lvm-devel

Allow input of key from file (or standard input)
by specifying --keyfile on commandline.

If the file is "-" stdin is used, e.g.
echo $key | lvcreate ...

(It is not safe, but useful in scripts. Similar approach
is used in cryptsetup.)

Currently supported only for lvcreate, vgchange, lvchange.

Signed-off-by: Milan Broz <mbroz@redhat.com>
---
 tools/args.h     |    1 +
 tools/commands.h |   17 +++++++++--------
 tools/lvchange.c |    7 +++++++
 tools/lvcreate.c |    7 +++++++
 tools/vgchange.c |    7 +++++++
 5 files changed, 31 insertions(+), 8 deletions(-)

diff --git a/tools/args.h b/tools/args.h
index a1347ea..cacbb2b 100644
--- a/tools/args.h
+++ b/tools/args.h
@@ -60,6 +60,7 @@ arg(rows_ARG, '\0', "rows", NULL, 0)
 arg(crypt_ARG, '\0', "crypt", string_arg, 0)
 arg(cipher_ARG, '\0', "cipher", string_arg, 0)
 arg(keysize_ARG, '\0', "keysize", int_arg, 0)
+arg(keyfile_ARG, '\0', "keyfile", string_arg, 0)
 
 /* Allow some variations */
 arg(resizable_ARG, '\0', "resizable", yes_no_arg, 0)
diff --git a/tools/commands.h b/tools/commands.h
index deb300b..07c472e 100644
--- a/tools/commands.h
+++ b/tools/commands.h
@@ -85,9 +85,10 @@ xx(lvchange,
    "\tLogicalVolume[Path] [LogicalVolume[Path]...]\n",
 
    alloc_ARG, autobackup_ARG, available_ARG, contiguous_ARG, force_ARG,
-   ignorelockingfailure_ARG, ignoremonitoring_ARG, major_ARG, minor_ARG,
-   monitor_ARG, partial_ARG, permission_ARG, persistent_ARG, readahead_ARG,
-   resync_ARG, refresh_ARG, addtag_ARG, deltag_ARG, test_ARG, yes_ARG)
+   ignorelockingfailure_ARG, ignoremonitoring_ARG, keyfile_ARG, major_ARG,
+   minor_ARG, monitor_ARG, partial_ARG, permission_ARG, persistent_ARG,
+   readahead_ARG, resync_ARG, refresh_ARG, addtag_ARG, deltag_ARG, test_ARG,
+   yes_ARG)
 
 xx(lvconvert,
    "Change logical volume layout",
@@ -136,7 +137,7 @@ xx(lvcreate,
    "\t -L|--size LogicalVolumeSize[kKmMgGtTpPeE]}\n"
    "\t[-M|--persistent {y|n}] [--major major] [--minor minor]\n"
    "\t[-m|--mirrors Mirrors [--nosync] [{--mirrorlog {disk|core}|--corelog}]]\n"
-   "\t[--crypt KeyStoreType --cipher Cipher --keysize KeySize]\n"
+   "\t[--crypt KeyStoreType --cipher Cipher --keysize KeySize [--keyfile filename]]\n"
    "\t[--crypt TemplateLogicalVolume[Path]]\n"
    "\t[-n|--name LogicalVolumeName]\n"
    "\t[-p|--permission {r|rw}]\n"
@@ -171,7 +172,7 @@ xx(lvcreate,
 
    addtag_ARG, alloc_ARG, autobackup_ARG, chunksize_ARG, cipher_ARG,
    contiguous_ARG, corelog_ARG, crypt_ARG, extents_ARG, keysize_ARG,
-   major_ARG, minor_ARG, mirrorlog_ARG, mirrors_ARG, name_ARG,
+   keyfile_ARG, major_ARG, minor_ARG, mirrorlog_ARG, mirrors_ARG, name_ARG,
    nosync_ARG, permission_ARG, persistent_ARG, readahead_ARG,
    regionsize_ARG, size_ARG, snapshot_ARG, stripes_ARG, stripesize_ARG,
    test_ARG, type_ARG, zero_ARG)
@@ -689,9 +690,9 @@ xx(vgchange,
 
    addtag_ARG, alloc_ARG, allocation_ARG, autobackup_ARG, available_ARG,
    clustered_ARG, deltag_ARG, ignorelockingfailure_ARG, ignoremonitoring_ARG,
-   logicalvolume_ARG, maxphysicalvolumes_ARG, monitor_ARG, partial_ARG,
-   physicalextentsize_ARG, refresh_ARG, resizeable_ARG, resizable_ARG,
-   test_ARG, uuid_ARG)
+   keyfile_ARG, logicalvolume_ARG, maxphysicalvolumes_ARG, monitor_ARG,
+   partial_ARG, physicalextentsize_ARG, refresh_ARG, resizeable_ARG,
+   resizable_ARG, test_ARG, uuid_ARG)
 
 xx(vgck,
    "Check the consistency of volume group(s)",
diff --git a/tools/lvchange.c b/tools/lvchange.c
index cd0ff5a..0a4778f 100644
--- a/tools/lvchange.c
+++ b/tools/lvchange.c
@@ -728,6 +728,13 @@ int lvchange(struct cmd_context *cmd, int argc, char **argv)
 		return EINVALID_CMD_LINE;
 	}
 
+	if (arg_count(cmd, keyfile_ARG) &&
+	    !lvm_set_password_dev(arg_value(cmd, keyfile_ARG))) {
+		log_error("--keyfile argument %s is invalid",
+			  arg_value(cmd, keyfile_ARG));
+		return EINVALID_CMD_LINE;
+	}
+
 	return process_each_lv(cmd, argc, argv, LCK_VG_WRITE, NULL,
 			       &lvchange_single);
 }
diff --git a/tools/lvcreate.c b/tools/lvcreate.c
index e0f59be..6eea76d 100644
--- a/tools/lvcreate.c
+++ b/tools/lvcreate.c
@@ -342,6 +342,13 @@ static int _read_crypt_params(struct lvcreate_params *lp,
 	if (!arg_count(cmd, crypt_ARG))
 		return 1;
 
+	if (arg_count(cmd, keyfile_ARG) &&
+	    !lvm_set_password_dev(arg_value(cmd, keyfile_ARG))) {
+		log_error("--keyfile argument %s is invalid",
+			  arg_value(cmd, keyfile_ARG));
+		return 0;
+	}
+
 	if (arg_count(cmd, cipher_ARG)) {
 		/*
 		 * Explicit cipher specification
diff --git a/tools/vgchange.c b/tools/vgchange.c
index 8831a23..ed00744 100644
--- a/tools/vgchange.c
+++ b/tools/vgchange.c
@@ -631,6 +631,13 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv)
 		return EINVALID_CMD_LINE;
 	}
 
+	if (arg_count(cmd, keyfile_ARG) &&
+	    !lvm_set_password_dev(arg_value(cmd, keyfile_ARG))) {
+		log_error("--keyfile argument %s is invalid",
+			  arg_value(cmd, keyfile_ARG));
+		return EINVALID_CMD_LINE;
+	}
+
 	return process_each_vg(cmd, argc, argv,
 			       (arg_count(cmd, available_ARG)) ?
 			       LCK_VG_READ : LCK_VG_WRITE, 0, NULL,
-- 
1.5.6.5



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 14/15] Add *testing* LUKS1 keystore implementation.
  2009-01-21 11:19                         ` [PATCH 13/15] Add --keyfile option Milan Broz
@ 2009-01-21 11:19                           ` Milan Broz
  2009-01-21 11:19                             ` [PATCH 15/15] Add simple test for crypto volumes Milan Broz
  0 siblings, 1 reply; 16+ messages in thread
From: Milan Broz @ 2009-01-21 11:19 UTC (permalink / raw)
  To: lvm-devel

BIG FAT WARNING: THIS IS JUST BUGGY TEST CODE
PROVIDED ONLY FOR TESTING OF PREVIOUS CODE :-)

This patch tries to implement real keystore handling,
using LUKS1 format.

If you have linear logical volume, formatted using

     cryptsetup luksFormat /dev/VG/LV --align-offset=<extent sectors>

you can import it to lvm as "luks1" keystore using

    lvconvert --crypt luks1 VG/LV

Now is the volume converted to crypto key store
(first extent of former volume) and internal encrypted
volume.

LUKS1 key handler then allows volume activation, using
on disk LUKS metadata.

(See following patch with test script for examples.)

    Notes:
    1) The whole LUKS parsing code was rewrited by me using
    libgcrypt instead of hardcoded SHA1 & PBKDF2 code.

    2) Simple configure script *requires* libgcrypt
    for linking. (In the future, only keystore library
    should require libgcrypt or nss crypto library).

    3) Why I didn't use libluks or libcryptsetup?
    - the luks library code need rewrite, API is not stable,
    some distros removed it from its build
    - there is huge amout of duplicated code which
    LVM already handles better
    - SHA1 is hardcoded in cryptsetup-luks, and it
    can cause serious problem for FIPS certification

    Open question is, if the crypsetup code should be
    fixed and used in lvm through some wrapper
    (which activates keystore device for it) or lvm
    should provide an alternative for key
    management operation.

For now, there is this simple testing alternative.

Signed-off-by: Milan Broz <mbroz@redhat.com>
---
 configure                |   94 +++++++++-
 configure.in             |   30 +++
 lib/Makefile.in          |    6 +
 lib/crypt/key_handlers.c |    3 +
 lib/crypt/key_luks.c     |  495 ++++++++++++++++++++++++++++++++++++++++++++++
 lib/crypt/lvm-crypto.h   |    3 +
 lib/crypt/pbkdf2.c       |  199 +++++++++++++++++++
 lib/crypt/pbkdf2.h       |   36 ++++
 lib/misc/configure.h.in  |    3 +
 9 files changed, 866 insertions(+), 3 deletions(-)
 create mode 100644 lib/crypt/key_luks.c
 create mode 100644 lib/crypt/pbkdf2.c
 create mode 100644 lib/crypt/pbkdf2.h

diff --git a/configure b/configure
index e4a8f82..2632dbd 100755
--- a/configure
+++ b/configure
@@ -686,6 +686,7 @@ CSCOPE_CMD
 ALLOCA
 LIBOBJS
 POW_LIB
+LIBGCRYPT_CONFIG
 LCOV
 GENHTML
 LVM2CMD_LIB
@@ -700,6 +701,7 @@ CLVMD
 CMDLIB
 COPTIMISE_FLAG
 CRYPTO
+CRYPTO_LUKS1
 DEBUG
 DEVMAPPER
 DMEVENTD
@@ -1328,6 +1330,7 @@ Optional Features:
                           statically.  Default is dynamic linking
   --enable-lvm1_fallback  Use this to fall back and use LVM1 binaries if
                           device-mapper is missing from the kernel
+  --enable-luks1          Enable LUKS1 crypto support
   --disable-readline      Disable readline support
   --disable-realtime      Disable realtime clock support
   --enable-debug          Enable debugging
@@ -8695,6 +8698,88 @@ _ACEOF
 
 fi
 
+{ echo "$as_me:$LINENO: checking whether to enable LUKS1 support" >&5
+echo $ECHO_N "checking whether to enable LUKS1 support... $ECHO_C" >&6; }
+# Check whether --enable-luks1 was given.
+if test "${enable_luks1+set}" = set; then
+  enableval=$enable_luks1; CRYPTO_LUKS1=$enableval
+else
+  CRYPTO_LUKS1=no
+fi
+
+{ echo "$as_me:$LINENO: result: $CRYPTO_LUKS1" >&5
+echo "${ECHO_T}$CRYPTO_LUKS1" >&6; }
+
+if test x$CRYPTO_LUKS1 = xyes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define CRYPT_LUKS1 1
+_ACEOF
+
+
+	if test x$CRYPTO = xnone ; then
+		{ { echo "$as_me:$LINENO: error: Cannot use LUKS without crypto support" >&5
+echo "$as_me: error: Cannot use LUKS without crypto support" >&2;}
+   { (exit 1); exit 1; }; }
+	fi
+
+	# Extract the first word of "libgcrypt-config", so it can be a program name with args.
+set dummy libgcrypt-config; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_LIBGCRYPT_CONFIG+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $LIBGCRYPT_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_LIBGCRYPT_CONFIG="$LIBGCRYPT_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_LIBGCRYPT_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  test -z "$ac_cv_path_LIBGCRYPT_CONFIG" && ac_cv_path_LIBGCRYPT_CONFIG="no"
+  ;;
+esac
+fi
+LIBGCRYPT_CONFIG=$ac_cv_path_LIBGCRYPT_CONFIG
+if test -n "$LIBGCRYPT_CONFIG"; then
+  { echo "$as_me:$LINENO: result: $LIBGCRYPT_CONFIG" >&5
+echo "${ECHO_T}$LIBGCRYPT_CONFIG" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+
+	if test x"$LIBGCRYPT_CONFIG" = x"no" ; then
+		{ { echo "$as_me:$LINENO: error: You selected option which require libgcrypt" >&5
+echo "$as_me: error: You selected option which require libgcrypt" >&2;}
+   { (exit 1); exit 1; }; }
+	fi
+
+	# libgcrypt-config fails here, this must go first
+	if test "x$STATIC_LINK" = xyes; then
+		LIBS="-lgpg-error $LIBS"
+	fi
+
+	LIBGCRYPT_LIBS=`$LIBGCRYPT_CONFIG --libs`
+	LIBS="$LIBGCRYPT_LIBS $LIBS"
+fi
+
 ################################################################################
 { echo "$as_me:$LINENO: checking whether to enable readline" >&5
 echo $ECHO_N "checking whether to enable readline... $ECHO_C" >&6; }
@@ -11753,6 +11838,7 @@ LVM_VERSION="\"`cat VERSION 2>/dev/null || echo Unknown`\""
 
 
 
+
 ################################################################################
 ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile doc/Makefile include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/snapshot/Makefile libdm/Makefile libdm/libdevmapper.pc man/Makefile po/Makefile scripts/clvmd_init_red_hat scripts/Makefile test/Makefile test/api/Makefile tools/Makefile tools/version.h"
 
@@ -12471,6 +12557,7 @@ CSCOPE_CMD!$CSCOPE_CMD$ac_delim
 ALLOCA!$ALLOCA$ac_delim
 LIBOBJS!$LIBOBJS$ac_delim
 POW_LIB!$POW_LIB$ac_delim
+LIBGCRYPT_CONFIG!$LIBGCRYPT_CONFIG$ac_delim
 LCOV!$LCOV$ac_delim
 GENHTML!$GENHTML$ac_delim
 LVM2CMD_LIB!$LVM2CMD_LIB$ac_delim
@@ -12485,6 +12572,7 @@ CLVMD!$CLVMD$ac_delim
 CMDLIB!$CMDLIB$ac_delim
 COPTIMISE_FLAG!$COPTIMISE_FLAG$ac_delim
 CRYPTO!$CRYPTO$ac_delim
+CRYPTO_LUKS1!$CRYPTO_LUKS1$ac_delim
 DEBUG!$DEBUG$ac_delim
 DEVMAPPER!$DEVMAPPER$ac_delim
 DMEVENTD!$DMEVENTD$ac_delim
@@ -12494,8 +12582,6 @@ DM_DEVICE_MODE!$DM_DEVICE_MODE$ac_delim
 DM_DEVICE_UID!$DM_DEVICE_UID$ac_delim
 DM_IOCTLS!$DM_IOCTLS$ac_delim
 DM_LIB_VERSION!$DM_LIB_VERSION$ac_delim
-DM_LIB_PATCHLEVEL!$DM_LIB_PATCHLEVEL$ac_delim
-FSADM!$FSADM$ac_delim
 _ACEOF
 
   if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then
@@ -12537,6 +12623,8 @@ _ACEOF
 ac_delim='%!_!# '
 for ac_last_try in false false false false false :; do
   cat >conf$$subs.sed <<_ACEOF
+DM_LIB_PATCHLEVEL!$DM_LIB_PATCHLEVEL$ac_delim
+FSADM!$FSADM$ac_delim
 GROUP!$GROUP$ac_delim
 HAVE_LIBDL!$HAVE_LIBDL$ac_delim
 HAVE_REALTIME!$HAVE_REALTIME$ac_delim
@@ -12569,7 +12657,7 @@ usrsbindir!$usrsbindir$ac_delim
 LTLIBOBJS!$LTLIBOBJS$ac_delim
 _ACEOF
 
-  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 30; then
+  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 32; then
     break
   elif $ac_last_try; then
     { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
diff --git a/configure.in b/configure.in
index a5e9236..a1072fb 100644
--- a/configure.in
+++ b/configure.in
@@ -325,6 +325,35 @@ if test x$CRYPTO = xinternal; then
 	AC_DEFINE([CRYPT_INTERNAL], 1, [Define to 1 to include built-in support for crypto.])
 fi
 
+dnl -- LUKS1 keystore support
+AC_MSG_CHECKING(whether to enable LUKS1 support)
+AC_ARG_ENABLE([luks1],
+  [  --enable-luks1          Enable LUKS1 crypto support],
+  [CRYPTO_LUKS1=$enableval], [CRYPTO_LUKS1=no])
+AC_MSG_RESULT($CRYPTO_LUKS1)
+
+if test x$CRYPTO_LUKS1 = xyes; then
+	AC_DEFINE([CRYPT_LUKS1], 1, [Define to 1 to include built-in support for LUKS1 keystore.])
+
+	if test x$CRYPTO = xnone ; then
+		AC_MSG_ERROR(Cannot use LUKS without crypto support)
+	fi
+
+	AC_PATH_PROG(LIBGCRYPT_CONFIG, libgcrypt-config, no)
+
+	if test x"$LIBGCRYPT_CONFIG" = x"no" ; then
+		AC_MSG_ERROR(You selected option which require libgcrypt)
+	fi
+
+	# libgcrypt-config fails here, this must go first
+	if test "x$STATIC_LINK" = xyes; then
+		LIBS="-lgpg-error $LIBS"
+	fi
+
+	LIBGCRYPT_LIBS=`$LIBGCRYPT_CONFIG --libs`
+	LIBS="$LIBGCRYPT_LIBS $LIBS"
+fi
+
 ################################################################################
 dnl -- Disable readline
 AC_MSG_CHECKING(whether to enable readline)
@@ -755,6 +784,7 @@ AC_SUBST(CLVMD)
 AC_SUBST(CMDLIB)
 AC_SUBST(COPTIMISE_FLAG)
 AC_SUBST(CRYPTO)
+AC_SUBST(CRYPTO_LUKS1)
 AC_SUBST(CSCOPE_CMD)
 AC_SUBST(DEBUG)
 AC_SUBST(DEVMAPPER)
diff --git a/lib/Makefile.in b/lib/Makefile.in
index 7167f04..912d1d9 100644
--- a/lib/Makefile.in
+++ b/lib/Makefile.in
@@ -131,6 +131,12 @@ ifeq ("@CRYPTO@", "internal")
   SOURCES += crypt/crypt.c
 endif
 
+ifeq ("@CRYPTO_LUKS1@", "yes")
+  SOURCES +=\
+	crypt/key_luks.c \
+	crypt/pbkdf2.c
+endif
+
 ifeq ("@DEVMAPPER@", "yes")
   SOURCES +=\
 	activate/dev_manager.c \
diff --git a/lib/crypt/key_handlers.c b/lib/crypt/key_handlers.c
index 678a260..4380218 100644
--- a/lib/crypt/key_handlers.c
+++ b/lib/crypt/key_handlers.c
@@ -60,6 +60,9 @@ int lvm_keystore_handlers_init()
 
 	// FIXME: here should be library loading
 	dm_list_add(&_keystore_handlers, &_plain_csh.list);
+#ifdef CRYPT_LUKS1
+	dm_list_add(&_keystore_handlers, &keystore_luks1_init()->list);
+#endif
 
 	return 1;
 }
diff --git a/lib/crypt/key_luks.c b/lib/crypt/key_luks.c
new file mode 100644
index 0000000..0f1a3d9
--- /dev/null
+++ b/lib/crypt/key_luks.c
@@ -0,0 +1,495 @@
+/*
+ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
+ *
+ * LUKS1 & AF merge code, completely rewrited for libgcrypt,
+ * function reference to cryptsetup-luks source,
+ * Copyright (C) 2004-2006, Clemens Fruhwirth
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ * LUKS version 1 metadata activation code
+ */
+
+#include <netinet/in.h>
+#include <gcrypt.h>
+#include "lib.h"
+#include "lvm-crypto.h"
+#include "pbkdf2.h"
+
+// This part is copied from LUKS cryptsetup implementation:
+#define LUKS_DIGESTSIZE 20 // since SHA1
+#define SHA1_DIGEST_SIZE LUKS_DIGESTSIZE
+#define LUKS_NUMKEYS 8
+#define SECTOR_SHIFT 9
+
+// Numbers of iterations for the master key digest
+#define LUKS_MKD_ITER 10
+
+#define LUKS_KEY_DISABLED 0x0000DEAD
+#define LUKS_KEY_ENABLED  0x00AC71F3
+
+#define LUKS_STRIPES 4000
+
+#define LUKS_MAGIC "LUKS\xba\xbe"
+
+#define dm_div_up(n, sz) (((n) + (sz) - 1) / (sz))
+#define dm_round_up(n, sz) (dm_div_up((n), (sz)) * (sz))
+
+/*
+ * on disk structure:
+ *
+ * | LUKS header | padding | keyslot 1 | .. | keyslot 8 || <VOLUME DATA>
+ */
+struct luks_keyslot_header {
+		uint32_t active;
+		uint32_t passwordIterations;
+		unsigned char passwordSalt[32];
+		uint32_t keyMaterialOffset;
+		uint32_t stripes;
+} __attribute__ ((packed));
+
+struct luks_header {
+	char		magic[6];	/* "LUKS\xba\xbe" */
+	uint16_t	version;	/* 1 */
+	char		cipherName[32];
+	char		cipherMode[32];
+	char		hashSpec[32];
+	uint32_t	payloadOffset;
+	uint32_t	keyBytes;
+	char		mkDigest[20];
+	unsigned char	mkDigestSalt[32];
+	uint32_t	mkDigestIterations;
+	char		uuid[40];
+
+	struct luks_keyslot_header ksh[LUKS_NUMKEYS];
+} __attribute__ ((packed));
+
+// FIXME: no return value checking
+// FIXME: too many static buffers
+
+static void sha1_buf(unsigned char *src, unsigned char *dst,
+		     uint32_t iv, int len)
+{
+	gcry_md_hd_t hd;
+	unsigned char *digest;
+
+	iv = htonl(iv);
+	gcry_md_open(&hd, GCRY_MD_SHA1, 0);
+	gcry_md_write(hd, (unsigned char *)&iv, sizeof(iv));
+	gcry_md_write(hd, src, len);
+	digest = gcry_md_read(hd, GCRY_MD_SHA1);
+	memcpy(dst, digest, len);
+	gcry_md_close(hd);
+}
+
+static void diffuse_g(unsigned char *src, unsigned char *dst, size_t size)
+{
+	unsigned int i, blocks, padding;
+
+	blocks = size / SHA1_DIGEST_SIZE;
+	padding = size % SHA1_DIGEST_SIZE;
+
+	if (gcry_md_get_algo_dlen (GCRY_MD_SHA1) != SHA1_DIGEST_SIZE)
+		return;
+
+	for (i = 0; i < blocks; i++)
+		sha1_buf(src + SHA1_DIGEST_SIZE * i,
+			 dst + SHA1_DIGEST_SIZE * i,
+			 i, SHA1_DIGEST_SIZE);
+
+	if(padding)
+		sha1_buf(src + SHA1_DIGEST_SIZE * i,
+			 dst + SHA1_DIGEST_SIZE * i,
+			 i, padding);
+}
+
+static int AF_merge_g(char *src, char *dst, size_t blocksize, unsigned int blocknumbers)
+{
+	unsigned int i, j;
+	unsigned char *buf;
+
+	if (!(buf = malloc(blocksize)))
+		return 1;
+
+	memset(buf, 0, blocksize);
+
+	for(i = 0; i < blocknumbers - 1; i++) {
+		for(j = 0; j < blocksize; j++)
+			buf[j] ^= src[blocksize * i + j];
+		diffuse_g(buf, buf, blocksize);
+	}
+
+	for(j = 0; j < blocksize; j++)
+		dst[j] = src[blocksize * i + j] ^ buf[j];
+
+	free(buf);
+	return 0;
+}
+
+/*
+ * DM helpers for temporary cryptsetup device
+ */
+// FIXME: this is stupid, we should have such funcions in library
+// Cannot use lvm helprs, library must be independend of lvm code
+// only libdevmapper calls possible here
+
+//FIXME: no uuid set for the temporary device
+
+static int _dm_simple(int task, const char *name)
+{
+	int r = 0;
+	struct dm_task *dmt;
+
+	if (!(dmt = dm_task_create(task)))
+		return 0;
+
+	if (!dm_task_set_name(dmt, name))
+		goto out;
+
+	r = dm_task_run(dmt);
+
+out:
+	dm_task_destroy(dmt);
+	return r;
+}
+
+static int _error_device(const char *name, size_t size)
+{
+	struct dm_task *dmt;
+	int r = 0;
+
+	if (!(dmt = dm_task_create(DM_DEVICE_RELOAD)))
+		return 0;
+
+	if (!dm_task_set_name(dmt, name))
+		goto error;
+
+	if (!dm_task_add_target(dmt, UINT64_C(0), size, "error", ""))
+		goto error;
+
+	if (!dm_task_set_ro(dmt))
+		goto error;
+
+	if (!dm_task_no_open_count(dmt))
+		goto error;
+
+	if (!dm_task_run(dmt))
+		goto error;
+
+	if (!_dm_simple(DM_DEVICE_RESUME, name)) {
+		_dm_simple(DM_DEVICE_CLEAR, name);
+		goto error;
+	}
+
+	r = 1;
+error:
+	dm_task_destroy(dmt);
+	return r;
+}
+
+static int dm_create_device(const char *name, char *params, size_t size, const char *target)
+{
+	struct dm_task *dmt = NULL;
+	int r = 0;
+
+	if (!(dmt = dm_task_create(DM_DEVICE_CREATE)))
+		return 0;
+	if (!dm_task_set_name(dmt, name))
+		goto out;
+	if (!dm_task_set_ro(dmt))
+                goto out;
+	if (!dm_task_add_target(dmt, 0, size, target, params))
+		goto out;
+	if (!dm_task_run(dmt))
+		goto out;
+	r = 1;
+	dm_task_update_nodes();
+out:
+	dm_task_destroy(dmt);
+
+	return r;
+}
+
+static int dm_remove_device(const char *name, size_t size)
+{
+	int r = -EINVAL;
+	int retries = 2;
+
+	 _error_device(name, size);
+
+again:
+	r = _dm_simple(DM_DEVICE_REMOVE, name);
+
+	if (!r && --retries) {
+		sleep(1);
+		goto again;
+	}
+
+	dm_task_update_nodes();
+
+	return r;
+}
+
+static int read_keyslot_dev(const char *name, char *buffer, size_t len)
+{
+	char path[PATH_MAX+1];
+	struct device *dev;
+	int r = 1;
+
+	if (dm_snprintf(path, PATH_MAX, "%s/%s", dm_dir(), name) < 0) {
+		log_error("dm_snprintf failed");
+		return 0;
+	}
+
+	if (!(dev = dev_create_file(path, NULL, NULL, 1)))
+		return 0;
+
+	if (!dev_open(dev))
+		return 0;
+
+	/*
+	 * Trick to disable aligning to PAGE_SIZE and out of device access
+	 */
+	dev->flags &= ~DEV_REGULAR;
+
+	if (!dev_read(dev, 0, len, buffer))
+		r = 0;
+
+	if (!dev_close(dev))
+		stack;
+
+	return r;
+}
+
+static void key_to_hexa(char *key, char *hexakey, unsigned len)
+{
+	int i;
+
+	for(i = 0; i < len; i++)
+		sprintf(&hexakey[i * 2], "%02x", (unsigned char)key[i]);
+}
+
+static int luks_query_keyslots(struct device_area *da, struct luks_header *lh, const char *password, char *buffer, unsigned buffer_len)
+{
+	int i;
+	struct luks_keyslot_header *ksh;
+	unsigned key_len = ntohl(lh->keyBytes);
+	char keyslot_key[2048];
+	char keyslot_hexakey[2048];
+	char params[4096];
+	char hash_buf[SHA1_DIGEST_SIZE + 1];
+
+	char *keyslot = NULL;
+
+	// FIXME: cannot use fixed device name here
+	const char *dev_tmp = "lvm_luks1_keystore";
+	size_t dev_tmp_size, dev_tmp_sectors;
+	int r = 0;
+
+	memset(keyslot_key, 0, sizeof(keyslot_key));
+
+	// FIXME: with dm-crypt multiple segment trick this can be done in one step!
+	// FIXME: it keeps some sensitive data not wiped now in memory
+	for(i = 0; r == 0 && i < LUKS_NUMKEYS && (ksh = &lh->ksh[i]); i++) {
+		if (ntohl(ksh->active) != LUKS_KEY_ENABLED)
+			continue;
+		log_debug("Scanning active keyslot %u", i);
+
+		pkcs5_pbkdf2(GCRY_MD_SHA1, password, strlen(password),
+			     ksh->passwordSalt, sizeof(ksh->passwordSalt),
+			     ntohl(ksh->passwordIterations),
+			     key_len, keyslot_key);
+
+		key_to_hexa(keyslot_key, keyslot_hexakey, strlen(keyslot_key));
+
+		// <cipher> <key> <iv_offset> <device path> <offset>
+		// FIXME - skip ignored
+		sprintf(params, "%s-%s %s 0 %s %" PRIu64,
+			lh->cipherName, lh->cipherMode,
+			keyslot_hexakey, dev_name(da->dev), (da->start >> SECTOR_SHIFT) + ntohl(ksh->keyMaterialOffset));
+
+		dev_tmp_size = dm_round_up(ntohl(ksh->stripes) * key_len, (1 << SECTOR_SHIFT));
+		dev_tmp_sectors = dev_tmp_size >> SECTOR_SHIFT;
+
+		if (!dm_create_device(&dev_tmp[0], params, dev_tmp_sectors, "crypt"))
+			break;
+
+		if (!(keyslot = dm_malloc(dev_tmp_size)))
+			break;
+
+		if (!read_keyslot_dev(&dev_tmp[0], keyslot, dev_tmp_size))
+			break;
+
+		if (!dm_remove_device(&dev_tmp[0], dev_tmp_sectors))
+			break;
+
+		memset(keyslot_key, 0, sizeof(keyslot_key));
+		if (AF_merge_g(keyslot, keyslot_key, key_len, ntohl(ksh->stripes)) < 0)
+			break;
+
+		pkcs5_pbkdf2(GCRY_MD_SHA1, keyslot_key, key_len,
+				 lh->mkDigestSalt, sizeof(lh->mkDigestSalt),
+				 ntohl(lh->mkDigestIterations),
+				 SHA1_DIGEST_SIZE, hash_buf);
+
+		if (memcmp(hash_buf, lh->mkDigest, SHA1_DIGEST_SIZE) == 0) {
+			log_debug("Using valid key for slot %u", i);
+			key_to_hexa(keyslot_key, buffer, key_len);
+			r = 1;
+		}
+
+		memset(keyslot_key, 0, sizeof(keyslot_key));
+		memset(keyslot, 0, dev_tmp_size);
+		dm_free(keyslot);
+		keyslot = NULL;
+	}
+
+	return r;
+}
+
+static int ask_for_luks_password(const char *device_name,
+				 char *buffer, unsigned buffer_len)
+{
+	char prompt[4096];
+
+	dm_snprintf(prompt, sizeof(prompt), "Enter LUKS password%s%s : ",
+		    device_name ?" for ":"", device_name ?: "");
+
+	return lvm_read_password(prompt, buffer, buffer_len);
+}
+
+static int read_header(struct device_area *da, struct luks_header *lh)
+{
+	int r = 1;
+
+	if (sizeof(*lh) > da->size) {
+		log_error("LUKS1 internal error - keystore area too small.");
+		return 0;
+	}
+
+	if (!dev_open(da->dev)) {
+		log_error("Failed to open device %s.", dev_name(da->dev));
+		return 0;
+	}
+
+	if (!dev_read(da->dev, da->start, sizeof(*lh), (char*)lh)) {
+		log_error("Failed to read LUKS header from %s.",
+			  dev_name(da->dev));
+		r = 0;
+	}
+
+	if (!dev_close(da->dev))
+		stack;
+
+	return r;
+}
+
+static int header_compatible(struct luks_header *lh)
+{
+	if (strncmp(lh->magic, LUKS_MAGIC, sizeof(lh->magic)))
+		return 0;
+
+	if (ntohs(lh->version) != 1 || strcmp(lh->hashSpec, "sha1"))
+		return 0;
+
+	return 1;
+}
+
+static int luks1_scan(struct device_area *da)
+{
+	struct luks_header lh;
+
+	log_debug("Scanning for LUKS on device %s, offset %llu",
+		  dev_name(da->dev), da->start);
+
+	if (!read_header(da, &lh))
+		return 0;
+
+	if (!header_compatible(&lh)) {
+		log_verbose("Compatible LUKS1 header not found on device %s",
+			    dev_name(da->dev));
+		return 0;
+	}
+
+	if (ntohl(lh.payloadOffset) != da->size) {
+		log_verbose("LUKS1 data area is not aligned to requested offset.\n"
+			    "Data on device %s cannot be directly imported.",
+			    dev_name(da->dev));
+		return 0;
+	}
+
+	log_debug("Compatible LUKS1 header found on device %s, offset %llu",
+		  dev_name(da->dev), da->start);
+
+	return 1;
+}
+
+static int luks1_retrieve(struct crypto_store *cs, const char *for_text, char *buffer, unsigned buffer_len)
+{
+	char password[4096];
+	char cipher[1024];
+	unsigned password_len = sizeof(password);
+	struct device_area *da = first_crypto_area(cs);
+	struct luks_header lh;
+	int r;
+
+	log_debug("Retrieving key from LUKS1 keystore on device %s, offset %llu",
+		  dev_name(da->dev), da->start);
+
+	if (!read_header(da, &lh))
+		return_0;
+
+	if (!header_compatible(&lh)) {
+		log_error("Internal error: LUKS1 keystore area on device %s"
+			  "is corrupted or not compatible.", dev_name(da->dev));
+		return_0;
+	}
+
+	if (!ask_for_luks_password(for_text, password, password_len)) {
+		log_error("No password received.");
+		return 0;
+	}
+
+	r = luks_query_keyslots(da, &lh, password, buffer, buffer_len);
+	memset(password, 0, sizeof(password));
+	if (!r) {
+		log_error("No valid key found.");
+		return 0;
+	}
+
+	sprintf(cipher, "%s-%s", lh.cipherName, lh.cipherMode);
+	cs->cipher = dm_pool_strdup(cs->mem, cipher);
+	cs->key_size = ntohl(lh.keyBytes) * 8;
+
+	return 1;
+}
+
+static struct crypto_store_ops _luks1_ops = {
+	.scan = luks1_scan,
+	.master_key_retrieve = luks1_retrieve,
+};
+
+static struct crypto_store_type _luks1_csh = {
+	.name = "luks1",
+	.flags = CS_IGNORE_CIPHER | CS_IGNORE_KEYLEN | CS_IGNORE_KEYHASH,
+	.ops = &_luks1_ops,
+};
+
+struct crypto_store_type *keystore_luks1_init()
+{
+	//FIXME: Just for test - libgcrypt initialization
+	gcry_control(GCRYCTL_DISABLE_SECMEM, 0);
+	gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
+
+	return &_luks1_csh;
+}
diff --git a/lib/crypt/lvm-crypto.h b/lib/crypt/lvm-crypto.h
index 42004b7..928ff5b 100644
--- a/lib/crypt/lvm-crypto.h
+++ b/lib/crypt/lvm-crypto.h
@@ -107,6 +107,9 @@ int lvm_masterkeys_retrieve(const char *for_text, struct crypto_store *cs);
 int lvm_keystore_handlers_init(void);
 void lvm_keystore_handlers_destroy(void);
 struct crypto_store_type *lvm_get_keystore_handler(const char *name);
+#ifdef CRYPT_LUKS1
+struct crypto_store_type *keystore_luks1_init(void);
+#endif
 
 /*
  * Crypto Helper functions
diff --git a/lib/crypt/pbkdf2.c b/lib/crypt/pbkdf2.c
new file mode 100644
index 0000000..b9ce46c
--- /dev/null
+++ b/lib/crypt/pbkdf2.c
@@ -0,0 +1,199 @@
+/* Implementation of Password-Based Cryptography as per PKCS#5
+ * Copyright (C) 2002,2003 Simon Josefsson
+ * Copyright (C) 2004 Free Software Foundation
+ *
+ * This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this file; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "pbkdf2.h"
+
+/*
+ * 5.2 PBKDF2
+ *
+ *  PBKDF2 applies a pseudorandom function (see Appendix B.1 for an
+ *  example) to derive keys. The length of the derived key is essentially
+ *  unbounded. (However, the maximum effective search space for the
+ *  derived key may be limited by the structure of the underlying
+ *  pseudorandom function. See Appendix B.1 for further discussion.)
+ *  PBKDF2 is recommended for new applications.
+ *
+ *  PBKDF2 (P, S, c, dkLen)
+ *
+ *  Options:        PRF        underlying pseudorandom function (hLen
+ *                             denotes the length in octets of the
+ *                             pseudorandom function output)
+ *
+ *  Input:          P          password, an octet string (ASCII or UTF-8)
+ *                  S          salt, an octet string
+ *                  c          iteration count, a positive integer
+ *                  dkLen      intended length in octets of the derived
+ *                             key, a positive integer, at most
+ *                             (2^32 - 1) * hLen
+ *
+ *  Output:         DK         derived key, a dkLen-octet string
+ */
+
+#define MAX_PRF_BLOCK_LEN 80
+
+int pkcs5_pbkdf2(int PRF,
+		     const char *P,
+		     size_t Plen,
+		     const unsigned char *S,
+		     size_t Slen, unsigned int c, unsigned int dkLen,
+		     char *DK)
+{
+    gcry_md_hd_t prf;
+    gcry_error_t err;
+    char U[MAX_PRF_BLOCK_LEN];
+    char T[MAX_PRF_BLOCK_LEN];
+    unsigned int u;
+    unsigned int hLen = gcry_md_get_algo_dlen(PRF);
+    unsigned int l;
+    unsigned int r;
+    int rc;
+    unsigned char *p;
+    int i;
+    int k;
+
+    if (hLen == 0 || hLen > MAX_PRF_BLOCK_LEN)
+	return PKCS5_INVALID_PRF;
+
+    if (c == 0)
+	return PKCS5_INVALID_ITERATION_COUNT;
+
+    if (dkLen == 0)
+	return PKCS5_INVALID_DERIVED_KEY_LENGTH;
+
+    /*
+     *
+     *  Steps:
+     *
+     *     1. If dkLen > (2^32 - 1) * hLen, output "derived key too long" and
+     *        stop.
+     */
+
+    if (dkLen > 4294967295U)
+	return PKCS5_DERIVED_KEY_TOO_LONG;
+
+    /*
+     *     2. Let l be the number of hLen-octet blocks in the derived key,
+     *        rounding up, and let r be the number of octets in the last
+     *        block:
+     *
+     *                  l = CEIL (dkLen / hLen) ,
+     *                  r = dkLen - (l - 1) * hLen .
+     *
+     *        Here, CEIL (x) is the "ceiling" function, i.e. the smallest
+     *        integer greater than, or equal to, x.
+     */
+
+    l = dkLen / hLen;
+    if (dkLen % hLen)
+	l++;
+    r = dkLen - (l - 1) * hLen;
+
+    /*
+     *     3. For each block of the derived key apply the function F defined
+     *        below to the password P, the salt S, the iteration count c, and
+     *        the block index to compute the block:
+     *
+     *                  T_1 = F (P, S, c, 1) ,
+     *                  T_2 = F (P, S, c, 2) ,
+     *                  ...
+     *                  T_l = F (P, S, c, l) ,
+     *
+     *        where the function F is defined as the exclusive-or sum of the
+     *        first c iterates of the underlying pseudorandom function PRF
+     *        applied to the password P and the concatenation of the salt S
+     *        and the block index i:
+     *
+     *                  F (P, S, c, i) = U_1 \xor U_2 \xor ... \xor U_c
+     *
+     *        where
+     *
+     *                  U_1 = PRF (P, S || INT (i)) ,
+     *                  U_2 = PRF (P, U_1) ,
+     *                  ...
+     *                  U_c = PRF (P, U_{c-1}) .
+     *
+     *        Here, INT (i) is a four-octet encoding of the integer i, most
+     *        significant octet first.
+     *
+     *     4. Concatenate the blocks and extract the first dkLen octets to
+     *        produce a derived key DK:
+     *
+     *                  DK = T_1 || T_2 ||  ...  || T_l<0..r-1>
+     *
+     *     5. Output the derived key DK.
+     *
+     *  Note. The construction of the function F follows a "belt-and-
+     *  suspenders" approach. The iterates U_i are computed recursively to
+     *  remove a degree of parallelism from an opponent; they are exclusive-
+     *  ored together to reduce concerns about the recursion degenerating
+     *  into a small set of values.
+     *
+     */
+
+    err = gcry_md_open(&prf, PRF, GCRY_MD_FLAG_HMAC);
+    if (err)
+	return PKCS5_INVALID_PRF;
+
+    for (i = 1; (uint) i <= l; i++) {
+	memset(T, 0, hLen);
+
+	for (u = 1; u <= c; u++) {
+	    gcry_md_reset(prf);
+
+	    rc = gcry_md_setkey(prf, P, Plen);
+	    if (rc)
+		return PKCS5_INVALID_PRF;
+
+	    if (u == 1) {
+		char *tmp;
+		size_t tmplen = Slen + 4;
+
+		tmp = alloca(tmplen);
+		if (tmp == NULL)
+		    return PKCS5_INVALID_PRF;
+
+		memcpy(tmp, S, Slen);
+		tmp[Slen + 0] = (i & 0xff000000) >> 24;
+		tmp[Slen + 1] = (i & 0x00ff0000) >> 16;
+		tmp[Slen + 2] = (i & 0x0000ff00) >> 8;
+		tmp[Slen + 3] = (i & 0x000000ff) >> 0;
+
+		gcry_md_write(prf, tmp, tmplen);
+	    } else {
+		gcry_md_write(prf, U, hLen);
+	    }
+
+	    p = gcry_md_read(prf, PRF);
+	    if (p == NULL)
+		return PKCS5_INVALID_PRF;
+
+	    memcpy(U, p, hLen);
+
+	    for (k = 0; (uint) k < hLen; k++)
+		T[k] ^= U[k];
+	}
+
+	memcpy(DK + (i - 1) * hLen, T, (uint) i == l ? r : hLen);
+    }
+
+    gcry_md_close(prf);
+
+    return PKCS5_OK;
+}
diff --git a/lib/crypt/pbkdf2.h b/lib/crypt/pbkdf2.h
new file mode 100644
index 0000000..3b6cc8e
--- /dev/null
+++ b/lib/crypt/pbkdf2.h
@@ -0,0 +1,36 @@
+/*
+ * pkcs5_pbkdf2 implementation
+ *
+ * Copyright (C) 2002 Simon Josefsson
+ * Copyright (C) 2009 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef PBKDF2_H
+#define PBKDF2_H
+
+#include <gcrypt.h>
+
+/* Error codes */
+enum {
+  PKCS5_OK = 0,
+  PKCS5_INVALID_PRF,
+  PKCS5_INVALID_ITERATION_COUNT,
+  PKCS5_INVALID_DERIVED_KEY_LENGTH,
+  PKCS5_DERIVED_KEY_TOO_LONG
+};
+
+int pkcs5_pbkdf2(int PRF, const char *P, size_t Plen,
+		 const unsigned char *S, size_t Slen,
+		 unsigned int c, unsigned int dkLen, char *DK);
+
+#endif /* PBKDF2_H */
diff --git a/lib/misc/configure.h.in b/lib/misc/configure.h.in
index d171445..1150b34 100644
--- a/lib/misc/configure.h.in
+++ b/lib/misc/configure.h.in
@@ -14,6 +14,9 @@
 /* Define to 1 to include built-in support for crypto. */
 #undef CRYPT_INTERNAL
 
+/* Define to 1 to include built-in support for LUKS1 keystore. */
+#undef CRYPT_LUKS1
+
 /* Define to 1 if using `alloca.c'. */
 #undef C_ALLOCA
 
-- 
1.5.6.5



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 15/15] Add simple test for crypto volumes.
  2009-01-21 11:19                           ` [PATCH 14/15] Add *testing* LUKS1 keystore implementation Milan Broz
@ 2009-01-21 11:19                             ` Milan Broz
  0 siblings, 0 replies; 16+ messages in thread
From: Milan Broz @ 2009-01-21 11:19 UTC (permalink / raw)
  To: lvm-devel

Signed-off-by: Milan Broz <mbroz@redhat.com>
---
 test/t-crypto-usage.sh |   54 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 54 insertions(+), 0 deletions(-)
 create mode 100755 test/t-crypto-usage.sh

diff --git a/test/t-crypto-usage.sh b/test/t-crypto-usage.sh
new file mode 100755
index 0000000..2462931
--- /dev/null
+++ b/test/t-crypto-usage.sh
@@ -0,0 +1,54 @@
+#!/bin/sh
+# Copyright (C) 2009 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+# 'Exercise some encrypted volumes operations'
+
+. ./test-utils.sh
+
+aux prepare_pvs 2
+aux pvcreate $devs
+vgcreate -cn $vg $devs -s 4M
+
+cipher="aes-cbc-essiv:sha256"
+key_plain="0123456789012345678901234567890101234567890123456789012345678901"
+keysize=256
+password="xxx"
+
+modprobe dm_crypt
+
+# 'lvcreate creates simple encrypted volume'
+echo $key_plain | lvcreate -n $lv1 -l 4 --crypt plain --cipher $cipher --keysize $keysize --keyfile - $vg
+echo $key_plain | lvcreate -n $lv2 -l 4 --crypt $vg/$lv1 --keyfile - $vg
+
+# 'deactivate volumes'
+lvchange -a n $vg/$lv1
+lvchange -a n $vg/$lv2
+echo $key_plain | vgchange -a y --keyfile -
+
+# 'cannot remove used cryptostore directly
+not lvremove $vg/cryptostore0
+
+# 'resize active volume'
+lvresize -l 8 $vg/$lv1
+lvresize -f -l 4 $vg/$lv1
+
+# 'lvremove removes simple encrypted volume'
+lvremove -ff $vg/$lv1
+lvremove -ff $vg/$lv2
+
+# 'import luks volume, using first extent as keystore (extent is 8192 sectors)'
+lvcreate -n $lv3 -L 36M $vg
+echo -n $password | cryptsetup luksFormat -q $G_dev_/$vg/$lv3 --key-size $keysize --align-payload=8192 --key-file -
+lvconvert --crypt luks1 $vg/$lv3
+echo $password | lvchange -a y $vg/$lv3 --keyfile -
+lvchange -a n $vg/$lv3
+lvremove -ff $vg/$lv3
+
-- 
1.5.6.5



^ permalink raw reply related	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2009-01-21 11:19 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-01-21 11:19 [PATCH 00/15][RFC] Encrypted logical volumes for LVM2 Milan Broz
2009-01-21 11:19 ` [PATCH 01/15] Support crypt segment in libdevmapper tree Milan Broz
2009-01-21 11:19   ` [PATCH 02/15] Add lvm-crypto header file with basic crypto struct definintions: Milan Broz
2009-01-21 11:19     ` [PATCH 03/15] Add master key cache to LVM Milan Broz
2009-01-21 11:19       ` [PATCH 04/15] Add simple password helpers Milan Broz
2009-01-21 11:19         ` [PATCH 05/15] Add key store handlers machinery Milan Broz
2009-01-21 11:19           ` [PATCH 06/15] Prepare source for recognising crypt segment Milan Broz
2009-01-21 11:19             ` [PATCH 07/15] Add "crypt" and "crypt-keystore" segment implementation Milan Broz
2009-01-21 11:19               ` [PATCH 08/15] Add crypto_store to LV segment allocation functions Milan Broz
2009-01-21 11:19                 ` [PATCH 09/15] Add encrypted LV manipulation functions Milan Broz
2009-01-21 11:19                   ` [PATCH 10/15] Cache key from crypt mapping table if segment is active Milan Broz
2009-01-21 11:19                     ` [PATCH 11/15] Add lvcreate crypto LV implementation Milan Broz
2009-01-21 11:19                       ` [PATCH 12/15] Add lvconcert crypt implementation Milan Broz
2009-01-21 11:19                         ` [PATCH 13/15] Add --keyfile option Milan Broz
2009-01-21 11:19                           ` [PATCH 14/15] Add *testing* LUKS1 keystore implementation Milan Broz
2009-01-21 11:19                             ` [PATCH 15/15] Add simple test for crypto volumes Milan Broz

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.