Skip to content

Latest commit

 

History

History
99 lines (79 loc) · 4.25 KB

Certificates.md

File metadata and controls

99 lines (79 loc) · 4.25 KB

Certificates and server authentication

Trust on first use

Default configuration

Use the default configuration like this:

client.open_connection(/*...*/, 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 unknown 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:

client.open_connection(/*...*/, CertificateVerificationMode::TrustOnFirstUse(TrustOnFirstUseConfig {
        known_hosts: KnownHosts::HostsFile("MyCustomFile".to_string()),
        ..Default::default()
    }),
);

Custom verifier behaviours with a custom store:

client.open_connection(/*...*/, 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 store 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 of CertInteractionEvent:

fn handle_cert_events(mut cert_action_events: EventReader<CertInteractionEvent>) {
    // We may receive a CertInteractionEvent during the connection
    for cert_event in cert_action_events.iter() {
        match cert_event.status {
            // We want to abort the connection if the certificate is untrusted, else we continue
            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.

Example:

::1 o1cpTe602uTq4pVwT+km8QtEPQE/xCAgk+3AicW/i9g=
1234::1234 kzXIwhvMSbWCQOimT3btnFlmc/Lq0UN0JhSeQadaGbg=

Limitations

This simple format implies 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.