Sổ tay kỹ thuật

TLS troubleshooting – chain thiếu, hết hạn, SAN sai, SNI, cipher

troubleshooting#tls#openssl#troubleshooting· cập nhật 2026-11-06

Khoanh vùng lỗi handshake TLS khi curl, trình duyệt, gNMI client hoặc thiết bị mạng không chịu kết nối HTTPS.

Sửa trang này
Mục lục

Triệu chứng chính: curl: (60) SSL certificate problem: unable to get local issuer certificate, certificate has expired, no alternative certificate subject name matches target host name, tlsv1 alert protocol version, handshake failure, Python CERTIFICATE_VERIFY_FAILED, Go x509: certificate signed by unknown authority.

Lỗi thường gặp

Triệu chứng Nguyên nhân Cách xử lý
unable to get local issuer certificate (trình duyệt vẫn chạy) Server chỉ gửi leaf, thiếu intermediate Cấu hình fullchain.pem thay cho cert.pem; kiểm tra bằng -showcerts
self-signed certificate in certificate chain / unknown authority Cert do CA nội bộ cấp, client chưa tin root Thêm root CA vào trust store, hoặc trỏ --cacert / -CAfile
certificate has expired Cert hết hạn, hoặc intermediate/root cũ hết hạn trong chain Renew; xem -dates của từng cert trong chain
certificate is not yet valid Đồng hồ client lệch Kiểm tra NTP: timedatectl, chronyc tracking
no alternative certificate subject name matches Hostname không có trong SAN (CN không còn được xét) Cấp lại cert có đúng DNS/IP trong SAN
Đúng domain nhưng nhận cert của domain khác Client không gửi SNI (gọi bằng IP, client cũ), server trả cert mặc định Gọi bằng hostname; với curl dùng --resolve thay vì sửa URL thành IP
tlsv1 alert protocol version Client chỉ hỗ trợ TLS 1.0/1.1 hoặc server tắt TLS 1.2 Bật TLS 1.2 + 1.3 phía server; nâng cấp client
handshake failure / no shared cipher Không có cipher chung (thiết bị cũ, FIPS, cert RSA vs ECDSA) So danh sách cipher hai bên; thử -tls1_2 và cipher cụ thể
key values mismatch khi Nginx start Key không khớp cert So hash public key, xem OpenSSL cheatsheet
wrong version number Nói TLS với cổng plain HTTP (hoặc ngược lại) Kiểm tra cổng/scheme, proxy có terminate TLS chưa
mTLS: certificate required / bad certificate Client không gửi cert, hoặc cert client không do CA server tin cấp Gửi -cert/-key; kiểm tra CA cấu hình phía server, EKU clientAuth
Java/thiết bị mạng báo lỗi, curl thì OK Trust store riêng (JKS, cert store của router) không có root/intermediate Import CA vào keystore/trustpoint riêng của ứng dụng

Các bước khoanh vùng

  1. DNS và cổng đúng chưa? dig +short api.example.com, nc -vz api.example.com 443.
  2. Server gửi gì? openssl s_client ... -showcerts: đếm số cert, xem s: (subject) và i: (issuer) từng cấp nối nhau đến root.
  3. Cert đúng tên, đúng hạn? -dates, -ext subjectAltName.
  4. Client tin CA không? Thử -CAfile với root nội bộ; nếu chạy được thì lỗi nằm ở trust store client.
  5. Phiên bản/cipher? Thử lần lượt -tls1_3, -tls1_2; đọc dòng Protocol và Cipher.
  6. Có proxy ở giữa? Load balancer, Cloudflare, proxy công ty có thể terminate TLS và trả cert khác: so fingerprint với cert trên origin.

Cấu hình đúng

Nginx tối thiểu, chạy được với mọi client hiện đại:

/etc/nginx/conf.d/api.conf
server {
    listen 443 ssl;
    http2 on;
    server_name api.example.com;
 
    ssl_certificate     /etc/letsencrypt/live/api.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
    ssl_protocols       TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers off;
}

Thêm root CA nội bộ vào trust store:

# Debian/Ubuntu (file phải có đuôi .crt, định dạng PEM)
sudo cp lab-root-ca.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates
 
# RHEL/Rocky
sudo cp lab-root-ca.crt /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust

Đừng "sửa" bằng curl -k, verify=False hay insecure: true trong tool automation. Lỗi sẽ biến mất cùng với toàn bộ lợi ích của TLS. Trỏ đúng CA bundle (REQUESTS_CA_BUNDLE, SSL_CERT_FILE, --cacert).

Kiểm tra nhanh

H=api.example.com
# Chain server gửi: dòng s:/i: phải nối nhau
openssl s_client -connect $H:443 -servername $H -showcerts </dev/null 2>/dev/null | grep -E '^ *[0-9] s:|^ *i:'
 
# Thời hạn + SAN của cert đang chạy
openssl s_client -connect $H:443 -servername $H </dev/null 2>/dev/null | openssl x509 -noout -dates -ext subjectAltName
 
# Kết quả verify (0 = ok)
openssl s_client -connect $H:443 -servername $H </dev/null 2>/dev/null | grep 'Verify return code'
 
# Protocol + cipher thương lượng được
openssl s_client -connect $H:443 -servername $H -brief </dev/null
 
# curl chi tiết handshake; ép IP mà vẫn gửi SNI đúng
curl -vI https://$H/ 2>&1 | grep -E 'SSL|TLS|subject|issuer|expire'
curl -vI --resolve $H:443:203.0.113.20 https://$H/
 
# Python dùng CA nào
python3 -c "import ssl; print(ssl.get_default_verify_paths())"

Liên quan: TLS và PKI, Let's Encrypt với certbot.