|
|
# Auth Details
|
|
|
|
|
|
Here we look at the low level details of the packet data in the authentication process.
|
|
|
|
|
|
We have 3 players:
|
|
|
* **AS**: The authentication server
|
|
|
* **S**: The service we want to connect to
|
|
|
* **C**: The client.
|
|
|
|
|
|
We assume that the client has taken and verified the DNSSEC data as described in the [DNSSEC Details page](DNSSEC_Details).
|
|
|
|
|
|
In this example the client will connect to **example.com**
|
|
|
|
|
|
Fenrir supports 2 connection algorithms:
|
|
|
* **3 Round-Trip**: full perfect forward security per each connection. used for authenticated connections.
|
|
|
* **2 Round-Trip**: QUIC-like, less rigid forward security. used for anonymous connections, since there is not much to protect anyway.
|
|
|
* A **1-RT** minimaLT-style is possible, but will probably be implemented only in the future.
|
|
|
|
|
|
Every connection can be either anonymous or authenticated, and when switching from an anonymous connection to an user authenticated one a new key exchange **must** take place, to better protect the authentication data.
|
|
|
|
|
|
|
|
|
----
|
|
|
|
|
|
## AS database
|
|
|
|
|
|
The AS need a (small) database with at least the following information for each Service:
|
|
|
* Service **fqdn** (example.com)
|
|
|
* Service priority (0-255)
|
|
|
* Service preference (0-255)
|
|
|
* Service id (random 16 bits)
|
|
|
* Service secret key (128/256bit key)
|
|
|
|
|
|
This information permits us to:
|
|
|
* decide where the client will connect
|
|
|
* support multiple servers
|
|
|
* support fallback servers.
|
|
|
|
|
|
In the future filters based on countries or other client-provided information might be added easily.
|
|
|
|
|
|
_By doing this now we have eliminated all the limitations of dns-based load balancing and client filtering_
|
|
|
|
|
|
---
|
|
|
|
|
|
## The beginning: S -> AS authentication
|
|
|
|
|
|
The first thing that need to happen, is that the service connects to the authentication server.
|
|
|
|
|
|
This connection is needed to inform the Service of new clients; By requiring an active connection between the AS and the Service we can also adapt quickly to any Service shutdown or load problem.
|
|
|
|
|
|
_In the future load-information messages might be added to automatically balance the load to different servers, without having to specify it manually._
|
|
|
|
|
|
The Service does a full 3-RTT handshake connection to the AS. Fenrir supports 2-RT connection setup, but Services must authenticate with 3-RoundTrip connections to force Perfect forward security and in general for added security. A service only connects once to the AS, and then the connection is kept alive, so the overhead is negligible.
|
|
|
|
|
|
This handshake is the same also for the client authentication.
|
|
|
|
|
|
|
|
|
* **S** does DNSSEC query. From this query the service can easily learn:
|
|
|
* ips of the authentication servers
|
|
|
* public keys
|
|
|
* supported authentication algorithms
|
|
|
|
|
|
* **S** now sends to **AS** the connection request. The message will be padded to 1280 total bytes, to avoid amplification.
|
|
|
* connection_id: 0...0; stream_id = random1.
|
|
|
* first byte: connection type request: **0x00 = Service full 3-RT handshake**
|
|
|
* 8 bytes: random nonce
|
|
|
* other bytes follow, content irrelevant. used to avoid amplification attacks.
|
|
|
* **AS** sends back a signed cookie containing:
|
|
|
* connection_id: 0...0; stream_id: random1.
|
|
|
* one byte: connection type (**0x00**=3-RT handshake)
|
|
|
* 8-bytes: timestamp.
|
|
|
* signature
|
|
|
* The signature also includes the originating ip, server ip and client packet information.
|
|
|
|
|
|
* The **S** answers with:
|
|
|
* connection_id: 0...0, stream_id: random1.
|
|
|
* connection type request: **0x01** = 3-RTT handshake answer
|
|
|
* previous client nonce
|
|
|
* new client nonce (8 bytes)
|
|
|
* server timestamp
|
|
|
* previous server signature
|
|
|
* supported chipers, pubkey, key-exchange and hmac algorithms: these are bitmasks of X bytes, where:
|
|
|
* bits 0-6: supported chipers/pubkeys
|
|
|
* bit 7: next byte is another "supported chipers" byte (true=1,false=0).
|
|
|
* 2 bytes: selected authentication algorithm.
|
|
|
|
|
|
* The **AS** verifies the signature and timestamp of its previous cookie and answers:
|
|
|
* connection id:0...0, stream_id: random1.
|
|
|
* connection type request: **0x01** = 3-RTT handshake answer
|
|
|
* previous client nonce
|
|
|
* selected cipher, pubkey, key-exchange,hmac algorithm.
|
|
|
* ephemeral public key
|
|
|
* key exchange data
|
|
|
* eventual authentication challenge (cleartext)
|
|
|
* signature of the above and previous client packet data
|
|
|
|
|
|
* The **S** can now safely authenticate, since it just has to create a new ephemeral public key, derive the secret keys and use them.
|
|
|
* ephemeral pubkey
|
|
|
* key exchange data
|
|
|
* encrypted data:
|
|
|
* domain, service id the client want to connect to
|
|
|
* connection information
|
|
|
* authentication data
|
|
|
* HMAC of all the above.
|
|
|
|
|
|
* The **AS** simply responds with:
|
|
|
* encrypted data:
|
|
|
* connection data
|
|
|
* succesful athentication info
|
|
|
* HMAC for the above
|
|
|
|
|
|
On authentication failure the AS will send a packet of roughly the same size as a succesullf one and close the connection.
|
|
|
|
|
|
Now the service has a secure connection to the authentication server.
|
|
|
|
|
|
----
|
|
|
|
|
|
## Client -> AS
|
|
|
|
|
|
If you want authenticated connections from the beginning, the setup is almost the same as before.
|
|
|
|
|
|
But for anonymous client connections, we can use a 2-RTT connection:
|
|
|
|
|
|
* **C** does DNSSEC query
|
|
|
* **C** sends to **AS** the connection request. The message **must** be at least 500 bytes, to avoid amplification.
|
|
|
* connection_id: 0...0; stream_id = random1.
|
|
|
* first byte: connection type request: **0x02 = Client 2-RT handshake**
|
|
|
* other bytes follow, content irrelevant. used to avoid amplification attacks.
|
|
|
* **AS** sends back a signed cookie:
|
|
|
* connection_id: 0...0; stream_id: random1.
|
|
|
* one byte: connection type (**0x02**=2-RTT handshake)
|
|
|
* cookie:
|
|
|
* supported chipers: this is a bitmask of X bytes, where:
|
|
|
* bits 0-6: supported chipers/pubkeys
|
|
|
* bit 7: next byte is another "supported chipers" byte (true=1,false=0).
|
|
|
* 8-bytes: timestamp.
|
|
|
* server ephemeral public key (changed every X minutes).
|
|
|
* one byte: next field length:
|
|
|
* Y bytes: key exchange data
|
|
|
* The signature of the cookie also includes the originating ip, server ip.
|
|
|
* The **C** answers with:
|
|
|
* connection_id: 0...0, stream_id: random2.
|
|
|
* connection type request: **0x03** = 2-RT handshake answer
|
|
|
* server-signed cookie
|
|
|
* supported chiper (see previous message)
|
|
|
* X bytes: public key
|
|
|
* one byte: next field length:
|
|
|
* Y bytes: key exchange data
|
|
|
* signature of the above data.
|
|
|
* The **AS** verifies the signature of its cookie and answers:
|
|
|
* connection id:0...0, stream_id: random2.
|
|
|
* connection type request: **0x03** = 2-RT handshake answer
|
|
|
* new connection_id (4 bytes)
|
|
|
* X bytes: newly-generated ephemeral public key.
|
|
|
* one byte: next field length:
|
|
|
* Y bytes: key exchange data
|
|
|
* selected ciphers
|
|
|
* encrypted details for service connection:
|
|
|
* new random stream_id (control_stream): 2 bytes
|
|
|
* ip of selected service.
|
|
|
* algorithm and symmetric key
|
|
|
* Service public key
|
|
|
* signature of the above data.
|
|
|
|
|
|
----
|
|
|
|
|
|
## Those packets seems large!
|
|
|
|
|
|
While the packets for the first RT should fit easily in a 1500 ethernet frame, in the client authentication the last packet will hardly fit into the ethernet frame.
|
|
|
|
|
|
That is because we are sending 2 public keys and a signature.
|
|
|
The following table lists all the openssl supported rsa/ec algorithms, with key size (DER format) and signature size (in bytes).
|
|
|
|
|
|
| algorithm | public key size | signature size |
|
|
|
|------:|------|:------|
|
|
|
| RSA-1024 | 162 | 128 |
|
|
|
| RSA-2048 | 294 | 256 |
|
|
|
| RSA-3072 | 422 | 384 |
|
|
|
| RSA-4096 | 550 | 512 |
|
|
|
| wap-wsg-idm-ecid-wtls8 | 52 | 35 |
|
|
|
| wap-wsg-idm-ecid-wtls6 | 52 | 36 |
|
|
|
| secp112r2 | 52 | 34 |
|
|
|
| secp112r1 | 52 | 35 |
|
|
|
| wap-wsg-idm-ecid-wtls4 | 54 | 34 |
|
|
|
| wap-wsg-idm-ecid-wtls1 | 54 | 34 |
|
|
|
| sect113r2 | 54 | 35 |
|
|
|
| sect113r1 | 54 | 34 |
|
|
|
| secp128r2 | 56 | 38 |
|
|
|
| secp128r1 | 56 | 40 |
|
|
|
| sect131r2 | 58 | 40 |
|
|
|
| sect131r1 | 58 | 39 |
|
|
|
| wap-wsg-idm-ecid-wtls9 | 64 | 47 |
|
|
|
| wap-wsg-idm-ecid-wtls7 | 64 | 48 |
|
|
|
| secp160r2 | 64 | 47 |
|
|
|
| secp160r1 | 64 | 47 |
|
|
|
| secp160k1 | 64 | 47 |
|
|
|
| wap-wsg-idm-ecid-wtls5 | 66 | 48 |
|
|
|
| wap-wsg-idm-ecid-wtls3 | 66 | 48 |
|
|
|
| sect163r2 | 66 | 48 |
|
|
|
| sect163r1 | 66 | 48 |
|
|
|
| sect163k1 | 66 | 48 |
|
|
|
| c2pnb163v3 | 69 | 48 |
|
|
|
| c2pnb163v2 | 69 | 48 |
|
|
|
| c2pnb163v1 | 69 | 48 |
|
|
|
| c2pnb176v1 | 71 | 48 |
|
|
|
| secp192k1 | 72 | 55 |
|
|
|
| sect193r2 | 74 | 56 |
|
|
|
| sect193r1 | 74 | 56 |
|
|
|
| prime192v3 | 75 | 55 |
|
|
|
| prime192v2 | 75 | 54 |
|
|
|
| prime192v1 | 75 | 55 |
|
|
|
| c2tnb191v3 | 75 | 54 |
|
|
|
| c2tnb191v2 | 75 | 54 |
|
|
|
| c2tnb191v1 | 75 | 54 |
|
|
|
| c2pnb208w1 | 79 | 55 |
|
|
|
| wap-wsg-idm-ecid-wtls12 | 80 | 63 |
|
|
|
| secp224r1 | 80 | 62 |
|
|
|
| secp224k1 | 80 | 63 |
|
|
|
| wap-wsg-idm-ecid-wtls11 | 84 | 64 |
|
|
|
| wap-wsg-idm-ecid-wtls10 | 84 | 64 |
|
|
|
| sect239k1 | 84 | 66 |
|
|
|
| sect233r1 | 84 | 64 |
|
|
|
| sect233k1 | 84 | 64 |
|
|
|
| prime239v3 | 87 | 66 |
|
|
|
| prime239v2 | 87 | 66 |
|
|
|
| prime239v1 | 87 | 66 |
|
|
|
| c2tnb239v3 | 87 | 66 |
|
|
|
| c2tnb239v2 | 87 | 66 |
|
|
|
| c2tnb239v1 | 87 | 66 |
|
|
|
| secp256k1 | 88 | 72 |
|
|
|
| prime256v1 | 91 | 71 |
|
|
|
| c2pnb272w1 | 95 | 71 |
|
|
|
| sect283r1 | 96 | 78 |
|
|
|
| sect283k1 | 96 | 76 |
|
|
|
| c2pnb304w1 | 103 | 78 |
|
|
|
| c2tnb359v1 | 117 | 95 |
|
|
|
| c2pnb368w1 | 119 | 95 |
|
|
|
| secp384r1 | 120 | 103 |
|
|
|
| sect409r1 | 128 | 108 |
|
|
|
| sect409k1 | 128 | 108 |
|
|
|
| c2tnb431r1 | 136 | 112 |
|
|
|
| secp521r1 | 158 | 138 |
|
|
|
| sect571r1 | 170 | 151 |
|
|
|
| sect571k1 | 170 | 150 |
|
|
|
|
|
|
|
|
|
In general the EC sizes are quite small, and even the bigger ones can fit in a single ethernet frame, **BUT**:
|
|
|
* we should actually consider **1280** bytes as the maximum, not 1500, as that is the ipv6 minimum.
|
|
|
* we actually have a minimum overhead of 18 (MAC) + 40 (ipv6) + 8 (udp) + 13 (Fenrir) = 79 bytes which we need to consider
|
|
|
|
|
|
And if we consider other cryptographic algorithms, like NTRU if we want something quantum-resistant, the public key size goes up a **lot** (think RSA-4096 and more).
|
|
|
|
|
|
Which means that somehow we need to be able to make this exchange a multi-packet one.
|
|
|
|
|
|
## Multi-packet key exchange:
|
|
|
|
|
|
I'm alway open to suggestions, but for now the only thing that comes to mind is that we can use the first byte to use additional "fragmented key exchange" packets.
|
|
|
|
|
|
This however is a little problem, because the server now need to buffer the packets and wait for them, which might open the door to DoS attacks.
|
|
|
|
|
|
To mitigate those attacks the server might refuse to acknowledge fragmented packets of less than 1280 bytes and have very little timeouts (1 second) for buffer reconstruction, but the solution is not defined for now.
|
|
|
|
|
|
Again, if you have ideas, just tell me :) |