EasyDeploy
Wróć do bloga
ssl tls certyfikaty security pki troubleshooting

Dlaczego mój certyfikat nie jest zaufany? Systematyczna checklista rozwiązywania problemów

Autor: Łukasz Tomalczyk , założyciel EasyDeploy ·
Dlaczego mój certyfikat nie jest zaufany? Systematyczna checklista rozwiązywania problemów

“Niezaufany”, “niebezpieczne połączenie”, “Twoje połączenie nie jest prywatne” — każdy klient formułuje to inaczej, ale pytanie w tle zawsze jest to samo: czy klient zdołał zbudować poprawny łańcuch zaufania od otrzymanego certyfikatu do roota, któremu już ufa? Kiedy się nie uda, to jedyny komunikat, jaki dostajesz. Nie mówi Ci, dlaczego.

To checklista pomagająca znaleźć rzeczywistą przyczynę, w mniej więcej takiej kolejności, w jakiej zwykle się okazuje, że to właśnie ona.

TL;DR: najszybszy sposób, żeby sprawdzić dlaczego

openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | grep -A2 "Verify return code"

Podmień example.com na swój host. Linia Verify return code na końcu mówi dokładnie, który test zawiódł. Przejdź do szybkiej ściągawki poniżej, żeby rozszyfrować numer, i przejdź od razu do odpowiedniego kroku.

Krok 1: Sprawdź, czy łańcuch jest kompletny

Zdecydowanie najczęstsza przyczyna. Serwer musi wysłać certyfikat liściowy oraz każdy certyfikat intermediate CA aż do (ale nie włącznie) roota, któremu klient już ufa. Brak intermediate daje kod weryfikacji 20 (unable to get local issuer certificate) albo 21 (unable to verify the first certificate).

openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null

Policz certyfikaty w wyniku. Jeśli widzisz tylko jeden (para s: / i:), serwer wysyła tylko certyfikat liściowy. Rozwiązanie: skonfiguruj serwer (albo load balancer, albo reverse proxy), żeby serwował pełny łańcuch, nie tylko certyfikat końcowy.

To także powód, dla którego ten sam źle skonfigurowany serwer może “działać” w przeglądarce, a zawodzić w curl albo backendowym kliencie HTTP: przeglądarki cache’ują intermediate’y widziane na innych stronach i po cichu same dokańczają łańcuch. curl, większość bibliotek HTTP i backendowe usługi z minimalnym trust store’em nie zrobią Ci tej przysługi.

Krok 2: Sprawdź terminy ważności — całego łańcucha, nie tylko swojego certyfikatu

openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null 2>/dev/null \
  | openssl x509 -noout -dates

To sprawdza tylko certyfikat liściowy. Twój certyfikat może być ważny, podczas gdy intermediate nad nim już wygasł — sprawdź każdy certyfikat, który wypisał s_client -showcerts, nie tylko pierwszy. Dokładnie to spowodowało kilka głośnych publicznych incydentów, gdzie pozornie w pełni poprawny certyfikat zaczynał zawodzić z dnia na dzień, bo wygasał intermediate CA.

Krok 3: Sprawdź zgodność hostname / SAN

openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null 2>/dev/null \
  | openssl x509 -noout -subject -ext subjectAltName

Od Chrome 58 przy walidacji hostname liczy się tylko Subject Alternative Name (SAN) — Common Name jest ignorowane. Jeśli hostname, z którym się łączysz, nie znajduje się w subjectAltName (włączając w to www. kontra goła domena — to różne hostname’y), walidacja zawiedzie niezależnie od tego, że wszystko inne jest poprawne.

Krok 4: Sprawdź, czy to certyfikat self-signed albo z prywatnego CA, któremu klient nie ufa

Kody weryfikacji 18 (self-signed certificate) i 19 (self-signed certificate in the chain) oznaczają, że root łańcucha nie znajduje się w trust store kliencie — spodziewane przy lokalnym developmencie, spodziewane też przy wewnętrznych/prywatnych CA, dopóki jawnie nie rozdystrybuujesz i nie zainstalujesz certyfikatu tego CA na każdej maszynie czy kontenerze, który ma mu ufać. Jeśli to usługa wewnętrzna, rozwiązaniem nie jest “prawdziwy” certyfikat — tylko upewnienie się, że Twoje prywatne CA jest faktycznie zaufane tam, gdzie powinno być.

Krok 5: Sprawdź zegar systemowy

Certyfikat jest ważny tylko w oknie notBefore / notAfter. Klient ze źle ustawionym zegarem — częste na kontenerach, maszynach wirtualnych, które straciły synchronizację NTP, albo runnerach CI — zgłosi całkowicie poprawny certyfikat jako wygasły albo “jeszcze nieważny”. Jeśli krok 2 mówi, że daty są w porządku, a błąd wciąż występuje, sprawdź date (albo w32tm /query /status na Windowsie) na kliencie, nie na serwerze.

Krok 6: Sprawdź, czy faktycznie serwujesz certyfikat, który myślisz, że serwujesz

