diff -Nru rust-rustls-0.21.9/debian/changelog rust-rustls-0.21.10/debian/changelog --- rust-rustls-0.21.9/debian/changelog 2023-11-27 15:19:59.000000000 +0000 +++ rust-rustls-0.21.10/debian/changelog 2024-01-14 17:41:57.000000000 +0000 @@ -1,3 +1,15 @@ +rust-rustls (0.21.10-1) unstable; urgency=medium + + [ upstream ] + * new release + + [ Jonas Smedegaard ] + * update dh-cargo fork + * update copyright info: update coverage + * bump project versions in virtual packages and autopkgtests + + -- Jonas Smedegaard Sun, 14 Jan 2024 18:41:57 +0100 + rust-rustls (0.21.9-1) unstable; urgency=medium * unfuzz patches diff -Nru rust-rustls-0.21.9/debian/control rust-rustls-0.21.10/debian/control --- rust-rustls-0.21.9/debian/control 2023-11-27 15:19:09.000000000 +0000 +++ rust-rustls-0.21.10/debian/control 2024-01-14 17:41:42.000000000 +0000 @@ -48,7 +48,7 @@ librust-rustls-0.21+secret-extraction-dev (= ${binary:Version}), librust-rustls-0.21+tls12-dev (= ${binary:Version}), librust-rustls-0.21-dev (= ${binary:Version}), - librust-rustls-0.21.9-dev (= ${binary:Version}), + librust-rustls-0.21.10-dev (= ${binary:Version}), Description: modern TLS library written in Rust - Rust source code Rustls is a modern TLS library written in Rust. It uses ring for cryptography diff -Nru rust-rustls-0.21.9/debian/copyright rust-rustls-0.21.10/debian/copyright --- rust-rustls-0.21.9/debian/copyright 2023-07-16 10:58:33.000000000 +0000 +++ rust-rustls-0.21.10/debian/copyright 2024-01-14 17:40:41.000000000 +0000 @@ -14,7 +14,7 @@ 2020 Bastian Germann 2020 Debian Rust Maintainers - 2022-2023 Jonas Smedegaard + 2022-2024 Jonas Smedegaard 2022 Purism, SPC License-Grant: This packaging is free software: @@ -27,7 +27,7 @@ Reference: debian/copyright Files: - debian/debcargo/bin/cargo + debian/dh-cargo/bin/cargo Copyright: 2022 Jonas Smedegaard 2015-2016 Luca Bruno @@ -36,11 +36,13 @@ License: Apache-2.0 or Expat Files: + debian/dh-cargo/bin/dh-cargo-built-using debian/debcargo/lib/* Copyright: 2022-2023 Jonas Smedegaard 2016 Josh Triplett - 2018 Ximin Luo + 2019-2021 Sylvestre Ledru + 2018-2021 Ximin Luo License: Expat License: Apache-2.0 diff -Nru rust-rustls-0.21.9/debian/dh-cargo/README.md rust-rustls-0.21.10/debian/dh-cargo/README.md --- rust-rustls-0.21.9/debian/dh-cargo/README.md 2023-08-24 10:50:01.000000000 +0000 +++ rust-rustls-0.21.10/debian/dh-cargo/README.md 2023-12-30 15:45:34.000000000 +0000 @@ -1,14 +1,14 @@ # dh-cargo fork This is a fork of the debhelper script [dh-cargo], -based on git commit e07347b -(included with version 30 released 2022-11-25), +based on git commit e0317c5 +(included with version 31 released 2023-12-22), with these functional changes: * support workspace (i.e. multi-crate project), * resolve crate name and version from Cargo.toml, using X-Cargo-Crates hint or library package name only as key - * support debhelper option --sourcedirectory + * support debhelper options --sourcedirectory --builddirectory * support debhelper option --no-package * validate package names against Cargo.toml entries, failing early (not after test) on crate vs. package mismatch @@ -25,16 +25,18 @@ (not confusingly only dh_auto_test) Also included is a slight fork of related [cargo] wrapper script, -based on git commit e4072cb -(included with version 0.63.1-1 released 2022-11-16), +based on git commit bac0ad2d +(included with version 0.66.0+ds2-1 released 2023-12-03), with these functional changes: + * support CARGO_MANIFEST_DIR=${debhelper_sourcedirectory} * support --remap-path-prefix option sets in RUSTFLAGS by omitting that (not fail) when DEB_CARGO_CRATE is not set * support documented shorter CARGO_HOME path * support cargo option --path * fix only inject path for "cargo install" when not passed as option * support DEB_BUILD_OPTIONS=terse + * warn when cargo wrapper bails due to mismatching CARGO_HOME * enable optimization flags by default also for tests, and support DEB_BUILD_OPTIONS=noopt @@ -62,4 +64,4 @@ ``` - -- Jonas Smedegaard Sat, Thu, 24 Aug 2023 11:55:01 +0200 + -- Jonas Smedegaard Sat, 30 Dec 2023 16:19:18 +0100 diff -Nru rust-rustls-0.21.9/debian/dh-cargo/bin/cargo rust-rustls-0.21.10/debian/dh-cargo/bin/cargo --- rust-rustls-0.21.9/debian/dh-cargo/bin/cargo 2023-08-24 10:50:01.000000000 +0000 +++ rust-rustls-0.21.10/debian/dh-cargo/bin/cargo 2023-12-30 15:45:34.000000000 +0000 @@ -2,9 +2,10 @@ """ Wrapper around cargo to have it build using Debian settings. +SPDX-FileCopyrightText: 2022 Jonas Smedegaard SPDX-FileCopyrightText: 2015-2016 Luca Bruno -SPDX-FileCopyrightText: 2016-2019 Ximin Luo SPDX-FileCopyrightText: 2017-2019 Vasudeva Kamath +SPDX-FileCopyrightText: 2016-2019 Ximin Luo SPDX-License-Identifier: Apache-2.0 or MIT @@ -138,13 +139,14 @@ def install(destdir, cratespec, host_rust_type, crate_in_registry, install_prefix, *args): crate, version = cratespec.rsplit("_", 1) + builddir = os.getenv("DEB_BUILDDIR", "target") log("installing into destdir '%s' prefix '%s'" % (destdir, install_prefix)) install_target = destdir + install_prefix path_args = [] if "--path" in args else ["--path", sourcepath()] logrun(["env", "RUST_BACKTRACE=1", # set CARGO_TARGET_DIR so build products are saved in target/ # normally `cargo install` deletes them when it exits - "CARGO_TARGET_DIR=" + sourcepath("target"), + "CARGO_TARGET_DIR=" + sourcepath(builddir), "/usr/bin/cargo"] + list(args) + ([crate, "--vers", version] if crate_in_registry else path_args) + ["--root", install_target], check=True) @@ -153,8 +155,8 @@ # if there was a custom build output, symlink it to debian/cargo_out_dir # hopefully cargo will provide a better solution in future https://github.com/rust-lang/cargo/issues/5457 - r = logrun('''ls -td "target/%s/release/build/%s"-*/out 2>/dev/null | head -n1''' - % (host_rust_type, crate), shell=True, stdout=subprocess.PIPE).stdout + r = logrun('''ls -td "%s/%s/release/build/%s"-*/out 2>/dev/null | head -n1''' + % (builddir, host_rust_type, crate), shell=True, stdout=subprocess.PIPE).stdout r = r.decode("utf-8").rstrip() if r: logrun(["ln", "-sfT", "../%s" % r, "debian/cargo_out_dir"], check=True) @@ -163,6 +165,7 @@ def main(*args): cargo_home = os.getenv("CARGO_HOME", "") if not cargo_home.endswith("debian/cargo_home"): + log(f"WARNING: falling back to simply calling upstream cargo, because CARGO_HOME does not end with debian/cargo_home: ", cargo_home) os.execv("/usr/bin/cargo", ["cargo"] + list(args)) if any(f not in os.environ for f in FLAGS.split()): @@ -175,9 +178,20 @@ build_profiles = os.getenv("DEB_BUILD_PROFILES", "").split() parallel = [] + lto = 0 for o in build_options: if o.startswith("parallel="): parallel = ["-j" + o[9:]] + elif o.startswith("optimize="): + opt_arg = o[9:] + for arg in opt_arg.split(","): + if opt_arg == "-lto": + lto = -1 + elif opt_arg == "+lto": + lto = 1 + else: + log(f"WARNING: unhandled optimization flag: {opt_arg}") + nodoc = "nodoc" in build_options or "nodoc" in build_profiles nocheck = "nocheck" in build_options or "nocheck" in build_profiles noopt = "noopt" in build_options @@ -190,7 +204,7 @@ host_rust_type = os.getenv("DEB_HOST_RUST_TYPE", "") host_gnu_type = os.getenv("DEB_HOST_GNU_TYPE", "") - log("options, profiles, parallel:", build_options, build_profiles, parallel) + log("options, profiles, parallel, lto:", build_options, build_profiles, parallel, lto) log("rust_type, gnu_type:", ", ".join([host_rust_type, host_gnu_type])) if "RUSTFLAGS" in os.environ: @@ -241,6 +255,11 @@ if nocheck and subcmd in ("test", "bench"): return 0 + if lto == 1: + newargs.append("--config profile.release.lto = \"thin\"") + elif lto == -1: + newargs.append("--config profile.release.lto = false") + if subcmd == "clean": logrun(["env", "RUST_BACKTRACE=1", "/usr/bin/cargo"] + list(newargs), check=True) if os.path.exists(cargo_home): diff -Nru rust-rustls-0.21.9/debian/dh-cargo/bin/dh-cargo-built-using rust-rustls-0.21.10/debian/dh-cargo/bin/dh-cargo-built-using --- rust-rustls-0.21.9/debian/dh-cargo/bin/dh-cargo-built-using 1970-01-01 00:00:00.000000000 +0000 +++ rust-rustls-0.21.10/debian/dh-cargo/bin/dh-cargo-built-using 2023-12-30 14:58:00.000000000 +0000 @@ -0,0 +1,180 @@ +#!/bin/sh +# Generates Built-Using after a successful cargo build. +# Run this in the package top-level directory where debian/ is. +# +# SPDX-FileCopyrightText: 2023 Jonas Smedegaard +# SPDX-FileCopyrightText: 2018-2021 Ximin Luo +# +# SPDX-License-Identifier: MIT + +set -e + +DEB_BUILDDIR="${DEB_BUILD_DIR:-target}" +DEB_HOST_RUST_TYPE="${DEB_HOST_RUST_TYPE:-$(printf "include /usr/share/rustc/architecture.mk\nall:\n\techo \$(DEB_HOST_RUST_TYPE)\n" | make --no-print-directory -sf -)}" +CARGO_REGISTRY="${CARGO_REGISTRY:-debian/cargo_registry}" +CARGO_CHANNEL="${CARGO_CHANNEL:-release}" +# useful for testing: +# CARGO_REGISTRY="$HOME/.cargo/registry/src/github.com-1ecc6299db9ec823" DEB_HOST_RUST_TYPE="." CARGO_CHANNEL=debug + +CARGO_TARGET_DIR="$DEB_BUILDDIR/$DEB_HOST_RUST_TYPE/$CARGO_CHANNEL" +CARGO_TARGET_DIR_ABS="$(readlink -f "$CARGO_TARGET_DIR")" + +CPRIGHT_FORMAT="https://www.debian.org/doc/packaging-manuals/copyright-format/1.0" +SRCLEFT_LICENSES="$(echo GPL LGPL AGPL GFDL MPL CDDL CPL Artistic Perl QPL | tr ' ' '\n')" +pkg_has_srcleft_license() { + local pkg="$1" + local ver="$2" + local f="/usr/share/doc/$pkg/copyright" + if ! sed -nre 's ^Format: (.*) \1 gp' "$f" | grep -qiw "$CPRIGHT_FORMAT"; then + echo >&2 "$0: abort: Not in machine-readable format: $f" + echo 2 + elif sed -nre 's ^X-Binary-Requires-Source: (.*) \1 gp' "$f" | grep -qiw yes; then + echo 1 + elif sed -nre 's ^License: (.*) \1 gp' "$f" | grep -qiwF "$SRCLEFT_LICENSES"; then + echo 1 + else + echo 0 + fi +} + +dep_files_to_pkgs() { + xargs -r dpkg -S \ + | sed -nre 's (.*): .* \1 gp' \ + | xargs -r dpkg-query --show \ + | while read pkg ver; do echo "$pkg $ver $(pkg_has_srcleft_license "${pkg%:*}" "$ver")"; done + # pkg_has_srcleft_license should be accurate for all rust crates, no need to give a $containing_crate + # this is due to nature of crate copyright info, and the debian rust packaging policy +} + +rust_dep_files() { + cat "$CARGO_TARGET_DIR/deps"/*.d \ + | sed -nre 's ^\S*/('"$CARGO_REGISTRY"'/[^/]*)/.* '"$(readlink -f "$PWD")/"'\1 gp' \ + | sort -u \ + | xargs -r readlink -f +} + +rust_libs() { + { which rustc; rust_dep_files; } | dep_files_to_pkgs +} + +gcc_default_searchdirs() { + gcc -print-search-dirs \ + | sed -nre 's ^libraries: (.*) \1 gp' \ + | tr ':' '\n' \ + | sed -e 's ^= '"$(gcc -print-sysroot)"' g' \ + | xargs readlink -m 2>/dev/null # suppress errors caused by early pipe closure +} + +rust_search_lib() { + local lib="$1" + { + cat + # rust does not actually search normal paths when linking static libs + # - see https://github.com/rust-lang/rust/issues/43118 + # - see also `fn link_rlib` in back/link.rs which calls + # `pub fn find_library` in back/archive.rs which generates the error message + #gcc_default_searchdirs + } | while read searchdir; do + #echo >&2 "searching $searchdir for static lib $lib" + local f="$(readlink -m "$searchdir/lib${lib}.a")" + if test -f "$f"; then + printf "%s\n" "$f" + break + fi + done +} + +native_libs() { + ls -1d "$CARGO_TARGET_DIR/build"/*/output 2>/dev/null | while read output; do + sed -nre 's ^cargo:rustc-link-lib=static=(.*) \1 '"$output"' gp' "$output" + done | while read lib output; do + local containing_crate="$(basename "$(dirname "$output")")" + test -n "$lib" || continue + local libfile="$(sed -nre 's ^cargo:rustc-link-search=native=(.*) \1 gp' "$output" | rust_search_lib "$lib")" + local srcleft="" + test -n "$libfile" || { echo >&2 "$0: abort: could not find static lib '$lib'; rustc should have failed already?"; exit 1; } + echo >&2 "$0: found static lib $lib at $libfile" + if [ "${libfile#$CARGO_TARGET_DIR_ABS/}" != "$libfile" ]; then + # static library source code embedded in crate + local srcstat="$(sed -nre 's ^dh-cargo:deb-built-using='"$lib"'=([01]=.*) \1 gp' "$output")" + case "$srcstat" in + 0=*|1=*) + srcleft="${srcstat%%=*}" + libfile="${srcstat#*=}" + if [ "$(readlink -f "$libfile")" = "$(readlink -f "$PWD")" ]; then + # Note that this exception only applies in the case that where you are building + # the Debian package for $containing_crate itself. In the case where you are + # building a Debian package for crate X depending on $containing_crate, the + # latter still has to output the dh-cargo:deb-built-using in their build.rs so + # that the Debian package for crate X can correctly set Built-Using themselves. + echo >&2 "$0: static library derived from $libfile which is the top-level crate being built, no need to add Built-Using" + continue + fi + ;; + *) + echo >&2 "$0: abort: could not determine source-distribution conditions of ${libfile#$CARGO_TARGET_DIR_ABS/}." + echo >&2 "You must patch build.rs of ${containing_crate%-*} to output 'println!(\"dh-cargo:deb-built-using=$lib=\$s={}\", env::var(\"CARGO_MANIFEST_DIR\").unwrap());' where:" + echo >&2 "- \$s is 1 if the license(s) of the included static libs require source distribution alongside binaries, otherwise 0" + exit 1 + ;; + esac + fi + local wpkg="$(dpkg -S "$(readlink -f "$libfile")")" + test -n "$wpkg" || { echo >&2 "$0: abort: could not find Debian package for file $libfile"; exit 1; } + local pkgstat="$(echo "$wpkg" | sed -nre 's (.*): .* \1 gp' | xargs -r dpkg-query --show)" + local pkg="$(echo "$pkgstat" | cut -f1)" + local ver="$(echo "$pkgstat" | cut -f2)" + # static library source code embedded in crate (from earlier) + if [ -n "$srcleft" ]; then + echo "$pkg $ver $srcleft" + # static libraries from another Debian package + elif sed -nre 's ^dh-cargo:deb-built-using='"$lib"'=0~=(.*) \1 gp' "$output" | { echo "${pkg%:*} $ver" | grep -qExf /dev/fd/3; } 3<&0; then + echo "$pkg $ver 0" + elif sed -nre 's ^dh-cargo:deb-built-using='"$lib"'=1~=(.*) \1 gp' "$output" | { echo "${pkg%:*} $ver" | grep -qExf /dev/fd/3; } 3<&0; then + echo "$pkg $ver 1" + else + # guess the conditions based on the whole d/copyright file + # this loses granularity, e.g. gcc is mostly distributed as GPL-3 but the libbacktrace portion is BSD-3 + # to retain granularity the crate package maintainer should patch build.rs as suggested + echo >&2 "$0: warning: guessing source-distribution conditions of $libfile, this may be inaccurate." + echo >&2 "$0: warning: patch build.rs to suppress the above warning" + srcleft="$(pkg_has_srcleft_license "${pkg%:*}" "$ver")" + if [ "$srcleft" -gt 1 ]; then + echo >&2 "You must patch build.rs of ${containing_crate%-*} to output 'dh-cargo:deb-built-using=$lib=\$s~=\$PAT' where:" + echo >&2 "- \$s is 1 if the license(s) of the included static libs require source distribution alongside binaries, otherwise 0" + echo >&2 "- \$PAT is an egrep pattern matching the \"\$pkg \$ver\" combinations that satisfy \$s" + echo >&2 " for example '$pkg .*' matches the currently-relevant package, $pkg $ver" + exit 1 + fi + echo "$pkg $ver $srcleft" + fi + done +} + +output() { + local binpkg="$1" + if [ -z "$binpkg" ]; then + cat + else + local built_using="" + local built_using_x="" + while read pkg ver srcleft; do + local src="$(dpkg-query -f '${source:Package}' --show "$pkg")" + local srcver="$(dpkg-query -f '${source:Version}' --show "$pkg")" + case "$srcleft" in + 2) exit 1;; + 1) built_using="${built_using}$src (= $srcver), ";; + esac + built_using_x="${built_using_x}$src (= $srcver), " + done + echo "cargo:Built-Using=${built_using%, }" >> "debian/$binpkg.substvars" + echo "cargo:X-Cargo-Built-Using=${built_using_x%, }" >> "debian/$binpkg.substvars" + echo "cargo:Static-Built-Using=${built_using_x%, }" >> "debian/$binpkg.substvars" + fi +} + +native_libs="$(native_libs)" # capture output outside of pipe so set -e works +{ +rust_libs +test -z "$native_libs" || echo "$native_libs" +} | LC_ALL=C.utf-8 sort -u | output "$@" diff -Nru rust-rustls-0.21.9/debian/dh-cargo/lib/Debian/Debhelper/Buildsystem/cargo.pm rust-rustls-0.21.10/debian/dh-cargo/lib/Debian/Debhelper/Buildsystem/cargo.pm --- rust-rustls-0.21.9/debian/dh-cargo/lib/Debian/Debhelper/Buildsystem/cargo.pm 2023-08-24 10:50:01.000000000 +0000 +++ rust-rustls-0.21.10/debian/dh-cargo/lib/Debian/Debhelper/Buildsystem/cargo.pm 2023-12-30 15:45:34.000000000 +0000 @@ -1,8 +1,9 @@ # debhelper buildsystem for Rust crates using Cargo # -# SPDX-FileCopyrightText: 2016 Josh Triplett -# SPDX-FileCopyrightText: 2018 Ximin Luo # SPDX-FileCopyrightText: 2022-2023 Jonas Smedegaard +# SPDX-FileCopyrightText: 2016 Josh Triplett +# SPDX-FileCopyrightText: 2019-2021 Sylvestre Ledru +# SPDX-FileCopyrightText: 2018-2021 Ximin Luo # # SPDX-License-Identifier: MIT # @@ -43,6 +44,10 @@ "Rust Cargo" } +sub DEFAULT_BUILD_DIRECTORY { + "target" +} + sub cargo_crates { my ( $root, $src, $default ) = @_; open(F, "cargo metadata --manifest-path $src --no-deps --format-version 1 |"); @@ -265,8 +270,9 @@ if ( -d 'debian/vendorlibs' ) { complex_doit( qw(find debian/cargo_registry -lname '../vendorlibs/*' -delete)); + # force to favor this crate over a dependency pulled from system complex_doit( - qw(ln --symbolic --relative --target-directory=debian/cargo_registry debian/vendorlibs/*)); + qw(ln --symbolic --force --relative --target-directory=debian/cargo_registry debian/vendorlibs/*)); } $this->doit_in_sourcedir(qw(cargo update)) if -f $cargo_lock; } @@ -285,10 +291,15 @@ # which might fail if e.g. the package # requires non-rust system dependencies and the maintainer didn't provide # this additional information to debcargo. - $this->doit_in_sourcedir($this->{cargo_command}, "test", @_); + $this->doit_in_sourcedir("env", + "DEB_BUILDDIR=" . $this->get_builddir(), + $this->{cargo_command}, "test", @_); # test generating Built-Using fields my $channel = get_buildoption("noopt") ? 'debug' : 'release'; - doit("env", "CARGO_CHANNEL=$channel", "/usr/share/cargo/bin/dh-cargo-built-using"); + doit("env", + "DEB_BUILDDIR=" . $this->get_builddir(), + "CARGO_CHANNEL=$channel", + "debian/dh-cargo/bin/dh-cargo-built-using"); } sub install { @@ -315,9 +326,10 @@ doit("touch", "-d@" . $ENV{SOURCE_DATE_EPOCH}, "$target/Cargo.toml"); # add crate to local registry, needed by some multi-crate workspaces # maybe related: + # force to favor this crate over a dependency pulled from system complex_doit( - qw(ln --symbolic --relative --target-directory=debian/cargo_registry), $target ); - } + qw(ln --symbolic --force --relative --target-directory=debian/cargo_registry), $target ); + } foreach my $featurepkg (@{$this->{featurepkg}}) { my $target = tmpdir( $featurepkg->{name} ) . "/usr/share/doc"; install_dir($target); @@ -327,17 +339,24 @@ # Do the install my $destdir = $ENV{'DESTDIR'} || tmpdir( $crate->{binpkg}{name} ); my @path_opts = $crate->{sourcepath} ne '.' ? ('--path', $crate->{sourcepath}) : (); - $this->doit_in_sourcedir("env", "DESTDIR=$destdir", "DEB_CARGO_CRATE=$crate->{cratespec}", - $this->{cargo_command}, "install", @path_opts, @_); + $this->doit_in_sourcedir("env", + "DEB_CARGO_CRATE=$crate->{cratespec}", + "DEB_BUILDDIR=" . $this->get_builddir(), + "DESTDIR=$destdir", + $this->{cargo_command}, "install", @path_opts, @_); # generate Built-Using fields - doit("env", "/usr/share/cargo/bin/dh-cargo-built-using", $crate->{binpkg}{name}); + doit("env", + "DEB_BUILDDIR=" . $this->get_builddir(), + "debian/dh-cargo/bin/dh-cargo-built-using", $crate->{binpkg}{name}); } } sub clean { my $this=shift; doit("touch", "--no-create", "-d@" . $ENV{SOURCE_DATE_EPOCH}, ".cargo_vcs_info.json"); - $this->doit_in_sourcedir($this->{cargo_command}, "clean", @_); + $this->doit_in_sourcedir("env", + "DEB_BUILDDIR=" . $this->get_builddir(), + $this->{cargo_command}, "clean", @_); doit("rm", "-rf", "debian/cargo_registry"); } diff -Nru rust-rustls-0.21.9/debian/tests/control rust-rustls-0.21.10/debian/tests/control --- rust-rustls-0.21.9/debian/tests/control 2023-11-27 15:19:15.000000000 +0000 +++ rust-rustls-0.21.10/debian/tests/control 2024-01-14 17:41:47.000000000 +0000 @@ -1,4 +1,4 @@ -Test-Command: /usr/share/cargo/bin/cargo-auto-test rustls 0.21.9 +Test-Command: /usr/share/cargo/bin/cargo-auto-test rustls 0.21.10 --all-targets --all-features Features: test-name=rust-rustls-0.21:@ Depends: @@ -20,7 +20,7 @@ librust-serde-derive-1+default-dev, Restrictions: allow-stderr -Test-Command: /usr/share/cargo/bin/cargo-auto-test rustls 0.21.9 +Test-Command: /usr/share/cargo/bin/cargo-auto-test rustls 0.21.10 --all-targets --no-default-features --features dangerous_configuration Features: test-name=rust-rustls-0.21:dangerous_configuration Depends: @@ -40,7 +40,7 @@ librust-serde-derive-1+default-dev, Restrictions: allow-stderr -Test-Command: /usr/share/cargo/bin/cargo-auto-test rustls 0.21.9 +Test-Command: /usr/share/cargo/bin/cargo-auto-test rustls 0.21.10 --all-targets --no-default-features --features quic Features: test-name=rust-rustls-0.21:quic Depends: @@ -60,7 +60,7 @@ librust-serde-derive-1+default-dev, Restrictions: allow-stderr -Test-Command: /usr/share/cargo/bin/cargo-auto-test rustls 0.21.9 +Test-Command: /usr/share/cargo/bin/cargo-auto-test rustls 0.21.10 --all-targets --no-default-features --features secret_extraction Features: test-name=rust-rustls-0.21:secret_extraction Depends: @@ -80,7 +80,7 @@ librust-serde-derive-1+default-dev, Restrictions: allow-stderr -Test-Command: /usr/share/cargo/bin/cargo-auto-test rustls 0.21.9 +Test-Command: /usr/share/cargo/bin/cargo-auto-test rustls 0.21.10 --all-targets --no-default-features --features tls12 Features: test-name=rust-rustls-0.21:tls12 Depends: @@ -100,7 +100,7 @@ librust-serde-derive-1+default-dev, Restrictions: allow-stderr -Test-Command: /usr/share/cargo/bin/cargo-auto-test rustls 0.21.9 +Test-Command: /usr/share/cargo/bin/cargo-auto-test rustls 0.21.10 --all-targets --no-default-features Features: test-name=rust-rustls-0.21: Depends: @@ -120,7 +120,7 @@ librust-serde-derive-1+default-dev, Restrictions: allow-stderr -Test-Command: /usr/share/cargo/bin/cargo-auto-test rustls 0.21.9 +Test-Command: /usr/share/cargo/bin/cargo-auto-test rustls 0.21.10 --all-targets Features: test-name=rust-rustls-0.21:default Depends: @@ -140,7 +140,7 @@ librust-serde-derive-1+default-dev, Restrictions: allow-stderr -Test-Command: /usr/share/cargo/bin/cargo-auto-test rustls 0.21.9 +Test-Command: /usr/share/cargo/bin/cargo-auto-test rustls 0.21.10 --all-targets --no-default-features --features logging Features: test-name=rust-rustls-0.21:logging Depends: diff -Nru rust-rustls-0.21.9/rustls/Cargo.toml rust-rustls-0.21.10/rustls/Cargo.toml --- rust-rustls-0.21.9/rustls/Cargo.toml 2023-11-16 15:23:46.000000000 +0000 +++ rust-rustls-0.21.10/rustls/Cargo.toml 2023-12-08 13:46:40.000000000 +0000 @@ -1,6 +1,6 @@ [package] name = "rustls" -version = "0.21.9" +version = "0.21.10" edition = "2021" rust-version = "1.61" license = "Apache-2.0 OR ISC OR MIT" diff -Nru rust-rustls-0.21.9/rustls/src/client/tls12.rs rust-rustls-0.21.10/rustls/src/client/tls12.rs --- rust-rustls-0.21.9/rustls/src/client/tls12.rs 2023-11-16 15:23:46.000000000 +0000 +++ rust-rustls-0.21.10/rustls/src/client/tls12.rs 2023-12-08 13:46:40.000000000 +0000 @@ -1072,6 +1072,18 @@ _fin_verified, })) } + + // we could not decrypt the encrypted handshake message with session resumption + // this might mean that the ticket was invalid for some reason, so we remove it + // from the store to restart a session from scratch + fn handle_decrypt_error(&self) { + if self.resuming { + self.config + .resumption + .store + .remove_tls12_session(&self.server_name); + } + } } // -- Traffic transit state -- diff -Nru rust-rustls-0.21.9/rustls/src/common_state.rs rust-rustls-0.21.10/rustls/src/common_state.rs --- rust-rustls-0.21.9/rustls/src/common_state.rs 2023-11-16 15:23:46.000000000 +0000 +++ rust-rustls-0.21.10/rustls/src/common_state.rs 2023-12-08 13:46:40.000000000 +0000 @@ -642,6 +642,8 @@ fn extract_secrets(&self) -> Result { Err(Error::HandshakeNotComplete) } + + fn handle_decrypt_error(&self) {} } pub(crate) struct Context<'a, Data> { diff -Nru rust-rustls-0.21.9/rustls/src/conn.rs rust-rustls-0.21.10/rustls/src/conn.rs --- rust-rustls-0.21.9/rustls/src/conn.rs 2023-11-16 15:23:46.000000000 +0000 +++ rust-rustls-0.21.10/rustls/src/conn.rs 2023-12-08 13:46:40.000000000 +0000 @@ -441,7 +441,7 @@ pub(crate) fn first_handshake_message(&mut self) -> Result, Error> { match self .core - .deframe()? + .deframe(None)? .map(Message::try_from) { Some(Ok(msg)) => Ok(Some(msg)), @@ -622,7 +622,7 @@ } }; - while let Some(msg) = self.deframe()? { + while let Some(msg) = self.deframe(Some(&*state))? { match self.process_msg(msg, state) { Ok(new) => state = new, Err(e) => { @@ -637,7 +637,7 @@ } /// Pull a message out of the deframer and send any messages that need to be sent as a result. - fn deframe(&mut self) -> Result, Error> { + fn deframe(&mut self, state: Option<&dyn State>) -> Result, Error> { match self .message_deframer .pop(&mut self.common_state.record_layer) @@ -678,9 +678,14 @@ Err(err @ Error::PeerSentOversizedRecord) => Err(self .common_state .send_fatal_alert(AlertDescription::RecordOverflow, err)), - Err(err @ Error::DecryptError) => Err(self - .common_state - .send_fatal_alert(AlertDescription::BadRecordMac, err)), + Err(err @ Error::DecryptError) => { + if let Some(state) = state { + state.handle_decrypt_error(); + } + Err(self + .common_state + .send_fatal_alert(AlertDescription::BadRecordMac, err)) + } Err(e) => Err(e), } } diff -Nru rust-rustls-0.21.9/rustls/src/versions.rs rust-rustls-0.21.10/rustls/src/versions.rs --- rust-rustls-0.21.9/rustls/src/versions.rs 2023-11-16 15:23:46.000000000 +0000 +++ rust-rustls-0.21.10/rustls/src/versions.rs 2023-12-08 13:46:40.000000000 +0000 @@ -8,6 +8,7 @@ /// the [`ALL_VERSIONS`] array, as well as individually as [`TLS12`] /// and [`TLS13`]. #[derive(Eq, PartialEq)] +#[allow(clippy::manual_non_exhaustive)] // Fixed in main pub struct SupportedProtocolVersion { /// The TLS enumeration naming this version. pub version: ProtocolVersion, diff -Nru rust-rustls-0.21.9/rustls/tests/api.rs rust-rustls-0.21.10/rustls/tests/api.rs --- rust-rustls-0.21.9/rustls/tests/api.rs 2023-11-16 15:23:46.000000000 +0000 +++ rust-rustls-0.21.10/rustls/tests/api.rs 2023-12-08 13:46:40.000000000 +0000 @@ -4887,3 +4887,61 @@ "DnsName(\"a.com\")" ) } + +#[cfg(feature = "tls12")] +#[test] +fn test_client_removes_tls12_session_if_server_sends_undecryptable_first_message() { + fn inject_corrupt_finished_message(msg: &mut Message) -> Altered { + if let MessagePayload::ChangeCipherSpec(_) = msg.payload { + // interdict "real" ChangeCipherSpec with its encoding, plus a faulty encrypted Finished. + let mut raw_change_cipher_spec = [0x14u8, 0x03, 0x03, 0x00, 0x01, 0x01].to_vec(); + let mut corrupt_finished = [0x16, 0x03, 0x03, 0x00, 0x28].to_vec(); + corrupt_finished.extend([0u8; 0x28]); + + let mut both = vec![]; + both.append(&mut raw_change_cipher_spec); + both.append(&mut corrupt_finished); + + Altered::Raw(both) + } else { + Altered::InPlace + } + } + + let mut client_config = + make_client_config_with_versions(KeyType::Rsa, &[&rustls::version::TLS12]); + let storage = Arc::new(ClientStorage::new()); + client_config.resumption = Resumption::store(storage.clone()); + let client_config = Arc::new(client_config); + let server_config = Arc::new(make_server_config(KeyType::Rsa)); + + // successful handshake to allow resumption + let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); + do_handshake(&mut client, &mut server); + + // resumption + let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); + transfer(&mut client, &mut server); + server.process_new_packets().unwrap(); + let mut client = client.into(); + transfer_altered( + &mut server.into(), + inject_corrupt_finished_message, + &mut client, + ); + + // discard storage operations up to this point, to observe the one we want to test for. + storage.ops_and_reset(); + + // client cannot decrypt faulty Finished, and deletes saved session in case + // server resumption is buggy. + assert_eq!( + Some(Error::DecryptError), + client.process_new_packets().err() + ); + + assert!(matches!( + storage.ops()[0], + ClientStorageOp::RemoveTls12Session(_) + )); +} diff -Nru rust-rustls-0.21.9/rustls/tests/common/mod.rs rust-rustls-0.21.10/rustls/tests/common/mod.rs --- rust-rustls-0.21.9/rustls/tests/common/mod.rs 2023-11-16 15:23:46.000000000 +0000 +++ rust-rustls-0.21.10/rustls/tests/common/mod.rs 2023-12-08 13:46:40.000000000 +0000 @@ -162,12 +162,21 @@ let mut reader = Reader::init(&buf[..sz]); while reader.any_left() { let message = OpaqueMessage::read(&mut reader).unwrap(); - let mut message = Message::try_from(message.into_plain_message()).unwrap(); - let message_enc = match filter(&mut message) { - Altered::InPlace => PlainMessage::from(message) - .into_unencrypted_opaque() - .encode(), - Altered::Raw(data) => data, + + // this is a bit of a falsehood: we don't know whether message + // is encrypted. it is quite unlikely that a genuine encrypted + // message can be decoded by `Message::try_from`. + let plain = message.into_plain_message(); + + let message_enc = match Message::try_from(plain.clone()) { + Ok(mut message) => match filter(&mut message) { + Altered::InPlace => PlainMessage::from(message) + .into_unencrypted_opaque() + .encode(), + Altered::Raw(data) => data, + }, + // pass through encrypted/undecodable messages + Err(_) => plain.into_unencrypted_opaque().encode(), }; let message_enc_reader: &mut dyn io::Read = &mut &message_enc[..];