How to configure ServerConfig of rustls

EDIT: changed title to be search friendly

I'm trying to create Server with TLS support. I know basics of SSL/TSL but I can't figure out how to use TLS. documentation on rustls is greate but it contains so many words that I don't understand. Also I can't find any tutorials on net with rustls without actix which I'm not using

I have created MyCa certificate of type Certificate Authority in XCA and exported it as MyCa.crt file and then created certificated signing request and singed it with MyCa and exported it as MyApp.crt.

Now I have MyCa.crt and MyApp.crt file. My understanding is that is that my server app will have MyApp.crt file and client app will have MyCa.crt and client will trust all certificates signed by MyCa.crt

I have following Server code:-

#[tokio::main]
async fn main() {
    let mut listener = TcpListener::bind("127.0.0.1:17017").await.unwrap();
    while let Some(socket) = listener.next().await {
        match socket {
            Err(e) => eprintln!("accept failed = {:?}", e),
            Ok(sock) => {
                //How can I upgrade sock which is normal TCP stream to TLS stream ??
                tokio::spawn(async move { somecoolstuff(sock) });  
            }
        }
    }
}

I believe it will look something like this:

#[tokio::main]
async fn main() {
    let config = rustls::ServerConfig::new(...);
    let acceptor = tokio_rustls::TlsAcceptor::from(Arc::new(config));

    let mut listener = TcpListener::bind("127.0.0.1:17017").await.unwrap();
    while let Some(socket) = listener.next().await {
        match socket {
            Err(e) => eprintln!("accept failed = {:?}", e),
            Ok(sock) => {
                let acceptor = acceptor.clone();
                tokio::spawn(async move {
                    let tls = acceptor.accept(sock).await.unwrap();
                    use_tls_stream(tls).await;
                });
            }
        }
    }
}
    let config = rustls::ServerConfig::new(...);

This is the most confusing part :sweat:. How can I use *crt files with this config?

there is set_single_cert method but it requires certificate chain and private key which is really confusing.

In XCA when I export certificate, there are bunch of options (pem,der, pkcs ..etc) but none of their description mentions certificate chain

Sorry, I don't know how to set up the ServerConfig.

Ok, so I was able to set up the ServerConfig.

First I created Root Certificate named KoolCA with [default] CA template in XCA which is self signed. btw don't forget to press Apply All button so that templete can take effect.

Then I created another Certificate named NiceApp which is signed by the KoolCA with default template as [default] TLS_Server. The common name field in subject tab was important for this one cause empty name was giving error like this in rust:-

Io(Custom { kind: Other, error: Custom { kind: InvalidData, error: WebPKIError(CertNotValidForName) } })

Now it looked like this in XCA:-


Screenshot_20201124_075154

And then I exported

  1. KoolCA as KoolCA.crt with export format being `PEM (*.crt).
  2. NiceApp as NiceApp.pem as PEM Chain with export format being PEM chain (*.pem)
  3. private used for NiceApp as NiceApp.pk8 as Encrypted PKCS#8 wirh format being PKCS# encrypted (*.pk8) in XCA

Now my code looked like this:-

Sever:-

let mut tls_config = ServerConfig::new(Arc::new(NoClientAuth));

let cert_file = &mut BufReader::new(File::open("/home/noone/development/ssl/NiceApp.pem").unwrap());
let key_file = &mut BufReader::new(File::open("/home/noone/development/ssl/NiceApp.pk8").unwrap());

let cert_chain = certs(cert_file).unwrap();
let mut keys = pkcs8_private_keys(key_file).unwrap();

tls_config.set_single_cert(cert_chain, keys.remove(0)).unwrap();

let tls_config = Arc::new(tls_config);
let tls_acceptor = TlsAcceptor::from(tls_config); 

Client:-

let ca_cert = &mut BufReader::new(File::open("/home/noone/development/ssl/KoolCA.crt").unwrap());
let ca_cert = certs(ca_cert).unwrap().remove(0);
let mut config = ClientConfig::new();
config.root_store.add(&ca_cert).unwrap();
let config = TlsConnector::from(Arc::new(config));

I was still getting CertNotValidForName error when client tried to connect to server. So i had to add an entry to /etc/hosts like this:-

127.0.0.1       NiceApp

where NiceApp is common name in NiceApp.crt. I also have to use NiceApp instead of localhost when connecting to the server. like this:-

connect_async_with_tls_connector( Url::parse("wss://NiceApp:17017").unwrap(),Some(config) )

Hope this helps someone and forgive me for my bad English.