Subject: [BEEPwg] Trouble with TLS and transport mappings

From: Jered Floyd <[email-masked]>
Date: 19 Nov 2001 15:43:03 -0500

Greetings,

I have encountered another (somewhat obscure) case in RFC 3080 where I
am unsure what the proper behaviour is for a BEEP library; or rather,
I am sure what the proper behaviour is, and also sure that it would
lead to deadlock.

RFC 3080, Section 3.1.3.1 states:

  When a BEEP peer sends the "ready" element, it MUST NOT send any
  further traffic on the underlying transport service until a
  corresponding reply ("proceed" or "error") is received; ...
  [emphasis mine]

This clearly includes SEQ frames, and must do so to ensure the
connection streams are in a consistent state when the underlying
negotiation process begins.

If the peer that sends the "ready" element cannot send SEQ frames for
the channel upon which it expects a reply (zero in the case of a
piggybacked request, some other channel in the case of a started
channel) it is not always possible for the remote peer to send its
response.  If the response to be sent exceeds the channel window size,
the peer that sent the "ready" element has no way to indicate to the
responding peer that more space is available after it partially
processes the response, as it is unable to send SEQ frames.

This cannot be fixed by allowing SEQ frames until the last frame of
the response is received; the peer has know way of knowing if the last
frame is already 'on the wire' when it sends a SEQ, and thus could
send a SEQ after the remote peer believes that the next bytes to be
received should correspond to the underlying negotiation process.

An example of a TLS negotation attempt that must result in deadlock
under the current guidelines:

C: MSG 0 1 . 52 158
C: Content-Type: application/beep+xml
C:
C: <start number='1'>
C:    <profile uri='http://iana.org/beep/TLS'>
C:       <![CDATA[<ready />]]>
C:    </profile>
C: </start>
C: END
S: RPY 0 1 * 110 4096
S: Content-Type: application/beep+xml
S:
S: <profile uri='http://iana.org/beep/TLS'>
S:    <![CDATA[<error code='554'>This is a very long error response
S:             that is still within the 4K limit for an initialization
S:             message embedded in a "start" transaction, but brings
S:             the channel zero message size to above the size of
S:             the channel zero TCP mapping window [more data here
S:             to reach 4K within this frame...]
S: END
<peer 'S' is now waiting for window space to become available so that
 it may send the remainder of RPY 1.>

(A successful negotation request for TLS that results in deadlock
would be extremely contrived, but this may not be the case for other
profiles that implement transport level security.)

It is insufficient to limit the full channel zero response to a tuning
request to less than 4K, as there's no reason in RFC 3081 for the peer
to necessarily have advertised that it has a completely empty window
(thus at least 4K).

The only solution I have come up with is to declare at the transport
level that channels implementing a tuning profile disregard the window
mechanism; the sending peer may send data at any time and the
recipient must be prepared to accept it.  I don't find this solution
particularly pleasing.

Does anyone have a better counter-proposal?

--Jered

_______________________________________________
BEEPwg mailing list
[email-masked]
http://lists.beepcore.org/mailman/listinfo/beepwg

---

From: "Marshall T. Rose" <[email-masked]>
Date: Mon, 19 Nov 2001 15:24:40 -0800

> recipient must be prepared to accept it.  I don't find this solution

doesn't this fall under the category that people doing stupid things deserve
what they get?

> Does anyone have a better counter-proposal?

it seems to me that it's worthwhile to note in the discussion on processing
the "<ready>" element, that the window isn't going to get updated and that
when a reply is generated it must fit within the window advertised...

/mtr

---

From: Jered Floyd <[email-masked]>
Date: 20 Nov 2001 16:24:07 -0500

"Marshall T. Rose" <[email-masked]> writes:

> doesn't this fall under the category that people doing stupid things
> deserve what they get?

I'm not sure I follow.  I agree that the example I gave was rather
contrived, but only because I was trying to demonstrate the issue
with minimal setup.  

> when a reply is generated it must fit within the window advertised...

Because a peer must process any pending replies before a <proceed/>
element may be returned, and some of these replies may be on the same
channel that the <proceed/> is to be returned upon, the window size
could be arbitrarily small; in fact, the advertised window could be
full even before the response to the <ready/> is generated.  In the
case of a connection that is significantly active before tls
negotiation occurs, I believe that in some cases there is nothing that
the peer can do to avoid deadlock.

Anyway, while that sits I have some slightly less pedantic tls-related
questions:

1) Once transport layer security of any kind has been negotiated, may
   a different tls negotiation occur?  Section 4.1 makes it clear that
   this is *not* allowed with SASL profiles ("Once transport security
   is successfully negotiated for a BEEP session, then a SASL security
   layer must not be negotiated; similarly, once any SASL negotiation
   is successful, a transport security profile must not begin its
   underlying negotiation process"), but RFC 3080 isn't clear on tls
   in general.

2) Re: TLS, Section 3.1.3.1 says:
      When a BEEP peer sends the "ready" element, it must not send any
      further traffic on the underlying transport service until a
      corresponding reply ("proceed" or "error") is received;
      similarly, the receiving BEEP peer must wait until any pending
      replies have been generated and sent before it processes a
      "ready" element.

   Consider the case in which several frames (but on the final frame)
   of a request have been sent on channel 1, and the same peer wishes
   to request TLS in a piggybacked message on channel 0. Should this
   be interpreted to mean:

      a) A BEEP peer must not sent a "ready" element until there are
         no partially-sent messages on any channel, or

      b) A BEEP peer should not consider partially-received messages
         to be pending replies?

   I greatly prefer the former interpretation, but I'm not sure this
   is correct.

