{"record":{"id":"9a39592236d93052","repo":"aio-libs/aiohttp","slug":"fingerprint-has-invalid-length","errorCode":null,"errorMessage":"fingerprint has invalid length","messagePattern":"fingerprint has invalid length","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"aiohttp/client_reqrep.py","lineNumber":187,"sourceCode":"        For backwards compatibility, the real_url parameter is optional.\n        \"\"\"\n        return tuple.__new__(\n            cls, (url, method, headers, url if real_url is sentinel else real_url)\n        )\n\n\nclass Fingerprint:\n    HASHFUNC_BY_DIGESTLEN = {\n        16: md5,\n        20: sha1,\n        32: sha256,\n    }\n\n    def __init__(self, fingerprint: bytes) -> None:\n        digestlen = len(fingerprint)\n        hashfunc = self.HASHFUNC_BY_DIGESTLEN.get(digestlen)\n        if not hashfunc:\n            raise ValueError(\"fingerprint has invalid length\")\n        elif hashfunc is md5 or hashfunc is sha1:\n            raise ValueError(\"md5 and sha1 are insecure and not supported. Use sha256.\")\n        self._hashfunc = hashfunc\n        self._fingerprint = fingerprint\n\n    @property\n    def fingerprint(self) -> bytes:\n        return self._fingerprint\n\n    def check(self, transport: asyncio.Transport) -> None:\n        if not transport.get_extra_info(\"sslcontext\"):\n            return\n        sslobj = transport.get_extra_info(\"ssl_object\")\n        cert = sslobj.getpeercert(binary_form=True)\n        got = self._hashfunc(cert).digest()\n        if got != self._fingerprint:\n            host, port, *_ = transport.get_extra_info(\"peername\")\n            raise ServerFingerprintMismatch(self._fingerprint, got, host, port)","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/d041d4d0fd48c3f0832084d33be16cf1c4835f85/aiohttp/client_reqrep.py#L169-L205","documentation":"Raised by Fingerprint.__init__ when the supplied fingerprint bytes are not exactly 16, 20, or 32 bytes long. aiohttp maps fingerprint length to a hash function (16=md5, 20=sha1, 32=sha256) and any other length has no mapping, so it raises ValueError. The fingerprint is used to pin/verify the TLS server certificate.","triggerScenarios":"Calling Fingerprint(some_bytes) where len(some_bytes) is not 16, 20, or 32 — e.g. passing a 64-byte SHA-512 digest, a base64/hex string (not raw bytes), or a truncated value. Construction fails immediately.","commonSituations":"Copying a hex-encoded fingerprint string instead of raw bytes; using SHA-512 (64 bytes) which aiohttp's Fingerprint does not support; passing a DER cert or a public-key pin (SPKI) which is a different length; truncating or padding a digest.","solutions":["Pass exactly 32 bytes of a SHA-256 digest of the DER-encoded server certificate (preferred).","If you have a hex string, convert it: Fingerprint(bytes.fromhex(hex_str)).","Do not use MD5 (16) or SHA-1 (20) — they raise a separate 'insecure' error; use SHA-256.","SHA-512 fingerprints are not supported by Fingerprint; switch to SHA-256 or implement a custom ssl.SSLContext."],"exampleFix":"# before\nfp = Fingerprint(b'\\x11' * 64)  # 64 bytes -> ValueError\nfp = Fingerprint('AB:CD:EF...')   # str, not bytes -> ValueError\n\n# after — 32-byte SHA-256 of the DER cert\nfp = Fingerprint(bytes.fromhex('a1b2c3...'))  # exactly 64 hex chars = 32 bytes\nssl_ctx = ssl.create_default_context()\nawait session.get(url, ssl=fp)","handlingStrategy":"type-guard","validationCode":"def make_fingerprint(raw: bytes):\n    if len(raw) not in (16, 20, 32):\n        raise ValueError(f'fingerprint must be 16/20/32 bytes, got {len(raw)}')\n    from aiohttp import Fingerprint\n    return Fingerprint(raw)","typeGuard":"def is_valid_fingerprint_length(fp: bytes) -> bool:\n    return isinstance(fp, (bytes, bytearray)) and len(fp) in (16, 20, 32)","tryCatchPattern":"from aiohttp import Fingerprint\n\ntry:\n    fp = Fingerprint(raw_bytes)\nexcept ValueError as e:\n    if 'invalid length' in str(e):\n        raise ValueError('Pass a 32-byte SHA-256 digest of the DER cert')\n    raise","preventionTips":["Always derive fingerprints with SHA-256 over the DER cert (32 bytes).","Convert hex to bytes explicitly with bytes.fromhex before constructing.","Never pass hex strings, PEM text, or 64-byte digests to Fingerprint."],"tags":["ssl","tls","fingerprint","security","client"],"backgroundTag":null,"analyzedSha":"d041d4d0fd48c3f0832084d33be16cf1c4835f85","analyzedAt":"2026-08-11T20:44:15.550Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}