Ubuntu پر سیلف سائنڈ سرٹیفکیٹ جو Chrome قبول کرے
Ubuntu 24.04 پر openssl کے ساتھ SAN والا سیلف سائنڈ TLS سرٹیفکیٹ بنائیں جو Chrome قبول کرے۔ nginx اور Apache کی تشکیل اور curl -k کے بغیر کلائنٹس کو بھروسہ دلانے کا طریقہ۔
آپ کیا بنا رہے ہیں
ایک سیلف سائنڈ TLS سرٹیفکیٹ جسے جدید براؤزر اور کلائنٹس درست طریقے سے قبول کریں — درست subjectAltName، مناسب کلید پرمیشنز، nginx یا Apache میں تشکیل شدہ — اس کے ساتھ ساتھ وہ حصہ جو تقریباً ہر گائیڈ چھوڑ دیتا ہے: اپنے کلائنٹس کو اس پر درست طریقے سے بھروسہ دلانا، کیونکہ وارننگز پر بھروسہ کرنے اور curl -k کو ہمیشہ کے لیے اسکرپٹس میں ہارڈ کوڈ کرنے کے بجائے یہ بہتر ہے۔ اختتام پر، پانچ کمانڈز پر مشتمل ایک پرائیویٹ CA، جب ایک اندرونی سروس چھ ہو جائے۔
سب سے پہلے فیصلہ، کیونکہ سیلف سائنڈ سرٹیفکیٹ اکثر اس سے کہیں کم درست ٹول ہوتا ہے جتنا اسے استعمال کیا جاتا ہے۔ اگر سروس پبلک انٹرنیٹ پر کسی حقیقی DNS نام تک قابل رسائی ہے، تو پڑھنا بند کریں اور اس کے بجائے nginx پر certbot کے ساتھ مفت Let's Encrypt سرٹیفکیٹ حاصل کریں یا Apache کا متبادل استعمال کریں۔ اس کی کوئی قیمت نہیں ہے، یہ خود بخود رینیو ہوتا ہے، اور دنیا کا ہر براؤزر اس پر پہلے سے بھروسہ کرتا ہے۔ کسی پبلک سائٹ پر سیلف سائنڈ سرٹیفکیٹ آپ کے یوزرز کو سیکیورٹی وارننگز پر بھروسہ کرنے کی عادت ڈالتا ہے، جو کہ سادہ HTTP سے بھی بری عادت ہے۔
سیلف سائنڈ اس وقت درست ٹول ہوتا ہے جب عوامی انٹرنیٹ شامل نہ ہو: آپ کے VPS پر WireGuard ٹنل ایڈریس سے جڑا ایڈمن پینل، پرائیویٹ نیٹ ورک پر ایک اسٹیجنگ باکس، بیک اینڈز کے درمیان سروس ٹو سروس ٹریفک، ہوم لیب آلہ، یا وہ پلیس ہولڈر سرٹیفکیٹ جسے Webmin پورٹ 10000 پر خود کے لیے جنریٹ کرتا ہے اس کی جگہ لینا۔ Let's Encrypt 10.8.0.1 یا git.internal.lan کے لیے سرٹیفکیٹ جاری نہیں کر سکتا — کوئی بھی پبلک CA پرائیویٹ IP یا فرضی TLD کو سرٹیفکیٹ میں شامل نہیں کرے گا۔ ان ناموں کے لیے، آپ خود CA ہیں۔
نیچے دی گئی ہر چیز ایک نئے Ubuntu 24.04 باکس پر چلتی ہے، جس میں OpenSSL 3.0.x موجود ہے (تصدیق کے لیے openssl version)۔ اس میں انٹرنیٹ تک رسائی کی ضرورت نہیں ہے؛ یہ سب کچھ ایئر گیپڈ ماحول میں بھی کام کرتا ہے۔
پرانا one-liner کیوں ایسے سرٹیفکیٹس بناتا ہے جنہیں Chrome مسترد کرتا ہے
ہر pre-2017 ٹیوٹوریل آپ کو جو کمانڈ دیتا ہے وہ اس طرح نظر آتی ہے:
# Do not run this — shown so you recognise it in old guides
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout selfsigned.key -out selfsigned.crtیہ کچھ انٹرایکٹو سوالات پوچھتا ہے، آپ کا hostname Common Name فیلڈ میں رکھتا ہے، اور ایک ایسا سرٹیفکیٹ بناتا ہے جس میں subjectAltName ایکسٹینشن نہیں ہوتی۔ وہ سرٹیفکیٹ بننے سے ہی بے کار ہے۔ Chrome نے اپریل 2017 میں ورژن 58 میں Common Name پڑنا بند کر دیا تھا — RFC 2818 نے سال 2000 میں ہی CN میچنگ کو deprecated کر دیا تھا — اور Firefox، Safari، curl اور Python بھی یہی رویہ رکھتے ہیں۔ ایک سرٹیفکیٹ اپنے سرور کی شناخت SAN ایکسٹینشن کے ذریعے کرتا ہے یا بالکل نہیں کرتا، اور براؤزر آپ کو ایسی بات بالکل ان الفاظ میں بتاتا ہے:
NET::ERR_CERT_COMMON_NAME_INVALID
This server could not prove that it is git.internal.lan; its security
certificate does not specify Subject Alternative Names.ٹرسٹ اسٹور سے ہاتھ ملانے سے اس ایرر کی کوئی اصلاح نہیں ہوتی، کیونکہ سرٹیفکیٹ واقعی کسی چیز کا نام نہیں رکھتا۔ اگر آپ اس وقت NET::ERR_CERT_COMMON_NAME_INVALID کو دیکھ رہے ہیں، تو آپ کے سرٹیفکیٹ میں SAN نہیں ہے (یا غلط ہے) اور آپ کو ایک نیا بنانا ہوگا۔ خوش قسمتی سے حل صرف ایک کمانڈ ہے۔
براؤزرز قبول کرنے والا سرٹیفکیٹ بنائیں: ایک کمانڈ
OpenSSL نے 1.1.1 میں -addext flag متعارف کرایا۔ اس کا مطلب ہے کہ SAN شامل کرنے کے لیے پرانی گائیڈز میں استعمال ہونے والی config-file کی پیچیدگی اب ضروری نہیں۔ Ubuntu 24.04 پر:
sudo openssl req -x509 -newkey rsa:4096 -sha256 -days 730 -noenc \
-keyout /etc/ssl/private/git.internal.key \
-out /etc/ssl/certs/git.internal.crt \
-subj "/CN=git.internal.lan" \
-addext "subjectAltName=DNS:git.internal.lan,IP:10.8.0.1"ہر flag کیا کام کرتا ہے:
-x509بجائے signing request کے براہ راست ایک self-signed سرٹیفکیٹ بناتا ہے۔-newkey rsa:4096اسی مرحلے میں ایک نیا key بناتا ہے۔ RSA 4096 کوئی پرانا کلائنٹ نہیں چکراتا؛ اگر تمام کلائنٹس جدید ہیں، تو-newkey ec -pkeyopt ec_paramgen_curve:P-256چھوٹا اور تیز ہے۔-noencپرانے-nodesکی OpenSSL 3.x ہجے ہے: key پر کوئی passphrase نہیں۔ دونوں ہجے کام کرتے ہیں۔ passphrase والا key اس کا مطلب ہے کہ nginx ہر boot پر ان پٹ کا انتظار کرتے ہوئے رک جاتا ہے، اس لیے سرور key کے لیے آپ کو ییہی چاہیے۔-days 730— دو سال؛ اس نمبر کے بارے میں expiry سیکشن میں مزید بتایا گیا ہے۔-subjانٹرایکٹو سوالات کے جوابات ان لائن دیتا ہے۔ CN اب صرف نام کے لیے ہے، لیکن پھر بھی اسے بنیادی نام پر مقرر کریں؛ کچھ ٹولز اسے دکھاتے ہیں۔-addext "subjectAltName=..."اہم flag ہے۔ کلائنٹس کے ٹائپ کرنے والے ہر نام اور ہر IP کی فہرست بنائیں: hostnames کے لیےDNS:اندراجات (wildcards جیسےDNS:*.internal.lanٹھیک ہیں)، پتوں کے لیےIP:اندراجات۔ اگر کوئی شخصhttps://10.8.0.1پر براؤز کرے گا، توIP:10.8.0.1اندراج وہاں موجود ہونا چاہیے — صرف DNS والا SAN انہیں دوبارہNET::ERR_CERT_COMMON_NAME_INVALIDدے گا۔
کچھ بھی منسلک کرنے سے پہلے تصدیق کریں کہ SAN دراصل شامل ہوا ہے:
openssl x509 -in /etc/ssl/certs/git.internal.crt -noout -ext subjectAltNameدرست آؤٹ پٹ:
X509v3 Subject Alternative Name:
DNS:git.internal.lan, IP Address:10.8.0.1اگر اس کے بجائے No extensions in certificate پرنٹ ہو، تو سرٹیفکیٹ میں کوئی SAN نہیں ہے اور براؤزرز اسے مسترد کر دیں گے — آگے بڑھنے کے بجائے اسے دوبارہ بنائیں۔
کلید کو محفوظ بنائیں
ایک نجی کلید جو ہر صارف پڑھ سکے وہ نجی نہیں رہتی۔ Ubuntu پر، /etc/ssl/private پہلے ہی 710 root:ssl-cert ہے، جو کہ عام نظر کو دور رکھتا ہے، لیکن فائل کو خود واضح طور پر سیٹ کریں:
sudo chown root:root /etc/ssl/private/git.internal.key
sudo chmod 600 /etc/ssl/private/git.internal.keynginx اور Apache دونوں استحقاق چھوڑنے سے پہلے سرٹیفکیٹس کو root کے طور پر پڑھتے ہیں، اس لیے ان کے لیے root:root mode 600 کام کرتا ہے۔ اگر کلید کسی ایسی سروس کے لیے ہے جو اپنے صارف کے طور پر چلتی ہے اور کلید خود لوڈ کرتی ہے — جیسے Node ایپ، Gitea، یا Python daemon — تو اسے chown اس سروس صارف کو دیں، اب بھی mode 600 پر۔ آپ جو کبھی نہیں کریں گے: mode 644، git repository میں کاپی، یا /tmp میں کاپی۔
اسے nginx میں مربوط کریں
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name git.internal.lan;
ssl_certificate /etc/ssl/certs/git.internal.crt;
ssl_certificate_key /etc/ssl/private/git.internal.key;
location / {
proxy_pass http://127.0.0.1:3000;
}
}sudo nginx -t && sudo systemctl reload nginxnginx -t کو syntax is ok اور test is successful چاپ کرنا چاہیے تاکہ reload کوئی کام کرے۔ اگر یہ اس کے بجائے SSL_CTX_use_PrivateKey_file() failed ... key values mismatch چاپ کرے، تو سرٹیفکیٹ اور کلید دو مختلف جنریشن رنز سے ہیں — فیلر موڈز والے سیکشن کو دیکھیں۔
اسے Apache میں مربوط کریں
sudo a2enmod ssl proxy proxy_httpیہاں صرف ssl کافی نہیں ہے: نیچے دیا گیا vhost ProxyPass استعمال کرتا ہے، اور mod_proxy اور mod_proxy_http کے بغور کنفیگریشن ٹیسٹ Invalid command 'ProxyPass', perhaps misspelled or defined by a module not included in the server configuration کے ساتھ ناکام ہو جاتا ہے۔ vhost کو /etc/apache2/sites-available/git-internal.conf کے نام سے محفوظ کریں:
<VirtualHost *:443>
ServerName git.internal.lan
SSLEngine on
SSLCertificateFile /etc/ssl/certs/git.internal.crt
SSLCertificateKeyFile /etc/ssl/private/git.internal.key
ProxyPass / http://127.0.0.1:3000/
ProxyPassReverse / http://127.0.0.1:3000/
</VirtualHost>sudo a2ensite git-internal
sudo apache2ctl configtest && sudo systemctl reload apache2configtest کو Syntax OK کا جواب دینا چاہیے۔ اب کسی کلائنٹ مشین سے ٹیسٹ کریں:
curl -v https://git.internal.lan/اور آپ کو ایک خرابی ملے گی:
curl: (60) SSL certificate problem: self-signed certificateیہ کوئی بگ نہیں ہے۔ یہ TLS کا درست کام کرنا ہے: curl نے آپ کے سرٹیفکیٹ کو کبھی نہیں دیکھا اور ایسے سرور سے بات کرنے سے انکار کرتا ہے جس کی وہ تصدیق نہیں کر سکتا۔ اگلا حصہ اصل حل ہے — اور یہ وہ نہیں جو اس وقت انٹرنیٹ کا آدھا حصہ بالکل یہی کر رہا ہے۔
کلائنٹس کو اس پر بھروسہ دلائیں — اور ان غلط طریقوں سے پرہیز کریں
پہلے غلط حل، ان کے اصل ناموں کے ساتھ۔ کسی اسکرپٹ میں شامل curl -k (یا --insecure، Python requests میں verify=False، Node میں NODE_TLS_REJECT_UNAUTHORIZED=0 — ان میں سے کوئی بھی آپ کے سرٹیفکیٹ کو قابلِ اعتماد نہیں بناتا۔ یہ سرٹیفکیٹ کی تصدیق بند کر دیتے ہیں۔ اس کا مطلب ہے کہ کلائنٹ کسی بھی سرور سے بلاتامل بات چیت کرے گا جو کوئی بھی سرٹیفکیٹ پیش کرے، بشمول کسی حملہ آور کا دیا ہوا۔ آپ TLS کا اوور ہیڈ تو برداشت کرتے ہیں، مگر تصدیق جو اس کا اصل مقصد تھی وہ ضائع ہو جاتی ہے۔ بدتر یہ کہ یہ فلگز پھیلتے ہیں: ایک cron job میں پیسٹ کیے جاتے ہیں، پھر deploy اسکرپٹ میں، پھر پروڈکشن کوڈ میں، یہاں تک کہ کوئی نہیں جانتا کہ کون سی کنکشنز عارضی تھیں۔ اگر verify=False ڈیبگنگ سیشن سے آگے بھی باقی رہتا ہے تو ڈیزائن غلط ہے۔
درست حل یہ ہے کہ ہر کلائنٹ OS کو بتایا جائے کہ یہ سرٹیفکیٹ ایک قابلِ اعتماد روٹ ہے۔ Ubuntu اور Debian کلائنٹس پر:
sudo cp git.internal.crt /usr/local/share/ca-certificates/git.internal.crt
sudo update-ca-certificatesآؤٹ پٹ میں جو لائن اہم ہے (اس کے بعد ایک Running hooks in /etc/ca-certificates/update.d... بلاک آتا ہے):
Updating certificates in /etc/ssl/certs...
1 added, 0 removed; done.ان لائنوں میں دو مشکلات چھپی ہیں۔ فائل کا اختتام .crt پر ضرور ہونا چاہیے — .pem ایکسٹینشن خاموشی سے نظر انداز ہو جاتی ہے اور آپ کو کوئی ایرر میسج کے بغیر 0 added مل جاتا ہے۔ اور مواد PEM ہونا چاہیے — فائل کا آغاز -----BEGIN CERTIFICATE----- سے ہوتا ہے؛ پہلے DER بائنری کو openssl x509 -inform der -in file.der -out file.crt سے تبدیل کریں۔ سیلف سائنڈ سرٹیفکیٹ کو بطورِ روٹ شامل کرنا اس لیے کام کرتا ہے کیونکہ سیلف سائنڈ سرٹیفکیٹ اپنا روٹ ہوتا ہے۔
اس کے بعد curl، wget، git، apt، اور نظام کے بنڈل کے خلاف OpenSSL استعمال کرنے والی ہر دوسری چیز بغیر کسی فلگ کے سرور پر بھروسہ کرتی ہے۔ چند کلائنٹس اپنے ذاتی ٹرسٹ اسٹورز رکھتے ہیں جن کے لیے انفرادی علاج درکار ہوتا ہے:
- لینکس پر Chrome/Chromium سسٹم اسٹور نہیں بلکہ NSS ڈیٹا بیس پڑھتا ہے: فی یوزر
sudo apt install libnss3-tools، پھرcertutil -d sql:$HOME/.pki/nssdb -A -t "C,," -n "git.internal" -i git.internal.crt۔ - Firefox کا اپنا اسٹور ہے: Settings → Privacy & Security → Certificates → Import، یا
about:configمیںsecurity.enterprise_roots.enabledکوtrueپر سیٹ کریں تاکہ یہ سسٹم اسٹور پڑھے۔ - Python requests اپنا CA بنڈل (certifi) شپ کرتا ہے اور سسٹم اسٹور کو نظر انداز کرتا ہے:
verify="/usr/local/share/ca-certificates/git.internal.crt"پاس کریں یاREQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crtایکسپورٹ کریں۔ - Node.js:
NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/git.internal.crtایکسپورٹ کریں۔
Windows کلائنٹس پر، .crt پر ڈبل کلک کریں اور اسے Trusted Root Certification Authorities میں انسٹال کریں؛ macOS پر، اسے Keychain Access میں System keychain میں شامل کریں اور Always Trust کا نشان لگائیں۔
ایک ہی روٹ متعدد سروسز کے لیے: ایک چھوٹا پرائیویٹ CA
فی سرٹیفکیٹ ٹرسٹ فوراً پیمانے پر نہیں اپتی ہے: 6 سروسز کا 4 کلائنٹ مشینوں کا ضرب 24 ٹرسٹ انسٹالیشنز بنتے ہیں، اور ہر نئی سروس مزید اضافہ کرتی ہے۔ اس کا حل ایک پرائیویٹ CA ہے — کلائنٹس ایک روٹ پر بھروسہ کرتے ہیں، اور آپ ہر سروس کا سرٹیفکیٹ اسی سے سائن کرتے ہیں۔
پسندیدہ آپشن mkcert ہے، جو Ubuntu 24.04 ریپوز میں موجود ہے اور NSS اسٹورز (Chrome، Firefox) کو سنبھالتا ہے جو update-ca-certificates چھوڑ دیتا ہے:
sudo apt install -y mkcert libnss3-tools
mkcert -install
mkcert git.internal.lan "*.internal.lan" 10.8.0.1mkcert -install ایک روٹ بنتا ہے اور اسے اس مشین کے ہر ٹرسٹ اسٹور میں رجسٹر کرتا ہے؛ تیسرا کمانڈ git.internal.lan+2.pem اور git.internal.lan+2-key.pem خارج کرتا ہے، جو اوپر والے nginx یا Apache اسنیپٹس میں ڈالنے کے لیے تیار ہیں۔ اس کا ڈیزائن مفروضہ ایک ڈویلپمنٹ مشین ہے — روٹ کلید اسی باکس پر رہتا ہے جس نے -install چلایا — لہٰذا یہ ڈیولپر لیپ ٹاپ کے لیے بہترین ہے اور سرور بیڑے کے لیے غلط شکل ہے۔
سرورز کے لیے، سادا OpenSSL پورا CA 5 کمانڈز میں کر دیتا ہے:
openssl genrsa -out lab-ca.key 4096
openssl req -x509 -new -key lab-ca.key -sha256 -days 3650 \
-out lab-ca.crt -subj "/CN=Lab Internal CA" \
-addext "basicConstraints=critical,CA:TRUE,pathlen:0" \
-addext "keyUsage=critical,keyCertSign,cRLSign"
openssl genrsa -out git.key 2048
openssl req -new -key git.key -out git.csr -subj "/CN=git.internal.lan" \
-addext "subjectAltName=DNS:git.internal.lan,IP:10.8.0.1"
openssl x509 -req -in git.csr -CA lab-ca.crt -CAkey lab-ca.key \
-CAcreateserial -days 730 -sha256 -copy_extensions copy -out git.crtفہرست کا آخری کمانڈ ایک جال ہے: openssl x509 -req بنیادی طور پر CSR سے تمام ایکسٹینشنز ہٹا دیتا ہے، بشمول وہ SAN جسے آپ نے احتیاط سے شامل کیا تھا۔ -copy_extensions copy (ایک OpenSSL 3.x آپشن، لہٰذا یہ 24.04 پر کام کرتا ہے) انہیں منتقل کرتا ہے؛ اسے چھوڑیں تو سائن شدہ سرٹیفکیٹ میں کوئی SAN نہیں ہوگا، اور Chrome آپ کو دوبارہ NET::ERR_CERT_COMMON_NAME_INVALID سے استقبال کرے گا۔ پہلے کی طرح اسی openssl x509 -noout -ext subjectAltName چیک سے تصدیق کریں۔
lab-ca.crt کو کلائنٹس پر اوپر والے ٹرسٹ اسٹور کے مراحل سے تقسیم کریں — فی مشین، صرف ایک بار، ہمیشہ کے لیے۔ lab-ca.key کی حفاظت اس کی موجودہ اہمیت کے مطابق کریں: mode 600، بالکل وہ باکس جو ان سرورز میں سے ایک نہیں ہے جن کے لیے یہ سائن کرتا ہے، کیونکہ جو اسے رکھتا ہے وہ آپ کے کلائنٹس کے ماننے والے کسی بھی نام کے لیے سرٹیفکیٹ بنا سکتا ہے۔
خروجی اور روٹیشن
پبلک CA سرٹیفکیٹ کی زندگی کم ہو رہی ہے — CA/Browser Forum نے مارچ 2026 میں نئے جاری شدہ پبلکلی ٹرسٹڈ سرٹیفکیٹس کی حد 200 دن مقرر کی (پہلے 398 تھی)، جو 2027 میں 100 دن اور مارچ 2029 تک 47 دن ہو جائے گی — لیکن یہ قواعد پبلکلی ٹرسٹڈ CA پر لاگو ہوتے ہیں۔ آپ کا پرائیویٹ CA ان کے تابع نہیں، اور براؤزرز انہیں مینولی انسٹال کردہ روٹس پر نافذ نہیں کرتے۔ ایک عملی پابندی ضرور لاگو ہوتی ہے: Apple پلیٹ فارمز 825 دن سے زیادہ مدت والے کسی بھی TLS سرور سرٹیفکیٹ کو مسترد کر دیتے ہیں، چاہے جو بھی جاری کرنے والا ہو۔ لہذا اگر iPhone یا Mac کنیکٹ ہوں گے، تو لیف سرٹیفکیٹس کو دو سال یا اس سے کم رکھیں۔ -days 730 ہر جگہ اس حد کو پورا کرتا ہے؛ دس سالہ روٹ کے ساتھ دو سالہ لیفز ایک بہترین اندرونی ڈھانچہ ہے۔
طویل عمر والے سرٹیفکیٹس صرف ایک ہی طرح ناکام ہوتے ہیں: خاموشی سے، ایک ساتھ، ایسی تاریخ پر جسے کوئی یاد نہیں رکھتا۔ آپ کے پاس کیا ہے اس کی جانچ کریں:
openssl x509 -in /etc/ssl/certs/git.internal.crt -noout -enddateنیول کو کسی حقیقی کیلنڈر میں داخل کریں، یا cron کو 30 دن پہلے یاد دلائیں — openssl x509 -checkend 2592000 -in cert.crt ایکسپائری اس سیکنڈ کے اندر ہونے پر non-zero ایگزٹ کرتا ہے۔ اگر آپ پہلے ہی Uptime Kuma اسٹیٹس مانیٹرنگ کے لیے چلا رہے ہیں، تو اس کے HTTPS مانیٹرز بغیر کسی اضافی قیمت کے قریب آنے والی سرٹیفکیٹ ایکسپائری کو ظاہر کر دیتے ہیں۔
پرائیویٹ CA کے ساتھ روٹیشن بہت آسان ہے: CSR-and-sign کمانڈز دوبارہ چلائیں، فائلیں تبدیل کریں، اور web server ری لوڈ کریں۔ روٹ تبدیل نہیں ہوا، اس لیے کلائنٹ کو کچھ بھی محسوس نہیں ہوتا۔
ناکامی کے طریقے، جن اسٹرنگز کی تمھیں نظر آئے گی
NET::ERR_CERT_AUTHORITY_INVALID — یہ اعتماد انسٹال کرنے سے پہلے کی متوقع حالت ہے، سرٹیفکیٹ میں کوئی خامی نہیں۔ اگر یہ روٹ انسٹال کرنے کے بعد بھی برقرار رہے: Linux پر، Chrome سسٹم اسٹور کے بجائے NSS پڑھتا ہے (certutil والا مرحلہ دیکھیں)؛ یا کاپی کی گئی فائل کا اختتام .crt پر نہیں ہوا اور update-ca-certificates نے 0 added بتایا؛ یا سرور وہ سرٹیفکیٹ پیش نہیں کر رہا جس پر تمھیں اعتماد ہے — فنگر پرنٹس کا موازنہ openssl s_client -connect git.internal.lan:443 </dev/null 2>/dev/null | openssl x509 -noout -fingerprint -sha256 سے کریں۔
NET::ERR_CERT_COMMON_NAME_INVALID — سرٹیفکیٹ میں کوئی SAN نہیں ہے، یا SAN ایڈریس بار میں موجود نام کا احاطہ نہیں کرتا۔ کلاسک کیس: SAN میں DNS:git.internal.lan درج ہے لیکن صارف نے https://10.8.0.1 تک براؤز کیا۔ اعتماد اسٹور میں تبدیلیاں اسے ٹھیک نہیں کر سکتیں؛ غائب اندراج کے ساتھ سرٹیفکیٹ دوبارہ جاری کریں۔
curl: (60) SSL certificate problem: self-signed certificate — curl کو سرٹیفکیٹ پر اعتماد نہیں ہے۔ قسم self-signed certificate in certificate chain کا مطلب آپ کی نجی CA کے دستخط شدہ سرٹیفکیٹ کے لیے وہی ہے۔ یکبار استعمال ہونے والا حل: curl --cacert lab-ca.crt https://...؛ مستقل حل: اعتماد اسٹور۔ -k نہیں۔
unable to load certificate ... Expecting: TRUSTED CERTIFICATE (یا Expecting: CERTIFICATE REQUEST، یا no start line) — PEM کا الجھنا۔ آپ نے OpenSSL کو غلط قسم کی فائل دی: وہاں سرٹیفکیٹ کی توقع تھی لیکن آپ نے کلید یا CSR دی، یا PEM کی توقع تھی لیکن آپ نے DER بائنری دی۔ head -1 filename آپ کو بتاتا ہے کہ آپ کے پاس اصل میں کیا ہے — ایک سرٹیفکیٹ کا آغاز -----BEGIN CERTIFICATE----- سے ہوتا ہے۔ DER کے لیے، openssl x509 -inform der -in file.der -out file.crt سے تبدیل کریں۔
nginx: [emerg] SSL_CTX_use_PrivateKey_file(...) failed (SSL: error ... key values mismatch) — سرٹیفکیٹ اور کلید ایک ساتھ تعلق نہیں رکھتے، عام طور پر اس لیے کہ جنریشن کمانڈ دو بار چلائی گئی اور فائلیں مل گئیں۔ تصدیق کریں: openssl x509 -in git.internal.crt -noout -pubkey | sha256sum بمقابلہ openssl pkey -in git.internal.key -pubout | sha256sum؛ میچنگ ہیشز کا مطلب میچنگ جوڑا ہے۔ اگر وہ مختلف ہوں، تو دونوں کو ایک ساتھ دوبارہ جنریٹ کریں۔
FAQ
جب میں نے خود دستخط شدہ سرٹیفکیٹ بنا دیا ہے تو Chrome اب بھی کیوں کہتا ہے "Not secure"؟
اگر خرابی NET::ERR_CERT_AUTHORITY_INVALID ہے تو سرٹیفکیٹ ٹھیک ہے۔ Chrome کا اس پر ابھی اعتبار کرنے کو کوئی وجہ نہیں ہے۔ اسے (یا اپنی نجی CA root کو) کلائنٹ کے trust store میں انسٹال کریں۔ یاد رکھیں کہ Linux پر Chrome system store کے بجائے certutil کے ذریعے NSS database استعمال کرتا ہے۔ اگر خرابی NET::ERR_CERT_COMMON_NAME_INVALID ہے تو سرٹیفکیٹ میں URL سے مطابقت رکھنے والا Subject Alternative Name موجود نہیں ہے اور اسے -addext "subjectAltName=..." کے ساتھ دوبارہ جاری کرنا ہوگا۔
میں curl کو -k کے بغیر خود دستخط شدہ سرٹیفکیٹ پر کیسے اعتبار کرواؤں؟
سرٹیفکیٹ (PEM format، .crt extension) کو /usr/local/share/ca-certificates/ میں کاپی کریں اور sudo update-ca-certificates چلائیں۔ output میں 1 added لکھا ہونا چاہیے۔ اس کے بعد curl اسے کسی بھی public سرٹیفکیٹ کی طرح تصدیق کرتا ہے۔ system کو چھوڑے بغیر صرف ایک درخواست کے لیے، curl --cacert /path/to/cert.crt صرف اسی فائل کے خلاف تصدیق کرتا ہے۔ -k تصدیق کو مکمل طور پر غیر فعال کر دیتا ہے اور یہ کسی کی scripts میں نہیں ہونا چاہیے۔
خود دستخط شدہ سرٹیفکیٹ کتنی مدت تک درست رہ سکتا ہے؟
تکنیکی طور پر جتنی چاہیں۔ CA/Browser Forum کی حدود (اب 200 دن، 2029 تک 47 دن) عوامی قابل اعتماد CAs پر لاگو ہوتی ہیں، نجی اعتبار پر نہیں۔ عملی طور پر، server سرٹیفکیٹس کو 825 دن تک محدود رکھیں، کیونکہ Apple devices جاری کنندہ کی پرواہ کیے بغیر اس سے طویل کچھ بھی مسترد کر دیتے ہیں۔ دو سال (-days 730) کے leaf سرٹیفکیٹس کے ساتھ دس سال کا نجی root ایک معقول default ہے۔ بس تجدید کی تاریخ کیلنڈر میں لگا دیں، کیونکہ ایک ختم ہونے والا internal سرٹیفکیٹ ایسی تاریخ پر خاموشی سے سب کچھ نیچے لے جاتا ہے جسے کوئی یاد نہیں رکھتا۔
کیا میں خود دستخط شدہ سرٹیفکیٹ استعمال کروں یا Let's Encrypt؟
اگر service کا ایک public DNS name ہے اور یہ internet سے قابل رسائی ہے، تو ہمیشہ Let's Encrypt استعمال کریں۔ یہ مفت ہے، خودکار ہے، اور ہر کلائنٹ پر پہلے سے قابل اعتماد ہے۔ خود دستخط شدہ (یا نجی CA) ان چیزوں کے لیے ہے جو Let's Encrypt جاری نہیں کر سکتا: نجی IP، صرف internal hostnames جیسے .lan، air-gapped networks، اور جان بوجھ کر VPN کے پیچھے چھپائی گئی services۔ یہ فیصلہ رسائی اور نام کے بارے میں ہے، سیکیورٹی کی طاقت کے بارے میں نہیں۔ cryptography بالکل یکساں ہے۔
جب میں نے اسے /usr/local/share/ca-certificates میں شامل کر دیا ہے تو میرا سرٹیفکیٹ اب بھی کیوں مسترد ہوتا ہے؟
تین چیزیں چیک کریں۔ فائل کا نام .crt پر ختم ہونا چاہیے۔ .pem extension کو خاموشی سے چھوڑ دیا جاتا ہے اور update-ca-certificates میں 0 added گزارش ہوتی ہے۔ contents میں -----BEGIN CERTIFICATE----- سے شروع ہونے والا PEM text ہونا چاہیے، DER binary نہیں۔ اور application واقعی system store استعمال کرتا ہو۔ Linux پر Chrome، Firefox، Python requests، Node.js، اور Java ہر ایک کا اپنا نجی trust store ہوتا ہے اور انہیں سرٹیفکیٹ علیحدہ طور پر شامل کرنا پڑتا ہے۔