diff options
Diffstat (limited to 'docs')
-rw-r--r-- | docs/Certificates.md | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/docs/Certificates.md b/docs/Certificates.md new file mode 100644 index 0000000..b2cf0ff --- /dev/null +++ b/docs/Certificates.md @@ -0,0 +1,88 @@ +# Certificates and server authentication + +## Trust on first use + +### Default configuration + +Use it like this: +```rust +client.connect(/*...*/, CertificateVerificationMode::TrustOnFirstUse(TrustOnFirstUseConfig { + ..Default::default() + }), +); +``` + +With the default configuration, known hosts and their fingerprints are stored in a file, which defaults to `quinnet/known_hosts`. +The defaults verifier behaviours are: +- For an `unknwon` certificate (first time this server is encountered) => the client trusts this certificate, stores its fingerprint and continue the connection; +- For a `trusted` certificate (the fingerprint matches the one stored for this server) => the client trusts this certificate and continue the connection; +- For an `untrusted` certificate (the certificate's fingerprint does not match the one in the store) => the client raises an event to the Bevy app and waits for an action to apply. + +### Examples configurations + +Default verifier behaviours with a custom store file: +```rust +client.connect(/*...*/, CertificateVerificationMode::TrustOnFirstUse(TrustOnFirstUseConfig { + known_hosts: KnownHosts::HostsFile("MyCustomFile".to_string()), + ..Default::default() + }), +); +``` + +Custom verifier behaviours with a custom store: +```rust +client.connect(/*...*/, CertificateVerificationMode::TrustOnFirstUse(TrustOnFirstUseConfig { + known_hosts: KnownHosts::Store(my_cert_store), + verifier_behaviour: HashMap::from([ + ( + CertVerificationStatus::UnknownCertificate, + CertVerifierBehaviour::ImmediateAction(CertVerifierAction::TrustAndStore), + ), + ( + CertVerificationStatus::UntrustedCertificate, + CertVerifierBehaviour::ImmediateAction(CertVerifierAction::AbortConnection), + ), + ( + CertVerificationStatus::TrustedCertificate, + CertVerifierBehaviour::ImmediateAction(CertVerifierAction::TrustOnce), + ), + ]), + }), +); +``` + +### Events + +The Quinnet client plugin raises Bevy events during the connection process (during the certificate verification). + +- `CertInteractionEvent`: a user action is requested before continuing. This event is only raised when the verifier behaviour for a specific certificate status is set to `CertVerifierBehaviour::RequestClientAction` +- `CertTrustUpdateEvent`: the client plugin encoutered a new trust entry to register. If the store is a file, the client plugin has already updated it. If the store is a custom hashmap given to the client plugin (via `KnownHosts::Store(my_cert_store)`), it is up to the user to update its sotre accordingly. +- `CertConnectionAbortEvent`: signals that the connection was aborted during the certificate verification (through the `CertVerifierAction::AbortConnection`). + +Here is a simple example for a custom handler for `CertInteractionEvent`: + +```rust +fn handle_cert_events(mut cert_action_events: EventReader<CertInteractionEvent>) { + for cert_event in cert_action_events.iter() { + match cert_event.status { + CertVerificationStatus::UntrustedCertificate => cert_event + .apply_cert_verifier_action(CertVerifierAction::AbortConnection) + .unwrap(), + _ => cert_event + .apply_cert_verifier_action(CertVerifierAction::TrustOnce) + .unwrap(), + } + } +} +``` + +### Fingerprints + +Fingerprints in Quinnet are a SHA-256 hash of the certificate data in DER form. + +### Known hosts file format + +This hosts file format is really simplistic for now. +There is one line per entry, and each entry is a server name (as dns or ip) followed by a space, followed by the currently known fingerprint encoded in base64. + +This means that if two servers are hosted on the same machine on two different ports, they should currently share the same certificate to avoid any conflict. |