エラーメッセージ
x509: certificate specifies an incompatible key usage
別の表記
- tls: failed to verify certificate: x509: certificate specifies an incompatible key usage
TLS クライアントでは、先頭に「tls: failed to verify certificate:」が付きます。クライアント証明書を検証する Go のサーバーは、「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
このエラーの意味
チェーンは信頼されていますが、証明書の extendedKeyUsage(または中間証明書のもの。Go はこれもチェックします)が、証明書が使われている役割を許可していません。serverAuth のないサーバー証明書や、相互 TLS で clientAuth のないクライアント証明書がこれに当たります。Go は EKU を厳格に適用します。ほかの TLS スタックの中にはより寛容なものもあるため、同じ証明書がほかの環境では動作することがあります。
発生する理由
クライアント証明書をサーバー証明書として使っている
よくある社内 PKI などで、クライアント認証用テンプレート(EKU は clientAuth のみ)から発行された証明書がサーバーにインストールされているケースです。
サーバー証明書を相互 TLS に使っている
よくあるWeb サーバーの証明書(EKU は serverAuth のみ)をクライアント証明書として使い回すと、clientAuth を要求する Go のサーバーでは失敗します。
中間証明書が許可される用途を制限している
ときどきGo は、中間証明書の EKU を、その配下にあるすべての証明書に対する制約として扱います。clientAuth に限定された中間証明書からは、使用可能なサーバー証明書を発行できません。
修正方法
- 1.
各証明書の extendedKeyUsage を確認する
リーフ証明書とすべての中間証明書を確認してください。必要な用途が、パス全体で許可されていなければなりません。
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.
正しい EKU で再発行する
サーバー証明書には serverAuth を、クライアント証明書には clientAuth を設定してください(同じ証明書でどうしても両方の役割を担う必要がある場合は両方を設定します)。
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.
相互 TLS:clientAuth を含むクライアント証明書を発行する
RequireAndVerifyClientCert を設定した Go のサーバーは、クライアント証明書の EKU に clientAuth が含まれているかをチェックします。
go // Go server verifying client certificates: they need clientAuth (or no EKU at all) cfg := &tls.Config{ ClientAuth: tls.RequireAndVerifyClientCert, ClientCAs: clientCAPool, }