diff mbox series

[v9,02/13] ndctl: add command for ndctl to receive the key encryption key (master)

Message ID 154777911312.42557.15688834797714631330.stgit@djiang5-desk3.ch.intel.com (mailing list archive)
State Superseded
Headers show
Series ndctl: add security support | expand

Commit Message

Dave Jiang Jan. 18, 2019, 2:38 a.m. UTC
Add command that allows the user to provide the master encryption key name
to be installed in the key material directory where ndctl can refer to
for later security operations.

Signed-off-by: Dave Jiang <dave.jiang@intel.com>
---
 Documentation/ndctl/Makefile.am                   |    3 
 Documentation/ndctl/ndctl-install-encrypt-key.txt |   31 +++++
 configure.ac                                      |    3 
 ndctl/Makefile.am                                 |    4 -
 ndctl/builtin.h                                   |    1 
 ndctl/kek.c                                       |  133 +++++++++++++++++++++
 ndctl/lib/libndctl.c                              |   31 +++++
 ndctl/lib/libndctl.sym                            |    1 
 ndctl/lib/private.h                               |    1 
 ndctl/libndctl.h                                  |    1 
 ndctl/ndctl.c                                     |    1 
 11 files changed, 208 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/ndctl/ndctl-install-encrypt-key.txt
 create mode 100644 ndctl/kek.c

Comments

Verma, Vishal L Jan. 18, 2019, 8:58 p.m. UTC | #1
On Thu, 2019-01-17 at 19:38 -0700, Dave Jiang wrote:
> Add command that allows the user to provide the master encryption key name
> to be installed in the key material directory where ndctl can refer to
> for later security operations.
> 
> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
> ---
>  Documentation/ndctl/Makefile.am                   |    3 
>  Documentation/ndctl/ndctl-install-encrypt-key.txt |   31 +++++
>  configure.ac                                      |    3 
>  ndctl/Makefile.am                                 |    4 -
>  ndctl/builtin.h                                   |    1 
>  ndctl/kek.c                                       |  133 +++++++++++++++++++++
>  ndctl/lib/libndctl.c                              |   31 +++++
>  ndctl/lib/libndctl.sym                            |    1 
>  ndctl/lib/private.h                               |    1 
>  ndctl/libndctl.h                                  |    1 
>  ndctl/ndctl.c                                     |    1 
>  11 files changed, 208 insertions(+), 2 deletions(-)
>  create mode 100644 Documentation/ndctl/ndctl-install-encrypt-key.txt
>  create mode 100644 ndctl/kek.c
> 
> diff --git a/Documentation/ndctl/Makefile.am b/Documentation/ndctl/Makefile.am
> index a30b139b..7cb7bd6b 100644
> --- a/Documentation/ndctl/Makefile.am
> +++ b/Documentation/ndctl/Makefile.am
> @@ -47,7 +47,8 @@ man1_MANS = \
>  	ndctl-inject-smart.1 \
>  	ndctl-update-firmware.1 \
>  	ndctl-list.1 \
> -	ndctl-monitor.1
> +	ndctl-monitor.1 \
> +	ndctl-install-encrypt-key.1

I think Dan's feedback was to call this command setup-passphrase?
By 'install-encrypt-key' it seems unclear whether you mean "install
encrypted key" vs. "install a key and encrypt it"
Alternatively, the command can simply be 'install-kek', and the
synopsis/description can expand on what 'kek' is and how it is used.

>  
>  CLEANFILES = $(man1_MANS)
>  
> diff --git a/Documentation/ndctl/ndctl-install-encrypt-key.txt b/Documentation/ndctl/ndctl-install-encrypt-key.txt
> new file mode 100644
> index 00000000..d00463e3
> --- /dev/null
> +++ b/Documentation/ndctl/ndctl-install-encrypt-key.txt
> @@ -0,0 +1,31 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +ndctl-install-encrypt-key(1)
> +============================
> +
> +NAME
> +----
> +ndctl-install-encrypt-key - store encryption key name for nvdimm bus

"store the encryption key handle for an nvdimm bus"

> +
> +SYNOPSIS
> +--------
> +[verse]
> +'ndctl install-encrypt-key <ndbus0> [<ndbus1>..<ndbusN>] [-k <master encryption key] [<options>]
> +
> +Take the provided master encryption key handle and store it in a file that

This sentence seems incomplete?

> +A file would be created for the designated bus provider.
> +i.e. /etc/ndctl/keys/nfit_test.0.kek