Na serwerze obsługującym wiele domen (wiele vhostów, wiele reguł ingress, load balancer routujący po SNI) łatwo skończyć z serwowaniem złego certyfikatu dla danego hostname — certyfikat poprawny, ale nie ta strona. Potwierdź, że subject i subjectAltName, które widzisz w kroku 1, faktycznie odpowiadają certyfikatowi, który zamierzałeś tam serwować, a nie po prostu jakiemuś ważnemu certyfikatowi.

Krok 7: Sprawdź status rewokacji

Najrzadsza przyczyna, ale warto wykluczyć ją na końcu: jeśli certyfikat został odwołany, część klientów aktywnie go odrzuci przez CRL albo OCSP zamiast po prostu zgłosić ogólny błąd. Sprawdź, czy certyfikat ma OCSP responder i czy jest osiągalny:

openssl x509 -in cert.pem -noout -ocsp_uri

Jeśli klient nie może połączyć się z tym URL-em (zablokowany firewallem OCSP responder, wygasły OCSP staple), część klientów działa w trybie “fail closed” i traktuje certyfikat jako niezaufany, mimo że technicznie wciąż jest ważny.

Szybka ściągawka: verify return codes

KodZnaczeniePrzejdź do
10Certyfikat wygasłKrok 2
18Certyfikat self-signedKrok 4
19Certyfikat self-signed w łańcuchuKrok 4
20Unable to get local issuer certificateKrok 1
21Unable to verify the first certificateKrok 1
24Invalid CA certificateKrok 1 albo Krok 2

Od reaktywnego rozwiązywania problemów do prewencji

Każdy krok powyżej to coś, co sprawdzasz po tym, jak ktoś już trafił na błąd — użytkownik, kolega z zespołu albo usługa, której właśnie nie udał się handshake. Problemy z łańcuchem, terminem ważności i hostname są szczególnie tego typu: oczywiste z perspektywy czasu i niewidoczne, dopóki czegoś nie zepsują. Dokładnie tę lukę wypełnia Certyfizer — śledzi łańcuch i termin ważności każdego certyfikatu we wszystkich środowiskach i sygnalizuje problem — brakujący intermediate, wygasający certyfikat liściowy, niepasujący SAN — zanim jakiś klient będzie musiał Ci o tym powiedzieć.

Najczęściej zadawane pytania

Co właściwie znaczy "certyfikat niezaufany"?

Znaczy to, że klient (przeglądarka, curl, biblioteka HTTP) nie zdołał zbudować poprawnego łańcucha zaufania od otrzymanego certyfikatu do root CA, któremu już ufa. Może się to zdarzyć z kilku niepowiązanych powodów — niekompletny łańcuch, wygasły certyfikat, niepasujący hostname, certyfikat podpisany przez nieznane CA albo źle ustawiony zegar — a komunikat błędu zwykle wygląda tak samo niezależnie od przyczyny.

Jaki jest najszybszy sposób, żeby sprawdzić dlaczego certyfikat nie jest zaufany?

Uruchom openssl s_client -connect host:443 -servername host </dev/null i przeczytaj linię "Verify return code" na końcu wyniku. Mówi ona dokładnie, który test zawiódł — wygasły, self-signed, unable to get local issuer certificate itd. — zamiast zgadywania.

Czym jest "verify return code" i co znaczą te najczęstsze?

To numeryczny wynik testu łańcucha zaufania w OpenSSL. Te, które widuje się najczęściej: 0 to sukces, 10 to wygasły certyfikat, 18 to certyfikat self-signed, 20 to unable to get local issuer certificate (brakujące intermediate), a 21 to unable to verify the first certificate (zwykle ta sama przyczyna co 20).

Dlaczego ważny, niewygasły certyfikat wciąż pokazuje się jako niezaufany?

Najczęstszym powodem jest niekompletny łańcuch — serwer wysyła certyfikat liściowy, ale nie wysyła certyfikatu intermediate CA, który łączy go z zaufanym rootem. Przeglądarki często maskują ten problem, cache'ując intermediate'y widziane na innych stronach — dlatego ten sam źle skonfigurowany serwer może wyglądać dobrze w przeglądarce, a zawodzić w curl albo backendowej usłudze.

Dlaczego mój certyfikat jest niezaufany tylko w niektórych przeglądarkach/klientach, a w innych nie?

Różne klienty mają różne trust store'y i różną tolerancję na niekompletne łańcuchy. Klient, który niedawno pobrał brakujący intermediate z innej strony, sam dokończy łańcuch; curl, aplikacja mobilna albo backendowa usługa z minimalnym trust store'em tego nie zrobi. Jeśli działa w jednym miejscu, a nie działa w innym — podejrzewaj najpierw niekompletny łańcuch.

Czy wygasłe root albo intermediate CA może spowodować ten problem, nawet jeśli mój certyfikat jest w porządku?

Tak. Twój certyfikat liściowy może być całkowicie poprawny i mimo to nie przejść walidacji, jeśli intermediate CA, które go podpisało, wygasło albo zostało odrzucone przez trust store — dokładnie to wydarzyło się, gdy przeglądarki wycofały zaufanie do rootów wystawionych przez Symanteca. Sprawdź termin ważności każdego certyfikatu w łańcuchu, nie tylko swojego.

Powiązane artykuły