aboutsummaryrefslogtreecommitdiff
path: root/cryptech_backup
diff options
context:
space:
mode:
Diffstat (limited to 'cryptech_backup')
-rwxr-xr-xcryptech_backup113
1 files changed, 78 insertions, 35 deletions
diff --git a/cryptech_backup b/cryptech_backup
index 18441a3..f14f119 100755
--- a/cryptech_backup
+++ b/cryptech_backup
@@ -1,18 +1,38 @@
#!/usr/bin/env python
-# KEY SOURCE KEY BACKUP
+"""
+Securely back up private keys from one Cryptech HSM to another.
+
+This works by having the destination HSM (the one importing keys)
+create an RSA keypair (the "KEKEK"), the public key of which can then
+be imported into the source HSM (the one exporting keys) and used to
+encrypt AES key encryption keys (KEKs) which in turn can be used to
+wrap the private keys being transfered. Transfers are encoded in
+JSON; the underlying ASN.1 formats are SubjectPublicKeyInfo (KEKEK
+public key) and PKCS #8 EncryptedPrivateKeyInfo (everything else).
+
+NOTE WELL: while this process makes it POSSIBLE to back up keys
+securely, it is not sufficient by itself: the operator MUST make
+sure only to export keys using a KEKEK known to have been generated by
+the target HSM. See the unit tests in the source repository for
+an example of how to fake this in a few lines of Python.
+
+YOU HAVE BEEN WARNED. Be careful out there.
+"""
+
+# Diagram of the trivial protocol we're using:
+#
+# SOURCE HSM DESTINATION HSM
#
# Generate and export KEKEK:
# hal_rpc_pkey_generate_rsa()
# hal_rpc_pkey_get_public_key()
#
-# Load KEKEK public <---------------- Export KEKEK public
-#
-# hal_rpc_pkey_load()
-# hal_rpc_pkey_export()
+# Load KEKEK public <--------- Export KEKEK public
+# hal_rpc_pkey_load()
+# hal_rpc_pkey_export()
#
# Export PKCS #8 and KEK ----------> Load PKCS #8 and KEK, import key
-#
# hal_rpc_pkey_import()
import sys
@@ -27,42 +47,63 @@ from cryptech.libhal import *
def main():
parser = argparse.ArgumentParser(
- formatter_class = argparse.ArgumentDefaultsHelpFormatter,
+ formatter_class = argparse.RawDescriptionHelpFormatter,
description = __doc__)
subparsers = parser.add_subparsers(
title = "Commands (use \"--help\" after command name for help with individual commands)",
metavar = "")
+ setup_parser = defcmd(subparsers, cmd_setup)
+ export_parser = defcmd(subparsers, cmd_export)
+ import_parser = defcmd(subparsers, cmd_import)
+ setup_mutex_group = setup_parser.add_mutually_exclusive_group()
+
+
parser.add_argument(
"-p", "--pin",
- help = "wheel PIN")
-
- subparser = defcmd(subparsers, cmd_setup)
- group = subparser.add_mutually_exclusive_group()
- group.add_argument(
- "-n", "--new", action = "store_true",
- help = "force creation of new KEKEK")
- group.add_argument(
+ help = "wheel PIN")
+
+
+ setup_mutex_group.add_argument(
+ "-n", "--new",
+ action = "store_true",
+ help = "force creation of new KEKEK")
+
+ setup_mutex_group.add_argument(
"-u", "--uuid",
- help = "UUID of existing KEKEK to use")
- subparser.add_argument(
- "-k", "--keylen", type = int, default = 2048,
- help = "length of new KEKEK if we need to create one")
- subparser.add_argument(
- "-o", "--output", type = argparse.FileType("w"), default = "-",
- help = "output file")
-
- subparser = defcmd(subparsers, cmd_export)
- subparser.add_argument(
- "-i", "--input", type = argparse.FileType("r"), default = "-",
- help = "input file")
- subparser.add_argument(
- "-o", "--output", type = argparse.FileType("w"), default = "-",
- help = "output file")
-
- subparser = defcmd(subparsers, cmd_import)
- subparser.add_argument(
- "-i", "--input", type = argparse.FileType("r"), default = "-",
- help = "input file")
+ help = "UUID of existing KEKEK to use")
+
+ setup_parser.add_argument(
+ "-k", "--keylen",
+ type = int,
+ default = 2048,
+ help = "length of new KEKEK if we need to create one")
+
+ setup_parser.add_argument(
+ "-o", "--output",
+ type = argparse.FileType("w"),
+ default = "-",
+ help = "output file")
+
+
+ export_parser.add_argument(
+ "-i", "--input",
+ type = argparse.FileType("r"),
+ default = "-",
+ help = "input file")
+
+ export_parser.add_argument(
+ "-o", "--output",
+ type = argparse.FileType("w"),
+ default = "-",
+ help = "output file")
+
+
+ import_parser.add_argument(
+ "-i", "--input",
+ type = argparse.FileType("r"),
+ default = "-",
+ help = "input file")
+
args = parser.parse_args()
@@ -138,6 +179,7 @@ def cmd_setup(args, hsm):
result.update(comment = "KEKEK public key")
json.dump(result, args.output, indent = 4, sort_keys = True)
+ args.output.write("\n")
def key_flag_names(flags):
@@ -195,6 +237,7 @@ def cmd_export(args, hsm):
db.update(comment = "Cryptech Alpha encrypted key backup",
keys = result)
json.dump(db, args.output, indent = 4, sort_keys = True)
+ args.output.write("\n")
def cmd_import(args, hsm):