Сообщение об ошибке
java.security.cert.CertPathValidatorException: Algorithm constraints check failed on keysize limits: RSA 768 bit key used with certificate: CN=api.example.com
Также выводится как
- Algorithm constraints check failed on keysize limits
- javax.net.ssl.SSLHandshakeException: (unsupported_certificate) PKIX path validation failed: java.security.cert.CertPathValidatorException: Algorithm constraints check failed on keysize limits
Тип ключа, его размер и субъект подставляются для каждого сертификата. На уровне TLS сообщение выглядит так: «(unsupported_certificate) PKIX path validation failed: …». С сертификатом сервера, подписанным MD5, наш тест завершился ошибкой раньше: сервер вернул handshake_failure, потому что JVM вообще не предлагает подписи MD5.
Java (PKIX validator) — jdk.certpath.disabledAlgorithms rejects a weak key or signature algorithm in the chain
Что это означает
В Java доверенный путь построен, но один из сертификатов в нём использует ключ (или алгоритм подписи), запрещённый в jdk.certpath.disabledAlgorithms, поэтому проверка цепочки сертификатов не проходит. В сообщении указаны алгоритм, размер ключа и субъект сертификата. Современные JDK отклоняют в цепочках сертификатов ключи RSA и DSA короче 1024 бит, ключи EC короче 224 бит и подписи MD2/MD5.
Почему это происходит
Старый сертификат с коротким ключом
частоСтарые аппаратные устройства, встроенные веб-серверы и тестовые сертификаты, созданные с ключами RSA длиной 512 или 768 бит.
Сертификат в цепочке подписан с использованием MD5 (или SHA-1 под корневым сертификатом из поставки JDK)
иногдаВ jdk.certpath.disabledAlgorithms также перечислены MD2 и MD5, а для цепочек TLS-серверов, которые заканчиваются на CA из поставки JDK, ещё и SHA-1.
Обновление JDK ужесточило ограничения
иногдаОграничения время от времени ужесточают в обновлениях безопасности; сертификаты, которые проходили проверку на более старом обновлении, после перехода на новое могут её не пройти.
Как исправить
- 1.
Найдите слабый сертификат
Выведите размер открытого ключа и алгоритм подписи каждого сертификата в цепочке, которую отдаёт сервер.
bash # Key size and signature algorithm of every certificate the server sends openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts </dev/null 2>/dev/null \ | awk '/BEGIN CERT/{n++; f="c" n ".pem"} /BEGIN CERT/,/END CERT/{print > f}' for f in c*.pem; do openssl x509 -in "$f" -noout -subject -text | grep -E 'subject=|Public-Key|Signature Algorithm' | sort -u; done - 2.
Перевыпустите сертификат с современным ключом
ECDSA P-256 или RSA 2048+ с подписью SHA-256 принимаются везде.
bash # Replace the weak key: ECDSA P-256 (or RSA 2048+) with a SHA-256 signature openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes -keyout server.key \ -subj "/CN=api.example.com" -addext "subjectAltName=DNS:api.example.com" -out server.csr - 3.
Изучите ограничения JDK
jdk.certpath.disabledAlgorithms в java.security перечисляет то, что отклоняется; ослабить ограничения можно, переопределив свойства безопасности, но тогда снова будут допущены ключи, которые можно взломать.
bash # What this JDK rejects in certificate chains sed -n '/^jdk.certpath.disabledAlgorithms=/,/[^\\]$/p' "$JAVA_HOME/conf/security/java.security"