Сообщение об ошибке
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 или клиентский сертификат без clientAuth при взаимной TLS-аутентификации. Go строго применяет EKU; некоторые другие TLS-стеки мягче, поэтому тот же сертификат может работать в другом месте.
Почему это происходит
Клиентский сертификат используется как серверный
частоНа сервере установлены сертификаты, выпущенные по шаблону для аутентификации клиентов (EKU только clientAuth), например во внутренней PKI.
Серверный сертификат используется для взаимной TLS-аутентификации
частоЕсли использовать сертификат веб-сервера (EKU только serverAuth) в качестве клиентского сертификата, серверы на Go, требующие clientAuth, его отклонят.
Промежуточный сертификат ограничивает допустимые назначения
иногда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
Серверы на Go с RequireAndVerifyClientCert проверяют, есть ли clientAuth в EKU клиентского сертификата.
go // Go server verifying client certificates: they need clientAuth (or no EKU at all) cfg := &tls.Config{ ClientAuth: tls.RequireAndVerifyClientCert, ClientCAs: clientCAPool, }