Created API Protocol (markdown)

Moxie Marlinspike 2013-12-08 23:12:08 -08:00
parent db06e91df2
commit c1fa8ffbcb
1 changed files with 356 additions and 0 deletions

356
API-Protocol.md Normal file

@ -0,0 +1,356 @@
# Registration
## Request a verification code
```
GET /v1/accounts/{transport}/code/{number}
```
The client requests an SMS or Voice verification code for the client's PSTN number.
1. `transport` is the string `sms` or `voice`, depending on how the client would like a verification code delivered.
1. `number` is the client's PSTN number.
**Returns**:
1. `200` request was processed successfully.
1. `400` badly formatted `number`.
1. `415` invalid `transport`.
1. `413` rate limit exceeded. Too many requests.
## Confirm a verification code
```
PUT /v1/acccounts/code/{verification_code}
Authorization: Basic {basic_auth}
{
"signalingKey" : "{bas64_encoded_52_byte_key}"
"supportsSms" : false
}
```
The client submits the verification code it received via voice or SMS to the server for confirmation.
1. `verification_code` is the code it received via voice or SMS, numeric only.
1. `basic_auth` are the authorization credentials the client would like to create. These are in the form of `Base64({number}:{password})`, where `number` is the client's verified PSTN number and `password` is a randomly generated 16 byte string.
1. `signalingKey` is a randomly generated 32 byte AES key and a 20 byte HMAC-SHA1 MAC key, concatenated together and Base64 encoded.
1. `supportsSms` indicates whether a client supports SMS as a transport.
**Returns**:
1. `200` account successfully verified.
1. `401` badly formatted `basic_auth`.
1. `403` incorrect `verification_code`.
1. `413` rate limit exceeded.
## Registering an APN or GCM id
```
PUT /v1/accounts/apn/
Authorization: Basic {basic_auth}
{
apnRegistrationId: "{apn_registration_id}"
}
```
or
```
PUT /v1/accounts/gcm/
Authorization: Basic {basic_auth}
{
gcmRegistrationId: "{gcm_registration_id}"
}
```
The client submits its APN or GCM push registration ID.
1. `basic_auth` is the client's authorization credentials (see above).
1. `gcm_reistration_id` or `apn_registration_id` is the client's registration ID.
**Returns**:
1. `200` request succeeded.
1. `401` invalid authentication credentials.
1. `415` badly formatted JSON.
## Registering prekeys
```
PUT /v1/keys/
Authorization: Basic {basic_auth}
{
lastResortKey : {
keyId: 0xFFFFFF
publicKey: "{public_key}"
identityKey: "{identity_key}"
},
keys: [
{
keyId: {key_id},
publicKey: "{public_key}",
identityKey: "{public_key}"
},
...]
}
```
1. `public_key` is a randomly generated Curve25519 public key with a leading byte of `0x05` to indicate its type. This is a total of 33 bytes, base64 encoded without padding (no ==).
1. `identity_key` is a Curve25519 public key with a leading byte of `0x05` to indicate its type. This is a total of 33 bytes, base64 encoded without padding (no ==). Each client should have a single identity key generated at install time.
1. `key_id` each prekey has a unique 24bit identifier. The last resort key is always 0xFFFFFF.
**Returns**:
1. `200` request succeeded.
1. `401` invalid authentication credentials.
1. `415` badly formatted JSON.
## Getting a contact intersection
```
PUT /v1/directory/tokens
Authorization: Basic {basic_auth}
{
"contacts": [{"{token}", "{token}", ..., "{token}"]
}
```
1. `token` is Base64(SHA1(E164number)[0:10]) without Base64 padding.
**Returns**:
1. `400` badly formatted token(s).
1. `401` invalid authentication credentials.
1. `415` badly formatted JSON.
1. `200` request succeeded. The structure below is returned.
```
{
contacts: [{token="{token}", relay="{relay}", supportsSms="true"},
{token="{token}"},
...,
{token="tokenN", relay="{relay}"}]
}
```
1. `token` is Base64(SHA1(E164number)[0:10]) without Base64 padding.
1. `relay` is the name of a federated node which this contact is associated with.
1. `supportsSms` indicates that the contact supports the SMS transport.
At this point the client should be fully registered.
# Sending Messages
## Message Format
Messages bodies sent and received by clients are a protocol buffer structure:
```
message PushMessageContent {
optional string body = 1;
message AttachmentPointer {
optional fixed64 id = 1;
optional string contentType = 2;
optional bytes key = 3;
}
repeated AttachmentPointer attachments = 2;
}
```
## Getting a recipient's PreKey
If a client does not have an existing session with a recipient, the client will need to retrieve a PreKey for the recipient in order to start one.
```
GET /v1/keys/{number}?relay={relay}
Authorization: Basic {basic_auth}
```
1. `number` is the PSTN number of the recipient.
1. `relay` (optional) is the federated relay the recipient is associated with. The `relay` param should only be included if the destination is at a federated node other than the sender.
**Returns**:
1. `401` invalid authentication credentials.
1. `413` rate limit exceeded.
1. `404` unknown/unregistered `number`.
1. `200` request succeeded. The structure below is returned.
```
{
keyId: {key_id},
publicKey: "{public_key}",
identityKey: "{public_key}"
}
```
## Submitting a message
```
POST /v1/messages/
Authorization Basic {basic_auth}
{
messages: [{
type: {type},
destination: "{destination_number}",
body: "{base64_encoded_message_body}", // Encrypted PushMessageContent
relay: "{relay}",
timestamp: "{time_sent_millis_since_epoc}"
},
...,
]
}
```
1. `type` is the type of message. Supported types are enumerated below.
1. `destination_number` is the PSTN number of the message recipient.
1. `body` is the Base64 encoded (without padding) and encrypted `PushMessageContent` (above).
1. `relay` (optional) is the relay the message recipient is registered with.
1. `timestamp_sent_millis_since_epoch` is the timestamp of the message in millis since the epoch.
**Returns**:
1. `401` invalid authentication credentials.
1. `413` rate limit exceeded.
1. `415` badly formatted JSON.
1. `200` request succeeded. The structure below is returned.
```
{
"success" : [{destination_number}, {destination_number}, ..., {destination_number}],
"failure" : [{destination_number},...,{destination_number}]
}
```
Supported types:
```
int TYPE_MESSAGE_PLAINTEXT = 0;
int TYPE_MESSAGE_CIPHERTEXT = 1;
int TYPE_MESSAGE_PREKEY_BUNDLE = 3;
```
## Receiving a message
APN clients will receive a push notification:
```
{
alert: "You have a new message!",
"m": "{payload}"
}
```
GCM clients will receive a push notification:
```
{payload}
```
1. `payload` is a Base64 encoded (without padding) `IncomingPushMessageSignal`, which is encrypted and MAC'd using the `signalingKey` submitted during registration.
Encrypted IncomingPushMessageSignal format:
```
struct {
opaque version[1];
opaque iv[16];
opaque ciphertext[...]; // The IncomingPushMessageSignal
opaque mac[10];
```
The IncomingPushMessageSignal protocol buffer:
```
message OutgoingMessageSignal {
optional uint32 type = 1;
optional string source = 2;
optional string relay = 3;
repeated string destinations = 4;
optional uint64 timestamp = 5;
optional bytes message = 6; // Encrypted PushMessageContent (above)
}
```
# Attachments
Recall that a push message is transmitted as the following structure:
```
message PushMessageContent {
optional string body = 1;
message AttachmentPointer {
optional fixed64 id = 1;
optional string contentType = 2;
optional bytes key = 3;
}
repeated AttachmentPointer attachments = 2;
}
```
To fill out the `AttachmentPointer` structure, the client takes the following steps:
1. Generates a single-use 32 byte AES key and 32 byte Hmac-SHA256 key.
1. Encrypts the attachment using AES in CBC mode with PKCS#5 padding and a random IV, then formats the encrypted blob as `IV || Ciphertext || MAC`.
1. Requests an attachment allocation from the server.
1. Uploads the attachment to the allocation.
1. Constructs the `AttachmentPointer` with the attachment allocation `id`, the attachment's MIME `contentType`, and the concatenated 32 byte AES and 32 byte Hmac-SHA256 `key`.
## Allocating an attachment
```
GET /v1/attachments/
Authorization: {basic_auth}
```
**Returns**:
1. `401` invalid authentication credentials.
1. `413` rate limit exceeded.
1. `200` request succeeded. The structure below is returned.
```
{
"id" : "{attachment_id}",
"location" : "{attachment_url}"
}
```
## Uploading an attachment
```
PUT {attachment_url}
Content-Type: application/octet-stream
```
The client `PUT`s the encrypted binary blob to the `attachment_url` returned from the attachment allocation step.
## Retrieving an attachment
```
GET /v1/attachments/{attachment_id}
Authorization: {basic_auth}
```
1. `attachment_id` is the `id` in a received `AttachmentPointer` protocol buffer.
**Returns**
1. `401` invalid authentication credentials.
1. `413` rate limit exceeded.
1. `200` request succeeded. The structure below is returned.
```
{
"location" : "{attachment_url}"
}
```
The client can now `GET {attachment_url}` to retrieve the encrypted binary blob.