# TLS

Driver uses either the
[`openssl`](https://github.com/sfackler/rust-openssl) crate or the
[`rustls`](https://github.com/rustls/rustls) crate for TLS functionality.

Both of this features are behind their respective feature flag.

## Hostname verification

For both implementations we provide node IP address for purposes of hostname verification.
Our assumption is that certificates on nodes will have node IP address in the subject alternative name.

Implementation details (might change in the future):
For openssl we use `set_ip` method on `X509VerifyParamRef`, which corresponds to `X509_VERIFY_PARAM_set1_ip` openssl function.
For rustls, we use `ServerName::IpAddress`, which is passed to `ClientConnection::new_with_alpn` (by `tokio_rustls`).

### Enabling feature

***NOTE:*** `openssl` is not a pure Rust library, so you need to **both** enable a feature **and** install the proper package.

To enable use of TLS using `openssl`, add in `Cargo.toml`:

```toml
scylla = { version = "0.4", features = ["openssl-010"] }
openssl = "0.10.70"
```

Then install the package with `openssl`:

* Debian/Ubuntu:
  ```bash
  apt install libssl-dev pkg-config
  ```
* Fedora:
  ```bash
  dnf install openssl-devel
  ```

<!--
 scylla-rust-driver doesn't build on Alpine, some strange cc linker errors in proc-macro-hack 0_o
 TODO: try building and add the section

 \* Alpine:
    \`\`\`bash
    apk add openssl-dev
    \`\`\`
-->
* Arch:
  ```bash
  pacman -S openssl pkg-config
  ```

### Using TLS

To use TLS you will have to a `TlsContext`. For convenience, both an
openssl
[`SslContext`](https://docs.rs/openssl/0.10.33/openssl/ssl/struct.SslContext.html)
and a rustls
[`ClientConfig`](https://docs.rs/rustls/latest/rustls/client/struct.ClientConfig.html)
can be automatically converted to a `TlsContext` when passing to
`SessionBuilder`.

***NOTE:*** Recommended API in `openssl` crate is `SslConnector`, because it has safer defaults. Please use it, and then call `into_context()` to
get `SslContext` instance you can pass to the driver.

For example, if database certificate is in the file `ca.crt`:

```rust
use scylla::client::session::Session;
use scylla::client::session_builder::SessionBuilder;
use openssl::ssl::{SslContextBuilder, SslMethod, SslVerifyMode};
use std::path::PathBuf;

let mut context_builder = SslContextBuilder::new(SslMethod::tls())?;
context_builder.set_ca_file("ca.crt")?;
context_builder.set_verify(SslVerifyMode::PEER);

let session: Session = SessionBuilder::new()
    .known_node("127.0.0.1:9142") // The the port is now 9142
    .tls_context(Some(context_builder.build()))
    .build()
    .await?;

```

See the full [openssl example](https://github.com/scylladb/scylla-rust-driver/blob/main/examples/tls-openssl.rs) and [rustls example](https://github.com/scylladb/scylla-rust-driver/blob/main/examples/tls-rustls.rs) for more details.
