aio-libs/aiohttp · error · ValueError
md5 and sha1 are insecure and not supported. Use sha256.
Error message
md5 and sha1 are insecure and not supported. Use sha256.
What it means
Raised as ValueError in Fingerprint.__init__ when the fingerprint length maps to md5 (16 bytes) or sha1 (20 bytes). Both algorithms are considered cryptographically broken, so aiohttp refuses to use them for TLS certificate pinning and only allows sha256 (32 bytes).
Source
Thrown at aiohttp/client_reqrep.py:189
return tuple.__new__(
cls, (url, method, headers, url if real_url is sentinel else real_url)
)
class Fingerprint:
HASHFUNC_BY_DIGESTLEN = {
16: md5,
20: sha1,
32: sha256,
}
def __init__(self, fingerprint: bytes) -> None:
digestlen = len(fingerprint)
hashfunc = self.HASHFUNC_BY_DIGESTLEN.get(digestlen)
if not hashfunc:
raise ValueError("fingerprint has invalid length")
elif hashfunc is md5 or hashfunc is sha1:
raise ValueError("md5 and sha1 are insecure and not supported. Use sha256.")
self._hashfunc = hashfunc
self._fingerprint = fingerprint
@property
def fingerprint(self) -> bytes:
return self._fingerprint
def check(self, transport: asyncio.Transport) -> None:
if not transport.get_extra_info("sslcontext"):
return
sslobj = transport.get_extra_info("ssl_object")
cert = sslobj.getpeercert(binary_form=True)
got = self._hashfunc(cert).digest()
if got != self._fingerprint:
host, port, *_ = transport.get_extra_info("peername")
raise ServerFingerprintMismatch(self._fingerprint, got, host, port)
View on GitHub (pinned to c0ef574e29)
Solutions
- Regenerate the fingerprint using sha256 to get a 32-byte digest.
- Update any config management / CI that generates pins to use sha256.
- Remove md5/sha1 pins from rotation after verifying the new sha256 pin matches.
Example fix
# before (sha1, 20 bytes) fp = aiohttp.Fingerprint(sha1_digest) # after (sha256, 32 bytes) fp = aiohttp.Fingerprint(sha256_digest)
Defensive patterns
Strategy: validation
Validate before calling
import hashlib fp_sha256 = hashlib.sha256(pubkey_der).digest() # 32 bytes aiohttp.Fingerprint(fp_sha256)
Type guard
def is_sha256_fingerprint(raw: bytes) -> bool:
return isinstance(raw, (bytes, bytearray)) and len(raw) == 32 Prevention
- Regenerate any legacy sha1/md5 pins as sha256.
- Audit config for 16- or 20-byte fingerprints.
- Pin generation scripts should hard-code sha256.
When it happens
Trigger: Fires at line 188-189 after HASHFUNC_BY_DIGESTLEN resolves the length to md5 or sha1. Triggered by passing a 16- or 20-byte fingerprint.
Common situations: Legacy pinning configs generated with sha1; copying fingerprints from old documentation; migrating from libraries that still allow sha1.
Related errors
- fingerprint has invalid length
- Cannot connect to host {host}:{port} ssl:{ssl} [{ClassName}:
- Cannot connect to host {host}:{port} ssl:{ssl} [{strerror}]
- 1009
- 1009
AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04).
Data as JSON: /data/errors/4a4c066ac1ebf5fc.json.
Report an issue: GitHub.