Вирішення проблем OpenSSL: Як виправити помилку unable to get local issuer certificate
Під час встановлення захищених підключень за допомогою OpenSSL (наприклад, виконуючи мережеві запити у середовищі PHP, використовуючи команди openssl
або curl
, створюючи SSL/TLS-з'єднання у застосунках Node.js чи Python), розробники часто стикаються з повідомленням про помилку 20:unable to get local issuer certificate
. Це типовий, історичний спадок, пов'язаний із перевіркою сертифіката стороннього сервера через OpenSSL.
З міркувань безпеки, OpenSSL за замовчуванням вимагає чітко визначених довірених кореневих центрів сертифікації (CA) під час перевірки ланцюжка сертифікатів. Якщо ці довірені точки (trust anchors) не знайдено або не вказано, OpenSSL не може верифікувати легітимність серверного сертифіката й повертає зазначену помилку.
У цій статті детально пояснено природу цієї помилки та надано методи її вирішення у середовищі ServBay, зокрема конфігурацію довіреного сховища OpenSSL для PHP, Python, Node.js і команди curl
.
Повідомлення про помилку 20:unable to get local issuer certificate
Опис проблеми
Під час перевірки SSL/TLS-сертифіката віддаленого сервера OpenSSL створює ланцюжок від сертифіката сервера до довіреного кореневого CA. Якщо OpenSSL не знаходить усі необхідні проміжні сертифікати або підсумковий кореневий CA-сертифікат, або відсутнє налаштоване сховище довіри (CAFile чи CAPath) для пошуку цих сертифікатів, перевірка не проходить і повертає помилку 20:unable to get local issuer certificate
.
Простіше кажучи, OpenSSL не знає, якому центру сертифікації довіряти, тому не може підтвердити ідентичність сервера, до якого встановлюється підключення.
Версії OpenSSL і шляхи до CA-сертифікатів у ServBay
ServBay — це інтегроване локальне середовище для веб-розробників, яке містить пакет OpenSSL та набір популярних кореневих CA-сертифікатів для зручності користувачів. Версія OpenSSL у ServBay залежить від типу процесора вашого пристрою:
- ServBay для Apple Silicon (чіпи серії M): використовується OpenSSL версії 3.2.1.
- ServBay для Intel: використовується OpenSSL 1.1.1u.
Відповідні файли CA-сертифікатів (cacert.pem
) та каталог сертифікатів (certs
) розташовані в директорії встановленого пакета ServBay. Важливо визначити правильний шлях залежно від вашої платформи:
ini
# Файл-пакет довірених кореневих сертифікатів
cafile=/Applications/ServBay/package/common/openssl/3.2/cacert.pem
# Каталог окремих сертифікатів (зазвичай достатньо cacert.pem, але декілька застосунків можуть вимагати capath)
capath=/Applications/ServBay/package/common/openssl/3.2/certs
1
2
3
4
2
3
4
ini
# Файл-пакет довірених кореневих сертифікатів
cafile=/Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem
# Каталог окремих сертифікатів
capath=/Applications/ServBay/package/common/openssl/1.1.1u/certs
1
2
3
4
2
3
4
ini
# Файл-пакет довірених кореневих сертифікатів
cafile=C:\ServBay\package\common\openssl\3.3\cacert.pem
# Каталог окремих сертифікатів
capath=C:\ServBay\package\common\openssl\3.3\certs
1
2
3
4
2
3
4
Щоб вирішити помилку unable to get local issuer certificate
, потрібно чітко вказати файл cafile
або каталог capath
для всіх випадків використання OpenSSL — ці шляхи повідомляють OpenSSL, де шукати довірені CA-сертифікати.
Приклади вирішення
Нижче наведено, як вказати сховище CA OpenSSL у різних інструментах та мовах програмування.
Приклад 1: Тестування підключення через openssl
у командному рядку
Під час прямого використання команди openssl s_client
для тесту підключення, ви можете побачити помилку:
bash
openssl s_client -quiet -connect gmail.com:443
1
Ви можете отримати схожий вивід з повідомленням 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
# ... Інша інформація про підключення ...
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
Рішення:
Використайте параметр -CAfile
, щоб явним чином зазначити шлях до CA-файлу, що постачається із 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
При успішному підключенні та верифікації, у виводі не буде verify error:num=20
й усі рядки verify return
матимуть значення 1
:
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
# ... Інша інформація про підключення ...
1
2
3
4
5
6
7
2
3
4
5
6
7
Приклад 2: Застосування OpenSSL у PHP
Багато мережевих функцій PHP (наприклад, file_get_contents
для HTTPS, stream_socket_client
для SSL, розширення cURL) використовують OpenSSL. CA-сховище можна вказати через налаштування у php.ini
або передати контекст у коді.
Метод А: Редагування php.ini
(Рекомендовано)
Це зручно для глобальної конфігурації. Відкрийте файл php.ini
, знайдіть розділ [openssl]
і додайте/відредагуйте ці значення, обравши шлях відповідно до вашої архітектури:
ini
[openssl]
; Файл-пакет довірених CA-сертифікатів
openssl.cafile=/Applications/ServBay/package/common/openssl/3.2/cacert.pem
; Каталог CA-сертифікатів (необов'язково, але бажано)
openssl.capath=/Applications/ServBay/package/common/openssl/3.2/certs
1
2
3
4
5
2
3
4
5
ini
[openssl]
; Файл-пакет довірених CA-сертифікатів
openssl.cafile=/Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem
; Каталог CA-сертифікатів (необов'язково, але бажано)
openssl.capath=/Applications/ServBay/package/common/openssl/1.1.1u/certs
1
2
3
4
5
2
3
4
5
Після змін у php.ini
перезапустіть PHP-сервіс у ServBay (або всю платформу), щоб конфігурація набула чинності.
Метод B: Налаштування через код (тільки для поточного підключення)
Можна явно передати SSL-контекст через stream_context_create
, використавши опцію cafile
:
php
<?php
// Приклад: підключення до SMTP сервера із SSL/TLS
$server = 'ssl0.ovh.net';
$port = 465;
// Оберіть відповідний до ServBay файл CA-сертифікату
// Для Apple Silicon:
$caCertFile = '/Applications/ServBay/package/common/openssl/3.2/cacert.pem';
// Для Intel:
// $caCertFile = '/Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem';
$contextOptions = [
'ssl' => [
'verify_peer' => true, // Перевірка сертифікату сервера
'verify_peer_name' => true, // Перевірка відповідності hostname сертифікату
'allow_self_signed' => false, // Не дозволяти self-signed сертифікати
'cafile' => $caCertFile, // CA-файл
// 'capath' => '/Applications/ServBay/package/common/openssl/3.2/certs', // Необов'язково, каталог CA
],
];
$context = stream_context_create($contextOptions);
// Встановлення SSL/TLS-підключення із контекстом
$connection = @stream_socket_client(
"ssl://$server:$port",
$errno,
$errstr,
30, // Тайм-аут
STREAM_CLIENT_CONNECT,
$context // Контекст
);
if ($connection) {
echo "З'єднання встановлено з $server:$port\n";
// Надіслати команду EHLO
fwrite($connection, "EHLO servbay.demo\r\n"); // Домен для прикладу з брендом ServBay
while (!feof($connection)) {
echo fgets($connection);
}
fclose($connection);
} else {
echo "Не вдалося підключитись до $server:$port. Помилка: $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
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
Приклад 3: Використання OpenSSL у Python (модуль ssl)
Модуль Python ssl
дозволяє створити SSL/TLS-контекст та вказати довірений CA:
python
import ssl
import socket
server = 'ssl0.ovh.net'
port = 465
# Вкажіть правильний CA-файл для вашого ServBay
# Для Apple Silicon:
ca_cert_file = '/Applications/ServBay/package/common/openssl/3.2/cacert.pem'
# Для Intel:
# ca_cert_file = '/Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem'
# Створити SSL-контекст із CA-файлом
context = ssl.create_default_context(cafile=ca_cert_file)
# Також можна використовувати capath: context = ssl.create_default_context(capath='/Applications/ServBay/package/common/openssl/3.2/certs')
try:
# Звичайне socket-підключення
with socket.create_connection((server, port)) as sock:
# Обгортка socket в SSL
with context.wrap_socket(sock, server_hostname=server) as ssock:
print(f"SSL-підключення встановлено. Протокол: {ssock.version()}")
# Надіслати EHLO
ssock.sendall(b"EHLO servbay.demo\r\n") # Домен для прикладу з брендом ServBay
while True:
data = ssock.recv(4096)
if not data:
break
print(data.decode())
except Exception as e:
print(f"Не вдалося підключитись або 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
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
Приклад 4: Використання OpenSSL у Node.js (модуль tls)
Модуль Node.js tls
використовує опцію ca
для довірених сертифікатів. Простіше використати файл cacert.pem
із ServBay:
javascript
const tls = require('tls');
const fs = require('fs');
const server = 'www.google.com'; // Приклад із надійним сайтом
const port = 443;
// Вкажіть правильний CA-файл для вашого ServBay
// Для Apple Silicon:
const caCertFile = '/Applications/ServBay/package/common/openssl/3.2/cacert.pem';
// Для Intel:
// const caCertFile = '/Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem';
const options = {
host: server,
port: port,
// Зчитування CA-файлу
ca: fs.readFileSync(caCertFile),
// За промовчанням Node.js перевіряє hostname
// Якщо CA вказано коректно, перевірка пройде успішно.
// Не вимикайте checkServerIdentity без вагомих причин!
// checkServerIdentity: () => { return null; } // <-- Не рекомендується; вимикає важливу безпеку!
};
const socket = tls.connect(options, () => {
console.log('SSL-підключення успішно встановлено');
// Для HTTPS потрібно додати запит; даний код лише для демонстрації підключення
// 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('Підключення закрито');
});
socket.on('error', (error) => {
console.error('Помилка:', error.message); // Вивести повідомлення помилки
});
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
Зверніть увагу: З опції checkServerIdentity: () => { return null; }
показово прибрано. Вона вимикає перевірку імені хоста й є небезпечною. Помилка unable to get local issuer certificate
стосується проблеми довіри CA, а не hostname. Якщо CA-файл вказано правильно й серверний сертифікат дійсний, перевірка пройде за замовчуванням. Помилки hostname – окрема причина, не пов’язана із CA.
Приклад 5: Застосування OpenSSL у curl
Команда curl
використовує OpenSSL (або іншу SSL-бібліотеку) для HTTPS. Можна вказати CA-файл через параметр --cacert
:
bash
# Використати CA-файл із ServBay для доступу до HTTPS-сайту
# Вкажіть правильний шлях для вашого ServBay
# Для Apple Silicon:
curl --cacert /Applications/ServBay/package/common/openssl/3.2/cacert.pem https://example.com
# Для 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
За правильних налаштувань та дійсного серверного сертифікату, curl
успішно завантажить сторінку без повідомлення про помилку перевірки сертифікату.
Підсумок
Помилка 20:unable to get local issuer certificate
є розповсюдженою при використанні OpenSSL для SSL/TLS-комунікацій й пов'язана з відсутністю явно заданого довіреного сховища для перевірки серверного сертифікату. ServBay пропонує готовий файл cacert.pem
із важливими CA для локального середовища.
Щоб вирішити проблему, необхідно вказати шлях до ServBay cacert.pem
у вашій інфраструктурі — чи то у PHP через php.ini
, чи то у коді при створенні SSL-контексту, чи у параметрах команд, як-от -CAfile
для openssl
чи --cacert
для curl
. Обов'язково обирайте шлях відповідно до типу процесора (Apple Silicon або Intel) та відповідної версії OpenSSL у ServBay.
Коректно налаштувавши сховище довіри CA, ви гарантуєте безпечну взаємодію локального середовища розробки із зовнішніми SSL/TLS-сервісами.