Re: [quicwg/base-drafts] Server should not accept 1-RTT traffic before handshake completion (#3159)

Antoine Delignat-Lavaud <notifications@github.com> Tue, 29 October 2019 16:05 UTC

Return-Path: <noreply@github.com>
X-Original-To: quic-issues@ietfa.amsl.com
Delivered-To: quic-issues@ietfa.amsl.com
Received: from localhost (localhost [127.0.0.1]) by ietfa.amsl.com (Postfix) with ESMTP id EAA1912006E for <quic-issues@ietfa.amsl.com>; Tue, 29 Oct 2019 09:05:55 -0700 (PDT)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: -8
X-Spam-Level:
X-Spam-Status: No, score=-8 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, HTML_MESSAGE=0.001, MAILING_LIST_MULTI=-1, RCVD_IN_DNSWL_HI=-5, SPF_HELO_NONE=0.001, SPF_PASS=-0.001] autolearn=ham autolearn_force=no
Authentication-Results: ietfa.amsl.com (amavisd-new); dkim=pass (1024-bit key) header.d=github.com
Received: from mail.ietf.org ([4.31.198.44]) by localhost (ietfa.amsl.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id kDnQqBQ4CyMe for <quic-issues@ietfa.amsl.com>; Tue, 29 Oct 2019 09:05:53 -0700 (PDT)
Received: from out-2.smtp.github.com (out-2.smtp.github.com [192.30.252.193]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by ietfa.amsl.com (Postfix) with ESMTPS id 48A1812002F for <quic-issues@ietf.org>; Tue, 29 Oct 2019 09:05:53 -0700 (PDT)
Received: from github-lowworker-2e54e43.va3-iad.github.net (github-lowworker-2e54e43.va3-iad.github.net [10.48.17.27]) by smtp.github.com (Postfix) with ESMTP id 9F63A1C063A for <quic-issues@ietf.org>; Tue, 29 Oct 2019 09:05:52 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=github.com; s=pf2014; t=1572365152; bh=Gj8OOEJtC07XY/UJdhMqBFBIIZsB+8qsptsAu5hnQeU=; h=Date:From:Reply-To:To:Cc:In-Reply-To:References:Subject:List-ID: List-Archive:List-Post:List-Unsubscribe:From; b=xQvF4dGe2eTq1XHaP+UFT1/g+a0iW0oNL6JRVFzRQtP3JNQPiL1Oq06ElsXBSzABe 1C/m/8RZuftgOAj7ckpDvs0YIolsE/S2NOnGIIqtPgmuBFBNdg7XVjdA3Usp2fuPXI /kB8wyfe4Orq2srty2UzAZFGSaI71S05lefmNALU=
Date: Tue, 29 Oct 2019 09:05:52 -0700
From: Antoine Delignat-Lavaud <notifications@github.com>
Reply-To: quicwg/base-drafts <reply+AFTOJK5YGWNUBKIK6AKZ3W53YWK6BEVBNHHB5FZ3ZY@reply.github.com>
To: quicwg/base-drafts <base-drafts@noreply.github.com>
Cc: Subscribed <subscribed@noreply.github.com>
Message-ID: <quicwg/base-drafts/issues/3159/547499323@github.com>
In-Reply-To: <quicwg/base-drafts/issues/3159@github.com>
References: <quicwg/base-drafts/issues/3159@github.com>
Subject: Re: [quicwg/base-drafts] Server should not accept 1-RTT traffic before handshake completion (#3159)
Mime-Version: 1.0
Content-Type: multipart/alternative; boundary="--==_mimepart_5db8636090fd1_3eb63fcb43ccd96013734e"; charset="UTF-8"
Content-Transfer-Encoding: 7bit
Precedence: list
X-GitHub-Sender: ad-l
X-GitHub-Recipient: quic-issues
X-GitHub-Reason: subscribed
X-Auto-Response-Suppress: All
X-GitHub-Recipient-Address: quic-issues@ietf.org
Archived-At: <https://mailarchive.ietf.org/arch/msg/quic-issues/OEkN0F-tIOVcSAFBy41Lt52ujB4>
X-BeenThere: quic-issues@ietf.org
X-Mailman-Version: 2.1.29
List-Id: Notification list for GitHub issues related to the QUIC WG <quic-issues.ietf.org>
List-Unsubscribe: <https://www.ietf.org/mailman/options/quic-issues>, <mailto:quic-issues-request@ietf.org?subject=unsubscribe>
List-Archive: <https://mailarchive.ietf.org/arch/browse/quic-issues/>
List-Post: <mailto:quic-issues@ietf.org>
List-Help: <mailto:quic-issues-request@ietf.org?subject=help>
List-Subscribe: <https://www.ietf.org/mailman/listinfo/quic-issues>, <mailto:quic-issues-request@ietf.org?subject=subscribe>
X-List-Received-Date: Tue, 29 Oct 2019 16:05:56 -0000

To help decide whether this is likely to be a problem, I decided to run an experiment. I wrote a very simple patch to OpenSSL to disable sending a finished:

```diff
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index a11ba60..9681787 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -439,6 +439,7 @@ static WRITE_TRAN ossl_statem_client13_write_transition(SSL *s)
         return WRITE_TRAN_CONTINUE;

     case TLS_ST_CR_FINISHED:
         if (s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY
                 || s->early_data_state == SSL_EARLY_DATA_FINISHED_WRITING)
             st->hand_state = TLS_ST_PENDING_EARLY_DATA_END;
@@ -446,8 +447,8 @@ static WRITE_TRAN ossl_statem_client13_write_transition(SSL *s)
                  && s->hello_retry_request == SSL_HRR_NONE)
             st->hand_state = TLS_ST_CW_CHANGE;
         else
-            st->hand_state = (s->s3.tmp.cert_req != 0) ? TLS_ST_CW_CERT
-                                                        : TLS_ST_CW_FINISHED;
+            st->hand_state = (s->s3.tmp.cert_req != 0) ? TLS_ST_CW_CERT : TLS_ST_OK;
         return WRITE_TRAN_CONTINUE;

     case TLS_ST_PENDING_EARLY_DATA_END:
@@ -459,8 +460,9 @@ static WRITE_TRAN ossl_statem_client13_write_transition(SSL *s)

     case TLS_ST_CW_END_OF_EARLY_DATA:
     case TLS_ST_CW_CHANGE:
-        st->hand_state = (s->s3.tmp.cert_req != 0) ? TLS_ST_CW_CERT
-                                                    : TLS_ST_CW_FINISHED;
+        st->hand_state = (s->s3.tmp.cert_req != 0) ? TLS_ST_CW_CERT : TLS_ST_OK;
         return WRITE_TRAN_CONTINUE;

     case TLS_ST_CW_CERT:
```

I checked with `openssl s_client -msg` to check that the patch works as expected. Then, I tried to connect to various public h3-23 endpoints listed on https://github.com/quicwg/base-drafts/wiki/Implementations using the ngtcp2 client built with my patched OpenSSL. The point of the experiment is to check which servers would acknowledge the short packets that I sent. Note that there can be false negatives in this experiment if the server is passing the 1-RTT data to the application but withholding the ACKS (this is insecure because the application may make unsafe side effects based on the received data, e.g. a POST/DELETE request).

Two servers on the list clearly implement a wrong behavior:

- quic.tech:4433 straight up acknowledged the 1-RTT packet in a short packet
```
I00000042 0xfd9df02263e4eeab1552a84d0e608bfa91 frm rx 0 Short(0x70) ACK(0x02) largest_ack=0 ack_delay=15(1919) ack_block_count=0
I00000042 0xfd9df02263e4eeab1552a84d0e608bfa91 frm rx 0 Short(0x70) ACK(0x02) block=[0..0] block_count=0
```

- http3-test.litespeedtech.com: acknowledges the client 1-RTT packet, but does that in an handshake packet (!)
```
I00000618 0x7d6af4994dbcab77dba708cb2ab0ef553f pkt rx pkn=5 dcid=0x7d6af4994dbcab77dba708cb2ab0ef553f scid=0x4b54982b8489544f type=Handshake(0x02) len=22 k=0
I00000618 0x7d6af4994dbcab77dba708cb2ab0ef553f frm rx 5 Handshake(0x02) ACK(0x02) largest_ack=0 ack_delay=0(0) ack_block_count=0
I00000618 0x7d6af4994dbcab77dba708cb2ab0ef553f frm rx 5 Handshake(0x02) ACK(0x02) block=[0..0] block_count=0
I00000618 0x7d6af4994dbcab77dba708cb2ab0ef553f pkt read packet 56 left 0
```

It seems very likely that some implementations will ignore this requirement in practice (and understandably so, as buffering the 1-RTT packets is expensive), to the point that I think it is worth making the correct behavior verifiable by the client (as it somewhat exposes the client in the downgrade case, although a complete exploit seems unlikely with a signature, and difficult with a PSK binder)

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3159#issuecomment-547499323