OpenSSL Sorun Giderme: unable to get local issuer certificate
Hatası Çözümü
OpenSSL ile güvenli bağlantı kurarken (örneğin, PHP ortamında ağ işlemleri, openssl
veya curl
komutlarının çalıştırılması, ya da Node.js/Python uygulamalarında SSL/TLS bağlantıları kurarken), geliştiriciler sıklıkla 20:unable to get local issuer certificate
hata mesajı ile karşılaşabilirler. Bu, OpenSSL’in karşı tarafın sertifikasını nasıl doğruladığı ile ilgili çok yaygın bir geçmişten gelen sorundur.
Güvenlik nedeniyle, OpenSSL varsayılan olarak bir sertifika zincirinin doğrulanmasında güvenilen kök sertifika otoritesini (CA) açıkça bilmek ister. Eksik ya da atanmış bir kök otoriteleri (CA dosyası veya CA dizini) kaynağı yoksa, OpenSSL sunucu sertifikasının geçerli olup olmadığını doğrulayamaz ve bu hatayı verir.
Bu dokümanda, bu hatanın nedenlerine detaylıca değinilecek ve ServBay ortamında çözüm için yöntemler sunulacaktır. Açıklamalar PHP, Python, Node.js ve curl
komutu ile OpenSSL’in güvenilen CA deposunu nasıl yapılandıracağınızı kapsayacaktır.
Hata Mesajı: 20:unable to get local issuer certificate
Sorunun Tanımı
OpenSSL uzak sunucunun SSL/TLS sertifikasını doğrularken, sunucu sertifikasından güvenilen kök CA’ya kadar bir sertifika zinciri oluşturur. Eğer OpenSSL yerelde zincirdeki ara sertifikaları veya nihai kök CA sertifikasını bulamazsa, ya da gerekli güven kaynağının (CAFile veya CAPath) yolu ayarlanmamışsa, doğrulama başarısız olur ve 20:unable to get local issuer certificate
hatasını döndürür.
Kısaca; OpenSSL hangi sertifika otoritesine güveneceğini bilmez ve dolayısıyla bağlanmak istediğiniz sunucunun kimliğini onaylayamaz.
ServBay’de OpenSSL Sürümü ve CA Sertifika Yolu
ServBay; entegre bir yerel web geliştirme ortamı olarak, OpenSSL paketini ve yaygın kök CA sertifikalarını önceden barındırır. ServBay’in kullandığı OpenSSL sürümü cihazınızın işlemci tipine göre değişir:
- Apple Silicon (M serisi çipler) için ServBay: OpenSSL 3.2.1 sürümünü kullanır.
- Intel çipli ServBay: OpenSSL 1.1.1u sürümünü kullanır.
Bu sürümlere karşılık gelen CA sertifika dosyası (cacert.pem
) ve sertifika dizini (certs
), ServBay’in kurulu olduğu dizinlerde bulunur. Cihazınızın platformuna uygun dizini aşağıda bulabilirsiniz:
ini
# Tüm güvenilir kök sertifikaları içeren paket dosyası
cafile=/Applications/ServBay/package/common/openssl/3.2/cacert.pem
# Tekil sertifika dosyalarının bulunduğu dizin (çoğu durumda cacert.pem yeterlidir; bazı uygulamalar capath isteyebilir)
capath=/Applications/ServBay/package/common/openssl/3.2/certs
1
2
3
4
2
3
4
ini
# Tüm güvenilir kök sertifikaları içeren paket dosyası
cafile=/Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem
# Tekil sertifika dosyalarının bulunduğu dizin
capath=/Applications/ServBay/package/common/openssl/1.1.1u/certs
1
2
3
4
2
3
4
ini
# Tüm güvenilir kök sertifikaları içeren paket dosyası
cafile=C:\ServBay\package\common\openssl\3.3\cacert.pem
# Tekil sertifika dosyalarının bulunduğu dizin
capath=C:\ServBay\package\common\openssl\3.3\certs
1
2
3
4
2
3
4
Bu hatayı gidermenin ana yolu, OpenSSL kullanılan her ortamda yukarıda belirtilen cafile
veya capath
yollarını net şekilde tanımlamak ve OpenSSL’e CA sertifikalarını nerede bulacağını göstermektir.
Çözüm Örnekleri
Aşağıda farklı araçlar ve programlama dilleri için OpenSSL CA güven depo yolları nasıl atanır örneklerle gösterilmiştir.
Örnek 1: Bağlantı Testi için openssl
Komutu Kullanımı
Eğer doğrudan openssl s_client
ile bağlantı test ederken hata alırsanız:
bash
openssl s_client -quiet -connect gmail.com:443
1
Benzer bir hata iletisi görebilirsiniz; içinde verify error:num=20:unable to get local issuer certificate
satırı bulunur:
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
# ... diğer bağlantı bilgileri ...
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
Çözüm:
ServBay’in CA sertifikası dosya yolunu -CAfile
parametresi ile belirtin:
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
Bağlantı başarılı olduysa verify return
satırlarında değer 1
olur ve artık verify error:num=20
görünmez:
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
# ... diğer bağlantı bilgileri ...
1
2
3
4
5
6
7
2
3
4
5
6
7
Örnek 2: PHP’de OpenSSL Kullanımı
PHP’de birçok ağ fonksiyonu (ör. HTTPS üzerinden file_get_contents
, stream_socket_client
ile SSL bağlantısı, curl uzantısı vb.) OpenSSL’e dayanır. CA güven deposu için php.ini
dosyasını güncelleyebileceğiniz gibi, kodda stream context ile manuel olarak yol belirtebilirsiniz.
Yöntem A: php.ini
Dosyasını Düzenleme (Önerilen)
Bu yöntemde mevcut PHP sürümüne uygun php.ini
dosyasının [openssl]
kısmına aşağıdaki satırları ekleyin veya güncelleyin; openssl.cafile
ve openssl.capath
ile CA dosyası/dizini belirtin. İşlemci türünüze uygun yolu seçmeyi unutmayın.
ini
[openssl]
; Güvenilir CA sertifikası paket dosyasını belirtin
openssl.cafile=/Applications/ServBay/package/common/openssl/3.2/cacert.pem
; CA sertifika dizinini belirtin (isteğe bağlı ama tavsiye edilir)
openssl.capath=/Applications/ServBay/package/common/openssl/3.2/certs
1
2
3
4
5
2
3
4
5
ini
[openssl]
; Güvenilir CA sertifikası paket dosyasını belirtin
openssl.cafile=/Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem
; CA sertifika dizinini belirtin (isteğe bağlı ama tavsiye edilir)
openssl.capath=/Applications/ServBay/package/common/openssl/1.1.1u/certs
1
2
3
4
5
2
3
4
5
php.ini
yapısı değiştikten sonra ServBay’de PHP servislerini (veya ServBay’i tamamen) yeniden başlatın, ayarlar geçerli olsun.
Yöntem B: Kod ile SSL Context Ayarı (Yalnızca Bağlantı Bazında)
Genel ayarları değiştirmek istemiyorsanız, stream_context_create
ile CA dosyasını doğrudan kodda belirtebilirsiniz.
php
<?php
// Örnek: SSL/TLS kullanan bir SMTP sunucusuna bağlanma
$server = 'ssl0.ovh.net';
$port = 465;
// ServBay sürümünüze uygun CA dosya yolunu seçin
// Apple Silicon için:
$caCertFile = '/Applications/ServBay/package/common/openssl/3.2/cacert.pem';
// Intel için:
// $caCertFile = '/Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem';
$contextOptions = [
'ssl' => [
'verify_peer' => true, // Karşı sertifikayı doğrula
'verify_peer_name' => true, // Sertifika ile bağlanılan host uyumunu kontrol et
'allow_self_signed' => false, // Kendi imzalı sertifikaları reddet (güvenli değil)
'cafile' => $caCertFile, // CA paket dosya yolu
// 'capath' => '/Applications/ServBay/package/common/openssl/3.2/certs', // (isteğe bağlı) CA dizini yolu
],
];
$context = stream_context_create($contextOptions);
// Oluşturulan context ile SSL/TLS bağlantısı açılır
$connection = @stream_socket_client(
"ssl://$server:$port",
$errno,
$errstr,
30, // bağlantı zaman aşımı
STREAM_CLIENT_CONNECT,
$context // context ayarı
);
if ($connection) {
echo "Bağlantı başarıyla kuruldu: $server:$port\n";
// Örnek: EHLO komutu gönderme
fwrite($connection, "EHLO servbay.demo\r\n"); // ServBay markalı örnek domain
while (!feof($connection)) {
echo fgets($connection);
}
fclose($connection);
} else {
echo "Bağlantı kurulamadı: $server:$port. Hata: $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
Örnek 3: Python’da OpenSSL Kullanımı (ssl modülü ile)
Python’un ssl
modülünde de, güvenilen CA dosya/dizini girerek SSL/TLS context oluşturabilirsiniz.
python
import ssl
import socket
server = 'ssl0.ovh.net'
port = 465
# ServBay sürümünüze göre CA dosya yolu
# Apple Silicon için:
ca_cert_file = '/Applications/ServBay/package/common/openssl/3.2/cacert.pem'
# Intel için:
# ca_cert_file = '/Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem'
# Varsayılan SSL context oluştur ve CA dosyasını belirt
context = ssl.create_default_context(cafile=ca_cert_file)
# Alternatif olarak dizin de belirtilebilir: context = ssl.create_default_context(capath='/Applications/ServBay/package/common/openssl/3.2/certs')
try:
# Standart socket bağlantısı
with socket.create_connection((server, port)) as sock:
# Standart socket'i SSL socket'e çevir
with context.wrap_socket(sock, server_hostname=server) as ssock:
print(f"SSL bağlantısı kuruldu. Kullanılan Protokol: {ssock.version()}")
# Örnek: EHLO komutu gönderme
ssock.sendall(b"EHLO servbay.demo\r\n") # ServBay markalı örnek domain
while True:
data = ssock.recv(4096)
if not data:
break
print(data.decode())
except Exception as e:
print(f"Bağlantı kurulamadı veya SSL hatası: {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
Örnek 4: Node.js’de OpenSSL Kullanımı (tls modülü ile)
Node.js’in tls
modülü ile TLS/SSL bağlantısı kurarken CA için dosya yolunu ca
parametresi ile tanımlayabilirsiniz. En kolay yol, ServBay’in cacert.pem
dosyasını okumaktır.
javascript
const tls = require('tls');
const fs = require('fs');
const server = 'www.google.com'; // Örnek olarak standart, güvenilir bir site
const port = 443;
// ServBay sürümüne göre CA dosya yolu
// Apple Silicon için:
const caCertFile = '/Applications/ServBay/package/common/openssl/3.2/cacert.pem';
// Intel için:
// const caCertFile = '/Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem';
const options = {
host: server,
port: port,
// CA sertifika dosyasını oku
ca: fs.readFileSync(caCertFile),
// Node.js tls modülü otomatikman sunucu adı doğrulaması yapar (checkServerIdentity)
// CA dosyası doğruysa ve sunucu sertifikası geçerliyse, doğrulama sorunsuz tamamlanır.
// Güvenlik nedeniyle checkServerIdentity kapatılmamalıdır.
// checkServerIdentity: () => { return null; } // <-- Bu satırı kullanmayın! Kritik güvenlik kontrolünü devre dışı bırakır.
};
const socket = tls.connect(options, () => {
console.log('SSL bağlantısı kuruldu');
// HTTPS bağlantısında genelde HTTP isteği gönderilir; örnek olarak bağlantı açıldıktan sonra
// 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('Bağlantı kapatıldı');
});
socket.on('error', (error) => {
console.error('Hata:', error.message); // Hata detayını yazdır
});
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
Not: Node.js örneğinde checkServerIdentity: () => { return null; }
satırı kaldırılmıştır. Bu kritik doğrulamayı devre dışı bırakır ve son derece güvensizdir. OpenSSL’de unable to get local issuer certificate
hatası; kök CA’nın eksikliği veya ayarsızlığı ile ilgilidir, hostname doğrulama (verify_peer_name
) ile karıştırılmamalıdır. CA dosya yolu düzgün atanır ve sunucu sertifikası geçerliyse, Node.js otomatik olarak hostname doğrulamasını sağlar. Eğer hostname doğrulama hatası alırsanız, bunun nedeni genellikle sertifikanın kendisidir, CA deposu değil.
Örnek 5: curl
Komutu ile OpenSSL Kullanımı
curl
komutu da HTTPS isteklerinde OpenSSL (veya benzeri SSL kütüphanesi) kullanır. --cacert
parametresi ile CA sertifika paket dosyasının yolunu belirtin.
bash
# ServBay’in CA sertifika dosyasını kullanarak bir HTTPS sitesine içerik isteği
# ServBay sürümünüze göre uygun yol seçin
# Apple Silicon için:
curl --cacert /Applications/ServBay/package/common/openssl/3.2/cacert.pem https://example.com
# Intel için:
# 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
CA yolu doğru ve sunucu sertifikası geçerliyse, curl
hata vermeden içeriği başarıyla çeker.
Özet
20:unable to get local issuer certificate
hatası; OpenSSL tabanlı SSL/TLS bağlantılarında yaygın şekilde görülür ve temel nedeni OpenSSL’in bir CA güven kaynağı olmadan sunucu sertifikasını doğrulayamamasıdır. ServBay, geliştiricilere en çok kullanılan CA kök sertifikalarını içeren hazır bir cacert.pem
dosyası sağlar.
Problemin çözümü ise; geliştirme ortamınızda (örn. php.ini
, kodda SSL context ayarları, komutlar için openssl
’de -CAfile
, veya curl
’da --cacert
) ServBay’in sağladığı cacert.pem
dosya yolunu net olarak tanımlamak ve işlemci tipinize (Apple Silicon veya Intel) uygun dizini seçmektir. Bu şekilde CA kaynağı doğru şekilde sunulur ve yerel geliştirme ortamınız dış SSL/TLS servislerle güvenli biçimde iletişim kurabilir.