Provide the remaining QUIC API.
authorjsing <jsing@openbsd.org>
Sun, 21 Aug 2022 19:42:15 +0000 (19:42 +0000)
committerjsing <jsing@openbsd.org>
Sun, 21 Aug 2022 19:42:15 +0000 (19:42 +0000)
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@

lib/libssl/ssl.h
lib/libssl/ssl_lib.c

index be116de..caee3d6 100644 (file)
@@ -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);
index f0f0150..c0ca19c 100644 (file)
@@ -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_)
 {