skip to content

A TLS 1.3 subtitle feed stops arriving and the socket reports end of file - what must the receiver have seen for that to be an orderly close?

level: middleimportance: must knowfreq 66%

answer

  1. a clean end is announced, not inferred
  2. transport end of file proves nothing
  3. close_notify(0) marks the end of data
  4. no alert means a truncated stream
  5. TLS 1.3 closes each direction independently

basics

~20 s

A close_notify(0) alert is the only thing that marks an orderly end of data in TLS. A transport end of file with no close_notify is a truncated stream, and the receiver cannot tell a finished sender from a cut connection.

solid answer

~40 s

The transport's own end of file is unauthenticated - anyone on the path can produce it - so TLS does not treat it as the end of anything. The signal is `close_notify(0)`, an alert carried inside a protected record, which says the sender will send no more data on this connection. If the transport closes and no `close_notify` arrived, the stream was **truncated**: the receiver knows only that the bytes stopped, not whether the sender had finished. Where the application protocol allows data on the transport after TLS closes, an implementation must not report end-of-data to the application until it has received `close_notify`. For a continuous ingest feed that distinction is the whole question: a clean close means the broadcast ended, a truncation means something cut it.

code

pseudocode · 14 lines
pseudocode
function read_stream(connection):
    saw_close_notify = false
    for each record received from connection:
        if record.inner_type is alert:
            if record.alert is close_notify:
                saw_close_notify = true
                stop reading
            reject("peer sent an error alert")
        if record.inner_type is application_data:
            deliver(record.content)

    if not saw_close_notify:
        return "truncated: the stream ended without close_notify"
    return "orderly end of data"

go deeper

for a junior

Remember one fact: TLS ends cleanly only when close_notify arrives. A socket that just stops is a truncated stream, and the two are not the same outcome.

for a middle

Explain why the transport's own close cannot be trusted, what close_notify says about the sender's write side, and how a receiver records truncation as an outcome distinct from success.

for a senior

Show the operational consequence: an ingest that alarms on a missing close_notify catches cut feeds that a plain end-of-file read would record as a normal finish.

for a principal

The judgment is where truncation is detected and who is told. Decide once, for the estate, whether an incomplete stream is a client error, an alert, or silently retried - inconsistency here hides real outages.

## Closing is a message, not an event A TLS connection runs over a transport the peer does not control and cannot authenticate. A TCP FIN, a reset, or a middlebox dropping the flow all show up at the receiver in the same way: reads stop returning data. None of those is signed, keyed or protected by anything, so an on-path party can produce one at a moment of its choosing. If TLS treated a closed transport as the end of the data, the ending of every stream would be a decision the network could make. So TLS says the ending out loud. `close_notify(0)` is an alert carried inside an ordinary protected record, and it means exactly one thing: **the sender will send no more data on this connection**. Because it travels protected, a receiver that sees it knows the peer sent it. ## Orderly close versus truncation | what the receiver sees | what it may conclude | |---|---| | `close_notify(0)`, then the transport closes | the peer finished sending; the data is the whole of what it meant to send | | the transport closes with no alert at all | the stream was truncated; the peer may have finished, crashed, or been cut off | | an error alert, then the transport closes | the connection ended on a failure the peer named | The middle row is the one interviewers are after. "The connection closed" is not an answer, because the receiver has learned nothing about completeness. In a live-subtitle ingest, a feed that stops at 14:03 with `close_notify` is a broadcast that ended; a feed that stops at 14:03 with silence is an incident, and the ingest edge is entitled to alarm on exactly that difference. ## What changed in TLS 1.3 Closure in TLS 1.3 is **half-duplex and independent per direction**: - Each party sends `close_notify` before closing its own write side, unless it has already sent an error alert. - Sending it says nothing about the sender's read side, which may carry on receiving. - Earlier versions required a party that received `close_notify` to respond immediately with one of its own, discarding whatever it still had to write. That requirement is gone, precisely because it caused truncation on the other side. - A party need not wait to receive `close_notify` before closing its read side - but closing early reintroduces the possibility of truncation, which is the trade it is making. ## Alerts as record-layer machinery The alert protocol is the layer's own control channel, and it is small: 1. Every alert carries a level - warning or fatal - and a description. 2. In TLS 1.3 the level field decides almost nothing. `close_notify` and `user_canceled(90)` are the two alerts that are not error alerts; **every other alert is treated as an error and ends the connection regardless of the level byte it carries**. 3. Two failures the record layer raises on its own account, rather than on behalf of the handshake or the application, are `bad_record_mac(20)` when a record fails its integrity check and `record_overflow(22)` when a record's length exceeds the ceiling. 4. An alert is never fragmented across records, and one alert record carries one alert. Mapping other alert descriptions back to a configuration mistake is a diagnostic exercise; the point here is structural. `close_notify` is the only alert that is a *framing* statement rather than a failure, which is why it is the one that distinguishes the two ways a stream can stop. ## What a receiver should actually do - Track whether `close_notify` arrived, separately from the transport's own state. - Report end-of-data to the application only when it did. - When it did not, report a truncated stream as its own outcome, distinct from both success and a protocol error, so that the layer above can decide what an incomplete feed means for it. - Do not treat a missing `close_notify` as proof of an attack. A crashed sender and a cut connection look identical here; the honest statement is that the ending is unknown. The cost of ignoring all this is quiet. A receiver that treats the transport's end of file as a clean ending will never log an error, never fail a test, and will simply record fewer bytes than the sender sent, on the days when something goes wrong.

  • In TLS 1.3, which alerts are not error alerts, and what does the level field decide for the rest?
    `close_notify(0)` and `user_canceled(90)` are the two. Every other alert is treated as an error alert when received, regardless of whether its level byte says warning or fatal, and the connection ends. The level field therefore carries no decision for them; the description does.
  • Which failures does the record layer raise on its own, rather than on behalf of the handshake?
    Two: `bad_record_mac(20)` when a protected record fails its integrity check, and `record_overflow(22)` when a record's length exceeds the permitted ceiling. Both are fatal and end the connection immediately, and both are detected inside the record layer without the handshake or the application being involved.
  • Why can closure not simply be a transport-level signal?
    Because the transport's close is unauthenticated. Anyone on the path can close or reset the underlying connection, so a receiver that treats that as the end of data lets the network decide where the stream ended. close_notify travels inside a protected record, so only the peer can have produced it.

A courier who hands over the last parcel and says "that is everything" has told you the delivery is complete. A courier who simply stops arriving has told you nothing at all - and the two look identical if you only watch the door.

saying these in an interview costs you the question

  • Treats a closed transport as a clean TLS shutdown
  • Says end of file proves the sender finished sending
  • Calls close_notify an error alert that reports a failure
  • Claims receiving close_notify obliges you to discard pending writes
  • Thinks a truncated stream always means an attack