-
Notifications
You must be signed in to change notification settings - Fork 0
Device Enrollment API
This document outlines the protocol for enrolling a new device for an existing user.
This document uses the following notation:
-
D: Device. The device that is being enrolled -
U: User. The already-registered user that is initiating this enrollment -
S: Server. The server, which has access to the user information
Unless otherwise stated, all connections are over TLS (i.e., HTTPS for HTTP connections, etc)
Note that, because of the nature of this messaging service, User Authentication is a subset of device enrollment; the user will only authenticate when enrolling (or re-enrolling) a device.
Before this protocol can be initiated, the user must first have registered an account on the server S. At a minimum, this registration produces the following side effects:
-
Sknows theU's ID (i.e., their handle) -
Salso knowsU's salted + hashed password.Sdoes NOT have access to the original password.
At this point, D is completely unknown to S. D does know how to contact the server (i.e., the server URL). D also has access to U's ID and plaintext password. Finally, D has an intrinsic property that can be used to uniquely identify it (but is not necessarily kept secret); in most cases, a MAC address would suffice.
In this document, any strings that are denoted as base-64 encoded are stored and used that way. For example, the salt is defined as base64-encoded; it is always used in this representation; calculating the password hash is
h(s, p)with the salt as a base-64 encoded string. When it is said to be 32-bytes or 16 bytes, this means the underlying data is that many bytes; the base-64 representation will likely be longer!
This step proceeds as follows:
-
Dsends aPOSTrequest to/api/deviceswith a JSON payload conforming to the following:
{
"handle": string;
"deviceID": string;
}-
handle: The ID of userU -
deviceID: The ID (see above) of the deviceD
-
Sresponds with a JSON payload conforming to the following format:
{
"salt": string;
"hashAlgorithm": HashAlgorithm;
"nonce": string;
}-
salt: The 32-byte salt used in the password hashing process, as a base64-encoded string. -
hashAlgorithm: The Hash Algorithm used to hash the password. This is an Enum; their values can be found at the end of this document. -
nonce: A 16-byte, base64-encoded string that represents a NONCE.
Note that, at this point, the existence of the user account is not known; if the user account does not exist, a random (but otherwise valid) salt is sent. However, the hash that results from this (i.e., in step 3) will never pass validation on the server side. This is done so that it is impossible to know if a user account actually exists.
-
Dcalculates its hash as follows. Suppose plaintext passwordp, salts, hashing algorithmh, device IDd, and noncen. Then, the hash is calculated by:hash <= h(h(s, p), d, n). -
Dsends aPUTrequest to/api/deviceswith the following payload:
{
"handle": string;
"deviceID": string;
"info"?:
{
"name"?: string;
"os"?: string;
"type"?: "mobile"|"tablet"|"desktop"|"other";
},
"hash": string;
}-
handleanddeviceIDare the same as before -
infois an optional field where the device can more fully describe itself; all fields are optional. -
hashis the hash calculated in the previous step, encoded as a base64 string.
Server S calculates this hash as well, using the nonce it previously sent to check that the hashes match. If they do NOT match, an HTTP 401 Unauthorized is sent back, and the operation is aborted. Otherwise, an HTTP 200 status code is sent back along with a new nonce, n2.
- At this point, the device and server now have a shared secret; namely, the following hash:
h(h(s, p), d, n2). The server stores this as a unique "Device Fingerprint", along with the device ID and optionally provided device information, tied to the user; the device also stores this fingerprint locally.
Notice that the nonce is discarded; if the server or the device loses the shared secret, the enrollment process must be repeated fully.
Thus, the user object could look something similar to this:
{
"handle": "JDoe",
"devices":
{
"device1ID":
{
"hash": "aef3232...",
"name": "My iPhone",
"os": "iOS 14.5.1",
"type": "mobile"
}
}
}For all future communications, the device can use this fingerprint as a "fast pass" to skip this process, providing the fingerprint, device ID, and handle.