All messages transmitted between the server (letmeind)
and the client (letmein) applications have the same format
and the same size (56 bytes):
| Byte offset | Size in bytes | Field name |
|---|---|---|
| 0 | 4 | MAGIC |
| 4 | 4 | OPERATION |
| 8 | 4 | USER |
| 12 | 4 | RESOURCE |
| 16 | 8 | SALT |
| 24 | 32 | AUTH |
The magic code is always 0x3B1BB719 (hex) encoded as
big-endian for all message types. There is no special meaning to this
value. It has been randomly chosen.
| Operation ID | Operation Name |
|---|---|
| 0 | KNOCK |
| 1 | CHALLENGE |
| 2 | RESPONSE |
| 3 | COMEIN |
| 4 | GOAWAY |
This field defines the message type. Only certain types of operations are allowed during different states of the communication. See Typical communication flow below.
The OPERATION field is encoded as big-endian 32-bit.
The user is the selected user identifier from the KEYS section of the configuration file. It identifies the user and the corresponding cryptographic key to be used for encryption.
The USER field is encoded as big-endian 32-bit.
the resource is the selected resource identifier from the RESOURCES section of the configuration file. It identifies the resource (port) that is supposed to get knocked open.
The RESOURCE field is encoded as big-endian 32-bit.
The salt is 8 random bytes unique to every message. The salt is generated with a secure CPRNG. The salt is never reused. It is always freshly generated for each message.
The auth field has different meanings depending on the
OPERATION. See the Cryptography section below for a
detailed description about how the AUTH field is generated
and validated.
Successful knocking:
| Client | Server | Server Firewall |
|---|---|---|
| KNOCK -> | ||
| <- CHALLENGE | ||
| RESPONSE -> | ||
| <- COMEIN | Firewall port opened |
A communication flow always starts with a KNOCK message
from the client to the server.
A CHALLENGE from the server can only follow a
KNOCK from the client.
A RESPONSE from the client can only follow a
CHALLENGE from the server.
A COMEIN from the server can only follow a
RESPONSE from the client.
A successful knocking always ends with a COMEIN message
from the server to the client.
If something goes wrong the server can send the GOAWAY
message to the client at any time. Whether and when that actually
happens depends on the error policy
configuration.
All other message flow combinations are invalid and shall result in
an immediate stop of the communication and authentication. Invalid
combinations may or may not trigger a GOAWAY, depending on
the error policy configuration.
The USER and RESOURCE values in all
messages shall always be equal to what the client requested in the first
KNOCK message.
The OPERATION field of this message shall be
KNOCK.
The USER and RESOURCE fields of this
message shall be what the user requested.
The SALT field in this message shall be a
cryptographically secure nonce.
Use a 32 byte long all-zeros CHALLENGE_TOKEN, generate a new AUTH token and
use the result as the AUTH field of this KNOCK
message.
The server must validate
the received AUTH token of this KNOCK message before
continuing with the communication flow. It is valid but not mandatory to
send a GOAWAY message from server to client, if the
validation failed. The communication must not continue beyond that, if
validation failed.
The OPERATION field of this message shall be
CHALLENGE.
The USER and RESOURCE fields of this
message are set to the same values used in the KNOCK
message.
The SALT field of this message is ignored.
The AUTH field in this message shall be a securely
generated random 32 byte long nonce. This is the
CHALLENGE_TOKEN.
The OPERATION field of this message shall be
RESPONSE.
The USER and RESOURCE fields of this
message are set to the same values used in the KNOCK
message.
The SALT field in this message shall be a
cryptographically secure nonce.
Use the AUTH field of the CHALLENGE message
that we are answering to as the CHALLENGE_TOKEN. Then generate a new AUTH token and
use the result as the AUTH field of this
RESPONSE message.
The server must validate
the received AUTH token of this RESPONSE message before
continuing with the communication flow. It is valid but not mandatory to
send a GOAWAY message from server to client, if the
validation failed. The communication must not continue beyond that, if
validation failed.
The COMEIN message is not cryptographically secured.
The OPERATION field of this message shall be
COMEIN.
The USER and RESOURCE fields of this
message are set to the same values used in the KNOCK
message.
The SALT and AUTH fields of this message
are ignored.
The GOAWAY message is not cryptographically secured.
The OPERATION field of this message shall be
GOAWAY.
The USER and RESOURCE fields of this
message are always set to the same values used in the KNOCK
message.
The SALT and AUTH fields of this message
are ignored.
The inputs for generating an AUTH token are:
KEY (length 32 bytes).CHALLENGE_TOKEN (length 32 bytes).OPERATION field of the message that this
AUTH token is generated for.USER field of the message that this
AUTH token is generated for.RESOURCE field of the message that this
AUTH token is generated for.SALT field of the message that this
AUTH token is generated for.The output is the AUTH token with length 32 bytes.
Compute the AUTH token as follows:
AUTH := HMAC_SHA3_256(KEY)(
message.OPERATION ||
message.USER ||
message.RESOURCE ||
message.SALT ||
CHALLENGE_TOKEN
)
This is the core cryptographic algorithm of letmein.
It uses HMAC together with a SHA3-256 algorithm.
All integer elements shall be serialized in 32-bit big-endian byte
order before passing them to HMAC function. The ||-operator
in the algorithm description above is a concatenation of the serialized
bytes.
Validation always only happens on the server side.
Generate the EXPECTED_AUTH
token for the received message using the expected
CHALLENGE_TOKEN. For a KNOCK message the
expected CHALLENGE_TOKEN is 32 bytes of zeros. For a
RESPONSE message the expected CHALLENGE_TOKEN
is the AUTH field of the CHALLENGE message
that the server sent to the client.
Compare the EXPECTED_AUTH token to the actual
AUTH token of the RESPONSE message using a
Constant Time Comparison Function. The result of the validation is Ok,
if the tokens are equal.