With the makefile-vars-in-man-pages patch[1], all instances of hard
coding this path in the documentation can now be converted to use the
new scheme, and that should keep the man pages in sync with the actual
build options.

[1]: https://patchwork.kernel.org/patch/10771507/


> +The command only succeeds on bus(es) that contain nvdimms with security support.

This should be implied and is true for any command - the command will
only work if the underlying feature is supported by the DIMM/platform,
so I think we can omit this sentence.

I think you had a 'Description' section before, I think it is valuable
to retain it and add a blurb about the keyctl steps that might be
needed before invoking this command.
> +
> +OPTIONS
> +-------
> +-k::
> +--kek=::
> +	Key encryption key (master key) handle. The key handle has the format
> +	of <key type>:<key name>. i.e. trusted:nvdimm-master.
> +
> +-v::
> +--verbose::
> +	Turn on debug output
> +
> +include::../copyright.txt[]
> 
>
Dave Jiang Jan. 18, 2019, 9:12 p.m. UTC | #2
On 1/18/19 1:58 PM, Verma, Vishal L wrote:
> 
> On Thu, 2019-01-17 at 19:38 -0700, Dave Jiang wrote:
>> Add command that allows the user to provide the master encryption key name
>> to be installed in the key material directory where ndctl can refer to
>> for later security operations.
>>
>> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
>> ---
>>  Documentation/ndctl/Makefile.am                   |    3 
>>  Documentation/ndctl/ndctl-install-encrypt-key.txt |   31 +++++
>>  configure.ac                                      |    3 
>>  ndctl/Makefile.am                                 |    4 -
>>  ndctl/builtin.h                                   |    1 
>>  ndctl/kek.c                                       |  133 +++++++++++++++++++++
>>  ndctl/lib/libndctl.c                              |   31 +++++
>>  ndctl/lib/libndctl.sym                            |    1 
>>  ndctl/lib/private.h                               |    1 
>>  ndctl/libndctl.h                                  |    1 
>>  ndctl/ndctl.c                                     |    1 
>>  11 files changed, 208 insertions(+), 2 deletions(-)
>>  create mode 100644 Documentation/ndctl/ndctl-install-encrypt-key.txt
>>  create mode 100644 ndctl/kek.c
>>
>> diff --git a/Documentation/ndctl/Makefile.am b/Documentation/ndctl/Makefile.am
>> index a30b139b..7cb7bd6b 100644
>> --- a/Documentation/ndctl/Makefile.am
>> +++ b/Documentation/ndctl/Makefile.am
>> @@ -47,7 +47,8 @@ man1_MANS = \
>>  	ndctl-inject-smart.1 \
>>  	ndctl-update-firmware.1 \
>>  	ndctl-list.1 \
>> -	ndctl-monitor.1
>> +	ndctl-monitor.1 \
>> +	ndctl-install-encrypt-key.1
> 
> I think Dan's feedback was to call this command setup-passphrase?
> By 'install-encrypt-key' it seems unclear whether you mean "install
> encrypted key" vs. "install a key and encrypt it"
> Alternatively, the command can simply be 'install-kek', and the
> synopsis/description can expand on what 'kek' is and how it is used.

It probably should be called install encrypted key or install encryption
key. The next patch has setup-passphrase. This isn't it.