--Jered

---

From: Jered Floyd <[email-masked]>
Date: 20 Nov 2001 16:55:17 -0500

>    I greatly prefer the former interpretation, but I'm not sure this

Err; strike that; I greatly prefer the latter interpretation because
the former is quite obnoxious to implement, but I can't find strong
support for either interpretation.

--jered

---

From: "Marshall T. Rose" <[email-masked]>
Date: Tue, 20 Nov 2001 14:51:34 -0800

maybe i'm missing the big picture here, but i don't understand why this
small problem requires a big solution.

anyone who sends a 4K+ "error" or "proceed" element has big problems. so, i
return to my suggestion that we add a sentence to the paragraph that talks
about the processing of the "ready" element that reminds implementors that
folks who try to use the "error" element as some kind of covert bulk
transfer facility are going to lose big...

/mtr

---

From: "Marshall T. Rose" <[email-masked]>
Date: Tue, 20 Nov 2001 14:55:08 -0800

i don't think beep has enough in it to solve the byzantine generals'
problem.

so, i think it wise that implementations try to avoid the problem
altogether.

for example, you shouldn't start the TLS profile if you have something
outstanding. this applies both to the peer who sends the start and the peer
who receives the start.

similarly, once a TLS channel is started, each peer shouldn't allow other
channels to be started or to send traffic.

/mtr

---

From: Jered Floyd <[email-masked]>
Date: 21 Nov 2001 15:26:00 -0500

> i don't think beep has enough in it to solve the byzantine generals'

I agree entirely.  But I believe that it is our responsibility in
defining a standard to avoid issues that are open to interpretation,
or that allow applications to get into untenable states.

Either the definition of BEEP should be expanded to address issues
that could affect implementation interoperability, or (much
preferably) BEEP should be restricted so that the situation cannot
occur.  I believe that my most recent concern is addressed by the
following change in Section 3.1.3.1:

  [...]; similarly, the receiving BEEP peer must wait until any
  pending replies have been generated and sent before it processes
  a "ready" element.

changes to:

  [...]; similarly, the receiving BEEP peer may wait until any
  pending replies to messages that have been fully received 
  have been generated and sent before it processes a "ready" 
  element.

In any case, the specification should document recommendations to
implementors on how to be good network citizens.  This is also why I
previously brought up the lack of recommendation to avoid sending many
small frames (as appears in TCP).

Yes, I am being obtuse.  Yes, I am being pedantic. But BEEP is a
standards track RFC, and I'd like to see it become a standard.

