SslAesTransport._create_ssl_context() in kasa/transports/sslaestransport.py restricts the TLS cipher list to a fixed set of non-ECDHE (static RSA key exchange, no forward secrecy) ciphers:
Recent Tapo camera firmware versions (confirmed on two separate Tapo C220 units, firmware version 1.5.4) appear to have dropped support for these legacy non-PFS ciphers, while still fully supporting modern ECDHE cipher suites. This causes every fresh pairing attempt from Home Assistant / python-kasa to fail with SSLV3_ALERT_HANDSHAKE_FAILURE, since none of the ciphers in the fixed whitelist are accepted by the device anymore.
Diagnosis
Tested directly against the camera (192.168.1.119:443) from inside the same container/environment running the integration:
Default OpenSSL cipher list (includes ECDHE):
openssl s_client -connect 192.168.1.119:443
→ Handshake succeeds: TLSv1.2, ECDHE-RSA-AES128-GCM-SHA256, camera responds HTTP/1.1 200 OK.
Exact cipher list used by SslAesTransport (no ECDHE):
openssl s_client -connect 192.168.1.119:443 -cipher 'AES256-GCM-SHA384:AES256-SHA256:AES128-GCM-SHA256:AES128-SHA256:AES256-SHA'
→ Fails immediately: SSL alert number 40 (handshake_failure), matching exactly the error seen in HA/kasa logs.
This confirms the camera rejects the whitelist in CIPHERS, but happily negotiates ECDHE-based ciphers.
Reproduction steps
Factory reset a Tapo C220 (or C210/C230) currently on the latest firmware (confirmed on 1.5.4).
Pair it fresh via the Tapo app, enable Third-Party Compatibility and set up a camera account.
Try adding it to Home Assistant via the TP-Link Smart Home integration.
Setup fails with:
Device connection error: <ip>: Cannot connect to host <ip>:443 ssl:<ssl.SSLContext object> [[SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] ssl/tls alert handshake failure]
Notably, a camera that was already paired and working before the firmware update continues to work fine after an in-place update — the issue only appears on a fresh handshake/pairing after the firmware update.
Suggested fix
Extend CIPHERS to include ECDHE suites (e.g. ECDHE-RSA-AES128-GCM-SHA256, ECDHE-RSA-AES256-GCM-SHA384), or fall back to the default OpenSSL cipher list if the current fixed set fails to negotiate. This should preserve compatibility with older cameras (which reportedly only support the legacy list) while restoring compatibility with newer firmware that has dropped non-PFS ciphers.
Environment
python-kasa version: (installed via Home Assistant Core) python-kasa 0.10.2.
Home Assistant Core/OS version: 2026.7.4
Device: TP-Link Tapo C220, firmware 1.5.4
OpenSSL: 3.5.7 (confirmed identical across two separate HAOS installations, ruling out a client-side OpenSSL/SECLEVEL issue)
This might be already fixed by one of the PRs that added more ciphers, but will have to check it so keeping open for now. I'm planning to make a release this weekend, if someone wants to verify it is working now in the master branch, that'd be great!
A data point from the other side, to make sure the release does not break older camera firmware: my Tapo C510W 2.0 (fw 1.3.4 Build 260523) refuses the ECDHE suites and only accepts the plain RSA ones. Probed with openssl s_client -tls1_2 -cipher ... on port 443:
cipher
C510W 1.3.4
ECDHE-RSA-AES128-GCM-SHA256
refused
ECDHE-RSA-AES256-GCM-SHA384
refused
AES256-GCM-SHA384
accepted
AES256-SHA256
accepted
AES128-GCM-SHA256
accepted
AES128-SHA256
accepted
AES256-SHA
refused
Since master only prepends the two ECDHE suites and keeps the old list, the negotiation still lands on an RSA suite here. Checked with master at 998ebe7: Device.connect() over SslAesTransport connects in 2.7 s and a second update() works (17 features). So both camera generations are covered by the new list, as long as the RSA entries stay in it.
As the client side only "offers" what it supports and let's the server ("device") decide what to use, my assumption was that it's safe to add new entries to this list.
For compatibility use cases like for this library, it's a bit silly not to offer all ciphers the ssl module, but it's good to test to avoid hitting some firmware bugs :-)
Activity
ToledoEM commented on Aug 8, 2026
I can add that camera TC70 and C201 are also affected
meyxiam commented on Sep 2, 2026
I have the same problem with my tapo C530WS
jasgggit commented on Sep 10, 2026
+1 - my old C200 e my new C230 cannot be added to HA.
EadwinCZ commented on Sep 11, 2026
https://github.com/RFC1918-hub/ha-tplink-camera-fix
rytilahti commented on Oct 1, 2026
This might be already fixed by one of the PRs that added more ciphers, but will have to check it so keeping open for now. I'm planning to make a release this weekend, if someone wants to verify it is working now in the master branch, that'd be great!
freeKC commented on Oct 1, 2026
A data point from the other side, to make sure the release does not break older camera firmware: my Tapo C510W 2.0 (fw 1.3.4 Build 260523) refuses the ECDHE suites and only accepts the plain RSA ones. Probed with openssl s_client -tls1_2 -cipher ... on port 443:
Since master only prepends the two ECDHE suites and keeps the old list, the negotiation still lands on an RSA suite here. Checked with master at 998ebe7: Device.connect() over SslAesTransport connects in 2.7 s and a second update() works (17 features). So both camera generations are covered by the new list, as long as the RSA entries stay in it.
rytilahti commented on Oct 1, 2026
Thanks for testing and reporting back, @freeKC!
As the client side only "offers" what it supports and let's the server ("device") decide what to use, my assumption was that it's safe to add new entries to this list.
For compatibility use cases like for this library, it's a bit silly not to offer all ciphers the ssl module, but it's good to test to avoid hitting some firmware bugs :-)
rytilahti commented on Oct 4, 2026
Both ECDHE-RSA-AES128-GCM-SHA256 and ECDHE-RSA-AES256-GCM-SHA384 in current master branch, the latter added in #1755, so this can be closed now.