SaiTLS/README.md

152 lines
6.1 KiB
Markdown
Raw Normal View History

2021-01-28 13:43:41 +08:00
# SaiTLS
`[no-std]` Client & Server side TLS implementation on top of smoltcp, using allocator.
## Features
This crate supports these algorithms:
- Cipher suites:
- TLS_AES_128_GCM_SHA256
- TLS_AES_256_GCM_SHA384
- TLS_CHACHA20_POLY1305_SHA256
- TLS_AES_128_CCM_SHA256
- Ecliptic curves:
- X25519
- secp256r1 (NIST P-256)
- Digital signature algorithms:
- ecdsa_secp256r1_sha256
- ed25519
- RSASSA-PKCS1-v1_5 algorithms
- RSASSA-PSS algorithms
Implementation of all algorithms (except x25519 & ed25519) are directly sourced from the [RustCrypto](https://github.com/RustCrypto) project.
Implementation of x25519 & ed25519 algorithms are directly sourced from the [dalek-cryptography](https://github.com/dalek-cryptography) project.
Algorithms not listed above are __NOT__ supported. Using certificates with unsupported algorithms will cause handshake/communication failure.
This crate supports these handshake features:
- Certificate verification, with a single self-signed certificate
- (Client) Client certificate verification, if requested by remote server
- (Server) Send Client Certificate Request to remote client
These handshake features are __NOT__ supported:
- HelloRetryRequest
- Pre-shared key & New session ticket
- Early data
- 0-RTT handshake
- Verification of non-self-signed certificates, including certificate chain
## TLS Socket
To create a TLS socket, the following items are needed:
- TCP Socket from smoltcp
- Random number generator (cryptographically secure RNG is recommended)
- (Optional) Client certificates in x509 certificate & the associated private key
The RNG requires the `TlsRng` trait to be implemented, which further include these traits:
- `RngCore` from rand_core
- `CryptoRng` from rand_core
TLS socket can be instantiated by the following lines of code:
```rust
// Typical TCP socket from smoltcp
let mut tx_storage = [0; 4096];
let mut rx_storage = [0; 4096];
let tx_buffer = net::socket::TcpSocketBuffer::new(&mut tx_storage[..]);
let rx_buffer = net::socket::TcpSocketBuffer::new(&mut rx_storage[..]);
let mut tcp_socket = net::socket::TcpSocket::new(rx_buffer, tx_buffer);
// TLS socket constructor
let tls_socket = TlsSocket::new(
tcp_socket,
&mut rng, // Assume rng is from a struct that implements TlsRng
None
);
```
## Socket Storage & Access
Similar to smoltcp, a `TlsSocketSet` is needed to hold the sockets.
Use `TlsSocketHandle` to gain access to a TLS Socket indirectly.
```rust
// Prepare a socket set for TLS sockets
let mut tls_socket_entries: [_; 1] = Default::default();
2021-01-29 12:31:04 +08:00
let mut tls_socket_set = SaiTLS::set::TlsSocketSet::new(
2021-01-28 13:43:41 +08:00
&mut tls_socket_entries[..]
);
// Use TLS socket set & handle to access TLS socket
let tls_handle = tls_socket_set.add(tls_socket);
{
let mut tls_socket = tls_socket_set.get(tls_handle);
/* Socket manipulations */
}
```
## Polling
The `poll(..)` function substitutes the `EthernetInterface.poll(..)` function in smoltcp.
```rust
2021-01-29 12:31:04 +08:00
SaiTLS::poll(
2021-01-28 13:43:41 +08:00
Some(&mut smoltcp_sockets), // Optional socket set from smoltcp
&mut tls_socket_set,
&mut ethernet_interface,
smoltcp::time::Instant::from_millis(time)
);
```
Sockets in either `smoltcp_sockets` or `tls_socket_set` will be updated.
2021-01-29 12:31:04 +08:00
## Authentication on SaiTLS side
If necessary, SaiTLS will send X.509 certificate to the remote side, designated in the constructor. This requires X.509 certificate and its associated private key to be loaded onto the socket. A X.509 self-signed certificate and the signature private key can be generated by OpenSSL using the following command:
```
openssl req -x509 -newkey rsa:1024 -sha256 -nodes -keyout key.der -out cert.der -days 30 -outform DER
```
This will generate a self-signed certificate in DER format as `cert.der`, signed by an RSA key with 1024 bits as `key.der`. The certificate supplied to SaiTLS must be in DER format.
The `include_bytes!()` Rust macro can load the DER certificate as a binary slice.
Private/Secrete key needs to be instantiated by the corresponding RustCrypto/Dalek library. The following is an example of loading `cert.der` and `key.der` into the constructor of `TLSSocket`.
```Rust
// This line includes the certificate in DER format
const CERT: &'static [u8] = include_bytes!( `<path-to-certificate>` );
// These lines contains components of the RSA private key
const PRIVATE_KEY_MOD: &'static [u8] = ... ;
const PUBLIC_KEY_EXP: &'static [u8] = &[ 0x01, 0x00, 0x01 ];
const PRIVATE_KEY_EXP: &'static [u8] = ... ;
const CLIENT_PRIME_1: &'static [u8] = ... ;
const CLIENT_PRIME_2: &'static [u8] = ... ;
```
The exact values of these constants can be found by printing out the content using OpenSSL, such as the following command.
```
openssl rsa -in key.der -text
```
The private key can then be assembled as such:
```Rust
let mut prime_vec = alloc::vec::Vec::new();
prime_vec.push(rsa::BigUint::from_bytes_be(&CLIENT_PRIME_1));
prime_vec.push(rsa::BigUint::from_bytes_be(&CLIENT_PRIME_2));
let rsa_key = rsa::RSAPrivateKey::from_components(
rsa::BigUint::from_bytes_be(CLIENT_PRIVATE_KEY_MOD),
rsa::BigUint::from_bytes_be(CLIENT_PUBLIC_KEY_EXP),
rsa::BigUint::from_bytes_be(CLIENT_PRIVATE_KEY_EXP),
prime_vec
);
```
Finally, the private key and the certificate are loaded onto the socket.
```Rust
let mut tls_socket = TlsSocket::new(
tcp_socket,
&mut rng_struct,
Some((cert_private_key, alloc::vec![CLIENT_CERT]))
);
```
Loading more than 1 certificate (i.e. a certificate chain) is experimental. Use at your own risk!
Note that the remote side may not necessarily accept the self-signed certificate. It is entirely up to the remote side to accept or reject your provided certificate. Designation of trusted files might be helpful (e.g. the `--trustfile` option in Ncat).
2021-01-28 13:43:41 +08:00
## Feature `nal_tcp_stack`
Implements `TcpStack` in embedded-nal (v0.1.0) for `TlsSocket`. This disguises `TlsSocket` as just another TCP socket, potentially useful for implementating application layer protocols (e.g. MQTT in minimq).
2021-01-29 12:31:04 +08:00
Usage:
```Rust
let tls_socket_set = SaiTLS::set::TlsSocketSet::new( .. );
let tls_stack = NetworkStack::new(tls_socket_set);
```