I'll be out of contact for the remainer of the week and early next.
To the US participants of this list, happy thanksgiving!

--Jered

---

From: "Marshall T. Rose" <[email-masked]>
Date: Wed, 21 Nov 2001 15:33:36 -0800

> I believe that my most recent concern is addressed by the

this would work, although you probably meant to say "must" instead of "may".

thanks,

/mtr

---

From: Jered Floyd <[email-masked]>
Date: 27 Nov 2001 11:32:39 -0500

> this would work, although you probably meant to say "must" instead

Great; works for me.  What's the next step?  Do we just note this and
remember it for when a specification revision occurs?

Something I mentioned 2 messages ago but didn't see an opinion on:
Once transport layer security of any kind has been negotiated, may a
different tls negotiation occur? Section 4.1 makes it clear that the
BEEP SASL profile (as opposed to the SASL BEEP profiles, argh)
explicitly does not permit multiple successful SASL negotiations.
Other (non-SASL) tls negotations are outside the scope of this,
though.

It would be consistent with the choice made in Section 4.1 to add
after the fist paragraph of section 3 the following:

  "Only one successful transport security negotiation may occur
   in a protocol session."

Would you be amenable to this?

The other option would be to explicitly allow multiple tls
negotations.  To be consistent with RFC 2222 (SASL) Section 5.3, only
one security layer may be in effect; if a subsequent negotiation
selects a second security layer, then the second security layer
replaces the first.  If this is preferred, then Section 4.1 of RFC
3080 should be changed to explicitly allow multiple SASL negotiations.

I can think of no reason to support this beyond paranoia; i.e. wishing
to obscure a high-security tls negotiation within a weakly-secured
connection.

Finally, while we're squashing issues, I'll bring up two options for
resolving my previous concern regarding the character set of base64
encoded initialization messages.

1) If backwards-compatibility is not a concern:

Errata against RFC 3080: the 'encoding' attribute is depricated.
Initialization messages as described in Section 2.3.1.2 are precisely
BEEP Messages, as defined in Section 2.2. A
"Content-Transfer-Encoding" may be specified to protect content.

Additionally, the default "Content-Type" could be
"application/beep+xml", which would maintain compatibility with
existing beep+xml profiles (such as TLS and SASL profiles). (This
would only add an additional newline to the head of the initialization
message.)

2) If backwards compatibility is a concern:

The 'base64' value for the 'encoding' attribute should not be used.
The 'encoding' attribute may take the value 'msg', in which case the
content is interpreted as a BEEP Message, as described in option 1
above.  Support for this is indicated via a feature in the greeting.

Which is the better solution?

--Jered

---

From: "Marshall T. Rose" <[email-masked]>
Date: Tue, 27 Nov 2001 10:41:29 -0800

> remember it for when a specification revision occurs?

presumably, at some time in the future, the wg will reactivate and look at
what changes and errata need to be me made.

>   "Only one successful transport security negotiation may occur

that sounds fine.

> encoded initialization messages.

i think i'd rather think on this for a while, since there's no particular
rush to resolve it until the wg reactivates.

/mtr

---

From: Darren New <[email-masked]>
Date: Wed, 28 Nov 2001 10:34:22 -0800

> contrived, but only because I was trying to demonstrate the issue

We call this a "Doctor Doctor!" error.   "Doctor, Doctor, it hurts when
I do this!"

> the peer can do to avoid deadlock.

Well, what the sender of the <ready> has to do is to avoid that
situation. Hence, in our implementations (or at least the one's I've
looked at closely), the profile implementations are told that a tuning
reset is about to start, they all stop processing outgoing messages
(just as if channel 0 was closing), and then finally the SEQ for the
channel carrying the <ready/> is sent to fully open the window, then the
<ready/> is sent. Only the channel on which the <ready/> is sent is
processed until either the error or the <proceed/> comes back. Yes, it's
kind of a pain in the butt. If you start a tuning reset while the other
side is half way thru sending a MSG, you're going to lose something, but
both sides will know what happened.

>    I greatly prefer the former interpretation, but I'm not sure this

