Dépannage OpenSSL : Résoudre l’erreur unable to get local issuer certificate
Lors de l’établissement de connexions sécurisées avec OpenSSL (par exemple, lors d’exécutions de requêtes réseau en environnement PHP, d’utilisation des commandes openssl
ou curl
, ou encore lors de connexions SSL/TLS dans des applications Node.js ou Python), il arrive fréquemment que les développeurs rencontrent l’erreur 20:unable to get local issuer certificate
. Il s’agit d’un problème classique lié au processus de validation des certificats par OpenSSL.
Pour des raisons de sécurité, OpenSSL exige par défaut que la chaîne de certificats soit validée grâce à une autorité de certification racine (CA) reconnue. Si aucune de ces références de confiance n’est disponible ou spécifiée, OpenSSL ne peut pas vérifier la légitimité du certificat du serveur et retourne cette erreur.
Ce guide détaille les causes de cette erreur et propose des solutions pour l’environnement ServBay, notamment la configuration de l’emplacement de stockage des certificats CA pour OpenSSL dans PHP, Python, Node.js et via la commande curl
.
Message d’erreur : 20:unable to get local issuer certificate
Description du problème
Lorsqu’OpenSSL tente de valider le certificat SSL/TLS d’un serveur distant, il doit construire une chaîne de confiance allant du certificat du serveur jusqu’à une CA racine reconnue. Si OpenSSL ne trouve pas, localement, les certificats intermédiaires ou les CA racines nécessaires, ou encore si aucun emplacement de confiance (CAFile ou CAPath) n’est configuré, le processus échoue et génère l’erreur 20:unable to get local issuer certificate
.
En d’autres termes : OpenSSL ignore quelle autorité de certification il doit approuver, et ne peut donc pas confirmer l’identité du serveur auquel il tente de se connecter.
Version d'OpenSSL et emplacement des certificats CA sous ServBay
ServBay, solution intégrée de développement Web local, est livré avec OpenSSL et un ensemble de certificats CA racines publics pour simplifier la configuration des développeurs. La version d’OpenSSL varie selon le type de processeur de votre appareil :
- ServBay pour Apple Silicon (puces série M) : OpenSSL version 3.2.1.
- ServBay pour processeur Intel : OpenSSL version 1.1.1u.
Les fichiers de certificats CA correspondants (cacert.pem
) et le dossier de certificats (certs
) sont situés dans le répertoire d’installation de ServBay. Selon votre plateforme, les chemins d’accès sont les suivants :
ini
# Fichier regroupant toutes les autorités de certification racines reconnues
cafile=/Applications/ServBay/package/common/openssl/3.2/cacert.pem
# Dossier contenant les certificats individuels (en général, cacert.pem suffit ; certains outils requièrent capath)
capath=/Applications/ServBay/package/common/openssl/3.2/certs
1
2
3
4
2
3
4
ini
# Fichier regroupant toutes les autorités de certification racines reconnues
cafile=/Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem
# Dossier contenant les certificats individuels
capath=/Applications/ServBay/package/common/openssl/1.1.1u/certs
1
2
3
4
2
3
4
ini
# Fichier regroupant toutes les autorités de certification racines reconnues
cafile=C:\ServBay\package\common\openssl\3.3\cacert.pem
# Dossier contenant les certificats individuels
capath=C:\ServBay\package\common\openssl\3.3\certs
1
2
3
4
2
3
4
En résumé, pour résoudre l’erreur unable to get local issuer certificate
, il faut toujours indiquer à OpenSSL l’emplacement du fichier cafile
ou du dossier capath
afin qu’il sache où trouver les autorités de certification à approuver.
Exemples de solutions
Voici comment indiquer à différents outils ou langages le stockage des CA nécessaires à OpenSSL.
Exemple 1 : Tester une connexion avec la commande openssl
Si vous testez une connexion SSL à l’aide de la commande openssl s_client
et obtenez une erreur :
bash
openssl s_client -quiet -connect gmail.com:443
1
Vous pourriez observer une sortie similaire à celle-ci, contenant l’erreur verify error:num=20:unable to get local issuer certificate
:
bash
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
# ... autres informations de connexion ...
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
Solution :
Utilisez le paramètre -CAfile
pour indiquer clairement le chemin vers le fichier des CA fourni par ServBay :
bash
openssl s_client -quiet -connect gmail.com:443 -CAfile /Applications/ServBay/package/common/openssl/3.2/cacert.pem
1
bash
openssl s_client -quiet -connect gmail.com:443 -CAfile /Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem
1
Si la connexion et la validation sont réussies, le champ verify return
reste à 1
et la ligne d’erreur verify error:num=20
n’apparaît plus :
bash
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
# ... autres informations de connexion ...
1
2
3
4
5
6
7
2
3
4
5
6
7
Exemple 2 : Utiliser OpenSSL dans PHP
Nombre des fonctions réseau de PHP (par exemple, file_get_contents
vers des URL HTTPS, stream_socket_client
pour des connexions SSL, le module cURL, etc.) s’appuient sur OpenSSL. Vous pouvez configurer l’emplacement de la CA soit dans le fichier php.ini
, soit directement dans votre code via les options de contexte de flux.
Méthode A : Modification de php.ini
(recommandé)
La solution la plus efficace et globale consiste à éditer le fichier php.ini
de votre version de PHP (l’accès à l’édition est disponible via le panneau ServBay). Repérez la section [openssl]
et ajoutez/modifiez les lignes suivantes en adaptant le chemin selon votre architecture :
ini
[openssl]
; Spécifie le fichier CA racine de confiance
openssl.cafile=/Applications/ServBay/package/common/openssl/3.2/cacert.pem
; Spécifie le dossier contenant les certificats CA (optionnel mais recommandé)
openssl.capath=/Applications/ServBay/package/common/openssl/3.2/certs
1
2
3
4
5
2
3
4
5
ini
[openssl]
; Spécifie le fichier CA racine de confiance
openssl.cafile=/Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem
; Spécifie le dossier contenant les certificats CA (optionnel mais recommandé)
openssl.capath=/Applications/ServBay/package/common/openssl/1.1.1u/certs
1
2
3
4
5
2
3
4
5
Après modification de php.ini
, redémarrez le service PHP dans ServBay (ou l’application entière) pour appliquer la configuration.
Méthode B : Ajouter la configuration dans le code (effet localisé)
Si vous ne souhaitez pas modifier php.ini
, vous pouvez spécifier le chemin du fichier CA directement lors de la création du contexte :
php
<?php
// Exemple : Connexion à un serveur SMTP utilisant SSL/TLS
$server = 'ssl0.ovh.net';
$port = 465;
// Choisissez le chemin du fichier CA selon votre installation ServBay
// Pour Apple Silicon :
$caCertFile = '/Applications/ServBay/package/common/openssl/3.2/cacert.pem';
// Pour Intel :
// $caCertFile = '/Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem';
$contextOptions = [
'ssl' => [
'verify_peer' => true, // Active la vérification du certificat distant
'verify_peer_name' => true, // Vérifie la concordance entre le nom du certificat et celui du server
'allow_self_signed' => false, // N’autorise pas les certificats auto-signés, sauf confiance explicite
'cafile' => $caCertFile, // Spécifie le fichier CA
// 'capath' => '/Applications/ServBay/package/common/openssl/3.2/certs', // Optionnel, dossier des CA
],
];
$context = stream_context_create($contextOptions);
// Création de la connexion SSL/TLS avec le contexte spécifié
$connection = @stream_socket_client(
"ssl://$server:$port",
$errno,
$errstr,
30, // Délai de connexion
STREAM_CLIENT_CONNECT,
$context // Options de contexte
);
if ($connection) {
echo "Connexion établie vers $server:$port\n";
// Exemple : envoi de la commande EHLO
fwrite($connection, "EHLO servbay.demo\r\n"); // Exemple de nom de domaine lié à ServBay
while (!feof($connection)) {
echo fgets($connection);
}
fclose($connection);
} else {
echo "Échec de la connexion à $server:$port. Erreur : $errstr ($errno)\n";
}
?>
1
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
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
Exemple 3 : Utiliser OpenSSL dans Python (module ssl)
Le module ssl
de Python permet également de créer un contexte SSL/TLS et de spécifier le fichier de CA de confiance.
python
import ssl
import socket
server = 'ssl0.ovh.net'
port = 465
# Chemin du fichier CA selon la version ServBay
# Pour Apple Silicon :
ca_cert_file = '/Applications/ServBay/package/common/openssl/3.2/cacert.pem'
# Pour Intel :
# ca_cert_file = '/Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem'
# Création du contexte SSL en spécifiant le fichier CA
context = ssl.create_default_context(cafile=ca_cert_file)
# Possibilité de spécifier le dossier : context = ssl.create_default_context(capath='/Applications/ServBay/package/common/openssl/3.2/certs')
try:
# Établit une connexion socket classique
with socket.create_connection((server, port)) as sock:
# Enveloppe la socket classique dans une socket SSL
with context.wrap_socket(sock, server_hostname=server) as ssock:
print(f"Connexion SSL établie. Protocole négocié : {ssock.version()}")
# Exemple : envoi de la commande EHLO
ssock.sendall(b"EHLO servbay.demo\r\n") # Exemple de nom de domaine lié à ServBay
while True:
data = ssock.recv(4096)
if not data:
break
print(data.decode())
except Exception as e:
print(f"Échec de connexion ou erreur SSL : {e}")
1
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
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
Exemple 4 : Utiliser OpenSSL dans Node.js (module tls)
Dans Node.js, le module tls
permet d’établir des connexions SSL/TLS. Vous pouvez spécifier le CA via la propriété ca
dans les options de connexion, en lisant le contenu du fichier fourni par ServBay.
javascript
const tls = require('tls');
const fs = require('fs');
const server = 'www.google.com'; // Utilisation d’un serveur de confiance comme exemple
const port = 443;
// Chemin du fichier CA selon la version ServBay
// Pour Apple Silicon :
const caCertFile = '/Applications/ServBay/package/common/openssl/3.2/cacert.pem';
// Pour Intel :
// const caCertFile = '/Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem';
const options = {
host: server,
port: port,
// Chargement du contenu du fichier CA
ca: fs.readFileSync(caCertFile),
// Le module tls de Node.js vérifie par défaut le nom du serveur (checkServerIdentity)
// Si la CA et le certificat du serveur sont valides, la vérification s'effectue correctement.
// Ne désactivez pas checkServerIdentity sans raison précise, cela annule des vérifications cruciales !
// checkServerIdentity: () => { return null; } // <-- Ne pas utiliser cette ligne à moins de bien comprendre les risques !
};
const socket = tls.connect(options, () => {
console.log('Connexion SSL établie');
// Pour une connexion HTTPS, il conviendrait normalement d’envoyer une requête HTTP ; ceci est un exemple minimal
// 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('Connexion fermée');
});
socket.on('error', (error) => {
console.error('Erreur :', error.message); // Affichage du message d’erreur
});
1
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
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
Remarque : Dans l’exemple Node.js, nous avons retiré checkServerIdentity: () => { return null; }
pour des raisons de sécurité. Cette option désactive la vérification du nom de serveur et ne doit en général jamais être utilisée. L’erreur OpenSSL unable to get local issuer certificate
concerne la chaîne de confiance et non la vérification du nom. Il est donc essentiel d’indiquer le bon fichier CA et de s’assurer que le certificat du serveur est valide.
Exemple 5 : Utiliser OpenSSL dans la commande curl
La commande curl
utilise également OpenSSL (ou une autre bibliothèque SSL/TLS) lors des requêtes HTTPS. Spécifiez le fichier CA à l’aide de l’option --cacert
.
bash
# Utilisation du fichier CA fourni par ServBay pour accéder à un site HTTPS
# Choisir le bon chemin selon votre version ServBay
# Pour Apple Silicon :
curl --cacert /Applications/ServBay/package/common/openssl/3.2/cacert.pem https://example.com
# Pour Intel :
# curl --cacert /Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem https://example.com
1
2
3
4
5
6
7
2
3
4
5
6
7
Si le chemin du certificat est correct et que le serveur présente un certificat valide, curl
exécutera la requête sans générer d’erreur de validation.
Résumé
L’erreur 20:unable to get local issuer certificate
est fréquente lors de connexions SSL/TLS gérées par OpenSSL. Elle apparaît lorsque la chaîne de confiance n’est pas explicitement indiquée à OpenSSL, qui ne peut alors pas valider les certificats du serveur.
ServBay propose aux développeurs un fichier cacert.pem
préconfiguré, regroupant l’ensemble des autorités publiques les plus courantes.
Pour solutionner ce problème, il vous suffit d’indiquer le chemin du fichier cacert.pem
de ServBay dans votre environnement de développement (dans php.ini
, dans le contexte SSL/TLS de votre code, ou via les arguments de ligne de commande tels que -CAfile
avec openssl
ou --cacert
avec curl
). Veillez à choisir le chemin correspondant à votre type de puce macOS (Apple Silicon ou Intel) et à la version installée d’OpenSSL via ServBay. Une configuration correcte du stockage des CA vous garantit des communications SSL/TLS fiables et sécurisées dans votre environnement local.