> 
>>  
>>  CLEANFILES = $(man1_MANS)
>>  
>> diff --git a/Documentation/ndctl/ndctl-install-encrypt-key.txt b/Documentation/ndctl/ndctl-install-encrypt-key.txt
>> new file mode 100644
>> index 00000000..d00463e3
>> --- /dev/null
>> +++ b/Documentation/ndctl/ndctl-install-encrypt-key.txt
>> @@ -0,0 +1,31 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +
>> +ndctl-install-encrypt-key(1)
>> +============================
>> +
>> +NAME
>> +----
>> +ndctl-install-encrypt-key - store encryption key name for nvdimm bus
> 
> "store the encryption key handle for an nvdimm bus"
> 
>> +
>> +SYNOPSIS
>> +--------
>> +[verse]
>> +'ndctl install-encrypt-key <ndbus0> [<ndbus1>..<ndbusN>] [-k <master encryption key] [<options>]
>> +
>> +Take the provided master encryption key handle and store it in a file that
> 
> This sentence seems incomplete?
> 
>> +A file would be created for the designated bus provider.
>> +i.e. /etc/ndctl/keys/nfit_test.0.kek
> 
> With the makefile-vars-in-man-pages patch[1], all instances of hard
> coding this path in the documentation can now be converted to use the
> new scheme, and that should keep the man pages in sync with the actual
> build options.
> 
> [1]: https://patchwork.kernel.org/patch/10771507/
> 
> 
>> +The command only succeeds on bus(es) that contain nvdimms with security support.
> 
> This should be implied and is true for any command - the command will
> only work if the underlying feature is supported by the DIMM/platform,
> so I think we can omit this sentence.
> 
> I think you had a 'Description' section before, I think it is valuable
> to retain it and add a blurb about the keyctl steps that might be
> needed before invoking this command.
>> +
>> +OPTIONS
>> +-------
>> +-k::
>> +--kek=::
>> +	Key encryption key (master key) handle. The key handle has the format
>> +	of <key type>:<key name>. i.e. trusted:nvdimm-master.
>> +
>> +-v::
>> +--verbose::
>> +	Turn on debug output
>> +
>> +include::../copyright.txt[]
>>
>>
>
Dan Williams Jan. 23, 2019, 5:08 p.m. UTC | #3
On Fri, Jan 18, 2019 at 1:12 PM Dave Jiang <dave.jiang@intel.com> wrote:
>
>
>
> On 1/18/19 1:58 PM, Verma, Vishal L wrote:
> >
> > On Thu, 2019-01-17 at 19:38 -0700, Dave Jiang wrote:
> >> Add command that allows the user to provide the master encryption key name
> >> to be installed in the key material directory where ndctl can refer to
> >> for later security operations.
> >>
> >> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
> >> ---
> >>  Documentation/ndctl/Makefile.am                   |    3
> >>  Documentation/ndctl/ndctl-install-encrypt-key.txt |   31 +++++
> >>  configure.ac                                      |    3
> >>  ndctl/Makefile.am                                 |    4 -
> >>  ndctl/builtin.h                                   |    1
> >>  ndctl/kek.c                                       |  133 +++++++++++++++++++++
> >>  ndctl/lib/libndctl.c                              |   31 +++++
> >>  ndctl/lib/libndctl.sym                            |    1
> >>  ndctl/lib/private.h                               |    1
> >>  ndctl/libndctl.h                                  |    1
> >>  ndctl/ndctl.c                                     |    1
> >>  11 files changed, 208 insertions(+), 2 deletions(-)
> >>  create mode 100644 Documentation/ndctl/ndctl-install-encrypt-key.txt
> >>  create mode 100644 ndctl/kek.c
> >>
> >> diff --git a/Documentation/ndctl/Makefile.am b/Documentation/ndctl/Makefile.am
> >> index a30b139b..7cb7bd6b 100644
> >> --- a/Documentation/ndctl/Makefile.am
> >> +++ b/Documentation/ndctl/Makefile.am
> >> @@ -47,7 +47,8 @@ man1_MANS = \
> >>      ndctl-inject-smart.1 \
> >>      ndctl-update-firmware.1 \
> >>      ndctl-list.1 \
> >> -    ndctl-monitor.1
> >> +    ndctl-monitor.1 \
> >> +    ndctl-install-encrypt-key.1
> >
> > I think Dan's feedback was to call this command setup-passphrase?
> > By 'install-encrypt-key' it seems unclear whether you mean "install
> > encrypted key" vs. "install a key and encrypt it"
> > Alternatively, the command can simply be 'install-kek', and the
> > synopsis/description can expand on what 'kek' is and how it is used.
>
> It probably should be called install encrypted key or install encryption
> key. The next patch has setup-passphrase. This isn't it.

