fix(lite-backend): verify TLS for the t-address scan and mempool monitor
The transparent-address txid scan in the sync loop and the mempool monitor both hard-coded no_cert = true, so they connected to the lightwalletd through get_client's NoCertificateVerification path in every Lite build, while the app always passes dangerous = false. Block sync, info, broadcast and the full-tx fetcher already honour LightClientConfig::no_cert_verification. An active man in the middle on those two channels could hide or invent transparent balance, UTXOs and pending transactions (signing stays local, so no funds can be taken). Both calls now take the setting from the config: - the sync loop passes self.config.no_cert_verification to scan_taddress_txids; - start_mempool_monitor reads config.no_cert_verification once and passes it to monitor_mempool. Flagged behaviour change: a lightwalletd with an invalid or self-signed certificate now fails the t-address stage (do_sync retries, then returns the error) and the mempool monitor (it logs and retries), as block sync already does. `dangerous` is the only bypass. No ABI, symbol or wallet format change. A tripwire test checks that lightclient.rs never again hard-codes the bypass for either call; its needles are joined at runtime so the test cannot match its own source. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+18
-5
@@ -1147,6 +1147,8 @@ impl LightClient {
|
|||||||
pub fn start_mempool_monitor(lc: Arc<LightClient>) -> Result<(), String> {
|
pub fn start_mempool_monitor(lc: Arc<LightClient>) -> Result<(), String> {
|
||||||
let config = lc.config.clone();
|
let config = lc.config.clone();
|
||||||
let uri = config.server.clone();
|
let uri = config.server.clone();
|
||||||
|
// TLS verification follows the config (default on), as block sync does; `dangerous` is the only bypass.
|
||||||
|
let no_cert = config.no_cert_verification;
|
||||||
let shutdown = lc.shutdown_flag.clone();
|
let shutdown = lc.shutdown_flag.clone();
|
||||||
|
|
||||||
let (incoming_mempool_tx, incoming_mempool_rx) = std::sync::mpsc::channel::<RawTransaction>();
|
let (incoming_mempool_tx, incoming_mempool_rx) = std::sync::mpsc::channel::<RawTransaction>();
|
||||||
@@ -1182,7 +1184,7 @@ pub fn start_mempool_monitor(lc: Arc<LightClient>) -> Result<(), String> {
|
|||||||
incoming_mempool_tx_clone.send(rtx).map_err(|e| Box::new(e) as Box<dyn std::error::Error>)
|
incoming_mempool_tx_clone.send(rtx).map_err(|e| Box::new(e) as Box<dyn std::error::Error>)
|
||||||
};
|
};
|
||||||
|
|
||||||
match grpcconnector::monitor_mempool(&uri.clone(), true, send_closure).await {
|
match grpcconnector::monitor_mempool(&uri.clone(), no_cert, send_closure).await {
|
||||||
Ok(_) => info!("Mempool monitor loop successful"),
|
Ok(_) => info!("Mempool monitor loop successful"),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
// If the server doesn't implement GetMempoolStream, stop the monitor instead
|
// If the server doesn't implement GetMempoolStream, stop the monitor instead
|
||||||
@@ -1558,10 +1560,9 @@ pub fn start_mempool_monitor(lc: Arc<LightClient>) -> Result<(), String> {
|
|||||||
start_height
|
start_height
|
||||||
};
|
};
|
||||||
|
|
||||||
let no_cert = true;
|
// Fetch the txids our transparent addresses are involved with. TLS verification follows the
|
||||||
|
// config (default on); `dangerous` is the only way to turn it off.
|
||||||
// We'll also fetch all the txids that our transparent addresses are involved with
|
self.scan_taddress_txids(&pool, block_times, transparent_start_height, end_height, self.config.no_cert_verification)?;
|
||||||
self.scan_taddress_txids(&pool, block_times, transparent_start_height, end_height, no_cert)?;
|
|
||||||
|
|
||||||
// Do block height accounting
|
// Do block height accounting
|
||||||
last_scanned_height = end_height;
|
last_scanned_height = end_height;
|
||||||
@@ -1905,4 +1906,16 @@ pub fn test_bad_import() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// C243 tripwire: the t-address scan and the mempool monitor must take TLS verification from the config
|
||||||
|
// (no_cert_verification, which only `dangerous` sets), never from a hard-coded `true`. The needles are
|
||||||
|
// joined at runtime so that this test's own source cannot match them.
|
||||||
|
#[test]
|
||||||
|
pub fn test_tls_verification_not_hardcoded_off() {
|
||||||
|
let src = include_str!("lightclient.rs");
|
||||||
|
let taddr_needle = ["let no_cert", "= true"].join(" ");
|
||||||
|
let mempool_needle = ["monitor_mempool(&uri.clone(),", "true"].join(" ");
|
||||||
|
assert!(!src.contains(&taddr_needle), "the t-address scan turns TLS verification off");
|
||||||
|
assert!(!src.contains(&mempool_needle), "the mempool monitor turns TLS verification off");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user