Pemecahan Masalah OpenSSL: Mengatasi Error unable to get local issuer certificate
Saat menggunakan OpenSSL untuk koneksi aman (misalnya melakukan permintaan jaringan di lingkungan PHP, menjalankan perintah openssl
atau curl
, atau membangun koneksi SSL/TLS di aplikasi Node.js/Python), para pengembang mungkin menemui pesan error 20:unable to get local issuer certificate
. Ini adalah sebuah masalah umum yang berkaitan dengan cara OpenSSL memverifikasi sertifikat pihak lawan.
Demi alasan keamanan, secara default, OpenSSL membutuhkan informasi jelas mengenai Otoritas Sertifikat (CA) akar yang dipercaya ketika memvalidasi rantai sertifikat. Jika CA tepercaya ini tidak ditemukan atau tidak ditetapkan, OpenSSL tidak dapat memverifikasi legalitas sertifikat server dan akhirnya akan menampilkan error tersebut.
Artikel ini akan menjelaskan penyebab error ini secara detail dan memberikan solusi di lingkungan ServBay, termasuk cara mengkonfigurasi trusted store OpenSSL untuk PHP, Python, Node.js, dan perintah curl
.
Pesan Error 20:unable to get local issuer certificate
Penjelasan Masalah
Ketika OpenSSL mencoba memverifikasi sertifikat SSL/TLS server jarak jauh, ia membangun rantai sertifikat dari sertifikat server hingga CA akar yang terpercaya. Jika OpenSSL tidak dapat menemukan salah satu sertifikat intermediate atau CA akar secara lokal, atau tidak menemukan lokasi trusted store (CAFile atau CAPath) yang dikonfigurasi dengan benar, proses verifikasi akan gagal dan menghasilkan error 20:unable to get local issuer certificate
.
Singkatnya, OpenSSL tidak tahu CA mana yang bisa dipercaya sehingga tidak dapat mengonfirmasi identitas server yang terhubung.
Versi OpenSSL di ServBay dan Path Sertifikat CA
Sebagai lingkungan pengembangan Web lokal terintegrasi, ServBay sudah mengemas paket OpenSSL beserta root CA sertifikat publik yang umum digunakan untuk kemudahan pengembang. Versi OpenSSL yang digunakan ServBay bergantung pada jenis chip perangkat Anda:
- ServBay untuk Apple Silicon (chip seri M): Menggunakan OpenSSL versi 3.2.1.
- ServBay untuk chip Intel: Menggunakan OpenSSL versi 1.1.1u.
Setiap versi OpenSSL ini memiliki file sertifikat CA (cacert.pem
) dan direktori sertifikat (certs
) yang terletak di dalam path instalasi paket ServBay. Temukan path yang sesuai menurut versi ServBay Anda:
ini
# File bundel berisi semua sertifikat root CA terpercaya
cafile=/Applications/ServBay/package/common/openssl/3.2/cacert.pem
# Direktori berisi file sertifikat mandiri (biasanya cacert.pem sudah cukup, tapi beberapa aplikasi mungkin butuh capath)
capath=/Applications/ServBay/package/common/openssl/3.2/certs
1
2
3
4
2
3
4
ini
# File bundel berisi semua sertifikat root CA terpercaya
cafile=/Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem
# Direktori berisi file sertifikat mandiri
capath=/Applications/ServBay/package/common/openssl/1.1.1u/certs
1
2
3
4
2
3
4
Kunci untuk mengatasi error unable to get local issuer certificate
adalah secara eksplisit menentukan path cafile
atau capath
di tempat OpenSSL digunakan, sehingga OpenSSL tahu di mana mencari CA sertifikat tepercaya.
Contoh Solusi
Berikut adalah contoh cara menentukan trusted store CA OpenSSL di berbagai alat dan lingkungan pemrograman.
Contoh 1: Menggunakan Perintah openssl
untuk Pengujian Koneksi
Jika Anda menggunakan perintah openssl s_client
untuk menguji koneksi dan menemukan error berikut:
bash
openssl s_client -quiet -connect gmail.com:443
1
Anda mungkin akan melihat error, seperti verify error:num=20:unable to get local issuer certificate
dalam output:
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 koneksi lainnya ...
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
Solusi:
Tentukan path file bundel CA yang disediakan ServBay melalui parameter -CAfile
:
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
Jika koneksi berhasil dan sertifikat tervalidasi, nilai verify return
pada output akan tetap 1
dan tidak akan muncul lagi baris 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 koneksi lainnya ...
1
2
3
4
5
6
7
2
3
4
5
6
7
Contoh 2: Menggunakan OpenSSL di PHP
Banyak fitur jaringan PHP (seperti mengakses HTTPS melalui file_get_contents
, membangun koneksi SSL dengan stream_socket_client
, atau menggunakan ekstensi cURL) secara internal membutuhkan OpenSSL. Anda bisa menentukan trusted store CA dengan mengedit php.ini
atau lewat stream context di kode.
Metode A: Edit php.ini
(Disarankan)
Ini adalah solusi global paling mudah. Edit file php.ini
yang digunakan PHP (Anda dapat menemukannya dari panel kontrol ServBay), cari bagian [openssl]
, lalu tambahkan atau ubah konfigurasi berikut sesuai jenis chip perangkat Anda.
ini
[openssl]
; Menentukan file bundel sertifikat CA terpercaya
openssl.cafile=/Applications/ServBay/package/common/openssl/3.2/cacert.pem
; Menentukan direktori sertifikat CA (opsional, namun disarankan)
openssl.capath=/Applications/ServBay/package/common/openssl/3.2/certs
1
2
3
4
5
2
3
4
5
ini
[openssl]
; Menentukan file bundel sertifikat CA terpercaya
openssl.cafile=/Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem
; Menentukan direktori sertifikat CA (opsional, namun disarankan)
openssl.capath=/Applications/ServBay/package/common/openssl/1.1.1u/certs
1
2
3
4
5
2
3
4
5
Setelah mengedit php.ini
, restart layanan PHP di ServBay (atau restart seluruh ServBay) agar perubahan berlaku.
Metode B: Menentukan Konfigurasi di Kode (Hanya Untuk Koneksi Tertentu)
Jika tidak ingin mengubah php.ini
global, Anda dapat menentukan opsi cafile
di SSL context ketika membuat koneksi TLS di kode Anda.
php
<?php
// Contoh: Koneksi ke server SMTP yang menggunakan SSL/TLS
$server = 'ssl0.ovh.net';
$port = 465;
// Pilih path file CA sesuai 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 verifikasi sertifikat pihak lawan
'verify_peer_name' => true, // Verifikasi kecocokan hostname dengan sertifikat
'allow_self_signed' => false, // Tidak mengizinkan self-signed certificate kecuali Anda benar-benar mempercayainya
'cafile' => $caCertFile, // Tentukan file CA
// 'capath' => '/Applications/ServBay/package/common/openssl/3.2/certs', // Opsional
],
];
$context = stream_context_create($contextOptions);
// Membuka koneksi SSL/TLS menggunakan context di atas
$connection = @stream_socket_client(
"ssl://$server:$port",
$errno,
$errstr,
30,
STREAM_CLIENT_CONNECT,
$context
);
if ($connection) {
echo "Connection established to $server:$port\n";
// Contoh: kirim perintah EHLO
fwrite($connection, "EHLO servbay.demo\r\n");
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
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
Contoh 3: Menggunakan OpenSSL di Python (modul ssl)
Modul ssl
di Python juga menyediakan opsi untuk membuat TLS context dengan trusted store CA yang Anda tentukan.
python
import ssl
import socket
server = 'ssl0.ovh.net'
port = 465
# Pilih path file CA sesuai versi ServBay Anda
# 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'
# Buat SSL context default dan tentukan file CA
context = ssl.create_default_context(cafile=ca_cert_file)
# Anda juga bisa menggunakan direktori: context = ssl.create_default_context(capath='/Applications/ServBay/package/common/openssl/3.2/certs')
try:
# Membuat koneksi socket biasa
with socket.create_connection((server, port)) as sock:
# Membungkus socket dalam SSL context
with context.wrap_socket(sock, server_hostname=server) as ssock:
print(f"SSL connection established. Negotiated Protocol: {ssock.version()}")
# Contoh: Kirim perintah EHLO
ssock.sendall(b"EHLO servbay.demo\r\n")
while True:
data = ssock.recv(4096)
if not data:
break
print(data.decode())
except Exception as e:
print(f"Failed to connect or SSL error: {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
Contoh 4: Menggunakan OpenSSL di Node.js (modul tls)
Modul tls
di Node.js digunakan untuk membangun koneksi SSL/TLS. Anda bisa menentukan trusted CA sertifikat melalui properti ca
pada pengaturan koneksi. Cara termudah adalah membaca isi file cacert.pem
dari ServBay.
javascript
const tls = require('tls');
const fs = require('fs');
const server = 'www.google.com';
const port = 443;
// Pilih path file CA sesuai 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,
// Membaca isi file sertifikat CA
ca: fs.readFileSync(caCertFile),
// Secara default, module tls Node.js akan melakukan verifikasi host (checkServerIdentity)
// Bila file CA ditentukan dengan benar dan sertifikat server valid, verifikasi akan berhasil.
// Jangan menonaktifkan checkServerIdentity kecuali sudah benar-benar paham risikonya!
// checkServerIdentity: () => { return null; } // <-- Jangan pakai ini sembarangan!
};
const socket = tls.connect(options, () => {
console.log('SSL connection established');
// Untuk koneksi HTTPS, Anda biasanya perlu mengirim HTTP request; di sini hanya sebagai contoh koneksi
// 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('Connection closed');
});
socket.on('error', (error) => {
console.error('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
Catatan: Di contoh Node.js, opsi checkServerIdentity: () => { return null; }
dihapus karena akan menonaktifkan verifikasi nama host server—ini sangat tidak aman. Error OpenSSL unable to get local issuer certificate
berkaitan dengan trusted CA, berbeda dengan verifikasi nama host (verify_peer_name
). Pastikan opsi ca
sudah benar dan sertifikat server valid agar verifikasi oleh Node.js berhasil. Bila error pada verifikasi nama host muncul, biasanya itu masalah sertifikat server, bukan trusted store CA.
Contoh 5: Menggunakan OpenSSL di Perintah curl
Perintah curl
juga menggunakan OpenSSL (atau pustaka SSL lainnya) untuk permintaan HTTPS. Anda bisa menentukan file bundel CA dengan opsi --cacert
.
bash
# Mengakses website HTTPS menggunakan file CA dari ServBay
# Pilih path sesuai versi ServBay
# 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.com
1
2
3
4
5
6
7
2
3
4
5
6
7
Jika path file CA sudah benar dan sertifikat server juga valid, curl
akan berhasil mengakses konten tanpa error verifikasi sertifikat.
Kesimpulan
Error 20:unable to get local issuer certificate
sangat umum ketika menggunakan OpenSSL untuk koneksi SSL/TLS. Penyebab utamanya adalah OpenSSL membutuhkan trusted store eksplisit untuk verifikasi sertifikat server. ServBay menyertakan file cacert.pem
berisi root CA terpercaya yang sering digunakan.
Solusinya adalah selalu menetapkan path file cacert.pem
dari ServBay (baik di php.ini
, opsi context SSL di kode, parameter perintah seperti -CAfile
pada openssl atau --cacert
pada curl), sesuai jenis chip serta versi OpenSSL ServBay Anda. Dengan mengatur trusted store CA dengan benar, Anda dapat memastikan lingkungan pengembangan lokal Anda dapat berkomunikasi dengan aman ke layanan SSL/TLS eksternal.