From 28b0acc0e63582b508066a0a06c2f330e0fae9af Mon Sep 17 00:00:00 2001 From: hashmap Date: Fri, 5 Oct 2018 17:03:15 +0200 Subject: [PATCH] Support pem TLS certificates Mostly to support let's encrypt. It requires to switch from native-tls and friends to rustls and friends, which perhap is a good thing per se, rustls looks more modern and for sure more Rusty. Alternative would be manually convert pkcs12 certificates to pem, which requires openssl tools to be installed and make transparent integration whith let's encrypt much harder (this is out of the scope for now, perhaps in near future) --- Cargo.lock | 119 ++++++++++++++++++++++++++++++++++++----- api/Cargo.toml | 7 +-- api/src/client.rs | 4 +- api/src/lib.rs | 7 +-- api/src/rest.rs | 109 ++++++++++++++++++++++--------------- api/tests/rest.rs | 13 +++-- config/src/comments.rs | 8 ++- src/bin/cmd/wallet.rs | 19 ++++--- wallet/src/types.rs | 6 +-- 9 files changed, 201 insertions(+), 91 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 01c99e309..8973b1160 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -377,6 +377,14 @@ dependencies = [ "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ct-logs" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "sct 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ctrlc" version = "3.1.1" @@ -670,17 +678,18 @@ dependencies = [ "grin_util 0.3.0", "http 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.12.10 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper-tls 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper-rustls 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "native-tls 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tls 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-rustls 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tcp 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -984,6 +993,24 @@ dependencies = [ "want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "hyper-rustls" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ct-logs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.10 (registry+https://github.com/rust-lang/crates.io-index)", + "rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-rustls 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tcp 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", + "webpki-roots 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "hyper-staticfile" version = "0.3.0" @@ -1810,6 +1837,17 @@ dependencies = [ "uuid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ring" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ripemd160" version = "0.7.0" @@ -1838,6 +1876,19 @@ dependencies = [ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rustls" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", + "sct 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ryu" version = "0.2.6" @@ -1875,6 +1926,15 @@ name = "scopeguard" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "sct" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ring 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "secp256k1zkp" version = "0.7.1" @@ -2279,6 +2339,16 @@ dependencies = [ "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tokio-rustls" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "tokio-service" version = "0.1.0" @@ -2325,16 +2395,6 @@ dependencies = [ "tokio-executor 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "tokio-tls" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", - "native-tls 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "tokio-udp" version = "0.1.2" @@ -2440,6 +2500,11 @@ dependencies = [ "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "untrusted" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "url" version = "1.7.1" @@ -2513,6 +2578,24 @@ dependencies = [ "try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "webpki" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ring 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "webpki-roots" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "which" version = "1.0.5" @@ -2647,6 +2730,7 @@ dependencies = [ "checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015" "checksum crypto-mac 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7afa06d05a046c7a47c3a849907ec303504608c927f4e85f7bfff22b7180d971" "checksum csv 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7ef22b37c7a51c564a365892c012dc0271221fdcc64c69b19ba4d6fa8bd96d9c" +"checksum ct-logs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "95a4bf5107667e12bf6ce31a3a5066d67acc88942b6742117a41198734aaccaa" "checksum ctrlc 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "630391922b1b893692c6334369ff528dcc3a9d8061ccf4c803aa8f83cb13db5e" "checksum cursive 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c75a59f5b54834c5853b1e8d0d4a256252d4ca1da02f0be3e245b48daa754233" "checksum daemonize 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4093d27eb267d617f03c2ee25d4c3ca525b89a76154001954a11984508ffbde5" @@ -2684,6 +2768,7 @@ dependencies = [ "checksum httparse 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7b6288d7db100340ca12873fd4d08ad1b8f206a9457798dfb17c018a33fee540" "checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e" "checksum hyper 0.12.10 (registry+https://github.com/rust-lang/crates.io-index)" = "529d00e4c998cced1a15ffd53bbe203917b39ed6071281c16184ab0014ca6ff3" +"checksum hyper-rustls 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "68f2aa6b1681795bf4da8063f718cd23145aa0c9a5143d9787b345aa60d38ee4" "checksum hyper-staticfile 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4080cb44b9c1e4c6dfd6f7ee85a9c3439777ec9c59df32f944836d3de58ac35e" "checksum hyper-tls 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "caaee4dea92794a9e697038bd401e264307d1f22c883dbcb6f6618ba0d3b3bd3" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" @@ -2776,16 +2861,19 @@ dependencies = [ "checksum regex-syntax 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "747ba3b235651f6e2f67dfa8bcdcd073ddb7c243cb21c442fc12395dfcac212d" "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" "checksum reqwest 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c4265be4dad32ffa4be2cea9c8ecb5e096feca6b4ff024482bfc0f64b6019b2f" +"checksum ring 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe642b9dd1ba0038d78c4a3999d1ee56178b4d415c1e1fbaba83b06dce012f0" "checksum ripemd160 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "482aa56cc68aaeccdaaff1cc5a72c247da8bbad3beb174ca5741f274c22883fb" "checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "942b71057b31981152970d57399c25f72e27a6ee0d207a669d8304cabf44705b" "checksum ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7153dd96dade874ab973e098cb62fcdbb89a03682e46b144fd09550998d4a4a7" "checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9" "checksum same-file 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "10f7794e2fda7f594866840e95f5c5962e886e228e68b6505885811a94dd728c" "checksum schannel 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "dc1fabf2a7b6483a141426e1afd09ad543520a77ac49bd03c286e7696ccfd77f" "checksum scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" +"checksum sct 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb8f61f9e6eadd062a71c380043d28036304a4706b3c4dd001ff3387ed00745a" "checksum secp256k1zkp 0.7.1 (git+https://github.com/mimblewimble/rust-secp256k1-zkp?tag=grin_integration_23a)" = "" "checksum security-framework 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "697d3f3c23a618272ead9e1fb259c1411102b31c6af8b93f1d64cca9c3b0e8e0" "checksum security-framework-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab01dfbe5756785b5b4d46e0289e5a18071dfa9a7c2b24213ea00b9ef9b665bf" @@ -2829,11 +2917,11 @@ dependencies = [ "checksum tokio-io 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8d6cc2de7725863c86ac71b0b9068476fec50834f055a243558ef1655bbd34cb" "checksum tokio-reactor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4bfbaf9f260635649ec26b6fb4aded03887295ffcd999f6e43fd2c4758f758ea" "checksum tokio-retry 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f05746ae87dca83a2016b4f5dba5b237b897dd12fd324f60afe282112f16969a" +"checksum tokio-rustls 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "208d62fa3e015426e3c64039d9d20adf054a3c9b4d9445560f1c41c75bef3eab" "checksum tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162" "checksum tokio-tcp 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5b4c329b47f071eb8a746040465fa751bd95e4716e98daef6a9b4e434c17d565" "checksum tokio-threadpool 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a5758cecb6e0633cea5d563ac07c975e04961690b946b04fd84e7d6445a8f6af" "checksum tokio-timer 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d03fa701f9578a01b7014f106b47f0a363b4727a7f3f75d666e312ab7acbbf1c" -"checksum tokio-tls 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e53fdbf3156f588be1676022fe794232b24922d426e8c14f4e46891c1e31c440" "checksum tokio-udp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "da941144b816d0dcda4db3a1ba87596e4df5e860a72b70783fe435891f80601c" "checksum tokio-uds 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "424c1ed15a0132251813ccea50640b224c809d6ceafb88154c1a8775873a0e89" "checksum toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a0263c6c02c4db6c8f7681f9fd35e90de799ebd4cfdeab77a38f4ff6b3d8c0d9" @@ -2848,6 +2936,7 @@ dependencies = [ "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +"checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f" "checksum url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a321979c09843d272956e73700d12c4e7d3d92b2ee112b31548aef0d4efc5a6" "checksum utf8-ranges 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd70f467df6810094968e2fce0ee1bd0e87157aceb026a8c083bcf5e25b9efe4" "checksum uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e1436e58182935dcd9ce0add9ea0b558e8a87befe01c1a301e6020aeb0876363" @@ -2858,6 +2947,8 @@ dependencies = [ "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum walkdir 2.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "af464bc7be7b785c7ac72e266a6b67c4c9070155606f51655a650a6686204e35" "checksum want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "797464475f30ddb8830cc529aaaae648d581f99e2036a928877dfde027ddf6b3" +"checksum webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "17d7967316d8411ca3b01821ee6c332bde138ba4363becdb492f12e514daa17f" +"checksum webpki-roots 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "85d1f408918fd590908a70d36b7ac388db2edc221470333e4d6e5b598e44cabf" "checksum which 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e84a603e7e0b1ce1aa1ee2b109c7be00155ce52df5081590d1ffb93f4f515cb2" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd" diff --git a/api/Cargo.toml b/api/Cargo.toml index bd243e00b..d4ac82a2b 100644 --- a/api/Cargo.toml +++ b/api/Cargo.toml @@ -17,11 +17,12 @@ serde_json = "1" slog = { version = "~2.3", features = ["max_level_trace", "release_max_level_trace"] } tokio = "0.1.7" tokio-core = "0.1.17" -tokio-tls = "0.2" -native-tls = "0.2" +tokio-tcp = "0.1" +tokio-rustls = "0.7" http = "0.1.5" -hyper-tls = "0.3" +hyper-rustls = "0.14" futures = "0.1.21" +rustls = "0.13" url = "1.7.0" grin_core = { path = "../core" } diff --git a/api/src/client.rs b/api/src/client.rs index 42d0a34af..b6bac3b33 100644 --- a/api/src/client.rs +++ b/api/src/client.rs @@ -19,11 +19,11 @@ use http::uri::{InvalidUri, Uri}; use hyper::header::{ACCEPT, AUTHORIZATION, USER_AGENT}; use hyper::rt::{Future, Stream}; use hyper::{Body, Client, Request}; -use hyper_tls; use serde::{Deserialize, Serialize}; use serde_json; use futures::future::{err, ok, Either}; +use hyper_rustls; use tokio::runtime::Runtime; use rest::{Error, ErrorKind}; @@ -186,7 +186,7 @@ where } fn send_request_async(req: Request) -> Box + Send> { - let https = hyper_tls::HttpsConnector::new(1).unwrap(); + let https = hyper_rustls::HttpsConnector::new(1); let client = Client::builder().build::<_, Body>(https); Box::new( client diff --git a/api/src/lib.rs b/api/src/lib.rs index 41be1cf71..9430c65de 100644 --- a/api/src/lib.rs +++ b/api/src/lib.rs @@ -24,7 +24,6 @@ extern crate failure; #[macro_use] extern crate failure_derive; extern crate hyper; -extern crate hyper_tls; #[macro_use] extern crate lazy_static; extern crate regex; @@ -36,10 +35,12 @@ extern crate serde_json; extern crate slog; extern crate futures; extern crate http; -extern crate native_tls; +extern crate hyper_rustls; +extern crate rustls; extern crate tokio; extern crate tokio_core; -extern crate tokio_tls; +extern crate tokio_rustls; +extern crate tokio_tcp; pub mod auth; pub mod client; diff --git a/api/src/rest.rs b/api/src/rest.rs index 9d440a4ef..f7738d0a5 100644 --- a/api/src/rest.rs +++ b/api/src/rest.rs @@ -22,17 +22,17 @@ use failure::{Backtrace, Context, Fail, ResultExt}; use futures::sync::oneshot; use futures::Stream; use hyper::rt::Future; -use hyper::server::conn::Http; use hyper::{rt, Body, Request, Server}; -use native_tls::{Identity, TlsAcceptor}; use router::{Handler, HandlerObj, ResponseFuture, Router}; +use rustls; +use rustls::internal::pemfile; use std::fmt::{self, Display}; use std::fs::File; -use std::io::Read; use std::net::SocketAddr; +use std::sync::Arc; use std::{io, thread}; -use tokio::net::TcpListener; -use tokio_tls; +use tokio_rustls::ServerConfigExt; +use tokio_tcp; use util::LOGGER; /// Errors that can be returned by an ApiEndpoint implementation. @@ -93,23 +93,55 @@ impl From> for Error { /// TLS config pub struct TLSConfig { - pub pkcs_bytes: Vec, - pub pass: String, + certificate: String, + private_key: String, } impl TLSConfig { - pub fn new(pass: String, file: String) -> Result { - let mut f = File::open(&file).context(ErrorKind::Internal(format!( - "can't open TLS certifiacte file {}", - file + pub fn new(certificate: String, private_key: String) -> TLSConfig { + TLSConfig { + certificate, + private_key, + } + } + + fn load_certs(&self) -> Result, Error> { + let certfile = File::open(&self.certificate).context(ErrorKind::Internal(format!( + "failed to open file {}", + self.certificate )))?; - let mut pkcs_bytes = Vec::new(); - f.read_to_end(&mut pkcs_bytes) - .context(ErrorKind::Internal(format!( - "can't read TLS certifiacte file {}", - file - )))?; - Ok(TLSConfig { pkcs_bytes, pass }) + let mut reader = io::BufReader::new(certfile); + + pemfile::certs(&mut reader) + .map_err(|_| ErrorKind::Internal("failed to load certificate".to_string()).into()) + } + + fn load_private_key(&self) -> Result { + let keyfile = File::open(&self.private_key).context(ErrorKind::Internal(format!( + "failed to open file {}", + self.private_key + )))?; + let mut reader = io::BufReader::new(keyfile); + + let keys = pemfile::pkcs8_private_keys(&mut reader) + .map_err(|_| ErrorKind::Internal("failed to load private key".to_string()))?; + if keys.len() != 1 { + return Err(ErrorKind::Internal( + "expected a single private key".to_string(), + ))?; + } + Ok(keys[0].clone()) + } + + pub fn build_server_config(&self) -> Result, Error> { + let certs = self.load_certs()?; + let key = self.load_private_key()?; + let mut cfg = rustls::ServerConfig::new(rustls::NoClientAuth::new()); + cfg.set_single_cert(certs, key) + .context(ErrorKind::Internal( + "set single certificate failed".to_string(), + ))?; + Ok(Arc::new(cfg)) } } @@ -180,37 +212,26 @@ impl ApiServer { "Can't start HTTPS API server, it's running already".to_string(), ))?; } + + let tls_conf = conf.build_server_config()?; + thread::Builder::new() .name("apis".to_string()) .spawn(move || { - let cert = Identity::from_pkcs12(conf.pkcs_bytes.as_slice(), &conf.pass).unwrap(); - let tls_cx = TlsAcceptor::builder(cert).build().unwrap(); - let tls_cx = tokio_tls::TlsAcceptor::from(tls_cx); - let srv = TcpListener::bind(&addr).expect("Error binding local port"); - // Use lower lever hyper API to be able to intercept client connection - let server = Http::new() - .serve_incoming( - srv.incoming().and_then(move |socket| { - tls_cx - .accept(socket) - .map_err(|e| io::Error::new(io::ErrorKind::Other, e)) - }), - router, - ).then(|res| match res { - Ok(conn) => Ok(Some(conn)), + let listener = tokio_tcp::TcpListener::bind(&addr).expect("failed to bind"); + let tls = listener + .incoming() + .and_then(move |s| tls_conf.accept_async(s)) + .then(|r| match r { + Ok(x) => Ok::<_, io::Error>(Some(x)), Err(e) => { - eprintln!("Error: {}", e); - Ok(None) + eprintln!("accept_async failed"); + Err(e) } - }).for_each(|conn_opt| { - if let Some(conn) = conn_opt { - rt::spawn( - conn.and_then(|c| c.map_err(|e| panic!("Hyper error {}", e))) - .map_err(|e| eprintln!("Connection error {}", e)), - ); - } - Ok(()) - }); + }).filter_map(|x| x); + let server = Server::builder(tls) + .serve(router) + .map_err(|e| eprintln!("HTTP API server error: {}", e)); rt::run(server); }).map_err(|_| ErrorKind::Internal("failed to spawn API thread".to_string()).into()) diff --git a/api/tests/rest.rs b/api/tests/rest.rs index c17495198..f522c5539 100644 --- a/api/tests/rest.rs +++ b/api/tests/rest.rs @@ -86,17 +86,16 @@ fn test_start_api() { #[test] fn test_start_api_tls() { util::init_test_logger(); - let tls_conf = TLSConfig { - pkcs_bytes: include_bytes!("localhost+1.p12").to_vec(), - pass: "changeit".to_string(), - }; + let tls_conf = TLSConfig::new( + "tests/fullchain.pem".to_string(), + "tests/privkey.pem".to_string(), + ); let mut server = ApiServer::new(); let router = build_router(); - let server_addr = "127.0.0.1:14444"; + let server_addr = "0.0.0.0:14444"; let addr: SocketAddr = server_addr.parse().expect("unable to parse server address"); assert!(server.start(addr, router, Some(tls_conf)).is_ok()); - let url = format!("https://{}/v1/", server_addr); - let index = api::client::get::>(url.as_str(), None).unwrap(); + let index = api::client::get::>("https://yourdomain.com:14444/v1/", None).unwrap(); assert_eq!(index.len(), 2); assert!(!server.stop()); } diff --git a/config/src/comments.rs b/config/src/comments.rs index a5f31cbaf..056eb4efb 100644 --- a/config/src/comments.rs +++ b/config/src/comments.rs @@ -311,12 +311,10 @@ fn comments() -> HashMap { " #port for wallet listener -#path of TLS certificate file (PKCS#12 format is supported) -#self-signed certificates are not supported, use https://github.com/FiloSottile/mkcert -#to test on localhost +#path of TLS certificate file, self-signed certificates are not supported #tls_certificate_file = \"\" -#password of TLS certificate file (PKCS#12 format is supported) -#tls_certificate_pass = \"\" +#private key for the TLS certificate +#tls_certificate_key = \"\" ".to_string(), ); diff --git a/src/bin/cmd/wallet.rs b/src/bin/cmd/wallet.rs index ac34ad327..fb62ac7c1 100644 --- a/src/bin/cmd/wallet.rs +++ b/src/bin/cmd/wallet.rs @@ -137,15 +137,13 @@ pub fn wallet_command(wallet_args: &ArgMatches, config: GlobalWalletConfig) { let tls_conf = match wallet_config.tls_certificate_file.clone() { None => None, - Some(file) => Some( - TLSConfig::new( - wallet_config - .tls_certificate_pass - .clone() - .expect("tls_certificate_pass must be set"), - file, - ).expect("failed to configure TLS"), - ), + Some(file) => Some(TLSConfig::new( + file, + wallet_config + .tls_certificate_key + .clone() + .expect("Private key for certificate is not set"), + )), }; match wallet_args.subcommand() { ("listen", Some(listen_args)) => { @@ -161,7 +159,8 @@ pub fn wallet_command(wallet_args: &ArgMatches, config: GlobalWalletConfig) { }); } ("owner_api", Some(_api_args)) => { - controller::owner_listener(wallet, "127.0.0.1:13420", api_secret, tls_conf) + // TLS is disabled because we bind to localhost + controller::owner_listener(wallet, "127.0.0.1:13420", api_secret, None) .unwrap_or_else(|e| { panic!( "Error creating wallet api listener: {:?} Config: {:?}", diff --git a/wallet/src/types.rs b/wallet/src/types.rs index 8bbc97119..97792e164 100644 --- a/wallet/src/types.rs +++ b/wallet/src/types.rs @@ -50,8 +50,8 @@ pub struct WalletConfig { pub data_file_dir: String, /// TLS ceritificate file pub tls_certificate_file: Option, - /// TLS ceritificate password - pub tls_certificate_pass: Option, + /// TLS ceritificate private key file + pub tls_certificate_key: Option, } impl Default for WalletConfig { @@ -65,7 +65,7 @@ impl Default for WalletConfig { check_node_api_http_addr: "http://127.0.0.1:13413".to_string(), data_file_dir: ".".to_string(), tls_certificate_file: None, - tls_certificate_pass: None, + tls_certificate_key: None, } } }