Re: [TLS] Sending fatal alerts over TCP

Martin Rex <> Wed, 21 December 2011 19:13 UTC

Return-Path: <>
Received: from localhost (localhost []) by (Postfix) with ESMTP id 5653E21F84FA for <>; Wed, 21 Dec 2011 11:13:40 -0800 (PST)
X-Virus-Scanned: amavisd-new at
X-Spam-Flag: NO
X-Spam-Score: -7.403
X-Spam-Status: No, score=-7.403 tagged_above=-999 required=5 tests=[AWL=-2.754, BAYES_00=-2.599, GB_SUMOF=5, HELO_EQ_DE=0.35, J_CHICKENPOX_101=0.6, RCVD_IN_DNSWL_HI=-8]
Received: from ([]) by localhost ( []) (amavisd-new, port 10024) with ESMTP id IrxGw4LlxxGS for <>; Wed, 21 Dec 2011 11:13:39 -0800 (PST)
Received: from ( []) by (Postfix) with ESMTP id 3478521F84E5 for <>; Wed, 21 Dec 2011 11:13:38 -0800 (PST)
Received: from by (26) with ESMTP id pBLJDYhX001815 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Wed, 21 Dec 2011 20:13:34 +0100 (MET)
From: Martin Rex <>
Message-Id: <>
To: (Bodo Moeller)
Date: Wed, 21 Dec 2011 20:13:33 +0100 (MET)
In-Reply-To: <> from "Bodo Moeller" at Dec 21, 11 11:07:09 am
MIME-Version: 1.0
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 8bit
X-SAP: out
Subject: Re: [TLS] Sending fatal alerts over TCP
X-Mailman-Version: 2.1.12
Precedence: list
List-Id: "This is the mailing list for the Transport Layer Security working group of the IETF." <>
List-Unsubscribe: <>, <>
List-Archive: <>
List-Post: <>
List-Help: <>
List-Subscribe: <>, <>
X-List-Received-Date: Wed, 21 Dec 2011 19:13:40 -0000

Bodo Moeller wrote:
> > > > (1)  X sends a fatal TLS alert to Y
> > > > (2)  X shuts down the connection
> > > > (3)  Y sends data to X
> > > > (4)  X receives from Y, sends RST to signal data loss to Y
> > > > (5)  Y receives RST
> > > >
> > > > (6) At this point, when Y tries to send further data,
> > > > it will receive EPIPE from the sockets API.
> > > > When it tries to read data, it will receive ECONNRESET.
> >
> > As long as Y does not call shutdown() on the socket, it will
> > receive all data that arrived on the socket prior to seeing
> > End-of-file (X with SO_LINGER) or ECONNRESET (X without SO_LINGER)
> > on recv().
> >
> That's not right.  Upon receiving RST, Y's TCP will reset the state for
> this connection and discard any data already buffered; no further data can
> be received by the application (in this case, by the TLS implementation);
> check RFC 793 for RST processing details.  If X doesn't want that, it must
> not send an RST.

That is not what my copies of rfc793 and rfc1122 specify.

Unless the local application performs a shutdown(), the TCP implementation
of Y MUST continue to deliver data that was received.

(4) from above indicates that X must have changed the SO_LINGER
socket option and called close() on the connection rather than
shutdown(SHUT_RD). (see Stevens, Unix Network Programming Vol.1,
on my second edition it is section 7.5, figure 7.10, page 191,
"close, l_onoff=1, l_linger=0") with the result that the TCP of X
has no more memories about the connection and considers the
connection "CLOSED".    In the alternative situation, X's TCP would
have sent a TCP FIN and be in the synchronized state FIN_WAIT_1.

rfc793 on Reset generation:

  Reset Generation

  As a general rule, reset (RST) must be sent whenever a segment arrives
  which apparently is not intended for the current connection.  A reset
  must not be sent if it is not clear that this is the case.

Specified processing for X in (CLOSED):

  There are three groups of states:

    1.  If the connection does not exist (CLOSED) then a reset is sent
    in response to any incoming segment except another reset.  In
    particular, SYNs addressed to a non-existent connection are rejected
    by this means.

    If the incoming segment has an ACK field, the reset takes its
    sequence number from the ACK field of the segment, otherwise the
    reset has sequence number zero and the ACK field is set to the sum
    of the sequence number and segment length of the incoming segment.
    The connection remains in the CLOSED state.

which means that X must send an RST with a SEQ number of 0!

Specified processing for X in (FIN_WAIT_1):

    3.  If the connection is in a synchronized state (ESTABLISHED,
    any unacceptable segment (out of window sequence number or
    unacceptible acknowledgment number) must elicit only an empty
    acknowledgment segment containing the current send-sequence number
    and an acknowledgment indicating the next sequence number expected
    to be received, and the connection remains in the same state.

    If an incoming segment has a security level, or compartment, or
    precedence which does not exactly match the level, and compartment,
    and precedence requested for the connection,a reset is sent and
    connection goes to the CLOSED state.  The reset takes its sequence
    number from the ACK field of the incoming segment.

which means that X must not send an RST at all.
On Shutdown() X dropped its receive buffer (so that the receive window
is now 0 (Zero)), but still knows the incoming Seqence number.  So
any further incoming data is "out of window" and must elicit only an
empty acknowledgement segment (rather than RST).

Now looking at the requirements for the RST processing:

  Reset Processing

  In all states except SYN-SENT, all reset (RST) segments are validated
  by checking their SEQ-fields.  A reset is valid if its sequence number
  is in the window.  In the SYN-SENT state (a RST received in response
  to an initial SYN), the RST is acceptable if the ACK field
  acknowledges the SYN.

  The receiver of a RST first validates it, then changes state.  If the
  receiver was in the LISTEN state, it ignores it.  If the receiver was
  in SYN-RECEIVED state and had previously been in the LISTEN state,
  then the receiver returns to the LISTEN state, otherwise the receiver
  aborts the connection and goes to the CLOSED state.  If the receiver
  was in any other state, it aborts the connection and advises the user
  and goes to the CLOSED state.

The RST generated by X at (CLOSED) has a SEQ 0, so it very probably
fail SEQ-validation and must be completely ignored by Y's TCP
Y is still in ESTABLISHED, because X didn't send a FIN.
If X had sent a FIN, then Y would be in CLOSE_WAIT, but X would 
have been prohibited to sent a FIN (and required to send an empty ACK

  3.5. Closing a Connection

  CLOSE is an operation meaning "I have no more data to send."  The
  notion of closing a full-duplex connection is subject to ambiguous
  interpretation, of course, since it may not be obvious how to treat
  the receiving side of the connection.  We have chosen to treat CLOSE
  in a simplex fashion.  The user who CLOSEs may continue to RECEIVE
  until he is told that the other side has CLOSED also.  Thus, a program
  could initiate several SENDs followed by a CLOSE, and then continue to
  RECEIVE until signaled that a RECEIVE failed because the other side
  has CLOSED.  We assume that the TCP will signal a user, even if no
  RECEIVEs are outstanding, that the other side has closed, so the user
  can terminate his side gracefully.  A TCP will reliably deliver all
  buffers SENT before the connection was CLOSED so a user who expects no
  data in return need only wait to hear the connection was CLOSED
  successfully to know that all his data was received at the destination
  TCP.  Users must keep reading connections they close for sending until
  the TCP says no more data.