@@ -1,6 +1,6 @@
//! # Raw Sockets for nrfxlib
//!
//! Generic socket related code.
//! Transport Layer Security (TLS, aka SSL) socket related code.
//!
//! Copyright (c) 42 Technology Ltd 2019
//!
Expand All
@@ -11,15 +11,16 @@
// Sub-Modules
//******************************************************************************
use super :: { get_last_error, Error } ;
use crate :: raw:: * ;
use nrfxlib_sys as sys;
// None
//******************************************************************************
// Imports
//******************************************************************************
// None
use super :: { get_last_error, Error } ;
use crate :: raw:: * ;
use log:: debug;
use nrfxlib_sys as sys;
//******************************************************************************
// Types
Expand All
@@ -29,7 +30,27 @@ use nrfxlib_sys as sys;
#[ derive( Debug ) ]
pub struct TlsSocket {
socket : Socket ,
peer_verify : i32 ,
}
/// Specify which version of the TLS standard to use
#[ derive( Debug , Copy , Clone ) ]
pub enum Version {
/// TLS v1.2
Tls1v2 ,
/// TLS v1.3
Tls1v3 ,
}
/// Specify whether to verify the peer
#[ derive( Debug , Copy , Clone ) ]
pub enum PeerVerification {
/// Yes - check the peer's certificate is valid and abort if it isn't
Enabled ,
/// Maybe - check the peer's certificate is valid but don't abort if it isn't
Optional ,
/// No - do not validate the peer's certificate. Using this option leaves
/// you vulnerable to man-in-the-middle attacks.
Disabled ,
}
//******************************************************************************
Expand All
@@ -55,38 +76,46 @@ pub struct TlsSocket {
//******************************************************************************
impl TlsSocket {
/// Create a new TLS socket. Only supports TLS v1.2 and IPv4 at the moment.
pub fn new ( peer_verify : bool , security_tags : & [ u32 ] ) -> Result < TlsSocket , Error > {
let socket = Socket :: new (
SocketDomain :: Inet ,
SocketType :: Stream ,
SocketProtocol :: Tls1v2 ,
) ?;
/// Create a new TLS socket. Only supports TLS v1.2/1.3 and IPv4 at the moment.
pub fn new (
peer_verify : PeerVerification ,
security_tags : & [ u32 ] ,
version : Version ,
) -> Result < TlsSocket , Error > {
let nrf_tls_version = match version {
Version :: Tls1v2 => SocketProtocol :: Tls1v2 ,
Version :: Tls1v3 => SocketProtocol :: Tls1v3 ,
} ;
let socket = Socket :: new ( SocketDomain :: Inet , SocketType :: Stream , nrf_tls_version) ?;
// Now configure this socket
// Set whether we verify the peer
socket. set_option ( SocketOption :: TlsPeerVerify ( if peer_verify { 1 } else { 0 } ) ) ?;
socket. set_option ( SocketOption :: TlsPeerVerify ( peer_verify. as_integer ( ) ) ) ?;
// We skip the cipher list
// Always enable session caching to speed up connecting. 0 = enabled, 1
// = disabled (the default).
socket. set_option ( SocketOption :: TlsSessionCache ( 0 ) ) ?;
// We don't set the cipher list, and assume the defaults are sensible.
if !security_tags. is_empty ( ) {
// Configure the socket to use the pre-stored certificates. See
// `provision_certificates`.
socket. set_option ( SocketOption :: TlsTagList ( security_tags) ) ?;
}
Ok ( TlsSocket {
socket,
peer_verify : if peer_verify { 1 } else { 0 } ,
} )
Ok ( TlsSocket { socket } )
}
/// Look up the hostname and for each result returned, try to connect to
/// it.
pub fn connect ( & self , hostname : & str , port : u16 ) -> Result < ( ) , Error > {
use core:: fmt:: Write ;
debug ! ( "Connecting via TLS to {}:{}" , hostname, port) ;
// First we set the hostname
self . socket
. set_option ( SocketOption :: TlsHostName ( hostname) ) ?;
Expand All
@@ -97,7 +126,7 @@ impl TlsSocket {
heapless:: String :: new ( ) ;
write ! ( hostname_smallstring, "{}\0 " , hostname) . map_err ( |_| Error :: HostnameTooLong ) ?;
// Now call getaddrinfo with some hints
let hints = crate :: NrfAddrInfo {
let hints = sys :: nrf_addrinfo {
ai_flags : 0 ,
ai_family : sys:: NRF_AF_INET as i32 ,
ai_socktype : sys:: NRF_SOCK_STREAM as i32 ,
Expand All
@@ -107,7 +136,7 @@ impl TlsSocket {
ai_canonname : core:: ptr:: null_mut ( ) ,
ai_next : core:: ptr:: null_mut ( ) ,
} ;
let mut output_ptr: * mut crate :: NrfAddrInfo = core:: ptr:: null_mut ( ) ;
let mut output_ptr: * mut sys :: nrf_addrinfo = core:: ptr:: null_mut ( ) ;
result = unsafe {
sys:: nrf_getaddrinfo (
// hostname
Expand All
@@ -124,23 +153,25 @@ impl TlsSocket {
if ( result != 0 ) && output_ptr. is_null ( ) {
return Err ( Error :: Nordic ( "tls_dns" , result, get_last_error ( ) ) ) ;
} else {
let mut record: & crate :: NrfAddrInfo = unsafe { & * output_ptr } ;
let mut record: & sys :: nrf_addrinfo = unsafe { & * output_ptr } ;
loop {
let dns_addr: & crate :: NrfSockAddrIn =
unsafe { & * ( record. ai_addr as * const crate :: NrfSockAddrIn ) } ;
let dns_addr: & sys :: nrf_sockaddr_in =
unsafe { & * ( record. ai_addr as * const sys :: nrf_sockaddr_in ) } ;
// Create a new sockaddr_in with the right port
let connect_addr = crate :: NrfSockAddrIn {
sin_len : core:: mem:: size_of :: < crate :: NrfSockAddrIn > ( ) as u8 ,
let connect_addr = sys :: nrf_sockaddr_in {
sin_len : core:: mem:: size_of :: < sys :: nrf_sockaddr_in > ( ) as u8 ,
sin_family : sys:: NRF_AF_INET as i32 ,
sin_port : htons ( port) ,
sin_addr : dns_addr. sin_addr . clone ( ) ,
} ;
debug ! ( "Trying IP address {}" , &crate ::NrfSockAddrIn ( connect_addr) ) ;
// try and connect to this result
result = unsafe {
sys:: nrf_connect (
self . socket . fd ,
& connect_addr as * const crate :: NrfSockAddrIn as * const _ ,
& connect_addr as * const sys :: nrf_sockaddr_in as * const _ ,
connect_addr. sin_len as u32 ,
)
} ;
Expand Down
Expand Up
@@ -185,6 +216,18 @@ impl core::ops::Deref for TlsSocket {
}
}
impl PeerVerification {
/// The NRF library wants peer verification as a integer, so this function
/// converts as per `sys::nrf_sec_peer_verify_t`.
fn as_integer ( self ) -> u32 {
match self {
PeerVerification :: Enabled => 2 ,
PeerVerification :: Optional => 1 ,
PeerVerification :: Disabled => 0 ,
}
}
}
/// Store SSL certificates in the modem NVRAM for use with a subsequent TLS
/// connection.
///
Expand Down