From 98775205fa6daaa784876d020a9f743bbffbf9f7 Mon Sep 17 00:00:00 2001
From: jsing <>
Date: Sun, 21 Aug 2022 19:42:15 +0000
Subject: Provide the remaining QUIC API.

While more work is still required, this is sufficient to get ngtcp2 to
compile with QUIC and for curl to be able to make HTTP/3 requests.

ok tb@
---
 src/lib/libssl/ssl.h     |  44 ++++++++++++++++++-
 src/lib/libssl/ssl_lib.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 149 insertions(+), 2 deletions(-)

(limited to 'src')

diff --git a/src/lib/libssl/ssl.h b/src/lib/libssl/ssl.h
index be116de775..caee3d60d9 100644
--- a/src/lib/libssl/ssl.h
+++ b/src/lib/libssl/ssl.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssl.h,v 1.226 2022/08/21 19:32:38 jsing Exp $ */
+/* $OpenBSD: ssl.h,v 1.227 2022/08/21 19:42:15 jsing Exp $ */
 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
  * All rights reserved.
  *
@@ -1742,6 +1742,41 @@ int SSL_set_quic_method(SSL *ssl, const SSL_QUIC_METHOD *quic_method);
 /* SSL_is_quic returns true if an SSL has been configured for use with QUIC. */
 int SSL_is_quic(const SSL *ssl);
 
+/*
+ * SSL_quic_max_handshake_flight_len returns returns the maximum number of bytes
+ * that may be received at the given encryption level. This function should be
+ * used to limit buffering in the QUIC implementation. See RFC 9000 section 7.5.
+ */
+size_t SSL_quic_max_handshake_flight_len(const SSL *ssl,
+    enum ssl_encryption_level_t level);
+
+/*
+ * SSL_quic_read_level returns the current read encryption level.
+ */
+enum ssl_encryption_level_t SSL_quic_read_level(const SSL *ssl);
+
+/*
+ * SSL_quic_write_level returns the current write encryption level.
+ */
+enum ssl_encryption_level_t SSL_quic_write_level(const SSL *ssl);
+
+/*
+ * SSL_provide_quic_data provides data from QUIC at a particular encryption
+ * level |level|. It returns one on success and zero on error. Note this
+ * function will return zero if the handshake is not expecting data from |level|
+ * at this time. The QUIC implementation should then close the connection with
+ * an error.
+ */
+int SSL_provide_quic_data(SSL *ssl, enum ssl_encryption_level_t level,
+    const uint8_t *data, size_t len);
+
+/*
+ * SSL_process_quic_post_handshake processes any data that QUIC has provided
+ * after the handshake has completed. This includes NewSessionTicket messages
+ * sent by the server. It returns one on success and zero on error.
+ */
+int SSL_process_quic_post_handshake(SSL *ssl);
+
 /*
  * SSL_set_quic_transport_params configures |ssl| to send |params| (of length
  * |params_len|) in the quic_transport_parameters extension in either the
@@ -1763,6 +1798,13 @@ int SSL_set_quic_transport_params(SSL *ssl, const uint8_t *params,
 void SSL_get_peer_quic_transport_params(const SSL *ssl,
     const uint8_t **out_params, size_t *out_params_len);
 
+/*
+ * SSL_set_quic_use_legacy_codepoint configures whether to use the legacy QUIC
+ * extension codepoint 0xffa5 as opposed to the official value 57. This is
+ * unsupported in LibreSSL.
+ */
+void SSL_set_quic_use_legacy_codepoint(SSL *ssl, int use_legacy);
+
 #endif
 
 void ERR_load_SSL_strings(void);
diff --git a/src/lib/libssl/ssl_lib.c b/src/lib/libssl/ssl_lib.c
index f0f0150d19..c0ca19c7c1 100644
--- a/src/lib/libssl/ssl_lib.c
+++ b/src/lib/libssl/ssl_lib.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssl_lib.c,v 1.303 2022/08/21 19:32:38 jsing Exp $ */
+/* $OpenBSD: ssl_lib.c,v 1.304 2022/08/21 19:42:15 jsing Exp $ */
 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
  * All rights reserved.
  *
