Skip to content

Implementation of authenticated sessions


Key generation


Authentication of users, like all communications between the client and server, occurs over a TLS channel. Encrypting all communications from the very beginning of the connection minimizes opportunities for adversaries to hijack or otherwise interfere with connections.

You can use BastionLabโ€™s Client Identity.create() function to generate the key pair that will allow both ends to verify with whom they communicate.

Hereโ€™s how the keys are generated:

We use Pythonโ€™s cryptography library to generate a key pair, using the elliptic curve NIST P-256 algorithm. The Python cryptography library itself uses OpenSSL, a standard library for cryptography. The keys are saved to the bin directory and labeled as foo (private key) and foo.pub (public key). You must share your public key with the server or the data owner so it can be added to the set of trusted keys when the server is initiated.

The transfer of the public key to the data owner is not something we cover. We leave it to you to choose a trusted means of transferring your public key.

Important

You do not have to generate the key with BastionLab. You can do it with any other means (OpenSSL for example), but the keys must be generated using the NIST P-256 elliptic curve algorithm.

Key management


We are working under the assumption that the server is hosted on the data ownerโ€™s infrastructure and that the infrastructure is trusted and safe.

The keys are stored in the bin directory with the following directory structure:

bin/keys:
|
    -owners:
        -ownerโ€™s public key
    -users:
        -user 1โ€™s public key
        -user 2โ€™s public key
        - โ€ฆ

When the server is initiated the keys are loaded from the directory. The keys are never read again until a server restart. This means that no keys can be added while the server is running.

Authentication


Authentication in BastionLab is designed to be simple and strong.

Since we donโ€™t use passwords (or the ability to reset them), the private key is the only proof of identity.

When a connection is established, a challenge is generated and sent to the client. The client signs this challenge with their private key and returns it along with a hash of their public key. The server verifies that it has a public key loaded matching the returned public key hash, before validating the signature using the public key.

Then, the server generates a session token which it shares with the client and stores until the connection disconnects or the session expires.

The client uses the session token to authenticate each request it sends from there on out.

Specifications

The challenges are generated using the ring crate. A seed is generated by a call to SystemRandom and the challenge is a 32-bit random number generated by a call to ring::rand().

The signature algorithm is `ECDSA P256-SHA256 .

The cryptography module is used in the client end to generate the signature. The ring crate is used in the server end to verify the signature. The spki crate is used to load the public key into memory.

The session tokens are generated exactly as the challenges are, producing a 32-bit random number.

Session token validation includes matching the client IP for which the session token was generated.

The session tokens have a lifetime of 1500 seconds. Should a session expire, the client will automatically generate a new session when a request is sent (this will require authentication to happen again with a challenge being issued and verified, but it is silent and automatic requiring no interaction from the client). *The session expiry update as mentioned above remains to be merged.

Flow