_________ /````````_\ S N I F ~ e2e TLS trust for IoT /\ , / O\ ___ | | | \__|_____/ o\ e2e TLS SNI Forwarder | | | ``/`````\___/ e2e TLS CA Proxy | | | . | <"""""""~~ | \___/ `` \________/ https://snif.host \ ''' ``` /```````` (C) 2021 VESvault Corp \_________/ https://github.com/vesvault/snif
Jim Zubov <jz&vesvault.com> VESvault Corp.
This document specifies protocols for communications between SNIF Relay and other parties.
SNIF Relay is a process that runs on a publicly accessible server, normally on the same physical server as SNIF CA Proxy.
SNIF Connector is a process that runs on an IoT device, or on other type of device that provides TLS-based services through SNIF.
SNIF Client is any common TLS-compatible client, such as a web browser or an email client, that connects to a SNIF hostname provided by a specific SNIF Connector.
SNIF Peripheral Process is any kind of additional service that extends or supplements functions of SNIF, in a way not defined within the scope of this document.
Except for SNIF Client Connection, all protocols involve sending and receiving asynchronous SNIF Messages over a specific type of stream connection.
SNIF Control Connection Protocol defines communications between SNIF Relay and SNIF Connector that runs on an IoT device, or other type of device that provides TLS-based services through SNIF.
SNIF Service Connection Protocol defines secondary communications between SNIF Relay and SNIF Connector that include end-to-end TLS traffic forwarded by the Relay.
SNIF Client Connection Protocol defines TLS communications between SNIF Relay and a Client, where the Relay acts as a transparent end-to-end forwarder.
SNIF IPC FIFO Protocol defines communications between nodes of a SNIF Relay cluster, and/or between SNIF Relay and SNIF Peripheral Processes.
A SNIF Message consists of a 1 or more ASCII characters excluding special characters, terminated by <CR><LF>.
The total length of a SNIF Message, including the terminal <CR><LF>, SHOULD not exceed 4096 bytes.
8-bit characters are discouraged. If 8-bit characters are used, they should comply to UTF-8.
The receiving party SHOULD silently ignore any invalid or malformed SNIF message.
Protocol name: snif
Default port: TCP 7123
Connection from: SNIF Connector.
Connection to: SNIF Relay.
Versioning: Future versions of the protocol SHOULD send and/or receive specific SNIF Messages defined in those versions to negotiate certain additional features with the connection peer.
Security Considerations: All sensitive information is communicated over a TLS connection with a trusted certificate.
To be able to open a SNIF Control Connection, the SNIF Connector MUST have a valid trusted TLS/SSL certificate, the CN hostname DNS pointing to the SNIF Relay or a wildcard CN having a sub-host DNS pointing to the SNIF Relay, and a Private Key that matches the Certificate. Normally, the SNIF Connector will generate the Private Key and use SNIF CA Proxy Protocol to obtain and maintain the Certificate, although other means can be used.
To initiate the Control Connection, the SNIF Connector opens a TCP connection to the hostname matching the Certificate's CN, that points to the Relay.
The SNIF Relay accepts the incoming TCP connection, and initiates a reversed TLS session as a client.
The SNIF Connector initiates the TLS as a server, using the Certificate and the Private Key.
Upon successful TLS negotiation, the SNIF Relay validates the SNIF Connector's certificate. If the certificate is not trusted, the SNIF Relay MUST shut down the TLS session and the TCP socket immediately.
If the certificate is accepted, both SNIF Relay and SNIF Connector are ready to accept SNIF messages from each other over the TLS connection, as following.
SNIF LISTEN {hostname}
Sent by: SNIF Connector
The SNIF LISTEN message informs the Relay that the Connector is ready to accept incoming TLS connections to {hostname} through the Relay.
{hostname} MUST specify a single host (no wildcards), and MUST match the CN of the Connector's TLS certificate – either match a wildcard CN, or exactly match a single host CN.
The SNIF LISTEN message SHOULD be send only once per the Control Connection. The Relay SHOULD ignore any invalid or subsequent SNIF LISTEN messages.
SNIF CONNECT {conn_id} {dst_host}:{dst_port} {fwd_host}:{fwd_port} {cln_addr}:{cln_port}
Sent by: SNIF Relay
The SNIF CONNECT message informs the Connector of an incoming TLS connection from a Client to the Connector's {dst_host}, TCP port {dst_port}.
{conn_id} is a unique alphanumeric connection identifier assigned by the Relay, {cln_addr}:{cln_port} are the Client's remote IPv4/IPv6 address and TCP port, {cln_addr} is supplied in [brackets].
The Relay sends the SNIF CONNECT message to Connectors with {dst_host} matching the {hostname} the Connector is listening to. The Connector doesn't need to verify {dst_host}.
If the Connector decides to accept the connection – it MUST launch a SNIF Service Connection to {fwd_host}:{fwd_port}. It also SHOULD send any SNIF message back to the Relay over the Control Connection to update the keep-alive timer, a copy of the SNIF ACCEPT message that is sent over the Service Connection can be used.
In case of a rejection – the Connector SHOULD send SNIF CLOSE with matching {conn_id}.
SNIF CLOSE {conn_id}
Sent by: SNIF Connector
The SNIF CLOSE message instructs the Relay to terminate the Client connection with matching {conn_id}.
For SNIF CLOSE received from a Connector, the Relay SHOULD validate that the connection was targeted at the Connector's {hostname}, otherwise ignore the message.
SNIF ABUSE {conn_id} {abuse_score}
Sent by: SNIF Connector
The SNIF ABUSE message instructs the Relay to increase the DoS protection abuse counter for the Client that initiated the connection {conn_id} by {abuse score}.
{abuse score} SHOULD be an integer from 1 to 255, 1 is the score for a normal non-abusive connection.
For SNIF ABUSE received from a Connector, the Relay SHOULD validate that the connection was targeted at the Connector's {hostname}, otherwise ignore the message.
SNIF MSG {hostname} {content}
Sent by: SNIF Connector or SNIF Relay
The SNIF MSG message is relayed between the Connector and the SNIF Peripheral Processes attached to the Relay.
{content} SHOULD NOT contain whitespaces or special characters. Its semantics is specific to the targeted Peripheral Process, and is not covered by this document.
For SNIF MSG received by the Relay from a Connector, the Relay SHOULD verify that the {hostname} matches the one associated with the Connector, forward the message to all IPC FIFOs if matched, ignore otherwise.
For SNIF MSG received by the Relay from an IPC FIFO, the Relay SHOULD forward the message to the Connector(s) with the matching {hostname}, ignore the message if none are found.
Note that in certain uncommon circumstances a SNIF MSG send by a Connector might come back to the Connector through a different Control Connection. The Connector SHOULD be aware of this fact to avoid a potential message storm.
NOOP
Sent by: SNIF Connector or SNIF Relay
The NOOP message is not associated with any explicit action, except that the Relay receiving NOOP from the connector SHOULD promply send NOOP or any other message back to the Connector. Therefore, the Connector may use NOOP as a keep-alive ping.
Protocol name: snif-srv
Default port: TCP 7120 (unofficial)
Connection from: SNIF Connector.
Connection to: SNIF Relay.
Versioning: Future versions of the snif control connection protocol may define additional features and/or replacements for this protocol.
Security Considerations: A randomly generated {conn_id} is transmitted over an unsecure TCP connection. Except if used over a trusted SNIF IPC FIFO, the {conn_id} can be used only once to accept the Client's TLS connection, which in turn can only be successfully negotiated by the targeted SNIF Connector. All further communications are comprised of end-to-end encrypted TLS traffic. The security of the TLS encrypted content between the Client and the Connector is specific to the protocols involved, and cannot be assessed within the scope of this document.
The SNIF Connector opens a TCP connection to the {fwd_host}:{fwd_port} in response to a SNIF CONNECT message received from the Relay over the Control Connection.
The Connector MUST immediately send a SNIF ACCEPT message over the Service Connection as a plain TCP:
SNIF ACCEPT {conn_id}
The {conn_id} is the one that was received in the SNIF CONNECT message over the Control Connection.
If the Relay decides to reject the connection, either because of invalid message or {conn_id}, or because of reaching the abuse threshold – the Relay SHOULD terminate the TCP connection immediately.
Otherwise, the Relay SHOULD link the Service Connection to the matched Client Connection, forward to the Service Connection all buffered TLS data previously received from the Client, and start bi-directional forwarding between the Client Connection and the Service Connection.
When either Client or Service Connection is shut down, or an inactivity timeout is reached, the Relay SHOULD shut down both the Client Connection and the Service Connection.
Once the Relay has linked the Client Connection matching the {conn_id} to the Service Connection, any further SNIF ACCEPT messages with the same {conn_id} on other Service Connections MUST be rejected.
Protocol name: snif-cln
Default port: N/A
Connection from: Any TLS enabled software, such as a web browser or an email client.
Connection to: SNIF Relay.
Versioning: Future versions of the protocol may support new TLS versions and features, and may specify certain alterations to the forwarded traffic as long as it's appropriate for end-to-end encrypted data.
Security Considerations: The Client Connection is a TLS session with a trusted certificate. The security of the TLS encrypted content between the Client and the Connector is specific to the protocols involved, and cannot be assessed within the scope of this document.
From the Client's perspective, a SNIF Client Connection functions as a direct TLS connection to the IoT Device.
The ports the Relay is listening to, can be any well-known ports for services with persistent TLS, such as https or imaps, or can be any custom ports agreed among the Relay, the Connectors and the Clients.
The Relay accepts an incoming TCP connection, receives and buffers the incoming initial data from the client, and attempts to interpret the received data as a TLS handshake.
If the received data is not recognized as a TLS handshake, does not contain an SNI record in a supported format, or the SNI hostname does not meet rules defined for the Relay – the Relay SHOULD immediately reject the TLS session with an appropriate error status, and shut down the Client Connection.
If the SNI hostname is found acceptable – the Relay allocates a unique {conn_id}, checks if there are current Control Connections that match the SNI hostname, and sends a SNIF CONNECT message over those connections.
If there are no active applicable Control Connections, or if the Relay doesn't receive a response from a SNIF Connector within a specified timeframe – the Relay SHOULD forward the same SNIF CONNECT message over IPC FIFOs (if any are open) to alert cluster peer Relays and Peripheral processes of the incoming Client Connection.
A Service Connection with a matching SNIF ACCEPT establishes an end-to-end TLS circuit with the Client Connection. Once established, the Relay bi-directionally forwards all traffic between the Client and the Service Connection until either of the connections is closed or is timed out due to inactivity.
Upon receiving a matching SNIF CLOSE – the Relay MUST terminate the Client Connection. If a Service Connection has already been linked it MUST be terminated too, otherwise the Relay SHOULD attempt to gracefully reject TLS on the Client Connection with an appropriate status prior to shutting down TCP.
Protocol name: snif-fifo
Default port: N/A
Connection from: SNIF Relay or SNIF Peripheral Service.
Connection to: SNIF Relay or SNIF Peripheral Service.
Versioning: Future versions of the protocol SHOULD send and/or receive specific SNIF Messages defined in those versions to negotiate certain additional features with the connection peer.
Security Considerations: SNIF IPC FIFO connections should only be established between mutually trusted parties, and need to be secured by external means specific to the implementation, such as filesystem permissions, TLS or SSH tunnels etc. The security of such external means cannot be assessed within the scope of this document.
SNIF IPC FIFO is a permanent trusted connection between the SNIF Relay and a SNIF Peripheral Process, or between a pair of nodes in a SNIF Relay cluster. An IPC FIFO is usually unidirectional, but a bidirectional connection can serve as a pair of FIFOs. An IPC FIFO can be implemented as a Unix FIFO pipe, a TCP socket, an SSH tunnel or by other means. The mechanism of establishing and maintaining IPC FIFOs is implementation specific and is not covered by this document.
The following SNIF messages are defined over an IPC FIFO from the perspective of a SNIF Relay:
SNIF CONNECT {conn_id} {dst_host}:{dst_port} {fwd_host}:{fwd_port} {cln_addr}:{cln_port}
Direction: Send or Receive
(see SNIF Control Connection).
The SNIF CONNECT message is sent by a Relay over an IPC FIFO in case if the Relay failed to reach the respective Connector through Control Connections. When sent by a Relay, SNIF CONNECT must be followed up by one of SNIF CLEAR or SNIF CLOSE to inform the Peripheral Processes of the further outcome.
When a SNIF CONNECT message is received by a Relay, the Relay should forward it to any matching open Control Connections, or ignore it otherwise.
SNIF CLEAR {conn_id}
Direction: Send
The SNIF CLEAR message should be sent by a Relay only as a followup to SNIF CONNECT with a matching {conn_id}, in case if the Client Connection that triggered SNIF CONNECT was accepted by a Service Connection.
The purpose of SNIF CLEAR is to advice Peripheral Processes to cease further attempts of reaching the Connector by external means, not specified within this document.
SNIF CLOSE {conn_id}
Direction: Send or Receive
(see SNIF Control Connection).
The SNIF CLOSE message should be sent by a Relay only as a followup to SNIF CONNECT with a matching {conn_id}, in case if the Client Connection that triggered SNIF CONNECT was closed without being accepted.
When the SNIF CLOSE is received by a Relay, the Relay should immediately close the matching Client and/or Service Connection if any found, ignore the message otherwise.
SNIF ABUSE {conn_id} {abuse_score}
Direction: Receive
(see SNIF Control Connection).
SNIF MSG {hostname} {content}
Direction: Send or Receive
(see SNIF Control Connection).
SNIF CTL {ctl_fd} {hostname} {remote_addr}:{remote_port} SNIF CTL {ctl_fd}
Direction: Send
The SNIF CTL message is sent by a Relay to inform Peripheral Processes about Control Connections. The first version is sent for each opening Control Connection, and is followed up by the second version with the matching {ctl_fd} when the Control Connection is closed. {ctl_fd} is a numeric descriptor which is unique for open connections, but can be reused after a connection is closed.