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

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