Compare commits

..

35 Commits

Author SHA1 Message Date
Milan Broz
c67861e875 Update README. 2022-01-13 10:24:00 +01:00
Milan Broz
f566d7c911 Fix reencrypt mangle test for older jq. 2022-01-13 10:09:54 +01:00
Milan Broz
f21b07fb1b Version 2.4.3. 2022-01-12 18:42:14 +01:00
Milan Broz
904cdd1161 Add Release Notes. 2022-01-12 18:42:10 +01:00
Milan Broz
5d75632a16 Update LUKS2 on-disk description. 2022-01-12 18:42:06 +01:00
Ondrej Kozina
da8bcf7270 Allow reencryption metadata repair from cryptsetup. 2022-01-12 18:42:02 +01:00
Ondrej Kozina
bbc3ff69db Add CRYPT_REENCRYPT_REPAIR_NEEDED flag.
crypt_reencrypt_status() returns this flag if old
online-reencrypt requirement is detected and reencryption
keyslot digest is missing.

crypt_reencrypt_init_by_passphrase() with same flag applied
repairs (upgrade) reencryption metadata so that
automatic reencryption recovery during activation
is again possible and reencryption operation can be resumed
post CVE-2021-4122 fix.
2022-01-12 18:41:58 +01:00
Milan Broz
7ef0d9c73a Add reencryption mangle test 2022-01-12 18:41:55 +01:00
Ondrej Kozina
8ced413876 Make reencryption flag and keyslot inseparable.
LUKS2 validation code now requires reencrypt keyslot together with
online-reencryption flag or none of those.
2022-01-12 18:41:50 +01:00
Ondrej Kozina
80a77bce2a Rename LUKS2_keyslot_reencrypt_create function.
The function never writes on-disk. Also removed validation
function call-in since it will be called later before
writing on-disk and metadata does not have to be complete
at the moment of LUKS2_keyslot_reencrypt_allocate call.
2022-01-12 18:41:46 +01:00
Ondrej Kozina
334606b6aa Add segments validation for reencryption.
Effective segments during LUKS2 reencryption must
match key characteristics of backup segment
(cipher, sector_size, segment type).
2022-01-12 18:41:39 +01:00
Ondrej Kozina
1162f1e1e3 Split requirements validation from config section validation. 2022-01-12 14:49:11 +01:00
Ondrej Kozina
47a1d9a6d6 Expose json_segment_contains_flag to internal library. 2022-01-12 14:49:11 +01:00
Ondrej Kozina
c257ae1eb4 Move requirement helpers for later changes. 2022-01-12 14:49:11 +01:00
Milan Broz
d37c3f0db2 Add disable-luks2 reencryption configure option.
The option --disable-luks2-reencryption 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.
2022-01-12 14:49:11 +01:00
Milan Broz
4a974ec582 Print better error if resilience hash is not available. 2022-01-12 14:49:11 +01:00
Milan Broz
c95a88f815 Do not run reencryption recovery when not needed. 2022-01-12 14:49:11 +01:00
Milan Broz
4af4a4a631 Reenc keyslot must have key_size == 1. 2022-01-12 14:49:11 +01:00
Milan Broz
3d269a5ae3 Fix debug message. 2022-01-12 14:49:11 +01:00
Ondrej Kozina
de98f01141 Fix CVE-2021-4122 - LUKS2 reencryption crash recovery attack
Fix possible attacks against data confidentiality through LUKS2 online
reencryption extension crash recovery.

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 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.
2022-01-12 14:49:11 +01:00
Vojtech Trefny
4d28153e53 bitlk: Fix support for startup key with new metadata entry
Windows 11 now includes the BitLocker volume GUID in the BEK file
metadata entries. This was previously not included so cryptsetup
refused to open the file because there was an unknown metadata
entry in the startup key.

Fixes: #690
2022-01-10 21:29:50 +01:00
Ondrej Kozina
dd864f5a61 Remove LUKS2 encryption data size restriction.
LUKS2 encryption with data shift required remaining
data size (size remaining after substracting --reduce-data-size value)
to be at least --reduce-data-size. This was wrong. Remaining
data size restriction should be correctly at least single sector
(whatever sector size is selected or auto-detected).
2022-01-10 21:29:32 +01:00
Josef Andersson
ca54398eec po: update sv.po (from translationproject.org) 2022-01-10 21:26:04 +01:00
Мирослав Николић
97cd16b8b9 po: update sr.po (from translationproject.org) 2022-01-10 21:25:55 +01:00
Antonio Ceballos
86d0d4f68e po: update es.po (from translationproject.org) 2022-01-10 21:25:44 +01:00
Tianjia Zhang
1a7d98b3ba Fix manual typo. 2022-01-10 21:25:30 +01:00
Sean
025a96df73 Update README.md 2022-01-10 21:25:17 +01:00
Milan Broz
e6edbc1fe5 Run CI on stable branches.
The stable branch is named "v2.<minor>.x".
2021-12-01 22:50:37 +01:00
Milan Broz
ed68b51526 Do not mix tabs and spaces in GitHub CI script. 2021-12-01 22:50:37 +01:00
Milan Broz
bcace16aa2 Do not mix tabs and spaces in Gitlab CI script. 2021-12-01 22:50:37 +01:00
Milan Broz
97aa31d32f Fix tabs in GitLab CI scripts and remove gcc comment.
The -Wall changes according to gcc versions.
2021-12-01 22:50:37 +01:00
Milan Broz
36a78ed17b Fix missing backslash in CI. 2021-12-01 22:50:37 +01:00
Milan Broz
0d4ecd92f1 Add limitation to cryptsetup group again in CI. 2021-12-01 22:50:37 +01:00
daniel.zatovic
94143c3428 Remove LLVM repo script 2021-12-01 22:50:37 +01:00
Daniel Zaťovič
af17d2256d Add compilation tests and static analysis on the Gitlab shared runner. 2021-12-01 22:50:37 +01:00
334 changed files with 19231 additions and 24867 deletions

View File

@@ -7,7 +7,6 @@ PACKAGES=(
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
asciidoctor
)
COMPILER="${COMPILER:?}"

View File

@@ -2,10 +2,9 @@ name: Build test
on:
push:
branches:
- 'main'
- 'master'
- 'wip-luks2'
- 'v2.3.x'
- 'v2.4.x'
paths-ignore:
- 'docs/**'

4
.gitignore vendored
View File

@@ -6,8 +6,6 @@ Makefile.in.in
*.lo
*.la
*.o
*.so
*.8
**/*.dirstamp
.deps/
.libs/
@@ -56,5 +54,3 @@ tests/luks1-images
tests/tcrypt-images
tests/unit-utils-io
tests/vectors-test
tests/test-symbols-list.h
tests/all-symbols-test

View File

@@ -1,20 +1,113 @@
stages:
- test
.dump_kernel_log:
after_script:
- sudo dmesg > /mnt/artifacts/dmesg.log
- sudo journalctl > /mnt/artifacts/journalctl.log
- '[ "$(ls -A /var/coredumps)" ] && exit 1 || true'
.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/debian.yml
- local: .gitlab/ci/fedora.yml
- local: .gitlab/ci/rhel.yml
- local: .gitlab/ci/centos.yml
- local: .gitlab/ci/annocheck.yml
- local: .gitlab/ci/csmock.yml
- local: .gitlab/ci/gitlab-shared-docker.yml
- local: .gitlab/ci/compilation-gcc.gitlab-ci.yml
- local: .gitlab/ci/compilation-clang.gitlab-ci.yml
- local: .gitlab/ci/alpinelinux.yml

View File

@@ -1,53 +0,0 @@
.alpinelinux-dependencies:
after_script:
- sudo dmesg > /mnt/artifacts/dmesg.log
- sudo cp /var/log/messages /mnt/artifacts/
- '[ "$(ls -A /var/coredumps)" ] && exit 1 || true'
before_script:
- >
sudo apk add
lvm2-dev openssl1.1-compat-dev popt-dev util-linux-dev json-c-dev
argon2-dev device-mapper which sharutils gettext gettext-dev automake
autoconf libtool build-base keyutils tar jq expect git asciidoctor
- ./autogen.sh
- ./configure --prefix=/usr --libdir=/lib --sbindir=/sbin --disable-static --enable-libargon2 --with-crypto_backend=openssl --disable-external-tokens --disable-ssh-token --enable-asciidoc
test-main-commit-job-alpinelinux:
extends:
- .alpinelinux-dependencies
tags:
- libvirt
- alpinelinux
stage: test
interruptible: true
variables:
RUN_SSH_PLUGIN_TEST: "0"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
rules:
- 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-alpinelinux:
extends:
- .alpinelinux-dependencies
tags:
- libvirt
- alpinelinux
stage: test
interruptible: true
variables:
RUN_SSH_PLUGIN_TEST: "0"
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

View File

@@ -1,19 +0,0 @@
test-main-commit-job-annocheck:
extends:
- .dump_kernel_log
tags:
- libvirt
- rhel9-annocheck
stage: test
interruptible: true
allow_failure: 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:
- /opt/build-rpm-script.sh > /dev/null 2>&1
- annocheck /var/lib/mock/rhel-9.0.0-candidate-x86_64/result/*.rpm --profile=el9
- annocheck /var/lib/mock/rhel-9.0.0-candidate-x86_64/result/*.rpm --profile=el8

View File

@@ -1,55 +0,0 @@
.centos-openssl-backend:
extends:
- .dump_kernel_log
before_script:
- >
sudo dnf -y -q install
autoconf automake device-mapper-devel gcc gettext-devel json-c-devel
libblkid-devel libpwquality-devel libselinux-devel libssh-devel libtool
libuuid-devel make popt-devel libsepol-devel nc openssh-clients passwd
pkgconfig sharutils sshpass tar uuid-devel vim-common device-mapper
expect gettext git jq keyutils openssl-devel openssl gem
- sudo gem install asciidoctor
- sudo -E git clean -xdf
- ./autogen.sh
- ./configure --enable-fips --enable-pwquality --with-crypto_backend=openssl --enable-asciidoc
# non-FIPS jobs
test-main-commit-centos-stream9:
extends:
- .centos-openssl-backend
tags:
- libvirt
- centos-stream9
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-centos-stream9:
extends:
- .centos-openssl-backend
tags:
- libvirt
- centos-stream9
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

View File

@@ -7,7 +7,6 @@ PACKAGES=(
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
asciidoctor
)
COMPILER="${COMPILER:?}"
@@ -43,7 +42,7 @@ apt-get -y build-dep cryptsetup
echo "====================== VERSIONS ==================="
if [[ $COMPILER == "clang" ]]; then
echo "Using scan-build${COMPILER_VERSION:+-$COMPILER_VERSION}"
scan-build${COMPILER_VERSION:+-$COMPILER_VERSION} --help
fi
${COMPILER}-$COMPILER_VERSION -v

View File

@@ -15,10 +15,8 @@ CLANG="clang${COMPILER_VERSION:+-$COMPILER_VERSION}"
#PEDANTIC="-pedantic -std=gnu99 -Wno-variadic-macros"
#CONVERSION="-Wconversion"
EXTRA="\
-Wextra \
EXTRA="-Wextra \
-Wsign-compare \
-Wcast-align
-Werror-implicit-function-declaration \
-Wpointer-arith \
-Wwrite-strings \
@@ -29,6 +27,7 @@ EXTRA="\
-Wold-style-definition \
-Wno-missing-field-initializers \
-Wno-unused-parameter \
-Wno-attributes \
-Wno-long-long"
exec $CLANG $PEDANTIC $CONVERSION \
@@ -44,6 +43,13 @@ exec $CLANG $PEDANTIC $CONVERSION \
-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
}

View File

@@ -3,25 +3,23 @@ test-clang-compilation:
- .gitlab-shared-clang
script:
- export CFLAGS="-Wall -Werror"
- ./configure
- ./configure --enable-pwquality --enable-libargon2
- make -j
- make -j check-programs
test-clang-Wall-script:
extends:
- .gitlab-shared-clang
script:
- export CFLAGS="-g -O0"
- export CC="$CI_PROJECT_DIR/.gitlab/ci/clang-Wall"
- ./configure
- make -j CFLAGS="-g -O0 -Werror"
- make -j CFLAGS="-g -O0 -Werror" check-programs
# 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"
- 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} --status-bugs -maxloop 10 make -j
- scan-build${COMPILER_VERSION:+-$COMPILER_VERSION} --status-bugs -maxloop 10 make -j check-programs
- scan-build${COMPILER_VERSION:+-$COMPILER_VERSION} -maxloop 10 make -j

View File

@@ -3,25 +3,22 @@ test-gcc-compilation:
- .gitlab-shared-gcc
script:
- export CFLAGS="-Wall -Werror"
- ./configure
- ./configure --enable-pwquality --enable-libargon2
- make -j
- make -j check-programs
test-gcc-Wall-script:
extends:
- .gitlab-shared-gcc
script:
- export CFLAGS="-g -O0"
- export CC="$CI_PROJECT_DIR/.gitlab/ci/gcc-Wall"
- ./configure
- make -j CFLAGS="-g -O0 -Werror"
- make -j CFLAGS="-g -O0 -Werror" check-programs
- 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
- ./configure --enable-pwquality --enable-libargon2
- make -j
- make -j check-programs

View File

@@ -1,17 +0,0 @@
test-commit-job-csmock:
extends:
- .dump_kernel_log
tags:
- libvirt
- rhel7-csmock
stage: test
interruptible: true
allow_failure: 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$/ || $CI_PIPELINE_SOURCE == "merge_request_event"
script:
- /opt/csmock-run-script.sh

View File

@@ -1,53 +0,0 @@
.debian-prep:
extends:
- .dump_kernel_log
before_script:
- >
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 asciidoctor
- sudo apt-get -y build-dep cryptsetup
- sudo -E git clean -xdf
- ./autogen.sh
- ./configure --enable-libargon2 --enable-asciidoc
test-mergerq-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_PIPELINE_SOURCE == "merge_request_event"
script:
- make -j
- make -j -C tests check-programs
- sudo -E make check
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

View File

@@ -1,55 +0,0 @@
.dnf-openssl-backend:
extends:
- .dump_kernel_log
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 asciidoctor
- sudo -E git clean -xdf
- ./autogen.sh
- ./configure --enable-fips --enable-pwquality --enable-libargon2 --with-crypto_backend=openssl --enable-asciidoc
test-main-commit-job-rawhide:
extends:
- .dnf-openssl-backend
tags:
- libvirt
- fedora-rawhide
stage: test
interruptible: true
allow_failure: 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-rawhide:
extends:
- .dnf-openssl-backend
tags:
- libvirt
- fedora-rawhide
stage: test
interruptible: true
allow_failure: 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

View File

@@ -16,8 +16,6 @@ GCC="gcc${COMPILER_VERSION:+-$COMPILER_VERSION}"
#CONVERSION="-Wconversion"
# -Wpacked \
# This does more than expected for gcc (mixed code with declarations)
# -Wdeclaration-after-statement \
EXTRA="-Wextra \
-Wsign-compare \
@@ -29,14 +27,14 @@ EXTRA="-Wextra \
-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 \
-Wformat-overflow \
-Wformat-truncation"
-Wvla"
exec $GCC $PEDANTIC $CONVERSION \
-Wall $Wuninitialized \
@@ -51,7 +49,13 @@ exec $GCC $PEDANTIC $CONVERSION \
-Wnested-externs \
-Wcomment \
-Winline \
-Wcast-align=strict \
-Wcast-align \
-Wcast-qual \
-Wredundant-decls $EXTRA \
"$@"
"$@" 2>&1 | {
if [[ $USE_FILTER -eq 1 ]]; then
.gitlab/ci/warnings_filter.py
else
cat
fi
}

View File

@@ -5,9 +5,7 @@
stage: test
interruptible: true
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_PIPELINE_SOURCE == "merge_request_event" || $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
- 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}"

View File

@@ -1,96 +0,0 @@
.rhel-openssl-backend:
extends:
- .dump_kernel_log
before_script:
- >
sudo yum -y -q install
autoconf automake device-mapper-devel gcc gettext-devel json-c-devel
libblkid-devel libpwquality-devel libselinux-devel libssh-devel libtool
libuuid-devel make popt-devel libsepol-devel nc openssh-clients passwd
pkgconfig sharutils sshpass tar uuid-devel vim-common device-mapper
expect gettext git jq keyutils openssl-devel openssl gem > /dev/null 2>&1
- sudo gem install asciidoctor
- sudo -E git clean -xdf
- ./autogen.sh
- ./configure --enable-fips --enable-pwquality --with-crypto_backend=openssl --enable-asciidoc
# non-FIPS jobs
test-main-commit-rhel8:
extends:
- .rhel-openssl-backend
tags:
- libvirt
- rhel8
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-main-commit-rhel9:
extends:
- .rhel-openssl-backend
tags:
- libvirt
- rhel9
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
# FIPS jobs
test-main-commit-rhel8-fips:
extends:
- .rhel-openssl-backend
tags:
- libvirt
- rhel8-fips
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-main-commit-rhel9-fips:
extends:
- .rhel-openssl-backend
tags:
- libvirt
- rhel9-fips
stage: test
interruptible: true
allow_failure: 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

31
.gitlab/ci/warnings_filter.py Executable file
View 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)

View File

@@ -1,11 +0,0 @@
queries:
- exclude: cpp/fixme-comment
- exclude: cpp/empty-block
# symver attribute detection cannot be used, disable it for lgtm
extraction:
cpp:
configure:
command:
- "./autogen.sh"
- "./configure --enable-external-tokens --enable-ssh-token"
- "echo \"#undef HAVE_ATTRIBUTE_SYMVER\" >> config.h"

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
EXTRA_DIST = README.md COPYING.LGPL FAQ.md docs misc autogen.sh
EXTRA_DIST = README.md COPYING.LGPL FAQ docs misc autogen.sh
SUBDIRS = po tests
CLEANFILES =
DISTCLEAN_TARGETS =
@@ -16,7 +16,7 @@ AM_CPPFLAGS = \
AM_CFLAGS = -Wall
AM_LDFLAGS =
LDADD = $(LTLIBINTL)
LDADD = $(LTLIBINTL) -lm
tmpfilesddir = @DEFAULT_TMPFILESDIR@
@@ -27,7 +27,6 @@ sbin_PROGRAMS =
man8_MANS =
tmpfilesd_DATA =
pkgconfig_DATA =
dist_noinst_DATA =
include man/Makemodule.am
@@ -47,7 +46,7 @@ ACLOCAL_AMFLAGS = -I m4
DISTCHECK_CONFIGURE_FLAGS = \
--with-tmpfilesdir=$$dc_install_base/usr/lib/tmpfiles.d \
--enable-internal-argon2 --enable-internal-sse-argon2 \
--enable-external-tokens --enable-ssh-token --enable-asciidoc
--enable-external-tokens --enable-ssh-token
distclean-local:
-find . -name \*~ -o -name \*.orig -o -name \*.rej | xargs rm -f
@@ -61,6 +60,3 @@ install-data-local:
uninstall-local:
rmdir $(DESTDIR)/${EXTERNAL_LUKS2_TOKENS_PATH} 2>/dev/null || :
check-programs: libcryptsetup.la
$(MAKE) -C tests $@

View File

@@ -13,6 +13,7 @@ The project also includes a **veritysetup** utility used to conveniently setup
and **integritysetup** to setup
[DMIntegrity](https://gitlab.com/cryptsetup/cryptsetup/wikis/DMIntegrity) block integrity kernel module.
LUKS Design
-----------
**LUKS** is the standard for Linux hard disk encryption. By providing a standard on-disk-format, it does not
@@ -45,12 +46,6 @@ Download
--------
All release tarballs and release notes are hosted on [kernel.org](https://www.kernel.org/pub/linux/utils/cryptsetup/).
**The latest stable release candidate cryptsetup version is 2.5.0-rc1**
* [cryptsetup-2.5.0-rc1.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.5/cryptsetup-2.5.0-rc1.tar.xz)
* Signature [cryptsetup-2.5.0-rc1.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.5/cryptsetup-2.5.0-rc1.tar.sign)
_(You need to decompress file first to check signature.)_
* [Cryptsetup 2.5.0-rc1 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.5/v2.5.0-rc1-ReleaseNotes).
**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)
@@ -79,6 +74,7 @@ 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 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 the internal testsuite you also need to install `sharutils device-mapper jq vim-common expect keyutils netcat shadow-utils openssh-clients openssh sshpass`.
@@ -87,17 +83,6 @@ Here is the list of packages needed for the compilation of project for particula
Note that the list could change as the distributions evolve.
Compilation
-----------
The cryptsetup project uses **automake** and **autoconf** system to generate all needed files for compilation. If you check it from the git snapshot, use ``./autogen.sh && ./configure && make`` to compile the project. If you use downloaded released ``*.tar.xz`` archive, the configure script is already pre-generated (no need to run ``autoconf.sh``).
See ``./configure --help`` and use ``--disable-*`` and ``--enable-*`` options.
For running the test suite that come with the project, type ``make check``.
Note that most tests will need root user privileges and run many dangerous storage fail simulations.
Do **not** run tests with root privilege on production systems! Some tests will need scsi_debug kernel module to be available.
For more details, please refer to [automake](https://www.gnu.org/software/automake/manual/automake.html) and [autoconf](https://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf.html) manuals.
Help!
-----
@@ -113,10 +98,10 @@ The FAQ is online and in the source code for the project. The Specifications ar
### Mailing List
For cryptsetup and LUKS related questions, please use the cryptsetup mailing list [cryptsetup@lists.linux.dev](mailto:cryptsetup@lists.linux.dev), hosted at [kernel.org subspace](https://subspace.kernel.org/lists.linux.dev.html).
To subscribe send an empty mail to [cryptsetup+subscribe@lists.linux.dev](mailto:cryptsetup+subscribe@lists.linux.dev).
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 archive](https://lore.kernel.org/cryptsetup/).
News (NNTP), Atom feed and git access to public inbox is available through [lore.kernel.org](https://lore.kernel.org) service.
You can also browse and/or search the mailing list archives using the following resources:
The former dm-crypt [list archive](https://lore.kernel.org/dm-crypt/) is also available.
* [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).

View File

@@ -1,10 +0,0 @@
# Reporting a Security Bug in cryptsetup project
If you think you have discovered a security issue, please report it through
the project issue tracker [New issue](https://gitlab.com/cryptsetup/cryptsetup/issues)
as a confidential issue (select confidential checkbox).
An alternative is to send PGP encrypted mail to the cryptsetup maintainer.
Current maintainer is [Milan Broz](mailto:gmazyland@gmail.com), use PGP key
with fingerprint 2A29 1824 3FDE 4664 8D06 86F9 D9B0 577B D93E 98FC.

View File

@@ -1,9 +1,9 @@
AC_PREREQ([2.67])
AC_INIT([cryptsetup],[2.5.0-rc1])
AC_INIT([cryptsetup],[2.4.3])
dnl library version from <major>.<minor>.<release>[-<suffix>]
LIBCRYPTSETUP_VERSION=$(echo $PACKAGE_VERSION | cut -f1 -d-)
LIBCRYPTSETUP_VERSION_INFO=20:0:8
LIBCRYPTSETUP_VERSION_INFO=19:0:7
AM_SILENT_RULES([yes])
AC_CONFIG_SRCDIR(src/cryptsetup.c)
@@ -34,6 +34,7 @@ AC_PROG_MKDIR_P
AC_ENABLE_STATIC(no)
LT_INIT
PKG_PROG_PKG_CONFIG
AM_ICONV
dnl ==========================================================================
dnl define PKG_CHECK_VAR for old pkg-config <= 0.28
@@ -52,33 +53,12 @@ AS_VAR_COPY([$1], [pkg_cv_][$1])
AS_VAR_IF([$1], [""], [$5], [$4])
])
])
dnl ==========================================================================
dnl AsciiDoc manual pages
AC_ARG_ENABLE([asciidoc],
AS_HELP_STRING([--disable-asciidoc], [do not generate man pages from asciidoc]),
[], [enable_asciidoc=yes]
)
AC_PATH_PROG([ASCIIDOCTOR], [asciidoctor])
if test "x$enable_asciidoc" = xyes -a "x$ASCIIDOCTOR" = x; then
AC_MSG_ERROR([Building man pages requires asciidoctor installed.])
fi
AM_CONDITIONAL([ENABLE_ASCIIDOC], [test "x$enable_asciidoc" = xyes])
have_manpages=no
AS_IF([test -f "$srcdir/man/cryptsetup-open.8"], [
AC_MSG_NOTICE([re-use already generated man-pages.])
have_manpages=yes]
)
AM_CONDITIONAL([HAVE_MANPAGES], [test "x$have_manpages" = xyes])
dnl ==========================================================================
AC_C_RESTRICT
AC_HEADER_DIRENT
AC_CHECK_HEADERS(fcntl.h malloc.h inttypes.h uchar.h sys/ioctl.h sys/mman.h \
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])],
[[
@@ -382,6 +362,11 @@ AC_ARG_ENABLE([veritysetup],
[], [enable_veritysetup=yes])
AM_CONDITIONAL(VERITYSETUP, test "x$enable_veritysetup" = "xyes")
AC_ARG_ENABLE([cryptsetup-reencrypt],
AS_HELP_STRING([--disable-cryptsetup-reencrypt], [disable cryptsetup-reencrypt tool]),
[], [enable_cryptsetup_reencrypt=yes])
AM_CONDITIONAL(REENCRYPT, test "x$enable_cryptsetup_reencrypt" = "xyes")
AC_ARG_ENABLE([integritysetup],
AS_HELP_STRING([--disable-integritysetup], [disable integritysetup support]),
[], [enable_integritysetup=yes])
@@ -434,7 +419,7 @@ if test "x$enable_ssh_token" = "xyes"; then
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_parse],[argp])
AC_SEARCH_LIBS([argp_usage],[argp])
AC_SUBST(ARGP_LIBS, $LIBS)
LIBS=$saved_LIBS
fi
@@ -575,23 +560,6 @@ if test "x$enable_static_cryptsetup" = "xyes"; then
PKG_CONFIG=$saved_PKG_CONFIG
fi
dnl Check compiler support for symver function attribute
AC_MSG_CHECKING([for symver attribute support])
saved_CFLAGS=$CFLAGS
CFLAGS="-O0 -Werror"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
void _test_sym(void);
__attribute__((__symver__("sym@VERSION_4.2"))) void _test_sym(void) {}
]],
[[ _test_sym() ]]
)],[
AC_DEFINE([HAVE_ATTRIBUTE_SYMVER], 1, [Define to 1 to use __attribute__((symver))])
AC_MSG_RESULT([yes])
], [
AC_MSG_RESULT([no])
])
CFLAGS=$saved_CFLAGS
AC_MSG_CHECKING([for systemd tmpfiles config directory])
PKG_CHECK_VAR([systemd_tmpfilesdir], [systemd], [tmpfilesdir], [], [systemd_tmpfilesdir=no])
AC_MSG_RESULT([$systemd_tmpfilesdir])

View File

@@ -1,7 +1,7 @@
/*
* libcryptsetup API log example
*
* Copyright (C) 2011-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2021 Red Hat, Inc. All rights reserved.
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

View File

@@ -1,7 +1,7 @@
/*
* libcryptsetup API - using LUKS device example
*
* Copyright (C) 2011-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2021 Red Hat, Inc. All rights reserved.
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

Binary file not shown.

View File

@@ -89,7 +89,7 @@ Important features
Integritysetup is intended to be used for settings that require
non-cryptographic data integrity protection with no data encryption.
For setting integrity protected encrypted devices, see disk authenticated
Fo setting integrity protected encrypted devices, see disk authenticated
encryption below.
Note that after formatting the checksums need to be initialized;
@@ -583,7 +583,7 @@ Unfinished things & TODO for next releases
in kernel (more on this later).
NOTE: Currently available authenticated modes (GCM, Chacha20-poly1305)
in kernel have too small 96-bit nonces that are problematic with
randomly generated IVs (the collision probability is not negligible).
randomly generated IVs (the collison probability is not negligible).
For the GCM, nonce collision is a fatal problem.
* Authenticated encryption do not set encryption for dm-integrity journal.

View File

@@ -75,7 +75,7 @@ Changes since version 2.3.3
If users want to use blake2b/blake2s, the kernel algorithm name includes
a dash (like "blake2s-256").
These algorithms can now be used for integritysetup devices.
Theses algorithms can now be used for integritysetup devices.
* Fix crypto backend to properly handle ECB mode.

View File

@@ -1,281 +0,0 @@
Cryptsetup 2.5.0-rc1 Release Notes
==================================
Stable release candidate with new features and bug fixes.
Changes since version 2.4.3
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Split manual pages into per-action pages and use AsciiDoc format.
Manual pages are now generated from AsciiDoc format, allowing easy
conditional modifications for per-action options.
Generation of man pages requires the asciidoctor tool installed.
Pre-generated man pages are also included in the distribution tarball.
You can use --disable-asciidoc configure option to skip man page
generation completely. In this case, pre-generated man pages will be
used for installation.
For cryptsetup, there is main man page (cryptsetup.8) that references
separate man pages for each command (for example, cryptsetup-open.8).
You can open such a man page by simply running "man cryptsetup open".
Also, man pages for action aliases are available (cryptsetup-luksOpen.8
is an alias for cryptsetup-open.8, etc.)
LUKS volume reencryption changes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Remove cryptsetup-reencrypt tool from the project and move reencryption
to already existing "cryptsetup reencrypt" command.
Cryptsetup reencrypt now handles both LUKS1 and LUKS2 reencryption,
encryption, and decryption.
If you need to emulate the old cryptsetup-reencrypt binary, use simple
wrappers script running "exec cryptsetup reencrypt $@".
All command line options should be compatible. An exception is the
reencryption of LUKS2 volumes with old LUKS1 reencryption code that was
replaced by native and more resilient LUKS2 reencryption.
* LUKS2: implement --decryption option that allows LUKS removal. The
operation can run online or offline and supports the data shift option.
During the initialization, the LUKS2 header is exported to a file.
The first data segment is moved to the head of the data device in place
of the original header.
The feature internally introduces several new resilience modes
(combination of existing modes datashift and "checksum" or "journal").
Datashift resilience mode is applied for data moved towards the first
segment, and the first segment is then decrypted in place.
This decryption mode is not backward compatible with prior LUKS2
reencryption. Interrupted operations in progress cannot be resumed
using older cryptsetup releases.
* Reencryption metadata options that are not compatible with recent code
(features implemented in more recent releases) are now only read, but
code will not activate or modify such metadata.
Reencryption metadata contains a version that is validated when
reencryption is resumed.
For more info, see the updated LUKS2 on-disk format specification.
Safe operation of reencryption is to always finish the operation with
only one version of the tools.
* Fix decryption operation with --active-name option and restrict
it to be used only with LUKS2.
* Do not refresh reencryption digest when not needed.
This should speed up the reencryption resume process.
* Store proper resilience data in LUKS2 reencrypt initialization.
Resuming reencryption now does not require specification of resilience
type parameters if these are the same as during initialization.
* Properly wipe the unused area after reencryption with datashift in
the forward direction.
* Check datashift value against larger sector size.
For example, it could cause an issue if misaligned 4K sector appears
during decryption.
* Do not allow sector size increase reencryption in offline mode.
The eventual logical block size increase on the dm-crypt device above
may lead to an unusable filesystem. Do not allow offline reencryption
when sector size increase is requested.
You can use --force-offline-reencrypt option to override this check
(and potentially destroy the data).
* Do not allow dangerous sector size change during reencryption.
By changing the encryption sector size during reencryption, a user
may increase the effective logical block size for the dm-crypt active
device.
Do not allow encryption sector size to be increased over the value
provided by fs superblock in BLOCK_SIZE property.
* Ask the user for confirmation before resuming reencryption.
The prompt is not shown in batch mode or when the user explicitly asks
for a reencryption resume via --resume-only.
* Do not resume reencryption with conflicting parameters.
For example, if the operation was initialized as --encrypt, do not
allow resume with opposing parameter --decrypt and vice versa.
Also, the code now checks for conflicting resilience parameters
(datashift cannot be changed after initialization).
* Add --force-offline-reencrypt option.
It can be used to enforce offline reencryption in batch mode when
the device is a regular file; therefore, cryptsetup cannot detect
properly active devices using it.
Also, it may be useful to override the active device auto-detection
for specific storage configurations (dangerous!).
* Do not allow nested encryption in LUKS reencrypt.
Avoid accidental nested encryption via cryptsetup reencrypt --encrypt.
* Fix --test-passphrase when the device is in reencryption.
* Do not upload keys in keyring during offline reencryption.
Reencryption runs in userspace, so the kernel does not need the key.
* Support all options allowed with luksFormat with encrypt action.
Other changes
~~~~~~~~~~~~~
* Add resize action to integritysetup.
This allows resizing of standalone integrity devices.
* Support --device-size option (that allows unit specification) for plain
devices (existing --size option requires 512-byte sectors units).
* Fix detection of encryption sector size if a detached header is used.
* Remove obsolete dracut plugin reencryption example.
* Fix possible keyslot area size overflow during conversion to LUKS2.
If keyslots are not sorted according to binary area offset, the area
size calculation was wrong and could overflow.
* Hardening and fixes to LUKS2 validation functions:
* Log a visible error if convert fails due to validation check.
* Check for interval (keyslot and segment area) overflow.
* Check cipher availability before LUKS conversion to LUKS2.
Some historic incompatibilities are ignored for LUKS1 but do not
work for LUKS2.
* Add empty string check to LUKS2 metadata JSON validation.
Most of the LUKS2 fields cannot be empty.
* Fix JSON objects validation to check JSON object type properly.
* TCRYPT: Properly apply retry count and continue if some PBKDF variant
is unavailable.
* BITLK: Add a warning when activating a device with the wrong size
stored in metadata.
* BITLK: Add BitLocker volume size to dump command.
* BITLK: Fix possible UTF16 buffer overflow in volume key dump.
* BITLK: Skip question if the batch mode is set for volume key dump.
* BITLK: Check dm-zero availability in the kernel.
Bitlocker compatible mode uses dm-zero to mask metadata area.
The device cannot be activated if dm-zero is not available.
* Fix error message for LUKS2-only cryptsetup commands to explicitly
state LUKS2 version is required.
* Fix error message for incompatible dm-integrity metadata.
If the integritysetup tool is too old, kernel dm-integrity may use
a more recent version of dm-integrity metadata.
* Properly deactivate the integrity device even if the LUKS2 header
is no longer available.
If LUKS2 is used with integrity protection, there is always
a dm-integrity device underneath that must be deactivated.
* Allow use of --header option for cryptsetup close.
This can be used to check that the activated device has the same UUID.
* Fix activation of LUKS2 device with integrity and detached header.
The kernel-parsed dm-integrity superblock is always located on the
data device, the incorrectly used detached header device here.
* Add ZEROOUT IOCTL support for crypt_wipe API call.
For block devices, we can use optimized in-kernel BLKZEROOUT ioctl.
* VERITY: set loopback sector size according to dm-verity block sizes.
Verity block size has the same limits, so we can optimize the loop
device to increase performance.
* Other Documentation and man page improvements:
* Update LUKS2 on-disk format description.
* Add per-keyslot LUKS2 options to the man page.
Some options were missing for LUKS2 luksAddKey and luksChangeKey.
* Fix cryptsetup manpage to use PBKDF consistently.
* Add compile info to README. This information was lost when we removed
the default automake INSTALL file.
* Use volume key consistently in FAQ and man pages.
* Use markdown version of FAQ directly for installation.
* Clarify graceful reencryption interruption.
Currently, it can be interrupted by both SIGINT and SIGTERM signals.
* Add new mailing list info.
* Mention non-cryptographic xxhash64 hash for integrity protection.
* veritysetup: dump device sizes.
Calculating device sizes for verity devices is a little bit tricky.
Data, hash, and FEC can share devices or be separate devices.
Now dump command prints used device sizes, but it requires that
the user specifies all values that are not stored in superblock
(like FEC device and FEC roots).
* Fix check for argp_usage in configure if argp-standalone lib is used.
* Add constant time memcmp and hexa print implementation and use it for
cryptographic keys handling.
* Display progress when wiping the end of the resized device.
* LUKS2 token: prefer token PIN query before passphrase in some cases.
When a user provides --token-type or specific --token-id, a token PIN
query is preferred to a passphrase query.
* LUKS2 token: allow tokens to be replaced with --token-replace option
for cryptsetup token command.
* LUKS2 token: do not continue operation when interrupted in PIN prompt.
* Add --progress-json parameter to utilities.
Progress data can now be printed out in JSON format suitable for
machine processing.
* Embedded Argon2 PBKDF: optimize and simplify thread exit.
* Avoid using SHA1 in tests and fix new enforcements introduced in FIPS
provider for OpenSSL3 (like minimal parameters for PBKDF2).
* Use custom UTF conversion and avoid linking to iconv as a dependency.
* Reimplement BASE64 with simplified code instead of coreutils version.
Libcryptsetup API extensions and changes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Properly define uint32_t constants in API.
This is not a real change, but it avoids strict compiler warnings.
* crypt_resume_by_token_pin() - Resume crypt device using LUKS2 token.
* crypt_get_label() - Get the label of the LUKS2 device.
* crypt_get_subsystem() - Get the subsystem label of the LUKS2 device.
* Make CRYPT_WIPE_ENCRYPTED_ZERO crypt_wipe() option obsolete.
It was never implemented (the idea was to speed up wipe), but with
the recent RNG performance changes, it makes no longer sense.
* Add struct crypt_params_reencrypt changes related to decryption.
* Improve crypt_reencrypt_status() return values.
Empty or any non-LUKS types now returns CRYPT_REENCRYPT_INVALID status.
For LUKS1 devices, it returns CRYPT_REENCRYPT_NONE.

View File

@@ -33,6 +33,7 @@ libcryptsetup_la_LIBADD = \
@JSON_C_LIBS@ \
@BLKID_LIBS@ \
@DL_LIBS@ \
$(LTLIBICONV) \
$(LTLIBINTL) \
libcrypto_backend.la \
libutils_io.la
@@ -69,6 +70,8 @@ libcryptsetup_la_SOURCES = \
lib/volumekey.c \
lib/random.c \
lib/crypt_plain.c \
lib/base64.h \
lib/base64.c \
lib/integrity/integrity.h \
lib/integrity/integrity.c \
lib/loopaes/loopaes.h \

605
lib/base64.c Normal file
View File

@@ -0,0 +1,605 @@
/* base64.c -- Encode binary data using printable characters.
Copyright (C) 1999-2001, 2004-2006, 2009-2019 Free Software Foundation, Inc.
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, 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, see <https://www.gnu.org/licenses/>. */
/* Written by Simon Josefsson. Partially adapted from GNU MailUtils
* (mailbox/filter_trans.c, as of 2004-11-28). Improved by review
* from Paul Eggert, Bruno Haible, and Stepan Kasal.
*
* See also RFC 4648 <https://www.ietf.org/rfc/rfc4648.txt>.
*
* Be careful with error checking. Here is how you would typically
* use these functions:
*
* bool ok = base64_decode_alloc (in, inlen, &out, &outlen);
* if (!ok)
* FAIL: input was not valid base64
* if (out == NULL)
* FAIL: memory allocation error
* OK: data in OUT/OUTLEN
*
* size_t outlen = base64_encode_alloc (in, inlen, &out);
* if (out == NULL && outlen == 0 && inlen != 0)
* FAIL: input too long
* if (out == NULL)
* FAIL: memory allocation error
* OK: data in OUT/OUTLEN.
*
*/
#include <config.h>
/* Get prototype. */
#include "base64.h"
/* Get malloc. */
#include <stdlib.h>
/* Get UCHAR_MAX. */
#include <limits.h>
#include <string.h>
/* C89 compliant way to cast 'char' to 'unsigned char'. */
static unsigned char
to_uchar (char ch)
{
return ch;
}
static const char b64c[64] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/* Base64 encode IN array of size INLEN into OUT array. OUT needs
to be of length >= BASE64_LENGTH(INLEN), and INLEN needs to be
a multiple of 3. */
static void
base64_encode_fast (const char *restrict in, size_t inlen, char *restrict out)
{
while (inlen)
{
*out++ = b64c[(to_uchar (in[0]) >> 2) & 0x3f];
*out++ = b64c[((to_uchar (in[0]) << 4) + (to_uchar (in[1]) >> 4)) & 0x3f];
*out++ = b64c[((to_uchar (in[1]) << 2) + (to_uchar (in[2]) >> 6)) & 0x3f];
*out++ = b64c[to_uchar (in[2]) & 0x3f];
inlen -= 3;
in += 3;
}
}
/* Base64 encode IN array of size INLEN into OUT array of size OUTLEN.
If OUTLEN is less than BASE64_LENGTH(INLEN), write as many bytes as
possible. If OUTLEN is larger than BASE64_LENGTH(INLEN), also zero
terminate the output buffer. */
void
base64_encode (const char *restrict in, size_t inlen,
char *restrict out, size_t outlen)
{
/* Note this outlen constraint can be enforced at compile time.
I.E. that the output buffer is exactly large enough to hold
the encoded inlen bytes. The inlen constraints (of corresponding
to outlen, and being a multiple of 3) can change at runtime
at the end of input. However the common case when reading
large inputs is to have both constraints satisfied, so we depend
on both in base_encode_fast(). */
if (outlen % 4 == 0 && inlen == outlen / 4 * 3)
{
base64_encode_fast (in, inlen, out);
return;
}
while (inlen && outlen)
{
*out++ = b64c[(to_uchar (in[0]) >> 2) & 0x3f];
if (!--outlen)
break;
*out++ = b64c[((to_uchar (in[0]) << 4)
+ (--inlen ? to_uchar (in[1]) >> 4 : 0))
& 0x3f];
if (!--outlen)
break;
*out++ =
(inlen
? b64c[((to_uchar (in[1]) << 2)
+ (--inlen ? to_uchar (in[2]) >> 6 : 0))
& 0x3f]
: '=');
if (!--outlen)
break;
*out++ = inlen ? b64c[to_uchar (in[2]) & 0x3f] : '=';
if (!--outlen)
break;
if (inlen)
inlen--;
if (inlen)
in += 3;
}
if (outlen)
*out = '\0';
}
/* Allocate a buffer and store zero terminated base64 encoded data
from array IN of size INLEN, returning BASE64_LENGTH(INLEN), i.e.,
the length of the encoded data, excluding the terminating zero. On
return, the OUT variable will hold a pointer to newly allocated
memory that must be deallocated by the caller. If output string
length would overflow, 0 is returned and OUT is set to NULL. If
memory allocation failed, OUT is set to NULL, and the return value
indicates length of the requested memory block, i.e.,
BASE64_LENGTH(inlen) + 1. */
size_t
base64_encode_alloc (const char *in, size_t inlen, char **out)
{
size_t outlen = 1 + BASE64_LENGTH (inlen);
/* Check for overflow in outlen computation.
*
* If there is no overflow, outlen >= inlen.
*
* If the operation (inlen + 2) overflows then it yields at most +1, so
* outlen is 0.
*
* If the multiplication overflows, we lose at least half of the
* correct value, so the result is < ((inlen + 2) / 3) * 2, which is
* less than (inlen + 2) * 0.66667, which is less than inlen as soon as
* (inlen > 4).
*/
if (inlen > outlen)
{
*out = NULL;
return 0;
}
*out = malloc (outlen);
if (!*out)
return outlen;
base64_encode (in, inlen, *out, outlen);
return outlen - 1;
}
/* With this approach this file works independent of the charset used
(think EBCDIC). However, it does assume that the characters in the
Base64 alphabet (A-Za-z0-9+/) are encoded in 0..255. POSIX
1003.1-2001 require that char and unsigned char are 8-bit
quantities, though, taking care of that problem. But this may be a
potential problem on non-POSIX C99 platforms.
IBM C V6 for AIX mishandles "#define B64(x) ...'x'...", so use "_"
as the formal parameter rather than "x". */
#define B64(_) \
((_) == 'A' ? 0 \
: (_) == 'B' ? 1 \
: (_) == 'C' ? 2 \
: (_) == 'D' ? 3 \
: (_) == 'E' ? 4 \
: (_) == 'F' ? 5 \
: (_) == 'G' ? 6 \
: (_) == 'H' ? 7 \
: (_) == 'I' ? 8 \
: (_) == 'J' ? 9 \
: (_) == 'K' ? 10 \
: (_) == 'L' ? 11 \
: (_) == 'M' ? 12 \
: (_) == 'N' ? 13 \
: (_) == 'O' ? 14 \
: (_) == 'P' ? 15 \
: (_) == 'Q' ? 16 \
: (_) == 'R' ? 17 \
: (_) == 'S' ? 18 \
: (_) == 'T' ? 19 \
: (_) == 'U' ? 20 \
: (_) == 'V' ? 21 \
: (_) == 'W' ? 22 \
: (_) == 'X' ? 23 \
: (_) == 'Y' ? 24 \
: (_) == 'Z' ? 25 \
: (_) == 'a' ? 26 \
: (_) == 'b' ? 27 \
: (_) == 'c' ? 28 \
: (_) == 'd' ? 29 \
: (_) == 'e' ? 30 \
: (_) == 'f' ? 31 \
: (_) == 'g' ? 32 \
: (_) == 'h' ? 33 \
: (_) == 'i' ? 34 \
: (_) == 'j' ? 35 \
: (_) == 'k' ? 36 \
: (_) == 'l' ? 37 \
: (_) == 'm' ? 38 \
: (_) == 'n' ? 39 \
: (_) == 'o' ? 40 \
: (_) == 'p' ? 41 \
: (_) == 'q' ? 42 \
: (_) == 'r' ? 43 \
: (_) == 's' ? 44 \
: (_) == 't' ? 45 \
: (_) == 'u' ? 46 \
: (_) == 'v' ? 47 \
: (_) == 'w' ? 48 \
: (_) == 'x' ? 49 \
: (_) == 'y' ? 50 \
: (_) == 'z' ? 51 \
: (_) == '0' ? 52 \
: (_) == '1' ? 53 \
: (_) == '2' ? 54 \
: (_) == '3' ? 55 \
: (_) == '4' ? 56 \
: (_) == '5' ? 57 \
: (_) == '6' ? 58 \
: (_) == '7' ? 59 \
: (_) == '8' ? 60 \
: (_) == '9' ? 61 \
: (_) == '+' ? 62 \
: (_) == '/' ? 63 \
: -1)
static const signed char b64[0x100] = {
B64 (0), B64 (1), B64 (2), B64 (3),
B64 (4), B64 (5), B64 (6), B64 (7),
B64 (8), B64 (9), B64 (10), B64 (11),
B64 (12), B64 (13), B64 (14), B64 (15),
B64 (16), B64 (17), B64 (18), B64 (19),
B64 (20), B64 (21), B64 (22), B64 (23),
B64 (24), B64 (25), B64 (26), B64 (27),
B64 (28), B64 (29), B64 (30), B64 (31),
B64 (32), B64 (33), B64 (34), B64 (35),
B64 (36), B64 (37), B64 (38), B64 (39),
B64 (40), B64 (41), B64 (42), B64 (43),
B64 (44), B64 (45), B64 (46), B64 (47),
B64 (48), B64 (49), B64 (50), B64 (51),
B64 (52), B64 (53), B64 (54), B64 (55),
B64 (56), B64 (57), B64 (58), B64 (59),
B64 (60), B64 (61), B64 (62), B64 (63),
B64 (64), B64 (65), B64 (66), B64 (67),
B64 (68), B64 (69), B64 (70), B64 (71),
B64 (72), B64 (73), B64 (74), B64 (75),
B64 (76), B64 (77), B64 (78), B64 (79),
B64 (80), B64 (81), B64 (82), B64 (83),
B64 (84), B64 (85), B64 (86), B64 (87),
B64 (88), B64 (89), B64 (90), B64 (91),
B64 (92), B64 (93), B64 (94), B64 (95),
B64 (96), B64 (97), B64 (98), B64 (99),
B64 (100), B64 (101), B64 (102), B64 (103),
B64 (104), B64 (105), B64 (106), B64 (107),
B64 (108), B64 (109), B64 (110), B64 (111),
B64 (112), B64 (113), B64 (114), B64 (115),
B64 (116), B64 (117), B64 (118), B64 (119),
B64 (120), B64 (121), B64 (122), B64 (123),
B64 (124), B64 (125), B64 (126), B64 (127),
B64 (128), B64 (129), B64 (130), B64 (131),
B64 (132), B64 (133), B64 (134), B64 (135),
B64 (136), B64 (137), B64 (138), B64 (139),
B64 (140), B64 (141), B64 (142), B64 (143),
B64 (144), B64 (145), B64 (146), B64 (147),
B64 (148), B64 (149), B64 (150), B64 (151),
B64 (152), B64 (153), B64 (154), B64 (155),
B64 (156), B64 (157), B64 (158), B64 (159),
B64 (160), B64 (161), B64 (162), B64 (163),
B64 (164), B64 (165), B64 (166), B64 (167),
B64 (168), B64 (169), B64 (170), B64 (171),
B64 (172), B64 (173), B64 (174), B64 (175),
B64 (176), B64 (177), B64 (178), B64 (179),
B64 (180), B64 (181), B64 (182), B64 (183),
B64 (184), B64 (185), B64 (186), B64 (187),
B64 (188), B64 (189), B64 (190), B64 (191),
B64 (192), B64 (193), B64 (194), B64 (195),
B64 (196), B64 (197), B64 (198), B64 (199),
B64 (200), B64 (201), B64 (202), B64 (203),
B64 (204), B64 (205), B64 (206), B64 (207),
B64 (208), B64 (209), B64 (210), B64 (211),
B64 (212), B64 (213), B64 (214), B64 (215),
B64 (216), B64 (217), B64 (218), B64 (219),
B64 (220), B64 (221), B64 (222), B64 (223),
B64 (224), B64 (225), B64 (226), B64 (227),
B64 (228), B64 (229), B64 (230), B64 (231),
B64 (232), B64 (233), B64 (234), B64 (235),
B64 (236), B64 (237), B64 (238), B64 (239),
B64 (240), B64 (241), B64 (242), B64 (243),
B64 (244), B64 (245), B64 (246), B64 (247),
B64 (248), B64 (249), B64 (250), B64 (251),
B64 (252), B64 (253), B64 (254), B64 (255)
};
#if UCHAR_MAX == 255
# define uchar_in_range(c) true
#else
# define uchar_in_range(c) ((c) <= 255)
#endif
/* Return true if CH is a character from the Base64 alphabet, and
false otherwise. Note that '=' is padding and not considered to be
part of the alphabet. */
bool
isbase64 (char ch)
{
return uchar_in_range (to_uchar (ch)) && 0 <= b64[to_uchar (ch)];
}
/* Initialize decode-context buffer, CTX. */
void
base64_decode_ctx_init (struct base64_decode_context *ctx)
{
ctx->i = 0;
}
/* If CTX->i is 0 or 4, there are four or more bytes in [*IN..IN_END), and
none of those four is a newline, then return *IN. Otherwise, copy up to
4 - CTX->i non-newline bytes from that range into CTX->buf, starting at
index CTX->i and setting CTX->i to reflect the number of bytes copied,
and return CTX->buf. In either case, advance *IN to point to the byte
after the last one processed, and set *N_NON_NEWLINE to the number of
verified non-newline bytes accessible through the returned pointer. */
static const char *
get_4 (struct base64_decode_context *ctx,
char const *restrict *in, char const *restrict in_end,
size_t *n_non_newline)
{
if (ctx->i == 4)
ctx->i = 0;
if (ctx->i == 0)
{
char const *t = *in;
if (4 <= in_end - *in && memchr (t, '\n', 4) == NULL)
{
/* This is the common case: no newline. */
*in += 4;
*n_non_newline = 4;
return (const char *) t;
}
}
{
/* Copy non-newline bytes into BUF. */
char const *p = *in;
while (p < in_end)
{
char c = *p++;
if (c != '\n')
{
ctx->buf[ctx->i++] = c;
if (ctx->i == 4)
break;
}
}
*in = p;
*n_non_newline = ctx->i;
return ctx->buf;
}
}
#define return_false \
do \
{ \
*outp = out; \
return false; \
} \
while (false)
/* Decode up to four bytes of base64-encoded data, IN, of length INLEN
into the output buffer, *OUT, of size *OUTLEN bytes. Return true if
decoding is successful, false otherwise. If *OUTLEN is too small,
as many bytes as possible are written to *OUT. On return, advance
*OUT to point to the byte after the last one written, and decrement
*OUTLEN to reflect the number of bytes remaining in *OUT. */
static bool
decode_4 (char const *restrict in, size_t inlen,
char *restrict *outp, size_t *outleft)
{
char *out = *outp;
if (inlen < 2)
return false;
if (!isbase64 (in[0]) || !isbase64 (in[1]))
return false;
if (*outleft)
{
*out++ = ((b64[to_uchar (in[0])] << 2)
| (b64[to_uchar (in[1])] >> 4));
--*outleft;
}
if (inlen == 2)
return_false;
if (in[2] == '=')
{
if (inlen != 4)
return_false;
if (in[3] != '=')
return_false;
}
else
{
if (!isbase64 (in[2]))
return_false;
if (*outleft)
{
*out++ = (((b64[to_uchar (in[1])] << 4) & 0xf0)
| (b64[to_uchar (in[2])] >> 2));
--*outleft;
}
if (inlen == 3)
return_false;
if (in[3] == '=')
{
if (inlen != 4)
return_false;
}
else
{
if (!isbase64 (in[3]))
return_false;
if (*outleft)
{
*out++ = (((b64[to_uchar (in[2])] << 6) & 0xc0)
| b64[to_uchar (in[3])]);
--*outleft;
}
}
}
*outp = out;
return true;
}
/* Decode base64-encoded input array IN of length INLEN to output array
OUT that can hold *OUTLEN bytes. The input data may be interspersed
with newlines. Return true if decoding was successful, i.e. if the
input was valid base64 data, false otherwise. If *OUTLEN is too
small, as many bytes as possible will be written to OUT. On return,
*OUTLEN holds the length of decoded bytes in OUT. Note that as soon
as any non-alphabet, non-newline character is encountered, decoding
is stopped and false is returned. If INLEN is zero, then process
only whatever data is stored in CTX.
Initially, CTX must have been initialized via base64_decode_ctx_init.
Subsequent calls to this function must reuse whatever state is recorded
in that buffer. It is necessary for when a quadruple of base64 input
bytes spans two input buffers.
If CTX is NULL then newlines are treated as garbage and the input
buffer is processed as a unit. */
bool
base64_decode_ctx (struct base64_decode_context *ctx,
const char *restrict in, size_t inlen,
char *restrict out, size_t *outlen)
{
size_t outleft = *outlen;
bool ignore_newlines = ctx != NULL;
bool flush_ctx = false;
unsigned int ctx_i = 0;
if (ignore_newlines)
{
ctx_i = ctx->i;
flush_ctx = inlen == 0;
}
while (true)
{
size_t outleft_save = outleft;
if (ctx_i == 0 && !flush_ctx)
{
while (true)
{
/* Save a copy of outleft, in case we need to re-parse this
block of four bytes. */
outleft_save = outleft;
if (!decode_4 (in, inlen, &out, &outleft))
break;
in += 4;
inlen -= 4;
}
}
if (inlen == 0 && !flush_ctx)
break;
/* Handle the common case of 72-byte wrapped lines.
This also handles any other multiple-of-4-byte wrapping. */
if (inlen && *in == '\n' && ignore_newlines)
{
++in;
--inlen;
continue;
}
/* Restore OUT and OUTLEFT. */
out -= outleft_save - outleft;
outleft = outleft_save;
{
char const *in_end = in + inlen;
char const *non_nl;
if (ignore_newlines)
non_nl = get_4 (ctx, &in, in_end, &inlen);
else
non_nl = in; /* Might have nl in this case. */
/* If the input is empty or consists solely of newlines (0 non-newlines),
then we're done. Likewise if there are fewer than 4 bytes when not
flushing context and not treating newlines as garbage. */
if (inlen == 0 || (inlen < 4 && !flush_ctx && ignore_newlines))
{
inlen = 0;
break;
}
if (!decode_4 (non_nl, inlen, &out, &outleft))
break;
inlen = in_end - in;
}
}
*outlen -= outleft;
return inlen == 0;
}
/* Allocate an output buffer in *OUT, and decode the base64 encoded
data stored in IN of size INLEN to the *OUT buffer. On return, the
size of the decoded data is stored in *OUTLEN. OUTLEN may be NULL,
if the caller is not interested in the decoded length. *OUT may be
NULL to indicate an out of memory error, in which case *OUTLEN
contains the size of the memory block needed. The function returns
true on successful decoding and memory allocation errors. (Use the
*OUT and *OUTLEN parameters to differentiate between successful
decoding and memory error.) The function returns false if the
input was invalid, in which case *OUT is NULL and *OUTLEN is
undefined. */
bool
base64_decode_alloc_ctx (struct base64_decode_context *ctx,
const char *in, size_t inlen, char **out,
size_t *outlen)
{
/* This may allocate a few bytes too many, depending on input,
but it's not worth the extra CPU time to compute the exact size.
The exact size is 3 * (inlen + (ctx ? ctx->i : 0)) / 4, minus 1 if the
input ends with "=" and minus another 1 if the input ends with "==".
Dividing before multiplying avoids the possibility of overflow. */
size_t needlen = 3 * (inlen / 4) + 3;
*out = malloc (needlen);
if (!*out)
return true;
if (!base64_decode_ctx (ctx, in, inlen, *out, &needlen))
{
free (*out);
*out = NULL;
return false;
}
if (outlen)
*outlen = needlen;
return true;
}

