User Tools

Site Tools


pawsd:protocol

This is an old revision of the document!


Protocol

This document is still a draft, and is subject to change at any time!

The PawSD protocol is designed around a simple request-response architecture that allows it to work over a variety of underlying transports. All a transport has to provide is a way for a client to send some bytes to a server and for the server to send some bytes back in response. It is imperative to choose transports that provide some form of data integrity, i.e. preventing malicious third parties from modifying data in-transit between the client and server.

Unless otherwise specified, the protocol uses big-endian byte and bit order, and no padding.

Within this document, integers are described in a shorthand format: a letter “u” for unsigned or “s” for signed, followed by their length in bits. “Enums” are unsigned integers that take one of a defined set of values. Arrays are indicated by prefixing their item type with the number of items in square brackets, or an underscore if it's variable: [16]u8 means 16 arbitrary bytes and [_]record means a number of records specified by a previous field.

Requests and responses

A request is structured as follows:

Field Length Type
request magic 8 bytes constant ASCII string “PawRqust”
protocol version 2 bytes u16 (current version is 1)
request verb 2 bytes enum
request payload varies according to verb

And a response looks like this:

Field Length Type
response magic 8 bytes constant ASCII string “PawRspns”
protocol version 2 bytes u16 (current version is 1)
status code 2 bytes enum
response payload varies according to status code

For all status codes except “OK”, the response payload is a string (2 byte length prefix, UTF-8, no null terminator) describing the error in a manner useful to client developers. Friendly user interfaces are expected to provide their own localised descriptions of errors, but may choose to also show the server's description.

Status codes

The currently defined status codes for responses are (in hexadecimal):

  • 0x0200: OK
  • 0x0400: generic client error
  • 0x0401–0x0403: TODO
  • 0x0404: resource not found
  • 0x0500: generic server error
  • 0x0501: not implemented
  • 0x0503: service temporarily unavailable
  • 0x0505: unknown verb

Zones, services and records

Zones are purely logical and are not literally sent over the wire. However, services are identified by the combination of their containing zone's public key (and its type/cryptosystem) along with their index within the zone (starting from 0 for the “metadata service” containing info about the zone itself).

Services are transmitted as follows:

Field Length Type
signature length 2 bytes u16
signature varies [_]u8
index 2 bytes u16
flags 4 bytes bitfield
record count 2 bytes u16
records varies [_]record

The signature is calculated from the concatenation of the index, flags, record count, and records fields (i.e. the entire service in wire format except for the signature itself). The signature algorithm is not given in the service itself but will be specified as part of the service's identifier, such as when requesting it.

Records are just a list of tag-value pairs:

Field Length Type
tag count 2 bytes u16
tag1 16 bytes [2]u64
value1 length 4 bytes u32
value1 varies [_]u8
tag2, etc

Signature algorithms

The only currently defined signature algorithm (or “public key type”) is Ed25519 (identified on the wire by u16 “25519”). All implementations are required to support it, and shouldn't implement any other algorithms except for testing purposes. This is the “pure” variant usually called ed25519 in crypto libraries, not “pre-hashed” (ed25519ph).

Verb 0: Echo

This is intended for troubleshooting purposes only. The server simply returns the same data back to the client.

Request and response payloads (identical):

Field Length Type
data 16 bytes [16]u8

Verb 1: Fetch service

The client asks the server for a particular service. Even if the service exists, the server may not have it, in which case it should respond “resource not found” (and should not perform any lookups of its own to try to find it).

Request payload:

Field Length Type
public key type 2 bytes enum
public key length 2 bytes u16
public key varies [_]u8
service index 2 bytes u16

Design note: although the length of the public key is implicitly given by the key type field (e.g. an ed25519 key will always be 32 bytes long), we still explicitly state its length, so that implementations that don't support a given key type can still parse the request properly, even if just to show a more useful error message.

Response payload:

Field Length Type
service varies service

TODO: other verbs!

Verb 4096 (0x1000): Start authentication

The client briefly identifies itself using a “client ID”, which is an arbitrary byte sequence that needs to uniquely but persistently identify the client. For example, it could be some hash of the concatenation of: the client's implementation name, a random number saved on the client's storage, and some information about the server such as its IP address (to prevent cross-server tracking). The client ID allows the server to keep track of the authentication session across subsequent requests. The client also asks for access to a particular set of scopes.

Request payload:

Field Length Type
client ID 16 bytes [16]u8
scopes ??? TODO

The server then returns either a “challenge set”, or an auth token for the given scopes. The response payload therefore is:

Field Length Type
completed? 1 byte boolean
token or challenges varies [32]u8 or challenges

If “completed?” is true (1), the “token or challenges” field will be:

Field Length Type
conjunction 1 byte enum (0 = or, 1 = and)
challenge count 1 byte u8 (≥ 1)
challenge1 ID 16 bytes [2]u64
challenge1 data length 4 bytes u32
challenge1 data varies [_]u8
challenge2 ID, etc

If the conjunction is “or”, the client may choose any one of the contained challenges to solve; if it's “and”, the client has to solve all of them. If the challenge count is 1, the conjunction is irrelevant. Consequently the client needs to send its challenge response(s) using the Continue authentication verb as follows.

Challenges

The structure of the “challenge data” and “response” fields are defined by each individual challenge. There is a non-exhaustive list of known challenges.

Verb 4097 (0x1001): Continue authentication

The client sends one or multiple responses to challenges previously given by the server. (Note confusing terminology: in this case the “responses” are responses in the sense of a challenge-response exchange, but they are sent as part of the request payload in the protocol.)

Request payload:

Field Length Type
client ID 16 bytes [16]u8
response count 1 byte u8
challenge1 ID 16 bytes [2]u64
response1 length 4 bytes u32
response1 varies [_]u8
challenge2 ID, etc

The response payload is identical to the Start authentication verb.

pawsd/protocol.1770832747.txt.gz · Last modified: by winter