I've been interpreting it as (a). That is, the <ready> doesn't get sent
until all the channels with outgoing frames have had them sent and
responses to all of those have been received. If the remote side has
MSGs to send and it receives a <ready>, it has the choice of either
telling the profiles that their MSGs have been lost due to a tuning
reset, or rejecting the <ready> with an <error>.

In summary, this is the way the beepcore-C team worked out what must
happen:

Without loss of generality, assume it's the initiator that wants to
tuning-reset. The initiator's TLS profile informs all open
initiator-side profiles that a tuning reset is starting, and gets
permission. It then waits until all outgoing MSGs have been sent and
answered. Initiator-side profiles have to stop sending MSGs just as if
channel 0 was being closed (which it is, basically). Then the SEQ for
the channel being tuned (0 if piggybacked) is sent, and then the <ready>
is sent. No other channels are processed until the response to the
<ready> is returned. Since they're not being processed, they don't send
SEQs. The listener side gets the <ready>, asks all the listener-side
profiles whether they're happy to be tuning-reset, and if so, sends the
<proceed>, then tosses any buffered data and generally "does" the reset.
If a listener-side profile says it doesn't want to reset, then an
<error> is sent back. On the initiator side, an <error> rolls back the
tuning reset request and everyone's free to process again, while a
<proceed> starts the tuning process.

-- 
Darren New 
San Diego, CA, USA (PST). Cryptokeys on demand.
   You will soon read a generic fortune cookie.
_______________________________________________
BEEPwg mailing list
[email-masked]
http://lists.beepcore.org/mailman/listinfo/beepwg

---

From: "Huston" <[email-masked]>
Date: Fri, 30 Nov 2001 10:15:20 -0700

> would only add an additional newline to the head of the initialization

If backwards-compatibility is not a concern, my vote is to make it
consistent with all other messages including the default "Content-Type".
This way beep libraries don't have to do anything special with the
piggyback'd data and to profiles the piggyback'd data will look just the
same as if it had been sent in the first MSG.

--Huston

---

From: Darren New <[email-masked]>
Date: Fri, 30 Nov 2001 11:08:16 -0800

> same as if it had been sent in the first MSG.

If backwards compatibility (with profile specifications) is a concern,
one could add an encoding value that means it's MIME-encoded all the
way. I.e., <... encoding="mime"> could indicate that the piggyback data
has content-type and perhaps content-transfer-encoding headers.

---

From: Jered Floyd <[email-masked]>
Date: 30 Nov 2001 15:22:28 -0500

One more thought on this before I let it rest;

Embedding a BEEP message proper within the content of a 'profile'
element presents some concerns that can be worked around, but are
layering violations. For example, if the outer message body has
(for some reason) a content-transfer encoding of 7bit, but 8bit 
data is present in the initialization message, one or the other
needs to know to use a transformative encoding instead.

OK, that was obscure; how about: if ']]>' appears in the
initialization message, a transformative encoding must be used (so
that it may be embedded in an XML CDATA.) This imposes additional
restrictions upon a MIME composer used to form initialization
messages. 

Something I would find a better (cleaner) solution:

'start' messages may be of MIME type multipart/mixed, where the first
part is the application/beep+xml message part, and all subsequent
parts are initialization messages for the identified profiles in 
the 'start' message.

This allows the MIME body to be delivered as an initialization message
to be precisely a BEEP message body.

--Jered

---

From: Darren New <[email-masked]>
Date: Fri, 30 Nov 2001 12:56:06 -0800

> Something I would find a better (cleaner) solution:

Actually, I think the better cleaner solution would be the original BXXP
solution, which was that a piggyback message is an XML fragment, and if
that wasn't good enough, don't piggyback the first message. ;-)

---

From: "Marshall T. Rose" <[email-masked]>
Date: Fri, 30 Nov 2001 13:07:53 -0800

> that wasn't good enough, don't piggyback the first message. ;-)

darren - where's the fun in that?

everytime someone adds to this thread, the solution becomes more complex. i
am deeply shocked that you would buck this trend...

/mtr