Merge pull request #56 from tomaka/secio-api-improvement

Improve the API of the secio crate
This commit is contained in:
tomaka
2017-12-07 12:16:14 +01:00
committed by GitHub
4 changed files with 80 additions and 47 deletions

View File

@ -9,7 +9,5 @@ futures = "0.1"
libp2p-secio = { path = "../libp2p-secio" } libp2p-secio = { path = "../libp2p-secio" }
libp2p-swarm = { path = "../libp2p-swarm" } libp2p-swarm = { path = "../libp2p-swarm" }
libp2p-tcp-transport = { path = "../libp2p-tcp-transport" } libp2p-tcp-transport = { path = "../libp2p-tcp-transport" }
ring = { version = "0.12.1", features = ["rsa_signing"] }
tokio-core = "0.1" tokio-core = "0.1"
tokio-io = "0.1" tokio-io = "0.1"
untrusted = "0.6"

View File

@ -23,24 +23,19 @@ extern crate futures;
extern crate libp2p_secio as secio; extern crate libp2p_secio as secio;
extern crate libp2p_swarm as swarm; extern crate libp2p_swarm as swarm;
extern crate libp2p_tcp_transport as tcp; extern crate libp2p_tcp_transport as tcp;
extern crate ring;
extern crate tokio_core; extern crate tokio_core;
extern crate tokio_io; extern crate tokio_io;
extern crate untrusted;
use bytes::Bytes; use bytes::Bytes;
use futures::future::{Future, FutureResult, IntoFuture}; use futures::future::{Future, FutureResult, IntoFuture};
use futures::{Stream, Sink}; use futures::{Stream, Sink};
use ring::signature::RSAKeyPair;
use std::io::Error as IoError; use std::io::Error as IoError;
use std::iter; use std::iter;
use std::sync::Arc;
use swarm::{Transport, ConnectionUpgrade}; use swarm::{Transport, ConnectionUpgrade};
use tcp::TcpConfig; use tcp::TcpConfig;
use tokio_core::reactor::Core; use tokio_core::reactor::Core;
use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::{AsyncRead, AsyncWrite};
use tokio_io::codec::length_delimited; use tokio_io::codec::length_delimited;
use untrusted::Input;
fn main() { fn main() {
let mut core = Core::new().unwrap(); let mut core = Core::new().unwrap();
@ -49,15 +44,10 @@ fn main() {
let with_secio = tcp let with_secio = tcp
.with_upgrade(swarm::PlainTextConfig) .with_upgrade(swarm::PlainTextConfig)
.or_upgrade({ .or_upgrade({
let private_key = { let private_key = include_bytes!("test-private-key.pk8");
let pkcs8 = include_bytes!("test-private-key.pk8");
Arc::new(RSAKeyPair::from_pkcs8(Input::from(&pkcs8[..])).unwrap())
};
let public_key = include_bytes!("test-public-key.der").to_vec(); let public_key = include_bytes!("test-public-key.der").to_vec();
secio::SecioConfig {
secio::SecioConnUpgrade { key: secio::SecioKeyPair::rsa_from_pkcs8(private_key, public_key).unwrap(),
local_public_key: public_key,
local_private_key: private_key,
} }
}); });

View File

@ -23,24 +23,19 @@ extern crate futures;
extern crate libp2p_secio as secio; extern crate libp2p_secio as secio;
extern crate libp2p_swarm as swarm; extern crate libp2p_swarm as swarm;
extern crate libp2p_tcp_transport as tcp; extern crate libp2p_tcp_transport as tcp;
extern crate ring;
extern crate tokio_core; extern crate tokio_core;
extern crate tokio_io; extern crate tokio_io;
extern crate untrusted;
use bytes::Bytes; use bytes::Bytes;
use futures::future::{Future, FutureResult, IntoFuture, loop_fn, Loop}; use futures::future::{Future, FutureResult, IntoFuture, loop_fn, Loop};
use futures::{Stream, Sink}; use futures::{Stream, Sink};
use ring::signature::RSAKeyPair;
use std::io::Error as IoError; use std::io::Error as IoError;
use std::iter; use std::iter;
use std::sync::Arc;
use swarm::{Transport, ConnectionUpgrade}; use swarm::{Transport, ConnectionUpgrade};
use tcp::TcpConfig; use tcp::TcpConfig;
use tokio_core::reactor::Core; use tokio_core::reactor::Core;
use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::{AsyncRead, AsyncWrite};
use tokio_io::codec::length_delimited; use tokio_io::codec::length_delimited;
use untrusted::Input;
fn main() { fn main() {
let mut core = Core::new().unwrap(); let mut core = Core::new().unwrap();
@ -49,15 +44,10 @@ fn main() {
let with_secio = tcp let with_secio = tcp
.with_upgrade(swarm::PlainTextConfig) .with_upgrade(swarm::PlainTextConfig)
.or_upgrade({ .or_upgrade({
let private_key = { let private_key = include_bytes!("test-private-key.pk8");
let pkcs8 = include_bytes!("test-private-key.pk8");
Arc::new(RSAKeyPair::from_pkcs8(Input::from(&pkcs8[..])).unwrap())
};
let public_key = include_bytes!("test-public-key.der").to_vec(); let public_key = include_bytes!("test-public-key.der").to_vec();
secio::SecioConfig {
secio::SecioConnUpgrade { key: secio::SecioKeyPair::rsa_from_pkcs8(private_key, public_key).unwrap(),
local_public_key: public_key,
local_private_key: private_key,
} }
}); });

View File

@ -29,7 +29,7 @@
//! `SecioMiddleware` that implements `Sink` and `Stream` and can be used to send packets of data. //! `SecioMiddleware` that implements `Sink` and `Stream` and can be used to send packets of data.
//! //!
//! However for integration with the rest of `libp2p` you are encouraged to use the //! However for integration with the rest of `libp2p` you are encouraged to use the
//! `SecioConnUpgrade` struct instead. This struct implements the `ConnectionUpgrade` trait and //! `SecioConfig` struct instead. This struct implements the `ConnectionUpgrade` trait and
//! will automatically apply secio on any incoming or outgoing connection. //! will automatically apply secio on any incoming or outgoing connection.
extern crate bytes; extern crate bytes;
@ -50,10 +50,12 @@ use futures::{Future, Poll, StartSend, Sink, Stream};
use futures::stream::MapErr as StreamMapErr; use futures::stream::MapErr as StreamMapErr;
use ring::signature::RSAKeyPair; use ring::signature::RSAKeyPair;
use rw_stream_sink::RwStreamSink; use rw_stream_sink::RwStreamSink;
use std::error::Error;
use std::io::{Error as IoError, ErrorKind as IoErrorKind}; use std::io::{Error as IoError, ErrorKind as IoErrorKind};
use std::iter; use std::iter;
use std::sync::Arc; use std::sync::Arc;
use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::{AsyncRead, AsyncWrite};
use untrusted::Input;
mod algo_support; mod algo_support;
mod codec; mod codec;
@ -62,18 +64,74 @@ mod keys_proto;
mod handshake; mod handshake;
mod structs_proto; mod structs_proto;
/// Implementation of the `ConnectionUpgrade` trait of `libp2p_swarm`. Automatically applies any /// Implementation of the `ConnectionUpgrade` trait of `libp2p_swarm`. Automatically applies
/// secio on any connection. /// secio on any connection.
#[derive(Clone)] #[derive(Clone)]
pub struct SecioConnUpgrade { pub struct SecioConfig {
/// Public key of the local node. Must match `local_private_key` or an error will happen during /// Private and public keys of the local node.
/// the handshake. pub key: SecioKeyPair,
pub local_public_key: Vec<u8>,
/// Private key that will be used to prove the identity of the local node.
pub local_private_key: Arc<RSAKeyPair>,
} }
impl<S> libp2p_swarm::ConnectionUpgrade<S> for SecioConnUpgrade /// 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<P>(private: &[u8], public: P)
-> Result<SecioKeyPair, Box<Error + Send + Sync>>
where P: Into<Vec<u8>>
{
let private = RSAKeyPair::from_pkcs8(Input::from(&private[..]))
.map_err(|err| Box::new(err))?;
Ok(SecioKeyPair {
inner: SecioKeyPairInner::Rsa {
public: public.into(),
private: Arc::new(private),
}
})
}
}
// Inner content of `SecioKeyPair`.
#[derive(Clone)]
enum SecioKeyPairInner {
Rsa {
public: Vec<u8>,
private: Arc<RSAKeyPair>,
}
}
#[derive(Debug, Clone)]
pub enum SecioPublicKey<'a> {
/// DER format.
Rsa(&'a [u8]),
}
impl<S> libp2p_swarm::ConnectionUpgrade<S> for SecioConfig
where S: AsyncRead + AsyncWrite + 'static where S: AsyncRead + AsyncWrite + 'static
{ {
type Output = RwStreamSink< type Output = RwStreamSink<
@ -95,8 +153,7 @@ impl<S> libp2p_swarm::ConnectionUpgrade<S> for SecioConnUpgrade
fn upgrade(self, incoming: S, _: ()) -> Self::Future { fn upgrade(self, incoming: S, _: ()) -> Self::Future {
let fut = SecioMiddleware::handshake( let fut = SecioMiddleware::handshake(
incoming, incoming,
self.local_public_key.clone(), self.key,
self.local_private_key.clone(),
); );
let wrapped = fut.map(|stream_sink| { let wrapped = fut.map(|stream_sink| {
let mapped = stream_sink.map_err(map_err as fn(_) -> _); let mapped = stream_sink.map_err(map_err as fn(_) -> _);
@ -125,19 +182,17 @@ impl<S> SecioMiddleware<S>
{ {
/// Attempts to perform a handshake on the given socket. /// Attempts to perform a handshake on the given socket.
/// ///
/// `local_public_key` and `local_private_key` must match. `local_public_key` must be in the
/// DER format.
///
/// On success, produces a `SecioMiddleware` that can then be used to encode/decode /// On success, produces a `SecioMiddleware` that can then be used to encode/decode
/// communications. /// communications.
pub fn handshake<'a>( pub fn handshake<'a>(
socket: S, socket: S,
local_public_key: Vec<u8>, key_pair: SecioKeyPair,
local_private_key: Arc<RSAKeyPair>,
) -> Box<Future<Item = SecioMiddleware<S>, Error = SecioError> + 'a> ) -> Box<Future<Item = SecioMiddleware<S>, Error = SecioError> + 'a>
where S: 'a where S: 'a
{ {
let fut = handshake::handshake(socket, local_public_key, local_private_key) let SecioKeyPairInner::Rsa { private, public } = key_pair.inner;
let fut = handshake::handshake(socket, public, private)
.map(|(inner, pubkey)| { .map(|(inner, pubkey)| {
SecioMiddleware { SecioMiddleware {
inner: inner, inner: inner,
@ -149,8 +204,8 @@ impl<S> SecioMiddleware<S>
/// Returns the public key of the remote in the `DER` format. /// Returns the public key of the remote in the `DER` format.
#[inline] #[inline]
pub fn remote_public_key_der(&self) -> &[u8] { pub fn remote_public_key_der(&self) -> SecioPublicKey {
&self.remote_pubkey_der SecioPublicKey::Rsa(&self.remote_pubkey_der)
} }
} }