True, but is it more: configure-key than install-key? All we're doing
at this point is recording the key details into a configuration file.
Dan Williams Jan. 23, 2019, 5:45 p.m. UTC | #4
On Thu, Jan 17, 2019 at 6:38 PM Dave Jiang <dave.jiang@intel.com> wrote:
>
> Add command that allows the user to provide the master encryption key name
> to be installed in the key material directory where ndctl can refer to
> for later security operations.
>
> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
> ---
>  Documentation/ndctl/Makefile.am                   |    3
>  Documentation/ndctl/ndctl-install-encrypt-key.txt |   31 +++++
>  configure.ac                                      |    3
>  ndctl/Makefile.am                                 |    4 -
>  ndctl/builtin.h                                   |    1
>  ndctl/kek.c                                       |  133 +++++++++++++++++++++
>  ndctl/lib/libndctl.c                              |   31 +++++
>  ndctl/lib/libndctl.sym                            |    1
>  ndctl/lib/private.h                               |    1
>  ndctl/libndctl.h                                  |    1
>  ndctl/ndctl.c                                     |    1
>  11 files changed, 208 insertions(+), 2 deletions(-)
>  create mode 100644 Documentation/ndctl/ndctl-install-encrypt-key.txt
>  create mode 100644 ndctl/kek.c
>
> diff --git a/Documentation/ndctl/Makefile.am b/Documentation/ndctl/Makefile.am
> index a30b139b..7cb7bd6b 100644
> --- a/Documentation/ndctl/Makefile.am
> +++ b/Documentation/ndctl/Makefile.am
> @@ -47,7 +47,8 @@ man1_MANS = \
>         ndctl-inject-smart.1 \
>         ndctl-update-firmware.1 \
>         ndctl-list.1 \
> -       ndctl-monitor.1
> +       ndctl-monitor.1 \
> +       ndctl-install-encrypt-key.1
>
>  CLEANFILES = $(man1_MANS)
>
> diff --git a/Documentation/ndctl/ndctl-install-encrypt-key.txt b/Documentation/ndctl/ndctl-install-encrypt-key.txt
> new file mode 100644
> index 00000000..d00463e3
> --- /dev/null
> +++ b/Documentation/ndctl/ndctl-install-encrypt-key.txt
> @@ -0,0 +1,31 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +ndctl-install-encrypt-key(1)
> +============================
> +
> +NAME
> +----
> +ndctl-install-encrypt-key - store encryption key name for nvdimm bus
> +
> +SYNOPSIS
> +--------
> +[verse]
> +'ndctl install-encrypt-key <ndbus0> [<ndbus1>..<ndbusN>] [-k <master encryption key] [<options>]
> +
> +Take the provided master encryption key handle and store it in a file that
> +A file would be created for the designated bus provider.
> +i.e. /etc/ndctl/keys/nfit_test.0.kek
> +The command only succeeds on bus(es) that contain nvdimms with security support.
> +
> +OPTIONS
> +-------
> +-k::
> +--kek=::
> +       Key encryption key (master key) handle. The key handle has the format
> +       of <key type>:<key name>. i.e. trusted:nvdimm-master.
> +
> +-v::
> +--verbose::
> +       Turn on debug output
> +
> +include::../copyright.txt[]
> diff --git a/configure.ac b/configure.ac
> index a02a2d80..61e91e0a 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -159,6 +159,9 @@ ndctl_monitorconf=monitor.conf
>  AC_SUBST([ndctl_monitorconfdir])
>  AC_SUBST([ndctl_monitorconf])
>
> +ndctl_keysdir=${sysconfdir}/ndctl/keys
> +AC_SUBST([ndctl_keysdir])
> +
>  my_CFLAGS="\
>  -Wall \
>  -Wchar-subscripts \
> diff --git a/ndctl/Makefile.am b/ndctl/Makefile.am
> index 97de1814..e412dbf7 100644
> --- a/ndctl/Makefile.am
> +++ b/ndctl/Makefile.am
> @@ -8,6 +8,7 @@ config.h: Makefile.am
>         $(AM_V_GEN) echo "/* Autogenerated by ndctl/Makefile.am */" >$@
>         $(AM_V_GEN) echo '#define NDCTL_CONF_FILE \
>                 "$(ndctl_monitorconfdir)/$(ndctl_monitorconf)"' >>$@
> +       $(AM_V_GEN) echo '#define NDCTL_KEYS_DIR  "$(ndctl_keysdir)"' >>$@
>
>  ndctl_SOURCES = ndctl.c \
>                 bus.c \
> @@ -23,7 +24,8 @@ ndctl_SOURCES = ndctl.c \
>                 util/json-firmware.c \
>                 inject-error.c \
>                 inject-smart.c \
> -               monitor.c
> +               monitor.c \
> +               kek.c
>
>  if ENABLE_DESTRUCTIVE
>  ndctl_SOURCES += ../test/blk_namespaces.c \
> diff --git a/ndctl/builtin.h b/ndctl/builtin.h
> index 17300df0..4af34f04 100644
> --- a/ndctl/builtin.h
> +++ b/ndctl/builtin.h
> @@ -32,4 +32,5 @@ int cmd_bat(int argc, const char **argv, struct ndctl_ctx *ctx);
>  #endif
>  int cmd_update_firmware(int argc, const char **argv, struct ndctl_ctx *ctx);
>  int cmd_inject_smart(int argc, const char **argv, struct ndctl_ctx *ctx);
> +int cmd_install_kek(int argc, const char **argv, struct ndctl_ctx *ctx);
>  #endif /* _NDCTL_BUILTIN_H_ */
> diff --git a/ndctl/kek.c b/ndctl/kek.c
> new file mode 100644
> index 00000000..1cb1555e
> --- /dev/null
> +++ b/ndctl/kek.c
> @@ -0,0 +1,133 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright(c) 2019 Intel Corporation. All rights reserved. */
> +
> +#include <stdio.h>
> +#include <errno.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <limits.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <dirent.h>
> +#include <fcntl.h>
> +#include <util/json.h>
> +#include <util/filter.h>
> +#include <util/log.h>
> +#include <json-c/json.h>
> +#include <ndctl/config.h>
> +#include <ndctl/libndctl.h>
> +#include <util/parse-options.h>
> +#include <ccan/array_size/array_size.h>
> +
> +#include <ndctl.h>
> +
> +static struct parameters {
> +       const char *kek;
> +       bool verbose;
> +} param;
> +
> +static int store_kek(const char *provider, const char *kek)
> +{
> +       char path[PATH_MAX];
> +       FILE *fp;
> +       ssize_t rc, wrote = 0;
> +       int size = strlen(kek);
> +
> +       rc = sprintf(path, "%s/%s.kek", NDCTL_KEYS_DIR, provider);
> +       if (rc < 0) {
> +               perror("sprintf kek path failed");
> +               return rc;
> +       }
> +
> +       fp = fopen(path, "w+");
> +       if (!fp) {
> +               fprintf(stderr, "Opening file %s failed: %s\n",
> +                               path, strerror(errno));
> +               return -errno;
> +       }
> +
> +       do {
> +               rc = fwrite(kek + wrote, 1, size - wrote, fp);
> +               if (rc < 0) {
> +                       fprintf(stderr, "writing file %s failed: %s\n",
> +                                       path, strerror(errno));
> +                       fclose(fp);
> +                       return -errno;
> +               }
> +               wrote += rc;
> +       } while (wrote != size);
> +
> +       fclose(fp);
> +       printf("key handle %s installed to %s\n", kek, path);
> +       return 0;

So the format of this file is just name it by the bus provider and
store the flat key name inside? That would seem to make supporting a
key per-dimm more complicated in the future.

It would be nice to steal the git config file handling since it could
do something like this:

[ key "<description>" ]
    bus = <provider>
    dimm = <dimm unique-id>
    file = <path to key data>

Where multiple keys can be recorded by unique descriptions and the
properties can be used as a match spec to scope that key to a set of
DIMMs. For example a system-wide master key

[ key "system-master" ]
    bus = all
    file = key.blob

...and the following would identify a kek for a single dimm.

[ key "dimm0" ]
    dimm = "8680-57341200"
    file = key.blob

...the roadblock of course being how easy (or not easy) it is to steal
the config file capabilities from git.

Too complicated? Other ideas?
Verma, Vishal L Jan. 24, 2019, 1:07 a.m. UTC | #5
On Wed, 2019-01-23 at 09:45 -0800, Dan Williams wrote:
> > 

[..]

> On Thu, Jan 17, 2019 at 6:38 PM Dave Jiang <dave.jiang@intel.com> wrote:
> > +static int store_kek(const char *provider, const char *kek)
> > +{
> > +       char path[PATH_MAX];
> > +       FILE *fp;
> > +       ssize_t rc, wrote = 0;
> > +       int size = strlen(kek);
> > +
> > +       rc = sprintf(path, "%s/%s.kek", NDCTL_KEYS_DIR, provider);
> > +       if (rc < 0) {
> > +               perror("sprintf kek path failed");
> > +               return rc;
> > +       }
> > +
> > +       fp = fopen(path, "w+");
> > +       if (!fp) {
> > +               fprintf(stderr, "Opening file %s failed: %s\n",
> > +                               path, strerror(errno));
> > +               return -errno;
> > +       }
> > +
> > +       do {
> > +               rc = fwrite(kek + wrote, 1, size - wrote, fp);
> > +               if (rc < 0) {
> > +                       fprintf(stderr, "writing file %s failed: %s\n",
> > +                                       path, strerror(errno));
> > +                       fclose(fp);
> > +                       return -errno;
> > +               }
> > +               wrote += rc;
> > +       } while (wrote != size);
> > +
> > +       fclose(fp);
> > +       printf("key handle %s installed to %s\n", kek, path);
> > +       return 0;
> 
> So the format of this file is just name it by the bus provider and
> store the flat key name inside? That would seem to make supporting a
> key per-dimm more complicated in the future.
> 
> It would be nice to steal the git config file handling since it could
> do something like this:
> 
> [ key "<description>" ]
>     bus = <provider>
>     dimm = <dimm unique-id>
>     file = <path to key data>
> 
> Where multiple keys can be recorded by unique descriptions and the
> properties can be used as a match spec to scope that key to a set of
> DIMMs. For example a system-wide master key
> 
> [ key "system-master" ]
>     bus = all
>     file = key.blob
> 
> ...and the following would identify a kek for a single dimm.
> 
> [ key "dimm0" ]
>     dimm = "8680-57341200"
>     file = key.blob
> 
> ...the roadblock of course being how easy (or not easy) it is to steal
> the config file capabilities from git.
> 
> Too complicated? Other ideas?

I like the general scheme..

But it sounds like a pre-requisite for this might be the config rework
that we will have for ndctl-monitor in the future. I'm trying to think
of how this will tie in with that - ideally we have one global config
file, and that includes sections for different commands. Ideally keys
also get described there.. Maybe each [key "foo"] section can be such a
top level section?

The other option is a security specific config file, but if we're
unifying the config file handling, I think this should be part of it
from the start.
diff mbox series

Patch

diff --git a/Documentation/ndctl/Makefile.am b/Documentation/ndctl/Makefile.am
index a30b139b..7cb7bd6b 100644
--- a/Documentation/ndctl/Makefile.am
+++ b/Documentation/ndctl/Makefile.am
@@ -47,7 +47,8 @@  man1_MANS = \
 	ndctl-inject-smart.1 \
 	ndctl-update-firmware.1 \
 	ndctl-list.1 \
-	ndctl-monitor.1
+	ndctl-monitor.1 \
+	ndctl-install-encrypt-key.1
 
 CLEANFILES = $(man1_MANS)
 
diff --git a/Documentation/ndctl/ndctl-install-encrypt-key.txt b/Documentation/ndctl/ndctl-install-encrypt-key.txt
new file mode 100644
index 00000000..d00463e3
--- /dev/null
+++ b/Documentation/ndctl/ndctl-install-encrypt-key.txt
@@ -0,0 +1,31 @@ 
+// SPDX-License-Identifier: GPL-2.0
+
+ndctl-install-encrypt-key(1)
+============================
+
+NAME
+----
+ndctl-install-encrypt-key - store encryption key name for nvdimm bus
+
+SYNOPSIS
+--------
+[verse]
+'ndctl install-encrypt-key <ndbus0> [<ndbus1>..<ndbusN>] [-k <master encryption key] [<options>]
+
+Take the provided master encryption key handle and store it in a file that
+A file would be created for the designated bus provider.
+i.e. /etc/ndctl/keys/nfit_test.0.kek
+The command only succeeds on bus(es) that contain nvdimms with security support.
+
+OPTIONS
+-------
+-k::
+--kek=::
+	Key encryption key (master key) handle. The key handle has the format
+	of <key type>:<key name>. i.e. trusted:nvdimm-master.
+
+-v::
+--verbose::
+	Turn on debug output
+
+include::../copyright.txt[]
diff --git a/configure.ac b/configure.ac
index a02a2d80..61e91e0a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -159,6 +159,9 @@  ndctl_monitorconf=monitor.conf
 AC_SUBST([ndctl_monitorconfdir])
 AC_SUBST([ndctl_monitorconf])
 
+ndctl_keysdir=${sysconfdir}/ndctl/keys
+AC_SUBST([ndctl_keysdir])
+
 my_CFLAGS="\
 -Wall \
 -Wchar-subscripts \
diff --git a/ndctl/Makefile.am b/ndctl/Makefile.am
index 97de1814..e412dbf7 100644
--- a/ndctl/Makefile.am
+++ b/ndctl/Makefile.am
@@ -8,6 +8,7 @@  config.h: Makefile.am
 	$(AM_V_GEN) echo "/* Autogenerated by ndctl/Makefile.am */" >$@
 	$(AM_V_GEN) echo '#define NDCTL_CONF_FILE \
 		"$(ndctl_monitorconfdir)/$(ndctl_monitorconf)"' >>$@
+	$(AM_V_GEN) echo '#define NDCTL_KEYS_DIR  "$(ndctl_keysdir)"' >>$@
 
 ndctl_SOURCES = ndctl.c \
 		bus.c \
@@ -23,7 +24,8 @@  ndctl_SOURCES = ndctl.c \
 		util/json-firmware.c \
 		inject-error.c \
 		inject-smart.c \
-		monitor.c
+		monitor.c \
+		kek.c
 
 if ENABLE_DESTRUCTIVE
 ndctl_SOURCES += ../test/blk_namespaces.c \
diff --git a/ndctl/builtin.h b/ndctl/builtin.h
index 17300df0..4af34f04 100644
--- a/ndctl/builtin.h
+++ b/ndctl/builtin.h
@@ -32,4 +32,5 @@  int cmd_bat(int argc, const char **argv, struct ndctl_ctx *ctx);
 #endif
 int cmd_update_firmware(int argc, const char **argv, struct ndctl_ctx *ctx);
 int cmd_inject_smart(int argc, const char **argv, struct ndctl_ctx *ctx);
+int cmd_install_kek(int argc, const char **argv, struct ndctl_ctx *ctx);
 #endif /* _NDCTL_BUILTIN_H_ */
diff --git a/ndctl/kek.c b/ndctl/kek.c
new file mode 100644
index 00000000..1cb1555e
--- /dev/null
+++ b/ndctl/kek.c
@@ -0,0 +1,133 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2019 Intel Corporation. All rights reserved. */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <util/json.h>
+#include <util/filter.h>
+#include <util/log.h>
+#include <json-c/json.h>
+#include <ndctl/config.h>
+#include <ndctl/libndctl.h>
+#include <util/parse-options.h>
+#include <ccan/array_size/array_size.h>
+
+#include <ndctl.h>
+
+static struct parameters {
+	const char *kek;
+	bool verbose;
+} param;
+
+static int store_kek(const char *provider, const char *kek)
+{
+	char path[PATH_MAX];
+	FILE *fp;
+	ssize_t rc, wrote = 0;
+	int size = strlen(kek);
+
+	rc = sprintf(path, "%s/%s.kek", NDCTL_KEYS_DIR, provider);
+	if (rc < 0) {
+		perror("sprintf kek path failed");
+		return rc;
+	}
+
+	fp = fopen(path, "w+");
+	if (!fp) {
+		fprintf(stderr, "Opening file %s failed: %s\n",
+				path, strerror(errno));
+		return -errno;
+	}
+
+	do {
+		rc = fwrite(kek + wrote, 1, size - wrote, fp);
+		if (rc < 0) {
+			fprintf(stderr, "writing file %s failed: %s\n",
+					path, strerror(errno));
+			fclose(fp);
+			return -errno;
+		}
+		wrote += rc;
+	} while (wrote != size);
+
+	fclose(fp);
+	printf("key handle %s installed to %s\n", kek, path);
+	return 0;
+}
+
+int cmd_install_kek(int argc, const char **argv, struct ndctl_ctx *ctx)
+{
+	const struct option options[] = {
+		OPT_BOOLEAN('v',"verbose", &param.verbose, "turn on debug"),
+		OPT_STRING('k', "kek", &param.kek, "kek",
+				"Key encription key (master)"),
+		OPT_END(),
+	};
+	const char * const u[] = {
+		"ndctl intall-encrypt-key <ndbus0> [<ndbus1>..<ndbusN>] [-k <master encryption key>]",
+		NULL
+	};
+	int i, rc;
+	bool all = false;
+
+	argc = parse_options(argc, argv, options, u, 0);
+
+	if (argc == 0) {
+		usage_with_options(u, options);
+		return -EINVAL;
+	}
+
+	if (!param.kek) {
+		usage_with_options(u, options);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < argc; i++) {
+		if (strcmp(argv[i], "all") == 0) {
+			argv[0] = "all";
+			argc = 1;
+			all = true;
+			break;
+		}
+	}
+
+	if (param.verbose)
+		ndctl_set_log_priority(ctx, LOG_DEBUG);
+
+	for (i = 0; i < argc; i++) {
+		struct ndctl_bus *bus;
+		struct ndctl_dimm *dimm;
+		bool security = false;
+
+		ndctl_bus_foreach(ctx, bus) {
+			if (!util_bus_filter(bus, argv[i]) && !all)
+				continue;
+
+			ndctl_dimm_foreach(bus, dimm) {
+				if (ndctl_dimm_get_security(dimm) >= 0) {
+					security = true;
+					break;
+				}
+			}
+
+			if (!security)
+				continue;
+
+			rc = store_kek(ndctl_bus_get_provider(bus),
+					param.kek);
+			if (rc < 0)
+				fprintf(stderr, "store kek %s for bus %s failed\n",
+						param.kek, ndctl_bus_get_devname(bus));
+
+		}
+	}
+
+	return 0;
+}
diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
index 830b7913..b255eb1b 100644
--- a/ndctl/lib/libndctl.c
+++ b/ndctl/lib/libndctl.c
@@ -36,6 +36,7 @@ 
 #include <ndctl/namespace.h>
 #include <daxctl/libdaxctl.h>
 #include <ndctl/libndctl-nfit.h>
+#include <ndctl/config.h>
 #include "private.h"
 
 static uuid_t null_uuid;
@@ -620,6 +621,7 @@  static void free_bus(struct ndctl_bus *bus, struct list_head *head)
 	free(bus->bus_buf);
 	free(bus->wait_probe_path);
 	free(bus->scrub_path);
+	free(bus->kek_handle);
 	free(bus);
 }
 
@@ -812,6 +814,28 @@  static void parse_dimm_flags(struct ndctl_dimm *dimm, char *flags)
 				ndctl_dimm_get_devname(dimm), flags);
 }
 
