#![recursion_limit = "128"]
#[cfg(any(target_os = "emscripten", target_os = "unknown"))]
#[macro_use]
extern crate stdweb;
pub use self::error::SecioError;
#[cfg(feature = "secp256k1")]
use asn1_der::{FromDerObject, DerObject};
use bytes::BytesMut;
use ed25519_dalek::Keypair as Ed25519KeyPair;
use futures::stream::MapErr as StreamMapErr;
use futures::{Future, Poll, Sink, StartSend, Stream};
use lazy_static::lazy_static;
use libp2p_core::{PeerId, PublicKey, upgrade::{UpgradeInfo, InboundUpgrade, OutboundUpgrade}};
use log::debug;
#[cfg(not(any(target_os = "emscripten", target_os = "unknown")))]
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};
#[cfg(not(any(target_os = "emscripten", target_os = "unknown")))]
use untrusted::Input;
mod algo_support;
mod codec;
mod error;
mod exchange;
mod handshake;
mod structs_proto;
mod stream_cipher;
pub use crate::algo_support::Digest;
pub use crate::exchange::KeyAgreement;
pub use crate::stream_cipher::Cipher;
#[cfg(feature = "secp256k1")]
lazy_static! {
static ref SECP256K1: secp256k1::Secp256k1<secp256k1::All> = secp256k1::Secp256k1::new();
}
#[derive(Clone)]
pub struct SecioConfig {
pub(crate) key: SecioKeyPair,
pub(crate) agreements_prop: Option<String>,
pub(crate) ciphers_prop: Option<String>,
pub(crate) digests_prop: Option<String>
}
impl SecioConfig {
pub fn new(kp: SecioKeyPair) -> Self {
SecioConfig {
key: kp,
agreements_prop: None,
ciphers_prop: None,
digests_prop: None
}
}
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
}
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
}
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
}
fn handshake<T>(self, socket: T) -> impl Future<Item=SecioOutput<T>, Error=SecioError>
where
T: AsyncRead + AsyncWrite + Send + 'static
{
debug!("Starting secio upgrade");
SecioMiddleware::handshake(socket, self)
.map(|(stream_sink, pubkey, ephemeral)| {
let mapped = stream_sink.map_err(map_err as fn(_) -> _);
SecioOutput {
stream: RwStreamSink::new(mapped),
remote_key: pubkey,
ephemeral_public_key: ephemeral
}
})
}
}
#[derive(Clone)]
pub struct SecioKeyPair {
inner: SecioKeyPairInner,
}
impl SecioKeyPair {
#[cfg(not(any(target_os = "emscripten", target_os = "unknown")))]
pub fn rsa_from_pkcs8<P>(
private: &[u8],
public: P,
) -> Result<SecioKeyPair, Box<dyn Error + Send + Sync>>
where
P: Into<Vec<u8>>,
{
let private = RsaKeyPair::from_pkcs8(Input::from(&private[..])).map_err(Box::new)?;
Ok(SecioKeyPair {
inner: SecioKeyPairInner::Rsa {
public: public.into(),
private: Arc::new(private),
},
})
}
pub fn ed25519_generated() -> Result<SecioKeyPair, Box<dyn Error + Send + Sync>> {
let mut csprng = rand::thread_rng();
let keypair: Ed25519KeyPair = Ed25519KeyPair::generate::<_>(&mut csprng);
Ok(SecioKeyPair {
inner: SecioKeyPairInner::Ed25519 {
key_pair: Arc::new(keypair),
}
})
}
pub fn ed25519_raw_key(key: impl AsRef<[u8]>) -> Result<SecioKeyPair, Box<dyn Error + Send + Sync>> {
let secret = ed25519_dalek::SecretKey::from_bytes(key.as_ref())
.map_err(|err| err.to_string())?;
let public = ed25519_dalek::PublicKey::from(&secret);
Ok(SecioKeyPair {
inner: SecioKeyPairInner::Ed25519 {
key_pair: Arc::new(Ed25519KeyPair {
secret,
public,
}),
}
})
}
#[cfg(feature = "secp256k1")]
pub fn secp256k1_generated() -> Result<SecioKeyPair, Box<dyn Error + Send + Sync>> {
let private = secp256k1::key::SecretKey::new(&mut secp256k1::rand::thread_rng());
Ok(SecioKeyPair {
inner: SecioKeyPairInner::Secp256k1 { private },
})
}
#[cfg(feature = "secp256k1")]
pub fn secp256k1_raw_key<K>(key: K) -> Result<SecioKeyPair, Box<dyn Error + Send + Sync>>
where
K: AsRef<[u8]>,
{
let private = secp256k1::key::SecretKey::from_slice(key.as_ref())?;
Ok(SecioKeyPair {
inner: SecioKeyPairInner::Secp256k1 { private },
})
}
#[cfg(feature = "secp256k1")]
pub fn secp256k1_from_der<K>(key: K) -> Result<SecioKeyPair, Box<dyn Error + Send + Sync>>
where
K: AsRef<[u8]>,
{
let obj: Vec<DerObject> =
FromDerObject::deserialize(key.as_ref().iter()).map_err(|err| err.to_string())?;
let priv_key_obj = obj.into_iter()
.nth(1)
.ok_or_else(|| "Not enough elements in DER".to_string())?;
let private_key: Vec<u8> =
FromDerObject::from_der_object(priv_key_obj).map_err(|err| err.to_string())?;
SecioKeyPair::secp256k1_raw_key(&private_key)
}
pub fn to_public_key(&self) -> PublicKey {
match self.inner {
#[cfg(not(any(target_os = "emscripten", target_os = "unknown")))]
SecioKeyPairInner::Rsa { ref public, .. } => PublicKey::Rsa(public.clone()),
SecioKeyPairInner::Ed25519 { ref key_pair } => {
PublicKey::Ed25519(key_pair.public.as_bytes().to_vec())
}
#[cfg(feature = "secp256k1")]
SecioKeyPairInner::Secp256k1 { ref private } => {
let pubkey = secp256k1::key::PublicKey::from_secret_key(&SECP256K1, private);
PublicKey::Secp256k1(pubkey.serialize().to_vec())
}
}
}
#[inline]
pub fn to_peer_id(&self) -> PeerId {
self.to_public_key().into_peer_id()
}
}
#[derive(Clone)]
enum SecioKeyPairInner {
#[cfg(not(any(target_os = "emscripten", target_os = "unknown")))]
Rsa {
public: Vec<u8>,
private: Arc<RsaKeyPair>,
},
Ed25519 {
key_pair: Arc<Ed25519KeyPair>,
},
#[cfg(feature = "secp256k1")]
Secp256k1 { private: secp256k1::key::SecretKey },
}
pub struct SecioOutput<S>
where
S: AsyncRead + AsyncWrite,
{
pub stream: RwStreamSink<StreamMapErr<SecioMiddleware<S>, fn(SecioError) -> IoError>>,
pub remote_key: PublicKey,
pub ephemeral_public_key: Vec<u8>,
}
impl UpgradeInfo for SecioConfig {
type Info = &'static [u8];
type InfoIter = iter::Once<Self::Info>;
fn protocol_info(&self) -> Self::InfoIter {
iter::once(b"/secio/1.0.0")
}
}
impl<T> InboundUpgrade<T> for SecioConfig
where
T: AsyncRead + AsyncWrite + Send + 'static
{
type Output = SecioOutput<T>;
type Error = SecioError;
type Future = Box<dyn Future<Item = Self::Output, Error = Self::Error> + Send>;
fn upgrade_inbound(self, socket: T, _: Self::Info) -> Self::Future {
Box::new(self.handshake(socket))
}
}
impl<T> OutboundUpgrade<T> for SecioConfig
where
T: AsyncRead + AsyncWrite + Send + 'static
{
type Output = SecioOutput<T>;
type Error = SecioError;
type Future = Box<dyn Future<Item = Self::Output, Error = Self::Error> + Send>;
fn upgrade_outbound(self, socket: T, _: Self::Info) -> Self::Future {
Box::new(self.handshake(socket))
}
}
#[inline]
fn map_err(err: SecioError) -> IoError {
debug!("error during secio handshake {:?}", err);
IoError::new(IoErrorKind::InvalidData, err)
}
pub struct SecioMiddleware<S> {
inner: codec::FullCodec<S>,
}
impl<S> SecioMiddleware<S>
where
S: AsyncRead + AsyncWrite + Send,
{
pub fn handshake(socket: S, config: SecioConfig)
-> impl Future<Item = (SecioMiddleware<S>, PublicKey, Vec<u8>), Error = SecioError>
{
handshake::handshake(socket, config).map(|(inner, pubkey, ephemeral)| {
let inner = SecioMiddleware { inner };
(inner, pubkey, ephemeral)
})
}
}
impl<S> Sink for SecioMiddleware<S>
where
S: AsyncRead + AsyncWrite,
{
type SinkItem = BytesMut;
type SinkError = IoError;
#[inline]
fn start_send(&mut self, item: Self::SinkItem) -> StartSend<Self::SinkItem, Self::SinkError> {
self.inner.start_send(item)
}
#[inline]
fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
self.inner.poll_complete()
}
#[inline]
fn close(&mut self) -> Poll<(), Self::SinkError> {
self.inner.close()
}
}
impl<S> Stream for SecioMiddleware<S>
where
S: AsyncRead + AsyncWrite,
{
type Item = Vec<u8>;
type Error = SecioError;
#[inline]
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
self.inner.poll()
}
}