openssl 3.1.5-1 (x86_64;znver1;aarch64) 2024-17666
9999

Status published
Submitter cris [@T] beebames.com
Platform rolling
Repository main
URL https://abf.openmandriva.org/build_lists/402382
Packages
lib64crypto3-3.1.5-1.x86_64.binary
lib64crypto3-debuginfo-3.1.5-1.x86_64.debuginfo
lib64openssl-devel-3.1.5-1.x86_64.binary
lib64openssl-static-devel-3.1.5-1.x86_64.binary
lib64ssl3-3.1.5-1.x86_64.binary
lib64ssl3-debuginfo-3.1.5-1.x86_64.debuginfo
libcrypto3-3.1.5-1.x86_64.binary
libcrypto3-debuginfo-3.1.5-1.x86_64.debuginfo
libopenssl-devel-3.1.5-1.x86_64.binary
libopenssl-static-devel-3.1.5-1.x86_64.binary
libssl3-3.1.5-1.x86_64.binary
libssl3-debuginfo-3.1.5-1.x86_64.debuginfo
openssl-3.1.5-1.x86_64.binary
openssl-3.1.5-1.x86_64.source
openssl-32-3.1.5-1.x86_64.binary
openssl-32-debuginfo-3.1.5-1.x86_64.debuginfo
openssl-debuginfo-3.1.5-1.x86_64.debuginfo
openssl-debugsource-3.1.5-1.x86_64.binary
openssl-perl-3.1.5-1.x86_64.binary
lib64crypto3-3.1.5-1.znver1.binary
lib64crypto3-debuginfo-3.1.5-1.znver1.debuginfo
lib64openssl-devel-3.1.5-1.znver1.binary
lib64openssl-static-devel-3.1.5-1.znver1.binary
lib64ssl3-3.1.5-1.znver1.binary
lib64ssl3-debuginfo-3.1.5-1.znver1.debuginfo
libcrypto3-3.1.5-1.znver1.binary
libcrypto3-debuginfo-3.1.5-1.znver1.debuginfo
libopenssl-devel-3.1.5-1.znver1.binary
libopenssl-static-devel-3.1.5-1.znver1.binary
libssl3-3.1.5-1.znver1.binary
libssl3-debuginfo-3.1.5-1.znver1.debuginfo
openssl-3.1.5-1.znver1.source
openssl-3.1.5-1.znver1.binary
openssl-32-3.1.5-1.znver1.binary
openssl-32-debuginfo-3.1.5-1.znver1.debuginfo
openssl-debuginfo-3.1.5-1.znver1.debuginfo
openssl-debugsource-3.1.5-1.znver1.binary
openssl-perl-3.1.5-1.znver1.binary
lib64crypto3-3.1.5-1.aarch64.binary
lib64crypto3-debuginfo-3.1.5-1.aarch64.debuginfo
lib64openssl-devel-3.1.5-1.aarch64.binary
lib64openssl-static-devel-3.1.5-1.aarch64.binary
lib64ssl3-3.1.5-1.aarch64.binary
lib64ssl3-debuginfo-3.1.5-1.aarch64.debuginfo
openssl-3.1.5-1.aarch64.source
openssl-3.1.5-1.aarch64.binary
openssl-debuginfo-3.1.5-1.aarch64.debuginfo
openssl-debugsource-3.1.5-1.aarch64.binary
openssl-perl-3.1.5-1.aarch64.binary
Build Date 2024-02-21 16:50:41 +0000 UTC
Last Updated 2024-03-01 17:55:44.93887974 +0000 UTC
$ git diff --patch-with-stat --summary 237535e7fb0ce3a88de6bb979e458e077f143bdf..f5ad4df158375b6c2f3c06152cb13d1f4ae09ac7

 .abf.yml                                           |    2 +-
 ...-QUIC-Add-support-for-BoringSSL-QUIC-APIs.patch | 1855 ++++++++++++++++++++
 ...QUIC-New-method-to-get-QUIC-secret-length.patch |   99 ++
 ...UIC-Make-temp-secret-names-less-confusing.patch |   76 +
 ...UIC-transport-params-to-encrypted-extensi.patch |   26 +
 0005-QUIC-Use-proper-secrets-for-handshake.patch   |   59 +
 0006-QUIC-Handle-partial-handshake-messages.patch  |   74 +
 0007-QUIC-Fix-duplicate-word-in-docs.patch         |   25 +
 ...C-Fix-quic_transport-constructors-parsers.patch |   89 +
 ...init-state-in-SSL_process_quic_post_hands.patch |   39 +
 ...-QUIC-Don-t-process-an-incomplete-message.patch |   51 +
 ...UIC-Quick-fix-s2c-to-c2s-for-early-secret.patch |   25 +
 ...C-Add-client-early-traffic-secret-storage.patch |   52 +
 0013-QUIC-Add-OPENSSL_NO_QUIC-wrapper.patch        |   28 +
 0014-QUIC-Correctly-disable-middlebox-compat.patch |   34 +
 ...UIC-code-out-of-tls13_change_cipher_state.patch |  332 ++++
 0016-QUIC-Tweeks-to-quic_change_cipher_state.patch |  126 ++
 0017-QUIC-Add-support-for-more-secrets.patch       |   44 +
 0018-QUIC-Fix-resumption-secret.patch              |   54 +
 ...IC-Handle-EndOfEarlyData-and-MaxEarlyData.patch |   98 ++
 0020-QUIC-Fall-through-for-0RTT.patch              |   31 +
 ...IC-Some-cleanup-for-the-main-QUIC-changes.patch |  677 +++++++
 0022-QUIC-Prevent-KeyUpdate-for-QUIC.patch         |   77 +
 0023-QUIC-Test-KeyUpdate-rejection.patch           |   37 +
 0024-QUIC-Buffer-all-provided-quic-data.patch      |  219 +++
 ...e-consistent-encryption-level-for-handsha.patch |   58 +
 0026-QUIC-add-v1-quic_transport_parameters.patch   |  669 +++++++
 ...eturn-success-when-no-post-handshake-data.patch |   27 +
 ...wur-makes-no-sense-for-void-return-values.patch |   25 +
 ...-QUIC-remove-SSL_R_BAD_DATA_LENGTH-unused.patch |   50 +
 0030-QUIC-Update-shared-library-version.patch      |   11 +
 0032-QUIC-Fix-3.0.0-GitHub-CI.patch                |   42 +
 0033-QUIC-SSLerr-ERR_raise-ERR_LIB_SSL.patch       |  165 ++
 ...IC-Add-compile-run-time-checking-for-QUIC.patch |  101 ++
 0035-QUIC-Add-early-data-support-11.patch          |  504 ++++++
 ...SL_provide_quic_data-accept-0-length-data.patch |   31 +
 ...s-multiple-post-handshake-messages-in-a-s.patch |   76 +
 ...n-up-some-language-in-SSL_CTX_set_quic_me.patch |   32 +
 0040-QUIC-Fix-CI-20.patch                          |   97 +
 0041-QUIC-Break-up-header-body-processing.patch    |  145 ++
 0042-QUIC-Fix-make-doc-nits.patch                  |   35 +
 0045-QUIC-Don-t-muck-with-FIPS-checksums.patch     |  131 ++
 0047-QUIC-Update-RFC-references.patch              |  112 ++
 0048-QUIC-revert-white-space-change.patch          |   24 +
 0049-QUIC-update-copyrights.patch                  |   49 +
 ...pdate-SSL_provide_quic_data-documentation.patch |   34 +
 ...C-expound-on-what-DoS-attacks-QUIC-avoids.patch |   29 +
 ...C-remove-SSL_get_current_cipher-reference.patch |   28 +
 0053-QUIC-use-SSL_IS_QUIC-in-more-places.patch     |   53 +
 ...-when-non-empty-session_id-in-CH-fixes-29.patch |   32 +
 ...-QUIC-Update-SSL_clear-to-clear-quic-data.patch |  140 ++
 0056-QUIC-Better-SSL_clear.patch                   |  216 +++
 0059-QUIC-Fix-extension-test.patch                 |   46 +
 0063-QUIC-Fix-use-of-create_a_psk.patch            |   25 +
 openssl.spec                                       |   95 +-
 55 files changed, 7295 insertions(+), 16 deletions(-)
 create mode 100644 0001-QUIC-Add-support-for-BoringSSL-QUIC-APIs.patch
 create mode 100644 0002-QUIC-New-method-to-get-QUIC-secret-length.patch
 create mode 100644 0003-QUIC-Make-temp-secret-names-less-confusing.patch
 create mode 100644 0004-QUIC-Move-QUIC-transport-params-to-encrypted-extensi.patch
 create mode 100644 0005-QUIC-Use-proper-secrets-for-handshake.patch
 create mode 100644 0006-QUIC-Handle-partial-handshake-messages.patch
 create mode 100644 0007-QUIC-Fix-duplicate-word-in-docs.patch
 create mode 100644 0008-QUIC-Fix-quic_transport-constructors-parsers.patch
 create mode 100644 0009-QUIC-Reset-init-state-in-SSL_process_quic_post_hands.patch
 create mode 100644 0010-QUIC-Don-t-process-an-incomplete-message.patch
 create mode 100644 0011-QUIC-Quick-fix-s2c-to-c2s-for-early-secret.patch
 create mode 100644 0012-QUIC-Add-client-early-traffic-secret-storage.patch
 create mode 100644 0013-QUIC-Add-OPENSSL_NO_QUIC-wrapper.patch
 create mode 100644 0014-QUIC-Correctly-disable-middlebox-compat.patch
 create mode 100644 0015-QUIC-Move-QUIC-code-out-of-tls13_change_cipher_state.patch
 create mode 100644 0016-QUIC-Tweeks-to-quic_change_cipher_state.patch
 create mode 100644 0017-QUIC-Add-support-for-more-secrets.patch
 create mode 100644 0018-QUIC-Fix-resumption-secret.patch
 create mode 100644 0019-QUIC-Handle-EndOfEarlyData-and-MaxEarlyData.patch
 create mode 100644 0020-QUIC-Fall-through-for-0RTT.patch
 create mode 100644 0021-QUIC-Some-cleanup-for-the-main-QUIC-changes.patch
 create mode 100644 0022-QUIC-Prevent-KeyUpdate-for-QUIC.patch
 create mode 100644 0023-QUIC-Test-KeyUpdate-rejection.patch
 create mode 100644 0024-QUIC-Buffer-all-provided-quic-data.patch
 create mode 100644 0025-QUIC-Enforce-consistent-encryption-level-for-handsha.patch
 create mode 100644 0026-QUIC-add-v1-quic_transport_parameters.patch
 create mode 100644 0027-QUIC-return-success-when-no-post-handshake-data.patch
 create mode 100644 0028-QUIC-__owur-makes-no-sense-for-void-return-values.patch
 create mode 100644 0029-QUIC-remove-SSL_R_BAD_DATA_LENGTH-unused.patch
 create mode 100644 0030-QUIC-Update-shared-library-version.patch
 create mode 100644 0032-QUIC-Fix-3.0.0-GitHub-CI.patch
 create mode 100644 0033-QUIC-SSLerr-ERR_raise-ERR_LIB_SSL.patch
 create mode 100644 0034-QUIC-Add-compile-run-time-checking-for-QUIC.patch
 create mode 100644 0035-QUIC-Add-early-data-support-11.patch
 create mode 100644 0036-QUIC-Make-SSL_provide_quic_data-accept-0-length-data.patch
 create mode 100644 0037-QUIC-Process-multiple-post-handshake-messages-in-a-s.patch
 create mode 100644 0038-QUIC-Tighten-up-some-language-in-SSL_CTX_set_quic_me.patch
 create mode 100644 0040-QUIC-Fix-CI-20.patch
 create mode 100644 0041-QUIC-Break-up-header-body-processing.patch
 create mode 100644 0042-QUIC-Fix-make-doc-nits.patch
 create mode 100644 0045-QUIC-Don-t-muck-with-FIPS-checksums.patch
 create mode 100644 0047-QUIC-Update-RFC-references.patch
 create mode 100644 0048-QUIC-revert-white-space-change.patch
 create mode 100644 0049-QUIC-update-copyrights.patch
 create mode 100644 0050-QUIC-update-SSL_provide_quic_data-documentation.patch
 create mode 100644 0051-QUIC-expound-on-what-DoS-attacks-QUIC-avoids.patch
 create mode 100644 0052-QUIC-remove-SSL_get_current_cipher-reference.patch
 create mode 100644 0053-QUIC-use-SSL_IS_QUIC-in-more-places.patch
 create mode 100644 0054-QUIC-Error-when-non-empty-session_id-in-CH-fixes-29.patch
 create mode 100644 0055-QUIC-Update-SSL_clear-to-clear-quic-data.patch
 create mode 100644 0056-QUIC-Better-SSL_clear.patch
 create mode 100644 0059-QUIC-Fix-extension-test.patch
 create mode 100644 0063-QUIC-Fix-use-of-create_a_psk.patch

diff --git a/.abf.yml b/.abf.yml
index 4991d65..bf11c9b 100644
--- a/.abf.yml
+++ b/.abf.yml
@@ -1,2 +1,2 @@
 sources:
-  openssl-3.0.6.tar.gz: df7c98f7780babdedd0810fb3c2b55332a8f6b89
+  openssl-3.1.5.tar.gz: bae9e00477fb036e28f1c2e9a837fb6992823c57
diff --git a/0001-QUIC-Add-support-for-BoringSSL-QUIC-APIs.patch b/0001-QUIC-Add-support-for-BoringSSL-QUIC-APIs.patch
new file mode 100644
index 0000000..3df351e
--- /dev/null
+++ b/0001-QUIC-Add-support-for-BoringSSL-QUIC-APIs.patch
@@ -0,0 +1,1855 @@
+From bcf0f1690bd031c2945e2875d03b7617a9dfafc7 Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Fri, 12 Apr 2019 11:13:25 -0400
+Subject: [PATCH 01/63] QUIC: Add support for BoringSSL QUIC APIs
+
+This adds a compatible API for BoringSSL's QUIC support, based
+on the current |draft-ietf-quic-tls|.
+
+Based on BoringSSL commit 3c034b2cf386b3131f75520705491871a2e0cafe
+Based on BoringSSL commit c8e0f90f83b9ec38ea833deb86b5a41360b62b6a
+Based on BoringSSL commit 3cbb0299a28a8bd0136257251a78b91a96c5eec8
+Based on BoringSSL commit cc9d935256539af2d3b7f831abf57c0d685ffd81
+Based on BoringSSL commit e6eef1ca16a022e476bbaedffef044597cfc8f4b
+Based on BoringSSL commit 6f733791148cf8a076bf0e95498235aadbe5926d
+Based on BoringSSL commit 384d0eaf1930af1ebc47eda751f0c78dfcba1c03
+Based on BoringSSL commit a0373182eb5cc7b81d49f434596b473c7801c942
+Based on BoringSSL commit b1b76aee3cb43ce11889403c5334283d951ebd37
+---
+ CHANGES.md                           |   6 +
+ Configure                            |   2 +
+ INSTALL.md                           |   4 +
+ crypto/err/openssl.txt               |   2 +
+ doc/man3/SSL_CIPHER_get_name.pod     |  13 ++
+ doc/man3/SSL_CTX_set_quic_method.pod | 232 +++++++++++++++++++++++++
+ include/openssl/evp.h                |   5 +
+ include/openssl/ssl.h.in             |  45 +++++
+ include/openssl/sslerr.h             |   2 +
+ include/openssl/tls1.h               |   3 +
+ include/openssl/types.h              |   2 +
+ ssl/build.info                       |   2 +
+ ssl/s3_msg.c                         |  10 ++
+ ssl/ssl_ciph.c                       |  32 ++++
+ ssl/ssl_err.c                        |   3 +
+ ssl/ssl_lib.c                        |  41 ++++-
+ ssl/ssl_local.h                      |  37 ++++
+ ssl/ssl_quic.c                       | 248 +++++++++++++++++++++++++++
+ ssl/statem/extensions.c              |  29 ++++
+ ssl/statem/extensions_clnt.c         |  48 ++++++
+ ssl/statem/extensions_srvr.c         |  51 ++++++
+ ssl/statem/statem.c                  |  20 ++-
+ ssl/statem/statem_lib.c              |  19 +-
+ ssl/statem/statem_local.h            |  19 ++
+ ssl/statem/statem_quic.c             | 106 ++++++++++++
+ ssl/tls13_enc.c                      |  59 +++++++
+ test/helpers/ssltestlib.c            |   5 +
+ test/sslapitest.c                    | 140 +++++++++++++++
+ test/tls13secretstest.c              |   7 +
+ util/libssl.num                      |  11 ++
+ util/other.syms                      |   2 +
+ 31 files changed, 1199 insertions(+), 6 deletions(-)
+ create mode 100644 doc/man3/SSL_CTX_set_quic_method.pod
+ create mode 100644 ssl/ssl_quic.c
+ create mode 100644 ssl/statem/statem_quic.c
+
+diff --git a/CHANGES.md b/CHANGES.md
+index 4fcb606ee3..be8707649d 100644
+--- a/CHANGES.md
++++ b/CHANGES.md
+@@ -264,6 +264,12 @@ breaking changes, and mappings for the large list of deprecated functions.
+ 
+ [Migration guide]: https://github.com/openssl/openssl/tree/master/doc/man7/migration_guide.pod
+ 
++### Changes between 3.0.8 and 3.0.8+quic [7 Feb 2023]
++
++ * Add QUIC API support from BoringSSL.
++
++   *Todd Short*
++
+ ### Changes between 3.0.7 and 3.0.8 [7 Feb 2023]
+ 
+  * Fixed NULL dereference during PKCS7 data verification.
+diff --git a/Configure b/Configure
+index 227e5daea2..bd4e0943bf 100755
+--- a/Configure
++++ b/Configure
+@@ -467,6 +467,7 @@ my @disablables = (
+     "poly1305",
+     "posix-io",
+     "psk",
++    "quic",
+     "rc2",
+     "rc4",
+     "rc5",
+@@ -635,6 +636,7 @@ my @disable_cascades = (
+     "legacy"            => [ "md2" ],
+ 
+     "cmp"               => [ "crmf" ],
++    "tls1_3"            => [ "quic" ],
+ 
+     "fips"              => [ "fips-securitychecks", "acvp-tests" ],
+ 
+diff --git a/INSTALL.md b/INSTALL.md
+index d13517873c..8268ae86b0 100644
+--- a/INSTALL.md
++++ b/INSTALL.md
+@@ -823,6 +823,10 @@ Don't use POSIX IO capabilities.
+ 
+ Don't build support for Pre-Shared Key based ciphersuites.
+ 
++### no-quic
++
++Don't build support for QUIC API from BoringSSL.
++
+ ### no-rdrand
+ 
+ Don't use hardware RDRAND capabilities.
+diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
+index fe4fdd4bf2..b2f90a413a 100644
+--- a/crypto/err/openssl.txt
++++ b/crypto/err/openssl.txt
+@@ -1262,6 +1262,7 @@ SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE:158:\
+ SSL_R_BAD_CHANGE_CIPHER_SPEC:103:bad change cipher spec
+ SSL_R_BAD_CIPHER:186:bad cipher
+ SSL_R_BAD_DATA:390:bad data
++SSL_R_BAD_DATA_LENGTH:802:bad data length
+ SSL_R_BAD_DATA_RETURNED_BY_CALLBACK:106:bad data returned by callback
+ SSL_R_BAD_DECOMPRESSION:107:bad decompression
+ SSL_R_BAD_DH_VALUE:102:bad dh value
+@@ -1549,6 +1550,7 @@ SSL_R_VERSION_TOO_LOW:396:version too low
+ SSL_R_WRONG_CERTIFICATE_TYPE:383:wrong certificate type
+ SSL_R_WRONG_CIPHER_RETURNED:261:wrong cipher returned
+ SSL_R_WRONG_CURVE:378:wrong curve
++SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED:800:wrong encryption level received
+ SSL_R_WRONG_SIGNATURE_LENGTH:264:wrong signature length
+ SSL_R_WRONG_SIGNATURE_SIZE:265:wrong signature size
+ SSL_R_WRONG_SIGNATURE_TYPE:370:wrong signature type
+diff --git a/doc/man3/SSL_CIPHER_get_name.pod b/doc/man3/SSL_CIPHER_get_name.pod
+index e22a85a063..7f00f09d67 100644
+--- a/doc/man3/SSL_CIPHER_get_name.pod
++++ b/doc/man3/SSL_CIPHER_get_name.pod
+@@ -13,6 +13,7 @@ SSL_CIPHER_get_digest_nid,
+ SSL_CIPHER_get_handshake_digest,
+ SSL_CIPHER_get_kx_nid,
+ SSL_CIPHER_get_auth_nid,
++SSL_CIPHER_get_prf_nid,
+ SSL_CIPHER_is_aead,
+ SSL_CIPHER_find,
+ SSL_CIPHER_get_id,
+@@ -34,6 +35,7 @@ SSL_CIPHER_get_protocol_id
+  const EVP_MD *SSL_CIPHER_get_handshake_digest(const SSL_CIPHER *c);
+  int SSL_CIPHER_get_kx_nid(const SSL_CIPHER *c);
+  int SSL_CIPHER_get_auth_nid(const SSL_CIPHER *c);
++ int SSL_CIPHER_get_prf_nid(const SSL_CIPHER *c);
+  int SSL_CIPHER_is_aead(const SSL_CIPHER *c);
+  const SSL_CIPHER *SSL_CIPHER_find(SSL *ssl, const unsigned char *ptr);
+  uint32_t SSL_CIPHER_get_id(const SSL_CIPHER *c);
+@@ -91,6 +93,15 @@ TLS 1.3 cipher suites) B<NID_auth_any> is returned. Examples (not comprehensive)
+  NID_auth_ecdsa
+  NID_auth_psk
+ 
++SSL_CIPHER_get_prf_nid() retuns the pseudo-random function NID for B<c>. If B<c> is
++a pre-TLS-1.2 cipher, it returns B<NID_md5_sha1> but note these ciphers use
++SHA-256 in TLS 1.2. Other return values may be treated uniformly in all
++applicable versions. Examples (not comprehensive):
++
++ NID_md5_sha1
++ NID_sha256
++ NID_sha384
++
+ SSL_CIPHER_is_aead() returns 1 if the cipher B<c> is AEAD (e.g. GCM or
+ ChaCha20/Poly1305), and 0 if it is not AEAD.
+ 
+@@ -201,6 +212,8 @@ required to enable this function.
+ 
+ The OPENSSL_cipher_name() function was added in OpenSSL 1.1.1.
+ 
++The SSL_CIPHER_get_prf_nid() function was added in OpenSSL 3.0.0.
++
+ =head1 COPYRIGHT
+ 
+ Copyright 2000-2021 The OpenSSL Project Authors. All Rights Reserved.
+diff --git a/doc/man3/SSL_CTX_set_quic_method.pod b/doc/man3/SSL_CTX_set_quic_method.pod
+new file mode 100644
+index 0000000000..d938eb4e30
+--- /dev/null
++++ b/doc/man3/SSL_CTX_set_quic_method.pod
+@@ -0,0 +1,232 @@
++=pod
++
++=head1 NAME
++
++SSL_QUIC_METHOD,
++OSSL_ENCRYPTION_LEVEL,
++SSL_CTX_set_quic_method,
++SSL_set_quic_method,
++SSL_set_quic_transport_params,
++SSL_get_peer_quic_transport_params,
++SSL_quic_max_handshake_flight_len,
++SSL_quic_read_level,
++SSL_quic_write_level,
++SSL_provide_quic_data,
++SSL_process_quic_post_handshake,
++SSL_is_quic
++- QUIC support
++
++=head1 SYNOPSIS
++
++ #include <openssl/ssl.h>
++
++ typedef struct ssl_quic_method_st SSL_QUIC_METHOD;
++ typedef enum ssl_encryption_level_t OSSL_ENCRYPTION_LEVEL;
++
++ int SSL_CTX_set_quic_method(SSL_CTX *ctx, const SSL_QUIC_METHOD *quic_method);
++ int SSL_set_quic_method(SSL *ssl, const SSL_QUIC_METHOD *quic_method);
++ int SSL_set_quic_transport_params(SSL *ssl,
++                                   const uint8_t *params,
++                                   size_t params_len);
++ void SSL_get_peer_quic_transport_params(const SSL *ssl,
++                                         const uint8_t **out_params,
++                                         size_t *out_params_len);
++ size_t SSL_quic_max_handshake_flight_len(const SSL *ssl, OSSL_ENCRYPTION_LEVEL level);
++ OSSL_ENCRYPTION_LEVEL SSL_quic_read_level(const SSL *ssl);
++ OSSL_ENCRYPTION_LEVEL SSL_quic_write_level(const SSL *ssl);
++ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
++                           const uint8_t *data, size_t len);
++ int SSL_process_quic_post_handshake(SSL *ssl);
++ int SSL_is_quic(SSL *ssl);
++
++=head1 DESCRIPTION
++
++SSL_CTX_set_quic_method() and SSL_set_quic_method() configures the QUIC methods.
++This should only be configured with a minimum version of TLS 1.3. B<quic_method>
++must remain valid for the lifetime of B<ctx> or B<ssl>. Calling this disables
++the SSL_OP_ENABLE_MIDDLEBOX_COMPAT option, which is not required for QUIC.
++
++SSL_set_quic_transport_params() configures B<ssl> to send B<params> (of length
++B<params_len>) in the quic_transport_parameters extension in either the
++ClientHello or EncryptedExtensions handshake message. This extension will
++only be sent if the TLS version is at least 1.3, and for a server, only if
++the client sent the extension. The buffer pointed to by B<params> only need be
++valid for the duration of the call to this function.
++
++SSL_get_peer_quic_transport_params() provides the caller with the value of the
++quic_transport_parameters extension sent by the peer. A pointer to the buffer
++containing the TransportParameters will be put in B<*out_params>, and its
++length in B<*out_params_len>. This buffer will be valid for the lifetime of the
++B<ssl>. If no params were received from the peer, B<*out_params_len> will be 0.
++
++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 https://tools.ietf.org/html/draft-ietf-quic-transport-16#section-4.4.
++
++SSL_quic_read_level() returns the current read encryption level.
++
++SSL_quic_write_level() returns the current write encryption level.
++
++SSL_provide_quic_data() provides data from QUIC at a particular encryption
++level B<level>. It is an error to call this function outside of the handshake
++or with an encryption level other than the current read level. It returns one
++on success and zero on error.
++
++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.
++
++SSL_is_quic() indicates whether a connection uses QUIC.
++
++=head1 NOTES
++
++These APIs are implementations of BoringSSL's QUIC APIs.
++
++QUIC acts as an underlying transport for the TLS 1.3 handshake. The following
++functions allow a QUIC implementation to serve as the underlying transport as
++described in draft-ietf-quic-tls.
++
++When configured for QUIC, SSL_do_handshake() will drive the handshake as
++before, but it will not use the configured B<BIO>. It will call functions on
++B<SSL_QUIC_METHOD> to configure secrets and send data. If data is needed from
++the peer, it will return B<SSL_ERROR_WANT_READ>. When received, the caller
++should call SSL_provide_quic_data() and then SSL_do_handshake() to continue
++the handshake. After the handshake is complete, the caller should call
++SSL_provide_quic_data() for any post-handshake data, followed by
++SSL_process_quic_post_handshake() to process it. It is an error to call
++SSL_read()/SSL_read_ex() and SSL_write()/SSL_write_ex() in QUIC.
++
++Note that secrets for an encryption level may be available to QUIC before the
++level is active in TLS. Callers should use SSL_quic_read_level() to determine
++the active read level for SSL_provide_quic_data(). SSL_do_handshake() will
++pass the active write level to add_handshake_data() when writing data. Callers
++can use SSL_quic_write_level() to query the active write level when
++generating their own errors.
++
++See https://tools.ietf.org/html/draft-ietf-quic-tls-15#section-4.1 for more
++details.
++
++To avoid DoS attacks, the QUIC implementation must limit the amount of data
++being queued up. The implementation can call
++SSL_quic_max_handshake_flight_len() to get the maximum buffer length at each
++encryption level.
++
++draft-ietf-quic-tls defines a new TLS extension quic_transport_parameters
++used by QUIC for each endpoint to unilaterally declare its supported
++transport parameters. draft-ietf-quic-transport (section 7.4) defines the
++contents of that extension (a TransportParameters struct) and describes how
++to handle it and its semantic meaning.
++
++OpenSSL handles this extension as an opaque byte string. The caller is
++responsible for serializing and parsing it.
++
++=head2 OSSL_ENCRYPTION_LEVEL
++
++B<OSSL_ENCRYPTION_LEVEL> (B<enum ssl_encryption_level_t>) represents the
++encryption levels:
++
++=over 4
++
++=item ssl_encryption_initial
++
++The initial encryption level that is used for client and server hellos.
++
++=item ssl_encryption_early_data
++
++The encryption level for early data. This is a write-level for the client
++and a read-level for the server.
++
++=item ssl_encryption_handshake
++
++The encryption level for the remainder of the handshake.
++
++=item ssl_encryption_application
++
++The encryption level for the application data.
++
++=back
++
++=head2 SSL_QUIC_METHOD
++
++The B<SSL_QUIC_METHOD> (B<struct ssl_quic_method_st>) describes the
++QUIC methods.
++
++ struct ssl_quic_method_st {
++     int (*set_encryption_secrets)(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
++                                   const uint8_t *read_secret,
++                                   const uint8_t *write_secret, size_t secret_len);
++     int (*add_handshake_data)(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
++                               const uint8_t *data, size_t len);
++     int (*flush_flight)(SSL *ssl);
++     int (*send_alert)(SSL *ssl, enum ssl_encryption_level_t level, uint8_t alert);
++ };
++ typedef struct ssl_quic_method_st SSL_QUIC_METHOD;
++
++set_encryption_secrets() configures the read and write secrets for the given
++encryption level. This function will always be called before an encryption
++level other than B<ssl_encryption_initial> is used. Note, however, that
++secrets for a level may be configured before TLS is ready to send or accept
++data at that level.
++
++When reading packets at a given level, the QUIC implementation must send
++ACKs at the same level, so this function provides read and write secrets
++together. The exception is B<ssl_encryption_early_data>, where secrets are
++only available in the client to server direction. The other secret will be
++NULL. The server acknowledges such data at B<ssl_encryption_application>,
++which will be configured in the same SSL_do_handshake() call.
++
++This function should use SSL_get_current_cipher() to determine the TLS
++cipher suite.
++
++add_handshake_data() adds handshake data to the current flight at the given
++encryption level. It returns one on success and zero on error.
++
++OpenSSL will pack data from a single encryption level together, but a
++single handshake flight may include multiple encryption levels. Callers
++should defer writing data to the network until flush_flight() to better
++pack QUIC packets into transport datagrams.
++
++flush_flight() is called when the current flight is complete and should be
++written to the transport. Note a flight may contain data at several
++encryption levels.
++
++send_alert() sends a fatal alert at the specified encryption level.
++
++All QUIC methods return 1 on success and 0 on error.
++
++=head1 RETURN VALUES
++
++SSL_CTX_set_quic_method(),
++SSL_set_quic_method(),
++SSL_set_quic_transport_params(), and
++SSL_process_quic_post_handshake()
++return 1 on success, and 0 on error.
++
++SSL_quic_read_level() and SSL_quic_write_level() return the current
++encryption  level as B<OSSL_ENCRYPTION_LEVEL> (B<enum ssl_encryption_level_t>).
++
++SSL_quic_max_handshake_flight_len() returns the maximum length of a flight
++for a given encryption level.
++
++SSL_is_quic() returns 1 if QUIC is being used, 0 if not.
++
++=head1 SEE ALSO
++
++L<ssl(7)>, L<SSL_CIPHER_get_prf_nid(3)>, L<SSL_do_handshake(3)>
++
++=head1 HISTORY
++
++These functions were added in OpenSSL 3.0.0.
++
++=head1 COPYRIGHT
++
++Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
++
++Licensed under the Apache License 2.0 (the "License").  You may not use
++this file except in compliance with the License.  You can obtain a copy
++in the file LICENSE in the source distribution or at
++L<https://www.openssl.org/source/license.html>.
++
++=cut
+diff --git a/include/openssl/evp.h b/include/openssl/evp.h
+index 86f4e22c70..8479f665f5 100644
+--- a/include/openssl/evp.h
++++ b/include/openssl/evp.h
+@@ -1742,6 +1742,11 @@ int EVP_PKEY_CTX_set_mac_key(EVP_PKEY_CTX *ctx, const unsigned char *key,
+  * Method handles all operations: don't assume any digest related defaults.
+  */
+ # define EVP_PKEY_FLAG_SIGCTX_CUSTOM     4
++
++/* Used by Chromium/QUIC */
++# define X25519_PRIVATE_KEY_LEN          32
++# define X25519_PUBLIC_VALUE_LEN         32
++
+ # ifndef OPENSSL_NO_DEPRECATED_3_0
+ OSSL_DEPRECATEDIN_3_0 const EVP_PKEY_METHOD *EVP_PKEY_meth_find(int type);
+ OSSL_DEPRECATEDIN_3_0 EVP_PKEY_METHOD *EVP_PKEY_meth_new(int id, int flags);
+diff --git a/include/openssl/ssl.h.in b/include/openssl/ssl.h.in
+index f03f52fbd8..e2e31bce9b 100644
+--- a/include/openssl/ssl.h.in
++++ b/include/openssl/ssl.h.in
+@@ -2524,6 +2524,51 @@ void SSL_set_allow_early_data_cb(SSL *s,
+ const char *OSSL_default_cipher_list(void);
+ const char *OSSL_default_ciphersuites(void);
+ 
++#  ifndef OPENSSL_NO_QUIC
++/*
++ * QUIC integration - The QUIC interface matches BoringSSL
++ *
++ * ssl_encryption_level_t represents a specific QUIC encryption level used to
++ * transmit handshake messages. BoringSSL has this as an 'enum'.
++ */
++typedef enum ssl_encryption_level_t {
++    ssl_encryption_initial = 0,
++    ssl_encryption_early_data,
++    ssl_encryption_handshake,
++    ssl_encryption_application
++} OSSL_ENCRYPTION_LEVEL;
++
++struct ssl_quic_method_st {
++    int (*set_encryption_secrets)(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
++                                  const uint8_t *read_secret,
++                                  const uint8_t *write_secret, size_t secret_len);
++    int (*add_handshake_data)(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
++                              const uint8_t *data, size_t len);
++    int (*flush_flight)(SSL *ssl);
++    int (*send_alert)(SSL *ssl, enum ssl_encryption_level_t level, uint8_t alert);
++};
++
++__owur int SSL_CTX_set_quic_method(SSL_CTX *ctx, const SSL_QUIC_METHOD *quic_method);
++__owur int SSL_set_quic_method(SSL *ssl, const SSL_QUIC_METHOD *quic_method);
++__owur int SSL_set_quic_transport_params(SSL *ssl,
++                                         const uint8_t *params,
++                                         size_t params_len);
++void SSL_get_peer_quic_transport_params(const SSL *ssl,
++                                        const uint8_t **out_params,
++                                        size_t *out_params_len);
++__owur size_t SSL_quic_max_handshake_flight_len(const SSL *ssl, OSSL_ENCRYPTION_LEVEL level);
++__owur OSSL_ENCRYPTION_LEVEL SSL_quic_read_level(const SSL *ssl);
++__owur OSSL_ENCRYPTION_LEVEL SSL_quic_write_level(const SSL *ssl);
++__owur int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
++                                 const uint8_t *data, size_t len);
++__owur int SSL_process_quic_post_handshake(SSL *ssl);
++
++__owur int SSL_is_quic(SSL *ssl);
++
++#  endif
++
++int SSL_CIPHER_get_prf_nid(const SSL_CIPHER *c);
++
+ # ifdef  __cplusplus
+ }
+ # endif
+diff --git a/include/openssl/sslerr.h b/include/openssl/sslerr.h
+index f1882558ba..d60c892037 100644
+--- a/include/openssl/sslerr.h
++++ b/include/openssl/sslerr.h
+@@ -28,6 +28,7 @@
+ # define SSL_R_BAD_CHANGE_CIPHER_SPEC                     103
+ # define SSL_R_BAD_CIPHER                                 186
+ # define SSL_R_BAD_DATA                                   390
++# define SSL_R_BAD_DATA_LENGTH                            802
+ # define SSL_R_BAD_DATA_RETURNED_BY_CALLBACK              106
+ # define SSL_R_BAD_DECOMPRESSION                          107
+ # define SSL_R_BAD_DH_VALUE                               102
+@@ -333,6 +334,7 @@
+ # define SSL_R_WRONG_CERTIFICATE_TYPE                     383
+ # define SSL_R_WRONG_CIPHER_RETURNED                      261
+ # define SSL_R_WRONG_CURVE                                378
++# define SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED            800
+ # define SSL_R_WRONG_SIGNATURE_LENGTH                     264
+ # define SSL_R_WRONG_SIGNATURE_SIZE                       265
+ # define SSL_R_WRONG_SIGNATURE_TYPE                       370
+diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h
+index 793155e186..c4f80dc332 100644
+--- a/include/openssl/tls1.h
++++ b/include/openssl/tls1.h
+@@ -151,6 +151,9 @@ extern "C" {
+ /* Temporary extension type */
+ # define TLSEXT_TYPE_renegotiate                 0xff01
+ 
++/* ExtensionType value from draft-ietf-quic-tls-13 */
++# define TLSEXT_TYPE_quic_transport_parameters   0xffa5
++
+ # ifndef OPENSSL_NO_NEXTPROTONEG
+ /* This is not an IANA defined extension number */
+ #  define TLSEXT_TYPE_next_proto_neg              13172
+diff --git a/include/openssl/types.h b/include/openssl/types.h
+index 5f9d8c23ea..31d8c18746 100644
+--- a/include/openssl/types.h
++++ b/include/openssl/types.h
+@@ -232,6 +232,8 @@ typedef struct ossl_decoder_ctx_st OSSL_DECODER_CTX;
+ 
+ typedef struct ossl_self_test_st OSSL_SELF_TEST;
+ 
++typedef struct ssl_quic_method_st SSL_QUIC_METHOD;
++
+ #ifdef  __cplusplus
+ }
+ #endif
+diff --git a/ssl/build.info b/ssl/build.info
+index 0851357f81..ac87437906 100644
+--- a/ssl/build.info
++++ b/ssl/build.info
+@@ -38,6 +38,8 @@ IF[{- !$disabled{'deprecated-3.0'} -}]
+   SOURCE[../libssl]=ssl_rsa_legacy.c
+ ENDIF
+ 
++SOURCE[../libssl]=ssl_quic.c statem/statem_quic.c
++
+ DEFINE[../libssl]=$AESDEF
+ 
+ SOURCE[../providers/libcommon.a]=record/tls_pad.c
+diff --git a/ssl/s3_msg.c b/ssl/s3_msg.c
+index c0f0dbc17d..667c5385e8 100644
+--- a/ssl/s3_msg.c
++++ b/ssl/s3_msg.c
+@@ -81,6 +81,16 @@ int ssl3_dispatch_alert(SSL *s)
+ 
+     s->s3.alert_dispatch = 0;
+     alertlen = 2;
++#ifndef OPENSSL_NO_QUIC
++    if (SSL_IS_QUIC(s)) {
++        if (!s->quic_method->send_alert(s, s->quic_write_level,
++                                        s->s3.send_alert[1])) {
++            SSLerr(SSL_F_SSL3_DISPATCH_ALERT, ERR_R_INTERNAL_ERROR);
++            return 0;
++        }
++        i = 1;
++    } else
++#endif
+     i = do_ssl3_write(s, SSL3_RT_ALERT, &s->s3.send_alert[0], &alertlen, 1, 0,
+                       &written);
+     if (i <= 0) {
+diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c
+index 93de9cf8fd..deb68b4062 100644
+--- a/ssl/ssl_ciph.c
++++ b/ssl/ssl_ciph.c
+@@ -2244,3 +2244,35 @@ const char *OSSL_default_ciphersuites(void)
+            "TLS_CHACHA20_POLY1305_SHA256:"
+            "TLS_AES_128_GCM_SHA256";
+ }
++
++int SSL_CIPHER_get_prf_nid(const SSL_CIPHER *c)
++{
++    switch (c->algorithm2 & (0xFF << TLS1_PRF_DGST_SHIFT)) {
++    default:
++        break;
++    case TLS1_PRF_SHA1_MD5: /* TLS1_PRF */
++        return NID_md5_sha1;
++    case TLS1_PRF_SHA256:
++        return NID_sha256;
++    case TLS1_PRF_SHA384:
++        return NID_sha384;
++    case TLS1_PRF_GOST94:
++        return NID_id_GostR3411_94_prf;
++    case TLS1_PRF_GOST12_256:
++        return NID_id_GostR3411_2012_256;
++    case TLS1_PRF_GOST12_512:
++        return NID_id_GostR3411_2012_512;
++    }
++    /* TLSv1.3 ciphers don't specify separate PRF */
++    switch (c->algorithm2 & SSL_HANDSHAKE_MAC_MASK) {
++    default:
++        break;
++    case SSL_HANDSHAKE_MAC_MD5_SHA1: /* SSL_HANDSHAKE_MAC_DEFAULT */
++        return NID_md5_sha1;
++    case SSL_HANDSHAKE_MAC_SHA256:
++        return NID_sha256;
++    case SSL_HANDSHAKE_MAC_SHA384:
++        return NID_sha384;
++    }
++    return NID_undef;
++}
+diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
+index 84ee821c3c..0c4d1c1332 100644
+--- a/ssl/ssl_err.c
++++ b/ssl/ssl_err.c
+@@ -27,6 +27,7 @@ static const ERR_STRING_DATA SSL_str_reasons[] = {
+     "bad change cipher spec"},
+     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_CIPHER), "bad cipher"},
+     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DATA), "bad data"},
++    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DATA_LENGTH), "bad data length"},
+     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DATA_RETURNED_BY_CALLBACK),
+     "bad data returned by callback"},
+     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DECOMPRESSION), "bad decompression"},
+@@ -544,6 +545,8 @@ static const ERR_STRING_DATA SSL_str_reasons[] = {
+     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_CIPHER_RETURNED),
+     "wrong cipher returned"},
+     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_CURVE), "wrong curve"},
++    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED),
++    "wrong encryption level received"},
+     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_SIGNATURE_LENGTH),
+     "wrong signature length"},
+     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_SIGNATURE_SIZE),
+diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
+index f12ad6d034..6b7633e8a5 100644
+--- a/ssl/ssl_lib.c
++++ b/ssl/ssl_lib.c
+@@ -842,6 +842,10 @@ SSL *SSL_new(SSL_CTX *ctx)
+ 
+     s->job = NULL;
+ 
++#ifndef OPENSSL_NO_QUIC
++    s->quic_method = ctx->quic_method;
++#endif
++
+ #ifndef OPENSSL_NO_CT
+     if (!SSL_set_ct_validation_callback(s, ctx->ct_validation_callback,
+                                         ctx->ct_validation_callback_arg))
+@@ -1241,6 +1245,18 @@ void SSL_free(SSL *s)
+     OPENSSL_free(s->pha_context);
+     EVP_MD_CTX_free(s->pha_dgst);
+ 
++#ifndef OPENSSL_NO_QUIC
++    OPENSSL_free(s->ext.quic_transport_params);
++    OPENSSL_free(s->ext.peer_quic_transport_params);
++    while (s->quic_input_data_head != NULL) {
++        QUIC_DATA *qd;
++
++        qd = s->quic_input_data_head;
++        s->quic_input_data_head = qd->next;
++        OPENSSL_free(qd);
++    }
++#endif
++
+     sk_X509_NAME_pop_free(s->ca_names, X509_NAME_free);
+     sk_X509_NAME_pop_free(s->client_ca_names, X509_NAME_free);
+ 
+@@ -1834,6 +1850,12 @@ static int ssl_io_intern(void *vargs)
+ 
+ int ssl_read_internal(SSL *s, void *buf, size_t num, size_t *readbytes)
+ {
++#ifndef OPENSSL_NO_QUIC
++    if (SSL_IS_QUIC(s)) {
++        SSLerr(SSL_F_SSL_READ_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return -1;
++    }
++#endif
+     if (s->handshake_func == NULL) {
+         ERR_raise(ERR_LIB_SSL, SSL_R_UNINITIALIZED);
+         return -1;
+@@ -1965,6 +1987,12 @@ int SSL_get_early_data_status(const SSL *s)
+ 
+ static int ssl_peek_internal(SSL *s, void *buf, size_t num, size_t *readbytes)
+ {
++#ifndef OPENSSL_NO_QUIC
++    if (SSL_IS_QUIC(s)) {
++        SSLerr(SSL_F_SSL_PEEK_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return -1;
++    }
++#endif
+     if (s->handshake_func == NULL) {
+         ERR_raise(ERR_LIB_SSL, SSL_R_UNINITIALIZED);
+         return -1;
+@@ -2025,6 +2053,12 @@ int SSL_peek_ex(SSL *s, void *buf, size_t num, size_t *readbytes)
+ 
+ int ssl_write_internal(SSL *s, const void *buf, size_t num, size_t *written)
+ {
++#ifndef OPENSSL_NO_QUIC
++    if (SSL_IS_QUIC(s)) {
++        SSLerr(SSL_F_SSL_WRITE_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return -1;
++    }
++#endif
+     if (s->handshake_func == NULL) {
+         ERR_raise(ERR_LIB_SSL, SSL_R_UNINITIALIZED);
+         return -1;
+@@ -3839,6 +3873,11 @@ int SSL_get_error(const SSL *s, int i)
+     }
+ 
+     if (SSL_want_read(s)) {
++#ifndef OPENSSL_NO_QUIC
++        if (SSL_IS_QUIC(s)) {
++            return SSL_ERROR_WANT_READ;
++        }
++#endif
+         bio = SSL_get_rbio(s);
+         if (BIO_should_read(bio))
+             return SSL_ERROR_WANT_READ;
+@@ -4206,7 +4245,7 @@ EVP_PKEY *SSL_CTX_get0_privatekey(const SSL_CTX *ctx)
+ 
+ const SSL_CIPHER *SSL_get_current_cipher(const SSL *s)
+ {
+-    if ((s->session != NULL) && (s->session->cipher != NULL))
++    if (s->session != NULL)
+         return s->session->cipher;
+     return NULL;
+ }
+diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h
+index 845329a809..3e67b36990 100644
+--- a/ssl/ssl_local.h
++++ b/ssl/ssl_local.h
+@@ -337,6 +337,13 @@
+ /* Flag used on OpenSSL ciphersuite ids to indicate they are for SSLv3+ */
+ # define SSL3_CK_CIPHERSUITE_FLAG                0x03000000
+ 
++/* Check if an SSL structure is using QUIC (which uses TLSv1.3) */
++# ifndef OPENSSL_NO_QUIC
++#  define SSL_IS_QUIC(s)  (s->quic_method != NULL)
++# else
++#  define SSL_IS_QUIC(s) 0
++# endif
++
+ /* Check if an SSL structure is using DTLS */
+ # define SSL_IS_DTLS(s)  (s->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_DTLS)
+ 
+@@ -766,6 +773,7 @@ typedef enum tlsext_index_en {
+     TLSEXT_IDX_cryptopro_bug,
+     TLSEXT_IDX_early_data,
+     TLSEXT_IDX_certificate_authorities,
++    TLSEXT_IDX_quic_transport_params,
+     TLSEXT_IDX_padding,
+     TLSEXT_IDX_psk,
+     /* Dummy index - must always be the last entry */
+@@ -1205,10 +1213,24 @@ struct ssl_ctx_st {
+     uint32_t disabled_mac_mask;
+     uint32_t disabled_mkey_mask;
+     uint32_t disabled_auth_mask;
++
++#ifndef OPENSSL_NO_QUIC
++    const SSL_QUIC_METHOD *quic_method;
++#endif
+ };
+ 
+ typedef struct cert_pkey_st CERT_PKEY;
+ 
++#ifndef OPENSSL_NO_QUIC
++struct quic_data_st {
++    struct quic_data_st *next;
++    OSSL_ENCRYPTION_LEVEL level;
++    size_t length;
++};
++typedef struct quic_data_st QUIC_DATA;
++int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level);
++#endif
++
+ struct ssl_st {
+     /*
+      * protocol version (one of SSL2_VERSION, SSL3_VERSION, TLS1_VERSION,
+@@ -1680,8 +1702,23 @@ struct ssl_st {
+          * selected.
+          */
+         int tick_identity;
++
++#ifndef OPENSSL_NO_QUIC
++        uint8_t *quic_transport_params;
++        size_t quic_transport_params_len;
++        uint8_t *peer_quic_transport_params;
++        size_t peer_quic_transport_params_len;
++#endif
+     } ext;
+ 
++#ifndef OPENSSL_NO_QUIC
++    OSSL_ENCRYPTION_LEVEL quic_read_level;
++    OSSL_ENCRYPTION_LEVEL quic_write_level;
++    QUIC_DATA *quic_input_data_head;
++    QUIC_DATA *quic_input_data_tail;
++    const SSL_QUIC_METHOD *quic_method;
++    size_t quic_len;
++#endif
+     /*
+      * Parsed form of the ClientHello, kept around across client_hello_cb
+      * calls.
+diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c
+new file mode 100644
+index 0000000000..a39e4419c9
+--- /dev/null
++++ b/ssl/ssl_quic.c
+@@ -0,0 +1,248 @@
++/*
++ * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
++ *
++ * Licensed under the Apache License 2.0 (the "License").  You may not use
++ * this file except in compliance with the License.  You can obtain a copy
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "ssl_local.h"
++#include "internal/cryptlib.h"
++#include "internal/refcount.h"
++
++#ifdef OPENSSL_NO_QUIC
++NON_EMPTY_TRANSLATION_UNIT
++#else
++
++int SSL_set_quic_transport_params(SSL *ssl, const uint8_t *params,
++                                  size_t params_len)
++{
++    uint8_t *tmp;
++
++    if (params == NULL || params_len == 0) {
++        tmp = NULL;
++        params_len = 0;
++    } else {
++        tmp = OPENSSL_memdup(params, params_len);
++        if (tmp == NULL)
++            return 0;
++    }
++
++    OPENSSL_free(ssl->ext.quic_transport_params);
++    ssl->ext.quic_transport_params = tmp;
++    ssl->ext.quic_transport_params_len = params_len;
++    return 1;
++}
++
++void SSL_get_peer_quic_transport_params(const SSL *ssl,
++                                        const uint8_t **out_params,
++                                        size_t *out_params_len)
++{
++    *out_params = ssl->ext.peer_quic_transport_params;
++    *out_params_len = ssl->ext.peer_quic_transport_params_len;
++}
++
++size_t SSL_quic_max_handshake_flight_len(const SSL *ssl, OSSL_ENCRYPTION_LEVEL level)
++{
++    /*
++     * Limits flights to 16K by default when there are no large
++     * (certificate-carrying) messages.
++     */
++    static const size_t DEFAULT_FLIGHT_LIMIT = 16384;
++
++    switch (level) {
++    case ssl_encryption_initial:
++        return DEFAULT_FLIGHT_LIMIT;
++    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->verify_mode & SSL_VERIFY_PEER)
++                    && ssl->max_cert_list > DEFAULT_FLIGHT_LIMIT)
++                return ssl->max_cert_list;
++        } else {
++            /*
++             * Clients may receive both Certificate message and a CertificateRequest
++             * message.
++             */
++            if (2*ssl->max_cert_list > DEFAULT_FLIGHT_LIMIT)
++                return 2 * ssl->max_cert_list;
++        }
++        return DEFAULT_FLIGHT_LIMIT;
++    case ssl_encryption_application:
++        return DEFAULT_FLIGHT_LIMIT;
++    }
++
++    return 0;
++}
++
++OSSL_ENCRYPTION_LEVEL SSL_quic_read_level(const SSL *ssl)
++{
++    return ssl->quic_read_level;
++}
++
++OSSL_ENCRYPTION_LEVEL SSL_quic_write_level(const SSL *ssl)
++{
++    return ssl->quic_write_level;
++}
++
++int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
++                          const uint8_t *data, size_t len)
++{
++    size_t l;
++
++    if (!SSL_IS_QUIC(ssl)) {
++        SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++
++    /* Level can be different than the current read, but not less */
++    if (level < ssl->quic_read_level
++            || (ssl->quic_input_data_tail != NULL && level < ssl->quic_input_data_tail->level)) {
++        SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED);
++        return 0;
++    }
++
++    /* Split the QUIC messages up, if necessary */
++    while (len > 0) {
++        QUIC_DATA *qd;
++        const uint8_t *p = data + 1;
++
++        n2l3(p, l);
++        l += SSL3_HM_HEADER_LENGTH;
++
++        if (l > len) {
++            SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_BAD_DATA_LENGTH);
++            return 0;
++        }
++
++        qd = OPENSSL_malloc(sizeof(QUIC_DATA) + l);
++        if (qd == NULL) {
++            SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR);
++            return 0;
++        }
++
++        qd->next = NULL;
++        qd->length = l;
++        qd->level = level;
++        memcpy((void*)(qd + 1), data, l);
++        if (ssl->quic_input_data_tail != NULL)
++            ssl->quic_input_data_tail->next = qd;
++        else
++            ssl->quic_input_data_head = qd;
++        ssl->quic_input_data_tail = qd;
++
++        data += l;
++        len -= l;
++    }
++
++    return 1;
++}
++
++int SSL_CTX_set_quic_method(SSL_CTX *ctx, const SSL_QUIC_METHOD *quic_method)
++{
++    switch (ctx->method->version) {
++    case DTLS1_VERSION:
++    case DTLS1_2_VERSION:
++    case DTLS_ANY_VERSION:
++    case DTLS1_BAD_VER:
++        return 0;
++    default:
++        break;
++    }
++    ctx->quic_method = quic_method;
++    ctx->options &= SSL_OP_ENABLE_MIDDLEBOX_COMPAT;
++    return 1;
++}
++
++int SSL_set_quic_method(SSL *ssl, const SSL_QUIC_METHOD *quic_method)
++{
++    switch (ssl->method->version) {
++    case DTLS1_VERSION:
++    case DTLS1_2_VERSION:
++    case DTLS_ANY_VERSION:
++    case DTLS1_BAD_VER:
++        return 0;
++    default:
++        break;
++    }
++    ssl->quic_method = quic_method;
++    ssl->options &= SSL_OP_ENABLE_MIDDLEBOX_COMPAT;
++    return 1;
++}
++
++int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level)
++{
++    uint8_t *read_secret = NULL;
++    uint8_t *write_secret = NULL;
++    static const unsigned char zeros[EVP_MAX_MD_SIZE];
++
++    if (!SSL_IS_QUIC(ssl))
++        return 1;
++
++    /* secrets from the POV of the client */
++    switch (level) {
++    case ssl_encryption_early_data:
++        write_secret = ssl->early_secret;
++        break;
++    case ssl_encryption_handshake:
++        read_secret = ssl->client_finished_secret;
++        write_secret = ssl->server_finished_secret;
++        break;
++    case ssl_encryption_application:
++        read_secret = ssl->client_app_traffic_secret;
++        write_secret = ssl->server_app_traffic_secret;
++        break;
++    default:
++        return 1;
++    }
++    /* In some cases, we want to set the secret only when BOTH are non-zero */
++    if (read_secret != NULL && write_secret != NULL
++            && !memcmp(read_secret, zeros, ssl->quic_len)
++            && !memcmp(write_secret, zeros, ssl->quic_len))
++        return 1;
++
++    if (ssl->server) {
++        if (!ssl->quic_method->set_encryption_secrets(ssl, level, read_secret,
++                                                      write_secret, ssl->quic_len)) {
++            SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
++            return 0;
++        }
++    } else {
++        if (!ssl->quic_method->set_encryption_secrets(ssl, level, write_secret,
++                                                      read_secret, ssl->quic_len)) {
++            SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
++            return 0;
++        }
++    }
++
++    return 1;
++}
++
++int SSL_process_quic_post_handshake(SSL *ssl)
++{
++    if (SSL_in_init(ssl) || !SSL_IS_QUIC(ssl)) {
++        SSLerr(SSL_F_SSL_PROCESS_QUIC_POST_HANDSHAKE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        return 0;
++    }
++
++    ossl_statem_set_in_init(ssl, 1);
++
++    if (ssl->handshake_func(ssl) <= 0)
++        return 0;
++
++    return 1;
++}
++
++int SSL_is_quic(SSL* ssl)
++{
++    return SSL_IS_QUIC(ssl);
++}
++
++#endif
+diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c
+index e182b5abac..d8fa8e6913 100644
+--- a/ssl/statem/extensions.c
++++ b/ssl/statem/extensions.c
+@@ -58,6 +58,10 @@ static int final_early_data(SSL *s, unsigned int context, int sent);
+ static int final_maxfragmentlen(SSL *s, unsigned int context, int sent);
+ static int init_post_handshake_auth(SSL *s, unsigned int context);
+ static int final_psk(SSL *s, unsigned int context, int sent);
++#ifndef OPENSSL_NO_QUIC
++static int init_quic_transport_params(SSL *s, unsigned int context);
++static int final_quic_transport_params(SSL *s, unsigned int context, int sent);
++#endif
+ 
+ /* Structure to define a built-in extension */
+ typedef struct extensions_definition_st {
+@@ -369,6 +373,19 @@ static const EXTENSION_DEFINITION ext_defs[] = {
+         tls_construct_certificate_authorities,
+         tls_construct_certificate_authorities, NULL,
+     },
++#ifndef OPENSSL_NO_QUIC
++    {
++        TLSEXT_TYPE_quic_transport_parameters,
++        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_SERVER_HELLO
++        | SSL_EXT_TLS_IMPLEMENTATION_ONLY | SSL_EXT_TLS1_3_ONLY,
++        init_quic_transport_params,
++        tls_parse_ctos_quic_transport_params, tls_parse_stoc_quic_transport_params,
++        tls_construct_stoc_quic_transport_params, tls_construct_ctos_quic_transport_params,
++        final_quic_transport_params,
++    },
++#else
++    INVALID_EXTENSION,
++#endif
+     {
+         /* Must be immediately before pre_shared_key */
+         TLSEXT_TYPE_padding,
+@@ -1724,3 +1741,15 @@ static int final_psk(SSL *s, unsigned int context, int sent)
+ 
+     return 1;
+ }
++
++#ifndef OPENSSL_NO_QUIC
++static int init_quic_transport_params(SSL *s, unsigned int context)
++{
++    return 1;
++}
++
++static int final_quic_transport_params(SSL *s, unsigned int context, int sent)
++{
++    return 1;
++}
++#endif
+diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c
+index 842be0722b..52742dc36a 100644
+--- a/ssl/statem/extensions_clnt.c
++++ b/ssl/statem/extensions_clnt.c
+@@ -1196,7 +1196,29 @@ EXT_RETURN tls_construct_ctos_post_handshake_auth(SSL *s, WPACKET *pkt,
+ #endif
+ }
+ 
++#ifndef OPENSSL_NO_QUIC
++/* SAME AS tls_construct_stoc_quic_transport_params() */
++EXT_RETURN tls_construct_ctos_quic_transport_params(SSL *s, WPACKET *pkt,
++                                                    unsigned int context, X509 *x,
++                                                    size_t chainidx)
++{
++    if (s->ext.quic_transport_params == NULL
++        || s->ext.quic_transport_params_len == 0) {
++        return EXT_RETURN_NOT_SENT;
++    }
+ 
++    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_quic_transport_parameters)
++            || !WPACKET_start_sub_packet_u16(pkt)
++            || !WPACKET_sub_memcpy_u16(pkt, s->ext.quic_transport_params,
++                                       s->ext.quic_transport_params_len)
++            || !WPACKET_close(pkt)) {
++        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
++        return EXT_RETURN_FAIL;
++    }
++
++    return EXT_RETURN_SENT;
++}
++#endif
+ /*
+  * Parse the server's renegotiation binding and abort if it's not right
+  */
+@@ -1981,3 +2003,29 @@ int tls_parse_stoc_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+ 
+     return 1;
+ }
++#ifndef OPENSSL_NO_QUIC
++/* SAME AS tls_parse_ctos_quic_transport_params() */
++int tls_parse_stoc_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context,
++                                         X509 *x, size_t chainidx)
++{
++    PACKET trans_param;
++
++    if (!PACKET_as_length_prefixed_2(pkt, &trans_param)
++            || PACKET_remaining(&trans_param) == 0) {
++        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
++        return 0;
++    }
++
++    OPENSSL_free(s->ext.peer_quic_transport_params);
++    s->ext.peer_quic_transport_params = NULL;
++    s->ext.peer_quic_transport_params_len = 0;
++
++    if (!PACKET_memdup(&trans_param,
++                       &s->ext.peer_quic_transport_params,
++                       &s->ext.peer_quic_transport_params_len)) {
++        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
++        return 0;
++    }
++    return 1;
++}
++#endif
+diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c
+index 00b1ee531e..929e272cd9 100644
+--- a/ssl/statem/extensions_srvr.c
++++ b/ssl/statem/extensions_srvr.c
+@@ -1232,6 +1232,33 @@ int tls_parse_ctos_post_handshake_auth(SSL *s, PACKET *pkt,
+     return 1;
+ }
+ 
++#ifndef OPENSSL_NO_QUIC
++/* SAME AS tls_parse_stoc_quic_transport_params() */
++int tls_parse_ctos_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context,
++                                         X509 *x, size_t chainidx)
++{
++    PACKET trans_param;
++
++    if (!PACKET_as_length_prefixed_2(pkt, &trans_param)
++            || PACKET_remaining(&trans_param) == 0) {
++        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
++        return 0;
++    }
++
++    OPENSSL_free(s->ext.peer_quic_transport_params);
++    s->ext.peer_quic_transport_params = NULL;
++    s->ext.peer_quic_transport_params_len = 0;
++
++    if (!PACKET_memdup(&trans_param,
++                       &s->ext.peer_quic_transport_params,
++                       &s->ext.peer_quic_transport_params_len)) {
++        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
++        return 0;
++    }
++    return 1;
++}
++#endif
++
+ /*
+  * Add the server's renegotiation binding
+  */
+@@ -1914,3 +1941,27 @@ EXT_RETURN tls_construct_stoc_psk(SSL *s, WPACKET *pkt, unsigned int context,
+ 
+     return EXT_RETURN_SENT;
+ }
++
++#ifndef OPENSSL_NO_QUIC
++/* SAME AS tls_construct_ctos_quic_transport_params() */
++EXT_RETURN tls_construct_stoc_quic_transport_params(SSL *s, WPACKET *pkt,
++                                                    unsigned int context, X509 *x,
++                                                    size_t chainidx)
++{
++    if (s->ext.quic_transport_params == NULL
++        || s->ext.quic_transport_params_len == 0) {
++        return EXT_RETURN_NOT_SENT;
++    }
++
++    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_quic_transport_parameters)
++            || !WPACKET_start_sub_packet_u16(pkt)
++            || !WPACKET_sub_memcpy_u16(pkt, s->ext.quic_transport_params,
++                                       s->ext.quic_transport_params_len)
++            || !WPACKET_close(pkt)) {
++        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
++        return EXT_RETURN_FAIL;
++    }
++
++    return EXT_RETURN_SENT;
++}
++#endif
+diff --git a/ssl/statem/statem.c b/ssl/statem/statem.c
+index 553546d93a..f6caa64e4c 100644
+--- a/ssl/statem/statem.c
++++ b/ssl/statem/statem.c
+@@ -583,6 +583,10 @@ static SUB_STATE_RETURN read_state_machine(SSL *s)
+                  * In DTLS we get the whole message in one go - header and body
+                  */
+                 ret = dtls_get_message(s, &mt);
++#ifndef OPENSSL_NO_QUIC
++            } else if (SSL_IS_QUIC(s)) {
++                ret = quic_get_message(s, &mt, &len);
++#endif
+             } else {
+                 ret = tls_get_message_header(s, &mt);
+             }
+@@ -612,8 +616,8 @@ static SUB_STATE_RETURN read_state_machine(SSL *s)
+                 return SUB_STATE_ERROR;
+             }
+ 
+-            /* dtls_get_message already did this */
+-            if (!SSL_IS_DTLS(s)
++            /* dtls_get_message/quic_get_message already did this */
++            if (!SSL_IS_DTLS(s) && !SSL_IS_QUIC(s)
+                     && s->s3.tmp.message_size > 0
+                     && !grow_init_buf(s, s->s3.tmp.message_size
+                                          + SSL3_HM_HEADER_LENGTH)) {
+@@ -631,7 +635,8 @@ static SUB_STATE_RETURN read_state_machine(SSL *s)
+                  * opportunity to do any further processing.
+                  */
+                 ret = dtls_get_message_body(s, &len);
+-            } else {
++            } else if (!SSL_IS_QUIC(s)) {
++                /* We already got this above for QUIC */
+                 ret = tls_get_message_body(s, &len);
+             }
+             if (ret == 0) {
+@@ -921,6 +926,15 @@ static SUB_STATE_RETURN write_state_machine(SSL *s)
+ int statem_flush(SSL *s)
+ {
+     s->rwstate = SSL_WRITING;
++#ifndef OPENSSL_NO_QUIC
++    if (SSL_IS_QUIC(s)) {
++        if (!s->quic_method->flush_flight(s)) {
++            /* NOTE: BIO_flush() does not generate an error */
++            SSLerr(SSL_F_STATEM_FLUSH, ERR_R_INTERNAL_ERROR);
++            return 0;
++        }
++    } else
++#endif
+     if (BIO_flush(s->wbio) <= 0) {
+         return 0;
+     }
+diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c
+index 25055df15c..65899e6b83 100644
+--- a/ssl/statem/statem_lib.c
++++ b/ssl/statem/statem_lib.c
+@@ -44,9 +44,23 @@ int ssl3_do_write(SSL *s, int type)
+ {
+     int ret;
+     size_t written = 0;
++#ifndef OPENSSL_NO_QUIC
++    if (SSL_IS_QUIC(s) && type == SSL3_RT_HANDSHAKE) {
++        ret = s->quic_method->add_handshake_data(s, s->quic_write_level,
++                                                 (const uint8_t*)&s->init_buf->data[s->init_off],
++                                          s->init_num);
++        if (!ret) {
++            ret = -1;
++            /* QUIC can't sent anything out sice the above failed */
++            SSLerr(SSL_F_SSL3_DO_WRITE, ERR_R_INTERNAL_ERROR);
++        } else {
++            written = s->init_num;
++        }
++    } else
++#endif
++        ret = ssl3_write_bytes(s, type, &s->init_buf->data[s->init_off],
++                               s->init_num, &written);
+ 
+-    ret = ssl3_write_bytes(s, type, &s->init_buf->data[s->init_off],
+-                           s->init_num, &written);
+     if (ret <= 0)
+         return -1;
+     if (type == SSL3_RT_HANDSHAKE)
+@@ -1163,6 +1177,7 @@ int tls_get_message_header(SSL *s, int *mt)
+ 
+     do {
+         while (s->init_num < SSL3_HM_HEADER_LENGTH) {
++            /* QUIC: either create a special ssl_read_bytes... or if/else this */
+             i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, &recvd_type,
+                                           &p[s->init_num],
+                                           SSL3_HM_HEADER_LENGTH - s->init_num,
+diff --git a/ssl/statem/statem_local.h b/ssl/statem/statem_local.h
+index ad4d93b1e2..57e314512b 100644
+--- a/ssl/statem/statem_local.h
++++ b/ssl/statem/statem_local.h
+@@ -104,6 +104,7 @@ __owur int tls_get_message_header(SSL *s, int *mt);
+ __owur int tls_get_message_body(SSL *s, size_t *len);
+ __owur int dtls_get_message(SSL *s, int *mt);
+ __owur int dtls_get_message_body(SSL *s, size_t *len);
++__owur int quic_get_message(SSL *s, int *mt, size_t *len);
+ 
+ /* Message construction and processing functions */
+ __owur int tls_process_initial_server_flight(SSL *s);
+@@ -251,6 +252,10 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                        size_t chainidx);
+ int tls_parse_ctos_post_handshake_auth(SSL *, PACKET *pkt, unsigned int context,
+                                        X509 *x, size_t chainidx);
++#ifndef OPENSSL_NO_QUIC
++int tls_parse_ctos_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context,
++                                         X509 *x, size_t chainidx);
++#endif
+ 
+ EXT_RETURN tls_construct_stoc_renegotiate(SSL *s, WPACKET *pkt,
+                                           unsigned int context, X509 *x,
+@@ -311,6 +316,11 @@ EXT_RETURN tls_construct_stoc_cryptopro_bug(SSL *s, WPACKET *pkt,
+                                             size_t chainidx);
+ EXT_RETURN tls_construct_stoc_psk(SSL *s, WPACKET *pkt, unsigned int context,
+                                   X509 *x, size_t chainidx);
++#ifndef OPENSSL_NO_QUIC
++EXT_RETURN tls_construct_stoc_quic_transport_params(SSL *s, WPACKET *pkt,
++                                                    unsigned int context, X509 *x,
++                                                    size_t chainidx);
++#endif
+ 
+ /* Client Extension processing */
+ EXT_RETURN tls_construct_ctos_renegotiate(SSL *s, WPACKET *pkt, unsigned int context,
+@@ -380,6 +390,11 @@ EXT_RETURN tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context,
+                                   X509 *x, size_t chainidx);
+ EXT_RETURN tls_construct_ctos_post_handshake_auth(SSL *s, WPACKET *pkt, unsigned int context,
+                                                   X509 *x, size_t chainidx);
++#ifndef OPENSSL_NO_QUIC
++EXT_RETURN tls_construct_ctos_quic_transport_params(SSL *s, WPACKET *pkt,
++                                                    unsigned int context, X509 *x,
++                                                    size_t chainidx);
++#endif
+ 
+ int tls_parse_stoc_renegotiate(SSL *s, PACKET *pkt, unsigned int context,
+                                X509 *x, size_t chainidx);
+@@ -423,6 +438,10 @@ int tls_parse_stoc_cookie(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                        size_t chainidx);
+ int tls_parse_stoc_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                        size_t chainidx);
++#ifndef OPENSSL_NO_QUIC
++int tls_parse_stoc_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context,
++                                         X509 *x, size_t chainidx);
++#endif
+ 
+ int tls_handle_alpn(SSL *s);
+ 
+diff --git a/ssl/statem/statem_quic.c b/ssl/statem/statem_quic.c
+new file mode 100644
+index 0000000000..66acc30d6d
+--- /dev/null
++++ b/ssl/statem/statem_quic.c
+@@ -0,0 +1,106 @@
++/*
++ * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
++ *
++ * Licensed under the Apache License 2.0 (the "License").  You may not use
++ * this file except in compliance with the License.  You can obtain a copy
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#include "../ssl_local.h"
++#include "statem_local.h"
++#include "internal/cryptlib.h"
++
++#ifdef OPENSSL_NO_QUIC
++NON_EMPTY_TRANSLATION_UNIT
++#else
++
++int quic_get_message(SSL *s, int *mt, size_t *len)
++{
++    size_t l;
++    QUIC_DATA *qd;
++    uint8_t *p;
++
++    if (s->quic_input_data_head == NULL) {
++        s->rwstate = SSL_READING;
++        *len = 0;
++        return 0;
++    }
++
++    /* This is where we check for the proper level, not when data is given */
++    if (s->quic_input_data_head->level != s->quic_read_level) {
++        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED);
++        *len = 0;
++        return 0;
++    }
++
++    if (!BUF_MEM_grow_clean(s->init_buf, (int)s->quic_input_data_head->length)) {
++        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_BUF_LIB);
++        *len = 0;
++        return 0;
++    }
++
++    /* Copy buffered data */
++    qd = s->quic_input_data_head;
++    memcpy(s->init_buf->data, (void*)(qd + 1), qd->length);
++    s->init_buf->length = qd->length;
++    s->quic_input_data_head = qd->next;
++    if (s->quic_input_data_head == NULL)
++        s->quic_input_data_tail = NULL;
++    OPENSSL_free(qd);
++
++    s->s3.tmp.message_type = *mt = *(s->init_buf->data);
++    p = (uint8_t*)s->init_buf->data + 1;
++    n2l3(p, l);
++    s->init_num = s->s3.tmp.message_size = *len = l;
++    s->init_msg = s->init_buf->data + SSL3_HM_HEADER_LENGTH;
++
++    /* No CCS in QUIC/TLSv1.3? */
++    if (*mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
++        SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_R_CCS_RECEIVED_EARLY);
++        *len = 0;
++        return 0;
++    }
++
++    /*
++     * If receiving Finished, record MAC of prior handshake messages for
++     * Finished verification.
++     */
++    if (*mt == SSL3_MT_FINISHED && !ssl3_take_mac(s)) {
++        /* SSLfatal() already called */
++        *len = 0;
++        return 0;
++    }
++
++    /*
++     * We defer feeding in the HRR until later. We'll do it as part of
++     * processing the message
++     * The TLsv1.3 handshake transcript stops at the ClientFinished
++     * message.
++     */
++#define SERVER_HELLO_RANDOM_OFFSET  (SSL3_HM_HEADER_LENGTH + 2)
++    /* KeyUpdate and NewSessionTicket do not need to be added */
++    if (!SSL_IS_TLS13(s) || (s->s3.tmp.message_type != SSL3_MT_NEWSESSION_TICKET
++                             && s->s3.tmp.message_type != SSL3_MT_KEY_UPDATE)) {
++        if (s->s3.tmp.message_type != SSL3_MT_SERVER_HELLO
++            || s->init_num < SERVER_HELLO_RANDOM_OFFSET + SSL3_RANDOM_SIZE
++            || memcmp(hrrrandom,
++                      s->init_buf->data + SERVER_HELLO_RANDOM_OFFSET,
++                      SSL3_RANDOM_SIZE) != 0) {
++            if (!ssl3_finish_mac(s, (unsigned char *)s->init_buf->data,
++                                 s->init_num + SSL3_HM_HEADER_LENGTH)) {
++                /* SSLfatal() already called */
++                *len = 0;
++                return 0;
++            }
++        }
++    }
++    if (s->msg_callback)
++        s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->init_buf->data,
++                        (size_t)s->init_num + SSL3_HM_HEADER_LENGTH, s,
++                        s->msg_callback_arg);
++
++    return 1;
++}
++
++#endif
+diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c
+index 9ae2126e3c..b828b509f4 100644
+--- a/ssl/tls13_enc.c
++++ b/ssl/tls13_enc.c
+@@ -422,6 +422,9 @@ int tls13_change_cipher_state(SSL *s, int which)
+     ktls_crypto_info_t crypto_info;
+     BIO *bio;
+ #endif
++#ifndef OPENSSL_NO_QUIC
++    OSSL_ENCRYPTION_LEVEL level = ssl_encryption_initial;
++#endif
+ 
+     if (which & SSL3_CC_READ) {
+         if (s->enc_read_ctx != NULL) {
+@@ -467,6 +470,9 @@ int tls13_change_cipher_state(SSL *s, int which)
+             label = client_early_traffic;
+             labellen = sizeof(client_early_traffic) - 1;
+             log_label = CLIENT_EARLY_LABEL;
++#ifndef OPENSSL_NO_QUIC
++            level = ssl_encryption_early_data;
++#endif
+ 
+             handlen = BIO_get_mem_data(s->s3.handshake_buffer, &hdata);
+             if (handlen <= 0) {
+@@ -526,6 +532,9 @@ int tls13_change_cipher_state(SSL *s, int which)
+                 goto err;
+             }
+             hashlen = hashlenui;
++#ifndef OPENSSL_NO_QUIC
++            s->quic_len = hashlen;
++#endif
+             EVP_MD_CTX_free(mdctx);
+ 
+             if (!tls13_hkdf_expand(s, md, insecret,
+@@ -543,6 +552,14 @@ int tls13_change_cipher_state(SSL *s, int which)
+                 /* SSLfatal() already called */
+                 goto err;
+             }
++#ifndef OPENSSL_NO_QUIC
++            if (SSL_IS_QUIC(s)) {
++                if (s->server)
++                    s->quic_read_level = ssl_encryption_early_data;
++                else
++                    s->quic_write_level = ssl_encryption_early_data;
++            }
++#endif
+         } else if (which & SSL3_CC_HANDSHAKE) {
+             insecret = s->handshake_secret;
+             finsecret = s->client_finished_secret;
+@@ -550,6 +567,15 @@ int tls13_change_cipher_state(SSL *s, int which)
+             label = client_handshake_traffic;
+             labellen = sizeof(client_handshake_traffic) - 1;
+             log_label = CLIENT_HANDSHAKE_LABEL;
++#ifndef OPENSSL_NO_QUIC
++            if (SSL_IS_QUIC(s)) {
++                level = ssl_encryption_handshake;
++                if (s->server)
++                    s->quic_read_level = ssl_encryption_handshake;
++                else
++                    s->quic_write_level = ssl_encryption_handshake;
++            }
++#endif
+             /*
+              * The handshake hash used for the server read/client write handshake
+              * traffic secret is the same as the hash for the server
+@@ -572,6 +598,15 @@ int tls13_change_cipher_state(SSL *s, int which)
+              * previously saved value.
+              */
+             hash = s->server_finished_hash;
++#ifndef OPENSSL_NO_QUIC
++            if (SSL_IS_QUIC(s)) {
++                level = ssl_encryption_application; /* ??? */
++                if (s->server)
++                    s->quic_read_level = ssl_encryption_application;
++                else
++                    s->quic_write_level = ssl_encryption_application;
++            }
++#endif
+         }
+     } else {
+         /* Early data never applies to client-read/server-write */
+@@ -582,11 +617,29 @@ int tls13_change_cipher_state(SSL *s, int which)
+             label = server_handshake_traffic;
+             labellen = sizeof(server_handshake_traffic) - 1;
+             log_label = SERVER_HANDSHAKE_LABEL;
++#ifndef OPENSSL_NO_QUIC
++            if (SSL_IS_QUIC(s)) {
++                level = ssl_encryption_handshake;
++                if (s->server)
++                    s->quic_write_level = ssl_encryption_handshake;
++                else
++                    s->quic_read_level = ssl_encryption_handshake;
++            }
++#endif
+         } else {
+             insecret = s->master_secret;
+             label = server_application_traffic;
+             labellen = sizeof(server_application_traffic) - 1;
+             log_label = SERVER_APPLICATION_LABEL;
++#ifndef OPENSSL_NO_QUIC
++            if (SSL_IS_QUIC(s)) {
++                level = ssl_encryption_application;
++                if (s->server)
++                    s->quic_write_level = ssl_encryption_application;
++                else
++                    s->quic_read_level = ssl_encryption_application;
++            }
++#endif
+         }
+     }
+ 
+@@ -714,6 +767,12 @@ int tls13_change_cipher_state(SSL *s, int which)
+ skip_ktls:
+ # endif
+ #endif
++
++#ifndef OPENSSL_NO_QUIC
++    if (!quic_set_encryption_secrets(s, level))
++        goto err;
++#endif
++
+     ret = 1;
+  err:
+     if ((which & SSL3_CC_EARLY) != 0) {
+diff --git a/test/helpers/ssltestlib.c b/test/helpers/ssltestlib.c
+index f0dccfa54c..c317e03d8e 100644
+--- a/test/helpers/ssltestlib.c
++++ b/test/helpers/ssltestlib.c
+@@ -1157,6 +1157,11 @@ int create_ssl_connection(SSL *serverssl, SSL *clientssl, int want)
+     if (!create_bare_ssl_connection(serverssl, clientssl, want, 1))
+         return 0;
+ 
++#ifndef OPENSSL_NO_QUIC
++    /* QUIC does not support SSL_read_ex */
++    if (SSL_is_quic(clientssl))
++        return 1;
++#endif
+     /*
+      * We attempt to read some data on the client side which we expect to fail.
+      * This will ensure we have received the NewSessionTicket in TLSv1.3 where
+diff --git a/test/sslapitest.c b/test/sslapitest.c
+index 45286653b9..b0bafe7549 100644
+--- a/test/sslapitest.c
++++ b/test/sslapitest.c
+@@ -10095,6 +10095,7 @@ static int test_inherit_verify_param(void)
+     return testresult;
+ }
+ 
++
+ static int test_load_dhfile(void)
+ {
+ #ifndef OPENSSL_NO_DH
+@@ -10130,9 +10131,144 @@ end:
+ #endif
+ }
+ 
++#ifndef OPENSSL_NO_QUIC
++static int test_quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
++                                            const uint8_t *read_secret,
++                                            const uint8_t *write_secret, size_t secret_len)
++{
++    test_printf_stderr("quic_set_encryption_secrets() %s, lvl=%d, len=%zd\n",
++                       ssl->server ? "server" : "client", level, secret_len);
++    return 1;
++}
++
++static int test_quic_add_handshake_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
++                                        const uint8_t *data, size_t len)
++{
++    SSL *peer = (SSL*)SSL_get_app_data(ssl);
++
++    test_printf_stderr("quic_add_handshake_data() %s, lvl=%d, *data=0x%02X, len=%zd\n",
++                       ssl->server ? "server" : "client", level, (int)*data, len);
++    if (!TEST_ptr(peer))
++        return 0;
++
++    if (!TEST_true(SSL_provide_quic_data(peer, level, data, len))) {
++        ERR_print_errors_fp(stderr);
++        return 0;
++    }
++
++    return 1;
++}
++
++static int test_quic_flush_flight(SSL *ssl)
++{
++    test_printf_stderr("quic_flush_flight() %s\n", ssl->server ? "server" : "client");
++    return 1;
++}
++
++static int test_quic_send_alert(SSL *ssl, enum ssl_encryption_level_t level, uint8_t alert)
++{
++    test_printf_stderr("quic_send_alert() %s, lvl=%d, alert=%d\n",
++                       ssl->server ? "server" : "client", level, alert);
++    return 1;
++}
++
++static SSL_QUIC_METHOD quic_method = {
++    test_quic_set_encryption_secrets,
++    test_quic_add_handshake_data,
++    test_quic_flush_flight,
++    test_quic_send_alert,
++};
++
++static int test_quic_api(void)
++{
++    SSL_CTX *cctx = NULL, *sctx = NULL;
++    SSL *clientssl = NULL, *serverssl = NULL;
++    int testresult = 0;
++	
++    static const char *server_str = "SERVER";
++    static const char *client_str = "CLIENT";
++    const uint8_t *peer_str;
++    size_t peer_str_len;
++
++    /* Clean up logging space */
++    memset(client_log_buffer, 0, sizeof(client_log_buffer));
++    memset(server_log_buffer, 0, sizeof(server_log_buffer));
++    client_log_buffer_index = 0;
++    server_log_buffer_index = 0;
++    error_writing_log = 0;
++
++
++    if (!TEST_ptr(sctx = SSL_CTX_new_ex(libctx, NULL, TLS_server_method()))
++            || !TEST_true(SSL_CTX_set_quic_method(sctx, &quic_method))
++            || !TEST_ptr(sctx->quic_method)
++            || !TEST_ptr(serverssl = SSL_new(sctx))
++            || !TEST_true(SSL_IS_QUIC(serverssl))
++            || !TEST_true(SSL_set_quic_method(serverssl, NULL))
++            || !TEST_false(SSL_IS_QUIC(serverssl))
++            || !TEST_true(SSL_set_quic_method(serverssl, &quic_method))
++            || !TEST_true(SSL_IS_QUIC(serverssl)))
++        goto end;
++
++    SSL_CTX_free(sctx);
++    sctx = NULL;
++    SSL_free(serverssl);
++    serverssl = NULL;
++
++    if (!TEST_true(create_ssl_ctx_pair(libctx,
++                                       TLS_server_method(),
++                                       TLS_client_method(),
++                                       TLS1_3_VERSION, 0,
++                                       &sctx, &cctx, cert, privkey))
++            || !TEST_true(SSL_CTX_set_quic_method(sctx, &quic_method))
++            || !TEST_true(SSL_CTX_set_quic_method(cctx, &quic_method))
++            || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl,
++                                             &clientssl, NULL, NULL))
++            || !TEST_true(SSL_set_quic_transport_params(serverssl,
++                                                        (unsigned char*)server_str,
++                                                        sizeof(server_str)))
++            || !TEST_true(SSL_set_quic_transport_params(clientssl,
++                                                        (unsigned char*)client_str,
++                                                        sizeof(client_str)))
++            || !TEST_true(SSL_set_app_data(serverssl, clientssl))
++            || !TEST_true(SSL_set_app_data(clientssl, serverssl))
++            || !TEST_true(create_ssl_connection(serverssl, clientssl,
++                                                SSL_ERROR_NONE))
++            || !TEST_true(SSL_version(serverssl) == TLS1_3_VERSION)
++            || !TEST_true(SSL_version(clientssl) == TLS1_3_VERSION)
++            || !(TEST_int_eq(SSL_quic_read_level(clientssl), ssl_encryption_application))
++            || !(TEST_int_eq(SSL_quic_read_level(serverssl), ssl_encryption_application))
++            || !(TEST_int_eq(SSL_quic_write_level(clientssl), ssl_encryption_application))
++            || !(TEST_int_eq(SSL_quic_write_level(serverssl), ssl_encryption_application)))
++        goto end;
++
++    SSL_get_peer_quic_transport_params(serverssl, &peer_str, &peer_str_len);
++    if (!TEST_mem_eq(peer_str, peer_str_len, client_str, sizeof(client_str)))
++        goto end;
++    SSL_get_peer_quic_transport_params(clientssl, &peer_str, &peer_str_len);
++    if (!TEST_mem_eq(peer_str, peer_str_len, server_str, sizeof(server_str)))
++        goto end;
++
++    /* Deal with two NewSessionTickets */
++    if (!TEST_true(SSL_process_quic_post_handshake(clientssl))
++            || !TEST_true(SSL_process_quic_post_handshake(clientssl)))
++        goto end;
++
++    testresult = 1;
++
++ end:
++	SSL_free(serverssl);
++    SSL_free(clientssl);
++    SSL_CTX_free(sctx);
++    SSL_CTX_free(cctx);
++
++    return testresult;
++}
++#endif /* OPENSSL_NO_QUIC */
++
+ #ifndef OSSL_NO_USABLE_TLS1_3
+ /* Test that read_ahead works across a key change */
+ static int test_read_ahead_key_change(void)
++
+ {
+     SSL_CTX *cctx = NULL, *sctx = NULL;
+     SSL *clientssl = NULL, *serverssl = NULL;
+@@ -10192,6 +10328,7 @@ end:
+     SSL_free(clientssl);
+     SSL_CTX_free(sctx);
+     SSL_CTX_free(cctx);
++
+     return testresult;
+ }
+ 
+@@ -10902,6 +11039,9 @@ int setup_tests(void)
+     ADD_ALL_TESTS(test_pipelining, 7);
+ #endif
+     ADD_ALL_TESTS(test_handshake_retry, 16);
++#ifndef OPENSSL_NO_QUIC
++    ADD_TEST(test_quic_api);
++#endif
+     return 1;
+ 
+  err:
+diff --git a/test/tls13secretstest.c b/test/tls13secretstest.c
+index bf214d3d5b..8323b23778 100644
+--- a/test/tls13secretstest.c
++++ b/test/tls13secretstest.c
+@@ -224,6 +224,13 @@ void ssl_evp_md_free(const EVP_MD *md)
+ {
+ }
+ 
++#ifndef OPENSSL_NO_QUIC
++int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level)
++{
++    return 1;
++}
++#endif
++
+ /* End of mocked out code */
+ 
+ static int test_secret(SSL *s, unsigned char *prk,
+diff --git a/util/libssl.num b/util/libssl.num
+index f055c967bf..72ee0bedc6 100644
+--- a/util/libssl.num
++++ b/util/libssl.num
+@@ -520,3 +520,14 @@ SSL_load_client_CA_file_ex              520	3_0_0	EXIST::FUNCTION:
+ SSL_set0_tmp_dh_pkey                    521	3_0_0	EXIST::FUNCTION:
+ SSL_CTX_set0_tmp_dh_pkey                522	3_0_0	EXIST::FUNCTION:
+ SSL_group_to_name                       523	3_0_0	EXIST::FUNCTION:
++SSL_quic_read_level                     20000	3_0_0	EXIST::FUNCTION:QUIC
++SSL_set_quic_transport_params           20001	3_0_0	EXIST::FUNCTION:QUIC
++SSL_CIPHER_get_prf_nid                  20002	3_0_0	EXIST::FUNCTION:
++SSL_is_quic                             20003	3_0_0	EXIST::FUNCTION:QUIC
++SSL_get_peer_quic_transport_params      20004	3_0_0	EXIST::FUNCTION:QUIC
++SSL_quic_write_level                    20005	3_0_0	EXIST::FUNCTION:QUIC
++SSL_CTX_set_quic_method                 20006	3_0_0	EXIST::FUNCTION:QUIC
++SSL_set_quic_method                     20007	3_0_0	EXIST::FUNCTION:QUIC
++SSL_quic_max_handshake_flight_len       20008	3_0_0	EXIST::FUNCTION:QUIC
++SSL_process_quic_post_handshake         20009	3_0_0	EXIST::FUNCTION:QUIC
++SSL_provide_quic_data                   20010	3_0_0	EXIST::FUNCTION:QUIC
+diff --git a/util/other.syms b/util/other.syms
+index cdd62e81d0..baba363337 100644
+--- a/util/other.syms
++++ b/util/other.syms
+@@ -142,6 +142,8 @@ custom_ext_free_cb                      datatype
+ custom_ext_parse_cb                     datatype
+ pem_password_cb                         datatype
+ ssl_ct_validation_cb                    datatype
++OSSL_ENCRYPTION_LEVEL                   datatype
++SSL_QUIC_METHOD                         datatype
+ #
+ ASN1_BIT_STRING_digest                  define
+ BIO_append_filename                     define
+-- 
+2.42.0
+
diff --git a/0002-QUIC-New-method-to-get-QUIC-secret-length.patch b/0002-QUIC-New-method-to-get-QUIC-secret-length.patch
new file mode 100644
index 0000000..e296d08
--- /dev/null
+++ b/0002-QUIC-New-method-to-get-QUIC-secret-length.patch
@@ -0,0 +1,99 @@
+From 3673eecaa83e6687d8e4d6ecd826928b27c5c639 Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Fri, 14 Jun 2019 12:04:14 -0400
+Subject: [PATCH 02/63] QUIC: New method to get QUIC secret length
+
+---
+ ssl/ssl_local.h |  1 -
+ ssl/ssl_quic.c  | 30 ++++++++++++++++++++++++++----
+ ssl/tls13_enc.c |  3 ---
+ 3 files changed, 26 insertions(+), 8 deletions(-)
+
+diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h
+index 3e67b36990..725ba1cdc5 100644
+--- a/ssl/ssl_local.h
++++ b/ssl/ssl_local.h
+@@ -1717,7 +1717,6 @@ struct ssl_st {
+     QUIC_DATA *quic_input_data_head;
+     QUIC_DATA *quic_input_data_tail;
+     const SSL_QUIC_METHOD *quic_method;
+-    size_t quic_len;
+ #endif
+     /*
+      * Parsed form of the ClientHello, kept around across client_hello_cb
+diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c
+index a39e4419c9..46cca0b4db 100644
+--- a/ssl/ssl_quic.c
++++ b/ssl/ssl_quic.c
+@@ -181,6 +181,8 @@ int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level)
+ {
+     uint8_t *read_secret = NULL;
+     uint8_t *write_secret = NULL;
++    size_t len;
++    const EVP_MD *md;
+     static const unsigned char zeros[EVP_MAX_MD_SIZE];
+ 
+     if (!SSL_IS_QUIC(ssl))
+@@ -202,21 +204,41 @@ int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level)
+     default:
+         return 1;
+     }
++
++    md = ssl_handshake_md(ssl);
++    if (md == NULL) {
++        /* May not have selected cipher, yet */
++        const SSL_CIPHER *c = NULL;
++
++        if (ssl->session != NULL)
++            c = SSL_SESSION_get0_cipher(ssl->session);
++        else if (ssl->psksession != NULL)
++            c = SSL_SESSION_get0_cipher(ssl->psksession);
++
++        if (c != NULL)
++            md = SSL_CIPHER_get_handshake_digest(c);
++    }
++
++    if ((len = EVP_MD_size(md)) <= 0) {
++        SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
++        return 0;
++    }
++
+     /* In some cases, we want to set the secret only when BOTH are non-zero */
+     if (read_secret != NULL && write_secret != NULL
+-            && !memcmp(read_secret, zeros, ssl->quic_len)
+-            && !memcmp(write_secret, zeros, ssl->quic_len))
++            && !memcmp(read_secret, zeros, len)
++            && !memcmp(write_secret, zeros, len))
+         return 1;
+ 
+     if (ssl->server) {
+         if (!ssl->quic_method->set_encryption_secrets(ssl, level, read_secret,
+-                                                      write_secret, ssl->quic_len)) {
++                                                      write_secret, len)) {
+             SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+             return 0;
+         }
+     } else {
+         if (!ssl->quic_method->set_encryption_secrets(ssl, level, write_secret,
+-                                                      read_secret, ssl->quic_len)) {
++                                                      read_secret, len)) {
+             SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+             return 0;
+         }
+diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c
+index b828b509f4..d4fafc4339 100644
+--- a/ssl/tls13_enc.c
++++ b/ssl/tls13_enc.c
+@@ -532,9 +532,6 @@ int tls13_change_cipher_state(SSL *s, int which)
+                 goto err;
+             }
+             hashlen = hashlenui;
+-#ifndef OPENSSL_NO_QUIC
+-            s->quic_len = hashlen;
+-#endif
+             EVP_MD_CTX_free(mdctx);
+ 
+             if (!tls13_hkdf_expand(s, md, insecret,
+-- 
+2.42.0
+
diff --git a/0003-QUIC-Make-temp-secret-names-less-confusing.patch b/0003-QUIC-Make-temp-secret-names-less-confusing.patch
new file mode 100644
index 0000000..fc7e7e2
--- /dev/null
+++ b/0003-QUIC-Make-temp-secret-names-less-confusing.patch
@@ -0,0 +1,76 @@
+From 0cf2cb7616be1c1133b7724f6972434d39a719a9 Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Thu, 15 Aug 2019 11:13:15 -0400
+Subject: [PATCH 03/63] QUIC: Make temp secret names less confusing
+
+---
+ ssl/ssl_quic.c | 28 ++++++++++++++--------------
+ 1 file changed, 14 insertions(+), 14 deletions(-)
+
+diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c
+index 46cca0b4db..6ba8f56952 100644
+--- a/ssl/ssl_quic.c
++++ b/ssl/ssl_quic.c
+@@ -179,8 +179,8 @@ int SSL_set_quic_method(SSL *ssl, const SSL_QUIC_METHOD *quic_method)
+ 
+ int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level)
+ {
+-    uint8_t *read_secret = NULL;
+-    uint8_t *write_secret = NULL;
++    uint8_t *c2s_secret = NULL;
++    uint8_t *s2c_secret = NULL;
+     size_t len;
+     const EVP_MD *md;
+     static const unsigned char zeros[EVP_MAX_MD_SIZE];
+@@ -191,15 +191,15 @@ int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level)
+     /* secrets from the POV of the client */
+     switch (level) {
+     case ssl_encryption_early_data:
+-        write_secret = ssl->early_secret;
++        s2c_secret = ssl->early_secret;
+         break;
+     case ssl_encryption_handshake:
+-        read_secret = ssl->client_finished_secret;
+-        write_secret = ssl->server_finished_secret;
++        c2s_secret = ssl->client_finished_secret;
++        s2c_secret = ssl->server_finished_secret;
+         break;
+     case ssl_encryption_application:
+-        read_secret = ssl->client_app_traffic_secret;
+-        write_secret = ssl->server_app_traffic_secret;
++        c2s_secret = ssl->client_app_traffic_secret;
++        s2c_secret = ssl->server_app_traffic_secret;
+         break;
+     default:
+         return 1;
+@@ -225,20 +225,20 @@ int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level)
+     }
+ 
+     /* In some cases, we want to set the secret only when BOTH are non-zero */
+-    if (read_secret != NULL && write_secret != NULL
+-            && !memcmp(read_secret, zeros, len)
+-            && !memcmp(write_secret, zeros, len))
++    if (c2s_secret != NULL && s2c_secret != NULL
++            && !memcmp(c2s_secret, zeros, len)
++            && !memcmp(s2c_secret, zeros, len))
+         return 1;
+ 
+     if (ssl->server) {
+-        if (!ssl->quic_method->set_encryption_secrets(ssl, level, read_secret,
+-                                                      write_secret, len)) {
++        if (!ssl->quic_method->set_encryption_secrets(ssl, level, c2s_secret,
++                                                      s2c_secret, len)) {
+             SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+             return 0;
+         }
+     } else {
+-        if (!ssl->quic_method->set_encryption_secrets(ssl, level, write_secret,
+-                                                      read_secret, len)) {
++        if (!ssl->quic_method->set_encryption_secrets(ssl, level, s2c_secret,
++                                                      c2s_secret, len)) {
+             SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+             return 0;
+         }
+-- 
+2.42.0
+
diff --git a/0004-QUIC-Move-QUIC-transport-params-to-encrypted-extensi.patch b/0004-QUIC-Move-QUIC-transport-params-to-encrypted-extensi.patch
new file mode 100644
index 0000000..273fbad
--- /dev/null
+++ b/0004-QUIC-Move-QUIC-transport-params-to-encrypted-extensi.patch
@@ -0,0 +1,26 @@
+From 796c5cd87644b07d7bd079388cc6495b2731b266 Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Thu, 15 Aug 2019 11:35:10 -0400
+Subject: [PATCH 04/63] QUIC: Move QUIC transport params to encrypted
+ extensions
+
+---
+ ssl/statem/extensions.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c
+index d8fa8e6913..548772be6d 100644
+--- a/ssl/statem/extensions.c
++++ b/ssl/statem/extensions.c
+@@ -376,7 +376,7 @@ static const EXTENSION_DEFINITION ext_defs[] = {
+ #ifndef OPENSSL_NO_QUIC
+     {
+         TLSEXT_TYPE_quic_transport_parameters,
+-        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_SERVER_HELLO
++        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS
+         | SSL_EXT_TLS_IMPLEMENTATION_ONLY | SSL_EXT_TLS1_3_ONLY,
+         init_quic_transport_params,
+         tls_parse_ctos_quic_transport_params, tls_parse_stoc_quic_transport_params,
+-- 
+2.42.0
+
diff --git a/0005-QUIC-Use-proper-secrets-for-handshake.patch b/0005-QUIC-Use-proper-secrets-for-handshake.patch
new file mode 100644
index 0000000..34ca0d0
--- /dev/null
+++ b/0005-QUIC-Use-proper-secrets-for-handshake.patch
@@ -0,0 +1,59 @@
+From 9e02139ca1b6aa2e644cc9b5214f058019c156e1 Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Thu, 15 Aug 2019 12:37:03 -0400
+Subject: [PATCH 05/63] QUIC: Use proper secrets for handshake
+
+---
+ ssl/ssl_local.h | 2 ++
+ ssl/ssl_quic.c  | 4 ++--
+ ssl/tls13_enc.c | 6 ++++++
+ 3 files changed, 10 insertions(+), 2 deletions(-)
+
+diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h
+index 725ba1cdc5..17f8aed1e3 100644
+--- a/ssl/ssl_local.h
++++ b/ssl/ssl_local.h
+@@ -1490,6 +1490,8 @@ struct ssl_st {
+     unsigned char handshake_traffic_hash[EVP_MAX_MD_SIZE];
+     unsigned char client_app_traffic_secret[EVP_MAX_MD_SIZE];
+     unsigned char server_app_traffic_secret[EVP_MAX_MD_SIZE];
++    unsigned char client_hand_traffic_secret[EVP_MAX_MD_SIZE];
++    unsigned char server_hand_traffic_secret[EVP_MAX_MD_SIZE];
+     unsigned char exporter_master_secret[EVP_MAX_MD_SIZE];
+     unsigned char early_exporter_master_secret[EVP_MAX_MD_SIZE];
+     EVP_CIPHER_CTX *enc_read_ctx; /* cryptographic state */
+diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c
+index 6ba8f56952..7ece8af9bb 100644
+--- a/ssl/ssl_quic.c
++++ b/ssl/ssl_quic.c
+@@ -194,8 +194,8 @@ int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level)
+         s2c_secret = ssl->early_secret;
+         break;
+     case ssl_encryption_handshake:
+-        c2s_secret = ssl->client_finished_secret;
+-        s2c_secret = ssl->server_finished_secret;
++        c2s_secret = ssl->client_hand_traffic_secret;
++        s2c_secret = ssl->server_hand_traffic_secret;
+         break;
+     case ssl_encryption_application:
+         c2s_secret = ssl->client_app_traffic_secret;
+diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c
+index d4fafc4339..68b6573fd1 100644
+--- a/ssl/tls13_enc.c
++++ b/ssl/tls13_enc.c
+@@ -705,6 +705,12 @@ int tls13_change_cipher_state(SSL *s, int which)
+         }
+     } else if (label == client_application_traffic)
+         memcpy(s->client_app_traffic_secret, secret, hashlen);
++#ifndef OPENSSL_NO_QUIC
++    else if (label == client_handshake_traffic)
++        memcpy(s->client_hand_traffic_secret, secret, hashlen);
++    else if (label == server_handshake_traffic)
++        memcpy(s->server_hand_traffic_secret, secret, hashlen);
++#endif
+ 
+     if (!ssl_log_secret(s, log_label, secret, hashlen)) {
+         /* SSLfatal() already called */
+-- 
+2.42.0
+
diff --git a/0006-QUIC-Handle-partial-handshake-messages.patch b/0006-QUIC-Handle-partial-handshake-messages.patch
new file mode 100644
index 0000000..3937e10
--- /dev/null
+++ b/0006-QUIC-Handle-partial-handshake-messages.patch
@@ -0,0 +1,74 @@
+From 25e71126baa0a061f11bf5365a888c18c92d5b1a Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Thu, 15 Aug 2019 13:26:32 -0400
+Subject: [PATCH 06/63] QUIC: Handle partial handshake messages
+
+---
+ ssl/ssl_local.h |  1 +
+ ssl/ssl_quic.c  | 28 ++++++++++++++++++++++------
+ 2 files changed, 23 insertions(+), 6 deletions(-)
+
+diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h
+index 17f8aed1e3..b3d0046f09 100644
+--- a/ssl/ssl_local.h
++++ b/ssl/ssl_local.h
+@@ -1225,6 +1225,7 @@ typedef struct cert_pkey_st CERT_PKEY;
+ struct quic_data_st {
+     struct quic_data_st *next;
+     OSSL_ENCRYPTION_LEVEL level;
++    size_t offset;
+     size_t length;
+ };
+ typedef struct quic_data_st QUIC_DATA;
+diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c
+index 7ece8af9bb..0959bcf2cf 100644
+--- a/ssl/ssl_quic.c
++++ b/ssl/ssl_quic.c
+@@ -114,15 +114,26 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
+         QUIC_DATA *qd;
+         const uint8_t *p = data + 1;
+ 
++        /* Check for an incomplete block */
++        qd = ssl->quic_input_data_tail;
++        if (qd != NULL) {
++            l = qd->length - qd->offset;
++            if (l != 0) {
++                /* we still need to copy `l` bytes into the last data block */
++                if (l > len)
++                    l = len;
++                memcpy((char*)(qd+1) + qd->offset, data, l);
++                qd->offset += l;
++                len -= l;
++                data += l;
++                continue;
++            }
++        }
++
+         n2l3(p, l);
+         l += SSL3_HM_HEADER_LENGTH;
+ 
+-        if (l > len) {
+-            SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_BAD_DATA_LENGTH);
+-            return 0;
+-        }
+-
+-        qd = OPENSSL_malloc(sizeof(QUIC_DATA) + l);
++        qd = OPENSSL_zalloc(sizeof(QUIC_DATA) + l);
+         if (qd == NULL) {
+             SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR);
+             return 0;
+@@ -131,6 +142,11 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
+         qd->next = NULL;
+         qd->length = l;
+         qd->level = level;
++        /* partial data received? */
++        if (l > len)
++            l = len;
++        qd->offset = l;
++
+         memcpy((void*)(qd + 1), data, l);
+         if (ssl->quic_input_data_tail != NULL)
+             ssl->quic_input_data_tail->next = qd;
+-- 
+2.42.0
+
diff --git a/0007-QUIC-Fix-duplicate-word-in-docs.patch b/0007-QUIC-Fix-duplicate-word-in-docs.patch
new file mode 100644
index 0000000..409377e
--- /dev/null
+++ b/0007-QUIC-Fix-duplicate-word-in-docs.patch
@@ -0,0 +1,25 @@
+From b3b6db9ea45d45ccf064c06fe20f876844f6ef83 Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Mon, 26 Aug 2019 13:14:19 -0400
+Subject: [PATCH 07/63] QUIC: Fix duplicate word in docs
+
+---
+ doc/man3/SSL_CTX_set_quic_method.pod | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/doc/man3/SSL_CTX_set_quic_method.pod b/doc/man3/SSL_CTX_set_quic_method.pod
+index d938eb4e30..60bf704944 100644
+--- a/doc/man3/SSL_CTX_set_quic_method.pod
++++ b/doc/man3/SSL_CTX_set_quic_method.pod
+@@ -59,7 +59,7 @@ containing the TransportParameters will be put in B<*out_params>, and its
+ length in B<*out_params_len>. This buffer will be valid for the lifetime of the
+ B<ssl>. If no params were received from the peer, B<*out_params_len> will be 0.
+ 
+-SSL_quic_max_handshake_flight_len() returns returns the maximum number of bytes
++SSL_quic_max_handshake_flight_len() 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.
+ 
+-- 
+2.42.0
+
diff --git a/0008-QUIC-Fix-quic_transport-constructors-parsers.patch b/0008-QUIC-Fix-quic_transport-constructors-parsers.patch
new file mode 100644
index 0000000..2f4c381
--- /dev/null
+++ b/0008-QUIC-Fix-quic_transport-constructors-parsers.patch
@@ -0,0 +1,89 @@
+From 70010beb14597a438e1a633df18990aa176687a7 Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Mon, 26 Aug 2019 13:29:17 -0400
+Subject: [PATCH 08/63] QUIC: Fix quic_transport constructors/parsers
+
+---
+ ssl/statem/extensions_clnt.c | 16 +++-------------
+ ssl/statem/extensions_srvr.c | 16 +++-------------
+ 2 files changed, 6 insertions(+), 26 deletions(-)
+
+diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c
+index 52742dc36a..3ae28e68dc 100644
+--- a/ssl/statem/extensions_clnt.c
++++ b/ssl/statem/extensions_clnt.c
+@@ -1208,10 +1208,8 @@ EXT_RETURN tls_construct_ctos_quic_transport_params(SSL *s, WPACKET *pkt,
+     }
+ 
+     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_quic_transport_parameters)
+-            || !WPACKET_start_sub_packet_u16(pkt)
+-            || !WPACKET_sub_memcpy_u16(pkt, s->ext.quic_transport_params,
+-                                       s->ext.quic_transport_params_len)
+-            || !WPACKET_close(pkt)) {
++        || !WPACKET_sub_memcpy_u16(pkt, s->ext.quic_transport_params,
++                                   s->ext.quic_transport_params_len)) {
+         SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+         return EXT_RETURN_FAIL;
+     }
+@@ -2008,19 +2006,11 @@ int tls_parse_stoc_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+ int tls_parse_stoc_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context,
+                                          X509 *x, size_t chainidx)
+ {
+-    PACKET trans_param;
+-
+-    if (!PACKET_as_length_prefixed_2(pkt, &trans_param)
+-            || PACKET_remaining(&trans_param) == 0) {
+-        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
+-        return 0;
+-    }
+-
+     OPENSSL_free(s->ext.peer_quic_transport_params);
+     s->ext.peer_quic_transport_params = NULL;
+     s->ext.peer_quic_transport_params_len = 0;
+ 
+-    if (!PACKET_memdup(&trans_param,
++    if (!PACKET_memdup(pkt,
+                        &s->ext.peer_quic_transport_params,
+                        &s->ext.peer_quic_transport_params_len)) {
+         SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c
+index 929e272cd9..2fad8f3788 100644
+--- a/ssl/statem/extensions_srvr.c
++++ b/ssl/statem/extensions_srvr.c
+@@ -1237,19 +1237,11 @@ int tls_parse_ctos_post_handshake_auth(SSL *s, PACKET *pkt,
+ int tls_parse_ctos_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context,
+                                          X509 *x, size_t chainidx)
+ {
+-    PACKET trans_param;
+-
+-    if (!PACKET_as_length_prefixed_2(pkt, &trans_param)
+-            || PACKET_remaining(&trans_param) == 0) {
+-        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
+-        return 0;
+-    }
+-
+     OPENSSL_free(s->ext.peer_quic_transport_params);
+     s->ext.peer_quic_transport_params = NULL;
+     s->ext.peer_quic_transport_params_len = 0;
+ 
+-    if (!PACKET_memdup(&trans_param,
++    if (!PACKET_memdup(pkt,
+                        &s->ext.peer_quic_transport_params,
+                        &s->ext.peer_quic_transport_params_len)) {
+         SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+@@ -1954,10 +1946,8 @@ EXT_RETURN tls_construct_stoc_quic_transport_params(SSL *s, WPACKET *pkt,
+     }
+ 
+     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_quic_transport_parameters)
+-            || !WPACKET_start_sub_packet_u16(pkt)
+-            || !WPACKET_sub_memcpy_u16(pkt, s->ext.quic_transport_params,
+-                                       s->ext.quic_transport_params_len)
+-            || !WPACKET_close(pkt)) {
++        || !WPACKET_sub_memcpy_u16(pkt, s->ext.quic_transport_params,
++                                   s->ext.quic_transport_params_len)) {
+         SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+         return EXT_RETURN_FAIL;
+     }
+-- 
+2.42.0
+
diff --git a/0009-QUIC-Reset-init-state-in-SSL_process_quic_post_hands.patch b/0009-QUIC-Reset-init-state-in-SSL_process_quic_post_hands.patch
new file mode 100644
index 0000000..523626d
--- /dev/null
+++ b/0009-QUIC-Reset-init-state-in-SSL_process_quic_post_hands.patch
@@ -0,0 +1,39 @@
+From 3e46358deb409f4d288fb28c03a287c9fec67f7d Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Thu, 29 Aug 2019 11:53:41 -0400
+Subject: [PATCH 09/63] QUIC: Reset init state in
+ SSL_process_quic_post_handshake()
+
+---
+ ssl/ssl_quic.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c
+index 0959bcf2cf..ad6696d964 100644
+--- a/ssl/ssl_quic.c
++++ b/ssl/ssl_quic.c
+@@ -265,16 +265,19 @@ int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level)
+ 
+ int SSL_process_quic_post_handshake(SSL *ssl)
+ {
++    int ret;
++
+     if (SSL_in_init(ssl) || !SSL_IS_QUIC(ssl)) {
+         SSLerr(SSL_F_SSL_PROCESS_QUIC_POST_HANDSHAKE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+         return 0;
+     }
+ 
+     ossl_statem_set_in_init(ssl, 1);
++    ret = ssl->handshake_func(ssl);
++    ossl_statem_set_in_init(ssl, 0);
+ 
+-    if (ssl->handshake_func(ssl) <= 0)
++    if (ret <= 0)
+         return 0;
+-
+     return 1;
+ }
+ 
+-- 
+2.42.0
+
diff --git a/0010-QUIC-Don-t-process-an-incomplete-message.patch b/0010-QUIC-Don-t-process-an-incomplete-message.patch
new file mode 100644
index 0000000..716b875
--- /dev/null
+++ b/0010-QUIC-Don-t-process-an-incomplete-message.patch
@@ -0,0 +1,51 @@
+From b665dee2afa9aced43334310bb88ec80d35b4960 Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Thu, 29 Aug 2019 12:03:48 -0400
+Subject: [PATCH 10/63] QUIC: Don't process an incomplete message
+
+---
+ ssl/statem/statem_quic.c | 9 ++++-----
+ 1 file changed, 4 insertions(+), 5 deletions(-)
+
+diff --git a/ssl/statem/statem_quic.c b/ssl/statem/statem_quic.c
+index 66acc30d6d..982a9a6292 100644
+--- a/ssl/statem/statem_quic.c
++++ b/ssl/statem/statem_quic.c
+@@ -18,30 +18,29 @@ NON_EMPTY_TRANSLATION_UNIT
+ int quic_get_message(SSL *s, int *mt, size_t *len)
+ {
+     size_t l;
+-    QUIC_DATA *qd;
++    QUIC_DATA *qd = s->quic_input_data_head;
+     uint8_t *p;
+ 
+-    if (s->quic_input_data_head == NULL) {
++    if (qd == NULL || (qd->length - qd->offset) != 0) {
+         s->rwstate = SSL_READING;
+         *len = 0;
+         return 0;
+     }
+ 
+     /* This is where we check for the proper level, not when data is given */
+-    if (s->quic_input_data_head->level != s->quic_read_level) {
++    if (qd->level != s->quic_read_level) {
+         SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED);
+         *len = 0;
+         return 0;
+     }
+ 
+-    if (!BUF_MEM_grow_clean(s->init_buf, (int)s->quic_input_data_head->length)) {
++    if (!BUF_MEM_grow_clean(s->init_buf, (int)qd->length)) {
+         SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_BUF_LIB);
+         *len = 0;
+         return 0;
+     }
+ 
+     /* Copy buffered data */
+-    qd = s->quic_input_data_head;
+     memcpy(s->init_buf->data, (void*)(qd + 1), qd->length);
+     s->init_buf->length = qd->length;
+     s->quic_input_data_head = qd->next;
+-- 
+2.42.0
+
diff --git a/0011-QUIC-Quick-fix-s2c-to-c2s-for-early-secret.patch b/0011-QUIC-Quick-fix-s2c-to-c2s-for-early-secret.patch
new file mode 100644
index 0000000..73b2c80
--- /dev/null
+++ b/0011-QUIC-Quick-fix-s2c-to-c2s-for-early-secret.patch
@@ -0,0 +1,25 @@
+From 81f5c892cc882c7fb26b246d13f92cca1d737131 Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Thu, 29 Aug 2019 20:21:58 -0400
+Subject: [PATCH 11/63] QUIC: Quick fix: s2c to c2s for early secret
+
+---
+ ssl/ssl_quic.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c
+index ad6696d964..14827da88c 100644
+--- a/ssl/ssl_quic.c
++++ b/ssl/ssl_quic.c
+@@ -207,7 +207,7 @@ int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level)
+     /* secrets from the POV of the client */
+     switch (level) {
+     case ssl_encryption_early_data:
+-        s2c_secret = ssl->early_secret;
++        c2s_secret = ssl->early_secret;
+         break;
+     case ssl_encryption_handshake:
+         c2s_secret = ssl->client_hand_traffic_secret;
+-- 
+2.42.0
+
diff --git a/0012-QUIC-Add-client-early-traffic-secret-storage.patch b/0012-QUIC-Add-client-early-traffic-secret-storage.patch
new file mode 100644
index 0000000..c308790
--- /dev/null
+++ b/0012-QUIC-Add-client-early-traffic-secret-storage.patch
@@ -0,0 +1,52 @@
+From fedcc8ecf230a025ba4f314101a8a2ac83ca257c Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Fri, 30 Aug 2019 09:09:42 -0400
+Subject: [PATCH 12/63] QUIC: Add client early traffic secret storage
+
+---
+ ssl/ssl_local.h | 1 +
+ ssl/ssl_quic.c  | 2 +-
+ ssl/tls13_enc.c | 2 ++
+ 3 files changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h
+index b3d0046f09..b3fd00dbfd 100644
+--- a/ssl/ssl_local.h
++++ b/ssl/ssl_local.h
+@@ -1493,6 +1493,7 @@ struct ssl_st {
+     unsigned char server_app_traffic_secret[EVP_MAX_MD_SIZE];
+     unsigned char client_hand_traffic_secret[EVP_MAX_MD_SIZE];
+     unsigned char server_hand_traffic_secret[EVP_MAX_MD_SIZE];
++    unsigned char client_early_traffic_secret[EVP_MAX_MD_SIZE];
+     unsigned char exporter_master_secret[EVP_MAX_MD_SIZE];
+     unsigned char early_exporter_master_secret[EVP_MAX_MD_SIZE];
+     EVP_CIPHER_CTX *enc_read_ctx; /* cryptographic state */
+diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c
+index 14827da88c..0017d1eba9 100644
+--- a/ssl/ssl_quic.c
++++ b/ssl/ssl_quic.c
+@@ -207,7 +207,7 @@ int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level)
+     /* secrets from the POV of the client */
+     switch (level) {
+     case ssl_encryption_early_data:
+-        c2s_secret = ssl->early_secret;
++        c2s_secret = ssl->client_early_traffic_secret;
+         break;
+     case ssl_encryption_handshake:
+         c2s_secret = ssl->client_hand_traffic_secret;
+diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c
+index 68b6573fd1..4d89eb314e 100644
+--- a/ssl/tls13_enc.c
++++ b/ssl/tls13_enc.c
+@@ -710,6 +710,8 @@ int tls13_change_cipher_state(SSL *s, int which)
+         memcpy(s->client_hand_traffic_secret, secret, hashlen);
+     else if (label == server_handshake_traffic)
+         memcpy(s->server_hand_traffic_secret, secret, hashlen);
++    else if (label == client_early_traffic)
++        memcpy(s->client_early_traffic_secret, secret, hashlen);
+ #endif
+ 
+     if (!ssl_log_secret(s, log_label, secret, hashlen)) {
+-- 
+2.42.0
+
diff --git a/0013-QUIC-Add-OPENSSL_NO_QUIC-wrapper.patch b/0013-QUIC-Add-OPENSSL_NO_QUIC-wrapper.patch
new file mode 100644
index 0000000..3a54397
--- /dev/null
+++ b/0013-QUIC-Add-OPENSSL_NO_QUIC-wrapper.patch
@@ -0,0 +1,28 @@
+From d86593e2dc6babf33f7e85bc66371cb4daf69229 Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Fri, 30 Aug 2019 09:15:31 -0400
+Subject: [PATCH 13/63] QUIC: Add OPENSSL_NO_QUIC wrapper
+
+---
+ ssl/ssl_local.h | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h
+index b3fd00dbfd..049d6448c9 100644
+--- a/ssl/ssl_local.h
++++ b/ssl/ssl_local.h
+@@ -1491,9 +1491,11 @@ struct ssl_st {
+     unsigned char handshake_traffic_hash[EVP_MAX_MD_SIZE];
+     unsigned char client_app_traffic_secret[EVP_MAX_MD_SIZE];
+     unsigned char server_app_traffic_secret[EVP_MAX_MD_SIZE];
++# ifndef OPENSSL_NO_QUIC
+     unsigned char client_hand_traffic_secret[EVP_MAX_MD_SIZE];
+     unsigned char server_hand_traffic_secret[EVP_MAX_MD_SIZE];
+     unsigned char client_early_traffic_secret[EVP_MAX_MD_SIZE];
++# endif
+     unsigned char exporter_master_secret[EVP_MAX_MD_SIZE];
+     unsigned char early_exporter_master_secret[EVP_MAX_MD_SIZE];
+     EVP_CIPHER_CTX *enc_read_ctx; /* cryptographic state */
+-- 
+2.42.0
+
diff --git a/0014-QUIC-Correctly-disable-middlebox-compat.patch b/0014-QUIC-Correctly-disable-middlebox-compat.patch
new file mode 100644
index 0000000..f1126e4
--- /dev/null
+++ b/0014-QUIC-Correctly-disable-middlebox-compat.patch
@@ -0,0 +1,34 @@
+From 748c9fecbea033aa244c9f6b70053468f1f78db9 Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Fri, 30 Aug 2019 09:47:48 -0400
+Subject: [PATCH 14/63] QUIC: Correctly disable middlebox compat
+
+---
+ ssl/ssl_quic.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c
+index 0017d1eba9..a76c24eac6 100644
+--- a/ssl/ssl_quic.c
++++ b/ssl/ssl_quic.c
+@@ -173,7 +173,7 @@ int SSL_CTX_set_quic_method(SSL_CTX *ctx, const SSL_QUIC_METHOD *quic_method)
+         break;
+     }
+     ctx->quic_method = quic_method;
+-    ctx->options &= SSL_OP_ENABLE_MIDDLEBOX_COMPAT;
++    ctx->options &= ~SSL_OP_ENABLE_MIDDLEBOX_COMPAT;
+     return 1;
+ }
+ 
+@@ -189,7 +189,7 @@ int SSL_set_quic_method(SSL *ssl, const SSL_QUIC_METHOD *quic_method)
+         break;
+     }
+     ssl->quic_method = quic_method;
+-    ssl->options &= SSL_OP_ENABLE_MIDDLEBOX_COMPAT;
++    ssl->options &= ~SSL_OP_ENABLE_MIDDLEBOX_COMPAT;
+     return 1;
+ }
+ 
+-- 
+2.42.0
+
diff --git a/0015-QUIC-Move-QUIC-code-out-of-tls13_change_cipher_state.patch b/0015-QUIC-Move-QUIC-code-out-of-tls13_change_cipher_state.patch
new file mode 100644
index 0000000..bc8b8a5
--- /dev/null
+++ b/0015-QUIC-Move-QUIC-code-out-of-tls13_change_cipher_state.patch
@@ -0,0 +1,332 @@
+From c0e8778136a689d8d11aec0f061ca6a1d37550b6 Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Fri, 30 Aug 2019 11:17:58 -0400
+Subject: [PATCH 15/63] QUIC: Move QUIC code out of tls13_change_cipher_state()
+
+Create quic_change_cipher_state() that does the minimal required
+to generate the QUIC secrets. (e.g. encryption contexts are not
+initialized).
+---
+ ssl/ssl_quic.c  |   7 --
+ ssl/tls13_enc.c | 216 +++++++++++++++++++++++++++++++-----------------
+ 2 files changed, 139 insertions(+), 84 deletions(-)
+
+diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c
+index a76c24eac6..670deea5ab 100644
+--- a/ssl/ssl_quic.c
++++ b/ssl/ssl_quic.c
+@@ -199,7 +199,6 @@ int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level)
+     uint8_t *s2c_secret = NULL;
+     size_t len;
+     const EVP_MD *md;
+-    static const unsigned char zeros[EVP_MAX_MD_SIZE];
+ 
+     if (!SSL_IS_QUIC(ssl))
+         return 1;
+@@ -240,12 +239,6 @@ int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level)
+         return 0;
+     }
+ 
+-    /* In some cases, we want to set the secret only when BOTH are non-zero */
+-    if (c2s_secret != NULL && s2c_secret != NULL
+-            && !memcmp(c2s_secret, zeros, len)
+-            && !memcmp(s2c_secret, zeros, len))
+-        return 1;
+-
+     if (ssl->server) {
+         if (!ssl->quic_method->set_encryption_secrets(ssl, level, c2s_secret,
+                                                       s2c_secret, len)) {
+diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c
+index 4d89eb314e..1f7b27d4f4 100644
+--- a/ssl/tls13_enc.c
++++ b/ssl/tls13_enc.c
+@@ -385,24 +385,144 @@ static int derive_secret_key_and_iv(SSL *s, int sending, const EVP_MD *md,
+     return 1;
+ }
+ 
++#ifdef CHARSET_EBCDIC
++static const unsigned char client_early_traffic[]       = {0x63, 0x20, 0x65, 0x20,       /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00};
++static const unsigned char client_handshake_traffic[]   = {0x63, 0x20, 0x68, 0x73, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00};
++static const unsigned char client_application_traffic[] = {0x63, 0x20, 0x61, 0x70, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00};
++static const unsigned char server_handshake_traffic[]   = {0x73, 0x20, 0x68, 0x73, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00};
++static const unsigned char server_application_traffic[] = {0x73, 0x20, 0x61, 0x70, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00};
++static const unsigned char exporter_master_secret[] = {0x65, 0x78, 0x70, 0x20,                    /* master*/  0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x00};
++static const unsigned char resumption_master_secret[] = {0x72, 0x65, 0x73, 0x20,                  /* master*/  0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x00};
++static const unsigned char early_exporter_master_secret[] = {0x65, 0x20, 0x65, 0x78, 0x70, 0x20,  /* master*/  0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x00};
++#else
++static const unsigned char client_early_traffic[] = "c e traffic";
++static const unsigned char client_handshake_traffic[] = "c hs traffic";
++static const unsigned char client_application_traffic[] = "c ap traffic";
++static const unsigned char server_handshake_traffic[] = "s hs traffic";
++static const unsigned char server_application_traffic[] = "s ap traffic";
++static const unsigned char exporter_master_secret[] = "exp master";
++static const unsigned char resumption_master_secret[] = "res master";
++static const unsigned char early_exporter_master_secret[] = "e exp master";
++#endif
++#ifndef OPENSSL_NO_QUIC
++static int quic_change_cipher_state(SSL *s, int which)
++{
++    unsigned char hash[EVP_MAX_MD_SIZE];
++    size_t hashlen = 0;
++    int hashleni;
++    int ret = 0;
++    const EVP_MD *md = NULL;
++    OSSL_ENCRYPTION_LEVEL level = ssl_encryption_initial;
++    int is_handshake = ((which & SSL3_CC_HANDSHAKE) == SSL3_CC_HANDSHAKE);
++    int is_client_read = ((which & SSL3_CHANGE_CIPHER_CLIENT_READ) == SSL3_CHANGE_CIPHER_CLIENT_READ);
++    int is_server_write = ((which & SSL3_CHANGE_CIPHER_SERVER_WRITE) == SSL3_CHANGE_CIPHER_SERVER_WRITE);
++    int is_early = (which & SSL3_CC_EARLY);
++
++    md = ssl_handshake_md(s);
++    if (!ssl3_digest_cached_records(s, 1)
++        || !ssl_handshake_hash(s, hash, sizeof(hash), &hashlen)) {
++        /* SSLfatal() already called */;
++        goto err;
++    }
++
++    /* Ensure cast to size_t is safe */
++    hashleni = EVP_MD_size(md);
++    if (!ossl_assert(hashleni >= 0)) {
++        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB);
++        goto err;
++    }
++    hashlen = (size_t)hashleni;
++
++    if (is_handshake)
++        level = ssl_encryption_handshake;
++    else
++        level = ssl_encryption_application;
++
++    if (is_client_read || is_server_write) {
++        if (is_handshake) {
++            level = ssl_encryption_handshake;
++
++            if (!tls13_hkdf_expand(s, md, s->handshake_secret, client_handshake_traffic,
++                                   sizeof(client_handshake_traffic)-1, hash, hashlen,
++                                   s->client_hand_traffic_secret, hashlen, 1)) {
++                /* SSLfatal() already called */
++                goto err;
++            }
++            if (!ssl_log_secret(s, CLIENT_HANDSHAKE_LABEL, s->client_hand_traffic_secret, hashlen)) {
++                /* SSLfatal() already called */
++                goto err;
++            }
++
++            if (!tls13_hkdf_expand(s, md, s->handshake_secret, server_handshake_traffic,
++                                   sizeof(server_handshake_traffic)-1, hash, hashlen,
++                                   s->server_hand_traffic_secret, hashlen, 1)) {
++                /* SSLfatal() already called */
++                goto err;
++            }
++            if (!ssl_log_secret(s, SERVER_HANDSHAKE_LABEL, s->server_hand_traffic_secret, hashlen)) {
++                /* SSLfatal() already called */
++                goto err;
++            }
++        } else {
++            level = ssl_encryption_application;
++
++            if (!tls13_hkdf_expand(s, md, s->master_secret, client_application_traffic,
++                                   sizeof(client_application_traffic)-1, hash, hashlen,
++                                   s->client_app_traffic_secret, hashlen, 1)) {
++                /* SSLfatal() already called */
++                goto err;
++            }
++            if (!ssl_log_secret(s, CLIENT_APPLICATION_LABEL, s->client_app_traffic_secret, hashlen)) {
++                /* SSLfatal() already called */
++                goto err;
++            }
++
++            if (!tls13_hkdf_expand(s, md, s->master_secret, server_application_traffic,
++                                   sizeof(server_application_traffic)-1, hash, hashlen,
++                                   s->server_app_traffic_secret, hashlen, 1)) {
++                /* SSLfatal() already called */
++                goto err;
++            }
++            if (!ssl_log_secret(s, SERVER_APPLICATION_LABEL, s->server_app_traffic_secret, hashlen)) {
++                /* SSLfatal() already called */
++                goto err;
++            }
++        }
++        if (s->server)
++            s->quic_write_level = level;
++        else
++            s->quic_read_level = level;
++    } else {
++        if (is_early) {
++            level = ssl_encryption_early_data;
++
++            if (!tls13_hkdf_expand(s, md, s->early_secret, client_early_traffic,
++                                   sizeof(client_early_traffic)-1, hash, hashlen,
++                                   s->client_early_traffic_secret, hashlen, 1)) {
++                /* SSLfatal() already called */
++                goto err;
++            }
++            if (!ssl_log_secret(s, CLIENT_EARLY_LABEL, s->client_early_traffic_secret, hashlen)) {
++                /* SSLfatal() already called */
++                goto err;
++            }
++        }
++        if (s->server)
++            s->quic_read_level = level;
++        else
++            s->quic_write_level = level;
++    }
++
++    if (level != ssl_encryption_initial && !quic_set_encryption_secrets(s, level))
++        goto err;
++
++    ret = 1;
++ err:
++    return ret;
++}
++#endif /* OPENSSL_NO_QUIC */
+ int tls13_change_cipher_state(SSL *s, int which)
+ {
+-    /* ASCII: "c e traffic", in hex for EBCDIC compatibility */
+-    static const unsigned char client_early_traffic[] = "\x63\x20\x65\x20\x74\x72\x61\x66\x66\x69\x63";
+-    /* ASCII: "c hs traffic", in hex for EBCDIC compatibility */
+-    static const unsigned char client_handshake_traffic[] = "\x63\x20\x68\x73\x20\x74\x72\x61\x66\x66\x69\x63";
+-    /* ASCII: "c ap traffic", in hex for EBCDIC compatibility */
+-    static const unsigned char client_application_traffic[] = "\x63\x20\x61\x70\x20\x74\x72\x61\x66\x66\x69\x63";
+-    /* ASCII: "s hs traffic", in hex for EBCDIC compatibility */
+-    static const unsigned char server_handshake_traffic[] = "\x73\x20\x68\x73\x20\x74\x72\x61\x66\x66\x69\x63";
+-    /* ASCII: "s ap traffic", in hex for EBCDIC compatibility */
+-    static const unsigned char server_application_traffic[] = "\x73\x20\x61\x70\x20\x74\x72\x61\x66\x66\x69\x63";
+-    /* ASCII: "exp master", in hex for EBCDIC compatibility */
+-    static const unsigned char exporter_master_secret[] = "\x65\x78\x70\x20\x6D\x61\x73\x74\x65\x72";
+-    /* ASCII: "res master", in hex for EBCDIC compatibility */
+-    static const unsigned char resumption_master_secret[] = "\x72\x65\x73\x20\x6D\x61\x73\x74\x65\x72";
+-    /* ASCII: "e exp master", in hex for EBCDIC compatibility */
+-    static const unsigned char early_exporter_master_secret[] = "\x65\x20\x65\x78\x70\x20\x6D\x61\x73\x74\x65\x72";
+     unsigned char *iv;
+     unsigned char key[EVP_MAX_KEY_LENGTH];
+     unsigned char secret[EVP_MAX_MD_SIZE];
+@@ -422,8 +542,10 @@ int tls13_change_cipher_state(SSL *s, int which)
+     ktls_crypto_info_t crypto_info;
+     BIO *bio;
+ #endif
++
+ #ifndef OPENSSL_NO_QUIC
+-    OSSL_ENCRYPTION_LEVEL level = ssl_encryption_initial;
++    if (SSL_IS_QUIC(s))
++        return quic_change_cipher_state(s, which);
+ #endif
+ 
+     if (which & SSL3_CC_READ) {
+@@ -470,9 +592,6 @@ int tls13_change_cipher_state(SSL *s, int which)
+             label = client_early_traffic;
+             labellen = sizeof(client_early_traffic) - 1;
+             log_label = CLIENT_EARLY_LABEL;
+-#ifndef OPENSSL_NO_QUIC
+-            level = ssl_encryption_early_data;
+-#endif
+ 
+             handlen = BIO_get_mem_data(s->s3.handshake_buffer, &hdata);
+             if (handlen <= 0) {
+@@ -549,14 +668,6 @@ int tls13_change_cipher_state(SSL *s, int which)
+                 /* SSLfatal() already called */
+                 goto err;
+             }
+-#ifndef OPENSSL_NO_QUIC
+-            if (SSL_IS_QUIC(s)) {
+-                if (s->server)
+-                    s->quic_read_level = ssl_encryption_early_data;
+-                else
+-                    s->quic_write_level = ssl_encryption_early_data;
+-            }
+-#endif
+         } else if (which & SSL3_CC_HANDSHAKE) {
+             insecret = s->handshake_secret;
+             finsecret = s->client_finished_secret;
+@@ -564,15 +675,6 @@ int tls13_change_cipher_state(SSL *s, int which)
+             label = client_handshake_traffic;
+             labellen = sizeof(client_handshake_traffic) - 1;
+             log_label = CLIENT_HANDSHAKE_LABEL;
+-#ifndef OPENSSL_NO_QUIC
+-            if (SSL_IS_QUIC(s)) {
+-                level = ssl_encryption_handshake;
+-                if (s->server)
+-                    s->quic_read_level = ssl_encryption_handshake;
+-                else
+-                    s->quic_write_level = ssl_encryption_handshake;
+-            }
+-#endif
+             /*
+              * The handshake hash used for the server read/client write handshake
+              * traffic secret is the same as the hash for the server
+@@ -595,15 +697,6 @@ int tls13_change_cipher_state(SSL *s, int which)
+              * previously saved value.
+              */
+             hash = s->server_finished_hash;
+-#ifndef OPENSSL_NO_QUIC
+-            if (SSL_IS_QUIC(s)) {
+-                level = ssl_encryption_application; /* ??? */
+-                if (s->server)
+-                    s->quic_read_level = ssl_encryption_application;
+-                else
+-                    s->quic_write_level = ssl_encryption_application;
+-            }
+-#endif
+         }
+     } else {
+         /* Early data never applies to client-read/server-write */
+@@ -614,29 +707,11 @@ int tls13_change_cipher_state(SSL *s, int which)
+             label = server_handshake_traffic;
+             labellen = sizeof(server_handshake_traffic) - 1;
+             log_label = SERVER_HANDSHAKE_LABEL;
+-#ifndef OPENSSL_NO_QUIC
+-            if (SSL_IS_QUIC(s)) {
+-                level = ssl_encryption_handshake;
+-                if (s->server)
+-                    s->quic_write_level = ssl_encryption_handshake;
+-                else
+-                    s->quic_read_level = ssl_encryption_handshake;
+-            }
+-#endif
+         } else {
+             insecret = s->master_secret;
+             label = server_application_traffic;
+             labellen = sizeof(server_application_traffic) - 1;
+             log_label = SERVER_APPLICATION_LABEL;
+-#ifndef OPENSSL_NO_QUIC
+-            if (SSL_IS_QUIC(s)) {
+-                level = ssl_encryption_application;
+-                if (s->server)
+-                    s->quic_write_level = ssl_encryption_application;
+-                else
+-                    s->quic_read_level = ssl_encryption_application;
+-            }
+-#endif
+         }
+     }
+ 
+@@ -705,14 +780,6 @@ int tls13_change_cipher_state(SSL *s, int which)
+         }
+     } else if (label == client_application_traffic)
+         memcpy(s->client_app_traffic_secret, secret, hashlen);
+-#ifndef OPENSSL_NO_QUIC
+-    else if (label == client_handshake_traffic)
+-        memcpy(s->client_hand_traffic_secret, secret, hashlen);
+-    else if (label == server_handshake_traffic)
+-        memcpy(s->server_hand_traffic_secret, secret, hashlen);
+-    else if (label == client_early_traffic)
+-        memcpy(s->client_early_traffic_secret, secret, hashlen);
+-#endif
+ 
+     if (!ssl_log_secret(s, log_label, secret, hashlen)) {
+         /* SSLfatal() already called */
+@@ -773,11 +840,6 @@ skip_ktls:
+ # endif
+ #endif
+ 
+-#ifndef OPENSSL_NO_QUIC
+-    if (!quic_set_encryption_secrets(s, level))
+-        goto err;
+-#endif
+-
+     ret = 1;
+  err:
+     if ((which & SSL3_CC_EARLY) != 0) {
+-- 
+2.42.0
+
diff --git a/0016-QUIC-Tweeks-to-quic_change_cipher_state.patch b/0016-QUIC-Tweeks-to-quic_change_cipher_state.patch
new file mode 100644
index 0000000..55c85ea
--- /dev/null
+++ b/0016-QUIC-Tweeks-to-quic_change_cipher_state.patch
@@ -0,0 +1,126 @@
+From fd4b090efe5e7034742d2a326de313b2f7cedf28 Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Fri, 30 Aug 2019 11:38:56 -0400
+Subject: [PATCH 16/63] QUIC: Tweeks to quic_change_cipher_state()
+
+---
+ ssl/tls13_enc.c | 69 +++++++++++++++++--------------------------------
+ 1 file changed, 24 insertions(+), 45 deletions(-)
+
+diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c
+index 1f7b27d4f4..5e472044b0 100644
+--- a/ssl/tls13_enc.c
++++ b/ssl/tls13_enc.c
+@@ -433,33 +433,18 @@ static int quic_change_cipher_state(SSL *s, int which)
+     }
+     hashlen = (size_t)hashleni;
+ 
+-    if (is_handshake)
+-        level = ssl_encryption_handshake;
+-    else
+-        level = ssl_encryption_application;
+-
+     if (is_client_read || is_server_write) {
+         if (is_handshake) {
+             level = ssl_encryption_handshake;
+ 
+             if (!tls13_hkdf_expand(s, md, s->handshake_secret, client_handshake_traffic,
+                                    sizeof(client_handshake_traffic)-1, hash, hashlen,
+-                                   s->client_hand_traffic_secret, hashlen, 1)) {
+-                /* SSLfatal() already called */
+-                goto err;
+-            }
+-            if (!ssl_log_secret(s, CLIENT_HANDSHAKE_LABEL, s->client_hand_traffic_secret, hashlen)) {
+-                /* SSLfatal() already called */
+-                goto err;
+-            }
+-
+-            if (!tls13_hkdf_expand(s, md, s->handshake_secret, server_handshake_traffic,
+-                                   sizeof(server_handshake_traffic)-1, hash, hashlen,
+-                                   s->server_hand_traffic_secret, hashlen, 1)) {
+-                /* SSLfatal() already called */
+-                goto err;
+-            }
+-            if (!ssl_log_secret(s, SERVER_HANDSHAKE_LABEL, s->server_hand_traffic_secret, hashlen)) {
++                                   s->client_hand_traffic_secret, hashlen, 1)
++                || !ssl_log_secret(s, CLIENT_HANDSHAKE_LABEL, s->client_hand_traffic_secret, hashlen)
++                || !tls13_hkdf_expand(s, md, s->handshake_secret, server_handshake_traffic,
++                                      sizeof(server_handshake_traffic)-1, hash, hashlen,
++                                      s->server_hand_traffic_secret, hashlen, 1)
++                || !ssl_log_secret(s, SERVER_HANDSHAKE_LABEL, s->server_hand_traffic_secret, hashlen)) {
+                 /* SSLfatal() already called */
+                 goto err;
+             }
+@@ -468,26 +453,20 @@ static int quic_change_cipher_state(SSL *s, int which)
+ 
+             if (!tls13_hkdf_expand(s, md, s->master_secret, client_application_traffic,
+                                    sizeof(client_application_traffic)-1, hash, hashlen,
+-                                   s->client_app_traffic_secret, hashlen, 1)) {
+-                /* SSLfatal() already called */
+-                goto err;
+-            }
+-            if (!ssl_log_secret(s, CLIENT_APPLICATION_LABEL, s->client_app_traffic_secret, hashlen)) {
+-                /* SSLfatal() already called */
+-                goto err;
+-            }
+-
+-            if (!tls13_hkdf_expand(s, md, s->master_secret, server_application_traffic,
+-                                   sizeof(server_application_traffic)-1, hash, hashlen,
+-                                   s->server_app_traffic_secret, hashlen, 1)) {
+-                /* SSLfatal() already called */
+-                goto err;
+-            }
+-            if (!ssl_log_secret(s, SERVER_APPLICATION_LABEL, s->server_app_traffic_secret, hashlen)) {
++                                   s->client_app_traffic_secret, hashlen, 1)
++                || !ssl_log_secret(s, CLIENT_APPLICATION_LABEL, s->client_app_traffic_secret, hashlen)
++                || !tls13_hkdf_expand(s, md, s->master_secret, server_application_traffic,
++                                      sizeof(server_application_traffic)-1, hash, hashlen,
++                                      s->server_app_traffic_secret, hashlen, 1)
++                || !ssl_log_secret(s, SERVER_APPLICATION_LABEL, s->server_app_traffic_secret, hashlen)) {
+                 /* SSLfatal() already called */
+                 goto err;
+             }
+         }
++        if (!quic_set_encryption_secrets(s, level)) {
++            /* SSLfatal() already called */
++            goto err;
++        }
+         if (s->server)
+             s->quic_write_level = level;
+         else
+@@ -498,24 +477,24 @@ static int quic_change_cipher_state(SSL *s, int which)
+ 
+             if (!tls13_hkdf_expand(s, md, s->early_secret, client_early_traffic,
+                                    sizeof(client_early_traffic)-1, hash, hashlen,
+-                                   s->client_early_traffic_secret, hashlen, 1)) {
+-                /* SSLfatal() already called */
+-                goto err;
+-            }
+-            if (!ssl_log_secret(s, CLIENT_EARLY_LABEL, s->client_early_traffic_secret, hashlen)) {
++                                   s->client_early_traffic_secret, hashlen, 1)
++                || !ssl_log_secret(s, CLIENT_EARLY_LABEL, s->client_early_traffic_secret, hashlen)
++                || !quic_set_encryption_secrets(s, level)) {
+                 /* SSLfatal() already called */
+                 goto err;
+             }
++        } else if (is_handshake) {
++            level = ssl_encryption_handshake;
++        } else {
++            level = ssl_encryption_application;
+         }
++
+         if (s->server)
+             s->quic_read_level = level;
+         else
+             s->quic_write_level = level;
+     }
+ 
+-    if (level != ssl_encryption_initial && !quic_set_encryption_secrets(s, level))
+-        goto err;
+-
+     ret = 1;
+  err:
+     return ret;
+-- 
+2.42.0
+
diff --git a/0017-QUIC-Add-support-for-more-secrets.patch b/0017-QUIC-Add-support-for-more-secrets.patch
new file mode 100644
index 0000000..850a111
--- /dev/null
+++ b/0017-QUIC-Add-support-for-more-secrets.patch
@@ -0,0 +1,44 @@
+From 6dbbc1e4d8edda90261e160da0e7633eab89e569 Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Tue, 24 Sep 2019 10:26:42 -0400
+Subject: [PATCH 17/63] QUIC: Add support for more secrets
+
+---
+ ssl/tls13_enc.c | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c
+index 5e472044b0..487365627a 100644
+--- a/ssl/tls13_enc.c
++++ b/ssl/tls13_enc.c
+@@ -441,10 +441,14 @@ static int quic_change_cipher_state(SSL *s, int which)
+                                    sizeof(client_handshake_traffic)-1, hash, hashlen,
+                                    s->client_hand_traffic_secret, hashlen, 1)
+                 || !ssl_log_secret(s, CLIENT_HANDSHAKE_LABEL, s->client_hand_traffic_secret, hashlen)
++                || !tls13_derive_finishedkey(s, md, s->client_hand_traffic_secret,
++                                             s->client_finished_secret, hashlen)
+                 || !tls13_hkdf_expand(s, md, s->handshake_secret, server_handshake_traffic,
+                                       sizeof(server_handshake_traffic)-1, hash, hashlen,
+                                       s->server_hand_traffic_secret, hashlen, 1)
+-                || !ssl_log_secret(s, SERVER_HANDSHAKE_LABEL, s->server_hand_traffic_secret, hashlen)) {
++                || !ssl_log_secret(s, SERVER_HANDSHAKE_LABEL, s->server_hand_traffic_secret, hashlen)
++                || !tls13_derive_finishedkey(s, md, s->server_hand_traffic_secret,
++                                             s->server_finished_secret, hashlen)) {
+                 /* SSLfatal() already called */
+                 goto err;
+             }
+@@ -458,7 +462,10 @@ static int quic_change_cipher_state(SSL *s, int which)
+                 || !tls13_hkdf_expand(s, md, s->master_secret, server_application_traffic,
+                                       sizeof(server_application_traffic)-1, hash, hashlen,
+                                       s->server_app_traffic_secret, hashlen, 1)
+-                || !ssl_log_secret(s, SERVER_APPLICATION_LABEL, s->server_app_traffic_secret, hashlen)) {
++                || !ssl_log_secret(s, SERVER_APPLICATION_LABEL, s->server_app_traffic_secret, hashlen)
++                || !tls13_hkdf_expand(s, md, s->master_secret, resumption_master_secret,
++                                      sizeof(resumption_master_secret)-1, hash, hashlen,
++                                      s->resumption_master_secret, hashlen, 1)) {
+                 /* SSLfatal() already called */
+                 goto err;
+             }
+-- 
+2.42.0
+
diff --git a/0018-QUIC-Fix-resumption-secret.patch b/0018-QUIC-Fix-resumption-secret.patch
new file mode 100644
index 0000000..d062d88
--- /dev/null
+++ b/0018-QUIC-Fix-resumption-secret.patch
@@ -0,0 +1,54 @@
+From 5b4537798713524910ecad330e9b7ce659b50a98 Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Tue, 12 Nov 2019 13:52:35 -0500
+Subject: [PATCH 18/63] QUIC: Fix resumption secret
+
+---
+ ssl/tls13_enc.c | 17 +++++++++++++----
+ 1 file changed, 13 insertions(+), 4 deletions(-)
+
+diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c
+index 487365627a..a5b674d04b 100644
+--- a/ssl/tls13_enc.c
++++ b/ssl/tls13_enc.c
+@@ -462,10 +462,7 @@ static int quic_change_cipher_state(SSL *s, int which)
+                 || !tls13_hkdf_expand(s, md, s->master_secret, server_application_traffic,
+                                       sizeof(server_application_traffic)-1, hash, hashlen,
+                                       s->server_app_traffic_secret, hashlen, 1)
+-                || !ssl_log_secret(s, SERVER_APPLICATION_LABEL, s->server_app_traffic_secret, hashlen)
+-                || !tls13_hkdf_expand(s, md, s->master_secret, resumption_master_secret,
+-                                      sizeof(resumption_master_secret)-1, hash, hashlen,
+-                                      s->resumption_master_secret, hashlen, 1)) {
++                || !ssl_log_secret(s, SERVER_APPLICATION_LABEL, s->server_app_traffic_secret, hashlen)) {
+                 /* SSLfatal() already called */
+                 goto err;
+             }
+@@ -479,6 +476,8 @@ static int quic_change_cipher_state(SSL *s, int which)
+         else
+             s->quic_read_level = level;
+     } else {
++        /* is_client_write || is_server_read */
++
+         if (is_early) {
+             level = ssl_encryption_early_data;
+ 
+@@ -494,6 +493,16 @@ static int quic_change_cipher_state(SSL *s, int which)
+             level = ssl_encryption_handshake;
+         } else {
+             level = ssl_encryption_application;
++            /*
++             * We also create the resumption master secret, but this time use the
++             * hash for the whole handshake including the Client Finished
++             */
++            if (!tls13_hkdf_expand(s, md, s->master_secret, resumption_master_secret,
++                                   sizeof(resumption_master_secret)-1, hash, hashlen,
++                                   s->resumption_master_secret, hashlen, 1)) {
++                /* SSLfatal() already called */
++                goto err;
++            }
+         }
+ 
+         if (s->server)
+-- 
+2.42.0
+
diff --git a/0019-QUIC-Handle-EndOfEarlyData-and-MaxEarlyData.patch b/0019-QUIC-Handle-EndOfEarlyData-and-MaxEarlyData.patch
new file mode 100644
index 0000000..9e871ed
--- /dev/null
+++ b/0019-QUIC-Handle-EndOfEarlyData-and-MaxEarlyData.patch
@@ -0,0 +1,98 @@
+From c60ebaf44ca48a2bfa9cd3bbd2edff3d2bde308e Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Wed, 13 Nov 2019 12:11:00 -0500
+Subject: [PATCH 19/63] QUIC: Handle EndOfEarlyData and MaxEarlyData
+
+---
+ ssl/statem/extensions_clnt.c | 11 +++++++++++
+ ssl/statem/extensions_srvr.c | 12 ++++++++++--
+ ssl/statem/statem_clnt.c     |  8 ++++++++
+ ssl/statem/statem_srvr.c     |  4 ++++
+ 4 files changed, 33 insertions(+), 2 deletions(-)
+
+diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c
+index 3ae28e68dc..3e76361199 100644
+--- a/ssl/statem/extensions_clnt.c
++++ b/ssl/statem/extensions_clnt.c
+@@ -1919,6 +1919,17 @@ int tls_parse_stoc_early_data(SSL *s, PACKET *pkt, unsigned int context,
+             return 0;
+         }
+ 
++#ifndef OPENSSL_NO_QUIC
++        /*
++         * QUIC server must send 0xFFFFFFFF or it's a PROTOCOL_VIOLATION
++         * per draft-ietf-quic-tls-24 S4.5
++         */
++        if (s->quic_method != NULL && max_early_data != 0xFFFFFFFF) {
++            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_INVALID_MAX_EARLY_DATA);
++            return 0;
++        }
++#endif
++
+         s->session->ext.max_early_data = max_early_data;
+ 
+         return 1;
+diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c
+index 2fad8f3788..344dca1292 100644
+--- a/ssl/statem/extensions_srvr.c
++++ b/ssl/statem/extensions_srvr.c
+@@ -1890,12 +1890,20 @@ EXT_RETURN tls_construct_stoc_early_data(SSL *s, WPACKET *pkt,
+                                          size_t chainidx)
+ {
+     if (context == SSL_EXT_TLS1_3_NEW_SESSION_TICKET) {
+-        if (s->max_early_data == 0)
++        uint32_t max_early_data = s->max_early_data;
++
++        if (max_early_data == 0)
+             return EXT_RETURN_NOT_SENT;
+ 
++#ifndef OPENSSL_NO_QUIC
++        /* QUIC server must always send 0xFFFFFFFF, per draft-ietf-quic-tls-24 S4.5 */
++        if (s->quic_method != NULL)
++            max_early_data = 0xFFFFFFFF;
++#endif
++
+         if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_early_data)
+                 || !WPACKET_start_sub_packet_u16(pkt)
+-                || !WPACKET_put_bytes_u32(pkt, s->max_early_data)
++                || !WPACKET_put_bytes_u32(pkt, max_early_data)
+                 || !WPACKET_close(pkt)) {
+             SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+             return EXT_RETURN_FAIL;
+diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
+index 3cd1ee2d3d..36cbba2a50 100644
+--- a/ssl/statem/statem_clnt.c
++++ b/ssl/statem/statem_clnt.c
+@@ -904,6 +904,14 @@ int ossl_statem_client_construct_message(SSL *s, WPACKET *pkt,
+         break;
+ 
+     case TLS_ST_CW_END_OF_EARLY_DATA:
++#ifndef OPENSSL_NO_QUIC
++        /* QUIC does not send EndOfEarlyData, draft-ietf-quic-tls-24 S8.3 */
++        if (s->quic_method != NULL) {
++            *confunc = NULL;
++            *mt = SSL3_MT_DUMMY;
++            break;
++        }
++#endif
+         *confunc = tls_construct_end_of_early_data;
+         *mt = SSL3_MT_END_OF_EARLY_DATA;
+         break;
+diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
+index 5d59d53563..1c4b7124e4 100644
+--- a/ssl/statem/statem_srvr.c
++++ b/ssl/statem/statem_srvr.c
+@@ -76,6 +76,10 @@ static int ossl_statem_server13_read_transition(SSL *s, int mt)
+             break;
+         } else if (s->ext.early_data == SSL_EARLY_DATA_ACCEPTED) {
+             if (mt == SSL3_MT_END_OF_EARLY_DATA) {
++#ifndef OPENSSL_NO_QUIC
++                if (s->quic_method != NULL)
++                    return 0;
++#endif
+                 st->hand_state = TLS_ST_SR_END_OF_EARLY_DATA;
+                 return 1;
+             }
+-- 
+2.42.0
+
diff --git a/0020-QUIC-Fall-through-for-0RTT.patch b/0020-QUIC-Fall-through-for-0RTT.patch
new file mode 100644
index 0000000..d1f0d76
--- /dev/null
+++ b/0020-QUIC-Fall-through-for-0RTT.patch
@@ -0,0 +1,31 @@
+From 98f16af8ea10b5bcb8243e438795c4f83e64339f Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Tue, 7 Jan 2020 10:59:08 -0500
+Subject: [PATCH 20/63] QUIC: Fall-through for 0RTT
+
+---
+ ssl/statem/statem_srvr.c | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
+index 1c4b7124e4..aba18e8c76 100644
+--- a/ssl/statem/statem_srvr.c
++++ b/ssl/statem/statem_srvr.c
+@@ -74,12 +74,9 @@ static int ossl_statem_server13_read_transition(SSL *s, int mt)
+                 return 1;
+             }
+             break;
+-        } else if (s->ext.early_data == SSL_EARLY_DATA_ACCEPTED) {
++        } else if (s->ext.early_data == SSL_EARLY_DATA_ACCEPTED
++                   && !SSL_IS_QUIC(s)) {
+             if (mt == SSL3_MT_END_OF_EARLY_DATA) {
+-#ifndef OPENSSL_NO_QUIC
+-                if (s->quic_method != NULL)
+-                    return 0;
+-#endif
+                 st->hand_state = TLS_ST_SR_END_OF_EARLY_DATA;
+                 return 1;
+             }
+-- 
+2.42.0
+
diff --git a/0021-QUIC-Some-cleanup-for-the-main-QUIC-changes.patch b/0021-QUIC-Some-cleanup-for-the-main-QUIC-changes.patch
new file mode 100644
index 0000000..105e93c
--- /dev/null
+++ b/0021-QUIC-Some-cleanup-for-the-main-QUIC-changes.patch
@@ -0,0 +1,677 @@
+From 3cd9c15ff714c4e23e1e7e62263940a53a55536a Mon Sep 17 00:00:00 2001
+From: Benjamin Kaduk <bkaduk@akamai.com>
+Date: Wed, 22 Apr 2020 09:12:36 -0700
+Subject: [PATCH 21/63] QUIC: Some cleanup for the main QUIC changes
+
+Try to reduce unneeded whitespace changes and wrap new code to 80 columns.
+Reword documentation to attempt to improve clarity.
+Add some more sanity checks and clarifying comments to the code.
+Update referenced I-D versions.
+---
+ doc/man3/SSL_CTX_set_quic_method.pod | 43 +++++++-------
+ include/openssl/ssl.h.in             |  4 +-
+ include/openssl/tls1.h               |  2 +-
+ ssl/build.info                       |  7 ++-
+ ssl/ssl_ciph.c                       |  2 +
+ ssl/ssl_lib.c                        |  2 +-
+ ssl/ssl_local.h                      |  1 +
+ ssl/ssl_quic.c                       | 45 +++++++--------
+ ssl/statem/extensions_clnt.c         |  2 +-
+ ssl/statem/extensions_srvr.c         |  2 +-
+ ssl/statem/statem.c                  |  2 +-
+ ssl/statem/statem_lib.c              | 26 +++++----
+ ssl/statem/statem_local.h            |  2 +
+ ssl/statem/statem_quic.c             | 22 ++++----
+ ssl/tls13_enc.c                      | 84 +++++++++++++++++++---------
+ test/sslapitest.c                    | 11 ++--
+ util/libssl.num                      |  2 +-
+ 17 files changed, 155 insertions(+), 104 deletions(-)
+
+diff --git a/doc/man3/SSL_CTX_set_quic_method.pod b/doc/man3/SSL_CTX_set_quic_method.pod
+index 60bf704944..3d7bf7e682 100644
+--- a/doc/man3/SSL_CTX_set_quic_method.pod
++++ b/doc/man3/SSL_CTX_set_quic_method.pod
+@@ -63,22 +63,25 @@ SSL_quic_max_handshake_flight_len() 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 https://tools.ietf.org/html/draft-ietf-quic-transport-16#section-4.4.
++See https://tools.ietf.org/html/draft-ietf-quic-transport-27#section-4.
+ 
+ SSL_quic_read_level() returns the current read encryption level.
+ 
+ SSL_quic_write_level() returns the current write encryption level.
+ 
+-SSL_provide_quic_data() provides data from QUIC at a particular encryption
+-level B<level>. It is an error to call this function outside of the handshake
+-or with an encryption level other than the current read level. It returns one
+-on success and zero on error.
++SSL_provide_quic_data() is used to provide data from QUIC CRYPTO frames to the
++state machine, at a particular encryption level B<level>. It is an error to
++call this function outside of the handshake or with an encryption level other
++than the current read level. The application must buffer and consolidate any
++frames with less than four bytes of content.  It returns one on success and
++zero on error.
+ 
+ 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.
+ 
+-SSL_is_quic() indicates whether a connection uses QUIC.
++SSL_is_quic() indicates whether a connection uses QUIC.  A given B<SSL>
++or B<SSL_CTX> can only be used with QUIC or TLS, but not both.
+ 
+ =head1 NOTES
+ 
+@@ -89,11 +92,11 @@ functions allow a QUIC implementation to serve as the underlying transport as
+ described in draft-ietf-quic-tls.
+ 
+ When configured for QUIC, SSL_do_handshake() will drive the handshake as
+-before, but it will not use the configured B<BIO>. It will call functions on
+-B<SSL_QUIC_METHOD> to configure secrets and send data. If data is needed from
+-the peer, it will return B<SSL_ERROR_WANT_READ>. When received, the caller
+-should call SSL_provide_quic_data() and then SSL_do_handshake() to continue
+-the handshake. After the handshake is complete, the caller should call
++before, but it will not use the configured B<BIO>. It will call functions from
++the configured B<SSL_QUIC_METHOD> to configure secrets and send data. If data
++is needed from the peer, it will return B<SSL_ERROR_WANT_READ>. When received,
++the caller should call SSL_provide_quic_data() and then SSL_do_handshake() to
++continue the handshake. After the handshake is complete, the caller should call
+ SSL_provide_quic_data() for any post-handshake data, followed by
+ SSL_process_quic_post_handshake() to process it. It is an error to call
+ SSL_read()/SSL_read_ex() and SSL_write()/SSL_write_ex() in QUIC.
+@@ -105,7 +108,7 @@ pass the active write level to add_handshake_data() when writing data. Callers
+ can use SSL_quic_write_level() to query the active write level when
+ generating their own errors.
+ 
+-See https://tools.ietf.org/html/draft-ietf-quic-tls-15#section-4.1 for more
++See https://tools.ietf.org/html/draft-ietf-quic-tls-27#section-4.1 for more
+ details.
+ 
+ To avoid DoS attacks, the QUIC implementation must limit the amount of data
+@@ -113,11 +116,12 @@ being queued up. The implementation can call
+ SSL_quic_max_handshake_flight_len() to get the maximum buffer length at each
+ encryption level.
+ 
+-draft-ietf-quic-tls defines a new TLS extension quic_transport_parameters
++draft-ietf-quic-tls defines a new TLS extension "quic_transport_parameters"
+ used by QUIC for each endpoint to unilaterally declare its supported
+-transport parameters. draft-ietf-quic-transport (section 7.4) defines the
+-contents of that extension (a TransportParameters struct) and describes how
+-to handle it and its semantic meaning.
++transport parameters. The contents of the extension are specified in
++https://tools.ietf.org/html/draft-ietf-quic-transport-27#section-18 (as
++a sequence of tag/length/value parameters) along with the interpretation of the
++various parameters and the rules for their processing.
+ 
+ OpenSSL handles this extension as an opaque byte string. The caller is
+ responsible for serializing and parsing it.
+@@ -205,10 +209,11 @@ SSL_process_quic_post_handshake()
+ return 1 on success, and 0 on error.
+ 
+ SSL_quic_read_level() and SSL_quic_write_level() return the current
+-encryption  level as B<OSSL_ENCRYPTION_LEVEL> (B<enum ssl_encryption_level_t>).
++encryption level as an B<OSSL_ENCRYPTION_LEVEL>
++(B<enum ssl_encryption_level_t>).
+ 
+-SSL_quic_max_handshake_flight_len() returns the maximum length of a flight
+-for a given encryption level.
++SSL_quic_max_handshake_flight_len() returns the maximum length in bytes of a
++flight for a given encryption level.
+ 
+ SSL_is_quic() returns 1 if QUIC is being used, 0 if not.
+ 
+diff --git a/include/openssl/ssl.h.in b/include/openssl/ssl.h.in
+index e2e31bce9b..6b5fbfbf02 100644
+--- a/include/openssl/ssl.h.in
++++ b/include/openssl/ssl.h.in
+@@ -2565,10 +2565,10 @@ __owur int SSL_process_quic_post_handshake(SSL *ssl);
+ 
+ __owur int SSL_is_quic(SSL *ssl);
+ 
+-#  endif
+-
+ int SSL_CIPHER_get_prf_nid(const SSL_CIPHER *c);
+ 
++#  endif
++
+ # ifdef  __cplusplus
+ }
+ # endif
+diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h
+index c4f80dc332..062e47c18a 100644
+--- a/include/openssl/tls1.h
++++ b/include/openssl/tls1.h
+@@ -151,7 +151,7 @@ extern "C" {
+ /* Temporary extension type */
+ # define TLSEXT_TYPE_renegotiate                 0xff01
+ 
+-/* ExtensionType value from draft-ietf-quic-tls-13 */
++/* ExtensionType value from draft-ietf-quic-tls-27 */
+ # define TLSEXT_TYPE_quic_transport_parameters   0xffa5
+ 
+ # ifndef OPENSSL_NO_NEXTPROTONEG
+diff --git a/ssl/build.info b/ssl/build.info
+index ac87437906..d99835c9a0 100644
+--- a/ssl/build.info
++++ b/ssl/build.info
+@@ -37,10 +37,11 @@ IF[{- !$disabled{'deprecated-3.0'} -}]
+   SHARED_SOURCE[../libssl]=s3_cbc.c
+   SOURCE[../libssl]=ssl_rsa_legacy.c
+ ENDIF
+-
+-SOURCE[../libssl]=ssl_quic.c statem/statem_quic.c
+-
+ DEFINE[../libssl]=$AESDEF
+ 
++IF[{- !$disabled{quic} -}]
++  SOURCE[../libssl]=ssl_quic.c statem/statem_quic.c
++ENDIF
++
+ SOURCE[../providers/libcommon.a]=record/tls_pad.c
+ SOURCE[../providers/libdefault.a ../providers/libfips.a]=s3_cbc.c
+diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c
+index deb68b4062..9dcb49d077 100644
+--- a/ssl/ssl_ciph.c
++++ b/ssl/ssl_ciph.c
+@@ -2245,6 +2245,7 @@ const char *OSSL_default_ciphersuites(void)
+            "TLS_AES_128_GCM_SHA256";
+ }
+ 
++#ifndef OPENSSL_NO_QUIC
+ int SSL_CIPHER_get_prf_nid(const SSL_CIPHER *c)
+ {
+     switch (c->algorithm2 & (0xFF << TLS1_PRF_DGST_SHIFT)) {
+@@ -2276,3 +2277,4 @@ int SSL_CIPHER_get_prf_nid(const SSL_CIPHER *c)
+     }
+     return NID_undef;
+ }
++#endif
+diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
+index 6b7633e8a5..9ab43d1573 100644
+--- a/ssl/ssl_lib.c
++++ b/ssl/ssl_lib.c
+@@ -4245,7 +4245,7 @@ EVP_PKEY *SSL_CTX_get0_privatekey(const SSL_CTX *ctx)
+ 
+ const SSL_CIPHER *SSL_get_current_cipher(const SSL *s)
+ {
+-    if (s->session != NULL)
++    if ((s->session != NULL) && (s->session->cipher != NULL))
+         return s->session->cipher;
+     return NULL;
+ }
+diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h
+index 049d6448c9..c4033b4688 100644
+--- a/ssl/ssl_local.h
++++ b/ssl/ssl_local.h
+@@ -1227,6 +1227,7 @@ struct quic_data_st {
+     OSSL_ENCRYPTION_LEVEL level;
+     size_t offset;
+     size_t length;
++    /* char data[]; should be here but C90 VLAs not allowed here */
+ };
+ typedef struct quic_data_st QUIC_DATA;
+ int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level);
+diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c
+index 670deea5ab..95b3a8b64e 100644
+--- a/ssl/ssl_quic.c
++++ b/ssl/ssl_quic.c
+@@ -11,10 +11,6 @@
+ #include "internal/cryptlib.h"
+ #include "internal/refcount.h"
+ 
+-#ifdef OPENSSL_NO_QUIC
+-NON_EMPTY_TRANSLATION_UNIT
+-#else
+-
+ int SSL_set_quic_transport_params(SSL *ssl, const uint8_t *params,
+                                   size_t params_len)
+ {
+@@ -109,10 +105,10 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
+         return 0;
+     }
+ 
+-    /* Split the QUIC messages up, if necessary */
++    /* Split on handshake message boundaries, if necessary */
+     while (len > 0) {
+         QUIC_DATA *qd;
+-        const uint8_t *p = data + 1;
++        const uint8_t *p;
+ 
+         /* Check for an incomplete block */
+         qd = ssl->quic_input_data_tail;
+@@ -130,6 +126,12 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
+             }
+         }
+ 
++        if (len < SSL3_HM_HEADER_LENGTH) {
++            SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_BAD_LENGTH);
++            return 0;
++        }
++        /* TLS Handshake message header has 1-byte type and 3-byte length */
++        p = data + 1;
+         n2l3(p, l);
+         l += SSL3_HM_HEADER_LENGTH;
+ 
+@@ -163,15 +165,8 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
+ 
+ int SSL_CTX_set_quic_method(SSL_CTX *ctx, const SSL_QUIC_METHOD *quic_method)
+ {
+-    switch (ctx->method->version) {
+-    case DTLS1_VERSION:
+-    case DTLS1_2_VERSION:
+-    case DTLS_ANY_VERSION:
+-    case DTLS1_BAD_VER:
++    if (ctx->method->version != TLS_ANY_VERSION)
+         return 0;
+-    default:
+-        break;
+-    }
+     ctx->quic_method = quic_method;
+     ctx->options &= ~SSL_OP_ENABLE_MIDDLEBOX_COMPAT;
+     return 1;
+@@ -179,15 +174,8 @@ int SSL_CTX_set_quic_method(SSL_CTX *ctx, const SSL_QUIC_METHOD *quic_method)
+ 
+ int SSL_set_quic_method(SSL *ssl, const SSL_QUIC_METHOD *quic_method)
+ {
+-    switch (ssl->method->version) {
+-    case DTLS1_VERSION:
+-    case DTLS1_2_VERSION:
+-    case DTLS_ANY_VERSION:
+-    case DTLS1_BAD_VER:
++    if (ssl->method->version != TLS_ANY_VERSION)
+         return 0;
+-    default:
+-        break;
+-    }
+     ssl->quic_method = quic_method;
+     ssl->options &= ~SSL_OP_ENABLE_MIDDLEBOX_COMPAT;
+     return 1;
+@@ -225,6 +213,12 @@ int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level)
+         /* May not have selected cipher, yet */
+         const SSL_CIPHER *c = NULL;
+ 
++        /*
++         * It probably doesn't make sense to use an (external) PSK session,
++         * but in theory some kinds of external session caches could be
++         * implemented using it, so allow psksession to be used as well as
++         * the regular session.
++         */
+         if (ssl->session != NULL)
+             c = SSL_SESSION_get0_cipher(ssl->session);
+         else if (ssl->psksession != NULL)
+@@ -265,6 +259,11 @@ int SSL_process_quic_post_handshake(SSL *ssl)
+         return 0;
+     }
+ 
++    /*
++     * This is always safe (we are sure to be at a record boundary) because
++     * SSL_read()/SSL_write() are never used for QUIC connections -- the
++     * application data is handled at the QUIC layer instead.
++     */
+     ossl_statem_set_in_init(ssl, 1);
+     ret = ssl->handshake_func(ssl);
+     ossl_statem_set_in_init(ssl, 0);
+@@ -278,5 +277,3 @@ int SSL_is_quic(SSL* ssl)
+ {
+     return SSL_IS_QUIC(ssl);
+ }
+-
+-#endif
+diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c
+index 3e76361199..06ccd855a0 100644
+--- a/ssl/statem/extensions_clnt.c
++++ b/ssl/statem/extensions_clnt.c
+@@ -1922,7 +1922,7 @@ int tls_parse_stoc_early_data(SSL *s, PACKET *pkt, unsigned int context,
+ #ifndef OPENSSL_NO_QUIC
+         /*
+          * QUIC server must send 0xFFFFFFFF or it's a PROTOCOL_VIOLATION
+-         * per draft-ietf-quic-tls-24 S4.5
++         * per draft-ietf-quic-tls-27 S4.5
+          */
+         if (s->quic_method != NULL && max_early_data != 0xFFFFFFFF) {
+             SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_INVALID_MAX_EARLY_DATA);
+diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c
+index 344dca1292..e3277f685f 100644
+--- a/ssl/statem/extensions_srvr.c
++++ b/ssl/statem/extensions_srvr.c
+@@ -1896,7 +1896,7 @@ EXT_RETURN tls_construct_stoc_early_data(SSL *s, WPACKET *pkt,
+             return EXT_RETURN_NOT_SENT;
+ 
+ #ifndef OPENSSL_NO_QUIC
+-        /* QUIC server must always send 0xFFFFFFFF, per draft-ietf-quic-tls-24 S4.5 */
++        /* QUIC server must always send 0xFFFFFFFF, per draft-ietf-quic-tls-27 S4.5 */
+         if (s->quic_method != NULL)
+             max_early_data = 0xFFFFFFFF;
+ #endif
+diff --git a/ssl/statem/statem.c b/ssl/statem/statem.c
+index f6caa64e4c..b040d14cd2 100644
+--- a/ssl/statem/statem.c
++++ b/ssl/statem/statem.c
+@@ -585,6 +585,7 @@ static SUB_STATE_RETURN read_state_machine(SSL *s)
+                 ret = dtls_get_message(s, &mt);
+ #ifndef OPENSSL_NO_QUIC
+             } else if (SSL_IS_QUIC(s)) {
++                /* QUIC behaves like DTLS -- all in one go. */
+                 ret = quic_get_message(s, &mt, &len);
+ #endif
+             } else {
+@@ -929,7 +930,6 @@ int statem_flush(SSL *s)
+ #ifndef OPENSSL_NO_QUIC
+     if (SSL_IS_QUIC(s)) {
+         if (!s->quic_method->flush_flight(s)) {
+-            /* NOTE: BIO_flush() does not generate an error */
+             SSLerr(SSL_F_STATEM_FLUSH, ERR_R_INTERNAL_ERROR);
+             return 0;
+         }
+diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c
+index 65899e6b83..c85f35d6bb 100644
+--- a/ssl/statem/statem_lib.c
++++ b/ssl/statem/statem_lib.c
+@@ -44,17 +44,24 @@ int ssl3_do_write(SSL *s, int type)
+ {
+     int ret;
+     size_t written = 0;
++
+ #ifndef OPENSSL_NO_QUIC
+-    if (SSL_IS_QUIC(s) && type == SSL3_RT_HANDSHAKE) {
+-        ret = s->quic_method->add_handshake_data(s, s->quic_write_level,
+-                                                 (const uint8_t*)&s->init_buf->data[s->init_off],
+-                                          s->init_num);
+-        if (!ret) {
+-            ret = -1;
+-            /* QUIC can't sent anything out sice the above failed */
+-            SSLerr(SSL_F_SSL3_DO_WRITE, ERR_R_INTERNAL_ERROR);
++    if (SSL_IS_QUIC(s)) {
++        if (type == SSL3_RT_HANDSHAKE) {
++            ret = s->quic_method->add_handshake_data(s, s->quic_write_level,
++                                                     (const uint8_t*)&s->init_buf->data[s->init_off],
++                                                     s->init_num);
++            if (!ret) {
++                ret = -1;
++                /* QUIC can't sent anything out sice the above failed */
++                SSLerr(SSL_F_SSL3_DO_WRITE, ERR_R_INTERNAL_ERROR);
++            } else {
++                written = s->init_num;
++            }
+         } else {
+-            written = s->init_num;
++            /* QUIC doesn't use ChangeCipherSpec */
++            ret = -1;
++            SSLerr(SSL_F_SSL3_DO_WRITE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+         }
+     } else
+ #endif
+@@ -1177,7 +1184,6 @@ int tls_get_message_header(SSL *s, int *mt)
+ 
+     do {
+         while (s->init_num < SSL3_HM_HEADER_LENGTH) {
+-            /* QUIC: either create a special ssl_read_bytes... or if/else this */
+             i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, &recvd_type,
+                                           &p[s->init_num],
+                                           SSL3_HM_HEADER_LENGTH - s->init_num,
+diff --git a/ssl/statem/statem_local.h b/ssl/statem/statem_local.h
+index 57e314512b..6d5820e2cf 100644
+--- a/ssl/statem/statem_local.h
++++ b/ssl/statem/statem_local.h
+@@ -104,7 +104,9 @@ __owur int tls_get_message_header(SSL *s, int *mt);
+ __owur int tls_get_message_body(SSL *s, size_t *len);
+ __owur int dtls_get_message(SSL *s, int *mt);
+ __owur int dtls_get_message_body(SSL *s, size_t *len);
++#ifndef OPENSSL_NO_QUIC
+ __owur int quic_get_message(SSL *s, int *mt, size_t *len);
++#endif
+ 
+ /* Message construction and processing functions */
+ __owur int tls_process_initial_server_flight(SSL *s);
+diff --git a/ssl/statem/statem_quic.c b/ssl/statem/statem_quic.c
+index 982a9a6292..df38afbc79 100644
+--- a/ssl/statem/statem_quic.c
++++ b/ssl/statem/statem_quic.c
+@@ -11,10 +11,6 @@
+ #include "statem_local.h"
+ #include "internal/cryptlib.h"
+ 
+-#ifdef OPENSSL_NO_QUIC
+-NON_EMPTY_TRANSLATION_UNIT
+-#else
+-
+ int quic_get_message(SSL *s, int *mt, size_t *len)
+ {
+     size_t l;
+@@ -23,20 +19,26 @@ int quic_get_message(SSL *s, int *mt, size_t *len)
+ 
+     if (qd == NULL || (qd->length - qd->offset) != 0) {
+         s->rwstate = SSL_READING;
+-        *len = 0;
++        *mt = *len = 0;
++        return 0;
++    }
++
++    if (!ossl_assert(qd->length >= SSL3_HM_HEADER_LENGTH)) {
++        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_BAD_LENGTH);
++        *mt = *len = 0;
+         return 0;
+     }
+ 
+     /* This is where we check for the proper level, not when data is given */
+     if (qd->level != s->quic_read_level) {
+         SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED);
+-        *len = 0;
++        *mt = *len = 0;
+         return 0;
+     }
+ 
+     if (!BUF_MEM_grow_clean(s->init_buf, (int)qd->length)) {
+         SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_BUF_LIB);
+-        *len = 0;
++        *mt = *len = 0;
+         return 0;
+     }
+ 
+@@ -79,8 +81,8 @@ int quic_get_message(SSL *s, int *mt, size_t *len)
+      */
+ #define SERVER_HELLO_RANDOM_OFFSET  (SSL3_HM_HEADER_LENGTH + 2)
+     /* KeyUpdate and NewSessionTicket do not need to be added */
+-    if (!SSL_IS_TLS13(s) || (s->s3.tmp.message_type != SSL3_MT_NEWSESSION_TICKET
+-                             && s->s3.tmp.message_type != SSL3_MT_KEY_UPDATE)) {
++    if (s->s3.tmp.message_type != SSL3_MT_NEWSESSION_TICKET
++            && s->s3.tmp.message_type != SSL3_MT_KEY_UPDATE) {
+         if (s->s3.tmp.message_type != SSL3_MT_SERVER_HELLO
+             || s->init_num < SERVER_HELLO_RANDOM_OFFSET + SSL3_RANDOM_SIZE
+             || memcmp(hrrrandom,
+@@ -101,5 +103,3 @@ int quic_get_message(SSL *s, int *mt, size_t *len)
+ 
+     return 1;
+ }
+-
+-#endif
+diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c
+index a5b674d04b..a63beea224 100644
+--- a/ssl/tls13_enc.c
++++ b/ssl/tls13_enc.c
+@@ -404,6 +404,7 @@ static const unsigned char exporter_master_secret[] = "exp master";
+ static const unsigned char resumption_master_secret[] = "res master";
+ static const unsigned char early_exporter_master_secret[] = "e exp master";
+ #endif
++
+ #ifndef OPENSSL_NO_QUIC
+ static int quic_change_cipher_state(SSL *s, int which)
+ {
+@@ -412,7 +413,7 @@ static int quic_change_cipher_state(SSL *s, int which)
+     int hashleni;
+     int ret = 0;
+     const EVP_MD *md = NULL;
+-    OSSL_ENCRYPTION_LEVEL level = ssl_encryption_initial;
++    OSSL_ENCRYPTION_LEVEL level;
+     int is_handshake = ((which & SSL3_CC_HANDSHAKE) == SSL3_CC_HANDSHAKE);
+     int is_client_read = ((which & SSL3_CHANGE_CIPHER_CLIENT_READ) == SSL3_CHANGE_CIPHER_CLIENT_READ);
+     int is_server_write = ((which & SSL3_CHANGE_CIPHER_SERVER_WRITE) == SSL3_CHANGE_CIPHER_SERVER_WRITE);
+@@ -435,34 +436,62 @@ static int quic_change_cipher_state(SSL *s, int which)
+ 
+     if (is_client_read || is_server_write) {
+         if (is_handshake) {
++            /*
++             * This looks a bit weird, since the condition is basically "the
++             * server is writing" but we set both the server *and* client
++             * handshake traffic keys here.  That's because there's only a fixed
++             * number of change-cipher-state events in the TLS 1.3 handshake,
++             * and in particular there's not an event in between when the server
++             * writes encrypted handshake messages and when the client writes
++             * encrypted handshake messages, so we generate both here.
++             */
+             level = ssl_encryption_handshake;
+ 
+-            if (!tls13_hkdf_expand(s, md, s->handshake_secret, client_handshake_traffic,
+-                                   sizeof(client_handshake_traffic)-1, hash, hashlen,
+-                                   s->client_hand_traffic_secret, hashlen, 1)
+-                || !ssl_log_secret(s, CLIENT_HANDSHAKE_LABEL, s->client_hand_traffic_secret, hashlen)
+-                || !tls13_derive_finishedkey(s, md, s->client_hand_traffic_secret,
++            if (!tls13_hkdf_expand(s, md, s->handshake_secret,
++                                   client_handshake_traffic,
++                                   sizeof(client_handshake_traffic)-1, hash,
++                                   hashlen, s->client_hand_traffic_secret,
++                                   hashlen, 1)
++                || !ssl_log_secret(s, CLIENT_HANDSHAKE_LABEL,
++                                   s->client_hand_traffic_secret, hashlen)
++                || !tls13_derive_finishedkey(s, md,
++                                             s->client_hand_traffic_secret,
+                                              s->client_finished_secret, hashlen)
+-                || !tls13_hkdf_expand(s, md, s->handshake_secret, server_handshake_traffic,
+-                                      sizeof(server_handshake_traffic)-1, hash, hashlen,
+-                                      s->server_hand_traffic_secret, hashlen, 1)
+-                || !ssl_log_secret(s, SERVER_HANDSHAKE_LABEL, s->server_hand_traffic_secret, hashlen)
+-                || !tls13_derive_finishedkey(s, md, s->server_hand_traffic_secret,
+-                                             s->server_finished_secret, hashlen)) {
++                || !tls13_hkdf_expand(s, md, s->handshake_secret,
++                                      server_handshake_traffic,
++                                      sizeof(server_handshake_traffic)-1, hash,
++                                      hashlen, s->server_hand_traffic_secret,
++                                      hashlen, 1)
++                || !ssl_log_secret(s, SERVER_HANDSHAKE_LABEL,
++                                   s->server_hand_traffic_secret, hashlen)
++                || !tls13_derive_finishedkey(s, md,
++                                             s->server_hand_traffic_secret,
++                                             s->server_finished_secret,
++                                             hashlen)) {
+                 /* SSLfatal() already called */
+                 goto err;
+             }
+         } else {
++            /*
++             * As above, we generate both sets of application traffic keys at
++             * the same time.
++             */
+             level = ssl_encryption_application;
+ 
+-            if (!tls13_hkdf_expand(s, md, s->master_secret, client_application_traffic,
+-                                   sizeof(client_application_traffic)-1, hash, hashlen,
+-                                   s->client_app_traffic_secret, hashlen, 1)
+-                || !ssl_log_secret(s, CLIENT_APPLICATION_LABEL, s->client_app_traffic_secret, hashlen)
+-                || !tls13_hkdf_expand(s, md, s->master_secret, server_application_traffic,
+-                                      sizeof(server_application_traffic)-1, hash, hashlen,
++            if (!tls13_hkdf_expand(s, md, s->master_secret,
++                                   client_application_traffic,
++                                   sizeof(client_application_traffic)-1, hash,
++                                   hashlen, s->client_app_traffic_secret,
++                                   hashlen, 1)
++                || !ssl_log_secret(s, CLIENT_APPLICATION_LABEL,
++                                   s->client_app_traffic_secret, hashlen)
++                || !tls13_hkdf_expand(s, md, s->master_secret,
++                                      server_application_traffic,
++                                      sizeof(server_application_traffic)-1,
++                                      hash, hashlen,
+                                       s->server_app_traffic_secret, hashlen, 1)
+-                || !ssl_log_secret(s, SERVER_APPLICATION_LABEL, s->server_app_traffic_secret, hashlen)) {
++                || !ssl_log_secret(s, SERVER_APPLICATION_LABEL,
++                                   s->server_app_traffic_secret, hashlen)) {
+                 /* SSLfatal() already called */
+                 goto err;
+             }
+@@ -482,9 +511,11 @@ static int quic_change_cipher_state(SSL *s, int which)
+             level = ssl_encryption_early_data;
+ 
+             if (!tls13_hkdf_expand(s, md, s->early_secret, client_early_traffic,
+-                                   sizeof(client_early_traffic)-1, hash, hashlen,
+-                                   s->client_early_traffic_secret, hashlen, 1)
+-                || !ssl_log_secret(s, CLIENT_EARLY_LABEL, s->client_early_traffic_secret, hashlen)
++                                   sizeof(client_early_traffic)-1, hash,
++                                   hashlen, s->client_early_traffic_secret,
++                                   hashlen, 1)
++                || !ssl_log_secret(s, CLIENT_EARLY_LABEL,
++                                   s->client_early_traffic_secret, hashlen)
+                 || !quic_set_encryption_secrets(s, level)) {
+                 /* SSLfatal() already called */
+                 goto err;
+@@ -497,9 +528,11 @@ static int quic_change_cipher_state(SSL *s, int which)
+              * We also create the resumption master secret, but this time use the
+              * hash for the whole handshake including the Client Finished
+              */
+-            if (!tls13_hkdf_expand(s, md, s->master_secret, resumption_master_secret,
+-                                   sizeof(resumption_master_secret)-1, hash, hashlen,
+-                                   s->resumption_master_secret, hashlen, 1)) {
++            if (!tls13_hkdf_expand(s, md, s->master_secret,
++                                   resumption_master_secret,
++                                   sizeof(resumption_master_secret)-1, hash,
++                                   hashlen, s->resumption_master_secret,
++                                   hashlen, 1)) {
+                 /* SSLfatal() already called */
+                 goto err;
+             }
+@@ -516,6 +549,7 @@ static int quic_change_cipher_state(SSL *s, int which)
+     return ret;
+ }
+ #endif /* OPENSSL_NO_QUIC */
++
+ int tls13_change_cipher_state(SSL *s, int which)
+ {
+     unsigned char *iv;
+diff --git a/test/sslapitest.c b/test/sslapitest.c
+index b0bafe7549..bd2b698303 100644
+--- a/test/sslapitest.c
++++ b/test/sslapitest.c
+@@ -10132,9 +10132,11 @@ end:
+ }
+ 
+ #ifndef OPENSSL_NO_QUIC
+-static int test_quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
++static int test_quic_set_encryption_secrets(SSL *ssl,
++                                            OSSL_ENCRYPTION_LEVEL level,
+                                             const uint8_t *read_secret,
+-                                            const uint8_t *write_secret, size_t secret_len)
++                                            const uint8_t *write_secret,
++                                            size_t secret_len)
+ {
+     test_printf_stderr("quic_set_encryption_secrets() %s, lvl=%d, len=%zd\n",
+                        ssl->server ? "server" : "client", level, secret_len);
+@@ -10146,11 +10148,12 @@ static int test_quic_add_handshake_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
+ {
+     SSL *peer = (SSL*)SSL_get_app_data(ssl);
+ 
+-    test_printf_stderr("quic_add_handshake_data() %s, lvl=%d, *data=0x%02X, len=%zd\n",
+-                       ssl->server ? "server" : "client", level, (int)*data, len);
++    TEST_info("quic_add_handshake_data() %s, lvl=%d, *data=0x%02X, len=%zd\n",
++              ssl->server ? "server" : "client", level, (int)*data, len);
+     if (!TEST_ptr(peer))
+         return 0;
+ 
++    /* We're called with what is locally written; this gives it to the peer */
+     if (!TEST_true(SSL_provide_quic_data(peer, level, data, len))) {
+         ERR_print_errors_fp(stderr);
+         return 0;
+diff --git a/util/libssl.num b/util/libssl.num
+index 72ee0bedc6..da35cf2970 100644
+--- a/util/libssl.num
++++ b/util/libssl.num
+@@ -522,7 +522,7 @@ SSL_CTX_set0_tmp_dh_pkey                522	3_0_0	EXIST::FUNCTION:
+ SSL_group_to_name                       523	3_0_0	EXIST::FUNCTION:
+ SSL_quic_read_level                     20000	3_0_0	EXIST::FUNCTION:QUIC
+ SSL_set_quic_transport_params           20001	3_0_0	EXIST::FUNCTION:QUIC
+-SSL_CIPHER_get_prf_nid                  20002	3_0_0	EXIST::FUNCTION:
++SSL_CIPHER_get_prf_nid                  20002	3_0_0	EXIST::FUNCTION:QUIC
+ SSL_is_quic                             20003	3_0_0	EXIST::FUNCTION:QUIC
+ SSL_get_peer_quic_transport_params      20004	3_0_0	EXIST::FUNCTION:QUIC
+ SSL_quic_write_level                    20005	3_0_0	EXIST::FUNCTION:QUIC
+-- 
+2.42.0
+
diff --git a/0022-QUIC-Prevent-KeyUpdate-for-QUIC.patch b/0022-QUIC-Prevent-KeyUpdate-for-QUIC.patch
new file mode 100644
index 0000000..b160db9
--- /dev/null
+++ b/0022-QUIC-Prevent-KeyUpdate-for-QUIC.patch
@@ -0,0 +1,77 @@
+From 9f8fd0f59fa76853371099aa2ae706ae4229d0e3 Mon Sep 17 00:00:00 2001
+From: Benjamin Kaduk <bkaduk@akamai.com>
+Date: Mon, 11 May 2020 13:13:01 -0700
+Subject: [PATCH 22/63] QUIC: Prevent KeyUpdate for QUIC
+
+QUIC does not use the TLS KeyUpdate message/mechanism, and indeed
+it is an error to generate or receive such a message.  Add the
+necessary checks (noting that the check for receipt should be
+redundant since SSL_provide_quic_data() is the only way to provide
+input to the TLS layer for a QUIC connection).
+---
+ ssl/ssl_quic.c          |  6 ++++++
+ ssl/statem/statem_lib.c | 14 ++++++++++++++
+ 2 files changed, 20 insertions(+)
+
+diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c
+index 95b3a8b64e..7b78b2ec53 100644
+--- a/ssl/ssl_quic.c
++++ b/ssl/ssl_quic.c
+@@ -92,6 +92,7 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
+                           const uint8_t *data, size_t len)
+ {
+     size_t l;
++    uint8_t mt;
+ 
+     if (!SSL_IS_QUIC(ssl)) {
+         SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+@@ -131,9 +132,14 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
+             return 0;
+         }
+         /* TLS Handshake message header has 1-byte type and 3-byte length */
++        mt = *data;
+         p = data + 1;
+         n2l3(p, l);
+         l += SSL3_HM_HEADER_LENGTH;
++        if (mt == SSL3_MT_KEY_UPDATE) {
++            SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_UNEXPECTED_MESSAGE);
++            return 0;
++        }
+ 
+         qd = OPENSSL_zalloc(sizeof(QUIC_DATA) + l);
+         if (qd == NULL) {
+diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c
+index c85f35d6bb..9c9ac0eda6 100644
+--- a/ssl/statem/statem_lib.c
++++ b/ssl/statem/statem_lib.c
+@@ -656,6 +656,13 @@ int tls_construct_finished(SSL *s, WPACKET *pkt)
+ 
+ int tls_construct_key_update(SSL *s, WPACKET *pkt)
+ {
++#ifndef OPENSSL_NO_QUIC
++    if (SSL_is_quic(s)) {
++        /* TLS KeyUpdate is not used for QUIC, so this is an error. */
++        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
++        return 0;
++    }
++#endif
+     if (!WPACKET_put_bytes_u8(pkt, s->key_update)) {
+         SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+         return 0;
+@@ -678,6 +685,13 @@ MSG_PROCESS_RETURN tls_process_key_update(SSL *s, PACKET *pkt)
+         return MSG_PROCESS_ERROR;
+     }
+ 
++#ifndef OPENSSL_NO_QUIC
++    if (SSL_is_quic(s)) {
++        SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_R_UNEXPECTED_MESSAGE);
++        return MSG_PROCESS_ERROR;
++    }
++#endif
++
+     if (!PACKET_get_1(pkt, &updatetype)
+             || PACKET_remaining(pkt) != 0) {
+         SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_KEY_UPDATE);
+-- 
+2.42.0
+
diff --git a/0023-QUIC-Test-KeyUpdate-rejection.patch b/0023-QUIC-Test-KeyUpdate-rejection.patch
new file mode 100644
index 0000000..5c2fa01
--- /dev/null
+++ b/0023-QUIC-Test-KeyUpdate-rejection.patch
@@ -0,0 +1,37 @@
+From 3e0ad6fa4444b3a1d9c7a4a98a8209d90b746169 Mon Sep 17 00:00:00 2001
+From: Benjamin Kaduk <bkaduk@akamai.com>
+Date: Mon, 11 May 2020 13:26:07 -0700
+Subject: [PATCH 23/63] QUIC: Test KeyUpdate rejection
+
+For now, just test that we don't generate any, since we don't really
+expose the mechanics for encrypting one and the QUIC API is not
+integrated into the TLSProxy setup.
+---
+ test/sslapitest.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/test/sslapitest.c b/test/sslapitest.c
+index bd2b698303..bc908dd382 100644
+--- a/test/sslapitest.c
++++ b/test/sslapitest.c
+@@ -10256,6 +10256,17 @@ static int test_quic_api(void)
+             || !TEST_true(SSL_process_quic_post_handshake(clientssl)))
+         goto end;
+ 
++    /* Dummy handshake call should succeed */
++    if (!TEST_true(SSL_do_handshake(clientssl)))
++        goto end;
++    /* Test that we (correctly) fail to send KeyUpdate */
++    if (!TEST_true(SSL_key_update(clientssl, SSL_KEY_UPDATE_NOT_REQUESTED))
++            || !TEST_int_le(SSL_do_handshake(clientssl), 0))
++        goto end;
++    if (!TEST_true(SSL_key_update(serverssl, SSL_KEY_UPDATE_NOT_REQUESTED))
++            || !TEST_int_le(SSL_do_handshake(serverssl), 0))
++        goto end;
++
+     testresult = 1;
+ 
+  end:
+-- 
+2.42.0
+
diff --git a/0024-QUIC-Buffer-all-provided-quic-data.patch b/0024-QUIC-Buffer-all-provided-quic-data.patch
new file mode 100644
index 0000000..0c28e1b
--- /dev/null
+++ b/0024-QUIC-Buffer-all-provided-quic-data.patch
@@ -0,0 +1,219 @@
+From 27215416c0b1de14648f137edc158b3d9645a193 Mon Sep 17 00:00:00 2001
+From: Benjamin Kaduk <bkaduk@akamai.com>
+Date: Mon, 31 Aug 2020 12:27:33 -0700
+Subject: [PATCH 24/63] QUIC: Buffer all provided quic data
+
+Make all data supplied via SSL_provide_quic_data() pass through an
+internal buffer, so that we can handle data supplied with arbitrary
+framing and only parse complete TLS records onto the list of QUIC_DATA
+managed by quic_input_data_head/quic_input_data_tail.
+
+This lets us remove the concept of "incomplete" QUIC_DATA structures,
+and the 'offset' field needed to support them.
+
+However, we've already moved the provided data onto the buffer by
+the time we can check for KeyUpdate messages, so defer that check
+to quic_get_message() (where it is adjacent to the preexisting
+ChangeCipherSpec check).
+
+To avoid extra memory copies, we also make the QUIC_DATA structures
+just store offsets into the consolidated buffer instead of having copies
+of the TLS handshake messages themselves.
+---
+ ssl/ssl_lib.c            |  1 +
+ ssl/ssl_local.h          |  5 +--
+ ssl/ssl_quic.c           | 75 +++++++++++++++++++---------------------
+ ssl/statem/statem_quic.c | 11 ++++--
+ 4 files changed, 49 insertions(+), 43 deletions(-)
+
+diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
+index 9ab43d1573..a78ebd55af 100644
+--- a/ssl/ssl_lib.c
++++ b/ssl/ssl_lib.c
+@@ -1248,6 +1248,7 @@ void SSL_free(SSL *s)
+ #ifndef OPENSSL_NO_QUIC
+     OPENSSL_free(s->ext.quic_transport_params);
+     OPENSSL_free(s->ext.peer_quic_transport_params);
++    BUF_MEM_free(s->quic_buf);
+     while (s->quic_input_data_head != NULL) {
+         QUIC_DATA *qd;
+ 
+diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h
+index c4033b4688..44395fb365 100644
+--- a/ssl/ssl_local.h
++++ b/ssl/ssl_local.h
+@@ -1225,9 +1225,8 @@ typedef struct cert_pkey_st CERT_PKEY;
+ struct quic_data_st {
+     struct quic_data_st *next;
+     OSSL_ENCRYPTION_LEVEL level;
+-    size_t offset;
++    size_t start;       /* offset into quic_buf->data */
+     size_t length;
+-    /* char data[]; should be here but C90 VLAs not allowed here */
+ };
+ typedef struct quic_data_st QUIC_DATA;
+ int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level);
+@@ -1721,8 +1720,10 @@ struct ssl_st {
+ #ifndef OPENSSL_NO_QUIC
+     OSSL_ENCRYPTION_LEVEL quic_read_level;
+     OSSL_ENCRYPTION_LEVEL quic_write_level;
++    BUF_MEM *quic_buf;          /* buffer incoming handshake messages */
+     QUIC_DATA *quic_input_data_head;
+     QUIC_DATA *quic_input_data_tail;
++    size_t quic_next_record_start;
+     const SSL_QUIC_METHOD *quic_method;
+ #endif
+     /*
+diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c
+index 7b78b2ec53..e396720551 100644
+--- a/ssl/ssl_quic.c
++++ b/ssl/ssl_quic.c
+@@ -91,8 +91,7 @@ OSSL_ENCRYPTION_LEVEL SSL_quic_write_level(const SSL *ssl)
+ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
+                           const uint8_t *data, size_t len)
+ {
+-    size_t l;
+-    uint8_t mt;
++    size_t l, offset;
+ 
+     if (!SSL_IS_QUIC(ssl)) {
+         SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+@@ -106,42 +105,46 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
+         return 0;
+     }
+ 
+-    /* Split on handshake message boundaries, if necessary */
+-    while (len > 0) {
+-        QUIC_DATA *qd;
+-        const uint8_t *p;
+-
+-        /* Check for an incomplete block */
+-        qd = ssl->quic_input_data_tail;
+-        if (qd != NULL) {
+-            l = qd->length - qd->offset;
+-            if (l != 0) {
+-                /* we still need to copy `l` bytes into the last data block */
+-                if (l > len)
+-                    l = len;
+-                memcpy((char*)(qd+1) + qd->offset, data, l);
+-                qd->offset += l;
+-                len -= l;
+-                data += l;
+-                continue;
+-            }
++    if (ssl->quic_buf == NULL) {
++        BUF_MEM *buf;
++        if ((buf = BUF_MEM_new()) == NULL) {
++            SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR);
++            return 0;
+         }
+-
+-        if (len < SSL3_HM_HEADER_LENGTH) {
+-            SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_BAD_LENGTH);
++        if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) {
++            SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR);
++            BUF_MEM_free(buf);
+             return 0;
+         }
++        ssl->quic_buf = buf;
++        /* We preallocated storage, but there's still no *data*. */
++        ssl->quic_buf->length = 0;
++        buf = NULL;
++    }
++
++    offset = ssl->quic_buf->length;
++    if (!BUF_MEM_grow(ssl->quic_buf, offset + len)) {
++        SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR);
++        return 0;
++    }
++    memcpy(ssl->quic_buf->data + offset, data, len);
++
++    /* Split on handshake message boundaries */
++    while (ssl->quic_buf->length > ssl->quic_next_record_start
++                                   + SSL3_HM_HEADER_LENGTH) {
++        QUIC_DATA *qd;
++        const uint8_t *p;
++
+         /* TLS Handshake message header has 1-byte type and 3-byte length */
+-        mt = *data;
+-        p = data + 1;
++        p = (const uint8_t *)ssl->quic_buf->data
++            + ssl->quic_next_record_start + 1;
+         n2l3(p, l);
+         l += SSL3_HM_HEADER_LENGTH;
+-        if (mt == SSL3_MT_KEY_UPDATE) {
+-            SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_UNEXPECTED_MESSAGE);
+-            return 0;
+-        }
++        /* Don't allocate a QUIC_DATA if we don't have a full record */
++        if (l > ssl->quic_buf->length - ssl->quic_next_record_start)
++            break;
+ 
+-        qd = OPENSSL_zalloc(sizeof(QUIC_DATA) + l);
++        qd = OPENSSL_zalloc(sizeof(*qd));
+         if (qd == NULL) {
+             SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR);
+             return 0;
+@@ -149,21 +152,15 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
+ 
+         qd->next = NULL;
+         qd->length = l;
++        qd->start = ssl->quic_next_record_start;
+         qd->level = level;
+-        /* partial data received? */
+-        if (l > len)
+-            l = len;
+-        qd->offset = l;
+ 
+-        memcpy((void*)(qd + 1), data, l);
+         if (ssl->quic_input_data_tail != NULL)
+             ssl->quic_input_data_tail->next = qd;
+         else
+             ssl->quic_input_data_head = qd;
+         ssl->quic_input_data_tail = qd;
+-
+-        data += l;
+-        len -= l;
++        ssl->quic_next_record_start += l;
+     }
+ 
+     return 1;
+diff --git a/ssl/statem/statem_quic.c b/ssl/statem/statem_quic.c
+index df38afbc79..a371eeaedb 100644
+--- a/ssl/statem/statem_quic.c
++++ b/ssl/statem/statem_quic.c
+@@ -17,7 +17,7 @@ int quic_get_message(SSL *s, int *mt, size_t *len)
+     QUIC_DATA *qd = s->quic_input_data_head;
+     uint8_t *p;
+ 
+-    if (qd == NULL || (qd->length - qd->offset) != 0) {
++    if (qd == NULL) {
+         s->rwstate = SSL_READING;
+         *mt = *len = 0;
+         return 0;
+@@ -43,7 +43,7 @@ int quic_get_message(SSL *s, int *mt, size_t *len)
+     }
+ 
+     /* Copy buffered data */
+-    memcpy(s->init_buf->data, (void*)(qd + 1), qd->length);
++    memcpy(s->init_buf->data, s->quic_buf->data + qd->start, qd->length);
+     s->init_buf->length = qd->length;
+     s->quic_input_data_head = qd->next;
+     if (s->quic_input_data_head == NULL)
+@@ -62,6 +62,13 @@ int quic_get_message(SSL *s, int *mt, size_t *len)
+         *len = 0;
+         return 0;
+     }
++    /* No KeyUpdate in QUIC */
++    if (*mt == SSL3_MT_KEY_UPDATE) {
++        SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_R_UNEXPECTED_MESSAGE);
++        *len = 0;
++        return 0;
++    }
++
+ 
+     /*
+      * If receiving Finished, record MAC of prior handshake messages for
+-- 
+2.42.0
+
diff --git a/0025-QUIC-Enforce-consistent-encryption-level-for-handsha.patch b/0025-QUIC-Enforce-consistent-encryption-level-for-handsha.patch
new file mode 100644
index 0000000..473af22
--- /dev/null
+++ b/0025-QUIC-Enforce-consistent-encryption-level-for-handsha.patch
@@ -0,0 +1,58 @@
+From 0533f66777e89e43091d03806c0bc3380f29ce11 Mon Sep 17 00:00:00 2001
+From: Benjamin Kaduk <bkaduk@akamai.com>
+Date: Tue, 1 Sep 2020 15:10:41 -0700
+Subject: [PATCH 25/63] QUIC: Enforce consistent encryption level for handshake
+ messages
+
+The QUIC-TLS spec requires that TLS handshake messages do not cross
+encryption level boundaries, but we were not previously enforcing this.
+---
+ ssl/ssl_local.h |  1 +
+ ssl/ssl_quic.c  | 12 +++++++++++-
+ 2 files changed, 12 insertions(+), 1 deletion(-)
+
+diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h
+index 44395fb365..d99b751bfc 100644
+--- a/ssl/ssl_local.h
++++ b/ssl/ssl_local.h
+@@ -1720,6 +1720,7 @@ struct ssl_st {
+ #ifndef OPENSSL_NO_QUIC
+     OSSL_ENCRYPTION_LEVEL quic_read_level;
+     OSSL_ENCRYPTION_LEVEL quic_write_level;
++    OSSL_ENCRYPTION_LEVEL quic_latest_level_received;
+     BUF_MEM *quic_buf;          /* buffer incoming handshake messages */
+     QUIC_DATA *quic_input_data_head;
+     QUIC_DATA *quic_input_data_tail;
+diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c
+index e396720551..136d2b8460 100644
+--- a/ssl/ssl_quic.c
++++ b/ssl/ssl_quic.c
+@@ -100,7 +100,8 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
+ 
+     /* Level can be different than the current read, but not less */
+     if (level < ssl->quic_read_level
+-            || (ssl->quic_input_data_tail != NULL && level < ssl->quic_input_data_tail->level)) {
++            || (ssl->quic_input_data_tail != NULL && level < ssl->quic_input_data_tail->level)
++            || level < ssl->quic_latest_level_received) {
+         SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED);
+         return 0;
+     }
+@@ -122,6 +123,15 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
+         buf = NULL;
+     }
+ 
++    /* A TLS message must not cross an encryption level boundary */
++    if (ssl->quic_buf->length != ssl->quic_next_record_start
++            && level != ssl->quic_latest_level_received) {
++        SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA,
++               SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED);
++        return 0;
++    }
++    ssl->quic_latest_level_received = level;
++
+     offset = ssl->quic_buf->length;
+     if (!BUF_MEM_grow(ssl->quic_buf, offset + len)) {
+         SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR);
+-- 
+2.42.0
+
diff --git a/0026-QUIC-add-v1-quic_transport_parameters.patch b/0026-QUIC-add-v1-quic_transport_parameters.patch
new file mode 100644
index 0000000..f3479df
--- /dev/null
+++ b/0026-QUIC-add-v1-quic_transport_parameters.patch
@@ -0,0 +1,669 @@
+From cfef4abc6486d982da98f5de80ea1547bea1b59d Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Sat, 12 Dec 2020 17:27:46 +0900
+Subject: [PATCH 26/63] QUIC: add v1 quic_transport_parameters
+
+---
+ crypto/err/openssl.txt               |   2 +
+ doc/man3/SSL_CTX_set_quic_method.pod |  25 +++++-
+ include/openssl/ssl.h.in             |  13 ++++
+ include/openssl/sslerr.h             |   1 +
+ include/openssl/tls1.h               |   3 +-
+ ssl/ssl_err.c                        |   2 +
+ ssl/ssl_lib.c                        |   1 +
+ ssl/ssl_local.h                      |  11 +++
+ ssl/ssl_quic.c                       |  41 +++++++++-
+ ssl/statem/extensions.c              |  39 ++++++++++
+ ssl/statem/extensions_clnt.c         |  44 ++++++++++-
+ ssl/statem/extensions_srvr.c         |  46 ++++++++++-
+ ssl/statem/statem_local.h            |  17 +++++
+ test/sslapitest.c                    | 110 +++++++++++++++++++++------
+ util/libssl.num                      |   4 +
+ 15 files changed, 322 insertions(+), 37 deletions(-)
+
+diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
+index b2f90a413a..0394c10077 100644
+--- a/crypto/err/openssl.txt
++++ b/crypto/err/openssl.txt
+@@ -1400,6 +1400,8 @@ SSL_R_MISSING_ECDSA_SIGNING_CERT:381:missing ecdsa signing cert
+ SSL_R_MISSING_FATAL:256:missing fatal
+ SSL_R_MISSING_PARAMETERS:290:missing parameters
+ SSL_R_MISSING_PSK_KEX_MODES_EXTENSION:310:missing psk kex modes extension
++SSL_R_MISSING_QUIC_TRANSPORT_PARAMETERS_EXTENSION:801:\
++	missing quic transport parameters extension
+ SSL_R_MISSING_RSA_CERTIFICATE:168:missing rsa certificate
+ SSL_R_MISSING_RSA_ENCRYPTING_CERT:169:missing rsa encrypting cert
+ SSL_R_MISSING_RSA_SIGNING_CERT:170:missing rsa signing cert
+diff --git a/doc/man3/SSL_CTX_set_quic_method.pod b/doc/man3/SSL_CTX_set_quic_method.pod
+index 3d7bf7e682..39ff3a8da4 100644
+--- a/doc/man3/SSL_CTX_set_quic_method.pod
++++ b/doc/man3/SSL_CTX_set_quic_method.pod
+@@ -13,7 +13,11 @@ SSL_quic_read_level,
+ SSL_quic_write_level,
+ SSL_provide_quic_data,
+ SSL_process_quic_post_handshake,
+-SSL_is_quic
++SSL_is_quic,
++SSL_get_peer_quic_transport_version,
++SSL_get_quic_transport_version,
++SSL_set_quic_transport_version,
++SSL_set_quic_use_legacy_codepoint
+ - QUIC support
+ 
+ =head1 SYNOPSIS
+@@ -39,6 +43,11 @@ SSL_is_quic
+  int SSL_process_quic_post_handshake(SSL *ssl);
+  int SSL_is_quic(SSL *ssl);
+ 
++ void SSL_set_quic_use_legacy_codepoint(SSL *ssl, int use_legacy);
++ void SSL_set_quic_transport_version(SSL *ssl, int version);
++ int SSL_get_quic_transport_version(const SSL *ssl);
++ int SSL_get_peer_quic_transport_version(const SSL *ssl);
++
+ =head1 DESCRIPTION
+ 
+ SSL_CTX_set_quic_method() and SSL_set_quic_method() configures the QUIC methods.
+@@ -83,6 +92,20 @@ sent by the server.
+ SSL_is_quic() indicates whether a connection uses QUIC.  A given B<SSL>
+ or B<SSL_CTX> can only be used with QUIC or TLS, but not both.
+ 
++SSL_set_quic_use_legacy_codepoint() specifies the legacy extension codepoint
++in manner compatible with some versions of BoringSSL.
++
++SSL_set_quic_transport_version() specifies the quic transport version that
++allows for backwards and forwards compatibility. If set to 0 (default) the
++server will use the highest version the client sent. If set to 0 (default)
++the client will send both extensions.
++
++SSL_get_quic_transport_version() returns the value set by
++SSL_set_quic_transport_version().
++
++SSL_get_peer_quic_transport_version() returns the version the that was 
++negotiated.
++
+ =head1 NOTES
+ 
+ These APIs are implementations of BoringSSL's QUIC APIs.
+diff --git a/include/openssl/ssl.h.in b/include/openssl/ssl.h.in
+index 6b5fbfbf02..e221ebbb41 100644
+--- a/include/openssl/ssl.h.in
++++ b/include/openssl/ssl.h.in
+@@ -2565,6 +2565,19 @@ __owur int SSL_process_quic_post_handshake(SSL *ssl);
+ 
+ __owur int SSL_is_quic(SSL *ssl);
+ 
++/* BoringSSL API */
++__owur void SSL_set_quic_use_legacy_codepoint(SSL *ssl, int use_legacy);
++
++/*
++ * Set an explicit value that you want to use
++ * If 0 (default) the server will use the highest extenstion the client sent
++ * If 0 (default) the client will send both extensions
++ */
++void SSL_set_quic_transport_version(SSL *ssl, int version);
++__owur int SSL_get_quic_transport_version(const SSL *ssl);
++/* Returns the negotiated version, or -1 on error */
++__owur int SSL_get_peer_quic_transport_version(const SSL *ssl);
++
+ int SSL_CIPHER_get_prf_nid(const SSL_CIPHER *c);
+ 
+ #  endif
+diff --git a/include/openssl/sslerr.h b/include/openssl/sslerr.h
+index d60c892037..058ef308d8 100644
+--- a/include/openssl/sslerr.h
++++ b/include/openssl/sslerr.h
+@@ -162,6 +162,7 @@
+ # define SSL_R_MISSING_FATAL                              256
+ # define SSL_R_MISSING_PARAMETERS                         290
+ # define SSL_R_MISSING_PSK_KEX_MODES_EXTENSION            310
++# define SSL_R_MISSING_QUIC_TRANSPORT_PARAMETERS_EXTENSION 801
+ # define SSL_R_MISSING_RSA_CERTIFICATE                    168
+ # define SSL_R_MISSING_RSA_ENCRYPTING_CERT                169
+ # define SSL_R_MISSING_RSA_SIGNING_CERT                   170
+diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h
+index 062e47c18a..54b6621aa3 100644
+--- a/include/openssl/tls1.h
++++ b/include/openssl/tls1.h
+@@ -152,7 +152,8 @@ extern "C" {
+ # define TLSEXT_TYPE_renegotiate                 0xff01
+ 
+ /* ExtensionType value from draft-ietf-quic-tls-27 */
+-# define TLSEXT_TYPE_quic_transport_parameters   0xffa5
++# define TLSEXT_TYPE_quic_transport_parameters_draft   0xffa5
++# define TLSEXT_TYPE_quic_transport_parameters         0x0039
+ 
+ # ifndef OPENSSL_NO_NEXTPROTONEG
+ /* This is not an IANA defined extension number */
+diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
+index 0c4d1c1332..ca981ac62b 100644
+--- a/ssl/ssl_err.c
++++ b/ssl/ssl_err.c
+@@ -242,6 +242,8 @@ static const ERR_STRING_DATA SSL_str_reasons[] = {
+     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_PARAMETERS), "missing parameters"},
+     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_PSK_KEX_MODES_EXTENSION),
+     "missing psk kex modes extension"},
++    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_QUIC_TRANSPORT_PARAMETERS_EXTENSION),
++    "missing quic transport parameters extension"},
+     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_RSA_CERTIFICATE),
+     "missing rsa certificate"},
+     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_RSA_ENCRYPTING_CERT),
+diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
+index a78ebd55af..1aaef74ef0 100644
+--- a/ssl/ssl_lib.c
++++ b/ssl/ssl_lib.c
+@@ -1247,6 +1247,7 @@ void SSL_free(SSL *s)
+ 
+ #ifndef OPENSSL_NO_QUIC
+     OPENSSL_free(s->ext.quic_transport_params);
++    OPENSSL_free(s->ext.peer_quic_transport_params_draft);
+     OPENSSL_free(s->ext.peer_quic_transport_params);
+     BUF_MEM_free(s->quic_buf);
+     while (s->quic_input_data_head != NULL) {
+diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h
+index d99b751bfc..9bbc528dd9 100644
+--- a/ssl/ssl_local.h
++++ b/ssl/ssl_local.h
+@@ -773,6 +773,7 @@ typedef enum tlsext_index_en {
+     TLSEXT_IDX_cryptopro_bug,
+     TLSEXT_IDX_early_data,
+     TLSEXT_IDX_certificate_authorities,
++    TLSEXT_IDX_quic_transport_params_draft,
+     TLSEXT_IDX_quic_transport_params,
+     TLSEXT_IDX_padding,
+     TLSEXT_IDX_psk,
+@@ -1712,6 +1713,8 @@ struct ssl_st {
+ #ifndef OPENSSL_NO_QUIC
+         uint8_t *quic_transport_params;
+         size_t quic_transport_params_len;
++        uint8_t *peer_quic_transport_params_draft;
++        size_t peer_quic_transport_params_draft_len;
+         uint8_t *peer_quic_transport_params;
+         size_t peer_quic_transport_params_len;
+ #endif
+@@ -1722,6 +1725,14 @@ struct ssl_st {
+     OSSL_ENCRYPTION_LEVEL quic_write_level;
+     OSSL_ENCRYPTION_LEVEL quic_latest_level_received;
+     BUF_MEM *quic_buf;          /* buffer incoming handshake messages */
++    /*
++     * defaults to 0, but can be set to:
++     * - TLSEXT_TYPE_quic_transport_parameters_draft
++     * - TLSEXT_TYPE_quic_transport_parameters
++     * Client: if 0, send both
++     * Server: if 0, use same version as client sent
++     */
++    int quic_transport_version;
+     QUIC_DATA *quic_input_data_head;
+     QUIC_DATA *quic_input_data_tail;
+     size_t quic_next_record_start;
+diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c
+index 136d2b8460..971af0f4c5 100644
+--- a/ssl/ssl_quic.c
++++ b/ssl/ssl_quic.c
+@@ -35,8 +35,45 @@ void SSL_get_peer_quic_transport_params(const SSL *ssl,
+                                         const uint8_t **out_params,
+                                         size_t *out_params_len)
+ {
+-    *out_params = ssl->ext.peer_quic_transport_params;
+-    *out_params_len = ssl->ext.peer_quic_transport_params_len;
++    if (ssl->ext.peer_quic_transport_params_len) {
++        *out_params = ssl->ext.peer_quic_transport_params;
++        *out_params_len = ssl->ext.peer_quic_transport_params_len;
++    } else {
++        *out_params = ssl->ext.peer_quic_transport_params_draft;
++        *out_params_len = ssl->ext.peer_quic_transport_params_draft_len;
++    }
++}
++
++/* Returns the negotiated version, or -1 on error */
++int SSL_get_peer_quic_transport_version(const SSL *ssl)
++{
++    if (ssl->ext.peer_quic_transport_params_len != 0
++            && ssl->ext.peer_quic_transport_params_draft_len != 0)
++        return -1;
++    if (ssl->ext.peer_quic_transport_params_len != 0)
++        return TLSEXT_TYPE_quic_transport_parameters;
++    if (ssl->ext.peer_quic_transport_params_draft_len != 0)
++        return TLSEXT_TYPE_quic_transport_parameters_draft;
++
++    return -1;
++}
++
++void SSL_set_quic_use_legacy_codepoint(SSL *ssl, int use_legacy)
++{
++    if (use_legacy)
++        ssl->quic_transport_version = TLSEXT_TYPE_quic_transport_parameters_draft;
++    else
++        ssl->quic_transport_version = TLSEXT_TYPE_quic_transport_parameters;
++}
++
++void SSL_set_quic_transport_version(SSL *ssl, int version)
++{
++    ssl->quic_transport_version = version;
++}
++
++int SSL_get_quic_transport_version(const SSL *ssl)
++{
++    return ssl->quic_transport_version;
+ }
+ 
+ size_t SSL_quic_max_handshake_flight_len(const SSL *ssl, OSSL_ENCRYPTION_LEVEL level)
+diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c
+index 548772be6d..34ba69e85e 100644
+--- a/ssl/statem/extensions.c
++++ b/ssl/statem/extensions.c
+@@ -60,6 +60,7 @@ static int init_post_handshake_auth(SSL *s, unsigned int context);
+ static int final_psk(SSL *s, unsigned int context, int sent);
+ #ifndef OPENSSL_NO_QUIC
+ static int init_quic_transport_params(SSL *s, unsigned int context);
++static int final_quic_transport_params_draft(SSL *s, unsigned int context, int sent);
+ static int final_quic_transport_params(SSL *s, unsigned int context, int sent);
+ #endif
+ 
+@@ -374,6 +375,15 @@ static const EXTENSION_DEFINITION ext_defs[] = {
+         tls_construct_certificate_authorities, NULL,
+     },
+ #ifndef OPENSSL_NO_QUIC
++    {
++        TLSEXT_TYPE_quic_transport_parameters_draft,
++        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS
++        | SSL_EXT_TLS_IMPLEMENTATION_ONLY | SSL_EXT_TLS1_3_ONLY,
++        init_quic_transport_params,
++        tls_parse_ctos_quic_transport_params_draft, tls_parse_stoc_quic_transport_params_draft,
++        tls_construct_stoc_quic_transport_params_draft, tls_construct_ctos_quic_transport_params_draft,
++        final_quic_transport_params_draft,
++    },
+     {
+         TLSEXT_TYPE_quic_transport_parameters,
+         SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS
+@@ -1748,8 +1758,37 @@ static int init_quic_transport_params(SSL *s, unsigned int context)
+     return 1;
+ }
+ 
++static int final_quic_transport_params_draft(SSL *s, unsigned int context,
++                                             int sent)
++{
++    return 1;
++}
++
+ static int final_quic_transport_params(SSL *s, unsigned int context, int sent)
+ {
++    /* called after final_quic_transport_params_draft */
++    if (SSL_IS_QUIC(s)) {
++        if (s->ext.peer_quic_transport_params_len == 0
++                && s->ext.peer_quic_transport_params_draft_len == 0) {
++            SSLfatal(s, SSL_AD_MISSING_EXTENSION,
++                     SSL_R_MISSING_QUIC_TRANSPORT_PARAMETERS_EXTENSION);
++            return 0;
++        }
++        /* if we got both, discard the one we can't use */
++        if (s->ext.peer_quic_transport_params_len != 0
++                && s->ext.peer_quic_transport_params_draft_len != 0) {
++            if (s->quic_transport_version == TLSEXT_TYPE_quic_transport_parameters_draft) {
++                OPENSSL_free(s->ext.peer_quic_transport_params);
++                s->ext.peer_quic_transport_params = NULL;
++                s->ext.peer_quic_transport_params_len = 0;
++            } else {
++                OPENSSL_free(s->ext.peer_quic_transport_params_draft);
++                s->ext.peer_quic_transport_params_draft = NULL;
++                s->ext.peer_quic_transport_params_draft_len = 0;
++            }
++        }
++    }
++
+     return 1;
+ }
+ #endif
+diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c
+index 06ccd855a0..6da3cc560f 100644
+--- a/ssl/statem/extensions_clnt.c
++++ b/ssl/statem/extensions_clnt.c
+@@ -1197,13 +1197,33 @@ EXT_RETURN tls_construct_ctos_post_handshake_auth(SSL *s, WPACKET *pkt,
+ }
+ 
+ #ifndef OPENSSL_NO_QUIC
+-/* SAME AS tls_construct_stoc_quic_transport_params() */
++EXT_RETURN tls_construct_ctos_quic_transport_params_draft(SSL *s, WPACKET *pkt,
++                                                          unsigned int context, X509 *x,
++                                                          size_t chainidx)
++{
++    if (s->quic_transport_version == TLSEXT_TYPE_quic_transport_parameters
++            || s->ext.quic_transport_params == NULL
++            || s->ext.quic_transport_params_len == 0) {
++        return EXT_RETURN_NOT_SENT;
++    }
++
++    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_quic_transport_parameters_draft)
++        || !WPACKET_sub_memcpy_u16(pkt, s->ext.quic_transport_params,
++                                   s->ext.quic_transport_params_len)) {
++        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
++        return EXT_RETURN_FAIL;
++    }
++
++    return EXT_RETURN_SENT;
++}
++
+ EXT_RETURN tls_construct_ctos_quic_transport_params(SSL *s, WPACKET *pkt,
+                                                     unsigned int context, X509 *x,
+                                                     size_t chainidx)
+ {
+-    if (s->ext.quic_transport_params == NULL
+-        || s->ext.quic_transport_params_len == 0) {
++    if (s->quic_transport_version == TLSEXT_TYPE_quic_transport_parameters_draft
++            || s->ext.quic_transport_params == NULL
++            || s->ext.quic_transport_params_len == 0) {
+         return EXT_RETURN_NOT_SENT;
+     }
+ 
+@@ -2013,7 +2033,23 @@ int tls_parse_stoc_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+     return 1;
+ }
+ #ifndef OPENSSL_NO_QUIC
+-/* SAME AS tls_parse_ctos_quic_transport_params() */
++int tls_parse_stoc_quic_transport_params_draft(SSL *s, PACKET *pkt,
++                                               unsigned int context, X509 *x,
++                                               size_t chainidx)
++{
++    OPENSSL_free(s->ext.peer_quic_transport_params_draft);
++    s->ext.peer_quic_transport_params_draft = NULL;
++    s->ext.peer_quic_transport_params_draft_len = 0;
++
++    if (!PACKET_memdup(pkt,
++                       &s->ext.peer_quic_transport_params_draft,
++                       &s->ext.peer_quic_transport_params_draft_len)) {
++        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
++        return 0;
++    }
++    return 1;
++}
++
+ int tls_parse_stoc_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context,
+                                          X509 *x, size_t chainidx)
+ {
+diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c
+index e3277f685f..bfab225651 100644
+--- a/ssl/statem/extensions_srvr.c
++++ b/ssl/statem/extensions_srvr.c
+@@ -1233,7 +1233,22 @@ int tls_parse_ctos_post_handshake_auth(SSL *s, PACKET *pkt,
+ }
+ 
+ #ifndef OPENSSL_NO_QUIC
+-/* SAME AS tls_parse_stoc_quic_transport_params() */
++int tls_parse_ctos_quic_transport_params_draft(SSL *s, PACKET *pkt, unsigned int context,
++                                               X509 *x, size_t chainidx)
++{
++    OPENSSL_free(s->ext.peer_quic_transport_params_draft);
++    s->ext.peer_quic_transport_params_draft = NULL;
++    s->ext.peer_quic_transport_params_draft_len = 0;
++
++    if (!PACKET_memdup(pkt,
++                       &s->ext.peer_quic_transport_params_draft,
++                       &s->ext.peer_quic_transport_params_draft_len)) {
++        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
++        return 0;
++    }
++    return 1;
++}
++
+ int tls_parse_ctos_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context,
+                                          X509 *x, size_t chainidx)
+ {
+@@ -1943,13 +1958,36 @@ EXT_RETURN tls_construct_stoc_psk(SSL *s, WPACKET *pkt, unsigned int context,
+ }
+ 
+ #ifndef OPENSSL_NO_QUIC
+-/* SAME AS tls_construct_ctos_quic_transport_params() */
++EXT_RETURN tls_construct_stoc_quic_transport_params_draft(SSL *s, WPACKET *pkt,
++                                                          unsigned int context,
++                                                          X509 *x,
++                                                          size_t chainidx)
++{
++    if (s->quic_transport_version == TLSEXT_TYPE_quic_transport_parameters
++            || s->ext.peer_quic_transport_params_draft_len == 0
++            || s->ext.quic_transport_params == NULL
++            || s->ext.quic_transport_params_len == 0) {
++        return EXT_RETURN_NOT_SENT;
++    }
++
++    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_quic_transport_parameters_draft)
++        || !WPACKET_sub_memcpy_u16(pkt, s->ext.quic_transport_params,
++                                   s->ext.quic_transport_params_len)) {
++        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
++        return EXT_RETURN_FAIL;
++    }
++
++    return EXT_RETURN_SENT;
++}
++
+ EXT_RETURN tls_construct_stoc_quic_transport_params(SSL *s, WPACKET *pkt,
+                                                     unsigned int context, X509 *x,
+                                                     size_t chainidx)
+ {
+-    if (s->ext.quic_transport_params == NULL
+-        || s->ext.quic_transport_params_len == 0) {
++    if (s->quic_transport_version == TLSEXT_TYPE_quic_transport_parameters_draft
++            || s->ext.peer_quic_transport_params_len == 0
++            || s->ext.quic_transport_params == NULL
++            || s->ext.quic_transport_params_len == 0) {
+         return EXT_RETURN_NOT_SENT;
+     }
+ 
+diff --git a/ssl/statem/statem_local.h b/ssl/statem/statem_local.h
+index 6d5820e2cf..0065db1744 100644
+--- a/ssl/statem/statem_local.h
++++ b/ssl/statem/statem_local.h
+@@ -255,6 +255,10 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+ int tls_parse_ctos_post_handshake_auth(SSL *, PACKET *pkt, unsigned int context,
+                                        X509 *x, size_t chainidx);
+ #ifndef OPENSSL_NO_QUIC
++int tls_parse_ctos_quic_transport_params_draft(SSL *s, PACKET *pkt,
++                                               unsigned int context, X509 *x,
++                                               size_t chainidx);
++
+ int tls_parse_ctos_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context,
+                                          X509 *x, size_t chainidx);
+ #endif
+@@ -319,6 +323,11 @@ EXT_RETURN tls_construct_stoc_cryptopro_bug(SSL *s, WPACKET *pkt,
+ EXT_RETURN tls_construct_stoc_psk(SSL *s, WPACKET *pkt, unsigned int context,
+                                   X509 *x, size_t chainidx);
+ #ifndef OPENSSL_NO_QUIC
++EXT_RETURN tls_construct_stoc_quic_transport_params_draft(SSL *s, WPACKET *pkt,
++                                                          unsigned int context,
++                                                          X509 *x,
++                                                          size_t chainidx);
++
+ EXT_RETURN tls_construct_stoc_quic_transport_params(SSL *s, WPACKET *pkt,
+                                                     unsigned int context, X509 *x,
+                                                     size_t chainidx);
+@@ -393,6 +402,10 @@ EXT_RETURN tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context,
+ EXT_RETURN tls_construct_ctos_post_handshake_auth(SSL *s, WPACKET *pkt, unsigned int context,
+                                                   X509 *x, size_t chainidx);
+ #ifndef OPENSSL_NO_QUIC
++EXT_RETURN tls_construct_ctos_quic_transport_params_draft(SSL *s, WPACKET *pkt,
++                                                          unsigned int context, X509 *x,
++                                                          size_t chainidx);
++
+ EXT_RETURN tls_construct_ctos_quic_transport_params(SSL *s, WPACKET *pkt,
+                                                     unsigned int context, X509 *x,
+                                                     size_t chainidx);
+@@ -441,6 +454,10 @@ int tls_parse_stoc_cookie(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+ int tls_parse_stoc_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                        size_t chainidx);
+ #ifndef OPENSSL_NO_QUIC
++int tls_parse_stoc_quic_transport_params_draft(SSL *s, PACKET *pkt,
++                                               unsigned int context, X509 *x,
++                                               size_t chainidx);
++
+ int tls_parse_stoc_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context,
+                                          X509 *x, size_t chainidx);
+ #endif
+diff --git a/test/sslapitest.c b/test/sslapitest.c
+index bc908dd382..bede6e839b 100644
+--- a/test/sslapitest.c
++++ b/test/sslapitest.c
+@@ -10182,7 +10182,13 @@ static SSL_QUIC_METHOD quic_method = {
+     test_quic_send_alert,
+ };
+ 
+-static int test_quic_api(void)
++static int test_quic_api_set_versions(SSL *ssl, int ver)
++{
++    SSL_set_quic_transport_version(ssl, ver);
++    return 1;
++}
++
++static int test_quic_api_version(int clnt, int srvr)
+ {
+     SSL_CTX *cctx = NULL, *sctx = NULL;
+     SSL *clientssl = NULL, *serverssl = NULL;
+@@ -10193,29 +10199,7 @@ static int test_quic_api(void)
+     const uint8_t *peer_str;
+     size_t peer_str_len;
+ 
+-    /* Clean up logging space */
+-    memset(client_log_buffer, 0, sizeof(client_log_buffer));
+-    memset(server_log_buffer, 0, sizeof(server_log_buffer));
+-    client_log_buffer_index = 0;
+-    server_log_buffer_index = 0;
+-    error_writing_log = 0;
+-
+-
+-    if (!TEST_ptr(sctx = SSL_CTX_new_ex(libctx, NULL, TLS_server_method()))
+-            || !TEST_true(SSL_CTX_set_quic_method(sctx, &quic_method))
+-            || !TEST_ptr(sctx->quic_method)
+-            || !TEST_ptr(serverssl = SSL_new(sctx))
+-            || !TEST_true(SSL_IS_QUIC(serverssl))
+-            || !TEST_true(SSL_set_quic_method(serverssl, NULL))
+-            || !TEST_false(SSL_IS_QUIC(serverssl))
+-            || !TEST_true(SSL_set_quic_method(serverssl, &quic_method))
+-            || !TEST_true(SSL_IS_QUIC(serverssl)))
+-        goto end;
+-
+-    SSL_CTX_free(sctx);
+-    sctx = NULL;
+-    SSL_free(serverssl);
+-    serverssl = NULL;
++    TEST_info("original clnt=0x%X, srvr=0x%X\n", clnt, srvr);
+ 
+     if (!TEST_true(create_ssl_ctx_pair(libctx,
+                                        TLS_server_method(),
+@@ -10234,6 +10218,8 @@ static int test_quic_api(void)
+                                                         sizeof(client_str)))
+             || !TEST_true(SSL_set_app_data(serverssl, clientssl))
+             || !TEST_true(SSL_set_app_data(clientssl, serverssl))
++            || !TEST_true(test_quic_api_set_versions(clientssl, clnt))
++            || !TEST_true(test_quic_api_set_versions(serverssl, srvr))
+             || !TEST_true(create_ssl_connection(serverssl, clientssl,
+                                                 SSL_ERROR_NONE))
+             || !TEST_true(SSL_version(serverssl) == TLS1_3_VERSION)
+@@ -10267,6 +10253,19 @@ static int test_quic_api(void)
+             || !TEST_int_le(SSL_do_handshake(serverssl), 0))
+         goto end;
+ 
++    TEST_info("original clnt=0x%X, srvr=0x%X\n", clnt, srvr);
++    if (srvr == 0 && clnt == 0)
++        srvr = clnt = TLSEXT_TYPE_quic_transport_parameters;
++    else if (srvr == 0)
++        srvr = clnt;
++    else if (clnt == 0)
++        clnt = srvr;
++    TEST_info("expected clnt=0x%X, srvr=0x%X\n", clnt, srvr);
++    if (!TEST_int_eq(SSL_get_peer_quic_transport_version(serverssl), clnt))
++        goto end;
++    if (!TEST_int_eq(SSL_get_peer_quic_transport_version(clientssl), srvr))
++        goto end;
++
+     testresult = 1;
+ 
+  end:
+@@ -10277,6 +10276,67 @@ static int test_quic_api(void)
+ 
+     return testresult;
+ }
++
++static int test_quic_api(int tst)
++{
++    SSL_CTX *sctx = NULL;
++    SSL *serverssl = NULL;
++    int testresult = 0;
++    static int clnt_params[] = { 0,
++                                 TLSEXT_TYPE_quic_transport_parameters_draft,
++                                 TLSEXT_TYPE_quic_transport_parameters,
++                                 0,
++                                 TLSEXT_TYPE_quic_transport_parameters_draft,
++                                 TLSEXT_TYPE_quic_transport_parameters,
++                                 0,
++                                 TLSEXT_TYPE_quic_transport_parameters_draft,
++                                 TLSEXT_TYPE_quic_transport_parameters };
++    static int srvr_params[] = { 0,
++                                 0,
++                                 0,
++                                 TLSEXT_TYPE_quic_transport_parameters_draft,
++                                 TLSEXT_TYPE_quic_transport_parameters_draft,
++                                 TLSEXT_TYPE_quic_transport_parameters_draft,
++                                 TLSEXT_TYPE_quic_transport_parameters,
++                                 TLSEXT_TYPE_quic_transport_parameters,
++                                 TLSEXT_TYPE_quic_transport_parameters };
++    static int results[] = { 1, 1, 1, 1, 1, 0, 1, 0, 1 };
++
++    /* Failure cases:
++     * test 6/[5] clnt = parameters, srvr = draft
++     * test 8/[7] clnt = draft, srvr = parameters
++     */
++
++    /* Clean up logging space */
++    memset(client_log_buffer, 0, sizeof(client_log_buffer));
++    memset(server_log_buffer, 0, sizeof(server_log_buffer));
++    client_log_buffer_index = 0;
++    server_log_buffer_index = 0;
++    error_writing_log = 0;
++
++    if (!TEST_ptr(sctx = SSL_CTX_new_ex(libctx, NULL, TLS_server_method()))
++            || !TEST_true(SSL_CTX_set_quic_method(sctx, &quic_method))
++            || !TEST_ptr(sctx->quic_method)
++            || !TEST_ptr(serverssl = SSL_new(sctx))
++            || !TEST_true(SSL_IS_QUIC(serverssl))
++            || !TEST_true(SSL_set_quic_method(serverssl, NULL))
++            || !TEST_false(SSL_IS_QUIC(serverssl))
++            || !TEST_true(SSL_set_quic_method(serverssl, &quic_method))
++            || !TEST_true(SSL_IS_QUIC(serverssl)))
++        goto end;
++
++    if (!TEST_int_eq(test_quic_api_version(clnt_params[tst], srvr_params[tst]), results[tst]))
++        goto end;
++
++    testresult = 1;
++
++end:
++    SSL_CTX_free(sctx);
++    sctx = NULL;
++    SSL_free(serverssl);
++    serverssl = NULL;
++    return testresult;
++}
+ #endif /* OPENSSL_NO_QUIC */
+ 
+ #ifndef OSSL_NO_USABLE_TLS1_3
+@@ -11054,7 +11114,7 @@ int setup_tests(void)
+ #endif
+     ADD_ALL_TESTS(test_handshake_retry, 16);
+ #ifndef OPENSSL_NO_QUIC
+-    ADD_TEST(test_quic_api);
++    ADD_ALL_TESTS(test_quic_api, 9);
+ #endif
+     return 1;
+ 
+diff --git a/util/libssl.num b/util/libssl.num
+index da35cf2970..41ebba40b2 100644
+--- a/util/libssl.num
++++ b/util/libssl.num
+@@ -531,3 +531,7 @@ SSL_set_quic_method                     20007	3_0_0	EXIST::FUNCTION:QUIC
+ SSL_quic_max_handshake_flight_len       20008	3_0_0	EXIST::FUNCTION:QUIC
+ SSL_process_quic_post_handshake         20009	3_0_0	EXIST::FUNCTION:QUIC
+ SSL_provide_quic_data                   20010	3_0_0	EXIST::FUNCTION:QUIC
++SSL_set_quic_use_legacy_codepoint       20011	3_0_0	EXIST::FUNCTION:QUIC
++SSL_set_quic_transport_version          20012	3_0_0	EXIST::FUNCTION:QUIC
++SSL_get_peer_quic_transport_version     20013	3_0_0	EXIST::FUNCTION:QUIC
++SSL_get_quic_transport_version          20014	3_0_0	EXIST::FUNCTION:QUIC
+-- 
+2.42.0
+
diff --git a/0027-QUIC-return-success-when-no-post-handshake-data.patch b/0027-QUIC-return-success-when-no-post-handshake-data.patch
new file mode 100644
index 0000000..cf8278b
--- /dev/null
+++ b/0027-QUIC-return-success-when-no-post-handshake-data.patch
@@ -0,0 +1,27 @@
+From 3ff0ba16566c029c1f5cf4d6bf5584e95b0661bb Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Tue, 5 Jan 2021 13:50:21 -0500
+Subject: [PATCH 27/63] QUIC: return success when no post-handshake data
+
+---
+ ssl/ssl_quic.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c
+index 971af0f4c5..477a386da3 100644
+--- a/ssl/ssl_quic.c
++++ b/ssl/ssl_quic.c
+@@ -309,6 +309,10 @@ int SSL_process_quic_post_handshake(SSL *ssl)
+         return 0;
+     }
+ 
++    /* if there is no data, return success as BoringSSL */
++    if (ssl->quic_input_data_head == NULL)
++        return 1;
++    
+     /*
+      * This is always safe (we are sure to be at a record boundary) because
+      * SSL_read()/SSL_write() are never used for QUIC connections -- the
+-- 
+2.42.0
+
diff --git a/0028-QUIC-__owur-makes-no-sense-for-void-return-values.patch b/0028-QUIC-__owur-makes-no-sense-for-void-return-values.patch
new file mode 100644
index 0000000..6626dc0
--- /dev/null
+++ b/0028-QUIC-__owur-makes-no-sense-for-void-return-values.patch
@@ -0,0 +1,25 @@
+From 9956f99908da7a53e4be8fbeb6cdc539546b0549 Mon Sep 17 00:00:00 2001
+From: Benjamin Kaduk <bkaduk@akamai.com>
+Date: Fri, 15 Jan 2021 15:04:00 -0800
+Subject: [PATCH 28/63] QUIC: __owur makes no sense for void return values
+
+---
+ include/openssl/ssl.h.in | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/include/openssl/ssl.h.in b/include/openssl/ssl.h.in
+index e221ebbb41..289f55feb1 100644
+--- a/include/openssl/ssl.h.in
++++ b/include/openssl/ssl.h.in
+@@ -2566,7 +2566,7 @@ __owur int SSL_process_quic_post_handshake(SSL *ssl);
+ __owur int SSL_is_quic(SSL *ssl);
+ 
+ /* BoringSSL API */
+-__owur void SSL_set_quic_use_legacy_codepoint(SSL *ssl, int use_legacy);
++void SSL_set_quic_use_legacy_codepoint(SSL *ssl, int use_legacy);
+ 
+ /*
+  * Set an explicit value that you want to use
+-- 
+2.42.0
+
diff --git a/0029-QUIC-remove-SSL_R_BAD_DATA_LENGTH-unused.patch b/0029-QUIC-remove-SSL_R_BAD_DATA_LENGTH-unused.patch
new file mode 100644
index 0000000..5e189fc
--- /dev/null
+++ b/0029-QUIC-remove-SSL_R_BAD_DATA_LENGTH-unused.patch
@@ -0,0 +1,50 @@
+From 43a80891c0e95614481d6f25e21922813d76f0b7 Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Fri, 19 Feb 2021 10:12:15 -0500
+Subject: [PATCH 29/63] QUIC: remove SSL_R_BAD_DATA_LENGTH (unused)
+
+---
+ crypto/err/openssl.txt   | 1 -
+ include/openssl/sslerr.h | 1 -
+ ssl/ssl_err.c            | 1 -
+ 3 files changed, 3 deletions(-)
+
+diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
+index 0394c10077..3ad6ccf87c 100644
+--- a/crypto/err/openssl.txt
++++ b/crypto/err/openssl.txt
+@@ -1262,7 +1262,6 @@ SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE:158:\
+ SSL_R_BAD_CHANGE_CIPHER_SPEC:103:bad change cipher spec
+ SSL_R_BAD_CIPHER:186:bad cipher
+ SSL_R_BAD_DATA:390:bad data
+-SSL_R_BAD_DATA_LENGTH:802:bad data length
+ SSL_R_BAD_DATA_RETURNED_BY_CALLBACK:106:bad data returned by callback
+ SSL_R_BAD_DECOMPRESSION:107:bad decompression
+ SSL_R_BAD_DH_VALUE:102:bad dh value
+diff --git a/include/openssl/sslerr.h b/include/openssl/sslerr.h
+index 058ef308d8..2281d68bb3 100644
+--- a/include/openssl/sslerr.h
++++ b/include/openssl/sslerr.h
+@@ -28,7 +28,6 @@
+ # define SSL_R_BAD_CHANGE_CIPHER_SPEC                     103
+ # define SSL_R_BAD_CIPHER                                 186
+ # define SSL_R_BAD_DATA                                   390
+-# define SSL_R_BAD_DATA_LENGTH                            802
+ # define SSL_R_BAD_DATA_RETURNED_BY_CALLBACK              106
+ # define SSL_R_BAD_DECOMPRESSION                          107
+ # define SSL_R_BAD_DH_VALUE                               102
+diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
+index ca981ac62b..4635c82fd1 100644
+--- a/ssl/ssl_err.c
++++ b/ssl/ssl_err.c
+@@ -27,7 +27,6 @@ static const ERR_STRING_DATA SSL_str_reasons[] = {
+     "bad change cipher spec"},
+     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_CIPHER), "bad cipher"},
+     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DATA), "bad data"},
+-    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DATA_LENGTH), "bad data length"},
+     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DATA_RETURNED_BY_CALLBACK),
+     "bad data returned by callback"},
+     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DECOMPRESSION), "bad decompression"},
+-- 
+2.42.0
+
diff --git a/0030-QUIC-Update-shared-library-version.patch b/0030-QUIC-Update-shared-library-version.patch
new file mode 100644
index 0000000..ff9e1f0
--- /dev/null
+++ b/0030-QUIC-Update-shared-library-version.patch
@@ -0,0 +1,11 @@
+diff -up openssl-3.1.3/VERSION.dat.31~ openssl-3.1.3/VERSION.dat
+--- openssl-3.1.3/VERSION.dat.31~	2023-09-21 16:47:49.935369218 +0200
++++ openssl-3.1.3/VERSION.dat	2023-09-21 16:48:44.834220109 +0200
+@@ -2,6 +2,6 @@ MAJOR=3
+ MINOR=1
+ PATCH=5
+ PRE_RELEASE_TAG=
+-BUILD_METADATA=
++BUILD_METADATA=quic
+ RELEASE_DATE="30 Jan 2024"
+ SHLIB_VERSION=3
diff --git a/0032-QUIC-Fix-3.0.0-GitHub-CI.patch b/0032-QUIC-Fix-3.0.0-GitHub-CI.patch
new file mode 100644
index 0000000..413b5e7
--- /dev/null
+++ b/0032-QUIC-Fix-3.0.0-GitHub-CI.patch
@@ -0,0 +1,42 @@
+From 10be9c95b8b73238c736879371103d3fbd9be365 Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Wed, 3 Mar 2021 17:32:31 -0500
+Subject: [PATCH 32/63] QUIC: Fix 3.0.0 GitHub CI
+
+---
+ test/sslapitest.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/test/sslapitest.c b/test/sslapitest.c
+index bede6e839b..f65878212c 100644
+--- a/test/sslapitest.c
++++ b/test/sslapitest.c
+@@ -10212,10 +10212,10 @@ static int test_quic_api_version(int clnt, int srvr)
+                                              &clientssl, NULL, NULL))
+             || !TEST_true(SSL_set_quic_transport_params(serverssl,
+                                                         (unsigned char*)server_str,
+-                                                        sizeof(server_str)))
++                                                        strlen(server_str)+1))
+             || !TEST_true(SSL_set_quic_transport_params(clientssl,
+                                                         (unsigned char*)client_str,
+-                                                        sizeof(client_str)))
++                                                        strlen(client_str)+1))
+             || !TEST_true(SSL_set_app_data(serverssl, clientssl))
+             || !TEST_true(SSL_set_app_data(clientssl, serverssl))
+             || !TEST_true(test_quic_api_set_versions(clientssl, clnt))
+@@ -10231,10 +10231,10 @@ static int test_quic_api_version(int clnt, int srvr)
+         goto end;
+ 
+     SSL_get_peer_quic_transport_params(serverssl, &peer_str, &peer_str_len);
+-    if (!TEST_mem_eq(peer_str, peer_str_len, client_str, sizeof(client_str)))
++    if (!TEST_mem_eq(peer_str, peer_str_len, client_str, strlen(client_str)+1))
+         goto end;
+     SSL_get_peer_quic_transport_params(clientssl, &peer_str, &peer_str_len);
+-    if (!TEST_mem_eq(peer_str, peer_str_len, server_str, sizeof(server_str)))
++    if (!TEST_mem_eq(peer_str, peer_str_len, server_str, strlen(server_str)+1))
+         goto end;
+ 
+     /* Deal with two NewSessionTickets */
+-- 
+2.42.0
+
diff --git a/0033-QUIC-SSLerr-ERR_raise-ERR_LIB_SSL.patch b/0033-QUIC-SSLerr-ERR_raise-ERR_LIB_SSL.patch
new file mode 100644
index 0000000..93c1e68
--- /dev/null
+++ b/0033-QUIC-SSLerr-ERR_raise-ERR_LIB_SSL.patch
@@ -0,0 +1,165 @@
+From c94831f012a90483021a5c6bd8ab58797104b467 Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Wed, 3 Mar 2021 17:43:46 -0500
+Subject: [PATCH 33/63] QUIC: SSLerr() -> ERR_raise(ERR_LIB_SSL)
+
+---
+ ssl/s3_msg.c            |  2 +-
+ ssl/ssl_lib.c           |  6 +++---
+ ssl/ssl_quic.c          | 17 ++++++++---------
+ ssl/statem/statem.c     |  2 +-
+ ssl/statem/statem_lib.c |  4 ++--
+ 5 files changed, 15 insertions(+), 16 deletions(-)
+
+diff --git a/ssl/s3_msg.c b/ssl/s3_msg.c
+index 667c5385e8..dd2fe040e0 100644
+--- a/ssl/s3_msg.c
++++ b/ssl/s3_msg.c
+@@ -85,7 +85,7 @@ int ssl3_dispatch_alert(SSL *s)
+     if (SSL_IS_QUIC(s)) {
+         if (!s->quic_method->send_alert(s, s->quic_write_level,
+                                         s->s3.send_alert[1])) {
+-            SSLerr(SSL_F_SSL3_DISPATCH_ALERT, ERR_R_INTERNAL_ERROR);
++            ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
+             return 0;
+         }
+         i = 1;
+diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
+index 1aaef74ef0..517104a4df 100644
+--- a/ssl/ssl_lib.c
++++ b/ssl/ssl_lib.c
+@@ -1854,7 +1854,7 @@ int ssl_read_internal(SSL *s, void *buf, size_t num, size_t *readbytes)
+ {
+ #ifndef OPENSSL_NO_QUIC
+     if (SSL_IS_QUIC(s)) {
+-        SSLerr(SSL_F_SSL_READ_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+         return -1;
+     }
+ #endif
+@@ -1991,7 +1991,7 @@ static int ssl_peek_internal(SSL *s, void *buf, size_t num, size_t *readbytes)
+ {
+ #ifndef OPENSSL_NO_QUIC
+     if (SSL_IS_QUIC(s)) {
+-        SSLerr(SSL_F_SSL_PEEK_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+         return -1;
+     }
+ #endif
+@@ -2057,7 +2057,7 @@ int ssl_write_internal(SSL *s, const void *buf, size_t num, size_t *written)
+ {
+ #ifndef OPENSSL_NO_QUIC
+     if (SSL_IS_QUIC(s)) {
+-        SSLerr(SSL_F_SSL_WRITE_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+         return -1;
+     }
+ #endif
+diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c
+index 477a386da3..d50b1247a6 100644
+--- a/ssl/ssl_quic.c
++++ b/ssl/ssl_quic.c
+@@ -131,7 +131,7 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
+     size_t l, offset;
+ 
+     if (!SSL_IS_QUIC(ssl)) {
+-        SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+         return 0;
+     }
+ 
+@@ -139,18 +139,18 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
+     if (level < ssl->quic_read_level
+             || (ssl->quic_input_data_tail != NULL && level < ssl->quic_input_data_tail->level)
+             || level < ssl->quic_latest_level_received) {
+-        SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED);
++        ERR_raise(ERR_LIB_SSL, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED);
+         return 0;
+     }
+ 
+     if (ssl->quic_buf == NULL) {
+         BUF_MEM *buf;
+         if ((buf = BUF_MEM_new()) == NULL) {
+-            SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR);
++            ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
+             return 0;
+         }
+         if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) {
+-            SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR);
++            ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
+             BUF_MEM_free(buf);
+             return 0;
+         }
+@@ -163,15 +163,14 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
+     /* A TLS message must not cross an encryption level boundary */
+     if (ssl->quic_buf->length != ssl->quic_next_record_start
+             && level != ssl->quic_latest_level_received) {
+-        SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA,
+-               SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED);
++        ERR_raise(ERR_LIB_SSL, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED);
+         return 0;
+     }
+     ssl->quic_latest_level_received = level;
+ 
+     offset = ssl->quic_buf->length;
+     if (!BUF_MEM_grow(ssl->quic_buf, offset + len)) {
+-        SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR);
++        ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
+         return 0;
+     }
+     memcpy(ssl->quic_buf->data + offset, data, len);
+@@ -193,7 +192,7 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
+ 
+         qd = OPENSSL_zalloc(sizeof(*qd));
+         if (qd == NULL) {
+-            SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR);
++            ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
+             return 0;
+         }
+ 
+@@ -305,7 +304,7 @@ int SSL_process_quic_post_handshake(SSL *ssl)
+     int ret;
+ 
+     if (SSL_in_init(ssl) || !SSL_IS_QUIC(ssl)) {
+-        SSLerr(SSL_F_SSL_PROCESS_QUIC_POST_HANDSHAKE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++        ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+         return 0;
+     }
+ 
+diff --git a/ssl/statem/statem.c b/ssl/statem/statem.c
+index b040d14cd2..df542579d0 100644
+--- a/ssl/statem/statem.c
++++ b/ssl/statem/statem.c
+@@ -930,7 +930,7 @@ int statem_flush(SSL *s)
+ #ifndef OPENSSL_NO_QUIC
+     if (SSL_IS_QUIC(s)) {
+         if (!s->quic_method->flush_flight(s)) {
+-            SSLerr(SSL_F_STATEM_FLUSH, ERR_R_INTERNAL_ERROR);
++            ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
+             return 0;
+         }
+     } else
+diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c
+index 9c9ac0eda6..877ffa5cb9 100644
+--- a/ssl/statem/statem_lib.c
++++ b/ssl/statem/statem_lib.c
+@@ -54,14 +54,14 @@ int ssl3_do_write(SSL *s, int type)
+             if (!ret) {
+                 ret = -1;
+                 /* QUIC can't sent anything out sice the above failed */
+-                SSLerr(SSL_F_SSL3_DO_WRITE, ERR_R_INTERNAL_ERROR);
++                ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
+             } else {
+                 written = s->init_num;
+             }
+         } else {
+             /* QUIC doesn't use ChangeCipherSpec */
+             ret = -1;
+-            SSLerr(SSL_F_SSL3_DO_WRITE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
++            ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+         }
+     } else
+ #endif
+-- 
+2.42.0
+
diff --git a/0034-QUIC-Add-compile-run-time-checking-for-QUIC.patch b/0034-QUIC-Add-compile-run-time-checking-for-QUIC.patch
new file mode 100644
index 0000000..df7ddd3
--- /dev/null
+++ b/0034-QUIC-Add-compile-run-time-checking-for-QUIC.patch
@@ -0,0 +1,101 @@
+From 14347b7d94207b9e44a39889aaf84809f674de81 Mon Sep 17 00:00:00 2001
+From: Todd Short <todd.short@me.com>
+Date: Fri, 5 Mar 2021 15:22:18 -0500
+Subject: [PATCH 34/63] QUIC: Add compile/run-time checking for QUIC
+
+---
+ apps/info.c                  | 12 ++++++++++++
+ crypto/info.c                |  4 ++++
+ doc/man3/OpenSSL_version.pod |  8 ++++++++
+ include/openssl/crypto.h.in  |  4 ++++
+ 4 files changed, 28 insertions(+)
+
+diff --git a/apps/info.c b/apps/info.c
+index c68603652f..f0f043b7f2 100644
+--- a/apps/info.c
++++ b/apps/info.c
+@@ -15,6 +15,9 @@ typedef enum OPTION_choice {
+     OPT_COMMON,
+     OPT_CONFIGDIR, OPT_ENGINESDIR, OPT_MODULESDIR, OPT_DSOEXT, OPT_DIRNAMESEP,
+     OPT_LISTSEP, OPT_SEEDS, OPT_CPUSETTINGS
++#ifndef OPENSSL_NO_QUIC
++    , OPT_QUIC
++#endif
+ } OPTION_CHOICE;
+ 
+ const OPTIONS info_options[] = {
+@@ -32,6 +35,9 @@ const OPTIONS info_options[] = {
+     {"listsep", OPT_LISTSEP, '-', "List separator character"},
+     {"seeds", OPT_SEEDS, '-', "Seed sources"},
+     {"cpusettings", OPT_CPUSETTINGS, '-', "CPU settings info"},
++#ifndef OPENSSL_NO_QUIC
++    {"quic", OPT_QUIC, '-', "QUIC info"},
++#endif
+     {NULL}
+ };
+ 
+@@ -84,6 +90,12 @@ opthelp:
+             type = OPENSSL_INFO_CPU_SETTINGS;
+             dirty++;
+             break;
++#ifndef OPENSSL_NO_QUIC
++        case OPT_QUIC:
++            type = OPENSSL_INFO_QUIC;
++            dirty++;
++            break;
++#endif
+         }
+     }
+     if (opt_num_rest() != 0)
+diff --git a/crypto/info.c b/crypto/info.c
+index 9ef9ee4704..f8a495e098 100644
+--- a/crypto/info.c
++++ b/crypto/info.c
+@@ -203,6 +203,10 @@ const char *OPENSSL_info(int t)
+         if (ossl_cpu_info_str[0] != '\0')
+             return ossl_cpu_info_str + strlen(CPUINFO_PREFIX);
+         break;
++#ifndef OPENSSL_NO_QUIC
++    case OPENSSL_INFO_QUIC:
++        return "QUIC";
++#endif
+     default:
+         break;
+     }
+diff --git a/doc/man3/OpenSSL_version.pod b/doc/man3/OpenSSL_version.pod
+index e1cf16e2a1..946bb151ba 100644
+--- a/doc/man3/OpenSSL_version.pod
++++ b/doc/man3/OpenSSL_version.pod
+@@ -211,6 +211,14 @@ automatically configured but may be set via an environment variable.
+ The value has the same syntax as the environment variable.
+ For x86 the string looks like C<OPENSSL_ia32cap=0x123:0x456>.
+ 
++=item OPENSSL_INFO_QUIC
++
++This is only defined when compiling with a QUIC-enabled version of
++OpenSSL. At run time, this will return "QUIC" if QUIC is supported.
++
++This can be used as a build time flag to determine if OpenSSL has
++QUIC enabled.
++
+ =back
+ 
+ For an unknown I<t>, NULL is returned.
+diff --git a/include/openssl/crypto.h.in b/include/openssl/crypto.h.in
+index fb0c7cbb87..6eca308b32 100644
+--- a/include/openssl/crypto.h.in
++++ b/include/openssl/crypto.h.in
+@@ -176,6 +176,10 @@ const char *OPENSSL_info(int type);
+ # define OPENSSL_INFO_SEED_SOURCE               1007
+ # define OPENSSL_INFO_CPU_SETTINGS              1008
+ 
++# ifndef OPENSSL_NO_QUIC
++#  define OPENSSL_INFO_QUIC                     2000
++# endif
++
+ int OPENSSL_issetugid(void);
+ 
+ struct crypto_ex_data_st {
+-- 
+2.42.0
+
diff --git a/0035-QUIC-Add-early-data-support-11.patch b/0035-QUIC-Add-early-data-support-11.patch
new file mode 100644
index 0000000..54520ff
--- /dev/null
+++ b/0035-QUIC-Add-early-data-support-11.patch
@@ -0,0 +1,504 @@
+From b76539534a8c3b4b799007fd24408286ac933b11 Mon Sep 17 00:00:00 2001
+From: Tatsuhiro Tsujikawa <404610+tatsuhiro-t@users.noreply.github.com>
+Date: Thu, 11 Mar 2021 23:07:55 +0900
+Subject: [PATCH 35/63] QUIC: Add early data support (#11)
+
+* QUIC: Add early data support
+
+This commit adds SSL_set_quic_early_data_enabled to add early data
+support to QUIC.
+---
+ doc/man3/SSL_CTX_set_quic_method.pod |  10 +-
+ include/openssl/ssl.h.in             |   2 +
+ ssl/ssl_lib.c                        |  15 +++
+ ssl/ssl_quic.c                       |  76 ++++++++++---
+ ssl/statem/statem_srvr.c             |  10 ++
+ ssl/tls13_enc.c                      |  90 +++++++++++++---
+ test/sslapitest.c                    | 156 +++++++++++++++++++++++++++
+ util/libssl.num                      |   1 +
+ 8 files changed, 327 insertions(+), 33 deletions(-)
+
+diff --git a/doc/man3/SSL_CTX_set_quic_method.pod b/doc/man3/SSL_CTX_set_quic_method.pod
+index 39ff3a8da4..86eb257e91 100644
+--- a/doc/man3/SSL_CTX_set_quic_method.pod
++++ b/doc/man3/SSL_CTX_set_quic_method.pod
+@@ -17,7 +17,8 @@ SSL_is_quic,
+ SSL_get_peer_quic_transport_version,
+ SSL_get_quic_transport_version,
+ SSL_set_quic_transport_version,
+-SSL_set_quic_use_legacy_codepoint
++SSL_set_quic_use_legacy_codepoint,
++SSL_set_quic_early_data_enabled
+ - QUIC support
+ 
+ =head1 SYNOPSIS
+@@ -47,6 +48,7 @@ SSL_set_quic_use_legacy_codepoint
+  void SSL_set_quic_transport_version(SSL *ssl, int version);
+  int SSL_get_quic_transport_version(const SSL *ssl);
+  int SSL_get_peer_quic_transport_version(const SSL *ssl);
++ void SSL_set_quic_early_data_enabled(SSL *ssl, int enabled);
+ 
+ =head1 DESCRIPTION
+ 
+@@ -106,6 +108,12 @@ SSL_set_quic_transport_version().
+ SSL_get_peer_quic_transport_version() returns the version the that was 
+ negotiated.
+ 
++SSL_set_quic_early_data_enabled() enables QUIC early data if a nonzero
++value is passed.  Client must set a resumed session before calling
++this function.  Server must set 0xffffffffu to
++SSL_CTX_set_max_early_data() or SSL_set_max_early_data() so that a
++session ticket indicates that server is able to accept early data.
++
+ =head1 NOTES
+ 
+ These APIs are implementations of BoringSSL's QUIC APIs.
+diff --git a/include/openssl/ssl.h.in b/include/openssl/ssl.h.in
+index 289f55feb1..f1d1ec0ec3 100644
+--- a/include/openssl/ssl.h.in
++++ b/include/openssl/ssl.h.in
+@@ -2580,6 +2580,8 @@ __owur int SSL_get_peer_quic_transport_version(const SSL *ssl);
+ 
+ int SSL_CIPHER_get_prf_nid(const SSL_CIPHER *c);
+ 
++void SSL_set_quic_early_data_enabled(SSL *ssl, int enabled);
++
+ #  endif
+ 
+ # ifdef  __cplusplus
+diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
+index 517104a4df..9c03564557 100644
+--- a/ssl/ssl_lib.c
++++ b/ssl/ssl_lib.c
+@@ -3979,6 +3979,21 @@ int SSL_do_handshake(SSL *s)
+             ret = s->handshake_func(s);
+         }
+     }
++#ifndef OPENSSL_NO_QUIC
++    if (SSL_IS_QUIC(s) && ret == 1) {
++        if (s->server) {
++            if (s->early_data_state == SSL_EARLY_DATA_ACCEPTING) {
++                s->early_data_state = SSL_EARLY_DATA_FINISHED_READING;
++                s->rwstate = SSL_READING;
++                ret = 0;
++            }
++        } else if (s->early_data_state == SSL_EARLY_DATA_CONNECTING) {
++            s->early_data_state = SSL_EARLY_DATA_WRITE_RETRY;
++            s->rwstate = SSL_READING;
++            ret = 0;
++        }
++    }
++#endif
+     return ret;
+ }
+ 
+diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c
+index d50b1247a6..9d4c801411 100644
+--- a/ssl/ssl_quic.c
++++ b/ssl/ssl_quic.c
+@@ -257,24 +257,46 @@ int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level)
+         return 1;
+     }
+ 
+-    md = ssl_handshake_md(ssl);
+-    if (md == NULL) {
+-        /* May not have selected cipher, yet */
+-        const SSL_CIPHER *c = NULL;
+-
+-        /*
+-         * It probably doesn't make sense to use an (external) PSK session,
+-         * but in theory some kinds of external session caches could be
+-         * implemented using it, so allow psksession to be used as well as
+-         * the regular session.
+-         */
+-        if (ssl->session != NULL)
+-            c = SSL_SESSION_get0_cipher(ssl->session);
+-        else if (ssl->psksession != NULL)
++    if (level == ssl_encryption_early_data) {
++        const SSL_CIPHER *c = SSL_SESSION_get0_cipher(ssl->session);
++        if (ssl->early_data_state == SSL_EARLY_DATA_CONNECTING
++                && ssl->max_early_data > 0
++                && ssl->session->ext.max_early_data == 0) {
++            if (!ossl_assert(ssl->psksession != NULL
++                    && ssl->max_early_data ==
++                       ssl->psksession->ext.max_early_data)) {
++                SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
++                return 0;
++            }
+             c = SSL_SESSION_get0_cipher(ssl->psksession);
++        }
++
++        if (c == NULL) {
++            SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
++            return 0;
++        }
+ 
+-        if (c != NULL)
+-            md = SSL_CIPHER_get_handshake_digest(c);
++        md = ssl_md(ssl->ctx, c->algorithm2);
++    } else {
++        md = ssl_handshake_md(ssl);
++        if (md == NULL) {
++            /* May not have selected cipher, yet */
++            const SSL_CIPHER *c = NULL;
++
++            /*
++             * It probably doesn't make sense to use an (external) PSK session,
++             * but in theory some kinds of external session caches could be
++             * implemented using it, so allow psksession to be used as well as
++             * the regular session.
++             */
++            if (ssl->session != NULL)
++                c = SSL_SESSION_get0_cipher(ssl->session);
++            else if (ssl->psksession != NULL)
++                c = SSL_SESSION_get0_cipher(ssl->psksession);
++
++            if (c != NULL)
++                md = SSL_CIPHER_get_handshake_digest(c);
++        }
+     }
+ 
+     if ((len = EVP_MD_size(md)) <= 0) {
+@@ -330,3 +352,25 @@ int SSL_is_quic(SSL* ssl)
+ {
+     return SSL_IS_QUIC(ssl);
+ }
++
++void SSL_set_quic_early_data_enabled(SSL *ssl, int enabled)
++{
++    if (!SSL_is_quic(ssl) || !SSL_in_before(ssl))
++        return;
++
++    if (!enabled) {
++      ssl->early_data_state = SSL_EARLY_DATA_NONE;
++      return;
++    }
++
++    if (ssl->server) {
++        ssl->early_data_state = SSL_EARLY_DATA_ACCEPTING;
++        return;
++    }
++
++    if ((ssl->session == NULL || ssl->session->ext.max_early_data == 0)
++            && ssl->psk_use_session_cb == NULL)
++        return;
++
++    ssl->early_data_state = SSL_EARLY_DATA_CONNECTING;
++}
+diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
+index aba18e8c76..e92b0e736e 100644
+--- a/ssl/statem/statem_srvr.c
++++ b/ssl/statem/statem_srvr.c
+@@ -964,6 +964,16 @@ WORK_STATE ossl_statem_server_post_work(SSL *s, WORK_STATE wst)
+                         SSL3_CC_APPLICATION | SSL3_CHANGE_CIPHER_SERVER_WRITE))
+             /* SSLfatal() already called */
+             return WORK_ERROR;
++
++#ifndef OPENSSL_NO_QUIC
++            if (SSL_IS_QUIC(s) && s->ext.early_data == SSL_EARLY_DATA_ACCEPTED) {
++                s->early_data_state = SSL_EARLY_DATA_FINISHED_READING;
++                if (!s->method->ssl3_enc->change_cipher_state(
++                        s, SSL3_CC_HANDSHAKE | SSL3_CHANGE_CIPHER_SERVER_READ))
++                    /* SSLfatal() already called */
++                    return WORK_ERROR;
++            }
++#endif
+         }
+         break;
+ 
+diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c
+index a63beea224..a1d4dd04b8 100644
+--- a/ssl/tls13_enc.c
++++ b/ssl/tls13_enc.c
+@@ -419,20 +419,76 @@ static int quic_change_cipher_state(SSL *s, int which)
+     int is_server_write = ((which & SSL3_CHANGE_CIPHER_SERVER_WRITE) == SSL3_CHANGE_CIPHER_SERVER_WRITE);
+     int is_early = (which & SSL3_CC_EARLY);
+ 
+-    md = ssl_handshake_md(s);
+-    if (!ssl3_digest_cached_records(s, 1)
+-        || !ssl_handshake_hash(s, hash, sizeof(hash), &hashlen)) {
+-        /* SSLfatal() already called */;
+-        goto err;
+-    }
++    if (is_early) {
++        EVP_MD_CTX *mdctx = NULL;
++        long handlen;
++        void *hdata;
++        unsigned int hashlenui;
++        const SSL_CIPHER *sslcipher = SSL_SESSION_get0_cipher(s->session);
++
++        handlen = BIO_get_mem_data(s->s3.handshake_buffer, &hdata);
++        if (handlen <= 0) {
++            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_BAD_HANDSHAKE_LENGTH);
++            goto err;
++        }
+ 
+-    /* Ensure cast to size_t is safe */
+-    hashleni = EVP_MD_size(md);
+-    if (!ossl_assert(hashleni >= 0)) {
+-        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB);
+-        goto err;
++        if (s->early_data_state == SSL_EARLY_DATA_CONNECTING
++                && s->max_early_data > 0
++                && s->session->ext.max_early_data == 0) {
++            /*
++             * If we are attempting to send early data, and we've decided to
++             * actually do it but max_early_data in s->session is 0 then we
++             * must be using an external PSK.
++             */
++            if (!ossl_assert(s->psksession != NULL
++                    && s->max_early_data ==
++                       s->psksession->ext.max_early_data)) {
++                SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
++                goto err;
++            }
++            sslcipher = SSL_SESSION_get0_cipher(s->psksession);
++        }
++        if (sslcipher == NULL) {
++            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_BAD_PSK);
++            goto err;
++        }
++
++        /*
++         * We need to calculate the handshake digest using the digest from
++         * the session. We haven't yet selected our ciphersuite so we can't
++         * use ssl_handshake_md().
++         */
++        mdctx = EVP_MD_CTX_new();
++        if (mdctx == NULL) {
++            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE);
++            goto err;
++        }
++        md = ssl_md(s->ctx, sslcipher->algorithm2);
++        if (md == NULL || !EVP_DigestInit_ex(mdctx, md, NULL)
++                || !EVP_DigestUpdate(mdctx, hdata, handlen)
++                || !EVP_DigestFinal_ex(mdctx, hash, &hashlenui)) {
++            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
++            EVP_MD_CTX_free(mdctx);
++            goto err;
++        }
++        hashlen = hashlenui;
++        EVP_MD_CTX_free(mdctx);
++    } else {
++        md = ssl_handshake_md(s);
++        if (!ssl3_digest_cached_records(s, 1)
++                || !ssl_handshake_hash(s, hash, sizeof(hash), &hashlen)) {
++            /* SSLfatal() already called */;
++            goto err;
++        }
++
++        /* Ensure cast to size_t is safe */
++        hashleni = EVP_MD_size(md);
++        if (!ossl_assert(hashleni >= 0)) {
++            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB);
++            goto err;
++        }
++        hashlen = (size_t)hashleni;
+     }
+-    hashlen = (size_t)hashleni;
+ 
+     if (is_client_read || is_server_write) {
+         if (is_handshake) {
+@@ -538,10 +594,12 @@ static int quic_change_cipher_state(SSL *s, int which)
+             }
+         }
+ 
+-        if (s->server)
+-            s->quic_read_level = level;
+-        else
+-            s->quic_write_level = level;
++        if (level != ssl_encryption_early_data) {
++            if (s->server)
++                s->quic_read_level = level;
++            else
++                s->quic_write_level = level;
++        }
+     }
+ 
+     ret = 1;
+diff --git a/test/sslapitest.c b/test/sslapitest.c
+index f65878212c..b8e1078670 100644
+--- a/test/sslapitest.c
++++ b/test/sslapitest.c
+@@ -10337,6 +10337,159 @@ end:
+     serverssl = NULL;
+     return testresult;
+ }
++
++# ifndef OSSL_NO_USABLE_TLS1_3
++/*
++ * Helper method to setup objects for QUIC early data test. Caller
++ * frees objects on error.
++ */
++static int quic_setupearly_data_test(SSL_CTX **cctx, SSL_CTX **sctx,
++                                     SSL **clientssl, SSL **serverssl,
++                                     SSL_SESSION **sess, int idx)
++{
++    static const char *server_str = "SERVER";
++    static const char *client_str = "CLIENT";
++
++    if (*sctx == NULL
++            && (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(),
++                                               TLS_client_method(),
++                                               TLS1_3_VERSION, 0,
++                                               sctx, cctx, cert, privkey))
++                || !TEST_true(SSL_CTX_set_quic_method(*sctx, &quic_method))
++                || !TEST_true(SSL_CTX_set_quic_method(*cctx, &quic_method))
++                || !TEST_true(SSL_CTX_set_max_early_data(*sctx, 0xffffffffu))))
++        return 0;
++
++    if (idx == 1) {
++        /* When idx == 1 we repeat the tests with read_ahead set */
++        SSL_CTX_set_read_ahead(*cctx, 1);
++        SSL_CTX_set_read_ahead(*sctx, 1);
++    } else if (idx == 2) {
++        /* When idx == 2 we are doing early_data with a PSK. Set up callbacks */
++        SSL_CTX_set_psk_use_session_callback(*cctx, use_session_cb);
++        SSL_CTX_set_psk_find_session_callback(*sctx, find_session_cb);
++        use_session_cb_cnt = 0;
++        find_session_cb_cnt = 0;
++        srvid = pskid;
++    }
++
++    if (!TEST_true(create_ssl_objects(*sctx, *cctx, serverssl, clientssl,
++                                      NULL, NULL))
++            || !TEST_true(SSL_set_quic_transport_params(*serverssl,
++                                                        (unsigned char*)server_str,
++                                                        strlen(server_str)+1))
++            || !TEST_true(SSL_set_quic_transport_params(*clientssl,
++                                                        (unsigned char*)client_str,
++                                                        strlen(client_str)+1))
++            || !TEST_true(SSL_set_app_data(*serverssl, *clientssl))
++            || !TEST_true(SSL_set_app_data(*clientssl, *serverssl)))
++        return 0;
++
++    /*
++     * For one of the run throughs (doesn't matter which one), we'll try sending
++     * some SNI data in the initial ClientHello. This will be ignored (because
++     * there is no SNI cb set up by the server), so it should not impact
++     * early_data.
++     */
++    if (idx == 1
++            && !TEST_true(SSL_set_tlsext_host_name(*clientssl, "localhost")))
++        return 0;
++
++    if (idx == 2) {
++        clientpsk = create_a_psk(*clientssl);
++        if (!TEST_ptr(clientpsk)
++                || !TEST_true(SSL_SESSION_set_max_early_data(clientpsk,
++                                                             0xffffffffu))
++                || !TEST_true(SSL_SESSION_up_ref(clientpsk))) {
++            SSL_SESSION_free(clientpsk);
++            clientpsk = NULL;
++            return 0;
++        }
++        serverpsk = clientpsk;
++
++        if (sess != NULL) {
++            if (!TEST_true(SSL_SESSION_up_ref(clientpsk))) {
++                SSL_SESSION_free(clientpsk);
++                SSL_SESSION_free(serverpsk);
++                clientpsk = serverpsk = NULL;
++                return 0;
++            }
++            *sess = clientpsk;
++        }
++
++        SSL_set_quic_early_data_enabled(*serverssl, 1);
++        SSL_set_quic_early_data_enabled(*clientssl, 1);
++
++        return 1;
++    }
++
++    if (sess == NULL)
++        return 1;
++
++    if (!TEST_true(create_ssl_connection(*serverssl, *clientssl,
++                                         SSL_ERROR_NONE)))
++        return 0;
++
++    /* Deal with two NewSessionTickets */
++    if (!TEST_true(SSL_process_quic_post_handshake(*clientssl))
++            || !TEST_true(SSL_process_quic_post_handshake(*clientssl)))
++        return 0;
++
++    *sess = SSL_get1_session(*clientssl);
++    SSL_shutdown(*clientssl);
++    SSL_shutdown(*serverssl);
++    SSL_free(*serverssl);
++    SSL_free(*clientssl);
++    *serverssl = *clientssl = NULL;
++
++    if (!TEST_true(create_ssl_objects(*sctx, *cctx, serverssl,
++                                      clientssl, NULL, NULL))
++            || !TEST_true(SSL_set_session(*clientssl, *sess))
++            || !TEST_true(SSL_set_quic_transport_params(*serverssl,
++                                                        (unsigned char*)server_str,
++                                                        strlen(server_str)+1))
++            || !TEST_true(SSL_set_quic_transport_params(*clientssl,
++                                                        (unsigned char*)client_str,
++                                                        strlen(client_str)+1))
++            || !TEST_true(SSL_set_app_data(*serverssl, *clientssl))
++            || !TEST_true(SSL_set_app_data(*clientssl, *serverssl)))
++        return 0;
++
++    SSL_set_quic_early_data_enabled(*serverssl, 1);
++    SSL_set_quic_early_data_enabled(*clientssl, 1);
++
++    return 1;
++}
++
++static int test_quic_early_data(int tst)
++{
++    SSL_CTX *cctx = NULL, *sctx = NULL;
++    SSL *clientssl = NULL, *serverssl = NULL;
++    int testresult = 0;
++    SSL_SESSION *sess = NULL;
++
++    if (!TEST_true(quic_setupearly_data_test(&cctx, &sctx, &clientssl,
++                                             &serverssl, &sess, tst)))
++        goto end;
++
++    if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE))
++            || !TEST_true(SSL_get_early_data_status(serverssl)))
++        goto end;
++
++    testresult = 1;
++
++ end:
++    SSL_SESSION_free(sess);
++    SSL_SESSION_free(clientpsk);
++    SSL_SESSION_free(serverpsk);
++    clientpsk = serverpsk = NULL;
++    SSL_free(serverssl);
++    SSL_free(clientssl);
++    SSL_CTX_free(sctx);
++    SSL_CTX_free(cctx);
++    return testresult;
++}
++# endif /* OSSL_NO_USABLE_TLS1_3 */
+ #endif /* OPENSSL_NO_QUIC */
+ 
+ #ifndef OSSL_NO_USABLE_TLS1_3
+@@ -11115,6 +11268,9 @@ int setup_tests(void)
+     ADD_ALL_TESTS(test_handshake_retry, 16);
+ #ifndef OPENSSL_NO_QUIC
+     ADD_ALL_TESTS(test_quic_api, 9);
++# ifndef OSSL_NO_USABLE_TLS1_3
++    ADD_ALL_TESTS(test_quic_early_data, 3);
++# endif
+ #endif
+     return 1;
+ 
+diff --git a/util/libssl.num b/util/libssl.num
+index 41ebba40b2..4a9d5b2007 100644
+--- a/util/libssl.num
++++ b/util/libssl.num
+@@ -535,3 +535,4 @@ SSL_set_quic_use_legacy_codepoint       20011	3_0_0	EXIST::FUNCTION:QUIC
+ SSL_set_quic_transport_version          20012	3_0_0	EXIST::FUNCTION:QUIC
+ SSL_get_peer_quic_transport_version     20013	3_0_0	EXIST::FUNCTION:QUIC
+ SSL_get_quic_transport_version          20014	3_0_0	EXIST::FUNCTION:QUIC
++SSL_set_quic_early_data_enabled         20015	3_0_0	EXIST::FUNCTION:QUIC
+-- 
+2.42.0
+
diff --git a/0036-QUIC-Make-SSL_provide_quic_data-accept-0-length-data.patch b/0036-QUIC-Make-SSL_provide_quic_data-accept-0-length-data.patch
new file mode 100644
index 0000000..c43352e
--- /dev/null
+++ b/0036-QUIC-Make-SSL_provide_quic_data-accept-0-length-data.patch
@@ -0,0 +1,31 @@
+From c3240737e2e41f0a3a3e01a49022ac3207302305 Mon Sep 17 00:00:00 2001
+From: Tatsuhiro Tsujikawa <404610+tatsuhiro-t@users.noreply.github.com>
+Date: Fri, 12 Mar 2021 00:39:20 +0900
+Subject: [PATCH 36/63] QUIC: Make SSL_provide_quic_data accept 0 length data
+ (#13)
+
+This commit makes SSL_provide_quic_data accept 0 length data, which
+matches BoringSSL behavior.
+
+Fixes #9
+---
+ ssl/ssl_quic.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c
+index 9d4c801411..49a4f3ab5c 100644
+--- a/ssl/ssl_quic.c
++++ b/ssl/ssl_quic.c
+@@ -143,6 +143,9 @@ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
+         return 0;
+     }
+ 
++    if (len == 0)
++        return 1;
++
+     if (ssl->quic_buf == NULL) {
+         BUF_MEM *buf;
+         if ((buf = BUF_MEM_new()) == NULL) {
+-- 
+2.42.0
+
diff --git a/0037-QUIC-Process-multiple-post-handshake-messages-in-a-s.patch b/0037-QUIC-Process-multiple-post-handshake-messages-in-a-s.patch
new file mode 100644
index 0000000..9836188
--- /dev/null
+++ b/0037-QUIC-Process-multiple-post-handshake-messages-in-a-s.patch
@@ -0,0 +1,76 @@
+From 8ec778771466e27485ff4e48414ff34c06af4935 Mon Sep 17 00:00:00 2001
+From: Tatsuhiro Tsujikawa <404610+tatsuhiro-t@users.noreply.github.com>
+Date: Sat, 13 Mar 2021 05:37:34 +0900
+Subject: [PATCH 37/63] QUIC: Process multiple post-handshake messages in a
+ single call (#16)
+
+---
+ ssl/ssl_quic.c    | 27 +++++++++++++--------------
+ test/sslapitest.c |  6 ++----
+ 2 files changed, 15 insertions(+), 18 deletions(-)
+
+diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c
+index 49a4f3ab5c..6cbd47ad2d 100644
+--- a/ssl/ssl_quic.c
++++ b/ssl/ssl_quic.c
+@@ -334,20 +334,19 @@ int SSL_process_quic_post_handshake(SSL *ssl)
+     }
+ 
+     /* if there is no data, return success as BoringSSL */
+-    if (ssl->quic_input_data_head == NULL)
+-        return 1;
+-    
+-    /*
+-     * This is always safe (we are sure to be at a record boundary) because
+-     * SSL_read()/SSL_write() are never used for QUIC connections -- the
+-     * application data is handled at the QUIC layer instead.
+-     */
+-    ossl_statem_set_in_init(ssl, 1);
+-    ret = ssl->handshake_func(ssl);
+-    ossl_statem_set_in_init(ssl, 0);
+-
+-    if (ret <= 0)
+-        return 0;
++    while (ssl->quic_input_data_head != NULL) {
++        /*
++         * This is always safe (we are sure to be at a record boundary) because
++         * SSL_read()/SSL_write() are never used for QUIC connections -- the
++         * application data is handled at the QUIC layer instead.
++         */
++        ossl_statem_set_in_init(ssl, 1);
++        ret = ssl->handshake_func(ssl);
++        ossl_statem_set_in_init(ssl, 0);
++
++        if (ret <= 0)
++            return 0;
++    }
+     return 1;
+ }
+ 
+diff --git a/test/sslapitest.c b/test/sslapitest.c
+index b8e1078670..e351a0b4e6 100644
+--- a/test/sslapitest.c
++++ b/test/sslapitest.c
+@@ -10238,8 +10238,7 @@ static int test_quic_api_version(int clnt, int srvr)
+         goto end;
+ 
+     /* Deal with two NewSessionTickets */
+-    if (!TEST_true(SSL_process_quic_post_handshake(clientssl))
+-            || !TEST_true(SSL_process_quic_post_handshake(clientssl)))
++    if (!TEST_true(SSL_process_quic_post_handshake(clientssl)))
+         goto end;
+ 
+     /* Dummy handshake call should succeed */
+@@ -10431,8 +10430,7 @@ static int quic_setupearly_data_test(SSL_CTX **cctx, SSL_CTX **sctx,
+         return 0;
+ 
+     /* Deal with two NewSessionTickets */
+-    if (!TEST_true(SSL_process_quic_post_handshake(*clientssl))
+-            || !TEST_true(SSL_process_quic_post_handshake(*clientssl)))
++    if (!TEST_true(SSL_process_quic_post_handshake(*clientssl)))
+         return 0;
+ 
+     *sess = SSL_get1_session(*clientssl);
+-- 
+2.42.0
+
diff --git a/0038-QUIC-Tighten-up-some-language-in-SSL_CTX_set_quic_me.patch b/0038-QUIC-Tighten-up-some-language-in-SSL_CTX_set_quic_me.patch
new file mode 100644
index 0000000..a1dee27
--- /dev/null
+++ b/0038-QUIC-Tighten-up-some-language-in-SSL_CTX_set_quic_me.patch
@@ -0,0 +1,32 @@
+From 50edeee44a1aed9eb5e819859aa3e561f307aaa0 Mon Sep 17 00:00:00 2001
+From: kaduk <kaduk-github@mit.edu>
+Date: Fri, 12 Mar 2021 13:03:14 -0800
+Subject: [PATCH 38/63] QUIC: Tighten up some language in
+ SSL_CTX_set_quic_method.pod (#18)
+
+---
+ doc/man3/SSL_CTX_set_quic_method.pod | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/doc/man3/SSL_CTX_set_quic_method.pod b/doc/man3/SSL_CTX_set_quic_method.pod
+index 86eb257e91..906c7591d9 100644
+--- a/doc/man3/SSL_CTX_set_quic_method.pod
++++ b/doc/man3/SSL_CTX_set_quic_method.pod
+@@ -109,10 +109,10 @@ SSL_get_peer_quic_transport_version() returns the version the that was
+ negotiated.
+ 
+ SSL_set_quic_early_data_enabled() enables QUIC early data if a nonzero
+-value is passed.  Client must set a resumed session before calling
+-this function.  Server must set 0xffffffffu to
+-SSL_CTX_set_max_early_data() or SSL_set_max_early_data() so that a
+-session ticket indicates that server is able to accept early data.
++value is passed.  Clients must set a resumed session before calling this
++function.  Servers must additionally call SSL_CTX_set_max_early_data() or
++SSL_set_max_early_data() with 0xffffffffu as the argument, so that any
++issued session tickets indicate that server is able to accept early data.
+ 
+ =head1 NOTES
+ 
+-- 
+2.42.0
+
diff --git a/0040-QUIC-Fix-CI-20.patch b/0040-QUIC-Fix-CI-20.patch
new file mode 100644
index 0000000..d5e2688
--- /dev/null
+++ b/0040-QUIC-Fix-CI-20.patch
@@ -0,0 +1,97 @@
+From 523bacebab18d0d0d5649a6096a4190ea733b518 Mon Sep 17 00:00:00 2001
+From: Todd Short <tmshort@users.noreply.github.com>
+Date: Thu, 18 Mar 2021 12:42:01 -0400
+Subject: [PATCH 40/63] QUIC: Fix CI (#20)
+
+Fixes #2 and #3 and #22
+
+Updates `Configure` script to disable QUIC with `no-bulk` and `no-ec`
+Updates build.info doc docs
+Fixes an issue with extension defintions and `no-quic`
+---
+ Configure                    | 3 ++-
+ doc/build.info               | 6 ++++++
+ ssl/statem/extensions.c      | 1 +
+ ssl/statem/extensions_srvr.c | 2 +-
+ 4 files changed, 10 insertions(+), 2 deletions(-)
+
+diff --git a/Configure b/Configure
+index bd4e0943bf..2b37fd497a 100755
+--- a/Configure
++++ b/Configure
+@@ -578,6 +578,7 @@ my @disable_cascades = (
+                              "sm3", "sm4", "srp",
+                              "srtp", "ssl3-method", "ssl-trace",
+                              "ts", "ui-console", "whirlpool",
++                             "quic",
+                              "fips-securitychecks" ],
+     sub { $config{processor} eq "386" }
+                         => [ "sse2" ],
+@@ -585,7 +586,7 @@ my @disable_cascades = (
+     "ssl3-method"       => [ "ssl3" ],
+     "zlib"              => [ "zlib-dynamic" ],
+     "des"               => [ "mdc2" ],
+-    "ec"                => [ "ec2m", "ecdsa", "ecdh", "sm2", "gost" ],
++    "ec"                => [ "ec2m", "ecdsa", "ecdh", "sm2", "gost", "quic" ],
+     "dgram"             => [ "dtls", "sctp" ],
+     "sock"              => [ "dgram" ],
+     "dtls"              => [ @dtls ],
+diff --git a/doc/build.info b/doc/build.info
+index 00dc150721..8f7186d89b 100644
+--- a/doc/build.info
++++ b/doc/build.info
+@@ -2263,6 +2263,10 @@ DEPEND[html/man3/SSL_CTX_set_psk_client_callback.html]=man3/SSL_CTX_set_psk_clie
+ GENERATE[html/man3/SSL_CTX_set_psk_client_callback.html]=man3/SSL_CTX_set_psk_client_callback.pod
+ DEPEND[man/man3/SSL_CTX_set_psk_client_callback.3]=man3/SSL_CTX_set_psk_client_callback.pod
+ GENERATE[man/man3/SSL_CTX_set_psk_client_callback.3]=man3/SSL_CTX_set_psk_client_callback.pod
++DEPEND[html/man3/SSL_CTX_set_quic_method.html]=man3/SSL_CTX_set_quic_method.pod
++GENERATE[html/man3/SSL_CTX_set_quic_method.html]=man3/SSL_CTX_set_quic_method.pod
++DEPEND[man/man3/SSL_CTX_set_quic_method.3]=man3/SSL_CTX_set_quic_method.pod
++GENERATE[man/man3/SSL_CTX_set_quic_method.3]=man3/SSL_CTX_set_quic_method.pod
+ DEPEND[html/man3/SSL_CTX_set_quiet_shutdown.html]=man3/SSL_CTX_set_quiet_shutdown.pod
+ GENERATE[html/man3/SSL_CTX_set_quiet_shutdown.html]=man3/SSL_CTX_set_quiet_shutdown.pod
+ DEPEND[man/man3/SSL_CTX_set_quiet_shutdown.3]=man3/SSL_CTX_set_quiet_shutdown.pod
+@@ -3329,6 +3333,7 @@ html/man3/SSL_CTX_set_msg_callback.html \
+ html/man3/SSL_CTX_set_num_tickets.html \
+ html/man3/SSL_CTX_set_options.html \
+ html/man3/SSL_CTX_set_psk_client_callback.html \
++html/man3/SSL_CTX_set_quic_method.html \
+ html/man3/SSL_CTX_set_quiet_shutdown.html \
+ html/man3/SSL_CTX_set_read_ahead.html \
+ html/man3/SSL_CTX_set_record_padding_callback.html \
+@@ -3932,6 +3937,7 @@ man/man3/SSL_CTX_set_msg_callback.3 \
+ man/man3/SSL_CTX_set_num_tickets.3 \
+ man/man3/SSL_CTX_set_options.3 \
+ man/man3/SSL_CTX_set_psk_client_callback.3 \
++man/man3/SSL_CTX_set_quic_method.3 \
+ man/man3/SSL_CTX_set_quiet_shutdown.3 \
+ man/man3/SSL_CTX_set_read_ahead.3 \
+ man/man3/SSL_CTX_set_record_padding_callback.3 \
+diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c
+index 34ba69e85e..a972f3be26 100644
+--- a/ssl/statem/extensions.c
++++ b/ssl/statem/extensions.c
+@@ -395,6 +395,7 @@ static const EXTENSION_DEFINITION ext_defs[] = {
+     },
+ #else
+     INVALID_EXTENSION,
++    INVALID_EXTENSION,
+ #endif
+     {
+         /* Must be immediately before pre_shared_key */
+diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c
+index bfab225651..c23b35593f 100644
+--- a/ssl/statem/extensions_srvr.c
++++ b/ssl/statem/extensions_srvr.c
+@@ -1912,7 +1912,7 @@ EXT_RETURN tls_construct_stoc_early_data(SSL *s, WPACKET *pkt,
+ 
+ #ifndef OPENSSL_NO_QUIC
+         /* QUIC server must always send 0xFFFFFFFF, per draft-ietf-quic-tls-27 S4.5 */
+-        if (s->quic_method != NULL)
++        if (SSL_IS_QUIC(s))
+             max_early_data = 0xFFFFFFFF;
+ #endif
+ 
+-- 
+2.42.0
+
diff --git a/0041-QUIC-Break-up-header-body-processing.patch b/0041-QUIC-Break-up-header-body-processing.patch
new file mode 100644
index 0000000..33b0747
--- /dev/null
+++ b/0041-QUIC-Break-up-header-body-processing.patch
@@ -0,0 +1,145 @@
+From ced2dc4b1d98ecfe0a8b3c33d7a5c797550fd551 Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Thu, 6 May 2021 16:24:03 -0400
+Subject: [PATCH 41/63] QUIC: Break up header/body processing
+
+As DTLS has changed, so too must QUIC.
+---
+ ssl/statem/statem.c       |  9 ++++++---
+ ssl/statem/statem_local.h |  3 ++-
+ ssl/statem/statem_quic.c  | 25 +++++++++++++++----------
+ 3 files changed, 23 insertions(+), 14 deletions(-)
+
+diff --git a/ssl/statem/statem.c b/ssl/statem/statem.c
+index df542579d0..e67ee26e87 100644
+--- a/ssl/statem/statem.c
++++ b/ssl/statem/statem.c
+@@ -586,7 +586,7 @@ static SUB_STATE_RETURN read_state_machine(SSL *s)
+ #ifndef OPENSSL_NO_QUIC
+             } else if (SSL_IS_QUIC(s)) {
+                 /* QUIC behaves like DTLS -- all in one go. */
+-                ret = quic_get_message(s, &mt, &len);
++                ret = quic_get_message(s, &mt);
+ #endif
+             } else {
+                 ret = tls_get_message_header(s, &mt);
+@@ -636,8 +636,11 @@ static SUB_STATE_RETURN read_state_machine(SSL *s)
+                  * opportunity to do any further processing.
+                  */
+                 ret = dtls_get_message_body(s, &len);
+-            } else if (!SSL_IS_QUIC(s)) {
+-                /* We already got this above for QUIC */
++#ifndef OPENSSL_NO_QUIC
++            } else if (SSL_IS_QUIC(s)) {
++                ret = quic_get_message_body(s, &len);
++#endif
++            } else {
+                 ret = tls_get_message_body(s, &len);
+             }
+             if (ret == 0) {
+diff --git a/ssl/statem/statem_local.h b/ssl/statem/statem_local.h
+index 0065db1744..4203c084e8 100644
+--- a/ssl/statem/statem_local.h
++++ b/ssl/statem/statem_local.h
+@@ -105,7 +105,8 @@ __owur int tls_get_message_body(SSL *s, size_t *len);
+ __owur int dtls_get_message(SSL *s, int *mt);
+ __owur int dtls_get_message_body(SSL *s, size_t *len);
+ #ifndef OPENSSL_NO_QUIC
+-__owur int quic_get_message(SSL *s, int *mt, size_t *len);
++__owur int quic_get_message(SSL *s, int *mt);
++__owur int quic_get_message_body(SSL *s, size_t *len);
+ #endif
+ 
+ /* Message construction and processing functions */
+diff --git a/ssl/statem/statem_quic.c b/ssl/statem/statem_quic.c
+index a371eeaedb..a51bfd74d8 100644
+--- a/ssl/statem/statem_quic.c
++++ b/ssl/statem/statem_quic.c
+@@ -11,7 +11,7 @@
+ #include "statem_local.h"
+ #include "internal/cryptlib.h"
+ 
+-int quic_get_message(SSL *s, int *mt, size_t *len)
++int quic_get_message(SSL *s, int *mt)
+ {
+     size_t l;
+     QUIC_DATA *qd = s->quic_input_data_head;
+@@ -19,26 +19,26 @@ int quic_get_message(SSL *s, int *mt, size_t *len)
+ 
+     if (qd == NULL) {
+         s->rwstate = SSL_READING;
+-        *mt = *len = 0;
++        *mt = 0;
+         return 0;
+     }
+ 
+     if (!ossl_assert(qd->length >= SSL3_HM_HEADER_LENGTH)) {
+         SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_BAD_LENGTH);
+-        *mt = *len = 0;
++        *mt = 0;
+         return 0;
+     }
+ 
+     /* This is where we check for the proper level, not when data is given */
+     if (qd->level != s->quic_read_level) {
+         SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED);
+-        *mt = *len = 0;
++        *mt = 0;
+         return 0;
+     }
+ 
+     if (!BUF_MEM_grow_clean(s->init_buf, (int)qd->length)) {
+         SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_BUF_LIB);
+-        *mt = *len = 0;
++        *mt = 0;
+         return 0;
+     }
+ 
+@@ -53,28 +53,32 @@ int quic_get_message(SSL *s, int *mt, size_t *len)
+     s->s3.tmp.message_type = *mt = *(s->init_buf->data);
+     p = (uint8_t*)s->init_buf->data + 1;
+     n2l3(p, l);
+-    s->init_num = s->s3.tmp.message_size = *len = l;
++    s->init_num = s->s3.tmp.message_size = l;
+     s->init_msg = s->init_buf->data + SSL3_HM_HEADER_LENGTH;
+ 
++    return 1;
++}
++
++int quic_get_message_body(SSL *s, size_t *len)
++{
+     /* No CCS in QUIC/TLSv1.3? */
+-    if (*mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
++    if (s->s3.tmp.message_type == SSL3_MT_CHANGE_CIPHER_SPEC) {
+         SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_R_CCS_RECEIVED_EARLY);
+         *len = 0;
+         return 0;
+     }
+     /* No KeyUpdate in QUIC */
+-    if (*mt == SSL3_MT_KEY_UPDATE) {
++    if (s->s3.tmp.message_type == SSL3_MT_KEY_UPDATE) {
+         SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_R_UNEXPECTED_MESSAGE);
+         *len = 0;
+         return 0;
+     }
+ 
+-
+     /*
+      * If receiving Finished, record MAC of prior handshake messages for
+      * Finished verification.
+      */
+-    if (*mt == SSL3_MT_FINISHED && !ssl3_take_mac(s)) {
++    if (s->s3.tmp.message_type == SSL3_MT_FINISHED && !ssl3_take_mac(s)) {
+         /* SSLfatal() already called */
+         *len = 0;
+         return 0;
+@@ -108,5 +112,6 @@ int quic_get_message(SSL *s, int *mt, size_t *len)
+                         (size_t)s->init_num + SSL3_HM_HEADER_LENGTH, s,
+                         s->msg_callback_arg);
+ 
++    *len = s->init_num;
+     return 1;
+ }
+-- 
+2.42.0
+
diff --git a/0042-QUIC-Fix-make-doc-nits.patch b/0042-QUIC-Fix-make-doc-nits.patch
new file mode 100644
index 0000000..b2be7d5
--- /dev/null
+++ b/0042-QUIC-Fix-make-doc-nits.patch
@@ -0,0 +1,35 @@
+From 117b887a7a132b25425c74613fc9621dd660fecb Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Thu, 24 Jun 2021 15:11:24 -0400
+Subject: [PATCH 42/63] QUIC: Fix make doc-nits
+
+---
+ doc/man1/openssl-info.pod.in | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/doc/man1/openssl-info.pod.in b/doc/man1/openssl-info.pod.in
+index 0e91bb28ee..fe7abee486 100644
+--- a/doc/man1/openssl-info.pod.in
++++ b/doc/man1/openssl-info.pod.in
+@@ -17,6 +17,7 @@ B<openssl info>
+ [B<-listsep>]
+ [B<-seeds>]
+ [B<-cpusettings>]
++[B<-quic>]
+ 
+ =head1 DESCRIPTION
+ 
+@@ -73,6 +74,10 @@ Outputs the randomness seed sources.
+ 
+ Outputs the OpenSSL CPU settings info.
+ 
++=item B<-quic>
++
++Outputs the OpenSSL QUIC info.
++
+ =back
+ 
+ =head1 HISTORY
+-- 
+2.42.0
+
diff --git a/0045-QUIC-Don-t-muck-with-FIPS-checksums.patch b/0045-QUIC-Don-t-muck-with-FIPS-checksums.patch
new file mode 100644
index 0000000..dabf450
--- /dev/null
+++ b/0045-QUIC-Don-t-muck-with-FIPS-checksums.patch
@@ -0,0 +1,131 @@
+From a35de9e5ccb192b8d8b242cff02d6b75ff618a8e Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Fri, 9 Jul 2021 13:29:03 -0400
+Subject: [PATCH 45/63] QUIC: Don't muck with FIPS checksums
+
+---
+ apps/info.c                 |  1 +
+ crypto/info.c               |  1 +
+ include/openssl/crypto.h.in |  4 ----
+ include/openssl/evp.h       |  4 ----
+ include/openssl/quic.h      | 19 +++++++++++++++++++
+ include/openssl/ssl.h.in    |  9 +++++++++
+ include/openssl/types.h     |  2 --
+ 7 files changed, 30 insertions(+), 10 deletions(-)
+ create mode 100644 include/openssl/quic.h
+
+diff --git a/apps/info.c b/apps/info.c
+index f0f043b7f2..66f3ef2587 100644
+--- a/apps/info.c
++++ b/apps/info.c
+@@ -10,6 +10,7 @@
+ #include <openssl/crypto.h>
+ #include "apps.h"
+ #include "progs.h"
++#include <openssl/quic.h>
+ 
+ typedef enum OPTION_choice {
+     OPT_COMMON,
+diff --git a/crypto/info.c b/crypto/info.c
+index f8a495e098..e7a37e3922 100644
+--- a/crypto/info.c
++++ b/crypto/info.c
+@@ -14,6 +14,7 @@
+ #include "internal/cryptlib.h"
+ #include "internal/e_os.h"
+ #include "buildinf.h"
++#include <openssl/quic.h>
+ 
+ #if defined(__arm__) || defined(__arm) || defined(__aarch64__)
+ # include "arm_arch.h"
+diff --git a/include/openssl/crypto.h.in b/include/openssl/crypto.h.in
+index 6eca308b32..fb0c7cbb87 100644
+--- a/include/openssl/crypto.h.in
++++ b/include/openssl/crypto.h.in
+@@ -176,10 +176,6 @@ const char *OPENSSL_info(int type);
+ # define OPENSSL_INFO_SEED_SOURCE               1007
+ # define OPENSSL_INFO_CPU_SETTINGS              1008
+ 
+-# ifndef OPENSSL_NO_QUIC
+-#  define OPENSSL_INFO_QUIC                     2000
+-# endif
+-
+ int OPENSSL_issetugid(void);
+ 
+ struct crypto_ex_data_st {
+diff --git a/include/openssl/evp.h b/include/openssl/evp.h
+index 8479f665f5..db38e5d921 100644
+--- a/include/openssl/evp.h
++++ b/include/openssl/evp.h
+@@ -1743,10 +1743,6 @@ int EVP_PKEY_CTX_set_mac_key(EVP_PKEY_CTX *ctx, const unsigned char *key,
+  */
+ # define EVP_PKEY_FLAG_SIGCTX_CUSTOM     4
+ 
+-/* Used by Chromium/QUIC */
+-# define X25519_PRIVATE_KEY_LEN          32
+-# define X25519_PUBLIC_VALUE_LEN         32
+-
+ # ifndef OPENSSL_NO_DEPRECATED_3_0
+ OSSL_DEPRECATEDIN_3_0 const EVP_PKEY_METHOD *EVP_PKEY_meth_find(int type);
+ OSSL_DEPRECATEDIN_3_0 EVP_PKEY_METHOD *EVP_PKEY_meth_new(int id, int flags);
+diff --git a/include/openssl/quic.h b/include/openssl/quic.h
+new file mode 100644
+index 0000000000..f95e9e8819
+--- /dev/null
++++ b/include/openssl/quic.h
+@@ -0,0 +1,19 @@
++/*
++ * Copyright 2018-2021 The OpenSSL Project Authors. All Rights Reserved.
++ *
++ * Licensed under the Apache License 2.0 (the "License").  You may not use
++ * this file except in compliance with the License.  You can obtain a copy
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++#ifndef OPENSSL_QUIC_H
++# define OPENSSL_QUIC_H
++# pragma once
++# ifndef OPENSSL_NO_QUIC
++
++/* moved from crypto.h.in to avoid breaking FIPS checksums */
++# define OPENSSL_INFO_QUIC                     2000
++
++# endif /* OPENSSL_NO_QUIC */
++#endif /* OPENSSL_QUIC_H */
+diff --git a/include/openssl/ssl.h.in b/include/openssl/ssl.h.in
+index f1d1ec0ec3..ce29710a95 100644
+--- a/include/openssl/ssl.h.in
++++ b/include/openssl/ssl.h.in
+@@ -2531,6 +2531,15 @@ const char *OSSL_default_ciphersuites(void);
+  * ssl_encryption_level_t represents a specific QUIC encryption level used to
+  * transmit handshake messages. BoringSSL has this as an 'enum'.
+  */
++#include <openssl/quic.h>
++
++/* Used by Chromium/QUIC - moved from evp.h to avoid breaking FIPS checksums */
++# define X25519_PRIVATE_KEY_LEN          32
++# define X25519_PUBLIC_VALUE_LEN         32
++
++/* moved from types.h to avoid breaking FIPS checksums */
++typedef struct ssl_quic_method_st SSL_QUIC_METHOD;
++
+ typedef enum ssl_encryption_level_t {
+     ssl_encryption_initial = 0,
+     ssl_encryption_early_data,
+diff --git a/include/openssl/types.h b/include/openssl/types.h
+index 31d8c18746..5f9d8c23ea 100644
+--- a/include/openssl/types.h
++++ b/include/openssl/types.h
+@@ -232,8 +232,6 @@ typedef struct ossl_decoder_ctx_st OSSL_DECODER_CTX;
+ 
+ typedef struct ossl_self_test_st OSSL_SELF_TEST;
+ 
+-typedef struct ssl_quic_method_st SSL_QUIC_METHOD;
+-
+ #ifdef  __cplusplus
+ }
+ #endif
+-- 
+2.42.0
+
diff --git a/0047-QUIC-Update-RFC-references.patch b/0047-QUIC-Update-RFC-references.patch
new file mode 100644
index 0000000..2d975f0
--- /dev/null
+++ b/0047-QUIC-Update-RFC-references.patch
@@ -0,0 +1,112 @@
+From 12f5f6d298f043d13f552725bc101c3de859c227 Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Tue, 7 Sep 2021 12:26:10 -0400
+Subject: [PATCH 47/63] QUIC: Update RFC references
+
+---
+ doc/man3/SSL_CTX_set_quic_method.pod | 11 +++++------
+ include/openssl/tls1.h               |  2 +-
+ ssl/statem/extensions_clnt.c         |  2 +-
+ ssl/statem/extensions_srvr.c         |  2 +-
+ ssl/statem/statem_clnt.c             |  2 +-
+ 5 files changed, 9 insertions(+), 10 deletions(-)
+
+diff --git a/doc/man3/SSL_CTX_set_quic_method.pod b/doc/man3/SSL_CTX_set_quic_method.pod
+index 906c7591d9..e38f1d2124 100644
+--- a/doc/man3/SSL_CTX_set_quic_method.pod
++++ b/doc/man3/SSL_CTX_set_quic_method.pod
+@@ -74,7 +74,7 @@ SSL_quic_max_handshake_flight_len() 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 https://tools.ietf.org/html/draft-ietf-quic-transport-27#section-4.
++See L<https://tools.ietf.org/html/RFC9000#section-4>.
+ 
+ SSL_quic_read_level() returns the current read encryption level.
+ 
+@@ -120,7 +120,7 @@ These APIs are implementations of BoringSSL's QUIC APIs.
+ 
+ QUIC acts as an underlying transport for the TLS 1.3 handshake. The following
+ functions allow a QUIC implementation to serve as the underlying transport as
+-described in draft-ietf-quic-tls.
++described in RFC9001.
+ 
+ When configured for QUIC, SSL_do_handshake() will drive the handshake as
+ before, but it will not use the configured B<BIO>. It will call functions from
+@@ -139,18 +139,17 @@ pass the active write level to add_handshake_data() when writing data. Callers
+ can use SSL_quic_write_level() to query the active write level when
+ generating their own errors.
+ 
+-See https://tools.ietf.org/html/draft-ietf-quic-tls-27#section-4.1 for more
+-details.
++See L<https://tools.ietf.org/html/RFC9001#section-4.1> for more details.
+ 
+ To avoid DoS attacks, the QUIC implementation must limit the amount of data
+ being queued up. The implementation can call
+ SSL_quic_max_handshake_flight_len() to get the maximum buffer length at each
+ encryption level.
+ 
+-draft-ietf-quic-tls defines a new TLS extension "quic_transport_parameters"
++RFC9001 defines a new TLS extension "quic_transport_parameters"
+ used by QUIC for each endpoint to unilaterally declare its supported
+ transport parameters. The contents of the extension are specified in
+-https://tools.ietf.org/html/draft-ietf-quic-transport-27#section-18 (as
++L<https://tools.ietf.org/html/RFC9000#section-18> (as
+ a sequence of tag/length/value parameters) along with the interpretation of the
+ various parameters and the rules for their processing.
+ 
+diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h
+index 54b6621aa3..ee96842e94 100644
+--- a/include/openssl/tls1.h
++++ b/include/openssl/tls1.h
+@@ -151,7 +151,7 @@ extern "C" {
+ /* Temporary extension type */
+ # define TLSEXT_TYPE_renegotiate                 0xff01
+ 
+-/* ExtensionType value from draft-ietf-quic-tls-27 */
++    /* ExtensionType value from RFC9001 */
+ # define TLSEXT_TYPE_quic_transport_parameters_draft   0xffa5
+ # define TLSEXT_TYPE_quic_transport_parameters         0x0039
+ 
+diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c
+index 6da3cc560f..e7c54e633e 100644
+--- a/ssl/statem/extensions_clnt.c
++++ b/ssl/statem/extensions_clnt.c
+@@ -1942,7 +1942,7 @@ int tls_parse_stoc_early_data(SSL *s, PACKET *pkt, unsigned int context,
+ #ifndef OPENSSL_NO_QUIC
+         /*
+          * QUIC server must send 0xFFFFFFFF or it's a PROTOCOL_VIOLATION
+-         * per draft-ietf-quic-tls-27 S4.5
++         * per RFC9001 S4.6.1
+          */
+         if (s->quic_method != NULL && max_early_data != 0xFFFFFFFF) {
+             SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_INVALID_MAX_EARLY_DATA);
+diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c
+index c23b35593f..a90d15d7df 100644
+--- a/ssl/statem/extensions_srvr.c
++++ b/ssl/statem/extensions_srvr.c
+@@ -1911,7 +1911,7 @@ EXT_RETURN tls_construct_stoc_early_data(SSL *s, WPACKET *pkt,
+             return EXT_RETURN_NOT_SENT;
+ 
+ #ifndef OPENSSL_NO_QUIC
+-        /* QUIC server must always send 0xFFFFFFFF, per draft-ietf-quic-tls-27 S4.5 */
++        /* QUIC server must always send 0xFFFFFFFF, per RFC9001 S4.6.1 */
+         if (SSL_IS_QUIC(s))
+             max_early_data = 0xFFFFFFFF;
+ #endif
+diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
+index 36cbba2a50..f9235d4160 100644
+--- a/ssl/statem/statem_clnt.c
++++ b/ssl/statem/statem_clnt.c
+@@ -905,7 +905,7 @@ int ossl_statem_client_construct_message(SSL *s, WPACKET *pkt,
+ 
+     case TLS_ST_CW_END_OF_EARLY_DATA:
+ #ifndef OPENSSL_NO_QUIC
+-        /* QUIC does not send EndOfEarlyData, draft-ietf-quic-tls-24 S8.3 */
++        /* QUIC does not send EndOfEarlyData, RFC9001 S8.3 */
+         if (s->quic_method != NULL) {
+             *confunc = NULL;
+             *mt = SSL3_MT_DUMMY;
+-- 
+2.42.0
+
diff --git a/0048-QUIC-revert-white-space-change.patch b/0048-QUIC-revert-white-space-change.patch
new file mode 100644
index 0000000..3e9668b
--- /dev/null
+++ b/0048-QUIC-revert-white-space-change.patch
@@ -0,0 +1,24 @@
+From 941ac4b890c4e24ce0cce3f1930c07c90217c4ae Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Tue, 7 Sep 2021 12:29:37 -0400
+Subject: [PATCH 48/63] QUIC: revert white-space change
+
+---
+ include/openssl/evp.h | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/include/openssl/evp.h b/include/openssl/evp.h
+index db38e5d921..86f4e22c70 100644
+--- a/include/openssl/evp.h
++++ b/include/openssl/evp.h
+@@ -1742,7 +1742,6 @@ int EVP_PKEY_CTX_set_mac_key(EVP_PKEY_CTX *ctx, const unsigned char *key,
+  * Method handles all operations: don't assume any digest related defaults.
+  */
+ # define EVP_PKEY_FLAG_SIGCTX_CUSTOM     4
+-
+ # ifndef OPENSSL_NO_DEPRECATED_3_0
+ OSSL_DEPRECATEDIN_3_0 const EVP_PKEY_METHOD *EVP_PKEY_meth_find(int type);
+ OSSL_DEPRECATEDIN_3_0 EVP_PKEY_METHOD *EVP_PKEY_meth_new(int id, int flags);
+-- 
+2.42.0
+
diff --git a/0049-QUIC-update-copyrights.patch b/0049-QUIC-update-copyrights.patch
new file mode 100644
index 0000000..f79daa4
--- /dev/null
+++ b/0049-QUIC-update-copyrights.patch
@@ -0,0 +1,49 @@
+From 5164990766f47f47af1f546fe3c0f0acbff2b7e2 Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Tue, 7 Sep 2021 12:32:54 -0400
+Subject: [PATCH 49/63] QUIC: update copyrights
+
+---
+ doc/man3/SSL_CTX_set_quic_method.pod | 2 +-
+ ssl/ssl_quic.c                       | 2 +-
+ ssl/statem/statem_quic.c             | 2 +-
+ 3 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/doc/man3/SSL_CTX_set_quic_method.pod b/doc/man3/SSL_CTX_set_quic_method.pod
+index e38f1d2124..b9191a0264 100644
+--- a/doc/man3/SSL_CTX_set_quic_method.pod
++++ b/doc/man3/SSL_CTX_set_quic_method.pod
+@@ -257,7 +257,7 @@ These functions were added in OpenSSL 3.0.0.
+ 
+ =head1 COPYRIGHT
+ 
+-Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
++Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved.
+ 
+ Licensed under the Apache License 2.0 (the "License").  You may not use
+ this file except in compliance with the License.  You can obtain a copy
+diff --git a/ssl/ssl_quic.c b/ssl/ssl_quic.c
+index 6cbd47ad2d..987c1e740c 100644
+--- a/ssl/ssl_quic.c
++++ b/ssl/ssl_quic.c
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
++ * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved.
+  *
+  * Licensed under the Apache License 2.0 (the "License").  You may not use
+  * this file except in compliance with the License.  You can obtain a copy
+diff --git a/ssl/statem/statem_quic.c b/ssl/statem/statem_quic.c
+index a51bfd74d8..7bd329c242 100644
+--- a/ssl/statem/statem_quic.c
++++ b/ssl/statem/statem_quic.c
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
++ * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved.
+  *
+  * Licensed under the Apache License 2.0 (the "License").  You may not use
+  * this file except in compliance with the License.  You can obtain a copy
+-- 
+2.42.0
+
diff --git a/0050-QUIC-update-SSL_provide_quic_data-documentation.patch b/0050-QUIC-update-SSL_provide_quic_data-documentation.patch
new file mode 100644
index 0000000..7aec907
--- /dev/null
+++ b/0050-QUIC-update-SSL_provide_quic_data-documentation.patch
@@ -0,0 +1,34 @@
+From 49c1562e8d9ecba4239405abb1426bdfe11b82f7 Mon Sep 17 00:00:00 2001
+From: Benjamin Kaduk <bkaduk@akamai.com>
+Date: Tue, 7 Sep 2021 09:17:39 -0700
+Subject: [PATCH 50/63] QUIC: update SSL_provide_quic_data() documentation
+
+We now let you call this function outside of the handshake, to provide
+post-handshake QUIC data.
+
+We also no longer have the limitation that the application must provide
+the TLS handshake message header in a single call.
+---
+ doc/man3/SSL_CTX_set_quic_method.pod | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+diff --git a/doc/man3/SSL_CTX_set_quic_method.pod b/doc/man3/SSL_CTX_set_quic_method.pod
+index b9191a0264..b2d78872ca 100644
+--- a/doc/man3/SSL_CTX_set_quic_method.pod
++++ b/doc/man3/SSL_CTX_set_quic_method.pod
+@@ -82,10 +82,8 @@ SSL_quic_write_level() returns the current write encryption level.
+ 
+ SSL_provide_quic_data() is used to provide data from QUIC CRYPTO frames to the
+ state machine, at a particular encryption level B<level>. It is an error to
+-call this function outside of the handshake or with an encryption level other
+-than the current read level. The application must buffer and consolidate any
+-frames with less than four bytes of content.  It returns one on success and
+-zero on error.
++call this function with an encryption level less than the current read level.
++It returns one on success and zero on error.
+ 
+ SSL_process_quic_post_handshake() processes any data that QUIC has provided
+ after the handshake has completed. This includes NewSessionTicket messages
+-- 
+2.42.0
+
diff --git a/0051-QUIC-expound-on-what-DoS-attacks-QUIC-avoids.patch b/0051-QUIC-expound-on-what-DoS-attacks-QUIC-avoids.patch
new file mode 100644
index 0000000..418ad66
--- /dev/null
+++ b/0051-QUIC-expound-on-what-DoS-attacks-QUIC-avoids.patch
@@ -0,0 +1,29 @@
+From e0900dbdeb1888fdb65af501ad8454463ef9a214 Mon Sep 17 00:00:00 2001
+From: Benjamin Kaduk <bkaduk@akamai.com>
+Date: Tue, 7 Sep 2021 09:17:56 -0700
+Subject: [PATCH 51/63] QUIC: expound on what DoS attacks QUIC avoids
+
+The limit on the amount of queued data is to avoid being an amplification
+vector, specifically.
+---
+ doc/man3/SSL_CTX_set_quic_method.pod | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/doc/man3/SSL_CTX_set_quic_method.pod b/doc/man3/SSL_CTX_set_quic_method.pod
+index b2d78872ca..1ed076c301 100644
+--- a/doc/man3/SSL_CTX_set_quic_method.pod
++++ b/doc/man3/SSL_CTX_set_quic_method.pod
+@@ -139,8 +139,8 @@ generating their own errors.
+ 
+ See L<https://tools.ietf.org/html/RFC9001#section-4.1> for more details.
+ 
+-To avoid DoS attacks, the QUIC implementation must limit the amount of data
+-being queued up. The implementation can call
++To avoid amplifying DoS attacks, the QUIC implementation must limit the amount
++of data being queued up. The implementation can call
+ SSL_quic_max_handshake_flight_len() to get the maximum buffer length at each
+ encryption level.
+ 
+-- 
+2.42.0
+
diff --git a/0052-QUIC-remove-SSL_get_current_cipher-reference.patch b/0052-QUIC-remove-SSL_get_current_cipher-reference.patch
new file mode 100644
index 0000000..fb33c86
--- /dev/null
+++ b/0052-QUIC-remove-SSL_get_current_cipher-reference.patch
@@ -0,0 +1,28 @@
+From fae17dc5d279bc6de0ad045c87a6e224a62b3730 Mon Sep 17 00:00:00 2001
+From: Benjamin Kaduk <bkaduk@akamai.com>
+Date: Tue, 7 Sep 2021 09:20:44 -0700
+Subject: [PATCH 52/63] QUIC: remove SSL_get_current_cipher() reference
+
+The QUIC APIs have no need to interact with TLS ciphers, since
+QUIC records use different cryptographic protections than TLS ciphers.
+---
+ doc/man3/SSL_CTX_set_quic_method.pod | 3 ---
+ 1 file changed, 3 deletions(-)
+
+diff --git a/doc/man3/SSL_CTX_set_quic_method.pod b/doc/man3/SSL_CTX_set_quic_method.pod
+index 1ed076c301..f12aa8662b 100644
+--- a/doc/man3/SSL_CTX_set_quic_method.pod
++++ b/doc/man3/SSL_CTX_set_quic_method.pod
+@@ -209,9 +209,6 @@ only available in the client to server direction. The other secret will be
+ NULL. The server acknowledges such data at B<ssl_encryption_application>,
+ which will be configured in the same SSL_do_handshake() call.
+ 
+-This function should use SSL_get_current_cipher() to determine the TLS
+-cipher suite.
+-
+ add_handshake_data() adds handshake data to the current flight at the given
+ encryption level. It returns one on success and zero on error.
+ 
+-- 
+2.42.0
+
diff --git a/0053-QUIC-use-SSL_IS_QUIC-in-more-places.patch b/0053-QUIC-use-SSL_IS_QUIC-in-more-places.patch
new file mode 100644
index 0000000..440cdfd
--- /dev/null
+++ b/0053-QUIC-use-SSL_IS_QUIC-in-more-places.patch
@@ -0,0 +1,53 @@
+From 6f0a1d5c216d28997e1fd4590b194e70a921779d Mon Sep 17 00:00:00 2001
+From: Benjamin Kaduk <bkaduk@akamai.com>
+Date: Tue, 7 Sep 2021 14:21:22 -0700
+Subject: [PATCH 53/63] QUIC: use SSL_IS_QUIC() in more places
+
+---
+ doc/man3/SSL_CTX_set_quic_method.pod | 2 +-
+ ssl/statem/extensions_clnt.c         | 2 +-
+ ssl/statem/statem_clnt.c             | 2 +-
+ 3 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/doc/man3/SSL_CTX_set_quic_method.pod b/doc/man3/SSL_CTX_set_quic_method.pod
+index f12aa8662b..aab5e38889 100644
+--- a/doc/man3/SSL_CTX_set_quic_method.pod
++++ b/doc/man3/SSL_CTX_set_quic_method.pod
+@@ -103,7 +103,7 @@ the client will send both extensions.
+ SSL_get_quic_transport_version() returns the value set by
+ SSL_set_quic_transport_version().
+ 
+-SSL_get_peer_quic_transport_version() returns the version the that was 
++SSL_get_peer_quic_transport_version() returns the version the that was
+ negotiated.
+ 
+ SSL_set_quic_early_data_enabled() enables QUIC early data if a nonzero
+diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c
+index e7c54e633e..caeb818a37 100644
+--- a/ssl/statem/extensions_clnt.c
++++ b/ssl/statem/extensions_clnt.c
+@@ -1944,7 +1944,7 @@ int tls_parse_stoc_early_data(SSL *s, PACKET *pkt, unsigned int context,
+          * QUIC server must send 0xFFFFFFFF or it's a PROTOCOL_VIOLATION
+          * per RFC9001 S4.6.1
+          */
+-        if (s->quic_method != NULL && max_early_data != 0xFFFFFFFF) {
++        if (SSL_IS_QUIC(s) && max_early_data != 0xFFFFFFFF) {
+             SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_INVALID_MAX_EARLY_DATA);
+             return 0;
+         }
+diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
+index f9235d4160..9d925091b6 100644
+--- a/ssl/statem/statem_clnt.c
++++ b/ssl/statem/statem_clnt.c
+@@ -906,7 +906,7 @@ int ossl_statem_client_construct_message(SSL *s, WPACKET *pkt,
+     case TLS_ST_CW_END_OF_EARLY_DATA:
+ #ifndef OPENSSL_NO_QUIC
+         /* QUIC does not send EndOfEarlyData, RFC9001 S8.3 */
+-        if (s->quic_method != NULL) {
++        if (SSL_IS_QUIC(s)) {
+             *confunc = NULL;
+             *mt = SSL3_MT_DUMMY;
+             break;
+-- 
+2.42.0
+
diff --git a/0054-QUIC-Error-when-non-empty-session_id-in-CH-fixes-29.patch b/0054-QUIC-Error-when-non-empty-session_id-in-CH-fixes-29.patch
new file mode 100644
index 0000000..1801e65
--- /dev/null
+++ b/0054-QUIC-Error-when-non-empty-session_id-in-CH-fixes-29.patch
@@ -0,0 +1,32 @@
+From 9a392d282e622730686a643dffcdfebd034794b1 Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Mon, 18 Oct 2021 16:54:31 -0400
+Subject: [PATCH 54/63] QUIC: Error when non-empty session_id in CH (fixes #29)
+
+---
+ ssl/statem/statem_srvr.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
+index e92b0e736e..f7d81370d8 100644
+--- a/ssl/statem/statem_srvr.c
++++ b/ssl/statem/statem_srvr.c
+@@ -1566,6 +1566,15 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt)
+                 goto err;
+             }
+         }
++#ifndef OPENSSL_NO_QUIC
++        if (SSL_IS_QUIC(s)) {
++            /* Any other QUIC checks on ClientHello here */
++            if (clienthello->session_id_len > 0) {
++                SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_LENGTH_MISMATCH);
++                goto err;
++            }
++        }
++#endif
+     }
+ 
+     if (!PACKET_copy_all(&compression, clienthello->compressions,
+-- 
+2.42.0
+
diff --git a/0055-QUIC-Update-SSL_clear-to-clear-quic-data.patch b/0055-QUIC-Update-SSL_clear-to-clear-quic-data.patch
new file mode 100644
index 0000000..f4cc146
--- /dev/null
+++ b/0055-QUIC-Update-SSL_clear-to-clear-quic-data.patch
@@ -0,0 +1,140 @@
+From 1493e2f43d4aedd088b75062301771aa917a1a3d Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Tue, 19 Oct 2021 12:13:31 -0400
+Subject: [PATCH 55/63] QUIC: Update SSL_clear() to clear quic data
+
+Fixes #55
+Had to fixup tests because SSL_accept() eventually calls SSL_clear() and
+it was removing the inital ClientHello sent via SSL_provide_quic_data()
+from the server SSL.
+---
+ ssl/ssl_lib.c             | 32 ++++++++++++++++++++++++++++++++
+ test/helpers/ssltestlib.c |  5 -----
+ test/sslapitest.c         | 19 ++++++++++++++-----
+ 3 files changed, 46 insertions(+), 10 deletions(-)
+
+diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
+index 9c03564557..3d1734b7cd 100644
+--- a/ssl/ssl_lib.c
++++ b/ssl/ssl_lib.c
+@@ -626,6 +626,38 @@ int SSL_clear(SSL *s)
+     s->shared_sigalgs = NULL;
+     s->shared_sigalgslen = 0;
+ 
++#if !defined(OPENSSL_NO_QUIC)
++    OPENSSL_free(s->ext.peer_quic_transport_params_draft);
++    s->ext.peer_quic_transport_params_draft = NULL;
++    s->ext.peer_quic_transport_params_draft_len = 0;
++    OPENSSL_free(s->ext.peer_quic_transport_params);
++    s->ext.peer_quic_transport_params = NULL;
++    s->ext.peer_quic_transport_params_len = 0;
++    s->quic_read_level = ssl_encryption_initial;
++    s->quic_write_level = ssl_encryption_initial;
++    s->quic_latest_level_received = ssl_encryption_initial;
++    while (s->quic_input_data_head != NULL) {
++        QUIC_DATA *qd;
++
++        qd = s->quic_input_data_head;
++        s->quic_input_data_head = qd->next;
++        OPENSSL_free(qd);
++    }
++    s->quic_input_data_tail = NULL;
++    BUF_MEM_free(s->quic_buf);
++    s->quic_buf = NULL;
++    s->quic_next_record_start = 0;
++    memset(s->client_hand_traffic_secret, 0, EVP_MAX_MD_SIZE);
++    memset(s->server_hand_traffic_secret, 0, EVP_MAX_MD_SIZE);
++    memset(s->client_early_traffic_secret, 0, EVP_MAX_MD_SIZE);
++    /*
++     * CONFIG - DON'T CLEAR
++     * s->ext.quic_transport_params
++     * s->ext.quic_transport_params_len
++     * s->quic_transport_version
++     * s->quic_method = NULL;
++     */
++#endif
+     /*
+      * Check to see if we were changed into a different method, if so, revert
+      * back.
+diff --git a/test/helpers/ssltestlib.c b/test/helpers/ssltestlib.c
+index c317e03d8e..f0dccfa54c 100644
+--- a/test/helpers/ssltestlib.c
++++ b/test/helpers/ssltestlib.c
+@@ -1157,11 +1157,6 @@ int create_ssl_connection(SSL *serverssl, SSL *clientssl, int want)
+     if (!create_bare_ssl_connection(serverssl, clientssl, want, 1))
+         return 0;
+ 
+-#ifndef OPENSSL_NO_QUIC
+-    /* QUIC does not support SSL_read_ex */
+-    if (SSL_is_quic(clientssl))
+-        return 1;
+-#endif
+     /*
+      * We attempt to read some data on the client side which we expect to fail.
+      * This will ensure we have received the NewSessionTicket in TLSv1.3 where
+diff --git a/test/sslapitest.c b/test/sslapitest.c
+index e351a0b4e6..977eee0d4b 100644
+--- a/test/sslapitest.c
++++ b/test/sslapitest.c
+@@ -10198,6 +10198,7 @@ static int test_quic_api_version(int clnt, int srvr)
+     static const char *client_str = "CLIENT";
+     const uint8_t *peer_str;
+     size_t peer_str_len;
++    int err;
+ 
+     TEST_info("original clnt=0x%X, srvr=0x%X\n", clnt, srvr);
+ 
+@@ -10220,8 +10221,10 @@ static int test_quic_api_version(int clnt, int srvr)
+             || !TEST_true(SSL_set_app_data(clientssl, serverssl))
+             || !TEST_true(test_quic_api_set_versions(clientssl, clnt))
+             || !TEST_true(test_quic_api_set_versions(serverssl, srvr))
+-            || !TEST_true(create_ssl_connection(serverssl, clientssl,
+-                                                SSL_ERROR_NONE))
++            || !TEST_int_eq(err = SSL_accept(serverssl), -1)
++            || !TEST_int_eq(SSL_get_error(serverssl, err), SSL_ERROR_WANT_READ)
++            || !TEST_true(create_bare_ssl_connection(serverssl, clientssl,
++                                              SSL_ERROR_NONE, 0))
+             || !TEST_true(SSL_version(serverssl) == TLS1_3_VERSION)
+             || !TEST_true(SSL_version(clientssl) == TLS1_3_VERSION)
+             || !(TEST_int_eq(SSL_quic_read_level(clientssl), ssl_encryption_application))
+@@ -10348,6 +10351,7 @@ static int quic_setupearly_data_test(SSL_CTX **cctx, SSL_CTX **sctx,
+ {
+     static const char *server_str = "SERVER";
+     static const char *client_str = "CLIENT";
++    int err;
+ 
+     if (*sctx == NULL
+             && (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(),
+@@ -10425,8 +10429,10 @@ static int quic_setupearly_data_test(SSL_CTX **cctx, SSL_CTX **sctx,
+     if (sess == NULL)
+         return 1;
+ 
+-    if (!TEST_true(create_ssl_connection(*serverssl, *clientssl,
+-                                         SSL_ERROR_NONE)))
++    if (!TEST_int_eq(err = SSL_accept(*serverssl), -1)
++            || !TEST_int_eq(SSL_get_error(*serverssl, err), SSL_ERROR_WANT_READ)
++            || !TEST_true(create_bare_ssl_connection(*serverssl, *clientssl,
++                                                     SSL_ERROR_NONE, 0)))
+         return 0;
+ 
+     /* Deal with two NewSessionTickets */
+@@ -10465,12 +10471,15 @@ static int test_quic_early_data(int tst)
+     SSL *clientssl = NULL, *serverssl = NULL;
+     int testresult = 0;
+     SSL_SESSION *sess = NULL;
++    int err;
+ 
+     if (!TEST_true(quic_setupearly_data_test(&cctx, &sctx, &clientssl,
+                                              &serverssl, &sess, tst)))
+         goto end;
+ 
+-    if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE))
++    if (!TEST_int_eq(err = SSL_accept(serverssl), -1)
++            || !TEST_int_eq(SSL_get_error(serverssl, err), SSL_ERROR_WANT_READ)
++            || !TEST_true(create_bare_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE, 0))
+             || !TEST_true(SSL_get_early_data_status(serverssl)))
+         goto end;
+ 
+-- 
+2.42.0
+
diff --git a/0056-QUIC-Better-SSL_clear.patch b/0056-QUIC-Better-SSL_clear.patch
new file mode 100644
index 0000000..9c0bf54
--- /dev/null
+++ b/0056-QUIC-Better-SSL_clear.patch
@@ -0,0 +1,216 @@
+From b90c5da95a0074369b390abce0f1522006c5d632 Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Fri, 29 Oct 2021 14:15:06 -0400
+Subject: [PATCH 56/63] QUIC: Better SSL_clear()
+
+Undo SSL_clear() changes in test
+Break apart SSL_clear() into SSL_clear_quic() and SSL_clear_not_quic()
+In SSL_clear(), call both functions
+In SSL_accept(), call SSL_clear_not_quic()
+Don't make the new functions public.
+---
+ ssl/ssl_lib.c       | 81 +++++++++++++++++++++++++++------------------
+ ssl/ssl_local.h     |  5 +++
+ ssl/statem/statem.c |  5 +++
+ test/sslapitest.c   | 17 +++-------
+ 4 files changed, 63 insertions(+), 45 deletions(-)
+
+diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
+index 3d1734b7cd..e636383e76 100644
+--- a/ssl/ssl_lib.c
++++ b/ssl/ssl_lib.c
+@@ -567,7 +567,56 @@ static void clear_ciphers(SSL *s)
+     ssl_clear_hash_ctx(&s->write_hash);
+ }
+ 
++#ifndef OPENSSL_NO_QUIC
+ int SSL_clear(SSL *s)
++{
++    if (!SSL_clear_not_quic(s))
++        return 0;
++    return SSL_clear_quic(s);
++}
++
++int SSL_clear_quic(SSL *s)
++{
++    OPENSSL_free(s->ext.peer_quic_transport_params_draft);
++    s->ext.peer_quic_transport_params_draft = NULL;
++    s->ext.peer_quic_transport_params_draft_len = 0;
++    OPENSSL_free(s->ext.peer_quic_transport_params);
++    s->ext.peer_quic_transport_params = NULL;
++    s->ext.peer_quic_transport_params_len = 0;
++    s->quic_read_level = ssl_encryption_initial;
++    s->quic_write_level = ssl_encryption_initial;
++    s->quic_latest_level_received = ssl_encryption_initial;
++    while (s->quic_input_data_head != NULL) {
++        QUIC_DATA *qd;
++
++        qd = s->quic_input_data_head;
++        s->quic_input_data_head = qd->next;
++        OPENSSL_free(qd);
++    }
++    s->quic_input_data_tail = NULL;
++    BUF_MEM_free(s->quic_buf);
++    s->quic_buf = NULL;
++    s->quic_next_record_start = 0;
++    memset(s->client_hand_traffic_secret, 0, EVP_MAX_MD_SIZE);
++    memset(s->server_hand_traffic_secret, 0, EVP_MAX_MD_SIZE);
++    memset(s->client_early_traffic_secret, 0, EVP_MAX_MD_SIZE);
++    /*
++     * CONFIG - DON'T CLEAR
++     * s->ext.quic_transport_params
++     * s->ext.quic_transport_params_len
++     * s->quic_transport_version
++     * s->quic_method = NULL;
++     */
++    return 1;
++}
++#endif
++
++/* Keep this conditional very local */
++#ifndef OPENSSL_NO_QUIC
++int SSL_clear_not_quic(SSL *s)
++#else
++int SSL_clear(SSL *s)
++#endif
+ {
+     if (s->method == NULL) {
+         ERR_raise(ERR_LIB_SSL, SSL_R_NO_METHOD_SPECIFIED);
+@@ -626,38 +675,6 @@ int SSL_clear(SSL *s)
+     s->shared_sigalgs = NULL;
+     s->shared_sigalgslen = 0;
+ 
+-#if !defined(OPENSSL_NO_QUIC)
+-    OPENSSL_free(s->ext.peer_quic_transport_params_draft);
+-    s->ext.peer_quic_transport_params_draft = NULL;
+-    s->ext.peer_quic_transport_params_draft_len = 0;
+-    OPENSSL_free(s->ext.peer_quic_transport_params);
+-    s->ext.peer_quic_transport_params = NULL;
+-    s->ext.peer_quic_transport_params_len = 0;
+-    s->quic_read_level = ssl_encryption_initial;
+-    s->quic_write_level = ssl_encryption_initial;
+-    s->quic_latest_level_received = ssl_encryption_initial;
+-    while (s->quic_input_data_head != NULL) {
+-        QUIC_DATA *qd;
+-
+-        qd = s->quic_input_data_head;
+-        s->quic_input_data_head = qd->next;
+-        OPENSSL_free(qd);
+-    }
+-    s->quic_input_data_tail = NULL;
+-    BUF_MEM_free(s->quic_buf);
+-    s->quic_buf = NULL;
+-    s->quic_next_record_start = 0;
+-    memset(s->client_hand_traffic_secret, 0, EVP_MAX_MD_SIZE);
+-    memset(s->server_hand_traffic_secret, 0, EVP_MAX_MD_SIZE);
+-    memset(s->client_early_traffic_secret, 0, EVP_MAX_MD_SIZE);
+-    /*
+-     * CONFIG - DON'T CLEAR
+-     * s->ext.quic_transport_params
+-     * s->ext.quic_transport_params_len
+-     * s->quic_transport_version
+-     * s->quic_method = NULL;
+-     */
+-#endif
+     /*
+      * Check to see if we were changed into a different method, if so, revert
+      * back.
+diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h
+index 9bbc528dd9..3fb1f0956f 100644
+--- a/ssl/ssl_local.h
++++ b/ssl/ssl_local.h
+@@ -2867,6 +2867,11 @@ void custom_exts_free(custom_ext_methods *exts);
+ 
+ void ssl_comp_free_compression_methods_int(void);
+ 
++#ifndef OPENSSL_NO_QUIC
++__owur int SSL_clear_not_quic(SSL *s);
++__owur int SSL_clear_quic(SSL *s);
++#endif
++
+ /* ssl_mcnf.c */
+ void ssl_ctx_system_config(SSL_CTX *ctx);
+ 
+diff --git a/ssl/statem/statem.c b/ssl/statem/statem.c
+index e67ee26e87..d80d4da203 100644
+--- a/ssl/statem/statem.c
++++ b/ssl/statem/statem.c
+@@ -334,8 +334,13 @@ static int state_machine(SSL *s, int server)
+          * If we are stateless then we already called SSL_clear() - don't do
+          * it again and clear the STATELESS flag itself.
+          */
++#ifndef OPENSSL_NO_QUIC
++        if ((s->s3.flags & TLS1_FLAGS_STATELESS) == 0 && !SSL_clear_not_quic(s))
++            return -1;
++#else
+         if ((s->s3.flags & TLS1_FLAGS_STATELESS) == 0 && !SSL_clear(s))
+             return -1;
++#endif
+     }
+ #ifndef OPENSSL_NO_SCTP
+     if (SSL_IS_DTLS(s) && BIO_dgram_is_sctp(SSL_get_wbio(s))) {
+diff --git a/test/sslapitest.c b/test/sslapitest.c
+index 977eee0d4b..5d2a754043 100644
+--- a/test/sslapitest.c
++++ b/test/sslapitest.c
+@@ -10198,7 +10198,6 @@ static int test_quic_api_version(int clnt, int srvr)
+     static const char *client_str = "CLIENT";
+     const uint8_t *peer_str;
+     size_t peer_str_len;
+-    int err;
+ 
+     TEST_info("original clnt=0x%X, srvr=0x%X\n", clnt, srvr);
+ 
+@@ -10221,10 +10220,8 @@ static int test_quic_api_version(int clnt, int srvr)
+             || !TEST_true(SSL_set_app_data(clientssl, serverssl))
+             || !TEST_true(test_quic_api_set_versions(clientssl, clnt))
+             || !TEST_true(test_quic_api_set_versions(serverssl, srvr))
+-            || !TEST_int_eq(err = SSL_accept(serverssl), -1)
+-            || !TEST_int_eq(SSL_get_error(serverssl, err), SSL_ERROR_WANT_READ)
+             || !TEST_true(create_bare_ssl_connection(serverssl, clientssl,
+-                                              SSL_ERROR_NONE, 0))
++                                                     SSL_ERROR_NONE, 0))
+             || !TEST_true(SSL_version(serverssl) == TLS1_3_VERSION)
+             || !TEST_true(SSL_version(clientssl) == TLS1_3_VERSION)
+             || !(TEST_int_eq(SSL_quic_read_level(clientssl), ssl_encryption_application))
+@@ -10351,7 +10348,6 @@ static int quic_setupearly_data_test(SSL_CTX **cctx, SSL_CTX **sctx,
+ {
+     static const char *server_str = "SERVER";
+     static const char *client_str = "CLIENT";
+-    int err;
+ 
+     if (*sctx == NULL
+             && (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(),
+@@ -10429,10 +10425,8 @@ static int quic_setupearly_data_test(SSL_CTX **cctx, SSL_CTX **sctx,
+     if (sess == NULL)
+         return 1;
+ 
+-    if (!TEST_int_eq(err = SSL_accept(*serverssl), -1)
+-            || !TEST_int_eq(SSL_get_error(*serverssl, err), SSL_ERROR_WANT_READ)
+-            || !TEST_true(create_bare_ssl_connection(*serverssl, *clientssl,
+-                                                     SSL_ERROR_NONE, 0)))
++    if (!TEST_true(create_bare_ssl_connection(*serverssl, *clientssl,
++                                              SSL_ERROR_NONE, 0)))
+         return 0;
+ 
+     /* Deal with two NewSessionTickets */
+@@ -10471,15 +10465,12 @@ static int test_quic_early_data(int tst)
+     SSL *clientssl = NULL, *serverssl = NULL;
+     int testresult = 0;
+     SSL_SESSION *sess = NULL;
+-    int err;
+ 
+     if (!TEST_true(quic_setupearly_data_test(&cctx, &sctx, &clientssl,
+                                              &serverssl, &sess, tst)))
+         goto end;
+ 
+-    if (!TEST_int_eq(err = SSL_accept(serverssl), -1)
+-            || !TEST_int_eq(SSL_get_error(serverssl, err), SSL_ERROR_WANT_READ)
+-            || !TEST_true(create_bare_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE, 0))
++    if (!TEST_true(create_bare_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE, 0))
+             || !TEST_true(SSL_get_early_data_status(serverssl)))
+         goto end;
+ 
+-- 
+2.42.0
+
diff --git a/0059-QUIC-Fix-extension-test.patch b/0059-QUIC-Fix-extension-test.patch
new file mode 100644
index 0000000..ddd0a2e
--- /dev/null
+++ b/0059-QUIC-Fix-extension-test.patch
@@ -0,0 +1,46 @@
+From d1ac5c28b113f9faebea2eadca9520bac580f931 Mon Sep 17 00:00:00 2001
+From: Todd Short <tshort@akamai.com>
+Date: Tue, 1 Nov 2022 12:55:46 -0400
+Subject: [PATCH 59/63] QUIC: Fix extension test
+
+---
+ ssl/ssl_local.h          | 4 ++--
+ test/ext_internal_test.c | 7 +++++++
+ 2 files changed, 9 insertions(+), 2 deletions(-)
+
+diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h
+index 3fb1f0956f..93f77f9612 100644
+--- a/ssl/ssl_local.h
++++ b/ssl/ssl_local.h
+@@ -773,8 +773,8 @@ typedef enum tlsext_index_en {
+     TLSEXT_IDX_cryptopro_bug,
+     TLSEXT_IDX_early_data,
+     TLSEXT_IDX_certificate_authorities,
+-    TLSEXT_IDX_quic_transport_params_draft,
+-    TLSEXT_IDX_quic_transport_params,
++    TLSEXT_IDX_quic_transport_parameters_draft,
++    TLSEXT_IDX_quic_transport_parameters,
+     TLSEXT_IDX_padding,
+     TLSEXT_IDX_psk,
+     /* Dummy index - must always be the last entry */
+diff --git a/test/ext_internal_test.c b/test/ext_internal_test.c
+index dec6ee61ef..769b25391d 100644
+--- a/test/ext_internal_test.c
++++ b/test/ext_internal_test.c
+@@ -69,6 +69,13 @@ static EXT_LIST ext_list[] = {
+     EXT_ENTRY(cryptopro_bug),
+     EXT_ENTRY(early_data),
+     EXT_ENTRY(certificate_authorities),
++#ifndef OPENSSL_NO_QUIC
++    EXT_ENTRY(quic_transport_parameters_draft),
++    EXT_ENTRY(quic_transport_parameters),
++#else
++    EXT_EXCEPTION(quic_transport_parameters_draft),
++    EXT_EXCEPTION(quic_transport_parameters),
++#endif
+     EXT_ENTRY(padding),
+     EXT_ENTRY(psk),
+     EXT_END(num_builtins)
+-- 
+2.42.0
+
diff --git a/0063-QUIC-Fix-use-of-create_a_psk.patch b/0063-QUIC-Fix-use-of-create_a_psk.patch
new file mode 100644
index 0000000..d283b28
--- /dev/null
+++ b/0063-QUIC-Fix-use-of-create_a_psk.patch
@@ -0,0 +1,25 @@
+From ee904e9093c377d0919a65dae9e06530c4459c6b Mon Sep 17 00:00:00 2001
+From: Todd Short <todd.short@me.com>
+Date: Tue, 1 Aug 2023 13:59:55 -0400
+Subject: [PATCH 63/63] QUIC: Fix use of create_a_psk
+
+---
+ test/sslapitest.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/test/sslapitest.c b/test/sslapitest.c
+index 5d2a754043..18d7941d2d 100644
+--- a/test/sslapitest.c
++++ b/test/sslapitest.c
+@@ -10395,7 +10395,7 @@ static int quic_setupearly_data_test(SSL_CTX **cctx, SSL_CTX **sctx,
+         return 0;
+ 
+     if (idx == 2) {
+-        clientpsk = create_a_psk(*clientssl);
++      clientpsk = create_a_psk(*clientssl, SHA384_DIGEST_LENGTH);
+         if (!TEST_ptr(clientpsk)
+                 || !TEST_true(SSL_SESSION_set_max_early_data(clientpsk,
+                                                              0xffffffffu))
+-- 
+2.42.0
+
diff --git a/openssl.spec b/openssl.spec
index 753af24..9ce01dd 100644
--- a/openssl.spec
+++ b/openssl.spec
@@ -6,15 +6,19 @@
 %endif
 
 # (tpg) enable PGO build
+%if %{cross_compiling}
+%bcond_with pgo
+%else
 %bcond_without pgo
+%endif
 
 %global optflags %{optflags} -O3
 
 # (tpg) use LLVM/polly for polyhedra optimization and automatic vector code generation
-%define pollyflags -mllvm -polly -mllvm -polly-run-dce -mllvm -polly-run-inliner -mllvm -polly-isl-arg=--no-schedule-serialize-sccs -mllvm -polly-ast-use-context -mllvm -polly-detect-keep-going -mllvm -polly-vectorizer=stripmine
-# "-mllvm -polly-invariant-load-hoisting" removed for now because of https://github.com/llvm/llvm-project/issues/57413
+%define pollyflags -mllvm -polly -mllvm -polly-position=early -mllvm -polly-parallel=true -fopenmp -fopenmp-version=50 -mllvm -polly-dependences-computeout=5000000 -mllvm -polly-detect-profitability-min-per-loop-insts=40 -mllvm -polly-tiling=true -mllvm -polly-prevect-width=256 -mllvm -polly-vectorizer=stripmine -mllvm -polly-omp-backend=LLVM -mllvm -polly-num-threads=0 -mllvm -polly-enable-delicm=true -mllvm -extra-vectorizer-passes -mllvm -enable-cond-stores-vec -mllvm -slp-vectorize-hor-store -mllvm -enable-loopinterchange -mllvm -enable-loop-distribute -mllvm -enable-unroll-and-jam -mllvm -enable-loop-flatten -mllvm -interleave-small-loop-scalar-reduction -mllvm -unroll-runtime-multi-exit -mllvm -aggressive-ext-opt -mllvm -polly-scheduling=dynamic -mllvm -polly-scheduling-chunksize=1 -mllvm -polly-invariant-load-hoisting -mllvm -polly-loopfusion-greedy -mllvm -polly-run-inliner
+# (tpg) 2022-11-21 this -mllvm -polly-run-dce causes segfault on aarch64
 
-#define beta beta2
+#define beta beta1
 %define major 3
 %define libssl %mklibname ssl %{major}
 %define libcrypto %mklibname crypto %{major}
@@ -26,12 +30,66 @@
 %define static32 libopenssl-static-devel
 
 Name:		openssl
-Version:	3.0.6
+Version:	3.1.5
 Release:	%{?beta:0.%{beta}.}1
 Group:		System/Libraries
 Summary:	The OpenSSL cryptography and TLS library
 Source0:	https://www.openssl.org/source/openssl-%{version}%{?beta:-%{beta}}.tar.gz
 Patch0:		openssl-3.0-additional-clang-targets.patch
+# QUIC support patches from https://github.com/quictls/openssl
+Patch1000:	0001-QUIC-Add-support-for-BoringSSL-QUIC-APIs.patch
+Patch1001:	0002-QUIC-New-method-to-get-QUIC-secret-length.patch
+Patch1002:	0003-QUIC-Make-temp-secret-names-less-confusing.patch
+Patch1003:	0004-QUIC-Move-QUIC-transport-params-to-encrypted-extensi.patch
+Patch1004:	0005-QUIC-Use-proper-secrets-for-handshake.patch
+Patch1005:	0006-QUIC-Handle-partial-handshake-messages.patch
+Patch1006:	0007-QUIC-Fix-duplicate-word-in-docs.patch
+Patch1007:	0008-QUIC-Fix-quic_transport-constructors-parsers.patch
+Patch1008:	0009-QUIC-Reset-init-state-in-SSL_process_quic_post_hands.patch
+Patch1009:	0010-QUIC-Don-t-process-an-incomplete-message.patch
+Patch1010:	0011-QUIC-Quick-fix-s2c-to-c2s-for-early-secret.patch
+Patch1011:	0012-QUIC-Add-client-early-traffic-secret-storage.patch
+Patch1012:	0013-QUIC-Add-OPENSSL_NO_QUIC-wrapper.patch
+Patch1013:	0014-QUIC-Correctly-disable-middlebox-compat.patch
+Patch1014:	0015-QUIC-Move-QUIC-code-out-of-tls13_change_cipher_state.patch
+Patch1015:	0016-QUIC-Tweeks-to-quic_change_cipher_state.patch
+Patch1016:	0017-QUIC-Add-support-for-more-secrets.patch
+Patch1017:	0018-QUIC-Fix-resumption-secret.patch
+Patch1018:	0019-QUIC-Handle-EndOfEarlyData-and-MaxEarlyData.patch
+Patch1019:	0020-QUIC-Fall-through-for-0RTT.patch
+Patch1020:	0021-QUIC-Some-cleanup-for-the-main-QUIC-changes.patch
+Patch1021:	0022-QUIC-Prevent-KeyUpdate-for-QUIC.patch
+Patch1022:	0023-QUIC-Test-KeyUpdate-rejection.patch
+Patch1023:	0024-QUIC-Buffer-all-provided-quic-data.patch
+Patch1024:	0025-QUIC-Enforce-consistent-encryption-level-for-handsha.patch
+Patch1025:	0026-QUIC-add-v1-quic_transport_parameters.patch
+Patch1026:	0027-QUIC-return-success-when-no-post-handshake-data.patch
+Patch1027:	0028-QUIC-__owur-makes-no-sense-for-void-return-values.patch
+Patch1028:	0029-QUIC-remove-SSL_R_BAD_DATA_LENGTH-unused.patch
+Patch1029:	0030-QUIC-Update-shared-library-version.patch
+Patch1031:	0032-QUIC-Fix-3.0.0-GitHub-CI.patch
+Patch1032:	0033-QUIC-SSLerr-ERR_raise-ERR_LIB_SSL.patch
+Patch1033:	0034-QUIC-Add-compile-run-time-checking-for-QUIC.patch
+Patch1034:	0035-QUIC-Add-early-data-support-11.patch
+Patch1035:	0036-QUIC-Make-SSL_provide_quic_data-accept-0-length-data.patch
+Patch1036:	0037-QUIC-Process-multiple-post-handshake-messages-in-a-s.patch
+Patch1037:	0038-QUIC-Tighten-up-some-language-in-SSL_CTX_set_quic_me.patch
+Patch1039:	0040-QUIC-Fix-CI-20.patch
+Patch1040:	0041-QUIC-Break-up-header-body-processing.patch
+Patch1041:	0042-QUIC-Fix-make-doc-nits.patch
+Patch1044:	0045-QUIC-Don-t-muck-with-FIPS-checksums.patch
+Patch1046:	0047-QUIC-Update-RFC-references.patch
+Patch1047:	0048-QUIC-revert-white-space-change.patch
+Patch1048:	0049-QUIC-update-copyrights.patch
+Patch1049:	0050-QUIC-update-SSL_provide_quic_data-documentation.patch
+Patch1050:	0051-QUIC-expound-on-what-DoS-attacks-QUIC-avoids.patch
+Patch1051:	0052-QUIC-remove-SSL_get_current_cipher-reference.patch
+Patch1052:	0053-QUIC-use-SSL_IS_QUIC-in-more-places.patch
+Patch1053:	0054-QUIC-Error-when-non-empty-session_id-in-CH-fixes-29.patch
+Patch1054:	0055-QUIC-Update-SSL_clear-to-clear-quic-data.patch
+Patch1055:	0056-QUIC-Better-SSL_clear.patch
+Patch1058:	0059-QUIC-Fix-extension-test.patch
+Patch1062:	0063-QUIC-Fix-use-of-create_a_psk.patch
 License:	Apache 2.0
 BuildRequires:	perl
 BuildRequires:	perl(Pod::Man)
@@ -89,6 +147,7 @@ Group:		System/Libraries
 The OpenSSL SSL/TLS library.
 
 %files -n %{libssl}
+%{_modulesloaddir}/openssl-tls.conf
 %{_libdir}/libssl.so.%{major}*
 
 %package -n %{libcrypto}
@@ -137,6 +196,7 @@ Static libraries for OpenSSL.
 Summary:	The OpenSSL SSL/TLS library (32-bit)
 Group:		System/Libraries
 BuildRequires:	libc6
+BuildRequires:	devel(libz)
 Requires:	libc6
 
 %description -n %{lib32ssl}
@@ -238,7 +298,7 @@ cd build32
 	--prefix=%{_prefix} \
 	--libdir=%{_prefix}/lib \
 	--openssldir=%{_sysconfdir}/pki/tls \
-	threads shared zlib-dynamic sctp 386 enable-fips enable-ktls no-tests
+	threads shared zlib sctp 386 enable-fips enable-ktls no-tests
 
 %make_build
 cd ..
@@ -269,15 +329,12 @@ LDFLAGS="$LDFLAGS -fprofile-generate" \
 %ifarch %{x86_64} %{ix86}
 	386 \
 %endif
-	threads shared zlib-dynamic sctp enable-fips enable-ktls no-tests
+	threads shared zlib sctp enable-fips enable-ktls no-tests
 
 %make_build
 
-# Run benchmarks on relevant algorithms to generate profile data.
-# We consider "relevant":
-# - Anything used in TLS 1.3
-# - Anything used by OpenSSH
-LD_PRELOAD="./libcrypto.so ./libssl.so" apps/openssl speed sha1 sha256 sha512 aes-128-cbc ecdsa eddsa md5 rsa des-ede3
+# Run benchmarks on all algorithms to generate profile data.
+LD_PRELOAD="./libcrypto.so ./libssl.so" apps/openssl speed
 
 unset LD_LIBRARY_PATH
 llvm-profdata merge --output=%{name}-llvm.profdata $(find . -name "*.profraw" -type f)
@@ -290,6 +347,8 @@ CFLAGS="$CFLAGS -fprofile-use=$PROFDATA %{pollyflags}" \
 CXXFLAGS="%{optflags} -fprofile-use=$PROFDATA %{pollyflags}" \
 LDFLAGS="$LDFLAGS -fprofile-use=$PROFDATA" \
 %endif
+CC="%{__cc}" \
+CXX="%{__cxx}" \
 ../Configure ${TARGET} \
 	--prefix=%{_prefix} \
 	--libdir=%{_libdir} \
@@ -300,7 +359,7 @@ LDFLAGS="$LDFLAGS -fprofile-use=$PROFDATA" \
 %ifarch %{x86_64} %{ix86}
 	386 \
 %endif
-	threads shared zlib-dynamic sctp enable-fips enable-ktls no-tests
+	threads shared zlib sctp enable-fips enable-ktls no-tests
 
 %make_build
 
@@ -313,12 +372,18 @@ LDFLAGS="$LDFLAGS -fprofile-use=$PROFDATA" \
 # Replace bogus absolute symlinks pointing to the buildroot
 cd %{buildroot}%{_mandir}
 for i in *; do
-	cd "$i"
+    cd "$i"
 	for j in *; do
-		[ -L "$j" ] && ln -sf "$(basename $(ls -l "$j" |cut -d'>' -f2-))" "$j"
+	    [ -L "$j" ] && ln -sf "$(basename $(ls -l "$j" |cut -d'>' -f2-))" "$j"
 	done
-	cd ..
+    cd ..
 done
 
 # Used by e.g. %_create_ssl_certificate (rpm-helper)
 mkdir -p %{buildroot}%{_sysconfdir}/pki/tls/private
+
+# enable kernel TLS offload support
+mkdir -p %{buildroot}%{_modulesloaddir}
+cat > %{buildroot}%{_modulesloaddir}/openssl-tls.conf << EOF
+tls
+EOF
Not Available

369start [@T] proton.meNo Comment.57d 16hrs
369start [@T] proton.meNo Comment.57d 15hrs