refactor: rename trustAllCerts → usePinnedTrustStore
The field no longer means 'trust all certificates' — since the Samsung One UI 7 fix, it means 'use the pinned trust store (hardcoded + TOFU-pinned certs + system CAs) instead of system-only trust.' The old name was actively misleading and could cause a future contributor to interpret the flag literally, potentially reintroducing the trust-all pattern that Samsung Knox and GrapheneOS reject. Renamed across all 4 files: - ElectrumxServer.kt: field definition + updated KDoc - ElectrumXClient.kt: createSocket() usage + comments - NamecoinSettings.kt: parseServerString() usage + comments - NamecoinSettingsTest.kt: test assertions
This commit is contained in:
+6
-8
@@ -66,7 +66,7 @@ data class NamecoinSettings(
|
|||||||
* TLS is the default protocol. Append `:tcp` for plaintext
|
* TLS is the default protocol. Append `:tcp` for plaintext
|
||||||
* (useful for `.onion` addresses and local servers).
|
* (useful for `.onion` addresses and local servers).
|
||||||
*
|
*
|
||||||
* `.onion` addresses automatically get `trustAllCerts = true`
|
* `.onion` addresses automatically get `usePinnedTrustStore = true`
|
||||||
* since certificate verification is meaningless over Tor.
|
* since certificate verification is meaningless over Tor.
|
||||||
*/
|
*/
|
||||||
fun parseServerString(s: String): ElectrumxServer? {
|
fun parseServerString(s: String): ElectrumxServer? {
|
||||||
@@ -77,17 +77,15 @@ data class NamecoinSettings(
|
|||||||
if (host.isEmpty() || port <= 0 || port > 65535) return null
|
if (host.isEmpty() || port <= 0 || port > 65535) return null
|
||||||
val useSsl = parts.getOrNull(2)?.trim()?.lowercase() != "tcp"
|
val useSsl = parts.getOrNull(2)?.trim()?.lowercase() != "tcp"
|
||||||
val isOnion = host.endsWith(".onion")
|
val isOnion = host.endsWith(".onion")
|
||||||
// All custom servers set trustAllCerts=true, which (despite the
|
// All custom servers use the pinned trust store. ElectrumX
|
||||||
// legacy name) means "use the pinned trust store" rather than
|
// servers almost universally use self-signed certs, so we
|
||||||
// "trust all certificates". ElectrumX servers almost universally
|
// route them through our pinned SSLSocketFactory (hardcoded
|
||||||
// use self-signed certs, so we route them through our pinned
|
// defaults + TOFU-pinned certs + system CAs).
|
||||||
// SSLSocketFactory (hardcoded defaults + TOFU-pinned certs).
|
|
||||||
// TODO: rename trustAllCerts → usePinnedTrustStore for clarity.
|
|
||||||
return ElectrumxServer(
|
return ElectrumxServer(
|
||||||
host = host,
|
host = host,
|
||||||
port = port,
|
port = port,
|
||||||
useSsl = useSsl,
|
useSsl = useSsl,
|
||||||
trustAllCerts = true,
|
usePinnedTrustStore = true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -56,7 +56,7 @@ class NamecoinSettingsTest {
|
|||||||
assertEquals("abc123def.onion", s!!.host)
|
assertEquals("abc123def.onion", s!!.host)
|
||||||
assertEquals(50001, s.port)
|
assertEquals(50001, s.port)
|
||||||
assertFalse(s.useSsl)
|
assertFalse(s.useSsl)
|
||||||
assertTrue(s.trustAllCerts)
|
assertTrue(s.usePinnedTrustStore)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -131,7 +131,7 @@ class NamecoinSettingsTest {
|
|||||||
assertTrue(servers[0].useSsl)
|
assertTrue(servers[0].useSsl)
|
||||||
assertEquals("server2.onion", servers[1].host)
|
assertEquals("server2.onion", servers[1].host)
|
||||||
assertFalse(servers[1].useSsl)
|
assertFalse(servers[1].useSsl)
|
||||||
assertTrue(servers[1].trustAllCerts)
|
assertTrue(servers[1].usePinnedTrustStore)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
+14
-8
@@ -44,8 +44,14 @@ data class ElectrumxServer(
|
|||||||
val host: String,
|
val host: String,
|
||||||
val port: Int,
|
val port: Int,
|
||||||
val useSsl: Boolean = true,
|
val useSsl: Boolean = true,
|
||||||
/** If true, accept any certificate (self-signed, expired, etc.) */
|
/**
|
||||||
val trustAllCerts: Boolean = false,
|
* If true, use the pinned trust store (hardcoded + TOFU-pinned certs
|
||||||
|
* plus system CAs) instead of the default system-only trust store.
|
||||||
|
*
|
||||||
|
* Required for ElectrumX servers that use self-signed certificates,
|
||||||
|
* which is the norm for the Namecoin ElectrumX ecosystem.
|
||||||
|
*/
|
||||||
|
val usePinnedTrustStore: Boolean = false,
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -90,9 +96,9 @@ data class ServerTestResult(
|
|||||||
/** Well-known public Namecoin ElectrumX servers (clearnet). */
|
/** Well-known public Namecoin ElectrumX servers (clearnet). */
|
||||||
val DEFAULT_ELECTRUMX_SERVERS =
|
val DEFAULT_ELECTRUMX_SERVERS =
|
||||||
listOf(
|
listOf(
|
||||||
ElectrumxServer("electrumx.testls.space", 50002, useSsl = true, trustAllCerts = true),
|
ElectrumxServer("electrumx.testls.space", 50002, useSsl = true, usePinnedTrustStore = true),
|
||||||
ElectrumxServer("nmc2.bitcoins.sk", 57002, useSsl = true, trustAllCerts = true),
|
ElectrumxServer("nmc2.bitcoins.sk", 57002, useSsl = true, usePinnedTrustStore = true),
|
||||||
ElectrumxServer("46.229.238.187", 57002, useSsl = true, trustAllCerts = true),
|
ElectrumxServer("46.229.238.187", 57002, useSsl = true, usePinnedTrustStore = true),
|
||||||
)
|
)
|
||||||
|
|
||||||
/** Tor-preferred server list: onion primary, clearnet fallback. */
|
/** Tor-preferred server list: onion primary, clearnet fallback. */
|
||||||
@@ -102,8 +108,8 @@ val TOR_ELECTRUMX_SERVERS =
|
|||||||
"i665jpwsq46zlsdbnj4axgzd3s56uzey5uhotsnxzsknzbn36jaddsid.onion",
|
"i665jpwsq46zlsdbnj4axgzd3s56uzey5uhotsnxzsknzbn36jaddsid.onion",
|
||||||
50002,
|
50002,
|
||||||
useSsl = true,
|
useSsl = true,
|
||||||
trustAllCerts = true,
|
usePinnedTrustStore = true,
|
||||||
),
|
),
|
||||||
ElectrumxServer("electrumx.testls.space", 50002, useSsl = true, trustAllCerts = true),
|
ElectrumxServer("electrumx.testls.space", 50002, useSsl = true, usePinnedTrustStore = true),
|
||||||
ElectrumxServer("nmc2.bitcoins.sk", 57002, useSsl = true, trustAllCerts = true),
|
ElectrumxServer("nmc2.bitcoins.sk", 57002, useSsl = true, usePinnedTrustStore = true),
|
||||||
)
|
)
|
||||||
|
|||||||
+5
-9
@@ -601,14 +601,10 @@ class ElectrumXClient(
|
|||||||
if (!server.useSsl) return baseSocket
|
if (!server.useSsl) return baseSocket
|
||||||
|
|
||||||
// Upgrade to TLS over the already-connected (possibly proxied) socket.
|
// Upgrade to TLS over the already-connected (possibly proxied) socket.
|
||||||
// When the server uses a self-signed certificate (trustAllCerts flag),
|
// When usePinnedTrustStore is set, we use a pinned trust store that
|
||||||
// we use a pinned trust store that contains the known ElectrumX server
|
// contains the known ElectrumX server certs plus system CAs. This is
|
||||||
// certs. This is required because Samsung One UI 7 (Android 16) silently
|
// required because Samsung One UI 7 (Android 16) and GrapheneOS
|
||||||
// rejects connections that use a no-op "trust-all" X509TrustManager.
|
// reject connections that use a no-op "trust-all" X509TrustManager.
|
||||||
//
|
|
||||||
// Exception: .onion addresses bypass cert pinning entirely — the Tor
|
|
||||||
// hidden service protocol already provides end-to-end authentication
|
|
||||||
// via the onion address, making TLS cert verification redundant.
|
|
||||||
val sslFactory =
|
val sslFactory =
|
||||||
if (server.host.endsWith(".onion")) {
|
if (server.host.endsWith(".onion")) {
|
||||||
// .onion addresses: prefer the pinned factory (the .onion server's
|
// .onion addresses: prefer the pinned factory (the .onion server's
|
||||||
@@ -618,7 +614,7 @@ class ElectrumXClient(
|
|||||||
// blanket trust-all that hardened TLS stacks (GrapheneOS, Samsung
|
// blanket trust-all that hardened TLS stacks (GrapheneOS, Samsung
|
||||||
// Knox) may reject at the Conscrypt/BoringSSL layer.
|
// Knox) may reject at the Conscrypt/BoringSSL layer.
|
||||||
cachedPinnedSslFactory()
|
cachedPinnedSslFactory()
|
||||||
} else if (server.trustAllCerts) {
|
} else if (server.usePinnedTrustStore) {
|
||||||
cachedPinnedSslFactory()
|
cachedPinnedSslFactory()
|
||||||
} else {
|
} else {
|
||||||
SSLSocketFactory.getDefault() as SSLSocketFactory
|
SSLSocketFactory.getDefault() as SSLSocketFactory
|
||||||
|
|||||||
Reference in New Issue
Block a user