From 9f3c339bfd46c2c739b67c0e757471b1ed072f5c Mon Sep 17 00:00:00 2001 From: Todd Short Date: Fri, 12 Apr 2019 11:13:25 -0400 Subject: [PATCH] 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 --- .github/workflows/fips-checksums.yml | 54 ++-- CHANGES.md | 5 + Configure | 13 +- INSTALL.md | 4 + README-OpenSSL.md | 224 ++++++++++++++ README.md | 334 ++++++--------------- VERSION.dat | 6 +- apps/info.c | 13 + crypto/err/openssl.txt | 3 + crypto/info.c | 5 + doc/build.info | 6 + doc/man1/openssl-info.pod.in | 5 + doc/man3/OpenSSL_version.pod | 8 + doc/man3/SSL_CIPHER_get_name.pod | 13 + doc/man3/SSL_CTX_set_quic_method.pod | 262 +++++++++++++++++ include/openssl/quic.h | 8 +- include/openssl/ssl.h.in | 66 +++++ include/openssl/sslerr.h | 2 + include/openssl/tls1.h | 3 + ssl/build.info | 6 + ssl/s3_msg.c | 12 +- ssl/ssl_ciph.c | 34 +++ ssl/ssl_err.c | 4 + ssl/ssl_lib.c | 110 ++++++- ssl/ssl_local.h | 58 ++++ ssl/ssl_quic.c | 420 +++++++++++++++++++++++++++ ssl/statem/extensions.c | 68 +++++ ssl/statem/extensions_clnt.c | 85 ++++++ ssl/statem/extensions_cust.c | 4 + ssl/statem/extensions_srvr.c | 90 +++++- ssl/statem/statem.c | 26 +- ssl/statem/statem_clnt.c | 8 + ssl/statem/statem_lib.c | 38 ++- ssl/statem/statem_local.h | 39 +++ ssl/statem/statem_quic.c | 117 ++++++++ ssl/statem/statem_srvr.c | 22 +- ssl/tls13_enc.c | 241 +++++++++++++-- test/ext_internal_test.c | 7 + test/sslapitest.c | 368 +++++++++++++++++++++++ test/tls13secretstest.c | 6 + util/libssl.num | 18 +- util/other.syms | 2 + 42 files changed, 2502 insertions(+), 315 deletions(-) create mode 100644 README-OpenSSL.md 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/.github/workflows/fips-checksums.yml b/.github/workflows/fips-checksums.yml index 1ea3195fc7527..0dc49cf7908b1 100644 --- a/.github/workflows/fips-checksums.yml +++ b/.github/workflows/fips-checksums.yml @@ -73,47 +73,29 @@ jobs: with: name: fips_checksum path: artifact/ - - compute-abidiff: + verify-checksums: runs-on: ubuntu-latest - env: - BUILD_OPTS: -g --strict-warnings enable-ktls enable-fips enable-egd enable-ec_nistp_64_gcc_128 enable-md2 enable-rc5 enable-sctp enable-ssl3 enable-ssl3-method enable-trace enable-zlib enable-zstd steps: + - name: install unifdef + run: | + sudo apt-get update + sudo apt-get -yq --no-install-suggests --no-install-recommends --force-yes install unifdef + - uses: actions/checkout@v2 - name: create build dirs run: | - mkdir ./build-pristine - mkdir ./source-pristine mkdir ./build - mkdir ./source - mkdir ./artifact - - name: install extra config support - run: sudo apt-get -y install libsctp-dev abigail-tools libzstd-dev zstd - - uses: actions/checkout@v4 - with: - repository: ${{ github.event.pull_request.base.repo.full_name }} - ref: ${{ github.event.pull_request.base.ref }} - path: source-pristine - - name: config pristine - run: ../source-pristine/config --banner=Configured $BUILD_OPTS && perl configdata.pm --dump - working-directory: ./build-pristine - - name: make pristine - run: make -s -j4 - working-directory: ./build-pristine - - uses: actions/checkout@v4 - with: - path: source - name: config - run: ../source/config --banner=Configured $BUILD_OPTS && perl configdata.pm --dump + run: ../config enable-fips && perl configdata.pm --dump working-directory: ./build - - name: make - run: make -s -j4 + - name: make build_generated + run: make -s build_generated + working-directory: ./build + - name: make fips-checksums + run: make fips-checksums + working-directory: ./build + - name: make fips-checksums + run: make fips-checksums + working-directory: ./build + - name: make diff-fips-checksums + run: make diff-fips-checksums working-directory: ./build - - name: abidiff - run: abidiff --headers-dir1 build-pristine/include/openssl --headers-dir2 build/include/openssl --drop-private-types ./build-pristine/libcrypto.so ./build/libcrypto.so && abidiff --headers-dir1 build-pristine/include/openssl --headers-dir2 build/include/openssl --drop-private-types ./build-pristine/libssl.so ./build/libssl.so && touch ./artifact/abi_unchanged || ( touch ./artifact/abi_changed ; echo ABI CHANGED ) - - name: save PR number - run: echo ${{ github.event.number }} > ./artifact/pr_num - - name: save artifact - uses: actions/upload-artifact@v3 - with: - name: abidiff - path: artifact/ diff --git a/CHANGES.md b/CHANGES.md index 7d637564ed18a..b5e02e454ccfd 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -26,6 +26,11 @@ OpenSSL Releases OpenSSL 3.3 ----------- +### Changes Between 3.3.0 and 3.3.0+quic + * Add QUIC API support from BoringSSL + + *Todd Short* + ### Changes between 3.2 and 3.3.0 [9 Apr 2024] * The `-verify` option to the `openssl crl` and `openssl req` will make diff --git a/Configure b/Configure index 3b6617c17719f..500872e4733ce 100755 --- a/Configure +++ b/Configure @@ -426,6 +426,7 @@ my @disablables = ( "autoload-config", "bf", "blake2", + "boring-quic-api", "brotli", "brotli-dynamic", "buildtest-c++", @@ -579,6 +580,7 @@ our %disabled = ( # "what" => "comment" "ktls" => "default", "md2" => "default", "msan" => "default", + "quic" => "default", "rc5" => "default", "sctp" => "default", "ssl3" => "default", @@ -613,6 +615,7 @@ my @disable_cascades = ( "srtp", "ssl3-method", "ssl-trace", "tfo", "ts", "ui-console", "whirlpool", + "boring-quic-api", "fips-securitychecks" ], sub { $config{processor} eq "386" } => [ "sse2" ], @@ -622,7 +625,7 @@ my @disable_cascades = ( "brotli" => [ "brotli-dynamic" ], "zstd" => [ "zstd-dynamic" ], "des" => [ "mdc2" ], - "ec" => [ "ec2m", "ecdsa", "ecdh", "sm2", "gost", "ecx" ], + "ec" => [ "ec2m", "ecdsa", "ecdh", "sm2", "gost", "ecx", "boring-quic-api" ], "dgram" => [ "dtls", "quic", "sctp" ], "sock" => [ "dgram", "tfo" ], "dtls" => [ @dtls ], @@ -632,7 +635,7 @@ my @disable_cascades = ( "tls" => [ @tls ], sub { 0 == scalar grep { !$disabled{$_} } @tls } => [ "tls" ], - "tls1_3" => [ "quic" ], + "tls1_3" => [ "quic" , "boring-quic-api"], "quic" => [ "unstable-qlog" ], "crypto-mdebug" => [ "crypto-mdebug-backtrace" ], @@ -675,6 +678,7 @@ my @disable_cascades = ( "legacy" => [ "md2" ], "cmp" => [ "crmf" ], + "tls1_3" => [ "boring-quic-api" ], "fips" => [ "fips-securitychecks", "acvp-tests" ], @@ -1214,6 +1218,11 @@ if (grep { /-rpath\b/ } ($user{LDFLAGS} ? @{$user{LDFLAGS}} : ()) "***** any of asan, msan or ubsan\n"; } +if (!($disabled{quic} || $disabled{"boring-quic-api"})) { + die "**** boring-quic-api and quic are incompatible options.\n", + "**** If you want to turn on quic explicitly disable boring-quic-api.\n"; +} + # If no target was given, try guessing. unless ($target) { my %system_config = OpenSSL::config::get_platform(%guess_opts, %user); diff --git a/INSTALL.md b/INSTALL.md index b486ee1556a25..d19f25cc4ed2f 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -904,6 +904,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/README-OpenSSL.md b/README-OpenSSL.md new file mode 100644 index 0000000000000..c917736e69850 --- /dev/null +++ b/README-OpenSSL.md @@ -0,0 +1,224 @@ +Welcome to the OpenSSL Project +============================== + +[![openssl logo]][www.openssl.org] + +[![github actions ci badge]][github actions ci] +[![appveyor badge]][appveyor jobs] + +OpenSSL is a robust, commercial-grade, full-featured Open Source Toolkit +for the Transport Layer Security (TLS) protocol formerly known as the +Secure Sockets Layer (SSL) protocol. The protocol implementation is based +on a full-strength general purpose cryptographic library, which can also +be used stand-alone. + +OpenSSL is descended from the SSLeay library developed by Eric A. Young +and Tim J. Hudson. + +The official Home Page of the OpenSSL Project is [www.openssl.org]. + +Table of Contents +================= + + - [Overview](#overview) + - [Download](#download) + - [Build and Install](#build-and-install) + - [Documentation](#documentation) + - [License](#license) + - [Support](#support) + - [Contributing](#contributing) + - [Legalities](#legalities) + +Overview +======== + +The OpenSSL toolkit includes: + +- **libssl** + an implementation of all TLS protocol versions up to TLSv1.3 ([RFC 8446]). + +- **libcrypto** + a full-strength general purpose cryptographic library. It constitutes the + basis of the TLS implementation, but can also be used independently. + +- **openssl** + the OpenSSL command line tool, a swiss army knife for cryptographic tasks, + testing and analyzing. It can be used for + - creation of key parameters + - creation of X.509 certificates, CSRs and CRLs + - calculation of message digests + - encryption and decryption + - SSL/TLS client and server tests + - handling of S/MIME signed or encrypted mail + - and more... + +Download +======== + +For Production Use +------------------ + +Source code tarballs of the official releases can be downloaded from +[www.openssl.org/source](https://www.openssl.org/source). +The OpenSSL project does not distribute the toolkit in binary form. + +However, for a large variety of operating systems precompiled versions +of the OpenSSL toolkit are available. In particular, on Linux and other +Unix operating systems, it is normally recommended to link against the +precompiled shared libraries provided by the distributor or vendor. + +For Testing and Development +--------------------------- + +Although testing and development could in theory also be done using +the source tarballs, having a local copy of the git repository with +the entire project history gives you much more insight into the +code base. + +The official OpenSSL Git Repository is located at [git.openssl.org]. +There is a GitHub mirror of the repository at [github.com/openssl/openssl], +which is updated automatically from the former on every commit. + +A local copy of the Git Repository can be obtained by cloning it from +the original OpenSSL repository using + + git clone git://git.openssl.org/openssl.git + +or from the GitHub mirror using + + git clone https://github.com/openssl/openssl.git + +If you intend to contribute to OpenSSL, either to fix bugs or contribute +new features, you need to fork the OpenSSL repository openssl/openssl on +GitHub and clone your public fork instead. + + git clone https://github.com/yourname/openssl.git + +This is necessary because all development of OpenSSL nowadays is done via +GitHub pull requests. For more details, see [Contributing](#contributing). + +Build and Install +================= + +After obtaining the Source, have a look at the [INSTALL](INSTALL.md) file for +detailed instructions about building and installing OpenSSL. For some +platforms, the installation instructions are amended by a platform specific +document. + + * [Notes for UNIX-like platforms](NOTES-UNIX.md) + * [Notes for Android platforms](NOTES-ANDROID.md) + * [Notes for Windows platforms](NOTES-WINDOWS.md) + * [Notes for the DOS platform with DJGPP](NOTES-DJGPP.md) + * [Notes for the OpenVMS platform](NOTES-VMS.md) + * [Notes on Perl](NOTES-PERL.md) + * [Notes on Valgrind](NOTES-VALGRIND.md) + +Specific notes on upgrading to OpenSSL 3.0 from previous versions can be found +in the [migration_guide(7ossl)] manual page. + +Documentation +============= + +Manual Pages +------------ + +The manual pages for the master branch and all current stable releases are +available online. + +- [OpenSSL master](https://www.openssl.org/docs/manmaster) +- [OpenSSL 3.0](https://www.openssl.org/docs/man3.0) +- [OpenSSL 1.1.1](https://www.openssl.org/docs/man1.1.1) + +Wiki +---- + +There is a Wiki at [wiki.openssl.org] which is currently not very active. +It contains a lot of useful information, not all of which is up-to-date. + +License +======= + +OpenSSL is licensed under the Apache License 2.0, which means that +you are free to get and use it for commercial and non-commercial +purposes as long as you fulfill its conditions. + +See the [LICENSE.txt](LICENSE.txt) file for more details. + +Support +======= + +There are various ways to get in touch. The correct channel depends on +your requirement. See the [SUPPORT](SUPPORT.md) file for more details. + +Contributing +============ + +If you are interested and willing to contribute to the OpenSSL project, +please take a look at the [CONTRIBUTING](CONTRIBUTING.md) file. + +Legalities +========== + +A number of nations restrict the use or export of cryptography. If you are +potentially subject to such restrictions, you should seek legal advice before +attempting to develop or distribute cryptographic code. + +Copyright +========= + +Copyright (c) 1998-2024 The OpenSSL Project + +Copyright (c) 1995-1998 Eric A. Young, Tim J. Hudson + +All rights reserved. + + + +[www.openssl.org]: + + "OpenSSL Homepage" + +[git.openssl.org]: + + "OpenSSL Git Repository" + +[git.openssl.org]: + + "OpenSSL Git Repository" + +[github.com/openssl/openssl]: + + "OpenSSL GitHub Mirror" + +[wiki.openssl.org]: + + "OpenSSL Wiki" + +[migration_guide(7ossl)]: + + "OpenSSL Migration Guide" + +[RFC 8446]: + + + + +[openssl logo]: + doc/images/openssl.svg + "OpenSSL Logo" + +[github actions ci badge]: + + "GitHub Actions CI Status" + +[github actions ci]: + + "GitHub Actions CI" + +[appveyor badge]: + + "AppVeyor Build Status" + +[appveyor jobs]: + + "AppVeyor Jobs" diff --git a/README.md b/README.md index bf4ae91524991..eada105022db7 100644 --- a/README.md +++ b/README.md @@ -1,271 +1,113 @@ -Welcome to the OpenSSL Project -============================== - -[![openssl logo]][www.openssl.org] - -[![github actions ci badge]][github actions ci] -[![appveyor badge]][appveyor jobs] - -OpenSSL is a robust, commercial-grade, full-featured Open Source Toolkit -for the TLS (formerly SSL), DTLS and QUIC (currently client side only) -protocols. - -The protocol implementations are based on a full-strength general purpose -cryptographic library, which can also be used stand-alone. Also included is a -cryptographic module validated to conform with FIPS standards. - -OpenSSL is descended from the SSLeay library developed by Eric A. Young -and Tim J. Hudson. - -The official Home Page of the OpenSSL Project is [www.openssl.org]. - -Table of Contents -================= - - - [Overview](#overview) - - [Download](#download) - - [Build and Install](#build-and-install) - - [Documentation](#documentation) - - [License](#license) - - [Support](#support) - - [Contributing](#contributing) - - [Legalities](#legalities) - -Overview -======== - -The OpenSSL toolkit includes: - -- **libssl** - an implementation of all TLS protocol versions up to TLSv1.3 ([RFC 8446]), - DTLS protocol versions up to DTLSv1.2 ([RFC 6347]) and - the QUIC (currently client side only) version 1 protocol ([RFC 9000]). - -- **libcrypto** - a full-strength general purpose cryptographic library. It constitutes the - basis of the TLS implementation, but can also be used independently. - -- **openssl** - the OpenSSL command line tool, a swiss army knife for cryptographic tasks, - testing and analyzing. It can be used for - - creation of key parameters - - creation of X.509 certificates, CSRs and CRLs - - calculation of message digests - - encryption and decryption - - SSL/TLS/DTLS and client and server tests - - QUIC client tests - - handling of S/MIME signed or encrypted mail - - and more... +What This Is +============ -Download -======== +This is a fork of [OpenSSL](https://www.openssl.org) to enable QUIC. In addition +to the website, the official source distribution is at +. The OpenSSL `README` can be found at +[README-OpenSSL.md](https://github.com/quictls/openssl/blob/openssl-3.1.5%2Bquic/README-OpenSSL.md) -For Production Use ------------------- +This fork adds APIs that can be used by QUIC implementations for connection +handshakes. Quoting the IETF Working group +[charter](https://datatracker.ietf.org/wg/quic/about/), QUIC is a "UDP-based, +stream-multiplexing, encrypted transport protocol." If you don't need QUIC, you +should use the official OpenSSL distributions. -Source code tarballs of the official releases can be downloaded from -[www.openssl.org/source](https://www.openssl.org/source). -The OpenSSL project does not distribute the toolkit in binary form. +The APIs here are used by Microsoft's +[MsQuic](https://github.com/microsoft/msquic) and Google's +[Chromium QUIC](https://chromium.googlesource.com/chromium/src/+/master/net/quic/) -However, for a large variety of operating systems precompiled versions -of the OpenSSL toolkit are available. In particular, on Linux and other -Unix operating systems, it is normally recommended to link against the -precompiled shared libraries provided by the distributor or vendor. +We are not in competition with OpenSSL project. We informed them of +our plans to fork the code before we went public. We do not speak for the +OpenSSL project, and can only point to a +[blog post](https://www.openssl.org/blog/blog/2020/02/17/QUIC-and-OpenSSL/) and +[openssl-project email](https://github.com/quictls/openssl/discussions/54) +that provides their view of QUIC support. -We also maintain a list of third parties that produce OpenSSL binaries for -various Operating Systems (including Windows) on the [Binaries] page on our -wiki. +As stated in their blog post, the OpenSSL team is focused on their 3.0 release +(released 2021-09-07), and does not intend to add QUIC functionality to 1.1.x. +There is a community need for a QUIC-capable TLS library. This fork is intended +as stopgap solution to enable higher level frameworks and runtimes to use QUIC +with the proven and reliable TLS functionality from OpenSSL. This fork will be +maintained until OpenSSL officially provides reasonable support for QUIC +implementations. -For Testing and Development ---------------------------- +This fork can be considered a supported version of +[OpenSSL PR 8797](https://github.com/openssl/openssl/pull/8797). +We will endeavor to track OpenSSL releases within a day or so, and there is an +item below about how we'll follow their tagging. -Although testing and development could in theory also be done using -the source tarballs, having a local copy of the git repository with -the entire project history gives you much more insight into the -code base. +On to the questions and answers. -The official OpenSSL Git Repository is located at [git.openssl.org]. -There is a GitHub mirror of the repository at [github.com/openssl/openssl], -which is updated automatically from the former on every commit. +What about branches? +-------------------- -A local copy of the Git Repository can be obtained by cloning it from -the original OpenSSL repository using +We don't want to conflict with OpenSSL branch names. Our current plan is to append +`+quic`. Release tags are likely to be the QUIC branch with `-releaseX` appended. +For example, the OpenSSL tag `openssl-3.0.0` would have a branch named +`openssl-3.0.0+quic` and a release tag of `openssl-3.0.0+quic-release1`. - git clone git://git.openssl.org/openssl.git +How are you keeping current with OpenSSL? +----------------------------------------- -or from the GitHub mirror using +(In other words, "What about rebasing?") - git clone https://github.com/openssl/openssl.git +Our plan is to always rebase on top of an upstream release tag. In particular: -If you intend to contribute to OpenSSL, either to fix bugs or contribute -new features, you need to fork the OpenSSL repository openssl/openssl on -GitHub and clone your public fork instead. +- The changes for QUIC will always be at the tip of the branch -- you will know what + is from the original OpenSSL and what is for QUIC. +- New versions are quickly created once upstream creates a new tag. +- The use of git commands (such as `cherry`) can be used to ensure that all changes + have moved forward with minimal or no changes. You will be able to see + "QUIC: Add X" on all branches and the commit itself will be nearly identical on + all branches, and any changes to that can be easily identified. - git clone https://github.com/yourname/openssl.git +What about library names? +------------------------- -This is necessary because all development of OpenSSL nowadays is done via -GitHub pull requests. For more details, see [Contributing](#contributing). +Library names will be the same, but will use a different version number. The version +numbers for the current OpenSSL libraries are `1.1` (for the 1.1.0 and 1.1.1 branches) +and `3` (for the 3.0 branch). We will be prefixing `81` (ASCII for 'Q') to +the version numbers to generate a unique version number. -Build and Install -================= +- `libcrypto.so.81.3` vs `libcrypto.so.3` +- `libcrypto.so.81.1.1` vs `libcrypto.so.1.1` +- `libssl.so.81.3` vs `libssl.so.3` +- `libssl.so.81.1.1` vs `libssl.so.1.1` -After obtaining the Source, have a look at the [INSTALL](INSTALL.md) file for -detailed instructions about building and installing OpenSSL. For some -platforms, the installation instructions are amended by a platform specific -document. +The SONAME of these libraries are all different, guaranteeing the correct library +will be used. - * [Notes for UNIX-like platforms](NOTES-UNIX.md) - * [Notes for Android platforms](NOTES-ANDROID.md) - * [Notes for Windows platforms](NOTES-WINDOWS.md) - * [Notes for the DOS platform with DJGPP](NOTES-DJGPP.md) - * [Notes for the OpenVMS platform](NOTES-VMS.md) - * [Notes on Perl](NOTES-PERL.md) - * [Notes on Valgrind](NOTES-VALGRIND.md) +...and the executable? +---------------------- -Specific notes on upgrading to OpenSSL 3.x from previous versions can be found -in the [ossl-guide-migration(7ossl)] manual page. +We currently do not have any plans to change the name, mainly because we +haven't made any changes there. If you see a need, please open an issue. -Documentation -============= +The `openssl version` command will report that it is `+quic` enabled. -README Files +...and FIPS? ------------ -There are some README.md files in the top level of the source distribution -containing additional information on specific topics. - - * [Information about the OpenSSL QUIC protocol implementation](README-QUIC.md) - * [Information about the OpenSSL Provider architecture](README-PROVIDERS.md) - * [Information about using the OpenSSL FIPS validated module](README-FIPS.md) - * [Information about the legacy OpenSSL Engine architecture](README-ENGINES.md) - -The OpenSSL Guide ------------------ - -There are some tutorial and introductory pages on some important OpenSSL topics -within the [OpenSSL Guide]. - -Manual Pages +We are not doing anything with FIPS. This is actually good news: you should +be able to load the OpenSSL 3.0 FIPS module into an application built against +this fork and everything should Just Work™. + +How can I contribute? +--------------------- + +We want any code here to be acceptable to OpenSSL. This means that all contributors +must have signed the appropriate +[contributor license agreements](https://www.openssl.org/policies/cla.html). We +will not ask for copies of any paperwork, you just need to tell us that you've +done so (and we might verify with OpenSSL). We are only interested in making it +easier and better for at least the mentioned QUIC implementations to use a variant +of OpenSSL. If you have a pull request that changes the TLS protocol, or adds +assembly support for a new CPU, or otherwise is not specific to enabling QUIC, +please contribute that to OpenSSL. This fork is intended to be a clean extension +to OpenSSL, with the deltas being specific to QUIC. + +Who are you? ------------ -The manual pages for the master branch and all current stable releases are -available online. - -- [OpenSSL master](https://www.openssl.org/docs/manmaster) -- [OpenSSL 3.0](https://www.openssl.org/docs/man3.0) -- [OpenSSL 3.1](https://www.openssl.org/docs/man3.1) -- [OpenSSL 3.2](https://www.openssl.org/docs/man3.2) - -Demos ------ - -The are numerous source code demos for using various OpenSSL capabilities in the -[demos subfolder](./demos). - -Wiki ----- - -There is a Wiki at [wiki.openssl.org] which is currently not very active. -It contains a lot of useful information, not all of which is up-to-date. - -License -======= - -OpenSSL is licensed under the Apache License 2.0, which means that -you are free to get and use it for commercial and non-commercial -purposes as long as you fulfill its conditions. - -See the [LICENSE.txt](LICENSE.txt) file for more details. - -Support -======= - -There are various ways to get in touch. The correct channel depends on -your requirement. See the [SUPPORT](SUPPORT.md) file for more details. - -Contributing -============ - -If you are interested and willing to contribute to the OpenSSL project, -please take a look at the [CONTRIBUTING](CONTRIBUTING.md) file. - -Legalities -========== - -A number of nations restrict the use or export of cryptography. If you are -potentially subject to such restrictions, you should seek legal advice before -attempting to develop or distribute cryptographic code. - -Copyright -========= - -Copyright (c) 1998-2024 The OpenSSL Project Authors - -Copyright (c) 1995-1998 Eric A. Young, Tim J. Hudson - -All rights reserved. - - - -[www.openssl.org]: - - "OpenSSL Homepage" - -[git.openssl.org]: - - "OpenSSL Git Repository" - -[git.openssl.org]: - - "OpenSSL Git Repository" - -[github.com/openssl/openssl]: - - "OpenSSL GitHub Mirror" - -[wiki.openssl.org]: - - "OpenSSL Wiki" - -[ossl-guide-migration(7ossl)]: - - "OpenSSL Migration Guide" - -[RFC 8446]: - - -[RFC 6347]: - - -[RFC 9000]: - - -[Binaries]: - - "List of third party OpenSSL binaries" - -[OpenSSL Guide]: - - "An introduction to OpenSSL" - - - -[openssl logo]: - doc/images/openssl.svg - "OpenSSL Logo" - -[github actions ci badge]: - - "GitHub Actions CI Status" - -[github actions ci]: - - "GitHub Actions CI" - -[appveyor badge]: - - "AppVeyor Build Status" - -[appveyor jobs]: - - "AppVeyor Jobs" +This is a collaborative effort between [Akamai](https://www.akamai.com) and +[Microsoft](https://www.microsoft.com). We welcome anyone to contribute! diff --git a/VERSION.dat b/VERSION.dat index 2663925ce0cd8..8f16b8abf4b18 100644 --- a/VERSION.dat +++ b/VERSION.dat @@ -2,6 +2,6 @@ MAJOR=3 MINOR=3 PATCH=0 PRE_RELEASE_TAG= -BUILD_METADATA= -RELEASE_DATE="9 Apr 2024" -SHLIB_VERSION=3 +BUILD_METADATA=quic +RELEASE_DATE="30 Jan 2024" +SHLIB_VERSION=81.3 diff --git a/apps/info.c b/apps/info.c index befc62dac1047..d42ebd40a24a2 100644 --- a/apps/info.c +++ b/apps/info.c @@ -10,11 +10,15 @@ #include #include "apps.h" #include "progs.h" +#include 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_BORING_QUIC_API + , OPT_QUIC +#endif } OPTION_CHOICE; const OPTIONS info_options[] = { @@ -32,6 +36,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_BORING_QUIC_API + {"quic", OPT_QUIC, '-', "QUIC info"}, +#endif {NULL} }; @@ -84,6 +91,12 @@ int info_main(int argc, char **argv) type = OPENSSL_INFO_CPU_SETTINGS; dirty++; break; +#ifndef OPENSSL_NO_BORING_QUIC_API + case OPT_QUIC: + type = OPENSSL_INFO_QUIC; + dirty++; + break; +#endif } } if (!opt_check_rest_arg(NULL)) diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index 1607ad835f3d4..3ae593f49be31 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -1451,6 +1451,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 @@ -1655,6 +1657,7 @@ 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_RPK_TYPE:351:wrong rpk type +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/crypto/info.c b/crypto/info.c index 9ef9ee4704705..36766ffab9af6 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 #if defined(__arm__) || defined(__arm) || defined(__aarch64__) # include "arm_arch.h" @@ -203,6 +204,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_BORING_QUIC_API + case OPENSSL_INFO_QUIC: + return "QUIC"; +#endif default: break; } diff --git a/doc/build.info b/doc/build.info index b4815fcf23a79..90c7937de095a 100644 --- a/doc/build.info +++ b/doc/build.info @@ -2323,6 +2323,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 @@ -3512,6 +3516,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 \ @@ -4157,6 +4162,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/doc/man1/openssl-info.pod.in b/doc/man1/openssl-info.pod.in index 0e91bb28ee10d..fe7abee486767 100644 --- a/doc/man1/openssl-info.pod.in +++ b/doc/man1/openssl-info.pod.in @@ -17,6 +17,7 @@ B [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 diff --git a/doc/man3/OpenSSL_version.pod b/doc/man3/OpenSSL_version.pod index e1cf16e2a109b..946bb151bafeb 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. +=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, NULL is returned. diff --git a/doc/man3/SSL_CIPHER_get_name.pod b/doc/man3/SSL_CIPHER_get_name.pod index 44af9d6dfe9e5..75aaee33d00e3 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 is returned. Examples (not comprehensive) NID_auth_ecdsa NID_auth_psk +SSL_CIPHER_get_prf_nid() retuns the pseudo-random function NID for B. If B is +a pre-TLS-1.2 cipher, it returns B 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 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-2019 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 0000000000000..aab5e38889b04 --- /dev/null +++ b/doc/man3/SSL_CTX_set_quic_method.pod @@ -0,0 +1,262 @@ +=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, +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_early_data_enabled +- QUIC support + +=head1 SYNOPSIS + + #include + + 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); + + 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); + void SSL_set_quic_early_data_enabled(SSL *ssl, int enabled); + +=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 +must remain valid for the lifetime of B or B. Calling this disables +the SSL_OP_ENABLE_MIDDLEBOX_COMPAT option, which is not required for QUIC. + +SSL_set_quic_transport_params() configures B to send B (of length +B) 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 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. If no params were received from the peer, B<*out_params_len> will be 0. + +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 L. + +SSL_quic_read_level() returns the current read encryption level. + +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. It is an error to +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 +sent by the server. + +SSL_is_quic() indicates whether a connection uses QUIC. A given B +or B 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. + +SSL_set_quic_early_data_enabled() enables QUIC early data if a nonzero +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 + +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 RFC9001. + +When configured for QUIC, SSL_do_handshake() will drive the handshake as +before, but it will not use the configured B. It will call functions from +the configured B to configure secrets and send data. If data +is needed from the peer, it will return B. 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 L for more details. + +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. + +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 +L (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. + +=head2 OSSL_ENCRYPTION_LEVEL + +B (B) 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 (B) 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 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, where secrets are +only available in the client to server direction. The other secret will be +NULL. The server acknowledges such data at B, +which will be configured in the same SSL_do_handshake() call. + +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 an B +(B). + +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. + +=head1 SEE ALSO + +L, L, L + +=head1 HISTORY + +These functions were added in OpenSSL 3.0.0. + +=head1 COPYRIGHT + +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 +in the file LICENSE in the source distribution or at +L. + +=cut diff --git a/include/openssl/quic.h b/include/openssl/quic.h index 3dc2f5e747b42..656e44eadf8c7 100644 --- a/include/openssl/quic.h +++ b/include/openssl/quic.h @@ -67,4 +67,10 @@ __owur const SSL_METHOD *OSSL_QUIC_client_thread_method(void); # endif # endif /* OPENSSL_NO_QUIC */ -#endif +# ifndef OPENSSL_NO_BORING_QUIC_API + +/* moved from crypto.h.in to avoid breaking FIPS checksums */ +# define OPENSSL_INFO_QUIC 2000 + +# endif /* OPENSSL_NO_BORING_QUIC_API */ +#endif /* OPENSSL_QUIC_H */ diff --git a/include/openssl/ssl.h.in b/include/openssl/ssl.h.in index 442d5cbc3c08f..af0a7f79f99d3 100644 --- a/include/openssl/ssl.h.in +++ b/include/openssl/ssl.h.in @@ -2815,6 +2815,72 @@ __owur int SSL_get0_client_cert_type(const SSL *s, unsigned char **t, size_t *le __owur int SSL_get0_server_cert_type(const SSL *s, unsigned char **t, size_t *len); __owur int SSL_CTX_get0_client_cert_type(const SSL_CTX *ctx, unsigned char **t, size_t *len); __owur int SSL_CTX_get0_server_cert_type(const SSL_CTX *s, unsigned char **t, size_t *len); +# ifndef OPENSSL_NO_BORING_QUIC_API +/* + * 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'. + */ +#include + +/* 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, + 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); + +/* BoringSSL API */ +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); + +void SSL_set_quic_early_data_enabled(SSL *ssl, int enabled); + +# endif # ifdef __cplusplus } diff --git a/include/openssl/sslerr.h b/include/openssl/sslerr.h index 980a6c7b2fd4f..25738acef35ad 100644 --- a/include/openssl/sslerr.h +++ b/include/openssl/sslerr.h @@ -171,6 +171,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 @@ -364,6 +365,7 @@ # define SSL_R_WRONG_CIPHER_RETURNED 261 # define SSL_R_WRONG_CURVE 378 # define SSL_R_WRONG_RPK_TYPE 351 +# 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 7e3d1a725b82e..48b6e71c5ae87 100644 --- a/include/openssl/tls1.h +++ b/include/openssl/tls1.h @@ -163,6 +163,9 @@ extern "C" { /* Temporary extension type */ # define TLSEXT_TYPE_renegotiate 0xff01 + /* ExtensionType value from RFC9001 */ +# define TLSEXT_TYPE_quic_transport_parameters_draft 0xffa5 + # ifndef OPENSSL_NO_NEXTPROTONEG /* This is not an IANA defined extension number */ # define TLSEXT_TYPE_next_proto_neg 13172 diff --git a/ssl/build.info b/ssl/build.info index de28a0700a03d..86bcf8fa484a5 100644 --- a/ssl/build.info +++ b/ssl/build.info @@ -34,3 +34,9 @@ ENDIF IF[{- !$disabled{quic} -}] SOURCE[../libssl]=priority_queue.c event_queue.c ENDIF +DEFINE[../libssl]=$AESDEF + +IF[{- !$disabled{'boring-quic-api'} -}] + SOURCE[../libssl]=ssl_quic.c statem/statem_quic.c +ENDIF + diff --git a/ssl/s3_msg.c b/ssl/s3_msg.c index 3fcea15e279e4..9f8e43cf64819 100644 --- a/ssl/s3_msg.c +++ b/ssl/s3_msg.c @@ -77,7 +77,7 @@ int ssl3_send_alert(SSL_CONNECTION *s, int level, int desc) int ssl3_dispatch_alert(SSL *s) { - int i, j; + int i = 0, j = 0; void (*cb) (const SSL *ssl, int type, int val) = NULL; SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s); OSSL_RECORD_TEMPLATE templ; @@ -102,6 +102,16 @@ int ssl3_dispatch_alert(SSL *s) } templ.buf = &sc->s3.send_alert[0]; templ.buflen = 2; +#ifndef OPENSSL_NO_BORING_QUIC_API + if (SSL_CONNECTION_IS_QUIC(sc)) { + if (!sc->quic_method->send_alert(s, sc->quic_write_level, + sc->s3.send_alert[1])) { + ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); + return 0; + } + i = 1; + } else +#endif if (RECORD_LAYER_write_pending(&sc->rlayer)) { if (sc->s3.alert_dispatch != SSL_ALERT_DISPATCH_RETRY) { diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c index ddde21b968c7c..754d57235f27a 100644 --- a/ssl/ssl_ciph.c +++ b/ssl/ssl_ciph.c @@ -2269,3 +2269,37 @@ const char *OSSL_default_ciphersuites(void) "TLS_CHACHA20_POLY1305_SHA256:" "TLS_AES_128_GCM_SHA256"; } + +#ifndef OPENSSL_NO_BORING_QUIC_API +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; +} +#endif diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index a1da9fde3946c..f2e62534c0353 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -258,6 +258,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), @@ -596,6 +598,8 @@ static const ERR_STRING_DATA SSL_str_reasons[] = { "wrong cipher returned"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_CURVE), "wrong curve"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_RPK_TYPE), "wrong rpk type"}, + {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 5ec6ac4b63dc5..ed72d7d3fc390 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -558,7 +558,57 @@ static int ssl_check_allowed_versions(int min_version, int max_version) void OPENSSL_VPROC_FUNC(void) {} #endif +#ifndef OPENSSL_NO_BORING_QUIC_API int SSL_clear(SSL *s) +{ + if (!SSL_clear_not_quic(s)) + return 0; + return SSL_clear_quic(s); +} + +int SSL_clear_quic(SSL *s) +{ + SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s); + OPENSSL_free(sc->ext.peer_quic_transport_params_draft); + sc->ext.peer_quic_transport_params_draft = NULL; + sc->ext.peer_quic_transport_params_draft_len = 0; + OPENSSL_free(sc->ext.peer_quic_transport_params); + sc->ext.peer_quic_transport_params = NULL; + sc->ext.peer_quic_transport_params_len = 0; + sc->quic_read_level = ssl_encryption_initial; + sc->quic_write_level = ssl_encryption_initial; + sc->quic_latest_level_received = ssl_encryption_initial; + while (sc->quic_input_data_head != NULL) { + QUIC_DATA *qd; + + qd = sc->quic_input_data_head; + sc->quic_input_data_head = qd->next; + OPENSSL_free(qd); + } + sc->quic_input_data_tail = NULL; + BUF_MEM_free(sc->quic_buf); + sc->quic_buf = NULL; + sc->quic_next_record_start = 0; + memset(sc->client_hand_traffic_secret, 0, EVP_MAX_MD_SIZE); + memset(sc->server_hand_traffic_secret, 0, EVP_MAX_MD_SIZE); + memset(sc->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_BORING_QUIC_API +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); @@ -900,6 +950,9 @@ SSL *ossl_ssl_connection_new_int(SSL_CTX *ctx, const SSL_METHOD *method) goto sslerr; s->server_cert_type_len = ctx->server_cert_type_len; } +#ifndef OPENSSL_NO_BORING_QUIC_API + s->quic_method = ctx->quic_method; +#endif #ifndef OPENSSL_NO_CT if (!SSL_set_ct_validation_callback(ssl, ctx->ct_validation_callback, @@ -959,6 +1012,9 @@ int SSL_is_tls(const SSL *s) int SSL_is_quic(const SSL *s) { + if (SSL_CONNECTION_IS_QUIC(SSL_CONNECTION_FROM_SSL(s))) + return 1; + #ifndef OPENSSL_NO_QUIC if (s->type == SSL_TYPE_QUIC_CONNECTION || s->type == SSL_TYPE_QUIC_XSO) return 1; @@ -1453,6 +1509,20 @@ void ossl_ssl_connection_free(SSL *ssl) OPENSSL_free(s->pha_context); EVP_MD_CTX_free(s->pha_dgst); +#ifndef OPENSSL_NO_BORING_QUIC_API + 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) { + 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); @@ -2276,6 +2346,12 @@ int ssl_read_internal(SSL *s, void *buf, size_t num, size_t *readbytes) if (sc == NULL) return -1; +#ifndef OPENSSL_NO_BORING_QUIC_API + if (SSL_CONNECTION_IS_QUIC(sc)) { + ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return -1; + } +#endif if (sc->handshake_func == NULL) { ERR_raise(ERR_LIB_SSL, SSL_R_UNINITIALIZED); return -1; @@ -2425,6 +2501,12 @@ static int ssl_peek_internal(SSL *s, void *buf, size_t num, size_t *readbytes) if (sc == NULL) return 0; +#ifndef OPENSSL_NO_BORING_QUIC_API + if (SSL_CONNECTION_IS_QUIC(sc)) { + ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return -1; + } +#endif if (sc->handshake_func == NULL) { ERR_raise(ERR_LIB_SSL, SSL_R_UNINITIALIZED); return -1; @@ -2495,7 +2577,12 @@ int ssl_write_internal(SSL *s, const void *buf, size_t num, if (sc == NULL) return 0; - +#ifndef OPENSSL_NO_BORING_QUIC_API + if (SSL_CONNECTION_IS_QUIC(sc)) { + ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return -1; + } +#endif if (sc->handshake_func == NULL) { ERR_raise(ERR_LIB_SSL, SSL_R_UNINITIALIZED); return -1; @@ -4623,6 +4710,12 @@ int ossl_ssl_get_error(const SSL *s, int i, int check_err) #endif { if (SSL_want_read(s)) { +#ifndef OPENSSL_NO_BORING_QUIC_API + 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; @@ -4734,6 +4827,21 @@ int SSL_do_handshake(SSL *s) ret = sc->handshake_func(s); } } +#ifndef OPENSSL_NO_BORING_QUIC_API + if (SSL_CONNECTION_IS_QUIC(sc) && ret == 1) { + if (sc->server) { + if (sc->early_data_state == SSL_EARLY_DATA_ACCEPTING) { + sc->early_data_state = SSL_EARLY_DATA_FINISHED_READING; + sc->rwstate = SSL_READING; + ret = 0; + } + } else if (sc->early_data_state == SSL_EARLY_DATA_CONNECTING) { + sc->early_data_state = SSL_EARLY_DATA_WRITE_RETRY; + sc->rwstate = SSL_READING; + ret = 0; + } + } +#endif return ret; } diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index f448cfdbc94a1..b5445c82afb38 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -254,6 +254,13 @@ /* Flag used on OpenSSL ciphersuite ids to indicate they are for SSLv3+ */ # define SSL3_CK_CIPHERSUITE_FLAG 0x03000000 +/* Check if an SSL connection structure is using QUIC (which uses TLSv1.3) */ +# ifndef OPENSSL_NO_BORING_QUIC_API +# define SSL_CONNECTION_IS_QUIC(s) (s->quic_method != NULL) +# else +# define SSL_CONNECTION_IS_QUIC(s) 0 +# endif + /* Check if an SSL structure is using DTLS */ # define SSL_CONNECTION_IS_DTLS(s) \ (SSL_CONNECTION_GET_SSL(s)->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_DTLS) @@ -707,6 +714,8 @@ typedef enum tlsext_index_en { TLSEXT_IDX_compress_certificate, TLSEXT_IDX_early_data, TLSEXT_IDX_certificate_authorities, + 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 */ @@ -1193,6 +1202,9 @@ struct ssl_ctx_st { # ifndef OPENSSL_NO_QLOG char *qlog_title; /* Session title for qlog */ # endif +#ifndef OPENSSL_NO_BORING_QUIC_API + const SSL_QUIC_METHOD *quic_method; +#endif }; typedef struct cert_pkey_st CERT_PKEY; @@ -1200,6 +1212,16 @@ typedef struct cert_pkey_st CERT_PKEY; #define SSL_TYPE_SSL_CONNECTION 0 #define SSL_TYPE_QUIC_CONNECTION 1 #define SSL_TYPE_QUIC_XSO 2 +#ifndef OPENSSL_NO_BORING_QUIC_API +struct quic_data_st { + struct quic_data_st *next; + OSSL_ENCRYPTION_LEVEL level; + size_t start; /* offset into quic_buf->data */ + 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 { int type; @@ -1471,6 +1493,11 @@ struct ssl_connection_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_BORING_QUIC_API + 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]; @@ -1682,8 +1709,34 @@ struct ssl_connection_st { uint8_t client_cert_type_ctos; uint8_t server_cert_type; uint8_t server_cert_type_ctos; +#ifndef OPENSSL_NO_BORING_QUIC_API + 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 } ext; +#ifndef OPENSSL_NO_BORING_QUIC_API + 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 */ + /* + * 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; + const SSL_QUIC_METHOD *quic_method; +#endif /* * Parsed form of the ClientHello, kept around across client_hello_cb * calls. @@ -2918,6 +2971,11 @@ void custom_exts_free(custom_ext_methods *exts); void ssl_comp_free_compression_methods_int(void); +#ifndef OPENSSL_NO_BORING_QUIC_API +__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/ssl_quic.c b/ssl/ssl_quic.c new file mode 100644 index 0000000000000..6e2f2165731b6 --- /dev/null +++ b/ssl/ssl_quic.c @@ -0,0 +1,420 @@ +/* + * 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 + * 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" + +int SSL_set_quic_transport_params(SSL *ssl, const uint8_t *params, + size_t params_len) +{ + SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl); + if (sc == NULL) + return 0; + + 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(sc->ext.quic_transport_params); + sc->ext.quic_transport_params = tmp; + sc->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) +{ + SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl); + if (sc == NULL) + return; + + if (sc->ext.peer_quic_transport_params_len) { + *out_params = sc->ext.peer_quic_transport_params; + *out_params_len = sc->ext.peer_quic_transport_params_len; + } else { + *out_params = sc->ext.peer_quic_transport_params_draft; + *out_params_len = sc->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) +{ + SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl); + if (sc == NULL) + return -1; + if (sc->ext.peer_quic_transport_params_len != 0 + && sc->ext.peer_quic_transport_params_draft_len != 0) + return -1; + if (sc->ext.peer_quic_transport_params_len != 0) + return TLSEXT_TYPE_quic_transport_parameters; + if (sc->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) +{ + SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl); + if (sc == NULL) + return; + if (use_legacy) + sc->quic_transport_version = TLSEXT_TYPE_quic_transport_parameters_draft; + else + sc->quic_transport_version = TLSEXT_TYPE_quic_transport_parameters; +} + +void SSL_set_quic_transport_version(SSL *ssl, int version) +{ + SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl); + if (sc == NULL) + return; + sc->quic_transport_version = version; +} + +int SSL_get_quic_transport_version(const SSL *ssl) +{ + SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl); + if (sc == NULL) + return -1; + return sc->quic_transport_version; +} + +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. + */ + SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl); + if (sc == NULL) + return -1; + 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 (sc->server) { + /* + * Servers may receive Certificate message if configured to request + * client certificates. + */ + if ((sc->verify_mode & SSL_VERIFY_PEER) + && sc->max_cert_list > DEFAULT_FLIGHT_LIMIT) + return sc->max_cert_list; + } else { + /* + * Clients may receive both Certificate message and a CertificateRequest + * message. + */ + if (2*sc->max_cert_list > DEFAULT_FLIGHT_LIMIT) + return 2 * sc->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) +{ + SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl); + if (sc == NULL) + return -1; + return sc->quic_read_level; +} + +OSSL_ENCRYPTION_LEVEL SSL_quic_write_level(const SSL *ssl) +{ + SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl); + if (sc == NULL) + return -1; + return sc->quic_write_level; +} + +int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, + const uint8_t *data, size_t len) +{ + size_t l, offset; + + if (!SSL_is_quic(ssl)) { + ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl); + if (sc == NULL) + return -1; + + /* Level can be different than the current read, but not less */ + if (level < sc->quic_read_level + || (sc->quic_input_data_tail != NULL && level < sc->quic_input_data_tail->level) + || level < sc->quic_latest_level_received) { + ERR_raise(ERR_LIB_SSL, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED); + return 0; + } + + if (len == 0) + return 1; + + if (sc->quic_buf == NULL) { + BUF_MEM *buf; + if ((buf = BUF_MEM_new()) == NULL) { + ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); + return 0; + } + if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) { + ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); + BUF_MEM_free(buf); + return 0; + } + sc->quic_buf = buf; + /* We preallocated storage, but there's still no *data*. */ + sc->quic_buf->length = 0; + buf = NULL; + } + + /* A TLS message must not cross an encryption level boundary */ + if (sc->quic_buf->length != sc->quic_next_record_start + && level != sc->quic_latest_level_received) { + ERR_raise(ERR_LIB_SSL, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED); + return 0; + } + sc->quic_latest_level_received = level; + + offset = sc->quic_buf->length; + if (!BUF_MEM_grow(sc->quic_buf, offset + len)) { + ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); + return 0; + } + memcpy(sc->quic_buf->data + offset, data, len); + + /* Split on handshake message boundaries */ + while (sc->quic_buf->length > sc->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 */ + p = (const uint8_t *)sc->quic_buf->data + + sc->quic_next_record_start + 1; + n2l3(p, l); + l += SSL3_HM_HEADER_LENGTH; + /* Don't allocate a QUIC_DATA if we don't have a full record */ + if (l > sc->quic_buf->length - sc->quic_next_record_start) + break; + + qd = OPENSSL_zalloc(sizeof(*qd)); + if (qd == NULL) { + ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); + return 0; + } + + qd->next = NULL; + qd->length = l; + qd->start = sc->quic_next_record_start; + qd->level = level; + + if (sc->quic_input_data_tail != NULL) + sc->quic_input_data_tail->next = qd; + else + sc->quic_input_data_head = qd; + sc->quic_input_data_tail = qd; + sc->quic_next_record_start += l; + } + + return 1; +} + +int SSL_CTX_set_quic_method(SSL_CTX *ctx, const SSL_QUIC_METHOD *quic_method) +{ + if (ctx->method->version != TLS_ANY_VERSION) + return 0; + 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) +{ + SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl); + if (sc == NULL) + return -1; + if (ssl->method->version != TLS_ANY_VERSION) + return 0; + sc->quic_method = quic_method; + sc->options &= ~SSL_OP_ENABLE_MIDDLEBOX_COMPAT; + return 1; +} + +int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level) +{ + uint8_t *c2s_secret = NULL; + uint8_t *s2c_secret = NULL; + size_t len; + const EVP_MD *md; + SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl); + + if (!SSL_is_quic(ssl)) + return 1; + + if (sc == NULL) + return -1; + + /* secrets from the POV of the client */ + switch (level) { + case ssl_encryption_early_data: + c2s_secret = sc->client_early_traffic_secret; + break; + case ssl_encryption_handshake: + c2s_secret = sc->client_hand_traffic_secret; + s2c_secret = sc->server_hand_traffic_secret; + break; + case ssl_encryption_application: + c2s_secret = sc->client_app_traffic_secret; + s2c_secret = sc->server_app_traffic_secret; + break; + default: + return 1; + } + + if (level == ssl_encryption_early_data) { + const SSL_CIPHER *c = SSL_SESSION_get0_cipher(sc->session); + if (sc->early_data_state == SSL_EARLY_DATA_CONNECTING + && sc->max_early_data > 0 + && sc->session->ext.max_early_data == 0) { + if (!ossl_assert(sc->psksession != NULL + && sc->max_early_data == + sc->psksession->ext.max_early_data)) { + SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + c = SSL_SESSION_get0_cipher(sc->psksession); + } + + if (c == NULL) { + SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + + md = ssl_md(ssl->ctx, c->algorithm2); + } else { + md = ssl_handshake_md(sc); + 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 (sc->session != NULL) + c = SSL_SESSION_get0_cipher(sc->session); + else if (sc->psksession != NULL) + c = SSL_SESSION_get0_cipher(sc->psksession); + + if (c != NULL) + md = SSL_CIPHER_get_handshake_digest(c); + } + } + + if ((len = EVP_MD_size(md)) <= 0) { + SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + + if (sc->server) { + if (!sc->quic_method->set_encryption_secrets(ssl, level, c2s_secret, + s2c_secret, len)) { + SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + } else { + if (!sc->quic_method->set_encryption_secrets(ssl, level, s2c_secret, + c2s_secret, len)) { + SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + } + + return 1; +} + +int SSL_process_quic_post_handshake(SSL *ssl) +{ + SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl); + if (sc == NULL) + return 0; + + int ret; + + if (SSL_in_init(ssl) || !SSL_is_quic(ssl)) { + ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + + /* if there is no data, return success as BoringSSL */ + while (sc->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(sc, 1); + ret = sc->handshake_func(ssl); + ossl_statem_set_in_init(sc, 0); + + if (ret <= 0) + return 0; + } + return 1; +} + +void SSL_set_quic_early_data_enabled(SSL *ssl, int enabled) +{ + SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl); + if (sc == NULL) + return; + + if (!SSL_is_quic(ssl) || !SSL_in_before(ssl)) + return; + + if (!enabled) { + sc->early_data_state = SSL_EARLY_DATA_NONE; + return; + } + + if (sc->server) { + sc->early_data_state = SSL_EARLY_DATA_ACCEPTING; + return; + } + + if ((sc->session == NULL || sc->session->ext.max_early_data == 0) + && sc->psk_use_session_cb == NULL) + return; + + sc->early_data_state = SSL_EARLY_DATA_CONNECTING; +} diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c index 0a64ca2246987..4c0152d1ea50a 100644 --- a/ssl/statem/extensions.c +++ b/ssl/statem/extensions.c @@ -71,6 +71,11 @@ static EXT_RETURN tls_construct_compress_certificate(SSL_CONNECTION *sc, WPACKET static int tls_parse_compress_certificate(SSL_CONNECTION *sc, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx); +#ifndef OPENSSL_NO_BORING_QUIC_API +static int init_quic_transport_params(SSL_CONNECTION *s, unsigned int context); +static int final_quic_transport_params_draft(SSL_CONNECTION *s, unsigned int context, int sent); +static int final_quic_transport_params(SSL_CONNECTION *s, unsigned int context, int sent); +#endif /* Structure to define a built-in extension */ typedef struct extensions_definition_st { @@ -411,6 +416,29 @@ static const EXTENSION_DEFINITION ext_defs[] = { tls_construct_certificate_authorities, tls_construct_certificate_authorities, NULL, }, +#ifndef OPENSSL_NO_BORING_QUIC_API + { + 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 + | 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, + INVALID_EXTENSION, +#endif { /* Must be immediately before pre_shared_key */ TLSEXT_TYPE_padding, @@ -1931,3 +1959,43 @@ static int init_client_cert_type(SSL_CONNECTION *sc, unsigned int context) } return 1; } +#ifndef OPENSSL_NO_BORING_QUIC_API +static int init_quic_transport_params(SSL_CONNECTION *s, unsigned int context) +{ + return 1; +} + +static int final_quic_transport_params_draft(SSL_CONNECTION *s, unsigned int context, + int sent) +{ + return 1; +} + +static int final_quic_transport_params(SSL_CONNECTION *s, unsigned int context, int sent) +{ + /* called after final_quic_transport_params_draft */ + if (SSL_CONNECTION_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 381a6c9d7b909..00e2ddd300914 100644 --- a/ssl/statem/extensions_clnt.c +++ b/ssl/statem/extensions_clnt.c @@ -1212,7 +1212,47 @@ EXT_RETURN tls_construct_ctos_post_handshake_auth(SSL_CONNECTION *s, WPACKET *pk #endif } +#ifndef OPENSSL_NO_BORING_QUIC_API +EXT_RETURN tls_construct_ctos_quic_transport_params_draft(SSL_CONNECTION *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_CONNECTION *s, WPACKET *pkt, + unsigned int context, X509 *x, + size_t chainidx) +{ + 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; + } + + if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_quic_transport_parameters) + || !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; +} +#endif /* * Parse the server's renegotiation binding and abort if it's not right */ @@ -1932,6 +1972,17 @@ int tls_parse_stoc_early_data(SSL_CONNECTION *s, PACKET *pkt, return 0; } +#ifndef OPENSSL_NO_BORING_QUIC_API + /* + * QUIC server must send 0xFFFFFFFF or it's a PROTOCOL_VIOLATION + * per RFC9001 S4.6.1 + */ + if (SSL_CONNECTION_IS_QUIC(s) && 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; if (SSL_IS_QUIC_HANDSHAKE(s) && max_early_data != 0xffffffff) { @@ -2135,3 +2186,37 @@ int tls_parse_stoc_server_cert_type(SSL_CONNECTION *sc, PACKET *pkt, sc->ext.server_cert_type = type; return 1; } +#ifndef OPENSSL_NO_BORING_QUIC_API +int tls_parse_stoc_quic_transport_params_draft(SSL_CONNECTION *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_CONNECTION *s, PACKET *pkt, unsigned int context, + X509 *x, size_t chainidx) +{ + 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(pkt, + &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_cust.c b/ssl/statem/extensions_cust.c index fd840e8918e83..f435d52fde763 100644 --- a/ssl/statem/extensions_cust.c +++ b/ssl/statem/extensions_cust.c @@ -532,6 +532,10 @@ int SSL_extension_supported(unsigned int ext_type) #endif #ifndef OPENSSL_NO_SRTP case TLSEXT_TYPE_use_srtp: +#endif +#ifndef OPENSSL_BORING_QUIC_API + case TLSEXT_TYPE_quic_transport_parameters_draft: + case TLSEXT_TYPE_quic_transport_parameters: #endif case TLSEXT_TYPE_encrypt_then_mac: case TLSEXT_TYPE_supported_versions: diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c index 21db977c88f3d..4e904748820c2 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -1271,6 +1271,40 @@ int tls_parse_ctos_post_handshake_auth(SSL_CONNECTION *s, PACKET *pkt, return 1; } +#ifndef OPENSSL_NO_BORING_QUIC_API +int tls_parse_ctos_quic_transport_params_draft(SSL_CONNECTION *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_CONNECTION *s, PACKET *pkt, unsigned int context, + X509 *x, size_t chainidx) +{ + 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(pkt, + &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 */ @@ -1922,12 +1956,20 @@ EXT_RETURN tls_construct_stoc_early_data(SSL_CONNECTION *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_BORING_QUIC_API + /* QUIC server must always send 0xFFFFFFFF, per RFC9001 S4.6.1 */ + if (SSL_CONNECTION_IS_QUIC(s)) + 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; @@ -2127,3 +2169,47 @@ int tls_parse_ctos_server_cert_type(SSL_CONNECTION *sc, PACKET *pkt, SSLfatal(sc, SSL_AD_UNSUPPORTED_CERTIFICATE, SSL_R_BAD_EXTENSION); return 0; } +#ifndef OPENSSL_NO_BORING_QUIC_API +EXT_RETURN tls_construct_stoc_quic_transport_params_draft(SSL_CONNECTION *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_CONNECTION *s, WPACKET *pkt, + unsigned int context, X509 *x, + size_t chainidx) +{ + 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; + } + + if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_quic_transport_parameters) + || !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; +} +#endif diff --git a/ssl/statem/statem.c b/ssl/statem/statem.c index 921d7cfb1e05d..ecbd3253e70a9 100644 --- a/ssl/statem/statem.c +++ b/ssl/statem/statem.c @@ -374,8 +374,13 @@ static int state_machine(SSL_CONNECTION *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_BORING_QUIC_API + if ((s->s3.flags & TLS1_FLAGS_STATELESS) == 0 && !SSL_clear_not_quic(ssl)) + return -1; +#else if ((s->s3.flags & TLS1_FLAGS_STATELESS) == 0 && !SSL_clear(ssl)) return -1; +#endif } #ifndef OPENSSL_NO_SCTP if (SSL_CONNECTION_IS_DTLS(s) && BIO_dgram_is_sctp(SSL_get_wbio(ssl))) { @@ -620,6 +625,11 @@ static SUB_STATE_RETURN read_state_machine(SSL_CONNECTION *s) * In DTLS we get the whole message in one go - header and body */ ret = dtls_get_message(s, &mt); +#ifndef OPENSSL_NO_BORING_QUIC_API + } else if (SSL_CONNECTION_IS_QUIC(s)) { + /* QUIC behaves like DTLS -- all in one go. */ + ret = quic_get_message(s, &mt); +#endif } else { ret = tls_get_message_header(s, &mt); } @@ -649,8 +659,8 @@ static SUB_STATE_RETURN read_state_machine(SSL_CONNECTION *s) return SUB_STATE_ERROR; } - /* dtls_get_message already did this */ - if (!SSL_CONNECTION_IS_DTLS(s) + /* dtls_get_message/quic_get_message already did this */ + if (!SSL_CONNECTION_IS_DTLS(s) && !SSL_CONNECTION_IS_QUIC(s) && s->s3.tmp.message_size > 0 && !grow_init_buf(s, s->s3.tmp.message_size + SSL3_HM_HEADER_LENGTH)) { @@ -668,6 +678,10 @@ static SUB_STATE_RETURN read_state_machine(SSL_CONNECTION *s) * opportunity to do any further processing. */ ret = dtls_get_message_body(s, &len); +#ifndef OPENSSL_NO_BORING_QUIC_API + } else if (SSL_CONNECTION_IS_QUIC(s)) { + ret = quic_get_message_body(s, &len); +#endif } else { ret = tls_get_message_body(s, &len); } @@ -960,6 +974,14 @@ static SUB_STATE_RETURN write_state_machine(SSL_CONNECTION *s) int statem_flush(SSL_CONNECTION *s) { s->rwstate = SSL_WRITING; +#ifndef OPENSSL_NO_BORING_QUIC_API + if (SSL_CONNECTION_IS_QUIC(s)) { + if (!s->quic_method->flush_flight(SSL_CONNECTION_GET_SSL(s))) { + ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); + return 0; + } + } else +#endif if (BIO_flush(s->wbio) <= 0) { return 0; } diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c index 7d8b140373add..d11ea449fa288 100644 --- a/ssl/statem/statem_clnt.c +++ b/ssl/statem/statem_clnt.c @@ -958,6 +958,14 @@ int ossl_statem_client_construct_message(SSL_CONNECTION *s, break; case TLS_ST_CW_END_OF_EARLY_DATA: +#ifndef OPENSSL_NO_BORING_QUIC_API + /* QUIC does not send EndOfEarlyData, RFC9001 S8.3 */ + if (SSL_CONNECTION_IS_QUIC(s)) { + *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_lib.c b/ssl/statem/statem_lib.c index 8932ac44ca8ac..fd24e6fa78b2a 100644 --- a/ssl/statem/statem_lib.c +++ b/ssl/statem/statem_lib.c @@ -90,8 +90,28 @@ int ssl3_do_write(SSL_CONNECTION *s, uint8_t type) s->statem.write_in_progress = 1; } - ret = ssl3_write_bytes(ssl, type, &s->init_buf->data[s->init_off], - s->init_num, &written); +#ifndef OPENSSL_NO_BORING_QUIC_API + if (SSL_CONNECTION_IS_QUIC(s)) { + if (type == SSL3_RT_HANDSHAKE) { + ret = s->quic_method->add_handshake_data(ssl, 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 */ + ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); + } else { + written = s->init_num; + } + } else { + /* QUIC doesn't use ChangeCipherSpec */ + ret = -1; + ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + } + } else +#endif + ret = ssl3_write_bytes(ssl, type, &s->init_buf->data[s->init_off], + s->init_num, &written); if (ret <= 0) return -1; if (type == SSL3_RT_HANDSHAKE) @@ -685,6 +705,13 @@ CON_FUNC_RETURN tls_construct_finished(SSL_CONNECTION *s, WPACKET *pkt) CON_FUNC_RETURN tls_construct_key_update(SSL_CONNECTION *s, WPACKET *pkt) { +#ifndef OPENSSL_NO_BORING_QUIC_API + if (SSL_CONNECTION_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 CON_FUNC_ERROR; @@ -707,6 +734,13 @@ MSG_PROCESS_RETURN tls_process_key_update(SSL_CONNECTION *s, PACKET *pkt) return MSG_PROCESS_ERROR; } +#ifndef OPENSSL_NO_BORING_QUIC_API + if (SSL_CONNECTION_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); diff --git a/ssl/statem/statem_local.h b/ssl/statem/statem_local.h index 04114b1e27d7f..e96b59cbf82b6 100644 --- a/ssl/statem/statem_local.h +++ b/ssl/statem/statem_local.h @@ -113,6 +113,10 @@ __owur int tls_get_message_header(SSL_CONNECTION *s, int *mt); __owur int tls_get_message_body(SSL_CONNECTION *s, size_t *len); __owur int dtls_get_message(SSL_CONNECTION *s, int *mt); __owur int dtls_get_message_body(SSL_CONNECTION *s, size_t *len); +#ifndef OPENSSL_NO_BORING_QUIC_API +__owur int quic_get_message(SSL_CONNECTION *s, int *mt); +__owur int quic_get_message_body(SSL_CONNECTION *s, size_t *len); +#endif /* Message construction and processing functions */ __owur int tls_process_initial_server_flight(SSL_CONNECTION *s); @@ -339,6 +343,14 @@ int tls_parse_ctos_psk(SSL_CONNECTION *s, PACKET *pkt, unsigned int context, int tls_parse_ctos_post_handshake_auth(SSL_CONNECTION *, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx); +#ifndef OPENSSL_NO_BORING_QUIC_API +int tls_parse_ctos_quic_transport_params_draft(SSL_CONNECTION *s, PACKET *pkt, + unsigned int context, X509 *x, + size_t chainidx); + +int tls_parse_ctos_quic_transport_params(SSL_CONNECTION *s, PACKET *pkt, unsigned int context, + X509 *x, size_t chainidx); +#endif EXT_RETURN tls_construct_stoc_renegotiate(SSL_CONNECTION *s, WPACKET *pkt, unsigned int context, X509 *x, @@ -405,6 +417,16 @@ EXT_RETURN tls_construct_stoc_cryptopro_bug(SSL_CONNECTION *s, WPACKET *pkt, EXT_RETURN tls_construct_stoc_psk(SSL_CONNECTION *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx); +#ifndef OPENSSL_NO_BORING_QUIC_API +EXT_RETURN tls_construct_stoc_quic_transport_params_draft(SSL_CONNECTION *s, WPACKET *pkt, + unsigned int context, + X509 *x, + size_t chainidx); + +EXT_RETURN tls_construct_stoc_quic_transport_params(SSL_CONNECTION *s, WPACKET *pkt, + unsigned int context, X509 *x, + size_t chainidx); +#endif /* Client Extension processing */ EXT_RETURN tls_construct_ctos_renegotiate(SSL_CONNECTION *s, WPACKET *pkt, @@ -487,6 +509,15 @@ EXT_RETURN tls_construct_ctos_psk(SSL_CONNECTION *s, WPACKET *pkt, EXT_RETURN tls_construct_ctos_post_handshake_auth(SSL_CONNECTION *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx); +#ifndef OPENSSL_NO_BORING_QUIC_API +EXT_RETURN tls_construct_ctos_quic_transport_params_draft(SSL_CONNECTION *s, WPACKET *pkt, + unsigned int context, X509 *x, + size_t chainidx); + +EXT_RETURN tls_construct_ctos_quic_transport_params(SSL_CONNECTION *s, WPACKET *pkt, + unsigned int context, X509 *x, + size_t chainidx); +#endif int tls_parse_stoc_renegotiate(SSL_CONNECTION *s, PACKET *pkt, unsigned int context, @@ -538,6 +569,14 @@ int tls_parse_stoc_cookie(SSL_CONNECTION *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx); int tls_parse_stoc_psk(SSL_CONNECTION *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx); +#ifndef OPENSSL_NO_BORING_QUIC_API +int tls_parse_stoc_quic_transport_params_draft(SSL_CONNECTION *s, PACKET *pkt, + unsigned int context, X509 *x, + size_t chainidx); + +int tls_parse_stoc_quic_transport_params(SSL_CONNECTION *s, PACKET *pkt, unsigned int context, + X509 *x, size_t chainidx); +#endif int tls_handle_alpn(SSL_CONNECTION *s); diff --git a/ssl/statem/statem_quic.c b/ssl/statem/statem_quic.c new file mode 100644 index 0000000000000..a65d6ec596e44 --- /dev/null +++ b/ssl/statem/statem_quic.c @@ -0,0 +1,117 @@ +/* + * 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 + * 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" + +int quic_get_message(SSL_CONNECTION *s, int *mt) +{ + size_t l; + QUIC_DATA *qd = s->quic_input_data_head; + uint8_t *p; + + if (qd == NULL) { + s->rwstate = SSL_READING; + *mt = 0; + return 0; + } + + if (!ossl_assert(qd->length >= SSL3_HM_HEADER_LENGTH)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_BAD_LENGTH); + *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 = 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 = 0; + return 0; + } + + /* Copy buffered data */ + 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) + 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 = l; + s->init_msg = s->init_buf->data + SSL3_HM_HEADER_LENGTH; + + return 1; +} + +int quic_get_message_body(SSL_CONNECTION *s, size_t *len) +{ + /* No CCS in QUIC/TLSv1.3? */ + 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 (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 (s->s3.tmp.message_type == 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 (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, SSL_CONNECTION_GET_SSL(s), + s->msg_callback_arg); + + *len = s->init_num; + return 1; +} diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c index 47855da5bd13b..82b449c583399 100644 --- a/ssl/statem/statem_srvr.c +++ b/ssl/statem/statem_srvr.c @@ -81,7 +81,8 @@ static int ossl_statem_server13_read_transition(SSL_CONNECTION *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_CONNECTION_IS_QUIC(s)) { if (mt == SSL3_MT_END_OF_EARLY_DATA) { st->hand_state = TLS_ST_SR_END_OF_EARLY_DATA; return 1; @@ -1024,6 +1025,16 @@ WORK_STATE ossl_statem_server_post_work(SSL_CONNECTION *s, WORK_STATE wst) SSL3_CC_APPLICATION | SSL3_CHANGE_CIPHER_SERVER_WRITE)) /* SSLfatal() already called */ return WORK_ERROR; + +#ifndef OPENSSL_NO_BORING_QUIC_API + if (SSL_CONNECTION_IS_QUIC(s) && s->ext.early_data == SSL_EARLY_DATA_ACCEPTED) { + s->early_data_state = SSL_EARLY_DATA_FINISHED_READING; + if (!ssl->method->ssl3_enc->change_cipher_state( + s, SSL3_CC_HANDSHAKE | SSL3_CHANGE_CIPHER_SERVER_READ)) + /* SSLfatal() already called */ + return WORK_ERROR; + } +#endif } break; @@ -1648,6 +1659,15 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL_CONNECTION *s, PACKET *pkt) goto err; } } +#ifndef OPENSSL_NO_BORING_QUIC_API + if (SSL_CONNECTION_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, diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c index 772a6fc173839..6dcce0d617adc 100644 --- a/ssl/tls13_enc.c +++ b/ssl/tls13_enc.c @@ -17,7 +17,22 @@ #include #define TLS13_MAX_LABEL_LEN 249 - +/* 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"; /* ASCII: "tls13 ", in hex for EBCDIC compatibility */ static const unsigned char label_prefix[] = "\x74\x6C\x73\x31\x33\x20"; @@ -410,24 +425,212 @@ static int derive_secret_key_and_iv(SSL_CONNECTION *s, const EVP_MD *md, return 1; } + +#ifndef OPENSSL_NO_BORING_QUIC_API +static int quic_change_cipher_state(SSL_CONNECTION *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; + 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); + + 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; + } + + 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(SSL_CONNECTION_GET_CTX(s), 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; + } + + 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, + 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)) { + /* 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, + 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(SSL_CONNECTION_GET_SSL(s), level)) { + /* SSLfatal() already called */ + goto err; + } + if (s->server) + s->quic_write_level = level; + else + s->quic_read_level = level; + } else { + /* is_client_write || is_server_read */ + + 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) + || !ssl_log_secret(s, CLIENT_EARLY_LABEL, + s->client_early_traffic_secret, hashlen) + || !quic_set_encryption_secrets(SSL_CONNECTION_GET_SSL(s), level)) { + /* SSLfatal() already called */ + goto err; + } + } else if (is_handshake) { + 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 (level != ssl_encryption_early_data) { + if (s->server) + s->quic_read_level = level; + else + s->quic_write_level = level; + } + } + + ret = 1; + err: + return ret; +} +#endif /* OPENSSL_NO_BORING_QUIC_API */ + int tls13_change_cipher_state(SSL_CONNECTION *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[EVP_MAX_IV_LENGTH]; unsigned char key[EVP_MAX_KEY_LENGTH]; unsigned char secret[EVP_MAX_MD_SIZE]; @@ -447,6 +650,10 @@ int tls13_change_cipher_state(SSL_CONNECTION *s, int which) int level; int direction = (which & SSL3_CC_READ) != 0 ? OSSL_RECORD_DIRECTION_READ : OSSL_RECORD_DIRECTION_WRITE; +#ifndef OPENSSL_NO_BORING_QUIC_API + if (SSL_CONNECTION_IS_QUIC(s)) + return quic_change_cipher_state(s, which); +#endif if (((which & SSL3_CC_CLIENT) && (which & SSL3_CC_WRITE)) || ((which & SSL3_CC_SERVER) && (which & SSL3_CC_READ))) { diff --git a/test/ext_internal_test.c b/test/ext_internal_test.c index 20cf708de27a3..be08aca474a61 100644 --- a/test/ext_internal_test.c +++ b/test/ext_internal_test.c @@ -72,6 +72,13 @@ static EXT_LIST ext_list[] = { EXT_ENTRY(compress_certificate), EXT_ENTRY(early_data), EXT_ENTRY(certificate_authorities), +#ifndef OPENSSL_NO_BORING_QUIC_API + 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) diff --git a/test/sslapitest.c b/test/sslapitest.c index 0b2d7b5e6d307..072e5704e5d24 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -10780,6 +10780,7 @@ static int test_inherit_verify_param(void) return testresult; } + static int test_load_dhfile(void) { #ifndef OPENSSL_NO_DH @@ -10815,9 +10816,369 @@ static int test_load_dhfile(void) #endif } +#ifndef OPENSSL_NO_BORING_QUIC_API +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_is_server(ssl) ? "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_info("quic_add_handshake_data() %s, lvl=%d, *data=0x%02X, len=%zd\n", + SSL_is_server(ssl) ? "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; + } + + return 1; +} + +static int test_quic_flush_flight(SSL *ssl) +{ + test_printf_stderr("quic_flush_flight() %s\n", SSL_is_server(ssl) ? "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_is_server(ssl) ? "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_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; + 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; + + TEST_info("original clnt=0x%X, srvr=0x%X\n", clnt, srvr); + + 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, + 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)) + || !TEST_true(test_quic_api_set_versions(clientssl, clnt)) + || !TEST_true(test_quic_api_set_versions(serverssl, srvr)) + || !TEST_true(create_bare_ssl_connection(serverssl, clientssl, + SSL_ERROR_NONE, 0,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)) + || !(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, 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, strlen(server_str)+1)) + goto end; + + /* Deal with two NewSessionTickets */ + if (!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; + + 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: + SSL_free(serverssl); + SSL_free(clientssl); + SSL_CTX_free(sctx); + SSL_CTX_free(cctx); + + 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; +} + +# 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, SHA384_DIGEST_LENGTH); + 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_bare_ssl_connection(*serverssl, *clientssl, + SSL_ERROR_NONE, 0, 0))) + return 0; + + /* Deal with two NewSessionTickets */ + if (!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_bare_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE, 0, 0)) + || !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_BORING_QUIC_API */ + #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; @@ -10877,6 +11238,7 @@ static int test_read_ahead_key_change(void) SSL_free(clientssl); SSL_CTX_free(sctx); SSL_CTX_free(cctx); + return testresult; } @@ -12119,6 +12481,12 @@ int setup_tests(void) ADD_ALL_TESTS(test_handshake_retry, 16); ADD_TEST(test_data_retry); ADD_ALL_TESTS(test_multi_resume, 5); +#ifndef OPENSSL_NO_BORING_QUIC_API + 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; err: diff --git a/test/tls13secretstest.c b/test/tls13secretstest.c index 352c1898adfb1..82324a9af964b 100644 --- a/test/tls13secretstest.c +++ b/test/tls13secretstest.c @@ -228,6 +228,12 @@ int ssl_set_new_record_layer(SSL_CONNECTION *s, int version, int direction, { return 0; } +#ifndef OPENSSL_NO_BORING_QUIC_API +int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level) +{ + return 1; +} +#endif /* End of mocked out code */ diff --git a/util/libssl.num b/util/libssl.num index da18be5a62ce4..7b40966f5094a 100644 --- a/util/libssl.num +++ b/util/libssl.num @@ -556,7 +556,7 @@ SSL_get_negotiated_server_cert_type 556 3_2_0 EXIST::FUNCTION: SSL_add_expected_rpk 557 3_2_0 EXIST::FUNCTION: d2i_SSL_SESSION_ex 558 3_2_0 EXIST::FUNCTION: SSL_is_tls 559 3_2_0 EXIST::FUNCTION: -SSL_is_quic 560 3_2_0 EXIST::FUNCTION: +SSL_is_quic 560 3_2_0 NOEXIST::FUNCTION: SSL_get_handshake_rtt 561 3_2_0 EXIST::FUNCTION: SSL_new_stream 562 3_2_0 EXIST::FUNCTION: SSL_get0_connection 563 3_2_0 EXIST::FUNCTION: @@ -583,3 +583,19 @@ SSL_set_value_uint 583 3_3_0 EXIST::FUNCTION: SSL_poll 584 3_3_0 EXIST::FUNCTION: SSL_SESSION_get_time_ex 585 3_3_0 EXIST::FUNCTION: SSL_SESSION_set_time_ex 586 3_3_0 EXIST::FUNCTION: +SSL_quic_read_level 20000 3_0_0 EXIST::FUNCTION:BORING_QUIC_API +SSL_set_quic_transport_params 20001 3_0_0 EXIST::FUNCTION:BORING_QUIC_API +SSL_CIPHER_get_prf_nid 20002 3_0_0 EXIST::FUNCTION:BORING_QUIC_API +SSL_is_quic 20003 3_0_0 EXIST::FUNCTION: +SSL_get_peer_quic_transport_params 20004 3_0_0 EXIST::FUNCTION:BORING_QUIC_API +SSL_quic_write_level 20005 3_0_0 EXIST::FUNCTION:BORING_QUIC_API +SSL_CTX_set_quic_method 20006 3_0_0 EXIST::FUNCTION:BORING_QUIC_API +SSL_set_quic_method 20007 3_0_0 EXIST::FUNCTION:BORING_QUIC_API +SSL_quic_max_handshake_flight_len 20008 3_0_0 EXIST::FUNCTION:BORING_QUIC_API +SSL_process_quic_post_handshake 20009 3_0_0 EXIST::FUNCTION:BORING_QUIC_API +SSL_provide_quic_data 20010 3_0_0 EXIST::FUNCTION:BORING_QUIC_API +SSL_set_quic_use_legacy_codepoint 20011 3_0_0 EXIST::FUNCTION:BORING_QUIC_API +SSL_set_quic_transport_version 20012 3_0_0 EXIST::FUNCTION:BORING_QUIC_API +SSL_get_peer_quic_transport_version 20013 3_0_0 EXIST::FUNCTION:BORING_QUIC_API +SSL_get_quic_transport_version 20014 3_0_0 EXIST::FUNCTION:BORING_QUIC_API +SSL_set_quic_early_data_enabled 20015 3_0_0 EXIST::FUNCTION:BORING_QUIC_API diff --git a/util/other.syms b/util/other.syms index 84e6bb6ba3efe..cc870011a7a42 100644 --- a/util/other.syms +++ b/util/other.syms @@ -146,6 +146,8 @@ ssl_ct_validation_cb datatype ASYNC_stack_alloc_fn datatype ASYNC_stack_free_fn datatype PKCS12_create_cb datatype +OSSL_ENCRYPTION_LEVEL datatype +SSL_QUIC_METHOD datatype # ASN1_BIT_STRING_digest define BIO_IS_ERRNO define