]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Utility for dumping OpenSSL config file
authorDmitry Belyavskiy <beldmit@gmail.com>
Mon, 7 Apr 2025 16:04:26 +0000 (18:04 +0200)
committerPauli <ppzgs1@gmail.com>
Thu, 8 May 2025 01:05:42 +0000 (11:05 +1000)
Based on @neverpanic code`

Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Paul Dale <ppzgs1@gmail.com>
(Merged from https://github.com/openssl/openssl/pull/27290)

apps/build.info
apps/configutl.c [new file with mode: 0644]

index e9565c45ee6d42e95f7f2801982eeefdbe081717..345f7079584a551ad9e7deba800651962313dafb 100644 (file)
@@ -12,7 +12,7 @@ ENDIF
 # Source for the 'openssl' program
 $OPENSSLSRC=\
         openssl.c \
-        asn1parse.c ca.c ciphers.c crl.c crl2pkcs7.c dgst.c \
+        asn1parse.c ca.c ciphers.c configutl.c crl.c crl2pkcs7.c dgst.c \
         enc.c errstr.c \
         genpkey.c kdf.c mac.c nseq.c passwd.c pkcs7.c \
         pkcs8.c pkey.c pkeyparam.c pkeyutl.c prime.c rand.c req.c \
diff --git a/apps/configutl.c b/apps/configutl.c
new file mode 100644 (file)
index 0000000..9c6a251
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/conf.h>
+#include <openssl/err.h>
+#include <openssl/safestack.h>
+
+#include "apps.h"
+#include "progs.h"
+
+/**
+ * Print the given value escaped for the OpenSSL configuration file format.
+ */
+static void print_escaped_value(BIO *out, const char *value)
+{
+    const char *p;
+
+    for (p = value; *p != '\0'; p++) {
+        switch (*p) {
+        case '"':
+        case '\'':
+        case '#':
+        case '\\':
+        case '$':
+            BIO_printf(out, "\\");
+            BIO_write(out, p, 1);
+            break;
+        case '\n':
+            BIO_printf(out, "%s", "\\n");
+            break;
+        case '\r':
+            BIO_printf(out, "%s", "\\r");
+            break;
+        case '\b':
+            BIO_printf(out, "%s", "\\b");
+            break;
+        case '\t':
+            BIO_printf(out, "%s", "\\t");
+            break;
+        case ' ':
+            if (p == value || p[1] == '\0') {
+                /*
+                 * Quote spaces if they are the first or last char of the
+                 * value. We could quote the entire string (and it would
+                 * certainly produce nicer output), but in quoted strings
+                 * the escape sequences for \n, \r, \t, and \b do not work.
+                 * To make sure we're producing correct results we'd thus
+                 * have to selectively not use those in quoted strings and
+                 * close and re-open the quotes if they appear, which is
+                 * more trouble than adding the quotes just around the
+                 * first and last leading and trailing space.
+                 */
+                BIO_printf(out, "%s", "\" \"");
+                break;
+            }
+            /* FALLTHROUGH */
+        default:
+            BIO_write(out, p, 1);
+            break;
+        }
+    }
+}
+
+/**
+ * Print all values in the configuration section identified by section_name
+ */
+static void print_section(BIO *out, const CONF *cnf, OPENSSL_CSTRING section_name)
+{
+    STACK_OF(CONF_VALUE) *values = NCONF_get_section(cnf, section_name);
+    int idx;
+
+    for (idx = 0; idx < sk_CONF_VALUE_num(values); idx++) {
+        CONF_VALUE *value = sk_CONF_VALUE_value(values, idx);
+
+        BIO_printf(out, "%s = ", value->name);
+        print_escaped_value(out, value->value);
+        BIO_printf(out, "\n");
+    }
+}
+
+typedef enum OPTION_choice {
+    OPT_COMMON,
+    OPT_OUT,
+    OPT_NOHEADER,
+    OPT_CONFIG
+} OPTION_CHOICE;
+
+const OPTIONS configutl_options[] = {
+    OPT_SECTION("General"),
+    {"help", OPT_HELP, '-', "Display this summary"},
+    {"config", OPT_CONFIG, 's', "Config file to deal with (the default one if omitted)"},
+    OPT_SECTION("Output"),
+    {"out", OPT_OUT, '>', "Output to filename rather than stdout"},
+    {"noheader", OPT_NOHEADER, '-', "Don't print the information about original config"},
+    {NULL}
+};
+
+/**
+ * Parse the passed OpenSSL configuration file (or the default one/specified in the
+ * OPENSSL_CONF environment variable) and write it back in
+ * a canonical format with all includes and variables expanded.
+ */
+int configutl_main(int argc, char *argv[])
+{
+    int ret = 1;
+    char *prog, *configfile = NULL;
+    OPTION_CHOICE o;
+    int dump = 1;
+    CONF *cnf = NULL;
+    long eline = 0;
+    int default_section_idx, idx;
+    int no_header = 0;
+    STACK_OF(OPENSSL_CSTRING) *sections = NULL;
+    BIO *out = NULL;
+    const char *outfile = NULL;
+
+    prog = opt_init(argc, argv, configutl_options);
+    while ((o = opt_next()) != OPT_EOF) {
+        switch (o) {
+        case OPT_EOF:
+        case OPT_ERR:
+ opthelp:
+            BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
+            goto end;
+        case OPT_HELP:
+            opt_help(configutl_options);
+            ret = 0;
+            goto end;
+            break;
+        case OPT_NOHEADER:
+            no_header = 1;
+            break;
+        case OPT_CONFIG:
+            configfile = OPENSSL_strdup(opt_arg());
+            break;
+        case OPT_OUT:
+            outfile = opt_arg();
+            break;
+        }
+    }
+
+    if (dump == 0)
+        goto opthelp;
+
+    out = bio_open_default(outfile, 'w', FORMAT_TEXT);
+    if (out == NULL)
+        goto end;
+
+    if (configfile == NULL)
+        configfile = CONF_get1_default_config_file();
+
+    if (configfile == NULL)
+        goto end;
+
+    if ((cnf = NCONF_new(NULL)) == NULL)
+        goto end;
+
+    if (NCONF_load(cnf, configfile, &eline) == 0) {
+        BIO_printf(bio_err, "Error on line %ld of configuration file\n", eline + 1);
+        goto end;
+    }
+
+    if ((sections = NCONF_get_section_names(cnf)) == NULL)
+        goto end;
+
+    if (no_header == 0)
+        BIO_printf(out, "# This configuration file was linearized and expanded from %s\n",
+                   configfile);
+
+    default_section_idx = sk_OPENSSL_CSTRING_find(sections, "default");
+    if (default_section_idx != -1)
+        print_section(out, cnf, "default");
+
+    for (idx = 0; idx < sk_OPENSSL_CSTRING_num(sections); idx++) {
+        OPENSSL_CSTRING section_name = sk_OPENSSL_CSTRING_value(sections, idx);
+
+        if (idx == default_section_idx)
+            continue;
+
+        BIO_printf(out, "\n[%s]\n", section_name);
+        print_section(out, cnf, section_name);
+    }
+
+    ret = 0;
+
+end:
+    ERR_print_errors(bio_err);
+    BIO_free(out);
+    OPENSSL_free(configfile);
+    NCONF_free(cnf);
+    sk_OPENSSL_CSTRING_free(sections);
+    return ret;
+}