Checks if given fingerprint matches the supplied certificate. :param cert: Certificate as bytes object. :param fingerprint: Fingerprint as string of hexdigits, can be interspersed by colons.
(cert: bytes | None, fingerprint: str)
| 105 | |
| 106 | |
| 107 | def assert_fingerprint(cert: bytes | None, fingerprint: str) -> None: |
| 108 | """ |
| 109 | Checks if given fingerprint matches the supplied certificate. |
| 110 | |
| 111 | :param cert: |
| 112 | Certificate as bytes object. |
| 113 | :param fingerprint: |
| 114 | Fingerprint as string of hexdigits, can be interspersed by colons. |
| 115 | """ |
| 116 | |
| 117 | if cert is None: |
| 118 | raise SSLError("No certificate for the peer.") |
| 119 | |
| 120 | fingerprint = fingerprint.replace(":", "").lower() |
| 121 | digest_length = len(fingerprint) |
| 122 | if digest_length not in HASHFUNC_MAP: |
| 123 | raise SSLError(f"Fingerprint of invalid length: {fingerprint}") |
| 124 | hashfunc = HASHFUNC_MAP.get(digest_length) |
| 125 | if hashfunc is None: |
| 126 | raise SSLError( |
| 127 | f"Hash function implementation unavailable for fingerprint length: {digest_length}" |
| 128 | ) |
| 129 | |
| 130 | # We need encode() here for py32; works on py2 and p33. |
| 131 | fingerprint_bytes = unhexlify(fingerprint.encode()) |
| 132 | |
| 133 | cert_digest = hashfunc(cert).digest() |
| 134 | |
| 135 | if not hmac.compare_digest(cert_digest, fingerprint_bytes): |
| 136 | raise SSLError( |
| 137 | f'Fingerprints did not match. Expected "{fingerprint}", got "{cert_digest.hex()}"' |
| 138 | ) |
| 139 | |
| 140 | |
| 141 | def resolve_cert_reqs(candidate: None | int | str) -> VerifyMode: |