68
lib/base64.h Normal file
View File

@@ -0,0 +1,68 @@
/* base64.h -- Encode binary data using printable characters.
Copyright (C) 2004-2006, 2009-2019 Free Software Foundation, Inc.
Written by Simon Josefsson.
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, 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, see <https://www.gnu.org/licenses/>. */
#ifndef BASE64_H
# define BASE64_H
/* Get size_t. */
# include <stddef.h>
/* Get bool. */
# include <stdbool.h>
# ifdef __cplusplus
extern "C" {
# endif
/* This uses that the expression (n+(k-1))/k means the smallest
integer >= n/k, i.e., the ceiling of n/k. */
# define BASE64_LENGTH(inlen) ((((inlen) + 2) / 3) * 4)
struct base64_decode_context
{
unsigned int i;
char buf[4];
};
extern bool isbase64 (char ch) __attribute__ ((__const__));
extern void base64_encode (const char *restrict in, size_t inlen,
char *restrict out, size_t outlen);
extern size_t base64_encode_alloc (const char *in, size_t inlen, char **out);
extern void base64_decode_ctx_init (struct base64_decode_context *ctx);
extern bool base64_decode_ctx (struct base64_decode_context *ctx,
const char *restrict in, size_t inlen,
char *restrict out, size_t *outlen);
extern bool base64_decode_alloc_ctx (struct base64_decode_context *ctx,
const char *in, size_t inlen,
char **out, size_t *outlen);
#define base64_decode(in, inlen, out, outlen) \
base64_decode_ctx (NULL, in, inlen, out, outlen)
#define base64_decode_alloc(in, inlen, out, outlen) \
base64_decode_alloc_ctx (NULL, in, inlen, out, outlen)
# ifdef __cplusplus
}
# endif
#endif /* BASE64_H */

View File

