OpenSSL-Fehlerbehebung: So beheben Sie den Fehler unable to get local issuer certificate
Bei der Herstellung sicherer Verbindungen mit OpenSSL – zum Beispiel beim Ausführen von Netzwerk-Anfragen in PHP, beim Einsatz von openssl
oder curl
am Terminal oder beim Aufbau von SSL/TLS-Verbindungen in Node.js- oder Python-Anwendungen – stoßen Entwickler häufig auf die Fehlermeldung 20:unable to get local issuer certificate
. Dabei handelt es sich um ein häufiges, historisch bedingtes Problem im Zusammenhang mit der Zertifikatsvalidierung von OpenSSL.
Aus Sicherheitsgründen verlangt OpenSSL standardmäßig beim Verifizieren der Zertifikatkette eine eindeutige Angabe einer vertrauenswürdigen Zertifizierungsstelle (CA). Wenn diese Vertrauensanker nicht gefunden oder nicht explizit angegeben werden, kann OpenSSL die Authentizität des Serverzertifikats nicht überprüfen und gibt diesen Fehler zurück.
In diesem Beitrag erklären wir die Ursachen für diesen Fehler und zeigen, wie Sie ihn in ServBay beheben. Die Beispiele umfassen dabei die Konfiguration des OpenSSL-Vertrauensspeichers für PHP, Python, Node.js sowie die Nutzung von curl
.
Fehlermeldung 20:unable to get local issuer certificate
Problembeschreibung
Versucht OpenSSL, das SSL/TLS-Zertifikat eines entfernten Servers zu überprüfen, baut die Software eine Kette vom Serverzertifikat bis zur vertrauenswürdigen Root-CA auf. Kann OpenSSL dabei lokal ein benötigtes Zwischenzertifikat oder das gewünschte Root-Zertifikat nicht finden – oder ist kein passender Vertrauensspeicher (CAFile
oder CAPath
) konfiguriert – schlägt die Verifikation fehl und es erscheint der Fehler 20:unable to get local issuer certificate
.
Kurz gesagt: OpenSSL weiß nicht, welcher Zertifizierungsstelle es vertrauen soll und kann deshalb die Identität des Servers nicht bestätigen.
OpenSSL-Version und CA-Zertifikatpfad in ServBay
ServBay ist eine integrierte lokale Webentwicklungsumgebung, die ein OpenSSL-Paket mit häufig benötigten öffentlichen Root-CA-Zertifikaten vorkonfiguriert. Die OpenSSL-Version von ServBay richtet sich nach Ihrem Mac-Chiptyp:
- Apple Silicon (M-Serie) ServBay: OpenSSL Version 3.2.1
- Intel-Chipsatz ServBay: OpenSSL Version 1.1.1u
Die entsprechenden CA-Zertifikatsdateien (cacert.pem
) und das Zertifikatsverzeichnis (certs
) befinden sich im Installationspfad des ServBay-Pakets. Den richtigen Speicherort finden Sie je nach Version hier:
# Bündeldatei mit allen vertrauenswürdigen Root-Zertifikaten
cafile=/Applications/ServBay/package/common/openssl/3.2/cacert.pem
# Verzeichnis für einzelne Zertifikatsdateien (meist reicht cacert.pem, manche Anwendungen benötigen capath)
capath=/Applications/ServBay/package/common/openssl/3.2/certs
2
3
4
# Bündeldatei mit allen vertrauenswürdigen Root-Zertifikaten
cafile=/Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem
# Verzeichnis für einzelne Zertifikatsdateien
capath=/Applications/ServBay/package/common/openssl/1.1.1u/certs
2
3
4
Um den Fehler unable to get local issuer certificate
zu lösen, müssen Sie OpenSSL (bzw. den jeweiligen Dienst oder das jeweilige Tool) stets den passenden Pfad zu cafile
oder capath
mitteilen, damit OpenSSL weiß, wo es vertrauenswürdige CA-Zertifikate findet.
Beispiel-Lösungen
Im Folgenden sehen Sie, wie Sie in verschiedenen Tools und Programmiersprachen den OpenSSL-CA-Speicher korrekt konfigurieren.
Beispiel 1: Verbindungstest mit dem openssl
-Befehl
Tritt der Fehler beim Testen einer Verbindung via openssl s_client
auf:
openssl s_client -quiet -connect gmail.com:443
könnte die Fehlermeldung wie folgt aussehen (einschließlich verify error:num=20:unable to get local issuer certificate
):
depth=2 C=US, O=Google Trust Services LLC, CN=GTS Root R1
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=1 C=US, O=Google Trust Services, CN=WR2
verify return:1
depth=0 CN=gmail.com
verify return:1
# ... weitere Verbindungsinformationen ...
2
3
4
5
6
7
8
Lösung:
Mit dem Parameter -CAfile
geben Sie explizit den CA-Bundle-Pfad aus ServBay an:
openssl s_client -quiet -connect gmail.com:443 -CAfile /Applications/ServBay/package/common/openssl/3.2/cacert.pem
openssl s_client -quiet -connect gmail.com:443 -CAfile /Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem
Bei erfolgreicher Verbindung und Zertifikatsvalidierung ist der Wert von verify return
jeweils 1
– ohne dass Zeilen vom Typ verify error:num=20
erscheinen:
depth=2 C=US, O=Google Trust Services LLC, CN=GTS Root R1
verify return:1
depth=1 C=US, O=Google Trust Services, CN=WR2
verify return:1
depth=0 CN=gmail.com
verify return:1
# ... weitere Verbindungsinformationen ...
2
3
4
5
6
7
Beispiel 2: OpenSSL-Nutzung in PHP
Viele PHP-Funktionen für Web-Kommunikation (wie file_get_contents
für HTTPS-URLs, stream_socket_client
für SSL-Verbindungen oder cURL-Erweiterungen) bauen auf OpenSSL auf. Sie können die CA über die php.ini
oder programmatisch pro Verbindung festlegen.
Möglichkeit A: Bearbeiten Sie die php.ini
(empfohlen)
Das ist die komfortabelste globale Lösung. Bearbeiten Sie die für Ihre PHP-Version gültige php.ini
(in ServBay leicht über das Control Panel auffindbar) und ergänzen oder ändern Sie unter [openssl]
die folgenden Zeilen. Passen Sie die Pfade an Ihren Chiptyp an.
[openssl]
; CA-Bundle mit den vertrauenswürdigen Zertifikaten
openssl.cafile=/Applications/ServBay/package/common/openssl/3.2/cacert.pem
; Verzeichnis mit einzelnen CA-Zertifikaten (optional, aber empfohlen)
openssl.capath=/Applications/ServBay/package/common/openssl/3.2/certs
2
3
4
5
[openssl]
; CA-Bundle mit den vertrauenswürdigen Zertifikaten
openssl.cafile=/Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem
; Verzeichnis mit einzelnen CA-Zertifikaten (optional, aber empfohlen)
openssl.capath=/Applications/ServBay/package/common/openssl/1.1.1u/certs
2
3
4
5
Starten Sie nach Anpassung der php.ini
den PHP-Service (oder ServBay komplett) neu, damit die Änderung aktiv wird.
Möglichkeit B: Konfiguration im PHP-Code (nur für die aktuelle Verbindung)
Ohne Änderung der globalen php.ini
können Sie mittels stream_context_create
im Code die CA-Bundle-Datei definieren:
<?php
// Beispiel: Verbindung zu einem SMTP-Server via SSL/TLS
$server = 'ssl0.ovh.net';
$port = 465;
// Passen Sie den CA-Pfad an Ihre ServBay-Version an
// Für Apple Silicon:
$caCertFile = '/Applications/ServBay/package/common/openssl/3.2/cacert.pem';
// Für Intel:
// $caCertFile = '/Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem';
$contextOptions = [
'ssl' => [
'verify_peer' => true, // Überprüfung des Gegenüberzertifikats aktivieren
'verify_peer_name' => true, // Hostname-Abgleich mit Zertifikat
'allow_self_signed' => false, // Keine selbstsignierten Zertifikate akzeptieren
'cafile' => $caCertFile, // CA-Bundle angeben
// 'capath' => '/Applications/ServBay/package/common/openssl/3.2/certs', // optional, falls CA-Verzeichnis benötigt wird
],
];
$context = stream_context_create($contextOptions);
// SSL/TLS-Verbindung mit Kontextoptionen aufbauen
$connection = @stream_socket_client(
"ssl://$server:$port",
$errno,
$errstr,
30, // Timeout
STREAM_CLIENT_CONNECT,
$context // Kontextoptionen übergeben
);
if ($connection) {
echo "Verbindung zu $server:$port hergestellt\n";
// Beispiel: Senden des EHLO-Befehls
fwrite($connection, "EHLO servbay.demo\r\n"); // Beispiel-Domain mit ServBay-Bezug
while (!feof($connection)) {
echo fgets($connection);
}
fclose($connection);
} else {
echo "Verbindung zu $server:$port fehlgeschlagen. Fehler: $errstr ($errno)\n";
}
?>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
Beispiel 3: OpenSSL-Nutzung in Python (ssl-Modul)
Das Python-ssl
-Modul erlaubt es, eine SSL/TLS-Umgebung mit bestimmten CA-Zertifikaten zu schaffen.
import ssl
import socket
server = 'ssl0.ovh.net'
port = 465
# Passen Sie den CA-Pfad an Ihre ServBay-Version an
# Für Apple Silicon:
ca_cert_file = '/Applications/ServBay/package/common/openssl/3.2/cacert.pem'
# Für Intel:
# ca_cert_file = '/Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem'
# Erstellen eines Default-SSL-Contexts mit eigenem CA-Bundle
context = ssl.create_default_context(cafile=ca_cert_file)
# Alternativ capath: context = ssl.create_default_context(capath='/Applications/ServBay/package/common/openssl/3.2/certs')
try:
# Normale Socket-Verbindung aufbauen
with socket.create_connection((server, port)) as sock:
# Socket auf SSL/TLS umstellen
with context.wrap_socket(sock, server_hostname=server) as ssock:
print(f"SSL-Verbindung aufgebaut. Protokoll: {ssock.version()}")
# Beispiel: EHLO-Befehl senden
ssock.sendall(b"EHLO servbay.demo\r\n") # Beispiel-Domain mit ServBay-Bezug
while True:
data = ssock.recv(4096)
if not data:
break
print(data.decode())
except Exception as e:
print(f"Verbindung fehlgeschlagen oder SSL-Fehler: {e}")
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Beispiel 4: OpenSSL-Nutzung in Node.js (tls-Modul)
Das tls
-Modul von Node.js steuert TLS/SSL. Über die Option ca
können Sie ein eigenes CA-Bundle nutzen. Am einfachsten ist es, den Inhalt der ServBay-cacert.pem
-Datei einzulesen.
const tls = require('tls');
const fs = require('fs');
const server = 'www.google.com'; // Beispiel: vertrauenswürdiger Standardserver
const port = 443;
// Passen Sie den CA-Pfad an Ihre ServBay-Version an
// Für Apple Silicon:
const caCertFile = '/Applications/ServBay/package/common/openssl/3.2/cacert.pem';
// Für Intel:
// const caCertFile = '/Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem';
const options = {
host: server,
port: port,
// CA-Zertifikatsbundle einlesen
ca: fs.readFileSync(caCertFile),
// Node.js prüft standardmäßig den Hostnamen (checkServerIdentity).
// Korrigieren Sie CA und Serverzertifikat, damit die Prüfung erfolgreich ist.
// checkServerIdentity: () => { return null; } // <-- Aus Sicherheitsgründen besser nicht verwenden!
};
const socket = tls.connect(options, () => {
console.log('SSL-Verbindung erfolgreich aufgebaut');
// Für HTTPS müsste hier ein HTTP-Request gesendet werden – dieser Code demonstriert nur die Verbindung.
// socket.write('GET / HTTP/1.1\r\nHost: ' + server + '\r\n\r\n');
});
socket.on('data', (data) => {
console.log(data.toString());
});
socket.on('close', () => {
console.log('Verbindung geschlossen');
});
socket.on('error', (error) => {
console.error('Fehler:', error.message); // Gibt Fehlermeldung aus
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
Hinweis: Im Node.js-Beispiel wurde die Zeile mit checkServerIdentity: () => { return null; }
entfernt. Diese Option deaktiviert die sehr wichtige Hostnamenprüfung und stellt ein Sicherheitsrisiko dar. Der Fehler unable to get local issuer certificate
bei OpenSSL bezieht sich auf das fehlende Root-Zertifikat und nicht auf die Hostnamenverifikation. Geben Sie das ca
korrekt an und achten Sie auf ein gültiges Serverzertifikat – dann funktioniert die Standard-Hostprüfung von Node.js einwandfrei. Fehler bei der Hostnamenüberprüfung sprechen in der Regel für ein Problem mit dem Serverzertifikat, nicht mit dem CA-Speicher.
Beispiel 5: OpenSSL im curl
-Kommando verwenden
Die Kommandozeile curl
verwendet ebenfalls OpenSSL (oder eine andere SSL-Bibliothek) für HTTPS-Anfragen. Mit dem Argument --cacert
lässt sich das CA-Bundle einfach angeben.
# Mit ServBay-CA-Bundle eine HTTPS-Seite aufrufen
# Wählen Sie den richtigen Pfad je nach Mac
# Für Apple Silicon:
curl --cacert /Applications/ServBay/package/common/openssl/3.2/cacert.pem https://example.com
# Für Intel:
# curl --cacert /Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem https://example.com
2
3
4
5
6
7
Ist der CA-Pfad richtig und das Serverzertifikat gültig, lädt curl
die Seite ohne Zertifikatsfehler.
Zusammenfassung
Der Fehler 20:unable to get local issuer certificate
ist ein typisches Problem bei SSL/TLS-Verbindungen mit OpenSSL, da OpenSSL zur Verifizierung einen klar benannten Vertrauensspeicher erwartet. ServBay stellt hierfür ein vorgefertigtes CA-Bundle (cacert.pem
) mit den gängigen öffentlichen Root-Zertifikaten zur Verfügung.
Die Lösung: Konfigurieren Sie in Ihrer Entwicklungsumgebung (etwa in der php.ini
, direkt bei SSL-Kontexten im Code, als Parameter beim OpenSSL- oder curl
-Kommando) explizit den Pfad zu ServBays cacert.pem
. Achten Sie darauf, je nach Mac (Apple Silicon oder Intel) und verwendeter ServBay-Version, den korrekten Pfad zu wählen. Mit der passenden CA-Konfiguration ist Ihr lokales Entwicklungsumfeld bestens für sichere SSL/TLS-Kommunikation mit externen Diensten gerüstet.