Kort svar
En mTLS-handshake fejler næsten altid af én af fem grunde: serveren stoler ikke på den CA, der udstedte klientcertifikatet; klientcertifikatet er udløbet; det mangler clientAuth EKU; klienten sender en ufuldstændig kæde; eller der er et hostname mismatch på serverens certifikat. Brug openssl s_client og curl -v til at se hvilken side der afviser, og hvorfor.
Første skridt: hvilken side afviser?
Den vigtigste skelnen er om det er serveren, der afviser klientcertifikatet, eller klienten, der afviser serverens. Kør med fuld debug:
curl -v --cert client.crt --key client.key \
--cacert ca.crt \
https://api.example.com/health
Ser du SSL certificate problem på serverens certifikat, er det klientens validering der fejler. Ser du i stedet alert unknown ca eller alert handshake failure efter at klientcertifikatet er sendt, er det serveren der afviser dit klientcertifikat.
1. Forkert CA (serveren stoler ikke på udstederen)
Den hyppigste årsag. Serveren validerer klientcertifikater mod en bestemt CA (ssl_client_certificate i nginx), og dit certifikat er udstedt af en anden. Symptom: alert unknown ca. Tjek hvilken CA der udstedte dit klientcertifikat, og sammenlign med serverens accepterede CA'er:
# Udsteder af dit klientcertifikat openssl x509 -in client.crt -noout -issuer # CA-navne serveren accepterer (kig efter "Acceptable client certificate CA names") openssl s_client -connect api.example.com:443 -servername api.example.com 2>/dev/null \ | grep -A20 "Acceptable client"
Matcher issuer'en ikke en af de accepterede CA-navne, har du fundet fejlen.
2. Udløbet klientcertifikat
Et udløbet klientcertifikat afvises lige så hårdt som et udløbet servercertifikat — men ingen browser advarer på forhånd. Tjek datoerne:
openssl x509 -in client.crt -noout -dates
Er notAfter i fortiden, skal certifikatet fornyes. Det er den mest oversete mTLS-fejl, netop fordi klientcertifikater sjældent overvåges lige så omhyggeligt som servercertifikater.
3. Manglende clientAuth EKU
Et certifikat skal have Extended Key Usage sat til clientAuth for at kunne bruges som klientcertifikat. Et certifikat udstedt til en server (med serverAuth) afvises ofte i klientrollen. Tjek:
openssl x509 -in client.crt -noout -text | grep -A1 "Extended Key Usage"
Du bør se TLS Web Client Authentication. Mangler den — eller står der kun TLS Web Server Authentication — skal certifikatet genudstedes med den rette EKU.
4. Ufuldstændig kæde fra klienten
Hvis dit klientcertifikat er udstedt via en intermediate, skal klienten sende både leaf og intermediate, så serveren kan bygge kæden op til sin betroede CA. Sender klienten kun leaf'en, ser du unable to get local issuer certificate på serversiden. Det er samme grundproblem som på serversiden — se "unable to get local issuer certificate" og certifikatkæden forklaret. Med curl sender du hele kæden i én fil:
# client-fullchain.pem = leaf + intermediate(s)
curl --cert client-fullchain.pem --key client.key \
--cacert ca.crt https://api.example.com/health
5. Hostname mismatch på serverens certifikat
Selv i mTLS validerer klienten stadig serverens certifikat normalt. Hvis serverens certifikat ikke dækker det navn, du forbinder til, fejler det — uafhængigt af klientcertifikatet. Det er en almindelig CA-relateret fejl; se hele baggrunden i TLS-handshaken. Tjek serverens SAN:
openssl s_client -connect api.example.com:443 -servername api.example.com 2>/dev/null \ | openssl x509 -noout -text | grep -A1 "Subject Alternative Name"
Beslutningstabel
| Symptom | Sandsynlig årsag |
|---|---|
alert unknown ca | Forkert CA på klientcertifikatet |
certificate has expired | Udløbet klientcertifikat |
unsupported certificate purpose | Manglende clientAuth EKU |
unable to get local issuer certificate | Ufuldstændig kæde |
handshake failure efter cert sendt | Serveren afviste klientidentiteten |
Stop med at fejlfinde udløb bagudrettet
To af de fem årsager — udløbet klientcertifikat og ufuldstændig kæde — er fuldt forudsigelige og rammer typisk på det værst tænkelige tidspunkt. CertControl overvåger både server- og klientcertifikater, også fra interne CA'er, validerer at kæderne er komplette, og advarer dage før et certifikat udløber. Så finder du fejlen før handshaken fejler — ikke bagefter med curl -v. Forstå grundlaget i vores mTLS-guide.
Ofte stillede spørgsmål
Hvorfor får jeg bare "handshake failure" uden detaljer?
TLS-alerts er bevidst sparsomme for ikke at lække information. Kør curl -v eller openssl s_client for at se mere, og afgør først om det er serveren eller klienten der afviser — det halverer fejlsøgningen.
Hvad er forskellen på clientAuth og serverAuth EKU?
Det er to forskellige værdier i Extended Key Usage-feltet. serverAuth tillader at certifikatet bruges af en server, clientAuth af en klient. Et mTLS-klientcertifikat skal have clientAuth; mange afviser et certifikat der kun har serverAuth.
Skal klienten sende hele kæden eller kun sit eget certifikat?
Hvis klientcertifikatet er udstedt via en intermediate, skal klienten sende både leaf og intermediate, så serveren kan bygge kæden op til den CA, den stoler på. Ellers risikerer du "unable to get local issuer certificate" på serversiden.
Hvordan ser jeg hvilke CA'er en mTLS-server accepterer?
Kør openssl s_client mod serveren og kig efter blokken Acceptable client certificate CA names i outputtet. Den lister de CA'er hvis klientcertifikater serveren vil acceptere.
Kan et forkert ur give mTLS-fejl?
Ja. Hvis klientens eller serverens ur går forkert, kan et gyldigt certifikat fremstå som udløbet eller endnu ikke gyldigt. Synkronisér uret via NTP før du fejlsøger videre.