Internet-Draft SNIF June 2026
Zubov Expires 31 December 2026 [Page]
Workgroup:
Network Working Group
Internet-Draft:
draft-zubov-snif-05
Published:
Intended Status:
Experimental
Expires:
Author:
J. Zubov
VESvault Corp

Deploying Publicly Trusted TLS Servers on Devices Behind NAT Using SNI-based End-to-End TLS Forwarding (SNIF)

Abstract

This document proposes a solution, referred to as SNIF, that provides the means for any Internet-connected device to:

The private key associated with the X.509 certificate is securely stored on the TLS terminating device, and is never exposed to any other party at any step of the process.

About This Document

This note is to be removed before publishing as an RFC.

Status information for this document may be found at https://datatracker.ietf.org/doc/draft-zubov-snif.

Information can be found at https://snif.host.

Source for this draft and an issue tracker can be found at https://github.com/vesvault/snif-i-d.

Status of This Memo

This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.

Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.

Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."

This Internet-Draft will expire on 31 December 2026.

Table of Contents

1. Introduction

Many Internet-connected devices and services operate behind NAT or on a dynamic IP address, and therefore cannot be reached by inbound connections over the Internet: they have no stable, publicly routable address at which a TLS client can establish a connection to them. An Internet-of-Things (IoT) device is a common example, but the same constraint applies to a wide range of physical and virtual hosts. A dedicated relay is commonly used to route the communications between such a device and its intended users. While all communications are recommended to be TLS encrypted, if the relay terminates each TLS connection - as a conventional reverse proxy does - it gains access to the unencrypted traffic between the devices and user clients, which may pose an undesirable security risk.

Designing a dedicated relay that works in end-to-end encrypted mode, where the TLS tunnel is established between the device and the client, and is passed by the relay in an encrypted form, raises additional challenges. Clients expect to be able to verify the authenticity of the TLS certificate presented by the device they are connecting to. Public certificate authorities require validation of the ownership of the hostname the certificate is being requested for, using certain challenge mechanisms. Therefore, the device needs to allocate a unique hostname, and to be able to complete the CA challenge in order to acquire a trusted certificate.

Alternatively, the client may decide to use a different certificate trust scheme, not based on publicly trusted root CAs. In this case, the client is limited to specifically built software with custom trust rules, or the system trust root on the client device needs to be customized.

This document proposes a solution, referred to as SNIF, that allows any common TLS client with standard root CAs, such as a web browser, to establish a trusted end-to-end TLS connection with a device behind NAT using the unique hostname permanently allocated to the device, via a dedicated relay.

IoT devices are a common motivating case, but SNIF is applicable to any physical or virtual device, service, or software that is behind NAT, on a dynamic address, or otherwise unable to accept inbound connections directly, and that can benefit from accepting trusted TLS connections to an anonymous hostname.

1.1. Notational Conventions

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.

2. Overview

SNIF CA Proxy is a combination of web-based services and background processes that run on a publicly accessible server, normally on the same physical server as SNIF Relay. SNIF CA Proxy allocates hostnames for SNIF Connectors and facilitates issuing and renewing X.509 certificates [RFC5280] without having access to the Connectors' private keys. The functions of SNIF CA Proxy are described in Section 3.

SNIF Relay is a process that runs on a publicly accessible server, normally on the same physical server as SNIF CA Proxy. SNIF Relay facilitates end-to-end TLS connections, [RFC8446] or older versions, between SNIF Clients and SNIF Connectors. The functions of SNIF Relay are described in Section 4.

SNIF Connector is a software process that runs on a device behind NAT, or on any other type of device or host that intends to provide TLS-based services that can be accessed by general purpose TLS clients using SNIF Relay. SNIF Connector can be implemented as a standalone process that communicates with the TLS server processes over local filesystem and sockets, or as an integral part of a TLS server process.

SNIF Client is any common TLS-compatible client with SNI capability [RFC6066], such as a web browser or an email client, that connects to a SNIF hostname provided by a specific SNIF Connector. SNIF Client does not need any awareness of SNIF, or of any protocols described in this document.

Certificate Authority (CA) is a service that issues public trusted TLS Certificates to specific hostnames when requested by the hostname owner, upon validating the ownership of the hostname. CA does not need any awareness of SNIF, except for a working relationship with the SNIF CA Proxy that requests certificates using protocols supported by the CA.

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.

3. SNIF CA Proxy Protocol

SNIF CA Proxy Protocol is designed for securely acquiring and maintaining a publicly trusted TLS/SSL X.509 certificate issued by a Certificate Authority to a uniquely allocated hostname, by an agent that has no direct control over that hostname, or over a server the hostname is pointing to.

SNIF CA Proxy accepts requests from SNIF Connectors via HTTP / HTTPS.

SNIF CA Proxy interacts with the CA using protocols supported by the CA, such as ACME [RFC8555], not covered by this document.

3.1. Protocol Variables

Each SNIF Connector MUST be configured with an initiation URL ({initUrl}), which is specific to the SNIF CA Proxy server the Connector intends to work with. Depending on the CA Proxy rules, {initUrl} might be unique for each Connector, or common for multiple Connectors.

The canonical name {cn} is received by a SNIF Connector in response to the CN Allocation Request (Section 3.3), and might be either a single hostname or a wildcard starting with "*.", depending on the CA Proxy rules.

{cn_host} is a hostname derived from the {cn} - it is identical to {cn} in case of a single-host CN, or is the {cn} with truncated initial "*." in case of a wildcard CN. Note that {cn_host} is different than the SNIF hostname in case of a wildcard CN.

Each SNIF Connector MAY be configured with an API URL base - {apiUrl} - identifying the SNIF CA Proxy. If configured, the {apiUrl} SHOULD be HTTPS. The {apiUrl} pertains only to certificate enrollment with the CA Proxy; it is not used to authenticate the Relay (see {relayHost} in Section 4.2).

In case {apiUrl} is not configured - the SNIF Connector MUST derive {apiUrl} from the {cn_host}, upon allocating the CN, as following:

   {apiUrl} := http://{cn_host}/snif-cert/

3.2. Protocol Flow

Upon the initial start or after a hard reset, the Connector SHALL generate a Private Key, which needs to be securely permanently stored by the Connector. Any key algorithm acceptable by the CA can be used, the choice of the algorithm should be made according to the CA guidelines and industry practices.

The Connector SHALL send a CN Allocation Request using the {initUrl}.

Having the canonical name {cn}, the Connector SHALL generate a CSR [RFC2986] using the Private Key, the subject containing the {cn}. The CSR subject may or may not have other fields besides {cn}, according to the specific requirements of the CA.

The Connector SHALL issue a CSR Submission Request to send the CSR to the CA Proxy.

Once the CSR is submitted, the Connector MUST permanently store the {cn} by some means - to minimize the storage compartments it might be practical to generate and store a dummy self-signed certificate with the {cn} in the subject until it gets replaced with a trusted certificate issued by the CA.

At this point, the Connector will normally know the SNIF hostname it will be using with the SNIF Relay - it matches the {cn} in case of a single host CN, or is one sub-level down from a wildcard {cn}, the name being derived by the Connector in a way that cannot be derived from the {cn} and the public key, e.g. a hash of the Private Key.

The Connector can now send a Certificate Download Request, and MUST verify the returned Certificate. If the Certificate is valid - the Connector MUST permanently store it.

If the Certificate Download Request fails - the Connector SHOULD repeat the request after certain delay. In case the response was 401 and the {authUrl} is returned in a header, and the Connector has the means of communicating with the device user - the Connector also SHOULD alert the user and bring {authUrl} to their attention by some means, so the user can complete the required authorization steps. If the Connector has no means of alerting the user, which is often the case with IoT devices - the user MUST be provided with some external means of authorizing with the CA Proxy, not covered by this document.

Once the Certificate is validated and stored, the Connector is capable of terminating SNIF connections, and may proceed launching a SNIF Control Connection (Section 4.2). The Connector SHOULD communicate its SNIF hostname by some means to the SNIF Clients that will be accessing the Connector. The means of such communication are not covered by this document.

The Connector SHOULD watch for the expiration of the stored Certificate. If the Certificate is about to expire in 7 days or less, or has already expired - the Connector SHOULD send a Certificate Download Request, and repeat with appropriate delays until the renewed Certificate is successfully downloaded and verified.

At any stage of the flow, if the Connector receives unexpected volume of rejections or inconsistent responses from the CA Proxy, the Connector MAY decide to hard reset the storage and start the flow over from the beginning. In such case, the Connector will have to re-send its new SNIF hostname to any concerned SNIF Clients, the means of such communication is not covered by this document.

3.3. CN Allocation Request

Connection from:
SNIF Connector
Connection to:
SNIF CA Proxy
Protocol:
https or http
   GET {initUrl}

Response 200: Canonical Name (CN) is successfully allocated. The response headers MUST include X-SNIF-CN: with the value of the allocated {cn}, either a wildcard starting with "*.", or a single hostname, depending on the CA Proxy rules. The CA Proxy MUST NOT return a CN that's been previously returned by another CN Allocation Request. The Connector SHOULD ignore the response body.

Any other response: Error, try again later.

3.4. CSR Submission Request

Connection from:
SNIF Connector
Connection to:
SNIF CA Proxy
Protocol:
https or http
   PUT {apiUrl}{cn_host}.csr
   Content-Type: application/pkcs10

The request body MUST contain a PEM encoded PKCS#10 CSR [RFC5967], the newlines are either <CR><LF> or <LF>, the length of the body SHOULD NOT exceed 16384 bytes.

Note that a CSR for the specific allocated CN can be submitted to the CA Proxy once in a lifetime. In case of an incorrect submission the Connector SHOULD hard reset the storage and restart the flow from the beginning, including allocating a new CN.

Response 201: the CSR is successfully submitted. The response headers MAY include X-SNIF-AuthUrl: with the value of an {authUrl}, that SHOULD, if possible, be communicated to the user to authorize the certificate issuance.

Response 403: the CSR for this CN has already been submitted, or is denied by the CA Proxy rules. If the Connector receives 403, it SHOULD hard reset the storage and restart the CA Proxy flow from the beginning.

Response 404: the CN was not allocated.

Any other response: Error, try again later.

3.5. Certificate Download Request

Connection from:
SNIF Connector
Connection to:
SNIF CA Proxy
Protocol:
https or http
   GET {apiUrl}{cn_host}.crt

The CA Proxy SHOULD check for a cached previously generated Certificate chain for the {cn}. If the cached Certificate chain is found and if it expires in more than 10 days in the future - the cached Certificate chain SHOULD be returned with status 200. Otherwise, if the {cn} has a valid CSR and a proper authorization to issue a certificate - the CA Proxy SHOULD return status 503 and SHOULD launch a background process that communicates with the CA to issue or renew the certificate, and caches the issued Certificate chain for subsequent Certificate Download Requests.

Response 200: the Certificate chain is returned. The Content-Type of such response SHOULD be "application/x-x509-ca-cert". The response body MUST be a PEM encoded X.509 certificate chain, the issued certificate being the first member, the newlines are either <CR><LF> or <LF>, the length of the body SHOULD NOT exceed 65535 bytes.

Response 503: the Certificate is being issued, try later.

Response 401: Certificate issuance authorization is required. The response headers MAY include X-SNIF-AuthUrl: with the value of an {authUrl}, that SHOULD, if possible, be communicated to the user to authorize the certificate issuance. If the CA Proxy expects to work with Connectors that cannot communicate with the user, it MUST include external means of the authorization, not covered by this document.

Response 404: the CN was not allocated, or the CSR was not submitted.

Any other response: Error, try again later.

4. SNIF Relay Protocol Suite

The SNIF Relay Protocol Suite defines the communications among a SNIF Relay, the SNIF Connectors that register with it, the SNIF Clients that reach those Connectors through it, and the SNIF Peripheral Processes attached to the Relay.

The suite is defined in two layers. Section 4.1 and Section 4.2 define, independently of any transport, the SNIF Messages exchanged and the logical connection roles they are exchanged over. Section 4.3 and Section 4.4 define two interchangeable transport bindings that realize those roles: SNIF over TCP, which every conformant Relay and Connector MUST support, and SNIF over QUIC, which is OPTIONAL.

Across every binding, the SNIF Relay forwards the end-to-end TLS traffic of a SNIF Client as an opaque octet stream. The Relay MUST NOT terminate, decrypt, or otherwise interpret that traffic - save for the single Encrypted ClientHello exception specified by the blind-relay invariant (Section 4.2) - and the Connector's certificate private key is never available to the Relay (see also Section 5).

4.1. SNIF Messages

A SNIF Message consists of one or more ASCII characters excluding non-printable 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 with UTF-8 [RFC3629].

The receiving party SHOULD silently ignore any invalid or malformed SNIF message.

The following messages are defined. The "Carried on" role names the logical connection role (Section 4.2) the message is exchanged over; the transport bindings (Section 4.3, Section 4.4) specify how that role is realized on the wire. The message wire formats are unchanged from earlier revisions of this document, so existing TCP deployments remain conformant.

   SNIF LISTEN {hostname}
   SNIF LISTEN {hostname} {options}
Sent by:
SNIF Connector
Carried on:
Control Connection

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 matching a wildcard CN or exactly matching a single-host CN. SHOULD be sent only once per Control Connection; the Relay SHOULD ignore invalid or subsequent SNIF LISTEN messages.

{options}, if present, is a whitespace-separated list of tokens by which the Connector requests optional behaviors for the session. No options are defined by this document; the field is reserved for future use. A Relay MUST ignore any option token it does not recognize, and a Connector MUST NOT assume an unrecognized option took effect. This keeps SNIF LISTEN forward compatible: future revisions may define option tokens (for example, to select a transport behavior) without breaking existing deployments.

   SNIF CONNECT {conn_id} {dst_host}:{dst_port} {fwd_host}:{fwd_port} {cln_addr}:{cln_port}
Sent by:
SNIF Relay
Carried on:
Control Connection

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. {fwd_host}:{fwd_port} is the address of the Relay node that holds this Client Connection. In the TCP binding it is the address at which that node accepts the corresponding Service Connection (Section 4.3). In the QUIC binding {fwd_host} identifies the node and the Service stream is delivered to it over a QUIC connection on the snif port (Section 4.4): the Connector reuses its Control Connection to that node when it has one, and otherwise (in a cluster) opens a new Control Connection to {fwd_host} on the snif port. {fwd_port} pertains to the TCP Service Connection and is not used in the QUIC binding. {cln_addr}:{cln_port} are the Client's remote IPv4/IPv6 address and TCP port, {cln_addr} enclosed in "[" brackets "]". The Relay sends SNIF CONNECT only to Connectors whose {hostname} matches {dst_host}; the Connector need not verify {dst_host}.

   SNIF ACCEPT {conn_id}
Sent by:
SNIF Connector
Carried on:
Service Connection

Binds a newly opened Service Connection (TCP binding) or Service stream (QUIC binding) to the {conn_id} previously received in a SNIF CONNECT message, signaling that the Connector accepts the connection. It is sent as the leading octets - the in-band SNIF ACCEPT preamble - of the Service Connection or Service stream in both bindings (Section 4.3, Section 4.4).

   SNIF CLOSE {conn_id}
Sent by:
SNIF Connector
Carried on:
Control Connection

Instructs the Relay to terminate the Client connection with the matching {conn_id} (e.g. to reject a connection). For SNIF CLOSE received from a Connector, the Relay MUST 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
Carried on:
Control Connection

Instructs the Relay to increase the DoS-protection abuse counter for the Client that initiated {conn_id} by {abuse_score}, an integer from 1 to 255 (1 is the score for a normal, non-abusive connection). The Relay MUST validate that {conn_id} was targeted at the Connector's {hostname}, otherwise ignore the message.

   SNIF MSG {hostname} {content}
Sent by:
SNIF Connector or SNIF Relay
Carried on:
Control Connection (and IPC FIFO, Section 4.6)

Relayed between the Connector and the SNIF Peripheral Processes attached to the Relay. {content} SHOULD NOT contain whitespace or non-printable characters; its semantics are specific to the targeted Peripheral Process and are out of scope. For SNIF MSG received from a Connector, the Relay MUST verify that {hostname} matches the one associated with the Connector before forwarding to the IPC FIFOs. A SNIF MSG sent by a Connector might, in some circumstances, return to it, and where a Connector holds Control Connections to more than one node of a Relay cluster (Section 4.4) a SNIF MSG for its {hostname} may be delivered to it once on each of them; a Connector MUST therefore process SNIF MSG idempotently and SHOULD account for duplicates to avoid message storms.

   NOOP
Sent by:
SNIF Connector or SNIF Relay
Carried on:
Control Connection

Carries no action. A Relay receiving NOOP from a Connector SHOULD promptly send NOOP or any other message back, so a Connector MAY use NOOP as a keep-alive ping. In the QUIC binding, transport-level keep-alive (Section 4.4) MAY be used instead.

4.2. SNIF Connection Roles

The protocols below are defined in terms of four logical connection roles. Each transport binding (Section 4.3, Section 4.4) specifies how these roles are realized on the wire.

Control Connection is a single, persistent, bidirectional channel between a SNIF Connector and a SNIF Relay that carries asynchronous SNIF Messages. It is always initiated by the Connector. The Connector MUST authenticate to the Relay with the certificate and private key for its SNIF hostname (Section 3); the Relay MUST validate that certificate and, if it is not trusted, MUST close the connection immediately.

Each SNIF Connector MAY be configured with a {relayHost} - the hostname identifying the Relay's TLS certificate, by which the Connector authenticates the Relay. {relayHost} is independent of the CA Proxy {apiUrl} (Section 3.1): the CA Proxy and the Relay are commonly the same host but need not be, and the Relay need not serve HTTPS. If {relayHost} is configured, the Connector MUST validate the certificate presented by the Relay against {relayHost} - in both the TCP (Section 4.3) and QUIC (Section 4.4) bindings - closing the connection if the Relay presents no certificate or the certificate does not match. If {relayHost} is not configured, the Connector does not authenticate the Relay's certificate.

Service Connection is a bidirectional, reliable, in-order octet stream dedicated to exactly one forwarded SNIF Client connection. It carries the Client's end-to-end TLS traffic as an opaque payload. The Relay MUST treat this payload as opaque ciphertext and MUST NOT attempt to interpret it, save for the Encrypted ClientHello exception in the blind-relay invariant below; the SNI, already interpreted to route the Client Connection, is merely forwarded to the Connector as part of this stream. Each Service Connection is associated with a {conn_id}.

Client Connection is the TLS connection between a SNIF Client and the SNIF Relay, in which the Relay acts as a transparent end-to-end forwarder (Section 4.5).

IPC FIFO carries communications between nodes of a SNIF Relay cluster and/or between a SNIF Relay and SNIF Peripheral Processes (Section 4.6).

Blind-relay invariant: under every binding the Relay MUST be able to route a Client Connection to a Connector using only the Server Name Indication of the Client's TLS ClientHello, and MUST forward the Service Connection payload without the means to decrypt it. The Connector's end-to-end certificate private key MUST NOT be transmitted to, derivable by, or stored on the Relay.

The sole exception to "without the means to decrypt it" is the Encrypted ClientHello (ECH) transform of Section 4.9: a Relay configured for ECH MAY decrypt the Client's initial ClientHello solely to recover the Server Name Indication it routes on, and forward the reconstructed inner ClientHello in place of the outer one. This is the only transformation a Relay is permitted to apply to the end-to-end TLS handshake; every octet from the reconstructed ClientHello onward remains opaque. The ECH key used for this transform is distinct from the Connector's end-to-end certificate key and confers no ability to decrypt or impersonate the end-to-end TLS session, which remains subject to the invariant above.

4.3. SNIF over TCP (baseline)

Every conformant SNIF Relay and SNIF Connector MUST support the TCP binding. It realizes the Control Connection as the "snif" protocol and each Service Connection as a separate "snif-srv" connection.

Protocol name (Control):
snif
Protocol name (Service):
snif-srv
Connection from:
SNIF Connector
Connection to:
SNIF Relay

Control Connection. The Connector opens a TCP connection to the hostname matching its certificate CN, which points to the Relay. Upon accepting the TCP connection, the Relay MUST initiate a reversed TLS session as the client peer and MAY supply a client certificate. The Connector MUST initiate TLS as the server peer, using its certificate and private key. If the Connector is configured with {relayHost} (Section 4.2), it MUST require the Relay to present a client certificate valid for {relayHost} and MUST shut down the TLS session and TCP socket if the Relay presents no certificate or it does not match. On successful negotiation the Relay MUST validate the Connector's certificate and, if untrusted, MUST shut down the TLS session and TCP socket immediately. If the host named in the Connector's certificate does not fall within any of the domains served by the Relay, the Relay SHOULD close the connection. Once validated, both peers exchange SNIF Messages (Section 4.1) over the TLS connection. The Connector sends SNIF LISTEN to begin accepting Client connections.

Service Connection. In response to a SNIF CONNECT received over the Control Connection, if the Connector accepts the connection it MUST open a TCP connection to {fwd_host}:{fwd_port} and MUST immediately send, as plain TCP, a SNIF ACCEPT {conn_id} message carrying the {conn_id} from the SNIF CONNECT. The Connector MUST then immediately assign all further traffic of that Service Connection to the matching TLS server process. To reject, the Connector SHOULD instead send SNIF CLOSE {conn_id} over the Control Connection. The Connector SHOULD also send any SNIF Message back over the Control Connection on accept to update the keep-alive timer (a copy of the SNIF ACCEPT MAY be used).

Relay forwarding. On a valid SNIF ACCEPT, the Relay SHOULD link the Service Connection to the matching Client Connection, forward to it all buffered TLS data previously received from the Client, and begin bidirectional forwarding. The Relay MUST reject any further SNIF ACCEPT bearing an already-linked {conn_id}. If the {conn_id} or message is invalid, or an abuse threshold is reached, the Relay SHOULD terminate the Service Connection immediately. When either the Client or Service Connection closes, or an inactivity timeout elapses, the Relay SHOULD shut down both.

4.4. SNIF over QUIC (optional)

A SNIF Relay and SNIF Connector MAY support the QUIC binding [RFC9000]. It realizes the Control Connection and all of a Connector's Service Connections as a single QUIC connection: the Control Connection is carried on a dedicated control stream, and each Service Connection is a distinct QUIC stream. This replaces the per-Client outbound connection of the TCP binding, and its transport handshake, with a lightweight per-Client stream open within the already-established QUIC connection, and isolates each forwarded session on its own stream (no cross-session head-of-line blocking), while preserving the blind-relay invariant of Section 4.2. As in the TCP binding the Connector opens each Service stream and admits the connection with SNIF ACCEPT, so no Client payload reaches the Connector before it accepts.

ALPN protocol identifier:
"snifq/1" (see Section 4.7 and Section 6)
QUIC connection from:
SNIF Connector (QUIC client)
QUIC connection to:
SNIF Relay (QUIC server)
Default UDP port:
7123 (the registered "snif" port, see Section 6)

Connection establishment and authentication. The Connector establishes a QUIC connection to the Relay on UDP port 7123 (the registered "snif" port, Section 6), unless a different port has been advertised out of band (Section 4.7). In the QUIC TLS handshake [RFC9001] the Connector MUST act as the QUIC client and MUST present, via TLS client authentication, the certificate for its SNIF hostname and prove possession of the corresponding private key. The private key MUST NOT be exposed to the Relay or any other party. The Relay MUST validate that certificate exactly as in Section 4.3 and MUST close the connection (with a TLS handshake failure) if it is untrusted. The Relay, as QUIC server, presents its own certificate. A Connector configured with {relayHost} (Section 4.2) MUST validate the Relay certificate against {relayHost}, closing the connection if it does not match; a Connector without {relayHost} does not authenticate the Relay certificate. ALPN [RFC7301] MUST be negotiated to "snifq/1".

The TLS roles in the QUIC binding are the reverse of those in the TCP binding (Section 4.3), where the Connector is the TLS server and a Relay certificate is optional. This reversal is inherent to QUIC, which binds the TLS handshake roles to the transport roles [RFC9001]: the endpoint that initiates the connection is necessarily the TLS client. Because the Connector is typically behind NAT and is the only endpoint able to initiate a connection (Section 1), it MUST be the QUIC client, and therefore the TLS client, and the Relay MUST present a server certificate. A Relay certificate is consequently REQUIRED in this binding rather than optional. A Connector without {relayHost} does not validate it, so it MAY be self-signed; a Connector configured with {relayHost} (Section 4.2) validates the certificate and thereby authenticates the Relay.

Control stream. Immediately after the handshake the Connector MUST open one client-initiated bidirectional stream as the Control Connection and send SNIF LISTEN on it. SNIF Messages carried on the Control Connection (Section 4.1) are exchanged on this stream. Transport-level keep-alive (QUIC PING / idle timeout, [RFC9000]) MAY replace NOOP.

Service streams. The Service stream flow mirrors the TCP binding (Section 4.3), with a QUIC stream in place of a dialed-back connection. For each incoming Client Connection the Relay MUST send a single SNIF CONNECT {conn_id} ... message on the control stream and MUST buffer the Client's initial TLS data (Section 4.5) while awaiting acceptance. To accept, the Connector MUST open a client-initiated bidirectional stream and MUST send, as the leading octets of that stream, a single SNIF ACCEPT {conn_id} message terminated by <CR><LF>, carrying the {conn_id} from the SNIF CONNECT. The Connector MUST then assign all further octets of that stream to the matching TLS server process.

In this binding {fwd_host} (Section 4.1) identifies the Relay node that holds the Client Connection and to which the Service stream MUST be delivered; {fwd_port} applies to the TCP dial-back (Section 4.3) and is not used here. When the Connector already holds a Control Connection to that node - the usual case, and always so for a single-node Relay - it opens the Service stream on that connection. When it does not, the clustered case of the following paragraph applies.

Clustered Relays. In a SNIF Relay cluster a Client Connection may arrive at a node to which the Connector holds no Control Connection. That node sets {fwd_host} (and, for TCP-capable Connectors, {fwd_port}) to its own address and, having no local Control Connection for the Connector, forwards the SNIF CONNECT to a node that does over an IPC FIFO (Section 4.6), which delivers it on the control stream. Because a QUIC stream can be opened only within the connection it belongs to, the Connector cannot serve such a Client on its existing connection; it MUST instead open a new QUIC connection to {fwd_host} on the snif port (UDP 7123 by default, or the port advertised out of band, Section 4.7) and open the Service stream there. This connection is an ordinary Control Connection: the Connector establishes and authenticates it exactly as above, sends SNIF LISTEN on its control stream, and opens the Service stream. The receiving node thereby gains a local Control Connection and routes subsequent Clients for that {hostname} to the Connector directly, without further IPC FIFO relay. Keeping the cross-node leg a QUIC connection also keeps that leg encrypted, preserving the routing-name concealment of the QUIC binding (Section 5.2), and of ECH (Section 4.9) when combined with it, across the cluster.

A Connector MAY therefore hold a Control Connection to more than one node of a cluster at once, each opened reactively as Clients arrive on new nodes, so the number of connections a Connector maintains is bounded by the size of the Relay cluster rather than by the number of Clients. A Connector MAY close a Control Connection that has been idle, reverting that node to IPC FIFO relay until a later Client reopens one. Because each such Control Connection carries SNIF MSG (Section 4.1), a Connector that holds Control Connections to multiple nodes MUST process SNIF MSG idempotently (Section 4.1).

To reject, the Connector does not open a Service stream, and SHOULD send SNIF CLOSE {conn_id} on the control stream so the Relay can tear down the matching Client Connection promptly rather than awaiting its accept timeout (Section 4.5).

Relay forwarding. On a SNIF ACCEPT preamble bearing a known, not-yet-linked {conn_id} the Relay MUST link the Service stream to the matching Client Connection, forward to it all buffered Client TLS data, and begin bidirectional forwarding of the end-to-end TLS payload. The Relay MUST reject a SNIF ACCEPT bearing an unknown or already-linked {conn_id} by aborting that stream (RESET_STREAM plus STOP_SENDING [RFC9000]). When either the Client Connection or the Service stream ends (FIN or reset), or an inactivity timeout elapses, the Relay MUST end the other. SNIF ABUSE {conn_id} and SNIF CLOSE {conn_id} on the control stream refer to the Service stream by {conn_id}.

Flow control: the Relay SHOULD bound the number of concurrent Service streams a Connector may open with MAX_STREAMS [RFC9000], and both peers SHOULD set per-stream and per-connection flow-control limits so that a single greedy forwarded session cannot starve other Service streams on the same Connector's connection (see Section 5).

Encapsulation overhead. On the Relay-to-Connector leg the Client's end-to-end TLS payload is carried inside the QUIC connection's own encrypted transport, so that leg is encrypted twice: once end-to-end between Client and Connector, and once by QUIC between Relay and Connector. This overhead is inherent to forwarding opaque end-to-end TLS over an encrypted transport, and is the cost of the infrastructure-leg confidentiality the QUIC binding provides (Section 5.2); the TCP binding avoids it by carrying the Service Connection as plain TCP, at the cost of exposing that leg (Section 5.2).

4.5. SNIF Client Connection Protocol

Protocol name:
snif-cln
Connection from:
Any TLS client with Server Name Indication, such as a web browser or an email client
Connection to:
SNIF Relay

From the Client's perspective, a SNIF Client Connection functions as a direct TLS connection to the 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 (TCP binding) or Service stream (QUIC binding) carrying 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.

4.6. SNIF IPC FIFO Protocol

Protocol name:
snif-fifo
Connection from:
SNIF Relay or SNIF Peripheral Service
Connection to:
SNIF Relay or SNIF Peripheral Service

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 Section 4.1).

The SNIF CONNECT message is sent by a Relay over an IPC FIFO in case the Relay failed to reach the respective Connector through Control Connections. SNIF CONNECT sent by a Relay MUST be followed up by one of SNIF CLEAR or SNIF CLOSE to inform the Peripheral Processes of the further outcome. Even when the SNIF CONNECT is acted upon by a peer Relay, the resulting Service Connection (TCP binding) or Service stream (QUIC binding) is established to the {fwd_host} carried in the message, which is the originating Relay; that Relay therefore always observes the acceptance and is the one that emits the followup.

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 the Client Connection that triggered SNIF CONNECT was accepted by a Service Connection. Because the Service Connection, or Service stream in the QUIC binding, is always established to the originating Relay (the {fwd_host} of the SNIF CONNECT), only that Relay processes the SNIF ACCEPT and therefore only it sends SNIF CLEAR.

The purpose of SNIF CLEAR is to advise 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 Section 4.1).

The SNIF CLOSE message SHOULD be sent by a Relay only as a followup to SNIF CONNECT with a matching {conn_id}, in case 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 Section 4.1).

   SNIF MSG {hostname} {content}
Direction:
Send or Receive

(see Section 4.1).

   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.

4.7. Transport discovery and fallback

The TCP binding (Section 4.3) is the mandatory baseline; a Connector that cannot use QUIC, or that fails to establish a QUIC connection, MUST be able to operate over TCP - unless its deployment requires the server name to be concealed on the infrastructure leg as well as the access leg, which requires the QUIC binding (Section 5.2) combined with ECH (Section 4.9). Such a Connector SHOULD instead treat QUIC unreachability as a failure rather than falling back to TCP, since the fallback would re-expose the server name on the infrastructure leg (see the transport-downgrade discussion in Section 5.2). Because the TCP and QUIC bindings use different transport protocols, selection is by attempt-and-fallback rather than in-band negotiation:

  • A Connector that supports the QUIC binding SHOULD attempt a QUIC connection to the Relay on UDP port 7123 (the registered "snif" port, Section 6) first, offering ALPN "snifq/1", and SHOULD fall back to the TCP binding (Section 4.3) if the QUIC connection cannot be established within a reasonable time or if "snifq/1" is not negotiated.
  • A Relay MAY advertise QUIC support, including an alternative UDP port, out of band (e.g. via the CA Proxy initiation response, Section 3) so Connectors can skip the QUIC attempt when it is known to be unavailable, or reach it on a non-default port.

A Connector MUST NOT maintain both a TCP and a QUIC Control Connection to the same Relay node for the same {hostname} simultaneously. A Connector MAY, however, hold QUIC Control Connections for the same {hostname} to several distinct nodes of a Relay cluster at once, as the clustered case of Section 4.4 requires.

4.8. Abuse Management

SNIF Relay SHOULD implement basic protection from denial of service. A separate abuse count SHOULD be assigned to each remote address, incremented by 1 on every incoming connection from the address, incremented by a specified score on every received SNIF ABUSE message, and periodically decremented or reset at regular time intervals.

If the abuse counter for a certain remote address reaches a specific threshold, the Relay SHOULD drop any further TCP connections from that address until the abuse counter goes below the threshold. The Relay MAY allow some grace above the threshold to incoming SNIF Service Connections, to minimize stalled Client Connections.

SNIF Connector MAY implement basic protection from denial of service by limiting the number of accepted connections per period of time and/or the total number of open connections, and reject connections over the limit.

4.9. SNIF with Encrypted ClientHello (optional)

A SNIF Relay MAY offer Encrypted ClientHello (ECH) [RFC9849] so that the true server name a Client requests is concealed from observers on the access leg between the Client and the Relay (Section 5.2). ECH is independent of the transport binding and MAY be combined with either the TCP binding (Section 4.3) or the QUIC binding (Section 4.4). When a Relay offers ECH it acts as the ECH client-facing server in the split-mode topology of [RFC9849]: it terminates the ECH encryption only, never the end-to-end TLS session.

Keying. A Relay that offers ECH holds a single ECH key pair for the names it serves. The private key resides on the Relay only and is never distributed to Connectors. In a Relay cluster (Section 4.4) every node MUST hold this ECH private key, because any node may receive a Client Connection and is then the node that decrypts and reconstructs its ClientHello (below) in order to route and serve it; the key is shared only among the mutually trusted nodes of one logical Relay and is still never distributed to Connectors. The corresponding ECHConfig, naming a "public_name" within the Relay's own domain, is published in the DNS HTTPS resource record [RFC9460] for the SNIF hostnames the Relay serves; a single wildcard record MAY cover an entire SNIF zone. Because the Relay recovers the routing name by decryption (below) rather than from a per-Connector value, one ECHConfig suffices for every Connector and no ECH state is required in a Connector's DNS.

Client. A SNIF Client is any ECH-capable TLS client. It resolves the SNIF hostname, obtains the Relay's ECHConfig from the HTTPS record, and connects to the Relay presenting the "public_name" as the outer (visible) Server Name Indication, with its true (inner) ClientHello, including the SNIF hostname, encrypted under the ECHConfig. The Client requires no awareness of SNIF (Section 1).

Relay processing. On receiving the Client's initial ClientHello (Section 4.5) the Relay examines it for an "encrypted_client_hello" extension of type "outer":

  • If the extension is absent, the Relay routes on the cleartext Server Name Indication exactly as in Section 4.5.
  • If the extension is present and the Relay can decrypt it with a held ECH key, the Relay MUST recover and reconstruct the inner ClientHello as specified in [RFC9849] (expanding any "ech_outer_extensions" compression against the outer ClientHello). The reconstruction MUST be byte-exact, because the reconstructed inner ClientHello is the message that both the Client and the Connector incorporate into the TLS handshake transcript; any deviation causes the handshake to fail. The Relay then routes on the inner Server Name Indication as in Section 4.5 and forwards the reconstructed inner ClientHello, in place of the outer one, as the leading end-to-end TLS octets of the Service Connection.
  • If the extension is present but the Relay cannot decrypt it (for example a decoy "GREASE" value ([RFC9849]), or an unknown or rotated configuration identifier), the Relay MUST treat ECH as not negotiated and route on the cleartext (outer) Server Name Indication exactly as in Section 4.5 - with one exception. A decoy ECH extension carries the Client's true name in that cleartext SNI, so this routes it to its Connector normally. A genuine ECH ClientHello the Relay cannot decrypt instead always carries the Relay's own "public_name" as the outer SNI. Because "public_name" names the Relay itself and matches no Connector, the Relay MUST NOT attempt to route such a Client Connection: it MUST NOT emit a SNIF CONNECT, forward over an IPC FIFO, or otherwise wait for a Connector to accept, since no accept can arrive and the Client Connection would only stall until it timed out (Section 4.5). The Relay MUST instead resolve the Client Connection immediately: by default it closes the Client Connection, or, if it holds a certificate for "public_name", it MAY complete the handshake as "public_name" and return fresh "retry_configs" as the ECH rejection of [RFC9849]. This retry_configs path is OPTIONAL, and is the only circumstance in which a Relay terminates, rather than forwards, a Client's TLS session, one that never carries Connector traffic. A Relay that holds no certificate for "public_name" MUST close the Client Connection.

Connector. The Connector terminates the end-to-end TLS session from the reconstructed inner ClientHello as usual, and MAY ignore the Server Name Indication as any single-host server may. It MUST, however, implement the ECH backend behavior of [RFC9849]: it MUST recognize the inner-type "encrypted_client_hello" marker in the forwarded ClientHello and emit the corresponding ECH acceptance signal in its ServerHello, which an ECH-capable Client verifies. A Connector that omits this signal is interpreted by the Client as ECH rejection, and the connection fails rather than reaching the intended host. The Connector needs no ECH key and performs no decryption; this backend behavior is the lighter half of ECH.

Ecosystem-wide requirement. Because a Relay publishes its ECHConfig for a set of SNIF hostnames at once (typically a wildcard record), every Connector reachable under those names MUST implement the ECH backend behavior above; a Client directed by the record to use ECH toward a Connector that does not will fail, and retrying does not help. Offering ECH is therefore a joint decision of a Relay and all of its Connectors. A deployment that needs ECH for only a subset of Connectors MUST publish per-name HTTPS records for those names rather than a wildcard.

ECH conceals the server name only on the access leg between the Client and the Relay; on the infrastructure leg the reconstructed inner ClientHello carries it in the clear. A deployment that requires the server name concealed on the infrastructure leg as well SHOULD combine ECH with the QUIC binding (Section 4.4), which encrypts that leg; the two mechanisms are complementary, and the per-leg exposure trade-offs are set out in Section 5.2.

5. Security Considerations

Requests to CA Proxy (Section 3) sent over plain unencrypted HTTP, including a PKCS#10 CSR in the CSR Submission Request payload, do not contain sensitive information.

The response to the CN Allocation Request, if sent over plain HTTP, is a randomly generated hostname or wildcard, that will also be publicly exposed through Certificate Transparency once the Certificate is issued. Any attempt by an intruder to submit an alternate CSR for the issued CN prior to the legitimate Connector, will result in a certificate that doesn't match the Connector's private key, therefore the Connector will need to hard reset and redo the initialization. If the intruder alters the X-SNIF-CN: response sent to the Connector, the CSR submission for a bad CN will be rejected by the CA Proxy, which will also require to hard reset the Connector.

The content of the Certificate Download Request response is an X.509 certificate which is safe to be exposed to any parties. If the intruder alters the HTTP response to the CSR Submission Request or to the Certificate Download request, the Connector won't receive a valid certificate and will need a hard reset.

SNIF Connector SHOULD NOT send its hostname to any parties until it downloads and successfully validates the Certificate from the CA Proxy.

To mitigate request flooding potentially resulting in denial of service, it is RECOMMENDED for SNIF CA Proxy to require a Certificate issuance authorization. For SNIF Connectors that have a means of interacting with a user, such as a console or a web browser, the CA Proxy SHOULD implement an interactive authorization mechanism not described in this document, and return {authUrl} to the Connector (Section 3.5); the Connector SHOULD then present {authUrl} to the user to complete the process.

For a SNIF CA Proxy that intends to work with Connectors that have limited or no means of interacting with a user, some non-interactive Certificate issuance authorization mechanism SHOULD be implemented. As an example of such mechanism, each SNIF Connector can have a unique {initUrl} that MUST be HTTPS to avoid possible interception, and each Connector is supplied with a unique setup URL presented to the user, the CA Proxy properly mapping each setup URL to the matching {initUrl}, and using the setup URL to authorize the certificate issuance and to communicate the SNIF Connector's hostname to the user's browser. Such mechanism MUST have a means of alerting the user about misrouted setup, when some agent other than the legitimate user has used the same setup URL during the setup process, in which case the user MUST be instructed to immediately hard reset the Connector and repeat the setup. Such mechanism is RECOMMENDED to use an HTTPS {apiUrl} (Section 3.1); otherwise it MUST provide a means to prevent or detect intercepted setup when an intruder alters a submitted CSR, such as an out-of-band indication of setup completion (for example, status lights on a hardware device). The details of such mechanism are not covered by this document.

Since each certificate issued by a CA remains on the certificate transparency public records, it is RECOMMENDED for SNIF CA Proxy to only issue Certificates with a wildcard CN. This way, the actual Connector's hostname (Section 3.2) will not be listed on the public records.

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.

A compromised SNIF CA Proxy can potentially issue certificates to any hostnames allocated by the Relay, including a catch-all wildcard, using an alternative private key, and thus allow a man-in-the-middle attack on any SNIF Connectors associated with the Relay. This vulnerability can be mitigated by constant monitoring of public TLS Transparency logs, such as [RFC6962]. At least one independent party SHOULD continuously monitor TLS Transparency logs for each deployed SNIF CA Proxy and Relay. Once any duplicate or overlapping certificates are detected - the corresponding SNIF Relay MUST be permanently deemed compromised.

5.1. Blind-relay property (applies to all transport bindings)

The security of SNIF rests on the SNIF Relay being unable to read or alter the traffic it forwards. Under every transport binding (Section 4.3, Section 4.4) the SNIF Relay MUST route a SNIF Client Connection to a SNIF Connector using only the Server Name Indication of the Client's TLS ClientHello, and MUST forward the Service Connection payload as opaque octets without the means to decrypt it. The private key of the Connector's certificate MUST NOT be transmitted to, derivable by, or stored on the Relay. Consequently a compromised Relay can deny service, observe traffic volume and timing, and learn the routable server name of each connection (Section 5.2), but cannot read or forge the end-to-end TLS content. From the Client's perspective the SNIF Client Connection is a TLS session with a trusted certificate; the security of the TLS content between the Client and the Connector is specific to the protocol carried and is unchanged by the choice of binding.

5.2. Routing name exposure on the infrastructure leg

SNIF forwarding requires the Relay to read a routable server name from the Client's ClientHello. That name is the Connector's SNIF hostname, which is already public (it appears in Certificate Transparency logs; see the wildcard-CN guidance earlier in this section). The Relay therefore necessarily learns which Connector each Client reaches; this is inherent to SNIF and is not concealed by any binding.

The bindings differ, however, in what an on-path observer between the Relay and the Connector can see:

  • In the TCP binding (Section 4.3), the Service Connection carries the Client's end-to-end TLS as plain TCP. The Client's ClientHello, including the cleartext Server Name Indication, is visible to any observer on the Relay-to-Connector path.
  • In the QUIC binding (Section 4.4), the Service Connection is a stream within the Relay-to-Connector QUIC connection and is thus encrypted on that leg; the Server Name Indication is concealed from on-path observers there (though not from the Relay itself).

A Connector whose deployment requires the server name to be hidden from on-path observers on the infrastructure leg SHOULD use the QUIC binding (Section 4.4). The QUIC binding does not, however, conceal the Server Name Indication on the access leg between the Client and the Relay: that is the Client's own ClientHello, sent in the clear under every binding. Encrypted ClientHello (ECH) [RFC9849], where a Relay offers it (Section 4.9), is the only mechanism in this document that conceals the server name on the access leg. It hides the true (inner) name from observers between the Client and the Relay, and keeps a specific name that sits below a public wildcard out of Certificate Transparency. ECH does not conceal the routing name from the Relay itself, which decrypts it to route (Section 4.9), nor from observers on the infrastructure leg, where the reconstructed inner ClientHello again carries the name in the clear unless the QUIC binding is also used. ECH and the QUIC binding are therefore complementary rather than alternatives: ECH covers the access leg, the QUIC binding covers the infrastructure leg.

Transport downgrade: because binding selection is by attempt-and- fallback (Section 4.7), a network attacker who blocks QUIC (UDP) can force a Connector to fall back to the TCP binding and thereby re-expose the routing name on the infrastructure leg. A Connector that depends on the QUIC binding's infrastructure-leg confidentiality SHOULD treat QUIC unreachability as a failure rather than silently falling back, and a Relay SHOULD advertise QUIC availability out of band (Section 4.7) so that an unexpected fallback is detectable.

5.3. Connection authentication and connection-identifier confidentiality

In the TCP binding, the Control Connection is a reverse TLS session in which the Connector authenticates as the TLS server using its SNIF certificate and the Relay validates it; in high-security settings the Connector SHOULD be configured with {relayHost} (Section 4.2), in which case the Relay MUST supply a client certificate valid for {relayHost} and the Connector MUST immediately terminate the Control Connection if the certificate is absent or does not match. If the Connector does not validate a client certificate from the Relay, it MUST NOT send sensitive information in SNIF MSG messages and MUST NOT consider messages received from the Relay to be trusted. The {conn_id} of a Service Connection is sent over an unsecured TCP connection; it is single-use and is only actionable by the targeted Connector, and all subsequent octets are end-to-end TLS.

In the QUIC binding, the Connector authenticates as the QUIC client using TLS client authentication, presenting the same SNIF certificate and proving possession of its private key without ever exposing the key, and the Relay MUST validate it with the same trust rules, closing the connection on failure. The Relay, as QUIC server, presents its own certificate; a Connector configured with {relayHost} (Section 4.2) MUST validate the Relay's certificate against it, closing the connection on mismatch. Because the control stream and all Service streams share this single authenticated, encrypted QUIC connection, the SNIF CONNECT and the SNIF ACCEPT preamble, including {conn_id}, are not exposed in cleartext on the wire, removing the cleartext {conn_id} exposure of the TCP Service Connection. In contrast to the TCP binding, where the Relay need not present a certificate at all, the QUIC binding always requires the Relay to present a server certificate, so a Connector configured with {relayHost} can authenticate the Relay on every connection.

When {relayHost} (Section 4.2) is not configured, the Connector does not authenticate the Relay, in either binding. An active on-path attacker that can impersonate the Relay may then observe connection metadata - notably the {conn_id} and the SNIF Messages on the Control Connection - and, in the TCP binding, redirect the Connector to a substitute Relay. It cannot read the forwarded Client traffic, which remains end-to-end TLS terminated only on the Connector. Operators that require infrastructure-leg confidentiality or Relay authenticity SHOULD configure {relayHost}.

5.4. QUIC resource and denial-of-service considerations

The QUIC binding multiplexes all of a Connector's forwarded sessions onto one connection, which changes the resource-exhaustion surface:

  • Connection admission. Because the QUIC binding mirrors the TCP accept flow (Section 4.4), the Connector opens a client-initiated Service stream only for connections it accepts, so no Client payload reaches the Connector before it admits the connection, exactly as in the TCP binding. The only unsolicited traffic a flood of Client connections can impose on the Connector is the small SNIF CONNECT messages on the control stream, which the Relay's abuse counting (Section 4.8) already gates; rejecting a connection (by not opening a stream, optionally with SNIF CLOSE) costs the Connector nothing beyond reading that message. This avoids the unsolicited-push exposure a relay-initiated stream design would have on a constrained or slow Connector link.
  • Cross-node Control Connections. In a Relay cluster a Connector may hold Control Connections to several nodes at once (Section 4.4), each opened reactively and authenticated with the Connector's SNIF certificate, so they are not an avenue for unauthenticated parties and their count is bounded by the cluster size rather than by the number of Clients. A Relay SHOULD apply the same abuse counting (Section 4.8) and per-Connector stream and flow-control limits to each. Because the same SNIF MSG may be delivered to a Connector on each of these connections, SNIF MSG handling MUST be idempotent (Section 4.1, Section 4.4).
  • Stream concurrency. The Connector opens a client-initiated Service stream per accepted Client Connection, bounded by the Relay's advertised MAX_STREAMS [RFC9000]. The Relay SHOULD use MAX_STREAMS to cap the number of concurrent forwarded sessions per Connector; the Connector likewise SHOULD limit how many it opens. The Connector already controls concurrency in the TCP binding, where it chooses whether to dial back a Service Connection in response to each SNIF CONNECT; MAX_STREAMS provides the equivalent control as an explicit, Relay-advertised limit native to the transport, rather than adding backpressure the TCP binding lacked.
  • Flow-control starvation. A single greedy forwarded session could otherwise consume the connection's flow-control budget and starve sibling Service streams. A Relay and a Connector SHOULD set per-stream and per-connection flow-control limits so no one session can starve the others.
  • Amplification. The Connector is the QUIC client (initiator), so the standard QUIC anti-amplification limit applies and the Relay (QUIC server) MUST NOT be usable as an amplification reflector. The SNIF ABUSE mechanism continues to apply per {conn_id} / Service stream.
  • 0-RTT. If 0-RTT is used to resume the QUIC connection, early data MUST be limited to idempotent operations; in particular, control messages whose replay could cause harm MUST NOT be sent in 0-RTT. Re-sending SNIF LISTEN for the same {hostname} is idempotent and is permitted.

5.5. Connection consolidation (availability trade)

Consolidating a Connector's sessions onto one QUIC connection improves resilience to packet loss (loss on one stream does not stall others) but concentrates connection-level faults: a QUIC connection close, stateless reset, or path failure drops all of that Connector's forwarded sessions at once, whereas independent TCP Service Connections fail independently. The dropped forwarded sessions cannot themselves be re-established: each is an end-to-end TLS session terminated on the Client and the Connector, so once its transport is gone the session is irrecoverable and the affected Clients simply reconnect, which the Relay forwards as fresh Service streams. Re-establishment therefore applies to the Control Connection, not to the individual Service streams: a Connector using the QUIC binding SHOULD detect connection loss promptly and re-establish the Control Connection, so that those Client reconnections can be served again.

5.6. CA Proxy trust is independent of the relay transport

The man-in-the-middle exposure from a compromised SNIF CA Proxy issuing certificates under an alternative key (described earlier in this section, with its Certificate Transparency monitoring mitigation) is a property of the certificate-issuance trust model and is unaffected by the choice of relay transport binding. Neither the TCP binding nor the QUIC binding adds to nor reduces that exposure.

6. IANA Considerations

Service Names "snif", "snif-srv", "snif-cln" and "snif-fifo" are registered with IANA.

TCP port 7123 is registered with IANA for service "snif".

This document also requests that UDP port 7123 be assigned to service "snif" for the SNIF over QUIC binding (Section 4.4), matching the existing TCP assignment.

This document additionally requests registration of the following protocol identifier in the "TLS Application-Layer Protocol Negotiation (ALPN) Protocol IDs" registry [RFC7301], identifying the SNIF over QUIC binding (Section 4.4):

Protocol:
SNIF over QUIC
Identification Sequence:
0x73 0x6E 0x69 0x66 0x71 0x2F 0x31 ("snifq/1")
Reference:
This document, Section 4.4

7. References

7.1. Normative References

[RFC2119]
Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, , <https://www.rfc-editor.org/info/rfc2119>.
[RFC2986]
Nystrom, M. and B. Kaliski, "PKCS #10: Certification Request Syntax Specification Version 1.7", RFC 2986, DOI 10.17487/RFC2986, , <https://www.rfc-editor.org/info/rfc2986>.
[RFC5280]
Cooper, D., Santesson, S., Farrell, S., Boeyen, S., Housley, R., and W. Polk, "Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile", RFC 5280, DOI 10.17487/RFC5280, , <https://www.rfc-editor.org/info/rfc5280>.
[RFC6066]
Eastlake 3rd, D., "Transport Layer Security (TLS) Extensions: Extension Definitions", RFC 6066, DOI 10.17487/RFC6066, , <https://www.rfc-editor.org/info/rfc6066>.
[RFC7301]
Friedl, S., Popov, A., Langley, A., and E. Stephan, "Transport Layer Security (TLS) Application-Layer Protocol Negotiation Extension", RFC 7301, DOI 10.17487/RFC7301, , <https://www.rfc-editor.org/info/rfc7301>.
[RFC8174]
Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, , <https://www.rfc-editor.org/info/rfc8174>.
[RFC8446]
Rescorla, E., "The Transport Layer Security (TLS) Protocol Version 1.3", RFC 8446, DOI 10.17487/RFC8446, , <https://www.rfc-editor.org/info/rfc8446>.
[RFC9000]
Iyengar, J., Ed. and M. Thomson, Ed., "QUIC: A UDP-Based Multiplexed and Secure Transport", RFC 9000, DOI 10.17487/RFC9000, , <https://www.rfc-editor.org/info/rfc9000>.
[RFC9001]
Thomson, M., Ed. and S. Turner, Ed., "Using TLS to Secure QUIC", RFC 9001, DOI 10.17487/RFC9001, , <https://www.rfc-editor.org/info/rfc9001>.
[RFC9460]
Schwartz, B., Bishop, M., and E. Nygren, "Service Binding and Parameter Specification via the DNS (SVCB and HTTPS Resource Records)", RFC 9460, DOI 10.17487/RFC9460, , <https://www.rfc-editor.org/info/rfc9460>.
[RFC9849]
Rescorla, E., Oku, K., Sullivan, N., and C. A. Wood, "TLS Encrypted Client Hello", RFC 9849, DOI 10.17487/RFC9849, , <https://www.rfc-editor.org/info/rfc9849>.

7.2. Informative References

[RFC3629]
Yergeau, F., "UTF-8, a transformation format of ISO 10646", STD 63, RFC 3629, DOI 10.17487/RFC3629, , <https://www.rfc-editor.org/info/rfc3629>.
[RFC5967]
Turner, S., "The application/pkcs10 Media Type", RFC 5967, DOI 10.17487/RFC5967, , <https://www.rfc-editor.org/info/rfc5967>.
[RFC6962]
Laurie, B., Langley, A., and E. Kasper, "Certificate Transparency", RFC 6962, DOI 10.17487/RFC6962, , <https://www.rfc-editor.org/info/rfc6962>.
[RFC8555]
Barnes, R., Hoffman-Andrews, J., McCarney, D., and J. Kasten, "Automatic Certificate Management Environment (ACME)", RFC 8555, DOI 10.17487/RFC8555, , <https://www.rfc-editor.org/info/rfc8555>.

Changes from draft-zubov-snif-04

This appendix summarizes the substantive changes in this revision. It is to be removed before publishing as an RFC.

Author's Address

Jim Zubov
VESvault Corp