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

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