sscg/0005-Add-password-support-for-private-keys.patch

274 lines
7.6 KiB
Diff

From 7190d08e1a166455e767769492b8c6b9f41bc0da Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Wed, 5 Jun 2019 17:08:23 -0400
Subject: [PATCH 5/6] Add password support for private keys
Fixes: https://github.com/sgallagher/sscg/issues/14
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
---
include/sscg.h | 7 +++
src/sscg.c | 152 ++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 157 insertions(+), 2 deletions(-)
diff --git a/include/sscg.h b/include/sscg.h
index fc90b81a0060af28529f3be6922b1b1501559300..ce9a7916e9432d0843d82af61d56ea7238ded682 100644
--- a/include/sscg.h
+++ b/include/sscg.h
@@ -141,8 +141,15 @@ struct sscg_options
int key_strength;
int minimum_key_strength;
char *hash_alg;
+ char *cipher_alg;
+ const EVP_CIPHER *cipher;
const EVP_MD *hash_fn;
+ bool ca_key_pass_prompt;
+ char *ca_key_pass;
+ bool cert_key_pass_prompt;
+ char *cert_key_pass;
+
/* Output Files */
char *ca_file;
char *ca_key_file;
diff --git a/src/sscg.c b/src/sscg.c
index 58855f764480d24d6c0f57460b22a3a83281e37e..9dc926c77038105ca881a612cccd1913bc2d42f1 100644
--- a/src/sscg.c
+++ b/src/sscg.c
@@ -97,6 +97,9 @@ set_default_options (struct sscg_options *opts)
}
opts->minimum_key_strength = opts->key_strength;
+
+ opts->cipher_alg = talloc_strdup (opts, "aes-256-cbc");
+
return 0;
}
@@ -170,6 +173,42 @@ done:
return ret;
}
+
+/* This function takes a copy of a string into a talloc hierarchy and memsets
+ * the original string to zeroes to avoid leaking it when that memory is freed.
+ */
+static char *
+sscg_secure_string_steal (TALLOC_CTX *mem_ctx, char *src)
+{
+ char *dest = talloc_strdup (mem_ctx, src);
+
+ memset (src, 0, strlen (src));
+
+ return dest;
+}
+
+
+static int
+sscg_options_destructor (TALLOC_CTX *opts)
+{
+ struct sscg_options *options =
+ talloc_get_type_abort (opts, struct sscg_options);
+
+ /* Zero out the memory before freeing it so we don't leak passwords */
+ if (options->ca_key_pass)
+ {
+ memset (options->ca_key_pass, 0, strlen (options->ca_key_pass));
+ }
+
+ if (options->cert_key_pass)
+ {
+ memset (options->cert_key_pass, 0, strlen (options->cert_key_pass));
+ }
+
+ return 0;
+}
+
+
int
main (int argc, const char **argv)
{
@@ -196,8 +235,11 @@ main (int argc, const char **argv)
int ca_mode = 0644;
int ca_key_mode = 0600;
+ char *ca_key_password = NULL;
+
int cert_mode = 0644;
int cert_key_mode = 0600;
+ char *cert_key_password = NULL;
char *create_mode = NULL;
@@ -227,6 +269,7 @@ main (int argc, const char **argv)
options = talloc_zero (main_ctx, struct sscg_options);
CHECK_MEM (options);
+ talloc_set_destructor ((TALLOC_CTX *)options, sscg_options_destructor);
ret = set_default_options (options);
if (ret != EOK)
@@ -366,6 +409,16 @@ main (int argc, const char **argv)
_ ("Hashing algorithm to use for signing."),
_ ("{sha256,sha384,sha512}"),
},
+ {
+ "cipher-alg",
+ '\0',
+ POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT,
+ &options->cipher_alg,
+ 0,
+ _ ("Cipher to use for encrypting key files."),
+ _ ("{des-ede3-cbc,aes-256-cbc}"),
+ },
+
{
"ca-file",
'\0',
@@ -404,6 +457,29 @@ main (int argc, const char **argv)
_ ("File mode of the created CA key. (default: 0600)"),
_ ("0600"),
},
+ {
+ "ca-key-password",
+ '\0',
+ POPT_ARG_STRING,
+ &ca_key_password,
+ 0,
+ _ ("Provide a password for the CA key file. Note that this will be "
+ "visible in the process table for all users, so it should be used "
+ "for testing purposes only. Use --ca-keypassfile or "
+ "--ca-key-password-prompt for secure password entry."),
+ NULL
+ },
+
+ {
+ "ca-key-password-prompt",
+ 'C',
+ POPT_ARG_NONE,
+ &options->ca_key_pass_prompt,
+ 0,
+ _ ("Prompt to enter a password for the CA key file."),
+ NULL
+ },
+
{
"cert-file",
'\0',
@@ -442,6 +518,29 @@ main (int argc, const char **argv)
_ ("File mode of the created certificate key. (default: 0600)"),
_ ("0600"),
},
+ {
+ "cert-key-password",
+ 'p',
+ POPT_ARG_STRING,
+ &cert_key_password,
+ 0,
+ _ ("Provide a password for the service key file. Note that this will be "
+ "visible in the process table for all users, so this flag should be "
+ "used for testing purposes only. Use --cert-keypassfile or "
+ "--cert-key-password-prompt for secure password entry."),
+ NULL
+ },
+
+ {
+ "cert-key-password-prompt",
+ 'P',
+ POPT_ARG_NONE,
+ &options->cert_key_pass_prompt,
+ 0,
+ _ ("Prompt to enter a password for the service key file."),
+ NULL
+ },
+
POPT_TABLEEND
};
@@ -592,6 +691,20 @@ main (int argc, const char **argv)
}
}
+ /* Password handling */
+ if (ca_key_password)
+ {
+ options->ca_key_pass =
+ sscg_secure_string_steal (options, ca_key_password);
+ }
+
+ if (cert_key_password)
+ {
+ options->cert_key_pass =
+ sscg_secure_string_steal (options, cert_key_password);
+ }
+
+
if (options->key_strength < options->minimum_key_strength)
{
fprintf (stderr,
@@ -601,6 +714,15 @@ main (int argc, const char **argv)
goto done;
}
+ /* Make sure we have a valid cipher */
+ options->cipher = EVP_get_cipherbyname (options->cipher_alg);
+ if (!options->cipher)
+ {
+ fprintf (stderr, "Invalid cipher specified: %s\n", options->cipher_alg);
+ ret = EINVAL;
+ goto done;
+ }
+
/* TODO: restrict this to approved hashes.
* For now, we'll only list SHA[256|384|512] in the help */
options->hash_fn = EVP_get_digestbyname (options->hash_alg);
@@ -696,8 +818,21 @@ main (int argc, const char **argv)
cert_key_out = BIO_new_file (options->cert_key_file, create_mode);
CHECK_BIO (cert_key_out, options->cert_key_file);
+ /* This function has a default mechanism for prompting for the
+ * password if it is passed a cipher and gets a NULL password.
+ *
+ * Only pass the cipher if we have a password or were instructed
+ * to prompt for one.
+ */
sret = PEM_write_bio_PrivateKey (
- cert_key_out, svc_key->evp_pkey, NULL, NULL, 0, NULL, NULL);
+ cert_key_out,
+ svc_key->evp_pkey,
+ options->cert_key_pass_prompt || options->cert_key_pass ? options->cipher :
+ NULL,
+ (unsigned char *)options->cert_key_pass,
+ options->cert_key_pass ? strlen (options->cert_key_pass) : 0,
+ NULL,
+ NULL);
CHECK_SSL (sret, PEM_write_bio_PrivateKey (svc));
BIO_get_fp (cert_key_out, &fp);
@@ -776,8 +911,21 @@ main (int argc, const char **argv)
}
CHECK_BIO (ca_key_out, options->ca_key_file);
+ /* This function has a default mechanism for prompting for the
+ * password if it is passed a cipher and gets a NULL password.
+ *
+ * Only pass the cipher if we have a password or were instructed
+ * to prompt for one.
+ */
sret = PEM_write_bio_PrivateKey (
- ca_key_out, cakey->evp_pkey, NULL, NULL, 0, NULL, NULL);
+ ca_key_out,
+ cakey->evp_pkey,
+ options->ca_key_pass_prompt || options->ca_key_pass ? options->cipher :
+ NULL,
+ (unsigned char *)options->ca_key_pass,
+ options->ca_key_pass ? strlen (options->ca_key_pass) : 0,
+ NULL,
+ NULL);
CHECK_SSL (sret, PEM_write_bio_PrivateKey (CA));
BIO_get_fp (ca_key_out, &fp);
if (options->verbosity >= SSCG_DEBUG)
--
2.23.0