+static int bus_retrieve_kek_handle(struct ndctl_bus *bus)
+{
+	char path[PATH_MAX];
+	FILE *fp;
+	ssize_t rc;
+
+	rc = sprintf(path, "%s/%s.kek", NDCTL_KEYS_DIR,
+			ndctl_bus_get_provider(bus));
+	if (rc < 0)
+		return -errno;
+
+	fp = fopen(path, "r");
+	if (!fp)
+		return -errno;
+
+	if (fscanf(fp, "%ms", &bus->kek_handle) == EOF)
+		return -errno;
+
+	fclose(fp);
+	return 0;
+}
+
 static void *add_bus(void *parent, int id, const char *ctl_base)
 {
 	char buf[SYSFS_ATTR_SIZE];
@@ -890,6 +914,8 @@  static void *add_bus(void *parent, int id, const char *ctl_base)
 			return bus_dup;
 		}
 
+	bus_retrieve_kek_handle(bus);
+
 	list_add(&ctx->busses, &bus->list);
 	free(path);
 
@@ -5396,3 +5422,8 @@  NDCTL_EXPORT struct daxctl_region *ndctl_dax_get_daxctl_region(
 
 	return dax->region;
 }
+
+NDCTL_EXPORT const char *ndctl_bus_get_kek_handle(struct ndctl_bus *bus)
+{
+	return bus->kek_handle;
+}
diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym
index 0888c824..6d5e6606 100644
--- a/ndctl/lib/libndctl.sym
+++ b/ndctl/lib/libndctl.sym
@@ -391,4 +391,5 @@  global:
 	ndctl_cmd_xlat_firmware_status;
 	ndctl_cmd_submit_xlat;
 	ndctl_dimm_get_security;
