Blame SOURCES/0010-Better-validation-of-command-line-arguments.patch

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