Note: this issue was written by Claude.
Every certificate verification failure in the ssl module surfaces as the same bare number, so there is no way to distinguish a hostname mismatch from an expired certificate, an untrusted CA, or a key-usage problem.
shared-module/ssl/SSLSocket.c never calls mbedtls_ssl_get_verify_result(). A failed handshake goes straight to mbedtls_raise_error(ret) (line 364) with ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED (-0x2700 = -9984), so the MBEDTLS_X509_BADCERT_* bitmask — which records exactly which check failed — is discarded.
This came up while debugging #10339, where the real cause was BADCERT_CN_MISMATCH arising from an unsupported iPAddress SAN. Identifying that required reading mbedtls source; the flag would have named it immediately.
CPython precedent: ssl.SSLCertVerificationError carries verify_code and verify_message, both included in str(e). The same condition there reads:
verify_code=62 verify_message="Hostname mismatch, certificate is not valid for 'nope.invalid'."
Two options, with a footprint tradeoff:
- Append the raw bitmask from
mbedtls_ssl_get_verify_result() to the exception. Nearly free in flash, and adds no new translatable strings — the value is a number.
- Render it with
mbedtls_x509_crt_verify_info(), which exists in lib/mbedtls 2.28 (include/mbedtls/x509_crt.h:561) and is not compiled out (MBEDTLS_X509_REMOVE_INFO is not defined in lib/mbedtls_config/mbedtls_config.h). Human-readable, but pulls in mbedtls's message strings, which is a real cost on small boards — and that text is untranslated English.
Claude has not attempted a patch; this is a report of the diagnostic gap.
Note: this issue was written by Claude.
Every certificate verification failure in the
sslmodule surfaces as the same bare number, so there is no way to distinguish a hostname mismatch from an expired certificate, an untrusted CA, or a key-usage problem.shared-module/ssl/SSLSocket.cnever callsmbedtls_ssl_get_verify_result(). A failed handshake goes straight tombedtls_raise_error(ret)(line 364) withret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED(-0x2700=-9984), so theMBEDTLS_X509_BADCERT_*bitmask — which records exactly which check failed — is discarded.This came up while debugging #10339, where the real cause was
BADCERT_CN_MISMATCHarising from an unsupportediPAddressSAN. Identifying that required reading mbedtls source; the flag would have named it immediately.CPython precedent:
ssl.SSLCertVerificationErrorcarriesverify_codeandverify_message, both included instr(e). The same condition there reads:Two options, with a footprint tradeoff:
mbedtls_ssl_get_verify_result()to the exception. Nearly free in flash, and adds no new translatable strings — the value is a number.mbedtls_x509_crt_verify_info(), which exists inlib/mbedtls2.28 (include/mbedtls/x509_crt.h:561) and is not compiled out (MBEDTLS_X509_REMOVE_INFOis not defined inlib/mbedtls_config/mbedtls_config.h). Human-readable, but pulls in mbedtls's message strings, which is a real cost on small boards — and that text is untranslated English.Claude has not attempted a patch; this is a report of the diagnostic gap.