+	ndctl_bus_get_kek_handle;
 } LIBNDCTL_18;
diff --git a/ndctl/lib/private.h b/ndctl/lib/private.h
index a387b0b5..a860f0db 100644
--- a/ndctl/lib/private.h
+++ b/ndctl/lib/private.h
@@ -172,6 +172,7 @@  struct ndctl_bus {
 	char *scrub_path;
 	unsigned long cmd_mask;
 	unsigned long nfit_dsm_mask;
+	char *kek_handle;
 };
 
 /**
diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h
index e228c64f..b0cc4543 100644
--- a/ndctl/libndctl.h
+++ b/ndctl/libndctl.h
@@ -694,6 +694,7 @@  enum ndctl_security_state {
 };
 
 enum ndctl_security_state ndctl_dimm_get_security(struct ndctl_dimm *dimm);
+const char *ndctl_bus_get_kek_handle(struct ndctl_bus *bus);
 
 #ifdef __cplusplus
 } /* extern "C" */
diff --git a/ndctl/ndctl.c b/ndctl/ndctl.c
index b01594e0..bd11ec03 100644
--- a/ndctl/ndctl.c
+++ b/ndctl/ndctl.c
@@ -90,6 +90,7 @@  static struct cmd_struct commands[] = {
 	{ "start-scrub", { cmd_start_scrub } },
 	{ "list", { cmd_list } },
 	{ "monitor", { cmd_monitor } },
+	{ "install-encrypt-key", { cmd_install_kek } },
 	{ "help", { cmd_help } },
 	#ifdef ENABLE_TEST
 	{ "test", { cmd_test } },