Ich schreibe ein Bash-Skript, das openssl verwendet, um eine Zertifikatsignierungsanforderung mit X509v3-Erweiterungs-konformzu generieren.
Da es hierfür keine Befehlszeilenoption gibt, war eine Lösung , die Option -config
zusammen mit der Option -reqexts
zu verwenden, indem die Werte für SAN an die Standardkonfigurationsdatei angefügt werden.
openssl req -new -sha256 -key domain.key -subj "/C=US/ST=CA/O=Acme, Inc./CN=example.com" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:example.com,DNS:www.example.com")) -out domain.csr
Mein Problem ist die Portabilität. Während eine ähnliche Frage versichert, dass dies in meiner Ubuntu-Umgebung funktioniert, da die Standardkonfigurationsdatei /etc/ssl/openssl.cnf
ist, funktioniert dies leider nicht überall, wobei Windows das offensichtliche Beispiel ist.
Wie bestimme ich programmatisch den vollständigen Pfad zur openssl default -Konfigurationsdatei?
Es gibt einen krassen Hinweis in der Dokumentation
-config Dateiname
Dadurch kann eine alternative Konfigurationsdatei angegeben werden, die die Kompilierzeit Dateiname oder eine andere in der Umgebungsvariable OPENSSL_CONF angegebene überschreibt.
Ich habe die Dokumentation config gelesen und den Quellcode durchsucht, aber ich kann nicht herausfinden, durch welchen Mechanismus sie die Standard-Konfigurationsdatei "compile time" lädt. Wenn ich das finden könnte, würde ich es vorziehen, es statt des hart codierten Pfads als Variable in das Skript zu laden.
Außerdem ist meine $OPENSSL_CONF
-Variable leer.
Derzeit überprüft mein Skript diese Bedingungen und verwendet die erste, die als wahr ausgewertet wird:
$OPENSSL_CONF
ist ausgefüllt und die Datei ist vorhanden/etc/ssl/openssl.cnf
existiertWenn keine der beiden zutreffend ist, enthält es eine Kopie einer Standardkonfiguration. Dies ist unerwünscht, da dadurch die vom Client festgelegten benutzerdefinierten Einstellungen überschrieben werden. Ich möchte die Umgebungsbedingungen vollständig nutzen und den Abschnitt SAN einfach als Nachtrag hinzufügen.
Ich könnte diese Kette um die Pfade der üblichen Verdächtigen oder sogar eine Systemsuche erweitern. Für den Fall, dass mehrere existieren, habe ich keine Sicherheit, welche von openssl tatsächlich als Standard verwendet wird.
Wie bestimme ich programmatisch den vollständigen Pfad zur Standardkonfigurationsdatei openssl?
Programmgesteuert ist es so einfach wie das OPENSSLDIR
-Makro von opensslconf.h
:
$ cat /usr/local/ssl/darwin/include/openssl/opensslconf.h | grep OPENSSLDIR
#if defined(HEADER_CRYPTLIB_H) && !defined(OPENSSLDIR)
#define OPENSSLDIR "/usr/local/ssl/darwin"
Wie kann ich den Standardspeicherort für openssl.cnf ermitteln?
Hier finden Sie weitere Informationen, mit denen Sie die Lücken der anderen Stack Overflow-Frage ausfüllen können. Dies hängt von der von Ihnen verwendeten OpenSSL-Installation ab.
Hier ist die kurze Antwort ... Die Bibliothek und die Programme suchen nach openssl.cnf
in OPENSSLDIR
. OPENSSLDIR
ist eine configure-Option und wird mit --openssldir
festgelegt.
Ich bin auf einem MacBook mit 3 verschiedenen OpenSSLs (Apple, MacPort und dem, das ich baue):
# Apple
$ /usr/bin/openssl version -a | grep OPENSSLDIR
OPENSSLDIR: "/System/Library/OpenSSL"
# MacPorts
$ /opt/local/bin/openssl version -a | grep OPENSSLDIR
OPENSSLDIR: "/opt/local/etc/openssl"
# My build of OpenSSL
$ openssl version -a | grep OPENSSLDIR
OPENSSLDIR: "/usr/local/ssl/darwin"
Hier ist die längere Antwort ... Es ist eine Art von OpenSSL-Quellcode für apps.c
, load_config
und was passiert, wenn cnf
NULL
ist (d. H. Keine -config
-Option oder OPENSSL_CONF
envar). Wenn cnf
NULL
ist und keine Überschreibungen vorhanden sind, wird OPENSSLDIR
verwendet.
int load_config(BIO *err, CONF *cnf)
{
static int load_config_called = 0;
if (load_config_called)
return 1;
load_config_called = 1;
if (!cnf)
cnf = config;
if (!cnf)
return 1;
OPENSSL_load_builtin_modules();
if (CONF_modules_load(cnf, NULL, 0) <= 0) {
BIO_printf(err, "Error configuring OpenSSL\n");
ERR_print_errors(err);
return 0;
}
return 1;
}
Dies funktioniert in meiner Ubuntu-Umgebung, da die Standardkonfigurationsdatei
/etc/ssl/openssl.cnf
ist. Dies funktioniert leider nicht überall. Windows ist das offensichtliche Beispiel.
Unter Windows ist dies möglicherweise immer noch ein Problem. Sie sollten OK sein, wenn Sie OpenSSL selbst aus Quellen erstellen. modulo ihre Behandlung mit langen Dateinamen in Windows (siehe auch Problem # 4490: "nmake install" schlägt fehl "Ziel muss ein Verzeichnis in.\util\copy.pl Zeile 39" in sein).
Benutzer wie Shinning Light und Win32 OpenSSL stellen Installationsprogramme bereit, und OpenSSL möglicherweise nicht wird in dem Verzeichnis installiert, das vom Packager vorgesehen ist. Ich habe sogar gesehen, dass Unix-Verzeichnisse wie /usr/local
auf Windows-Rechnern erscheinen.
Für Windows ist Ihre sicherste Wette wahrscheinlich, dass die Umgebungsvariable OPENSSL_CONF
so eingestellt ist, dass gebrochene Pfade und Fehler bei der Pfadverarbeitung überschrieben werden.
Ich kenne auch keinen CONF_*
- oder NCONF_*
-API-Aufruf, der Ihnen das effektive Verzeichnis zur Laufzeit gibt. Das effektive Verzeichnis wäre hier das Konfigurationsverzeichnis plus Dinge wie OPENSSL_CONF
überschreibt. Jetzt in der OpenSSL-Benutzerliste öffnen: Gültigen OPENSSLDIR-Pfad zur Laufzeit abrufen?
Wie in einem Kommentar erwähnt, sollte die einfache Antwort darin bestehen, den Pfad mithilfe des folgenden Befehls zu finden:
openssl version -d
Wenn dies nicht funktioniert, können Sie davon ausgehen, dass OpenSSL nicht richtig konfiguriert ist oder zumindest nicht über die erforderliche Konfiguration verfügt. In Node.js finden Sie ein Beispiel, wie Sie den Speicherort von openssl.cnf ermitteln können:
const util = require('util');
const path = require('path');
const exec = util.promisify(require('child_process').exec);
(async () => {
const opensslCnfPath = path.normalize(`${(await exec('openssl version -d')).stdout.match(/"(.*)"/).pop()}/openssl.cnf`);
console.log(opensslCnfPath);
})();