import sscg-3.0.0-5.el8

This commit is contained in:
CentOS Sources 2022-11-08 01:43:22 -05:00 committed by Stepan Oksanichenko
parent d2d2ae226a
commit aaf66f5eb4
16 changed files with 167 additions and 4584 deletions

2
.gitignore vendored
View File

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

View File

@ -1 +1 @@
6e880fc36f7d1ebf4a9668dbcb9276b3afcb2904 SOURCES/sscg-2.3.3-stripped.tar.xz
81e3b33e118edff96583314ceb4bfde9a1e6b45c SOURCES/sscg-3.0.0.tar.xz

View File

@ -0,0 +1,34 @@
From d2277e711bb16e3b98f43565e71b7865b5fed423 Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Sat, 7 Aug 2021 11:48:04 -0400
Subject: [PATCH 1/2] Drop usage of ERR_GET_FUNC()
This macro was dropped in OpenSSL 3.0 and has actually not been
providing a valid return code for some time.
Related: rhbz#1964837
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
---
include/sscg.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/include/sscg.h b/include/sscg.h
index faf86ba4f68e186bd35c7bc3ec77b98b8e37d253..851dc93175607e5223a70ef40a5feb24b7b69215 100644
--- a/include/sscg.h
+++ b/include/sscg.h
@@ -94,11 +94,10 @@
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, \
--
2.33.0

View File

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

@ -1,208 +0,0 @@
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,46 @@
From 87604820a935f87a8f533e3f294419d27c0514eb Mon Sep 17 00:00:00 2001
From: Allison Karlitskaya <allison.karlitskaya@redhat.com>
Date: Tue, 26 Oct 2021 12:32:13 +0200
Subject: [PATCH 2/2] Correct certificate lifetime calculation
sscg allows passing the certificate lifetime, as a number of days, as a
commandline argument. It converts this value to seconds using the
formula
days * 24 * 3650
which is incorrect. The correct value is 3600.
This effectively adds an extra 20 minutes to the lifetime of the
certificate for each day as given on the commandline, and was enough to
cause some new integration tests in cockpit to fail.
Interestingly, 3650 is the old default value for the number of days of
certificate validity (~10 years) so this probably slipped in as a sort
of muscle-memory-assisted typo.
Let's just write `24 * 60 * 60` to make things clear.
---
src/x509.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/x509.c b/src/x509.c
index dc1594a4bdcb9d81607f0fe5ad2d4562e5edb533..7c7e4dfe56d5756862f3e0f851941e846ce96f31 100644
--- a/src/x509.c
+++ b/src/x509.c
@@ -416,11 +416,11 @@ sscg_sign_x509_csr (TALLOC_CTX *mem_ctx,
X509_set_issuer_name (cert, X509_REQ_get_subject_name (csr));
}
/* set time */
X509_gmtime_adj (X509_get_notBefore (cert), 0);
- X509_gmtime_adj (X509_get_notAfter (cert), days * 24 * 3650);
+ X509_gmtime_adj (X509_get_notAfter (cert), days * 24 * 60 * 60);
/* set subject */
subject = X509_NAME_dup (X509_REQ_get_subject_name (csr));
sslret = X509_set_subject_name (cert, subject);
CHECK_SSL (sslret, X509_set_subject_name);
--
2.33.0

View File

@ -1,115 +0,0 @@
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,68 @@
From 0875cd6169e876c4296a307631d49b801fc686dc Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Tue, 8 Mar 2022 16:33:35 -0500
Subject: [PATCH] Truncate IP address in SAN
In OpenSSL 1.1, this was done automatically when addind a SAN extension,
but in OpenSSL 3.0 it is rejected as an invalid input.
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
---
src/x509.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/src/x509.c b/src/x509.c
index 7c7e4dfe56d5756862f3e0f851941e846ce96f31..e828ec725b23d7ea79393151e7bb436e2f61bdb8 100644
--- a/src/x509.c
+++ b/src/x509.c
@@ -131,10 +131,11 @@ sscg_x509v3_csr_new (TALLOC_CTX *mem_ctx,
size_t i;
X509_NAME *subject;
char *alt_name = NULL;
char *tmp = NULL;
char *san = NULL;
+ char *slash = NULL;
TALLOC_CTX *tmp_ctx;
X509_EXTENSION *ex = NULL;
struct sscg_x509_req *csr;
/* Make sure we have a key available */
@@ -265,10 +266,16 @@ sscg_x509v3_csr_new (TALLOC_CTX *mem_ctx,
tmp_ctx, "DNS:%s", certinfo->subject_alt_names[i]);
}
else
{
san = talloc_strdup (tmp_ctx, certinfo->subject_alt_names[i]);
+ /* SAN IP addresses cannot include the subnet mask */
+ if ((slash = strchr (san, '/')))
+ {
+ /* Truncate at the slash */
+ *slash = '\0';
+ }
}
CHECK_MEM (san);
if (strnlen (san, MAXHOSTNAMELEN + 5) > MAXHOSTNAMELEN + 4)
{
@@ -287,11 +294,17 @@ sscg_x509v3_csr_new (TALLOC_CTX *mem_ctx,
alt_name = tmp;
}
}
ex = X509V3_EXT_conf_nid (NULL, NULL, NID_subject_alt_name, alt_name);
- CHECK_MEM (ex);
+ if (!ex)
+ {
+ ret = EINVAL;
+ fprintf (stderr, "Invalid subjectAlternativeName: %s\n", alt_name);
+ goto done;
+ }
+
sk_X509_EXTENSION_push (certinfo->extensions, ex);
/* Set the public key for the certificate */
sslret = X509_REQ_set_pubkey (csr->x509_req, spkey->evp_pkey);
CHECK_SSL (sslret, X509_REQ_set_pubkey (OU));
--
2.35.1

View File

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

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

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

View File

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

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

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

View File

@ -8,16 +8,13 @@
Name: sscg
Version: 2.3.3
Release: 14%{?dist}
Version: 3.0.0
Release: 5%{?dist}
Summary: Simple SSL certificate generator
License: BSD
License: GPLv3+ with exceptions
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
Source0: https://%{provider_prefix}/releases/download/%{repo}-%{version}/%{repo}-%{version}.tar.xz
BuildRequires: gcc
BuildRequires: libtalloc-devel
@ -28,23 +25,11 @@ 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
Patch0001: 0001-Drop-usage-of-ERR_GET_FUNC.patch
Patch0002: 0002-Correct-certificate-lifetime-calculation.patch
Patch0003: 0003-Truncate-IP-address-in-SAN.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"
@ -54,7 +39,6 @@ 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
@ -67,10 +51,7 @@ false signatures from the service certificate.
%meson_install
%check
%ifnarch %{arm}
%meson_test
%endif
%meson_test -t 10
%files
%license COPYING
@ -79,6 +60,15 @@ false signatures from the service certificate.
%{_mandir}/man8/%{name}.8*
%changelog
* Thu Jul 14 2022 Stephen Gallagher <sgallagh@redhat.com> - 3.0.0-5
- Rebase to sscg 3.0.0
- Resolves: rhbz#2107369
- Resolves: rhbz#2091525
* Thu Jun 02 2022 Stephen Gallagher <sgallagh@redhat.com> - 2.3.3-15
- Fix certificate lifetime calculation
- Resolves: rhbz#2091525
* Tue Jan 21 2020 Stephen Gallagher <sgallagh@redhat.com> - 2.3.3-14
- Properly handling reading long passphrase files.