mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-06 16:30:04 +01:00
Compare commits
153 Commits
v2.4.0-rc1
...
v2.4.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c67861e875 | ||
|
|
f566d7c911 | ||
|
|
f21b07fb1b | ||
|
|
904cdd1161 | ||
|
|
5d75632a16 | ||
|
|
da8bcf7270 | ||
|
|
bbc3ff69db | ||
|
|
7ef0d9c73a | ||
|
|
8ced413876 | ||
|
|
80a77bce2a | ||
|
|
334606b6aa | ||
|
|
1162f1e1e3 | ||
|
|
47a1d9a6d6 | ||
|
|
c257ae1eb4 | ||
|
|
d37c3f0db2 | ||
|
|
4a974ec582 | ||
|
|
c95a88f815 | ||
|
|
4af4a4a631 | ||
|
|
3d269a5ae3 | ||
|
|
de98f01141 | ||
|
|
4d28153e53 | ||
|
|
dd864f5a61 | ||
|
|
ca54398eec | ||
|
|
97cd16b8b9 | ||
|
|
86d0d4f68e | ||
|
|
1a7d98b3ba | ||
|
|
025a96df73 | ||
|
|
e6edbc1fe5 | ||
|
|
ed68b51526 | ||
|
|
bcace16aa2 | ||
|
|
97aa31d32f | ||
|
|
36a78ed17b | ||
|
|
0d4ecd92f1 | ||
|
|
94143c3428 | ||
|
|
af17d2256d | ||
|
|
ff51d5a8fa | ||
|
|
949ed8c9e2 | ||
|
|
31698f8388 | ||
|
|
c400a84987 | ||
|
|
ce52bb2f5a | ||
|
|
bf374ca9e6 | ||
|
|
17ca463767 | ||
|
|
aa8d8ec0ae | ||
|
|
1b08d47045 | ||
|
|
0f656105e2 | ||
|
|
0b3a7ecd01 | ||
|
|
a364355c16 | ||
|
|
7086c414bc | ||
|
|
0bb193d487 | ||
|
|
80b57c6e24 | ||
|
|
9576549fee | ||
|
|
0cc5f2fdf9 | ||
|
|
26a3f3b058 | ||
|
|
e03f3bb36e | ||
|
|
be5ab79c9d | ||
|
|
083cdb9310 | ||
|
|
ca30d3cda9 | ||
|
|
5c17722854 | ||
|
|
49177aac46 | ||
|
|
d20beacba0 | ||
|
|
26cc1644b4 | ||
|
|
9ed0036286 | ||
|
|
00f7d92514 | ||
|
|
43674b2903 | ||
|
|
5cfd5fc4cd | ||
|
|
9f252d4bf8 | ||
|
|
321057eed5 | ||
|
|
1a3d049454 | ||
|
|
9d1f29a9fd | ||
|
|
da31341d5d | ||
|
|
10b1d6493e | ||
|
|
a76310b53f | ||
|
|
26d26d7134 | ||
|
|
a1b577c085 | ||
|
|
8a0682650e | ||
|
|
85e5ccec17 | ||
|
|
3da5352b89 | ||
|
|
1569558503 | ||
|
|
ce704859b8 | ||
|
|
fd18e0b1c9 | ||
|
|
ba4d5680d6 | ||
|
|
75e45462f0 | ||
|
|
f8eb7b225a | ||
|
|
29ea07ef66 | ||
|
|
6c9d386303 | ||
|
|
bf84ead85c | ||
|
|
ca2ba1a6f5 | ||
|
|
284d1615c8 | ||
|
|
b4181ffa3b | ||
|
|
8c0caf9a1f | ||
|
|
d2682c4841 | ||
|
|
39ddcfaaa0 | ||
|
|
669ad1933a | ||
|
|
84fa6ffbde | ||
|
|
2206f7f108 | ||
|
|
ec946b17eb | ||
|
|
a619cc1757 | ||
|
|
6c3e2e2bee | ||
|
|
621dcea8ee | ||
|
|
f6fb530121 | ||
|
|
0066f9dd83 | ||
|
|
46b70d7317 | ||
|
|
8c28774917 | ||
|
|
e5d84156e4 | ||
|
|
5f2c751dd8 | ||
|
|
53b22cc32e | ||
|
|
26679e223c | ||
|
|
9b7d3be5c6 | ||
|
|
358dec19b2 | ||
|
|
863fd08305 | ||
|
|
93481d1566 | ||
|
|
3a79b2b09b | ||
|
|
246d306eeb | ||
|
|
03943acbb1 | ||
|
|
20b678c9f3 | ||
|
|
e008a88b98 | ||
|
|
5efa782567 | ||
|
|
ab37ad0dc9 | ||
|
|
03208167b2 | ||
|
|
0f8e7f317f | ||
|
|
c5b0a4dd32 | ||
|
|
5c5551d1d3 | ||
|
|
aa324567a8 | ||
|
|
0ee752c42d | ||
|
|
4746717b75 | ||
|
|
3ad942e338 | ||
|
|
b5190da581 | ||
|
|
5fa8e84ef0 | ||
|
|
63adb3b0cf | ||
|
|
20774374a9 | ||
|
|
d169020001 | ||
|
|
76766f11c0 | ||
|
|
5d6d65ce86 | ||
|
|
24ab0871e7 | ||
|
|
11e325a112 | ||
|
|
6ea32db1fa | ||
|
|
49c8a8b9ef | ||
|
|
a480c388b8 | ||
|
|
5406064f55 | ||
|
|
9b66d0d039 | ||
|
|
adff844c46 | ||
|
|
f702246d78 | ||
|
|
8606342b53 | ||
|
|
ccb0f7c0b2 | ||
|
|
72384b43bd | ||
|
|
5ef3de8945 | ||
|
|
ad913cf437 | ||
|
|
7820f07e85 | ||
|
|
01bda280ee | ||
|
|
b40f31fb8c | ||
|
|
066d651210 | ||
|
|
b00946d449 | ||
|
|
6a14f52e5d |
28
.github/workflows/cibuild-setup-ubuntu.sh
vendored
Executable file
28
.github/workflows/cibuild-setup-ubuntu.sh
vendored
Executable file
@@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -ex
|
||||
|
||||
PACKAGES=(
|
||||
git make autoconf automake autopoint pkg-config libtool libtool-bin
|
||||
gettext libssl-dev libdevmapper-dev libpopt-dev uuid-dev libsepol1-dev
|
||||
libjson-c-dev libssh-dev libblkid-dev tar libargon2-0-dev libpwquality-dev
|
||||
sharutils dmsetup jq xxd expect keyutils netcat passwd openssh-client sshpass
|
||||
)
|
||||
|
||||
COMPILER="${COMPILER:?}"
|
||||
COMPILER_VERSION="${COMPILER_VERSION:?}"
|
||||
RELEASE="$(lsb_release -cs)"
|
||||
|
||||
bash -c "echo 'deb-src http://archive.ubuntu.com/ubuntu/ $RELEASE main restricted universe multiverse' >>/etc/apt/sources.list"
|
||||
|
||||
# Latest gcc stack deb packages provided by
|
||||
# https://launchpad.net/~ubuntu-toolchain-r/+archive/ubuntu/test
|
||||
add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
PACKAGES+=(gcc-$COMPILER_VERSION)
|
||||
|
||||
# scsi_debug, gost crypto
|
||||
PACKAGES+=(dkms linux-headers-$(uname -r) linux-modules-extra-$(uname -r) gost-crypto-dkms)
|
||||
|
||||
apt-get -y update --fix-missing
|
||||
apt-get -y install "${PACKAGES[@]}"
|
||||
apt-get -y build-dep cryptsetup
|
||||
38
.github/workflows/cibuild.sh
vendored
Executable file
38
.github/workflows/cibuild.sh
vendored
Executable file
@@ -0,0 +1,38 @@
|
||||
#!/bin/bash
|
||||
|
||||
PHASES=(${@:-CONFIGURE MAKE CHECK})
|
||||
COMPILER="${COMPILER:?}"
|
||||
COMPILER_VERSION="${COMPILER_VERSION}"
|
||||
CFLAGS=(-O1 -g)
|
||||
CXXFLAGS=(-O1 -g)
|
||||
|
||||
CC="gcc${COMPILER_VERSION:+-$COMPILER_VERSION}"
|
||||
CXX="g++${COMPILER_VERSION:+-$COMPILER_VERSION}"
|
||||
|
||||
set -ex
|
||||
|
||||
for phase in "${PHASES[@]}"; do
|
||||
case $phase in
|
||||
CONFIGURE)
|
||||
opts=(
|
||||
--enable-libargon2
|
||||
)
|
||||
|
||||
sudo -E git clean -xdf
|
||||
|
||||
./autogen.sh
|
||||
CC="$CC" CXX="$CXX" CFLAGS="${CFLAGS[@]}" CXXFLAGS="${CXXFLAGS[@]}" ./configure "${opts[@]}"
|
||||
;;
|
||||
MAKE)
|
||||
make -j
|
||||
make -j -C tests check-programs
|
||||
;;
|
||||
CHECK)
|
||||
make check
|
||||
;;
|
||||
|
||||
*)
|
||||
echo >&2 "Unknown phase '$phase'"
|
||||
exit 1
|
||||
esac
|
||||
done
|
||||
29
.github/workflows/cibuild.yml
vendored
Normal file
29
.github/workflows/cibuild.yml
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
name: Build test
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- 'wip-luks2'
|
||||
- 'v2.3.x'
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'mbroz/cryptsetup'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
env:
|
||||
- { COMPILER: "gcc", COMPILER_VERSION: "11", RUN_SSH_PLUGIN_TEST: "1" }
|
||||
env: ${{ matrix.env }}
|
||||
steps:
|
||||
- name: Repository checkout
|
||||
uses: actions/checkout@v1
|
||||
- name: Ubuntu setup
|
||||
run: sudo -E .github/workflows/cibuild-setup-ubuntu.sh
|
||||
- name: Configure & Make
|
||||
run: .github/workflows/cibuild.sh CONFIGURE MAKE
|
||||
- name: Check
|
||||
run: sudo -E .github/workflows/cibuild.sh CHECK
|
||||
48
.github/workflows/coverity.yml
vendored
Normal file
48
.github/workflows/coverity.yml
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
name: Coverity test
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'coverity_scan'
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
|
||||
jobs:
|
||||
latest:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'mbroz/cryptsetup'
|
||||
steps:
|
||||
- name: Repository checkout
|
||||
uses: actions/checkout@v1
|
||||
- name: Ubuntu setup
|
||||
run: sudo -E .github/workflows/cibuild-setup-ubuntu.sh
|
||||
env:
|
||||
COMPILER: "gcc"
|
||||
COMPILER_VERSION: "11"
|
||||
- name: Install Coverity
|
||||
run: |
|
||||
wget -q https://scan.coverity.com/download/cxx/linux64 --post-data "token=$TOKEN&project=mbroz/cryptsetup" -O cov-analysis-linux64.tar.gz
|
||||
mkdir cov-analysis-linux64
|
||||
tar xzf cov-analysis-linux64.tar.gz --strip 1 -C cov-analysis-linux64
|
||||
env:
|
||||
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
|
||||
- name: Run autoconf & configure
|
||||
run: |
|
||||
./autogen.sh
|
||||
./configure
|
||||
- name: Run cov-build
|
||||
run: |
|
||||
export PATH=`pwd`/cov-analysis-linux64/bin:$PATH
|
||||
cov-build --dir cov-int make
|
||||
- name: Submit to Coverity Scan
|
||||
run: |
|
||||
tar czvf cryptsetup.tgz cov-int
|
||||
curl \
|
||||
--form project=mbroz/cryptsetup \
|
||||
--form token=$TOKEN \
|
||||
--form email=gmazyland@gmail.com \
|
||||
--form file=@cryptsetup.tgz \
|
||||
--form version=trunk \
|
||||
--form description="`./cryptsetup --version`" \
|
||||
https://scan.coverity.com/builds?project=mbroz/cryptsetup
|
||||
env:
|
||||
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
|
||||
113
.gitlab-ci.yml
Normal file
113
.gitlab-ci.yml
Normal file
@@ -0,0 +1,113 @@
|
||||
stages:
|
||||
- test
|
||||
|
||||
.debian-prep:
|
||||
before_script:
|
||||
- sudo apt-get -y update --fix-missing
|
||||
- >
|
||||
sudo apt-get -y install -y -qq git gcc make
|
||||
autoconf automake autopoint pkg-config libtool libtool-bin gettext
|
||||
libssl-dev libdevmapper-dev libpopt-dev uuid-dev libsepol1-dev
|
||||
libjson-c-dev libssh-dev libblkid-dev tar libargon2-0-dev
|
||||
libpwquality-dev sharutils dmsetup jq xxd expect keyutils
|
||||
netcat passwd openssh-client sshpass
|
||||
- sudo apt-get -y build-dep cryptsetup
|
||||
- sudo -E git clean -xdf
|
||||
- ./autogen.sh
|
||||
- ./configure --enable-libargon2
|
||||
|
||||
.dnf-openssl-backend:
|
||||
before_script:
|
||||
- >
|
||||
sudo dnf -y -q install
|
||||
autoconf automake device-mapper-devel gcc gettext-devel json-c-devel
|
||||
libargon2-devel libblkid-devel libpwquality-devel libselinux-devel
|
||||
libssh-devel libtool libuuid-devel make popt-devel
|
||||
libsepol-devel.x86_64 netcat openssh-clients passwd pkgconfig sharutils
|
||||
sshpass tar uuid-devel vim-common device-mapper expect gettext git jq
|
||||
keyutils openssl-devel openssl
|
||||
- sudo -E git clean -xdf
|
||||
- ./autogen.sh
|
||||
- ./configure --enable-fips --enable-pwquality --enable-libargon2 --with-crypto_backend=openssl
|
||||
|
||||
# Merge request: Build and run only non-root tests
|
||||
test-mergerq-job-debian-noroot:
|
||||
extends:
|
||||
- .debian-prep
|
||||
tags:
|
||||
- libvirt
|
||||
- debian10
|
||||
stage: test
|
||||
interruptible: true
|
||||
rules:
|
||||
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
|
||||
when: never
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
script:
|
||||
- make -j
|
||||
- make -j -C tests check-programs
|
||||
- make check
|
||||
|
||||
# For main branch commit, run all tests as root
|
||||
test-main-commit-job-debian:
|
||||
extends:
|
||||
- .debian-prep
|
||||
tags:
|
||||
- libvirt
|
||||
- debian10
|
||||
stage: test
|
||||
interruptible: true
|
||||
variables:
|
||||
RUN_SSH_PLUGIN_TEST: "1"
|
||||
rules:
|
||||
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
|
||||
when: never
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
|
||||
script:
|
||||
- make -j
|
||||
- make -j -C tests check-programs
|
||||
- sudo -E make check
|
||||
- sudo -E make clean
|
||||
|
||||
test-main-commit-job-dnf:
|
||||
extends:
|
||||
- .dnf-openssl-backend
|
||||
tags:
|
||||
- libvirt
|
||||
- fedora-rawhide
|
||||
stage: test
|
||||
interruptible: true
|
||||
variables:
|
||||
RUN_SSH_PLUGIN_TEST: "1"
|
||||
rules:
|
||||
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
|
||||
when: never
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
|
||||
script:
|
||||
- make -j
|
||||
- make -j -C tests check-programs
|
||||
- sudo -E make check
|
||||
|
||||
test-mergerq-job-dnf:
|
||||
extends:
|
||||
- .dnf-openssl-backend
|
||||
tags:
|
||||
- libvirt
|
||||
- fedora-rawhide
|
||||
stage: test
|
||||
interruptible: true
|
||||
variables:
|
||||
RUN_SSH_PLUGIN_TEST: "1"
|
||||
rules:
|
||||
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
|
||||
when: never
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
script:
|
||||
- make -j
|
||||
- make -j -C tests check-programs
|
||||
- sudo -E make check
|
||||
|
||||
include:
|
||||
- local: .gitlab/ci/gitlab-shared-docker.yml
|
||||
- local: .gitlab/ci/compilation-gcc.gitlab-ci.yml
|
||||
- local: .gitlab/ci/compilation-clang.gitlab-ci.yml
|
||||
49
.gitlab/ci/cibuild-setup-ubuntu.sh
Executable file
49
.gitlab/ci/cibuild-setup-ubuntu.sh
Executable file
@@ -0,0 +1,49 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -ex
|
||||
|
||||
PACKAGES=(
|
||||
git make autoconf automake autopoint pkg-config libtool libtool-bin
|
||||
gettext libssl-dev libdevmapper-dev libpopt-dev uuid-dev libsepol1-dev
|
||||
libjson-c-dev libssh-dev libblkid-dev tar libargon2-0-dev libpwquality-dev
|
||||
sharutils dmsetup jq xxd expect keyutils netcat passwd openssh-client sshpass
|
||||
)
|
||||
|
||||
COMPILER="${COMPILER:?}"
|
||||
COMPILER_VERSION="${COMPILER_VERSION:?}"
|
||||
|
||||
grep -E '^deb' /etc/apt/sources.list > /etc/apt/sources.list~
|
||||
sed -Ei 's/^deb /deb-src /' /etc/apt/sources.list~
|
||||
cat /etc/apt/sources.list~ >> /etc/apt/sources.list
|
||||
|
||||
apt-get -y update --fix-missing
|
||||
DEBIAN_FRONTEND=noninteractive apt-get -yq install software-properties-common wget lsb-release
|
||||
RELEASE="$(lsb_release -cs)"
|
||||
|
||||
if [[ $COMPILER == "gcc" ]]; then
|
||||
# Latest gcc stack deb packages provided by
|
||||
# https://launchpad.net/~ubuntu-toolchain-r/+archive/ubuntu/test
|
||||
add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
PACKAGES+=(gcc-$COMPILER_VERSION)
|
||||
elif [[ $COMPILER == "clang" ]]; then
|
||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
|
||||
add-apt-repository "deb http://apt.llvm.org/${RELEASE}/ llvm-toolchain-${RELEASE}-${COMPILER_VERSION} main"
|
||||
|
||||
# scan-build
|
||||
PACKAGES+=(clang-tools-$COMPILER_VERSION clang-$COMPILER_VERSION lldb-$COMPILER_VERSION lld-$COMPILER_VERSION clangd-$COMPILER_VERSION)
|
||||
PACKAGES+=(perl)
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
apt-get -y update --fix-missing
|
||||
DEBIAN_FRONTEND=noninteractive apt-get -yq install "${PACKAGES[@]}"
|
||||
apt-get -y build-dep cryptsetup
|
||||
|
||||
echo "====================== VERSIONS ==================="
|
||||
if [[ $COMPILER == "clang" ]]; then
|
||||
scan-build${COMPILER_VERSION:+-$COMPILER_VERSION} --help
|
||||
fi
|
||||
|
||||
${COMPILER}-$COMPILER_VERSION -v
|
||||
echo "====================== END VERSIONS ==================="
|
||||
55
.gitlab/ci/clang-Wall
Executable file
55
.gitlab/ci/clang-Wall
Executable file
@@ -0,0 +1,55 @@
|
||||
#!/bin/bash
|
||||
# clang -Wall plus other important warnings not included in -Wall
|
||||
|
||||
for arg in "$@"
|
||||
do
|
||||
case $arg in
|
||||
-O*) Wuninitialized=-Wuninitialized;; # only makes sense with `-O'
|
||||
esac
|
||||
done
|
||||
|
||||
CLANG="clang${COMPILER_VERSION:+-$COMPILER_VERSION}"
|
||||
|
||||
#PEDANTIC="-std=gnu99"
|
||||
#PEDANTIC="-pedantic -std=gnu99"
|
||||
#PEDANTIC="-pedantic -std=gnu99 -Wno-variadic-macros"
|
||||
#CONVERSION="-Wconversion"
|
||||
|
||||
EXTRA="-Wextra \
|
||||
-Wsign-compare \
|
||||
-Werror-implicit-function-declaration \
|
||||
-Wpointer-arith \
|
||||
-Wwrite-strings \
|
||||
-Wswitch \
|
||||
-Wmissing-format-attribute \
|
||||
-Winit-self \
|
||||
-Wdeclaration-after-statement \
|
||||
-Wold-style-definition \
|
||||
-Wno-missing-field-initializers \
|
||||
-Wno-unused-parameter \
|
||||
-Wno-attributes \
|
||||
-Wno-long-long"
|
||||
|
||||
exec $CLANG $PEDANTIC $CONVERSION \
|
||||
-Wall $Wuninitialized \
|
||||
-Wno-switch \
|
||||
-Wdisabled-optimization \
|
||||
-Wwrite-strings \
|
||||
-Wpointer-arith \
|
||||
-Wbad-function-cast \
|
||||
-Wmissing-prototypes \
|
||||
-Wmissing-declarations \
|
||||
-Wstrict-prototypes \
|
||||
-Wnested-externs \
|
||||
-Wcomment \
|
||||
-Winline \
|
||||
-Wcast-align \
|
||||
-Wcast-qual \
|
||||
-Wredundant-decls $EXTRA \
|
||||
"$@" 2>&1 | {
|
||||
if [[ $USE_FILTER -eq 1 ]]; then
|
||||
.gitlab/ci/warnings_filter.py
|
||||
else
|
||||
cat
|
||||
fi
|
||||
}
|
||||
25
.gitlab/ci/compilation-clang.gitlab-ci.yml
Normal file
25
.gitlab/ci/compilation-clang.gitlab-ci.yml
Normal file
@@ -0,0 +1,25 @@
|
||||
test-clang-compilation:
|
||||
extends:
|
||||
- .gitlab-shared-clang
|
||||
script:
|
||||
- export CFLAGS="-Wall -Werror"
|
||||
- ./configure --enable-pwquality --enable-libargon2
|
||||
- make -j
|
||||
|
||||
# Clang doesn't support json output, so we cannot use the warnings filter
|
||||
# test-clang-Wall-script:
|
||||
# extends:
|
||||
# - .gitlab-shared-clang
|
||||
# script:
|
||||
# - export CFLAGS="-g -O0"
|
||||
# - export CC=".gitlab/ci/clang-Wall"
|
||||
# - ./configure --enable-pwquality --enable-libargon2
|
||||
# - make -j CFLAGS="-g -O0 -Werror"
|
||||
|
||||
test-scan-build:
|
||||
extends:
|
||||
- .gitlab-shared-clang
|
||||
script:
|
||||
- scan-build${COMPILER_VERSION:+-$COMPILER_VERSION} -V ./configure CFLAGS="-g -O0" --enable-internal-sse-argon2 --enable-pwquality --enable-libargon2
|
||||
- make clean
|
||||
- scan-build${COMPILER_VERSION:+-$COMPILER_VERSION} -maxloop 10 make -j
|
||||
24
.gitlab/ci/compilation-gcc.gitlab-ci.yml
Normal file
24
.gitlab/ci/compilation-gcc.gitlab-ci.yml
Normal file
@@ -0,0 +1,24 @@
|
||||
test-gcc-compilation:
|
||||
extends:
|
||||
- .gitlab-shared-gcc
|
||||
script:
|
||||
- export CFLAGS="-Wall -Werror"
|
||||
- ./configure --enable-pwquality --enable-libargon2
|
||||
- make -j
|
||||
|
||||
test-gcc-Wall-script:
|
||||
extends:
|
||||
- .gitlab-shared-gcc
|
||||
script:
|
||||
- export CFLAGS="-g -O0"
|
||||
- export CC=".gitlab/ci/gcc-Wall"
|
||||
- USE_FILTER=0 ./configure --enable-pwquality --enable-libargon2
|
||||
- USE_FILTER=1 make -j CFLAGS="-g -O0 -fdiagnostics-format=json"
|
||||
|
||||
test-gcc-fanalyzer:
|
||||
extends:
|
||||
- .gitlab-shared-gcc
|
||||
script:
|
||||
- export CFLAGS="-Wall -Werror -g -O0 -fanalyzer -fdiagnostics-path-format=separate-events"
|
||||
- ./configure --enable-pwquality --enable-libargon2
|
||||
- make -j
|
||||
61
.gitlab/ci/gcc-Wall
Executable file
61
.gitlab/ci/gcc-Wall
Executable file
@@ -0,0 +1,61 @@
|
||||
#!/bin/bash
|
||||
# gcc -Wall plus other important warnings not included in -Wall
|
||||
|
||||
for arg in "$@"
|
||||
do
|
||||
case $arg in
|
||||
-O*) Wuninitialized=-Wuninitialized;; # only makes sense with `-O'
|
||||
esac
|
||||
done
|
||||
|
||||
GCC="gcc${COMPILER_VERSION:+-$COMPILER_VERSION}"
|
||||
|
||||
#PEDANTIC="-std=gnu99"
|
||||
#PEDANTIC="-pedantic -std=gnu99"
|
||||
#PEDANTIC="-pedantic -std=gnu99 -Wno-variadic-macros"
|
||||
#CONVERSION="-Wconversion"
|
||||
# -Wpacked \
|
||||
|
||||
|
||||
EXTRA="-Wextra \
|
||||
-Wsign-compare \
|
||||
-Werror-implicit-function-declaration \
|
||||
-Wpointer-arith \
|
||||
-Wwrite-strings \
|
||||
-Wswitch \
|
||||
-Wmissing-format-attribute \
|
||||
-Wstrict-aliasing=3 \
|
||||
-Winit-self \
|
||||
-Wunsafe-loop-optimizations \
|
||||
-Wdeclaration-after-statement \
|
||||
-Wold-style-definition \
|
||||
-Wno-missing-field-initializers \
|
||||
-Wno-unused-parameter \
|
||||
-Wno-attributes \
|
||||
-Wno-long-long \
|
||||
-Wmaybe-uninitialized \
|
||||
-Wvla"
|
||||
|
||||
exec $GCC $PEDANTIC $CONVERSION \
|
||||
-Wall $Wuninitialized \
|
||||
-Wno-switch \
|
||||
-Wdisabled-optimization \
|
||||
-Wwrite-strings \
|
||||
-Wpointer-arith \
|
||||
-Wbad-function-cast \
|
||||
-Wmissing-prototypes \
|
||||
-Wmissing-declarations \
|
||||
-Wstrict-prototypes \
|
||||
-Wnested-externs \
|
||||
-Wcomment \
|
||||
-Winline \
|
||||
-Wcast-align \
|
||||
-Wcast-qual \
|
||||
-Wredundant-decls $EXTRA \
|
||||
"$@" 2>&1 | {
|
||||
if [[ $USE_FILTER -eq 1 ]]; then
|
||||
.gitlab/ci/warnings_filter.py
|
||||
else
|
||||
cat
|
||||
fi
|
||||
}
|
||||
29
.gitlab/ci/gitlab-shared-docker.yml
Normal file
29
.gitlab/ci/gitlab-shared-docker.yml
Normal file
@@ -0,0 +1,29 @@
|
||||
.gitlab-shared-docker:
|
||||
image: ubuntu:focal
|
||||
tags:
|
||||
- gitlab-org-docker
|
||||
stage: test
|
||||
interruptible: true
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
|
||||
before_script:
|
||||
- .gitlab/ci/cibuild-setup-ubuntu.sh
|
||||
- export CC="${COMPILER}${COMPILER_VERSION:+-$COMPILER_VERSION}"
|
||||
- export CXX="${COMPILER}++${COMPILER_VERSION:+-$COMPILER_VERSION}"
|
||||
- ./autogen.sh
|
||||
|
||||
.gitlab-shared-gcc:
|
||||
extends:
|
||||
- .gitlab-shared-docker
|
||||
variables:
|
||||
COMPILER: "gcc"
|
||||
COMPILER_VERSION: "11"
|
||||
RUN_SSH_PLUGIN_TEST: "1"
|
||||
|
||||
.gitlab-shared-clang:
|
||||
extends:
|
||||
- .gitlab-shared-docker
|
||||
variables:
|
||||
COMPILER: "clang"
|
||||
COMPILER_VERSION: "13"
|
||||
RUN_SSH_PLUGIN_TEST: "1"
|
||||
31
.gitlab/ci/warnings_filter.py
Executable file
31
.gitlab/ci/warnings_filter.py
Executable file
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import sys
|
||||
import json
|
||||
import linecache
|
||||
|
||||
if __name__ == "__main__":
|
||||
json_string = sys.stdin.read()
|
||||
if json_string in [None, ""]:
|
||||
sys.exit(0)
|
||||
|
||||
parsed = json.loads(json_string)
|
||||
#print(json.dumps(parsed, indent=4, sort_keys=True))
|
||||
|
||||
r = 0
|
||||
|
||||
for o in parsed:
|
||||
kind = o["kind"]
|
||||
|
||||
start = o["locations"][0]["caret"]
|
||||
l = linecache.getline(start["file"], int(start["line"]))
|
||||
|
||||
ignored = "json_object_object_foreach" in l
|
||||
|
||||
print(f"{o['kind']} {'ignored' if ignored else 'FOUND'} in {start['file']}:{start['line']}:{start['column']} {o['message']}")
|
||||
print(f"line contains:\n\t{l}", end="")
|
||||
|
||||
if not ignored:
|
||||
r = 1
|
||||
|
||||
sys.exit(r)
|
||||
@@ -1,174 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# .travis-functions.sh:
|
||||
# - helper functions to be sourced from .travis.yml
|
||||
# - designed to respect travis' environment but testing locally is possible
|
||||
# - modified copy from util-linux project
|
||||
#
|
||||
|
||||
if [ ! -f "configure.ac" ]; then
|
||||
echo ".travis-functions.sh must be sourced from source dir" >&2
|
||||
return 1 || exit 1
|
||||
fi
|
||||
|
||||
## some config settings
|
||||
# travis docs say we get 1.5 CPUs
|
||||
MAKE="make -j2"
|
||||
DUMP_CONFIG_LOG="short"
|
||||
export TS_OPT_parsable="yes"
|
||||
|
||||
export RUN_SSH_PLUGIN_TEST=1
|
||||
|
||||
function configure_travis
|
||||
{
|
||||
./configure "$@"
|
||||
err=$?
|
||||
if [ "$DUMP_CONFIG_LOG" = "short" ]; then
|
||||
grep -B1 -A10000 "^## Output variables" config.log | grep -v "_FALSE="
|
||||
elif [ "$DUMP_CONFIG_LOG" = "full" ]; then
|
||||
cat config.log
|
||||
fi
|
||||
return $err
|
||||
}
|
||||
|
||||
function check_nonroot
|
||||
{
|
||||
local cfg_opts="$1"
|
||||
|
||||
[ -z "$cfg_opts" ] && return
|
||||
|
||||
configure_travis \
|
||||
--enable-cryptsetup-reencrypt \
|
||||
--enable-internal-sse-argon2 \
|
||||
--enable-external-tokens \
|
||||
--enable-ssh-token \
|
||||
"$cfg_opts" \
|
||||
|| return
|
||||
|
||||
$MAKE || return
|
||||
|
||||
make check
|
||||
}
|
||||
|
||||
function check_root
|
||||
{
|
||||
local cfg_opts="$1"
|
||||
|
||||
[ -z "$cfg_opts" ] && return
|
||||
|
||||
configure_travis \
|
||||
--enable-cryptsetup-reencrypt \
|
||||
--enable-internal-sse-argon2 \
|
||||
--enable-external-tokens \
|
||||
--enable-ssh-token \
|
||||
"$cfg_opts" \
|
||||
|| return
|
||||
|
||||
$MAKE || return
|
||||
|
||||
# FIXME: we should use -E option here
|
||||
sudo make check
|
||||
}
|
||||
|
||||
function check_nonroot_compile_only
|
||||
{
|
||||
local cfg_opts="$1"
|
||||
|
||||
[ -z "$cfg_opts" ] && return
|
||||
|
||||
configure_travis \
|
||||
--enable-cryptsetup-reencrypt \
|
||||
--enable-internal-sse-argon2 \
|
||||
"$cfg_opts" \
|
||||
|| return
|
||||
|
||||
$MAKE
|
||||
}
|
||||
|
||||
function travis_install_script
|
||||
{
|
||||
# install some packages from Ubuntu's default sources
|
||||
sudo apt-get -qq update
|
||||
sudo apt-get install -qq >/dev/null \
|
||||
sharutils \
|
||||
libgcrypt20-dev \
|
||||
libssl-dev \
|
||||
libdevmapper-dev \
|
||||
libpopt-dev \
|
||||
uuid-dev \
|
||||
libsepol1-dev \
|
||||
libtool \
|
||||
dmsetup \
|
||||
autoconf \
|
||||
automake \
|
||||
pkg-config \
|
||||
autopoint \
|
||||
gettext \
|
||||
expect \
|
||||
keyutils \
|
||||
libjson-c-dev \
|
||||
libblkid-dev \
|
||||
dkms \
|
||||
linux-headers-$(uname -r) \
|
||||
linux-modules-extra-$(uname -r) \
|
||||
libssh-dev \
|
||||
sshpass \
|
||||
|| return
|
||||
|
||||
# For VeraCrypt test
|
||||
sudo apt-get install gost-crypto-dkms
|
||||
}
|
||||
|
||||
function travis_before_script
|
||||
{
|
||||
set -o xtrace
|
||||
|
||||
./autogen.sh
|
||||
ret=$?
|
||||
|
||||
set +o xtrace
|
||||
return $ret
|
||||
}
|
||||
|
||||
function travis_script
|
||||
{
|
||||
local ret
|
||||
set -o xtrace
|
||||
|
||||
case "$MAKE_CHECK" in
|
||||
gcrypt)
|
||||
check_nonroot "--with-crypto_backend=gcrypt" && \
|
||||
check_root "--with-crypto_backend=gcrypt"
|
||||
;;
|
||||
gcrypt_compile)
|
||||
check_nonroot_compile_only "--with-crypto_backend=gcrypt"
|
||||
;;
|
||||
openssl)
|
||||
check_nonroot "--with-crypto_backend=openssl" && \
|
||||
check_root "--with-crypto_backend=openssl"
|
||||
;;
|
||||
openssl_compile)
|
||||
check_nonroot_compile_only "--with-crypto_backend=openssl"
|
||||
;;
|
||||
kernel)
|
||||
check_nonroot "--with-crypto_backend=kernel" && \
|
||||
check_root "--with-crypto_backend=kernel"
|
||||
;;
|
||||
kernel_compile)
|
||||
check_nonroot_compile_only "--with-crypto_backend=kernel"
|
||||
;;
|
||||
*)
|
||||
echo "error, check environment (travis.yml)" >&2
|
||||
false
|
||||
;;
|
||||
esac
|
||||
|
||||
ret=$?
|
||||
set +o xtrace
|
||||
return $ret
|
||||
}
|
||||
|
||||
function travis_after_script
|
||||
{
|
||||
return 0
|
||||
}
|
||||
42
.travis.yml
42
.travis.yml
@@ -1,42 +0,0 @@
|
||||
language: c
|
||||
|
||||
sudo: required
|
||||
os: linux
|
||||
dist: focal
|
||||
group: edge
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
|
||||
env:
|
||||
# MAKE_CHECK="gcrypt"
|
||||
- MAKE_CHECK="openssl"
|
||||
# MAKE_CHECK="kernel"
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- wip-luks2
|
||||
- v2.3.x
|
||||
|
||||
before_install:
|
||||
- uname -a
|
||||
- $CC --version
|
||||
- which $CC
|
||||
# workaround clang not system wide, fail on sudo make install
|
||||
- export CC=`which $CC`
|
||||
# workaround travis-ci issue #5301
|
||||
- unset PYTHON_CFLAGS
|
||||
|
||||
install:
|
||||
- source ./.travis-functions.sh
|
||||
- travis_install_script
|
||||
|
||||
before_script:
|
||||
- travis_before_script
|
||||
|
||||
script:
|
||||
- travis_script
|
||||
|
||||
after_script:
|
||||
- travis_after_script
|
||||
88
FAQ
88
FAQ
@@ -51,7 +51,7 @@ A. Contributors
|
||||
security model BEFORE you face such a disaster! In particular, make
|
||||
sure you have a current header backup before doing any potentially
|
||||
dangerous operations. The LUKS2 header should be a bit more resilient
|
||||
as critical data starts later and is stored twice, but you can decidedly
|
||||
as critical data starts later and is stored twice, but you can decidely
|
||||
still destroy it or a keyslot permanently by accident.
|
||||
|
||||
DEBUG COMMANDS: While the --debug and --debug-json options should not
|
||||
@@ -235,6 +235,31 @@ A. Contributors
|
||||
nothing and are sure you did not confirm, then you should look into a
|
||||
possible compromise of your email account.
|
||||
|
||||
* 1.9 What can I do if cryptsetup is running out of memory?
|
||||
|
||||
Memory issues are generally related to the key derivation function. You may
|
||||
be able to tune usage with the options --pbkdf-memory or --pbkdf pbkdf2.
|
||||
|
||||
|
||||
* 1.10 Can cryptsetup be run without root access?
|
||||
|
||||
Elevated privileges are required to use cryptsetup and LUKS. Some operations
|
||||
require root access. There are a few features which will work without root
|
||||
access with the right switches but there are caveats.
|
||||
|
||||
|
||||
* 1.11 What are the problems with running as non root?
|
||||
|
||||
The first issue is one of permissions to devices. Generally, root or a group
|
||||
such as disk has ownership of the storage devices. The non root user will
|
||||
need write access to the block device used for LUKS.
|
||||
|
||||
Next, file locking is managed in /run/cryptsetup. You may use
|
||||
--disable-locks but cryptsetup will no longer protect you from race
|
||||
conditions and problems with concurrent access to the same devices.
|
||||
|
||||
Also, device mapper requires root access. cryptsetup uses device mapper to
|
||||
manage the decrypted container.
|
||||
|
||||
2. Setup
|
||||
|
||||
@@ -399,6 +424,14 @@ A. Contributors
|
||||
it in some other way. The PC is just not set-up for a really secure
|
||||
boot-chain (whatever some people may claim).
|
||||
|
||||
That said, if you want an encrypted root partition, you have to store
|
||||
an initrd with cryptsetup somewhere else. The traditional approach is
|
||||
to have a separate partition under /boot for that. You can also put that
|
||||
initrd on a bootable memory stick, bootable CD or bootable external
|
||||
drive as well. The kernel and Grub typically go to the same location
|
||||
as that initrd. A minimal example what such an initrd can look like is
|
||||
given in Section 9.
|
||||
|
||||
(2) Fully encrypted raw block device: For this, put LUKS on the raw
|
||||
device (e.g. /dev/sdb) and put a filesystem into the LUKS container, no
|
||||
partitioning whatsoever involved. This is very suitable for things like
|
||||
@@ -818,7 +851,7 @@ A. Contributors
|
||||
|
||||
|
||||
* 2.20 How do I wipe only the LUKS header?
|
||||
|
||||
|
||||
This does _not_ describe an emergency wipe procedure, see Item 5.4 for
|
||||
that. This procedure here is intended to be used when the data should
|
||||
stay intact, e.g. when you change your LUKS container to use a detached
|
||||
@@ -831,20 +864,26 @@ A. Contributors
|
||||
cryptsetup luksDump <device with LUKS container>
|
||||
|
||||
-> ...
|
||||
Payload offset: <number>
|
||||
Payload offset: <number> [of 512 byte sectors]
|
||||
...
|
||||
|
||||
02) Take the result number, multiply by 512 zeros and write to
|
||||
the start of the device, e.g. like this:
|
||||
the start of the device, e.g. using one of the following alternatives:
|
||||
|
||||
dd bs=512 count=<number> if=/dev/zero of=<device>
|
||||
|
||||
|
||||
LUKS2: (warning, untested! Remember that backup?) This assumes the
|
||||
head -c <number * 512> /dev/zero > /dev/<device>
|
||||
|
||||
|
||||
LUKS2:
|
||||
(warning, untested! Remember that backup?) This assumes the
|
||||
LUKS2 container uses the defaults, in particular there is only one data
|
||||
segment. 01) Determine the data-segment offset using luksDump, same
|
||||
segment.
|
||||
01) Determine the data-segment offset using luksDump, same
|
||||
as above for LUKS1:
|
||||
|
||||
cryptsetup luksDump <device with LUKS container>
|
||||
-> ...
|
||||
Data segments:
|
||||
0: crypt
|
||||
@@ -854,7 +893,7 @@ A. Contributors
|
||||
02) Overwrite the stated number of bytes from the start of the device.
|
||||
Just to give yet another way to get a defined number of zeros:
|
||||
|
||||
head -c /dev/zero > /dev/<device>
|
||||
head -c <number> /dev/zero > /dev/<device>
|
||||
|
||||
|
||||
3. Common Problems
|
||||
@@ -969,7 +1008,7 @@ A. Contributors
|
||||
that is intact.
|
||||
|
||||
In order to find out whether a key-slot is damaged one has to look for
|
||||
"non-random looking" data in it. There is a tool that automates this
|
||||
"non-random looking" data in it. There is a tool that automatizes this
|
||||
for LUKS1 in the cryptsetup distribution from version 1.6.0 onwards. It
|
||||
is located in misc/keyslot_checker/. Instructions how to use and how to
|
||||
interpret results are in the README file. Note that this tool requires
|
||||
@@ -1207,6 +1246,17 @@ A. Contributors
|
||||
countries like the US or the UK are not civilized and do not have fair
|
||||
laws.
|
||||
|
||||
As a side-note, standards for biometrics (fingerprint, retina,
|
||||
vein-pattern, etc.) are often different and much lower. If you put
|
||||
your LUKS passphrase into a device that can be unlocked using biometrics,
|
||||
they may force a biometric sample in many countries where they could not
|
||||
force you to give them a passphrase you solely have in your memory and
|
||||
can claim to have forgotten if needed (it happens). If you need protection
|
||||
on this level, make sure you know what the respective legal situation is,
|
||||
also while traveling, and make sure you decide beforehand what you
|
||||
will do if push comes to shove as they will definitely put you under
|
||||
as much pressure as they can legally apply.
|
||||
|
||||
This means that if you have a large set of random-looking data, they can
|
||||
already lock you up. Hidden containers (encryption hidden within
|
||||
encryption), as possible with Truecrypt, do not help either. They will
|
||||
@@ -1608,9 +1658,8 @@ A. Contributors
|
||||
|
||||
cryptsetup -c aes-xts-plain64 luksFormat <device>
|
||||
|
||||
There is a potential security issue with XTS mode and blocks larger
|
||||
than 2^20 bytes or so. LUKS and dm-crypt always use smaller blocks
|
||||
and the issue does not apply.
|
||||
There is a potential security issue with XTS mode and large blocks.
|
||||
LUKS and dm-crypt always use 512B blocks and the issue does not apply.
|
||||
|
||||
|
||||
* 5.17 Is LUKS FIPS-140-2 certified?
|
||||
@@ -2629,7 +2678,7 @@ offset length name data type description
|
||||
safe under these circumstances, then you have bigger problems than this
|
||||
somewhat expected behavior.
|
||||
|
||||
The CVE was exaggerated and should not be assigned to upstream
|
||||
The CVE was exagerrated and should not be assigned to upstream
|
||||
cryptsetup in the first place (it is a distro specific initrd issue).
|
||||
It was driven more by a try to make a splash for self-aggrandizement,
|
||||
than by any actual security concerns. Ignore it.
|
||||
@@ -2953,9 +3002,24 @@ offset length name data type description
|
||||
start of the device, nothing gets stored somewhere in the middle or at
|
||||
the end.
|
||||
|
||||
* 10.12 What is a LUKS2 Token?
|
||||
|
||||
A LUKS2 token is an object that describes "how to get a passphrase or
|
||||
key" to unlock particular keyslot. A LUKS2 token is stored as json data
|
||||
in the LUKS2 header. The token can be related to all keyslots or a
|
||||
specific one. As the token is stored in JSON formay it is text by
|
||||
default but binary data can be encoded into it according to the JSON
|
||||
conventions.
|
||||
|
||||
Documentation on the last changes to LUKS2 tokens can be found in the
|
||||
release notes. As of version 2.4 of cryptsetup, there are significant
|
||||
features. The standard documentation for working with tokens is
|
||||
in the luks2 reference available as PDF on the project page.
|
||||
|
||||
|
||||
11. References and Further Reading
|
||||
|
||||
|
||||
* Purpose of this Section
|
||||
|
||||
The purpose of this section is to collect references to all materials
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
EXTRA_DIST = README.md COPYING.LGPL FAQ docs misc
|
||||
EXTRA_DIST = README.md COPYING.LGPL FAQ docs misc autogen.sh
|
||||
SUBDIRS = po tests
|
||||
CLEANFILES =
|
||||
DISTCLEAN_TARGETS =
|
||||
@@ -54,3 +54,9 @@ distclean-local:
|
||||
|
||||
clean-local:
|
||||
-rm -rf docs/doxygen_api_docs libargon2.la
|
||||
|
||||
install-data-local:
|
||||
$(MKDIR_P) -m 0755 $(DESTDIR)/${EXTERNAL_LUKS2_TOKENS_PATH}
|
||||
|
||||
uninstall-local:
|
||||
rmdir $(DESTDIR)/${EXTERNAL_LUKS2_TOKENS_PATH} 2>/dev/null || :
|
||||
|
||||
55
README.md
55
README.md
@@ -20,6 +20,8 @@ LUKS Design
|
||||
only facilitate compatibility among distributions, but also provides secure management of multiple user passwords.
|
||||
LUKS stores all necessary setup information in the partition header, enabling to transport or migrate data seamlessly.
|
||||
|
||||
### Specifications
|
||||
|
||||
Last version of the LUKS2 format specification is
|
||||
[available here](https://gitlab.com/cryptsetup/LUKS2-docs).
|
||||
|
||||
@@ -44,22 +46,16 @@ Download
|
||||
--------
|
||||
All release tarballs and release notes are hosted on [kernel.org](https://www.kernel.org/pub/linux/utils/cryptsetup/).
|
||||
|
||||
**The latest release candidate cryptsetup version is 2.4.0-rc1**
|
||||
* [cryptsetup-2.4.0-rc1.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.4/cryptsetup-2.4.0-rc1.tar.xz)
|
||||
* Signature [cryptsetup-2.4.0-rc1.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.4/cryptsetup-2.4.0-rc1.tar.sign)
|
||||
**The latest stable cryptsetup version is 2.4.3**
|
||||
* [cryptsetup-2.4.3.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.4/cryptsetup-2.4.3.tar.xz)
|
||||
* Signature [cryptsetup-2.4.3.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.4/cryptsetup-2.4.3.tar.sign)
|
||||
_(You need to decompress file first to check signature.)_
|
||||
* [Cryptsetup 2.4.0-rc1 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.4/v2.4.0-rc1-ReleaseNotes).
|
||||
|
||||
**The latest stable cryptsetup version is 2.3.6**
|
||||
* [cryptsetup-2.3.6.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/cryptsetup-2.3.6.tar.xz)
|
||||
* Signature [cryptsetup-2.3.6.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/cryptsetup-2.3.6.tar.sign)
|
||||
_(You need to decompress file first to check signature.)_
|
||||
* [Cryptsetup 2.3.6 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/v2.3.6-ReleaseNotes).
|
||||
* [Cryptsetup 2.4.3 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.4/v2.4.3-ReleaseNotes).
|
||||
|
||||
Previous versions
|
||||
* [Version 2.0.6](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.6.tar.xz) -
|
||||
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.6.tar.sign) -
|
||||
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.6-ReleaseNotes).
|
||||
* [Version 2.3.7](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/cryptsetup-2.3.7.tar.xz) -
|
||||
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/cryptsetup-2.3.7.tar.sign) -
|
||||
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/v2.3.7-ReleaseNotes).
|
||||
* [Version 1.7.5](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.5.tar.xz) -
|
||||
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.5.tar.sign) -
|
||||
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/v1.7.5-ReleaseNotes).
|
||||
@@ -77,22 +73,35 @@ NLS PO files are maintained by [TranslationProject](https://translationproject.o
|
||||
|
||||
Required packages
|
||||
-----------------
|
||||
All distributions provide cryptsetup as distro package. If you need to compile cryptsetup youfself, some packages are required for compilation. Please always prefer distro specific build tools to manually configuring cryptsetup.
|
||||
Fo available compile options, check ``configure --help`` for more info. If you are using a git snapshot, you need to generate configure script with ``autogen.sh`` script.
|
||||
All distributions provide cryptsetup as distro package. If you need to compile cryptsetup yourself, some packages are required for compilation. Please always prefer distro specific build tools to manually configuring cryptsetup.
|
||||
For available compile options, check ``configure --help`` for more info. If you are using a git snapshot, you need to generate a configure script with ``autogen.sh`` script.
|
||||
|
||||
Here is the list of packages needed for the compilation of project for particular distributions:
|
||||
* For Fedora: `git gcc make autoconf automake gettext-devel pkgconfig openssl-devel popt-devel device-mapper-devel libuuid-devel json-c-devel libblkid-devel findutils libtool libssh-devel tar`. Optionally `libargon2-devel libpwquality-devel`. To run internal testsuite you also need `sharutils device-mapper jq vim-common expect keyutils netcat shadow-utils openssh-clients openssh sshpass`.
|
||||
* For Fedora: `git gcc make autoconf automake gettext-devel pkgconfig openssl-devel popt-devel device-mapper-devel libuuid-devel json-c-devel libblkid-devel findutils libtool libssh-devel tar`. Optionally `libargon2-devel libpwquality-devel`. To run the internal testsuite you also need to install `sharutils device-mapper jq vim-common expect keyutils netcat shadow-utils openssh-clients openssh sshpass`.
|
||||
|
||||
* For Debian and Ubuntu: `git gcc make autoconf automake autopoint pkg-config libtool gettext libssl-dev libdevmapper-dev libpopt-dev uuid-dev libsepol1-dev libjson-c-dev libssh-dev libblkid-dev tar`. Optionally `libargon2-0-dev libpwquality-dev`. To run internal testsuite you also need `sharutils dmsetup jq xxd expect keyutils netcat passwd openssh-client sshpass`
|
||||
* For Debian and Ubuntu: `git gcc make autoconf automake autopoint pkg-config libtool gettext libssl-dev libdevmapper-dev libpopt-dev uuid-dev libsepol1-dev libjson-c-dev libssh-dev libblkid-dev tar`. Optionally `libargon2-0-dev libpwquality-dev`. To run the internal testsuite you also need to install `sharutils dmsetup jq xxd expect keyutils netcat passwd openssh-client sshpass`
|
||||
|
||||
Note that the list could change as distributions evolve.
|
||||
Note that the list could change as the distributions evolve.
|
||||
|
||||
Help!
|
||||
-----
|
||||
Please always read [FAQ](https://gitlab.com/cryptsetup/cryptsetup/wikis/FrequentlyAskedQuestions) first.
|
||||
For cryptsetup and LUKS related questions, please use the dm-crypt mailing list, [dm-crypt@saout.de](mailto:dm-crypt@saout.de).
|
||||
|
||||
If you want to subscribe just send an empty mail to [dm-crypt-subscribe@saout.de](mailto:dm-crypt-subscribe@saout.de).
|
||||
### Documentation
|
||||
|
||||
You can also browse [list archive](https://www.saout.de/pipermail/dm-crypt/) or read and search it through
|
||||
[web interface on lore.kernel.org](https://lore.kernel.org/dm-crypt/) or alternatively on [marc.info](https://marc.info/?l=dm-crypt).
|
||||
Please read the following documentation before posting questions in the mailing list. You will be able to ask better questions and better understand the answers.
|
||||
|
||||
* [FAQ](https://gitlab.com/cryptsetup/cryptsetup/wikis/FrequentlyAskedQuestions)
|
||||
* LUKS Specifications
|
||||
* manuals (aka man page, man pages, man-page)
|
||||
|
||||
The FAQ is online and in the source code for the project. The Specifications are referenced above in this document. The man pages are in source and should be available after installation using standard man commands. e.g. man cryptsetup
|
||||
|
||||
### Mailing List
|
||||
|
||||
For cryptsetup and LUKS related questions, please use the dm-crypt mailing list, [dm-crypt@saout.de](mailto:dm-crypt@saout.de). To subscribe send an empty mail to [dm-crypt-subscribe@saout.de](mailto:dm-crypt-subscribe@saout.de).
|
||||
|
||||
You can also browse and/or search the mailing list archives using the following resources:
|
||||
|
||||
* [list archive](https://www.saout.de/pipermail/dm-crypt/)
|
||||
* [web interface on lore.kernel.org](https://lore.kernel.org/dm-crypt/)
|
||||
* [marc.info](https://marc.info/?l=dm-crypt).
|
||||
|
||||
@@ -29,10 +29,10 @@ DIE=0
|
||||
DIE=1
|
||||
}
|
||||
|
||||
(grep "^AM_PROG_LIBTOOL" $srcdir/configure.ac >/dev/null) && {
|
||||
(libtool --version) < /dev/null > /dev/null 2>&1 || {
|
||||
(grep "^LT_INIT" $srcdir/configure.ac >/dev/null) && {
|
||||
(libtoolize --version) < /dev/null > /dev/null 2>&1 || {
|
||||
echo
|
||||
echo "**Error**: You must have libtool installed."
|
||||
echo "**Error**: You must have libtoolize installed."
|
||||
echo "Download the appropriate package for your distribution."
|
||||
DIE=1
|
||||
}
|
||||
|
||||
25
configure.ac
25
configure.ac
@@ -1,5 +1,5 @@
|
||||
AC_PREREQ([2.67])
|
||||
AC_INIT([cryptsetup],[2.4.0-rc1])
|
||||
AC_INIT([cryptsetup],[2.4.3])
|
||||
|
||||
dnl library version from <major>.<minor>.<release>[-<suffix>]
|
||||
LIBCRYPTSETUP_VERSION=$(echo $PACKAGE_VERSION | cut -f1 -d-)
|
||||
@@ -30,6 +30,7 @@ AM_PROG_CC_C_O
|
||||
AC_PROG_CPP
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_MAKE_SET
|
||||
AC_PROG_MKDIR_P
|
||||
AC_ENABLE_STATIC(no)
|
||||
LT_INIT
|
||||
PKG_PROG_PKG_CONFIG
|
||||
@@ -57,7 +58,6 @@ dnl ==========================================================================
|
||||
AC_C_RESTRICT
|
||||
|
||||
AC_HEADER_DIRENT
|
||||
AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS(fcntl.h malloc.h inttypes.h sys/ioctl.h sys/mman.h \
|
||||
sys/sysmacros.h sys/statvfs.h ctype.h unistd.h locale.h byteswap.h endian.h stdint.h)
|
||||
AC_CHECK_DECLS([O_CLOEXEC],,[AC_DEFINE([O_CLOEXEC],[0], [Defined to 0 if not provided])],
|
||||
@@ -123,6 +123,12 @@ AC_ARG_ENABLE([external-tokens],
|
||||
[], [enable_external_tokens=yes])
|
||||
if test "x$enable_external_tokens" = "xyes"; then
|
||||
AC_DEFINE(USE_EXTERNAL_TOKENS, 1, [Use external tokens])
|
||||
dnl we need dynamic library loading here
|
||||
saved_LIBS=$LIBS
|
||||
AC_SEARCH_LIBS([dlsym],[dl])
|
||||
AC_CHECK_FUNCS([dlvsym])
|
||||
AC_SUBST(DL_LIBS, $LIBS)
|
||||
LIBS=$saved_LIBS
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE([ssh-token],
|
||||
@@ -134,6 +140,14 @@ if test "x$enable_ssh_token" = "xyes" -a "x$enable_external_tokens" = "xno"; the
|
||||
AC_MSG_ERROR([Requested LUKS2 ssh-token build, but external tokens are disabled.])
|
||||
fi
|
||||
|
||||
dnl LUKS2 online reencryption
|
||||
AC_ARG_ENABLE([luks2-reencryption],
|
||||
AS_HELP_STRING([--disable-luks2-reencryption], [disable LUKS2 online reencryption extension]),
|
||||
[], [enable_luks2_reencryption=yes])
|
||||
if test "x$enable_luks2_reencryption" = "xyes"; then
|
||||
AC_DEFINE(USE_LUKS2_REENCRYPTION, 1, [Use LUKS2 online reencryption extension])
|
||||
fi
|
||||
|
||||
dnl ==========================================================================
|
||||
|
||||
AM_GNU_GETTEXT([external],[need-ngettext])
|
||||
@@ -399,10 +413,15 @@ PKG_CHECK_MODULES([JSON_C], [json-c])
|
||||
AC_CHECK_DECLS([json_object_object_add_ex], [], [], [#include <json-c/json.h>])
|
||||
AC_CHECK_DECLS([json_object_deep_copy], [], [], [#include <json-c/json.h>])
|
||||
|
||||
dnl Check for libssh for SSH plugin
|
||||
dnl Check for libssh and argp for SSH plugin
|
||||
if test "x$enable_ssh_token" = "xyes"; then
|
||||
PKG_CHECK_MODULES([LIBSSH], [libssh])
|
||||
AC_CHECK_DECLS([ssh_session_is_known_server], [], [], [#include <libssh/libssh.h>])
|
||||
AC_CHECK_HEADER([argp.h], [], AC_MSG_ERROR([You need argp library.]))
|
||||
saved_LIBS=$LIBS
|
||||
AC_SEARCH_LIBS([argp_usage],[argp])
|
||||
AC_SUBST(ARGP_LIBS, $LIBS)
|
||||
LIBS=$saved_LIBS
|
||||
fi
|
||||
|
||||
dnl Crypto backend configuration.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Doxyfile 1.8.8
|
||||
# Doxyfile 1.9.1
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Project related configuration options
|
||||
@@ -12,6 +12,7 @@ OUTPUT_DIRECTORY = doxygen_api_docs
|
||||
CREATE_SUBDIRS = NO
|
||||
ALLOW_UNICODE_NAMES = NO
|
||||
OUTPUT_LANGUAGE = English
|
||||
OUTPUT_TEXT_DIRECTION = None
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
ABBREVIATE_BRIEF =
|
||||
@@ -22,40 +23,47 @@ STRIP_FROM_PATH =
|
||||
STRIP_FROM_INC_PATH =
|
||||
SHORT_NAMES = NO
|
||||
JAVADOC_AUTOBRIEF = NO
|
||||
JAVADOC_BANNER = NO
|
||||
QT_AUTOBRIEF = NO
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
PYTHON_DOCSTRING = YES
|
||||
INHERIT_DOCS = YES
|
||||
SEPARATE_MEMBER_PAGES = NO
|
||||
TAB_SIZE = 8
|
||||
ALIASES =
|
||||
TCL_SUBST =
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
OPTIMIZE_FOR_FORTRAN = NO
|
||||
OPTIMIZE_OUTPUT_VHDL = NO
|
||||
OPTIMIZE_OUTPUT_SLICE = NO
|
||||
EXTENSION_MAPPING =
|
||||
MARKDOWN_SUPPORT = YES
|
||||
TOC_INCLUDE_HEADINGS = 5
|
||||
AUTOLINK_SUPPORT = YES
|
||||
BUILTIN_STL_SUPPORT = NO
|
||||
CPP_CLI_SUPPORT = NO
|
||||
SIP_SUPPORT = NO
|
||||
IDL_PROPERTY_SUPPORT = YES
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
GROUP_NESTED_COMPOUNDS = NO
|
||||
SUBGROUPING = YES
|
||||
INLINE_GROUPED_CLASSES = NO
|
||||
INLINE_SIMPLE_STRUCTS = NO
|
||||
TYPEDEF_HIDES_STRUCT = YES
|
||||
LOOKUP_CACHE_SIZE = 0
|
||||
NUM_PROC_THREADS = 1
|
||||
#---------------------------------------------------------------------------
|
||||
# Build related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
EXTRACT_ALL = NO
|
||||
EXTRACT_PRIVATE = NO
|
||||
EXTRACT_PRIV_VIRTUAL = NO
|
||||
EXTRACT_PACKAGE = NO
|
||||
EXTRACT_STATIC = NO
|
||||
EXTRACT_LOCAL_CLASSES = YES
|
||||
EXTRACT_LOCAL_METHODS = NO
|
||||
EXTRACT_ANON_NSPACES = NO
|
||||
RESOLVE_UNNAMED_PARAMS = YES
|
||||
HIDE_UNDOC_MEMBERS = NO
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
HIDE_FRIEND_COMPOUNDS = NO
|
||||
@@ -63,6 +71,7 @@ HIDE_IN_BODY_DOCS = NO
|
||||
INTERNAL_DOCS = NO
|
||||
CASE_SENSE_NAMES = YES
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
HIDE_COMPOUND_REFERENCE= NO
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
SHOW_GROUPED_MEMB_INC = NO
|
||||
FORCE_LOCAL_INCLUDES = NO
|
||||
@@ -93,13 +102,14 @@ WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_NO_PARAMDOC = NO
|
||||
WARN_AS_ERROR = NO
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
WARN_LOGFILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
INPUT = "doxygen_index.h" \
|
||||
"../lib/libcryptsetup.h"
|
||||
INPUT = doxygen_index.h \
|
||||
../lib/libcryptsetup.h
|
||||
INPUT_ENCODING = UTF-8
|
||||
FILE_PATTERNS =
|
||||
RECURSIVE = NO
|
||||
@@ -107,7 +117,7 @@ EXCLUDE =
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXCLUDE_PATTERNS =
|
||||
EXCLUDE_SYMBOLS =
|
||||
EXAMPLE_PATH = "examples"
|
||||
EXAMPLE_PATH = examples
|
||||
EXAMPLE_PATTERNS =
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
IMAGE_PATH =
|
||||
@@ -129,12 +139,13 @@ SOURCE_TOOLTIPS = YES
|
||||
USE_HTAGS = NO
|
||||
VERBATIM_HEADERS = YES
|
||||
CLANG_ASSISTED_PARSING = NO
|
||||
CLANG_ADD_INC_PATHS = YES
|
||||
CLANG_OPTIONS =
|
||||
CLANG_DATABASE_PATH =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
ALPHABETICAL_INDEX = YES
|
||||
COLS_IN_ALPHA_INDEX = 5
|
||||
IGNORE_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the HTML output
|
||||
@@ -151,6 +162,7 @@ HTML_COLORSTYLE_HUE = 220
|
||||
HTML_COLORSTYLE_SAT = 100
|
||||
HTML_COLORSTYLE_GAMMA = 80
|
||||
HTML_TIMESTAMP = YES
|
||||
HTML_DYNAMIC_MENUS = YES
|
||||
HTML_DYNAMIC_SECTIONS = NO
|
||||
HTML_INDEX_NUM_ENTRIES = 100
|
||||
GENERATE_DOCSET = NO
|
||||
@@ -180,8 +192,10 @@ GENERATE_TREEVIEW = NO
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
TREEVIEW_WIDTH = 250
|
||||
EXT_LINKS_IN_WINDOW = NO
|
||||
HTML_FORMULA_FORMAT = png
|
||||
FORMULA_FONTSIZE = 10
|
||||
FORMULA_TRANSPARENT = YES
|
||||
FORMULA_MACROFILE =
|
||||
USE_MATHJAX = NO
|
||||
MATHJAX_FORMAT = HTML-CSS
|
||||
MATHJAX_RELPATH = http://www.mathjax.org/mathjax
|
||||
@@ -201,11 +215,13 @@ GENERATE_LATEX = YES
|
||||
LATEX_OUTPUT = latex
|
||||
LATEX_CMD_NAME = latex
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
LATEX_MAKEINDEX_CMD = makeindex
|
||||
COMPACT_LATEX = NO
|
||||
PAPER_TYPE = a4
|
||||
EXTRA_PACKAGES =
|
||||
LATEX_HEADER =
|
||||
LATEX_FOOTER =
|
||||
LATEX_EXTRA_STYLESHEET =
|
||||
LATEX_EXTRA_FILES =
|
||||
PDF_HYPERLINKS = YES
|
||||
USE_PDFLATEX = YES
|
||||
@@ -213,6 +229,8 @@ LATEX_BATCHMODE = NO
|
||||
LATEX_HIDE_INDICES = NO
|
||||
LATEX_SOURCE_CODE = NO
|
||||
LATEX_BIB_STYLE = plain
|
||||
LATEX_TIMESTAMP = NO
|
||||
LATEX_EMOJI_DIRECTORY =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the RTF output
|
||||
#---------------------------------------------------------------------------
|
||||
@@ -222,6 +240,7 @@ COMPACT_RTF = NO
|
||||
RTF_HYPERLINKS = NO
|
||||
RTF_STYLESHEET_FILE =
|
||||
RTF_EXTENSIONS_FILE =
|
||||
RTF_SOURCE_CODE = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the man page output
|
||||
#---------------------------------------------------------------------------
|
||||
@@ -236,6 +255,7 @@ MAN_LINKS = NO
|
||||
GENERATE_XML = NO
|
||||
XML_OUTPUT = xml
|
||||
XML_PROGRAMLISTING = YES
|
||||
XML_NS_MEMB_FILE_SCOPE = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the DOCBOOK output
|
||||
#---------------------------------------------------------------------------
|
||||
@@ -273,12 +293,10 @@ GENERATE_TAGFILE =
|
||||
ALLEXTERNALS = NO
|
||||
EXTERNAL_GROUPS = YES
|
||||
EXTERNAL_PAGES = YES
|
||||
PERL_PATH =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
CLASS_DIAGRAMS = YES
|
||||
MSCGEN_PATH =
|
||||
DIA_PATH =
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
HAVE_DOT = NO
|
||||
@@ -291,6 +309,8 @@ COLLABORATION_GRAPH = YES
|
||||
GROUP_GRAPHS = YES
|
||||
UML_LOOK = NO
|
||||
UML_LIMIT_NUM_FIELDS = 10
|
||||
DOT_UML_DETAILS = NO
|
||||
DOT_WRAP_THRESHOLD = 17
|
||||
TEMPLATE_RELATIONS = NO
|
||||
INCLUDE_GRAPH = YES
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
@@ -305,6 +325,8 @@ DOTFILE_DIRS =
|
||||
MSCFILE_DIRS =
|
||||
DIAFILE_DIRS =
|
||||
PLANTUML_JAR_PATH =
|
||||
PLANTUML_CFG_FILE =
|
||||
PLANTUML_INCLUDE_PATH =
|
||||
DOT_GRAPH_MAX_NODES = 50
|
||||
MAX_DOT_GRAPH_DEPTH = 0
|
||||
DOT_TRANSPARENT = NO
|
||||
|
||||
Binary file not shown.
@@ -1,31 +1,10 @@
|
||||
Cryptsetup 2.4.0-rc1 Release Notes
|
||||
==================================
|
||||
Stable release candidate with new features and bug fixes.
|
||||
Cryptsetup 2.4.0 Release Notes
|
||||
==============================
|
||||
Stable release with new features and bug fixes.
|
||||
|
||||
This version introduces support for external libraries
|
||||
(plugins) for handling LUKS2 token objects.
|
||||
|
||||
Changes since version 2.4.0-rc0
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Add cryptsetup --token-type parameter.
|
||||
|
||||
It restricts token type to the parameter value in case no specific
|
||||
token-id is selected.
|
||||
|
||||
* Do not retry token operations if PIN entry failed.
|
||||
|
||||
* Respect keyslot priority with token-based activation.
|
||||
|
||||
* veritysetup: add --root-hash-file option
|
||||
Allow passing the root hash via a file, rather than verbatim on
|
||||
the command line, for the open, verify, and format actions.
|
||||
|
||||
* Add crypt_reencrypt_run superseding now deprecated crypt_reencrypt
|
||||
API call (fixes API break in rc0 release).
|
||||
|
||||
* Respect keyslot priority with token-based activation.
|
||||
|
||||
Changes since version 2.3.6
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -39,7 +18,13 @@ Changes since version 2.3.6
|
||||
in external libraries (possibly provided by other projects).
|
||||
|
||||
A token library allows cryptsetup to understand metadata and provide
|
||||
basic operations (activate, resize, dump metadata, handle keyslots).
|
||||
basic operations. Currently external tokens may be used to unlock
|
||||
keyslots for following CLI actions: open (luksOpen),
|
||||
refresh (open --refresh), resize and dump (prints token specific
|
||||
content).
|
||||
|
||||
LUKS2 devices cannot be resumed (luksResume action) via tokens yet.
|
||||
Support for resume and other actions will be added later.
|
||||
|
||||
The library now provides an interface that automatically tries to load
|
||||
an external library for a token object in LUKS2 metadata.
|
||||
@@ -61,8 +46,14 @@ Changes since version 2.3.6
|
||||
External projects can use this interface to handle specific hardware
|
||||
without introducing additional dependencies to libcryptsetup core.
|
||||
|
||||
Examples of such tokens are already available for the systemd project
|
||||
for TPM2 and FIDO2 interfaces.
|
||||
As of cryptsetup 2.4.0 release systemd project already merged upstream
|
||||
native cryptsetup token handler for its systemd-tpm2 LUKS2 token
|
||||
released originally in systemd-v248. The token can be created using
|
||||
systemd-cryptenroll utility and devices may be manipulated either by
|
||||
systemd-cryptsetup cli or by cryptsetup for actions listed above.
|
||||
|
||||
Other tokens like systemd-fido2 and systemd-pkcs11 are currently
|
||||
in-review.
|
||||
|
||||
* Experimental SSH token
|
||||
|
||||
@@ -119,6 +110,19 @@ Example (how to activate LUKS2 through remote keyfile):
|
||||
Please note SSH token is just demonstration of plugin interface API,
|
||||
it is an EXPERIMENTAL feature.
|
||||
|
||||
* Add cryptsetup --token-type parameter.
|
||||
|
||||
It restricts token type to the parameter value in case no specific
|
||||
token-id is selected.
|
||||
|
||||
* Support for token based activation with PIN.
|
||||
|
||||
If specific token requires PIN to unlock keyslot passphrase and
|
||||
--token-only parameter was used cryptsetup asks for additional
|
||||
token PIN.
|
||||
|
||||
* Respect keyslot priority with token-based activation.
|
||||
|
||||
* Default LUKS2 PBKDF is now Argon2id
|
||||
|
||||
Cryptsetup LUKS2 was using Argon2 while there were two versions,
|
||||
@@ -266,6 +270,10 @@ Example (how to activate LUKS2 through remote keyfile):
|
||||
Note that it cannot detect unknown algorithm names and similar where
|
||||
we need call API functions.
|
||||
|
||||
* veritysetup: add --root-hash-file option
|
||||
Allow passing the root hash via a file, rather than verbatim on
|
||||
the command line, for the open, verify, and format actions.
|
||||
|
||||
* libcryptsetup C API extensions (see libcryptsetup.h for details)
|
||||
|
||||
- crypt_logf - a printf like log function
|
||||
@@ -275,7 +283,7 @@ Example (how to activate LUKS2 through remote keyfile):
|
||||
- crypt_token_external_path - get path for plugins (or NULL)
|
||||
- crypt_token_external_disable - disable runtime support for plugins
|
||||
- crypt_activate_by_token_pin - activate by token with additional PIN
|
||||
- crypt_reencrypt - fixed prototype
|
||||
- crypt_reencrypt_run - fixed API for deprecated crypt_reencrypt
|
||||
|
||||
The token plugin library interface cosists from these versioned
|
||||
exported symbols (for details see header file and SSH token example):
|
||||
47
docs/v2.4.1-ReleaseNotes
Normal file
47
docs/v2.4.1-ReleaseNotes
Normal file
@@ -0,0 +1,47 @@
|
||||
Cryptsetup 2.4.1 Release Notes
|
||||
==============================
|
||||
Stable bug-fix release with minor extensions.
|
||||
|
||||
All users of cryptsetup 2.4.0 should upgrade to this version.
|
||||
|
||||
Changes since version 2.4.0
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Fix compilation for libc implementations without dlvsym().
|
||||
|
||||
Some alternative libc implementations (like musl) do not provide
|
||||
versioned symbols dlvsym function. Code now fallbacks to dlsym
|
||||
operation for dynamic LUKS2 token load.
|
||||
It is up to maintainers to ensure that LUKS2 token plugins are
|
||||
compiled for the supported version.
|
||||
|
||||
* Fix compilation and tests on systems with non-standard libraries
|
||||
(standalone argp library, external gettext library, BusyBox
|
||||
implementations of standard tools).
|
||||
|
||||
* Try to workaround some issues on systems without udev support.
|
||||
NOTE: non-udev systems cannot provide all functionality for kernel
|
||||
device-mapper, and some operations can fail.
|
||||
|
||||
* Fixes for OpenSSL3 crypto backend (including FIPS mode).
|
||||
Because cryptsetup still requires some hash functions implemented
|
||||
in OpenSSL3 legacy provider, crypto backend now uses its library
|
||||
context and tries to load both default and legacy OpenSSL3 providers.
|
||||
|
||||
If FIPS mode is detected, no library context is used, and it is up
|
||||
to the OpenSSL system-wide policy to load proper providers.
|
||||
|
||||
NOTE: We still use some deprecated API in the OpenSSL3 backend,
|
||||
and there are some known problems in OpenSSL 3.0.0.
|
||||
|
||||
* Print error message when assigning a token to an inactive keyslot.
|
||||
|
||||
* Fix offset bug in LUKS2 encryption code if --offset option was used.
|
||||
|
||||
* Do not allow LUKS2 decryption for devices with data offset.
|
||||
Such devices cannot be used after decryption.
|
||||
|
||||
* Fix LUKS1 cryptsetup repair command for some specific problems.
|
||||
Repair code can now fix wrongly used initialization vector
|
||||
specification in ECB mode (that is insecure anyway!) and repair
|
||||
the upper-case hash specification in the LUKS1 header.
|
||||
37
docs/v2.4.2-ReleaseNotes
Normal file
37
docs/v2.4.2-ReleaseNotes
Normal file
@@ -0,0 +1,37 @@
|
||||
Cryptsetup 2.4.2 Release Notes
|
||||
==============================
|
||||
Stable bug-fix release.
|
||||
|
||||
All users of cryptsetup 2.4.1 should upgrade to this version.
|
||||
|
||||
Changes since version 2.4.1
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Fix possible large memory allocation if LUKS2 header size is invalid.
|
||||
LUKS2 code read the full header to buffer to verify the checksum.
|
||||
The maximal supported header size now limits the memory allocation.
|
||||
|
||||
* Fix memory corruption in debug message printing LUKS2 checksum.
|
||||
|
||||
* veritysetup: remove link to the UUID library for the static build.
|
||||
|
||||
* Remove link to pwquality library for integritysetup and veritysetup.
|
||||
These tools do not read passphrases.
|
||||
|
||||
* OpenSSL3 backend: avoid remaining deprecated calls in API.
|
||||
Crypto backend no longer use API deprecated in OpenSSL 3.0
|
||||
|
||||
|
||||
* Check if kernel device-mapper create device failed in an early phase.
|
||||
This happens when a concurrent creation of device-mapper devices
|
||||
meets in the very early state.
|
||||
|
||||
* Do not set compiler optimization flag for Argon2 KDF if the memory
|
||||
wipe is implemented in libc.
|
||||
|
||||
* Do not attempt to unload LUKS2 tokens if external tokens are disabled.
|
||||
This allows building a static binary with --disable-external-tokens.
|
||||
|
||||
* LUKS convert: also check sysfs for device activity.
|
||||
If udev symlink is missing, code fallbacks to sysfs scan to prevent
|
||||
data corruption for the active device.
|
||||
101
docs/v2.4.3-ReleaseNotes
Normal file
101
docs/v2.4.3-ReleaseNotes
Normal file
@@ -0,0 +1,101 @@
|
||||
Cryptsetup 2.4.3 Release Notes
|
||||
==============================
|
||||
Stable security bug-fix release that fixes CVE-2021-4122.
|
||||
|
||||
All users of cryptsetup 2.4.x must upgrade to this version.
|
||||
|
||||
Changes since version 2.4.2
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Fix possible attacks against data confidentiality through LUKS2 online
|
||||
reencryption extension crash recovery (CVE-2021-4122).
|
||||
|
||||
An attacker can modify on-disk metadata to simulate decryption in
|
||||
progress with crashed (unfinished) reencryption step and persistently
|
||||
decrypt part of the LUKS device.
|
||||
|
||||
This attack requires repeated physical access to the LUKS device but
|
||||
no knowledge of user passphrases.
|
||||
|
||||
The decryption step is performed after a valid user activates
|
||||
the device with a correct passphrase and modified metadata.
|
||||
There are no visible warnings for the user that such recovery happened
|
||||
(except using the luksDump command). The attack can also be reversed
|
||||
afterward (simulating crashed encryption from a plaintext) with
|
||||
possible modification of revealed plaintext.
|
||||
|
||||
The size of possible decrypted data depends on configured LUKS2 header
|
||||
size (metadata size is configurable for LUKS2).
|
||||
With the default parameters (16 MiB LUKS2 header) and only one
|
||||
allocated keyslot (512 bit key for AES-XTS), simulated decryption with
|
||||
checksum resilience SHA1 (20 bytes checksum for 4096-byte blocks),
|
||||
the maximal decrypted size can be over 3GiB.
|
||||
|
||||
The attack is not applicable to LUKS1 format, but the attacker can
|
||||
update metadata in place to LUKS2 format as an additional step.
|
||||
For such a converted LUKS2 header, the keyslot area is limited to
|
||||
decrypted size (with SHA1 checksums) over 300 MiB.
|
||||
|
||||
The issue is present in all cryptsetup releases since 2.2.0.
|
||||
Versions 1.x, 2.0.x, and 2.1.x are not affected, as these do not
|
||||
contain LUKS2 reencryption extension.
|
||||
|
||||
The problem was caused by reusing a mechanism designed for actual
|
||||
reencryption operation without reassessing the security impact for new
|
||||
encryption and decryption operations. While the reencryption requires
|
||||
calculating and verifying both key digests, no digest was needed to
|
||||
initiate decryption recovery if the destination is plaintext (no
|
||||
encryption key). Also, some metadata (like encryption cipher) is not
|
||||
protected, and an attacker could change it. Note that LUKS2 protects
|
||||
visible metadata only when a random change occurs. It does not protect
|
||||
against intentional modification but such modification must not cause
|
||||
a violation of data confidentiality.
|
||||
|
||||
The fix introduces additional digest protection of reencryption
|
||||
metadata. The digest is calculated from known keys and critical
|
||||
reencryption metadata. Now an attacker cannot create correct metadata
|
||||
digest without knowledge of a passphrase for used keyslots.
|
||||
For more details, see LUKS2 On-Disk Format Specification version 1.1.0.
|
||||
|
||||
The former reencryption operation (without the additional digest) is no
|
||||
longer supported (reencryption with the digest is not backward
|
||||
compatible). You need to finish in-progress reencryption before
|
||||
updating to new packages. The alternative approach is to perform
|
||||
a repair command from the updated package to recalculate reencryption
|
||||
digest and fix metadata.
|
||||
The reencryption repair operation always require a user passphrase.
|
||||
|
||||
WARNING: Devices with older reencryption in progress can be no longer
|
||||
activated without performing the action mentioned above.
|
||||
|
||||
Encryption in progress can be detected by running the luksDump command
|
||||
(output includes reencrypt keyslot with reencryption parameters). Also,
|
||||
during the active reencryption, no keyslot operations are available
|
||||
(change of passphrases, etc.).
|
||||
|
||||
The issue was found by Milan Broz as cryptsetup maintainer.
|
||||
|
||||
Other changes
|
||||
~~~~~~~~~~~~~
|
||||
* Add configure option --disable-luks2-reencryption to completely disable
|
||||
LUKS2 reencryption code.
|
||||
|
||||
When used, the libcryptsetup library can read metadata with
|
||||
reencryption code, but all reencryption API calls and cryptsetup
|
||||
reencrypt commands are disabled.
|
||||
|
||||
Devices with online reencryption in progress cannot be activated.
|
||||
This option can cause some incompatibilities. Please use with care.
|
||||
|
||||
* Improve internal metadata validation code for reencryption metadata.
|
||||
|
||||
* Add updated documentation for LUKS2 On-Disk Format Specification
|
||||
version 1.1.0 (with reencryption extension description and updated
|
||||
metadata description). See docs/on-disk-format-luks2.pdf or online
|
||||
version in https://gitlab.com/cryptsetup/LUKS2-docs repository.
|
||||
|
||||
* Fix support for bitlk (BitLocker compatible) startup key with new
|
||||
metadata entry introduced in Windows 11.
|
||||
|
||||
* Fix space restriction for LUKS2 reencryption with data shift.
|
||||
The code required more space than was needed.
|
||||
@@ -32,7 +32,9 @@ libcryptsetup_la_LIBADD = \
|
||||
@LIBARGON2_LIBS@ \
|
||||
@JSON_C_LIBS@ \
|
||||
@BLKID_LIBS@ \
|
||||
@DL_LIBS@ \
|
||||
$(LTLIBICONV) \
|
||||
$(LTLIBINTL) \
|
||||
libcrypto_backend.la \
|
||||
libutils_io.la
|
||||
|
||||
@@ -98,6 +100,7 @@ libcryptsetup_la_SOURCES = \
|
||||
lib/luks2/luks2_keyslot_luks2.c \
|
||||
lib/luks2/luks2_keyslot_reenc.c \
|
||||
lib/luks2/luks2_reencrypt.c \
|
||||
lib/luks2/luks2_reencrypt_digest.c \
|
||||
lib/luks2/luks2_segment.c \
|
||||
lib/luks2/luks2_token_keyring.c \
|
||||
lib/luks2/luks2_token.c \
|
||||
|
||||
@@ -869,13 +869,20 @@ static int get_recovery_key(struct crypt_device *cd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_external_key_entry(struct crypt_device *cd, const char *data, int start, int end, struct volume_key **vk)
|
||||
static int parse_external_key_entry(struct crypt_device *cd,
|
||||
const char *data,
|
||||
int start,
|
||||
int end,
|
||||
struct volume_key **vk,
|
||||
const struct bitlk_metadata *params)
|
||||
{
|
||||
uint16_t key_entry_size = 0;
|
||||
uint16_t key_entry_type = 0;
|
||||
uint16_t key_entry_value = 0;
|
||||
size_t key_size = 0;
|
||||
const char *key = NULL;
|
||||
struct bitlk_guid guid;
|
||||
char guid_buf[UUID_STR_LEN] = {0};
|
||||
|
||||
while (end - start > 2) {
|
||||
/* size of this entry */
|
||||
@@ -892,8 +899,7 @@ static int parse_external_key_entry(struct crypt_device *cd, const char *data, i
|
||||
key_entry_type = le16_to_cpu(key_entry_type);
|
||||
key_entry_value = le16_to_cpu(key_entry_value);
|
||||
|
||||
/* only properties should be in this entry */
|
||||
if (key_entry_type != BITLK_ENTRY_TYPE_PROPERTY) {
|
||||
if (key_entry_type != BITLK_ENTRY_TYPE_PROPERTY && key_entry_type != BITLK_ENTRY_TYPE_VOLUME_GUID) {
|
||||
log_err(cd, _("Unexpected metadata entry type '%u' found when parsing external key."), key_entry_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -908,7 +914,15 @@ static int parse_external_key_entry(struct crypt_device *cd, const char *data, i
|
||||
/* optional "ExternalKey" string, we can safely ignore it */
|
||||
} else if (key_entry_value == BITLK_ENTRY_VALUE_STRING)
|
||||
;
|
||||
else {
|
||||
/* GUID of the BitLocker device we are trying to open with this key */
|
||||
else if (key_entry_value == BITLK_ENTRY_VALUE_GUID) {
|
||||
memcpy(&guid, data + start + BITLK_ENTRY_HEADER_LEN, sizeof(struct bitlk_guid));
|
||||
guid_to_string(&guid, guid_buf);
|
||||
if (strcmp(guid_buf, params->guid) != 0) {
|
||||
log_err(cd, _("BEK file GUID '%s' does not match GUID of the volume."), guid_buf);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
log_err(cd, _("Unexpected metadata entry value '%u' found when parsing external key."), key_entry_value);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -925,7 +939,8 @@ static int get_startup_key(struct crypt_device *cd,
|
||||
const char *password,
|
||||
size_t passwordLen,
|
||||
const struct bitlk_vmk *vmk,
|
||||
struct volume_key **su_key)
|
||||
struct volume_key **su_key,
|
||||
const struct bitlk_metadata *params)
|
||||
{
|
||||
struct bitlk_bek_header bek_header = {0};
|
||||
char guid_buf[UUID_STR_LEN] = {0};
|
||||
@@ -947,12 +962,12 @@ static int get_startup_key(struct crypt_device *cd,
|
||||
return -EPERM;
|
||||
|
||||
if (bek_header.metadata_version != 1) {
|
||||
log_err(cd, "Unsupported BEK metadata version %" PRIu32 "", bek_header.metadata_version);
|
||||
log_err(cd, _("Unsupported BEK metadata version %" PRIu32), bek_header.metadata_version);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (bek_header.metadata_size != passwordLen) {
|
||||
log_err(cd, "Unexpected BEK metadata size %" PRIu32 " does not match BEK file length", bek_header.metadata_size);
|
||||
log_err(cd, _("Unexpected BEK metadata size %" PRIu32 " does not match BEK file length"), bek_header.metadata_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -975,7 +990,7 @@ static int get_startup_key(struct crypt_device *cd,
|
||||
if (key_entry_type == BITLK_ENTRY_TYPE_STARTUP_KEY && key_entry_value == BITLK_ENTRY_VALUE_EXTERNAL_KEY) {
|
||||
return parse_external_key_entry(cd, password,
|
||||
BITLK_BEK_FILE_HEADER_LEN + BITLK_ENTRY_HEADER_LEN + BITLK_STARTUP_KEY_HEADER_LEN,
|
||||
passwordLen, su_key);
|
||||
passwordLen, su_key, params);
|
||||
} else {
|
||||
log_err(cd, _("Unexpected metadata entry found when parsing startup key."));
|
||||
log_dbg(cd, "Entry type: %u, entry value: %u", key_entry_type, key_entry_value);
|
||||
@@ -1142,7 +1157,7 @@ int BITLK_get_volume_key(struct crypt_device *cd,
|
||||
if (r)
|
||||
return r;
|
||||
} else if (next_vmk->protection == BITLK_PROTECTION_STARTUP_KEY) {
|
||||
r = get_startup_key(cd, password, passwordLen, next_vmk, &vmk_dec_key);
|
||||
r = get_startup_key(cd, password, passwordLen, next_vmk, &vmk_dec_key, params);
|
||||
if (r) {
|
||||
next_vmk = next_vmk->next;
|
||||
continue;
|
||||
|
||||
@@ -61,6 +61,7 @@ typedef enum {
|
||||
BITLK_ENTRY_TYPE_STARTUP_KEY = 0x0006,
|
||||
BITLK_ENTRY_TYPE_DESCRIPTION = 0x0007,
|
||||
BITLK_ENTRY_TYPE_VOLUME_HEADER = 0x000f,
|
||||
BITLK_ENTRY_TYPE_VOLUME_GUID = 0x0019,
|
||||
} BITLKFVEEntryType;
|
||||
|
||||
typedef enum {
|
||||
@@ -76,6 +77,7 @@ typedef enum {
|
||||
BITLK_ENTRY_VALUE_EXTERNAL_KEY = 0x0009,
|
||||
BITLK_ENTRY_VALUE_OFFSET_SIZE = 0x000f,
|
||||
BITLK_ENTRY_VALUE_RECOVERY_TIME = 0x015,
|
||||
BITLK_ENTRY_VALUE_GUID = 0x0017,
|
||||
} BITLKFVEEntryValue;
|
||||
|
||||
struct bitlk_vmk {
|
||||
|
||||
@@ -120,18 +120,24 @@ void free_memory(const argon2_context *context, uint8_t *memory,
|
||||
}
|
||||
}
|
||||
|
||||
void NOT_OPTIMIZED secure_wipe_memory(void *v, size_t n) {
|
||||
#if defined(_MSC_VER) && VC_GE_2005(_MSC_VER)
|
||||
void secure_wipe_memory(void *v, size_t n) {
|
||||
SecureZeroMemory(v, n);
|
||||
}
|
||||
#elif defined memset_s
|
||||
void secure_wipe_memory(void *v, size_t n) {
|
||||
memset_s(v, n, 0, n);
|
||||
}
|
||||
#elif defined(HAVE_EXPLICIT_BZERO)
|
||||
void secure_wipe_memory(void *v, size_t n) {
|
||||
explicit_bzero(v, n);
|
||||
}
|
||||
#else
|
||||
void NOT_OPTIMIZED secure_wipe_memory(void *v, size_t n) {
|
||||
static void *(*const volatile memset_sec)(void *, int, size_t) = &memset;
|
||||
memset_sec(v, 0, n);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Memory clear flag defaults to true. */
|
||||
int FLAG_clear_internal_memory = 1;
|
||||
|
||||
@@ -31,7 +31,7 @@ struct crypt_hmac;
|
||||
struct crypt_cipher;
|
||||
struct crypt_storage;
|
||||
|
||||
int crypt_backend_init(void);
|
||||
int crypt_backend_init(bool fips);
|
||||
void crypt_backend_destroy(void);
|
||||
|
||||
#define CRYPT_BACKEND_KERNEL (1 << 0) /* Crypto uses kernel part, for benchmark */
|
||||
|
||||
@@ -94,7 +94,7 @@ static void crypt_hash_test_whirlpool_bug(void)
|
||||
crypto_backend_whirlpool_bug = 1;
|
||||
}
|
||||
|
||||
int crypt_backend_init(void)
|
||||
int crypt_backend_init(bool fips __attribute__((unused)))
|
||||
{
|
||||
int r;
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ static int crypt_kernel_socket_init(struct sockaddr_alg *sa, int *tfmfd, int *op
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_backend_init(void)
|
||||
int crypt_backend_init(bool fips __attribute__((unused)))
|
||||
{
|
||||
struct utsname uts;
|
||||
struct sockaddr_alg sa = {
|
||||
|
||||
@@ -213,7 +213,7 @@ static struct hash_alg *_get_alg(const char *name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int crypt_backend_init(void)
|
||||
int crypt_backend_init(bool fips __attribute__((unused)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ static struct hash_alg *_get_alg(const char *name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int crypt_backend_init(void)
|
||||
int crypt_backend_init(bool fips __attribute__((unused)))
|
||||
{
|
||||
int r;
|
||||
|
||||
|
||||
@@ -28,11 +28,6 @@
|
||||
* for all of the code used other than OpenSSL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* HMAC will be later rewritten to a new API from OpenSSL 3
|
||||
*/
|
||||
#define OPENSSL_SUPPRESS_DEPRECATED
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <openssl/evp.h>
|
||||
@@ -41,8 +36,12 @@
|
||||
#include "crypto_backend_internal.h"
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
#include <openssl/provider.h>
|
||||
#include <openssl/kdf.h>
|
||||
#include <openssl/core_names.h>
|
||||
static OSSL_PROVIDER *ossl_legacy = NULL;
|
||||
static OSSL_PROVIDER *ossl_default = NULL;
|
||||
static OSSL_LIB_CTX *ossl_ctx = NULL;
|
||||
static char backend_version[256] = "OpenSSL";
|
||||
#endif
|
||||
|
||||
#define CONST_CAST(x) (x)(uintptr_t)
|
||||
@@ -56,8 +55,14 @@ struct crypt_hash {
|
||||
};
|
||||
|
||||
struct crypt_hmac {
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
EVP_MAC *mac;
|
||||
EVP_MAC_CTX *md;
|
||||
EVP_MAC_CTX *md_org;
|
||||
#else
|
||||
HMAC_CTX *md;
|
||||
const EVP_MD *hash_id;
|
||||
#endif
|
||||
int hash_len;
|
||||
};
|
||||
|
||||
@@ -68,6 +73,7 @@ struct crypt_cipher {
|
||||
struct {
|
||||
EVP_CIPHER_CTX *hd_enc;
|
||||
EVP_CIPHER_CTX *hd_dec;
|
||||
const EVP_CIPHER *cipher_type;
|
||||
size_t iv_length;
|
||||
} lib;
|
||||
} u;
|
||||
@@ -84,9 +90,10 @@ struct hash_alg {
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
|
||||
(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
|
||||
|
||||
static void openssl_backend_init(void)
|
||||
static int openssl_backend_init(bool fips __attribute__((unused)))
|
||||
{
|
||||
OpenSSL_add_all_algorithms();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void openssl_backend_exit(void)
|
||||
@@ -130,46 +137,79 @@ static void HMAC_CTX_free(HMAC_CTX *md)
|
||||
free(md);
|
||||
}
|
||||
#else
|
||||
static void openssl_backend_init(void)
|
||||
static void openssl_backend_exit(void)
|
||||
{
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
if (ossl_legacy)
|
||||
OSSL_PROVIDER_unload(ossl_legacy);
|
||||
if (ossl_default)
|
||||
OSSL_PROVIDER_unload(ossl_default);
|
||||
if (ossl_ctx)
|
||||
OSSL_LIB_CTX_free(ossl_ctx);
|
||||
|
||||
ossl_legacy = NULL;
|
||||
ossl_default = NULL;
|
||||
ossl_ctx = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int openssl_backend_init(bool fips)
|
||||
{
|
||||
/*
|
||||
* OpenSSL >= 3.0.0 provides some algorithms in legacy provider
|
||||
*/
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
OPENSSL_init_crypto(OPENSSL_INIT_NO_ATEXIT, NULL);
|
||||
ossl_legacy = OSSL_PROVIDER_try_load(NULL, "legacy", 0);
|
||||
ossl_default = OSSL_PROVIDER_try_load(NULL, "default", 0);
|
||||
#endif
|
||||
}
|
||||
int r;
|
||||
|
||||
static void openssl_backend_exit(void)
|
||||
{
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
/*
|
||||
* If Destructor was already called, we must not call it again
|
||||
* In FIPS mode we keep default OpenSSL context & global config
|
||||
*/
|
||||
if (OPENSSL_init_crypto(0, NULL) != 0) {
|
||||
OSSL_PROVIDER_unload(ossl_legacy);
|
||||
OSSL_PROVIDER_unload(ossl_default);
|
||||
OPENSSL_cleanup();
|
||||
if (!fips) {
|
||||
ossl_ctx = OSSL_LIB_CTX_new();
|
||||
if (!ossl_ctx)
|
||||
return -EINVAL;
|
||||
|
||||
ossl_default = OSSL_PROVIDER_try_load(ossl_ctx, "default", 0);
|
||||
if (!ossl_default) {
|
||||
OSSL_LIB_CTX_free(ossl_ctx);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Optional */
|
||||
ossl_legacy = OSSL_PROVIDER_try_load(ossl_ctx, "legacy", 0);
|
||||
}
|
||||
|
||||
r = snprintf(backend_version, sizeof(backend_version), "%s %s%s%s",
|
||||
OpenSSL_version(OPENSSL_VERSION),
|
||||
ossl_default ? "[default]" : "",
|
||||
ossl_legacy ? "[legacy]" : "",
|
||||
fips ? "[fips]" : "");
|
||||
|
||||
if (r < 0 || (size_t)r >= sizeof(backend_version)) {
|
||||
openssl_backend_exit();
|
||||
return -EINVAL;
|
||||
}
|
||||
ossl_legacy = NULL;
|
||||
ossl_default = NULL;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *openssl_backend_version(void)
|
||||
{
|
||||
return OpenSSL_version(OPENSSL_VERSION);
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
return backend_version;
|
||||
#else
|
||||
return OpenSSL_version(OPENSSL_VERSION);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
int crypt_backend_init(void)
|
||||
int crypt_backend_init(bool fips)
|
||||
{
|
||||
if (crypto_backend_initialised)
|
||||
return 0;
|
||||
|
||||
openssl_backend_init();
|
||||
if (openssl_backend_init(fips))
|
||||
return -EINVAL;
|
||||
|
||||
crypto_backend_initialised = 1;
|
||||
return 0;
|
||||
@@ -177,7 +217,14 @@ int crypt_backend_init(void)
|
||||
|
||||
void crypt_backend_destroy(void)
|
||||
{
|
||||
/*
|
||||
* If Destructor was already called, we must not call it again
|
||||
*/
|
||||
if (!crypto_backend_initialised)
|
||||
return;
|
||||
|
||||
crypto_backend_initialised = 0;
|
||||
|
||||
openssl_backend_exit();
|
||||
}
|
||||
|
||||
@@ -215,16 +262,51 @@ static const char *crypt_hash_compat_name(const char *name)
|
||||
return hash_name;
|
||||
}
|
||||
|
||||
static const EVP_MD *hash_id_get(const char *name)
|
||||
{
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
return EVP_MD_fetch(ossl_ctx, crypt_hash_compat_name(name), NULL);
|
||||
#else
|
||||
return EVP_get_digestbyname(crypt_hash_compat_name(name));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void hash_id_free(const EVP_MD *hash_id)
|
||||
{
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
EVP_MD_free(CONST_CAST(EVP_MD*)hash_id);
|
||||
#endif
|
||||
}
|
||||
|
||||
static const EVP_CIPHER *cipher_type_get(const char *name)
|
||||
{
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
return EVP_CIPHER_fetch(ossl_ctx, name, NULL);
|
||||
#else
|
||||
return EVP_get_cipherbyname(name);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void cipher_type_free(const EVP_CIPHER *cipher_type)
|
||||
{
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
EVP_CIPHER_free(CONST_CAST(EVP_CIPHER*)cipher_type);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* HASH */
|
||||
int crypt_hash_size(const char *name)
|
||||
{
|
||||
int size;
|
||||
const EVP_MD *hash_id;
|
||||
|
||||
hash_id = EVP_get_digestbyname(crypt_hash_compat_name(name));
|
||||
hash_id = hash_id_get(name);
|
||||
if (!hash_id)
|
||||
return -EINVAL;
|
||||
|
||||
return EVP_MD_size(hash_id);
|
||||
size = EVP_MD_size(hash_id);
|
||||
hash_id_free(hash_id);
|
||||
return size;
|
||||
}
|
||||
|
||||
int crypt_hash_init(struct crypt_hash **ctx, const char *name)
|
||||
@@ -241,7 +323,7 @@ int crypt_hash_init(struct crypt_hash **ctx, const char *name)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
h->hash_id = EVP_get_digestbyname(crypt_hash_compat_name(name));
|
||||
h->hash_id = hash_id_get(name);
|
||||
if (!h->hash_id) {
|
||||
EVP_MD_CTX_free(h->md);
|
||||
free(h);
|
||||
@@ -249,6 +331,7 @@ int crypt_hash_init(struct crypt_hash **ctx, const char *name)
|
||||
}
|
||||
|
||||
if (EVP_DigestInit_ex(h->md, h->hash_id, NULL) != 1) {
|
||||
hash_id_free(h->hash_id);
|
||||
EVP_MD_CTX_free(h->md);
|
||||
free(h);
|
||||
return -EINVAL;
|
||||
@@ -300,6 +383,7 @@ int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
|
||||
|
||||
void crypt_hash_destroy(struct crypt_hash *ctx)
|
||||
{
|
||||
hash_id_free(ctx->hash_id);
|
||||
EVP_MD_CTX_free(ctx->md);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
@@ -315,7 +399,39 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
|
||||
const void *key, size_t key_length)
|
||||
{
|
||||
struct crypt_hmac *h;
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
OSSL_PARAM params[] = {
|
||||
OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, CONST_CAST(void*)name, 0),
|
||||
OSSL_PARAM_END
|
||||
};
|
||||
|
||||
h = malloc(sizeof(*h));
|
||||
if (!h)
|
||||
return -ENOMEM;
|
||||
|
||||
h->mac = EVP_MAC_fetch(ossl_ctx, OSSL_MAC_NAME_HMAC, NULL);
|
||||
if (!h->mac) {
|
||||
free(h);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
h->md = EVP_MAC_CTX_new(h->mac);
|
||||
if (!h->md) {
|
||||
EVP_MAC_free(h->mac);
|
||||
free(h);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (EVP_MAC_init(h->md, key, key_length, params) != 1) {
|
||||
EVP_MAC_CTX_free(h->md);
|
||||
EVP_MAC_free(h->mac);
|
||||
free(h);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
h->hash_len = EVP_MAC_CTX_get_mac_size(h->md);
|
||||
h->md_org = EVP_MAC_CTX_dup(h->md);
|
||||
#else
|
||||
h = malloc(sizeof(*h));
|
||||
if (!h)
|
||||
return -ENOMEM;
|
||||
@@ -326,7 +442,7 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
h->hash_id = EVP_get_digestbyname(crypt_hash_compat_name(name));
|
||||
h->hash_id = hash_id_get(name);
|
||||
if (!h->hash_id) {
|
||||
HMAC_CTX_free(h->md);
|
||||
free(h);
|
||||
@@ -336,45 +452,75 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
|
||||
HMAC_Init_ex(h->md, key, key_length, h->hash_id, NULL);
|
||||
|
||||
h->hash_len = EVP_MD_size(h->hash_id);
|
||||
#endif
|
||||
*ctx = h;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void crypt_hmac_restart(struct crypt_hmac *ctx)
|
||||
static int crypt_hmac_restart(struct crypt_hmac *ctx)
|
||||
{
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
EVP_MAC_CTX_free(ctx->md);
|
||||
ctx->md = EVP_MAC_CTX_dup(ctx->md_org);
|
||||
if (!ctx->md)
|
||||
return -EINVAL;
|
||||
#else
|
||||
HMAC_Init_ex(ctx->md, NULL, 0, ctx->hash_id, NULL);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hmac_write(struct crypt_hmac *ctx, const char *buffer, size_t length)
|
||||
{
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
return EVP_MAC_update(ctx->md, (const unsigned char *)buffer, length) == 1 ? 0 : -EINVAL;
|
||||
#else
|
||||
HMAC_Update(ctx->md, (const unsigned char *)buffer, length);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
|
||||
{
|
||||
unsigned char tmp[EVP_MAX_MD_SIZE];
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
size_t tmp_len = 0;
|
||||
|
||||
if (length > (size_t)ctx->hash_len)
|
||||
return -EINVAL;
|
||||
|
||||
if (EVP_MAC_final(ctx->md, tmp, &tmp_len, sizeof(tmp)) != 1)
|
||||
return -EINVAL;
|
||||
#else
|
||||
unsigned int tmp_len = 0;
|
||||
|
||||
if (length > (size_t)ctx->hash_len)
|
||||
return -EINVAL;
|
||||
|
||||
HMAC_Final(ctx->md, tmp, &tmp_len);
|
||||
|
||||
#endif
|
||||
memcpy(buffer, tmp, length);
|
||||
crypt_backend_memzero(tmp, sizeof(tmp));
|
||||
|
||||
if (tmp_len < length)
|
||||
return -EINVAL;
|
||||
|
||||
crypt_hmac_restart(ctx);
|
||||
if (crypt_hmac_restart(ctx))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void crypt_hmac_destroy(struct crypt_hmac *ctx)
|
||||
{
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
EVP_MAC_CTX_free(ctx->md);
|
||||
EVP_MAC_CTX_free(ctx->md_org);
|
||||
EVP_MAC_free(ctx->mac);
|
||||
#else
|
||||
hash_id_free(ctx->hash_id);
|
||||
HMAC_CTX_free(ctx->md);
|
||||
#endif
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
}
|
||||
@@ -389,48 +535,91 @@ int crypt_backend_rng(char *buffer, size_t length,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int openssl_pbkdf2(const char *password, size_t password_length,
|
||||
const char *salt, size_t salt_length, uint32_t iterations,
|
||||
const char *hash, char *key, size_t key_length)
|
||||
{
|
||||
int r;
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
EVP_KDF_CTX *ctx;
|
||||
EVP_KDF *pbkdf2;
|
||||
OSSL_PARAM params[] = {
|
||||
OSSL_PARAM_octet_string(OSSL_KDF_PARAM_PASSWORD,
|
||||
CONST_CAST(void*)password, password_length),
|
||||
OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SALT,
|
||||
CONST_CAST(void*)salt, salt_length),
|
||||
OSSL_PARAM_uint32(OSSL_KDF_PARAM_ITER, &iterations),
|
||||
OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_DIGEST,
|
||||
CONST_CAST(void*)hash, 0),
|
||||
OSSL_PARAM_END
|
||||
};
|
||||
|
||||
pbkdf2 = EVP_KDF_fetch(ossl_ctx, "pbkdf2", NULL);
|
||||
if (!pbkdf2)
|
||||
return -EINVAL;
|
||||
|
||||
ctx = EVP_KDF_CTX_new(pbkdf2);
|
||||
if (!ctx) {
|
||||
EVP_KDF_free(pbkdf2);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = EVP_KDF_derive(ctx, (unsigned char*)key, key_length, params);
|
||||
|
||||
EVP_KDF_CTX_free(ctx);
|
||||
EVP_KDF_free(pbkdf2);
|
||||
#else
|
||||
const EVP_MD *hash_id = EVP_get_digestbyname(crypt_hash_compat_name(hash));
|
||||
if (!hash_id)
|
||||
return -EINVAL;
|
||||
|
||||
r = PKCS5_PBKDF2_HMAC(password, (int)password_length, (const unsigned char *)salt,
|
||||
(int)salt_length, iterations, hash_id, (int)key_length, (unsigned char*) key);
|
||||
#endif
|
||||
return r == 1 ? 0 : -EINVAL;
|
||||
}
|
||||
|
||||
static int openssl_argon2(const char *type, const char *password, size_t password_length,
|
||||
const char *salt, size_t salt_length, char *key, size_t key_length,
|
||||
uint32_t iterations, uint32_t memory, uint32_t parallel)
|
||||
{
|
||||
return argon2(type, password, password_length, salt, salt_length,
|
||||
key, key_length, iterations, memory, parallel);
|
||||
}
|
||||
|
||||
/* PBKDF */
|
||||
int crypt_pbkdf(const char *kdf, const char *hash,
|
||||
const char *password, size_t password_length,
|
||||
const char *salt, size_t salt_length,
|
||||
char *key, size_t key_length,
|
||||
uint32_t iterations, uint32_t memory, uint32_t parallel)
|
||||
|
||||
{
|
||||
const EVP_MD *hash_id;
|
||||
|
||||
if (!kdf)
|
||||
return -EINVAL;
|
||||
|
||||
if (!strcmp(kdf, "pbkdf2")) {
|
||||
hash_id = EVP_get_digestbyname(crypt_hash_compat_name(hash));
|
||||
if (!hash_id)
|
||||
return -EINVAL;
|
||||
|
||||
if (!PKCS5_PBKDF2_HMAC(password, (int)password_length,
|
||||
(const unsigned char *)salt, (int)salt_length,
|
||||
(int)iterations, hash_id, (int)key_length, (unsigned char *)key))
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
} else if (!strncmp(kdf, "argon2", 6)) {
|
||||
return argon2(kdf, password, password_length, salt, salt_length,
|
||||
key, key_length, iterations, memory, parallel);
|
||||
}
|
||||
|
||||
if (!strcmp(kdf, "pbkdf2"))
|
||||
return openssl_pbkdf2(password, password_length, salt, salt_length,
|
||||
iterations, hash, key, key_length);
|
||||
if (!strncmp(kdf, "argon2", 6))
|
||||
return openssl_argon2(kdf, password, password_length, salt, salt_length,
|
||||
key, key_length, iterations, memory, parallel);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Block ciphers */
|
||||
static void _cipher_destroy(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec)
|
||||
static void _cipher_destroy(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec, const EVP_CIPHER **cipher_type)
|
||||
{
|
||||
EVP_CIPHER_CTX_free(*hd_enc);
|
||||
*hd_enc = NULL;
|
||||
|
||||
EVP_CIPHER_CTX_free(*hd_dec);
|
||||
*hd_dec = NULL;
|
||||
|
||||
cipher_type_free(*cipher_type);
|
||||
*cipher_type = NULL;
|
||||
}
|
||||
|
||||
static int _cipher_init(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec, const char *name,
|
||||
static int _cipher_init(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec, const EVP_CIPHER **cipher_type, const char *name,
|
||||
const char *mode, const void *key, size_t key_length, size_t *iv_length)
|
||||
{
|
||||
char cipher_name[256];
|
||||
@@ -445,32 +634,38 @@ static int _cipher_init(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec, const
|
||||
if (r < 0 || (size_t)r >= sizeof(cipher_name))
|
||||
return -EINVAL;
|
||||
|
||||
type = EVP_get_cipherbyname(cipher_name);
|
||||
type = cipher_type_get(cipher_name);
|
||||
if (!type)
|
||||
return -ENOENT;
|
||||
|
||||
if (EVP_CIPHER_key_length(type) != (int)key_length)
|
||||
if (EVP_CIPHER_key_length(type) != (int)key_length) {
|
||||
cipher_type_free(type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*hd_enc = EVP_CIPHER_CTX_new();
|
||||
*hd_dec = EVP_CIPHER_CTX_new();
|
||||
*iv_length = EVP_CIPHER_iv_length(type);
|
||||
|
||||
if (!*hd_enc || !*hd_dec)
|
||||
if (!*hd_enc || !*hd_dec) {
|
||||
cipher_type_free(type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (EVP_EncryptInit_ex(*hd_enc, type, NULL, key, NULL) != 1 ||
|
||||
EVP_DecryptInit_ex(*hd_dec, type, NULL, key, NULL) != 1) {
|
||||
_cipher_destroy(hd_enc, hd_dec);
|
||||
_cipher_destroy(hd_enc, hd_dec, &type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (EVP_CIPHER_CTX_set_padding(*hd_enc, 0) != 1 ||
|
||||
EVP_CIPHER_CTX_set_padding(*hd_dec, 0) != 1) {
|
||||
_cipher_destroy(hd_enc, hd_dec);
|
||||
_cipher_destroy(hd_enc, hd_dec, &type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*cipher_type = type;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -484,7 +679,7 @@ int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
|
||||
if (!h)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!_cipher_init(&h->u.lib.hd_enc, &h->u.lib.hd_dec, name, mode, key,
|
||||
if (!_cipher_init(&h->u.lib.hd_enc, &h->u.lib.hd_dec, &h->u.lib.cipher_type, name, mode, key,
|
||||
key_length, &h->u.lib.iv_length)) {
|
||||
h->use_kernel = false;
|
||||
*ctx = h;
|
||||
@@ -507,7 +702,7 @@ void crypt_cipher_destroy(struct crypt_cipher *ctx)
|
||||
if (ctx->use_kernel)
|
||||
crypt_cipher_destroy_kernel(&ctx->u.kernel);
|
||||
else
|
||||
_cipher_destroy(&ctx->u.lib.hd_enc, &ctx->u.lib.hd_dec);
|
||||
_cipher_destroy(&ctx->u.lib.hd_enc, &ctx->u.lib.hd_dec, &ctx->u.lib.cipher_type);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
|
||||
@@ -129,9 +129,10 @@ void crypt_free(struct crypt_device *cd);
|
||||
* other values mean accepted.
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param confirm user defined confirm callback reference
|
||||
* @param confirm user defined confirm callback reference; use
|
||||
* @p msg for message for user to confirm and
|
||||
* @p usrptr for identification in callback
|
||||
* @param usrptr provided identification in callback
|
||||
* @param msg Message for user to confirm
|
||||
*
|
||||
* @note Current version of cryptsetup API requires confirmation for UUID change and
|
||||
* LUKS header restore only.
|
||||
@@ -196,10 +197,11 @@ int crypt_set_data_offset(struct crypt_device *cd, uint64_t data_offset);
|
||||
* Set log function.
|
||||
*
|
||||
* @param cd crypt device handle (can be @e NULL to set default log function)
|
||||
* @param log user defined log function reference
|
||||
* @param log user defined log function reference; use
|
||||
* @p level for log level,
|
||||
* @p msg for message, and
|
||||
* @p usrptr for identification in callback
|
||||
* @param usrptr provided identification in callback
|
||||
* @param level log level below (debug messages can uses other levels)
|
||||
* @param msg log message
|
||||
*/
|
||||
void crypt_set_log_callback(struct crypt_device *cd,
|
||||
void (*log)(int level, const char *msg, void *usrptr),
|
||||
@@ -2285,15 +2287,20 @@ const char *crypt_token_external_path(void);
|
||||
*/
|
||||
void crypt_token_external_disable(void);
|
||||
|
||||
/** ABI version for external token in libcryptsetup-token-<name>.so */
|
||||
/** ABI version for external token in libcryptsetup-token-[name].so */
|
||||
#define CRYPT_TOKEN_ABI_VERSION1 "CRYPTSETUP_TOKEN_1.0"
|
||||
|
||||
/** ABI exported symbol for external token */
|
||||
#define CRYPT_TOKEN_ABI_OPEN "cryptsetup_token_open" /* mandatory */
|
||||
/** open by token - ABI exported symbol for external token (mandatory) */
|
||||
#define CRYPT_TOKEN_ABI_OPEN "cryptsetup_token_open"
|
||||
/** open by token with PIN - ABI exported symbol for external token */
|
||||
#define CRYPT_TOKEN_ABI_OPEN_PIN "cryptsetup_token_open_pin"
|
||||
/** deallocate callback - ABI exported symbol for external token */
|
||||
#define CRYPT_TOKEN_ABI_BUFFER_FREE "cryptsetup_token_buffer_free"
|
||||
/** validate token metadata - ABI exported symbol for external token */
|
||||
#define CRYPT_TOKEN_ABI_VALIDATE "cryptsetup_token_validate"
|
||||
/** dump token metadata - ABI exported symbol for external token */
|
||||
#define CRYPT_TOKEN_ABI_DUMP "cryptsetup_token_dump"
|
||||
/** token version - ABI exported symbol for external token */
|
||||
#define CRYPT_TOKEN_ABI_VERSION "cryptsetup_token_version"
|
||||
|
||||
/**
|
||||
@@ -2319,7 +2326,7 @@ void crypt_token_external_disable(void);
|
||||
* @note Negative EAGAIN errno means token handler requires additional hardware
|
||||
* not present in the system.
|
||||
*
|
||||
* @note with @param token set to CRYPT_ANY_TOKEN libcryptsetup runs best effort loop
|
||||
* @note with @e token set to CRYPT_ANY_TOKEN libcryptsetup runs best effort loop
|
||||
* to unlock device using any available token. It may happen that various token handlers
|
||||
* return different error codes. At the end loop returns error codes in the following
|
||||
* order (from the most significant to the least) any negative errno except those
|
||||
@@ -2357,7 +2364,7 @@ int crypt_activate_by_token(struct crypt_device *cd,
|
||||
* @note Negative EAGAIN errno means token handler requires additional hardware
|
||||
* not present in the system.
|
||||
*
|
||||
* @note with @param token set to CRYPT_ANY_TOKEN libcryptsetup runs best effort loop
|
||||
* @note with @e token set to CRYPT_ANY_TOKEN libcryptsetup runs best effort loop
|
||||
* to unlock device using any available token. It may happen that various token handlers
|
||||
* return different error codes. At the end loop returns error codes in the following
|
||||
* order (from the most significant to the least) any negative errno except those
|
||||
@@ -2390,6 +2397,8 @@ int crypt_activate_by_token_pin(struct crypt_device *cd,
|
||||
#define CRYPT_REENCRYPT_RESUME_ONLY (1 << 2)
|
||||
/** Run reencryption recovery only. (in) */
|
||||
#define CRYPT_REENCRYPT_RECOVERY (1 << 3)
|
||||
/** Reencryption requires metadata protection. (in/out) */
|
||||
#define CRYPT_REENCRYPT_REPAIR_NEEDED (1 << 4)
|
||||
|
||||
/**
|
||||
* Reencryption direction
|
||||
|
||||
@@ -1243,7 +1243,7 @@ static int dm_prepare_uuid(struct crypt_device *cd, const char *name, const char
|
||||
|
||||
int lookup_dm_dev_by_uuid(struct crypt_device *cd, const char *uuid, const char *type)
|
||||
{
|
||||
int r;
|
||||
int r_udev, r;
|
||||
char *c;
|
||||
char dev_uuid[DM_UUID_LEN + DM_BY_ID_PREFIX_LEN] = DM_BY_ID_PREFIX;
|
||||
|
||||
@@ -1257,13 +1257,16 @@ int lookup_dm_dev_by_uuid(struct crypt_device *cd, const char *uuid, const char
|
||||
/* cut of dm name */
|
||||
*c = '\0';
|
||||
|
||||
/* Either udev or sysfs can report that device is active. */
|
||||
r = lookup_by_disk_id(dev_uuid);
|
||||
if (r == -ENOENT) {
|
||||
log_dbg(cd, "Search by disk id not available. Using sysfs instead.");
|
||||
r = lookup_by_sysfs_uuid_field(dev_uuid + DM_BY_ID_PREFIX_LEN);
|
||||
}
|
||||
if (r > 0)
|
||||
return r;
|
||||
|
||||
return r;
|
||||
r_udev = r;
|
||||
if (r_udev <= 0)
|
||||
r = lookup_by_sysfs_uuid_field(dev_uuid + DM_BY_ID_PREFIX_LEN);
|
||||
|
||||
return r == -ENOENT ? r_udev : r;
|
||||
}
|
||||
|
||||
static int _add_dm_targets(struct dm_task *dmt, struct crypt_dm_active_device *dmd)
|
||||
@@ -1346,12 +1349,6 @@ err:
|
||||
return r;
|
||||
}
|
||||
|
||||
static bool dm_device_exists(struct crypt_device *cd, const char *name)
|
||||
{
|
||||
int r = dm_status_device(cd, name);
|
||||
return (r >= 0 || r == -EEXIST);
|
||||
}
|
||||
|
||||
static int _dm_create_device(struct crypt_device *cd, const char *name, const char *type,
|
||||
struct crypt_dm_active_device *dmd)
|
||||
{
|
||||
@@ -1402,8 +1399,11 @@ static int _dm_create_device(struct crypt_device *cd, const char *name, const ch
|
||||
goto out;
|
||||
|
||||
if (!dm_task_run(dmt)) {
|
||||
if (dm_device_exists(cd, name))
|
||||
r = dm_status_device(cd, name);;
|
||||
if (r >= 0)
|
||||
r = -EEXIST;
|
||||
if (r != -EEXIST && r != -ENODEV)
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -2303,16 +2303,16 @@ static int _dm_target_query_verity(struct crypt_device *cd,
|
||||
str = strsep(¶ms, " ");
|
||||
if (!str)
|
||||
goto err;
|
||||
if (!root_hash_sig_key_desc) {
|
||||
if (vp && !root_hash_sig_key_desc) {
|
||||
root_hash_sig_key_desc = strdup(str);
|
||||
if (!root_hash_sig_key_desc) {
|
||||
r = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
/* not stored in params, but cannot be used without vp */
|
||||
vp->flags |= CRYPT_VERITY_ROOT_HASH_SIGNATURE;
|
||||
}
|
||||
i++;
|
||||
if (vp)
|
||||
vp->flags |= CRYPT_VERITY_ROOT_HASH_SIGNATURE;
|
||||
} else /* unknown option */
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -65,6 +65,27 @@ static void LUKS_sort_keyslots(const struct luks_phdr *hdr, int *array)
|
||||
}
|
||||
}
|
||||
|
||||
static int _is_not_lower(char *str, unsigned max_len)
|
||||
{
|
||||
for(; *str && max_len; str++, max_len--)
|
||||
if (isupper(*str))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _to_lower(char *str, unsigned max_len)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
for(; *str && max_len; str++, max_len--)
|
||||
if (isupper(*str)) {
|
||||
*str = tolower(*str);
|
||||
r = 1;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
size_t LUKS_device_sectors(const struct luks_phdr *hdr)
|
||||
{
|
||||
int sorted_areas[LUKS_NUMKEYS] = { 0, 1, 2, 3, 4, 5, 6, 7 };
|
||||
@@ -385,6 +406,30 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* ECB mode does not use IV but legacy dmcrypt silently allows it.
|
||||
* Today device cannot be activated anyway, so we need to fix it here.
|
||||
*/
|
||||
if (!strncmp(phdr->cipherMode, "ecb-", 4)) {
|
||||
log_err(ctx, _("Cipher mode repaired (%s -> %s)."), phdr->cipherMode, "ecb");
|
||||
memset(phdr->cipherMode, 0, LUKS_CIPHERMODE_L);
|
||||
strcpy(phdr->cipherMode, "ecb");
|
||||
need_write = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Old cryptsetup expects "sha1", gcrypt allows case insensitive names,
|
||||
* so always convert hash to lower case in header
|
||||
*/
|
||||
if (_to_lower(phdr->hashSpec, LUKS_HASHSPEC_L)) {
|
||||
log_err(ctx, _("Cipher hash repaired to lowercase (%s)."), phdr->hashSpec);
|
||||
if (crypt_hmac_size(phdr->hashSpec) < LUKS_DIGESTSIZE) {
|
||||
log_err(ctx, _("Requested LUKS hash %s is not supported."), phdr->hashSpec);
|
||||
return -EINVAL;
|
||||
}
|
||||
need_write = 1;
|
||||
}
|
||||
|
||||
r = LUKS_check_cipher(ctx, phdr->keyBytes, phdr->cipherName, phdr->cipherMode);
|
||||
if (r < 0)
|
||||
return -EINVAL;
|
||||
@@ -486,7 +531,7 @@ static int _check_and_convert_hdr(const char *device,
|
||||
hdr->hashSpec[LUKS_HASHSPEC_L - 1] = '\0';
|
||||
if (crypt_hmac_size(hdr->hashSpec) < LUKS_DIGESTSIZE) {
|
||||
log_err(ctx, _("Requested LUKS hash %s is not supported."), hdr->hashSpec);
|
||||
return -EINVAL;
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
||||
/* Header detected */
|
||||
@@ -510,6 +555,16 @@ static int _check_and_convert_hdr(const char *device,
|
||||
hdr->uuid[UUID_STRING_L - 1] = '\0';
|
||||
|
||||
if (repair) {
|
||||
if (!strncmp(hdr->cipherMode, "ecb-", 4)) {
|
||||
log_err(ctx, _("LUKS cipher mode %s is invalid."), hdr->cipherMode);
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
||||
if (_is_not_lower(hdr->hashSpec, LUKS_HASHSPEC_L)) {
|
||||
log_err(ctx, _("LUKS hash %s is invalid."), hdr->hashSpec);
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
||||
if (r == -EINVAL)
|
||||
r = _keyslot_repair(hdr, ctx);
|
||||
else
|
||||
@@ -519,27 +574,6 @@ static int _check_and_convert_hdr(const char *device,
|
||||
return r;
|
||||
}
|
||||
|
||||
static void _to_lower(char *str, unsigned max_len)
|
||||
{
|
||||
for(; *str && max_len; str++, max_len--)
|
||||
if (isupper(*str))
|
||||
*str = tolower(*str);
|
||||
}
|
||||
|
||||
static void LUKS_fix_header_compatible(struct luks_phdr *header)
|
||||
{
|
||||
/* Old cryptsetup expects "sha1", gcrypt allows case insensitive names,
|
||||
* so always convert hash to lower case in header */
|
||||
_to_lower(header->hashSpec, LUKS_HASHSPEC_L);
|
||||
|
||||
/* ECB mode does not use IV but dmcrypt silently allows it.
|
||||
* Drop any IV here if ECB is used (that is not secure anyway).*/
|
||||
if (!strncmp(header->cipherMode, "ecb-", 4)) {
|
||||
memset(header->cipherMode, 0, LUKS_CIPHERMODE_L);
|
||||
strcpy(header->cipherMode, "ecb");
|
||||
}
|
||||
}
|
||||
|
||||
int LUKS_read_phdr_backup(const char *backup_file,
|
||||
struct luks_phdr *hdr,
|
||||
int require_luks_device,
|
||||
@@ -559,11 +593,9 @@ int LUKS_read_phdr_backup(const char *backup_file,
|
||||
|
||||
if (read_buffer(devfd, hdr, hdr_size) < hdr_size)
|
||||
r = -EIO;
|
||||
else {
|
||||
LUKS_fix_header_compatible(hdr);
|
||||
else
|
||||
r = _check_and_convert_hdr(backup_file, hdr,
|
||||
require_luks_device, 0, ctx);
|
||||
}
|
||||
|
||||
close(devfd);
|
||||
return r;
|
||||
@@ -771,11 +803,10 @@ int LUKS_generate_phdr(struct luks_phdr *header,
|
||||
strncpy(header->cipherName,cipherName,LUKS_CIPHERNAME_L-1);
|
||||
strncpy(header->cipherMode,cipherMode,LUKS_CIPHERMODE_L-1);
|
||||
strncpy(header->hashSpec,hashSpec,LUKS_HASHSPEC_L-1);
|
||||
_to_lower(header->hashSpec, LUKS_HASHSPEC_L);
|
||||
|
||||
header->keyBytes=vk->keylength;
|
||||
|
||||
LUKS_fix_header_compatible(header);
|
||||
|
||||
log_dbg(ctx, "Generating LUKS header version %d using hash %s, %s, %s, MK %d bytes",
|
||||
header->version, header->hashSpec ,header->cipherName, header->cipherMode,
|
||||
header->keyBytes);
|
||||
|
||||
@@ -401,6 +401,8 @@ int LUKS2_config_set_flags(struct crypt_device *cd, struct luks2_hdr *hdr, uint3
|
||||
int LUKS2_config_get_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t *reqs);
|
||||
int LUKS2_config_set_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs, bool commit);
|
||||
|
||||
int LUKS2_config_get_reencrypt_version(struct luks2_hdr *hdr, uint32_t *version);
|
||||
|
||||
int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs_mask, int quiet);
|
||||
|
||||
int LUKS2_key_description_by_segment(struct crypt_device *cd,
|
||||
@@ -453,4 +455,8 @@ int LUKS2_reencrypt_check_device_size(struct crypt_device *cd,
|
||||
bool activation,
|
||||
bool dynamic);
|
||||
|
||||
int LUKS2_reencrypt_digest_verify(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
struct volume_key *vks);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -62,8 +62,8 @@ static void log_dbg_checksum(struct crypt_device *cd,
|
||||
int i;
|
||||
|
||||
for (i = 0; i < crypt_hash_size(csum_alg); i++)
|
||||
snprintf(&csum_txt[i*2], 3, "%02hhx", (const char)csum[i]);
|
||||
csum_txt[i*2+1] = '\0'; /* Just to be safe, sprintf should write \0 there. */
|
||||
if (snprintf(&csum_txt[i*2], 3, "%02hhx", (const char)csum[i]) != 2)
|
||||
return;
|
||||
|
||||
log_dbg(cd, "Checksum:%s (%s)", &csum_txt[0], info);
|
||||
}
|
||||
@@ -195,6 +195,8 @@ static int hdr_disk_sanity_check_pre(struct crypt_device *cd,
|
||||
size_t *hdr_json_size, int secondary,
|
||||
uint64_t offset)
|
||||
{
|
||||
uint64_t hdr_size;
|
||||
|
||||
if (memcmp(hdr->magic, secondary ? LUKS2_MAGIC_2ND : LUKS2_MAGIC_1ST, LUKS2_MAGIC_L))
|
||||
return -EINVAL;
|
||||
|
||||
@@ -204,24 +206,31 @@ static int hdr_disk_sanity_check_pre(struct crypt_device *cd,
|
||||
}
|
||||
|
||||
if (offset != be64_to_cpu(hdr->hdr_offset)) {
|
||||
log_dbg(cd, "LUKS2 offset 0x%04x on device differs to expected offset 0x%04x.",
|
||||
(unsigned)be64_to_cpu(hdr->hdr_offset), (unsigned)offset);
|
||||
log_dbg(cd, "LUKS2 offset 0x%04" PRIx64 " on device differs to expected offset 0x%04" PRIx64 ".",
|
||||
be64_to_cpu(hdr->hdr_offset), offset);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (secondary && (offset != be64_to_cpu(hdr->hdr_size))) {
|
||||
log_dbg(cd, "LUKS2 offset 0x%04x in secondary header does not match size 0x%04x.",
|
||||
(unsigned)offset, (unsigned)be64_to_cpu(hdr->hdr_size));
|
||||
hdr_size = be64_to_cpu(hdr->hdr_size);
|
||||
|
||||
if (hdr_size < LUKS2_HDR_16K_LEN || hdr_size > LUKS2_HDR_OFFSET_MAX) {
|
||||
log_dbg(cd, "LUKS2 header has bogus size 0x%04" PRIx64 ".", hdr_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (secondary && (offset != hdr_size)) {
|
||||
log_dbg(cd, "LUKS2 offset 0x%04" PRIx64 " in secondary header does not match size 0x%04" PRIx64 ".",
|
||||
offset, hdr_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* FIXME: sanity check checksum alg. */
|
||||
|
||||
log_dbg(cd, "LUKS2 header version %u of size %u bytes, checksum %s.",
|
||||
(unsigned)be16_to_cpu(hdr->version), (unsigned)be64_to_cpu(hdr->hdr_size),
|
||||
log_dbg(cd, "LUKS2 header version %u of size %" PRIu64 " bytes, checksum %s.",
|
||||
be16_to_cpu(hdr->version), hdr_size,
|
||||
hdr->checksum_alg);
|
||||
|
||||
*hdr_json_size = be64_to_cpu(hdr->hdr_size) - LUKS2_HDR_BIN_LEN;
|
||||
*hdr_json_size = hdr_size - LUKS2_HDR_BIN_LEN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -252,18 +261,19 @@ static int hdr_read_disk(struct crypt_device *cd,
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* hdr_json_size is validated if this call succeeds
|
||||
*/
|
||||
r = hdr_disk_sanity_check_pre(cd, hdr_disk, &hdr_json_size, secondary, offset);
|
||||
if (r < 0) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate and read JSON area. Always the whole area must be read.
|
||||
*/
|
||||
*json_area = malloc(hdr_json_size);
|
||||
if (!*json_area) {
|
||||
if (!*json_area)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
|
||||
device_alignment(device), *json_area, hdr_json_size,
|
||||
@@ -279,6 +289,8 @@ static int hdr_read_disk(struct crypt_device *cd,
|
||||
if (hdr_checksum_check(cd, hdr_disk->checksum_alg, hdr_disk,
|
||||
*json_area, hdr_json_size)) {
|
||||
log_dbg(cd, "LUKS2 header checksum error (offset %" PRIu64 ").", offset);
|
||||
free(*json_area);
|
||||
*json_area = NULL;
|
||||
r = -EINVAL;
|
||||
}
|
||||
memset(hdr_disk->csum, 0, LUKS2_CHECKSUM_L);
|
||||
|
||||
@@ -234,14 +234,20 @@ int LUKS2_keyslot_reencrypt_store(struct crypt_device *cd,
|
||||
const void *buffer,
|
||||
size_t buffer_length);
|
||||
|
||||
int LUKS2_keyslot_reencrypt_create(struct crypt_device *cd,
|
||||
int LUKS2_keyslot_reencrypt_allocate(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
const struct crypt_params_reencrypt *params);
|
||||
|
||||
int LUKS2_keyslot_reencrypt_digest_create(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
struct volume_key *vks);
|
||||
|
||||
int LUKS2_keyslot_dump(struct crypt_device *cd,
|
||||
int keyslot);
|
||||
|
||||
int LUKS2_keyslot_jobj_area(json_object *jobj_keyslot, uint64_t *offset, uint64_t *length);
|
||||
|
||||
/* JSON helpers */
|
||||
uint64_t json_segment_get_offset(json_object *jobj_segment, unsigned blockwise);
|
||||
const char *json_segment_type(json_object *jobj_segment);
|
||||
@@ -257,6 +263,8 @@ uint64_t json_segments_get_minimal_offset(json_object *jobj_segments, unsigned b
|
||||
json_object *json_segment_create_linear(uint64_t offset, const uint64_t *length, unsigned reencryption);
|
||||
json_object *json_segment_create_crypt(uint64_t offset, uint64_t iv_offset, const uint64_t *length, const char *cipher, uint32_t sector_size, unsigned reencryption);
|
||||
int json_segments_segment_in_reencrypt(json_object *jobj_segments);
|
||||
bool json_segment_cmp(json_object *jobj_segment_1, json_object *jobj_segment_2);
|
||||
bool json_segment_contains_flag(json_object *jobj_segment, const char *flag_str, size_t len);
|
||||
|
||||
int LUKS2_assembly_multisegment_dmd(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
|
||||
@@ -592,6 +592,78 @@ static bool validate_segment_intervals(struct crypt_device *cd,
|
||||
return true;
|
||||
}
|
||||
|
||||
static int reqs_unknown(uint32_t reqs)
|
||||
{
|
||||
return reqs & CRYPT_REQUIREMENT_UNKNOWN;
|
||||
}
|
||||
|
||||
static int reqs_reencrypt(uint32_t reqs)
|
||||
{
|
||||
return reqs & CRYPT_REQUIREMENT_OFFLINE_REENCRYPT;
|
||||
}
|
||||
|
||||
static int reqs_reencrypt_online(uint32_t reqs)
|
||||
{
|
||||
return reqs & CRYPT_REQUIREMENT_ONLINE_REENCRYPT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Config section requirements object must be valid.
|
||||
* Also general segments section must be validated first.
|
||||
*/
|
||||
static int validate_reencrypt_segments(struct crypt_device *cd, json_object *hdr_jobj, json_object *jobj_segments, int first_backup, int segments_count)
|
||||
{
|
||||
json_object *jobj, *jobj_backup_previous = NULL, *jobj_backup_final = NULL;
|
||||
uint32_t reqs;
|
||||
int i, r;
|
||||
struct luks2_hdr dummy = {
|
||||
.jobj = hdr_jobj
|
||||
};
|
||||
|
||||
r = LUKS2_config_get_requirements(cd, &dummy, &reqs);
|
||||
if (r)
|
||||
return 1;
|
||||
|
||||
if (reqs_reencrypt_online(reqs)) {
|
||||
for (i = first_backup; i < segments_count; i++) {
|
||||
jobj = json_segments_get_segment(jobj_segments, i);
|
||||
if (!jobj)
|
||||
return 1;
|
||||
if (json_segment_contains_flag(jobj, "backup-final", 0))
|
||||
jobj_backup_final = jobj;
|
||||
else if (json_segment_contains_flag(jobj, "backup-previous", 0))
|
||||
jobj_backup_previous = jobj;
|
||||
}
|
||||
|
||||
if (!jobj_backup_final || !jobj_backup_previous) {
|
||||
log_dbg(cd, "Backup segment is missing.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < first_backup; i++) {
|
||||
jobj = json_segments_get_segment(jobj_segments, i);
|
||||
if (!jobj)
|
||||
return 1;
|
||||
|
||||
if (json_segment_contains_flag(jobj, "in-reencryption", 0)) {
|
||||
if (!json_segment_cmp(jobj, jobj_backup_final)) {
|
||||
log_dbg(cd, "Segment in reencryption does not match backup final segment.");
|
||||
return 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!json_segment_cmp(jobj, jobj_backup_final) &&
|
||||
!json_segment_cmp(jobj, jobj_backup_previous)) {
|
||||
log_dbg(cd, "Segment does not match neither backup final or backup previous segment.");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hdr_validate_segments(struct crypt_device *cd, json_object *hdr_jobj)
|
||||
{
|
||||
json_object *jobj_segments, *jobj_digests, *jobj_offset, *jobj_size, *jobj_type, *jobj_flags, *jobj;
|
||||
@@ -718,7 +790,7 @@ static int hdr_validate_segments(struct crypt_device *cd, json_object *hdr_jobj)
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return validate_reencrypt_segments(cd, hdr_jobj, jobj_segments, first_backup, count);
|
||||
}
|
||||
|
||||
static uint64_t LUKS2_metadata_size_jobj(json_object *jobj)
|
||||
@@ -841,9 +913,10 @@ static int hdr_validate_digests(struct crypt_device *cd, json_object *hdr_jobj)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* requirements being validated in stand-alone routine */
|
||||
static int hdr_validate_config(struct crypt_device *cd, json_object *hdr_jobj)
|
||||
{
|
||||
json_object *jobj_config, *jobj, *jobj1;
|
||||
json_object *jobj_config, *jobj;
|
||||
int i;
|
||||
uint64_t keyslots_size, metadata_size, segment_offset;
|
||||
|
||||
@@ -898,6 +971,19 @@ static int hdr_validate_config(struct crypt_device *cd, json_object *hdr_jobj)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hdr_validate_requirements(struct crypt_device *cd, json_object *hdr_jobj)
|
||||
{
|
||||
int i;
|
||||
json_object *jobj_config, *jobj, *jobj1;
|
||||
|
||||
if (!json_object_object_get_ex(hdr_jobj, "config", &jobj_config)) {
|
||||
log_dbg(cd, "Missing config section.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Requirements object is optional */
|
||||
if (json_object_object_get_ex(jobj_config, "requirements", &jobj)) {
|
||||
if (!json_contains(cd, jobj_config, "section", "Config", "requirements", json_type_object))
|
||||
@@ -923,6 +1009,7 @@ int LUKS2_hdr_validate(struct crypt_device *cd, json_object *hdr_jobj, uint64_t
|
||||
struct {
|
||||
int (*validate)(struct crypt_device *, json_object *);
|
||||
} checks[] = {
|
||||
{ hdr_validate_requirements },
|
||||
{ hdr_validate_tokens },
|
||||
{ hdr_validate_digests },
|
||||
{ hdr_validate_segments },
|
||||
@@ -1139,21 +1226,6 @@ int LUKS2_hdr_backup(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
return r;
|
||||
}
|
||||
|
||||
static int reqs_unknown(uint32_t reqs)
|
||||
{
|
||||
return reqs & CRYPT_REQUIREMENT_UNKNOWN;
|
||||
}
|
||||
|
||||
static int reqs_reencrypt(uint32_t reqs)
|
||||
{
|
||||
return reqs & CRYPT_REQUIREMENT_OFFLINE_REENCRYPT;
|
||||
}
|
||||
|
||||
static int reqs_reencrypt_online(uint32_t reqs)
|
||||
{
|
||||
return reqs & CRYPT_REQUIREMENT_ONLINE_REENCRYPT;
|
||||
}
|
||||
|
||||
int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
const char *backup_file)
|
||||
{
|
||||
@@ -1389,24 +1461,106 @@ int LUKS2_config_set_flags(struct crypt_device *cd, struct luks2_hdr *hdr, uint3
|
||||
*/
|
||||
|
||||
/* LUKS2 library requirements */
|
||||
static const struct {
|
||||
struct requirement_flag {
|
||||
uint32_t flag;
|
||||
uint32_t version;
|
||||
const char *description;
|
||||
} requirements_flags[] = {
|
||||
{ CRYPT_REQUIREMENT_OFFLINE_REENCRYPT, "offline-reencrypt" },
|
||||
{ CRYPT_REQUIREMENT_ONLINE_REENCRYPT, "online-reencrypt" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static uint32_t get_requirement_by_name(const char *requirement)
|
||||
static const struct requirement_flag unknown_requirement_flag = { CRYPT_REQUIREMENT_UNKNOWN, 0, NULL };
|
||||
|
||||
static const struct requirement_flag requirements_flags[] = {
|
||||
{ CRYPT_REQUIREMENT_OFFLINE_REENCRYPT,1, "offline-reencrypt" },
|
||||
{ CRYPT_REQUIREMENT_ONLINE_REENCRYPT, 2, "online-reencrypt-v2" },
|
||||
{ CRYPT_REQUIREMENT_ONLINE_REENCRYPT, 1, "online-reencrypt" },
|
||||
{ 0, 0, NULL }
|
||||
};
|
||||
|
||||
static const struct requirement_flag *get_requirement_by_name(const char *requirement)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; requirements_flags[i].description; i++)
|
||||
if (!strcmp(requirement, requirements_flags[i].description))
|
||||
return requirements_flags[i].flag;
|
||||
return requirements_flags + i;
|
||||
|
||||
return CRYPT_REQUIREMENT_UNKNOWN;
|
||||
return &unknown_requirement_flag;
|
||||
}
|
||||
|
||||
int LUKS2_config_get_reencrypt_version(struct luks2_hdr *hdr, uint32_t *version)
|
||||
{
|
||||
json_object *jobj_config, *jobj_requirements, *jobj_mandatory, *jobj;
|
||||
int i, len;
|
||||
const struct requirement_flag *req;
|
||||
|
||||
assert(hdr && version);
|
||||
if (!hdr || !version)
|
||||
return -EINVAL;
|
||||
|
||||
if (!json_object_object_get_ex(hdr->jobj, "config", &jobj_config))
|
||||
return -EINVAL;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_config, "requirements", &jobj_requirements))
|
||||
return -ENOENT;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_requirements, "mandatory", &jobj_mandatory))
|
||||
return -ENOENT;
|
||||
|
||||
len = (int) json_object_array_length(jobj_mandatory);
|
||||
if (len <= 0)
|
||||
return -ENOENT;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
jobj = json_object_array_get_idx(jobj_mandatory, i);
|
||||
|
||||
/* search for requirements prefixed with "online-reencrypt" */
|
||||
if (strncmp(json_object_get_string(jobj), "online-reencrypt", 16))
|
||||
continue;
|
||||
|
||||
/* check current library is aware of the requirement */
|
||||
req = get_requirement_by_name(json_object_get_string(jobj));
|
||||
if (req->flag == (uint32_t)CRYPT_REQUIREMENT_UNKNOWN)
|
||||
continue;
|
||||
|
||||
*version = req->version;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static const struct requirement_flag *stored_requirement_name_by_id(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t req_id)
|
||||
{
|
||||
json_object *jobj_config, *jobj_requirements, *jobj_mandatory, *jobj;
|
||||
int i, len;
|
||||
const struct requirement_flag *req;
|
||||
|
||||
assert(hdr);
|
||||
if (!hdr)
|
||||
return NULL;
|
||||
|
||||
if (!json_object_object_get_ex(hdr->jobj, "config", &jobj_config))
|
||||
return NULL;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_config, "requirements", &jobj_requirements))
|
||||
return NULL;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_requirements, "mandatory", &jobj_mandatory))
|
||||
return NULL;
|
||||
|
||||
len = (int) json_object_array_length(jobj_mandatory);
|
||||
if (len <= 0)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
jobj = json_object_array_get_idx(jobj_mandatory, i);
|
||||
req = get_requirement_by_name(json_object_get_string(jobj));
|
||||
if (req->flag == req_id)
|
||||
return req;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1416,7 +1570,7 @@ int LUKS2_config_get_requirements(struct crypt_device *cd, struct luks2_hdr *hdr
|
||||
{
|
||||
json_object *jobj_config, *jobj_requirements, *jobj_mandatory, *jobj;
|
||||
int i, len;
|
||||
uint32_t req;
|
||||
const struct requirement_flag *req;
|
||||
|
||||
assert(hdr);
|
||||
if (!hdr || !reqs)
|
||||
@@ -1443,8 +1597,8 @@ int LUKS2_config_get_requirements(struct crypt_device *cd, struct luks2_hdr *hdr
|
||||
jobj = json_object_array_get_idx(jobj_mandatory, i);
|
||||
req = get_requirement_by_name(json_object_get_string(jobj));
|
||||
log_dbg(cd, "%s - %sknown", json_object_get_string(jobj),
|
||||
reqs_unknown(req) ? "un" : "");
|
||||
*reqs |= req;
|
||||
reqs_unknown(req->flag) ? "un" : "");
|
||||
*reqs |= req->flag;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1454,6 +1608,8 @@ int LUKS2_config_set_requirements(struct crypt_device *cd, struct luks2_hdr *hdr
|
||||
{
|
||||
json_object *jobj_config, *jobj_requirements, *jobj_mandatory, *jobj;
|
||||
int i, r = -EINVAL;
|
||||
const struct requirement_flag *req;
|
||||
uint32_t req_id;
|
||||
|
||||
if (!hdr)
|
||||
return -EINVAL;
|
||||
@@ -1463,8 +1619,14 @@ int LUKS2_config_set_requirements(struct crypt_device *cd, struct luks2_hdr *hdr
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; requirements_flags[i].description; i++) {
|
||||
if (reqs & requirements_flags[i].flag) {
|
||||
jobj = json_object_new_string(requirements_flags[i].description);
|
||||
req_id = reqs & requirements_flags[i].flag;
|
||||
if (req_id) {
|
||||
/* retain already stored version of requirement flag */
|
||||
req = stored_requirement_name_by_id(cd, hdr, req_id);
|
||||
if (req)
|
||||
jobj = json_object_new_string(req->description);
|
||||
else
|
||||
jobj = json_object_new_string(requirements_flags[i].description);
|
||||
if (!jobj) {
|
||||
r = -ENOMEM;
|
||||
goto err;
|
||||
|
||||
@@ -27,7 +27,9 @@ extern const keyslot_handler reenc_keyslot;
|
||||
|
||||
static const keyslot_handler *keyslot_handlers[LUKS2_KEYSLOTS_MAX] = {
|
||||
&luks2_keyslot,
|
||||
#if USE_LUKS2_REENCRYPTION
|
||||
&reenc_keyslot,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -288,19 +290,9 @@ crypt_keyslot_info LUKS2_keyslot_info(struct luks2_hdr *hdr, int keyslot)
|
||||
return CRYPT_SLOT_ACTIVE;
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_area(struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
uint64_t *offset,
|
||||
uint64_t *length)
|
||||
int LUKS2_keyslot_jobj_area(json_object *jobj_keyslot, uint64_t *offset, uint64_t *length)
|
||||
{
|
||||
json_object *jobj_keyslot, *jobj_area, *jobj;
|
||||
|
||||
if(LUKS2_keyslot_info(hdr, keyslot) == CRYPT_SLOT_INVALID)
|
||||
return -EINVAL;
|
||||
|
||||
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
|
||||
if (!jobj_keyslot)
|
||||
return -ENOENT;
|
||||
json_object *jobj_area, *jobj;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
|
||||
return -EINVAL;
|
||||
@@ -316,6 +308,23 @@ int LUKS2_keyslot_area(struct luks2_hdr *hdr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_area(struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
uint64_t *offset,
|
||||
uint64_t *length)
|
||||
{
|
||||
json_object *jobj_keyslot;
|
||||
|
||||
if (LUKS2_keyslot_info(hdr, keyslot) == CRYPT_SLOT_INVALID)
|
||||
return -EINVAL;
|
||||
|
||||
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
|
||||
if (!jobj_keyslot)
|
||||
return -ENOENT;
|
||||
|
||||
return LUKS2_keyslot_jobj_area(jobj_keyslot, offset, length);
|
||||
}
|
||||
|
||||
static int _open_and_verify(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
const keyslot_handler *h,
|
||||
@@ -596,7 +605,7 @@ int LUKS2_keyslot_open(struct crypt_device *cd,
|
||||
return r;
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_reencrypt_create(struct crypt_device *cd,
|
||||
int LUKS2_keyslot_reencrypt_allocate(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
const struct crypt_params_reencrypt *params)
|
||||
@@ -625,9 +634,6 @@ int LUKS2_keyslot_reencrypt_create(struct crypt_device *cd,
|
||||
return r;
|
||||
}
|
||||
|
||||
if (LUKS2_hdr_validate(cd, hdr->jobj, hdr->hdr_size - LUKS2_HDR_BIN_LEN))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -878,10 +884,17 @@ int LUKS2_keyslots_validate(struct crypt_device *cd, json_object *hdr_jobj)
|
||||
const keyslot_handler *h;
|
||||
int keyslot;
|
||||
json_object *jobj_keyslots, *jobj_type;
|
||||
uint32_t reqs, reencrypt_count = 0;
|
||||
struct luks2_hdr dummy = {
|
||||
.jobj = hdr_jobj
|
||||
};
|
||||
|
||||
if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
|
||||
return -EINVAL;
|
||||
|
||||
if (LUKS2_config_get_requirements(cd, &dummy, &reqs))
|
||||
return -EINVAL;
|
||||
|
||||
json_object_object_foreach(jobj_keyslots, slot, val) {
|
||||
keyslot = atoi(slot);
|
||||
json_object_object_get_ex(val, "type", &jobj_type);
|
||||
@@ -897,6 +910,24 @@ int LUKS2_keyslots_validate(struct crypt_device *cd, json_object *hdr_jobj)
|
||||
log_dbg(cd, "Keyslot %d is not assigned to exactly 1 digest.", keyslot);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!strcmp(h->name, "reencrypt"))
|
||||
reencrypt_count++;
|
||||
}
|
||||
|
||||
if ((reqs & CRYPT_REQUIREMENT_ONLINE_REENCRYPT) && reencrypt_count == 0) {
|
||||
log_dbg(cd, "Missing reencryption keyslot.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!(reqs & CRYPT_REQUIREMENT_ONLINE_REENCRYPT) && reencrypt_count) {
|
||||
log_dbg(cd, "Missing reencryption requirement flag.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (reencrypt_count > 1) {
|
||||
log_dbg(cd, "Too many reencryption keyslots.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -248,6 +248,7 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
|
||||
/*
|
||||
* Calculate keyslot content, split and store it to keyslot area.
|
||||
*/
|
||||
log_dbg(cd, "Running keyslot key derivation.");
|
||||
r = crypt_pbkdf(pbkdf.type, pbkdf.hash, password, passwordLen,
|
||||
salt, LUKS_SALTSIZE,
|
||||
derived_key->key, derived_key->keylength,
|
||||
@@ -269,7 +270,7 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
|
||||
r = AF_split(cd, volume_key, AfKey, volume_key_len, LUKS_STRIPES, af_hash);
|
||||
|
||||
if (r == 0) {
|
||||
log_dbg(cd, "Updating keyslot area [0x%04x].", (unsigned)area_offset);
|
||||
log_dbg(cd, "Updating keyslot area [0x%04" PRIx64 "].", area_offset);
|
||||
/* FIXME: sector_offset should be size_t, fix LUKS_encrypt... accordingly */
|
||||
r = luks2_encrypt_to_storage(AfKey, AFEKSize, cipher, cipher_mode,
|
||||
derived_key, (unsigned)(area_offset / SECTOR_SIZE), cd);
|
||||
@@ -350,6 +351,7 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
|
||||
/*
|
||||
* Calculate derived key, decrypt keyslot content and merge it.
|
||||
*/
|
||||
log_dbg(cd, "Running keyslot key derivation.");
|
||||
r = crypt_pbkdf(pbkdf.type, pbkdf.hash, password, passwordLen,
|
||||
salt, LUKS_SALTSIZE,
|
||||
derived_key->key, derived_key->keylength,
|
||||
@@ -360,7 +362,7 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
|
||||
crypt_serialize_unlock(cd);
|
||||
|
||||
if (r == 0) {
|
||||
log_dbg(cd, "Reading keyslot area [0x%04x].", (unsigned)area_offset);
|
||||
log_dbg(cd, "Reading keyslot area [0x%04" PRIx64 "].", area_offset);
|
||||
/* FIXME: sector_offset should be size_t, fix LUKS_decrypt... accordingly */
|
||||
r = luks2_decrypt_from_storage(AfKey, AFEKSize, cipher, cipher_mode,
|
||||
derived_key, (unsigned)(area_offset / SECTOR_SIZE), cd);
|
||||
|
||||
@@ -176,9 +176,17 @@ static int reenc_keyslot_store(struct crypt_device *cd,
|
||||
return r < 0 ? r : keyslot;
|
||||
}
|
||||
|
||||
static int reenc_keyslot_wipe(struct crypt_device *cd __attribute__((unused)),
|
||||
int keyslot __attribute__((unused)))
|
||||
static int reenc_keyslot_wipe(struct crypt_device *cd,
|
||||
int keyslot)
|
||||
{
|
||||
struct luks2_hdr *hdr;
|
||||
|
||||
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
|
||||
return -EINVAL;
|
||||
|
||||
/* remove reencryption verification data */
|
||||
LUKS2_digest_assign(cd, hdr, keyslot, CRYPT_ANY_DIGEST, 0, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -222,7 +230,7 @@ static int reenc_keyslot_dump(struct crypt_device *cd, int keyslot)
|
||||
|
||||
static int reenc_keyslot_validate(struct crypt_device *cd, json_object *jobj_keyslot)
|
||||
{
|
||||
json_object *jobj_mode, *jobj_area, *jobj_type, *jobj_shift_size, *jobj_hash, *jobj_sector_size, *jobj_direction;
|
||||
json_object *jobj_mode, *jobj_area, *jobj_type, *jobj_shift_size, *jobj_hash, *jobj_sector_size, *jobj_direction, *jobj_key_size;
|
||||
const char *mode, *type, *direction;
|
||||
uint32_t sector_size;
|
||||
uint64_t shift_size;
|
||||
@@ -242,12 +250,18 @@ static int reenc_keyslot_validate(struct crypt_device *cd, json_object *jobj_key
|
||||
!json_object_object_get_ex(jobj_area, "type", &jobj_type))
|
||||
return -EINVAL;
|
||||
|
||||
jobj_key_size = json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "key_size", json_type_int);
|
||||
jobj_mode = json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "mode", json_type_string);
|
||||
jobj_direction = json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "direction", json_type_string);
|
||||
|
||||
if (!jobj_mode || !jobj_direction)
|
||||
if (!jobj_mode || !jobj_direction || !jobj_key_size)
|
||||
return -EINVAL;
|
||||
|
||||
if (!validate_json_uint32(jobj_key_size) || crypt_jobj_get_uint32(jobj_key_size) != 1) {
|
||||
log_dbg(cd, "Illegal reencrypt key size.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mode = json_object_get_string(jobj_mode);
|
||||
type = json_object_get_string(jobj_type);
|
||||
direction = json_object_get_string(jobj_direction);
|
||||
|
||||
@@ -91,10 +91,11 @@ struct luks2_reencrypt {
|
||||
|
||||
struct crypt_lock_handle *reenc_lock;
|
||||
};
|
||||
|
||||
#if USE_LUKS2_REENCRYPTION
|
||||
static int reencrypt_keyslot_update(struct crypt_device *cd,
|
||||
const struct luks2_reencrypt *rh)
|
||||
{
|
||||
int r;
|
||||
json_object *jobj_keyslot, *jobj_area, *jobj_area_type;
|
||||
struct luks2_hdr *hdr;
|
||||
|
||||
@@ -124,7 +125,11 @@ static int reencrypt_keyslot_update(struct crypt_device *cd,
|
||||
} else
|
||||
log_dbg(cd, "No update of reencrypt keyslot needed.");
|
||||
|
||||
return 0;
|
||||
r = LUKS2_keyslot_reencrypt_digest_create(cd, hdr, rh->vks);
|
||||
if (r < 0)
|
||||
log_err(cd, "Failed to refresh reencryption verification digest.");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static json_object *reencrypt_segment(struct luks2_hdr *hdr, unsigned new)
|
||||
@@ -190,7 +195,7 @@ static uint64_t reencrypt_get_data_offset_old(struct luks2_hdr *hdr)
|
||||
{
|
||||
return reencrypt_data_offset(hdr, 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
static int reencrypt_digest(struct luks2_hdr *hdr, unsigned new)
|
||||
{
|
||||
int segment = LUKS2_get_segment_id_by_flag(hdr, new ? "backup-final" : "backup-previous");
|
||||
@@ -249,7 +254,7 @@ static const char *reencrypt_resilience_hash(struct luks2_hdr *hdr)
|
||||
|
||||
return json_object_get_string(jobj_hash);
|
||||
}
|
||||
|
||||
#if USE_LUKS2_REENCRYPTION
|
||||
static uint32_t reencrypt_alignment(struct luks2_hdr *hdr)
|
||||
{
|
||||
json_object *jobj_keyslot, *jobj_area, *jobj_type, *jobj_hash, *jobj_sector_size;
|
||||
@@ -661,7 +666,7 @@ static int reencrypt_make_post_segments(struct crypt_device *cd,
|
||||
|
||||
return rh->jobj_segs_post ? 0 : -EINVAL;
|
||||
}
|
||||
|
||||
#endif
|
||||
static uint64_t reencrypt_data_shift(struct luks2_hdr *hdr)
|
||||
{
|
||||
json_object *jobj_keyslot, *jobj_area, *jobj_data_shift;
|
||||
@@ -767,7 +772,7 @@ void LUKS2_reencrypt_free(struct crypt_device *cd, struct luks2_reencrypt *rh)
|
||||
crypt_unlock_internal(cd, rh->reenc_lock);
|
||||
free(rh);
|
||||
}
|
||||
|
||||
#if USE_LUKS2_REENCRYPTION
|
||||
static size_t reencrypt_get_alignment(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr)
|
||||
{
|
||||
@@ -825,7 +830,7 @@ static int reencrypt_offset_backward_moved(struct luks2_hdr *hdr, json_object *j
|
||||
linear_length += LUKS2_segment_size(hdr, sg, 0);
|
||||
|
||||
/* all active linear segments length */
|
||||
if (linear_length) {
|
||||
if (linear_length && segs > 1) {
|
||||
if (linear_length < data_shift)
|
||||
return -EINVAL;
|
||||
tmp = linear_length - data_shift;
|
||||
@@ -1020,7 +1025,7 @@ static int reencrypt_context_init(struct crypt_device *cd, struct luks2_hdr *hdr
|
||||
}
|
||||
|
||||
if (crypt_hash_init(&rh->rp.p.csum.ch, params->hash)) {
|
||||
log_dbg(cd, "Failed to initialize checksum resilience hash %s", params->hash);
|
||||
log_err(cd, _("Hash algorithm %s not supported."), params->hash);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -1745,7 +1750,8 @@ static int reencrypt_set_encrypt_segments(struct crypt_device *cd, struct luks2_
|
||||
int r;
|
||||
uint64_t first_segment_offset, first_segment_length,
|
||||
second_segment_offset, second_segment_length,
|
||||
data_offset = LUKS2_get_data_offset(hdr) << SECTOR_SHIFT;
|
||||
data_offset = LUKS2_get_data_offset(hdr) << SECTOR_SHIFT,
|
||||
data_size = dev_size - data_shift;
|
||||
json_object *jobj_segment_first = NULL, *jobj_segment_second = NULL, *jobj_segments;
|
||||
|
||||
if (dev_size < data_shift)
|
||||
@@ -1760,9 +1766,14 @@ static int reencrypt_set_encrypt_segments(struct crypt_device *cd, struct luks2_
|
||||
* [future LUKS2 header (data shift size)][second data segment][gap (data shift size)][first data segment (data shift size)]
|
||||
*/
|
||||
first_segment_offset = dev_size;
|
||||
first_segment_length = data_shift;
|
||||
second_segment_offset = data_shift;
|
||||
second_segment_length = dev_size - 2 * data_shift;
|
||||
if (data_size < data_shift) {
|
||||
first_segment_length = data_size;
|
||||
second_segment_length = second_segment_offset = 0;
|
||||
} else {
|
||||
first_segment_length = data_shift;
|
||||
second_segment_offset = data_shift;
|
||||
second_segment_length = data_size - data_shift;
|
||||
}
|
||||
} else if (data_shift) {
|
||||
first_segment_offset = data_offset;
|
||||
first_segment_length = dev_size;
|
||||
@@ -1834,6 +1845,9 @@ static int reencrypt_make_targets(struct crypt_device *cd,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (reenc_seg)
|
||||
segment_offset -= crypt_get_data_offset(cd);
|
||||
|
||||
if (!strcmp(json_segment_type(jobj), "crypt")) {
|
||||
vk = crypt_volume_key_by_id(vks, reenc_seg ? LUKS2_reencrypt_digest_new(hdr) : LUKS2_digest_by_segment(hdr, s));
|
||||
if (!vk) {
|
||||
@@ -1841,9 +1855,6 @@ static int reencrypt_make_targets(struct crypt_device *cd,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (reenc_seg)
|
||||
segment_offset -= crypt_get_data_offset(cd);
|
||||
|
||||
r = dm_crypt_target_set(result, segment_start, segment_size,
|
||||
reenc_seg ? hz_device : crypt_data_device(cd),
|
||||
vk,
|
||||
@@ -2163,17 +2174,10 @@ static int reencrypt_move_data(struct crypt_device *cd, int devfd, uint64_t data
|
||||
|
||||
log_dbg(cd, "Going to move data from head of data device.");
|
||||
|
||||
buffer_len = data_shift;
|
||||
if (!buffer_len)
|
||||
return -EINVAL;
|
||||
|
||||
offset = json_segment_get_offset(LUKS2_get_segment_jobj(hdr, 0), 0);
|
||||
|
||||
/* this is nonsense anyway */
|
||||
if (buffer_len != json_segment_get_size(LUKS2_get_segment_jobj(hdr, 0), 0)) {
|
||||
log_dbg(cd, "buffer_len %" PRIu64", segment size %" PRIu64, buffer_len, json_segment_get_size(LUKS2_get_segment_jobj(hdr, 0), 0));
|
||||
buffer_len = json_segment_get_size(LUKS2_get_segment_jobj(hdr, 0), 0);
|
||||
if (!buffer_len || buffer_len > data_shift)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (posix_memalign(&buffer, device_alignment(crypt_data_device(cd)), buffer_len))
|
||||
return -ENOMEM;
|
||||
@@ -2249,7 +2253,11 @@ static int reencrypt_make_backup_segments(struct crypt_device *cd,
|
||||
r = LUKS2_get_data_size(hdr, &tmp, NULL);
|
||||
if (r)
|
||||
goto err;
|
||||
jobj_segment_old = json_segment_create_linear(0, tmp ? &tmp : NULL, 0);
|
||||
|
||||
if (params->flags & CRYPT_REENCRYPT_MOVE_FIRST_SEGMENT)
|
||||
jobj_segment_old = json_segment_create_linear(0, tmp ? &tmp : NULL, 0);
|
||||
else
|
||||
jobj_segment_old = json_segment_create_linear(data_offset, tmp ? &tmp : NULL, 0);
|
||||
}
|
||||
|
||||
if (!jobj_segment_old) {
|
||||
@@ -2443,7 +2451,7 @@ static int reencrypt_init(struct crypt_device *cd,
|
||||
* encryption initialization (or mount)
|
||||
*/
|
||||
if (move_first_segment) {
|
||||
if (dev_size < 2 * (params->data_shift << SECTOR_SHIFT)) {
|
||||
if (dev_size < (params->data_shift << SECTOR_SHIFT)) {
|
||||
log_err(cd, _("Device %s is too small."), device_path(crypt_data_device(cd)));
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -2466,7 +2474,7 @@ static int reencrypt_init(struct crypt_device *cd,
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = LUKS2_keyslot_reencrypt_create(cd, hdr, reencrypt_keyslot,
|
||||
r = LUKS2_keyslot_reencrypt_allocate(cd, hdr, reencrypt_keyslot,
|
||||
params);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
@@ -2481,6 +2489,10 @@ static int reencrypt_init(struct crypt_device *cd,
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = LUKS2_keyslot_reencrypt_digest_create(cd, hdr, *vks);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
if (name && params->mode != CRYPT_REENCRYPT_ENCRYPT) {
|
||||
r = reencrypt_verify_and_upload_keys(cd, hdr, LUKS2_reencrypt_digest_old(hdr), LUKS2_reencrypt_digest_new(hdr), *vks);
|
||||
if (r)
|
||||
@@ -2611,20 +2623,28 @@ static int reencrypt_context_update(struct crypt_device *cd,
|
||||
static int reencrypt_load(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
uint64_t device_size,
|
||||
const struct crypt_params_reencrypt *params,
|
||||
struct volume_key *vks,
|
||||
struct luks2_reencrypt **rh)
|
||||
{
|
||||
int r;
|
||||
struct luks2_reencrypt *tmp = NULL;
|
||||
crypt_reencrypt_info ri = LUKS2_reencrypt_status(hdr);
|
||||
|
||||
if (ri == CRYPT_REENCRYPT_NONE) {
|
||||
log_err(cd, _("Device not marked for LUKS2 reencryption."));
|
||||
return -EINVAL;
|
||||
} else if (ri == CRYPT_REENCRYPT_INVALID)
|
||||
return -EINVAL;
|
||||
|
||||
r = LUKS2_reencrypt_digest_verify(cd, hdr, vks);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ri == CRYPT_REENCRYPT_CLEAN)
|
||||
r = reencrypt_load_clean(cd, hdr, device_size, &tmp, params);
|
||||
else if (ri == CRYPT_REENCRYPT_CRASH)
|
||||
r = reencrypt_load_crashed(cd, hdr, device_size, &tmp);
|
||||
else if (ri == CRYPT_REENCRYPT_NONE) {
|
||||
log_err(cd, _("Device not marked for LUKS2 reencryption."));
|
||||
return -EINVAL;
|
||||
} else
|
||||
else
|
||||
r = -EINVAL;
|
||||
|
||||
if (r < 0 || !tmp) {
|
||||
@@ -2636,7 +2656,7 @@ static int reencrypt_load(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
static int reencrypt_lock_internal(struct crypt_device *cd, const char *uuid, struct crypt_lock_handle **reencrypt_lock)
|
||||
{
|
||||
int r;
|
||||
@@ -2698,7 +2718,7 @@ void LUKS2_reencrypt_unlock(struct crypt_device *cd, struct crypt_lock_handle *r
|
||||
{
|
||||
crypt_unlock_internal(cd, reencrypt_lock);
|
||||
}
|
||||
|
||||
#if USE_LUKS2_REENCRYPTION
|
||||
static int reencrypt_lock_and_verify(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
struct crypt_lock_handle **reencrypt_lock)
|
||||
{
|
||||
@@ -2873,7 +2893,7 @@ static int reencrypt_load_by_passphrase(struct crypt_device *cd,
|
||||
rparams.device_size = required_size;
|
||||
}
|
||||
|
||||
r = reencrypt_load(cd, hdr, device_size, &rparams, &rh);
|
||||
r = reencrypt_load(cd, hdr, device_size, &rparams, *vks, &rh);
|
||||
if (r < 0 || !rh)
|
||||
goto err;
|
||||
|
||||
@@ -2968,6 +2988,85 @@ static int reencrypt_recovery_by_passphrase(struct crypt_device *cd,
|
||||
return r;
|
||||
}
|
||||
|
||||
static int reencrypt_repair_by_passphrase(
|
||||
struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot_old,
|
||||
int keyslot_new,
|
||||
const char *passphrase,
|
||||
size_t passphrase_size)
|
||||
{
|
||||
int r;
|
||||
struct crypt_lock_handle *reencrypt_lock;
|
||||
struct luks2_reencrypt *rh;
|
||||
crypt_reencrypt_info ri;
|
||||
struct volume_key *vks = NULL;
|
||||
|
||||
log_dbg(cd, "Loading LUKS2 reencryption context for metadata repair.");
|
||||
|
||||
rh = crypt_get_luks2_reencrypt(cd);
|
||||
if (rh) {
|
||||
LUKS2_reencrypt_free(cd, rh);
|
||||
crypt_set_luks2_reencrypt(cd, NULL);
|
||||
rh = NULL;
|
||||
}
|
||||
|
||||
ri = LUKS2_reencrypt_status(hdr);
|
||||
if (ri == CRYPT_REENCRYPT_INVALID)
|
||||
return -EINVAL;
|
||||
|
||||
if (ri < CRYPT_REENCRYPT_CLEAN) {
|
||||
log_err(cd, _("Device is not in reencryption."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = LUKS2_reencrypt_lock(cd, &reencrypt_lock);
|
||||
if (r < 0) {
|
||||
if (r == -EBUSY)
|
||||
log_err(cd, _("Reencryption process is already running."));
|
||||
else
|
||||
log_err(cd, _("Failed to acquire reencryption lock."));
|
||||
return r;
|
||||
}
|
||||
|
||||
/* With reencryption lock held, reload device context and verify metadata state */
|
||||
r = crypt_load(cd, CRYPT_LUKS2, NULL);
|
||||
if (r)
|
||||
goto out;
|
||||
|
||||
ri = LUKS2_reencrypt_status(hdr);
|
||||
if (ri == CRYPT_REENCRYPT_INVALID) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (ri == CRYPT_REENCRYPT_NONE) {
|
||||
r = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = LUKS2_keyslot_open_all_segments(cd, keyslot_old, keyslot_new, passphrase, passphrase_size, &vks);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = LUKS2_keyslot_reencrypt_digest_create(cd, hdr, vks);
|
||||
crypt_free_volume_key(vks);
|
||||
vks = NULL;
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
/* removes online-reencrypt flag v1 */
|
||||
if ((r = reencrypt_update_flag(cd, 0, false)))
|
||||
goto out;
|
||||
|
||||
/* adds online-reencrypt flag v2 and commits metadata */
|
||||
r = reencrypt_update_flag(cd, 1, true);
|
||||
out:
|
||||
LUKS2_reencrypt_unlock(cd, reencrypt_lock);
|
||||
crypt_free_volume_key(vks);
|
||||
return r;
|
||||
|
||||
}
|
||||
#endif
|
||||
static int reencrypt_init_by_passphrase(struct crypt_device *cd,
|
||||
const char *name,
|
||||
const char *passphrase,
|
||||
@@ -2978,12 +3077,17 @@ static int reencrypt_init_by_passphrase(struct crypt_device *cd,
|
||||
const char *cipher_mode,
|
||||
const struct crypt_params_reencrypt *params)
|
||||
{
|
||||
#if USE_LUKS2_REENCRYPTION
|
||||
int r;
|
||||
crypt_reencrypt_info ri;
|
||||
struct volume_key *vks = NULL;
|
||||
uint32_t flags = params ? params->flags : 0;
|
||||
struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
|
||||
|
||||
/* short-circuit in reencryption metadata update and finish immediately. */
|
||||
if (flags & CRYPT_REENCRYPT_REPAIR_NEEDED)
|
||||
return reencrypt_repair_by_passphrase(cd, hdr, keyslot_old, keyslot_new, passphrase, passphrase_size);
|
||||
|
||||
/* short-circuit in recovery and finish immediately. */
|
||||
if (flags & CRYPT_REENCRYPT_RECOVERY)
|
||||
return reencrypt_recovery_by_passphrase(cd, hdr, keyslot_old, keyslot_new, passphrase, passphrase_size);
|
||||
@@ -3033,6 +3137,10 @@ out:
|
||||
crypt_drop_keyring_key(cd, vks);
|
||||
crypt_free_volume_key(vks);
|
||||
return r < 0 ? r : LUKS2_find_keyslot(hdr, "reencrypt");
|
||||
#else
|
||||
log_err(cd, _("This operation is not supported for this device type."));
|
||||
return -ENOTSUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
int crypt_reencrypt_init_by_keyring(struct crypt_device *cd,
|
||||
@@ -3085,6 +3193,7 @@ int crypt_reencrypt_init_by_passphrase(struct crypt_device *cd,
|
||||
return reencrypt_init_by_passphrase(cd, name, passphrase, passphrase_size, keyslot_old, keyslot_new, cipher, cipher_mode, params);
|
||||
}
|
||||
|
||||
#if USE_LUKS2_REENCRYPTION
|
||||
static reenc_status_t reencrypt_step(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
struct luks2_reencrypt *rh,
|
||||
@@ -3093,13 +3202,6 @@ static reenc_status_t reencrypt_step(struct crypt_device *cd,
|
||||
{
|
||||
int r;
|
||||
|
||||
/* update reencrypt keyslot protection parameters in memory only */
|
||||
r = reencrypt_keyslot_update(cd, rh);
|
||||
if (r < 0) {
|
||||
log_dbg(cd, "Keyslot update failed.");
|
||||
return REENC_ERR;
|
||||
}
|
||||
|
||||
/* in memory only */
|
||||
r = reencrypt_make_segments(cd, hdr, rh, device_size);
|
||||
if (r)
|
||||
@@ -3269,15 +3371,20 @@ static int reencrypt_teardown_ok(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
log_dbg(cd, "Failed to set new keyslots area size.");
|
||||
if (rh->digest_old >= 0 && rh->digest_new != rh->digest_old)
|
||||
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++)
|
||||
if (LUKS2_digest_by_keyslot(hdr, i) == rh->digest_old)
|
||||
crypt_keyslot_destroy(cd, i);
|
||||
crypt_keyslot_destroy(cd, rh->reenc_keyslot);
|
||||
if (LUKS2_digest_by_keyslot(hdr, i) == rh->digest_old && crypt_keyslot_destroy(cd, i))
|
||||
log_err(cd, _("Failed to remove unused (unbound) keyslot %d."), i);
|
||||
|
||||
if (reencrypt_erase_backup_segments(cd, hdr))
|
||||
log_dbg(cd, "Failed to erase backup segments");
|
||||
|
||||
/* do we need atomic erase? */
|
||||
if (reencrypt_update_flag(cd, 0, true))
|
||||
log_err(cd, _("Failed to disable reencryption requirement flag."));
|
||||
if (reencrypt_update_flag(cd, 0, false))
|
||||
log_dbg(cd, "Failed to disable reencryption requirement flag.");
|
||||
|
||||
/* metadata commit point also removing reencryption flag on-disk */
|
||||
if (crypt_keyslot_destroy(cd, rh->reenc_keyslot)) {
|
||||
log_err(cd, _("Failed to remove reencryption keyslot."));
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -3289,7 +3396,7 @@ static void reencrypt_teardown_fatal(struct crypt_device *cd, struct luks2_reenc
|
||||
(rh->offset >> SECTOR_SHIFT) + crypt_get_data_offset(cd), rh->length >> SECTOR_SHIFT);
|
||||
|
||||
if (rh->online) {
|
||||
log_err(cd, "Reencryption was run in online mode.");
|
||||
log_err(cd, _("Online reencryption failed."));
|
||||
if (dm_status_suspended(cd, rh->hotzone_name) > 0) {
|
||||
log_dbg(cd, "Hotzone device %s suspended, replacing with dm-error.", rh->hotzone_name);
|
||||
if (dm_error_device(cd, rh->hotzone_name)) {
|
||||
@@ -3326,12 +3433,14 @@ static int reencrypt_teardown(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
int crypt_reencrypt_run(
|
||||
struct crypt_device *cd,
|
||||
int (*progress)(uint64_t size, uint64_t offset, void *usrptr),
|
||||
void *usrptr)
|
||||
{
|
||||
#if USE_LUKS2_REENCRYPTION
|
||||
int r;
|
||||
crypt_reencrypt_info ri;
|
||||
struct luks2_hdr *hdr;
|
||||
@@ -3367,6 +3476,15 @@ int crypt_reencrypt_run(
|
||||
|
||||
rs = REENC_OK;
|
||||
|
||||
/* update reencrypt keyslot protection parameters in memory only */
|
||||
if (!quit && (rh->device_size > rh->progress)) {
|
||||
r = reencrypt_keyslot_update(cd, rh);
|
||||
if (r < 0) {
|
||||
log_dbg(cd, "Keyslot update failed.");
|
||||
return reencrypt_teardown(cd, hdr, rh, REENC_ERR, quit, progress, usrptr);
|
||||
}
|
||||
}
|
||||
|
||||
while (!quit && (rh->device_size > rh->progress)) {
|
||||
rs = reencrypt_step(cd, hdr, rh, rh->device_size, rh->online);
|
||||
if (rs != REENC_OK)
|
||||
@@ -3389,6 +3507,10 @@ int crypt_reencrypt_run(
|
||||
|
||||
r = reencrypt_teardown(cd, hdr, rh, rs, quit, progress, usrptr);
|
||||
return r;
|
||||
#else
|
||||
log_err(cd, _("This operation is not supported for this device type."));
|
||||
return -ENOTSUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
int crypt_reencrypt(
|
||||
@@ -3397,7 +3519,7 @@ int crypt_reencrypt(
|
||||
{
|
||||
return crypt_reencrypt_run(cd, progress, NULL);
|
||||
}
|
||||
|
||||
#if USE_LUKS2_REENCRYPTION
|
||||
static int reencrypt_recovery(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
uint64_t device_size,
|
||||
@@ -3406,7 +3528,7 @@ static int reencrypt_recovery(struct crypt_device *cd,
|
||||
int r;
|
||||
struct luks2_reencrypt *rh = NULL;
|
||||
|
||||
r = reencrypt_load(cd, hdr, device_size, NULL, &rh);
|
||||
r = reencrypt_load(cd, hdr, device_size, NULL, vks, &rh);
|
||||
if (r < 0) {
|
||||
log_err(cd, _("Failed to load LUKS2 reencryption context."));
|
||||
return r;
|
||||
@@ -3433,7 +3555,7 @@ out:
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#endif
|
||||
/*
|
||||
* use only for calculation of minimal data device size.
|
||||
* The real data offset is taken directly from segments!
|
||||
@@ -3475,12 +3597,12 @@ int LUKS2_reencrypt_check_device_size(struct crypt_device *cd, struct luks2_hdr
|
||||
return r;
|
||||
|
||||
log_dbg(cd, "Required minimal device size: %" PRIu64 " (%" PRIu64 " sectors)"
|
||||
", real device size: %" PRIu64 " (%" PRIu64 " sectors)\n"
|
||||
", real device size: %" PRIu64 " (%" PRIu64 " sectors) "
|
||||
"calculated device size: %" PRIu64 " (%" PRIu64 " sectors)",
|
||||
check_size, check_size >> SECTOR_SHIFT, real_size, real_size >> SECTOR_SHIFT,
|
||||
real_size - data_offset, (real_size - data_offset) >> SECTOR_SHIFT);
|
||||
|
||||
if (real_size < data_offset || (check_size && (real_size - data_offset) < check_size)) {
|
||||
if (real_size < data_offset || (check_size && real_size < check_size)) {
|
||||
log_err(cd, _("Device %s is too small."), device_path(crypt_data_device(cd)));
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -3489,7 +3611,7 @@ int LUKS2_reencrypt_check_device_size(struct crypt_device *cd, struct luks2_hdr
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if USE_LUKS2_REENCRYPTION
|
||||
/* returns keyslot number on success (>= 0) or negative errnor otherwise */
|
||||
int LUKS2_reencrypt_locked_recovery_by_passphrase(struct crypt_device *cd,
|
||||
int keyslot_old,
|
||||
@@ -3539,16 +3661,32 @@ out:
|
||||
|
||||
return r < 0 ? r : keyslot;
|
||||
}
|
||||
|
||||
#endif
|
||||
crypt_reencrypt_info LUKS2_reencrypt_get_params(struct luks2_hdr *hdr,
|
||||
struct crypt_params_reencrypt *params)
|
||||
{
|
||||
crypt_reencrypt_info ri;
|
||||
int digest;
|
||||
uint32_t version;
|
||||
|
||||
ri = LUKS2_reencrypt_status(hdr);
|
||||
if (ri == CRYPT_REENCRYPT_NONE || ri == CRYPT_REENCRYPT_INVALID || !params)
|
||||
return ri;
|
||||
|
||||
digest = LUKS2_digest_by_keyslot(hdr, LUKS2_find_keyslot(hdr, "reencrypt"));
|
||||
if (digest < 0 && digest != -ENOENT)
|
||||
return CRYPT_REENCRYPT_INVALID;
|
||||
|
||||
/*
|
||||
* In case there's an old "online-reencrypt" requirement or reencryption
|
||||
* keyslot digest is missing inform caller reencryption metadata requires repair.
|
||||
*/
|
||||
if (!LUKS2_config_get_reencrypt_version(hdr, &version) &&
|
||||
(version < 2 || digest == -ENOENT)) {
|
||||
params->flags |= CRYPT_REENCRYPT_REPAIR_NEEDED;
|
||||
return ri;
|
||||
}
|
||||
|
||||
params->mode = reencrypt_mode(hdr);
|
||||
params->direction = reencrypt_direction(hdr);
|
||||
params->resilience = reencrypt_resilience_type(hdr);
|
||||
|
||||
381
lib/luks2/luks2_reencrypt_digest.c
Normal file
381
lib/luks2/luks2_reencrypt_digest.c
Normal file
@@ -0,0 +1,381 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2, reencryption digest helpers
|
||||
*
|
||||
* Copyright (C) 2022, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2022, Ondrej Kozina
|
||||
* Copyright (C) 2022, Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "luks2_internal.h"
|
||||
#include <assert.h>
|
||||
|
||||
#define MAX_STR 64
|
||||
|
||||
struct jtype {
|
||||
enum { JNONE = 0, JSTR, JU64, JX64, JU32 } type;
|
||||
json_object *jobj;
|
||||
const char *id;
|
||||
};
|
||||
|
||||
static size_t sr(struct jtype *j, uint8_t *ptr)
|
||||
{
|
||||
json_object *jobj;
|
||||
size_t len = 0;
|
||||
uint64_t u64;
|
||||
uint32_t u32;
|
||||
|
||||
if (!json_object_is_type(j->jobj, json_type_object))
|
||||
return 0;
|
||||
|
||||
if (!json_object_object_get_ex(j->jobj, j->id, &jobj))
|
||||
return 0;
|
||||
|
||||
switch(j->type) {
|
||||
case JSTR: /* JSON string */
|
||||
if (!json_object_is_type(jobj, json_type_string))
|
||||
return 0;
|
||||
len = strlen(json_object_get_string(jobj));
|
||||
if (len > MAX_STR)
|
||||
return 0;
|
||||
if (ptr)
|
||||
memcpy(ptr, json_object_get_string(jobj), len);
|
||||
break;
|
||||
case JU64: /* Unsigned 64bit integer stored as string */
|
||||
if (!json_object_is_type(jobj, json_type_string))
|
||||
break;
|
||||
len = sizeof(u64);
|
||||
if (ptr) {
|
||||
u64 = cpu_to_be64(crypt_jobj_get_uint64(jobj));
|
||||
memcpy(ptr, &u64, len);
|
||||
}
|
||||
break;
|
||||
case JX64: /* Unsigned 64bit segment size (allows "dynamic") */
|
||||
if (!json_object_is_type(jobj, json_type_string))
|
||||
break;
|
||||
if (!strcmp(json_object_get_string(jobj), "dynamic")) {
|
||||
len = strlen("dynamic");
|
||||
if (ptr)
|
||||
memcpy(ptr, json_object_get_string(jobj), len);
|
||||
} else {
|
||||
len = sizeof(u64);
|
||||
u64 = cpu_to_be64(crypt_jobj_get_uint64(jobj));
|
||||
if (ptr)
|
||||
memcpy(ptr, &u64, len);
|
||||
}
|
||||
break;
|
||||
case JU32: /* Unsigned 32bit integer, stored as JSON int */
|
||||
if (!json_object_is_type(jobj, json_type_int))
|
||||
return 0;
|
||||
len = sizeof(u32);
|
||||
if (ptr) {
|
||||
u32 = cpu_to_be32(crypt_jobj_get_uint32(jobj));
|
||||
memcpy(ptr, &u32, len);
|
||||
}
|
||||
break;
|
||||
case JNONE:
|
||||
return 0;
|
||||
};
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static size_t srs(struct jtype j[], uint8_t *ptr)
|
||||
{
|
||||
size_t l, len = 0;
|
||||
|
||||
while(j->jobj) {
|
||||
l = sr(j, ptr);
|
||||
if (!l)
|
||||
return 0;
|
||||
len += l;
|
||||
if (ptr)
|
||||
ptr += l;
|
||||
j++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static size_t segment_linear_serialize(json_object *jobj_segment, uint8_t *buffer)
|
||||
{
|
||||
struct jtype j[] = {
|
||||
{ JSTR, jobj_segment, "type" },
|
||||
{ JU64, jobj_segment, "offset" },
|
||||
{ JX64, jobj_segment, "size" },
|
||||
{}
|
||||
};
|
||||
return srs(j, buffer);
|
||||
}
|
||||
|
||||
static size_t segment_crypt_serialize(json_object *jobj_segment, uint8_t *buffer)
|
||||
{
|
||||
struct jtype j[] = {
|
||||
{ JSTR, jobj_segment, "type" },
|
||||
{ JU64, jobj_segment, "offset" },
|
||||
{ JX64, jobj_segment, "size" },
|
||||
{ JU64, jobj_segment, "iv_tweak" },
|
||||
{ JSTR, jobj_segment, "encryption" },
|
||||
{ JU32, jobj_segment, "sector_size" },
|
||||
{}
|
||||
};
|
||||
return srs(j, buffer);
|
||||
}
|
||||
|
||||
static size_t segment_serialize(json_object *jobj_segment, uint8_t *buffer)
|
||||
{
|
||||
json_object *jobj_type;
|
||||
const char *segment_type;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_segment, "type", &jobj_type))
|
||||
return 0;
|
||||
|
||||
if (!(segment_type = json_object_get_string(jobj_type)))
|
||||
return 0;
|
||||
|
||||
if (!strcmp(segment_type, "crypt"))
|
||||
return segment_crypt_serialize(jobj_segment, buffer);
|
||||
else if (!strcmp(segment_type, "linear"))
|
||||
return segment_linear_serialize(jobj_segment, buffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t backup_segments_serialize(struct luks2_hdr *hdr, uint8_t *buffer)
|
||||
{
|
||||
json_object *jobj_segment;
|
||||
size_t l, len = 0;
|
||||
|
||||
jobj_segment = LUKS2_get_segment_by_flag(hdr, "backup-previous");
|
||||
if (!jobj_segment || !(l = segment_serialize(jobj_segment, buffer)))
|
||||
return 0;
|
||||
len += l;
|
||||
if (buffer)
|
||||
buffer += l;
|
||||
|
||||
jobj_segment = LUKS2_get_segment_by_flag(hdr, "backup-final");
|
||||
if (!jobj_segment || !(l = segment_serialize(jobj_segment, buffer)))
|
||||
return 0;
|
||||
len += l;
|
||||
if (buffer)
|
||||
buffer += l;
|
||||
|
||||
jobj_segment = LUKS2_get_segment_by_flag(hdr, "backup-moved-segment");
|
||||
if (jobj_segment) {
|
||||
if (!(l = segment_serialize(jobj_segment, buffer)))
|
||||
return 0;
|
||||
len += l;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static size_t reenc_keyslot_serialize(struct luks2_hdr *hdr, uint8_t *buffer)
|
||||
{
|
||||
json_object *jobj_keyslot, *jobj_area, *jobj_type;
|
||||
const char *area_type;
|
||||
int keyslot_reencrypt;
|
||||
|
||||
keyslot_reencrypt = LUKS2_find_keyslot(hdr, "reencrypt");
|
||||
if (keyslot_reencrypt < 0)
|
||||
return 0;
|
||||
|
||||
if (!(jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot_reencrypt)))
|
||||
return 0;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
|
||||
return 0;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_area, "type", &jobj_type))
|
||||
return 0;
|
||||
|
||||
if (!(area_type = json_object_get_string(jobj_type)))
|
||||
return 0;
|
||||
|
||||
struct jtype j[] = {
|
||||
{ JSTR, jobj_keyslot, "mode" },
|
||||
{ JSTR, jobj_keyslot, "direction" },
|
||||
{ JSTR, jobj_area, "type" },
|
||||
{ JU64, jobj_area, "offset" },
|
||||
{ JU64, jobj_area, "size" },
|
||||
{}
|
||||
};
|
||||
struct jtype j_datashift[] = {
|
||||
{ JSTR, jobj_keyslot, "mode" },
|
||||
{ JSTR, jobj_keyslot, "direction" },
|
||||
{ JSTR, jobj_area, "type" },
|
||||
{ JU64, jobj_area, "offset" },
|
||||
{ JU64, jobj_area, "size" },
|
||||
{ JU64, jobj_area, "shift_size" },
|
||||
{}
|
||||
};
|
||||
struct jtype j_checksum[] = {
|
||||
{ JSTR, jobj_keyslot, "mode" },
|
||||
{ JSTR, jobj_keyslot, "direction" },
|
||||
{ JSTR, jobj_area, "type" },
|
||||
{ JU64, jobj_area, "offset" },
|
||||
{ JU64, jobj_area, "size" },
|
||||
{ JSTR, jobj_area, "hash" },
|
||||
{ JU32, jobj_area, "sector_size" },
|
||||
{}
|
||||
};
|
||||
|
||||
if (!strcmp(area_type, "datashift"))
|
||||
return srs(j_datashift, buffer);
|
||||
else if (!strcmp(area_type, "checksum"))
|
||||
return srs(j_checksum, buffer);
|
||||
|
||||
return srs(j, buffer);
|
||||
}
|
||||
|
||||
static size_t blob_serialize(void *blob, size_t length, uint8_t *buffer)
|
||||
{
|
||||
if (buffer)
|
||||
memcpy(buffer, blob, length);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
static int reencrypt_assembly_verification_data(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
struct volume_key *vks,
|
||||
struct volume_key **verification_data)
|
||||
{
|
||||
uint8_t *ptr;
|
||||
int digest_new, digest_old;
|
||||
struct volume_key *data = NULL, *vk_old = NULL, *vk_new = NULL;
|
||||
size_t keyslot_data_len, segments_data_len, data_len = 2;
|
||||
|
||||
/* Keys - calculate length */
|
||||
digest_new = LUKS2_reencrypt_digest_new(hdr);
|
||||
digest_old = LUKS2_reencrypt_digest_old(hdr);
|
||||
|
||||
if (digest_old >= 0) {
|
||||
vk_old = crypt_volume_key_by_id(vks, digest_old);
|
||||
if (!vk_old)
|
||||
return -EINVAL;
|
||||
data_len += blob_serialize(vk_old->key, vk_old->keylength, NULL);
|
||||
}
|
||||
|
||||
if (digest_new >= 0 && digest_old != digest_new) {
|
||||
vk_new = crypt_volume_key_by_id(vks, digest_new);
|
||||
if (!vk_new)
|
||||
return -EINVAL;
|
||||
data_len += blob_serialize(vk_new->key, vk_new->keylength, NULL);
|
||||
}
|
||||
|
||||
if (data_len == 2)
|
||||
return -EINVAL;
|
||||
|
||||
/* Metadata - calculate length */
|
||||
if (!(keyslot_data_len = reenc_keyslot_serialize(hdr, NULL)))
|
||||
return -EINVAL;
|
||||
data_len += keyslot_data_len;
|
||||
|
||||
if (!(segments_data_len = backup_segments_serialize(hdr, NULL)))
|
||||
return -EINVAL;
|
||||
data_len += segments_data_len;
|
||||
|
||||
/* Alloc and fill serialization data */
|
||||
data = crypt_alloc_volume_key(data_len, NULL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
ptr = (uint8_t*)data->key;
|
||||
|
||||
/* v2 */
|
||||
*ptr++ = 0x76;
|
||||
*ptr++ = 0x32;
|
||||
|
||||
if (vk_old)
|
||||
ptr += blob_serialize(vk_old->key, vk_old->keylength, ptr);
|
||||
|
||||
if (vk_new)
|
||||
ptr += blob_serialize(vk_new->key, vk_new->keylength, ptr);
|
||||
|
||||
if (!reenc_keyslot_serialize(hdr, ptr))
|
||||
goto bad;
|
||||
ptr += keyslot_data_len;
|
||||
|
||||
if (!backup_segments_serialize(hdr, ptr))
|
||||
goto bad;
|
||||
ptr += segments_data_len;
|
||||
|
||||
assert((size_t)(ptr - (uint8_t*)data->key) == data_len);
|
||||
|
||||
*verification_data = data;
|
||||
|
||||
return 0;
|
||||
bad:
|
||||
crypt_free_volume_key(data);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_reencrypt_digest_create(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
struct volume_key *vks)
|
||||
{
|
||||
int digest_reencrypt, keyslot_reencrypt, r;
|
||||
struct volume_key *data;
|
||||
|
||||
keyslot_reencrypt = LUKS2_find_keyslot(hdr, "reencrypt");
|
||||
if (keyslot_reencrypt < 0)
|
||||
return keyslot_reencrypt;
|
||||
|
||||
r = reencrypt_assembly_verification_data(cd, hdr, vks, &data);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = LUKS2_digest_create(cd, "pbkdf2", hdr, data);
|
||||
crypt_free_volume_key(data);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
digest_reencrypt = r;
|
||||
|
||||
r = LUKS2_digest_assign(cd, hdr, keyslot_reencrypt, CRYPT_ANY_DIGEST, 0, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return LUKS2_digest_assign(cd, hdr, keyslot_reencrypt, digest_reencrypt, 1, 0);
|
||||
}
|
||||
|
||||
int LUKS2_reencrypt_digest_verify(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
struct volume_key *vks)
|
||||
{
|
||||
int r, keyslot_reencrypt;
|
||||
struct volume_key *data;
|
||||
|
||||
keyslot_reencrypt = LUKS2_find_keyslot(hdr, "reencrypt");
|
||||
if (keyslot_reencrypt < 0)
|
||||
return keyslot_reencrypt;
|
||||
|
||||
r = reencrypt_assembly_verification_data(cd, hdr, vks, &data);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = LUKS2_digest_verify(cd, hdr, data, keyslot_reencrypt);
|
||||
crypt_free_volume_key(data);
|
||||
|
||||
if (r < 0) {
|
||||
if (r == -ENOENT)
|
||||
log_dbg(cd, "Reencryption digest is missing.");
|
||||
log_err(cd, _("Reencryption metadata is invalid."));
|
||||
} else
|
||||
log_dbg(cd, "Reencryption metadata verified.");
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -123,7 +123,7 @@ static json_object *json_segment_get_flags(json_object *jobj_segment)
|
||||
return jobj;
|
||||
}
|
||||
|
||||
static bool json_segment_contains_flag(json_object *jobj_segment, const char *flag_str, size_t len)
|
||||
bool json_segment_contains_flag(json_object *jobj_segment, const char *flag_str, size_t len)
|
||||
{
|
||||
int r, i;
|
||||
json_object *jobj, *jobj_flags = json_segment_get_flags(jobj_segment);
|
||||
@@ -410,3 +410,23 @@ json_object *LUKS2_get_segment_by_flag(struct luks2_hdr *hdr, const char *flag)
|
||||
|
||||
return jobj_segment;
|
||||
}
|
||||
|
||||
/* compares key characteristics of both segments */
|
||||
bool json_segment_cmp(json_object *jobj_segment_1, json_object *jobj_segment_2)
|
||||
{
|
||||
const char *type = json_segment_type(jobj_segment_1);
|
||||
const char *type2 = json_segment_type(jobj_segment_2);
|
||||
|
||||
if (!type || !type2)
|
||||
return false;
|
||||
|
||||
if (strcmp(type, type2))
|
||||
return false;
|
||||
|
||||
if (!strcmp(type, "crypt"))
|
||||
return (json_segment_get_sector_size(jobj_segment_1) == json_segment_get_sector_size(jobj_segment_2) &&
|
||||
!strcmp(json_segment_get_cipher(jobj_segment_1),
|
||||
json_segment_get_cipher(jobj_segment_2)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -63,9 +63,13 @@ static void *token_dlvsym(struct crypt_device *cd,
|
||||
char *error;
|
||||
void *sym;
|
||||
|
||||
#ifdef HAVE_DLVSYM
|
||||
log_dbg(cd, "Loading symbol %s@%s.", symbol, version);
|
||||
|
||||
sym = dlvsym(handle, symbol, version);
|
||||
#else
|
||||
log_dbg(cd, "Loading default version of symbol %s.", symbol);
|
||||
sym = dlsym(handle, symbol);
|
||||
#endif
|
||||
error = dlerror();
|
||||
|
||||
if (error)
|
||||
@@ -182,7 +186,7 @@ crypt_token_load_external(struct crypt_device *cd, const char *name, struct cryp
|
||||
if (r < 0 || (size_t)r >= sizeof(buf))
|
||||
*buf = '\0';
|
||||
|
||||
log_dbg(cd, "Token handler %s-%s loaded sucessfuly.", token->name, buf);
|
||||
log_dbg(cd, "Token handler %s-%s loaded successfully.", token->name, buf);
|
||||
|
||||
token->dlhandle = h;
|
||||
ret->version = 2;
|
||||
@@ -241,6 +245,7 @@ int crypt_token_register(const crypt_token_handler *handler)
|
||||
|
||||
void crypt_token_unload_external_all(struct crypt_device *cd)
|
||||
{
|
||||
#if USE_EXTERNAL_TOKENS
|
||||
int i;
|
||||
|
||||
for (i = LUKS2_TOKENS_MAX - 1; i >= 0; i--) {
|
||||
@@ -254,6 +259,7 @@ void crypt_token_unload_external_all(struct crypt_device *cd)
|
||||
if (dlclose(CONST_CAST(void *)token_handlers[i].u.v2.dlhandle))
|
||||
log_dbg(cd, "%s", dlerror());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static const void
|
||||
|
||||
78
lib/setup.c
78
lib/setup.c
@@ -227,7 +227,7 @@ int init_crypto(struct crypt_device *ctx)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = crypt_backend_init();
|
||||
r = crypt_backend_init(crypt_fips_mode());
|
||||
if (r < 0)
|
||||
log_err(ctx, _("Cannot initialize crypto backend."));
|
||||
|
||||
@@ -1840,7 +1840,7 @@ static int _crypt_format_luks2(struct crypt_device *cd,
|
||||
|
||||
if (sector_size_autodetect) {
|
||||
if (cd->data_offset && MISALIGNED(cd->data_offset, sector_size)) {
|
||||
log_dbg(cd, "Data offset not alligned to sector size. Reverting to 512 bytes.");
|
||||
log_dbg(cd, "Data offset not aligned to sector size. Reverting to 512 bytes.");
|
||||
sector_size = SECTOR_SIZE;
|
||||
} else if (MISALIGNED(dev_size - (uint64_t)required_alignment - (uint64_t)alignment_offset, sector_size)) {
|
||||
/* underflow does not affect misalignment checks */
|
||||
@@ -3955,21 +3955,6 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int load_all_keys(struct crypt_device *cd, struct luks2_hdr *hdr, struct volume_key *vks)
|
||||
{
|
||||
int r;
|
||||
struct volume_key *vk = vks;
|
||||
|
||||
while (vk) {
|
||||
r = LUKS2_volume_key_load_in_keyring_by_digest(cd, hdr, vk, crypt_volume_key_get_id(vk));
|
||||
if (r < 0)
|
||||
return r;
|
||||
vk = crypt_volume_key_next(vk);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* See fixmes in _open_and_activate_luks2 */
|
||||
int update_reencryption_flag(struct crypt_device *cd, int enable, bool commit);
|
||||
|
||||
@@ -4017,6 +4002,22 @@ out:
|
||||
return r < 0 ? r : keyslot;
|
||||
}
|
||||
|
||||
#if USE_LUKS2_REENCRYPTION
|
||||
static int load_all_keys(struct crypt_device *cd, struct luks2_hdr *hdr, struct volume_key *vks)
|
||||
{
|
||||
int r;
|
||||
struct volume_key *vk = vks;
|
||||
|
||||
while (vk) {
|
||||
r = LUKS2_volume_key_load_in_keyring_by_digest(cd, hdr, vk, crypt_volume_key_get_id(vk));
|
||||
if (r < 0)
|
||||
return r;
|
||||
vk = crypt_volume_key_next(vk);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _open_all_keys(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
@@ -4131,6 +4132,12 @@ static int _open_and_activate_reencrypt_device(struct crypt_device *cd,
|
||||
keyslot = r;
|
||||
}
|
||||
|
||||
if (r >= 0) {
|
||||
r = LUKS2_reencrypt_digest_verify(cd, hdr, vks);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
log_dbg(cd, "Entering clean reencryption state mode.");
|
||||
|
||||
if (r >= 0)
|
||||
@@ -4158,8 +4165,9 @@ static int _open_and_activate_luks2(struct crypt_device *cd,
|
||||
uint32_t flags)
|
||||
{
|
||||
crypt_reencrypt_info ri;
|
||||
int r;
|
||||
int r, rv;
|
||||
struct luks2_hdr *hdr = &cd->u.luks2.hdr;
|
||||
struct volume_key *vks = NULL;
|
||||
|
||||
ri = LUKS2_reencrypt_status(hdr);
|
||||
if (ri == CRYPT_REENCRYPT_INVALID)
|
||||
@@ -4169,15 +4177,45 @@ static int _open_and_activate_luks2(struct crypt_device *cd,
|
||||
if (name)
|
||||
r = _open_and_activate_reencrypt_device(cd, hdr, keyslot, name, passphrase,
|
||||
passphrase_size, flags);
|
||||
else
|
||||
else {
|
||||
r = _open_all_keys(cd, hdr, keyslot, passphrase,
|
||||
passphrase_size, flags, NULL);
|
||||
passphrase_size, flags, &vks);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
rv = LUKS2_reencrypt_digest_verify(cd, hdr, vks);
|
||||
crypt_free_volume_key(vks);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
}
|
||||
} else
|
||||
r = _open_and_activate(cd, keyslot, name, passphrase,
|
||||
passphrase_size, flags);
|
||||
|
||||
return r;
|
||||
}
|
||||
#else
|
||||
static int _open_and_activate_luks2(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
const char *name,
|
||||
const char *passphrase,
|
||||
size_t passphrase_size,
|
||||
uint32_t flags)
|
||||
{
|
||||
crypt_reencrypt_info ri;
|
||||
|
||||
ri = LUKS2_reencrypt_status(&cd->u.luks2.hdr);
|
||||
if (ri == CRYPT_REENCRYPT_INVALID)
|
||||
return -EINVAL;
|
||||
|
||||
if (ri > CRYPT_REENCRYPT_NONE) {
|
||||
log_err(cd, _("This operation is not supported for this device type."));
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return _open_and_activate(cd, keyslot, name, passphrase, passphrase_size, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int _activate_by_passphrase(struct crypt_device *cd,
|
||||
const char *name,
|
||||
|
||||
@@ -505,11 +505,11 @@ int device_locked_verify(struct crypt_device *cd, int dev_fd, struct crypt_lock_
|
||||
|
||||
/* if device handle is regular file the handle must match the lock handle */
|
||||
if (S_ISREG(dev_st.st_mode)) {
|
||||
log_dbg(cd, "Veryfing locked device handle (regular file)");
|
||||
log_dbg(cd, "Verifying locked device handle (regular file)");
|
||||
if (!same_inode(dev_st, lck_st))
|
||||
return 1;
|
||||
} else if (S_ISBLK(dev_st.st_mode)) {
|
||||
log_dbg(cd, "Veryfing locked device handle (bdev)");
|
||||
log_dbg(cd, "Verifying locked device handle (bdev)");
|
||||
if (resource_by_devno(res, sizeof(res), dev_st.st_rdev, 1) ||
|
||||
stat(res, &st) ||
|
||||
!same_inode(lck_st, st))
|
||||
|
||||
@@ -24,9 +24,12 @@
|
||||
#include "utils_fips.h"
|
||||
|
||||
#if !ENABLE_FIPS
|
||||
int crypt_fips_mode(void) { return 0; }
|
||||
bool crypt_fips_mode(void) { return false; }
|
||||
#else
|
||||
static int kernel_fips_mode(void)
|
||||
static bool fips_checked = false;
|
||||
static bool fips_mode = false;
|
||||
|
||||
static bool kernel_fips_mode(void)
|
||||
{
|
||||
int fd;
|
||||
char buf[1] = "";
|
||||
@@ -36,11 +39,17 @@ static int kernel_fips_mode(void)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return (buf[0] == '1') ? 1 : 0;
|
||||
return (buf[0] == '1');
|
||||
}
|
||||
|
||||
int crypt_fips_mode(void)
|
||||
bool crypt_fips_mode(void)
|
||||
{
|
||||
return kernel_fips_mode() && !access("/etc/system-fips", F_OK);
|
||||
if (fips_checked)
|
||||
return fips_mode;
|
||||
|
||||
fips_mode = kernel_fips_mode() && !access("/etc/system-fips", F_OK);
|
||||
fips_checked = true;
|
||||
|
||||
return fips_mode;
|
||||
}
|
||||
#endif /* ENABLE_FIPS */
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#ifndef _UTILS_FIPS_H
|
||||
#define _UTILS_FIPS_H
|
||||
|
||||
int crypt_fips_mode(void);
|
||||
#include <stdbool.h>
|
||||
|
||||
bool crypt_fips_mode(void);
|
||||
|
||||
#endif /* _UTILS_FIPS_H */
|
||||
|
||||
@@ -830,6 +830,13 @@ are fixable. This command will only change the LUKS header, not
|
||||
any key-slot data. You may enforce LUKS version by adding \-\-type
|
||||
option.
|
||||
|
||||
It also repairs (upgrades) LUKS2 reencryption metadata by adding
|
||||
metadata digest that protects it against malicious changes.
|
||||
|
||||
If LUKS2 reencryption was interrupted in the middle of writting
|
||||
reencryption segment the repair command can be used to perform
|
||||
reencryption recovery so that reencryption can continue later.
|
||||
|
||||
\fBWARNING:\fR Always create a binary backup of the original
|
||||
header before calling this command.
|
||||
.PP
|
||||
@@ -1568,7 +1575,7 @@ sudo cryptsetup luksAddKey --key-slot 5 /dev/sdX
|
||||
Example 3: Create LUKS header backup and save it to file.
|
||||
sudo cryptsetup luksHeaderBackup /dev/sdX --header-backup-file /var/tmp/NameOfBackupFile
|
||||
.TP
|
||||
Example 4: Open LUKS contaner on /dev/sdX and map it to sdX_crypt.
|
||||
Example 4: Open LUKS container on /dev/sdX and map it to sdX_crypt.
|
||||
sudo cryptsetup open /dev/sdX sdX_crypt
|
||||
.TP
|
||||
.B WARNING: The command in example 5 will erase all key slots.
|
||||
|
||||
@@ -6,6 +6,7 @@ Version: 2.4.0
|
||||
Release: 1%{?dist}
|
||||
License: GPLv2+ and LGPLv2+
|
||||
URL: https://gitlab.com/cryptsetup/cryptsetup
|
||||
BuildRequires: autoconf, automake, libtool, gettext-devel,
|
||||
BuildRequires: openssl-devel, popt-devel, device-mapper-devel
|
||||
BuildRequires: libuuid-devel, gcc, json-c-devel, libargon2-devel
|
||||
BuildRequires: libpwquality-devel, libblkid-devel
|
||||
@@ -13,10 +14,8 @@ BuildRequires: make libssh-devel
|
||||
Requires: cryptsetup-libs = %{version}-%{release}
|
||||
Requires: libpwquality >= 1.2.0
|
||||
|
||||
%global upstream_version %{version}-git
|
||||
%global upstream_version %{version_no_tilde}
|
||||
Source0: https://www.kernel.org/pub/linux/utils/cryptsetup/v2.4/cryptsetup-%{upstream_version}.tar.xz
|
||||
# Following patch has to applied last
|
||||
#Patch9999: %{name}-add-system-library-paths.patch
|
||||
|
||||
%description
|
||||
The cryptsetup package contains a utility for setting up
|
||||
@@ -72,12 +71,12 @@ can be used for offline reencryption of disk in situ.
|
||||
%autosetup -n cryptsetup-%{upstream_version} -p 1
|
||||
|
||||
%build
|
||||
./autogen.sh
|
||||
%configure --enable-fips --enable-pwquality --enable-libargon2
|
||||
%make_build
|
||||
|
||||
%install
|
||||
%make_install
|
||||
mkdir -p -m 0755 $RPM_BUILD_ROOT%{_libdir}/%{name}/
|
||||
rm -rf %{buildroot}%{_libdir}/*.la
|
||||
rm -rf %{buildroot}%{_libdir}/%{name}/*.la
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ lib/luks2/luks2_keyslot_luks2.c
|
||||
lib/luks2/luks2_keyslot_reenc.c
|
||||
lib/luks2/luks2_luks1_convert.c
|
||||
lib/luks2/luks2_reencrypt.c
|
||||
lib/luks2/luks2_reencrypt_digest.c
|
||||
lib/luks2/luks2_segment.c
|
||||
lib/luks2/luks2_token.c
|
||||
lib/luks2/luks2_token_keyring.c
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -52,7 +52,6 @@ veritysetup_SOURCES = \
|
||||
src/utils_arg_names.h \
|
||||
src/utils_arg_macros.h \
|
||||
src/utils_tools.c \
|
||||
src/utils_password.c \
|
||||
src/veritysetup.c \
|
||||
src/veritysetup_args.h \
|
||||
src/veritysetup_arg_list.h \
|
||||
@@ -61,8 +60,6 @@ veritysetup_SOURCES = \
|
||||
veritysetup_LDADD = $(LDADD) \
|
||||
libcryptsetup.la \
|
||||
@POPT_LIBS@ \
|
||||
@PWQUALITY_LIBS@ \
|
||||
@PASSWDQC_LIBS@ \
|
||||
@BLKID_LIBS@
|
||||
|
||||
sbin_PROGRAMS += veritysetup
|
||||
@@ -74,8 +71,7 @@ veritysetup_static_LDFLAGS = $(AM_LDFLAGS) -all-static
|
||||
veritysetup_static_LDADD = \
|
||||
$(veritysetup_LDADD) \
|
||||
@CRYPTO_STATIC_LIBS@ \
|
||||
@DEVMAPPER_STATIC_LIBS@ \
|
||||
@UUID_LIBS@
|
||||
@DEVMAPPER_STATIC_LIBS@
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -91,7 +87,6 @@ integritysetup_SOURCES = \
|
||||
src/utils_arg_names.h \
|
||||
src/utils_arg_macros.h \
|
||||
src/utils_tools.c \
|
||||
src/utils_password.c \
|
||||
src/utils_blockdev.c \
|
||||
src/integritysetup.c \
|
||||
src/integritysetup_args.h \
|
||||
@@ -101,8 +96,6 @@ integritysetup_SOURCES = \
|
||||
integritysetup_LDADD = $(LDADD) \
|
||||
libcryptsetup.la \
|
||||
@POPT_LIBS@ \
|
||||
@PWQUALITY_LIBS@ \
|
||||
@PASSWDQC_LIBS@ \
|
||||
@UUID_LIBS@ \
|
||||
@BLKID_LIBS@
|
||||
|
||||
@@ -115,8 +108,7 @@ integritysetup_static_LDFLAGS = $(AM_LDFLAGS) -all-static
|
||||
integritysetup_static_LDADD = \
|
||||
$(integritysetup_LDADD) \
|
||||
@CRYPTO_STATIC_LIBS@ \
|
||||
@DEVMAPPER_STATIC_LIBS@ \
|
||||
@UUID_LIBS@
|
||||
@DEVMAPPER_STATIC_LIBS@
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
104
src/cryptsetup.c
104
src/cryptsetup.c
@@ -1172,24 +1172,63 @@ static int set_keyslot_params(struct crypt_device *cd, int keyslot)
|
||||
return crypt_set_pbkdf_type(cd, &pbkdf);
|
||||
}
|
||||
|
||||
static int _do_luks2_reencrypt_recovery(struct crypt_device *cd)
|
||||
static int reencrypt_metadata_repair(struct crypt_device *cd)
|
||||
{
|
||||
char *password;
|
||||
size_t passwordLen;
|
||||
int r;
|
||||
struct crypt_params_reencrypt params = {
|
||||
.flags = CRYPT_REENCRYPT_REPAIR_NEEDED
|
||||
};
|
||||
|
||||
if (!ARG_SET(OPT_BATCH_MODE_ID) &&
|
||||
!yesDialog(_("Unprotected LUKS2 reencryption metadata detected. "
|
||||
"Please verify the reencryption operation is desirable (see luksDump output)\n"
|
||||
"and continue (upgrade metadata) only if you acknowledge the operation as genuine."),
|
||||
_("Operation aborted.\n")))
|
||||
return -EINVAL;
|
||||
|
||||
r = tools_get_key(_("Enter passphrase to protect and uppgrade reencryption metadata: "),
|
||||
&password, &passwordLen, ARG_UINT64(OPT_KEYFILE_OFFSET_ID),
|
||||
ARG_UINT32(OPT_KEYFILE_SIZE_ID), ARG_STR(OPT_KEY_FILE_ID), ARG_UINT32(OPT_TIMEOUT_ID),
|
||||
_verify_passphrase(0), 0, cd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = crypt_reencrypt_init_by_passphrase(cd, NULL, password, passwordLen,
|
||||
ARG_INT32(OPT_KEY_SLOT_ID), ARG_INT32(OPT_KEY_SLOT_ID), NULL, NULL, ¶ms);
|
||||
tools_passphrase_msg(r);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = crypt_activate_by_passphrase(cd, NULL, ARG_INT32(OPT_KEY_SLOT_ID),
|
||||
password, passwordLen, 0);
|
||||
tools_passphrase_msg(r);
|
||||
if (r >= 0)
|
||||
r = 0;
|
||||
|
||||
out:
|
||||
crypt_safe_free(password);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int luks2_reencrypt_repair(struct crypt_device *cd)
|
||||
{
|
||||
int r;
|
||||
size_t passwordLen;
|
||||
const char *msg;
|
||||
char *password = NULL;
|
||||
struct crypt_params_reencrypt recovery_params = {
|
||||
.flags = CRYPT_REENCRYPT_RECOVERY
|
||||
};
|
||||
struct crypt_params_reencrypt params = {};
|
||||
|
||||
crypt_reencrypt_info ri = crypt_reencrypt_status(cd, ¶ms);
|
||||
|
||||
if (params.flags & CRYPT_REENCRYPT_REPAIR_NEEDED)
|
||||
return reencrypt_metadata_repair(cd);
|
||||
|
||||
crypt_reencrypt_info ri = crypt_reencrypt_status(cd, NULL);
|
||||
switch (ri) {
|
||||
case CRYPT_REENCRYPT_NONE:
|
||||
/* fall through */
|
||||
return 0;
|
||||
case CRYPT_REENCRYPT_CLEAN:
|
||||
if (ARG_SET(OPT_BATCH_MODE_ID) ||
|
||||
!noDialog(_("Seems device does not require reencryption recovery.\n"
|
||||
"Do you want to proceed anyway?"), NULL))
|
||||
return 0;
|
||||
break;
|
||||
case CRYPT_REENCRYPT_CRASH:
|
||||
if (!ARG_SET(OPT_BATCH_MODE_ID) &&
|
||||
@@ -1201,8 +1240,12 @@ static int _do_luks2_reencrypt_recovery(struct crypt_device *cd)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = tools_get_key(_("Enter passphrase for reencryption recovery: "),
|
||||
&password, &passwordLen, ARG_UINT64(OPT_KEYFILE_OFFSET_ID),
|
||||
if (ri == CRYPT_REENCRYPT_CLEAN)
|
||||
msg = _("Enter passphrase to verify reencryption metadata digest: ");
|
||||
else
|
||||
msg = _("Enter passphrase for reencryption recovery: ");
|
||||
|
||||
r = tools_get_key(msg, &password, &passwordLen, ARG_UINT64(OPT_KEYFILE_OFFSET_ID),
|
||||
ARG_UINT32(OPT_KEYFILE_SIZE_ID), ARG_STR(OPT_KEY_FILE_ID), ARG_UINT32(OPT_TIMEOUT_ID),
|
||||
_verify_passphrase(0), 0, cd);
|
||||
if (r < 0)
|
||||
@@ -1213,8 +1256,14 @@ static int _do_luks2_reencrypt_recovery(struct crypt_device *cd)
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
if (ri == CRYPT_REENCRYPT_CLEAN) {
|
||||
r = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = crypt_reencrypt_init_by_passphrase(cd, NULL, password, passwordLen,
|
||||
ARG_INT32(OPT_KEY_SLOT_ID), ARG_INT32(OPT_KEY_SLOT_ID), NULL, NULL, &recovery_params);
|
||||
ARG_INT32(OPT_KEY_SLOT_ID), ARG_INT32(OPT_KEY_SLOT_ID), NULL, NULL,
|
||||
&(struct crypt_params_reencrypt){ .flags = CRYPT_REENCRYPT_RECOVERY });
|
||||
if (r > 0)
|
||||
r = 0;
|
||||
out:
|
||||
@@ -1235,7 +1284,11 @@ static int action_luksRepair(void)
|
||||
crypt_set_log_callback(cd, quiet_log, &log_parms);
|
||||
r = crypt_load(cd, luksType(device_type), NULL);
|
||||
crypt_set_log_callback(cd, tool_log, &log_parms);
|
||||
if (r == 0) {
|
||||
if (r == 0 && isLUKS2(crypt_get_type(cd))) {
|
||||
/*
|
||||
* LUKS2 triggers autorepair in crypt_load() above
|
||||
* LUKS1 need to call crypt_repair() even if crypt_load() is ok
|
||||
*/
|
||||
log_verbose(_("No known problems detected for LUKS header."));
|
||||
goto out;
|
||||
}
|
||||
@@ -1251,9 +1304,9 @@ static int action_luksRepair(void)
|
||||
else
|
||||
r = crypt_repair(cd, luksType(device_type), NULL);
|
||||
out:
|
||||
/* Header is ok, check if possible interrupted reencryption need repairs. */
|
||||
/* Header is ok, check if reencryption metadata needs repair/recovery. */
|
||||
if (!r && isLUKS2(crypt_get_type(cd)))
|
||||
r = _do_luks2_reencrypt_recovery(cd);
|
||||
r = luks2_reencrypt_repair(cd);
|
||||
|
||||
crypt_free(cd);
|
||||
return r;
|
||||
@@ -2624,6 +2677,11 @@ static int _token_add(struct crypt_device *cd)
|
||||
}
|
||||
}
|
||||
|
||||
if (crypt_keyslot_status(cd, ARG_INT32(OPT_KEY_SLOT_ID)) == CRYPT_SLOT_INACTIVE) {
|
||||
log_err(_("Keyslot %d is not active."), ARG_INT32(OPT_KEY_SLOT_ID));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = crypt_token_luks2_keyring_set(cd, ARG_INT32(OPT_TOKEN_ID_ID), ¶ms);
|
||||
if (r < 0) {
|
||||
log_err(_("Failed to add luks2-keyring token %d."), ARG_INT32(OPT_TOKEN_ID_ID));
|
||||
@@ -2676,6 +2734,11 @@ static int _token_import(struct crypt_device *cd)
|
||||
}
|
||||
}
|
||||
|
||||
if (crypt_keyslot_status(cd, ARG_INT32(OPT_KEY_SLOT_ID)) == CRYPT_SLOT_INACTIVE) {
|
||||
log_err(_("Keyslot %d is not active."), ARG_INT32(OPT_KEY_SLOT_ID));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = tools_read_json_file(ARG_STR(OPT_JSON_FILE_ID), &json, &json_length, ARG_SET(OPT_BATCH_MODE_ID));
|
||||
if (r)
|
||||
return r;
|
||||
@@ -2958,7 +3021,7 @@ static int action_encrypt_luks2(struct crypt_device **cd)
|
||||
if (!ARG_SET(OPT_LUKS2_KEYSLOTS_SIZE_ID))
|
||||
ARG_SET_UINT64(OPT_LUKS2_KEYSLOTS_SIZE_ID, -data_shift - 2 * ARG_UINT64(OPT_LUKS2_METADATA_SIZE_ID));
|
||||
if (2 * ARG_UINT64(OPT_LUKS2_METADATA_SIZE_ID) + ARG_UINT64(OPT_LUKS2_KEYSLOTS_SIZE_ID) > (uint64_t)-data_shift) {
|
||||
log_err("LUKS2 metadata size is larger than data shift value.");
|
||||
log_err(_("LUKS2 metadata size is larger than data shift value."));
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
@@ -2990,7 +3053,7 @@ static int action_encrypt_luks2(struct crypt_device **cd)
|
||||
r = crypt_header_restore(*cd, CRYPT_LUKS2, header_file);
|
||||
|
||||
if (r) {
|
||||
log_err("Failed to place new header at head of device %s.", action_argv[0]);
|
||||
log_err(_("Failed to place new header at head of device %s."), action_argv[0]);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -3036,8 +3099,9 @@ static int action_decrypt_luks2(struct crypt_device *cd)
|
||||
};
|
||||
size_t passwordLen;
|
||||
|
||||
if (!crypt_get_metadata_device_name(cd) || crypt_header_is_detached(cd) <= 0) {
|
||||
log_err(_("LUKS2 decryption is supported with detached header device only."));
|
||||
if (!crypt_get_metadata_device_name(cd) || crypt_header_is_detached(cd) <= 0 ||
|
||||
crypt_get_data_offset(cd) > 0) {
|
||||
log_err(_("LUKS2 decryption is supported with detached header device only (with data offset set to 0)."));
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
|
||||
@@ -350,7 +350,7 @@ static int parse_log(struct reenc_ctx *rc)
|
||||
if (end) {
|
||||
*end++ = '\0';
|
||||
if (parse_line_log(rc, start)) {
|
||||
log_err("Wrong log format.");
|
||||
log_err(_("Wrong log format."));
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,10 +291,10 @@ int tools_wipe_all_signatures(const char *path)
|
||||
|
||||
while ((pr = blk_probe(h)) < PRB_EMPTY) {
|
||||
if (blk_is_partition(h))
|
||||
log_verbose("Existing '%s' partition signature on device %s will be wiped.",
|
||||
log_verbose(_("Existing '%s' partition signature on device %s will be wiped."),
|
||||
blk_get_partition_type(h), path);
|
||||
if (blk_is_superblock(h))
|
||||
log_verbose("Existing '%s' superblock signature on device %s will be wiped.",
|
||||
log_verbose(_("Existing '%s' superblock signature on device %s will be wiped."),
|
||||
blk_get_superblock_type(h), path);
|
||||
if (blk_do_wipe(h)) {
|
||||
log_err(_("Failed to wipe device signature."));
|
||||
|
||||
@@ -318,59 +318,3 @@ void tools_passphrase_msg(int r)
|
||||
else if (r == -ENOENT)
|
||||
log_err(_("No usable keyslot is available."));
|
||||
}
|
||||
|
||||
int tools_read_mk(const char *file, char **key, int keysize)
|
||||
{
|
||||
int fd = -1, r = -EINVAL;
|
||||
|
||||
if (keysize <= 0 || !key)
|
||||
return -EINVAL;
|
||||
|
||||
*key = crypt_safe_alloc(keysize);
|
||||
if (!*key)
|
||||
return -ENOMEM;
|
||||
|
||||
fd = open(file, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
log_err(_("Cannot read keyfile %s."), file);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (read_buffer(fd, *key, keysize) != keysize) {
|
||||
log_err(_("Cannot read %d bytes from keyfile %s."), keysize, file);
|
||||
goto out;
|
||||
}
|
||||
r = 0;
|
||||
out:
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
|
||||
if (r) {
|
||||
crypt_safe_free(*key);
|
||||
*key = NULL;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int tools_write_mk(const char *file, const char *key, int keysize)
|
||||
{
|
||||
int fd, r = -EINVAL;
|
||||
|
||||
if (keysize <= 0 || !key)
|
||||
return -EINVAL;
|
||||
|
||||
fd = open(file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR);
|
||||
if (fd < 0) {
|
||||
log_err(_("Cannot open keyfile %s for write."), file);
|
||||
return r;
|
||||
}
|
||||
|
||||
if (write_buffer(fd, key, keysize) == keysize)
|
||||
r = 0;
|
||||
else
|
||||
log_err(_("Cannot write to keyfile %s."), file);
|
||||
|
||||
close(fd);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -116,8 +116,9 @@ static int _dialog(const char *msg, void *usrptr, int default_answer)
|
||||
set_int_block(0);
|
||||
|
||||
if (isatty(STDIN_FILENO)) {
|
||||
log_std("\nWARNING!\n========\n");
|
||||
log_std("%s\n\nAre you sure? (Type 'yes' in capital letters): ", msg);
|
||||
log_std(_("\nWARNING!\n========\n"));
|
||||
/* TRANSLATORS: User must type "YES" (in capital letters), do not translate this word. */
|
||||
log_std(_("%s\n\nAre you sure? (Type 'yes' in capital letters): "), msg);
|
||||
fflush(stdout);
|
||||
if(getline(&answer, &size, stdin) == -1) {
|
||||
r = 0;
|
||||
@@ -493,3 +494,59 @@ int tools_reencrypt_progress(uint64_t size, uint64_t offset, void *usrptr)
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int tools_read_mk(const char *file, char **key, int keysize)
|
||||
{
|
||||
int fd = -1, r = -EINVAL;
|
||||
|
||||
if (keysize <= 0 || !key)
|
||||
return -EINVAL;
|
||||
|
||||
*key = crypt_safe_alloc(keysize);
|
||||
if (!*key)
|
||||
return -ENOMEM;
|
||||
|
||||
fd = open(file, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
log_err(_("Cannot read keyfile %s."), file);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (read_buffer(fd, *key, keysize) != keysize) {
|
||||
log_err(_("Cannot read %d bytes from keyfile %s."), keysize, file);
|
||||
goto out;
|
||||
}
|
||||
r = 0;
|
||||
out:
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
|
||||
if (r) {
|
||||
crypt_safe_free(*key);
|
||||
*key = NULL;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int tools_write_mk(const char *file, const char *key, int keysize)
|
||||
{
|
||||
int fd, r = -EINVAL;
|
||||
|
||||
if (keysize <= 0 || !key)
|
||||
return -EINVAL;
|
||||
|
||||
fd = open(file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR);
|
||||
if (fd < 0) {
|
||||
log_err(_("Cannot open keyfile %s for write."), file);
|
||||
return r;
|
||||
}
|
||||
|
||||
if (write_buffer(fd, key, keysize) == keysize)
|
||||
r = 0;
|
||||
else
|
||||
log_err(_("Cannot write to keyfile %s."), file);
|
||||
|
||||
close(fd);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ if [ -f /etc/os-release ] ; then
|
||||
fi
|
||||
|
||||
echo "Memory"
|
||||
free -h
|
||||
free -m
|
||||
|
||||
pversion cryptsetup
|
||||
pversion veritysetup
|
||||
|
||||
@@ -27,7 +27,7 @@ TESTS += verity-compat-test
|
||||
endif
|
||||
|
||||
if REENCRYPT
|
||||
TESTS += reencryption-compat-test reencryption-compat-test2 luks2-reencryption-test
|
||||
TESTS += reencryption-compat-test reencryption-compat-test2 luks2-reencryption-test luks2-reencryption-mangle-test
|
||||
endif
|
||||
|
||||
if INTEGRITYSETUP
|
||||
@@ -36,6 +36,7 @@ endif
|
||||
|
||||
if SSHPLUGIN_TOKEN
|
||||
TESTS += ssh-plugin-test
|
||||
endif
|
||||
|
||||
ssh-plugin-test: fake_token_path.so
|
||||
|
||||
@@ -44,7 +45,6 @@ fake_token_path.so:
|
||||
-Wl,--version-script=$(top_srcdir)/lib/libcryptsetup.sym \
|
||||
-o fake_token_path.so $(top_srcdir)/tests/fake_token_path.c \
|
||||
-DBUILD_DIR=\"$(abs_top_srcdir)/.libs/\"
|
||||
endif
|
||||
|
||||
EXTRA_DIST = compatimage.img.xz compatv10image.img.xz \
|
||||
compatimage2.img.xz \
|
||||
@@ -72,6 +72,7 @@ EXTRA_DIST = compatimage.img.xz compatv10image.img.xz \
|
||||
reencryption-compat-test \
|
||||
reencryption-compat-test2 \
|
||||
luks2-reencryption-test \
|
||||
luks2-reencryption-mangle-test \
|
||||
tcrypt-compat-test \
|
||||
luks1-compat-test \
|
||||
luks2-validation-test generators \
|
||||
@@ -95,19 +96,17 @@ CLEANFILES = cryptsetup-tst* valglog* *-fail-*.log test-symbols-list.h fake_toke
|
||||
clean-local:
|
||||
-rm -rf tcrypt-images luks1-images luks2-images bitlk-images conversion_imgs luks2_valid_hdr.img blkid-luks2-pv-img blkid-luks2-pv-img.bcp
|
||||
|
||||
LDADD = $(LTLIBINTL)
|
||||
|
||||
differ_SOURCES = differ.c
|
||||
differ_CFLAGS = $(AM_CFLAGS) -Wall -O2
|
||||
|
||||
api_test_SOURCES = api-test.c api_test.h test_utils.c
|
||||
api_test_LDADD = $(LDADD) ../libcryptsetup.la
|
||||
api_test_LDADD = ../libcryptsetup.la
|
||||
api_test_LDFLAGS = $(AM_LDFLAGS) -static
|
||||
api_test_CFLAGS = -g -Wall -O0 $(AM_CFLAGS) -I$(top_srcdir)/lib
|
||||
api_test_CPPFLAGS = $(AM_CPPFLAGS) -include config.h
|
||||
|
||||
api_test_2_SOURCES = api-test-2.c api_test.h test_utils.c
|
||||
api_test_2_LDADD = $(LDADD) ../libcryptsetup.la
|
||||
api_test_2_LDADD = ../libcryptsetup.la
|
||||
api_test_2_LDFLAGS = $(AM_LDFLAGS) -static
|
||||
api_test_2_CFLAGS = -g -Wall -O0 $(AM_CFLAGS) -I$(top_srcdir)/lib
|
||||
api_test_2_CPPFLAGS = $(AM_CPPFLAGS) -include config.h
|
||||
@@ -132,11 +131,14 @@ test-symbols-list.h: $(top_srcdir)/lib/libcryptsetup.sym generate-symbols-list
|
||||
all_symbols_test_SOURCES = all-symbols-test.c
|
||||
nodist_all_symbols_test_SOURCES = test-symbols-list.h
|
||||
all_symbols_test.$(OBJEXT): test-symbols-list.h
|
||||
all_symbols_test_CFLAGS = -ldl
|
||||
all_symbols_test_LDFLAGS = $(AM_LDFLAGS) -ldl
|
||||
all_symbols_test_CFLAGS = $(AM_CFLAGS)
|
||||
all_symbols_test_CPPFLAGS = $(AM_CPPFLAGS) -D_GNU_SOURCE
|
||||
|
||||
check_PROGRAMS = api-test api-test-2 differ vectors-test unit-utils-io all-symbols-test
|
||||
|
||||
check-programs: $(check_PROGRAMS) fake_token_path.so
|
||||
|
||||
conversion_imgs:
|
||||
@tar xJf conversion_imgs.tar.xz
|
||||
|
||||
@@ -153,6 +155,7 @@ valgrind-check: api-test api-test-2 differ
|
||||
@INFOSTRING="api-test-000" ./valg-api.sh ./api-test
|
||||
@INFOSTRING="api-test-002" ./valg-api.sh ./api-test-2
|
||||
@VALG=1 ./luks2-reencryption-test
|
||||
@VALG=1 ./luks2-reencryption-mangle-test
|
||||
@VALG=1 ./bitlk-compat-test
|
||||
@VALG=1 ./tcrypt-compat-test
|
||||
@grep -l "ERROR SUMMARY: [^0] errors" valglog* || echo "No leaks detected."
|
||||
|
||||
@@ -68,34 +68,57 @@ static void test_logf(int level, const char *format, ...)
|
||||
#define log_std(x...) test_logf(LOG_NORMAL, x)
|
||||
#define log_err(x...) test_logf(LOG_ERROR, x)
|
||||
|
||||
static int check_all_symbols(void *h)
|
||||
static int check_dlvsym(void *h, const char *symbol, const char *version)
|
||||
{
|
||||
#ifdef HAVE_DLVSYM
|
||||
void *sym;
|
||||
char *err;
|
||||
|
||||
log_dbg("Checking %s@%s...", symbol, version);
|
||||
sym = dlvsym(h, symbol, version);
|
||||
UNUSED(sym);
|
||||
err = dlerror();
|
||||
|
||||
if (err) {
|
||||
log_err("%s.", err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
log_dbg("OK\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_dlsym(void *h, const char *symbol)
|
||||
{
|
||||
void *sym;
|
||||
char *err;
|
||||
|
||||
log_dbg("Checking %s...", symbol);
|
||||
sym = dlsym(h, symbol);
|
||||
UNUSED(sym);
|
||||
err = dlerror();
|
||||
|
||||
if (err) {
|
||||
log_err("%s", err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
log_dbg("OK\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_all_symbols(void *h)
|
||||
{
|
||||
unsigned scount = 0;
|
||||
|
||||
#define CHECK_SYMBOL(SYM, VER) \
|
||||
do { \
|
||||
log_dbg("Checking " #SYM "@" #VER "..."); \
|
||||
sym = dlvsym(h, #SYM, #VER); \
|
||||
UNUSED(sym); \
|
||||
err = dlerror(); \
|
||||
\
|
||||
if (err) { \
|
||||
log_err("%s.", err); \
|
||||
return 1; \
|
||||
} \
|
||||
\
|
||||
log_dbg("OK\nChecking " #SYM "..."); \
|
||||
sym = dlsym(h, #SYM); \
|
||||
UNUSED(sym); \
|
||||
err = dlerror(); \
|
||||
if (err) { \
|
||||
log_err("%s", err); \
|
||||
return 1; \
|
||||
} \
|
||||
log_dbg("OK\n"); \
|
||||
scount++; \
|
||||
#define CHECK_SYMBOL(SYM, VER) \
|
||||
do { \
|
||||
if (check_dlvsym(h, #SYM, #VER)) \
|
||||
return 1; \
|
||||
if (check_dlsym(h, #SYM)) \
|
||||
return 1; \
|
||||
scount++; \
|
||||
} while (0);
|
||||
|
||||
#include "test-symbols-list.h"
|
||||
@@ -106,7 +129,7 @@ do { \
|
||||
return 1;
|
||||
}
|
||||
|
||||
log_std("Performed %u symbol checks in total\n.", scount);
|
||||
log_std("Performed %u symbol checks in total.\n", scount);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -44,8 +44,6 @@ typedef int32_t key_serial_t;
|
||||
#include "luks1/luks.h"
|
||||
#include "libcryptsetup.h"
|
||||
|
||||
#define DMDIR "/dev/mapper/"
|
||||
|
||||
#define DEVICE_1_UUID "28632274-8c8a-493f-835b-da802e1c576b"
|
||||
#define DEVICE_EMPTY_name "crypt_zero"
|
||||
#define DEVICE_EMPTY DMDIR DEVICE_EMPTY_name
|
||||
@@ -3807,6 +3805,7 @@ static void Luks2Flags(void)
|
||||
CRYPT_FREE(cd);
|
||||
}
|
||||
|
||||
#if KERNEL_KEYRING && USE_LUKS2_REENCRYPTION
|
||||
static int test_progress(uint64_t size __attribute__((unused)),
|
||||
uint64_t offset __attribute__((unused)),
|
||||
void *usrptr __attribute__((unused)))
|
||||
@@ -3819,7 +3818,6 @@ static int test_progress(uint64_t size __attribute__((unused)),
|
||||
static void Luks2Reencryption(void)
|
||||
{
|
||||
/* reencryption currently depends on kernel keyring support */
|
||||
#if KERNEL_KEYRING
|
||||
/* NOTES:
|
||||
* - reencryption requires luks2 parameters. can we avoid it?
|
||||
*/
|
||||
@@ -3844,6 +3842,7 @@ static void Luks2Reencryption(void)
|
||||
.hash = "sha1",
|
||||
.luks2 = ¶ms2,
|
||||
};
|
||||
dev_t devno;
|
||||
|
||||
const char *mk_hex = "bb21babe733229347bd4e681891e213d94c685be6a5b84818afe7a78a6de7a1a";
|
||||
size_t key_size = strlen(mk_hex) / 2;
|
||||
@@ -4239,7 +4238,7 @@ static void Luks2Reencryption(void)
|
||||
|
||||
_cleanup_dmdevices();
|
||||
OK_(create_dmdevice_over_loop(H_DEVICE, r_header_size));
|
||||
OK_(create_dmdevice_over_loop(L_DEVICE_OK, 12*1024*2+1));
|
||||
OK_(create_dmdevice_over_loop(L_DEVICE_OK, 8*1024*2+1));
|
||||
|
||||
/* encryption with datashift and moved segment (data shift + 1 sector) */
|
||||
OK_(crypt_init(&cd, DMDIR H_DEVICE));
|
||||
@@ -4259,11 +4258,11 @@ static void Luks2Reencryption(void)
|
||||
|
||||
_cleanup_dmdevices();
|
||||
OK_(create_dmdevice_over_loop(H_DEVICE, r_header_size));
|
||||
OK_(create_dmdevice_over_loop(L_DEVICE_OK, 12*1024*2));
|
||||
OK_(create_dmdevice_over_loop(L_DEVICE_OK, 2*8200));
|
||||
|
||||
OK_(crypt_init(&cd, DMDIR H_DEVICE));
|
||||
|
||||
/* encryption with datashift and moved segment (data shift + data offset > device size) */
|
||||
/* encryption with datashift and moved segment (data shift + data offset <= device size) */
|
||||
memset(&rparams, 0, sizeof(rparams));
|
||||
params2.sector_size = 512;
|
||||
params2.data_device = DMDIR L_DEVICE_OK;
|
||||
@@ -4320,6 +4319,22 @@ static void Luks2Reencryption(void)
|
||||
OK_(crypt_reencrypt_run(cd, NULL, NULL));
|
||||
CRYPT_FREE(cd);
|
||||
|
||||
/* decryption forward (online) */
|
||||
OK_(crypt_init(&cd, DMDIR L_DEVICE_OK));
|
||||
params2.data_device = NULL;
|
||||
OK_(crypt_format(cd, CRYPT_LUKS2, "aes", "cbc-essiv:sha256", NULL, NULL, 32, ¶ms2));
|
||||
OK_(crypt_set_pbkdf_type(cd, &pbkdf));
|
||||
EQ_(crypt_keyslot_add_by_volume_key(cd, 6, NULL, 32, PASSPHRASE, strlen(PASSPHRASE)), 6);
|
||||
EQ_(crypt_activate_by_passphrase(cd, CDEVICE_2, 6, PASSPHRASE, strlen(PASSPHRASE), 0), 6);
|
||||
memset(&rparams, 0, sizeof(rparams));
|
||||
rparams.mode = CRYPT_REENCRYPT_DECRYPT;
|
||||
rparams.direction = CRYPT_REENCRYPT_FORWARD;
|
||||
rparams.resilience = "none";
|
||||
rparams.max_hotzone_size = 2048;
|
||||
OK_(crypt_reencrypt_init_by_passphrase(cd, CDEVICE_2, PASSPHRASE, strlen(PASSPHRASE), 6, CRYPT_ANY_SLOT, NULL, NULL, &rparams));
|
||||
OK_(crypt_reencrypt_run(cd, NULL, NULL));
|
||||
CRYPT_FREE(cd);
|
||||
|
||||
/* decryption with data shift */
|
||||
OK_(crypt_init(&cd, DMDIR L_DEVICE_OK));
|
||||
params2.data_device = NULL;
|
||||
@@ -4354,6 +4369,8 @@ static void Luks2Reencryption(void)
|
||||
EQ_(crypt_activate_by_passphrase(cd, CDEVICE_2, 6, PASSPHRASE, strlen(PASSPHRASE), 0), 6);
|
||||
OK_(t_device_size(DMDIR CDEVICE_2, &r_size_1));
|
||||
EQ_(r_size_1, 512);
|
||||
// store devno for later size check
|
||||
OK_(t_get_devno(CDEVICE_2, &devno));
|
||||
// create placeholder device to block automatic deactivation after decryption
|
||||
OK_(_system("dmsetup create " CDEVICE_1 " --table \"0 1 linear " DMDIR CDEVICE_2 " 0\"", 1));
|
||||
remove(BACKUP_FILE);
|
||||
@@ -4373,7 +4390,7 @@ static void Luks2Reencryption(void)
|
||||
EQ_(crypt_get_data_offset(cd), 0);
|
||||
OK_(crypt_reencrypt_run(cd, NULL, NULL));
|
||||
remove(BACKUP_FILE);
|
||||
OK_(t_device_size(DMDIR CDEVICE_2, &r_size_1));
|
||||
OK_(t_device_size_by_devno(devno, &r_size_1));
|
||||
EQ_(r_size_1, 512);
|
||||
OK_(_system("dmsetup remove " DM_RETRY CDEVICE_1 DM_NOSTDERR, 0));
|
||||
CRYPT_FREE(cd);
|
||||
@@ -4521,8 +4538,8 @@ static void Luks2Reencryption(void)
|
||||
crypt_free(cd);
|
||||
|
||||
_cleanup_dmdevices();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
static void Luks2Repair(void)
|
||||
{
|
||||
@@ -4638,7 +4655,9 @@ int main(int argc, char *argv[])
|
||||
RUN_(Luks2Integrity, "LUKS2 with data integrity");
|
||||
RUN_(Luks2Refresh, "Active device table refresh");
|
||||
RUN_(Luks2Flags, "LUKS2 persistent flags");
|
||||
#if KERNEL_KEYRING && USE_LUKS2_REENCRYPTION
|
||||
RUN_(Luks2Reencryption, "LUKS2 reencryption");
|
||||
#endif
|
||||
RUN_(Luks2Repair, "LUKS2 repair"); // test disables metadata locking. Run always last!
|
||||
|
||||
_cleanup();
|
||||
|
||||
@@ -34,8 +34,6 @@
|
||||
#include "luks1/luks.h"
|
||||
#include "libcryptsetup.h"
|
||||
|
||||
#define DMDIR "/dev/mapper/"
|
||||
|
||||
#define DEVICE_1_UUID "28632274-8c8a-493f-835b-da802e1c576b"
|
||||
#define DEVICE_EMPTY_name "crypt_zero"
|
||||
#define DEVICE_EMPTY DMDIR DEVICE_EMPTY_name
|
||||
|
||||
@@ -96,6 +96,8 @@ void xlog(const char *msg, const char *tst, const char *func, int line, const ch
|
||||
|
||||
#define CRYPT_FREE(x) do { crypt_free(x); x = NULL; } while (0)
|
||||
|
||||
#define DMDIR "/dev/mapper/"
|
||||
|
||||
#define TST_SECTOR_SHIFT 9L
|
||||
#define TST_SECTOR_SIZE 512
|
||||
#define TST_LOOP_FILE_SIZE (((1 << 20) * 100) >> TST_SECTOR_SHIFT)
|
||||
@@ -124,4 +126,7 @@ int loop_attach(char **loop, const char *file, int offset,
|
||||
int autoclear, int *readonly);
|
||||
int loop_detach(const char *loop);
|
||||
|
||||
int t_device_size_by_devno(dev_t devno, uint64_t *retval);
|
||||
int t_get_devno(const char *dev, dev_t *devno);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -16,6 +16,7 @@ CRYPTSETUP_LIB_VALGRIND=../.libs
|
||||
function remove_mapping()
|
||||
{
|
||||
[ -b /dev/mapper/$MAP ] && dmsetup remove --retry $MAP
|
||||
rm -rf $TST_DIR
|
||||
}
|
||||
|
||||
function fail()
|
||||
@@ -32,6 +33,7 @@ function skip()
|
||||
{
|
||||
[ -n "$1" ] && echo "$1"
|
||||
echo "Test skipped."
|
||||
remove_mapping
|
||||
exit 77
|
||||
}
|
||||
|
||||
@@ -92,7 +94,7 @@ function valgrind_run()
|
||||
}
|
||||
|
||||
export LANG=C
|
||||
[ ! -d $TST_DIR ] && tar xJSf $srcdir/bitlk-images.tar.xz --no-same-owner
|
||||
[ ! -d $TST_DIR ] && tar xJSf $srcdir/bitlk-images.tar.xz --no-same-owner 2>/dev/null || skip "Incompatible tar."
|
||||
|
||||
[ -n "$VALG" ] && valgrind_setup && CRYPTSETUP=valgrind_run
|
||||
|
||||
@@ -106,11 +108,10 @@ done
|
||||
|
||||
if [ $(id -u) != 0 ]; then
|
||||
echo "WARNING: You must be root to run activation part of test, test skipped."
|
||||
remove_mapping
|
||||
exit 0
|
||||
fi
|
||||
|
||||
remove_mapping
|
||||
|
||||
echo "ACTIVATION FS UUID CHECK"
|
||||
for file in $(ls $TST_DIR/bitlk-*) ; do
|
||||
# load variables for this image from config file
|
||||
@@ -185,3 +186,6 @@ for file in $(ls $TST_DIR/bitlk-*) ; do
|
||||
|
||||
fi
|
||||
done
|
||||
|
||||
remove_mapping
|
||||
exit 0
|
||||
|
||||
Binary file not shown.
@@ -434,10 +434,12 @@ $CRYPTSETUP -q luksFormat --type luks1 $FAST_PBKDF_OPT --master-key-file /dev/ur
|
||||
$CRYPTSETUP luksOpen -d $KEY1 $LOOPDEV $DEV_NAME || fail
|
||||
$CRYPTSETUP -q luksClose $DEV_NAME || fail
|
||||
# open by UUID
|
||||
force_uevent # some systems do not update loop by-uuid
|
||||
$CRYPTSETUP luksOpen -d $KEY1 UUID=X$TEST_UUID $DEV_NAME 2>/dev/null && fail
|
||||
$CRYPTSETUP luksOpen -d $KEY1 UUID=$TEST_UUID $DEV_NAME || fail
|
||||
$CRYPTSETUP -q luksClose $DEV_NAME || fail
|
||||
if [ -d /dev/disk/by-uuid ] ; then
|
||||
force_uevent # some systems do not update loop by-uuid
|
||||
$CRYPTSETUP luksOpen -d $KEY1 UUID=X$TEST_UUID $DEV_NAME 2>/dev/null && fail
|
||||
$CRYPTSETUP luksOpen -d $KEY1 UUID=$TEST_UUID $DEV_NAME || fail
|
||||
$CRYPTSETUP -q luksClose $DEV_NAME || fail
|
||||
fi
|
||||
# empty keyfile
|
||||
$CRYPTSETUP -q luksFormat --type luks1 $FAST_PBKDF_OPT $LOOPDEV $KEYE || fail
|
||||
$CRYPTSETUP luksOpen -d $KEYE $LOOPDEV $DEV_NAME || fail
|
||||
@@ -788,6 +790,17 @@ $CRYPTSETUP luksOpen -d $KEY1 $LOOPDEV $DEV_NAME >/dev/null 2>&1 && fail
|
||||
$CRYPTSETUP -q repair $LOOPDEV >/dev/null 2>&1 || fail
|
||||
$CRYPTSETUP luksOpen -d $KEY1 $LOOPDEV $DEV_NAME || fail
|
||||
$CRYPTSETUP luksClose $DEV_NAME || fail
|
||||
# fix ecb-plain
|
||||
$CRYPTSETUP -q luksFormat --type luks1 $FAST_PBKDF_OPT $LOOPDEV $KEY1 --hash sha256 -c aes-ecb || fail
|
||||
echo -n "ecb-xxx" | dd of=$LOOPDEV bs=1 seek=40 >/dev/null 2>&1
|
||||
$CRYPTSETUP -q repair $LOOPDEV >/dev/null 2>&1 || fail
|
||||
$CRYPTSETUP luksOpen -d $KEY1 $LOOPDEV $DEV_NAME || fail
|
||||
$CRYPTSETUP luksClose $DEV_NAME || fail
|
||||
# fix uppercase hash
|
||||
echo -n "SHA256" | dd of=$LOOPDEV bs=1 seek=72 >/dev/null 2>&1
|
||||
$CRYPTSETUP -q repair $LOOPDEV >/dev/null 2>&1 || fail
|
||||
$CRYPTSETUP luksOpen -d $KEY1 $LOOPDEV $DEV_NAME || fail
|
||||
$CRYPTSETUP luksClose $DEV_NAME || fail
|
||||
|
||||
prepare "[30] LUKS erase" wipe
|
||||
$CRYPTSETUP -q luksFormat --type luks1 $FAST_PBKDF_OPT $LOOPDEV $KEY5 --key-slot 5 || fail
|
||||
|
||||
@@ -415,10 +415,12 @@ $CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --master-key-file /dev/urandom -s 256
|
||||
$CRYPTSETUP luksOpen -d $KEY1 $LOOPDEV $DEV_NAME || fail
|
||||
$CRYPTSETUP -q luksClose $DEV_NAME || fail
|
||||
# open by UUID
|
||||
force_uevent # some systems do not update loop by-uuid
|
||||
$CRYPTSETUP luksOpen -d $KEY1 UUID=X$TEST_UUID $DEV_NAME 2>/dev/null && fail
|
||||
$CRYPTSETUP luksOpen -d $KEY1 UUID=$TEST_UUID $DEV_NAME || fail
|
||||
$CRYPTSETUP -q luksClose $DEV_NAME || fail
|
||||
if [ -d /dev/disk/by-uuid ] ; then
|
||||
force_uevent # some systems do not update loop by-uuid
|
||||
$CRYPTSETUP luksOpen -d $KEY1 UUID=X$TEST_UUID $DEV_NAME 2>/dev/null && fail
|
||||
$CRYPTSETUP luksOpen -d $KEY1 UUID=$TEST_UUID $DEV_NAME || fail
|
||||
$CRYPTSETUP -q luksClose $DEV_NAME || fail
|
||||
fi
|
||||
# empty keyfile
|
||||
$CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV $KEYE || fail
|
||||
$CRYPTSETUP luksOpen -d $KEYE $LOOPDEV $DEV_NAME || fail
|
||||
@@ -872,9 +874,12 @@ echo -n "$IMPORT_TOKEN" | $CRYPTSETUP token import $LOOPDEV --token-id 11 --json
|
||||
echo -n "$IMPORT_TOKEN" > $TOKEN_FILE0
|
||||
$CRYPTSETUP token import $LOOPDEV --token-id 12 --json-file $TOKEN_FILE0 || fail
|
||||
$CRYPTSETUP token import $LOOPDEV --token-id 12 --json-file $TOKEN_FILE0 2>/dev/null && fail
|
||||
$CRYPTSETUP token export $LOOPDEV --token-id 10 | diff --from-file - $TOKEN_FILE0 || fail
|
||||
$CRYPTSETUP token export $LOOPDEV --token-id 11 | diff --from-file - $TOKEN_FILE0 || fail
|
||||
$CRYPTSETUP token export $LOOPDEV --token-id 12 | diff --from-file - $TOKEN_FILE0 || fail
|
||||
$CRYPTSETUP token export $LOOPDEV --token-id 10 >$TOKEN_FILE1 || fail
|
||||
diff $TOKEN_FILE0 $TOKEN_FILE1 || fail
|
||||
$CRYPTSETUP token export $LOOPDEV --token-id 11 >$TOKEN_FILE1 || fail
|
||||
diff $TOKEN_FILE0 $TOKEN_FILE1 || fail
|
||||
$CRYPTSETUP token export $LOOPDEV --token-id 12 >$TOKEN_FILE1 || fail
|
||||
diff $TOKEN_FILE0 $TOKEN_FILE1 || fail
|
||||
$CRYPTSETUP token export $LOOPDEV --token-id 12 --json-file $TOKEN_FILE1 || fail
|
||||
diff $TOKEN_FILE0 $TOKEN_FILE1 || fail
|
||||
$CRYPTSETUP token export $LOOPDEV --token-id 12 > $TOKEN_FILE1 || fail
|
||||
@@ -1002,7 +1007,8 @@ for mda in 16 32 64 128 256 512 1024 2048 4096 ; do
|
||||
echo $PWD4 | $CRYPTSETUP open --test-passphrase test_image_$mda || fail
|
||||
echo $PWD3 | $CRYPTSETUP open -S9 --test-passphrase test_image_$mda || fail
|
||||
echo -n "$IMPORT_TOKEN" | $CRYPTSETUP token import test_image_$mda --token-id 10 || fail
|
||||
$CRYPTSETUP token export test_image_$mda --token-id 10 | diff --from-file - $TOKEN_FILE0 || fail
|
||||
$CRYPTSETUP token export test_image_$mda --token-id 10 >$TOKEN_FILE1 || fail
|
||||
diff $TOKEN_FILE1 $TOKEN_FILE0 || fail
|
||||
echo -n "[OK]"
|
||||
done
|
||||
echo
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "crypto_backend/crypto_backend.h"
|
||||
|
||||
@@ -40,6 +42,24 @@ static void printhex(const char *s, const char *buf, size_t len)
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static bool fips_mode(void)
|
||||
{
|
||||
int fd;
|
||||
char buf = 0;
|
||||
|
||||
fd = open("/proc/sys/crypto/fips_enabled", O_RDONLY);
|
||||
|
||||
if (fd < 0)
|
||||
return false;
|
||||
|
||||
if (read(fd, &buf, 1) != 1)
|
||||
buf = '0';
|
||||
|
||||
close(fd);
|
||||
|
||||
return (buf == '1');
|
||||
}
|
||||
|
||||
/*
|
||||
* KDF tests
|
||||
*/
|
||||
@@ -104,6 +124,27 @@ static struct kdf_test_vector kdf_test_vectors[] = {
|
||||
// "\xd0\x1e\xf0\x45\x2d\x75\xb6\x5e"
|
||||
// "\xb5\x25\x20\xe9\x6b\x01\xe6\x59", 32
|
||||
},
|
||||
/* empty password */
|
||||
{
|
||||
"argon2i", NULL, 0, 3, 128, 1,
|
||||
"", 0,
|
||||
"\x00\x01\x02\x03\x04\x05\x06\x07"
|
||||
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", 16,
|
||||
"\xbb\x1f\xf2\xb9\x9f\xd4\x4a\xd9"
|
||||
"\xdf\x7f\xb9\x54\x55\x9e\xb8\xeb"
|
||||
"\xb5\x9d\xab\xce\x2e\x62\x9f\x9b"
|
||||
"\x89\x09\xfe\xde\x57\xcc\x63\x86", 32
|
||||
},
|
||||
{
|
||||
"argon2id", NULL, 0, 3, 128, 1,
|
||||
"", 0,
|
||||
"\x00\x01\x02\x03\x04\x05\x06\x07"
|
||||
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", 16,
|
||||
"\x09\x2f\x38\x35\xac\xb2\x43\x92"
|
||||
"\x93\xeb\xcd\xe8\x04\x16\x6a\x31"
|
||||
"\xce\x14\xd4\x55\xdb\xd8\xf7\xe6"
|
||||
"\xb4\xf5\x9d\x64\x8e\xd0\x3a\xdb", 32
|
||||
},
|
||||
/* RFC 3962 */
|
||||
{
|
||||
"pbkdf2", "sha1", 64, 1, 0, 0,
|
||||
@@ -918,7 +959,7 @@ static int pbkdf_test_vectors(void)
|
||||
unsigned int i;
|
||||
const struct kdf_test_vector *vec;
|
||||
|
||||
for (i = 0; i < (sizeof(kdf_test_vectors) / sizeof(*kdf_test_vectors)); i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(kdf_test_vectors); i++) {
|
||||
crypt_backend_memzero(result, sizeof(result));
|
||||
vec = &kdf_test_vectors[i];
|
||||
printf("PBKDF vector %02d %s ", i, vec->type);
|
||||
@@ -1012,17 +1053,37 @@ static int hash_test(void)
|
||||
if (!r)
|
||||
r = crypt_hash_final(h, result, vector->out[j].length);
|
||||
|
||||
crypt_hash_destroy(h);
|
||||
|
||||
if (r)
|
||||
if (r) {
|
||||
crypt_hash_destroy(h);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (memcmp(result, vector->out[j].out, vector->out[j].length)) {
|
||||
printf("[FAILED]\n");
|
||||
printhex(" got", result, vector->out[j].length);
|
||||
printhex("want", vector->out[j].out, vector->out[j].length);
|
||||
crypt_hash_destroy(h);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/*
|
||||
* After crypt_hash_final() the context must be reset, repeat
|
||||
*/
|
||||
crypt_backend_memzero(result, sizeof(result));
|
||||
r = crypt_hash_write(h, vector->data, vector->data_length);
|
||||
if (!r)
|
||||
r = crypt_hash_final(h, result, vector->out[j].length);
|
||||
|
||||
if (r || memcmp(result, vector->out[j].out, vector->out[j].length)) {
|
||||
printf("[FAILED (RESET CONTEXT)]\n");
|
||||
printhex(" got", result, vector->out[j].length);
|
||||
printhex("want", vector->out[j].out, vector->out[j].length);
|
||||
crypt_hash_destroy(h);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
crypt_hash_destroy(h);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
@@ -1065,17 +1126,36 @@ static int hmac_test(void)
|
||||
if (!r)
|
||||
r = crypt_hmac_final(hmac, result, vector->out[j].length);
|
||||
|
||||
crypt_hmac_destroy(hmac);
|
||||
|
||||
if (r)
|
||||
if (r) {
|
||||
crypt_hmac_destroy(hmac);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (memcmp(result, vector->out[j].out, vector->out[j].length)) {
|
||||
printf("[FAILED]\n");
|
||||
printhex(" got", result, vector->out[j].length);
|
||||
printhex("want", vector->out[j].out, vector->out[j].length);
|
||||
crypt_hmac_destroy(hmac);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/*
|
||||
* After crypt_hmac_final() the context must be reset, repeat
|
||||
*/
|
||||
crypt_backend_memzero(result, sizeof(result));
|
||||
r = crypt_hmac_write(hmac, vector->data, vector->data_length);
|
||||
if (!r)
|
||||
r = crypt_hmac_final(hmac, result, vector->out[j].length);
|
||||
|
||||
if (r || memcmp(result, vector->out[j].out, vector->out[j].length)) {
|
||||
printf("[FAILED (RESET CONTEXT)]\n");
|
||||
printhex(" got", result, vector->out[j].length);
|
||||
printhex("want", vector->out[j].out, vector->out[j].length);
|
||||
crypt_hmac_destroy(hmac);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
crypt_hmac_destroy(hmac);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
@@ -1231,6 +1311,39 @@ static int cipher_iv_test(void)
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int check_hash(const char *hash)
|
||||
{
|
||||
struct crypt_hash *h;
|
||||
|
||||
if (crypt_hash_size(hash) < 0)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if (crypt_hash_init(&h, hash))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
crypt_hash_destroy(h);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int default_alg_test(void)
|
||||
{
|
||||
printf("Defaults: [LUKS1 hash %s] ", DEFAULT_LUKS1_HASH);
|
||||
if (check_hash(DEFAULT_LUKS1_HASH))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
printf("[PLAIN hash %s] ", DEFAULT_PLAIN_HASH);
|
||||
if (check_hash(DEFAULT_PLAIN_HASH))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
printf("[VERITY hash %s] ", DEFAULT_VERITY_HASH);
|
||||
if (check_hash(DEFAULT_VERITY_HASH))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
printf("[OK]\n");
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static void __attribute__((noreturn)) exit_test(const char *msg, int r)
|
||||
{
|
||||
if (msg)
|
||||
@@ -1248,7 +1361,7 @@ int main(__attribute__ ((unused)) int argc, __attribute__ ((unused))char *argv[]
|
||||
exit(77);
|
||||
}
|
||||
|
||||
if (crypt_backend_init())
|
||||
if (crypt_backend_init(fips_mode()))
|
||||
exit_test("Crypto backend init error.", EXIT_FAILURE);
|
||||
|
||||
printf("Test vectors using %s crypto backend.\n", crypt_backend_version());
|
||||
@@ -1268,5 +1381,12 @@ int main(__attribute__ ((unused)) int argc, __attribute__ ((unused))char *argv[]
|
||||
if (cipher_iv_test())
|
||||
exit_test("IV test failed.", EXIT_FAILURE);
|
||||
|
||||
if (default_alg_test()) {
|
||||
if (fips_mode())
|
||||
printf("\nDefault compiled-in algorithms test ignored (FIPS mode on).\n");
|
||||
else
|
||||
exit_test("\nDefault compiled-in algorithms test failed.", EXIT_FAILURE);
|
||||
}
|
||||
|
||||
exit_test(NULL, EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
96
tests/generators/generate-luks2-metadata-size-invalid-secondary.img.sh
Executable file
96
tests/generators/generate-luks2-metadata-size-invalid-secondary.img.sh
Executable file
@@ -0,0 +1,96 @@
|
||||
#!/bin/bash
|
||||
|
||||
. lib.sh
|
||||
|
||||
#
|
||||
# *** Description ***
|
||||
#
|
||||
# generate primary with predefined json_size. There's only limited
|
||||
# set of values allowed as json size in config section of LUKS2
|
||||
# metadata
|
||||
#
|
||||
# secondary header is corrupted on purpose as well
|
||||
#
|
||||
|
||||
# $1 full target dir
|
||||
# $2 full source luks2 image
|
||||
|
||||
function prepare()
|
||||
{
|
||||
cp $SRC_IMG $TGT_IMG
|
||||
test -d $TMPDIR || mkdir $TMPDIR
|
||||
read_luks2_json0 $TGT_IMG $TMPDIR/json0
|
||||
read_luks2_bin_hdr0 $TGT_IMG $TMPDIR/hdr0
|
||||
read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr1
|
||||
}
|
||||
|
||||
function generate()
|
||||
{
|
||||
TEST_MDA_SIZE=$LUKS2_HDR_SIZE_1M
|
||||
|
||||
TEST_MDA_SIZE_BYTES=$((TEST_MDA_SIZE*512))
|
||||
TEST_MDA_SIZE_BOGUS_BYTES=$((TEST_MDA_SIZE*512*2*1024))
|
||||
TEST_JSN_SIZE=$((TEST_MDA_SIZE-LUKS2_BIN_HDR_SIZE))
|
||||
KEYSLOTS_OFFSET=$((TEST_MDA_SIZE*1024))
|
||||
JSON_DIFF=$(((TEST_MDA_SIZE-LUKS2_HDR_SIZE)*1024))
|
||||
JSON_SIZE=$((TEST_JSN_SIZE*512))
|
||||
DATA_OFFSET=16777216
|
||||
|
||||
json_str=$(jq -c --arg jdiff $JSON_DIFF --arg jsize $JSON_SIZE --arg off $DATA_OFFSET \
|
||||
'.keyslots[].area.offset |= ( . | tonumber + ($jdiff | tonumber) | tostring) |
|
||||
.config.json_size = $jsize |
|
||||
.segments."0".offset = $off' $TMPDIR/json0)
|
||||
test -n "$json_str" || exit 2
|
||||
test ${#json_str} -lt $((LUKS2_JSON_SIZE*512)) || exit 2
|
||||
|
||||
write_luks2_json "$json_str" $TMPDIR/json0 $TEST_JSN_SIZE
|
||||
|
||||
write_bin_hdr_size $TMPDIR/hdr0 $TEST_MDA_SIZE_BYTES
|
||||
write_bin_hdr_size $TMPDIR/hdr1 $TEST_MDA_SIZE_BOGUS_BYTES
|
||||
|
||||
write_bin_hdr_offset $TMPDIR/hdr1 $TEST_MDA_SIZE_BYTES
|
||||
|
||||
merge_bin_hdr_with_json $TMPDIR/hdr0 $TMPDIR/json0 $TMPDIR/area0 $TEST_JSN_SIZE
|
||||
merge_bin_hdr_with_json $TMPDIR/hdr1 $TMPDIR/json0 $TMPDIR/area1 $TEST_JSN_SIZE
|
||||
|
||||
erase_checksum $TMPDIR/area0
|
||||
chks0=$(calc_sha256_checksum_file $TMPDIR/area0)
|
||||
write_checksum $chks0 $TMPDIR/area0
|
||||
|
||||
erase_checksum $TMPDIR/area1
|
||||
chks0=$(calc_sha256_checksum_file $TMPDIR/area1)
|
||||
write_checksum $chks0 $TMPDIR/area1
|
||||
|
||||
kill_bin_hdr $TMPDIR/area0
|
||||
|
||||
write_luks2_hdr0 $TMPDIR/area0 $TGT_IMG $TEST_MDA_SIZE
|
||||
write_luks2_hdr1 $TMPDIR/area1 $TGT_IMG $TEST_MDA_SIZE
|
||||
}
|
||||
|
||||
function check()
|
||||
{
|
||||
read_luks2_bin_hdr0 $TGT_IMG $TMPDIR/hdr_res0 $TEST_MDA_SIZE
|
||||
local str_res0=$(head -c 6 $TMPDIR/hdr_res0)
|
||||
test "$str_res0" = "VACUUM" || exit 2
|
||||
read_luks2_json1 $TGT_IMG $TMPDIR/json_res1 $TEST_JSN_SIZE
|
||||
jq -c --arg koff $KEYSLOTS_OFFSET --arg jsize $JSON_SIZE \
|
||||
'if ([.keyslots[].area.offset] | map(tonumber) | min | tostring != $koff) or
|
||||
(.config.json_size != $jsize)
|
||||
then error("Unexpected value in result json") else empty end' $TMPDIR/json_res1 || exit 5
|
||||
}
|
||||
|
||||
function cleanup()
|
||||
{
|
||||
rm -f $TMPDIR/*
|
||||
rm -fd $TMPDIR
|
||||
}
|
||||
|
||||
test $# -eq 2 || exit 1
|
||||
|
||||
TGT_IMG=$1/$(test_img_name $0)
|
||||
SRC_IMG=$2
|
||||
|
||||
prepare
|
||||
generate
|
||||
check
|
||||
cleanup
|
||||
94
tests/generators/generate-luks2-metadata-size-invalid.img.sh
Executable file
94
tests/generators/generate-luks2-metadata-size-invalid.img.sh
Executable file
@@ -0,0 +1,94 @@
|
||||
#!/bin/bash
|
||||
|
||||
. lib.sh
|
||||
|
||||
#
|
||||
# *** Description ***
|
||||
#
|
||||
# generate primary with predefined json_size. There's only limited
|
||||
# set of values allowed as json size in config section of LUKS2
|
||||
# metadata
|
||||
#
|
||||
# secondary header is corrupted on purpose as well
|
||||
#
|
||||
|
||||
# $1 full target dir
|
||||
# $2 full source luks2 image
|
||||
|
||||
function prepare()
|
||||
{
|
||||
cp $SRC_IMG $TGT_IMG
|
||||
test -d $TMPDIR || mkdir $TMPDIR
|
||||
read_luks2_json0 $TGT_IMG $TMPDIR/json0
|
||||
read_luks2_bin_hdr0 $TGT_IMG $TMPDIR/hdr0
|
||||
read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr1
|
||||
}
|
||||
|
||||
function generate()
|
||||
{
|
||||
TEST_MDA_SIZE=$LUKS2_HDR_SIZE_1M
|
||||
|
||||
TEST_MDA_SIZE_BYTES=$((TEST_MDA_SIZE*512))
|
||||
TEST_MDA_SIZE_BOGUS_BYTES=$((TEST_MDA_SIZE*512*2*1024))
|
||||
TEST_JSN_SIZE=$((TEST_MDA_SIZE-LUKS2_BIN_HDR_SIZE))
|
||||
KEYSLOTS_OFFSET=$((TEST_MDA_SIZE*1024))
|
||||
JSON_DIFF=$(((TEST_MDA_SIZE-LUKS2_HDR_SIZE)*1024))
|
||||
JSON_SIZE=$((TEST_JSN_SIZE*512))
|
||||
DATA_OFFSET=16777216
|
||||
|
||||
json_str=$(jq -c --arg jdiff $JSON_DIFF --arg jsize $JSON_SIZE --arg off $DATA_OFFSET \
|
||||
'.keyslots[].area.offset |= ( . | tonumber + ($jdiff | tonumber) | tostring) |
|
||||
.config.json_size = $jsize |
|
||||
.segments."0".offset = $off' $TMPDIR/json0)
|
||||
test -n "$json_str" || exit 2
|
||||
test ${#json_str} -lt $((LUKS2_JSON_SIZE*512)) || exit 2
|
||||
|
||||
write_luks2_json "$json_str" $TMPDIR/json0 $TEST_JSN_SIZE
|
||||
|
||||
write_bin_hdr_size $TMPDIR/hdr0 $TEST_MDA_SIZE_BOGUS_BYTES
|
||||
write_bin_hdr_size $TMPDIR/hdr1 $TEST_MDA_SIZE_BOGUS_BYTES
|
||||
|
||||
merge_bin_hdr_with_json $TMPDIR/hdr0 $TMPDIR/json0 $TMPDIR/area0 $TEST_JSN_SIZE
|
||||
merge_bin_hdr_with_json $TMPDIR/hdr1 $TMPDIR/json0 $TMPDIR/area1 $TEST_JSN_SIZE
|
||||
|
||||
erase_checksum $TMPDIR/area0
|
||||
chks0=$(calc_sha256_checksum_file $TMPDIR/area0)
|
||||
write_checksum $chks0 $TMPDIR/area0
|
||||
|
||||
erase_checksum $TMPDIR/area1
|
||||
chks0=$(calc_sha256_checksum_file $TMPDIR/area1)
|
||||
write_checksum $chks0 $TMPDIR/area1
|
||||
|
||||
kill_bin_hdr $TMPDIR/area1
|
||||
|
||||
write_luks2_hdr0 $TMPDIR/area0 $TGT_IMG $TEST_MDA_SIZE
|
||||
write_luks2_hdr1 $TMPDIR/area1 $TGT_IMG $TEST_MDA_SIZE
|
||||
}
|
||||
|
||||
function check()
|
||||
{
|
||||
read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr_res1 $TEST_MDA_SIZE
|
||||
local str_res1=$(head -c 6 $TMPDIR/hdr_res1)
|
||||
test "$str_res1" = "VACUUM" || exit 2
|
||||
read_luks2_json0 $TGT_IMG $TMPDIR/json_res0 $TEST_JSN_SIZE
|
||||
jq -c --arg koff $KEYSLOTS_OFFSET --arg jsize $JSON_SIZE \
|
||||
'if ([.keyslots[].area.offset] | map(tonumber) | min | tostring != $koff) or
|
||||
(.config.json_size != $jsize)
|
||||
then error("Unexpected value in result json") else empty end' $TMPDIR/json_res0 || exit 5
|
||||
}
|
||||
|
||||
function cleanup()
|
||||
{
|
||||
rm -f $TMPDIR/*
|
||||
rm -fd $TMPDIR
|
||||
}
|
||||
|
||||
test $# -eq 2 || exit 1
|
||||
|
||||
TGT_IMG=$1/$(test_img_name $0)
|
||||
SRC_IMG=$2
|
||||
|
||||
prepare
|
||||
generate
|
||||
check
|
||||
cleanup
|
||||
@@ -168,12 +168,11 @@ intformat() # alg alg_out tagsize outtagsize sector_size csum [keyfile keysize]
|
||||
echo -n "[FORMAT]"
|
||||
$INTSETUP format --integrity-legacy-padding -q --integrity $1 $TAG_PARAMS --sector-size $5 $KEY_PARAMS $DEV >/dev/null 2>&1
|
||||
if [ $? -ne 0 ] ; then
|
||||
ALG=$(echo $1 | sed -e 's/hmac-//')
|
||||
if ! grep -q $ALG /proc/crypto ; then
|
||||
echo "[N/A]"
|
||||
return
|
||||
if [[ $1 =~ "sha" || $1 =~ "crc" ]] ; then
|
||||
fail "Cannot format device."
|
||||
fi
|
||||
fail "Cannot format device."
|
||||
echo "[N/A]"
|
||||
return
|
||||
fi
|
||||
|
||||
dump_check "tag_size" $4
|
||||
@@ -335,6 +334,7 @@ which blockdev >/dev/null || skip "Cannot find blockdev utility, test skipped."
|
||||
|
||||
[ -n "$VALG" ] && valgrind_setup && INTSETUP=valgrind_run
|
||||
which hexdump >/dev/null 2>&1 || skip "WARNING: hexdump tool required."
|
||||
which xxd >/dev/null 2>&1 || skip "WARNING: xxd tool required."
|
||||
modprobe dm-integrity >/dev/null 2>&1
|
||||
dm_integrity_features
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ KEYFILE=keyfile1
|
||||
function remove_mapping()
|
||||
{
|
||||
[ -b /dev/mapper/$MAP ] && dmsetup remove --retry $MAP
|
||||
rm -rf $TST_DIR
|
||||
}
|
||||
|
||||
function fail()
|
||||
@@ -33,6 +34,7 @@ function skip()
|
||||
{
|
||||
[ -n "$1" ] && echo "$1"
|
||||
echo "Test skipped."
|
||||
remove_mapping
|
||||
exit 77
|
||||
}
|
||||
|
||||
@@ -80,6 +82,7 @@ done
|
||||
|
||||
if [ $(id -u) != 0 ]; then
|
||||
echo "WARNING: You must be root to run activation part of test, test skipped."
|
||||
remove_mapping
|
||||
exit 0
|
||||
fi
|
||||
|
||||
@@ -102,3 +105,6 @@ for file in $(ls $TST_DIR/luks1_*) ; do
|
||||
[ "$UUID" != "DEAD-BABE" ] && fail "UUID check failed."
|
||||
echo " [OK]"
|
||||
done
|
||||
|
||||
remove_mapping
|
||||
exit 0
|
||||
|
||||
504
tests/luks2-reencryption-mangle-test
Executable file
504
tests/luks2-reencryption-mangle-test
Executable file
@@ -0,0 +1,504 @@
|
||||
#!/bin/bash
|
||||
|
||||
PS4='$LINENO:'
|
||||
[ -z "$CRYPTSETUP_PATH" ] && CRYPTSETUP_PATH=".."
|
||||
CRYPTSETUP=$CRYPTSETUP_PATH/cryptsetup
|
||||
CRYPTSETUP_RAW=$CRYPTSETUP
|
||||
|
||||
CRYPTSETUP_VALGRIND=../.libs/cryptsetup
|
||||
CRYPTSETUP_LIB_VALGRIND=../.libs
|
||||
IMG=reenc-mangle-data
|
||||
IMG_HDR=$IMG.hdr
|
||||
IMG_JSON=$IMG.json
|
||||
KEY1=key1
|
||||
DEV_NAME=reenc3492834
|
||||
|
||||
FAST_PBKDF2="--pbkdf pbkdf2 --pbkdf-force-iterations 1000"
|
||||
CS_PWPARAMS="--disable-keyring --key-file $KEY1"
|
||||
CS_PARAMS="-q --disable-locks $CS_PWPARAMS"
|
||||
JSON_MSIZE=16384
|
||||
|
||||
function remove_mapping()
|
||||
{
|
||||
[ -b /dev/mapper/$DEV_NAME ] && dmsetup remove --retry $DEV_NAME
|
||||
rm -f $IMG $IMG_HDR $IMG_JSON $KEY1 >/dev/null 2>&1
|
||||
}
|
||||
|
||||
function fail()
|
||||
{
|
||||
local frame=0
|
||||
[ -n "$1" ] && echo "$1"
|
||||
echo "FAILED backtrace:"
|
||||
while caller $frame; do ((frame++)); done
|
||||
remove_mapping
|
||||
exit 2
|
||||
}
|
||||
|
||||
function skip()
|
||||
{
|
||||
[ -n "$1" ] && echo "$1"
|
||||
remove_mapping
|
||||
exit 77
|
||||
}
|
||||
|
||||
function bin_check()
|
||||
{
|
||||
which $1 >/dev/null 2>&1 || skip "WARNING: test require $1 binary, test skipped."
|
||||
}
|
||||
|
||||
function img_json_save()
|
||||
{
|
||||
# FIXME: why --json-file cannot be used?
|
||||
$CRYPTSETUP luksDump --dump-json-metadata $IMG | jq -c -M . | tr -d '\n' >$IMG_JSON
|
||||
}
|
||||
|
||||
function img_json_dump()
|
||||
{
|
||||
img_json_save
|
||||
jq . $IMG_JSON
|
||||
}
|
||||
|
||||
function img_hash_save()
|
||||
{
|
||||
IMG_HASH=$(sha256sum $IMG | cut -d' ' -f 1)
|
||||
}
|
||||
|
||||
function img_hash_unchanged()
|
||||
{
|
||||
local IMG_HASH2=$(sha256sum $IMG | cut -d' ' -f 1)
|
||||
[ "$IMG_HASH" != "$IMG_HASH2" ] && fail "Image changed!"
|
||||
}
|
||||
|
||||
function img_prepare_raw() # $1 options
|
||||
{
|
||||
remove_mapping
|
||||
|
||||
if [ ! -e $KEY1 ]; then
|
||||
dd if=/dev/urandom of=$KEY1 count=1 bs=32 >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
truncate -s 32M $IMG || fail
|
||||
$CRYPTSETUP luksFormat $FAST_PBKDF2 $CS_PARAMS --luks2-metadata-size $JSON_MSIZE $IMG $1 || fail
|
||||
}
|
||||
|
||||
function img_prepare() # $1 options
|
||||
{
|
||||
img_prepare_raw
|
||||
# FIXME: resilience is not saved here (always none)?
|
||||
$CRYPTSETUP reencrypt $IMG $CS_PARAMS -q --init-only --resilience none $1 >/dev/null 2>&1
|
||||
[ $? -ne 0 ] && skip "Reencryption unsupported, test skipped."
|
||||
img_json_save
|
||||
img_hash_save
|
||||
}
|
||||
|
||||
function _dd()
|
||||
{
|
||||
dd $@ status=none conv=notrunc bs=1
|
||||
}
|
||||
|
||||
# header mangle functions
|
||||
function img_update_json()
|
||||
{
|
||||
local LUKS2_BIN1_OFFSET=448
|
||||
local LUKS2_BIN2_OFFSET=$((LUKS2_BIN1_OFFSET + $JSON_MSIZE))
|
||||
local LUKS2_JSON_SIZE=$(($JSON_MSIZE - 4096))
|
||||
|
||||
# if present jq script, mangle JSON
|
||||
if [ -n "$1" ]; then
|
||||
local JSON=$(cat $IMG_JSON)
|
||||
echo $JSON | jq -M -c "$1" >$IMG_JSON || fail
|
||||
local JSON=$(cat $IMG_JSON)
|
||||
echo $JSON | tr -d '\n' >$IMG_JSON || fail
|
||||
fi
|
||||
|
||||
# wipe JSON areas
|
||||
_dd if=/dev/zero of=$IMG count=$LUKS2_JSON_SIZE seek=4096
|
||||
_dd if=/dev/zero of=$IMG count=$LUKS2_JSON_SIZE seek=$(($JSON_MSIZE + 4096))
|
||||
|
||||
# write JSON data
|
||||
_dd if=$IMG_JSON of=$IMG count=$LUKS2_JSON_SIZE seek=4096
|
||||
_dd if=$IMG_JSON of=$IMG count=$LUKS2_JSON_SIZE seek=$(($JSON_MSIZE + 4096))
|
||||
|
||||
# erase sha256 checksums
|
||||
_dd if=/dev/zero of=$IMG count=64 seek=$LUKS2_BIN1_OFFSET
|
||||
_dd if=/dev/zero of=$IMG count=64 seek=$LUKS2_BIN2_OFFSET
|
||||
|
||||
# calculate sha256 and write chexksums
|
||||
local SUM1_HEX=$(_dd if=$IMG count=$JSON_MSIZE | sha256sum | cut -d ' ' -f 1)
|
||||
echo $SUM1_HEX | xxd -r -p | _dd of=$IMG seek=$LUKS2_BIN1_OFFSET count=64 || fail
|
||||
|
||||
local SUM2_HEX=$(_dd if=$IMG skip=$JSON_MSIZE count=$JSON_MSIZE | sha256sum | cut -d ' ' -f 1)
|
||||
echo $SUM2_HEX | xxd -r -p | _dd of=$IMG seek=$LUKS2_BIN2_OFFSET count=64 || fail
|
||||
|
||||
img_hash_save
|
||||
}
|
||||
|
||||
function img_check_ok()
|
||||
{
|
||||
if [ $(id -u) == 0 ]; then
|
||||
$CRYPTSETUP open $CS_PWPARAMS $IMG $DEV_NAME || fail
|
||||
$CRYPTSETUP close $DEV_NAME || fail
|
||||
fi
|
||||
|
||||
$CRYPTSETUP repair $IMG $CS_PARAMS || fail
|
||||
}
|
||||
|
||||
function img_check_fail()
|
||||
{
|
||||
if [ $(id -u) == 0 ]; then
|
||||
$CRYPTSETUP open $CS_PWPARAMS $IMG $DEV_NAME 2>/dev/null && fail
|
||||
fi
|
||||
|
||||
$CRYPTSETUP repair $IMG $CS_PARAMS 2>/dev/null && fail
|
||||
img_hash_unchanged
|
||||
}
|
||||
|
||||
function img_run_reenc_ok()
|
||||
{
|
||||
local EXPECT_TIMEOUT=5
|
||||
[ -n "$VALG" ] && EXPECT_TIMEOUT=60
|
||||
# For now, we cannot run reencryption in batch mode for non-block device. Just fake the terminal here.
|
||||
expect_run - >/dev/null <<EOF
|
||||
proc abort {} { send_error "Timeout. "; exit 2 }
|
||||
set timeout $EXPECT_TIMEOUT
|
||||
eval spawn $CRYPTSETUP_RAW reencrypt $IMG $CS_PWPARAMS --disable-locks --resilience none
|
||||
expect timeout abort "Are you sure? (Type 'yes' in capital letters):"
|
||||
send "YES\n"
|
||||
expect timeout abort eof
|
||||
exit
|
||||
EOF
|
||||
[ $? -eq 0 ] || fail "Expect script failed."
|
||||
}
|
||||
|
||||
function img_run_reenc_fail()
|
||||
{
|
||||
local EXPECT_TIMEOUT=5
|
||||
[ -n "$VALG" ] && EXPECT_TIMEOUT=60
|
||||
# For now, we cannot run reencryption in batch mode for non-block device. Just fake the terminal here.
|
||||
expect_run - >/dev/null <<EOF
|
||||
proc abort {} { send_error "Timeout. "; exit 42 }
|
||||
set timeout $EXPECT_TIMEOUT
|
||||
eval spawn $CRYPTSETUP_RAW reencrypt $IMG $CS_PWPARAMS --disable-locks
|
||||
expect timeout abort "Are you sure? (Type 'yes' in capital letters):"
|
||||
send "YES\n"
|
||||
expect timeout abort eof
|
||||
catch wait result
|
||||
exit [lindex \$result 3]
|
||||
EOF
|
||||
local ret=$?
|
||||
[ $ret -eq 0 ] && fail "Reencryption passed (should have failed)."
|
||||
[ $ret -eq 42 ] && fail "Expect script failed."
|
||||
img_hash_unchanged
|
||||
}
|
||||
|
||||
function img_check_fail_repair_ok()
|
||||
{
|
||||
if [ $(id -u) == 0 ]; then
|
||||
$CRYPTSETUP open $CS_PWPARAMS $IMG $DEV_NAME 2>/dev/null && fail
|
||||
fi
|
||||
|
||||
img_run_reenc_fail
|
||||
|
||||
# repair metadata
|
||||
$CRYPTSETUP repair $IMG $CS_PARAMS || fail
|
||||
|
||||
img_check_ok
|
||||
img_run_reenc_ok
|
||||
}
|
||||
|
||||
function valgrind_setup()
|
||||
{
|
||||
bin_check valgrind
|
||||
[ ! -f $CRYPTSETUP_VALGRIND ] && fail "Unable to get location of cryptsetup executable."
|
||||
export LD_LIBRARY_PATH="$CRYPTSETUP_LIB_VALGRIND:$LD_LIBRARY_PATH"
|
||||
CRYPTSETUP=valgrind_run
|
||||
CRYPTSETUP_RAW="./valg.sh ${CRYPTSETUP_VALGRIND}"
|
||||
}
|
||||
|
||||
function valgrind_run()
|
||||
{
|
||||
INFOSTRING="$(basename ${BASH_SOURCE[1]})-line-${BASH_LINENO[0]}" ./valg.sh ${CRYPTSETUP_VALGRIND} "$@"
|
||||
}
|
||||
|
||||
function expect_run()
|
||||
{
|
||||
export INFOSTRING="$(basename ${BASH_SOURCE[1]})-line-${BASH_LINENO[0]}"
|
||||
expect "$@"
|
||||
}
|
||||
|
||||
bin_check jq
|
||||
bin_check sha256sum
|
||||
bin_check xxd
|
||||
bin_check expect
|
||||
|
||||
export LANG=C
|
||||
|
||||
[ -n "$VALG" ] && valgrind_setup && CRYPTSETUP=valgrind_run
|
||||
|
||||
#while false; do
|
||||
|
||||
echo "[1] Reencryption with old flag is rejected"
|
||||
img_prepare
|
||||
img_update_json '.config.requirements.mandatory = ["online-reencryptx"]'
|
||||
img_check_fail
|
||||
img_update_json '.config.requirements.mandatory = ["online-reencrypt-v2"]'
|
||||
img_check_ok
|
||||
img_run_reenc_ok
|
||||
img_check_ok
|
||||
|
||||
# Simulate old reencryption with no digest (repairable)
|
||||
img_prepare
|
||||
img_update_json 'del(.digests."2") | .config.requirements.mandatory = ["online-reencrypt"]'
|
||||
img_check_fail_repair_ok
|
||||
|
||||
# This must fail for new releases
|
||||
echo "[2] Old reencryption in-progress (journal)"
|
||||
img_prepare
|
||||
img_update_json '
|
||||
del(.digests."2") |
|
||||
.keyslots."2".area.type = "journal" |
|
||||
.segments = {
|
||||
"0" : (.segments."0" +
|
||||
{"size" : .keyslots."2".area.size} +
|
||||
{"flags" : ["in-reencryption"]}),
|
||||
"1" : (.segments."0" +
|
||||
{"offset" : ((.segments."0".offset|tonumber) +
|
||||
(.keyslots."2".area.size|tonumber))|tostring}),
|
||||
"2" : .segments."1",
|
||||
"3" : .segments."2"
|
||||
} |
|
||||
.digests."0".segments = ["1","2"] |
|
||||
.digests."1".segments = ["0","3"] |
|
||||
.config.requirements.mandatory = ["online-reencrypt"]'
|
||||
img_check_fail_repair_ok
|
||||
|
||||
echo "[3] Old reencryption in-progress (checksum)"
|
||||
img_prepare
|
||||
img_update_json '
|
||||
del(.digests."2") |
|
||||
.keyslots."2".area.type = "checksum" |
|
||||
.keyslots."2".area.hash = "sha256" |
|
||||
.keyslots."2".area.sector_size = 4096 |
|
||||
.segments = {
|
||||
"0" : (.segments."0" +
|
||||
{"size" : .keyslots."2".area.size} +
|
||||
{"flags" : ["in-reencryption"]}),
|
||||
"1" : (.segments."0" +
|
||||
{"offset": ((.segments."0".offset|tonumber) +
|
||||
(.keyslots."2".area.size|tonumber))|tostring}),
|
||||
"2" : .segments."1",
|
||||
"3" : .segments."2"
|
||||
} |
|
||||
.digests."0".segments = ["1","2"] |
|
||||
.digests."1".segments = ["0","3"] |
|
||||
.config.requirements.mandatory = ["online-reencrypt"]'
|
||||
img_check_fail_repair_ok
|
||||
|
||||
# Note: older tools cannot create this from commandline
|
||||
echo "[4] Old decryption in-progress (journal)"
|
||||
img_prepare
|
||||
img_update_json '
|
||||
del(.digests."1") |
|
||||
del(.digests."2") |
|
||||
del(.keyslots."1") |
|
||||
.keyslots."2".mode = "decrypt" |
|
||||
.keyslots."2".area.type = "journal" |
|
||||
.segments = {
|
||||
"0" : {
|
||||
"type" : "linear",
|
||||
"offset" : .segments."0".offset,
|
||||
"size" : .keyslots."2".area.size,
|
||||
"flags" : ["in-reencryption"]
|
||||
},
|
||||
"1" : (.segments."0" +
|
||||
{"offset" : ((.segments."0".offset|tonumber) +
|
||||
(.keyslots."2".area.size|tonumber))|tostring}),
|
||||
"2" : .segments."1",
|
||||
"3" : {
|
||||
"type" : "linear",
|
||||
"offset" : .segments."0".offset,
|
||||
"size" : "dynamic",
|
||||
"flags" : ["backup-final"]
|
||||
}
|
||||
} |
|
||||
.digests."0".segments = ["1","2"] |
|
||||
.config.requirements.mandatory = ["online-reencrypt"]'
|
||||
img_check_fail_repair_ok
|
||||
|
||||
echo "[5] Old decryption in-progress (checksum)"
|
||||
img_prepare
|
||||
img_update_json '
|
||||
del(.digests."1") |
|
||||
del(.digests."2") |
|
||||
del(.keyslots."1") |
|
||||
.keyslots."2".mode = "decrypt" |
|
||||
.keyslots."2".area.type = "checksum" |
|
||||
.keyslots."2".area.hash = "sha256" |
|
||||
.keyslots."2".area.sector_size = 4096 |
|
||||
.segments = {
|
||||
"0" : {
|
||||
"type" : "linear",
|
||||
"offset" : .segments."0".offset,
|
||||
"size" : .keyslots."2".area.size,
|
||||
"flags" : ["in-reencryption"]
|
||||
},
|
||||
"1" : (.segments."0" +
|
||||
{"offset" : ((.segments."0".offset|tonumber) +
|
||||
(.keyslots."2".area.size|tonumber))|tostring}),
|
||||
"2" : .segments."1",
|
||||
"3" : {
|
||||
"type" : "linear",
|
||||
"offset" : .segments."0".offset,
|
||||
"size" : "dynamic",
|
||||
"flags" : ["backup-final"]
|
||||
}
|
||||
} |
|
||||
.digests."0".segments = ["1","2"] |
|
||||
.config.requirements.mandatory = ["online-reencrypt"]'
|
||||
img_check_fail_repair_ok
|
||||
|
||||
# Note - offset is set to work with the old version (with a datashift bug)
|
||||
echo "[6] Old reencryption in-progress (datashift)"
|
||||
img_prepare
|
||||
img_update_json '
|
||||
del(.digests."2") |
|
||||
.keyslots."2".direction = "backward" |
|
||||
.keyslots."2".area.type = "datashift" |
|
||||
.keyslots."2".area.size = "4096" |
|
||||
.keyslots."2".area.shift_size = ((1 * 1024 * 1024)|tostring) |
|
||||
.segments = {
|
||||
"0" : (.segments."0" +
|
||||
{"size" : ((13 * 1024 * 1024)|tostring)}),
|
||||
"1" : (.segments."0" +
|
||||
{"offset" : ((30 * 1024 * 1024)|tostring)}),
|
||||
"2" : .segments."1",
|
||||
"3" : (.segments."2" +
|
||||
{"offset" : ((17 * 1024 * 1024)|tostring)}),
|
||||
} |
|
||||
.digests."0".segments = ["0","2"] |
|
||||
.digests."1".segments = ["1","3"] |
|
||||
.config.requirements.mandatory = ["online-reencrypt"]'
|
||||
img_check_fail_repair_ok
|
||||
|
||||
#
|
||||
# NEW metadata (with reenc digest)
|
||||
#
|
||||
echo "[7] Reencryption with various mangled metadata"
|
||||
|
||||
# Normal situation
|
||||
img_prepare
|
||||
img_run_reenc_ok
|
||||
img_check_ok
|
||||
|
||||
# The same in various steps.
|
||||
# Repair must validate not only metadata, but also reencryption digest.
|
||||
img_prepare
|
||||
img_update_json 'del(.digests."2")'
|
||||
img_check_fail_repair_ok
|
||||
|
||||
img_prepare '--reduce-device-size 2M'
|
||||
img_update_json '.keyslots."2".area.shift_size = ((.keyslots."2".area.shift_size|tonumber / 2)|tostring)'
|
||||
img_check_fail
|
||||
|
||||
#FIXME: cannot check with correct digest for now (--init-only does not store area type)
|
||||
img_prepare
|
||||
img_update_json '
|
||||
.keyslots."2".area.type = "checksum" |
|
||||
.keyslots."2".area.hash = "sha256" |
|
||||
.keyslots."2".area.sector_size = 4096'
|
||||
img_check_fail
|
||||
|
||||
img_prepare
|
||||
img_update_json '.keyslots."2".area.type = "journal"'
|
||||
img_check_fail
|
||||
|
||||
img_prepare
|
||||
img_update_json '.keyslots."2".mode = "decrypt"'
|
||||
img_check_fail
|
||||
|
||||
img_prepare
|
||||
img_update_json '.keyslots."2".direction = "backward"'
|
||||
img_check_fail
|
||||
|
||||
# key_size must be 1
|
||||
img_prepare
|
||||
img_update_json '.keyslots."2".key_size = 16'
|
||||
img_check_fail
|
||||
|
||||
# Mangling segments
|
||||
img_prepare
|
||||
img_update_json 'del(.segments."1")'
|
||||
img_check_fail
|
||||
|
||||
img_prepare
|
||||
img_update_json '.segments."0".encryption = "aes-cbc-null"'
|
||||
img_check_fail
|
||||
|
||||
img_prepare
|
||||
img_update_json '.segments."1".encryption = "aes-cbc-null"'
|
||||
img_check_fail
|
||||
|
||||
img_prepare
|
||||
img_update_json '.segments."2".encryption = "aes-cbc-null"'
|
||||
img_check_fail
|
||||
|
||||
# Mangling digests
|
||||
img_prepare
|
||||
img_update_json '
|
||||
.digests."2" = .digests."0" |
|
||||
.digests."2".keyslots = ["2"] |
|
||||
.digests."2".segments = []'
|
||||
img_check_fail
|
||||
|
||||
img_prepare
|
||||
img_update_json '.digests."2".iterations = 1111'
|
||||
img_check_fail
|
||||
|
||||
# Simulate correct progress
|
||||
img_prepare
|
||||
img_update_json '
|
||||
.segments = {
|
||||
"0" : (.segments."0" +
|
||||
{"size" : ((1 * 1024 * 1024)|tostring)}),
|
||||
"1" : (.segments."0" +
|
||||
{"offset" : ((17 * 1024 * 1024)|tostring)}),
|
||||
"2" : .segments."1",
|
||||
"3" : .segments."2"
|
||||
} |
|
||||
.digests."0".segments = ["1","2"] |
|
||||
.digests."1".segments = ["0","3"]'
|
||||
img_check_ok
|
||||
|
||||
# Mangling keyslots
|
||||
|
||||
# Set reencrypt slot to non-ignore priority
|
||||
# This should be benign, just avoid noisy messages
|
||||
img_prepare
|
||||
img_update_json 'del(.keyslots."2".priority)'
|
||||
img_check_ok
|
||||
|
||||
# Flags
|
||||
|
||||
# Remove mandatory reenc flag, but keep reenc metadata
|
||||
img_prepare
|
||||
img_update_json '.config.requirements.mandatory = []'
|
||||
img_check_fail
|
||||
|
||||
# Unknown segment flag, should be ignored
|
||||
img_prepare
|
||||
img_update_json '.segments."0".flags = ["dead-parrot"]'
|
||||
img_check_ok
|
||||
|
||||
echo "[8] Reencryption with AEAD is not supported"
|
||||
img_prepare_raw
|
||||
img_json_save
|
||||
img_update_json '
|
||||
.segments."0".integrity = {
|
||||
"type" : "hmac(sha256)",
|
||||
"journal_encryption": "none",
|
||||
"journal_integrity": "none"
|
||||
}'
|
||||
$CRYPTSETUP reencrypt $IMG $CS_PARAMS >/dev/null 2>&1 && fail
|
||||
|
||||
remove_mapping
|
||||
exit 0
|
||||
@@ -116,6 +116,7 @@ function fail()
|
||||
function skip()
|
||||
{
|
||||
[ -n "$1" ] && echo "$1"
|
||||
remove_mapping
|
||||
exit 77
|
||||
}
|
||||
|
||||
@@ -152,14 +153,30 @@ function open_crypt() # $1 pwd, $2 hdr
|
||||
fi
|
||||
}
|
||||
|
||||
function wipe_dev_head() # $1 dev, $2 length (in MiBs)
|
||||
{
|
||||
dd if=/dev/zero of=$1 bs=1M count=$2 conv=notrunc >/dev/null 2>&1
|
||||
}
|
||||
|
||||
function wipe_dev() # $1 dev
|
||||
{
|
||||
if [ -b $1 ] ; then
|
||||
blkdiscard --zeroout $1 2>/dev/null || dd if=/dev/zero of=$1 bs=1M conv=notrunc >/dev/null 2>&1
|
||||
if [ $# -gt 2 ]; then
|
||||
dd if=/dev/urandom of=$1 bs=1M seek=$2 conv=notrunc >/dev/null 2>&1
|
||||
fi
|
||||
else
|
||||
local size=$(stat --printf="%s" $1)
|
||||
truncate -s 0 $1
|
||||
truncate -s $size $1
|
||||
if [ $# -gt 2 ]; then
|
||||
local diff=$((size-$2*1024*1024))
|
||||
echo "size: $size, diff: $diff"
|
||||
truncate -s $diff $1
|
||||
# wipe_dev_head $1 $((diff/(1024*1024)))
|
||||
dd if=/dev/urandom of=$1 bs=1M seek=$2 size=$((diff/(1024*1024))) conv=notrunc >/dev/null 2>&1
|
||||
else
|
||||
truncate -s $size $1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -214,15 +231,16 @@ function check_hash() # $1 pwd, $2 hash, $3 hdr
|
||||
$CRYPTSETUP remove $DEV_NAME || fail
|
||||
}
|
||||
|
||||
function check_hash_dev_head() # $1 dev, $2 len, $3 hash
|
||||
{
|
||||
local hash=$(dd if=$1 bs=512 count=$2 2>/dev/null | sha256sum | cut -d' ' -f1)
|
||||
[ $hash != "$3" ] && fail "HASH differs (expected: $3) (result $hash)"
|
||||
}
|
||||
|
||||
function check_hash_head() # $1 pwd, $2 len, $3 hash, $4 hdr
|
||||
{
|
||||
open_crypt $1 $4
|
||||
if [ -n "$4" ]; then
|
||||
echo $1 | $CRYPTSETUP resize $DEV_NAME --size $2 --header $4 || fail
|
||||
else
|
||||
echo $1 | $CRYPTSETUP resize $DEV_NAME --size $2 || fail
|
||||
fi
|
||||
check_hash_dev /dev/mapper/$DEV_NAME $3
|
||||
check_hash_dev_head /dev/mapper/$DEV_NAME $2 $3
|
||||
$CRYPTSETUP remove $DEV_NAME || fail
|
||||
}
|
||||
|
||||
@@ -722,6 +740,8 @@ HASH6=39f7c6d38af574fe2c90ef400dfaba8ef8edccd11bdac998a3f8143a86837331
|
||||
HASH7=18a393d1a505e22ccf3e29effe3005ea8627e4c36b7cca0e53f58121f49b67e1
|
||||
# 60 MiBs of zeroes
|
||||
HASH8=cf5ac69ca412f9b3b1a8b8de27d368c5c05ed4b1b6aa40e6c38d9cbf23711342
|
||||
# 240 MiBs of zeroes (256MiBs - 16MiBs default LUKS2 header size)
|
||||
HASH9=17088b031491a37e0ee9e1025a3938f55ee94ae27653370ad2fe5b0b32e35334
|
||||
|
||||
prepare dev_size_mb=32
|
||||
setup_luks2_env
|
||||
@@ -731,6 +751,7 @@ echo -n "[512 sector]"
|
||||
echo $PWD1 | $CRYPTSETUP -q luksFormat --type luks2 -s 128 -c aes-cbc-essiv:sha256 --offset 8192 $FAST_PBKDF_ARGON $DEV || fail
|
||||
wipe $PWD1
|
||||
check_hash $PWD1 $HASH1
|
||||
echo $PWD1 | $CRYPTSETUP reencrypt $DEV -q $FAST_PBKDF_ARGON 2>&1 | tail -1 | grep -q "not supported" && skip " No reenryption support, test skipped."
|
||||
echo $PWD1 | $CRYPTSETUP reencrypt $DEV -q $FAST_PBKDF_ARGON || fail
|
||||
check_hash $PWD1 $HASH1
|
||||
echo $PWD1 | $CRYPTSETUP reencrypt $DEV -q -s 256 -c twofish-cbc-essiv:sha256 --resilience journal $FAST_PBKDF_ARGON || fail
|
||||
@@ -863,6 +884,21 @@ $CRYPTSETUP status $DEV_NAME >/dev/null 2>&1 || fail
|
||||
$CRYPTSETUP close $DEV_NAME
|
||||
echo $PWD1 | $CRYPTSETUP open $DEV --test-passphrase || fail
|
||||
|
||||
# Small device encryption test
|
||||
preparebig 65
|
||||
# wipe only 1st MiB (final data size after encryption)
|
||||
wipe_dev $DEV 1
|
||||
check_hash_dev_head $DEV 2048 $HASH2
|
||||
echo $PWD1 | $CRYPTSETUP reencrypt $DEV --encrypt --reduce-device-size 64M -q $FAST_PBKDF_ARGON || fail
|
||||
check_hash_head $PWD1 2048 $HASH2
|
||||
|
||||
wipe_dev_head $DEV 1
|
||||
check_hash_dev_head $DEV 2048 $HASH2
|
||||
echo $PWD1 | $CRYPTSETUP reencrypt $DEV --encrypt --reduce-device-size 64M --init-only -q $FAST_PBKDF_ARGON $DEV_NAME >/dev/null || fail
|
||||
check_hash_dev_head /dev/mapper/$DEV_NAME 2048 $HASH2
|
||||
echo $PWD1 | $CRYPTSETUP reencrypt $DEV -q || fail
|
||||
check_hash_dev_head /dev/mapper/$DEV_NAME 2048 $HASH2
|
||||
|
||||
echo "[3] Encryption with detached header"
|
||||
preparebig 256
|
||||
wipe_dev $DEV
|
||||
@@ -889,6 +925,12 @@ echo $PWD1 | $CRYPTSETUP reencrypt $DEV --encrypt -c aes-cbc-essiv:sha256 -s 128
|
||||
$CRYPTSETUP close $DEV_NAME
|
||||
check_hash $PWD1 $HASH3 $IMG_HDR
|
||||
|
||||
# Device encryption with data offset set in detached header
|
||||
wipe_dev $DEV
|
||||
dd if=/dev/urandom of=$DEV bs=512 count=32768 >/dev/null 2>&1
|
||||
echo $PWD1 | $CRYPTSETUP reencrypt --encrypt --header $IMG_HDR --offset 32768 -q $FAST_PBKDF_ARGON $DEV || fail
|
||||
check_hash $PWD1 $HASH9 $IMG_HDR
|
||||
|
||||
# Device activation using key file
|
||||
wipe_dev $DEV
|
||||
echo -n $PWD1 > $KEY1
|
||||
@@ -961,6 +1003,18 @@ echo $PWD1 | $CRYPTSETUP reencrypt --decrypt --active-name $DEV_NAME --header $D
|
||||
$CRYPTSETUP status $DEV_NAME | grep -q "reencryption: in-progress" && fail
|
||||
$CRYPTSETUP close $DEV_NAME
|
||||
|
||||
# yet another funny idea
|
||||
rm -f $IMG_HDR
|
||||
$CRYPTSETUP luksHeaderBackup --header-backup-file $IMG_HDR $DEV || fail
|
||||
chmod +w $IMG_HDR || fail
|
||||
which wipefs >/dev/null 2>&1 && {
|
||||
wipefs -a $DEV >/dev/null 2>&1 || fail
|
||||
}
|
||||
open_crypt $PWD1 $IMG_HDR
|
||||
echo $PWD1 | $CRYPTSETUP reencrypt --active-name $DEV_NAME --decrypt --header $IMG_HDR -q 2>/dev/null && fail
|
||||
$CRYPTSETUP status $DEV_NAME | grep -q "reencryption: in-progress" && fail
|
||||
$CRYPTSETUP close $DEV_NAME || fail
|
||||
|
||||
if ! dm_delay_features; then
|
||||
echo "dm-delay target is missing, skipping recovery tests."
|
||||
remove_mapping
|
||||
|
||||
@@ -229,6 +229,8 @@ RUN luks2-metadata-size-512k-secondary.img "R" "Valid 512KiB metadata size in s
|
||||
RUN luks2-metadata-size-1m-secondary.img "R" "Valid 1MiB metadata size in secondary hdr failed to validate"
|
||||
RUN luks2-metadata-size-2m-secondary.img "R" "Valid 2MiB metadata size in secondary hdr failed to validate"
|
||||
RUN luks2-metadata-size-4m-secondary.img "R" "Valid 4MiB metadata size in secondary hdr failed to validate"
|
||||
RUN luks2-metadata-size-invalid.img "F" "Invalid metadata size in secondary hdr not rejected"
|
||||
RUN luks2-metadata-size-invalid-secondary.img "F" "Invalid metadata size in secondary hdr not rejected"
|
||||
|
||||
remove_mapping
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ function create_user()
|
||||
[ $? -eq 0 ] && skip "User account $USER exists, aborting."
|
||||
[ -f $SSH_KEY_PATH ] && skip "SSH key $SSH_KEY_PATH already exists, aborting."
|
||||
|
||||
useradd -m $USER -p $(openssl passwd -crypt $PASSWD) || skip "Failed to add user for SSH plugin test."
|
||||
useradd -m $USER -p $(openssl passwd $PASSWD) || skip "Failed to add user for SSH plugin test."
|
||||
|
||||
ssh-keygen -f $SSH_KEY_PATH -q -N "" >/dev/null 2>&1
|
||||
[ $? -ne 0 ] && remove_user && skip "Failed to create SSH key."
|
||||
@@ -60,10 +60,18 @@ function bin_check()
|
||||
|
||||
function ssh_setup()
|
||||
{
|
||||
# .ssh is used by ssh-copy-id for temp files so it must exist even if key is not there
|
||||
[ -d "$HOME/.ssh" ] || mkdir -m 700 $HOME/.ssh
|
||||
|
||||
# ssh-copy-id
|
||||
sshpass -p $PASSWD ssh-copy-id -i $SSH_KEY_PATH $SSH_OPTIONS $USER@$SSH_SERVER >/dev/null 2>&1
|
||||
[ $? -ne 0 ] && remove_user && skip "Failed to copy SSH key."
|
||||
|
||||
# make sure /home/sshtest/.ssh and /home/sshtest/.ssh/authorized_keys have correct permissions
|
||||
chown -R $USER:$USER /home/$USER/.ssh
|
||||
chmod 700 /home/$USER/.ssh
|
||||
chmod 644 /home/$USER/.ssh/authorized_keys
|
||||
|
||||
# try to ssh and also create keyfile
|
||||
ssh -i $SSH_KEY_PATH $SSH_OPTIONS -o BatchMode=yes -n $USER@$SSH_SERVER -f "echo -n $PASSWD > $SSH_PATH" >/dev/null 2>&1
|
||||
[ $? -ne 0 ] && remove_user && skip "Failed to connect using SSH."
|
||||
@@ -83,6 +91,7 @@ function fail()
|
||||
function skip()
|
||||
{
|
||||
[ -n "$1" ] && echo "$1"
|
||||
remove_mapping
|
||||
exit 77
|
||||
}
|
||||
|
||||
@@ -133,6 +142,7 @@ bin_check useradd
|
||||
bin_check ssh
|
||||
bin_check ssh-keygen
|
||||
bin_check sshpass
|
||||
bin_check openssl
|
||||
|
||||
format
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ function remove_mapping()
|
||||
[ -b /dev/mapper/$MAP ] && dmsetup remove --retry $MAP
|
||||
[ -b /dev/mapper/"$MAP"_1 ] && dmsetup remove --retry "$MAP"_1
|
||||
[ -b /dev/mapper/"$MAP"_2 ] && dmsetup remove --retry "$MAP"_2
|
||||
rm -rf $TST_DIR
|
||||
}
|
||||
|
||||
function fail()
|
||||
@@ -37,6 +38,7 @@ function skip()
|
||||
{
|
||||
[ -n "$1" ] && echo "$1"
|
||||
echo "Test skipped."
|
||||
remove_mapping
|
||||
exit 77
|
||||
}
|
||||
|
||||
@@ -166,6 +168,7 @@ done
|
||||
|
||||
if [ $(id -u) != 0 ]; then
|
||||
echo "WARNING: You must be root to run activation part of test, test skipped."
|
||||
remove_mapping
|
||||
exit 0
|
||||
fi
|
||||
|
||||
@@ -202,3 +205,6 @@ for file in $(ls $TST_DIR/[tv]c_*-hidden) ; do
|
||||
[ "$UUID" != "CAFE-BABE" ] && fail "UUID check failed."
|
||||
echo " [OK]"
|
||||
done
|
||||
|
||||
remove_mapping
|
||||
exit 0
|
||||
|
||||
@@ -684,3 +684,60 @@ int loop_detach(const char *loop)
|
||||
close(loop_fd);
|
||||
return r;
|
||||
}
|
||||
|
||||
int t_get_devno(const char *name, dev_t *devno)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
int r;
|
||||
struct stat st;
|
||||
|
||||
r = snprintf(path, sizeof(path), DMDIR "%s", name);
|
||||
if (r < 0 || (size_t)r >= sizeof(path))
|
||||
return 1;
|
||||
|
||||
if (stat(path, &st) || !S_ISBLK(st.st_mode))
|
||||
return 1;
|
||||
|
||||
*devno = st.st_rdev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _read_uint64(const char *sysfs_path, uint64_t *value)
|
||||
{
|
||||
char tmp[64] = {0};
|
||||
int fd, r;
|
||||
|
||||
if ((fd = open(sysfs_path, O_RDONLY)) < 0)
|
||||
return 0;
|
||||
r = read(fd, tmp, sizeof(tmp));
|
||||
close(fd);
|
||||
|
||||
if (r <= 0)
|
||||
return 0;
|
||||
|
||||
if (sscanf(tmp, "%" PRIu64, value) != 1)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _sysfs_get_uint64(int major, int minor, uint64_t *value, const char *attr)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
|
||||
if (snprintf(path, sizeof(path), "/sys/dev/block/%d:%d/%s",
|
||||
major, minor, attr) < 0)
|
||||
return 0;
|
||||
|
||||
return _read_uint64(path, value);
|
||||
}
|
||||
|
||||
int t_device_size_by_devno(dev_t devno, uint64_t *retval)
|
||||
{
|
||||
if (!_sysfs_get_uint64(major(devno), minor(devno), retval, "size"))
|
||||
return 1;
|
||||
|
||||
*retval *= 512;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -99,11 +99,13 @@ function check_root_hash_fail()
|
||||
|
||||
$VERITYSETUP open $IMG $DEV_NAME $IMG_HASH $ROOT_HASH || fail
|
||||
check_exists
|
||||
dd if=/dev/mapper/$DEV_NAME of=/dev/null bs=4096 count=1 >/dev/null 2>&1
|
||||
dmsetup status $DEV_NAME | grep "verity V" >/dev/null || fail
|
||||
$VERITYSETUP close $DEV_NAME >/dev/null 2>&1 || fail
|
||||
|
||||
$VERITYSETUP open $IMG $DEV_NAME $IMG_HASH $ROOT_HASH_BAD >/dev/null 2>&1 || fail
|
||||
check_exists
|
||||
dd if=/dev/mapper/$DEV_NAME of=/dev/null bs=4096 count=1 >/dev/null 2>&1
|
||||
dmsetup status $DEV_NAME | grep "verity C" >/dev/null || fail
|
||||
$VERITYSETUP close $DEV_NAME >/dev/null 2>&1 || fail
|
||||
|
||||
@@ -260,7 +262,7 @@ function check_fec()
|
||||
return 3
|
||||
fi
|
||||
|
||||
udevadm settle
|
||||
udevadm settle > /dev/null 2>&1
|
||||
|
||||
dd if=/dev/mapper/$DEV_NAME of=$IMG_TMP > /dev/null 2>&1
|
||||
ARR=(`sha256sum $IMG_TMP`)
|
||||
|
||||
@@ -21,7 +21,7 @@ cryptsetup_ssh_SOURCES = tokens/ssh/cryptsetup-ssh.c \
|
||||
lib/utils_io.c \
|
||||
lib/utils_loop.c
|
||||
cryptsetup_ssh_LDADD = -lm libcryptsetup.la @LIBSSH_LIBS@ @JSON_C_LIBS@ @POPT_LIBS@ \
|
||||
@PWQUALITY_LIBS@ @PASSWDQC_LIBS@
|
||||
@PWQUALITY_LIBS@ @PASSWDQC_LIBS@ @ARGP_LIBS@
|
||||
|
||||
cryptsetup_ssh_CFLAGS = $(AM_CFLAGS)
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@ static struct argp_option options[] = {
|
||||
{"ssh-user", OPT_SSH_USER, "STRING", 0, N_("Username used for the remote server")},
|
||||
{"ssh-path", OPT_SSH_PATH, "STRING", 0, N_("Path to the key file on the remote server")},
|
||||
{"ssh-keypath", OPT_KEY_PATH, "STRING", 0, N_("Path to the SSH key for connecting to the remote server")},
|
||||
{"key-slot", OPT_KEY_SLOT, "NUM", 0, N_("Keyslot to assing the token to. If not specified, token will "\
|
||||
{"key-slot", OPT_KEY_SLOT, "NUM", 0, N_("Keyslot to assign the token to. If not specified, token will "\
|
||||
"be assigned to the first keyslot matching provided passphrase.")},
|
||||
{0, 0, 0, 0, N_("Generic options:")},
|
||||
{"verbose", 'v', 0, 0, N_("Shows more detailed error messages")},
|
||||
|
||||
Reference in New Issue
Block a user