From dcfb27bbc585607b0717843225f9980768742a9b Mon Sep 17 00:00:00 2001 From: Huguenin-Elie Steve Date: Wed, 14 Oct 2020 14:43:07 +0200 Subject: [PATCH 1/2] added server support for DTLS encryption over UDP --- Cargo.toml | 1 + src/server.rs | 102 ++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 96 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5e787f14e..83d3984a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ serde = { version= "1.0.88", features= [ "derive" ] } url = "1.7.2" num-derive = "0.2.4" num-traits = "0.2.6" +openssl = "0.10" log = "0.4.6" regex = "1.1.0" tokio = {version = "0.2", features = ["full"]} diff --git a/src/server.rs b/src/server.rs index 36d7ec394..9e8e9df8d 100644 --- a/src/server.rs +++ b/src/server.rs @@ -4,6 +4,7 @@ use std::{ net::{self, SocketAddr, ToSocketAddrs}, task::Context, future::Future, + time::Duration, }; use log::{debug, error}; use futures::{SinkExt, Stream, StreamExt, select, stream::FusedStream, task::Poll}; @@ -13,6 +14,11 @@ use tokio::{ net::UdpSocket }; use tokio_util::udp::{UdpFramed}; +use openssl::{ + error::ErrorStack, + sha::Sha256, + ssl::{self, HandshakeError, Ssl, SslContextBuilder, SslMethod, SslStream, SslVerifyMode} +}; use super::message::{ packet::Packet, @@ -44,6 +50,12 @@ pub enum Message { Received(Packet, SocketAddr), } +pub enum Encryption { + DTLS, + TLS, + SSL, +} + pub struct Server<'a, HandlerRet> where HandlerRet: Future> { server: CoAPServer, observer: Observer, @@ -52,10 +64,10 @@ pub struct Server<'a, HandlerRet> where HandlerRet: Future Server<'a, HandlerRet> where HandlerRet: Future> { /// Creates a CoAP server listening on the given address. - pub fn new(addr: A) -> Result, io::Error> { + pub fn new(addr: A, method: Option) -> Result, io::Error> { let (tx, rx) = mpsc::unbounded_channel(); Ok(Server { - server: CoAPServer::new(addr, rx)?, + server: CoAPServer::new(addr, rx, method.unwrap())?, observer: Observer::new(tx), handler: None, }) @@ -117,21 +129,89 @@ impl<'a, HandlerRet> Server<'a, HandlerRet> where HandlerRet: Future std::io::Result { + if self.connected { + self.socket.recv(buf) + } else { + match self.socket.recv_from(buf) { + Ok((bytes, addr)) => { + self.connect(addr)?; + Ok(bytes) + } + Err(e) => Err(e), + } + } + } + +} + +impl std::io::Write for UdpStream { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + self.socket.send(buf) + } + fn flush(&mut self) -> std::io::Result<()> { + Ok(()) + } +} + +impl UdpStream { + /// Binds to the given address and sets timeouts to reasonable values. + pub fn new(addr: A) -> std::io::Result { + let socket = std::net::UdpSocket::bind(addr).unwrap(); + let duration = Duration::from_millis(300); + socket.set_read_timeout(Some(duration))?; + socket.set_write_timeout(Some(duration))?; + Ok(UdpStream { + socket: socket, + connected: false, + }) + } + + /// Connects the UDP socket to the given address. + pub fn connect(&mut self, addr: A) -> std::io::Result<()> { + self.socket.connect(addr)?; + self.connected = true; + Ok(()) + } +} + pub struct CoAPServer { receiver: MessageReceiver, is_terminated: bool, socket: UdpFramed, + ssl_stream: Option, HandshakeError>>, } impl CoAPServer { /// Creates a CoAP server listening on the given address. - pub fn new(addr: A, receiver: MessageReceiver) -> Result { + pub fn new(addr: A, receiver: MessageReceiver, method: Encryption) -> Result { let socket = UdpSocket::from_std(net::UdpSocket::bind(addr).unwrap())?; - Ok(CoAPServer { receiver, is_terminated: false, socket: UdpFramed::new(socket, Codec::new()), + ssl_stream: match method { + Encryption::DTLS => { + let mut context_builder = SslContextBuilder::new(SslMethod::dtls()).unwrap(); + context_builder.set_verify(SslVerifyMode::PEER | SslVerifyMode::FAIL_IF_NO_PEER_CERT); + let ssl_context = context_builder.build(); + let ssl = Ssl::new(&ssl_context).unwrap(); + let socket = UdpStream::new(addr).unwrap(); + match ssl.accept(socket) { + Ok(stream) => Some(Ok(stream)), + Err(e) => Some(Err(e)) + } + } + Encryption::TLS => None, + Encryption::SSL => None + }, }) } @@ -195,12 +275,12 @@ pub mod test { use super::super::*; use super::*; - pub fn spawn_server HandlerRet + Send + 'static, HandlerRet>(request_handler: F) -> mpsc::Receiver where HandlerRet: Future> { + fn spawn_server HandlerRet + Send + 'static, HandlerRet>(request_handler: F, method: Encryption) -> mpsc::Receiver where HandlerRet: Future> { let (tx, rx) = mpsc::channel(); std::thread::Builder::new().name(String::from("server")).spawn(move || { tokio::runtime::Runtime::new().unwrap().block_on(async move { - let mut server = server::Server::new("127.0.0.1:0").unwrap(); + let mut server = server::Server::new("127.0.0.1:0", Some(method)).unwrap(); tx.send(server.socket_addr().unwrap().port()).unwrap(); @@ -210,6 +290,14 @@ pub mod test { rx } + + pub fn spawn_udp(request_handler: F) { + spawn_server(request_handler, Encryption::DTLS); + } + + pub fn spawn_dtls_over_udp(request_handler: F) { + spawn_server(request_handler, None); + } async fn request_handler(req: CoAPRequest) -> Option { let uri_path_list = req.get_option(CoAPOption::UriPath).unwrap().clone(); @@ -223,6 +311,7 @@ pub mod test { _ => None, } } +} #[test] fn test_echo_server() { @@ -307,4 +396,3 @@ pub mod test { client2.receive().unwrap(); assert_eq!(rx2.recv_timeout(Duration::new(5, 0)).unwrap(), ()); } -} From e4e645626eb669d8b537105f0ad84ce92986de00 Mon Sep 17 00:00:00 2001 From: Huguenin-Elie Steve Date: Sun, 20 Dec 2020 19:36:09 +0100 Subject: [PATCH 2/2] unwanted bracket move --- src/server.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server.rs b/src/server.rs index 9e8e9df8d..38538ccf0 100644 --- a/src/server.rs +++ b/src/server.rs @@ -311,7 +311,6 @@ pub mod test { _ => None, } } -} #[test] fn test_echo_server() { @@ -396,3 +395,4 @@ pub mod test { client2.receive().unwrap(); assert_eq!(rx2.recv_timeout(Duration::new(5, 0)).unwrap(), ()); } +}