Phidget22 Network Protocol

From Phidgets Support
Revision as of 16:01, 26 July 2017 by Chad (talk | contribs) (→‎AuthS1)

Introduction

The Phidget22 Network Protocol is primarily JSON based with a binary header that describes the contents of the JSON.

Header

The network request header is a union of a NR_HEADERLEN byte array and the members of the netreq structure. The values are not marshalled in C (except on big endian), and must be handled correctly by light clients.

The header contains a four byte magic, four byte length, two byte flags, two byte request sequence number, two byte reply sequence number, one byte type and a one byte sub-type.

Header Members

Member Size Description
magic 4 used to identify the header and to ensure stream alignment 0x50484930
len 4 indicates the payload length NR_MAXDATALEN
flags 2 flags
NRF_REQUEST 0x0001 The payload is a request
NRF_REPLY 0x0002 The payload is a reply
NRF_EVENT 0x0004 The payload is an event
NRF_USERMASK 0x0F00 Bits reserved for applications
0xF0F8 - Reserved and must not be set
reqseq 2 Request sequence number. Ignored for replies and events.
repseq 2 Reply sequence number (the reqseq the reply is for). Used to route replies to async requests.
type 1 Indicates the packet type, and what the payload should contain
stype 1 Packet sub-type. Further describes the type.

Packet Types

MSG_CONNECT 10 Connection control packet SMSG_AUTHC0 || 10 || Begin authentication request
SMSG_CLOSECONN 1 Close the connection
SMSG_HANDSHAKEC0 10 Connection establishment request
SMSG_HANDSHAKES0 10 Connection establishment reply
SMSG_AUTHS0 10 Begin authentication reply
SMSG_AUTHC1 10 Challenge Response
SMSG_AUTHS1 10 Challenge Response reply
SMSG_DGRAMSTART 20 Data Gram event negotiation
SMSG_DGRAMSTARTOK 21 Data Gram event negotiation reply
MSG_COMMAND 20 Command packet
SMSG_REPLY 40 Request reply
SMSG_KEEPALIVE 41 Keep-alive request
MSG_DEVICE 30 Device or Channel packet
SMSG_DEVATTACH 50 Device was added
SMSG_DEVDETACH 55 Device was removed
SMSG_DEVOPEN 60 Open Device
SMSG_DEVCLOSE 65 Close Device
SMSG_DEVBRIDGEPKT 70 Device specific packet
SMSG_DEVCHANNEL 80 Device channel information (for www clients)

Connection

A connection begins with the client opening a TCP/IP connection to the server and sending the initial packet.

HandShakeC0

The identification packet is MSG_CONNECT.SMSG_HANDSHAKEC0. The playload contains at least the keys type, pmajor, and pminor.

type string the type of the server
pmajor int the major protocol version supported by the client
pminor int the minor protocol version supported by the client
dgram bool Optional if 1 datagram is supported by the client
port int Optional if dgram is true, the UDP port the client is listening on

If type begins with "www", the server will send SMSG_DEVCHANNEL messages to the client; otherwise, the server assumes the client is aware of channels belonging to specific devices.

 HDR(REQUEST, MSG_CONNECT, MSG_HANDSHAKEC0) {
   type: '[www],clienttype',
   pmajor: 2,
   pminor: 1,
   dgram: 1,
   port: <UDP port number>
 }

HandShakeS0

The server will reply to MSG_CONNECT.SMSG_HANDSHAKEC0 with MSG_CONNECT.SMSG_HANDSHAKES0. The payload must contain at least type, pmajor, pminor and result.

string | identifies the server type
int | the major protocol version supported by the server
int | the minor protocol version supported by the server
int | result code from the SMSG_HANDSHAKEC0 request

result indicates success or failure of the client handshake request, and will be zero if successful. If result is not zero, the server has rejected the request, and the socket will have been closed.

HDR(REQUEST, MSG_CONNECT, MSG_HANDSHAKES0) {
   type: PHIDGET_NET_PROTOCOL, // phid22device
   pmajor: 2,
   pminor: 1,
   result: 0
}

AuthC0

Once the handshake has completed, authentication begins. The client begins by sending MSG_CONNECT.SMSG_AUTHC0 with a payload containing ident and nonceC.

ident string must be phidgetclient
nonceC string(15) random client nonce

nonceC is a 15 byte random value. Typical implementations generate a random array of bytes, calculate the base64 of those bytes and send the first 15 bytes of the base64.

HDR(REQUEST, MSG_CONNECT, MSG_AUTHC0) {
   ident: 'phidgetclient',
   nonceC: '0123456789abcde'
}

AuthS0

The server handles a SMSG_AUTHC0 request by validating the 'ident', and then sending a MSG_CONNECT.SMSG_AUTHS0 command. The payload will contain srvname, nonceC, nonceS, salt, count, and result.

srvname string the name of the server
nonceC string(15) the nonce send to the server by the client
nonceS string(15) random server nonce
salt string(15) random server generated salt
count int the number of sha256 rounds (currently 1)
result int the result code for the SMSG_AUTHC0 request

If the server failed to handle the clients SMSG_AUTHC0 request, no response will be sent, and the server will close the connection.

HDR(REQUEST, MSG_CONNECT, MSG_AUTHS0) {
   srvname: 'srvname',
   nonceC: '0123456789abcde',
   nonceS: 'edcba9876543210',
   salt: 'randomsalt00000',
   count: 1,
   result: 0
}

AuthC1

The client handles the SMSG_AUTHS0 reply by first validating that the nonceC value in the playload matches the nonceC value that was sent, and that the result value is zero. If validation is not successful, the client must close the connection.

A challenge response is calculated on the client by building a string containing the protocol ident, any password, nonceC, nonceS and salt.

challenge = ('phidgetclient' + <passwd> + <nonceC> + <nonceS> + <salt>)

The resulting challenge string must be SHA256 hashed count times, and base64 encoded.

The client sends a MSG_CONNECT.SMSG_AUTHC1 request with the playload nonceC, nonceS, and proof. nonceC must be the nonceC value from the original SMSG_AUTHC0 request, and nonceS must be the nonceS value received in the SMSG_AUTHS0 request. proof is the full length base64 encoded challenge string.

HDR(REQUEST, MSG_CONNECT, MSG_AUTHC1) {
   nonceC: '0123456789abcde',
   nonceS: 'edcba9876543210',
   proof: '<base64 challenge response>'
}

AuthS1

The server handles the SMSG_AUTHC1 request by first validating the nonceC and nonceS values, and then by validating the challenge response. If validation is successful, a reply packet is sent with a result of zero. If validation is not successful, a reply packet is sent with a result code of EPHIDGET_ACCESS.

Note that the password used to calculate the challange and response is never transferred, and must be previously known by both the client and the server. If no password is required, it must be a zero length string.

HDR(REPLY, MSG_COMMAND, SMSG_REPLY) {
   E: <result code>
}

Completion

Once authentication is complete, the server will begin delivering events to the client, and the client may begin sending commands to the server.