// 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`). //! //! # Connection upgrade //! //! 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. //! //! ```no_run //! extern crate futures; //! extern crate tokio_core; //! extern crate tokio_io; //! extern crate libp2p_swarm; //! extern crate libp2p_secio; //! extern crate libp2p_tcp_transport; //! //! # fn main() { //! use futures::Future; //! use libp2p_secio::{SecioConfig, SecioKeyPair}; //! use libp2p_swarm::{Multiaddr, Transport}; //! use libp2p_tcp_transport::TcpConfig; //! use tokio_core::reactor::Core; //! use tokio_io::io::write_all; //! //! let mut core = Core::new().unwrap(); //! //! let transport = TcpConfig::new(core.handle()) //! .with_upgrade({ //! # let private_key = b""; //! //let private_key = include_bytes!("test-private-key.pk8"); //! # let public_key = vec![]; //! //let public_key = include_bytes!("test-public-key.der").to_vec(); //! SecioConfig { //! // See the documentation of `SecioKeyPair`. //! key: SecioKeyPair::rsa_from_pkcs8(private_key, public_key).unwrap(), //! } //! }); //! //! let future = transport.dial(Multiaddr::new("/ip4/127.0.0.1/tcp/12345").unwrap()) //! .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") //! }); //! //! core.run(future).unwrap(); //! # } //! ``` //! //! # Manual usage //! //! > **Note**: You are encouraged to use `SecioConfig` as described above. //! //! 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. //! extern crate bytes; extern crate crypto; extern crate futures; extern crate libp2p_swarm; extern crate protobuf; extern crate rand; extern crate ring; extern crate rw_stream_sink; extern crate tokio_io; extern crate untrusted; pub use self::error::SecioError; use bytes::{Bytes, BytesMut}; use futures::{Future, Poll, StartSend, Sink, Stream}; use futures::stream::MapErr as StreamMapErr; use ring::signature::RSAKeyPair; use rw_stream_sink::RwStreamSink; use std::error::Error; use std::io::{Error as IoError, ErrorKind as IoErrorKind}; use std::iter; use std::sync::Arc; use tokio_io::{AsyncRead, AsyncWrite}; use untrusted::Input; mod algo_support; mod codec; mod error; mod keys_proto; mod handshake; mod structs_proto; /// Implementation of the `ConnectionUpgrade` trait of `libp2p_swarm`. Automatically applies /// secio on any connection. #[derive(Clone)] pub struct SecioConfig { /// Private and public keys of the local node. pub key: SecioKeyPair, } /// 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 /// let key_pair = SecioKeyPair::rsa_from_pkcs8(include_bytes!("private.pk8"), /// include_bytes!("public.der")); /// ``` /// #[derive(Clone)] pub struct SecioKeyPair { inner: SecioKeyPairInner, } impl SecioKeyPair { pub fn rsa_from_pkcs8
(private: &[u8], public: P)
-> Result libp2p_swarm::ConnectionUpgrade for SecioConfig
where S: AsyncRead + AsyncWrite + 'static
{
type Output = RwStreamSink<
StreamMapErr<
SecioMiddleware,
fn(SecioError) -> IoError,
>,
>;
type Future = Box {
inner: codec::FullCodec,
remote_pubkey_der: Vec SecioMiddleware
where S: AsyncRead + AsyncWrite
{
/// Attempts to perform a handshake on the given socket.
///
/// On success, produces a `SecioMiddleware` that can then be used to encode/decode
/// communications.
pub fn handshake<'a>(
socket: S,
key_pair: SecioKeyPair,
) -> Box Sink for SecioMiddleware
where S: AsyncRead + AsyncWrite
{
type SinkItem = BytesMut;
type SinkError = IoError;
#[inline]
fn start_send(&mut self, item: Self::SinkItem) -> StartSend Stream for SecioMiddleware
where S: AsyncRead + AsyncWrite
{
type Item = Vec