aboutsummaryrefslogtreecommitdiff
path: root/utils/pkey.c
diff options
context:
space:
mode:
authorPaul Selkirk <paul@psgd.org>2019-11-06 14:34:00 -0500
committerPaul Selkirk <paul@psgd.org>2019-11-06 14:34:00 -0500
commit323bc8ade3eae73174961bbf604257a1b099fe55 (patch)
tree1559cea03677438ca9a7cb0313b65aa0cfb8f7b5 /utils/pkey.c
parent9e6edd6082cc8d501e2b062983ed58b01ef677d7 (diff)
Export/import "raw" keys for external storage.
Exported keys are wrapped with the MKM KEK, not a transit KEK, and can only be imported back to the same HSM. The idea is to support operators who have more keys than will fit on the HSM, so they will cycle keys into and out of the HSM as needed. NOTE that hashsig is, as always, special. The hashsig key has an internal index that is updated on every signature. To prevent a hashsig key from being re-imported with an old index (which would compromise the security of the key), the hashsig key is disabled on export, and must be deleted from the HSM before being re-imported.
Diffstat (limited to 'utils/pkey.c')
-rw-r--r--utils/pkey.c104
1 files changed, 66 insertions, 38 deletions
diff --git a/utils/pkey.c b/utils/pkey.c
index 76c1bf7..efd360d 100644
--- a/utils/pkey.c
+++ b/utils/pkey.c
@@ -62,8 +62,8 @@
* list [-t type]
* sign [-h (hash)] [-k keyname] [-m msgfile] [-s sigfile] [-n iterations]
* verify [-h (hash)] [-k keyname] [-m msgfile] [-s sigfile]
- * export [-k keyname] [-K kekekfile] [-o outfile]
- * import [-K kekekfile] [-i infile] [-x (exportable)] [-v (volatile keystore)]
+ * export [-k keyname] [-r (raw) | -K kekekfile] [-o outfile]
+ * import [-r (raw) | -K kekekfile] [-i infile] [-x (exportable)] [-v (volatile keystore)]
* delete [-k keyname] ...
*/
@@ -166,7 +166,7 @@ static int file_write(const char * const fn, const void * const buf, const size_
if (fclose(fp) != 0)
lose("Error closing %s: %s\n", fn, strerror(errno));
- if (secret && chmod(fn, S_IRUSR) != 0)
+ if (secret && chmod(fn, S_IRUSR|S_IWUSR) != 0)
lose("Error chmod'ing %s: %s\n", fn, strerror(errno));
return 0;
@@ -799,6 +799,8 @@ done:
m, mlen, sig, &sig_len, sizeof(sig))) != HAL_OK) {
if (i > 0 && err == HAL_ERROR_HASHSIG_KEY_EXHAUSTED)
break;
+ else if (n == 1)
+ lose("Error signing: %s\n", hal_error_string(err));
else
lose("Error signing (%d): %s\n", i, hal_error_string(err));
}
@@ -923,14 +925,15 @@ fail:
static int pkey_export(int argc, char *argv[])
{
- char usage[] = "Usage: export [-k keyname] [-K kekekfile] [-o outfile]";
+ char usage[] = "Usage: export [-k keyname] [-r | -K kekekfile] [-o outfile]";
hal_pkey_handle_t kekek_handle = {HAL_HANDLE_NONE};
char *kekek_fn = NULL;
char *out_fn = NULL;
+ int raw = 0;
int opt;
- while ((opt = getopt(argc, argv, "-k:K:o:")) != -1) {
+ while ((opt = getopt(argc, argv, "-k:K:o:r")) != -1) {
switch (opt) {
case 1:
/* found the next command */
@@ -947,6 +950,9 @@ static int pkey_export(int argc, char *argv[])
case 'o':
out_fn = optarg;
break;
+ case 'r':
+ raw = 1;
+ break;
default:
puts(usage);
return -1;
@@ -960,7 +966,7 @@ done:
return -1;
}
- if (kekek_fn == NULL) {
+ if (!raw && kekek_fn == NULL) {
printf("export: missing kekek\n");
puts(usage);
return -1;
@@ -975,34 +981,43 @@ done:
out_fn = key_name;
}
- if (pkey_load(kekek_fn, &kekek_handle) != 0)
+ if (!raw && pkey_load(kekek_fn, &kekek_handle) != 0)
goto fail;
uint8_t der[HAL_KS_WRAPPED_KEYSIZE]; size_t der_len;
uint8_t kek[HAL_KS_WRAPPED_KEYSIZE]; size_t kek_len;
- if ((err = hal_rpc_pkey_export(key_handle, kekek_handle,
- der, &der_len, sizeof(der),
- kek, &kek_len, sizeof(kek))) != HAL_OK)
- lose("Error exporting private key: %s\n", hal_error_string(err));
+ if (!raw) {
+ if ((err = hal_rpc_pkey_export(key_handle, kekek_handle,
+ der, &der_len, sizeof(der),
+ kek, &kek_len, sizeof(kek))) != HAL_OK)
+ lose("Error exporting private key: %s\n", hal_error_string(err));
+ }
+ else {
+ if ((err = hal_rpc_pkey_export_raw(key_handle,
+ der, &der_len, sizeof(der))) != HAL_OK)
+ lose("Error exporting private key: %s\n", hal_error_string(err));
+ }
char fn[strlen(out_fn) + 5];
strcpy(fn, out_fn); strcat(fn, ".der");
if (file_write(fn, der, der_len, 1) != 0)
goto fail;
- strcpy(fn, out_fn); strcat(fn, ".kek");
- if (file_write(fn, kek, kek_len, 1) != 0)
- goto fail;
+ if (!raw) {
+ strcpy(fn, out_fn); strcat(fn, ".kek");
+ if (file_write(fn, kek, kek_len, 1) != 0)
+ goto fail;
- if ((err = hal_rpc_pkey_delete(kekek_handle)) != HAL_OK)
- lose("Could not delete key: %s\n", hal_error_string(err));
+ if ((err = hal_rpc_pkey_delete(kekek_handle)) != HAL_OK)
+ lose("Could not delete key: %s\n", hal_error_string(err));
+ }
}
return 0;
fail:
- if (kekek_handle.handle != HAL_HANDLE_NONE)
+ if (!raw && kekek_handle.handle != HAL_HANDLE_NONE)
(void)hal_rpc_pkey_delete(kekek_handle);
return -1;
@@ -1010,14 +1025,15 @@ fail:
static int pkey_import(int argc, char *argv[])
{
- char usage[] = "Usage: import [-K kekekfile] [-i infile] [-x (exportable)] [-v (volatile keystore)]";
+ char usage[] = "Usage: import [-r | -K kekekfile] [-i infile] [-x (exportable)] [-v (volatile keystore)]";
hal_pkey_handle_t kekek_handle = {HAL_HANDLE_NONE};
char *kekek_fn = NULL;
char *in_fn = NULL;
+ int raw = 0;
int opt;
- while ((opt = getopt(argc, argv, "-K:i:xv")) != -1) {
+ while ((opt = getopt(argc, argv, "-K:i:xvr")) != -1) {
switch (opt) {
case 1:
/* found the next command */
@@ -1036,6 +1052,9 @@ static int pkey_import(int argc, char *argv[])
case 'v':
flags &= ~HAL_KEY_FLAG_TOKEN;
break;
+ case 'r':
+ raw = 1;
+ break;
default:
puts(usage);
return -1;
@@ -1043,7 +1062,7 @@ static int pkey_import(int argc, char *argv[])
}
done:
- if (kekek_fn == NULL) {
+ if (!raw && kekek_fn == NULL) {
printf("export: missing kekek\n");
puts(usage);
return -1;
@@ -1055,10 +1074,11 @@ done:
return -1;
}
- if (pkey_load(kekek_fn, &kekek_handle) != 0)
+ if (!raw && pkey_load(kekek_fn, &kekek_handle) != 0)
goto fail;
{
+ hal_error_t err;
char fn[strlen(in_fn) + 5];
strcpy(fn, in_fn); strcat(fn, ".der");
size_t der_len = file_size(fn);
@@ -1068,36 +1088,44 @@ done:
if (file_read(fn, der, &der_len, sizeof(der)) != 0)
goto fail;
- strcpy(fn, in_fn); strcat(fn, ".kek");
- size_t kek_len = file_size(fn);
- if (kek_len == SIZE_MAX)
- goto fail;
- uint8_t kek[kek_len];
- if (file_read(fn, kek, &kek_len, sizeof(kek)) != 0)
- goto fail;
+ if (!raw) {
+ strcpy(fn, in_fn); strcat(fn, ".kek");
+ size_t kek_len = file_size(fn);
+ if (kek_len == SIZE_MAX)
+ goto fail;
+ uint8_t kek[kek_len];
+ if (file_read(fn, kek, &kek_len, sizeof(kek)) != 0)
+ goto fail;
- hal_error_t err;
- if ((err = hal_rpc_pkey_import(client, session,
- &key_handle, &key_uuid,
- kekek_handle,
- der, der_len,
- kek, kek_len,
- flags)) != HAL_OK)
- lose("Error importing private key: %s\n", hal_error_string(err));
+ if ((err = hal_rpc_pkey_import(client, session,
+ &key_handle, &key_uuid,
+ kekek_handle,
+ der, der_len,
+ kek, kek_len,
+ flags)) != HAL_OK)
+ lose("Error importing private key: %s\n", hal_error_string(err));
+ }
+ else {
+ if ((err = hal_rpc_pkey_import_raw(client, session,
+ &key_handle, &key_uuid,
+ der, der_len,
+ flags)) != HAL_OK)
+ lose("Error importing private key: %s\n", hal_error_string(err));
+ }
char name_str[HAL_UUID_TEXT_SIZE];
if ((err = hal_uuid_format(&key_uuid, name_str, sizeof(name_str))) != HAL_OK)
lose("Error formatting private key name: %s\n", hal_error_string(err));
printf("New private key name: %s\n", name_str);
- if ((err = hal_rpc_pkey_delete(kekek_handle)) != HAL_OK)
+ if (!raw && (err = hal_rpc_pkey_delete(kekek_handle)) != HAL_OK)
lose("Could not delete key: %s\n", hal_error_string(err));
}
return 0;
fail:
- if (kekek_handle.handle != HAL_HANDLE_NONE)
+ if (!raw && kekek_handle.handle != HAL_HANDLE_NONE)
(void)hal_rpc_pkey_delete(kekek_handle);
return -1;