@@ -1,9 +1,9 @@
/*
* BITLK (BitLocker-compatible) volume handling
*
* Copyright (C) 2019-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2019-2022 Milan Broz
* Copyright (C) 2019-2022 Vojtech Trefny
* Copyright (C) 2019-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2019-2021 Milan Broz
* Copyright (C) 2019-2021 Vojtech Trefny
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -24,6 +24,7 @@
#include <string.h>
#include <uuid/uuid.h>
#include <time.h>
#include <iconv.h>
#include <limits.h>
#include "bitlk.h"
@@ -233,11 +234,86 @@ static const char* get_bitlk_type_string(BITLKEncryptionType type)
}
}
/* TODO -- move to some utils file */
static void hexprint(struct crypt_device *cd, const char *d, int n, const char *sep)
{
int i;
for(i = 0; i < n; i++)
log_std(cd, "%02hhx%s", (const char)d[i], sep);
}
static uint64_t filetime_to_unixtime(uint64_t time)
{
return (time - EPOCH_AS_FILETIME) / HUNDREDS_OF_NANOSECONDS;
}
static int convert_to_utf8(struct crypt_device *cd, uint8_t *input, size_t inlen, char **out)
{
char *outbuf = NULL;
iconv_t ic;
size_t ic_inlen = inlen;
size_t ic_outlen = inlen;
char *ic_outbuf = NULL;
size_t r = 0;
outbuf = malloc(inlen);
if (outbuf == NULL)
return -ENOMEM;
memset(outbuf, 0, inlen);
ic_outbuf = outbuf;
ic = iconv_open("UTF-8", "UTF-16LE");
r = iconv(ic, (char **) &input, &ic_inlen, &ic_outbuf, &ic_outlen);
iconv_close(ic);
if (r == 0)
*out = strdup(outbuf);
else {
*out = NULL;
log_dbg(cd, "Failed to convert volume description: %s", strerror(errno));
r = 0;
}
free(outbuf);
return r;
}
static int passphrase_to_utf16(struct crypt_device *cd, char *input, size_t inlen, char **out)
{
char *outbuf = NULL;
iconv_t ic;
size_t ic_inlen = inlen;
size_t ic_outlen = inlen * 2;
char *ic_outbuf = NULL;
size_t r = 0;
if (inlen == 0)
return r;
outbuf = crypt_safe_alloc(inlen * 2);
if (outbuf == NULL)
return -ENOMEM;
memset(outbuf, 0, inlen * 2);
ic_outbuf = outbuf;
ic = iconv_open("UTF-16LE", "UTF-8");
r = iconv(ic, &input, &ic_inlen, &ic_outbuf, &ic_outlen);
iconv_close(ic);
if (r == 0) {
*out = outbuf;
} else {
*out = NULL;
crypt_safe_free(outbuf);
log_dbg(cd, "Failed to convert passphrase: %s", strerror(errno));
r = -errno;
}
return r;
}
static int parse_vmk_entry(struct crypt_device *cd, uint8_t *data, int start, int end, struct bitlk_vmk **vmk)
{
uint16_t key_entry_size = 0;
@@ -248,7 +324,6 @@ static int parse_vmk_entry(struct crypt_device *cd, uint8_t *data, int start, in
const char *key = NULL;
struct volume_key *vk = NULL;
bool supported = false;
int r = 0;
/* only passphrase or recovery passphrase vmks are supported (can be used to activate) */
supported = (*vmk)->protection == BITLK_PROTECTION_PASSPHRASE ||
@@ -318,14 +393,9 @@ static int parse_vmk_entry(struct crypt_device *cd, uint8_t *data, int start, in
} else if (key_entry_value == BITLK_ENTRY_VALUE_RECOVERY_TIME) {
;
} else if (key_entry_value == BITLK_ENTRY_VALUE_STRING) {
string = malloc((key_entry_size - BITLK_ENTRY_HEADER_LEN) * 2 + 1);
if (!string)
return -ENOMEM;
r = crypt_utf16_to_utf8(&string, CONST_CAST(char16_t *)(data + start + BITLK_ENTRY_HEADER_LEN),
key_entry_size - BITLK_ENTRY_HEADER_LEN);
if (r < 0 || !string) {
free(string);
if (convert_to_utf8(cd, data + start + BITLK_ENTRY_HEADER_LEN, key_entry_size - BITLK_ENTRY_HEADER_LEN, &string) < 0) {
log_err(cd, _("Invalid string found when parsing Volume Master Key."));
free(string);
return -EINVAL;
} else if ((*vmk)->name != NULL) {
if (supported) {
@@ -416,7 +486,6 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
int end = 0;
size_t key_size = 0;
const char *key = NULL;
char *description = NULL;
struct bitlk_vmk *vmk = NULL;
struct bitlk_vmk *vmk_p = params->vmks;
@@ -430,8 +499,8 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
/* read and check the signature */
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
device_alignment(device), &sig, sizeof(sig), 0) != sizeof(sig)) {
log_dbg(cd, "Failed to read BITLK signature from %s.", device_path(device));
r = -EIO;
log_err(cd, _("Failed to read BITLK signature from %s."), device_path(device));
r = -EINVAL;
goto out;
}
@@ -442,7 +511,7 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
params->togo = true;
fve_offset = BITLK_HEADER_METADATA_OFFSET_TOGO;
} else {
log_dbg(cd, "Invalid or unknown signature for BITLK device.");
log_err(cd, _("Invalid or unknown signature for BITLK device."));
r = -EINVAL;
goto out;
}
@@ -512,7 +581,6 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
le16_to_cpu(fve.curr_state), le16_to_cpu(fve.next_state));
}
params->volume_size = le64_to_cpu(fve.volume_size);
params->metadata_version = le16_to_cpu(fve.fve_version);
fve_metadata_size = le32_to_cpu(fve.metadata_size);
@@ -670,18 +738,13 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
params->volume_header_size = le64_to_cpu(entry_header.size);
/* volume description (utf-16 string) */
} else if (entry_type == BITLK_ENTRY_TYPE_DESCRIPTION) {
description = malloc((entry_size - BITLK_ENTRY_HEADER_LEN - BITLK_ENTRY_HEADER_LEN) * 2 + 1);
if (!description)
return -ENOMEM;
r = crypt_utf16_to_utf8(&description, CONST_CAST(char16_t *)(fve_entries + start + BITLK_ENTRY_HEADER_LEN),
entry_size - BITLK_ENTRY_HEADER_LEN);
if (r < 0 || !description) {
free(description);
r = convert_to_utf8(cd, fve_entries + start + BITLK_ENTRY_HEADER_LEN,
entry_size - BITLK_ENTRY_HEADER_LEN,
&(params->description));
if (r < 0) {
BITLK_bitlk_vmk_free(vmk);
log_err(cd, _("Failed to convert BITLK volume description"));
goto out;
}
params->description = description;
}
start += entry_size;
@@ -704,7 +767,6 @@ int BITLK_dump(struct crypt_device *cd, struct device *device, struct bitlk_meta
log_std(cd, "Version: \t%u\n", params->metadata_version);
log_std(cd, "GUID: \t%s\n", params->guid);
log_std(cd, "Sector size: \t%u [bytes]\n", params->sector_size);
log_std(cd, "Volume size: \t%" PRIu64 " [bytes]\n", params->volume_size);
log_std(cd, "Created: \t%s", ctime((time_t *)&(params->creation_time)));
log_std(cd, "Description: \t%s\n", params->description);
log_std(cd, "Cipher name: \t%s\n", params->cipher);
@@ -723,7 +785,7 @@ int BITLK_dump(struct crypt_device *cd, struct device *device, struct bitlk_meta
log_std(cd, "\tGUID: \t%s\n", vmk_p->guid);
log_std(cd, "\tProtection: \t%s\n", get_vmk_protection_string (vmk_p->protection));
log_std(cd, "\tSalt: \t");
crypt_log_hex(cd, (const char *) vmk_p->salt, 16, "", 0, NULL);
hexprint(cd, (const char *) vmk_p->salt, 16, "");
log_std(cd, "\n");
vk_p = vmk_p->vk;
@@ -946,7 +1008,7 @@ static int bitlk_kdf(struct crypt_device *cd,
struct bitlk_kdf_data kdf = {};
struct crypt_hash *hd = NULL;
int len = 0;
char16_t *utf16Password = NULL;
char *utf16Password = NULL;
int i = 0;
int r = 0;
@@ -963,16 +1025,11 @@ static int bitlk_kdf(struct crypt_device *cd,
if (!recovery) {
/* passphrase: convert to UTF-16 first, then sha256(sha256(pw)) */
utf16Password = crypt_safe_alloc(sizeof(char16_t) * (passwordLen + 1));
if (!utf16Password) {
r = -ENOMEM;
goto out;
}
r = crypt_utf8_to_utf16(&utf16Password, CONST_CAST(char*)password, passwordLen);
r = passphrase_to_utf16(cd, CONST_CAST(char*)password, passwordLen, &utf16Password);
if (r < 0)
goto out;
crypt_hash_write(hd, (char*)utf16Password, passwordLen * 2);
crypt_hash_write(hd, utf16Password, passwordLen * 2);
r = crypt_hash_final(hd, kdf.initial_sha256, len);
if (r < 0)
goto out;
@@ -1201,7 +1258,7 @@ static int _activate(struct crypt_device *cd,
uint64_t next_start = 0;
uint64_t next_end = 0;
uint64_t last_segment = 0;
uint32_t dmt_flags = 0;
uint32_t dmt_flags;
r = _activate_check(cd, params);
if (r)
@@ -1212,11 +1269,6 @@ static int _activate(struct crypt_device *cd,
if (r)
return r;
if (dmd.size * SECTOR_SIZE != params->volume_size)
log_std(cd, _("WARNING: BitLocker volume size %" PRIu64 " does not match the underlying device size %" PRIu64 ""),
params->volume_size,
dmd.size * SECTOR_SIZE);
/* there will be always 4 dm-zero segments: 3x metadata, 1x FS header */
for (i = 0; i < 3; i++) {
segments[num_segments].offset = params->metadata_offset[i] / SECTOR_SIZE;
@@ -1347,14 +1399,6 @@ static int _activate(struct crypt_device *cd,
log_err(cd, _("Cannot activate device, kernel dm-crypt is missing support for BITLK Elephant diffuser."));
r = -ENOTSUP;
}
if ((dmd.flags & CRYPT_ACTIVATE_IV_LARGE_SECTORS) && !(dmt_flags & DM_SECTOR_SIZE_SUPPORTED)) {
log_err(cd, _("Cannot activate device, kernel dm-crypt is missing support for large sector size."));
r = -ENOTSUP;
}
if (dm_flags(cd, DM_ZERO, &dmt_flags) < 0) {
log_err(cd, _("Cannot activate device, kernel dm-zero module is missing."));
r = -ENOTSUP;
}
}
out:
dm_targets_free(cd, &dmd);

View File

@@ -1,9 +1,9 @@
/*
* BITLK (BitLocker-compatible) header definition
*
* Copyright (C) 2019-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2019-2022 Milan Broz
* Copyright (C) 2019-2022 Vojtech Trefny
* Copyright (C) 2019-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2019-2021 Milan Broz
* Copyright (C) 2019-2021 Vojtech Trefny
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -99,7 +99,6 @@ struct bitlk_fvek {
struct bitlk_metadata {
uint16_t sector_size;
uint64_t volume_size;
bool togo;
bool state;
BITLKEncryptionType type;

View File

@@ -2,8 +2,8 @@
* cryptsetup plain device helper functions
*
* Copyright (C) 2004 Jana Saout <jana@saout.de>
* Copyright (C) 2010-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2022 Milan Broz
* Copyright (C) 2010-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2021 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

View File

@@ -9,8 +9,6 @@ libcrypto_backend_la_SOURCES = \
lib/crypto_backend/crypto_storage.c \
lib/crypto_backend/pbkdf_check.c \
lib/crypto_backend/crc32.c \
lib/crypto_backend/base64.c \
lib/crypto_backend/utf8.c \
lib/crypto_backend/argon2_generic.c \
lib/crypto_backend/cipher_generic.c \
lib/crypto_backend/cipher_check.c

View File

@@ -279,6 +279,7 @@ static void *fill_segment_thr(void *thread_data)
{
argon2_thread_data *my_data = thread_data;
fill_segment(my_data->instance_ptr, my_data->pos);
argon2_thread_exit();
return 0;
}

View File

@@ -46,4 +46,12 @@ int argon2_thread_join(argon2_thread_handle_t handle) {
#endif
}
void argon2_thread_exit(void) {
#if defined(_WIN32)
_endthreadex(0);
#else
pthread_exit(NULL);
#endif
}
#endif /* ARGON2_NO_THREADS */

View File

@@ -58,5 +58,10 @@ int argon2_thread_create(argon2_thread_handle_t *handle,
*/
int argon2_thread_join(argon2_thread_handle_t handle);
/* Terminate the current thread. Must be run inside a thread created by
* argon2_thread_create.
*/
void argon2_thread_exit(void);
#endif /* ARGON2_NO_THREADS */
#endif

View File

@@ -1,8 +1,8 @@
/*
* Argon2 PBKDF2 library wrapper
*
* Copyright (C) 2016-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2022 Milan Broz
* Copyright (C) 2016-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2021 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

View File

@@ -1,277 +0,0 @@
/*
* Base64 "Not encryption" helpers, copied and adapted from systemd project.
*
* Copyright (C) 2010 Lennart Poettering
*
* cryptsetup related changes
* Copyright (C) 2021-2022 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <errno.h>
#include <stdlib.h>
#include <limits.h>
#include <assert.h>
#include "crypto_backend.h"
#define WHITESPACE " \t\n\r"
/* https://tools.ietf.org/html/rfc4648#section-4 */
static char base64char(int x)
{
static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
return table[x & 63];
}
static int unbase64char(char c)
{
unsigned offset;
if (c >= 'A' && c <= 'Z')
return c - 'A';
offset = 'Z' - 'A' + 1;
if (c >= 'a' && c <= 'z')
return c - 'a' + offset;
offset += 'z' - 'a' + 1;
if (c >= '0' && c <= '9')
return c - '0' + offset;
offset += '9' - '0' + 1;
if (c == '+')
return offset;
offset++;
if (c == '/')
return offset;
return -EINVAL;
}
int crypt_base64_encode(char **out, size_t *out_length, const char *in, size_t in_length)
{
char *r, *z;
const uint8_t *x;
assert(in || in_length == 0);
assert(out);
/* three input bytes makes four output bytes, padding is added so we must round up */
z = r = malloc(4 * (in_length + 2) / 3 + 1);
if (!r)
return -ENOMEM;
for (x = (const uint8_t *)in; x < (const uint8_t*)in + (in_length / 3) * 3; x += 3) {
/* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
*(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
*(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
*(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */
*(z++) = base64char(x[2] & 63); /* 00ZZZZZZ */
}
switch (in_length % 3) {
case 2:
*(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
*(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
*(z++) = base64char((x[1] & 15) << 2); /* 00YYYY00 */
*(z++) = '=';
break;
case 1:
*(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
*(z++) = base64char((x[0] & 3) << 4); /* 00XX0000 */
*(z++) = '=';
*(z++) = '=';
break;
}
*z = 0;
*out = r;
if (out_length)
*out_length = z - r;
return 0;
}
static int unbase64_next(const char **p, size_t *l)
{
int ret;
assert(p);
assert(l);
/* Find the next non-whitespace character, and decode it. If we find padding, we return it as INT_MAX. We
* greedily skip all preceding and all following whitespace. */
for (;;) {
if (*l == 0)
return -EPIPE;
if (!strchr(WHITESPACE, **p))
break;
/* Skip leading whitespace */
(*p)++, (*l)--;
}
if (**p == '=')
ret = INT_MAX; /* return padding as INT_MAX */
else {
ret = unbase64char(**p);
if (ret < 0)
return ret;
}
for (;;) {
(*p)++, (*l)--;
if (*l == 0)
break;
if (!strchr(WHITESPACE, **p))
break;
/* Skip following whitespace */
}
return ret;
}
int crypt_base64_decode(char **out, size_t *out_length, const char *in, size_t in_length)
{
uint8_t *buf = NULL;
const char *x;
uint8_t *z;
size_t len;
int r;
assert(in || in_length == 0);
assert(out);
assert(out_length);
if (in_length == (size_t) -1)
in_length = strlen(in);
/* A group of four input bytes needs three output bytes, in case of padding we need to add two or three extra
* bytes. Note that this calculation is an upper boundary, as we ignore whitespace while decoding */
len = (in_length / 4) * 3 + (in_length % 4 != 0 ? (in_length % 4) - 1 : 0);
buf = malloc(len + 1);
if (!buf)
return -ENOMEM;
for (x = in, z = buf;;) {
int a, b, c, d; /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
a = unbase64_next(&x, &in_length);
if (a == -EPIPE) /* End of string */
break;
if (a < 0) {
r = a;
goto err;
}
if (a == INT_MAX) { /* Padding is not allowed at the beginning of a 4ch block */
r = -EINVAL;
goto err;
}
b = unbase64_next(&x, &in_length);
if (b < 0) {
r = b;
goto err;
}
if (b == INT_MAX) { /* Padding is not allowed at the second character of a 4ch block either */
r = -EINVAL;
goto err;
}
c = unbase64_next(&x, &in_length);
if (c < 0) {
r = c;
goto err;
}
d = unbase64_next(&x, &in_length);
if (d < 0) {
r = d;
goto err;
}
if (c == INT_MAX) { /* Padding at the third character */
if (d != INT_MAX) { /* If the third character is padding, the fourth must be too */
r = -EINVAL;
goto err;
}
/* b == 00YY0000 */
if (b & 15) {
r = -EINVAL;
goto err;
}
if (in_length > 0) { /* Trailing rubbish? */
r = -ENAMETOOLONG;
goto err;
}
*(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
break;
}
if (d == INT_MAX) {
/* c == 00ZZZZ00 */
if (c & 3) {
r = -EINVAL;
goto err;
}
if (in_length > 0) { /* Trailing rubbish? */
r = -ENAMETOOLONG;
goto err;
}
*(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
*(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
break;
}
*(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
*(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
*(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */
}
*z = 0;
*out_length = (size_t) (z - buf);
*out = (char *)buf;
return 0;
err:
free(buf);
/* Ignore other errors in crypt_backend */
if (r != -ENOMEM)
r = -EINVAL;
return r;
}

View File

@@ -1,8 +1,8 @@
/*
* Cipher performance check
*
* Copyright (C) 2018-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2018-2022 Milan Broz
* Copyright (C) 2018-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2018-2021 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

View File

@@ -1,8 +1,8 @@
/*
* Linux kernel cipher generic utilities
*
* Copyright (C) 2018-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2018-2022 Milan Broz
* Copyright (C) 2018-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2018-2021 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

View File

@@ -1,8 +1,8 @@
/*
* crypto backend implementation
*
* Copyright (C) 2010-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2022 Milan Broz
* Copyright (C) 2010-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2021 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -25,12 +25,6 @@
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#ifdef HAVE_UCHAR_H
#include <uchar.h>
#else
#define char32_t uint32_t
#define char16_t uint16_t
#endif
struct crypt_hash;
struct crypt_hmac;
@@ -89,14 +83,6 @@ int crypt_pbkdf_perf(const char *kdf, const char *hash,
/* CRC32 */
uint32_t crypt_crc32(uint32_t seed, const unsigned char *buf, size_t len);
/* Base64 */
int crypt_base64_encode(char **out, size_t *out_length, const char *in, size_t in_length);
int crypt_base64_decode(char **out, size_t *out_length, const char *in, size_t in_length);
/* UTF8/16 */
int crypt_utf16_to_utf8(char **out, const char16_t *s, size_t length /* bytes! */);
int crypt_utf8_to_utf16(char16_t **out, const char *s, size_t length);
/* Block ciphers */
int crypt_cipher_ivsize(const char *name, const char *mode);
int crypt_cipher_wrapped_key(const char *name, const char *mode);
@@ -149,7 +135,4 @@ static inline void crypt_backend_memzero(void *s, size_t n)
#endif
}
/* Memcmp helper (memcmp in constant time) */
int crypt_backend_memeq(const void *m1, const void *m2, size_t n);
#endif /* _CRYPTO_BACKEND_H */

View File

@@ -1,8 +1,8 @@
/*
* crypto backend implementation
*
* Copyright (C) 2010-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2022 Milan Broz
* Copyright (C) 2010-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2021 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -58,18 +58,4 @@ int crypt_bitlk_decrypt_key_kernel(const void *key, size_t key_length,
const char *iv, size_t iv_length,
const char *tag, size_t tag_length);
/* Internal implementation for constant time memory comparison */
static inline int crypt_internal_memeq(const void *m1, const void *m2, size_t n)
{
const unsigned char *_m1 = (const unsigned char *) m1;
const unsigned char *_m2 = (const unsigned char *) m2;
unsigned char result = 0;
size_t i;
for (i = 0; i < n; i++)
result |= _m1[i] ^ _m2[i];
return result;
}
#endif /* _CRYPTO_BACKEND_INTERNAL_H */

View File

@@ -1,8 +1,8 @@
/*
* Linux kernel userspace API crypto backend implementation (skcipher)
*
* Copyright (C) 2012-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2022 Milan Broz
* Copyright (C) 2012-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2021 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

View File

@@ -1,8 +1,8 @@
/*
* GCRYPT crypto backend implementation
*
* Copyright (C) 2010-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2022 Milan Broz
* Copyright (C) 2010-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2021 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -550,8 +550,3 @@ out:
return -ENOTSUP;
#endif
}
int crypt_backend_memeq(const void *m1, const void *m2, size_t n)
{
return crypt_internal_memeq(m1, m2, n);
}

View File

@@ -1,8 +1,8 @@
/*
* Linux kernel userspace API crypto backend implementation
*
* Copyright (C) 2010-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2022 Milan Broz
* Copyright (C) 2010-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2021 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -416,8 +416,3 @@ int crypt_bitlk_decrypt_key(const void *key, size_t key_length,
return crypt_bitlk_decrypt_key_kernel(key, key_length, in, out, length,
iv, iv_length, tag, tag_length);
}
int crypt_backend_memeq(const void *m1, const void *m2, size_t n)
{
return crypt_internal_memeq(m1, m2, n);
}

View File

@@ -1,8 +1,8 @@
/*
* Nettle crypto backend implementation
*
* Copyright (C) 2011-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2022 Milan Broz
* Copyright (C) 2011-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2021 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -26,7 +26,6 @@
#include <nettle/sha3.h>
#include <nettle/hmac.h>
#include <nettle/pbkdf2.h>
#include <nettle/memops.h>
#include "crypto_backend_internal.h"
#if HAVE_NETTLE_VERSION_H
@@ -447,9 +446,3 @@ int crypt_bitlk_decrypt_key(const void *key, size_t key_length,
return crypt_bitlk_decrypt_key_kernel(key, key_length, in, out, length,
iv, iv_length, tag, tag_length);
}
int crypt_backend_memeq(const void *m1, const void *m2, size_t n)
{
/* The logic is inverse to memcmp... */
return !memeql_sec(m1, m2, n);
}

View File

@@ -1,8 +1,8 @@
/*
* NSS crypto backend implementation
*
* Copyright (C) 2010-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2022 Milan Broz
* Copyright (C) 2010-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2021 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -395,8 +395,3 @@ int crypt_bitlk_decrypt_key(const void *key, size_t key_length,
return crypt_bitlk_decrypt_key_kernel(key, key_length, in, out, length,
iv, iv_length, tag, tag_length);
}
int crypt_backend_memeq(const void *m1, const void *m2, size_t n)
{
return NSS_SecureMemcmp(m1, m2, n);
}

View File

@@ -1,8 +1,8 @@
/*
* OPENSSL crypto backend implementation
*
* Copyright (C) 2010-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2022 Milan Broz
* Copyright (C) 2010-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2021 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -30,7 +30,6 @@
#include <string.h>
#include <errno.h>
#include <openssl/crypto.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/rand.h>
@@ -790,6 +789,9 @@ int crypt_bitlk_decrypt_key(const void *key, size_t key_length __attribute__((un
if (EVP_DecryptInit_ex(ctx, EVP_aes_256_ccm(), NULL, NULL, NULL) != 1)
goto out;
//EVP_CIPHER_CTX_key_length(ctx)
//EVP_CIPHER_CTX_iv_length(ctx)
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, iv_length, NULL) != 1)
goto out;
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, tag_length, CONST_CAST(void*)tag) != 1)
@@ -807,8 +809,3 @@ out:
return -ENOTSUP;
#endif
}
int crypt_backend_memeq(const void *m1, const void *m2, size_t n)
{
return CRYPTO_memcmp(m1, m2, n);
}

View File

@@ -2,7 +2,7 @@
* Generic wrapper for storage encryption modes and Initial Vectors
* (reimplementation of some functions from Linux dm-crypt kernel)
*
* Copyright (C) 2014-2022 Milan Broz
* Copyright (C) 2014-2021 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -151,8 +151,7 @@ static int crypt_sector_iv_init(struct crypt_sector_iv *ctx,
static int crypt_sector_iv_generate(struct crypt_sector_iv *ctx, uint64_t sector)
{
uint64_t val, *u64_iv;
uint32_t *u32_iv;
uint64_t val;
switch (ctx->type) {
case IV_NONE:
@@ -162,24 +161,19 @@ static int crypt_sector_iv_generate(struct crypt_sector_iv *ctx, uint64_t sector
break;
case IV_PLAIN:
memset(ctx->iv, 0, ctx->iv_size);
u32_iv = (void *)ctx->iv;
*u32_iv = cpu_to_le32(sector & 0xffffffff);
*(uint32_t *)ctx->iv = cpu_to_le32(sector & 0xffffffff);
break;
case IV_PLAIN64:
memset(ctx->iv, 0, ctx->iv_size);
u64_iv = (void *)ctx->iv;
*u64_iv = cpu_to_le64(sector);
*(uint64_t *)ctx->iv = cpu_to_le64(sector);
break;
case IV_PLAIN64BE:
memset(ctx->iv, 0, ctx->iv_size);
/* iv_size is at least of size u64; usually it is 16 bytes */
u64_iv = (void *)&ctx->iv[ctx->iv_size - sizeof(uint64_t)];
*u64_iv = cpu_to_be64(sector);
*(uint64_t *)&ctx->iv[ctx->iv_size - sizeof(uint64_t)] = cpu_to_be64(sector);
break;
case IV_ESSIV:
memset(ctx->iv, 0, ctx->iv_size);
u64_iv = (void *)ctx->iv;
*u64_iv = cpu_to_le64(sector);
*(uint64_t *)ctx->iv = cpu_to_le64(sector);
return crypt_cipher_encrypt(ctx->cipher,
ctx->iv, ctx->iv, ctx->iv_size, NULL, 0);
break;
@@ -190,8 +184,7 @@ static int crypt_sector_iv_generate(struct crypt_sector_iv *ctx, uint64_t sector
break;
case IV_EBOIV:
memset(ctx->iv, 0, ctx->iv_size);
u64_iv = (void *)ctx->iv;
*u64_iv = cpu_to_le64(sector << ctx->shift);
*(uint64_t *)ctx->iv = cpu_to_le64(sector << ctx->shift);
return crypt_cipher_encrypt(ctx->cipher,
ctx->iv, ctx->iv, ctx->iv_size, NULL, 0);
break;

View File

@@ -4,8 +4,8 @@
* Copyright (C) 2004 Free Software Foundation
*
* cryptsetup related changes
* Copyright (C) 2012-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2022 Milan Broz
* Copyright (C) 2012-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2021 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

View File

@@ -1,7 +1,7 @@
/*
* PBKDF performance check
* Copyright (C) 2012-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2022 Milan Broz
* Copyright (C) 2012-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2021 Milan Broz
* Copyright (C) 2016-2020 Ondrej Mosnacek
*
* This file is free software; you can redistribute it and/or

View File

@@ -1,289 +0,0 @@
/*
* UTF8/16 helpers, copied and adapted from systemd project.
*
* Copyright (C) 2010 Lennart Poettering
*
* cryptsetup related changes
* Copyright (C) 2021-2022 Vojtech Trefny
* Parts of the original systemd implementation are based on the GLIB utf8
* validation functions.
* gutf8.c - Operations on UTF-8 strings.
*
* Copyright (C) 1999 Tom Tromey
* Copyright (C) 2000 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <assert.h>
#include <errno.h>
#include <endian.h>
#include "crypto_backend.h"
static inline bool utf16_is_surrogate(char16_t c)
{
return c >= 0xd800U && c <= 0xdfffU;
}
static inline bool utf16_is_trailing_surrogate(char16_t c)
{
return c >= 0xdc00U && c <= 0xdfffU;
}
static inline char32_t utf16_surrogate_pair_to_unichar(char16_t lead, char16_t trail)
{
return ((((char32_t) lead - 0xd800U) << 10) + ((char32_t) trail - 0xdc00U) + 0x10000U);
}
/**
* utf8_encode_unichar() - Encode single UCS-4 character as UTF-8
* @out_utf8: output buffer of at least 4 bytes or NULL
* @g: UCS-4 character to encode
*
* This encodes a single UCS-4 character as UTF-8 and writes it into @out_utf8.
* The length of the character is returned. It is not zero-terminated! If the
* output buffer is NULL, only the length is returned.
*
* Returns: The length in bytes that the UTF-8 representation does or would
* occupy.
*/
static size_t utf8_encode_unichar(char *out_utf8, char32_t g)
{
if (g < (1 << 7)) {
if (out_utf8)
out_utf8[0] = g & 0x7f;
return 1;
} else if (g < (1 << 11)) {
if (out_utf8) {
out_utf8[0] = 0xc0 | ((g >> 6) & 0x1f);
out_utf8[1] = 0x80 | (g & 0x3f);
}
return 2;
} else if (g < (1 << 16)) {
if (out_utf8) {
out_utf8[0] = 0xe0 | ((g >> 12) & 0x0f);
out_utf8[1] = 0x80 | ((g >> 6) & 0x3f);
out_utf8[2] = 0x80 | (g & 0x3f);
}
return 3;
} else if (g < (1 << 21)) {
if (out_utf8) {
out_utf8[0] = 0xf0 | ((g >> 18) & 0x07);
out_utf8[1] = 0x80 | ((g >> 12) & 0x3f);
out_utf8[2] = 0x80 | ((g >> 6) & 0x3f);
out_utf8[3] = 0x80 | (g & 0x3f);
}
return 4;
}
return 0;
}
/**
* crypt_utf16_to_utf8()
* @out: output buffer, should be 2 * @length + 1 long
* @s: string to convert
* @length: length of @s in bytes
*
* Converts a UTF16LE encoded string to a UTF8 encoded string.
*
* Returns: 0 on success, negative errno otherwise
*/
int crypt_utf16_to_utf8(char **out, const char16_t *s, size_t length /* bytes! */)
{
const uint8_t *f;
char *t;
assert(s);
assert(out);
assert(*out);
/* Input length is in bytes, i.e. the shortest possible character takes 2 bytes. Each unicode character may
* take up to 4 bytes in UTF-8. Let's also account for a trailing NUL byte. */
if (length * 2 < length)
return -EOVERFLOW; /* overflow */
f = (const uint8_t*) s;
t = *out;
while (f + 1 < (const uint8_t*) s + length) {
char16_t w1, w2;
/* see RFC 2781 section 2.2 */
w1 = f[1] << 8 | f[0];
f += 2;
if (!utf16_is_surrogate(w1)) {
t += utf8_encode_unichar(t, w1);
continue;
}
if (utf16_is_trailing_surrogate(w1))
continue; /* spurious trailing surrogate, ignore */
if (f + 1 >= (const uint8_t*) s + length)
break;
w2 = f[1] << 8 | f[0];
f += 2;
if (!utf16_is_trailing_surrogate(w2)) {
f -= 2;
continue; /* surrogate missing its trailing surrogate, ignore */
}
t += utf8_encode_unichar(t, utf16_surrogate_pair_to_unichar(w1, w2));
}
*t = 0;
return 0;
}
/* count of characters used to encode one unicode char */
static size_t utf8_encoded_expected_len(uint8_t c)
{
if (c < 0x80)
return 1;
if ((c & 0xe0) == 0xc0)
return 2;
if ((c & 0xf0) == 0xe0)
return 3;
if ((c & 0xf8) == 0xf0)
return 4;
if ((c & 0xfc) == 0xf8)
return 5;
if ((c & 0xfe) == 0xfc)
return 6;
return 0;
}
/* decode one unicode char */
static int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar)
{
char32_t unichar;
size_t len, i;
assert(str);
len = utf8_encoded_expected_len(str[0]);
switch (len) {
case 1:
*ret_unichar = (char32_t)str[0];
return 0;
case 2:
unichar = str[0] & 0x1f;
break;
case 3:
unichar = (char32_t)str[0] & 0x0f;
break;
case 4:
unichar = (char32_t)str[0] & 0x07;
break;
case 5:
unichar = (char32_t)str[0] & 0x03;
break;
case 6:
unichar = (char32_t)str[0] & 0x01;
break;
default:
return -EINVAL;
}
for (i = 1; i < len; i++) {
if (((char32_t)str[i] & 0xc0) != 0x80)
return -EINVAL;
unichar <<= 6;
unichar |= (char32_t)str[i] & 0x3f;
}
*ret_unichar = unichar;
return 0;
}
static size_t utf16_encode_unichar(char16_t *out, char32_t c)
{
/* Note that this encodes as little-endian. */
switch (c) {
case 0 ... 0xd7ffU:
case 0xe000U ... 0xffffU:
out[0] = htole16(c);
return 1;
case 0x10000U ... 0x10ffffU:
c -= 0x10000U;
out[0] = htole16((c >> 10) + 0xd800U);
out[1] = htole16((c & 0x3ffU) + 0xdc00U);
return 2;
default: /* A surrogate (invalid) */
return 0;
}
}
/**
* crypt_utf8_to_utf16()
* @out: output buffer, should be @length + 1 long
* @s: string to convert
* @length: length of @s in bytes
*
* Converts a UTF8 encoded string to a UTF16LE encoded string.
*
* Returns: 0 on success, negative errno otherwise
*/
int crypt_utf8_to_utf16(char16_t **out, const char *s, size_t length)
{
char16_t *p;
size_t i;
int r;
assert(s);
p = *out;
for (i = 0; i < length;) {
char32_t unichar;
size_t e;
e = utf8_encoded_expected_len(s[i]);
if (e <= 1) /* Invalid and single byte characters are copied as they are */
goto copy;
if (i + e > length) /* sequence longer than input buffer, then copy as-is */
goto copy;
r = utf8_encoded_to_unichar(s + i, &unichar);
if (r < 0) /* sequence invalid, then copy as-is */
goto copy;
p += utf16_encode_unichar(p, unichar);
i += e;
continue;
copy:
*(p++) = htole16(s[i++]);
}
*p = 0;
return 0;
}

View File

@@ -1,7 +1,7 @@
/*
* Integrity volume handling
*
* Copyright (C) 2016-2022 Milan Broz
* Copyright (C) 2016-2021 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -27,17 +27,6 @@
#include "integrity.h"
#include "internal.h"
/* For LUKS2, integrity metadata are on DATA device even for detached header! */
static struct device *INTEGRITY_metadata_device(struct crypt_device *cd)
{
const char *type = crypt_get_type(cd);
if (type && !strcmp(type, CRYPT_LUKS2))
return crypt_data_device(cd);
return crypt_metadata_device(cd);
}
static int INTEGRITY_read_superblock(struct crypt_device *cd,
struct device *device,
uint64_t offset, struct superblock *sb)
@@ -49,13 +38,11 @@ static int INTEGRITY_read_superblock(struct crypt_device *cd,
return -EINVAL;
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
device_alignment(device), sb, sizeof(*sb), offset) != sizeof(*sb) ||
memcmp(sb->magic, SB_MAGIC, sizeof(sb->magic))) {
log_dbg(cd, "No kernel dm-integrity metadata detected on %s.", device_path(device));
r = -EINVAL;
} else if (sb->version < SB_VERSION_1 || sb->version > SB_VERSION_5) {
log_err(cd, _("Incompatible kernel dm-integrity metadata (version %u) detected on %s."),
sb->version, device_path(device));
device_alignment(device), sb, sizeof(*sb), offset) != sizeof(*sb) ||
memcmp(sb->magic, SB_MAGIC, sizeof(sb->magic)) ||
sb->version < SB_VERSION_1 || sb->version > SB_VERSION_5) {
log_std(cd, "No integrity superblock detected on %s.\n",
device_path(device));
r = -EINVAL;
} else {
sb->integrity_tag_size = le16toh(sb->integrity_tag_size);
@@ -76,7 +63,7 @@ int INTEGRITY_read_sb(struct crypt_device *cd,
struct superblock sb;
int r;
r = INTEGRITY_read_superblock(cd, INTEGRITY_metadata_device(cd), 0, &sb);
r = INTEGRITY_read_superblock(cd, crypt_metadata_device(cd), 0, &sb);
if (r)
return r;
@@ -133,7 +120,7 @@ int INTEGRITY_data_sectors(struct crypt_device *cd,
return 0;
}
int INTEGRITY_key_size(const char *integrity)
int INTEGRITY_key_size(struct crypt_device *cd __attribute__((unused)), const char *integrity)
{
if (!integrity)
return 0;
@@ -167,9 +154,6 @@ int INTEGRITY_hash_tag_size(const char *integrity)
if (!strcmp(integrity, "crc32") || !strcmp(integrity, "crc32c"))
return 4;
if (!strcmp(integrity, "xxhash64"))
return 8;
r = sscanf(integrity, "hmac(%" MAX_CIPHER_LEN_STR "[^)]s", hash);
if (r == 1)
r = crypt_hash_size(hash);
@@ -179,7 +163,8 @@ int INTEGRITY_hash_tag_size(const char *integrity)
return r < 0 ? 0 : r;
}
int INTEGRITY_tag_size(const char *integrity,
int INTEGRITY_tag_size(struct crypt_device *cd __attribute__((unused)),
const char *integrity,
const char *cipher,
const char *cipher_mode)
{
@@ -243,13 +228,13 @@ int INTEGRITY_create_dmd_device(struct crypt_device *cd,
if (sb_flags & SB_FLAG_RECALCULATING)
dmd->flags |= CRYPT_ACTIVATE_RECALCULATE;
r = INTEGRITY_data_sectors(cd, INTEGRITY_metadata_device(cd),
r = INTEGRITY_data_sectors(cd, crypt_metadata_device(cd),
crypt_get_data_offset(cd) * SECTOR_SIZE, &dmd->size);
if (r < 0)
return r;
return dm_integrity_target_set(cd, &dmd->segment, 0, dmd->size,
INTEGRITY_metadata_device(cd), crypt_data_device(cd),
crypt_metadata_device(cd), crypt_data_device(cd),
crypt_get_integrity_tag_size(cd), crypt_get_data_offset(cd),
crypt_get_sector_size(cd), vk, journal_crypt_key,
journal_mac_key, params);
@@ -271,8 +256,18 @@ int INTEGRITY_activate_dmd_device(struct crypt_device *cd,
log_dbg(cd, "Trying to activate INTEGRITY device on top of %s, using name %s, tag size %d, provided sectors %" PRIu64".",
device_path(tgt->data_device), name, tgt->u.integrity.tag_size, dmd->size);
r = create_or_reload_device(cd, name, type, dmd);
r = device_block_adjust(cd, tgt->data_device, DEV_EXCL,
tgt->u.integrity.offset, NULL, &dmd->flags);
if (r)
return r;
if (tgt->u.integrity.meta_device) {
r = device_block_adjust(cd, tgt->u.integrity.meta_device, DEV_EXCL, 0, NULL, NULL);
if (r)
return r;
}
r = dm_create_device(cd, name, type, dmd);
if (r < 0 && (dm_flags(cd, DM_INTEGRITY, &dmi_flags) || !(dmi_flags & DM_INTEGRITY_SUPPORTED))) {
log_err(cd, _("Kernel does not support dm-integrity mapping."));
return -ENOTSUP;
@@ -304,33 +299,14 @@ int INTEGRITY_activate(struct crypt_device *cd,
struct volume_key *journal_mac_key,
uint32_t flags, uint32_t sb_flags)
{
struct crypt_dm_active_device dmdq = {}, dmd = {};
int r;
struct crypt_dm_active_device dmd = {};
int r = INTEGRITY_create_dmd_device(cd, params, vk, journal_crypt_key,
journal_mac_key, &dmd, flags, sb_flags);
if (flags & CRYPT_ACTIVATE_REFRESH) {
r = dm_query_device(cd, name, DM_ACTIVE_CRYPT_KEYSIZE |
DM_ACTIVE_CRYPT_KEY |
DM_ACTIVE_INTEGRITY_PARAMS |
DM_ACTIVE_JOURNAL_CRYPT_KEY |
DM_ACTIVE_JOURNAL_MAC_KEY, &dmdq);
if (r < 0)
return r;
if (r < 0)
return r;
r = INTEGRITY_create_dmd_device(cd, params, vk ?: dmdq.segment.u.integrity.vk,
journal_crypt_key ?: dmdq.segment.u.integrity.journal_crypt_key,
journal_mac_key ?: dmdq.segment.u.integrity.journal_integrity_key,
&dmd, flags, sb_flags);
if (!r)
dmd.size = dmdq.size;
} else
r = INTEGRITY_create_dmd_device(cd, params, vk, journal_crypt_key,
journal_mac_key, &dmd, flags, sb_flags);
if (!r)
r = INTEGRITY_activate_dmd_device(cd, name, CRYPT_INTEGRITY, &dmd, sb_flags);
dm_targets_free(cd, &dmdq);
r = INTEGRITY_activate_dmd_device(cd, name, CRYPT_INTEGRITY, &dmd, sb_flags);
dm_targets_free(cd, &dmd);
return r;
}
@@ -362,7 +338,7 @@ int INTEGRITY_format(struct crypt_device *cd,
if (params && params->integrity_key_size)
vk = crypt_alloc_volume_key(params->integrity_key_size, NULL);
r = dm_integrity_target_set(cd, tgt, 0, dmdi.size, INTEGRITY_metadata_device(cd),
r = dm_integrity_target_set(cd, tgt, 0, dmdi.size, crypt_metadata_device(cd),
crypt_data_device(cd), crypt_get_integrity_tag_size(cd),
crypt_get_data_offset(cd), crypt_get_sector_size(cd), vk,
journal_crypt_key, journal_mac_key, params);

View File

@@ -1,7 +1,7 @@
/*
* Integrity header definition
*
* Copyright (C) 2016-2022 Milan Broz
* Copyright (C) 2016-2021 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -66,8 +66,9 @@ int INTEGRITY_dump(struct crypt_device *cd, struct device *device, uint64_t offs
int INTEGRITY_data_sectors(struct crypt_device *cd,
struct device *device, uint64_t offset,
uint64_t *data_sectors);
int INTEGRITY_key_size(const char *integrity);
int INTEGRITY_tag_size(const char *integrity,
int INTEGRITY_key_size(struct crypt_device *cd, const char *integrity);
int INTEGRITY_tag_size(struct crypt_device *cd,
const char *integrity,
const char *cipher,
const char *cipher_mode);
int INTEGRITY_hash_tag_size(const char *integrity);

View File

@@ -3,8 +3,8 @@
*
* Copyright (C) 2004 Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2022 Milan Broz
* Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2021 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

View File

@@ -3,8 +3,8 @@
*
* Copyright (C) 2004 Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2022 Milan Broz
* Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2021 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -271,9 +271,9 @@ struct crypt_pbkdf_type {
};
/** Iteration time set by crypt_set_iteration_time(), for compatibility only. */
#define CRYPT_PBKDF_ITER_TIME_SET (UINT32_C(1) << 0)
#define CRYPT_PBKDF_ITER_TIME_SET (1 << 0)
/** Never run benchmarks, use pre-set value or defaults. */
#define CRYPT_PBKDF_NO_BENCHMARK (UINT32_C(1) << 1)
#define CRYPT_PBKDF_NO_BENCHMARK (1 << 1)
/** PBKDF2 according to RFC2898, LUKS1 legacy */
#define CRYPT_KDF_PBKDF2 "pbkdf2"
@@ -513,13 +513,13 @@ struct crypt_params_verity {
};
/** No on-disk header (only hashes) */
#define CRYPT_VERITY_NO_HEADER (UINT32_C(1) << 0)
#define CRYPT_VERITY_NO_HEADER (1 << 0)
/** Verity hash in userspace before activation */
#define CRYPT_VERITY_CHECK_HASH (UINT32_C(1) << 1)
#define CRYPT_VERITY_CHECK_HASH (1 << 1)
/** Create hash - format hash device */
#define CRYPT_VERITY_CREATE_HASH (UINT32_C(1) << 2)
#define CRYPT_VERITY_CREATE_HASH (1 << 2)
/** Root hash signature required for activation */
#define CRYPT_VERITY_ROOT_HASH_SIGNATURE (UINT32_C(1) << 3)
#define CRYPT_VERITY_ROOT_HASH_SIGNATURE (1 << 3)
/**
*
@@ -542,18 +542,18 @@ struct crypt_params_tcrypt {
};
/** Include legacy modes when scanning for header */
#define CRYPT_TCRYPT_LEGACY_MODES (UINT32_C(1) << 0)
#define CRYPT_TCRYPT_LEGACY_MODES (1 << 0)
/** Try to load hidden header (describing hidden device) */
#define CRYPT_TCRYPT_HIDDEN_HEADER (UINT32_C(1) << 1)
#define CRYPT_TCRYPT_HIDDEN_HEADER (1 << 1)
/** Try to load backup header */
#define CRYPT_TCRYPT_BACKUP_HEADER (UINT32_C(1) << 2)
#define CRYPT_TCRYPT_BACKUP_HEADER (1 << 2)
/** Device contains encrypted system (with boot loader) */
#define CRYPT_TCRYPT_SYSTEM_HEADER (UINT32_C(1) << 3)
#define CRYPT_TCRYPT_SYSTEM_HEADER (1 << 3)
/** Include VeraCrypt modes when scanning for header,
* all other TCRYPT flags applies as well.
* VeraCrypt device is reported as TCRYPT type.
*/
#define CRYPT_TCRYPT_VERA_MODES (UINT32_C(1) << 4)
#define CRYPT_TCRYPT_VERA_MODES (1 << 4)
/**
*
@@ -662,11 +662,11 @@ void crypt_set_compatibility(struct crypt_device *cd, uint32_t flags);
uint32_t crypt_get_compatibility(struct crypt_device *cd);
/** dm-integrity device uses less effective (legacy) padding (old kernels) */
#define CRYPT_COMPAT_LEGACY_INTEGRITY_PADDING (UINT32_C(1) << 0)
#define CRYPT_COMPAT_LEGACY_INTEGRITY_PADDING (1 << 0)
/** dm-integrity device does not protect superblock with HMAC (old kernels) */
#define CRYPT_COMPAT_LEGACY_INTEGRITY_HMAC (UINT32_C(1) << 1)
#define CRYPT_COMPAT_LEGACY_INTEGRITY_HMAC (1 << 1)
/** dm-integrity allow recalculating of volumes with HMAC keys (old kernels) */
#define CRYPT_COMPAT_LEGACY_INTEGRITY_RECALC (UINT32_C(1) << 2)
#define CRYPT_COMPAT_LEGACY_INTEGRITY_RECALC (1 << 2)
/**
* Convert to new type for already existing device.
@@ -718,24 +718,6 @@ int crypt_set_label(struct crypt_device *cd,
const char *label,
const char *subsystem);
/**
* Get the label of an existing device.
*
* @param cd crypt device handle
*
* @return label, or @e NULL otherwise
*/
const char *crypt_get_label(struct crypt_device *cd);
/**
* Get the subsystem of an existing device.
*
* @param cd crypt device handle
*
* @return subsystem, or @e NULL otherwise
*/
const char *crypt_get_subsystem(struct crypt_device *cd);
/**
* Enable or disable loading of volume keys via kernel keyring. When set to
* 'enabled' library loads key in kernel keyring first and pass the key
@@ -767,8 +749,7 @@ int crypt_volume_key_keyring(struct crypt_device *cd, int enable);
* @post In case LUKS header is read successfully but payload device is too small
* error is returned and device type in context is set to @e NULL
*
* @note Note that load works only for device types with on-disk metadata.
* @note Function does not print visible error message if metadata is not present.
* @note Note that in current version load works only for LUKS and VERITY device type.
*
*/
int crypt_load(struct crypt_device *cd,
@@ -900,43 +881,6 @@ int crypt_resume_by_volume_key(struct crypt_device *cd,
const char *name,
const char *volume_key,
size_t volume_key_size);
/**
* Resume crypt device using LUKS2 token.
*
* @param cd LUKS2 crypt device handle
* @param name name of device to resume
* @param type restrict type of token, if @e NULL all types are allowed
* @param pin passphrase (or PIN) to unlock token (may be binary data)
* @param pin_size size of @e pin
* @param usrptr provided identification in callback
*
* @return unlocked key slot number or negative errno otherwise.
*
* @note EPERM errno means token provided passphrase successfully, but
* passphrase did not unlock any keyslot associated with the token.
*
* @note ENOENT errno means no token (or subsequently assigned keyslot) was
* eligible to resume LUKS2 device.
*
* @note ENOANO errno means that token is PIN protected and was either missing
* (NULL) or wrong.
*
* @note Negative EAGAIN errno means token handler requires additional hardware
* not present in the system to unlock keyslot.
*
* @note with @param token set to CRYPT_ANY_TOKEN libcryptsetup runs best effort loop
* to resume 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
* listed below, non negative token id (success), -ENOANO, -EAGAIN, -EPERM, -ENOENT.
*/
int crypt_resume_by_token_pin(struct crypt_device *cd,
const char *name,
const char *type,
int token,
const char *pin,
size_t pin_size,
void *usrptr);
/** @} */
/**
@@ -1061,13 +1005,13 @@ int crypt_keyslot_add_by_volume_key(struct crypt_device *cd,
size_t passphrase_size);
/** create keyslot with volume key not associated with current dm-crypt segment */
#define CRYPT_VOLUME_KEY_NO_SEGMENT (UINT32_C(1) << 0)
#define CRYPT_VOLUME_KEY_NO_SEGMENT (1 << 0)
/** create keyslot with new volume key and assign it to current dm-crypt segment */
#define CRYPT_VOLUME_KEY_SET (UINT32_C(1) << 1)
#define CRYPT_VOLUME_KEY_SET (1 << 1)
/** Assign key to first matching digest before creating new digest */
#define CRYPT_VOLUME_KEY_DIGEST_REUSE (UINT32_C(1) << 2)
#define CRYPT_VOLUME_KEY_DIGEST_REUSE (1 << 2)
/**
* Add key slot using provided key.
@@ -1129,59 +1073,59 @@ int crypt_keyslot_destroy(struct crypt_device *cd, int keyslot);
*/
/** device is read only */
#define CRYPT_ACTIVATE_READONLY (UINT32_C(1) << 0)
#define CRYPT_ACTIVATE_READONLY (1 << 0)
/** only reported for device without uuid */
#define CRYPT_ACTIVATE_NO_UUID (UINT32_C(1) << 1)
#define CRYPT_ACTIVATE_NO_UUID (1 << 1)
/** activate even if cannot grant exclusive access (DANGEROUS) */
#define CRYPT_ACTIVATE_SHARED (UINT32_C(1) << 2)
#define CRYPT_ACTIVATE_SHARED (1 << 2)
/** enable discards aka TRIM */
#define CRYPT_ACTIVATE_ALLOW_DISCARDS (UINT32_C(1) << 3)
#define CRYPT_ACTIVATE_ALLOW_DISCARDS (1 << 3)
/** skip global udev rules in activation ("private device"), input only */
#define CRYPT_ACTIVATE_PRIVATE (UINT32_C(1) << 4)
#define CRYPT_ACTIVATE_PRIVATE (1 << 4)
/** corruption detected (verity), output only */
#define CRYPT_ACTIVATE_CORRUPTED (UINT32_C(1) << 5)
#define CRYPT_ACTIVATE_CORRUPTED (1 << 5)
/** use same_cpu_crypt option for dm-crypt */
#define CRYPT_ACTIVATE_SAME_CPU_CRYPT (UINT32_C(1) << 6)
#define CRYPT_ACTIVATE_SAME_CPU_CRYPT (1 << 6)
/** use submit_from_crypt_cpus for dm-crypt */
#define CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS (UINT32_C(1) << 7)
#define CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS (1 << 7)
/** dm-verity: ignore_corruption flag - ignore corruption, log it only */
#define CRYPT_ACTIVATE_IGNORE_CORRUPTION (UINT32_C(1) << 8)
#define CRYPT_ACTIVATE_IGNORE_CORRUPTION (1 << 8)
/** dm-verity: restart_on_corruption flag - restart kernel on corruption */
#define CRYPT_ACTIVATE_RESTART_ON_CORRUPTION (UINT32_C(1) << 9)
#define CRYPT_ACTIVATE_RESTART_ON_CORRUPTION (1 << 9)
/** dm-verity: ignore_zero_blocks - do not verify zero blocks */
#define CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS (UINT32_C(1) << 10)
#define CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS (1 << 10)
/** key loaded in kernel keyring instead directly in dm-crypt */
#define CRYPT_ACTIVATE_KEYRING_KEY (UINT32_C(1) << 11)
#define CRYPT_ACTIVATE_KEYRING_KEY (1 << 11)
/** dm-integrity: direct writes, do not use journal */
#define CRYPT_ACTIVATE_NO_JOURNAL (UINT32_C(1) << 12)
#define CRYPT_ACTIVATE_NO_JOURNAL (1 << 12)
/** dm-integrity: recovery mode - no journal, no integrity checks */
#define CRYPT_ACTIVATE_RECOVERY (UINT32_C(1) << 13)
#define CRYPT_ACTIVATE_RECOVERY (1 << 13)
/** ignore persistently stored flags */
#define CRYPT_ACTIVATE_IGNORE_PERSISTENT (UINT32_C(1) << 14)
#define CRYPT_ACTIVATE_IGNORE_PERSISTENT (1 << 14)
/** dm-verity: check_at_most_once - check data blocks only the first time */
#define CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE (UINT32_C(1) << 15)
#define CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE (1 << 15)
/** allow activation check including unbound keyslots (keyslots without segments) */
#define CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY (UINT32_C(1) << 16)
#define CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY (1 << 16)
/** dm-integrity: activate automatic recalculation */
#define CRYPT_ACTIVATE_RECALCULATE (UINT32_C(1) << 17)
#define CRYPT_ACTIVATE_RECALCULATE (1 << 17)
/** reactivate existing and update flags, input only */
#define CRYPT_ACTIVATE_REFRESH (UINT32_C(1) << 18)
#define CRYPT_ACTIVATE_REFRESH (1 << 18)
/** Use global lock to serialize memory hard KDF on activation (OOM workaround) */
#define CRYPT_ACTIVATE_SERIALIZE_MEMORY_HARD_PBKDF (UINT32_C(1) << 19)
#define CRYPT_ACTIVATE_SERIALIZE_MEMORY_HARD_PBKDF (1 << 19)
/** dm-integrity: direct writes, use bitmap to track dirty sectors */
#define CRYPT_ACTIVATE_NO_JOURNAL_BITMAP (UINT32_C(1) << 20)
#define CRYPT_ACTIVATE_NO_JOURNAL_BITMAP (1 << 20)
/** device is suspended (key should be wiped from memory), output only */
#define CRYPT_ACTIVATE_SUSPENDED (UINT32_C(1) << 21)
#define CRYPT_ACTIVATE_SUSPENDED (1 << 21)
/** use IV sector counted in sector_size instead of default 512 bytes sectors */
#define CRYPT_ACTIVATE_IV_LARGE_SECTORS (UINT32_C(1) << 22)
#define CRYPT_ACTIVATE_IV_LARGE_SECTORS (1 << 22)
/** dm-verity: panic_on_corruption flag - panic kernel on corruption */
#define CRYPT_ACTIVATE_PANIC_ON_CORRUPTION (UINT32_C(1) << 23)
#define CRYPT_ACTIVATE_PANIC_ON_CORRUPTION (1 << 23)
/** dm-crypt: bypass internal workqueue and process read requests synchronously. */
#define CRYPT_ACTIVATE_NO_READ_WORKQUEUE (UINT32_C(1) << 24)
#define CRYPT_ACTIVATE_NO_READ_WORKQUEUE (1 << 24)
/** dm-crypt: bypass internal workqueue and process write requests synchronously. */
#define CRYPT_ACTIVATE_NO_WRITE_WORKQUEUE (UINT32_C(1) << 25)
#define CRYPT_ACTIVATE_NO_WRITE_WORKQUEUE (1 << 25)
/** dm-integrity: reset automatic recalculation */
#define CRYPT_ACTIVATE_RECALCULATE_RESET (UINT32_C(1) << 26)
#define CRYPT_ACTIVATE_RECALCULATE_RESET (1 << 26)
/**
* Active device runtime attributes
@@ -1230,11 +1174,11 @@ uint64_t crypt_get_active_integrity_failures(struct crypt_device *cd,
* LUKS2 header requirements
*/
/** Unfinished offline reencryption */
#define CRYPT_REQUIREMENT_OFFLINE_REENCRYPT (UINT32_C(1) << 0)
#define CRYPT_REQUIREMENT_OFFLINE_REENCRYPT (1 << 0)
/** Online reencryption in-progress */
#define CRYPT_REQUIREMENT_ONLINE_REENCRYPT (UINT32_C(1) << 1)
#define CRYPT_REQUIREMENT_ONLINE_REENCRYPT (1 << 1)
/** unknown requirement in header (output only) */
#define CRYPT_REQUIREMENT_UNKNOWN (UINT32_C(1) << 31)
#define CRYPT_REQUIREMENT_UNKNOWN (1 << 31)
/**
* Persistent flags type
@@ -1364,8 +1308,8 @@ int crypt_activate_by_keyfile(struct crypt_device *cd,
* @note For VERITY the volume key means root hash required for activation.
* Because kernel dm-verity is always read only, you have to provide
* CRYPT_ACTIVATE_READONLY flag always.
* @note For TCRYPT the volume key should be always NULL
* the key from decrypted header is used instead.
* @note For TCRYPT the volume key should be always NULL and because master
* key from decrypted header is used instead.
*/
int crypt_activate_by_volume_key(struct crypt_device *cd,
const char *name,
@@ -1421,11 +1365,11 @@ int crypt_activate_by_keyring(struct crypt_device *cd,
uint32_t flags);
/** lazy deactivation - remove once last user releases it */
#define CRYPT_DEACTIVATE_DEFERRED (UINT32_C(1) << 0)
#define CRYPT_DEACTIVATE_DEFERRED (1 << 0)
/** force deactivation - if the device is busy, it is replaced by error device */
#define CRYPT_DEACTIVATE_FORCE (UINT32_C(1) << 1)
#define CRYPT_DEACTIVATE_FORCE (1 << 1)
/** if set, remove lazy deactivation */
#define CRYPT_DEACTIVATE_DEFERRED_CANCEL (UINT32_C(1) << 2)
#define CRYPT_DEACTIVATE_DEFERRED_CANCEL (1 << 2)
/**
* Deactivate crypt device. This function tries to remove active device-mapper
@@ -1487,10 +1431,6 @@ int crypt_volume_key_get(struct crypt_device *cd,
* @param volume_key_size size of @e volume_key
*
* @return @e 0 on success or negative errno value otherwise.
*
* @note Negative EPERM return value means that passed volume_key
* did not pass digest verification routine (not a valid volume
* key).
*/
int crypt_volume_key_verify(struct crypt_device *cd,
const char *volume_key,
@@ -1983,7 +1923,7 @@ int crypt_keyfile_read(struct crypt_device *cd,
uint32_t flags);
/** Read key only to the first end of line (\\n). */
#define CRYPT_KEYFILE_STOP_EOL (UINT32_C(1) << 0)
#define CRYPT_KEYFILE_STOP_EOL (1 << 0)
/** @} */
/**
@@ -1997,7 +1937,7 @@ int crypt_keyfile_read(struct crypt_device *cd,
typedef enum {
CRYPT_WIPE_ZERO, /**< Fill with zeroes */
CRYPT_WIPE_RANDOM, /**< Use RNG to fill data */
CRYPT_WIPE_ENCRYPTED_ZERO, /**< Obsolete, same as CRYPT_WIPE_RANDOM */
CRYPT_WIPE_ENCRYPTED_ZERO, /**< Add encryption and fill with zeroes as plaintext */
CRYPT_WIPE_SPECIAL, /**< Compatibility only, do not use (Gutmann method) */
} crypt_wipe_pattern;
@@ -2033,7 +1973,7 @@ int crypt_wipe(struct crypt_device *cd,
);
/** Use direct-io */
#define CRYPT_WIPE_NO_DIRECT_IO (UINT32_C(1) << 0)
#define CRYPT_WIPE_NO_DIRECT_IO (1 << 0)
/** @} */
/**
@@ -2450,16 +2390,15 @@ int crypt_activate_by_token_pin(struct crypt_device *cd,
*/
/** Initialize reencryption metadata but do not run reencryption yet. (in) */
#define CRYPT_REENCRYPT_INITIALIZE_ONLY (UINT32_C(1) << 0)
/** Move the first segment, used only with datashift resilience mode
* and subvariants. (in/out) */
#define CRYPT_REENCRYPT_MOVE_FIRST_SEGMENT (UINT32_C(1) << 1)
#define CRYPT_REENCRYPT_INITIALIZE_ONLY (1 << 0)
/** Move the first segment, used only with data shift. (in/out) */
#define CRYPT_REENCRYPT_MOVE_FIRST_SEGMENT (1 << 1)
/** Resume already initialized reencryption only. (in) */
#define CRYPT_REENCRYPT_RESUME_ONLY (UINT32_C(1) << 2)
#define CRYPT_REENCRYPT_RESUME_ONLY (1 << 2)
/** Run reencryption recovery only. (in) */
#define CRYPT_REENCRYPT_RECOVERY (UINT32_C(1) << 3)
#define CRYPT_REENCRYPT_RECOVERY (1 << 3)
/** Reencryption requires metadata protection. (in/out) */
#define CRYPT_REENCRYPT_REPAIR_NEEDED (UINT32_C(1) << 4)
#define CRYPT_REENCRYPT_REPAIR_NEEDED (1 << 4)
/**
* Reencryption direction
@@ -2484,15 +2423,10 @@ typedef enum {
struct crypt_params_reencrypt {
crypt_reencrypt_mode_info mode; /**< Reencryption mode, immutable after first init. */
crypt_reencrypt_direction_info direction; /**< Reencryption direction, immutable after first init. */
const char *resilience; /**< Resilience mode: "none", "checksum", "journal", "datashift",
"datashift-checksum" or "datashift-journal".
"datashift" mode is immutable, "datashift-" subvariant can be only
changed to other "datashift-" subvariant */
const char *resilience; /**< Resilience mode: "none", "checksum", "journal" or "shift" (only "shift" is immutable after init) */
const char *hash; /**< Used hash for "checksum" resilience type, ignored otherwise. */
uint64_t data_shift; /**< Used in "datashift" mode (and subvariants), must be non-zero,
immutable after first init. */
uint64_t max_hotzone_size; /**< Maximum hotzone size (may be lowered by library). For "datashift-" subvariants
it is used to set size of moved segment (decryption only). */
uint64_t data_shift; /**< Used in "shift" mode, must be non-zero, immutable after first init. */
uint64_t max_hotzone_size; /**< Exact hotzone size for "none" mode. Maximum hotzone size for "checksum" and "journal" modes. */
uint64_t device_size; /**< Reencrypt only initial part of the data device. */
const struct crypt_params_luks2 *luks2; /**< LUKS2 parameters for the final reencryption volume.*/
uint32_t flags; /**< Reencryption flags. */

View File

@@ -144,10 +144,3 @@ CRYPTSETUP_2.4 {
crypt_token_external_disable;
crypt_token_external_path;
} CRYPTSETUP_2.0;
CRYPTSETUP_2.5 {
global:
crypt_get_label;
crypt_get_subsystem;
crypt_resume_by_token_pin;
} CRYPTSETUP_2.4;

View File

@@ -1,8 +1,8 @@
/*
* Definitions of common constant and generic macros of libcryptsetup
* Definitions of common constant and generic macros fo libcryptsetup
*
* Copyright (C) 2009-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2022 Milan Broz
* Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2021 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -25,9 +25,6 @@
/* to silent gcc -Wcast-qual for const cast */
#define CONST_CAST(x) (x)(uintptr_t)
/* to silent clang -Wcast-align when working with byte arrays */
#define VOIDP_CAST(x) (x)(void*)
#define UNUSED(x) (void)(x)
#ifndef ARRAY_SIZE

View File

@@ -1,7 +1,7 @@
/*
* Helpers for defining versioned symbols
*
* Copyright (C) 2021-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2021 Red Hat, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -31,7 +31,7 @@
* It's supposed to be used only with symbols that are exported in at least
* two versions simultaneously as follows:
*
* - the latest version is marked with _NEW variant and all other compatible
* - the latest version is marked with _NEW variant and oll other compatible
* symbols should be marked with _OLD variant
*
* Examples:
@@ -67,9 +67,11 @@
* under CRYPT_SYMBOL_EXPORT_OLD(int, crypt_func_X, ...) macro
*/
#if HAVE_ATTRIBUTE_SYMVER
# define _CRYPT_SYMVER(_local_sym, _public_sym, _ver_str, _maj, _min) \
__attribute__((__symver__(#_public_sym _ver_str #_maj "." #_min)))
#ifdef __has_attribute
# if __has_attribute(symver)
# define _CRYPT_SYMVER(_local_sym, _public_sym, _ver_str, _maj, _min) \
__attribute__((__symver__(#_public_sym _ver_str #_maj "." #_min)))
# endif
#endif
#if !defined(_CRYPT_SYMVER) && defined(__GNUC__)

View File

@@ -3,8 +3,8 @@
*
* Copyright (C) 2004 Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2022 Milan Broz
* Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2021 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -47,7 +47,6 @@ static bool _dm_ioctl_checked = false;
static bool _dm_crypt_checked = false;
static bool _dm_verity_checked = false;
static bool _dm_integrity_checked = false;
static bool _dm_zero_checked = false;
static int _quiet_log = 0;
static uint32_t _dm_flags = 0;
@@ -242,20 +241,6 @@ static void _dm_set_integrity_compat(struct crypt_device *cd,
_dm_integrity_checked = true;
}
static void _dm_set_zero_compat(struct crypt_device *cd,
unsigned zero_maj,
unsigned zero_min,
unsigned zero_patch)
{
if (_dm_zero_checked || zero_maj == 0)
return;
log_dbg(cd, "Detected dm-zero version %i.%i.%i.",
zero_maj, zero_min, zero_patch);
_dm_zero_checked = true;
}
/* We use this for loading target module */
static void _dm_check_target(dm_target_type target_type)
{
@@ -293,12 +278,11 @@ static int _dm_check_versions(struct crypt_device *cd, dm_target_type target_typ
unsigned dm_maj, dm_min, dm_patch;
int r = 0;
if ((target_type == DM_CRYPT && _dm_crypt_checked) ||
if ((target_type == DM_CRYPT && _dm_crypt_checked) ||
(target_type == DM_VERITY && _dm_verity_checked) ||
(target_type == DM_INTEGRITY && _dm_integrity_checked) ||
(target_type == DM_ZERO && _dm_zero_checked) ||
(target_type == DM_LINEAR) ||
(_dm_crypt_checked && _dm_verity_checked && _dm_integrity_checked && _dm_zero_checked))
(target_type == DM_LINEAR) || (target_type == DM_ZERO) ||
(_dm_crypt_checked && _dm_verity_checked && _dm_integrity_checked))
return 1;
/* Shut up DM while checking */
@@ -347,12 +331,8 @@ static int _dm_check_versions(struct crypt_device *cd, dm_target_type target_typ
_dm_set_integrity_compat(cd, (unsigned)target->version[0],
(unsigned)target->version[1],
(unsigned)target->version[2]);
} else if (!strcmp(DM_ZERO_TARGET, target->name)) {
_dm_set_zero_compat(cd, (unsigned)target->version[0],
(unsigned)target->version[1],
(unsigned)target->version[2]);
}
target = VOIDP_CAST(struct dm_versions *)((char *) target + target->next);
target = (struct dm_versions *)((char *) target + target->next);
} while (last_target != target);
r = 1;
@@ -375,14 +355,13 @@ int dm_flags(struct crypt_device *cd, dm_target_type target, uint32_t *flags)
*flags = _dm_flags;
if (target == DM_UNKNOWN &&
_dm_crypt_checked && _dm_verity_checked && _dm_integrity_checked && _dm_zero_checked)
_dm_crypt_checked && _dm_verity_checked && _dm_integrity_checked)
return 0;
if ((target == DM_CRYPT && _dm_crypt_checked) ||
if ((target == DM_CRYPT && _dm_crypt_checked) ||
(target == DM_VERITY && _dm_verity_checked) ||
(target == DM_INTEGRITY && _dm_integrity_checked) ||
(target == DM_ZERO && _dm_zero_checked) ||
(target == DM_LINEAR)) /* nothing to check */
(target == DM_LINEAR) || (target == DM_ZERO)) /* nothing to check */
return 0;
return -ENODEV;
@@ -465,6 +444,14 @@ char *dm_device_name(const char *path)
return dm_device_path(NULL, major(st.st_rdev), minor(st.st_rdev));
}
static void hex_key(char *hexkey, size_t key_size, const char *key)
{
unsigned i;
for(i = 0; i < key_size; i++)
sprintf(&hexkey[i * 2], "%02x", (unsigned char)key[i]);
}
static size_t int_log10(uint64_t x)
{
uint64_t r = 0;
@@ -668,20 +655,24 @@ static char *get_dm_crypt_params(const struct dm_target *tgt, uint32_t flags)
null_cipher = 1;
if (null_cipher)
hexkey = crypt_bytes_to_hex(0, NULL);
hexkey = crypt_safe_alloc(2);
else if (flags & CRYPT_ACTIVATE_KEYRING_KEY) {
keystr_len = strlen(tgt->u.crypt.vk->key_description) + int_log10(tgt->u.crypt.vk->keylength) + 10;
hexkey = crypt_safe_alloc(keystr_len);
if (!hexkey)
goto out;
} else
hexkey = crypt_safe_alloc(tgt->u.crypt.vk->keylength * 2 + 1);
if (!hexkey)
goto out;
if (null_cipher)
strncpy(hexkey, "-", 2);
else if (flags & CRYPT_ACTIVATE_KEYRING_KEY) {
r = snprintf(hexkey, keystr_len, ":%zu:logon:%s", tgt->u.crypt.vk->keylength, tgt->u.crypt.vk->key_description);
if (r < 0 || r >= keystr_len)
goto out;
} else
hexkey = crypt_bytes_to_hex(tgt->u.crypt.vk->keylength, tgt->u.crypt.vk->key);
if (!hexkey)
goto out;
hex_key(hexkey, tgt->u.crypt.vk->keylength, tgt->u.crypt.vk->key);
max_size = strlen(hexkey) + strlen(cipher_dm) +
strlen(device_block_path(tgt->data_device)) +
@@ -776,13 +767,18 @@ static char *get_dm_verity_params(const struct dm_target *tgt, uint32_t flags)
} else
*features = '\0';
hexroot = crypt_bytes_to_hex(tgt->u.verity.root_hash_size, tgt->u.verity.root_hash);
hexroot = crypt_safe_alloc(tgt->u.verity.root_hash_size * 2 + 1);
if (!hexroot)
goto out;
hex_key(hexroot, tgt->u.verity.root_hash_size, tgt->u.verity.root_hash);
hexsalt = crypt_bytes_to_hex(vp->salt_size, vp->salt);
hexsalt = crypt_safe_alloc(vp->salt_size ? vp->salt_size * 2 + 1 : 2);
if (!hexsalt)
goto out;
if (vp->salt_size)
hex_key(hexsalt, vp->salt_size, vp->salt);
else
strncpy(hexsalt, "-", 2);
max_size = strlen(hexroot) + strlen(hexsalt) +
strlen(device_block_path(tgt->data_device)) +
@@ -847,9 +843,10 @@ static char *get_dm_integrity_params(const struct dm_target *tgt, uint32_t flags
num_options++;
if (tgt->u.integrity.vk) {
hexkey = crypt_bytes_to_hex(tgt->u.integrity.vk->keylength, tgt->u.integrity.vk->key);
hexkey = crypt_safe_alloc(tgt->u.integrity.vk->keylength * 2 + 1);
if (!hexkey)
goto out;
hex_key(hexkey, tgt->u.integrity.vk->keylength, tgt->u.integrity.vk->key);
} else
hexkey = NULL;
@@ -864,10 +861,11 @@ static char *get_dm_integrity_params(const struct dm_target *tgt, uint32_t flags
num_options++;
if (tgt->u.integrity.journal_integrity_key) {
hexkey = crypt_bytes_to_hex( tgt->u.integrity.journal_integrity_key->keylength,
tgt->u.integrity.journal_integrity_key->key);
hexkey = crypt_safe_alloc(tgt->u.integrity.journal_integrity_key->keylength * 2 + 1);
if (!hexkey)
goto out;
hex_key(hexkey, tgt->u.integrity.journal_integrity_key->keylength,
tgt->u.integrity.journal_integrity_key->key);
} else
hexkey = NULL;
@@ -882,10 +880,11 @@ static char *get_dm_integrity_params(const struct dm_target *tgt, uint32_t flags
num_options++;
if (tgt->u.integrity.journal_crypt_key) {
hexkey = crypt_bytes_to_hex(tgt->u.integrity.journal_crypt_key->keylength,
tgt->u.integrity.journal_crypt_key->key);
hexkey = crypt_safe_alloc(tgt->u.integrity.journal_crypt_key->keylength * 2 + 1);
if (!hexkey)
goto out;
hex_key(hexkey, tgt->u.integrity.journal_crypt_key->keylength,
tgt->u.integrity.journal_crypt_key->key);
} else
hexkey = NULL;
@@ -981,7 +980,7 @@ out:
return params_out;
}
static char *get_dm_linear_params(const struct dm_target *tgt)
static char *get_dm_linear_params(const struct dm_target *tgt, uint32_t flags __attribute__((unused)))
{
char *params;
int r;
@@ -1002,7 +1001,7 @@ static char *get_dm_linear_params(const struct dm_target *tgt)
return params;
}
static char *get_dm_zero_params(void)
static char *get_dm_zero_params(const struct dm_target *tgt __attribute__((unused)), uint32_t flags __attribute__((unused)))
{
char *params = crypt_safe_alloc(1);
if (!params)
@@ -1264,7 +1263,8 @@ int lookup_dm_dev_by_uuid(struct crypt_device *cd, const char *uuid, const char
return r;
r_udev = r;
r = lookup_by_sysfs_uuid_field(dev_uuid + DM_BY_ID_PREFIX_LEN);
if (r_udev <= 0)
r = lookup_by_sysfs_uuid_field(dev_uuid + DM_BY_ID_PREFIX_LEN);
return r == -ENOENT ? r_udev : r;
}
@@ -1328,9 +1328,9 @@ static int _create_dm_targets_params(struct crypt_dm_active_device *dmd)
else if (tgt->type == DM_INTEGRITY)
tgt->params = get_dm_integrity_params(tgt, dmd->flags);
else if (tgt->type == DM_LINEAR)
tgt->params = get_dm_linear_params(tgt);
tgt->params = get_dm_linear_params(tgt, dmd->flags);
else if (tgt->type == DM_ZERO)
tgt->params = get_dm_zero_params();
tgt->params = get_dm_zero_params(tgt, dmd->flags);
else {
r = -ENOTSUP;
goto err;
@@ -1576,9 +1576,6 @@ static void _dm_target_free_query_path(struct crypt_device *cd, struct dm_target
static void _dm_target_erase(struct crypt_device *cd, struct dm_target *tgt)
{
if (tgt->direction == TARGET_EMPTY)
return;
if (tgt->direction == TARGET_QUERY)
_dm_target_free_query_path(cd, tgt);
@@ -2373,8 +2370,6 @@ static int _dm_target_query_integrity(struct crypt_device *cd,
struct device *data_device = NULL, *meta_device = NULL;
char *integrity = NULL, *journal_crypt = NULL, *journal_integrity = NULL;
struct volume_key *vk = NULL;
struct volume_key *journal_integrity_key = NULL;
struct volume_key *journal_crypt_key = NULL;
tgt->type = DM_INTEGRITY;
tgt->direction = TARGET_QUERY;
@@ -2504,28 +2499,6 @@ static int _dm_target_query_integrity(struct crypt_device *cd,
goto err;
}
}
if (str) {
len = crypt_hex_to_bytes(str, &str2, 1);
if (len < 0) {
r = len;
goto err;
}
r = 0;
if (get_flags & DM_ACTIVE_JOURNAL_CRYPT_KEY) {
journal_crypt_key = crypt_alloc_volume_key(len, str2);
if (!journal_crypt_key)
r = -ENOMEM;
} else if (get_flags & DM_ACTIVE_JOURNAL_CRYPT_KEYSIZE) {
journal_crypt_key = crypt_alloc_volume_key(len, NULL);
if (!journal_crypt_key)
r = -ENOMEM;
}
crypt_safe_free(str2);
if (r < 0)
goto err;
}
} else if (!strncmp(arg, "journal_mac:", 12) && !journal_integrity) {
str = &arg[12];
arg = strsep(&str, ":");
@@ -2536,28 +2509,6 @@ static int _dm_target_query_integrity(struct crypt_device *cd,
goto err;
}
}
if (str) {
len = crypt_hex_to_bytes(str, &str2, 1);
if (len < 0) {
r = len;
goto err;
}
r = 0;
if (get_flags & DM_ACTIVE_JOURNAL_MAC_KEY) {
journal_integrity_key = crypt_alloc_volume_key(len, str2);
if (!journal_integrity_key)
r = -ENOMEM;
} else if (get_flags & DM_ACTIVE_JOURNAL_MAC_KEYSIZE) {
journal_integrity_key = crypt_alloc_volume_key(len, NULL);
if (!journal_integrity_key)
r = -ENOMEM;
}
crypt_safe_free(str2);
if (r < 0)
goto err;
}
} else if (!strcmp(arg, "recalculate")) {
*act_flags |= CRYPT_ACTIVATE_RECALCULATE;
} else if (!strcmp(arg, "reset_recalculate")) {
@@ -2593,10 +2544,6 @@ static int _dm_target_query_integrity(struct crypt_device *cd,
tgt->u.integrity.journal_integrity = journal_integrity;
if (vk)
tgt->u.integrity.vk = vk;
if (journal_integrity_key)
tgt->u.integrity.journal_integrity_key = journal_integrity_key;
if (journal_crypt_key)
tgt->u.integrity.journal_crypt_key = journal_crypt_key;
return 0;
err:
device_free(cd, data_device);
@@ -2605,8 +2552,6 @@ err:
free(journal_crypt);
free(journal_integrity);
crypt_free_volume_key(vk);
crypt_free_volume_key(journal_integrity_key);
crypt_free_volume_key(journal_crypt_key);
return r;
}
@@ -2650,7 +2595,7 @@ err:
return r;
}
static int _dm_target_query_error(struct dm_target *tgt)
static int _dm_target_query_error(struct crypt_device *cd __attribute__((unused)), struct dm_target *tgt)
{
tgt->type = DM_ERROR;
tgt->direction = TARGET_QUERY;
@@ -2658,7 +2603,7 @@ static int _dm_target_query_error(struct dm_target *tgt)
return 0;
}
static int _dm_target_query_zero(struct dm_target *tgt)
static int _dm_target_query_zero(struct crypt_device *cd __attribute__((unused)), struct dm_target *tgt)
{
tgt->type = DM_ZERO;
tgt->direction = TARGET_QUERY;
@@ -2686,9 +2631,9 @@ static int dm_target_query(struct crypt_device *cd, struct dm_target *tgt, const
else if (!strcmp(target_type, DM_LINEAR_TARGET))
r = _dm_target_query_linear(cd, tgt, get_flags, params);
else if (!strcmp(target_type, DM_ERROR_TARGET))
r = _dm_target_query_error(tgt);
r = _dm_target_query_error(cd, tgt);
else if (!strcmp(target_type, DM_ZERO_TARGET))
r = _dm_target_query_zero(tgt);
r = _dm_target_query_zero(cd, tgt);
if (!r) {
tgt->offset = *start;
@@ -3003,7 +2948,7 @@ int dm_resume_and_reinstate_key(struct crypt_device *cd, const char *name,
{
uint32_t dmt_flags;
int msg_size;
char *msg = NULL, *key = NULL;
char *msg = NULL;
int r = -ENOTSUP;
if (dm_init_context(cd, DM_CRYPT) || dm_flags(cd, DM_CRYPT, &dmt_flags))
@@ -3025,21 +2970,14 @@ int dm_resume_and_reinstate_key(struct crypt_device *cd, const char *name,
goto out;
}
if (vk->key_description) {
r = snprintf(msg, msg_size, "key set :%zu:logon:%s", vk->keylength, vk->key_description);
} else {
key = crypt_bytes_to_hex(vk->keylength, vk->key);
if (!key) {
r = -ENOMEM;
goto out;
}
strcpy(msg, "key set ");
if (!vk->keylength)
snprintf(msg + 8, msg_size - 8, "-");
else if (vk->key_description)
snprintf(msg + 8, msg_size - 8, ":%zu:logon:%s", vk->keylength, vk->key_description);
else
hex_key(&msg[8], vk->keylength, vk->key);
r = snprintf(msg, msg_size, "key set %s", key);
}
if (r < 0 || r >= msg_size) {
r = -EINVAL;
goto out;
}
if (!_dm_message(name, msg) ||
_dm_resume_device(name, 0)) {
r = -EINVAL;
@@ -3048,7 +2986,6 @@ int dm_resume_and_reinstate_key(struct crypt_device *cd, const char *name,
r = 0;
out:
crypt_safe_free(msg);
crypt_safe_free(key);
dm_exit_context();
return r;
}

View File

@@ -1,8 +1,8 @@
/*
* loop-AES compatible volume handling
*
* Copyright (C) 2011-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2022 Milan Broz
* Copyright (C) 2011-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2021 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

View File

@@ -1,8 +1,8 @@
/*
* loop-AES compatible volume handling
*
* Copyright (C) 2011-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2022 Milan Broz
* Copyright (C) 2011-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2021 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

View File

@@ -2,7 +2,7 @@
* AFsplitter - Anti forensic information splitter
*
* Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved.
*
* AFsplitter diffuses information over a large stripe of data,
* therefore supporting secure data destruction.
@@ -131,7 +131,7 @@ out:
return r;
}
int AF_merge(const char *src, char *dst,
int AF_merge(struct crypt_device *ctx __attribute__((unused)), const char *src, char *dst,
size_t blocksize, unsigned int blocknumbers, const char *hash)
{
unsigned int i;
@@ -142,7 +142,7 @@ int AF_merge(const char *src, char *dst,
if (!bufblock)
return -ENOMEM;
for (i = 0; i < blocknumbers - 1; i++) {
for(i = 0; i < blocknumbers - 1; i++) {
XORblock(src + blocksize * i, bufblock, bufblock, blocksize);
r = diffuse(bufblock, bufblock, blocksize, hash);
if (r < 0)

View File

@@ -2,7 +2,7 @@
* AFsplitter - Anti forensic information splitter
*
* Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved.
*
* AFsplitter diffuses information over a large stripe of data,
* therefore supporting secure data destruction.
@@ -44,7 +44,7 @@ struct volume_key;
int AF_split(struct crypt_device *ctx, const char *src, char *dst,
size_t blocksize, unsigned int blocknumbers, const char *hash);
int AF_merge(const char *src, char *dst, size_t blocksize,
int AF_merge(struct crypt_device *ctx, const char *src, char *dst, size_t blocksize,
unsigned int blocknumbers, const char *hash);
size_t AF_split_sectors(size_t blocksize, unsigned int blocknumbers);

View File

@@ -2,8 +2,8 @@
* LUKS - Linux Unified Key Setup
*
* Copyright (C) 2004-2006 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2022 Milan Broz
* Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2021 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

View File

@@ -2,8 +2,8 @@
* LUKS - Linux Unified Key Setup
*
* Copyright (C) 2004-2006 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2013-2022 Milan Broz
* Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2013-2021 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -399,7 +399,7 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
/*
* cryptsetup 1.0 did not align keyslots to 4k, cannot repair this one
* Also we cannot trust possibly broken keyslots metadata here through LUKS_keyslots_offset().
* Expect first keyslot is aligned, if not, then manual repair is necessary.
* Expect first keyslot is aligned, if not, then manual repair is neccessary.
*/
if (phdr->keyblock[0].keyMaterialOffset < (LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE)) {
log_err(ctx, _("Non standard keyslots alignment, manual repair required."));
@@ -817,7 +817,7 @@ int LUKS_generate_phdr(struct luks_phdr *header,
return r;
}
/* Compute volume key digest */
/* Compute master key digest */
pbkdf = crypt_get_pbkdf(ctx);
r = crypt_benchmark_pbkdf_internal(ctx, pbkdf, vk->keylength);
if (r < 0)
@@ -926,7 +926,7 @@ int LUKS_set_key(unsigned int keyIndex,
goto out;
/*
* AF splitting, the volume key stored in vk->key is split to AfKey
* AF splitting, the masterkey stored in vk->key is split to AfKey
*/
assert(vk->keylength == hdr->keyBytes);
AFEKSize = AF_split_sectors(vk->keylength, hdr->keyblock[keyIndex].stripes) * SECTOR_SIZE;
@@ -982,7 +982,7 @@ int LUKS_verify_volume_key(const struct luks_phdr *hdr,
hdr->mkDigestIterations, 0, 0) < 0)
return -EINVAL;
if (crypt_backend_memeq(checkHashBuf, hdr->mkDigest, LUKS_DIGESTSIZE))
if (memcmp(checkHashBuf, hdr->mkDigest, LUKS_DIGESTSIZE))
return -EPERM;
return 0;
@@ -1044,7 +1044,7 @@ static int LUKS_open_key(unsigned int keyIndex,
if (r < 0)
goto out;
r = AF_merge(AfKey, (*vk)->key, (*vk)->keylength, hdr->keyblock[keyIndex].stripes, hdr->hashSpec);
r = AF_merge(ctx, AfKey, (*vk)->key, (*vk)->keylength, hdr->keyblock[keyIndex].stripes, hdr->hashSpec);
if (r < 0)
goto out;

View File

@@ -2,7 +2,7 @@
* LUKS - Linux Unified Key Setup
*
* Copyright (C) 2004-2006 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2
*
* Copyright (C) 2015-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2022 Milan Broz
* Copyright (C) 2015-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2021 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -62,16 +62,8 @@
/* 1 GiB */
#define LUKS2_REENCRYPT_MAX_HOTZONE_LENGTH 0x40000000
/* supported reencryption requirement versions */
#define LUKS2_REENCRYPT_REQ_VERSION UINT8_C(2)
#define LUKS2_DECRYPT_DATASHIFT_REQ_VERSION UINT8_C(3)
/* see reencrypt_assembly_verification_data() in luks2_reencrypt_digest.c */
/* LUKS2_REENCRYPT_MAX_VERSION UINT8_C(207) */
struct device;
struct luks2_reencrypt;
struct reenc_protection;
struct crypt_lock_handle;
struct crypt_dm_active_device;
struct luks_phdr; /* LUKS1 for conversion */
@@ -225,7 +217,9 @@ int LUKS2_keyslot_wipe(struct crypt_device *cd,
int keyslot,
int wipe_area_only);
crypt_keyslot_priority LUKS2_keyslot_priority_get(struct luks2_hdr *hdr, int keyslot);
crypt_keyslot_priority LUKS2_keyslot_priority_get(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot);
int LUKS2_keyslot_priority_set(struct crypt_device *cd,
struct luks2_hdr *hdr,
@@ -241,7 +235,8 @@ int LUKS2_keyslot_swap(struct crypt_device *cd,
/*
* Generic LUKS2 token
*/
int LUKS2_token_json_get(struct luks2_hdr *hdr,
int LUKS2_token_json_get(struct crypt_device *cd,
struct luks2_hdr *hdr,
int token,
const char **json);
@@ -252,7 +247,8 @@ int LUKS2_token_assign(struct crypt_device *cd,
int assign,
int commit);
int LUKS2_token_is_assigned(struct luks2_hdr *hdr,
int LUKS2_token_is_assigned(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
int token);
@@ -283,17 +279,8 @@ int LUKS2_token_open_and_activate(struct crypt_device *cd,
uint32_t flags,
void *usrptr);
int LUKS2_token_unlock_volume_key(struct crypt_device *cd,
int LUKS2_token_keyring_get(struct crypt_device *cd,
struct luks2_hdr *hdr,
int token,
const char *type,
const char *pin,
size_t pin_size,
uint32_t flags,
void *usrptr,
struct volume_key **vk);
int LUKS2_token_keyring_get(struct luks2_hdr *hdr,
int token,
struct crypt_token_params_luks2_keyring *keyring_params);
@@ -385,7 +372,7 @@ int LUKS2_wipe_header_areas(struct crypt_device *cd,
uint64_t LUKS2_get_data_offset(struct luks2_hdr *hdr);
int LUKS2_get_data_size(struct luks2_hdr *hdr, uint64_t *size, bool *dynamic);
uint32_t LUKS2_get_sector_size(struct luks2_hdr *hdr);
int LUKS2_get_sector_size(struct luks2_hdr *hdr);
const char *LUKS2_get_cipher(struct luks2_hdr *hdr, int segment);
const char *LUKS2_get_integrity(struct luks2_hdr *hdr, int segment);
int LUKS2_keyslot_params_default(struct crypt_device *cd, struct luks2_hdr *hdr,
@@ -413,11 +400,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_set_requirement_version(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t req_id, uint8_t req_version, bool commit);
int LUKS2_config_get_reencrypt_version(struct luks2_hdr *hdr, uint8_t *version);
bool LUKS2_reencrypt_requirement_candidate(struct luks2_hdr *hdr);
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);
@@ -426,7 +410,7 @@ int LUKS2_key_description_by_segment(struct crypt_device *cd,
int LUKS2_volume_key_load_in_keyring_by_keyslot(struct crypt_device *cd,
struct luks2_hdr *hdr, struct volume_key *vk, int keyslot);
int LUKS2_volume_key_load_in_keyring_by_digest(struct crypt_device *cd,
struct volume_key *vk, int digest);
struct luks2_hdr *hdr, struct volume_key *vk, int digest);
int LUKS2_luks1_to_luks2(struct crypt_device *cd,
struct luks_phdr *hdr1,
@@ -443,6 +427,7 @@ int LUKS2_reencrypt_locked_recovery_by_passphrase(struct crypt_device *cd,
int keyslot_new,
const char *passphrase,
size_t passphrase_size,
uint32_t flags,
struct volume_key **vks);
void LUKS2_reencrypt_free(struct crypt_device *cd,
@@ -474,12 +459,4 @@ int LUKS2_reencrypt_digest_verify(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct volume_key *vks);
int LUKS2_reencrypt_max_hotzone_size(struct crypt_device *cd,
struct luks2_hdr *hdr,
const struct reenc_protection *rp,
int reencrypt_keyslot,
uint64_t *r_length);
void LUKS2_reencrypt_protection_erase(struct reenc_protection *rp);
#endif

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, digest handling
*
* Copyright (C) 2015-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2022 Milan Broz
* Copyright (C) 2015-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2021 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -111,6 +111,7 @@ int LUKS2_digest_by_keyslot(struct luks2_hdr *hdr, int keyslot)
}
int LUKS2_digest_verify_by_digest(struct crypt_device *cd,
struct luks2_hdr *hdr __attribute__((unused)),
int digest,
const struct volume_key *vk)
{
@@ -143,7 +144,7 @@ int LUKS2_digest_verify(struct crypt_device *cd,
log_dbg(cd, "Verifying key from keyslot %d, digest %d.", keyslot, digest);
return LUKS2_digest_verify_by_digest(cd, digest, vk);
return LUKS2_digest_verify_by_digest(cd, hdr, digest, vk);
}
int LUKS2_digest_dump(struct crypt_device *cd, int digest)
@@ -163,7 +164,7 @@ int LUKS2_digest_any_matching(struct crypt_device *cd,
int digest;
for (digest = 0; digest < LUKS2_DIGEST_MAX; digest++)
if (LUKS2_digest_verify_by_digest(cd, digest, vk) == digest)
if (LUKS2_digest_verify_by_digest(cd, hdr, digest, vk) == digest)
return digest;
return -ENOENT;
@@ -174,7 +175,7 @@ int LUKS2_digest_verify_by_segment(struct crypt_device *cd,
int segment,
const struct volume_key *vk)
{
return LUKS2_digest_verify_by_digest(cd, LUKS2_digest_by_segment(hdr, segment), vk);
return LUKS2_digest_verify_by_digest(cd, hdr, LUKS2_digest_by_segment(hdr, segment), vk);
}
/* FIXME: segment can have more digests */
@@ -258,7 +259,8 @@ int LUKS2_digest_assign(struct crypt_device *cd, struct luks2_hdr *hdr,
return commit ? LUKS2_hdr_write(cd, hdr) : 0;
}
static int assign_all_segments(struct luks2_hdr *hdr, int digest, int assign)
static int assign_all_segments(struct crypt_device *cd __attribute__((unused)),
struct luks2_hdr *hdr, int digest, int assign)
{
json_object *jobj1, *jobj_digest, *jobj_digest_segments;
@@ -334,7 +336,7 @@ int LUKS2_digest_segment_assign(struct crypt_device *cd, struct luks2_hdr *hdr,
json_object_object_foreach(jobj_digests, key, val) {
UNUSED(val);
if (segment == CRYPT_ANY_SEGMENT)
r = assign_all_segments(hdr, atoi(key), assign);
r = assign_all_segments(cd, hdr, atoi(key), assign);
else
r = assign_one_segment(cd, hdr, segment, atoi(key), assign);
if (r < 0)
@@ -342,7 +344,7 @@ int LUKS2_digest_segment_assign(struct crypt_device *cd, struct luks2_hdr *hdr,
}
} else {
if (segment == CRYPT_ANY_SEGMENT)
r = assign_all_segments(hdr, digest, assign);
r = assign_all_segments(cd, hdr, digest, assign);
else
r = assign_one_segment(cd, hdr, segment, digest, assign);
}
@@ -441,7 +443,7 @@ int LUKS2_volume_key_load_in_keyring_by_keyslot(struct crypt_device *cd,
}
int LUKS2_volume_key_load_in_keyring_by_digest(struct crypt_device *cd,
struct volume_key *vk, int digest)
struct luks2_hdr *hdr __attribute__((unused)), struct volume_key *vk, int digest)
{
char *desc = get_key_description_by_digest(cd, digest);
int r;

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, PBKDF2 digest handler (LUKS1 compatible)
*
* Copyright (C) 2015-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2022 Milan Broz
* Copyright (C) 2015-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2021 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -33,10 +33,10 @@ static int PBKDF2_digest_verify(struct crypt_device *cd,
char checkHashBuf[64];
json_object *jobj_digest, *jobj1;
const char *hashSpec;
char *mkDigest = NULL, *mkDigestSalt = NULL;
char *mkDigest = NULL, mkDigestSalt[LUKS_SALTSIZE];
unsigned int mkDigestIterations;
size_t len;
int r = -EINVAL;
int r;
/* This can be done only for internally linked digests */
jobj_digest = LUKS2_get_digest_jobj(crypt_get_hdr(cd, CRYPT_LUKS2), digest);
@@ -53,23 +53,25 @@ static int PBKDF2_digest_verify(struct crypt_device *cd,
if (!json_object_object_get_ex(jobj_digest, "salt", &jobj1))
return -EINVAL;
r = crypt_base64_decode(&mkDigestSalt, &len, json_object_get_string(jobj1),
json_object_get_string_len(jobj1));
if (r < 0)
goto out;
len = sizeof(mkDigestSalt);
if (!base64_decode(json_object_get_string(jobj1),
json_object_get_string_len(jobj1), mkDigestSalt, &len))
return -EINVAL;
if (len != LUKS_SALTSIZE)
goto out;
return -EINVAL;
if (!json_object_object_get_ex(jobj_digest, "digest", &jobj1))
goto out;
r = crypt_base64_decode(&mkDigest, &len, json_object_get_string(jobj1),
json_object_get_string_len(jobj1));
if (r < 0)
goto out;
return -EINVAL;
len = 0;
if (!base64_decode_alloc(json_object_get_string(jobj1),
json_object_get_string_len(jobj1), &mkDigest, &len))
return -EINVAL;
if (len < LUKS_DIGESTSIZE ||
len > sizeof(checkHashBuf) ||
(len != LUKS_DIGESTSIZE && len != (size_t)crypt_hash_size(hashSpec)))
goto out;
(len != LUKS_DIGESTSIZE && len != (size_t)crypt_hash_size(hashSpec))) {
free(mkDigest);
return -EINVAL;
}
r = -EPERM;
if (crypt_pbkdf(CRYPT_KDF_PBKDF2, hashSpec, volume_key, volume_key_len,
@@ -78,12 +80,11 @@ static int PBKDF2_digest_verify(struct crypt_device *cd,
mkDigestIterations, 0, 0) < 0) {
r = -EINVAL;
} else {
if (crypt_backend_memeq(checkHashBuf, mkDigest, len) == 0)
if (memcmp(checkHashBuf, mkDigest, len) == 0)
r = 0;
}
out:
free(mkDigest);
free(mkDigestSalt);
return r;
}
@@ -153,18 +154,18 @@ static int PBKDF2_digest_store(struct crypt_device *cd,
json_object_object_add(jobj_digest, "hash", json_object_new_string(pbkdf.hash));
json_object_object_add(jobj_digest, "iterations", json_object_new_int(pbkdf.iterations));
r = crypt_base64_encode(&base64_str, NULL, salt, LUKS_SALTSIZE);
if (r < 0) {
base64_encode_alloc(salt, LUKS_SALTSIZE, &base64_str);
if (!base64_str) {
json_object_put(jobj_digest);
return r;
return -ENOMEM;
}
json_object_object_add(jobj_digest, "salt", json_object_new_string(base64_str));
free(base64_str);
r = crypt_base64_encode(&base64_str, NULL, digest_raw, hmac_size);
if (r < 0) {
base64_encode_alloc(digest_raw, hmac_size, &base64_str);
if (!base64_str) {
json_object_put(jobj_digest);
return r;
return -ENOMEM;
}
json_object_object_add(jobj_digest, "digest", json_object_new_string(base64_str));
free(base64_str);

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2
*
* Copyright (C) 2015-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2022 Milan Broz
* Copyright (C) 2015-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2021 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -707,7 +707,7 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
memcpy(&hdr_disk2, &hdr_disk1, LUKS2_HDR_BIN_LEN);
r = crypt_random_get(cd, (char*)hdr_disk2.salt, sizeof(hdr_disk2.salt), CRYPT_RND_SALT);
if (r)
log_dbg(cd, "Cannot generate header salt.");
log_dbg(cd, "Cannot generate master salt.");
else {
hdr_from_disk(&hdr_disk1, &hdr_disk2, hdr, 0);
r = hdr_write_disk(cd, device, hdr, json_area1, 1);
@@ -728,7 +728,7 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
memcpy(&hdr_disk1, &hdr_disk2, LUKS2_HDR_BIN_LEN);
r = crypt_random_get(cd, (char*)hdr_disk1.salt, sizeof(hdr_disk1.salt), CRYPT_RND_SALT);
if (r)
log_dbg(cd, "Cannot generate header salt.");
log_dbg(cd, "Cannot generate master salt.");
else {
hdr_from_disk(&hdr_disk2, &hdr_disk1, hdr, 1);
r = hdr_write_disk(cd, device, hdr, json_area2, 0);

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2
*
* Copyright (C) 2015-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2022 Milan Broz
* Copyright (C) 2015-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2021 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -27,6 +27,7 @@
#include <json-c/json.h>
#include "internal.h"
#include "base64.h"
#include "luks2.h"
/* override useless forward slash escape when supported by json-c */
@@ -72,11 +73,9 @@ void JSON_DBG(struct crypt_device *cd, json_object *jobj, const char *desc);
*/
/* validation helper */
bool validate_json_uint32(json_object *jobj);
json_bool validate_json_uint32(json_object *jobj);
json_object *json_contains(struct crypt_device *cd, json_object *jobj, const char *name,
const char *section, const char *key, json_type type);
json_object *json_contains_string(struct crypt_device *cd, json_object *jobj,
const char *name, const char *section, const char *key);
int LUKS2_hdr_validate(struct crypt_device *cd, json_object *hdr_jobj, uint64_t json_size);
int LUKS2_check_json_size(struct crypt_device *cd, const struct luks2_hdr *hdr);
@@ -117,13 +116,14 @@ typedef int (*keyslot_store_func)(struct crypt_device *cd, int keyslot,
typedef int (*keyslot_wipe_func) (struct crypt_device *cd, int keyslot);
typedef int (*keyslot_dump_func) (struct crypt_device *cd, int keyslot);
typedef int (*keyslot_validate_func) (struct crypt_device *cd, json_object *jobj_keyslot);
typedef void(*keyslot_repair_func) (json_object *jobj_keyslot);
typedef void(*keyslot_repair_func) (struct crypt_device *cd, json_object *jobj_keyslot);
/* see LUKS2_luks2_to_luks1 */
int placeholder_keyslot_alloc(struct crypt_device *cd,
int keyslot,
uint64_t area_offset,
uint64_t area_length);
uint64_t area_length,
size_t volume_key_len);
/* validate all keyslot implementations in hdr json */
int LUKS2_keyslots_validate(struct crypt_device *cd, json_object *hdr_jobj);
@@ -140,28 +140,11 @@ typedef struct {
keyslot_repair_func repair;
} keyslot_handler;
struct reenc_protection {
enum { REENC_PROTECTION_NOT_SET = 0,
REENC_PROTECTION_NONE,
REENC_PROTECTION_CHECKSUM,
REENC_PROTECTION_JOURNAL,
REENC_PROTECTION_DATASHIFT } type;
union {
struct {
char hash[LUKS2_CHECKSUM_ALG_L];
struct crypt_hash *ch;
size_t hash_size;
/* buffer for checksums */
void *checksums;
size_t checksums_len;
size_t block_size;
} csum;
struct {
uint64_t data_shift;
} ds;
} p;
};
/* can not fit prototype alloc function */
int reenc_keyslot_alloc(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const struct crypt_params_reencrypt *params);
/**
* LUKS2 digest handlers (EXPERIMENTAL)
@@ -254,31 +237,10 @@ int LUKS2_keyslot_reencrypt_store(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,
size_t alignment);
int LUKS2_keyslot_reencrypt_update_needed(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const struct crypt_params_reencrypt *params,
size_t alignment);
int LUKS2_keyslot_reencrypt_update(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const struct crypt_params_reencrypt *params,
size_t alignment,
struct volume_key *vks);
int LUKS2_keyslot_reencrypt_load(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
struct reenc_protection *rp,
bool primary);
const struct crypt_params_reencrypt *params);
int LUKS2_keyslot_reencrypt_digest_create(struct crypt_device *cd,
struct luks2_hdr *hdr,
uint8_t version,
struct volume_key *vks);
int LUKS2_keyslot_dump(struct crypt_device *cd,
@@ -292,7 +254,7 @@ const char *json_segment_type(json_object *jobj_segment);
uint64_t json_segment_get_iv_offset(json_object *jobj_segment);
uint64_t json_segment_get_size(json_object *jobj_segment, unsigned blockwise);
const char *json_segment_get_cipher(json_object *jobj_segment);
uint32_t json_segment_get_sector_size(json_object *jobj_segment);
int json_segment_get_sector_size(json_object *jobj_segment);
bool json_segment_is_backup(json_object *jobj_segment);
json_object *json_segments_get_segment(json_object *jobj_segments, int segment);
unsigned json_segments_count(json_object *jobj_segments);
@@ -356,6 +318,7 @@ int LUKS2_reencrypt_data_offset(struct luks2_hdr *hdr, bool blockwise);
* Generic LUKS2 digest
*/
int LUKS2_digest_verify_by_digest(struct crypt_device *cd,
struct luks2_hdr *hdr,
int digest,
const struct volume_key *vk);
@@ -381,6 +344,8 @@ int LUKS2_reload(struct crypt_device *cd,
int LUKS2_keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment);
int LUKS2_find_keyslot(struct luks2_hdr *hdr, const char *type);
int LUKS2_set_keyslots_size(struct luks2_hdr *hdr, uint64_t data_offset);
int LUKS2_set_keyslots_size(struct crypt_device *cd,
struct luks2_hdr *hdr,
uint64_t data_offset);
#endif

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, LUKS2 header format code
*
* Copyright (C) 2015-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2022 Milan Broz
* Copyright (C) 2015-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2021 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -383,7 +383,9 @@ int LUKS2_wipe_header_areas(struct crypt_device *cd,
offset, length, wipe_block, NULL, NULL);
}
int LUKS2_set_keyslots_size(struct luks2_hdr *hdr, uint64_t data_offset)
int LUKS2_set_keyslots_size(struct crypt_device *cd __attribute__((unused)),
struct luks2_hdr *hdr,
uint64_t data_offset)
{
json_object *jobj_config;
uint64_t keyslots_size;

View File

@@ -1,9 +1,9 @@
/*
* LUKS - Linux Unified Key Setup v2
*
* Copyright (C) 2015-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2022 Milan Broz
* Copyright (C) 2015-2022 Ondrej Kozina
* Copyright (C) 2015-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2021 Milan Broz
* Copyright (C) 2015-2021 Ondrej Kozina
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -40,8 +40,9 @@ void hexprint_base64(struct crypt_device *cd, json_object *jobj,
size_t buf_len;
unsigned int i;
if (crypt_base64_decode(&buf, &buf_len, json_object_get_string(jobj),
json_object_get_string_len(jobj)))
if (!base64_decode_alloc(json_object_get_string(jobj),
json_object_get_string_len(jobj),
&buf, &buf_len))
return;
for (i = 0; i < buf_len; i++) {
@@ -208,7 +209,7 @@ int LUKS2_get_default_segment(struct luks2_hdr *hdr)
if (s >= 0)
return s;
if (LUKS2_segments_count(hdr) >= 1)
if (LUKS2_segments_count(hdr) == 1)
return 0;
return -EINVAL;
@@ -224,7 +225,7 @@ uint32_t crypt_jobj_get_uint32(json_object *jobj)
}
/* jobj has to be json_type_string and numbered */
static bool json_str_to_uint64(json_object *jobj, uint64_t *value)
static json_bool json_str_to_uint64(json_object *jobj, uint64_t *value)
{
char *endptr;
unsigned long long tmp;
@@ -233,11 +234,11 @@ static bool json_str_to_uint64(json_object *jobj, uint64_t *value)
tmp = strtoull(json_object_get_string(jobj), &endptr, 10);
if (*endptr || errno) {
*value = 0;
return false;
return 0;
}
*value = tmp;
return true;
return 1;
}
uint64_t crypt_jobj_get_uint64(json_object *jobj)
@@ -265,16 +266,16 @@ json_object *crypt_jobj_new_uint64(uint64_t value)
/*
* Validate helpers
*/
static bool numbered(struct crypt_device *cd, const char *name, const char *key)
static json_bool numbered(struct crypt_device *cd, const char *name, const char *key)
{
int i;
for (i = 0; key[i]; i++)
if (!isdigit(key[i])) {
log_dbg(cd, "%s \"%s\" is not in numbered form.", name, key);
return false;
return 0;
}
return true;
return 1;
}
json_object *json_contains(struct crypt_device *cd, json_object *jobj, const char *name,
@@ -292,31 +293,18 @@ json_object *json_contains(struct crypt_device *cd, json_object *jobj, const cha
return sobj;
}
json_object *json_contains_string(struct crypt_device *cd, json_object *jobj,
const char *name, const char *section, const char *key)
{
json_object *sobj = json_contains(cd, jobj, name, section, key, json_type_string);
if (!sobj)
return NULL;
if (strlen(json_object_get_string(sobj)) < 1)
return NULL;
return sobj;
}
bool validate_json_uint32(json_object *jobj)
json_bool validate_json_uint32(json_object *jobj)
{
int64_t tmp;
errno = 0;
tmp = json_object_get_int64(jobj);
return (errno || tmp < 0 || tmp > UINT32_MAX) ? false : true;
return (errno || tmp < 0 || tmp > UINT32_MAX) ? 0 : 1;
}
static bool validate_keyslots_array(struct crypt_device *cd, json_object *jarr, json_object *jobj_keys)
static json_bool validate_keyslots_array(struct crypt_device *cd,
json_object *jarr, json_object *jobj_keys)
{
json_object *jobj;
int i = 0, length = (int) json_object_array_length(jarr);
@@ -325,20 +313,21 @@ static bool validate_keyslots_array(struct crypt_device *cd, json_object *jarr,
jobj = json_object_array_get_idx(jarr, i);
if (!json_object_is_type(jobj, json_type_string)) {
log_dbg(cd, "Illegal value type in keyslots array at index %d.", i);
return false;
return 0;
}
if (!json_contains(cd, jobj_keys, "", "Keyslots section",
json_object_get_string(jobj), json_type_object))
return false;
return 0;
i++;
}
return true;
return 1;
}
static bool validate_segments_array(struct crypt_device *cd, json_object *jarr, json_object *jobj_segments)
static json_bool validate_segments_array(struct crypt_device *cd,
json_object *jarr, json_object *jobj_segments)
{
json_object *jobj;
int i = 0, length = (int) json_object_array_length(jarr);
@@ -347,20 +336,20 @@ static bool validate_segments_array(struct crypt_device *cd, json_object *jarr,
jobj = json_object_array_get_idx(jarr, i);
if (!json_object_is_type(jobj, json_type_string)) {
log_dbg(cd, "Illegal value type in segments array at index %d.", i);
return false;
return 0;
}
if (!json_contains(cd, jobj_segments, "", "Segments section",
json_object_get_string(jobj), json_type_object))
return false;
return 0;
i++;
}
return true;
return 1;
}
static bool segment_has_digest(const char *segment_name, json_object *jobj_digests)
static json_bool segment_has_digest(const char *segment_name, json_object *jobj_digests)
{
json_object *jobj_segments;
@@ -368,70 +357,58 @@ static bool segment_has_digest(const char *segment_name, json_object *jobj_diges
UNUSED(key);
json_object_object_get_ex(val, "segments", &jobj_segments);
if (LUKS2_array_jobj(jobj_segments, segment_name))
return true;
return 1;
}
return false;
return 0;
}
static bool validate_intervals(struct crypt_device *cd,
int length, const struct interval *ix,
uint64_t metadata_size, uint64_t keyslots_area_end)
static json_bool validate_intervals(struct crypt_device *cd,
int length, const struct interval *ix,
uint64_t metadata_size, uint64_t keyslots_area_end)
{
int j, i = 0;
while (i < length) {
/* Offset cannot be inside primary or secondary JSON area */
if (ix[i].offset < 2 * metadata_size) {
log_dbg(cd, "Illegal area offset: %" PRIu64 ".", ix[i].offset);
return false;
return 0;
}
if (!ix[i].length) {
log_dbg(cd, "Area length must be greater than zero.");
return false;
}
if (ix[i].offset > (UINT64_MAX - ix[i].length)) {
log_dbg(cd, "Interval offset+length overflow.");
return false;
return 0;
}
if ((ix[i].offset + ix[i].length) > keyslots_area_end) {
log_dbg(cd, "Area [%" PRIu64 ", %" PRIu64 "] overflows binary keyslots area (ends at offset: %" PRIu64 ").",
ix[i].offset, ix[i].offset + ix[i].length, keyslots_area_end);
return false;
return 0;
}
for (j = 0; j < length; j++) {
if (i == j)
continue;
if (ix[j].offset > (UINT64_MAX - ix[j].length)) {
log_dbg(cd, "Interval offset+length overflow.");
return false;
}
if ((ix[i].offset >= ix[j].offset) && (ix[i].offset < (ix[j].offset + ix[j].length))) {
log_dbg(cd, "Overlapping areas [%" PRIu64 ",%" PRIu64 "] and [%" PRIu64 ",%" PRIu64 "].",
ix[i].offset, ix[i].offset + ix[i].length,
ix[j].offset, ix[j].offset + ix[j].length);
return false;
return 0;
}
}
i++;
}
return true;
return 1;
}
static int LUKS2_keyslot_validate(struct crypt_device *cd, json_object *hdr_keyslot, const char *key)
static int LUKS2_keyslot_validate(struct crypt_device *cd, json_object *hdr_jobj __attribute__((unused)),
json_object *hdr_keyslot, const char *key)
{
json_object *jobj_key_size;
if (!json_contains_string(cd, hdr_keyslot, key, "Keyslot", "type"))
if (!json_contains(cd, hdr_keyslot, key, "Keyslot", "type", json_type_string))
return 1;
if (!(jobj_key_size = json_contains(cd, hdr_keyslot, key, "Keyslot", "key_size", json_type_int)))
return 1;
@@ -455,7 +432,7 @@ int LUKS2_token_validate(struct crypt_device *cd,
if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
return 1;
if (!json_contains_string(cd, jobj_token, key, "Token", "type"))
if (!json_contains(cd, jobj_token, key, "Token", "type", json_type_string))
return 1;
jarr = json_contains(cd, jobj_token, key, "Token", "keyslots", json_type_array);
@@ -504,13 +481,15 @@ static int hdr_validate_keyslots(struct crypt_device *cd, json_object *hdr_jobj)
{
json_object *jobj;
if (!(jobj = json_contains(cd, hdr_jobj, "", "JSON area", "keyslots", json_type_object)))
if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj)) {
log_dbg(cd, "Missing keyslots section.");
return 1;
}
json_object_object_foreach(jobj, key, val) {
if (!numbered(cd, "Keyslot", key))
return 1;
if (LUKS2_keyslot_validate(cd, val, key))
if (LUKS2_keyslot_validate(cd, hdr_jobj, val, key))
return 1;
}
@@ -521,8 +500,10 @@ static int hdr_validate_tokens(struct crypt_device *cd, json_object *hdr_jobj)
{
json_object *jobj;
if (!(jobj = json_contains(cd, hdr_jobj, "", "JSON area", "tokens", json_type_object)))
if (!json_object_object_get_ex(hdr_jobj, "tokens", &jobj)) {
log_dbg(cd, "Missing tokens section.");
return 1;
}
json_object_object_foreach(jobj, key, val) {
if (!numbered(cd, "Token", key))
@@ -534,26 +515,25 @@ static int hdr_validate_tokens(struct crypt_device *cd, json_object *hdr_jobj)
return 0;
}
static int hdr_validate_crypt_segment(struct crypt_device *cd, json_object *jobj,
const char *key, json_object *jobj_digests,
uint64_t size)
static int hdr_validate_crypt_segment(struct crypt_device *cd,
json_object *jobj, const char *key, json_object *jobj_digests,
uint64_t offset __attribute__((unused)), uint64_t size)
{
int r;
json_object *jobj_ivoffset, *jobj_sector_size, *jobj_integrity;
uint32_t sector_size;
uint64_t ivoffset;
if (!(jobj_ivoffset = json_contains_string(cd, jobj, key, "Segment", "iv_tweak")) ||
!json_contains_string(cd, jobj, key, "Segment", "encryption") ||
if (!(jobj_ivoffset = json_contains(cd, jobj, key, "Segment", "iv_tweak", json_type_string)) ||
!json_contains(cd, jobj, key, "Segment", "encryption", json_type_string) ||
!(jobj_sector_size = json_contains(cd, jobj, key, "Segment", "sector_size", json_type_int)))
return 1;
/* integrity */
if (json_object_object_get_ex(jobj, "integrity", &jobj_integrity)) {
if (!json_contains(cd, jobj, key, "Segment", "integrity", json_type_object) ||
!json_contains_string(cd, jobj_integrity, key, "Segment integrity", "type") ||
!json_contains_string(cd, jobj_integrity, key, "Segment integrity", "journal_encryption") ||
!json_contains_string(cd, jobj_integrity, key, "Segment integrity", "journal_integrity"))
!json_contains(cd, jobj_integrity, key, "Segment integrity", "type", json_type_string) ||
!json_contains(cd, jobj_integrity, key, "Segment integrity", "journal_encryption", json_type_string) ||
!json_contains(cd, jobj_integrity, key, "Segment integrity", "journal_integrity", json_type_string))
return 1;
}
@@ -581,12 +561,7 @@ static int hdr_validate_crypt_segment(struct crypt_device *cd, json_object *jobj
return 1;
}
r = segment_has_digest(key, jobj_digests);
if (!r)
log_dbg(cd, "Crypt segment %s not assigned to key digest.", key);
return !r;
return !segment_has_digest(key, jobj_digests);
}
static bool validate_segment_intervals(struct crypt_device *cd,
@@ -603,12 +578,6 @@ static bool validate_segment_intervals(struct crypt_device *cd,
for (j = 0; j < length; j++) {
if (i == j)
continue;
if (ix[j].length != UINT64_MAX && ix[j].offset > (UINT64_MAX - ix[j].length)) {
log_dbg(cd, "Interval offset+length overflow.");
return false;
}
if ((ix[i].offset >= ix[j].offset) && (ix[j].length == UINT64_MAX || (ix[i].offset < (ix[j].offset + ix[j].length)))) {
log_dbg(cd, "Overlapping segments [%" PRIu64 ",%" PRIu64 "]%s and [%" PRIu64 ",%" PRIu64 "]%s.",
ix[i].offset, ix[i].offset + ix[i].length, ix[i].length == UINT64_MAX ? "(dynamic)" : "",
@@ -702,8 +671,10 @@ static int hdr_validate_segments(struct crypt_device *cd, json_object *hdr_jobj)
int i, r, count, first_backup = -1;
struct interval *intervals = NULL;
if (!(jobj_segments = json_contains(cd, hdr_jobj, "", "JSON area", "segments", json_type_object)))
if (!json_object_object_get_ex(hdr_jobj, "segments", &jobj_segments)) {
log_dbg(cd, "Missing segments section.");
return 1;
}
count = json_object_object_length(jobj_segments);
if (count < 1) {
@@ -720,27 +691,20 @@ static int hdr_validate_segments(struct crypt_device *cd, json_object *hdr_jobj)
return 1;
/* those fields are mandatory for all segment types */
if (!(jobj_type = json_contains_string(cd, val, key, "Segment", "type")) ||
!(jobj_offset = json_contains_string(cd, val, key, "Segment", "offset")) ||
!(jobj_size = json_contains_string(cd, val, key, "Segment", "size")))
if (!(jobj_type = json_contains(cd, val, key, "Segment", "type", json_type_string)) ||
!(jobj_offset = json_contains(cd, val, key, "Segment", "offset", json_type_string)) ||
!(jobj_size = json_contains(cd, val, key, "Segment", "size", json_type_string)))
return 1;
if (!numbered(cd, "offset", json_object_get_string(jobj_offset)))
if (!numbered(cd, "offset", json_object_get_string(jobj_offset)) ||
!json_str_to_uint64(jobj_offset, &offset))
return 1;
if (!json_str_to_uint64(jobj_offset, &offset)) {
log_dbg(cd, "Illegal segment offset value.");
return 1;
}
/* size "dynamic" means whole device starting at 'offset' */
if (strcmp(json_object_get_string(jobj_size), "dynamic")) {
if (!numbered(cd, "size", json_object_get_string(jobj_size)))
if (!numbered(cd, "size", json_object_get_string(jobj_size)) ||
!json_str_to_uint64(jobj_size, &size) || !size)
return 1;
if (!json_str_to_uint64(jobj_size, &size) || !size) {
log_dbg(cd, "Illegal segment size value.");
return 1;
}
} else
size = 0;
@@ -776,7 +740,7 @@ static int hdr_validate_segments(struct crypt_device *cd, json_object *hdr_jobj)
/* crypt */
if (!strcmp(json_object_get_string(jobj_type), "crypt") &&
hdr_validate_crypt_segment(cd, val, key, jobj_digests, size))
hdr_validate_crypt_segment(cd, val, key, jobj_digests, offset, size))
return 1;
}
@@ -883,9 +847,9 @@ static int hdr_validate_areas(struct crypt_device *cd, json_object *hdr_jobj)
json_object_object_foreach(jobj_keyslots, key, val) {
if (!(jobj_area = json_contains(cd, val, key, "Keyslot", "area", json_type_object)) ||
!json_contains_string(cd, jobj_area, key, "Keyslot area", "type") ||
!(jobj_offset = json_contains_string(cd, jobj_area, key, "Keyslot", "offset")) ||
!(jobj_length = json_contains_string(cd, jobj_area, key, "Keyslot", "size")) ||
!json_contains(cd, jobj_area, key, "Keyslot area", "type", json_type_string) ||
!(jobj_offset = json_contains(cd, jobj_area, key, "Keyslot", "offset", json_type_string)) ||
!(jobj_length = json_contains(cd, jobj_area, key, "Keyslot", "size", json_type_string)) ||
!numbered(cd, "offset", json_object_get_string(jobj_offset)) ||
!numbered(cd, "size", json_object_get_string(jobj_length))) {
free(intervals);
@@ -895,7 +859,6 @@ static int hdr_validate_areas(struct crypt_device *cd, json_object *hdr_jobj)
/* rule out values > UINT64_MAX */
if (!json_str_to_uint64(jobj_offset, &intervals[i].offset) ||
!json_str_to_uint64(jobj_length, &intervals[i].length)) {
log_dbg(cd, "Illegal keyslot area values.");
free(intervals);
return 1;
}
@@ -919,22 +882,24 @@ static int hdr_validate_digests(struct crypt_device *cd, json_object *hdr_jobj)
{
json_object *jarr_keys, *jarr_segs, *jobj, *jobj_keyslots, *jobj_segments;
if (!(jobj = json_contains(cd, hdr_jobj, "", "JSON area", "digests", json_type_object)))
if (!json_object_object_get_ex(hdr_jobj, "digests", &jobj)) {
log_dbg(cd, "Missing digests section.");
return 1;
}
/* keyslots are not yet validated, but we need to know digest doesn't reference missing keyslot */
if (!(jobj_keyslots = json_contains(cd, hdr_jobj, "", "JSON area", "keyslots", json_type_object)))
if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
return 1;
/* segments are not yet validated, but we need to know digest doesn't reference missing segment */
if (!(jobj_segments = json_contains(cd, hdr_jobj, "", "JSON area", "segments", json_type_object)))
if (!json_object_object_get_ex(hdr_jobj, "segments", &jobj_segments))
return 1;
json_object_object_foreach(jobj, key, val) {
if (!numbered(cd, "Digest", key))
return 1;
if (!json_contains_string(cd, val, key, "Digest", "type") ||
if (!json_contains(cd, val, key, "Digest", "type", json_type_string) ||
!(jarr_keys = json_contains(cd, val, key, "Digest", "keyslots", json_type_array)) ||
!(jarr_segs = json_contains(cd, val, key, "Digest", "segments", json_type_array)))
return 1;
@@ -955,26 +920,22 @@ static int hdr_validate_config(struct crypt_device *cd, json_object *hdr_jobj)
int i;
uint64_t keyslots_size, metadata_size, segment_offset;
if (!(jobj_config = json_contains(cd, hdr_jobj, "", "JSON area", "config", json_type_object)))
return 1;
if (!(jobj = json_contains_string(cd, jobj_config, "section", "Config", "json_size")))
return 1;
if (!json_str_to_uint64(jobj, &metadata_size)) {
log_dbg(cd, "Illegal config json_size value.");
if (!json_object_object_get_ex(hdr_jobj, "config", &jobj_config)) {
log_dbg(cd, "Missing config section.");
return 1;
}
if (!(jobj = json_contains(cd, jobj_config, "section", "Config", "json_size", json_type_string)) ||
!json_str_to_uint64(jobj, &metadata_size))
return 1;
/* single metadata instance is assembled from json area size plus
* binary header size */
metadata_size += LUKS2_HDR_BIN_LEN;
if (!(jobj = json_contains_string(cd, jobj_config, "section", "Config", "keyslots_size")))
if (!(jobj = json_contains(cd, jobj_config, "section", "Config", "keyslots_size", json_type_string)) ||
!json_str_to_uint64(jobj, &keyslots_size))
return 1;
if(!json_str_to_uint64(jobj, &keyslots_size)) {
log_dbg(cd, "Illegal config keyslot_size value.");
return 1;
}
if (LUKS2_check_metadata_area_size(metadata_size)) {
log_dbg(cd, "Unsupported LUKS2 header size (%" PRIu64 ").", metadata_size);
@@ -1013,39 +974,15 @@ static int hdr_validate_config(struct crypt_device *cd, json_object *hdr_jobj)
return 0;
}
static bool reencrypt_candidate_flag(const char *flag)
{
const char *ptr;
assert(flag);
if (!strcmp(flag, "online-reencrypt"))
return true;
if (strncmp(flag, "online-reencrypt-v", 18))
return false;
ptr = flag + 18;
if (!*ptr)
return false;
while (*ptr) {
if (!isdigit(*ptr))
return false;
ptr++;
}
return true;
}
static int hdr_validate_requirements(struct crypt_device *cd, json_object *hdr_jobj)
{
int i;
json_object *jobj_config, *jobj, *jobj1;
unsigned online_reencrypt_flag = 0;
if (!(jobj_config = json_contains(cd, hdr_jobj, "", "JSON area", "config", json_type_object)))
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)) {
@@ -1058,22 +995,12 @@ static int hdr_validate_requirements(struct crypt_device *cd, json_object *hdr_j
return 1;
/* All array members must be strings */
for (i = 0; i < (int) json_object_array_length(jobj1); i++) {
for (i = 0; i < (int) json_object_array_length(jobj1); i++)
if (!json_object_is_type(json_object_array_get_idx(jobj1, i), json_type_string))
return 1;
if (reencrypt_candidate_flag(json_object_get_string(json_object_array_get_idx(jobj1, i))))
online_reencrypt_flag++;
}
}
}
if (online_reencrypt_flag > 1) {
log_dbg(cd, "Multiple online reencryption requirement flags detected.");
return 1;
}
return 0;
}
@@ -1536,7 +1463,7 @@ int LUKS2_config_set_flags(struct crypt_device *cd, struct luks2_hdr *hdr, uint3
/* LUKS2 library requirements */
struct requirement_flag {
uint32_t flag;
uint8_t version;
uint32_t version;
const char *description;
};
@@ -1545,7 +1472,6 @@ static const struct requirement_flag unknown_requirement_flag = { CRYPT_REQUIREM
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, 3, "online-reencrypt-v3" },
{ CRYPT_REQUIREMENT_ONLINE_REENCRYPT, 1, "online-reencrypt" },
{ 0, 0, NULL }
};
@@ -1561,58 +1487,23 @@ static const struct requirement_flag *get_requirement_by_name(const char *requir
return &unknown_requirement_flag;
}
static json_object *mandatory_requirements_jobj(struct luks2_hdr *hdr)
int LUKS2_config_get_reencrypt_version(struct luks2_hdr *hdr, uint32_t *version)
{
json_object *jobj_config, *jobj_requirements, *jobj_mandatory;
assert(hdr);
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;
return jobj_mandatory;
}
bool LUKS2_reencrypt_requirement_candidate(struct luks2_hdr *hdr)
{
json_object *jobj_mandatory;
int i, len;
assert(hdr);
jobj_mandatory = mandatory_requirements_jobj(hdr);
if (!jobj_mandatory)
return false;
len = (int) json_object_array_length(jobj_mandatory);
if (len <= 0)
return false;
for (i = 0; i < len; i++) {
if (reencrypt_candidate_flag(json_object_get_string(json_object_array_get_idx(jobj_mandatory, i))))
return true;
}
return false;
}
int LUKS2_config_get_reencrypt_version(struct luks2_hdr *hdr, uint8_t *version)
{
json_object *jobj_mandatory, *jobj;
json_object *jobj_config, *jobj_requirements, *jobj_mandatory, *jobj;
int i, len;
const struct requirement_flag *req;
assert(hdr);
assert(version);
assert(hdr && version);
if (!hdr || !version)
return -EINVAL;
jobj_mandatory = mandatory_requirements_jobj(hdr);
if (!jobj_mandatory)
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);
@@ -1628,7 +1519,7 @@ int LUKS2_config_get_reencrypt_version(struct luks2_hdr *hdr, uint8_t *version)
/* check current library is aware of the requirement */
req = get_requirement_by_name(json_object_get_string(jobj));
if (req->flag == CRYPT_REQUIREMENT_UNKNOWN)
if (req->flag == (uint32_t)CRYPT_REQUIREMENT_UNKNOWN)
continue;
*version = req->version;
@@ -1641,19 +1532,26 @@ int LUKS2_config_get_reencrypt_version(struct luks2_hdr *hdr, uint8_t *version)
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_mandatory, *jobj;
json_object *jobj_config, *jobj_requirements, *jobj_mandatory, *jobj;
int i, len;
const struct requirement_flag *req;
assert(hdr);
if (!hdr)
return NULL;
jobj_mandatory = mandatory_requirements_jobj(hdr);
if (!jobj_mandatory)
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 NULL;
return 0;
for (i = 0; i < len; i++) {
jobj = json_object_array_get_idx(jobj_mandatory, i);
@@ -1670,17 +1568,23 @@ static const struct requirement_flag *stored_requirement_name_by_id(struct crypt
*/
int LUKS2_config_get_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t *reqs)
{
json_object *jobj_mandatory, *jobj;
json_object *jobj_config, *jobj_requirements, *jobj_mandatory, *jobj;
int i, len;
const struct requirement_flag *req;
assert(hdr);
assert(reqs);
if (!hdr || !reqs)
return -EINVAL;
*reqs = 0;
jobj_mandatory = mandatory_requirements_jobj(hdr);
if (!jobj_mandatory)
if (!json_object_object_get_ex(hdr->jobj, "config", &jobj_config))
return 0;
if (!json_object_object_get_ex(jobj_config, "requirements", &jobj_requirements))
return 0;
if (!json_object_object_get_ex(jobj_requirements, "mandatory", &jobj_mandatory))
return 0;
len = (int) json_object_array_length(jobj_mandatory);
@@ -1770,94 +1674,6 @@ err:
return r;
}
static json_object *LUKS2_get_mandatory_requirements_filtered_jobj(struct luks2_hdr *hdr,
uint32_t filter_req_ids)
{
int i, len;
const struct requirement_flag *req;
json_object *jobj_mandatory, *jobj_mandatory_filtered, *jobj;
jobj_mandatory_filtered = json_object_new_array();
if (!jobj_mandatory_filtered)
return NULL;
jobj_mandatory = mandatory_requirements_jobj(hdr);
if (!jobj_mandatory)
return jobj_mandatory_filtered;
len = (int) json_object_array_length(jobj_mandatory);
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 == CRYPT_REQUIREMENT_UNKNOWN || req->flag & filter_req_ids)
continue;
json_object_array_add(jobj_mandatory_filtered,
json_object_new_string(req->description));
}
return jobj_mandatory_filtered;
}
/*
* The function looks for specific version of requirement id.
* If it can't be fulfilled function fails.
*/
int LUKS2_config_set_requirement_version(struct crypt_device *cd,
struct luks2_hdr *hdr,
uint32_t req_id,
uint8_t req_version,
bool commit)
{
json_object *jobj_config, *jobj_requirements, *jobj_mandatory;
const struct requirement_flag *req;
int r = -EINVAL;
if (!hdr || req_id == CRYPT_REQUIREMENT_UNKNOWN)
return -EINVAL;
req = requirements_flags;
while (req->description) {
/* we have a match */
if (req->flag == req_id && req->version == req_version)
break;
req++;
}
if (!req->description)
return -EINVAL;
/*
* Creates copy of mandatory requirements set without specific requirement
* (no matter the version) we want to set.
*/
jobj_mandatory = LUKS2_get_mandatory_requirements_filtered_jobj(hdr, req_id);
if (!jobj_mandatory)
return -ENOMEM;
json_object_array_add(jobj_mandatory, json_object_new_string(req->description));
if (!json_object_object_get_ex(hdr->jobj, "config", &jobj_config))
goto err;
if (!json_object_object_get_ex(jobj_config, "requirements", &jobj_requirements)) {
jobj_requirements = json_object_new_object();
if (!jobj_requirements) {
r = -ENOMEM;
goto err;
}
json_object_object_add(jobj_config, "requirements", jobj_requirements);
}
json_object_object_add(jobj_requirements, "mandatory", jobj_mandatory);
return commit ? LUKS2_hdr_write(cd, hdr) : 0;
err:
json_object_put(jobj_mandatory);
return r;
}
/*
* Header dump
*/
@@ -1926,8 +1742,7 @@ static void hdr_dump_keyslots(struct crypt_device *cd, json_object *hdr_jobj)
json_object_object_get_ex(hdr_jobj, "keyslots", &keyslots_jobj);
for (j = 0; j < LUKS2_KEYSLOTS_MAX; j++) {
if (snprintf(slot, sizeof(slot), "%i", j) < 0)
slot[0] = '\0';
(void) snprintf(slot, sizeof(slot), "%i", j);
json_object_object_get_ex(keyslots_jobj, slot, &val);
if (!val)
continue;
@@ -1969,8 +1784,7 @@ static void hdr_dump_tokens(struct crypt_device *cd, json_object *hdr_jobj)
json_object_object_get_ex(hdr_jobj, "tokens", &tokens_jobj);
for (j = 0; j < LUKS2_TOKENS_MAX; j++) {
if (snprintf(token, sizeof(token), "%i", j) < 0)
token[0] = '\0';
(void) snprintf(token, sizeof(token), "%i", j);
json_object_object_get_ex(tokens_jobj, token, &val);
if (!val)
continue;
@@ -2000,8 +1814,7 @@ static void hdr_dump_segments(struct crypt_device *cd, json_object *hdr_jobj)
json_object_object_get_ex(hdr_jobj, "segments", &jobj_segments);
for (i = 0; i < LUKS2_SEGMENT_MAX; i++) {
if (snprintf(segment, sizeof(segment), "%i", i) < 0)
segment[0] = '\0';
(void) snprintf(segment, sizeof(segment), "%i", i);
if (!json_object_object_get_ex(jobj_segments, segment, &jobj_segment))
continue;
@@ -2056,8 +1869,7 @@ static void hdr_dump_digests(struct crypt_device *cd, json_object *hdr_jobj)
json_object_object_get_ex(hdr_jobj, "digests", &jobj1);
for (i = 0; i < LUKS2_DIGEST_MAX; i++) {
if (snprintf(key, sizeof(key), "%i", i) < 0)
key[0] = '\0';
(void) snprintf(key, sizeof(key), "%i", i);
json_object_object_get_ex(jobj1, key, &val);
if (!val)
continue;
@@ -2115,25 +1927,21 @@ int LUKS2_hdr_dump_json(struct crypt_device *cd, struct luks2_hdr *hdr, const ch
int LUKS2_get_data_size(struct luks2_hdr *hdr, uint64_t *size, bool *dynamic)
{
int i, len, sector_size;
json_object *jobj_segments, *jobj_segment, *jobj_size;
int sector_size;
json_object *jobj_segments, *jobj_size;
uint64_t tmp = 0;
if (!size || !json_object_object_get_ex(hdr->jobj, "segments", &jobj_segments))
return -EINVAL;
len = json_object_object_length(jobj_segments);
json_object_object_foreach(jobj_segments, key, val) {
UNUSED(key);
if (json_segment_is_backup(val))
continue;
for (i = 0; i < len; i++) {
if (!(jobj_segment = json_segments_get_segment(jobj_segments, i)))
return -EINVAL;
if (json_segment_is_backup(jobj_segment))
break;
json_object_object_get_ex(jobj_segment, "size", &jobj_size);
json_object_object_get_ex(val, "size", &jobj_size);
if (!strcmp(json_object_get_string(jobj_size), "dynamic")) {
sector_size = json_segment_get_sector_size(jobj_segment);
sector_size = json_segment_get_sector_size(val);
/* last dynamic segment must have at least one sector in size */
if (tmp)
*size = tmp + (sector_size > 0 ? sector_size : SECTOR_SIZE);
@@ -2340,9 +2148,15 @@ int LUKS2_get_volume_key_size(struct luks2_hdr *hdr, int segment)
return -1;
}
uint32_t LUKS2_get_sector_size(struct luks2_hdr *hdr)
int LUKS2_get_sector_size(struct luks2_hdr *hdr)
{
return json_segment_get_sector_size(LUKS2_get_segment_jobj(hdr, CRYPT_DEFAULT_SEGMENT));
json_object *jobj_segment;
jobj_segment = LUKS2_get_segment_jobj(hdr, CRYPT_DEFAULT_SEGMENT);
if (!jobj_segment)
return SECTOR_SIZE;
return json_segment_get_sector_size(jobj_segment) ?: SECTOR_SIZE;
}
int LUKS2_assembly_multisegment_dmd(struct crypt_device *cd,
@@ -2619,7 +2433,7 @@ int LUKS2_deactivate(struct crypt_device *cd, const char *name, struct luks2_hdr
tgt = &dmd->segment;
/* TODO: We have LUKS2 dependencies now */
if (single_segment(dmd) && tgt->type == DM_CRYPT && tgt->u.crypt.tag_size)
if (hdr && single_segment(dmd) && tgt->type == DM_CRYPT && crypt_get_integrity_tag_size(cd))
namei = device_dm_name(tgt->data_device);
r = dm_device_deps(cd, name, deps_uuid_prefix, deps, ARRAY_SIZE(deps));

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, keyslot handling
*
* Copyright (C) 2015-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2022 Milan Broz
* Copyright (C) 2015-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2021 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -34,7 +34,7 @@ static const keyslot_handler *keyslot_handlers[LUKS2_KEYSLOTS_MAX] = {
};
static const keyslot_handler
*LUKS2_keyslot_handler_type(const char *type)
*LUKS2_keyslot_handler_type(struct crypt_device *cd __attribute__((unused)), const char *type)
{
int i;
@@ -64,7 +64,7 @@ static const keyslot_handler
if (!json_object_object_get_ex(jobj1, "type", &jobj2))
return NULL;
return LUKS2_keyslot_handler_type(json_object_get_string(jobj2));
return LUKS2_keyslot_handler_type(cd, json_object_get_string(jobj2));
}
int LUKS2_keyslot_find_empty(struct crypt_device *cd, struct luks2_hdr *hdr, size_t keylength)
@@ -605,6 +605,38 @@ int LUKS2_keyslot_open(struct crypt_device *cd,
return r;
}
int LUKS2_keyslot_reencrypt_allocate(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const struct crypt_params_reencrypt *params)
{
const keyslot_handler *h;
int r;
if (keyslot == CRYPT_ANY_SLOT)
return -EINVAL;
h = LUKS2_keyslot_handler_type(cd, "reencrypt");
if (!h)
return -EINVAL;
r = reenc_keyslot_alloc(cd, hdr, keyslot, params);
if (r < 0)
return r;
r = LUKS2_keyslot_priority_set(cd, hdr, keyslot, CRYPT_SLOT_PRIORITY_IGNORE, 0);
if (r < 0)
return r;
r = h->validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot));
if (r) {
log_dbg(cd, "Keyslot validation failed.");
return r;
}
return 0;
}
int LUKS2_keyslot_reencrypt_store(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
@@ -643,7 +675,7 @@ int LUKS2_keyslot_store(struct crypt_device *cd,
if (!LUKS2_get_keyslot_jobj(hdr, keyslot)) {
/* Try to allocate default and empty keyslot type */
h = LUKS2_keyslot_handler_type("luks2");
h = LUKS2_keyslot_handler_type(cd, "luks2");
if (!h)
return -EINVAL;
@@ -749,7 +781,8 @@ int LUKS2_keyslot_dump(struct crypt_device *cd, int keyslot)
return h->dump(cd, keyslot);
}
crypt_keyslot_priority LUKS2_keyslot_priority_get(struct luks2_hdr *hdr, int keyslot)
crypt_keyslot_priority LUKS2_keyslot_priority_get(struct crypt_device *cd __attribute__((unused)),
struct luks2_hdr *hdr, int keyslot)
{
json_object *jobj_keyslot, *jobj_priority;
@@ -783,7 +816,8 @@ int LUKS2_keyslot_priority_set(struct crypt_device *cd, struct luks2_hdr *hdr,
int placeholder_keyslot_alloc(struct crypt_device *cd,
int keyslot,
uint64_t area_offset,
uint64_t area_length)
uint64_t area_length,
size_t volume_key_len __attribute__((unused)))
{
struct luks2_hdr *hdr;
json_object *jobj_keyslots, *jobj_keyslot, *jobj_area;
@@ -864,7 +898,7 @@ int LUKS2_keyslots_validate(struct crypt_device *cd, json_object *hdr_jobj)
json_object_object_foreach(jobj_keyslots, slot, val) {
keyslot = atoi(slot);
json_object_object_get_ex(val, "type", &jobj_type);
h = LUKS2_keyslot_handler_type(json_object_get_string(jobj_type));
h = LUKS2_keyslot_handler_type(cd, json_object_get_string(jobj_type));
if (!h)
continue;
if (h->validate && h->validate(cd, val)) {
@@ -886,7 +920,7 @@ int LUKS2_keyslots_validate(struct crypt_device *cd, json_object *hdr_jobj)
return -EINVAL;
}
if (reencrypt_count && !LUKS2_reencrypt_requirement_candidate(&dummy)) {
if (!(reqs & CRYPT_REQUIREMENT_ONLINE_REENCRYPT) && reencrypt_count) {
log_dbg(cd, "Missing reencryption requirement flag.");
return -EINVAL;
}
@@ -911,9 +945,9 @@ void LUKS2_keyslots_repair(struct crypt_device *cd, json_object *jobj_keyslots)
!json_object_is_type(jobj_type, json_type_string))
continue;
h = LUKS2_keyslot_handler_type(json_object_get_string(jobj_type));
h = LUKS2_keyslot_handler_type(cd, json_object_get_string(jobj_type));
if (h && h->repair)
h->repair(val);
h->repair(cd, val);
}
}

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, LUKS2 type keyslot handler
*
* Copyright (C) 2015-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2022 Milan Broz
* Copyright (C) 2015-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2021 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -142,11 +142,10 @@ static int luks2_decrypt_from_storage(char *dst, size_t dstLength,
}
static int luks2_keyslot_get_pbkdf_params(json_object *jobj_keyslot,
struct crypt_pbkdf_type *pbkdf, char **salt)
struct crypt_pbkdf_type *pbkdf, char *salt)
{
json_object *jobj_kdf, *jobj1, *jobj2;
size_t salt_len;
int r;
if (!jobj_keyslot || !pbkdf)
return -EINVAL;
@@ -182,16 +181,13 @@ static int luks2_keyslot_get_pbkdf_params(json_object *jobj_keyslot,
if (!json_object_object_get_ex(jobj_kdf, "salt", &jobj2))
return -EINVAL;
r = crypt_base64_decode(salt, &salt_len, json_object_get_string(jobj2),
json_object_get_string_len(jobj2));
if (r < 0)
return r;
if (salt_len != LUKS_SALTSIZE) {
free(*salt);
salt_len = LUKS_SALTSIZE;
if (!base64_decode(json_object_get_string(jobj2),
json_object_get_string_len(jobj2),
salt, &salt_len))
return -EINVAL;
if (salt_len != LUKS_SALTSIZE)
return -EINVAL;
}
return 0;
}
@@ -202,7 +198,7 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
const char *volume_key, size_t volume_key_len)
{
struct volume_key *derived_key;
char *salt = NULL, cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
char salt[LUKS_SALTSIZE], cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
char *AfKey = NULL;
const char *af_hash = NULL;
size_t AFEKSize, keyslot_key_len;
@@ -240,18 +236,15 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
return -EINVAL;
af_hash = json_object_get_string(jobj2);
r = luks2_keyslot_get_pbkdf_params(jobj_keyslot, &pbkdf, &salt);
if (r < 0)
return r;
if (luks2_keyslot_get_pbkdf_params(jobj_keyslot, &pbkdf, salt))
return -EINVAL;
/*
* Allocate derived key storage.
*/
derived_key = crypt_alloc_volume_key(keyslot_key_len, NULL);
if (!derived_key) {
free(salt);
if (!derived_key)
return -ENOMEM;
}
/*
* Calculate keyslot content, split and store it to keyslot area.
*/
@@ -261,7 +254,6 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
derived_key->key, derived_key->keylength,
pbkdf.iterations, pbkdf.max_memory_kb,
pbkdf.parallel_threads);
free(salt);
if (r < 0) {
crypt_free_volume_key(derived_key);
return r;
@@ -297,12 +289,12 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
const char *password, size_t passwordLen,
char *volume_key, size_t volume_key_len)
{
struct volume_key *derived_key = NULL;
struct volume_key *derived_key;
struct crypt_pbkdf_type pbkdf;
char *AfKey = NULL;
char *AfKey;
size_t AFEKSize;
const char *af_hash = NULL;
char *salt = NULL, cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
char salt[LUKS_SALTSIZE], cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
json_object *jobj2, *jobj_af, *jobj_area;
uint64_t area_offset;
size_t keyslot_key_len;
@@ -313,6 +305,9 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
return -EINVAL;
if (luks2_keyslot_get_pbkdf_params(jobj_keyslot, &pbkdf, salt))
return -EINVAL;
if (!json_object_object_get_ex(jobj_af, "hash", &jobj2))
return -EINVAL;
af_hash = json_object_get_string(jobj2);
@@ -331,18 +326,12 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
return -EINVAL;
keyslot_key_len = json_object_get_int(jobj2);
r = luks2_keyslot_get_pbkdf_params(jobj_keyslot, &pbkdf, &salt);
if (r < 0)
return r;
/*
* Allocate derived key storage space.
*/
derived_key = crypt_alloc_volume_key(keyslot_key_len, NULL);
if (!derived_key) {
r = -ENOMEM;
goto out;
}
if (!derived_key)
return -ENOMEM;
AFEKSize = AF_split_sectors(volume_key_len, LUKS_STRIPES) * SECTOR_SIZE;
AfKey = crypt_safe_alloc(AFEKSize);
@@ -380,9 +369,9 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
}
if (r == 0)
r = AF_merge(AfKey, volume_key, volume_key_len, LUKS_STRIPES, af_hash);
r = AF_merge(cd, AfKey, volume_key, volume_key_len, LUKS_STRIPES, af_hash);
out:
free(salt);
crypt_free_volume_key(derived_key);
crypt_safe_free(AfKey);
@@ -443,9 +432,9 @@ static int luks2_keyslot_update_json(struct crypt_device *cd,
r = crypt_random_get(cd, salt, LUKS_SALTSIZE, CRYPT_RND_SALT);
if (r < 0)
return r;
r = crypt_base64_encode(&salt_base64, NULL, salt, LUKS_SALTSIZE);
if (r < 0)
return r;
base64_encode_alloc(salt, LUKS_SALTSIZE, &salt_base64);
if (!salt_base64)
return -ENOMEM;
json_object_object_add(jobj_kdf, "salt", json_object_new_string(salt_base64));
free(salt_base64);
@@ -673,56 +662,50 @@ static int luks2_keyslot_validate(struct crypt_device *cd, json_object *jobj_key
if (!jobj_keyslot)
return -EINVAL;
if (!(jobj_kdf = json_contains(cd, jobj_keyslot, "", "keyslot", "kdf", json_type_object)) ||
!(jobj_af = json_contains(cd, jobj_keyslot, "", "keyslot", "af", json_type_object)) ||
!(jobj_area = json_contains(cd, jobj_keyslot, "", "keyslot", "area", json_type_object)))
if (!json_object_object_get_ex(jobj_keyslot, "kdf", &jobj_kdf) ||
!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af) ||
!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
return -EINVAL;
count = json_object_object_length(jobj_kdf);
jobj1 = json_contains_string(cd, jobj_kdf, "", "kdf section", "type");
jobj1 = json_contains(cd, jobj_kdf, "", "kdf section", "type", json_type_string);
if (!jobj1)
return -EINVAL;
type = json_object_get_string(jobj1);
if (!strcmp(type, CRYPT_KDF_PBKDF2)) {
if (count != 4 || /* type, salt, hash, iterations only */
!json_contains_string(cd, jobj_kdf, "kdf type", type, "hash") ||
!json_contains(cd, jobj_kdf, "kdf type", type, "hash", json_type_string) ||
!json_contains(cd, jobj_kdf, "kdf type", type, "iterations", json_type_int) ||
!json_contains_string(cd, jobj_kdf, "kdf type", type, "salt"))
!json_contains(cd, jobj_kdf, "kdf type", type, "salt", json_type_string))
return -EINVAL;
} else if (!strcmp(type, CRYPT_KDF_ARGON2I) || !strcmp(type, CRYPT_KDF_ARGON2ID)) {
if (count != 5 || /* type, salt, time, memory, cpus only */
!json_contains(cd, jobj_kdf, "kdf type", type, "time", json_type_int) ||
!json_contains(cd, jobj_kdf, "kdf type", type, "memory", json_type_int) ||
!json_contains(cd, jobj_kdf, "kdf type", type, "cpus", json_type_int) ||
!json_contains_string(cd, jobj_kdf, "kdf type", type, "salt"))
!json_contains(cd, jobj_kdf, "kdf type", type, "salt", json_type_string))
return -EINVAL;
}
jobj1 = json_contains_string(cd, jobj_af, "", "af section", "type");
if (!jobj1)
if (!json_object_object_get_ex(jobj_af, "type", &jobj1))
return -EINVAL;
type = json_object_get_string(jobj1);
if (!strcmp(type, "luks1")) {
if (!json_contains_string(cd, jobj_af, "", "luks1 af", "hash") ||
if (!strcmp(json_object_get_string(jobj1), "luks1")) {
if (!json_contains(cd, jobj_af, "", "luks1 af", "hash", json_type_string) ||
!json_contains(cd, jobj_af, "", "luks1 af", "stripes", json_type_int))
return -EINVAL;
} else
return -EINVAL;
// FIXME check numbered
jobj1 = json_contains_string(cd, jobj_area, "", "area section", "type");
if (!jobj1)
if (!json_object_object_get_ex(jobj_area, "type", &jobj1))
return -EINVAL;
type = json_object_get_string(jobj1);
if (!strcmp(type, "raw")) {
if (!json_contains_string(cd, jobj_area, "area", "raw type", "encryption") ||
if (!strcmp(json_object_get_string(jobj1), "raw")) {
if (!json_contains(cd, jobj_area, "area", "raw type", "encryption", json_type_string) ||
!json_contains(cd, jobj_area, "area", "raw type", "key_size", json_type_int) ||
!json_contains_string(cd, jobj_area, "area", "raw type", "offset") ||
!json_contains_string(cd, jobj_area, "area", "raw type", "size"))
!json_contains(cd, jobj_area, "area", "raw type", "offset", json_type_string) ||
!json_contains(cd, jobj_area, "area", "raw type", "size", json_type_string))
return -EINVAL;
} else
return -EINVAL;
@@ -757,7 +740,7 @@ static int luks2_keyslot_update(struct crypt_device *cd,
return r;
}
static void luks2_keyslot_repair(json_object *jobj_keyslot)
static void luks2_keyslot_repair(struct crypt_device *cd __attribute__((unused)), json_object *jobj_keyslot)
{
const char *type;
json_object *jobj_kdf, *jobj_type;

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, reencryption keyslot handler
*
* Copyright (C) 2016-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2022 Ondrej Kozina
* Copyright (C) 2016-2021, Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2021, Ondrej Kozina
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -31,77 +31,10 @@ static int reenc_keyslot_open(struct crypt_device *cd __attribute__((unused)),
return -ENOENT;
}
static json_object *reencrypt_keyslot_area_jobj(struct crypt_device *cd,
const struct crypt_params_reencrypt *params,
size_t alignment,
uint64_t area_offset,
uint64_t area_length)
{
json_object *jobj_area = json_object_new_object();
if (!jobj_area || !params || !params->resilience)
return NULL;
json_object_object_add(jobj_area, "offset", crypt_jobj_new_uint64(area_offset));
json_object_object_add(jobj_area, "size", crypt_jobj_new_uint64(area_length));
json_object_object_add(jobj_area, "type", json_object_new_string(params->resilience));
if (!strcmp(params->resilience, "checksum")) {
log_dbg(cd, "Setting reencrypt keyslot for checksum protection.");
json_object_object_add(jobj_area, "hash", json_object_new_string(params->hash));
json_object_object_add(jobj_area, "sector_size", json_object_new_int64(alignment));
} else if (!strcmp(params->resilience, "journal")) {
log_dbg(cd, "Setting reencrypt keyslot for journal protection.");
} else if (!strcmp(params->resilience, "none")) {
log_dbg(cd, "Setting reencrypt keyslot for none protection.");
} else if (!strcmp(params->resilience, "datashift")) {
log_dbg(cd, "Setting reencrypt keyslot for datashift protection.");
json_object_object_add(jobj_area, "shift_size",
crypt_jobj_new_uint64(params->data_shift << SECTOR_SHIFT));
} else if (!strcmp(params->resilience, "datashift-checksum")) {
log_dbg(cd, "Setting reencrypt keyslot for datashift and checksum protection.");
json_object_object_add(jobj_area, "hash", json_object_new_string(params->hash));
json_object_object_add(jobj_area, "sector_size", json_object_new_int64(alignment));
json_object_object_add(jobj_area, "shift_size",
crypt_jobj_new_uint64(params->data_shift << SECTOR_SHIFT));
} else if (!strcmp(params->resilience, "datashift-journal")) {
log_dbg(cd, "Setting reencrypt keyslot for datashift and journal protection.");
json_object_object_add(jobj_area, "shift_size",
crypt_jobj_new_uint64(params->data_shift << SECTOR_SHIFT));
} else {
json_object_put(jobj_area);
return NULL;
}
return jobj_area;
}
static json_object *reencrypt_keyslot_area_jobj_update_block_size(struct crypt_device *cd,
json_object *jobj_area, size_t alignment)
{
json_object *jobj_type, *jobj_area_new = NULL;
if (!jobj_area ||
!json_object_object_get_ex(jobj_area, "type", &jobj_type) ||
(strcmp(json_object_get_string(jobj_type), "checksum") &&
strcmp(json_object_get_string(jobj_type), "datashift-checksum")))
return NULL;
if (json_object_copy(jobj_area, &jobj_area_new))
return NULL;
log_dbg(cd, "Updating reencrypt resilience checksum block size.");
json_object_object_add(jobj_area_new, "sector_size", json_object_new_int64(alignment));
return jobj_area_new;
}
static int reenc_keyslot_alloc(struct crypt_device *cd,
int reenc_keyslot_alloc(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const struct crypt_params_reencrypt *params,
size_t alignment)
const struct crypt_params_reencrypt *params)
{
int r;
json_object *jobj_keyslots, *jobj_keyslot, *jobj_area;
@@ -109,41 +42,50 @@ static int reenc_keyslot_alloc(struct crypt_device *cd,
log_dbg(cd, "Allocating reencrypt keyslot %d.", keyslot);
if (!params || !params->resilience || params->direction > CRYPT_REENCRYPT_BACKWARD)
return -EINVAL;
if (keyslot < 0 || keyslot >= LUKS2_KEYSLOTS_MAX)
return -ENOMEM;
if (!json_object_object_get_ex(hdr->jobj, "keyslots", &jobj_keyslots))
return -EINVAL;
/* only plain datashift resilience mode does not require additional storage */
if (!strcmp(params->resilience, "datashift"))
r = LUKS2_find_area_gap(cd, hdr, 1, &area_offset, &area_length);
else
/* encryption doesn't require area (we shift data and backup will be available) */
if (!params->data_shift) {
r = LUKS2_find_area_max_gap(cd, hdr, &area_offset, &area_length);
if (r < 0)
return r;
jobj_area = reencrypt_keyslot_area_jobj(cd, params, alignment, area_offset, area_length);
if (!jobj_area)
return -EINVAL;
if (r < 0)
return r;
} else { /* we can't have keyslot w/o area...bug? */
r = LUKS2_find_area_gap(cd, hdr, 1, &area_offset, &area_length);
if (r < 0)
return r;
}
jobj_keyslot = json_object_new_object();
if (!jobj_keyslot) {
json_object_put(jobj_area);
if (!jobj_keyslot)
return -ENOMEM;
}
json_object_object_add(jobj_keyslot, "area", jobj_area);
jobj_area = json_object_new_object();
if (params->data_shift) {
json_object_object_add(jobj_area, "type", json_object_new_string("datashift"));
json_object_object_add(jobj_area, "shift_size", crypt_jobj_new_uint64(params->data_shift << SECTOR_SHIFT));
} else
/* except data shift protection, initial setting is irrelevant. Type can be changed during reencryption */
json_object_object_add(jobj_area, "type", json_object_new_string("none"));
json_object_object_add(jobj_area, "offset", crypt_jobj_new_uint64(area_offset));
json_object_object_add(jobj_area, "size", crypt_jobj_new_uint64(area_length));
json_object_object_add(jobj_keyslot, "type", json_object_new_string("reencrypt"));
json_object_object_add(jobj_keyslot, "key_size", json_object_new_int(1)); /* useless but mandatory */
json_object_object_add(jobj_keyslot, "mode", json_object_new_string(crypt_reencrypt_mode_to_str(params->mode)));
if (params->direction == CRYPT_REENCRYPT_FORWARD)
json_object_object_add(jobj_keyslot, "direction", json_object_new_string("forward"));
else
else if (params->direction == CRYPT_REENCRYPT_BACKWARD)
json_object_object_add(jobj_keyslot, "direction", json_object_new_string("backward"));
else
return -EINVAL;
json_object_object_add(jobj_keyslot, "area", jobj_area);
json_object_object_add_by_uint(jobj_keyslots, keyslot, jobj_keyslot);
if (LUKS2_check_json_size(cd, hdr)) {
@@ -288,8 +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, *jobj_key_size;
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;
@@ -297,10 +238,10 @@ static int reenc_keyslot_validate(struct crypt_device *cd, json_object *jobj_key
/* mode (string: encrypt,reencrypt,decrypt)
* direction (string:)
* area {
* type: (string: datashift, journal, checksum, none, datashift-journal, datashift-checksum)
* hash: (string: checksum and datashift-checksum types)
* sector_size (uint32: checksum and datashift-checksum types)
* shift_size (uint64: all datashift based types)
* type: (string: datashift, journal, checksum, none)
* hash: (string: checksum only)
* sector_size (uint32: checksum only)
* shift_size (uint64: datashift only)
* }
*/
@@ -310,8 +251,8 @@ static int reenc_keyslot_validate(struct crypt_device *cd, json_object *jobj_key
return -EINVAL;
jobj_key_size = json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "key_size", json_type_int);
jobj_mode = json_contains_string(cd, jobj_keyslot, "", "reencrypt keyslot", "mode");
jobj_direction = json_contains_string(cd, jobj_keyslot, "", "reencrypt keyslot", "direction");
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 || !jobj_key_size)
return -EINVAL;
@@ -336,26 +277,20 @@ static int reenc_keyslot_validate(struct crypt_device *cd, json_object *jobj_key
return -EINVAL;
}
if (!strcmp(type, "checksum") || !strcmp(type, "datashift-checksum")) {
jobj_hash = json_contains_string(cd, jobj_area, "type:checksum",
"Keyslot area", "hash");
jobj_sector_size = json_contains(cd, jobj_area, "type:checksum",
"Keyslot area", "sector_size", json_type_int);
if (!strcmp(type, "checksum")) {
jobj_hash = json_contains(cd, jobj_area, "type:checksum", "Keyslot area", "hash", json_type_string);
jobj_sector_size = json_contains(cd, jobj_area, "type:checksum", "Keyslot area", "sector_size", json_type_int);
if (!jobj_hash || !jobj_sector_size)
return -EINVAL;
if (!validate_json_uint32(jobj_sector_size))
return -EINVAL;
sector_size = crypt_jobj_get_uint32(jobj_sector_size);
if (sector_size < SECTOR_SIZE || NOTPOW2(sector_size)) {
log_dbg(cd, "Invalid sector_size (%" PRIu32 ") for checksum resilience mode.",
sector_size);
log_dbg(cd, "Invalid sector_size (%" PRIu32 ") for checksum resilience mode.", sector_size);
return -EINVAL;
}
} else if (!strcmp(type, "datashift") ||
!strcmp(type, "datashift-checksum") ||
!strcmp(type, "datashift-journal")) {
if (!(jobj_shift_size = json_contains_string(cd, jobj_area, "type:datashift",
"Keyslot area", "shift_size")))
} else if (!strcmp(type, "datashift")) {
if (!(jobj_shift_size = json_contains(cd, jobj_area, "type:datashift", "Keyslot area", "shift_size", json_type_string)))
return -EINVAL;
shift_size = crypt_jobj_get_uint64(jobj_shift_size);
@@ -363,7 +298,7 @@ static int reenc_keyslot_validate(struct crypt_device *cd, json_object *jobj_key
return -EINVAL;
if (MISALIGNED_512(shift_size)) {
log_dbg(cd, "Shift size field has to be aligned to 512 bytes.");
log_dbg(cd, "Shift size field has to be aligned to sector size: %" PRIu32, SECTOR_SIZE);
return -EINVAL;
}
}
@@ -371,377 +306,6 @@ static int reenc_keyslot_validate(struct crypt_device *cd, json_object *jobj_key
return 0;
}
static int reenc_keyslot_update_needed(struct crypt_device *cd,
json_object *jobj_keyslot,
const struct crypt_params_reencrypt *params,
size_t alignment)
{
const char *type;
json_object *jobj_area, *jobj_type, *jobj;
if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
!json_object_object_get_ex(jobj_area, "type", &jobj_type) ||
!(type = json_object_get_string(jobj_type)))
return -EINVAL;
/*
* If no resilience mode change is requested and effective
* resilience mode is 'checksum' then check alignment matches
* stored checksum block size.
*/
if (!params || !params->resilience) {
if (!strcmp(json_object_get_string(jobj_type), "checksum") ||
!strcmp(json_object_get_string(jobj_type), "datashift-checksum"))
return (json_object_object_get_ex(jobj_area, "sector_size", &jobj) ||
alignment != crypt_jobj_get_uint32(jobj));
return 0;
}
if (strcmp(params->resilience, type))
return 1;
if (!strcmp(type, "checksum") ||
!strcmp(type, "datashift-checksum")) {
if (!params->hash)
return -EINVAL;
if (!json_object_object_get_ex(jobj_area, "hash", &jobj) ||
strcmp(json_object_get_string(jobj), params->hash) ||
!json_object_object_get_ex(jobj_area, "sector_size", &jobj) ||
crypt_jobj_get_uint32(jobj) != alignment)
return 1;
}
if (!strncmp(type, "datashift", 9)) {
if (!json_object_object_get_ex(jobj_area, "shift_size", &jobj))
return -EINVAL;
if ((params->data_shift << SECTOR_SHIFT) != crypt_jobj_get_uint64(jobj))
return 1;
}
/* nothing to compare with 'none' and 'journal' */
return 0;
}
static int load_checksum_protection(struct crypt_device *cd,
json_object *jobj_area,
uint64_t area_length,
struct reenc_protection *rp)
{
int r;
json_object *jobj_hash, *jobj_block_size;
if (!jobj_area || !rp ||
!json_object_object_get_ex(jobj_area, "hash", &jobj_hash) ||
!json_object_object_get_ex(jobj_area, "sector_size", &jobj_block_size))
return -EINVAL;
r = snprintf(rp->p.csum.hash, sizeof(rp->p.csum.hash), "%s", json_object_get_string(jobj_hash));
if (r < 0 || (size_t)r >= sizeof(rp->p.csum.hash))
return -EINVAL;
if (crypt_hash_init(&rp->p.csum.ch, rp->p.csum.hash)) {
log_err(cd, _("Hash algorithm %s is not available."), rp->p.csum.hash);
return -EINVAL;
}
r = crypt_hash_size(rp->p.csum.hash);
if (r <= 0) {
crypt_hash_destroy(rp->p.csum.ch);
rp->p.csum.ch = NULL;
log_dbg(cd, "Invalid hash size");
return -EINVAL;
}
rp->p.csum.hash_size = r;
rp->p.csum.block_size = crypt_jobj_get_uint32(jobj_block_size);
rp->p.csum.checksums_len = area_length;
rp->type = REENC_PROTECTION_CHECKSUM;
return 0;
}
static int reenc_keyslot_load_resilience_primary(struct crypt_device *cd,
const char *type,
json_object *jobj_area,
uint64_t area_length,
struct reenc_protection *rp)
{
json_object *jobj;
if (!strcmp(type, "checksum")) {
log_dbg(cd, "Initializing checksum resilience mode.");
return load_checksum_protection(cd, jobj_area, area_length, rp);
} else if (!strcmp(type, "journal")) {
log_dbg(cd, "Initializing journal resilience mode.");
rp->type = REENC_PROTECTION_JOURNAL;
} else if (!strcmp(type, "none")) {
log_dbg(cd, "Initializing none resilience mode.");
rp->type = REENC_PROTECTION_NONE;
} else if (!strcmp(type, "datashift") ||
!strcmp(type, "datashift-checksum") ||
!strcmp(type, "datashift-journal")) {
log_dbg(cd, "Initializing datashift resilience mode.");
if (!json_object_object_get_ex(jobj_area, "shift_size", &jobj))
return -EINVAL;
rp->type = REENC_PROTECTION_DATASHIFT;
rp->p.ds.data_shift = crypt_jobj_get_uint64(jobj);
} else
return -EINVAL;
return 0;
}
static int reenc_keyslot_load_resilience_secondary(struct crypt_device *cd,
const char *type,
json_object *jobj_area,
uint64_t area_length,
struct reenc_protection *rp)
{
if (!strcmp(type, "datashift-checksum")) {
log_dbg(cd, "Initializing checksum resilience mode.");
return load_checksum_protection(cd, jobj_area, area_length, rp);
} else if (!strcmp(type, "datashift-journal")) {
log_dbg(cd, "Initializing journal resilience mode.");
rp->type = REENC_PROTECTION_JOURNAL;
} else
rp->type = REENC_PROTECTION_NOT_SET;
return 0;
}
static int reenc_keyslot_load_resilience(struct crypt_device *cd,
json_object *jobj_keyslot,
struct reenc_protection *rp,
bool primary)
{
const char *type;
int r;
json_object *jobj_area, *jobj_type;
uint64_t dummy, area_length;
if (!rp || !json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
!json_object_object_get_ex(jobj_area, "type", &jobj_type))
return -EINVAL;
r = LUKS2_keyslot_jobj_area(jobj_keyslot, &dummy, &area_length);
if (r < 0)
return r;
type = json_object_get_string(jobj_type);
if (!type)
return -EINVAL;
if (primary)
return reenc_keyslot_load_resilience_primary(cd, type, jobj_area, area_length, rp);
else
return reenc_keyslot_load_resilience_secondary(cd, type, jobj_area, area_length, rp);
}
static bool reenc_keyslot_update_is_valid(struct crypt_device *cd,
json_object *jobj_area,
const struct crypt_params_reencrypt *params)
{
const char *type;
json_object *jobj_type, *jobj;
if (!json_object_object_get_ex(jobj_area, "type", &jobj_type) ||
!(type = json_object_get_string(jobj_type)))
return false;
/* do not allow switch to/away from datashift resilience type */
if ((strcmp(params->resilience, "datashift") && !strcmp(type, "datashift")) ||
(!strcmp(params->resilience, "datashift") && strcmp(type, "datashift")))
return false;
/* do not allow switch to/away from datashift- resilience subvariants */
if ((strncmp(params->resilience, "datashift-", 10) &&
!strncmp(type, "datashift-", 10)) ||
(!strncmp(params->resilience, "datashift-", 10) &&
strncmp(type, "datashift-", 10)))
return false;
/* datashift value is also immutable */
if (!strncmp(type, "datashift", 9)) {
if (!json_object_object_get_ex(jobj_area, "shift_size", &jobj))
return false;
return (params->data_shift << SECTOR_SHIFT) == crypt_jobj_get_uint64(jobj);
}
return true;
}
static int reenc_keyslot_update(struct crypt_device *cd,
json_object *jobj_keyslot,
const struct crypt_params_reencrypt *params,
size_t alignment)
{
int r;
json_object *jobj_area, *jobj_area_new;
uint64_t area_offset, area_length;
if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
return -EINVAL;
r = LUKS2_keyslot_jobj_area(jobj_keyslot, &area_offset, &area_length);
if (r < 0)
return r;
if (!params || !params->resilience)
jobj_area_new = reencrypt_keyslot_area_jobj_update_block_size(cd, jobj_area, alignment);
else {
if (!reenc_keyslot_update_is_valid(cd, jobj_area, params)) {
log_err(cd, _("Invalid reencryption resilience mode change requested."));
return -EINVAL;
}
jobj_area_new = reencrypt_keyslot_area_jobj(cd, params, alignment,
area_offset, area_length);
}
if (!jobj_area_new)
return -EINVAL;
/* increase refcount for validation purposes */
json_object_get(jobj_area);
json_object_object_add(jobj_keyslot, "area", jobj_area_new);
r = reenc_keyslot_validate(cd, jobj_keyslot);
if (r) {
/* replace invalid object with previous valid one */
json_object_object_add(jobj_keyslot, "area", jobj_area);
return -EINVAL;
}
/* previous area object is no longer needed */
json_object_put(jobj_area);
return 0;
}
int LUKS2_keyslot_reencrypt_allocate(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const struct crypt_params_reencrypt *params,
size_t alignment)
{
int r;
if (keyslot == CRYPT_ANY_SLOT)
return -EINVAL;
r = reenc_keyslot_alloc(cd, hdr, keyslot, params, alignment);
if (r < 0)
return r;
r = LUKS2_keyslot_priority_set(cd, hdr, keyslot, CRYPT_SLOT_PRIORITY_IGNORE, 0);
if (r < 0)
return r;
r = reenc_keyslot_validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot));
if (r) {
log_dbg(cd, "Keyslot validation failed.");
return r;
}
return 0;
}
int LUKS2_keyslot_reencrypt_update_needed(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const struct crypt_params_reencrypt *params,
size_t alignment)
{
int r;
json_object *jobj_type, *jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
if (!jobj_keyslot ||
!json_object_object_get_ex(jobj_keyslot, "type", &jobj_type) ||
strcmp(json_object_get_string(jobj_type), "reencrypt"))
return -EINVAL;
r = reenc_keyslot_update_needed(cd, jobj_keyslot, params, alignment);
if (!r)
log_dbg(cd, "No update of reencrypt keyslot needed.");
return r;
}
int LUKS2_keyslot_reencrypt_update(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const struct crypt_params_reencrypt *params,
size_t alignment,
struct volume_key *vks)
{
int r;
uint8_t version;
uint64_t max_size, moved_segment_size;
json_object *jobj_type, *jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
struct reenc_protection check_rp = {};
if (!jobj_keyslot ||
!json_object_object_get_ex(jobj_keyslot, "type", &jobj_type) ||
strcmp(json_object_get_string(jobj_type), "reencrypt"))
return -EINVAL;
if (LUKS2_config_get_reencrypt_version(hdr, &version))
return -EINVAL;
/* verify existing reencryption metadata before updating */
r = LUKS2_reencrypt_digest_verify(cd, hdr, vks);
if (r < 0)
return r;
r = reenc_keyslot_update(cd, jobj_keyslot, params, alignment);
if (r < 0)
return r;
r = reenc_keyslot_load_resilience(cd, jobj_keyslot, &check_rp, false);
if (r < 0)
return r;
if (check_rp.type != REENC_PROTECTION_NOT_SET) {
r = LUKS2_reencrypt_max_hotzone_size(cd, hdr, &check_rp, keyslot, &max_size);
LUKS2_reencrypt_protection_erase(&check_rp);
if (r < 0)
return r;
moved_segment_size = json_segment_get_size(LUKS2_get_segment_by_flag(hdr, "backup-moved-segment"), 0);
if (!moved_segment_size)
return -EINVAL;
if (moved_segment_size > max_size) {
log_err(cd, _("Can not update resilience type. "
"New type only provides %" PRIu64 " bytes, "
"required space is: %" PRIu64 " bytes."),
max_size, moved_segment_size);
return -EINVAL;
}
}
r = LUKS2_keyslot_reencrypt_digest_create(cd, hdr, version, vks);
if (r < 0)
log_err(cd, _("Failed to refresh reencryption verification digest."));
return r ?: LUKS2_hdr_write(cd, hdr);
}
int LUKS2_keyslot_reencrypt_load(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
struct reenc_protection *rp,
bool primary)
{
json_object *jobj_type, *jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
if (!jobj_keyslot ||
!json_object_object_get_ex(jobj_keyslot, "type", &jobj_type) ||
strcmp(json_object_get_string(jobj_type), "reencrypt"))
return -EINVAL;
return reenc_keyslot_load_resilience(cd, jobj_keyslot, rp, primary);
}
const keyslot_handler reenc_keyslot = {
.name = "reencrypt",
.open = reenc_keyslot_open,

View File

@@ -1,9 +1,9 @@
/*
* LUKS - Linux Unified Key Setup v2, LUKS1 conversion code
*
* Copyright (C) 2015-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2022 Ondrej Kozina
* Copyright (C) 2015-2022 Milan Broz
* Copyright (C) 2015-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2021 Ondrej Kozina
* Copyright (C) 2015-2021 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -24,38 +24,12 @@
#include "../luks1/luks.h"
#include "../luks1/af.h"
/* This differs from LUKS_check_cipher() that it does not check dm-crypt fallback. */
int LUKS2_check_cipher(struct crypt_device *cd,
size_t keylength,
const char *cipher,
const char *cipher_mode)
{
int r;
struct crypt_storage *s;
char buf[SECTOR_SIZE], *empty_key;
log_dbg(cd, "Checking if cipher %s-%s is usable (storage wrapper).", cipher, cipher_mode);
empty_key = crypt_safe_alloc(keylength);
if (!empty_key)
return -ENOMEM;
/* No need to get KEY quality random but it must avoid known weak keys. */
r = crypt_random_get(cd, empty_key, keylength, CRYPT_RND_NORMAL);
if (r < 0)
goto out;
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode, empty_key, keylength, false);
if (r < 0)
goto out;
memset(buf, 0, sizeof(buf));
r = crypt_storage_decrypt(s, 0, sizeof(buf), buf);
crypt_storage_destroy(s);
out:
crypt_safe_free(empty_key);
crypt_safe_memzero(buf, sizeof(buf));
return r;
return LUKS_check_cipher(cd, keylength, cipher, cipher_mode);
}
static int json_luks1_keyslot(const struct luks_phdr *hdr_v1, int keyslot, struct json_object **keyslot_object)
@@ -63,8 +37,7 @@ static int json_luks1_keyslot(const struct luks_phdr *hdr_v1, int keyslot, struc
char *base64_str, cipher[LUKS_CIPHERNAME_L+LUKS_CIPHERMODE_L];
size_t base64_len;
struct json_object *keyslot_obj, *field, *jobj_kdf, *jobj_af, *jobj_area;
uint64_t offset, area_size, length;
int r;
uint64_t offset, area_size, offs_a, offs_b, length;
keyslot_obj = json_object_new_object();
json_object_object_add(keyslot_obj, "type", json_object_new_string("luks2"));
@@ -76,11 +49,13 @@ static int json_luks1_keyslot(const struct luks_phdr *hdr_v1, int keyslot, struc
json_object_object_add(jobj_kdf, "hash", json_object_new_string(hdr_v1->hashSpec));
json_object_object_add(jobj_kdf, "iterations", json_object_new_int64(hdr_v1->keyblock[keyslot].passwordIterations));
/* salt field */
r = crypt_base64_encode(&base64_str, &base64_len, hdr_v1->keyblock[keyslot].passwordSalt, LUKS_SALTSIZE);
if (r < 0) {
base64_len = base64_encode_alloc(hdr_v1->keyblock[keyslot].passwordSalt, LUKS_SALTSIZE, &base64_str);
if (!base64_str) {
json_object_put(keyslot_obj);
json_object_put(jobj_kdf);
return r;
if (!base64_len)
return -EINVAL;
return -ENOMEM;
}
field = json_object_new_string_len(base64_str, base64_len);
free(base64_str);
@@ -92,7 +67,7 @@ static int json_luks1_keyslot(const struct luks_phdr *hdr_v1, int keyslot, struc
json_object_object_add(jobj_af, "type", json_object_new_string("luks1"));
json_object_object_add(jobj_af, "hash", json_object_new_string(hdr_v1->hashSpec));
/* stripes field ignored, fixed to LUKS_STRIPES (4000) */
json_object_object_add(jobj_af, "stripes", json_object_new_int(LUKS_STRIPES));
json_object_object_add(jobj_af, "stripes", json_object_new_int(4000));
json_object_object_add(keyslot_obj, "af", jobj_af);
/* Area */
@@ -101,22 +76,20 @@ static int json_luks1_keyslot(const struct luks_phdr *hdr_v1, int keyslot, struc
/* encryption algorithm field */
if (*hdr_v1->cipherMode != '\0') {
if (snprintf(cipher, sizeof(cipher), "%s-%s", hdr_v1->cipherName, hdr_v1->cipherMode) < 0) {
json_object_put(keyslot_obj);
json_object_put(jobj_area);
return -EINVAL;
}
(void) snprintf(cipher, sizeof(cipher), "%s-%s", hdr_v1->cipherName, hdr_v1->cipherMode);
json_object_object_add(jobj_area, "encryption", json_object_new_string(cipher));
} else
json_object_object_add(jobj_area, "encryption", json_object_new_string(hdr_v1->cipherName));
/* area */
if (LUKS_keyslot_area(hdr_v1, keyslot, &offset, &length)) {
if (LUKS_keyslot_area(hdr_v1, 0, &offs_a, &length) ||
LUKS_keyslot_area(hdr_v1, 1, &offs_b, &length) ||
LUKS_keyslot_area(hdr_v1, keyslot, &offset, &length)) {
json_object_put(keyslot_obj);
json_object_put(jobj_area);
return -EINVAL;
}
area_size = size_round_up(length, 4096);
area_size = offs_b - offs_a;
json_object_object_add(jobj_area, "key_size", json_object_new_int(hdr_v1->keyBytes));
json_object_object_add(jobj_area, "offset", crypt_jobj_new_uint64(offset));
json_object_object_add(jobj_area, "size", crypt_jobj_new_uint64(area_size));
@@ -197,10 +170,7 @@ static int json_luks1_segment(const struct luks_phdr *hdr_v1, struct json_object
/* cipher field */
if (*hdr_v1->cipherMode != '\0') {
if (snprintf(cipher, sizeof(cipher), "%s-%s", hdr_v1->cipherName, hdr_v1->cipherMode) < 0) {
json_object_put(segment_obj);
return -EINVAL;
}
(void) snprintf(cipher, sizeof(cipher), "%s-%s", hdr_v1->cipherName, hdr_v1->cipherMode);
c = cipher;
} else
c = hdr_v1->cipherName;
@@ -246,8 +216,8 @@ static int json_luks1_segments(const struct luks_phdr *hdr_v1, struct json_objec
static int json_luks1_digest(const struct luks_phdr *hdr_v1, struct json_object **digest_object)
{
char keyslot_str[16], *base64_str;
int r, ks;
char keyslot_str[2], *base64_str;
int ks;
size_t base64_len;
struct json_object *digest_obj, *array, *field;
@@ -274,12 +244,7 @@ static int json_luks1_digest(const struct luks_phdr *hdr_v1, struct json_object
for (ks = 0; ks < LUKS_NUMKEYS; ks++) {
if (hdr_v1->keyblock[ks].active != LUKS_KEY_ENABLED)
continue;
if (snprintf(keyslot_str, sizeof(keyslot_str), "%d", ks) < 0) {
json_object_put(field);
json_object_put(array);
json_object_put(digest_obj);
return -EINVAL;
}
(void) snprintf(keyslot_str, sizeof(keyslot_str), "%d", ks);
field = json_object_new_string(keyslot_str);
if (!field || json_object_array_add(array, field) < 0) {
@@ -319,10 +284,12 @@ static int json_luks1_digest(const struct luks_phdr *hdr_v1, struct json_object
json_object_object_add(digest_obj, "hash", field);
/* salt field */
r = crypt_base64_encode(&base64_str, &base64_len, hdr_v1->mkDigestSalt, LUKS_SALTSIZE);
if (r < 0) {
base64_len = base64_encode_alloc(hdr_v1->mkDigestSalt, LUKS_SALTSIZE, &base64_str);
if (!base64_str) {
json_object_put(digest_obj);
return r;
if (!base64_len)
return -EINVAL;
return -ENOMEM;
}
field = json_object_new_string_len(base64_str, base64_len);
@@ -334,10 +301,12 @@ static int json_luks1_digest(const struct luks_phdr *hdr_v1, struct json_object
json_object_object_add(digest_obj, "salt", field);
/* digest field */
r = crypt_base64_encode(&base64_str, &base64_len, hdr_v1->mkDigest, LUKS_DIGESTSIZE);
if (r < 0) {
base64_len = base64_encode_alloc(hdr_v1->mkDigest, LUKS_DIGESTSIZE, &base64_str);
if (!base64_str) {
json_object_put(digest_obj);
return r;
if (!base64_len)
return -EINVAL;
return -ENOMEM;
}
field = json_object_new_string_len(base64_str, base64_len);
@@ -455,6 +424,7 @@ static void move_keyslot_offset(json_object *jobj, int offset_add)
}
}
/* FIXME: return specific error code for partial write error (aka keyslots are gone) */
static int move_keyslot_areas(struct crypt_device *cd, off_t offset_from,
off_t offset_to, size_t buf_size)
{
@@ -565,12 +535,6 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
return -EINVAL;
}
if (LUKS2_check_cipher(cd, hdr1->keyBytes, hdr1->cipherName, hdr1->cipherMode)) {
log_err(cd, _("Unable to use cipher specification %s-%s for LUKS2."),
hdr1->cipherName, hdr1->cipherMode);
return -EINVAL;
}
if (luksmeta_header_present(cd, luks1_size))
return -EINVAL;
@@ -594,7 +558,7 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
move_keyslot_offset(jobj, luks1_shift);
/* Create and fill LUKS2 hdr */
// fill hdr2
memset(hdr2, 0, sizeof(*hdr2));
hdr2->hdr_size = LUKS2_HDR_16K_LEN;
hdr2->seqid = 1;
@@ -616,7 +580,6 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
/* check future LUKS2 metadata before moving keyslots area */
if (LUKS2_hdr_validate(cd, hdr2->jobj, hdr2->hdr_size - LUKS2_HDR_BIN_LEN)) {
log_err(cd, _("Cannot convert to LUKS2 format - invalid metadata."));
r = -EINVAL;
goto out;
}
@@ -627,7 +590,7 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
goto out;
}
/* move keyslots 4k -> 32k offset */
// move keyslots 4k -> 32k offset
buf_offset = 2 * LUKS2_HDR_16K_LEN;
buf_size = luks1_size - LUKS_ALIGN_KEYSLOTS;
@@ -643,7 +606,7 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
goto out;
}
/* Write new LUKS2 JSON */
// Write JSON hdr2
r = LUKS2_hdr_write(cd, hdr2);
out:
LUKS2_hdr_free(cd, hdr2);
@@ -688,6 +651,8 @@ static int keyslot_LUKS1_compatible(struct crypt_device *cd, struct luks2_hdr *h
strcmp(json_object_get_string(jobj), hash))
return 0;
/* FIXME: should this go to validation code instead (aka invalid luks2 header if assigned to segment 0)? */
/* FIXME: check all keyslots are assigned to segment id 0, and segments count == 1 */
ks_cipher = LUKS2_get_keyslot_cipher(hdr, keyslot, &ks_key_size);
data_cipher = LUKS2_get_cipher(hdr, CRYPT_DEFAULT_SEGMENT);
if (!ks_cipher || !data_cipher || key_size != ks_key_size || strcmp(ks_cipher, data_cipher)) {
@@ -711,14 +676,14 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
{
size_t buf_size, buf_offset;
char cipher[LUKS_CIPHERNAME_L], cipher_mode[LUKS_CIPHERMODE_L];
char *digest, *digest_salt;
char digest[LUKS_DIGESTSIZE], digest_salt[LUKS_SALTSIZE];
const char *hash;
size_t len;
json_object *jobj_keyslot, *jobj_digest, *jobj_segment, *jobj_kdf, *jobj_area, *jobj1, *jobj2;
uint32_t key_size;
int i, r, last_active = 0;
uint64_t offset, area_length;
char *buf, luksMagic[] = LUKS_MAGIC;
char buf[256], luksMagic[] = LUKS_MAGIC;
jobj_digest = LUKS2_get_digest_jobj(hdr2, 0);
if (!jobj_digest)
@@ -753,11 +718,6 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
return -EINVAL;
}
if (json_segments_count(LUKS2_get_segments_jobj(hdr2)) != 1) {
log_err(cd, _("Cannot convert to LUKS1 format - device uses more segments."));
return -EINVAL;
}
r = LUKS2_tokens_count(hdr2);
if (r < 0)
return r;
@@ -813,7 +773,7 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
* inactive keyslots. Otherwise we would allocate all
* inactive luks1 keyslots over same binary keyslot area.
*/
if (placeholder_keyslot_alloc(cd, i, offset, area_length))
if (placeholder_keyslot_alloc(cd, i, offset, area_length, key_size))
return -EINVAL;
}
@@ -840,16 +800,14 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
if (!json_object_object_get_ex(jobj_kdf, "salt", &jobj1))
continue;
if (crypt_base64_decode(&buf, &len, json_object_get_string(jobj1),
json_object_get_string_len(jobj1)))
len = sizeof(buf);
memset(buf, 0, len);
if (!base64_decode(json_object_get_string(jobj1),
json_object_get_string_len(jobj1), buf, &len))
continue;
if (len > 0 && len != LUKS_SALTSIZE) {
free(buf);
if (len > 0 && len != LUKS_SALTSIZE)
continue;
}
memcpy(hdr1->keyblock[i].passwordSalt, buf, LUKS_SALTSIZE);
free(buf);
}
if (!jobj_keyslot) {
@@ -885,36 +843,31 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
if (!json_object_object_get_ex(jobj_digest, "digest", &jobj1))
return -EINVAL;
r = crypt_base64_decode(&digest, &len, json_object_get_string(jobj1),
json_object_get_string_len(jobj1));
if (r < 0)
return r;
/* We can store full digest here, not only sha1 length */
if (len < LUKS_DIGESTSIZE) {
free(digest);
len = sizeof(digest);
if (!base64_decode(json_object_get_string(jobj1),
json_object_get_string_len(jobj1), digest, &len))
return -EINVAL;
/* We can store full digest here, not only sha1 length */
if (len < LUKS_DIGESTSIZE)
return -EINVAL;
}
memcpy(hdr1->mkDigest, digest, LUKS_DIGESTSIZE);
free(digest);
if (!json_object_object_get_ex(jobj_digest, "salt", &jobj1))
return -EINVAL;
r = crypt_base64_decode(&digest_salt, &len, json_object_get_string(jobj1),
json_object_get_string_len(jobj1));
if (r < 0)
return r;
if (len != LUKS_SALTSIZE) {
free(digest_salt);
len = sizeof(digest_salt);
if (!base64_decode(json_object_get_string(jobj1),
json_object_get_string_len(jobj1), digest_salt, &len))
return -EINVAL;
if (len != LUKS_SALTSIZE)
return -EINVAL;
}
memcpy(hdr1->mkDigestSalt, digest_salt, LUKS_SALTSIZE);
free(digest_salt);
if (!json_object_object_get_ex(jobj_segment, "offset", &jobj1))
return -EINVAL;
offset = crypt_jobj_get_uint64(jobj1) / SECTOR_SIZE;
if (offset > UINT32_MAX)
return -EINVAL;
/* FIXME: LUKS1 requires offset == 0 || offset >= luks1_hdr_size */
hdr1->payloadOffset = offset;
strncpy(hdr1->uuid, hdr2->uuid, UUID_STRING_L); /* max 36 chars */
@@ -928,7 +881,7 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
if (r)
return r > 0 ? -EBUSY : r;
/* move keyslots 32k -> 4k offset */
// move keyslots 32k -> 4k offset
buf_offset = 2 * LUKS2_HDR_16K_LEN;
buf_size = LUKS2_keyslots_size(hdr2);
r = move_keyslot_areas(cd, buf_offset, 8 * SECTOR_SIZE, buf_size);
@@ -940,6 +893,6 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
crypt_wipe_device(cd, crypt_metadata_device(cd), CRYPT_WIPE_ZERO, 0,
8 * SECTOR_SIZE, 8 * SECTOR_SIZE, NULL, NULL);
/* Write new LUKS1 hdr */
// Write LUKS1 hdr
return LUKS_write_phdr(hdr1, cd);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,9 @@
/*
* 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
* 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
@@ -231,22 +231,8 @@ static size_t reenc_keyslot_serialize(struct luks2_hdr *hdr, uint8_t *buffer)
{ JU32, jobj_area, "sector_size" },
{}
};
struct jtype j_datashift_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" },
{ JU64, jobj_area, "shift_size" },
{}
};
if (!strcmp(area_type, "datashift-checksum"))
return srs(j_datashift_checksum, buffer);
else if (!strcmp(area_type, "datashift") ||
!strcmp(area_type, "datashift-journal"))
if (!strcmp(area_type, "datashift"))
return srs(j_datashift, buffer);
else if (!strcmp(area_type, "checksum"))
return srs(j_checksum, buffer);
@@ -265,7 +251,6 @@ static size_t blob_serialize(void *blob, size_t length, uint8_t *buffer)
static int reencrypt_assembly_verification_data(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct volume_key *vks,
uint8_t version,
struct volume_key **verification_data)
{
uint8_t *ptr;
@@ -273,30 +258,21 @@ static int reencrypt_assembly_verification_data(struct crypt_device *cd,
struct volume_key *data = NULL, *vk_old = NULL, *vk_new = NULL;
size_t keyslot_data_len, segments_data_len, data_len = 2;
/*
* This works up to (including) version v207.
*/
assert(version < (UINT8_MAX - 0x2F));
/* 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) {
log_dbg(cd, "Key (digest id %d) required but not unlocked.", 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) {
log_dbg(cd, "Key (digest id %d) required but not unlocked.", digest_new);
if (!vk_new)
return -EINVAL;
}
data_len += blob_serialize(vk_new->key, vk_new->keylength, NULL);
}
@@ -319,8 +295,9 @@ static int reencrypt_assembly_verification_data(struct crypt_device *cd,
ptr = (uint8_t*)data->key;
/* v2 */
*ptr++ = 0x76;
*ptr++ = 0x30 + version;
*ptr++ = 0x32;
if (vk_old)
ptr += blob_serialize(vk_old->key, vk_old->keylength, ptr);
@@ -348,7 +325,6 @@ bad:
int LUKS2_keyslot_reencrypt_digest_create(struct crypt_device *cd,
struct luks2_hdr *hdr,
uint8_t version,
struct volume_key *vks)
{
int digest_reencrypt, keyslot_reencrypt, r;
@@ -358,7 +334,7 @@ int LUKS2_keyslot_reencrypt_digest_create(struct crypt_device *cd,
if (keyslot_reencrypt < 0)
return keyslot_reencrypt;
r = reencrypt_assembly_verification_data(cd, hdr, vks, version, &data);
r = reencrypt_assembly_verification_data(cd, hdr, vks, &data);
if (r < 0)
return r;
@@ -382,18 +358,12 @@ int LUKS2_reencrypt_digest_verify(struct crypt_device *cd,
{
int r, keyslot_reencrypt;
struct volume_key *data;
uint8_t version;
log_dbg(cd, "Verifying reencryption metadata.");
keyslot_reencrypt = LUKS2_find_keyslot(hdr, "reencrypt");
if (keyslot_reencrypt < 0)
return keyslot_reencrypt;
if (LUKS2_config_get_reencrypt_version(hdr, &version))
return -EINVAL;
r = reencrypt_assembly_verification_data(cd, hdr, vks, version, &data);
r = reencrypt_assembly_verification_data(cd, hdr, vks, &data);
if (r < 0)
return r;

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, internal segment handling
*
* Copyright (C) 2018-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2018-2022 Ondrej Kozina
* Copyright (C) 2018-2021, Red Hat, Inc. All rights reserved.
* Copyright (C) 2018-2021, Ondrej Kozina
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -103,17 +103,15 @@ const char *json_segment_get_cipher(json_object *jobj_segment)
return json_object_get_string(jobj);
}
uint32_t json_segment_get_sector_size(json_object *jobj_segment)
int json_segment_get_sector_size(json_object *jobj_segment)
{
json_object *jobj;
int i;
if (!jobj_segment ||
!json_object_object_get_ex(jobj_segment, "sector_size", &jobj))
return SECTOR_SIZE;
return -1;
i = json_object_get_int(jobj);
return i < 0 ? SECTOR_SIZE : i;
return json_object_get_int(jobj);
}
static json_object *json_segment_get_flags(json_object *jobj_segment)
@@ -346,11 +344,19 @@ int LUKS2_segment_by_type(struct luks2_hdr *hdr, const char *type)
int LUKS2_segment_first_unused_id(struct luks2_hdr *hdr)
{
json_object *jobj_segments;
int id, last_id = -1;
if (!json_object_object_get_ex(hdr->jobj, "segments", &jobj_segments))
return -EINVAL;
return json_object_object_length(jobj_segments);
json_object_object_foreach(jobj_segments, slot, val) {
UNUSED(val);
id = atoi(slot);
if (id > last_id)
last_id = id;
}
return last_id + 1;
}
int LUKS2_segment_set_flag(json_object *jobj_segment, const char *flag)

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, token handling
*
* Copyright (C) 2016-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2022 Milan Broz
* Copyright (C) 2016-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2021 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -446,7 +446,7 @@ static int token_is_usable(struct luks2_hdr *hdr, json_object *jobj_token, int s
for (i = 0; i < len; i++) {
keyslot = atoi(json_object_get_string(json_object_array_get_idx(jobj_array, i)));
keyslot_priority = LUKS2_keyslot_priority_get(hdr, keyslot);
keyslot_priority = LUKS2_keyslot_priority_get(NULL, hdr, keyslot);
if (keyslot_priority == CRYPT_SLOT_PRIORITY_INVALID)
return -EINVAL;
@@ -589,7 +589,7 @@ static int LUKS2_keyslot_open_by_token(struct crypt_device *cd,
for (i = 0; i < (int) json_object_array_length(jobj_token_keyslots) && r < 0; i++) {
jobj = json_object_array_get_idx(jobj_token_keyslots, i);
num = atoi(json_object_get_string(jobj));
keyslot_priority = LUKS2_keyslot_priority_get(hdr, num);
keyslot_priority = LUKS2_keyslot_priority_get(NULL, hdr, num);
if (keyslot_priority == CRYPT_SLOT_PRIORITY_INVALID)
return -EINVAL;
if (keyslot_priority < priority)
@@ -688,22 +688,22 @@ static int token_open_any(struct crypt_device *cd, struct luks2_hdr *hdr, const
return token_open_priority(cd, hdr, jobj_tokens, type, segment, CRYPT_SLOT_PRIORITY_NORMAL, pin, pin_size, usrptr, &retval, &blocked, vk);
}
int LUKS2_token_unlock_volume_key(struct crypt_device *cd,
int LUKS2_token_open_and_activate(struct crypt_device *cd,
struct luks2_hdr *hdr,
int token,
const char *name,
const char *type,
const char *pin,
size_t pin_size,
uint32_t flags,
void *usrptr,
struct volume_key **vk)
void *usrptr)
{
bool use_keyring;
char *buffer;
size_t buffer_size;
json_object *jobj_token;
int segment, r = -ENOENT;
assert(vk);
int keyslot, segment, r = -ENOENT;
struct volume_key *vk = NULL;
if (flags & CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY)
segment = CRYPT_ANY_SEGMENT;
@@ -718,7 +718,7 @@ int LUKS2_token_unlock_volume_key(struct crypt_device *cd,
r = LUKS2_token_open(cd, hdr, token, jobj_token, type, segment, CRYPT_SLOT_PRIORITY_IGNORE, pin, pin_size, &buffer, &buffer_size, usrptr);
if (!r) {
r = LUKS2_keyslot_open_by_token(cd, hdr, token, segment, CRYPT_SLOT_PRIORITY_IGNORE,
buffer, buffer_size, vk);
buffer, buffer_size, &vk);
LUKS2_token_buffer_free(cd, token, buffer, buffer_size);
}
}
@@ -733,28 +733,10 @@ int LUKS2_token_unlock_volume_key(struct crypt_device *cd,
* success (>= 0) or any other negative errno short-circuits token activation loop
* immediately
*/
r = token_open_any(cd, hdr, type, segment, pin, pin_size, usrptr, vk);
r = token_open_any(cd, hdr, type, segment, pin, pin_size, usrptr, &vk);
else
r = -EINVAL;
return -EINVAL;
return r;
}
int LUKS2_token_open_and_activate(struct crypt_device *cd,
struct luks2_hdr *hdr,
int token,
const char *name,
const char *type,
const char *pin,
size_t pin_size,
uint32_t flags,
void *usrptr)
{
bool use_keyring;
int keyslot, r;
struct volume_key *vk = NULL;
r = LUKS2_token_unlock_volume_key(cd, hdr, token, type, pin, pin_size, flags, usrptr, &vk);
if (r < 0)
return r;
@@ -797,7 +779,8 @@ void LUKS2_token_dump(struct crypt_device *cd, int token)
}
}
int LUKS2_token_json_get(struct luks2_hdr *hdr, int token, const char **json)
int LUKS2_token_json_get(struct crypt_device *cd __attribute__((unused)), struct luks2_hdr *hdr,
int token, const char **json)
{
json_object *jobj_token;
@@ -912,7 +895,8 @@ static int token_is_assigned(struct luks2_hdr *hdr, int keyslot, int token)
return -ENOENT;
}
int LUKS2_token_is_assigned(struct luks2_hdr *hdr, int keyslot, int token)
int LUKS2_token_is_assigned(struct crypt_device *cd __attribute__((unused)), struct luks2_hdr *hdr,
int keyslot, int token)
{
if (keyslot < 0 || keyslot >= LUKS2_KEYSLOTS_MAX || token < 0 || token >= LUKS2_TOKENS_MAX)
return -EINVAL;

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, kernel keyring token
*
* Copyright (C) 2016-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2022 Ondrej Kozina
* Copyright (C) 2016-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2021 Ondrej Kozina
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -124,7 +124,7 @@ int LUKS2_token_keyring_json(char *buffer, size_t buffer_size,
return 0;
}
int LUKS2_token_keyring_get(struct luks2_hdr *hdr,
int LUKS2_token_keyring_get(struct crypt_device *cd __attribute__((unused)), struct luks2_hdr *hdr,
int token, struct crypt_token_params_luks2_keyring *keyring_params)
{
json_object *jobj_token, *jobj;

View File

@@ -1,7 +1,7 @@
/*
* cryptsetup kernel RNG access functions
*
* Copyright (C) 2010-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2021 Red Hat, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -42,7 +42,8 @@ static int random_fd = -1;
#define RANDOM_DEVICE_TIMEOUT 5
/* URANDOM_DEVICE access */
static int _get_urandom(char *buf, size_t len)
static int _get_urandom(struct crypt_device *ctx __attribute__((unused)),
char *buf, size_t len)
{
int r;
size_t old_len = len;
@@ -50,7 +51,7 @@ static int _get_urandom(char *buf, size_t len)
assert(urandom_fd != -1);
while (len) {
while(len) {
r = read(urandom_fd, buf, len);
if (r == -1 && errno != EINTR)
return -EINVAL;
@@ -177,13 +178,13 @@ int crypt_random_get(struct crypt_device *ctx, char *buf, size_t len, int qualit
switch(quality) {
case CRYPT_RND_NORMAL:
status = _get_urandom(buf, len);
status = _get_urandom(ctx, buf, len);
break;
case CRYPT_RND_SALT:
if (crypt_fips_mode())
status = crypt_backend_rng(buf, len, quality, 1);
else
status = _get_urandom(buf, len);
status = _get_urandom(ctx, buf, len);
break;
case CRYPT_RND_KEY:
if (crypt_fips_mode()) {
@@ -194,7 +195,7 @@ int crypt_random_get(struct crypt_device *ctx, char *buf, size_t len, int qualit
crypt_random_default_key_rng();
switch (rng_type) {
case CRYPT_RNG_URANDOM:
status = _get_urandom(buf, len);
status = _get_urandom(ctx, buf, len);
break;
case CRYPT_RNG_RANDOM:
status = _get_random(ctx, buf, len);

View File

@@ -3,8 +3,8 @@
*
* Copyright (C) 2004 Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2022 Milan Broz
* Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2021 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -752,7 +752,7 @@ static void _luks2_reload(struct crypt_device *cd)
}
static int _crypt_load_luks(struct crypt_device *cd, const char *requested_type,
bool quiet, bool repair)
int require_header, int repair)
{
char *cipher_spec;
struct luks_phdr hdr = {};
@@ -784,7 +784,7 @@ static int _crypt_load_luks(struct crypt_device *cd, const char *requested_type,
return r;
}
r = LUKS_read_phdr(&hdr, !quiet, repair, cd);
r = LUKS_read_phdr(&hdr, require_header, repair, cd);
if (r)
goto out;
@@ -829,8 +829,6 @@ static int _crypt_load_luks(struct crypt_device *cd, const char *requested_type,
r = _crypt_load_luks2(cd, cd->type != NULL, repair);
if (!r)
device_set_block_size(crypt_data_device(cd), LUKS2_get_sector_size(&cd->u.luks2.hdr));
else if (!quiet)
log_err(cd, _("Device %s is not a valid LUKS device."), mdata_device_path(cd));
} else {
if (version > 2)
log_err(cd, _("Unsupported LUKS version %d."), version);
@@ -974,7 +972,8 @@ static int _crypt_load_integrity(struct crypt_device *cd,
return 0;
}
static int _crypt_load_bitlk(struct crypt_device *cd)
static int _crypt_load_bitlk(struct crypt_device *cd,
struct bitlk_metadata *params __attribute__((unused)))
{
int r;
@@ -1026,7 +1025,7 @@ int crypt_load(struct crypt_device *cd,
return -EINVAL;
}
r = _crypt_load_luks(cd, requested_type, true, false);
r = _crypt_load_luks(cd, requested_type, 1, 0);
} else if (isVERITY(requested_type)) {
if (cd->type && !isVERITY(cd->type)) {
log_dbg(cd, "Context is already initialized to type %s", cd->type);
@@ -1050,7 +1049,7 @@ int crypt_load(struct crypt_device *cd,
log_dbg(cd, "Context is already initialized to type %s", cd->type);
return -EINVAL;
}
r = _crypt_load_bitlk(cd);
r = _crypt_load_bitlk(cd, params);
} else
return -EINVAL;
@@ -1270,7 +1269,7 @@ static int _init_by_name_crypt(struct crypt_device *cd, const char *name)
cd->u.loopaes.key_size = tgt->u.crypt.vk->keylength / key_nums;
} else if (isLUKS1(cd->type) || isLUKS2(cd->type)) {
if (crypt_metadata_device(cd)) {
r = _crypt_load_luks(cd, cd->type, true, false);
r = _crypt_load_luks(cd, cd->type, 0, 0);
if (r < 0) {
log_dbg(cd, "LUKS device header does not match active device.");
crypt_set_null_type(cd);
@@ -1297,7 +1296,7 @@ static int _init_by_name_crypt(struct crypt_device *cd, const char *name)
r = TCRYPT_init_by_name(cd, name, dmd.uuid, tgt, &cd->device,
&cd->u.tcrypt.params, &cd->u.tcrypt.hdr);
} else if (isBITLK(cd->type)) {
r = _crypt_load_bitlk(cd);
r = _crypt_load_bitlk(cd, NULL);
if (r < 0) {
log_dbg(cd, "BITLK device header not available.");
crypt_set_null_type(cd);
@@ -1743,16 +1742,6 @@ static int _crypt_format_luks2(struct crypt_device *cd,
if (params && params->sector_size)
sector_size_autodetect = false;
if (params && params->data_device) {
if (!cd->metadata_device)
cd->metadata_device = cd->device;
else
device_free(cd, cd->device);
cd->device = NULL;
if (device_alloc(cd, &cd->device, params->data_device) < 0)
return -ENOMEM;
}
if (sector_size_autodetect) {
sector_size = device_optimal_encryption_sector_size(cd, crypt_data_device(cd));
log_dbg(cd, "Auto-detected optimal encryption sector size for device %s is %d bytes.",
@@ -1786,13 +1775,13 @@ static int _crypt_format_luks2(struct crypt_device *cd,
params->integrity_params->journal_integrity)
return -ENOTSUP;
}
if (!INTEGRITY_tag_size(integrity, cipher, cipher_mode)) {
if (!INTEGRITY_tag_size(cd, integrity, cipher, cipher_mode)) {
if (!strcmp(integrity, "none"))
integrity = NULL;
else
return -EINVAL;
}
integrity_key_size = INTEGRITY_key_size(integrity);
integrity_key_size = INTEGRITY_key_size(cd, integrity);
if ((integrity_key_size < 0) || (integrity_key_size >= (int)volume_key_size)) {
log_err(cd, _("Volume key is too small for encryption with integrity extensions."));
return -EINVAL;
@@ -1823,6 +1812,16 @@ static int _crypt_format_luks2(struct crypt_device *cd,
if (r < 0)
return r;
if (params && params->data_device) {
if (!cd->metadata_device)
cd->metadata_device = cd->device;
else
device_free(cd, cd->device);
cd->device = NULL;
if (device_alloc(cd, &cd->device, params->data_device) < 0)
return -ENOMEM;
}
if (params && cd->metadata_device) {
/* For detached header the alignment is used directly as data offset */
if (!cd->data_offset)
@@ -1861,7 +1860,7 @@ static int _crypt_format_luks2(struct crypt_device *cd,
}
if ((!integrity || integrity_key_size) && !crypt_cipher_wrapped_key(cipher, cipher_mode) &&
!INTEGRITY_tag_size(NULL, cipher, cipher_mode)) {
!INTEGRITY_tag_size(cd, NULL, cipher, cipher_mode)) {
r = LUKS_check_cipher(cd, volume_key_size - integrity_key_size,
cipher, cipher_mode);
if (r < 0)
@@ -2155,7 +2154,7 @@ static int _crypt_format_verity(struct crypt_device *cd,
if (!(cd->u.verity.uuid = strdup(uuid)))
r = -ENOMEM;
} else
r = VERITY_UUID_generate(&cd->u.verity.uuid);
r = VERITY_UUID_generate(cd, &cd->u.verity.uuid);
if (!r)
r = VERITY_write_sb(cd, cd->u.verity.hdr.hash_area_offset,
@@ -2379,7 +2378,7 @@ int crypt_repair(struct crypt_device *cd,
return -EINVAL;
/* Load with repair */
r = _crypt_load_luks(cd, requested_type, false, true);
r = _crypt_load_luks(cd, requested_type, 1, 1);
if (r < 0)
return r;
@@ -2403,7 +2402,7 @@ static int _compare_volume_keys(struct volume_key *svk, unsigned skeyring_only,
return 1;
if (!skeyring_only && !tkeyring_only)
return crypt_backend_memeq(svk->key, tvk->key, svk->keylength);
return memcmp(svk->key, tvk->key, svk->keylength);
if (svk->key_description && tvk->key_description)
return strcmp(svk->key_description, tvk->key_description);
@@ -2436,7 +2435,7 @@ static int _compare_device_types(struct crypt_device *cd,
log_dbg(cd, "Unexpected uuid prefix %s in target device.", tgt->uuid);
return -EINVAL;
}
} else if (!isINTEGRITY(cd->type)) {
} else {
log_dbg(cd, "Unsupported device type %s for reload.", cd->type ?: "<empty>");
return -ENOTSUP;
}
@@ -2525,6 +2524,15 @@ static int _compare_integrity_devices(struct crypt_device *cd,
return -EINVAL;
}
/* unsupported underneath dm-crypt with auth. encryption */
if (src->u.integrity.meta_device || tgt->u.integrity.meta_device)
return -ENOTSUP;
if (src->size != tgt->size) {
log_dbg(cd, "Device size parameters do not match.");
return -EINVAL;
}
if (device_is_identical(src->data_device, tgt->data_device) <= 0) {
log_dbg(cd, "Data devices do not match.");
return -EINVAL;
@@ -2597,13 +2605,13 @@ static int _reload_device(struct crypt_device *cd, const char *name,
r = dm_query_device(cd, name, DM_ACTIVE_DEVICE | DM_ACTIVE_CRYPT_CIPHER |
DM_ACTIVE_UUID | DM_ACTIVE_CRYPT_KEYSIZE |
DM_ACTIVE_CRYPT_KEY | DM_ACTIVE_INTEGRITY_PARAMS | DM_ACTIVE_JOURNAL_CRYPT_KEY | DM_ACTIVE_JOURNAL_MAC_KEY, &tdmd);
DM_ACTIVE_CRYPT_KEY, &tdmd);
if (r < 0) {
log_err(cd, _("Device %s is not active."), name);
return -EINVAL;
}
if (!single_segment(&tdmd) || (tgt->type != DM_CRYPT && tgt->type != DM_INTEGRITY) || (tgt->type == DM_CRYPT && tgt->u.crypt.tag_size)) {
if (!single_segment(&tdmd) || tgt->type != DM_CRYPT || tgt->u.crypt.tag_size) {
r = -ENOTSUP;
log_err(cd, _("Unsupported parameters on device %s."), name);
goto out;
@@ -2623,11 +2631,11 @@ static int _reload_device(struct crypt_device *cd, const char *name,
else
sdmd->flags &= ~CRYPT_ACTIVATE_READONLY;
if (tgt->type == DM_CRYPT && sdmd->flags & CRYPT_ACTIVATE_KEYRING_KEY) {
if (sdmd->flags & CRYPT_ACTIVATE_KEYRING_KEY) {
r = crypt_volume_key_set_description(tgt->u.crypt.vk, src->u.crypt.vk->key_description);
if (r)
goto out;
} else if (tgt->type == DM_CRYPT) {
} else {
crypt_free_volume_key(tgt->u.crypt.vk);
tgt->u.crypt.vk = crypt_alloc_volume_key(src->u.crypt.vk->keylength, src->u.crypt.vk->key);
if (!tgt->u.crypt.vk) {
@@ -2636,15 +2644,8 @@ static int _reload_device(struct crypt_device *cd, const char *name,
}
}
if (tgt->type == DM_CRYPT)
r = device_block_adjust(cd, src->data_device, DEV_OK,
src->u.crypt.offset, &sdmd->size, NULL);
else if (tgt->type == DM_INTEGRITY)
r = device_block_adjust(cd, src->data_device, DEV_OK,
src->u.integrity.offset, &sdmd->size, NULL);
else
r = -EINVAL;
r = device_block_adjust(cd, src->data_device, DEV_OK,
src->u.crypt.offset, &sdmd->size, NULL);
if (r)
goto out;
@@ -2708,10 +2709,6 @@ static int _reload_device_with_integrity(struct crypt_device *cd,
goto out;
}
/* unsupported underneath dm-crypt with auth. encryption */
if (sdmdi->segment.u.integrity.meta_device || tdmdi.segment.u.integrity.meta_device)
return -ENOTSUP;
src = &sdmd->segment;
srci = &sdmdi->segment;
@@ -2833,9 +2830,6 @@ int crypt_resize(struct crypt_device *cd, const char *name, uint64_t new_size)
{
struct crypt_dm_active_device dmdq, dmd = {};
struct dm_target *tgt = &dmdq.segment;
struct crypt_params_integrity params = {};
uint32_t supported_flags = 0;
uint64_t old_size;
int r;
/*
@@ -2854,12 +2848,12 @@ int crypt_resize(struct crypt_device *cd, const char *name, uint64_t new_size)
log_dbg(cd, "Resizing device %s to %" PRIu64 " sectors.", name, new_size);
r = dm_query_device(cd, name, DM_ACTIVE_CRYPT_KEYSIZE | DM_ACTIVE_CRYPT_KEY | DM_ACTIVE_INTEGRITY_PARAMS | DM_ACTIVE_JOURNAL_CRYPT_KEY | DM_ACTIVE_JOURNAL_MAC_KEY, &dmdq);
r = dm_query_device(cd, name, DM_ACTIVE_CRYPT_KEYSIZE | DM_ACTIVE_CRYPT_KEY, &dmdq);
if (r < 0) {
log_err(cd, _("Device %s is not active."), name);
return -EINVAL;
}
if (!single_segment(&dmdq) || (tgt->type != DM_CRYPT && tgt->type != DM_INTEGRITY)) {
if (!single_segment(&dmdq) || tgt->type != DM_CRYPT) {
log_dbg(cd, "Unsupported device table detected in %s.", name);
r = -EINVAL;
goto out;
@@ -2891,52 +2885,12 @@ int crypt_resize(struct crypt_device *cd, const char *name, uint64_t new_size)
log_err(cd, _("Cannot resize loop device."));
}
/*
* Integrity device metadata are maintained by the kernel. We need to
* reload the device (with the same parameters) and let the kernel
* calculate the maximum size of integrity device and store it in the
* superblock.
*/
if (!new_size && tgt->type == DM_INTEGRITY) {
r = INTEGRITY_data_sectors(cd, crypt_metadata_device(cd),
crypt_get_data_offset(cd) * SECTOR_SIZE, &old_size);
if (r < 0)
return r;
dmd.size = dmdq.size;
dmd.flags = dmdq.flags | CRYPT_ACTIVATE_REFRESH | CRYPT_ACTIVATE_PRIVATE;
r = crypt_get_integrity_info(cd, &params);
if (r)
goto out;
r = dm_integrity_target_set(cd, &dmd.segment, 0, dmdq.segment.size,
crypt_metadata_device(cd), crypt_data_device(cd),
crypt_get_integrity_tag_size(cd), crypt_get_data_offset(cd),
crypt_get_sector_size(cd), tgt->u.integrity.vk, tgt->u.integrity.journal_crypt_key, tgt->u.integrity.journal_integrity_key, &params);
if (r)
goto out;
r = _reload_device(cd, name, &dmd);
if (r)
goto out;
r = INTEGRITY_data_sectors(cd, crypt_metadata_device(cd),
crypt_get_data_offset(cd) * SECTOR_SIZE, &new_size);
if (r < 0)
return r;
log_dbg(cd, "Maximum integrity device size from kernel %" PRIu64, new_size);
if (old_size == new_size && new_size == dmdq.size && !dm_flags(cd, tgt->type, &supported_flags) && !(supported_flags & DM_INTEGRITY_RESIZE_SUPPORTED))
log_std(cd, _("WARNING: Maximum size already set or kernel doesn't support resize.\n"));
}
r = device_block_adjust(cd, crypt_data_device(cd), DEV_OK,
crypt_get_data_offset(cd), &new_size, &dmdq.flags);
crypt_get_data_offset(cd), &new_size, &dmdq.flags);
if (r)
goto out;
if (MISALIGNED(new_size, (tgt->type == DM_CRYPT ? tgt->u.crypt.sector_size : tgt->u.integrity.sector_size) >> SECTOR_SHIFT)) {
if (MISALIGNED(new_size, tgt->u.crypt.sector_size >> SECTOR_SHIFT)) {
log_err(cd, _("Device size is not aligned to requested sector size."));
r = -EINVAL;
goto out;
@@ -2951,27 +2905,13 @@ int crypt_resize(struct crypt_device *cd, const char *name, uint64_t new_size)
dmd.uuid = crypt_get_uuid(cd);
dmd.size = new_size;
dmd.flags = dmdq.flags | CRYPT_ACTIVATE_REFRESH;
if (tgt->type == DM_CRYPT) {
r = dm_crypt_target_set(&dmd.segment, 0, new_size, crypt_data_device(cd),
tgt->u.crypt.vk, crypt_get_cipher_spec(cd),
crypt_get_iv_offset(cd), crypt_get_data_offset(cd),
crypt_get_integrity(cd), crypt_get_integrity_tag_size(cd),
crypt_get_sector_size(cd));
if (r < 0)
goto out;
} else if (tgt->type == DM_INTEGRITY) {
r = crypt_get_integrity_info(cd, &params);
if (r)
goto out;
r = dm_integrity_target_set(cd, &dmd.segment, 0, new_size,
crypt_metadata_device(cd), crypt_data_device(cd),
crypt_get_integrity_tag_size(cd), crypt_get_data_offset(cd),
crypt_get_sector_size(cd), tgt->u.integrity.vk, tgt->u.integrity.journal_crypt_key, tgt->u.integrity.journal_integrity_key, &params);
if (r)
goto out;
}
r = dm_crypt_target_set(&dmd.segment, 0, new_size, crypt_data_device(cd),
tgt->u.crypt.vk, crypt_get_cipher_spec(cd),
crypt_get_iv_offset(cd), crypt_get_data_offset(cd),
crypt_get_integrity(cd), crypt_get_integrity_tag_size(cd),
crypt_get_sector_size(cd));
if (r < 0)
goto out;
if (new_size == dmdq.size) {
log_dbg(cd, "Device has already requested size %" PRIu64
@@ -2984,9 +2924,6 @@ int crypt_resize(struct crypt_device *cd, const char *name, uint64_t new_size)
r = LUKS2_unmet_requirements(cd, &cd->u.luks2.hdr, 0, 0);
if (!r)
r = _reload_device(cd, name, &dmd);
if (r && tgt->type == DM_INTEGRITY && !dm_flags(cd, tgt->type, &supported_flags) && !(supported_flags & DM_INTEGRITY_RESIZE_SUPPORTED))
log_err(cd, _("Resize failed, the kernel doesn't support it."));
}
out:
dm_targets_free(cd, &dmd);
@@ -3039,22 +2976,6 @@ int crypt_set_label(struct crypt_device *cd, const char *label, const char *subs
return LUKS2_hdr_labels(cd, &cd->u.luks2.hdr, label, subsystem, 1);
}
const char *crypt_get_label(struct crypt_device *cd)
{
if (_onlyLUKS2(cd, CRYPT_CD_QUIET | CRYPT_CD_UNRESTRICTED, 0))
return NULL;
return cd->u.luks2.hdr.label;
}
const char *crypt_get_subsystem(struct crypt_device *cd)
{
if (_onlyLUKS2(cd, CRYPT_CD_QUIET | CRYPT_CD_UNRESTRICTED, 0))
return NULL;
return cd->u.luks2.hdr.subsystem;
}
int crypt_header_backup(struct crypt_device *cd,
const char *requested_type,
const char *backup_file)
@@ -3068,7 +2989,7 @@ int crypt_header_backup(struct crypt_device *cd,
return -EINVAL;
/* Load with repair */
r = _crypt_load_luks(cd, requested_type, false, false);
r = _crypt_load_luks(cd, requested_type, 1, 0);
if (r < 0)
return r;
@@ -3134,7 +3055,7 @@ int crypt_header_restore(struct crypt_device *cd,
r = -EINVAL;
if (!r)
r = _crypt_load_luks(cd, version == 1 ? CRYPT_LUKS1 : CRYPT_LUKS2, false, true);
r = _crypt_load_luks(cd, version == 1 ? CRYPT_LUKS1 : CRYPT_LUKS2, 1, 1);
return r;
}
@@ -3160,7 +3081,7 @@ void crypt_free(struct crypt_device *cd)
if (!cd)
return;
log_dbg(cd, "Releasing crypt device %s context.", mdata_device_path(cd) ?: "empty");
log_dbg(cd, "Releasing crypt device %s context.", mdata_device_path(cd));
dm_backend_exit(cd);
crypt_free_volume_key(cd->volume_key);
@@ -3279,7 +3200,8 @@ static int resume_by_volume_key(struct crypt_device *cd,
digest = LUKS2_digest_by_segment(&cd->u.luks2.hdr, CRYPT_DEFAULT_SEGMENT);
if (digest < 0)
return -EINVAL;
r = LUKS2_volume_key_load_in_keyring_by_digest(cd, vk, digest);
r = LUKS2_volume_key_load_in_keyring_by_digest(cd,
&cd->u.luks2.hdr, vk, digest);
if (r < 0)
return r;
}
@@ -3465,40 +3387,6 @@ int crypt_resume_by_volume_key(struct crypt_device *cd,
return r;
}
int crypt_resume_by_token_pin(struct crypt_device *cd, const char *name,
const char *type, int token, const char *pin, size_t pin_size,
void *usrptr)
{
struct volume_key *vk = NULL;
int r, keyslot;
if (!name)
return -EINVAL;
log_dbg(cd, "Resuming volume %s by token (%s type) %d.",
name, type ?: "any", token);
if ((r = _onlyLUKS2(cd, CRYPT_CD_QUIET, 0)))
return r;
r = dm_status_suspended(cd, name);
if (r < 0)
return r;
if (!r) {
log_err(cd, _("Volume %s is not suspended."), name);
return -EINVAL;
}
r = LUKS2_token_unlock_volume_key(cd, &cd->u.luks2.hdr, token, type, pin, pin_size, 0, usrptr, &vk);
keyslot = r;
if (r >= 0)
r = resume_by_volume_key(cd, vk, name);
crypt_free_volume_key(vk);
return r < 0 ? r : keyslot;
}
/*
* Keyslot manipulation
*/
@@ -4013,7 +3901,7 @@ int create_or_reload_device(struct crypt_device *cd, const char *name,
return -EINVAL;
tgt = &dmd->segment;
if (tgt->type != DM_CRYPT && tgt->type != DM_INTEGRITY)
if (tgt->type != DM_CRYPT)
return -EINVAL;
/* drop CRYPT_ACTIVATE_REFRESH flag if any device is inactive */
@@ -4024,27 +3912,12 @@ int create_or_reload_device(struct crypt_device *cd, const char *name,
if (dmd->flags & CRYPT_ACTIVATE_REFRESH)
r = _reload_device(cd, name, dmd);
else {
if (tgt->type == DM_CRYPT) {
device_check = dmd->flags & CRYPT_ACTIVATE_SHARED ? DEV_OK : DEV_EXCL;
device_check = dmd->flags & CRYPT_ACTIVATE_SHARED ? DEV_OK : DEV_EXCL;
r = device_block_adjust(cd, tgt->data_device, device_check,
r = device_block_adjust(cd, tgt->data_device, device_check,
tgt->u.crypt.offset, &dmd->size, &dmd->flags);
if (!r) {
tgt->size = dmd->size;
r = dm_create_device(cd, name, type, dmd);
}
} else if (tgt->type == DM_INTEGRITY) {
r = device_block_adjust(cd, tgt->data_device, DEV_EXCL,
tgt->u.integrity.offset, NULL, &dmd->flags);
if (r)
return r;
if (tgt->u.integrity.meta_device) {
r = device_block_adjust(cd, tgt->u.integrity.meta_device, DEV_EXCL, 0, NULL, NULL);
if (r)
return r;
}
if (!r) {
tgt->size = dmd->size;
r = dm_create_device(cd, name, type, dmd);
}
}
@@ -4082,6 +3955,10 @@ out:
return r;
}
/* See fixmes in _open_and_activate_luks2 */
int update_reencryption_flag(struct crypt_device *cd, int enable, bool commit);
/* TODO: This function should 1:1 with pre-reencryption code */
static int _open_and_activate(struct crypt_device *cd,
int keyslot,
const char *name,
@@ -4132,7 +4009,7 @@ static int load_all_keys(struct crypt_device *cd, struct luks2_hdr *hdr, struct
struct volume_key *vk = vks;
while (vk) {
r = LUKS2_volume_key_load_in_keyring_by_digest(cd, vk, crypt_volume_key_get_id(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);
@@ -4223,7 +4100,7 @@ static int _open_and_activate_reencrypt_device(struct crypt_device *cd,
if (ri == CRYPT_REENCRYPT_CRASH) {
r = LUKS2_reencrypt_locked_recovery_by_passphrase(cd, keyslot,
keyslot, passphrase, passphrase_size, &vks);
keyslot, passphrase, passphrase_size, flags, &vks);
if (r < 0) {
log_err(cd, _("LUKS2 reencryption recovery failed."));
goto out;
@@ -4688,10 +4565,7 @@ int crypt_activate_by_signed_key(struct crypt_device *cd,
return -EINVAL;
}
if (name)
log_dbg(cd, "Activating volume %s by %skey.", name, signature ? "signed " : "");
else
log_dbg(cd, "Checking volume by key.");
log_dbg(cd, "%s volume %s by %skey.", name ? "Activating" : "Checking", name ?: "", signature ? "signed " : "");
if (cd->u.verity.hdr.flags & CRYPT_VERITY_ROOT_HASH_SIGNATURE && !signature) {
log_err(cd, _("Root hash signature required."));
@@ -4985,6 +4859,10 @@ int crypt_volume_key_verify(struct crypt_device *cd,
else
r = -EINVAL;
if (r == -EPERM)
log_err(cd, _("Volume key does not match the volume."));
crypt_free_volume_key(vk);
return r >= 0 ? 0 : r;
@@ -5063,6 +4941,13 @@ crypt_status_info crypt_status(struct crypt_device *cd, const char *name)
return CRYPT_INACTIVE;
}
static void hexprint(struct crypt_device *cd, const char *d, int n, const char *sep)
{
int i;
for(i = 0; i < n; i++)
log_std(cd, "%02hhx%s", (const char)d[i], sep);
}
static int _luks_dump(struct crypt_device *cd)
{
int i;
@@ -5075,12 +4960,12 @@ static int _luks_dump(struct crypt_device *cd)
log_std(cd, "Payload offset:\t%" PRIu32 "\n", cd->u.luks1.hdr.payloadOffset);
log_std(cd, "MK bits: \t%" PRIu32 "\n", cd->u.luks1.hdr.keyBytes * 8);
log_std(cd, "MK digest: \t");
crypt_log_hex(cd, cd->u.luks1.hdr.mkDigest, LUKS_DIGESTSIZE, " ", 0, NULL);
hexprint(cd, cd->u.luks1.hdr.mkDigest, LUKS_DIGESTSIZE, " ");
log_std(cd, "\n");
log_std(cd, "MK salt: \t");
crypt_log_hex(cd, cd->u.luks1.hdr.mkDigestSalt, LUKS_SALTSIZE/2, " ", 0, NULL);
hexprint(cd, cd->u.luks1.hdr.mkDigestSalt, LUKS_SALTSIZE/2, " ");
log_std(cd, "\n \t");
crypt_log_hex(cd, cd->u.luks1.hdr.mkDigestSalt+LUKS_SALTSIZE/2, LUKS_SALTSIZE/2, " ", 0, NULL);
hexprint(cd, cd->u.luks1.hdr.mkDigestSalt+LUKS_SALTSIZE/2, LUKS_SALTSIZE/2, " ");
log_std(cd, "\n");
log_std(cd, "MK iterations: \t%" PRIu32 "\n", cd->u.luks1.hdr.mkDigestIterations);
log_std(cd, "UUID: \t%s\n\n", cd->u.luks1.hdr.uuid);
@@ -5090,11 +4975,11 @@ static int _luks_dump(struct crypt_device *cd)
log_std(cd, "\tIterations: \t%" PRIu32 "\n",
cd->u.luks1.hdr.keyblock[i].passwordIterations);
log_std(cd, "\tSalt: \t");
crypt_log_hex(cd, cd->u.luks1.hdr.keyblock[i].passwordSalt,
LUKS_SALTSIZE/2, " ", 0, NULL);
hexprint(cd, cd->u.luks1.hdr.keyblock[i].passwordSalt,
LUKS_SALTSIZE/2, " ");
log_std(cd, "\n\t \t");
crypt_log_hex(cd, cd->u.luks1.hdr.keyblock[i].passwordSalt +
LUKS_SALTSIZE/2, LUKS_SALTSIZE/2, " ", 0, NULL);
hexprint(cd, cd->u.luks1.hdr.keyblock[i].passwordSalt +
LUKS_SALTSIZE/2, LUKS_SALTSIZE/2, " ");
log_std(cd, "\n");
log_std(cd, "\tKey material offset:\t%" PRIu32 "\n",
@@ -5108,6 +4993,29 @@ static int _luks_dump(struct crypt_device *cd)
return 0;
}
static int _verity_dump(struct crypt_device *cd)
{
log_std(cd, "VERITY header information for %s\n", mdata_device_path(cd));
log_std(cd, "UUID: \t%s\n", cd->u.verity.uuid ?: "");
log_std(cd, "Hash type: \t%u\n", cd->u.verity.hdr.hash_type);
log_std(cd, "Data blocks: \t%" PRIu64 "\n", cd->u.verity.hdr.data_size);
log_std(cd, "Data block size: \t%u\n", cd->u.verity.hdr.data_block_size);
log_std(cd, "Hash block size: \t%u\n", cd->u.verity.hdr.hash_block_size);
log_std(cd, "Hash algorithm: \t%s\n", cd->u.verity.hdr.hash_name);
log_std(cd, "Salt: \t");
if (cd->u.verity.hdr.salt_size)
hexprint(cd, cd->u.verity.hdr.salt, cd->u.verity.hdr.salt_size, "");
else
log_std(cd, "-");
log_std(cd, "\n");
if (cd->u.verity.root_hash) {
log_std(cd, "Root hash: \t");
hexprint(cd, cd->u.verity.root_hash, cd->u.verity.root_hash_size, "");
log_std(cd, "\n");
}
return 0;
}
int crypt_dump(struct crypt_device *cd)
{
if (!cd)
@@ -5117,9 +5025,7 @@ int crypt_dump(struct crypt_device *cd)
else if (isLUKS2(cd->type))
return LUKS2_hdr_dump(cd, &cd->u.luks2.hdr);
else if (isVERITY(cd->type))
return VERITY_dump(cd, &cd->u.verity.hdr,
cd->u.verity.root_hash, cd->u.verity.root_hash_size,
cd->u.verity.fec_device);
return _verity_dump(cd);
else if (isTCRYPT(cd->type))
return TCRYPT_dump(cd, &cd->u.tcrypt.hdr, &cd->u.tcrypt.params);
else if (isINTEGRITY(cd->type))
@@ -5247,15 +5153,13 @@ const char *crypt_get_integrity(struct crypt_device *cd)
/* INTERNAL only */
int crypt_get_integrity_key_size(struct crypt_device *cd)
{
int key_size = 0;
if (isINTEGRITY(cd->type))
key_size = INTEGRITY_key_size(crypt_get_integrity(cd));
return INTEGRITY_key_size(cd, crypt_get_integrity(cd));
if (isLUKS2(cd->type))
key_size = INTEGRITY_key_size(crypt_get_integrity(cd));
return INTEGRITY_key_size(cd, crypt_get_integrity(cd));
return key_size > 0 ? key_size : 0;
return 0;
}
/* INTERNAL only */
@@ -5265,7 +5169,7 @@ int crypt_get_integrity_tag_size(struct crypt_device *cd)
return cd->u.integrity.params.tag_size;
if (isLUKS2(cd->type))
return INTEGRITY_tag_size(crypt_get_integrity(cd),
return INTEGRITY_tag_size(cd, crypt_get_integrity(cd),
crypt_get_cipher(cd),
crypt_get_cipher_mode(cd));
return 0;
@@ -5619,7 +5523,7 @@ crypt_keyslot_priority crypt_keyslot_get_priority(struct crypt_device *cd, int k
return CRYPT_SLOT_PRIORITY_INVALID;
if (isLUKS2(cd->type))
return LUKS2_keyslot_priority_get(&cd->u.luks2.hdr, keyslot);
return LUKS2_keyslot_priority_get(cd, &cd->u.luks2.hdr, keyslot);
return CRYPT_SLOT_PRIORITY_NORMAL;
}
@@ -5711,7 +5615,7 @@ int crypt_get_integrity_info(struct crypt_device *cd,
ip->integrity = LUKS2_get_integrity(&cd->u.luks2.hdr, CRYPT_DEFAULT_SEGMENT);
ip->integrity_key_size = crypt_get_integrity_key_size(cd);
ip->tag_size = INTEGRITY_tag_size(ip->integrity, crypt_get_cipher(cd), crypt_get_cipher_mode(cd));
ip->tag_size = INTEGRITY_tag_size(cd, ip->integrity, crypt_get_cipher(cd), crypt_get_cipher_mode(cd));
ip->journal_integrity = NULL;
ip->journal_integrity_key_size = 0;
@@ -5849,7 +5753,7 @@ int crypt_token_json_get(struct crypt_device *cd, int token, const char **json)
if ((r = _onlyLUKS2(cd, CRYPT_CD_UNRESTRICTED, 0)))
return r;
return LUKS2_token_json_get(&cd->u.luks2.hdr, token, json) ?: token;
return LUKS2_token_json_get(cd, &cd->u.luks2.hdr, token, json) ?: token;
}
int crypt_token_json_set(struct crypt_device *cd, int token, const char *json)
@@ -5915,7 +5819,7 @@ int crypt_token_luks2_keyring_get(struct crypt_device *cd,
return -EINVAL;
}
return LUKS2_token_keyring_get(&cd->u.luks2.hdr, token, params);
return LUKS2_token_keyring_get(cd, &cd->u.luks2.hdr, token, params);
}
int crypt_token_luks2_keyring_set(struct crypt_device *cd,
@@ -5967,7 +5871,7 @@ int crypt_token_is_assigned(struct crypt_device *cd, int token, int keyslot)
if ((r = _onlyLUKS2(cd, CRYPT_CD_QUIET | CRYPT_CD_UNRESTRICTED, 0)))
return r;
return LUKS2_token_is_assigned(&cd->u.luks2.hdr, keyslot, token);
return LUKS2_token_is_assigned(cd, &cd->u.luks2.hdr, keyslot, token);
}
/* Internal only */
@@ -6336,13 +6240,7 @@ void crypt_serialize_unlock(struct crypt_device *cd)
crypt_reencrypt_info crypt_reencrypt_status(struct crypt_device *cd,
struct crypt_params_reencrypt *params)
{
if (params)
memset(params, 0, sizeof(*params));
if (!cd || !isLUKS(cd->type))
return CRYPT_REENCRYPT_INVALID;
if (isLUKS1(cd->type))
if (!cd || !isLUKS2(cd->type))
return CRYPT_REENCRYPT_NONE;
if (_onlyLUKS2(cd, CRYPT_CD_QUIET, CRYPT_REQUIREMENT_ONLINE_REENCRYPT))

View File

@@ -1,8 +1,8 @@
/*
* TCRYPT (TrueCrypt-compatible) and VeraCrypt volume handling
*
* Copyright (C) 2012-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2022 Milan Broz
* Copyright (C) 2012-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2021 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -264,8 +264,8 @@ static int TCRYPT_hdr_from_disk(struct crypt_device *cd,
*/
static void TCRYPT_swab_le(char *buf)
{
uint32_t *l = VOIDP_CAST(uint32_t*)&buf[0];
uint32_t *r = VOIDP_CAST(uint32_t*)&buf[4];
uint32_t *l = (uint32_t*)&buf[0];
uint32_t *r = (uint32_t*)&buf[4];
*l = swab32(*l);
*r = swab32(*r);
}
@@ -588,6 +588,7 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
(tcrypt_kdf[i].veracrypt_pim_mult * params->veracrypt_pim);
} else
iterations = tcrypt_kdf[i].iterations;
/* Derive header key */
log_dbg(cd, "TCRYPT: trying KDF: %s-%s-%d%s.",
tcrypt_kdf[i].name, tcrypt_kdf[i].hash, tcrypt_kdf[i].iterations,
@@ -600,8 +601,6 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
if (r < 0) {
log_verbose(cd, _("PBKDF2 hash algorithm %s not available, skipping."),
tcrypt_kdf[i].hash);
skipped++;
r = -EPERM;
continue;
}
@@ -610,18 +609,16 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
if (r == -ENOENT) {
skipped++;
r = -EPERM;
continue;
}
if (r != -EPERM)
break;
}
if ((r < 0 && skipped && skipped == i) || r == -ENOTSUP) {
if ((r < 0 && r != -EPERM && skipped && skipped == i) || r == -ENOTSUP) {
log_err(cd, _("Required kernel crypto interface not available."));
#ifdef ENABLE_AF_ALG
log_err(cd, _("Ensure you have algif_skcipher kernel module loaded."));
#endif
r = -ENOTSUP;
}
if (r < 0)
goto out;
@@ -830,10 +827,7 @@ int TCRYPT_activate(struct crypt_device *cd,
strncpy(dm_name, name, sizeof(dm_name)-1);
dmd.flags = flags;
} else {
if (snprintf(dm_name, sizeof(dm_name), "%s_%d", name, i-1) < 0) {
r = -EINVAL;
break;
}
snprintf(dm_name, sizeof(dm_name), "%s_%d", name, i-1);
dmd.flags = flags | CRYPT_ACTIVATE_PRIVATE;
}
@@ -841,10 +835,8 @@ int TCRYPT_activate(struct crypt_device *cd,
vk->key, hdr->d.keys);
if (algs->chain_count != i) {
if (snprintf(dm_dev_name, sizeof(dm_dev_name), "%s/%s_%d", dm_get_dir(), name, i) < 0) {
r = -EINVAL;
break;
}
snprintf(dm_dev_name, sizeof(dm_dev_name), "%s/%s_%d",
dm_get_dir(), name, i);
r = device_alloc(cd, &device, dm_dev_name);
if (r)
break;

View File

@@ -1,8 +1,8 @@
/*
* TCRYPT (TrueCrypt-compatible) header definition
*
* Copyright (C) 2012-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2022 Milan Broz
* Copyright (C) 2012-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2021 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

View File

@@ -3,8 +3,8 @@
*
* Copyright (C) 2004 Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2022 Milan Broz
* Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2021 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

View File

@@ -1,8 +1,8 @@
/*
* libcryptsetup - cryptsetup library, cipher benchmark
*
* Copyright (C) 2012-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2022 Milan Broz
* Copyright (C) 2012-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2021 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -184,7 +184,7 @@ int crypt_benchmark_pbkdf_internal(struct crypt_device *cd,
pbkdf->parallel_threads = 0; /* N/A in PBKDF2 */
pbkdf->max_memory_kb = 0; /* N/A in PBKDF2 */
r = crypt_benchmark_pbkdf(cd, pbkdf, "foo", 3, "01234567890abcdef", 16,
r = crypt_benchmark_pbkdf(cd, pbkdf, "foo", 3, "bar", 3,
volume_key_size, &benchmark_callback, &u);
pbkdf->time_ms = ms_tmp;
if (r < 0) {

View File

@@ -1,7 +1,7 @@
/*
* blkid probe utilities
*
* Copyright (C) 2018-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2018-2021 Red Hat, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -19,7 +19,6 @@
*/
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -73,20 +72,14 @@ void blk_set_chains_for_full_print(struct blkid_handle *h)
blk_set_chains_for_wipes(h);
}
void blk_set_chains_for_superblocks(struct blkid_handle *h)
{
#ifdef HAVE_BLKID
blkid_probe_enable_superblocks(h->pr, 1);
blkid_probe_set_superblocks_flags(h->pr, BLKID_SUBLKS_TYPE);
#endif
}
void blk_set_chains_for_fast_detection(struct blkid_handle *h)
{
#ifdef HAVE_BLKID
blkid_probe_enable_partitions(h->pr, 1);
blkid_probe_set_partitions_flags(h->pr, 0);
blk_set_chains_for_superblocks(h);
blkid_probe_enable_superblocks(h->pr, 1);
blkid_probe_set_superblocks_flags(h->pr, BLKID_SUBLKS_TYPE);
#endif
}
@@ -142,34 +135,16 @@ int blk_init_by_fd(struct blkid_handle **h, int fd)
return r;
}
#ifdef HAVE_BLKID
static int blk_superblocks_luks(struct blkid_handle *h, bool enable)
int blk_superblocks_filter_luks(struct blkid_handle *h)
{
int r = -ENOTSUP;
#ifdef HAVE_BLKID
char luks[] = "crypto_LUKS";
char *luks_filter[] = {
luks,
NULL
};
return blkid_probe_filter_superblocks_type(h->pr,
enable ? BLKID_FLTR_ONLYIN : BLKID_FLTR_NOTIN,
luks_filter);
}
#endif
int blk_superblocks_filter_luks(struct blkid_handle *h)
{
int r = -ENOTSUP;
#ifdef HAVE_BLKID
r = blk_superblocks_luks(h, false);
#endif
return r;
}
int blk_superblocks_only_luks(struct blkid_handle *h)
{
int r = -ENOTSUP;
#ifdef HAVE_BLKID
r = blk_superblocks_luks(h, true);
r = blkid_probe_filter_superblocks_type(h->pr, BLKID_FLTR_NOTIN, luks_filter);
#endif
return r;
}
@@ -333,15 +308,16 @@ int blk_supported(void)
return r;
}
unsigned blk_get_block_size(struct blkid_handle *h)
off_t blk_get_offset(struct blkid_handle *h)
{
unsigned block_size = 0;
off_t offset_value = -1;
#ifdef HAVE_BLKID
const char *data;
if (!blk_is_superblock(h) || !blkid_probe_has_value(h->pr, "BLOCK_SIZE") ||
blkid_probe_lookup_value(h->pr, "BLOCK_SIZE", &data, NULL) ||
sscanf(data, "%u", &block_size) != 1)
block_size = 0;
const char *offset;
if (blk_is_superblock(h)) {
if (!blkid_probe_lookup_value(h->pr, "SBMAGIC_OFFSET", &offset, NULL))
offset_value = strtoll(offset, NULL, 10);
} else if (blk_is_partition(h) && !blkid_probe_lookup_value(h->pr, "PTMAGIC_OFFSET", &offset, NULL))
offset_value = strtoll(offset, NULL, 10);
#endif
return block_size;
return offset_value;
}

View File

@@ -1,7 +1,7 @@
/*
* blkid probe utilities
*
* Copyright (C) 2018-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2018-2021 Red Hat, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -41,12 +41,9 @@ void blk_set_chains_for_wipes(struct blkid_handle *h);
void blk_set_chains_for_full_print(struct blkid_handle *h);
void blk_set_chains_for_superblocks(struct blkid_handle *h);
void blk_set_chains_for_fast_detection(struct blkid_handle *h);
int blk_superblocks_filter_luks(struct blkid_handle *h);
int blk_superblocks_only_luks(struct blkid_handle *h);
blk_probe_status blk_safeprobe(struct blkid_handle *h);
@@ -64,6 +61,6 @@ int blk_do_wipe(struct blkid_handle *h);
int blk_supported(void);
unsigned blk_get_block_size(struct blkid_handle *h);
off_t blk_get_offset(struct blkid_handle *h);
#endif

View File

@@ -2,8 +2,8 @@
* utils_crypt - cipher utilities for cryptsetup
*
* Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2022 Milan Broz
* Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2021 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -152,50 +152,10 @@ int crypt_parse_pbkdf(const char *s, const char **pbkdf)
return 0;
}
/*
* Thanks Mikulas Patocka for these two char converting functions.
*
* This function is used to load cryptographic keys, so it is coded in such a
* way that there are no conditions or memory accesses that depend on data.
*
* Explanation of the logic:
* (ch - '9' - 1) is negative if ch <= '9'
* ('0' - 1 - ch) is negative if ch >= '0'
* we "and" these two values, so the result is negative if ch is in the range
* '0' ... '9'
* we are only interested in the sign, so we do a shift ">> 8"; note that right
* shift of a negative value is implementation-defined, so we cast the
* value to (unsigned) before the shift --- we have 0xffffff if ch is in
* the range '0' ... '9', 0 otherwise
* we "and" this value with (ch - '0' + 1) --- we have a value 1 ... 10 if ch is
* in the range '0' ... '9', 0 otherwise
* we add this value to -1 --- we have a value 0 ... 9 if ch is in the range '0'
* ... '9', -1 otherwise
* the next line is similar to the previous one, but we need to decode both
* uppercase and lowercase letters, so we use (ch & 0xdf), which converts
* lowercase to uppercase
*/
static int hex_to_bin(unsigned char ch)
{
unsigned char cu = ch & 0xdf;
return -1 +
((ch - '0' + 1) & (unsigned)((ch - '9' - 1) & ('0' - 1 - ch)) >> 8) +
((cu - 'A' + 11) & (unsigned)((cu - 'F' - 1) & ('A' - 1 - cu)) >> 8);
}
static char hex2asc(unsigned char c)
{
return c + '0' + ((unsigned)(9 - c) >> 4 & 0x27);
}
ssize_t crypt_hex_to_bytes(const char *hex, char **result, int safe_alloc)
{
char *bytes;
char buf[3] = "xx\0", *endp, *bytes;
size_t i, len;
int bl, bh;
if (!hex || !result)
return -EINVAL;
len = strlen(hex);
if (len % 2)
@@ -207,59 +167,17 @@ ssize_t crypt_hex_to_bytes(const char *hex, char **result, int safe_alloc)
return -ENOMEM;
for (i = 0; i < len; i++) {
bh = hex_to_bin(hex[i * 2]);
bl = hex_to_bin(hex[i * 2 + 1]);
if (bh == -1 || bl == -1) {
memcpy(buf, &hex[i * 2], 2);
bytes[i] = strtoul(buf, &endp, 16);
if (endp != &buf[2]) {
safe_alloc ? crypt_safe_free(bytes) : free(bytes);
return -EINVAL;
}
bytes[i] = (bh << 4) | bl;
}
*result = bytes;
return i;
}
char *crypt_bytes_to_hex(size_t size, const char *bytes)
{
unsigned i;
char *hex;
if (size && !bytes)
return NULL;
/* Alloc adds trailing \0 */
if (size == 0)
hex = crypt_safe_alloc(2);
else
hex = crypt_safe_alloc(size * 2 + 1);
if (!hex)
return NULL;
if (size == 0)
hex[0] = '-';
else for (i = 0; i < size; i++) {
hex[i * 2] = hex2asc((const unsigned char)bytes[i] >> 4);
hex[i * 2 + 1] = hex2asc((const unsigned char)bytes[i] & 0xf);
}
return hex;
}
void crypt_log_hex(struct crypt_device *cd,
const char *bytes, size_t size,
const char *sep, int numwrap, const char *wrapsep)
{
unsigned i;
for (i = 0; i < size; i++) {
if (wrapsep && numwrap && i && !(i % numwrap))
crypt_logf(cd, CRYPT_LOG_NORMAL, wrapsep);
crypt_logf(cd, CRYPT_LOG_NORMAL, "%c%c%s",
hex2asc((const unsigned char)bytes[i] >> 4),
hex2asc((const unsigned char)bytes[i] & 0xf), sep);
}
}
bool crypt_is_cipher_null(const char *cipher_spec)
{
if (!cipher_spec)

View File

@@ -2,8 +2,8 @@
* utils_crypt - cipher utilities for cryptsetup
*
* Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2022 Milan Broz
* Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2021 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -25,8 +25,6 @@
#include <stdbool.h>
struct crypt_device;
#define MAX_CIPHER_LEN 32
#define MAX_CIPHER_LEN_STR "31"
#define MAX_KEYFILES 32
@@ -39,10 +37,6 @@ int crypt_parse_integrity_mode(const char *s, char *integrity,
int crypt_parse_pbkdf(const char *s, const char **pbkdf);
ssize_t crypt_hex_to_bytes(const char *hex, char **result, int safe_alloc);
char *crypt_bytes_to_hex(size_t size, const char *bytes);
void crypt_log_hex(struct crypt_device *cd,
const char *bytes, size_t size,
const char *sep, int numwrap, const char *wrapsep);
bool crypt_is_cipher_null(const char *cipher_spec);

View File

@@ -3,8 +3,8 @@
*
* Copyright (C) 2004 Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2022 Milan Broz
* Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2021 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -351,7 +351,7 @@ int device_open_excl(struct crypt_device *cd, struct device *device, int flags)
else {
/* open(2) with O_EXCL (w/o O_CREAT) on regular file is undefined behaviour according to man page */
/* coverity[toctou] */
device->dev_fd_excl = open(path, O_RDONLY | O_EXCL); /* lgtm[cpp/toctou-race-condition] */
device->dev_fd_excl = open(path, O_RDONLY | O_EXCL);
if (device->dev_fd_excl < 0)
return errno == EBUSY ? -EBUSY : device->dev_fd_excl;
if (fstat(device->dev_fd_excl, &st) || !S_ISBLK(st.st_mode)) {

View File

@@ -1,8 +1,8 @@
/*
* Metadata on-disk locking for processes serialization
*
* Copyright (C) 2016-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2022 Ondrej Kozina
* Copyright (C) 2016-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2021 Ondrej Kozina
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -229,7 +229,7 @@ static void release_lock_handle(struct crypt_device *cd, struct crypt_lock_handl
!stat(res, &buf_b) && /* does path file still exist? */
same_inode(buf_a, buf_b)) { /* is it same id as the one referenced by fd? */
/* coverity[toctou] */
if (unlink(res)) /* yes? unlink the file. lgtm[cpp/toctou-race-condition] */
if (unlink(res)) /* yes? unlink the file */
log_dbg(cd, "Failed to unlink resource file: %s", res);
}
@@ -240,7 +240,7 @@ static void release_lock_handle(struct crypt_device *cd, struct crypt_lock_handl
!stat(res, &buf_b) && /* does path file still exist? */
same_inode(buf_a, buf_b)) { /* is it same id as the one referenced by fd? */
/* coverity[toctou] */
if (unlink(res)) /* yes? unlink the file. lgtm[cpp/toctou-race-condition] */
if (unlink(res)) /* yes? unlink the file */
log_dbg(cd, "Failed to unlink resource file: %s", res);
}

View File

@@ -1,8 +1,8 @@
/*
* Metadata on-disk locking for processes serialization
*
* Copyright (C) 2016-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2022 Ondrej Kozina
* Copyright (C) 2016-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2021 Ondrej Kozina
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

Some files were not shown because too many files have changed in this diff Show More