Skip to content

Fix sweep nonce non-determinism and disabled TLS hostname verification - #14

Closed
RobGanon wants to merge 1 commit into
TruthMachine:masterfrom
RobGanon:fix-sweep-sec
Closed

Fix sweep nonce non-determinism and disabled TLS hostname verification#14
RobGanon wants to merge 1 commit into
TruthMachine:masterfrom
RobGanon:fix-sweep-sec

Conversation

@RobGanon

Copy link
Copy Markdown

ElectrumSVP: fix two sweep-path security issues

Attach electrumsvp-fixes.patch (or paste the diff below) to an Issue — or open it as a PR against TruthMachine/ElectrumSVP.

Problem 1 — non-deterministic ECDSA nonce in sweep signing

electrumsv/gui/qt/sweep_helper.py signs sweep txs with
ecdsa.SigningKey.sign_digest(...), which — because no k is supplied —
falls back to os.urandom for the nonce (the ecdsa docs themselves say to
use sign_digest_deterministic instead). With a weak/broken RNG or nonce
reuse, an attacker can recover the swept private key. Everywhere else the
wallet uses RFC6979 (bitcoinx PrivateKey.sign → libsecp256k1); the sweep
path is the only exception.

Fix: sign with an RFC6979 deterministic nonce:

-        der_sig = sk.sign_digest(sighash, sigencode=ecdsa.util.sigencode_der_canonize)
+        der_sig = sk.sign_digest_deterministic(
+            sighash, hashfunc=hashlib.sha256, sigencode=ecdsa.util.sigencode_der_canonize)

hashlib is already imported in this module. Output format is unchanged
(low-S canonical DER + 0x41 sighash suffix).

Problem 2 — TLS hostname verification disabled

sweep_helper.create_ssl_context() sets ctx.check_hostname = False for the
direct ElectrumX socket fallback, disabling hostname verification (normal
wallet connections via aiorpcx don't do this). Fix: remove that line.

             ctx.load_verify_locations(cafile=pem_path)
-            ctx.check_hostname = False

Verification performed

  • Confirmed old path emits different signatures on repeated signings.
  • Confirmed new path is deterministic (RFC6979), same low-S canonical DER
    structure, and the signature verifies against the public key.
  • Confirmed the SSL context keeps check_hostname=True / CERT_REQUIRED.
  • py_compile passes; the only changes are in sweep_helper.py (2+/2-).

How to apply

git apply electrumsvp-fixes.patch

or

patch -p1 < electrumsvp-fixes.patch

In electrumsv/gui/qt/sweep_helper.py:
- Sign sweep transactions with RFC6979 deterministic nonce
  (sign_digest_deterministic) instead of the non-deterministic
  ecdsa.sign_digest which falls back to os.urandom. Prevents
  potential private key recovery via nonce reuse.
- Stop setting check_hostname=False on the ElectrumX socket TLS
  context, restoring hostname verification (fails secure).
@TruthMachine

Copy link
Copy Markdown
Owner

I investigated both changes separately. The deterministic-signature issue is already resolved in my development branch, where sweep signing uses bitcoinx/libsecp256k1 rather than the ecdsa signing path in this PR.

Regarding TLS hostname verification, I agree that disabling hostname verification weakens TLS security. However, ElectrumSVP currently uses server-specific self-signed certificates, and I verified that at least sv2.satoshi.io currently presents a self-signed certificate for CN=electrumr with no SAN for sv2.satoshi.io. With that certificate explicitly trusted, hostname verification succeeds only when check_hostname=False; enabling it produces a hostname-mismatch failure. Simply removing check_hostname=False would therefore break some existing configured servers.

This is not ideal, but in the specific case of the sweep operation, a MITM would not gain access to the private keys. They could potentially provide incomplete or incorrect UTXO data, which could cause a sweep to fail or result in fewer UTXOs being included, but they would not be able to sign transactions with the user's private keys.

I am not adopting that change as-is and will investigate the certificate/TLS architecture separately.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants