One document matched: draft-hildebrand-spud-prototype-02.xml


<?xml version="1.0" encoding="UTF-8"?>
  <?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?>
  <!-- generated by https://github.com/cabo/kramdown-rfc2629 version 1.0.22 -->

<!DOCTYPE rfc SYSTEM "rfc2629.dtd" [
<!ENTITY RFC2119 SYSTEM "http://xml2rfc.tools.ietf.org/public/rfc/bibxml/reference.RFC.2119.xml">
<!ENTITY RFC3168 SYSTEM "http://xml2rfc.tools.ietf.org/public/rfc/bibxml/reference.RFC.3168.xml">
<!ENTITY RFC4443 SYSTEM "http://xml2rfc.tools.ietf.org/public/rfc/bibxml/reference.RFC.4443.xml">
<!ENTITY RFC5646 SYSTEM "http://xml2rfc.tools.ietf.org/public/rfc/bibxml/reference.RFC.5646.xml">
<!ENTITY RFC7049 SYSTEM "http://xml2rfc.tools.ietf.org/public/rfc/bibxml/reference.RFC.7049.xml">
<!ENTITY RFC1149 SYSTEM "http://xml2rfc.tools.ietf.org/public/rfc/bibxml/reference.RFC.1149.xml">
]>


<rfc ipr="trust200902" docName="draft-hildebrand-spud-prototype-02" category="info">

  <front>
    <title abbrev="I-D">Substrate Protocol for User Datagrams (SPUD) Prototype</title>

    <author initials="J." surname="Hildebrand" fullname="Joe Hildebrand">
      <organization>Cisco Systems</organization>
      <address>
        <email>jhildebr@cisco.com</email>
      </address>
    </author>
    <author initials="B." surname="Trammell" fullname="Brian Trammell">
      <organization>ETH Zurich</organization>
      <address>
        <email>ietf@trammell.ch</email>
      </address>
    </author>

    <date year="2015" month="March" day="03"/>

    
    
    

    <abstract>


<t>SPUD is a prototype for grouping UDP packets together in a “tube”, also
allowing network devices on the path between endpoints to participate
explicitly in the tube outside the end-to-end context.</t>



    </abstract>


  </front>

  <middle>


<section anchor="introduction" title="Introduction">

<t>The goal of SPUD (Substrate Protocol for User Datagrams) is to provide a
mechanism for grouping UDP packets together into a “tube” with a defined
beginning and end in time.  Devices on the network path between the endpoints
speaking SPUD may communicate explicitly with the endpoints outside the context
of the end-to-end conversation.</t>

<t>The SPUD protocol is a prototype, intended to promote further discussion of
potential use cases within the framework of a concrete approach.  To move
forward, ideas explored in this protocol might be implemented inside another
protocol such as DTLS.</t>

<section anchor="terminology" title="Terminology">

<t>In this document, the key words “MUST”, “MUST NOT”, “REQUIRED”,
“SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”,
and “OPTIONAL” are to be interpreted as described in BCP 14, RFC 2119
<xref target="RFC2119"/>.</t>

</section>
</section>
<section anchor="requirements-assumptions-and-rationale" title="Requirements, Assumptions and Rationale">

<t>The prototype described in this document is designed to provide an encapsulation
for transport protocols which allows minimal and selective exposure of transport
semantics, and other transport- and higher-layer information; and explicit
discovery of selected information about devices along the path by the transport
and higher layers.</t>

<t>The encryption of transport- and higher-layer content encapsulated within SPUD
is not mandatory; however, the eventual intention is that explicit communication
between endpoints and the path can largely replace the implicit endpoint-to-path
communication presently derived by middleboxes through deep packet inspection
(DPI).</t>

<t>SPUD is not a transport protocol; rather, we envision it as the lowest layer of
a “transport construction kit”. Using SPUD as a common encapsulation, such that
new transports have a common appearance to middleboxes, applications, platforms,
and operating systems can provide a variety of transport protocols or transport
protocol modules. This construction kit is out of scope for this prototype, and
left to future work, though we note it could be an alternate implementation of
an eventual TAPS interface.</t>

<t>The design is based on the following requirements and assumptions:</t>

<t><list style="symbols">
  <t>Transport semantics and many properties of communication that endpoints may
want to expose to middleboxes are bound to flows or groups of flows. SPUD must
therefore provide a basic facility for associating packets together (into what
we call a “tube” for lack of a better term).</t>
  <t>SPUD and transports above SPUD must be implementable without requiring kernel
replacements or modules on the endpoints, and without having special privilege
(root or “jailbreak”) on the endpoints. Eventually, we envision that SPUD will
be implemented in operating system kernels as part of the IP stack. However,
we also assume that there will be a (very) long transition to this state, and
SPUD must be useful and deployable during this transition. In addition,
userspace implementations of SPUD can be used for rapid deployment of SPUD
itself and new transport protocols over SPUD, e.g. in web browsers.</t>
  <t>SPUD must operate in the present Internet. In order to ensure deployment, it
must also be useful as an encapsulation between endpoints even before the
deployment of middleboxes that understand it.</t>
  <t>SPUD must be low-overhead, specifically requiring very little effort to
recognize that a packet is a SPUD packet and to determine the tube it is
associated with.</t>
  <t>SPUD must impose minimal restrictions on the transport protocols it
encapsulates.  SPUD must work in multipath, multicast, and mobile
environments.</t>
  <t>SPUD must provide incentives for development and deployment by multiple
communities.  These communities and incentives will be defined through the
prototyping process.</t>
</list></t>

</section>
<section anchor="lifetime-of-a-tube" title="Lifetime of a tube">

<t>A tube is a grouping of packets between two endpoints on the network.
Tubes are started by the “initiator” expressing an interest in comminicating
with the “responder”.  A tube may be closed by either endpoint.  </t>

<t>A tube may be in one of the following states:</t>

<t><list style="hanging">
  <t hangText='unknown'>
  no information is currently known about the tube.  All tubes
implicitly start in the unknown state.</t>
  <t hangText='opening'>
  the initiator has requested a tube that the responder has not yet
acknowledged.</t>
  <t hangText='running'>
  the tube is set up and will allow data to flow</t>
  <t hangText='resuming'>
  an out-of-sequence SPUD packet has been received for this tube.
Policy will need to be developed describing how (or if) this state can be
exploited for quicker tube resumption by higher-level protocols.</t>
</list></t>

<t>This leads to the following state transitions (see <xref target="commands"/> for details on
the commands that cause transitions):</t>

<figure title="State transitions" anchor="states"><artwork><![CDATA[
+---------------------+ +-----+
|                     | |close|
|                     v |     v
|        +---sopen--- +-------+ <--close----+
|        |            |unknown|             |
|        |    +-----> +-------+ -ack,--+    |
|        |    |            \     data  |    |
|        |  close         open         |    |
|        v    |              \         v    |
|       +-------+ ------data-------> +--------+
| +-----|opening|              )     |resuming|----+
| |     +-------+ <-----open-------- +--------+    |
| |       ^   |              /         |    ^      |
| |       |   |             v          |    |      |
| +-sopen-+   +-ack-> +-------+ <-ack,-+    +-data-+
|                     |running|   open
+---------close------ +-------+
                        ^    |
                        |    | open,ack,data
                        +----+
]]></artwork></figure>

<t>All of the state transitions happen when a command is received, except for the
“sopen” transition which occurs when an open command is sent.</t>

</section>
<section anchor="packet-layout" title="Packet layout">

<t>SPUD packets are sent inside UDP packets, with the SPUD header directly after
the UDP header.</t>

<figure title="SPUD packets" anchor="packet"><artwork><![CDATA[
0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       magic = 0xd80000d8                      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                            tube ID                            |
+                                                               +
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|cmd|a|p|  resv |           CBOR map...                         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
]]></artwork></figure>

<t>The fields in the packet are:</t>

<t><list style="symbols">
  <t>32-bit constant magic number (see <xref target="magic"/>)</t>
  <t>64 bits defining the id of this tube</t>
  <t>2 bits of command (see <xref target="commands"/>)</t>
  <t>1 bit marking this packet as an application declaration (adec)</t>
  <t>1 bit marking this packet as a path declaration (pdec)</t>
  <t>4 reserved bits that MUST be set to 0 for this version of the protocol</t>
  <t>If more bytes are present, they contain a CBOR map</t>
</list></t>

<section anchor="magic" title="Detecting usage">

<t>The first 32 bits of every SPUD packet is the constant bit pattern d80000d8
(hex), or 1101 1000 0000 0000 1101 1000 (binary).  This pattern was selected to
be invalid UTF-8, UTF-16 (both big- and little-endian), and UTF-32 (both big-
and little-endian).  The intent is to ensure that text-based non-SPUD protocols
would not use this pattern by mistake.  A survey of other protocols will be done
to see if this pattern occurs often in existing traffic.</t>

<t>The intent of this magic number is not to provide conclusive evidence that SPUD
is being used in this packet, but instead to allow a very fast (i.e., trivially
implementable in hardware) way to decide that SPUD is not in use on packets that
do not include the magic number.</t>

</section>
<section anchor="tube-id" title="TUBE ID">

<t>The 64-bit tube ID uniquely identifies a given tube.  All commands (see
<xref target="commands"/>) are scoped to a single tube.</t>

<t>[EDITOR’S NOTE: Does a Tube ID have to be bound to a single source address or
not?  This would be for mobility, not multipath.]</t>

</section>
<section anchor="commands" title="Commands">

<t>The next 2 bits of a SPUD packet encode a command:</t>

<t><list style="hanging">
  <t hangText='Data (00)'>
  Normal data in a running tube</t>
  <t hangText='Open (01)'>
  A request to begin a tube</t>
  <t hangText='Close (10)'>
  A request to end a tube</t>
  <t hangText='Ack (11)'>
  An acknowledgement to an open request</t>
</list></t>

</section>
<section anchor="declaration-bits" title="Declaration bits">

<t>The adec bit is set when the application is making a declaration to the path.
The pdec bit is set when the path is making a declaration to the application.</t>

</section>
<section anchor="reserved-bits" title="Reserved bits">

<t>The final required four bits of SPUD packet MUST all be set to zero in this
version of the protocol.  These bits could be used for extensions in future
versions.</t>

</section>
<section anchor="additional-information" title="Additional information">

<t>The information after the SPUD header (if it exists) is a CBOR <xref target="RFC7049"/> map
(major type 5). Each key in the map may be an integer (major type 0 or 1) or a
text string (major type 3).  Integer keys are reserved for standardized
protocols, with a registry defining their meaning.  This convention can save
several bytes per packet, since small integers only take a single byte in the
CBOR encoding, and a single-character string takes at least two bytes (more when
useful-length strings are used).</t>

<t>The only integer keys reserved by this version of the document are:</t>

<t><list style="hanging">
  <t hangText='0 (anything)'>
  Application Data. Any CBOR data type, used as application-specific data.
Often this will be a byte string (major type 2), particularly for protocols
that encrypt data.</t>
</list></t>

<t>The 0 key MUST NOT be used when the adec or pdec bit is set.  Path elements MUST
NOT inspect or modify the contents of the 0 key.</t>

<t>The overhead for always using CBOR is therefore effectively three or more bytes:
0xA1 (map with one element), 0x00 (integer 0 as the key), and 0x41 (byte string
containing one byte).  [EDITOR’S NOTE: It may be that the simplicity and
extensibility of this approach is worth the three bytes of overhead.]  </t>

</section>
</section>
<section anchor="initiating-a-tube" title="Initiating a tube">

<t>To begin a tube, the initiator sends a SPUD packet with the “open” command
(bits 01).  </t>

<t>Future versions of this specification may contain CBOR in the open packet.  One
example might be requesting proof of implementation from the receiving endpoint,</t>

</section>
<section anchor="acknowledging-tube-creation" title="Acknowledging tube creation">

<t>To acknowledge the creation of a tube, the responder sends a SPUD packet with
the “ack” command (bits 11).  The current thought is that the security provided
by the TCP three-way handshake would be left to transport protocols inside of
SPUD.  Further exploration of this prototype will help decide how much of this
handshake needs to be made visible to path elements that <spanx style="emph">only</spanx> process SPUD.</t>

<t>Future versions of this specification may contain CBOR in the ack packet.  One
example might be answering an implementation proof request from the initiator.</t>

</section>
<section anchor="closing-a-tube" title="Closing a tube">

<t>To close a tube, either side sends a packet with the “close” command (bits 10).
Whenever a path element sees a close packet for a tube, it MAY drop all stored
state for that tube.  Further exploration of this prototype will determine when
close packets are sent, what CBOR they contain, and how they interact with
transport protocols inside of SPUD.</t>

<t>What is likely at this time is that SPUD close packets MAY contain error
information in the following CBOR keys (and associated values):</t>

<t><list style="hanging">
  <t hangText='“error” (map, major type 5)'>
  a map from text string (major type 3) to text string.  The keys are
<xref target="RFC5646"/> language tags, and the values are strings that can be presented to
a user that understands that language.  The key “*” can be used as the
default.</t>
  <t hangText='“url” (text string, major type 3)'>
  a URL identifying some information about the path or its relationship with
the tube. The URL represents some path condition, and retrieval of
content at the URL should include a human-readable description.</t>
</list></t>

</section>
<section anchor="path-declarations" title="Path declarations">

<t>SPUD can be used for path declarations: information delivered to the endpoints
from devices along the path. Path declarations can be thought of as enhanced
ICMP for transports using SPUD, allowing information about the condition or
state of the path or the tube to be communicated directly to a sender.</t>

<t>Path declarations may be sent in either direction (toward the initiator or
responder) at any time.  The scope of a path declaration is the tube (identified
by tube ID) to which it is associated. Devices along the path cannot make
declarations to endpoints without a tube to associate them with.  Path
declarations are sent to one endpoint in a SPUD conversation by the path device
sending SPUD packets with the source IP address and UDP port from the other
endpoint in the conversation.  These “spoofed” packets  are required to allow
existing network elements that pass traffic for a given 5-tuple to continue to
work.  To ensure that the context for these declarations is correct, path
declaration packets MUST have the pdec bit set.  Path declarations MUST use the
“data” command (bits 00).</t>

<t>Path declarations do not imply specific required actions on the part of
receivers.  Any path declaration MAY be ignored by a receiving application.
When using a path declaration as input to an algorithm, the application will
make decisions about the trustworthiness of the declaration before using the
data in the declaration.</t>

<t>The data associated with a path declaration may always have the following keys
(and associated values), regardless of what other information is included:</t>

<t><list style="hanging">
  <t hangText='“ipaddr” (byte string, major type 2)'>
  the IPv4 address or IPv6 address of the sender, as a string of 4 or 16 bytes
in network order. This is necessary as the source IP address of the packet is
spoofed</t>
  <t hangText='“cookie” (byte string, major type 2)'>
  data that identifies the sending path element unambiguously</t>
  <t hangText='“url” (text string, major type 3)'>
  a URL identifying some information about the path or its relationship with
the tube. The URL represents some path condition, and retrieval of
content at the URL should include a human-readable description.</t>
  <t hangText='“warning” (map, major type 5)'>
  a map from text string (major type 3) to text string.  The keys are
<xref target="RFC5646"/> language tags, and the values are strings that can be presented to
a user that understands that language.  The key “*” can be used as the
default.</t>
</list></t>

<t>The SPUD mechanism is defined to be completely extensible in terms of the types
of path declarations that can be made. However, in order for this mechanism to
be of use, endpoints and devices along the path must share a relatively limited
vocabulary of path declarations. The following subsections briefly explore
declarations we believe may be useful, and which will be further developed on
the background of concrete use cases to be defined as part of the SPUD effort.</t>

<t>Terms in this vocabulary considered universally useful may be added to the SPUD
path declaration map keys, which in this case would then be defined as an IANA
registry.</t>

<section anchor="icmp" title="ICMP">

<t>ICMP <xref target="RFC4443"/> (e.g.) messages are sometimes blocked by path elements
attempting to provide  security.  Even when they are delivered to the host, many
ICMP messages are not  made available to applications through portable socket
interfaces.  As such, a path element might decide to copy the ICMP message
into a path declaration, using the following key/value pairs:</t>

<t><list style="hanging">
  <t hangText='“icmp” (byte string, major type 2)'>
  the full ICMP payload. This is  intended to allow ICMP messages (which may be
blocked by the path, or not made available to the receiving application) to be
bound to a tube. Note that sending a path declaration ICMP message is not a
substitute for sending a required ICMP or ICMPv6 message.</t>
  <t hangText='“icmp-type” (unsigned, major type 0)'>
  the ICMP type</t>
  <t hangText='“icmp-code” (unsigned, major type 0)'>
  the ICMP code</t>
</list></t>

<t>Other information from particular ICMP codes may be parsed out into key/value
pairs.</t>

</section>
<section anchor="address-translation" title="Address translation">

<t>SPUD-aware path elements that perform Network Address Translation MUST send a
path declaration describing the translation that was done, using the following
key/value pairs:</t>

<t><list style="hanging">
  <t hangText='“translated-external-address” (byte string, major type 2)'>
  The translated external IPv4 address or IPv6 address for this endpoint, as a
string of 4 or 16 bytes in network order</t>
  <t hangText='“translated-external-port” (unsigned, major type 0)'>
  The translated external UDP port number for this endpoint</t>
  <t hangText='“internal-address” (byte string, major type 2)'>
  The pre-translation (internal) IPv4 address or IPv6 address for this endpoint,
as a string of 4 or 16 bytes in network order</t>
  <t hangText='“internal-port” (unsigned, major type 0)'>
  The pre-translation (internal) UDP port number for this endpoint</t>
</list></t>

<t>The internal addresses are useful when multiple address translations take place
on the same path.</t>

</section>
<section anchor="tube-lifetime" title="Tube lifetime">

<t>SPUD-aware path elements that are maintaining state MAY drop state using
inactivity timers, however if they use a timer they MUST send a path declaration
in both directions with the length of that timer, using the following key/value
pairs:</t>

<t><list style="hanging">
  <t hangText='“inactivity-timer” (unsigned, major type 0)'>
  The length of the inactivity timer (in microseconds).  A value of 0 means no
timeout is being enforced by this path element, which might be useful if the
timeout changes over the lifetime of a tube.</t>
</list></t>

</section>
<section anchor="path-element-identity" title="Path element identity">

<t>Path elements can describe themselves using the following key/value pairs:</t>

<t><list style="hanging">
  <t hangText='“description” (text string, major type 3)'>
  the name of the software, hardware, product, etc. that generated the
declaration</t>
  <t hangText='“version” (text string, major type 3)'>
  the version of the software, hardware, product, etc. that generated the
declaration</t>
  <t hangText='“caps” (byte string, major type 2)'>
  a hash of the capabilities of the software, hardware, product, etc. that
generated the declaration [TO BE DESCRIBED]</t>
  <t hangText='“ttl” (unisigned integer, major type 0)'>
  IP time to live / IPv6 Hop Limit of associated device [EDITOR’S NOTE: more
detail is required on how this is calculated]</t>
</list></t>

</section>
<section anchor="maximum-datagram-size" title="Maximum Datagram Size">

<t>A path element may tell the endpoint the maximum size of a datagram it is
willing or able to forward for a tube, to augment various path MTU discovery
mechanisms.  This declaration uses the following key/value pairs:</t>

<t><list style="hanging">
  <t hangText='“mtu” (unsigned, major type 0)'>
  the maximum transmission unit (in bytes)</t>
</list></t>

</section>
<section anchor="rate-limit" title="Rate Limit">

<t>A path element may tell the endpoint the maximum data rate (in octets or
packets) that it is willing or able to forward for a tube. As all path
declarations are advisory, the device along the path must not rely on the
endpoint to set its sending rate at or below the declared rate limit, and
reduction of rate is not a guarantee to the endpoint of zero queueing delay.
This mechanism is intended for “gross” rate limitation, i.e. to declare that the
output interface is connected to a limited or congested link, not as a
substitute for loss-based or explicit congestion notification on the RTT
timescale.  This declaration uses the following key/value pairs:</t>

<t><list style="hanging">
  <t hangText='“max-byte-rate” (unsigned, major type 0)'>
  the maximum bandwidth (in bytes per second)</t>
  <t hangText='“max-packet-rate” (unsigned, major type 0)'>
  the maximum bandwidth (in packets
per second)</t>
</list></t>

</section>
<section anchor="latency-advisory" title="Latency Advisory">

<t>A path element may tell the endpoint the latency attributable to traversing that
path element. This mechanism is intended for “gross” latency advisories, for
instance to declare the output interface is connected to a satellite or
<xref target="RFC1149"/> link.  This declaration uses the following key/value pairs:</t>

<t><list style="hanging">
  <t hangText='“latency” (unsigned, major type 0)'>
  the latency (in microseconds)</t>
</list></t>

</section>
<section anchor="prohibition-report" title="Prohibition Report">

<t>A path element which refuses to forward a packet may declare why the packet was
not forwarded, similar to the various Destination Unreachable codes of ICMP.  </t>

<t>[EDITOR’S NOTE: Further thought will be given to how these reports interact with
the ICMP support from <xref target="icmp"/>.]</t>

</section>
</section>
<section anchor="declaration-reflection" title="Declaration reflection">

<t>In some cases, a device along the path may wish to send a path declaration but
may not be able to send packets ont he reverse path.  It may ask the endpoint in
the forward direction to reflect a SPUD packet back along the reverse path in
this case.</t>

<t>[EDITOR’S NOTE: Bob Briscoe raised this issue during the SEMI workshop, which
has largely to do with tunnels. It is not clear to the authors yet how a point
along the path would know that it must reflect a declaration, but this approach
is included for completeness.]</t>

<t>A reflected declaration is a SPUD packet with both the pdec and adec flags set,
and contains the same content as a path declaration would. However the packet
has the same source address and port and destination address and port as the
SPUD packet which triggered it.</t>

<t>When a SPUD endpoint receives a declaration reflection, it SHOULD reflect it:
swapping the source and destination addresses IP addresses and ports.  The
reflecting endpoint MUST unset the adec bit, sending the packet it as if it were
a path declaration.</t>

<t>[EDITOR’s NOTE: this facility will need careful security analysis before it
makes it into any final specification.]</t>

</section>
<section anchor="application-declarations" title="Application declarations">

<t>Applications may also use the SPUD mechanism to describe the traffic in the
tube to the application on the other side, and/or to any point along the
path. As with path declarations, the scope of an application declaration is the
tube (identified by tube ID) to which it is associated.</t>

<t>An application declaration is a SPUD packet with the adec flag set, and contains
an application declaration formatted in CBOR in its payload. As with path
declarations, an application declaration is a CBOR map, which may always have
the following keys:</t>

<t><list style="symbols">
  <t>cookie (byte string, major type 2): an identifier for this application
declaration, used to address a particular path element</t>
</list></t>

<t>Unless the cookie matches one sent by the path element for this tube, every
device along the path MUST forward application declarations on towards the
destination endpoint.</t>

<t>The definition of an application declaration vocabulary is left as future work;
we note only at this point that the mechanism supports such declarations.</t>

</section>
<section anchor="cbor-profile" title="CBOR Profile">

<t>Moving forward, we will likely specify a subset of CBOR that can be used in
SPUD, including the avoidance of floating point numbers, indefinite-length
arrays, and indefinite-length maps.  This will allow a significantly less
complicated CBOR implementation to be used, which would be particularly nice on
constrained devices.</t>

</section>
<section anchor="security-considerations" title="Security Considerations">

<t>This gives endpoints the ability to expose information about conversations to
elements on path.  As such, there are going to be very strict security
requirements about what can be exposed, how it can be exposed, etc.  This
prototype DOES NOT tackle these issues yet.</t>

<t>The goal is to ensure that this layer is better than TCP from a
security perspective.  The prototype is clearly not yet to that point.</t>

</section>
<section anchor="iana-considerations" title="IANA Considerations">

<t>If this protocol progresses beyond prototype in some way, a registry will be
needed for well-known CBOR map keys.</t>

</section>
<section anchor="acknowledgements" title="Acknowledgements">

<t>Thanks to Ted Hardie for suggesting the change from “Session” to “Substrate” in
the title, and to Joel Halpern for suggesting the change from “session” to
“tube” in the protocol description.</t>

</section>


  </middle>

  <back>

    <references title='Normative References'>

&RFC2119;
&RFC3168;
&RFC4443;
&RFC5646;
&RFC7049;


    </references>

    <references title='Informative References'>

&RFC1149;


    </references>



  </back>
</rfc>


PAFTECH AB 2003-20262026-04-24 01:07:20