Error message
x509: certificate specifies an incompatible key usage
Also printed as
- tls: failed to verify certificate: x509: certificate specifies an incompatible key usage
TLS clients add the "tls: failed to verify certificate: " prefix; Go servers verifying client certificates log "http: TLS handshake error from <addr>: tls: failed to verify certificate: x509: certificate specifies an incompatible key usage".
Go crypto/x509 — CertificateInvalidError (IncompatibleUsage): extendedKeyUsage does not allow this role
What it means
The chain is trusted, but the certificate's extendedKeyUsage (or that of an intermediate, which Go also checks) does not allow the role it is used for: a server certificate without serverAuth, or a client certificate without clientAuth in mutual TLS. Go enforces EKU strictly; some other TLS stacks are more lenient, so the same certificate may work elsewhere.
Why it happens
A client certificate is served as a server certificate
commonCertificates from a client-authentication template (EKU clientAuth only), for example from an internal PKI, installed on a server.
A server certificate is used for mutual TLS
commonReusing a web server's certificate (EKU serverAuth only) as a client certificate fails on Go servers that require clientAuth.
An intermediate restricts the allowed usages
occasionalGo treats EKU on intermediates as a constraint on everything below them; an intermediate limited to clientAuth cannot issue usable server certificates.
How to fix it
- 1.
Read the extendedKeyUsage of each certificate
Check the leaf and every intermediate; the purpose you need must be allowed along the whole path.
bash # Leaf and intermediates: which purposes do they allow? openssl x509 -in server.pem -noout -ext extendedKeyUsage,keyUsage # TLS Web Server Authentication = serverAuth, TLS Web Client Authentication = clientAuth - 2.
Reissue with the correct EKU
serverAuth for server certificates, clientAuth for client certificates (both if one certificate really must serve both roles).
bash # Server certificates need serverAuth; for mutual TLS client certificates need clientAuth openssl req -new -key server.key -out server.csr -subj "/CN=api.example.com" \ -addext "subjectAltName=DNS:api.example.com" -addext "extendedKeyUsage=serverAuth" - 3.
Mutual TLS: issue client certificates with clientAuth
Go servers with RequireAndVerifyClientCert check the client certificate's EKU for clientAuth.
go // Go server verifying client certificates: they need clientAuth (or no EKU at all) cfg := &tls.Config{ ClientAuth: tls.RequireAndVerifyClientCert, ClientCAs: clientCAPool, }