Penyelesaian Masalah OpenSSL: Atasi Ralat unable to get local issuer certificate
Semasa membuat sambungan selamat dengan OpenSSL (seperti membuat permintaan rangkaian dalam PHP, menjalankan arahan openssl atau curl, atau membina sambungan SSL/TLS dalam aplikasi Node.js/Python), pembangun mungkin akan berdepan mesej ralat 20:unable to get local issuer certificate. Ini merupakan isu lama yang biasa berlaku kerana segala perubahan dan cara OpenSSL mengesahkan sijil rakan sekutu.
Atas sebab keselamatan, OpenSSL secara lalai memerlukan pengetahuan jelas tentang institusi sijil akar (CA) yang dipercayai apabila mengesahkan rantaian sijil. Jika tidak dapat menemui atau tidak menetapkan CA dipercayai ini, OpenSSL tidak dapat mengesahkan kesahihan sijil pelayan, lalu melaporkan ralat tersebut.
Dokumen ini akan menerangkan punca ralat ini serta kaedah untuk mengatasinya dalam persekitaran ServBay, termasuk cara konfigurasi ke stor kepercayaan OpenSSL bagi PHP, Python, Node.js dan arahan curl.
Mesej Ralat 20:unable to get local issuer certificate
Penerangan Masalah
Apabila OpenSSL cuba mengesahkan sijil pelayan jauh melalui SSL/TLS, ia akan membina rantaian sijil dari sijil pelayan ke sijil akar CA yang dipercayai. Jika OpenSSL gagal mencari mana-mana sijil perantaraan atau sijil akar CA yang diperlukan secara tempatan, atau tidak menemui stor kepercayaan yang dikonfigurasi (CAFile atau CAPath), proses pengesahan akan gagal dan ralat 20:unable to get local issuer certificate akan dipaparkan.
Ringkasnya, OpenSSL tidak tahu CA mana yang boleh dipercayai, jadi ia tidak dapat memastikan identiti pelayan yang disambungkan.
Versi OpenSSL dan Laluan Sijil CA dalam ServBay
ServBay adalah persekitaran pembangunan web tempatan yang telah pun menyertakan pakej OpenSSL dan membekalkan sijil akar CA umum yang kerap digunakan untuk kemudahan pembangun. Versi OpenSSL yang digunakan oleh ServBay bergantung pada jenis cip peranti anda:
- ServBay Apple Silicon (Cip Siri M): OpenSSL versi 3.2.1 digunakan.
- ServBay Intel: Menggunakan OpenSSL versi 1.1.1u.
Setiap versi OpenSSL mempunyai fail sijil CA (cacert.pem) dan direktori sijil (certs) masing-masing dalam laluan pemasangan pakej ServBay. Pastikan anda rujuk laluan yang betul mengikut platform dan seni bina anda:
ini
# Fail bundel yang mengandungi semua sijil akar dipercayai
cafile=/Applications/ServBay/package/common/openssl/3.2/cacert.pem
# Direktori fail sijil individu (biasanya cacert.pem sudah memadai, tapi sesetengah aplikasi mungkin perlu capath)
capath=/Applications/ServBay/package/common/openssl/3.2/certs1
2
3
4
2
3
4
ini
# Fail bundel yang mengandungi semua sijil akar dipercayai
cafile=/Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem
# Direktori fail sijil individu
capath=/Applications/ServBay/package/common/openssl/1.1.1u/certs1
2
3
4
2
3
4
ini
# Fail bundel yang mengandungi semua sijil akar dipercayai
cafile=C:\ServBay\package\common\openssl\3.3\cacert.pem
# Direktori fail sijil individu
capath=C:\ServBay\package\common\openssl\3.3\certs1
2
3
4
2
3
4
Kunci utama untuk atasi ralat unable to get local issuer certificate ialah dengan menetapkan laluan cafile atau capath yang dinyatakan di atas di mana-mana aplikasi yang memerlukan OpenSSL, supaya OpenSSL tahu di mana untuk mencari CA dipercayai.
Contoh Penyelesaian
Berikut adalah contoh spesifik bagaimana anda boleh menetapkan stor kepercayaan CA OpenSSL dalam pelbagai alat dan bahasa.
Contoh 1: Ujian Sambungan dengan Arahan openssl
Jika anda menggunakan arahan openssl s_client untuk menguji sambungan dan menghadapi ralat:
bash
openssl s_client -quiet -connect gmail.com:4431
Anda mungkin akan menemui ralat seperti di bawah termasuk 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
# ... Informasi sambungan lain ...1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
Cara Penyelesaian:
Secara jelas tentukan laluan fail sijil CA yang dibekalkan ServBay dengan parameter -CAfile:
bash
openssl s_client -quiet -connect gmail.com:443 -CAfile /Applications/ServBay/package/common/openssl/3.2/cacert.pem1
bash
openssl s_client -quiet -connect gmail.com:443 -CAfile /Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem1
Jika bersambung dan pengesahan berjaya, output verify return akan bernilai 1 dan tiada lagi verify error:num=20:
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
# ... Informasi sambungan lain ...1
2
3
4
5
6
7
2
3
4
5
6
7
Contoh 2: Guna OpenSSL dalam PHP
Banyak ciri rangkaian PHP (seperti file_get_contents untuk HTTPS, stream_socket_client, ekstensi cURL dan lain-lain) bergantung pada OpenSSL. Anda boleh tetapkan stor CA melalui konfigurasi php.ini atau kod melalui stream context.
Kaedah A: Edit php.ini (Disyorkan)
Ini adalah cara paling mudah dan menyeluruh. Edit fail php.ini bagi versi PHP aktif anda (boleh diakses melalui panel kawalan ServBay), cari bahagian [openssl] dan tambah/ubah sebegini, dengan laluan yang betul mengikut cip:
ini
[openssl]
; Fail bundel sijil CA yang dipercayai
openssl.cafile=/Applications/ServBay/package/common/openssl/3.2/cacert.pem
; Direktori sijil CA (pilihan, tetapi digalakkan)
openssl.capath=/Applications/ServBay/package/common/openssl/3.2/certs1
2
3
4
5
2
3
4
5
ini
[openssl]
; Fail bundel sijil CA yang dipercayai
openssl.cafile=/Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem
; Direktori sijil CA (pilihan, tetapi digalakkan)
openssl.capath=/Applications/ServBay/package/common/openssl/1.1.1u/certs1
2
3
4
5
2
3
4
5
Selepas mengubah php.ini, sila but semula servis PHP ServBay atau restart ServBay supaya konfigurasi berkuat kuasa.
Kaedah B: Tambah Konfigurasi dalam Kod (untuk sambungan semasa sahaja)
Jika anda tidak ingin ubah php.ini global, dalam kod anda boleh tetapkan option cafile ketika mencipta stream context.
php
<?php
// Contoh: Membina sambungan ke pelayan SMTP menggunakan SSL/TLS
$server = 'ssl0.ovh.net';
$port = 465;
// Pilih laluan fail CA yang sepadan dengan versi ServBay anda
// Untuk Apple Silicon:
$caCertFile = '/Applications/ServBay/package/common/openssl/3.2/cacert.pem';
// Untuk Intel:
// $caCertFile = '/Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem';
$contextOptions = [
'ssl' => [
'verify_peer' => true, // Aktifkan pengesahan sijil rakan sekutu
'verify_peer_name' => true, // Sahkan nama host dalam sijil
'allow_self_signed' => false, // Jangan benarkan sijil sendiri kecuali anda mempercayainya
'cafile' => $caCertFile, // Fail sijil CA yang dipercayai
// 'capath' => '/Applications/ServBay/package/common/openssl/3.2/certs', // Pilihan, direktori sijil CA
],
];
$context = stream_context_create($contextOptions);
// Membina sambungan SSL/TLS menggunakan context yang ditetapkan
$connection = @stream_socket_client(
"ssl://$server:$port",
$errno,
$errstr,
30, // Masa tamat sambungan
STREAM_CLIENT_CONNECT,
$context // Pilihan context
);
if ($connection) {
echo "Connection established to $server:$port\n";
// Contoh: Hantar arahan EHLO
fwrite($connection, "EHLO servbay.demo\r\n"); // Menggunakan domain demo ServBay
while (!feof($connection)) {
echo fgets($connection);
}
fclose($connection);
} else {
echo "Failed to connect to $server:$port. Error: $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
Contoh 3: Guna OpenSSL dalam Python (modul ssl)
Modul ssl Python membolehkan anda mencipta konteks SSL/TLS serta tentukan sijil CA dipercayai.
python
import ssl
import socket
server = 'ssl0.ovh.net'
port = 465
# Pilih laluan fail CA ServBay yang sesuai
# Untuk Apple Silicon:
ca_cert_file = '/Applications/ServBay/package/common/openssl/3.2/cacert.pem'
# Untuk Intel:
# ca_cert_file = '/Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem'
# Wujudkan konteks SSL default, tentukan fail CA
context = ssl.create_default_context(cafile=ca_cert_file)
# Atau boleh tetapkan direktori: context = ssl.create_default_context(capath='/Applications/ServBay/package/common/openssl/3.2/certs')
try:
# Sambungkan socket biasa dahulu
with socket.create_connection((server, port)) as sock:
# Bungkus socket biasa kepada SSL socket
with context.wrap_socket(sock, server_hostname=server) as ssock:
print(f"Sambungan SSL berjaya. Protokol dirunding: {ssock.version()}")
# Contoh: Hantar arahan EHLO
ssock.sendall(b"EHLO servbay.demo\r\n") # Demo domain ServBay
while True:
data = ssock.recv(4096)
if not data:
break
print(data.decode())
except Exception as e:
print(f"Gagal sambung atau ralat 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
Contoh 4: Guna OpenSSL dalam Node.js (modul tls)
Modul tls Node.js digunakan untuk membina sambungan TLS/SSL. Tentukan CA yang dipercayai melalui property ca dalam pilihan sambungan, yang boleh jadi string, array, atau Buffer sijil. Kaedah paling mudah ialah baca isi cacert.pem ServBay.
javascript
const tls = require('tls');
const fs = require('fs');
const server = 'www.google.com'; // Contoh: laman web yang dipercayai
const port = 443;
// Pilih laluan fail CA yang sesuai dengan versi ServBay anda
// Untuk Apple Silicon:
const caCertFile = '/Applications/ServBay/package/common/openssl/3.2/cacert.pem';
// Untuk Intel:
// const caCertFile = '/Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem';
const options = {
host: server,
port: port,
// Baca isi fail CA
ca: fs.readFileSync(caCertFile),
// Secara lalai, Node.js akan sahkan identiti host (checkServerIdentity)
// Jika fail CA betul dan sijil pelayan sah, pengesahan akan berjaya.
// Jangan matikan checkServerIdentity kecuali anda faham risikonya sepenuhnya.
// checkServerIdentity: () => { return null; } // <-- Tidak digalakkan!
};
const socket = tls.connect(options, () => {
console.log('Sambungan SSL berjaya');
// Untuk HTTPS biasanya memerlukan permintaan HTTP, di sini hanya contoh sambungan
// 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('Sambungan ditutup');
});
socket.on('error', (error) => {
console.error('Ralat:', error.message); // Paparkan error
});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
Perhatian: Dalam contoh Node.js, baris checkServerIdentity: () => { return null; } telah dikeluarkan. Ini kerana ia akan melumpuhkan pengesahan nama host pelayan, sangat berisiko. Ralat unable to get local issuer certificate berkaitan isu CA kepercayaan, bukan sama seperti pengesahan host (verify_peer_name). Jika anda tentukan ca dengan betul dan sijil pelayan sah, Node.js akan melepasi pemeriksaan nama host secara lalai. Jika anda tetap mendapat ralat nama host, biasanya itu isu sijil pelayan dan bukannya CA.
Contoh 5: Guna Arahan curl dengan OpenSSL
Arahan curl turut menggunakan OpenSSL untuk permintaan HTTPS. Anda boleh tentukan fail sijil CA dengan parameter --cacert.
bash
# Akses laman web HTTPS menggunakan fail CA ServBay
# Pilih laluan yang sepadan dengan versi ServBay anda
# Untuk Apple Silicon:
curl --cacert /Applications/ServBay/package/common/openssl/3.2/cacert.pem https://example.com
# Untuk Intel:
# curl --cacert /Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem https://example.com1
2
3
4
5
6
7
2
3
4
5
6
7
Jika laluan CA betul dan sijil pelayan sah, curl akan berjaya mendapatkan kandungan tanpa ralat sijil.
Kesimpulan
Ralat 20:unable to get local issuer certificate adalah sangat lazim semasa membina sambungan SSL/TLS dengan OpenSSL, kerana OpenSSL perlukan stor kepercayaan CA yang jelas untuk pengesahan sijil pelayan. ServBay memudahkan pembangun dengan fail sijil cacert.pem yang telah siap dimuatkan dengan sijil akar awam utama.
Cara utama mengatasi isu ini ialah sentiasa tetapkan laluan fail cacert.pem ServBay di tempat yang sesuai dalam persekitaran anda—sama ada dalam php.ini, pilihan konteks SSL dalam kod, atau parameter arahan seperti -CAfile untuk openssl dan --cacert untuk curl. Pastikan anda pilih laluan yang sepadan dengan cip macOS anda (Apple Silicon atau Intel) dan versi OpenSSL ServBay. Dengan konfigurasi kepercayaan CA yang betul, anda dapat menjamin persekitaran pembangunan tempatan anda mampu berkomunikasi secara selamat dengan servis SSL/TLS luar.
