import sscg-2.3.3-14.el8

This commit is contained in:
CentOS Sources 2020-04-23 23:10:57 +00:00 committed by Andrew Lukoshko
commit 51067783f2
13 changed files with 4826 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
SOURCES/sscg-2.3.3-stripped.tar.xz

1
.sscg.metadata Normal file
View File

@ -0,0 +1 @@
6e880fc36f7d1ebf4a9668dbcb9276b3afcb2904 SOURCES/sscg-2.3.3-stripped.tar.xz

View File

@ -0,0 +1,50 @@
From 71e2451c6ba4d5f17de9e24687b66b93f2e58954 Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Mon, 17 Sep 2018 09:58:25 -0400
Subject: [PATCH 1/6] Generate manpage
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
---
meson.build | 22 +++++++++++++++++++++-
1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/meson.build b/meson.build
index e6f33475cce6891d17656bcd10e1afabd43bdc07..a2ca4ba1472bfff61fbbd30ba1ddc7ecc89e723c 100644
--- a/meson.build
+++ b/meson.build
@@ -7,7 +7,7 @@ project('sscg', 'c',
'b_asneeded=true',
],
license : 'MIT',
- meson_version : '>=0.36.0')
+ meson_version : '>=0.40.0')
cc = meson.get_compiler('c')
test_cflags = [
@@ -141,3 +141,23 @@ configure_file(
output : 'config.h',
configuration : cdata)
+# Generate a manpage from the POPT documentation
+help2man = find_program('help2man')
+
+manpage = custom_target('manpage',
+ output : 'sscg.8',
+ capture : true,
+ command : [
+ help2man,
+ '-s', '8',
+ '-n', 'Tool for generating x.509 certificates',
+ '-N',
+ sscg,
+ ],
+ install : true,
+ build_by_default : true,
+ install_dir : join_paths(
+ get_option('prefix'),
+ get_option('mandir'),
+ 'man8'),
+)
--
2.23.0

View File

@ -0,0 +1,208 @@
From 942d9fa4f582a372af3d0bd499f073760dec2335 Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Tue, 27 Nov 2018 13:24:37 -0500
Subject: [PATCH 2/6] Adjust defaults based on system security level
Also permit arbitrary keylengths.
Disallow keylengths smaller than the configured system minimum.
Resolves: rhbz#1653323
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
---
config.h.in | 1 -
include/sscg.h | 1 +
meson.build | 10 ++++++--
src/sscg.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++----
4 files changed, 68 insertions(+), 8 deletions(-)
delete mode 100644 config.h.in
diff --git a/config.h.in b/config.h.in
deleted file mode 100644
index 6044a4355f6c8bfac8d36e533f48f395c597e5ac..0000000000000000000000000000000000000000
--- a/config.h.in
+++ /dev/null
@@ -1 +0,0 @@
-#define PACKAGE_VERSION "@version@"
diff --git a/include/sscg.h b/include/sscg.h
index 2bd42bbee965c754efb91febd10b6a94af6f508e..3e97cfe49a5cd8fc734ecf43a94156e376227eb7 100644
--- a/include/sscg.h
+++ b/include/sscg.h
@@ -139,6 +139,7 @@ struct sscg_options
/* Encryption requirements */
int key_strength;
+ int minimum_key_strength;
const EVP_MD *hash_fn;
/* Output Files */
diff --git a/meson.build b/meson.build
index a2ca4ba1472bfff61fbbd30ba1ddc7ecc89e723c..c7b08ed3d6dff686f08a90ca869ba5881a9e8aaa 100644
--- a/meson.build
+++ b/meson.build
@@ -34,6 +34,7 @@ endforeach
pkg = import('pkgconfig')
crypto = dependency('libcrypto')
+ssl = dependency('libssl')
path_utils = dependency('path_utils')
talloc = dependency('talloc')
@@ -49,6 +50,10 @@ else
popt_incdirs = include_directories('subprojects/popt')
endif
+has_get_sec_level = cc.has_function(
+ 'SSL_CTX_get_security_level',
+ dependencies: [ ssl])
+
sscg_lib_srcs = [
'src/authority.c',
'src/bignum.c',
@@ -70,6 +75,7 @@ sscg_lib = static_library(
sources : sscg_lib_srcs,
dependencies : [
crypto,
+ ssl,
talloc,
],
install : false,
@@ -135,9 +141,9 @@ init_bignum_test = executable(
test('init_bignum_test', init_bignum_test)
cdata = configuration_data()
-cdata.set('version', meson.project_version())
+cdata.set_quoted('PACKAGE_VERSION', meson.project_version())
+cdata.set('HAVE_SSL_CTX_GET_SECURITY_LEVEL', has_get_sec_level)
configure_file(
- input : 'config.h.in',
output : 'config.h',
configuration : cdata)
diff --git a/src/sscg.c b/src/sscg.c
index b2c7cbbfd9dc69d9f55a18bc91ed6023c0e64c2e..85a42404aa94524b560755d506b893300a4414cd 100644
--- a/src/sscg.c
+++ b/src/sscg.c
@@ -17,6 +17,7 @@
Copyright 2017 by Stephen Gallagher <sgallagh@redhat.com>
*/
+#define _GNU_SOURCE
#include <popt.h>
#include <stdlib.h>
#include <stdio.h>
@@ -25,6 +26,7 @@
#include <path_utils.h>
#include <unistd.h>
#include <openssl/evp.h>
+#include <openssl/ssl.h>
#include <sys/param.h>
#include "config.h"
@@ -32,11 +34,59 @@
#include "include/authority.h"
#include "include/service.h"
+static int
+get_security_level (void)
+{
+#ifdef HAVE_SSL_CTX_GET_SECURITY_LEVEL
+ SSL_CTX *ssl_ctx = SSL_CTX_new (TLS_method ());
+ int security_level = SSL_CTX_get_security_level (ssl_ctx);
+ SSL_CTX_free (ssl_ctx);
+ ssl_ctx = NULL;
+ return security_level;
+#else
+ return 0;
+#endif
+}
+
static int
set_default_options (struct sscg_options *opts)
{
+ int security_level = get_security_level ();
+
opts->lifetime = 3650;
- opts->key_strength = 2048;
+
+ /* Select the default key strength based on the system security level
+ * See:
+ * https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_get_security_level.html
+ * for the specification of the minimums.
+ */
+ switch (security_level)
+ {
+ case 0:
+ case 1:
+ case 2:
+ /* Security level 2 and below permits lower key-strengths, but SSCG
+ * will set a minimum of 2048 bits
+ */
+ opts->key_strength = 2048;
+ break;
+
+ case 3: opts->key_strength = 3072; break;
+
+ case 4: opts->key_strength = 7680; break;
+
+ default:
+ /* Unknown security level. Default to the highest we know about */
+ fprintf (stderr,
+ "Unknown system security level %d. Defaulting to highest-known "
+ "level.\n",
+ security_level);
+ /* Fall through */
+
+ case 5: opts->key_strength = 15360; break;
+ }
+
+ opts->minimum_key_strength = opts->key_strength;
return 0;
}
@@ -117,6 +167,7 @@ main (int argc, const char **argv)
size_t i;
poptContext pc;
struct sscg_options *options;
+ char *minimum_key_strength_help = NULL;
char *country = NULL;
char *state = NULL;
@@ -172,6 +223,9 @@ main (int argc, const char **argv)
if (ret != EOK)
goto done;
+ minimum_key_strength_help =
+ talloc_asprintf (main_ctx, "%d or larger", options->minimum_key_strength);
+
options->verbosity = SSCG_DEFAULT;
struct poptOption long_options[] = {
POPT_AUTOHELP{ "quiet",
@@ -293,7 +347,7 @@ main (int argc, const char **argv)
&options->key_strength,
0,
_ ("Strength of the certificate private keys in bits."),
- _ ("{512,1024,2048,4096}") },
+ minimum_key_strength_help },
{
"hash-alg",
'\0',
@@ -529,11 +583,11 @@ main (int argc, const char **argv)
}
}
- if (options->key_strength != 512 && options->key_strength != 1024 &&
- options->key_strength != 2048 && options->key_strength != 4096)
+ if (options->key_strength < options->minimum_key_strength)
{
fprintf (stderr,
- "Key strength must be one of {512, 1024, 2048, 4096}.\n");
+ "Key strength must be at least %d bits.\n",
+ options->minimum_key_strength);
ret = EINVAL;
goto done;
}
--
2.23.0

View File

@ -0,0 +1,115 @@
From 298015e8a7cf35cc0de581203b44826d2ae1d406 Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Wed, 28 Nov 2018 08:00:08 -0500
Subject: [PATCH 3/6] Adjust hash defaults based on system security level
Unlike the key-strength, this does not set a minimum level because
it's not a simple calculation. We will have to rely on libcrypto
rejecting any explicitly-set algorithms as a violation of policy.
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
---
include/sscg.h | 1 +
src/sscg.c | 40 +++++++++++++++++++++-------------------
2 files changed, 22 insertions(+), 19 deletions(-)
diff --git a/include/sscg.h b/include/sscg.h
index 3e97cfe49a5cd8fc734ecf43a94156e376227eb7..fc90b81a0060af28529f3be6922b1b1501559300 100644
--- a/include/sscg.h
+++ b/include/sscg.h
@@ -140,6 +140,7 @@ struct sscg_options
/* Encryption requirements */
int key_strength;
int minimum_key_strength;
+ char *hash_alg;
const EVP_MD *hash_fn;
/* Output Files */
diff --git a/src/sscg.c b/src/sscg.c
index 85a42404aa94524b560755d506b893300a4414cd..58855f764480d24d6c0f57460b22a3a83281e37e 100644
--- a/src/sscg.c
+++ b/src/sscg.c
@@ -66,14 +66,21 @@ set_default_options (struct sscg_options *opts)
case 1:
case 2:
/* Security level 2 and below permits lower key-strengths, but SSCG
- * will set a minimum of 2048 bits
+ * will set a minimum of 2048 bits and the sha256 hash algorithm.
*/
+ opts->hash_alg = talloc_strdup (opts, "sha256");
opts->key_strength = 2048;
break;
- case 3: opts->key_strength = 3072; break;
+ case 3:
+ opts->hash_alg = talloc_strdup (opts, "sha256");
+ opts->key_strength = 3072;
+ break;
- case 4: opts->key_strength = 7680; break;
+ case 4:
+ opts->hash_alg = talloc_strdup (opts, "sha384");
+ opts->key_strength = 7680;
+ break;
default:
/* Unknown security level. Default to the highest we know about */
@@ -83,7 +90,10 @@ set_default_options (struct sscg_options *opts)
security_level);
/* Fall through */
- case 5: opts->key_strength = 15360; break;
+ case 5:
+ opts->hash_alg = talloc_strdup (opts, "sha512");
+ opts->key_strength = 15360;
+ break;
}
opts->minimum_key_strength = opts->key_strength;
@@ -177,7 +187,6 @@ main (int argc, const char **argv)
char *email = NULL;
char *hostname = NULL;
char *packagename;
- char *hash_alg = NULL;
char **alternative_names = NULL;
char *ca_file = NULL;
@@ -351,10 +360,10 @@ main (int argc, const char **argv)
{
"hash-alg",
'\0',
- POPT_ARG_STRING,
- &hash_alg,
+ POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT,
+ &options->hash_alg,
0,
- _ ("Hashing algorithm to use for signing. (default: sha256)"),
+ _ ("Hashing algorithm to use for signing."),
_ ("{sha256,sha384,sha512}"),
},
{
@@ -592,17 +601,10 @@ main (int argc, const char **argv)
goto done;
}
- if (!hash_alg)
- {
- /* Default to SHA256 */
- options->hash_fn = EVP_sha256 ();
- }
- else
- {
- /* 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 (hash_alg);
- }
+ /* 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);
+
if (!options->hash_fn)
{
fprintf (stderr, "Unsupported hashing algorithm.");
--
2.23.0

View File

@ -0,0 +1,51 @@
From 9e4497d1dd2a337be1f69e0cfb24ce8080690ccf Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Wed, 28 Nov 2018 09:16:29 -0500
Subject: [PATCH 4/6] Properly check all return values
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
---
src/authority.c | 1 +
src/service.c | 1 +
src/x509.c | 1 +
3 files changed, 3 insertions(+)
diff --git a/src/authority.c b/src/authority.c
index b735868416b7fb5d016f0854baf0f27cd5f98b26..4e0dccc6c1210beffb38acd9f7dfb6108ca4a4ad 100644
--- a/src/authority.c
+++ b/src/authority.c
@@ -180,6 +180,7 @@ create_private_CA (TALLOC_CTX *mem_ctx,
/* Finalize the CSR */
ret = sscg_x509v3_csr_finalize (ca_certinfo, pkey, csr);
+ CHECK_OK (ret);
if (options->verbosity >= SSCG_DEBUG)
{
diff --git a/src/service.c b/src/service.c
index b292e94063f032fd3c34a8134702063ea46bfa0c..34c976dbe905528000b181c24d1fa95da3cd1377 100644
--- a/src/service.c
+++ b/src/service.c
@@ -126,6 +126,7 @@ create_service_cert (TALLOC_CTX *mem_ctx,
/* Finalize the CSR */
ret = sscg_x509v3_csr_finalize (svc_certinfo, pkey, csr);
+ CHECK_OK (ret);
if (options->verbosity >= SSCG_DEBUG)
{
diff --git a/src/x509.c b/src/x509.c
index 6d152fc969d745cc5cf085116c8688866f9d6ab4..18f0627bc64e7cb503a9e81c36dbe726186d1144 100644
--- a/src/x509.c
+++ b/src/x509.c
@@ -41,6 +41,7 @@ sscg_generate_serial (TALLOC_CTX *mem_ctx, struct sscg_bignum **serial)
}
ret = sscg_init_bignum (tmp_ctx, 0, &bn);
+ CHECK_OK (ret);
/* We'll create a random number of sizeof(unsigned long) - 1 bits
to use as the serial. We use unsigned long to ensure that it
--
2.23.0

View File

@ -0,0 +1,273 @@
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

View File

@ -0,0 +1,153 @@
From 9cb7daa54708dcf5e6500cd20ec7b1cc2f6f6350 Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Mon, 10 Jun 2019 10:15:42 -0400
Subject: [PATCH 6/6] Allow specifying keyfile password by file
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
---
src/sscg.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 84 insertions(+)
diff --git a/src/sscg.c b/src/sscg.c
index 9dc926c77038105ca881a612cccd1913bc2d42f1..a02e4df66c6cf9ec1865f425b4a15da82fbfdc72 100644
--- a/src/sscg.c
+++ b/src/sscg.c
@@ -34,6 +34,10 @@
#include "include/authority.h"
#include "include/service.h"
+
+/* Same as OpenSSL CLI */
+#define MAX_PW_LEN 1024
+
static int
get_security_level (void)
{
@@ -209,6 +213,44 @@ sscg_options_destructor (TALLOC_CTX *opts)
}
+static char *
+sscg_read_pw_file (TALLOC_CTX *mem_ctx, char *path)
+{
+ int i;
+ BIO *pwdbio = NULL;
+ char tpass[MAX_PW_LEN];
+ char *tmp = NULL;
+ char *password = NULL;
+
+ pwdbio = BIO_new_file (path, "r");
+ if (pwdbio == NULL)
+ {
+ fprintf (stderr, "Can't open file %s\n", path);
+ return NULL;
+ }
+
+ i = BIO_gets (pwdbio, tpass, MAX_PW_LEN);
+ BIO_free_all (pwdbio);
+ pwdbio = NULL;
+
+ if (i <= 0)
+ {
+ fprintf (stderr, "Error reading password from BIO\n");
+ return NULL;
+ }
+
+ tmp = strchr (tpass, '\n');
+ if (tmp != NULL)
+ *tmp = 0;
+
+ password = talloc_strdup (mem_ctx, tpass);
+
+ memset (tpass, 0, MAX_PW_LEN);
+
+ return password;
+}
+
+
int
main (int argc, const char **argv)
{
@@ -236,10 +278,12 @@ main (int argc, const char **argv)
int ca_mode = 0644;
int ca_key_mode = 0600;
char *ca_key_password = NULL;
+ char *ca_key_passfile = NULL;
int cert_mode = 0644;
int cert_key_mode = 0600;
char *cert_key_password = NULL;
+ char *cert_key_passfile = NULL;
char *create_mode = NULL;
@@ -470,6 +514,16 @@ main (int argc, const char **argv)
NULL
},
+ {
+ "ca-key-passfile",
+ '\0',
+ POPT_ARG_STRING,
+ &ca_key_passfile,
+ 0,
+ _ ("A file containing the password to encrypt the CA key file."),
+ NULL
+ },
+
{
"ca-key-password-prompt",
'C',
@@ -531,6 +585,16 @@ main (int argc, const char **argv)
NULL
},
+ {
+ "cert-key-passfile",
+ '\0',
+ POPT_ARG_STRING,
+ &cert_key_passfile,
+ 0,
+ _ ("A file containing the password to encrypt the service key file."),
+ NULL
+ },
+
{
"cert-key-password-prompt",
'P',
@@ -697,12 +761,32 @@ main (int argc, const char **argv)
options->ca_key_pass =
sscg_secure_string_steal (options, ca_key_password);
}
+ else if (ca_key_passfile)
+ {
+ options->ca_key_pass = sscg_read_pw_file (options, ca_key_passfile);
+ if (!options->ca_key_pass)
+ {
+ fprintf (
+ stderr, "Failed to read passphrase from %s", ca_key_passfile);
+ goto done;
+ }
+ }
if (cert_key_password)
{
options->cert_key_pass =
sscg_secure_string_steal (options, cert_key_password);
}
+ else if (cert_key_passfile)
+ {
+ options->cert_key_pass = sscg_read_pw_file (options, cert_key_passfile);
+ if (!options->cert_key_pass)
+ {
+ fprintf (
+ stderr, "Failed to read passphrase from %s", cert_key_passfile);
+ goto done;
+ }
+ }
if (options->key_strength < options->minimum_key_strength)
--
2.23.0

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,98 @@
From 8afa0ce578ecd5cc3a397707fdb163cc169b9bd1 Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Fri, 13 Dec 2019 08:25:01 -0500
Subject: [PATCH 8/8] Fix client-cert issues found by CI tests
Resolves: rhbz#1720667
Better error message for client certs without public key file
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
Fix memory leak in sscg_sign_x509_csr()
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
Address clang-analyzer warning
clang-analyzer determined that it was possible for the GET_BIO()
return value to have changed between conditional creation of the
client certificate and writing it out. This patch stores the result
of the lookup so it's certain to be consistent.
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
---
src/io_utils.c | 4 ++--
src/sscg.c | 8 +++++---
src/x509.c | 1 +
3 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/src/io_utils.c b/src/io_utils.c
index 809a1da0e455afa0dba0796a5f7ac406742328a1..a2502afb20f4bcb536428f3528900c2bb06997f5 100644
--- a/src/io_utils.c
+++ b/src/io_utils.c
@@ -363,8 +363,8 @@ sscg_io_utils_open_output_files (struct sscg_stream **streams, bool overwrite)
case IO_UTILS_CLIENT_UNMATCHED:
SSCG_ERROR (
- "The client certificate must have both public and private key "
- "locations specified.\n");
+ "The client certificate must have the public key location "
+ "specified.\n");
ret = EINVAL;
goto done;
diff --git a/src/sscg.c b/src/sscg.c
index 470af815d91f5170a1e8fe00006dbaee4d07b209..f34a43b83e562d0bd7da9a77e25911762db83693 100644
--- a/src/sscg.c
+++ b/src/sscg.c
@@ -300,6 +300,7 @@ main (int argc, const char **argv)
char *cert_key_password = NULL;
char *cert_key_passfile = NULL;
+ bool build_client_cert = false;
int client_mode = SSCG_CERT_DEFAULT_MODE;
int client_key_mode = SSCG_KEY_DEFAULT_MODE;
char *client_key_password = NULL;
@@ -1118,7 +1119,8 @@ main (int argc, const char **argv)
/* If requested, generate the client auth certificate and sign it with the
* private CA.
*/
- if (GET_BIO (SSCG_FILE_TYPE_CLIENT))
+ build_client_cert = !!(GET_BIO (SSCG_FILE_TYPE_CLIENT));
+ if (build_client_cert)
{
ret = create_cert (main_ctx,
options,
@@ -1136,7 +1138,7 @@ main (int argc, const char **argv)
/* Write private keys first */
- if (GET_BIO (SSCG_FILE_TYPE_CLIENT_KEY))
+ if (build_client_cert)
{
/* This function has a default mechanism for prompting for the
* password if it is passed a cipher and gets a NULL password.
@@ -1201,7 +1203,7 @@ main (int argc, const char **argv)
/* Public keys come next, in chain order */
/* Start with the client certificate */
- if (GET_BIO (SSCG_FILE_TYPE_CLIENT))
+ if (build_client_cert)
{
sret = PEM_write_bio_X509 (GET_BIO (SSCG_FILE_TYPE_CLIENT),
client_cert->certificate);
diff --git a/src/x509.c b/src/x509.c
index 18f0627bc64e7cb503a9e81c36dbe726186d1144..c173f539791fbbc51e52e6b121e587dca43924d4 100644
--- a/src/x509.c
+++ b/src/x509.c
@@ -482,5 +482,6 @@ done:
*_cert = talloc_steal (mem_ctx, scert);
}
X509_NAME_free (subject);
+ talloc_free(tmp_ctx);
return ret;
}
--
2.23.0

View File

@ -0,0 +1,36 @@
From fa6be1a9bbc8c5d42a248e398e3aac08078e311e Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Fri, 13 Dec 2019 11:51:43 -0500
Subject: [PATCH 9/9] Fix help message for --client-key-file
Resolves: rhbz#1720667
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
Further clarify --client-key-file help message
Resolves: rhbz#1720667
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
---
src/sscg.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/src/sscg.c b/src/sscg.c
index f34a43b83e562d0bd7da9a77e25911762db83693..4d009a67488e83c4332f58ee52f7d6ea72a8ddbd 100644
--- a/src/sscg.c
+++ b/src/sscg.c
@@ -734,9 +734,7 @@ main (int argc, const char **argv)
&client_key_file,
0,
_ ("Path where the client's private key will be stored. "
- "(default is client-file with a .key suffix, if "
- "--client-file was passed, otherwise this file will not "
- "be generated.)"),
+ "(default is the client-file)"),
NULL,
},
--
2.24.1

View File

@ -0,0 +1,920 @@
From 87530e9ebc872761c06506f3cb6a4fa5c494a614 Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Tue, 7 Jan 2020 14:32:01 -0500
Subject: [PATCH 10/10] Better validation of command line arguments
Check that key passphrases are within 4-1023 characters
OpenSSL CLI tools cannot handle files with passphrases outside this
range.
Resolves: rhbz#1784441
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
Output private keys with 2048 iteration count
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
Rework passphrase handling
Handle passphrases as part of the sscg_stream for a file. This will
allow us to check for relevance as well as reducing code duplication.
Resolves: rhbz#1784443
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
Fix wrong x509 version in CSR
This was, fortunately, not causing any problems because the signing
process resulted in the certificates being generated with the
correct version. It's best to be correct anyway.
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
Fix memory leaks
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
Fix alignment issue with popt
The boolean values need to be explicitly defined as int because
a bool may not be aligned properly. It was working prior to some
recent changes by lucky accident.
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
Prevent uninitialized read error
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
Add missing newline for error message
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
Fix OpenSSL 1.0 support
The symbol UI_F_UI_SET_RESULT changed to UI_F_UI_SET_RESULT_EX in
OpenSSL 1.1, but no other semantics changed that we care about.
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
Fix formatting
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
Fix missing error check
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
Read long password files properly
Long passphrase files may require more than a single call to BIO_read()
to gather the whole string.
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
---
include/io_utils.h | 37 ++++++-
include/key.h | 6 +-
include/sscg.h | 42 +++++---
include/x509.h | 6 +-
meson.build | 1 +
src/io_utils.c | 199 ++++++++++++++++++++++++++++++++++++-
src/sscg.c | 239 +++++++--------------------------------------
src/x509.c | 6 +-
8 files changed, 310 insertions(+), 226 deletions(-)
diff --git a/include/io_utils.h b/include/io_utils.h
index 6a89a476b3d982447b6603153c6765835cd67464..907097c7ff1f7ae3c3adf35d0dfba0f5763dc8c0 100644
--- a/include/io_utils.h
+++ b/include/io_utils.h
@@ -24,6 +24,7 @@
#include <stdbool.h>
#include <talloc.h>
+#include "include/key.h"
#include "include/sscg.h"
@@ -33,6 +34,9 @@ struct sscg_stream
char *path;
int mode;
int filetypes;
+
+ bool pass_prompt;
+ char *passphrase;
};
@@ -69,8 +73,6 @@ sscg_io_utils_get_path_by_type (struct sscg_stream **streams,
* @path: The path to the file on disk.
* @mode: The filesystem mode this file should have when written to disk.
* See chmod(1) for the possible values.
- * @overwrite: If true, replace any existing file at @normalized_path. If
- * false, opening will fail if it already exists and return an error.
*
* Prepares all output filenames to be opened. Files are not created until
* sscg_io_utils_open_output_files() is called.
@@ -82,9 +84,40 @@ sscg_io_utils_add_output_file (struct sscg_stream **streams,
int mode);
+/**
+ * sscg_io_utils_add_output_key:
+ * @streams: The array of streams from the sscg_options
+ * @filetype:
+ * @path: The path to the file on disk.
+ * @mode: The filesystem mode this file should have when written to disk.
+ * See chmod(1) for the possible values.
+ * @pass_prompt: Whether the user should be prompted to enter a passphrase
+ * interactively.
+ * @passphrase: The passphrase supplied at the command line.
+ * @passfile: The path to a file containing the passphrase.
+ *
+ * Prepares all output filenames to be opened. Files are not created until
+ * sscg_io_utils_open_output_files() is called.
+ */
+int
+sscg_io_utils_add_output_key (struct sscg_stream **streams,
+ enum sscg_file_type filetype,
+ const char *path,
+ int mode,
+ bool pass_prompt,
+ char *passphrase,
+ char *passfile);
+
+
int
sscg_io_utils_open_output_files (struct sscg_stream **streams, bool overwrite);
+int
+sscg_io_utils_write_privatekey (struct sscg_stream **streams,
+ enum sscg_file_type filetype,
+ struct sscg_evp_pkey *key,
+ struct sscg_options *options);
+
/* If this function fails, some of the output files may be left as 0400 */
int
sscg_io_utils_finalize_output_files (struct sscg_stream **streams);
diff --git a/include/key.h b/include/key.h
index ef871d6937e2fc805a445d6686263b023a38eaaa..4c32cad04950ee7fd75ec4144147eb919280c00a 100644
--- a/include/key.h
+++ b/include/key.h
@@ -17,15 +17,15 @@
Copyright 2017 by Stephen Gallagher <sgallagh@redhat.com>
*/
+#ifndef _SSCG_KEY_H
+#define _SSCG_KEY_H
+
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include "include/sscg.h"
#include "include/bignum.h"
-#ifndef _SSCG_KEY_H
-#define _SSCG_KEY_H
-
struct sscg_evp_pkey
{
EVP_PKEY *evp_pkey;
diff --git a/include/sscg.h b/include/sscg.h
index 2744404c25c68ed905ca621bb955e0c04b33ca81..96b78152ccc492deafbbc61eb98702562a8fe5e6 100644
--- a/include/sscg.h
+++ b/include/sscg.h
@@ -20,17 +20,18 @@
/* This is a master header file that should be included by all
sscg source files. */
+
+#ifndef _SSCG_H
+#define _SSCG_H
+
#include <errno.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
+#include <openssl/ui.h>
#include <stdbool.h>
#include <talloc.h>
#include <stdint.h>
-#include "include/io_utils.h"
-
-#ifndef _SSCG_H
-#define _SSCG_H
/* TODO: implement internationalization */
@@ -81,15 +82,34 @@
} \
while (0)
+/* The function changed in 1.1, but the library and reason names did not */
+#ifndef UI_F_UI_SET_RESULT_EX
+#define UI_F_UI_SET_RESULT_EX UI_F_UI_SET_RESULT
+#endif
+
#define CHECK_SSL(_sslret, _fn) \
do \
{ \
if (_sslret != 1) \
{ \
/* Get information about error from OpenSSL */ \
+ unsigned long _ssl_error = ERR_get_error (); \
+ if ((ERR_GET_LIB (_ssl_error) == ERR_LIB_UI) && \
+ (ERR_GET_FUNC (_ssl_error) == UI_F_UI_SET_RESULT_EX) && \
+ ((ERR_GET_REASON (_ssl_error) == UI_R_RESULT_TOO_LARGE) || \
+ (ERR_GET_REASON (_ssl_error) == UI_R_RESULT_TOO_SMALL))) \
+ { \
+ fprintf ( \
+ stderr, \
+ "Passphrases must be between %d and %d characters. \n", \
+ SSCG_MIN_KEY_PASS_LEN, \
+ SSCG_MAX_KEY_PASS_LEN); \
+ ret = EINVAL; \
+ goto done; \
+ } \
fprintf (stderr, \
"Error occurred in " #_fn ": [%s].\n", \
- ERR_error_string (ERR_get_error (), NULL)); \
+ ERR_error_string (_ssl_error, NULL)); \
ret = EIO; \
goto done; \
} \
@@ -223,12 +243,9 @@ struct sscg_options
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;
- bool client_key_pass_prompt;
- char *client_key_pass;
+ int ca_key_pass_prompt;
+ int cert_key_pass_prompt;
+ int client_key_pass_prompt;
/* Output Files */
struct sscg_stream **streams;
@@ -251,4 +268,7 @@ enum sscg_cert_type
SSCG_NUM_CERT_TYPES
};
+#define SSCG_MIN_KEY_PASS_LEN 4
+#define SSCG_MAX_KEY_PASS_LEN 1023
+
#endif /* _SSCG_H */
diff --git a/include/x509.h b/include/x509.h
index 865cd0018d3ea77915cd86349e333ae6f4de2af0..cc7e498d06c4d2e503d7d8748dfd5386f9ad0794 100644
--- a/include/x509.h
+++ b/include/x509.h
@@ -17,6 +17,9 @@
Copyright 2017 by Stephen Gallagher <sgallagh@redhat.com>
*/
+#ifndef _SSCG_X509_H
+#define _SSCG_X509_H
+
#include <openssl/x509.h>
#include <openssl/x509v3.h>
@@ -24,9 +27,6 @@
#include "include/bignum.h"
#include "include/key.h"
-#ifndef _SSCG_X509_H
-#define _SSCG_X509_H
-
struct sscg_cert_info
{
/* === Input Data === */
diff --git a/meson.build b/meson.build
index eb339ea8c768adab6d576736fbe476b83529e78d..3d8937ce73dc84f652f6fdad461a1468a532f0f2 100644
--- a/meson.build
+++ b/meson.build
@@ -76,6 +76,7 @@ sscg_lib_hdrs = [
'include/dhparams.h',
'include/io_utils.h',
'include/key.h',
+ 'include/sscg.h',
'include/x509.h',
]
diff --git a/src/io_utils.c b/src/io_utils.c
index a2502afb20f4bcb536428f3528900c2bb06997f5..1b8bc41c3849acbe4657ae14dfe55e3010957129 100644
--- a/src/io_utils.c
+++ b/src/io_utils.c
@@ -24,8 +24,14 @@
#include <talloc.h>
#include "include/io_utils.h"
+#include "include/key.h"
#include "include/sscg.h"
+
+/* Same as OpenSSL CLI */
+#define MAX_PW_LEN 1024
+
+
int
sscg_normalize_path (TALLOC_CTX *mem_ctx,
const char *path,
@@ -62,6 +68,12 @@ sscg_stream_destructor (TALLOC_CTX *ptr)
BIO_free (stream->bio);
+ /* Zero out the memory before freeing it so we don't leak passwords */
+ if (stream->passphrase)
+ {
+ memset (stream->passphrase, 0, strnlen (stream->passphrase, MAX_PW_LEN));
+ }
+
return 0;
}
@@ -147,11 +159,101 @@ sscg_io_utils_get_path_by_type (struct sscg_stream **streams,
}
+/* 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 ((void *)src, 0, strlen (src));
+
+ return dest;
+}
+
+
+static int
+validate_passphrase (struct sscg_stream *stream)
+{
+ /* Ignore non-key types */
+ if (!(stream->filetypes & SSCG_FILE_TYPE_KEYS))
+ return EOK;
+
+ /* Ignore unset passwords; these will be prompted for when writing out the
+ * key file
+ */
+ if (!stream->passphrase)
+ return EOK;
+
+ size_t pass_len = strnlen (stream->passphrase, SSCG_MAX_KEY_PASS_LEN + 1);
+
+ if ((pass_len < SSCG_MIN_KEY_PASS_LEN) || (pass_len > SSCG_MAX_KEY_PASS_LEN))
+ {
+ SSCG_ERROR ("Passphrases must be between %d and %d characters. \n",
+ SSCG_MIN_KEY_PASS_LEN,
+ SSCG_MAX_KEY_PASS_LEN);
+ return EINVAL;
+ }
+ return EOK;
+}
+
+
+static char *
+sscg_read_pw_file (TALLOC_CTX *mem_ctx, char *path)
+{
+ int i;
+ BIO *pwdbio = NULL;
+ char tpass[MAX_PW_LEN + 1];
+ int offset = 0;
+ char *tmp = NULL;
+ char *password = NULL;
+
+ pwdbio = BIO_new_file (path, "r");
+ if (pwdbio == NULL)
+ {
+ fprintf (stderr, "Can't open file %s\n", path);
+ return NULL;
+ }
+
+ /* Read up to one more character than the MAX_PW_LEN */
+ for (offset = 0;
+ (i = BIO_read (pwdbio, tpass + offset, MAX_PW_LEN + 1 - offset)) > 0 &&
+ offset < (MAX_PW_LEN + 1);
+ offset += i)
+ ;
+
+ tpass[MAX_PW_LEN] = '\0';
+
+ BIO_free_all (pwdbio);
+ pwdbio = NULL;
+
+ if (i < 0)
+ {
+ fprintf (stderr, "Error reading password from BIO\n");
+ return NULL;
+ }
+
+ tmp = strchr (tpass, '\n');
+ if (tmp != NULL)
+ *tmp = 0;
+
+ password = talloc_strdup (mem_ctx, tpass);
+
+ memset (tpass, 0, MAX_PW_LEN + 1);
+
+ return password;
+}
+
+
int
-sscg_io_utils_add_output_file (struct sscg_stream **streams,
- enum sscg_file_type filetype,
- const char *path,
- int mode)
+sscg_io_utils_add_output_key (struct sscg_stream **streams,
+ enum sscg_file_type filetype,
+ const char *path,
+ int mode,
+ bool pass_prompt,
+ char *passphrase,
+ char *passfile)
{
int ret, i;
TALLOC_CTX *tmp_ctx = NULL;
@@ -163,6 +265,22 @@ sscg_io_utils_add_output_file (struct sscg_stream **streams,
*/
if (path == NULL)
{
+ if (pass_prompt)
+ {
+ SSCG_ERROR (
+ "Passphrase prompt requested for %s, but no file path provided.\n",
+ sscg_get_file_type_name (filetype));
+ return EINVAL;
+ }
+
+ if (passphrase)
+ {
+ SSCG_ERROR (
+ "Passphrase provided for %s, but no file path provided.\n",
+ sscg_get_file_type_name (filetype));
+ return EINVAL;
+ }
+
SSCG_LOG (SSCG_DEBUG,
"Got a NULL path with filetype: %s\n",
sscg_get_file_type_name (filetype));
@@ -220,6 +338,31 @@ sscg_io_utils_add_output_file (struct sscg_stream **streams,
/* Add the file type */
stream->filetypes |= (1 << filetype);
+
+ /* Set the password options */
+ stream->pass_prompt = pass_prompt;
+
+ if (passphrase)
+ {
+ stream->passphrase = sscg_secure_string_steal (stream, passphrase);
+ ret = validate_passphrase (stream);
+ if (ret != EOK)
+ goto done;
+ }
+ else if (passfile)
+ {
+ stream->passphrase = sscg_read_pw_file (stream, passfile);
+ if (!stream->passphrase)
+ {
+ fprintf (stderr, "Failed to read passphrase from %s", passfile);
+ ret = EIO;
+ goto done;
+ }
+ }
+ ret = validate_passphrase (stream);
+ if (ret != EOK)
+ goto done;
+
ret = EOK;
done:
@@ -228,6 +371,17 @@ done:
}
+int
+sscg_io_utils_add_output_file (struct sscg_stream **streams,
+ enum sscg_file_type filetype,
+ const char *path,
+ int mode)
+{
+ return sscg_io_utils_add_output_key (
+ streams, filetype, path, mode, false, NULL, NULL);
+}
+
+
enum io_utils_errors
{
IO_UTILS_OK = 0,
@@ -400,6 +554,43 @@ done:
}
+int
+sscg_io_utils_write_privatekey (struct sscg_stream **streams,
+ enum sscg_file_type filetype,
+ struct sscg_evp_pkey *key,
+ struct sscg_options *options)
+{
+ int ret, sret;
+
+ struct sscg_stream *stream =
+ sscg_io_utils_get_stream_by_type (streams, filetype);
+ if (stream)
+ {
+ /* 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_PKCS8PrivateKey (
+ stream->bio,
+ key->evp_pkey,
+ stream->pass_prompt || stream->passphrase ? options->cipher : NULL,
+ stream->passphrase,
+ stream->passphrase ? strlen (stream->passphrase) : 0,
+ NULL,
+ NULL);
+ CHECK_SSL (sret, PEM_write_bio_PKCS8PrivateKey);
+ ANNOUNCE_WRITE (filetype);
+ }
+
+ ret = EOK;
+
+done:
+ return ret;
+}
+
+
int
sscg_io_utils_finalize_output_files (struct sscg_stream **streams)
{
diff --git a/src/sscg.c b/src/sscg.c
index 4d009a67488e83c4332f58ee52f7d6ea72a8ddbd..96a9be1232d890590e97c126f8f4a78d571d7247 100644
--- a/src/sscg.c
+++ b/src/sscg.c
@@ -18,6 +18,7 @@
*/
#define _GNU_SOURCE
+#include <assert.h>
#include <popt.h>
#include <stdlib.h>
#include <stdio.h>
@@ -40,9 +41,6 @@
int verbosity;
-/* Same as OpenSSL CLI */
-#define MAX_PW_LEN 1024
-
static int
get_security_level (void)
{
@@ -140,79 +138,6 @@ print_options (struct sscg_options *opts)
}
-/* 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;
-}
-
-
-static char *
-sscg_read_pw_file (TALLOC_CTX *mem_ctx, char *path)
-{
- int i;
- BIO *pwdbio = NULL;
- char tpass[MAX_PW_LEN];
- char *tmp = NULL;
- char *password = NULL;
-
- pwdbio = BIO_new_file (path, "r");
- if (pwdbio == NULL)
- {
- fprintf (stderr, "Can't open file %s\n", path);
- return NULL;
- }
-
- i = BIO_gets (pwdbio, tpass, MAX_PW_LEN);
- BIO_free_all (pwdbio);
- pwdbio = NULL;
-
- if (i <= 0)
- {
- fprintf (stderr, "Error reading password from BIO\n");
- return NULL;
- }
-
- tmp = strchr (tpass, '\n');
- if (tmp != NULL)
- *tmp = 0;
-
- password = talloc_strdup (mem_ctx, tpass);
-
- memset (tpass, 0, MAX_PW_LEN);
-
- return password;
-}
-
-
const char *
sscg_get_verbosity_name (enum sscg_verbosity type)
{
@@ -310,12 +235,14 @@ main (int argc, const char **argv)
struct sscg_evp_pkey *cakey;
struct sscg_x509_cert *svc_cert;
struct sscg_evp_pkey *svc_key;
- struct sscg_x509_cert *client_cert;
- struct sscg_evp_pkey *client_key;
+ struct sscg_x509_cert *client_cert = NULL;
+ struct sscg_evp_pkey *client_key = NULL;
int dhparams_mode = SSCG_CERT_DEFAULT_MODE;
struct sscg_dhparams *dhparams = NULL;
+ struct sscg_stream *stream = NULL;
+
/* Always use umask 0577 for generating certificates and keys
This means that it's opened as write-only by the effective
user. */
@@ -335,7 +262,6 @@ 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);
options->streams =
talloc_zero_array (options, struct sscg_stream *, SSCG_NUM_FILE_TYPES);
@@ -965,56 +891,6 @@ main (int argc, const char **argv)
}
}
- /* Password handling */
- if (ca_key_password)
- {
- options->ca_key_pass =
- sscg_secure_string_steal (options, ca_key_password);
- }
- else if (ca_key_passfile)
- {
- options->ca_key_pass = sscg_read_pw_file (options, ca_key_passfile);
- if (!options->ca_key_pass)
- {
- fprintf (
- stderr, "Failed to read passphrase from %s", ca_key_passfile);
- goto done;
- }
- }
-
- if (cert_key_password)
- {
- options->cert_key_pass =
- sscg_secure_string_steal (options, cert_key_password);
- }
- else if (cert_key_passfile)
- {
- options->cert_key_pass = sscg_read_pw_file (options, cert_key_passfile);
- if (!options->cert_key_pass)
- {
- fprintf (
- stderr, "Failed to read passphrase from %s", cert_key_passfile);
- goto done;
- }
- }
-
- if (client_key_password)
- {
- options->client_key_pass =
- sscg_secure_string_steal (options, client_key_password);
- }
- else if (client_key_passfile)
- {
- options->client_key_pass =
- sscg_read_pw_file (options, client_key_passfile);
- if (!options->client_key_pass)
- {
- fprintf (
- stderr, "Failed to read passphrase from %s", client_key_passfile);
- goto done;
- }
- }
-
if (options->key_strength < options->minimum_key_strength)
{
fprintf (stderr,
@@ -1055,8 +931,13 @@ main (int argc, const char **argv)
ca_mode);
CHECK_OK (ret);
- ret = sscg_io_utils_add_output_file (
- options->streams, SSCG_FILE_TYPE_CA_KEY, ca_key_file, ca_key_mode);
+ ret = sscg_io_utils_add_output_key (options->streams,
+ SSCG_FILE_TYPE_CA_KEY,
+ ca_key_file,
+ ca_key_mode,
+ options->ca_key_pass_prompt,
+ ca_key_password,
+ ca_key_passfile);
CHECK_OK (ret);
ret = sscg_io_utils_add_output_file (options->streams,
@@ -1065,11 +946,14 @@ main (int argc, const char **argv)
cert_mode);
CHECK_OK (ret);
- ret = sscg_io_utils_add_output_file (options->streams,
- SSCG_FILE_TYPE_SVC_KEY,
- cert_key_file ? cert_key_file :
- "./service-key.pem",
- cert_key_mode);
+ ret = sscg_io_utils_add_output_key (options->streams,
+ SSCG_FILE_TYPE_SVC_KEY,
+ cert_key_file ? cert_key_file :
+ "./service-key.pem",
+ cert_key_mode,
+ options->cert_key_pass_prompt,
+ cert_key_password,
+ cert_key_passfile);
CHECK_OK (ret);
@@ -1078,11 +962,14 @@ main (int argc, const char **argv)
CHECK_OK (ret);
- ret = sscg_io_utils_add_output_file (options->streams,
- SSCG_FILE_TYPE_CLIENT_KEY,
- client_key_file ? client_key_file :
- client_file,
- client_key_mode);
+ ret = sscg_io_utils_add_output_key (options->streams,
+ SSCG_FILE_TYPE_CLIENT_KEY,
+ client_key_file ? client_key_file :
+ client_file,
+ client_key_mode,
+ options->client_key_pass_prompt,
+ client_key_password,
+ client_key_passfile);
CHECK_OK (ret);
ret = sscg_io_utils_add_output_file (
@@ -1136,67 +1023,17 @@ main (int argc, const char **argv)
/* Write private keys first */
- if (build_client_cert)
- {
- /* 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 (
- GET_BIO (SSCG_FILE_TYPE_CLIENT_KEY),
- client_key->evp_pkey,
- options->client_key_pass_prompt || options->client_key_pass ?
- options->cipher :
- NULL,
- (unsigned char *)options->client_key_pass,
- options->client_key_pass ? strlen (options->client_key_pass) : 0,
- NULL,
- NULL);
- CHECK_SSL (sret, PEM_write_bio_PrivateKey (svc));
- ANNOUNCE_WRITE (SSCG_FILE_TYPE_SVC_KEY);
- }
+ ret = sscg_io_utils_write_privatekey (
+ options->streams, SSCG_FILE_TYPE_CLIENT_KEY, client_key, options);
+ CHECK_OK (ret);
- /* 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 (
- GET_BIO (SSCG_FILE_TYPE_SVC_KEY),
- 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));
- ANNOUNCE_WRITE (SSCG_FILE_TYPE_SVC_KEY);
+ ret = sscg_io_utils_write_privatekey (
+ options->streams, SSCG_FILE_TYPE_SVC_KEY, svc_key, options);
+ CHECK_OK (ret);
- /* Create CA private key, if requested */
- if (GET_BIO (SSCG_FILE_TYPE_CA_KEY))
- {
- /* 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 (
- GET_BIO (SSCG_FILE_TYPE_CA_KEY),
- 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));
- ANNOUNCE_WRITE (SSCG_FILE_TYPE_CA_KEY);
- }
+ ret = sscg_io_utils_write_privatekey (
+ options->streams, SSCG_FILE_TYPE_CA_KEY, cakey, options);
+ CHECK_OK (ret);
/* Public keys come next, in chain order */
@@ -1217,7 +1054,7 @@ main (int argc, const char **argv)
/* Create CA public certificate */
- struct sscg_stream *stream =
+ stream =
sscg_io_utils_get_stream_by_type (options->streams, SSCG_FILE_TYPE_CA);
sret = PEM_write_bio_X509 (stream->bio, cacert->certificate);
CHECK_SSL (sret, PEM_write_bio_X509 (CA));
diff --git a/src/x509.c b/src/x509.c
index c173f539791fbbc51e52e6b121e587dca43924d4..42315d42d1e03460a8121e1592d8e7fcc0fef1df 100644
--- a/src/x509.c
+++ b/src/x509.c
@@ -72,7 +72,7 @@ _sscg_certinfo_destructor (TALLOC_CTX *ctx)
struct sscg_cert_info *certinfo =
talloc_get_type_abort (ctx, struct sscg_cert_info);
- sk_X509_EXTENSION_free (certinfo->extensions);
+ sk_X509_EXTENSION_pop_free (certinfo->extensions, X509_EXTENSION_free);
return 0;
}
@@ -155,7 +155,7 @@ sscg_x509v3_csr_new (TALLOC_CTX *mem_ctx,
talloc_set_destructor ((TALLOC_CTX *)csr, _sscg_csr_destructor);
/* We will generate only x509v3 certificates */
- sslret = X509_REQ_set_version (csr->x509_req, 3);
+ sslret = X509_REQ_set_version (csr->x509_req, 2);
CHECK_SSL (sslret, X509_REQ_set_version);
subject = X509_REQ_get_subject_name (csr->x509_req);
@@ -461,6 +461,8 @@ sscg_sign_x509_csr (TALLOC_CTX *mem_ctx,
}
sslret = X509_add_ext (cert, ext, -1);
CHECK_SSL (sslret, X509_add_ext);
+
+ X509_EXTENSION_free (ext);
}
/* Sign the new certificate */
--
2.24.1

269
SPECS/sscg.spec Normal file
View File

@ -0,0 +1,269 @@
%global provider github
%global provider_tld com
%global project sgallagher
%global repo sscg
# https://github.com/sgallagher/sscg
%global provider_prefix %{provider}.%{provider_tld}/%{project}/%{repo}
%global import_path %{provider_prefix}
Name: sscg
Version: 2.3.3
Release: 14%{?dist}
Summary: Simple SSL certificate generator
License: BSD
URL: https://%{provider_prefix}
# Run ./sscg-strip.sh to produce a tarball with the bundled popt library
# stripped out to reduce license issues.
Source0: https://%{provider_prefix}/releases/download/%{repo}-%{version}/%{repo}-%{version}-stripped.tar.xz
BuildRequires: gcc
BuildRequires: libtalloc-devel
BuildRequires: openssl-devel
BuildRequires: popt-devel
BuildRequires: libpath_utils-devel
BuildRequires: meson
BuildRequires: ninja-build
BuildRequires: help2man
# Patches
Patch0001: 0001-Generate-manpage.patch
Patch0002: 0002-Adjust-defaults-based-on-system-security-level.patch
Patch0003: 0003-Adjust-hash-defaults-based-on-system-security-level.patch
Patch0004: 0004-Properly-check-all-return-values.patch
# RHBZ #1717880
Patch0005: 0005-Add-password-support-for-private-keys.patch
Patch0006: 0006-Allow-specifying-keyfile-password-by-file.patch
# RHBZ #1720667
Patch0007: 0007-Add-support-for-client-certificates-and-dhparams.patch
Patch0008: 0008-Fix-client-cert-issues-found-by-CI-tests.patch
Patch0009: 0009-Fix-help-message-for-client-key-file.patch
# RHBZ #1784441 and 1784443
Patch0010: 0010-Better-validation-of-command-line-arguments.patch
%description
A utility to aid in the creation of more secure "self-signed"
certificates. The certificates created by this tool are generated in a
way so as to create a CA certificate that can be safely imported into a
client machine to trust the service certificate without needing to set
up a full PKI environment and without exposing the machine to a risk of
false signatures from the service certificate.
%prep
%autosetup -p1
%build
%meson
%meson_build
%install
%meson_install
%check
%ifnarch %{arm}
%meson_test
%endif
%files
%license COPYING
%doc README.md
%{_bindir}/%{name}
%{_mandir}/man8/%{name}.8*
%changelog
* Tue Jan 21 2020 Stephen Gallagher <sgallagh@redhat.com> - 2.3.3-14
- Properly handling reading long passphrase files.
* Tue Jan 21 2020 Stephen Gallagher <sgallagh@redhat.com> - 2.3.3-13
- Fix missing error check for --*-key-passfile
* Thu Jan 09 2020 Stephen Gallagher <sgallagh@redhat.com> - 2.3.3-12
- Improve validation of command-line arguments
- Resolves: rhbz#1784441
- Resolves: rhbz#1784443
* Tue Jan 07 2020 Stephen Gallagher <sgallagh@redhat.com> - 2.3.3-11
- Further improve --client-key-file help message
- Resolves: rhbz#1720667
* Fri Dec 13 2019 Stephen Gallagher <sgallagh@redhat.com> - 2.3.3-10
- Fix incorrect help message
- Resolves: rhbz#1720667
* Fri Dec 13 2019 Stephen Gallagher <sgallagh@redhat.com> - 2.3.3-9
- Fix null-dereference and memory leak issues with client certs
- Resolves: rhbz#1720667
* Wed Dec 11 2019 Stephen Gallagher <sgallagh@redhat.com> - 2.3.3-8
- Add support for generating client authentication certificates
- Resolves: rhbz#1720667
* Fri Nov 01 2019 Stephen Gallagher <sgallagh@redhat.com> - 2.3.3-7
- Add support for password-protecting the private key files
- Resolves: rhbz#1717880
* Wed Nov 28 2018 Stephen Gallagher <sgallagh@redhat.com> - 2.3.3-6
- Fixes for issues detected by automated testing.
- Resolves: rhbz#1653323
* Wed Nov 28 2018 Stephen Gallagher <sgallagh@redhat.com> - 2.3.3-5
- Autodetect the minimum key strength from the system security level.
- Autodetect the hash algorithm to use from the system security level.
- Disallow setting a key strength below the system minimum.
- Resolves: rhbz#1653323
* Mon Sep 17 2018 Stephen Gallagher <sgallagh@redhat.com> - 2.3.3-4
- Add a manpage for sscg.
* Thu Jul 05 2018 Stephen Gallagher <sgallagh@redhat.com> - 2.3.3-3
- Strip out bundled popt since RHEL 8 has a new-enough version.
* Fri Feb 09 2018 Fedora Release Engineering <releng@fedoraproject.org> - 2.3.3-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild
* Fri Feb 02 2018 Stephen Gallagher <sgallagh@redhat.com> - 2.3.3-1
- Update to 2.3.3
- Do not overwrite destination files without --force
* Thu Jan 25 2018 Stephen Gallagher <sgallagh@redhat.com> - 2.3.2-1
- Update to 2.3.2
- Properly support hostnames up to 64 characters
- Resolves: rhbz#1535537
* Tue Jan 02 2018 Stephen Gallagher <sgallagh@redhat.com> - 2.3.1-2
- Skip tests on 32-bit ARM for now
* Tue Jan 02 2018 Stephen Gallagher <sgallagh@redhat.com> - 2.3.1-1
- Update to 2.3.1
- Bundle popt 1.16 on older releases like EPEL.
* Mon Dec 18 2017 Stephen Gallagher <sgallagh@redhat.com> - 2.3.0-1
- Update to 2.3.0
- Switch to meson build system
- Add support for non-DNS subjectAlternativeName values (issue #4)
* Thu Sep 21 2017 Stephen Gallagher <sgallagh@redhat.com> - 2.2.0-1
- Reorder combined PEM file
- Resolves: RHBZ#1494208
* Wed Sep 20 2017 Stephen Gallagher <sgallagh@redhat.com> - 2.1.0-1
- Add --email argument for setting emailAddress in the issuer
* Thu Aug 03 2017 Fedora Release Engineering <releng@fedoraproject.org> - 2.0.4-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild
* Thu Jul 27 2017 Fedora Release Engineering <releng@fedoraproject.org> - 2.0.4-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild
* Mon Apr 03 2017 Stephen Gallagher <sgallagh@redhat.com> - 2.0.4-2
- Bump release to perform taskotron tests
* Tue Mar 21 2017 Stephen Gallagher <sgallagh@redhat.com> - 2.0.4-1
- Update to 2.0.4
- Addresses a potential race-condition when the key and certificate share the
same file.
* Wed Mar 08 2017 Stephen Gallagher <sgallagh@redhat.com> - 2.0.3-1
- Update to 2.0.3
- Adds support for setting the file mode on the output certificates
and keys.
* Fri Mar 03 2017 Stephen Gallagher <sgallagh@redhat.com> - 2.0.2-1
- Update to 2.0.2
- Always run with umask(077)
* Fri Mar 03 2017 Stephen Gallagher <sgallagh@redhat.com> - 2.0.1-1
- Update to 2.0.1
- Fix an issue with passing certificate lifetime explicitly
* Thu Feb 16 2017 Stephen Gallagher <sgallagh@redhat.com> - 2.0.0-1
- Update to 2.0.0
* Thu Feb 16 2017 Stephen Gallagher <sgallagh@redhat.com> - 1.1.0-6
- Exclude PPC64 from the build since it doesn't support linking to OpenSSL
* Sat Feb 11 2017 Fedora Release Engineering <releng@fedoraproject.org> - 1.1.0-5
- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild
* Wed Nov 23 2016 Stephen Gallagher <sgallagh@redhat.com> - 1.1.0-4
- Use compat-openssl10-devel on F26+
* Thu Jul 21 2016 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.1.0-3
- https://fedoraproject.org/wiki/Changes/golang1.7
* Tue May 31 2016 Stephen Gallagher <sgallagh@redhat.com> - 1.1.0-2
- Debundle spacelog
* Wed May 25 2016 Stephen Gallagher <sgallagh@redhat.com> - 1.1.0-1
- Update to 1.1.0
- Add support for signing service keys with an existing CA
* Wed May 25 2016 Stephen Gallagher <sgallagh@redhat.com> - 1.0.4-1
- Add support for exporting the CA private key
- Fix incorrect output from -version
- Add README.md
* Tue May 24 2016 Stephen Gallagher <sgallagh@redhat.com> - 1.0.3-1
- Only sign certificates after all extensions have been added
* Mon May 23 2016 Stephen Gallagher <sgallagh@redhat.com> - 1.0.2-1
- Generate x509v3 certificates
* Mon May 23 2016 Stephen Gallagher <sgallagh@redhat.com> - 1.0.1-1
- Fix issue with temporary file creation
* Mon May 23 2016 Stephen Gallagher <sgallagh@redhat.com> - 1.0.0-1
- New upstream release 1.0.0
- Rewritten in Go
- Runtime depends only on OpenSSL, no more Python
- Support for writing certificate and key in a single file
* Wed May 18 2016 Stephen Gallagher <sgallagh@redhat.com> - 0.4.1-4
- Add requirement on python-setuptools
* Fri Feb 05 2016 Fedora Release Engineering <releng@fedoraproject.org> - 0.4.1-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild
* Tue Nov 10 2015 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.4.1-2
- Rebuilt for https://fedoraproject.org/wiki/Changes/python3.5
* Fri Jun 19 2015 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.4.1-1
- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild
* Mon Mar 30 2015 Stephen Gallagher <sgallagh@redhat.com> 0.4.1-1
- Change default CA location to match service certificate
- Improve error handling
* Tue Mar 24 2015 Stephen Gallagher <sgallagh@redhat.com> 0.4.0-1
- Spec file cleanups
- PEP8 Cleanups
- Make location arguments optional
* Mon Mar 23 2015 Stephen Gallagher <sgallagh@redhat.com> 0.3.0-1
- Rename to sscg
- Only build with default python interpreter
* Tue Mar 17 2015 Stephen Gallagher <sgallagh@redhat.com> 0.2.1-1
- Include the LICENSE file in the tarball
* Tue Mar 17 2015 Stephen Gallagher <sgallagh@redhat.com> 0.2-2
- Include the license in the build RPMs
* Tue Mar 17 2015 Stephen Gallagher <sgallagh@redhat.com> 0.2-1
- Add support for namedConstraints
- Add support for subjectAltNames
- Fix packaging issues from Fedora package review
* Mon Mar 16 2015 Stephen Gallagher <sgallagh@redhat.com> 0.1-2
- Update BuildRequires
* Mon Mar 16 2015 Stephen Gallagher <sgallagh@redhat.com> 0.1-1
- First packaging