2017-10-30 10:22:38 +01:00
|
|
|
// Copyright 2017 Parity Technologies (UK) Ltd.
|
|
|
|
//
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
// copy of this software and associated documentation files (the "Software"),
|
|
|
|
// to deal in the Software without restriction, including without limitation
|
|
|
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
// and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
// Software is furnished to do so, subject to the following conditions:
|
|
|
|
//
|
|
|
|
// The above copyright notice and this permission notice shall be included in
|
|
|
|
// all copies or substantial portions of the Software.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
|
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
// DEALINGS IN THE SOFTWARE.
|
|
|
|
|
|
|
|
//! The `secio` protocol is a middleware that will encrypt and decrypt communications going
|
|
|
|
//! through a socket (or anything that implements `AsyncRead + AsyncWrite`).
|
|
|
|
//!
|
2017-12-07 15:34:22 +01:00
|
|
|
//! # Connection upgrade
|
2018-03-07 16:20:55 +01:00
|
|
|
//!
|
2017-12-07 15:34:22 +01:00
|
|
|
//! The `SecioConfig` struct implements the `ConnectionUpgrade` trait. You can apply it over a
|
|
|
|
//! `Transport` by using the `with_upgrade` method. The returned object will also implement
|
|
|
|
//! `Transport` and will automatically apply the secio protocol over any connection that is opened
|
|
|
|
//! through it.
|
2018-03-07 16:20:55 +01:00
|
|
|
//!
|
2017-12-07 15:34:22 +01:00
|
|
|
//! ```no_run
|
|
|
|
//! extern crate futures;
|
2018-07-16 12:15:27 +02:00
|
|
|
//! extern crate tokio_current_thread;
|
2017-12-07 15:34:22 +01:00
|
|
|
//! extern crate tokio_io;
|
2018-05-16 12:59:36 +02:00
|
|
|
//! extern crate libp2p_core;
|
2017-12-07 15:34:22 +01:00
|
|
|
//! extern crate libp2p_secio;
|
|
|
|
//! extern crate libp2p_tcp_transport;
|
2018-03-07 16:20:55 +01:00
|
|
|
//!
|
2017-12-07 15:34:22 +01:00
|
|
|
//! # fn main() {
|
|
|
|
//! use futures::Future;
|
2018-07-04 17:07:38 +02:00
|
|
|
//! use libp2p_secio::{SecioConfig, SecioKeyPair, SecioOutput};
|
2018-05-16 12:59:36 +02:00
|
|
|
//! use libp2p_core::{Multiaddr, Transport, upgrade};
|
2017-12-07 15:34:22 +01:00
|
|
|
//! use libp2p_tcp_transport::TcpConfig;
|
|
|
|
//! use tokio_io::io::write_all;
|
2018-03-07 16:20:55 +01:00
|
|
|
//!
|
2018-07-16 12:15:27 +02:00
|
|
|
//! let transport = TcpConfig::new()
|
2018-03-07 16:20:55 +01:00
|
|
|
//! .with_upgrade({
|
|
|
|
//! # let private_key = b"";
|
2018-05-31 14:50:24 +02:00
|
|
|
//! //let private_key = include_bytes!("test-rsa-private-key.pk8");
|
2018-03-07 16:20:55 +01:00
|
|
|
//! # let public_key = vec![];
|
2018-05-31 14:50:24 +02:00
|
|
|
//! //let public_key = include_bytes!("test-rsa-public-key.der").to_vec();
|
2018-09-12 09:10:05 +02:00
|
|
|
//! // See the documentation of `SecioKeyPair`.
|
|
|
|
//! let keypair = SecioKeyPair::rsa_from_pkcs8(private_key, public_key).unwrap();
|
|
|
|
//! let upgrade = SecioConfig::new(keypair);
|
2018-05-14 15:55:16 +02:00
|
|
|
//!
|
2018-07-04 17:07:38 +02:00
|
|
|
//! upgrade::map(upgrade, |out: SecioOutput<_>| out.stream)
|
2018-03-07 16:20:55 +01:00
|
|
|
//! });
|
|
|
|
//!
|
2017-12-28 18:07:49 +01:00
|
|
|
//! let future = transport.dial("/ip4/127.0.0.1/tcp/12345".parse::<Multiaddr>().unwrap())
|
2018-03-07 16:20:55 +01:00
|
|
|
//! .unwrap_or_else(|_| panic!("Unable to dial node"))
|
|
|
|
//! .and_then(|(connection, _)| {
|
|
|
|
//! // Sends "hello world" on the connection, will be encrypted.
|
|
|
|
//! write_all(connection, "hello world")
|
|
|
|
//! });
|
|
|
|
//!
|
2018-07-16 12:15:27 +02:00
|
|
|
//! tokio_current_thread::block_on_all(future).unwrap();
|
2017-12-07 15:34:22 +01:00
|
|
|
//! # }
|
|
|
|
//! ```
|
|
|
|
//!
|
|
|
|
//! # Manual usage
|
|
|
|
//!
|
|
|
|
//! > **Note**: You are encouraged to use `SecioConfig` as described above.
|
|
|
|
//!
|
2017-10-30 10:22:38 +01:00
|
|
|
//! You can add the `secio` layer over a socket by calling `SecioMiddleware::handshake()`. This
|
|
|
|
//! method will perform a handshake with the host, and return a future that corresponds to the
|
|
|
|
//! moment when the handshake succeeds or errored. On success, the future produces a
|
|
|
|
//! `SecioMiddleware` that implements `Sink` and `Stream` and can be used to send packets of data.
|
2017-11-02 11:58:02 +01:00
|
|
|
//!
|
2017-10-30 10:22:38 +01:00
|
|
|
|
2018-09-17 10:05:37 +02:00
|
|
|
extern crate aes_ctr;
|
2018-06-22 13:07:57 +02:00
|
|
|
#[cfg(feature = "secp256k1")]
|
2018-06-20 09:47:43 +02:00
|
|
|
extern crate asn1_der;
|
2017-10-30 10:22:38 +01:00
|
|
|
extern crate bytes;
|
2018-09-17 10:05:37 +02:00
|
|
|
extern crate ctr;
|
2017-10-30 10:22:38 +01:00
|
|
|
extern crate futures;
|
2018-05-16 12:59:36 +02:00
|
|
|
extern crate libp2p_core;
|
2018-02-14 13:02:56 +01:00
|
|
|
#[macro_use]
|
|
|
|
extern crate log;
|
2017-10-30 10:22:38 +01:00
|
|
|
extern crate protobuf;
|
|
|
|
extern crate rand;
|
|
|
|
extern crate ring;
|
2017-11-02 11:58:02 +01:00
|
|
|
extern crate rw_stream_sink;
|
2018-06-22 13:07:57 +02:00
|
|
|
#[cfg(feature = "secp256k1")]
|
2018-06-20 09:47:43 +02:00
|
|
|
extern crate secp256k1;
|
2017-10-30 10:22:38 +01:00
|
|
|
extern crate tokio_io;
|
2018-09-17 10:05:37 +02:00
|
|
|
extern crate twofish;
|
2017-10-30 10:22:38 +01:00
|
|
|
extern crate untrusted;
|
|
|
|
|
2018-09-17 10:05:37 +02:00
|
|
|
#[cfg(feature = "aes-all")]
|
|
|
|
#[macro_use]
|
|
|
|
extern crate lazy_static;
|
2017-10-30 10:22:38 +01:00
|
|
|
pub use self::error::SecioError;
|
|
|
|
|
2018-06-22 13:07:57 +02:00
|
|
|
#[cfg(feature = "secp256k1")]
|
2018-07-11 11:14:40 +02:00
|
|
|
use asn1_der::{traits::FromDerEncoded, traits::FromDerObject, DerObject};
|
2017-11-02 11:58:02 +01:00
|
|
|
use bytes::{Bytes, BytesMut};
|
|
|
|
use futures::stream::MapErr as StreamMapErr;
|
2018-05-14 15:55:16 +02:00
|
|
|
use futures::{Future, Poll, Sink, StartSend, Stream};
|
2018-06-25 17:56:36 +02:00
|
|
|
use libp2p_core::{PeerId, PublicKey};
|
2018-05-31 14:50:24 +02:00
|
|
|
use ring::rand::SystemRandom;
|
2018-07-11 11:14:40 +02:00
|
|
|
use ring::signature::{Ed25519KeyPair, RSAKeyPair};
|
2017-11-02 11:58:02 +01:00
|
|
|
use rw_stream_sink::RwStreamSink;
|
2017-12-04 15:39:40 +01:00
|
|
|
use std::error::Error;
|
2017-11-02 11:58:02 +01:00
|
|
|
use std::io::{Error as IoError, ErrorKind as IoErrorKind};
|
|
|
|
use std::iter;
|
2017-10-30 10:22:38 +01:00
|
|
|
use std::sync::Arc;
|
|
|
|
use tokio_io::{AsyncRead, AsyncWrite};
|
2017-12-04 15:39:40 +01:00
|
|
|
use untrusted::Input;
|
2017-10-30 10:22:38 +01:00
|
|
|
|
|
|
|
mod algo_support;
|
|
|
|
mod codec;
|
|
|
|
mod error;
|
|
|
|
mod handshake;
|
2018-09-07 14:05:42 +02:00
|
|
|
mod structs_proto;
|
2018-09-17 10:05:37 +02:00
|
|
|
mod stream_cipher;
|
2017-10-30 10:22:38 +01:00
|
|
|
|
2018-09-12 09:10:05 +02:00
|
|
|
pub use algo_support::{Digest, KeyAgreement};
|
|
|
|
pub use stream_cipher::Cipher;
|
|
|
|
|
2018-05-16 12:59:36 +02:00
|
|
|
/// Implementation of the `ConnectionUpgrade` trait of `libp2p_core`. Automatically applies
|
2017-11-02 11:58:02 +01:00
|
|
|
/// secio on any connection.
|
|
|
|
#[derive(Clone)]
|
2017-12-04 15:50:14 +01:00
|
|
|
pub struct SecioConfig {
|
2018-03-07 16:20:55 +01:00
|
|
|
/// Private and public keys of the local node.
|
2018-09-12 09:10:05 +02:00
|
|
|
pub(crate) key: SecioKeyPair,
|
|
|
|
pub(crate) agreements_prop: Option<String>,
|
|
|
|
pub(crate) ciphers_prop: Option<String>,
|
|
|
|
pub(crate) digests_prop: Option<String>
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SecioConfig {
|
|
|
|
/// Create a new `SecioConfig` with the given keypair.
|
|
|
|
pub fn new(kp: SecioKeyPair) -> Self {
|
|
|
|
SecioConfig {
|
|
|
|
key: kp,
|
|
|
|
agreements_prop: None,
|
|
|
|
ciphers_prop: None,
|
|
|
|
digests_prop: None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Override the default set of supported key agreement algorithms.
|
|
|
|
pub fn key_agreements<'a, I>(mut self, xs: I) -> Self
|
|
|
|
where
|
|
|
|
I: IntoIterator<Item=&'a KeyAgreement>
|
|
|
|
{
|
|
|
|
self.agreements_prop = Some(algo_support::key_agreements_proposition(xs));
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Override the default set of supported ciphers.
|
|
|
|
pub fn ciphers<'a, I>(mut self, xs: I) -> Self
|
|
|
|
where
|
|
|
|
I: IntoIterator<Item=&'a Cipher>
|
|
|
|
{
|
|
|
|
self.ciphers_prop = Some(algo_support::ciphers_proposition(xs));
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Override the default set of supported digest algorithms.
|
|
|
|
pub fn digests<'a, I>(mut self, xs: I) -> Self
|
|
|
|
where
|
|
|
|
I: IntoIterator<Item=&'a Digest>
|
|
|
|
{
|
|
|
|
self.digests_prop = Some(algo_support::digests_proposition(xs));
|
|
|
|
self
|
|
|
|
}
|
2017-11-02 11:58:02 +01:00
|
|
|
}
|
|
|
|
|
2017-12-04 15:39:40 +01:00
|
|
|
/// Private and public keys of the local node.
|
|
|
|
///
|
|
|
|
/// # Generating offline keys with OpenSSL
|
|
|
|
///
|
|
|
|
/// ## RSA
|
|
|
|
///
|
|
|
|
/// Generating the keys:
|
|
|
|
///
|
|
|
|
/// ```ignore
|
|
|
|
/// openssl genrsa -out private.pem 2048
|
|
|
|
/// openssl rsa -in private.pem -outform DER -pubout -out public.der
|
|
|
|
/// openssl pkcs8 -in private.pem -topk8 -nocrypt -out private.pk8
|
|
|
|
/// rm private.pem # optional
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Loading the keys:
|
|
|
|
///
|
|
|
|
/// ```ignore
|
2017-12-07 12:05:38 +01:00
|
|
|
/// let key_pair = SecioKeyPair::rsa_from_pkcs8(include_bytes!("private.pk8"),
|
2018-03-07 16:20:55 +01:00
|
|
|
/// include_bytes!("public.der"));
|
2017-12-04 15:39:40 +01:00
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct SecioKeyPair {
|
2018-03-07 16:20:55 +01:00
|
|
|
inner: SecioKeyPairInner,
|
2017-12-04 15:39:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl SecioKeyPair {
|
2018-05-31 14:50:24 +02:00
|
|
|
/// Builds a `SecioKeyPair` from a PKCS8 private key and public key.
|
2018-03-07 16:20:55 +01:00
|
|
|
pub fn rsa_from_pkcs8<P>(
|
|
|
|
private: &[u8],
|
|
|
|
public: P,
|
|
|
|
) -> Result<SecioKeyPair, Box<Error + Send + Sync>>
|
|
|
|
where
|
|
|
|
P: Into<Vec<u8>>,
|
|
|
|
{
|
2018-07-17 11:55:18 +02:00
|
|
|
let private = RSAKeyPair::from_pkcs8(Input::from(&private[..])).map_err(Box::new)?;
|
2017-12-04 15:39:40 +01:00
|
|
|
|
2018-03-07 16:20:55 +01:00
|
|
|
Ok(SecioKeyPair {
|
|
|
|
inner: SecioKeyPairInner::Rsa {
|
|
|
|
public: public.into(),
|
|
|
|
private: Arc::new(private),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
2018-05-31 14:50:24 +02:00
|
|
|
|
|
|
|
/// Builds a `SecioKeyPair` from a PKCS8 ED25519 private key.
|
|
|
|
pub fn ed25519_from_pkcs8<K>(key: K) -> Result<SecioKeyPair, Box<Error + Send + Sync>>
|
2018-07-11 11:14:40 +02:00
|
|
|
where
|
|
|
|
K: AsRef<[u8]>,
|
2018-05-31 14:50:24 +02:00
|
|
|
{
|
2018-07-17 11:55:18 +02:00
|
|
|
let key_pair = Ed25519KeyPair::from_pkcs8(Input::from(key.as_ref())).map_err(Box::new)?;
|
2018-05-31 14:50:24 +02:00
|
|
|
|
|
|
|
Ok(SecioKeyPair {
|
|
|
|
inner: SecioKeyPairInner::Ed25519 {
|
|
|
|
key_pair: Arc::new(key_pair),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Generates a new Ed25519 key pair and uses it.
|
|
|
|
pub fn ed25519_generated() -> Result<SecioKeyPair, Box<Error + Send + Sync>> {
|
|
|
|
let rng = SystemRandom::new();
|
2018-07-17 11:55:18 +02:00
|
|
|
let gen = Ed25519KeyPair::generate_pkcs8(&rng).map_err(Box::new)?;
|
2018-05-31 14:50:24 +02:00
|
|
|
Ok(SecioKeyPair::ed25519_from_pkcs8(&gen[..])
|
|
|
|
.expect("failed to parse generated Ed25519 key"))
|
|
|
|
}
|
|
|
|
|
2018-09-13 10:26:52 +02:00
|
|
|
/// Generates a new random sec256k1 key pair.
|
|
|
|
#[cfg(feature = "secp256k1")]
|
|
|
|
pub fn secp256k1_generated() -> Result<SecioKeyPair, Box<Error + Send + Sync>> {
|
|
|
|
let secp = secp256k1::Secp256k1::with_caps(secp256k1::ContextFlag::Full);
|
|
|
|
let (private, _) = secp.generate_keypair(&mut ::rand::thread_rng())
|
|
|
|
.expect("failed to generate secp256k1 key");
|
|
|
|
|
|
|
|
Ok(SecioKeyPair {
|
|
|
|
inner: SecioKeyPairInner::Secp256k1 { private },
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-06-20 09:47:43 +02:00
|
|
|
/// Builds a `SecioKeyPair` from a raw secp256k1 32 bytes private key.
|
2018-06-22 13:07:57 +02:00
|
|
|
#[cfg(feature = "secp256k1")]
|
2018-06-20 09:47:43 +02:00
|
|
|
pub fn secp256k1_raw_key<K>(key: K) -> Result<SecioKeyPair, Box<Error + Send + Sync>>
|
2018-07-11 11:14:40 +02:00
|
|
|
where
|
|
|
|
K: AsRef<[u8]>,
|
2018-06-20 09:47:43 +02:00
|
|
|
{
|
|
|
|
let secp = secp256k1::Secp256k1::with_caps(secp256k1::ContextFlag::None);
|
|
|
|
let private = secp256k1::key::SecretKey::from_slice(&secp, key.as_ref())?;
|
|
|
|
|
|
|
|
Ok(SecioKeyPair {
|
2018-07-11 11:14:40 +02:00
|
|
|
inner: SecioKeyPairInner::Secp256k1 { private },
|
2018-06-20 09:47:43 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Builds a `SecioKeyPair` from a secp256k1 private key in DER format.
|
2018-06-22 13:07:57 +02:00
|
|
|
#[cfg(feature = "secp256k1")]
|
2018-06-20 09:47:43 +02:00
|
|
|
pub fn secp256k1_from_der<K>(key: K) -> Result<SecioKeyPair, Box<Error + Send + Sync>>
|
2018-07-11 11:14:40 +02:00
|
|
|
where
|
|
|
|
K: AsRef<[u8]>,
|
2018-06-20 09:47:43 +02:00
|
|
|
{
|
|
|
|
// See ECPrivateKey in https://tools.ietf.org/html/rfc5915
|
2018-07-11 11:14:40 +02:00
|
|
|
let obj: Vec<DerObject> =
|
|
|
|
FromDerEncoded::with_der_encoded(key.as_ref()).map_err(|err| err.to_string())?;
|
|
|
|
let priv_key_obj = obj.into_iter()
|
|
|
|
.nth(1)
|
2018-07-17 11:55:18 +02:00
|
|
|
.ok_or_else(|| "Not enough elements in DER".to_string())?;
|
2018-07-11 11:14:40 +02:00
|
|
|
let private_key: Vec<u8> =
|
|
|
|
FromDerObject::from_der_object(priv_key_obj).map_err(|err| err.to_string())?;
|
2018-06-20 09:47:43 +02:00
|
|
|
SecioKeyPair::secp256k1_raw_key(&private_key)
|
|
|
|
}
|
|
|
|
|
2018-05-31 18:35:18 +02:00
|
|
|
/// Returns the public key corresponding to this key pair.
|
2018-06-25 14:54:55 +02:00
|
|
|
pub fn to_public_key(&self) -> PublicKey {
|
2018-05-31 18:35:18 +02:00
|
|
|
match self.inner {
|
2018-07-11 11:14:40 +02:00
|
|
|
SecioKeyPairInner::Rsa { ref public, .. } => PublicKey::Rsa(public.clone()),
|
2018-05-31 18:35:18 +02:00
|
|
|
SecioKeyPairInner::Ed25519 { ref key_pair } => {
|
2018-06-25 14:54:55 +02:00
|
|
|
PublicKey::Ed25519(key_pair.public_key_bytes().to_vec())
|
2018-07-11 11:14:40 +02:00
|
|
|
}
|
2018-06-22 13:07:57 +02:00
|
|
|
#[cfg(feature = "secp256k1")]
|
2018-06-20 09:47:43 +02:00
|
|
|
SecioKeyPairInner::Secp256k1 { ref private } => {
|
|
|
|
let secp = secp256k1::Secp256k1::with_caps(secp256k1::ContextFlag::SignOnly);
|
|
|
|
let pubkey = secp256k1::key::PublicKey::from_secret_key(&secp, private)
|
|
|
|
.expect("wrong secp256k1 private key ; type safety violated");
|
2018-07-02 11:56:50 +02:00
|
|
|
PublicKey::Secp256k1(pubkey.serialize_vec(&secp, true).to_vec())
|
2018-07-11 11:14:40 +02:00
|
|
|
}
|
2018-05-31 18:35:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Builds a `PeerId` corresponding to the public key of this key pair.
|
2018-06-25 17:56:36 +02:00
|
|
|
#[inline]
|
2018-05-31 18:35:18 +02:00
|
|
|
pub fn to_peer_id(&self) -> PeerId {
|
2018-06-25 17:56:36 +02:00
|
|
|
self.to_public_key().into_peer_id()
|
2018-05-31 18:35:18 +02:00
|
|
|
}
|
|
|
|
|
2018-05-31 14:50:24 +02:00
|
|
|
// TODO: method to save generated key on disk?
|
2017-12-04 15:39:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Inner content of `SecioKeyPair`.
|
|
|
|
#[derive(Clone)]
|
|
|
|
enum SecioKeyPairInner {
|
2018-03-07 16:20:55 +01:00
|
|
|
Rsa {
|
|
|
|
public: Vec<u8>,
|
2018-05-31 14:50:24 +02:00
|
|
|
// We use an `Arc` so that we can clone the enum.
|
2018-03-07 16:20:55 +01:00
|
|
|
private: Arc<RSAKeyPair>,
|
|
|
|
},
|
2018-05-31 14:50:24 +02:00
|
|
|
Ed25519 {
|
|
|
|
// We use an `Arc` so that we can clone the enum.
|
|
|
|
key_pair: Arc<Ed25519KeyPair>,
|
|
|
|
},
|
2018-06-22 13:07:57 +02:00
|
|
|
#[cfg(feature = "secp256k1")]
|
2018-07-11 11:14:40 +02:00
|
|
|
Secp256k1 { private: secp256k1::key::SecretKey },
|
2017-12-04 15:39:40 +01:00
|
|
|
}
|
|
|
|
|
2018-07-04 17:07:38 +02:00
|
|
|
/// Output of the secio protocol.
|
|
|
|
pub struct SecioOutput<S>
|
2018-07-11 11:14:40 +02:00
|
|
|
where
|
|
|
|
S: AsyncRead + AsyncWrite,
|
2018-07-04 17:07:38 +02:00
|
|
|
{
|
|
|
|
/// The encrypted stream.
|
|
|
|
pub stream: RwStreamSink<StreamMapErr<SecioMiddleware<S>, fn(SecioError) -> IoError>>,
|
|
|
|
/// The public key of the remote.
|
|
|
|
pub remote_key: PublicKey,
|
|
|
|
/// Ephemeral public key used during the negotiation.
|
|
|
|
pub ephemeral_public_key: Vec<u8>,
|
|
|
|
}
|
|
|
|
|
2018-06-19 14:38:55 +02:00
|
|
|
impl<S, Maf> libp2p_core::ConnectionUpgrade<S, Maf> for SecioConfig
|
2018-03-07 16:20:55 +01:00
|
|
|
where
|
2018-09-06 09:54:35 +02:00
|
|
|
S: AsyncRead + AsyncWrite + Send + 'static, // TODO: 'static :(
|
|
|
|
Maf: Send + 'static, // TODO: 'static :(
|
2017-11-02 11:58:02 +01:00
|
|
|
{
|
2018-07-04 17:07:38 +02:00
|
|
|
type Output = SecioOutput<S>;
|
2018-06-19 14:38:55 +02:00
|
|
|
type MultiaddrFuture = Maf;
|
2018-09-06 09:54:35 +02:00
|
|
|
type Future = Box<Future<Item = (Self::Output, Maf), Error = IoError> + Send>;
|
2018-03-07 16:20:55 +01:00
|
|
|
type NamesIter = iter::Once<(Bytes, ())>;
|
|
|
|
type UpgradeIdentifier = ();
|
2017-11-02 11:58:02 +01:00
|
|
|
|
2018-03-07 16:20:55 +01:00
|
|
|
#[inline]
|
|
|
|
fn protocol_names(&self) -> Self::NamesIter {
|
|
|
|
iter::once(("/secio/1.0.0".into(), ()))
|
|
|
|
}
|
2017-11-02 11:58:02 +01:00
|
|
|
|
2018-03-07 16:20:55 +01:00
|
|
|
#[inline]
|
|
|
|
fn upgrade(
|
|
|
|
self,
|
|
|
|
incoming: S,
|
|
|
|
_: (),
|
2018-05-16 12:59:36 +02:00
|
|
|
_: libp2p_core::Endpoint,
|
2018-06-19 14:38:55 +02:00
|
|
|
remote_addr: Maf,
|
2018-03-07 16:20:55 +01:00
|
|
|
) -> Self::Future {
|
2018-06-19 14:38:55 +02:00
|
|
|
debug!("Starting secio upgrade");
|
2018-02-14 13:02:56 +01:00
|
|
|
|
2018-09-12 09:10:05 +02:00
|
|
|
let fut = SecioMiddleware::handshake(incoming, self);
|
2018-07-04 17:07:38 +02:00
|
|
|
let wrapped = fut.map(|(stream_sink, pubkey, ephemeral)| {
|
2018-03-07 16:20:55 +01:00
|
|
|
let mapped = stream_sink.map_err(map_err as fn(_) -> _);
|
2018-07-04 17:07:38 +02:00
|
|
|
SecioOutput {
|
|
|
|
stream: RwStreamSink::new(mapped),
|
|
|
|
remote_key: pubkey,
|
|
|
|
ephemeral_public_key: ephemeral,
|
|
|
|
}
|
2018-03-07 16:20:55 +01:00
|
|
|
}).map_err(map_err);
|
2018-06-19 14:38:55 +02:00
|
|
|
Box::new(wrapped.map(move |out| (out, remote_addr)))
|
2018-03-07 16:20:55 +01:00
|
|
|
}
|
2017-11-02 11:58:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn map_err(err: SecioError) -> IoError {
|
2018-05-17 15:14:13 +02:00
|
|
|
debug!("error during secio handshake {:?}", err);
|
2018-03-07 16:20:55 +01:00
|
|
|
IoError::new(IoErrorKind::InvalidData, err)
|
2017-11-02 11:58:02 +01:00
|
|
|
}
|
|
|
|
|
2017-10-30 10:22:38 +01:00
|
|
|
/// Wraps around an object that implements `AsyncRead` and `AsyncWrite`.
|
|
|
|
///
|
|
|
|
/// Implements `Sink` and `Stream` whose items are frames of data. Each frame is encoded
|
|
|
|
/// individually, so you are encouraged to group data in few frames if possible.
|
|
|
|
pub struct SecioMiddleware<S> {
|
2018-03-07 16:20:55 +01:00
|
|
|
inner: codec::FullCodec<S>,
|
2017-10-30 10:22:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<S> SecioMiddleware<S>
|
2018-03-07 16:20:55 +01:00
|
|
|
where
|
2018-09-06 09:54:35 +02:00
|
|
|
S: AsyncRead + AsyncWrite + Send,
|
2017-10-30 10:22:38 +01:00
|
|
|
{
|
2018-03-07 16:20:55 +01:00
|
|
|
/// Attempts to perform a handshake on the given socket.
|
|
|
|
///
|
|
|
|
/// On success, produces a `SecioMiddleware` that can then be used to encode/decode
|
2018-07-04 17:07:38 +02:00
|
|
|
/// communications, plus the public key of the remote, plus the ephemeral public key.
|
2018-03-07 16:20:55 +01:00
|
|
|
pub fn handshake<'a>(
|
|
|
|
socket: S,
|
2018-09-12 09:10:05 +02:00
|
|
|
config: SecioConfig,
|
2018-09-06 09:54:35 +02:00
|
|
|
) -> Box<Future<Item = (SecioMiddleware<S>, PublicKey, Vec<u8>), Error = SecioError> + Send + 'a>
|
2018-03-07 16:20:55 +01:00
|
|
|
where
|
|
|
|
S: 'a,
|
|
|
|
{
|
2018-09-12 09:10:05 +02:00
|
|
|
let fut = handshake::handshake(socket, config).map(|(inner, pubkey, ephemeral)| {
|
2018-05-14 15:55:16 +02:00
|
|
|
let inner = SecioMiddleware { inner };
|
2018-07-04 17:07:38 +02:00
|
|
|
(inner, pubkey, ephemeral)
|
2018-05-14 15:55:16 +02:00
|
|
|
});
|
2018-05-31 14:50:24 +02:00
|
|
|
|
2018-03-07 16:20:55 +01:00
|
|
|
Box::new(fut)
|
|
|
|
}
|
2017-10-30 10:22:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<S> Sink for SecioMiddleware<S>
|
2018-03-07 16:20:55 +01:00
|
|
|
where
|
|
|
|
S: AsyncRead + AsyncWrite,
|
2017-10-30 10:22:38 +01:00
|
|
|
{
|
2018-03-07 16:20:55 +01:00
|
|
|
type SinkItem = BytesMut;
|
|
|
|
type SinkError = IoError;
|
2017-10-30 10:22:38 +01:00
|
|
|
|
2018-03-07 16:20:55 +01:00
|
|
|
#[inline]
|
|
|
|
fn start_send(&mut self, item: Self::SinkItem) -> StartSend<Self::SinkItem, Self::SinkError> {
|
|
|
|
self.inner.start_send(item)
|
|
|
|
}
|
2017-10-30 10:22:38 +01:00
|
|
|
|
2018-03-07 16:20:55 +01:00
|
|
|
#[inline]
|
|
|
|
fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
|
|
|
|
self.inner.poll_complete()
|
|
|
|
}
|
2018-09-17 15:01:37 +02:00
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn close(&mut self) -> Poll<(), Self::SinkError> {
|
|
|
|
self.inner.close()
|
|
|
|
}
|
2017-10-30 10:22:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<S> Stream for SecioMiddleware<S>
|
2018-03-07 16:20:55 +01:00
|
|
|
where
|
|
|
|
S: AsyncRead + AsyncWrite,
|
2017-10-30 10:22:38 +01:00
|
|
|
{
|
2018-03-07 16:20:55 +01:00
|
|
|
type Item = Vec<u8>;
|
|
|
|
type Error = SecioError;
|
2017-10-30 10:22:38 +01:00
|
|
|
|
2018-03-07 16:20:55 +01:00
|
|
|
#[inline]
|
|
|
|
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
|
|
|
|
self.inner.poll()
|
|
|
|
}
|
2017-10-30 10:22:38 +01:00
|
|
|
}
|