electrum: add rustls
as the default ssl implementation
This commit is contained in:
parent
f5a201b98d
commit
c4dc741310
@ -7,16 +7,21 @@ authors = ["Alekos Filini <alekos.filini@gmail.com>"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = "^0.4"
|
log = "^0.4"
|
||||||
|
bitcoin = { version = "0.23", features = ["use-serde"] }
|
||||||
serde = { version = "^1.0", features = ["derive"] }
|
serde = { version = "^1.0", features = ["derive"] }
|
||||||
serde_json = { version = "^1.0" }
|
serde_json = { version = "^1.0" }
|
||||||
|
|
||||||
|
# Optional dependencies
|
||||||
socks = { version = "^0.3", optional = true }
|
socks = { version = "^0.3", optional = true }
|
||||||
openssl = { version = "^0.10", optional = true }
|
openssl = { version = "^0.10", optional = true }
|
||||||
|
rustls = { version = "0.16.0", optional = true, features = ["dangerous_configuration"] }
|
||||||
[dependencies.bitcoin]
|
webpki = { version = "0.21.0", optional = true }
|
||||||
version = "0.23"
|
webpki-roots = { version = "^0.19", optional = true }
|
||||||
features = ["use-serde"]
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
default = ["socks", "webpki", "webpki-roots", "rustls"]
|
||||||
|
minimal = []
|
||||||
debug-calls = []
|
debug-calls = []
|
||||||
proxy = ["socks"]
|
proxy = ["socks"]
|
||||||
ssl = ["openssl"]
|
use-rustls = ["webpki", "webpki-roots", "rustls"]
|
||||||
|
use-openssl = ["openssl"]
|
||||||
|
9
core/electrum_client/examples/plaintext.rs
Normal file
9
core/electrum_client/examples/plaintext.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
extern crate electrum_client;
|
||||||
|
|
||||||
|
use electrum_client::Client;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut client = Client::new("kirsche.emzy.de:50001").unwrap();
|
||||||
|
let res = client.server_features();
|
||||||
|
println!("{:#?}", res);
|
||||||
|
}
|
13
core/electrum_client/examples/ssl.rs
Normal file
13
core/electrum_client/examples/ssl.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
extern crate electrum_client;
|
||||||
|
|
||||||
|
use electrum_client::Client;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut client = Client::new_ssl(
|
||||||
|
"electrum2.hodlister.co:50002",
|
||||||
|
Some("electrum2.hodlister.co"),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let res = client.server_features();
|
||||||
|
println!("{:#?}", res);
|
||||||
|
}
|
21
core/electrum_client/examples/tor.rs
Normal file
21
core/electrum_client/examples/tor.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
extern crate electrum_client;
|
||||||
|
|
||||||
|
use electrum_client::Client;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// NOTE: This assumes Tor is running localy, with an unauthenticated Socks5 listening at
|
||||||
|
// localhost:9050
|
||||||
|
|
||||||
|
let mut client = Client::new_proxy("ozahtqwp25chjdjd.onion:50001", "127.0.0.1:9050").unwrap();
|
||||||
|
let res = client.server_features();
|
||||||
|
println!("{:#?}", res);
|
||||||
|
|
||||||
|
// works both with onion v2/v3 (if your Tor supports them)
|
||||||
|
let mut client = Client::new_proxy(
|
||||||
|
"v7gtzf7nua6hdmb2wtqaqioqmesdb4xrlly4zwr7bvayxv2bpg665pqd.onion:50001",
|
||||||
|
"127.0.0.1:9050",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let res = client.server_features();
|
||||||
|
println!("{:#?}", res);
|
||||||
|
}
|
@ -13,13 +13,23 @@ use bitcoin::consensus::encode::{deserialize, serialize};
|
|||||||
use bitcoin::hashes::hex::{FromHex, ToHex};
|
use bitcoin::hashes::hex::{FromHex, ToHex};
|
||||||
use bitcoin::{Script, Txid};
|
use bitcoin::{Script, Txid};
|
||||||
|
|
||||||
#[cfg(feature = "ssl")]
|
#[cfg(feature = "use-openssl")]
|
||||||
use openssl::ssl::{SslConnector, SslMethod, SslStream, SslVerifyMode};
|
use openssl::ssl::{SslConnector, SslMethod, SslStream, SslVerifyMode};
|
||||||
|
#[cfg(all(
|
||||||
|
any(feature = "default", feature = "use-rustls"),
|
||||||
|
not(feature = "use-openssl")
|
||||||
|
))]
|
||||||
|
use rustls::{ClientConfig, ClientSession, StreamOwned};
|
||||||
|
|
||||||
#[cfg(feature = "socks")]
|
#[cfg(any(feature = "default", feature = "proxy"))]
|
||||||
use socks::{Socks5Stream, ToTargetAddr};
|
use socks::{Socks5Stream, ToTargetAddr};
|
||||||
|
|
||||||
#[cfg(any(feature = "socks", feature = "proxy"))]
|
#[cfg(any(
|
||||||
|
feature = "default",
|
||||||
|
feature = "use-rustls",
|
||||||
|
feature = "use-openssl",
|
||||||
|
feature = "proxy"
|
||||||
|
))]
|
||||||
use stream::ClonableStream;
|
use stream::ClonableStream;
|
||||||
|
|
||||||
use batch::Batch;
|
use batch::Batch;
|
||||||
@ -76,7 +86,7 @@ impl Client<TcpStream> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "ssl")]
|
#[cfg(feature = "use-openssl")]
|
||||||
impl Client<ClonableStream<SslStream<TcpStream>>> {
|
impl Client<ClonableStream<SslStream<TcpStream>>> {
|
||||||
pub fn new_ssl<A: ToSocketAddrs>(socket_addr: A, domain: Option<&str>) -> Result<Self, Error> {
|
pub fn new_ssl<A: ToSocketAddrs>(socket_addr: A, domain: Option<&str>) -> Result<Self, Error> {
|
||||||
let mut builder =
|
let mut builder =
|
||||||
@ -107,7 +117,71 @@ impl Client<ClonableStream<SslStream<TcpStream>>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "proxy")]
|
#[cfg(all(
|
||||||
|
any(feature = "default", feature = "use-rustls"),
|
||||||
|
not(feature = "use-openssl")
|
||||||
|
))]
|
||||||
|
mod danger {
|
||||||
|
use rustls;
|
||||||
|
use webpki;
|
||||||
|
|
||||||
|
pub struct NoCertificateVerification {}
|
||||||
|
|
||||||
|
impl rustls::ServerCertVerifier for NoCertificateVerification {
|
||||||
|
fn verify_server_cert(
|
||||||
|
&self,
|
||||||
|
_roots: &rustls::RootCertStore,
|
||||||
|
_presented_certs: &[rustls::Certificate],
|
||||||
|
_dns_name: webpki::DNSNameRef<'_>,
|
||||||
|
_ocsp: &[u8],
|
||||||
|
) -> Result<rustls::ServerCertVerified, rustls::TLSError> {
|
||||||
|
Ok(rustls::ServerCertVerified::assertion())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(
|
||||||
|
any(feature = "default", feature = "use-rustls"),
|
||||||
|
not(feature = "use-openssl")
|
||||||
|
))]
|
||||||
|
impl Client<ClonableStream<StreamOwned<ClientSession, TcpStream>>> {
|
||||||
|
pub fn new_ssl<A: ToSocketAddrs>(socket_addr: A, domain: Option<&str>) -> Result<Self, Error> {
|
||||||
|
let mut config = ClientConfig::new();
|
||||||
|
if domain.is_none() {
|
||||||
|
config
|
||||||
|
.dangerous()
|
||||||
|
.set_certificate_verifier(std::sync::Arc::new(danger::NoCertificateVerification {}))
|
||||||
|
} else {
|
||||||
|
// TODO: cert pinning
|
||||||
|
config
|
||||||
|
.root_store
|
||||||
|
.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
let tcp_stream = TcpStream::connect(socket_addr)?;
|
||||||
|
let session = ClientSession::new(
|
||||||
|
&std::sync::Arc::new(config),
|
||||||
|
webpki::DNSNameRef::try_from_ascii_str(domain.unwrap_or("not.validated"))
|
||||||
|
.map_err(|_| Error::InvalidDNSNameError(domain.unwrap_or("<NONE>").to_string()))?,
|
||||||
|
);
|
||||||
|
let stream = StreamOwned::new(session, tcp_stream);
|
||||||
|
let stream: ClonableStream<_> = stream.into();
|
||||||
|
|
||||||
|
let buf_reader = BufReader::new(stream.clone());
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
stream,
|
||||||
|
buf_reader,
|
||||||
|
headers: VecDeque::new(),
|
||||||
|
script_notifications: BTreeMap::new(),
|
||||||
|
|
||||||
|
#[cfg(feature = "debug-calls")]
|
||||||
|
calls: 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "default", feature = "proxy"))]
|
||||||
impl Client<ClonableStream<Socks5Stream>> {
|
impl Client<ClonableStream<Socks5Stream>> {
|
||||||
pub fn new_proxy<A: ToSocketAddrs, T: ToTargetAddr>(
|
pub fn new_proxy<A: ToSocketAddrs, T: ToTargetAddr>(
|
||||||
target_addr: T,
|
target_addr: T,
|
||||||
@ -478,7 +552,7 @@ impl<S: Read + Write> Client<S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "debug-calls")]
|
#[cfg(feature = "debug-calls")]
|
||||||
pub fn calls_made(&self) -> u32 {
|
pub fn calls_made(&self) -> usize {
|
||||||
self.calls
|
self.calls
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,15 +1,29 @@
|
|||||||
pub extern crate bitcoin;
|
pub extern crate bitcoin;
|
||||||
extern crate log;
|
extern crate log;
|
||||||
#[cfg(feature = "ssl")]
|
#[cfg(feature = "use-openssl")]
|
||||||
extern crate openssl;
|
extern crate openssl;
|
||||||
|
#[cfg(all(
|
||||||
|
any(feature = "default", feature = "use-rustls"),
|
||||||
|
not(feature = "use-openssl")
|
||||||
|
))]
|
||||||
|
extern crate rustls;
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
#[cfg(feature = "proxy")]
|
#[cfg(any(feature = "default", feature = "proxy"))]
|
||||||
extern crate socks;
|
extern crate socks;
|
||||||
|
#[cfg(any(feature = "use-rustls", feature = "default"))]
|
||||||
|
extern crate webpki;
|
||||||
|
#[cfg(any(feature = "use-rustls", feature = "default"))]
|
||||||
|
extern crate webpki_roots;
|
||||||
|
|
||||||
pub mod batch;
|
pub mod batch;
|
||||||
pub mod client;
|
pub mod client;
|
||||||
#[cfg(any(feature = "socks", feature = "proxy"))]
|
#[cfg(any(
|
||||||
|
feature = "default",
|
||||||
|
feature = "use-rustls",
|
||||||
|
feature = "use-openssl",
|
||||||
|
feature = "proxy"
|
||||||
|
))]
|
||||||
mod stream;
|
mod stream;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test_stream;
|
mod test_stream;
|
||||||
|
@ -167,10 +167,11 @@ pub enum Error {
|
|||||||
NotSubscribed(ScriptHash),
|
NotSubscribed(ScriptHash),
|
||||||
InvalidResponse(serde_json::Value),
|
InvalidResponse(serde_json::Value),
|
||||||
Message(String),
|
Message(String),
|
||||||
|
InvalidDNSNameError(String),
|
||||||
|
|
||||||
#[cfg(feature = "ssl")]
|
#[cfg(feature = "use-openssl")]
|
||||||
InvalidSslMethod(openssl::error::ErrorStack),
|
InvalidSslMethod(openssl::error::ErrorStack),
|
||||||
#[cfg(feature = "ssl")]
|
#[cfg(feature = "use-openssl")]
|
||||||
SslHandshakeError(openssl::ssl::HandshakeError<std::net::TcpStream>),
|
SslHandshakeError(openssl::ssl::HandshakeError<std::net::TcpStream>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user