OpenSSL समस्या निवारण: unable to get local issuer certificate
त्रुटि का समाधान
जब आप OpenSSL का उपयोग सुरक्षित कनेक्शन बनाने के लिए करते हैं (जैसे PHP वातावरण में नेटवर्क अनुरोध करना, openssl
या curl
कमांड चलाना, या Node.js/Python ऐप्स में SSL/TLS कनेक्शन स्थापित करना), तो डेवलपर्स को अक्सर 20:unable to get local issuer certificate
जैसी त्रुटि दिखाई देती है। यह एक सामान्य समस्या है, जो OpenSSL के प्रमाणपत्र मान्यकरण प्रक्रिया से संबंधित है।
सुरक्षा कारणों से, डिफ़ॉल्ट रूप से OpenSSL को प्रमाणपत्र चेन वैरिफाई करते समय विश्वसनीय रूट सर्टिफिकेट अथॉरिटी (CA) का पता होना चाहिए। यदि ये ट्रस्ट एंकर नहीं मिलते या निर्धारित नहीं होते, तो OpenSSL सर्वर सर्टिफिकेट की वैधता नहीं पहचान पाता और यही त्रुटि दिखाता है।
यह लेख इस त्रुटि के कारणों की व्याख्या करता है और ServBay वातावरण में PHP, Python, Node.js और curl
कमांड्स के लिए OpenSSL ट्रस्ट स्टोरेज को कॉन्फ़िगर करके इसे हल करने के तरीके प्रदान करता है।
त्रुटि संदेश 20:unable to get local issuer certificate
समस्या विवरण
जब OpenSSL किसी रिमोट सर्वर के SSL/TLS प्रमाणपत्र को वैरिफाई करता है, तो यह सर्वर सर्टिफिकेट से विश्वसनीय रूट CA तक चेन बनाता है। अगर OpenSSL को जरूरी इंटरमीडिएट सर्टिफिकेट्स या रूट CA सर्टिफिकेट लोकल सिस्टम में नहीं मिलते या यदि विश्वसनीय ट्रस्ट स्टोरेज (CAFile या CAPath) कॉन्फ़िगर नहीं किया गया है, तो वैरिफिकेशन विफल होगा और 20:unable to get local issuer certificate
त्रुटि मिलेगी।
साधारण शब्दों में, OpenSSL को पता नहीं है कि किस सर्टिफिकेट अथॉरिटी पर विश्वास करना है, इसलिए यह सर्वर की पहचान की पुष्टि नहीं कर सकता।
ServBay में OpenSSL संस्करण और CA सर्टिफिकेट पथ
ServBay एक इंटीग्रेटेड लोकल वेब डेवलपमेंट वातावरण है, जिसमें OpenSSL पैकेज और प्रमुख पब्लिक रूट CA सर्टिफिकेट्स पहले से शामिल हैं। ServBay में इस्तेमाल हो रहे OpenSSL संस्करण आपके डिवाइस के चिपसेट पर निर्भर करते हैं:
- Apple Silicon (M सीरीज़ चिप्स) वाला ServBay: OpenSSL 3.2.1 संस्करण का उपयोग।
- Intel चिप वाला ServBay: OpenSSL 1.1.1u संस्करण का उपयोग।
इन दोनों OpenSSL संस्करणों के लिए 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
त्रुटि का समाधान यही है कि जिस जगह OpenSSL की ज़रूरत हो, वहां ऊपर बताए गए cafile
या capath
पथ को स्पष्ट रूप से सेट करें ताकि OpenSSL को CA सर्टिफिकेट मिल सके।
समाधान उदाहरण
नीचे दिखाया गया है कि विभिन्न टूल्स एवं प्रोग्रामिंग लैंग्वेज में OpenSSL के CA ट्रस्ट स्टोरेज को कैसे सेट करें।
उदाहरण 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
पैरामीटर द्वारा ServBay में उपलब्ध CA सर्टिफिकेट फाइल का पथ स्पष्ट रूप से दें:
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 return
सिर्फ 1
दिखेगा और 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
# ... अन्य कनेक्शन जानकारी ...
1
2
3
4
5
6
7
2
3
4
5
6
7
उदाहरण 2: PHP में OpenSSL का उपयोग
PHP की अधिकांश नेटवर्किंग सुविधाएँ (जैसे कि file_get_contents
के ज़रिए HTTPS URLs एक्सेस करना, stream_socket_client
से SSL कनेक्शन बनाना, या cURL एक्सटेंशन) OpenSSL पर निर्भर करती हैं। आप php.ini
को एडिट करके या कोड में stream context विकल्पों के माध्यम से CA ट्रस्ट स्टोरेज सेट कर सकते हैं।
विधि A: php.ini
को संशोधित करें (सुपरिश्ट मनाया गया)
यह ग्लोबल समाधान है। अपने PHP संस्करण के लिए php.ini
फाइल एडिट करें (ServBay कंट्रोल पैनल के ज़रिए एडिटिंग संभव है), [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
बदलने के बाद, ServBay में PHP सेवा (या पूरा ServBay) पुनः प्रारंभ करें ताकि बदलाव सक्रिय हों।
विधि B: कोड में सेट करें (केवल वर्तमान कनेक्शन के लिए)
यदि आप ग्लोबल php.ini
नहीं बदलना चाहते, तो stream_context_create
में ssl विकल्पों के जरिए cafile
निर्दिष्ट कर सकते हैं।
php
<?php
// उदाहरण: SSL/TLS के साथ SMTP सर्वर से कनेक्ट करना
$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, // केवल विश्वसनीय CA प्रमाणपत्र स्वीकार करें
'cafile' => $caCertFile, // CA सर्टिफिकेट फाइल निर्दिष्ट करें
// 'capath' => '/Applications/ServBay/package/common/openssl/3.2/certs', // वैकल्पिक
],
];
$context = stream_context_create($contextOptions);
// बनाए गए context से 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
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
उदाहरण 3: Python में OpenSSL का उपयोग (ssl मॉड्यूल)
Python का ssl
मॉड्यूल SSL/TLS context बनाने और ट्रस्टेड CA प्रमाणपत्र निर्दिष्ट करने की सुविधा देता है।
python
import ssl
import socket
server = 'ssl0.ovh.net'
port = 465
# अपने ServBay संस्करण के अनुसार सही CA फाइल पथ निर्दिष्ट करें
# 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 context बनाएँ और CA फाइल निर्दिष्ट करें
context = ssl.create_default_context(cafile=ca_cert_file)
# वैकल्पिक: 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 socket में रैप करें
with context.wrap_socket(sock, server_hostname=server) as ssock:
print(f"SSL कनेक्शन स्थापित। Negotiated Protocol: {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: Node.js में OpenSSL का उपयोग (tls मॉड्यूल)
Node.js का tls
मॉड्यूल TLS/SSL कनेक्शन बनाने के लिए उपयोग किया जाता है। आप कनेक्शन विकल्पों में CA प्रमाणपत्र ca
प्रॉपर्टी के ज़रिए सेट कर सकते हैं, इसकी वैल्यू प्रमाणपत्र string या Buffer array हो सकती है। सबसे आसान तरीका है ServBay की cacert.pem
फाइल को पढ़ना।
javascript
const tls = require('tls');
const fs = require('fs');
const server = 'www.google.com'; // एक स्टैण्डर्ड, विश्वसनीय साइट का उदाहरण
const port = 443;
// ServBay संस्करण के अनुसार सही CA फाइल पथ
// 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 tls मॉड्यूल डिफ़ॉल्ट रूप से hostname वैरिफिकेशन करता है
// यदि CA फाइल सही है और सर्वर सर्टिफिकेट वैध है तो वैरिफिकेशन सफल होना चाहिए।
// checkServerIdentity: () => { return null; } // <-- इस लाइन का उपयोग ना करें, यह सुरक्षा चेक को बंद कर देता है!
};
const socket = tls.connect(options, () => {
console.log('SSL कनेक्शन स्थापित');
// HTTPS कनेक्शन के लिए सामान्य रूप से HTTP request भेजी जाती है; यहाँ केवल कनेक्शन दिखा रहे हैं
// 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
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
नोट: Node.js उदाहरण में checkServerIdentity: () => { return null; }
हटाया गया है। यह विकल्प सुरक्षा कारणों से खतरनाक है, क्योंकि यह सर्वर hostname वैरिफिकेशन को डिसेबल करता है। OpenSSL की “unable to get local issuer certificate” त्रुटि ट्रस्ट रूट से संबंधित है, न कि hostname वैरिफिकेशन से। जब तक CA सही सेट है और सर्वर सर्टिफिकेट वैध है, Node.js डिफॉल्ट वैरिफिकेशन सफल होना चाहिए। अगर hostname वैरिफिकेशन विफल हो तो वह सर्टिफिकेट में गड़बड़ी के कारण होता है न कि CA स्टोर की वजह से।
उदाहरण 5: curl
कमांड में OpenSSL का उपयोग
curl
कमांड HTTPS अनुरोधों के लिए OpenSSL (या कोई अन्य SSL लाइब्रेरी) का इस्तेमाल करता है। आप --cacert
पैरामीटर से CA सर्टिफिकेट फाइल को निर्दिष्ट कर सकते हैं।
bash
# ServBay के CA सर्टिफिकेट फाइल का उपयोग करके 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
अगर CA प्रमाणपत्र पथ सही है और सर्वर सर्टिफिकेट वैध है, तो curl
बिना सर्टिफिकेट त्रुटि दिखाए कंटेन्ट सफलतापूर्वक प्राप्त करेगा।
निष्कर्ष
20:unable to get local issuer certificate
OpenSSL की SSL/TLS कनेक्शन में एक आम त्रुटि है, जो इस कारण से उत्पन्न होती है कि OpenSSL को एक स्पष्ट ट्रस्ट स्टोरेज की जरूरत होती है ताकि वह सर्वर सर्टिफिकेट की वैधता जांच सके। ServBay डेवलपर्स को तैयारशुदा cacert.pem
फाइल मुहैया कराता है जिसमें प्रमुख सार्वजनिक CA रूट्स होते हैं।
इस समस्या का समाधान यह है कि आप अपने डेवलपमेंट वातावरण में (php.ini
, कोड में SSL context विकल्प, openssl
की कमांड लाइन -CAfile
, या curl
की --cacert
) ServBay द्वारा प्रदान की गई cacert.pem
फाइल का स्पष्ट पथ सेट करें। सुनिश्चित करें कि अपने macOS के चिप प्रकार (Apple Silicon या Intel) और संबंधित ServBay OpenSSL संस्करण के अनुसार ही पथ चुनें। CA ट्रस्ट स्टोरेज को सही ढंग से सेट करके, आप अपने लोकल विकास वातावरण को बाहरी SSL/TLS सेवाओं के साथ सुरक्षित रूप से संवाद करने के लिए सक्षम बना सकते हैं।