@@ -2607,6 +2607,105 @@ SSL_set_quic_method(SSL *ssl, const SSL_QUIC_METHOD *quic_method)
 	return 1;
 }
 
+size_t
+SSL_quic_max_handshake_flight_len(const SSL *ssl,
+    enum ssl_encryption_level_t level)
+{
+	size_t flight_len;
+
+	/* Limit flights to 16K when there are no large certificate messages. */
+	flight_len = 16384;
+
+	switch (level) {
+	case ssl_encryption_initial:
+		return flight_len;
+
+	case ssl_encryption_early_data:
+		/* QUIC does not send EndOfEarlyData. */
+		return 0;
+
+	case ssl_encryption_handshake:
+		if (ssl->server) {
+			/*
+			 * Servers may receive Certificate message if configured
+			 * to request client certificates.
+			 */
+			if ((SSL_get_verify_mode(ssl) & SSL_VERIFY_PEER) != 0 &&
+			    ssl->internal->max_cert_list > flight_len)
+				flight_len = ssl->internal->max_cert_list;
+		} else {
+			/*
+			 * Clients may receive both Certificate message and a
+			 * CertificateRequest message.
+			 */
+			if (ssl->internal->max_cert_list * 2 > flight_len)
+				flight_len = ssl->internal->max_cert_list * 2;
+		}
+		return flight_len;
+	case ssl_encryption_application:
+		/*
+		 * Note there is not actually a bound on the number of
+		 * NewSessionTickets one may send in a row. This level may need
+		 * more involved flow control.
+		 */
+		return flight_len;
+	}
+
+	return 0;
+}
+
+enum ssl_encryption_level_t
+SSL_quic_read_level(const SSL *ssl)
+{
+	return ssl->s3->hs.tls13.quic_read_level;
+}
+
+enum ssl_encryption_level_t
+SSL_quic_write_level(const SSL *ssl)
+{
+	return ssl->s3->hs.tls13.quic_write_level;
+}
+
+int
+SSL_provide_quic_data(SSL *ssl, enum ssl_encryption_level_t level,
+    const uint8_t *data, size_t len)
+{
+	if (!SSL_is_quic(ssl)) {
+		SSLerror(ssl, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+		return 0;
+	}
+
+	if (level != SSL_quic_read_level(ssl)) {
+		SSLerror(ssl, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED);
+		return 0;
+	}
+
+	if (ssl->s3->hs.tls13.quic_read_buffer == NULL) {
+		ssl->s3->hs.tls13.quic_read_buffer = tls_buffer_new(0);
+		if (ssl->s3->hs.tls13.quic_read_buffer == NULL) {
+			SSLerror(ssl, ERR_R_MALLOC_FAILURE);
+			return 0;
+		}
+	}
+
+	/* XXX - note that this does not currently downsize. */
+	tls_buffer_set_capacity_limit(ssl->s3->hs.tls13.quic_read_buffer,
+	    SSL_quic_max_handshake_flight_len(ssl, level));
+
+	/*
+	 * XXX - an append that fails due to exceeding capacity should set
+	 * SSL_R_EXCESSIVE_MESSAGE_SIZE.
+	 */
+	return tls_buffer_append(ssl->s3->hs.tls13.quic_read_buffer, data, len);
+}
+
+int
+SSL_process_quic_post_handshake(SSL *ssl)
+{
+	/* XXX - this needs to run PHH received. */
+	return 1;
+}
+
 int
 SSL_do_handshake(SSL *s)
 {
@@ -3371,6 +3470,12 @@ SSL_get_peer_quic_transport_params(const SSL *ssl, const uint8_t **out_params,
 	*out_params_len = ssl->s3->peer_quic_transport_params_len;
 }
 
+void
+SSL_set_quic_use_legacy_codepoint(SSL *ssl, int use_legacy)
+{
+	/* Not supported. */
+}
+
 static int
 ssl_cipher_id_cmp_BSEARCH_CMP_FN(const void *a_, const void *b_)
 {
-- 
cgit v1.2.3-55-g6feb