Compare commits

..

77 Commits

Author SHA1 Message Date
Milan Broz
7500a8dfc6 Update README for version 2.7.3. 2024-06-17 14:24:31 +02:00
Milan Broz
aaaff70999 Update cryptsetup.pot. 2024-06-17 14:05:50 +02:00
Milan Broz
7f3387ce27 Add CONTRIBUTING.md file. 2024-06-17 14:04:40 +02:00
Milan Broz
89c0808dcb Add release notes for 2.7.3. 2024-06-17 13:56:40 +02:00
Yuri Chornoivan
5fe366ede6 po: update uk.po (from translationproject.org) 2024-06-11 12:32:37 +02:00
Remus-Gabriel Chelu
9b0283aef8 po: update ro.po (from translationproject.org) 2024-06-11 12:32:37 +02:00
Jakub Bogusz
d3df14064a po: update pl.po (from translationproject.org) 2024-06-11 12:32:37 +02:00
Hiroshi Takekawa
f6ef7d06bc po: update ja.po (from translationproject.org) 2024-06-11 12:32:37 +02:00
Roland Illig
c628a37422 po: update de.po (from translationproject.org) 2024-06-11 12:32:37 +02:00
Petr Pisar
a22335b03c po: update cs.po (from translationproject.org) 2024-06-11 12:32:37 +02:00
Milan Broz
a0fb414bc2 Set version 2.7.3. 2024-06-06 21:13:07 +02:00
Milan Broz
6c95dfe76d tests: Fix test numbers in compat-test2 again 2024-06-06 21:09:08 +02:00
Milan Broz
81747508b4 Fix warning for printf argument. 2024-06-06 21:04:53 +02:00
Ondrej Kozina
457389972f Add opal test for detached header erase command. 2024-06-06 21:04:35 +02:00
Ondrej Kozina
9c59e8e7e5 Simplify LUKS2_wipe_header_areas.
For LUKS2 headers with non zero data offset LUKS2_wipe_header_areas
will always erase the smallest from following:

- metadata device size
- data offset value
- maximal LUKS2 metadata size (twice 2 MiBs json area including 128 MiB for
binary keyslot areas) even with detached header.

For zero value data offset (LUKS2 header can not be restored back to
data device), we erase up to smallest from the following values:

- metadata device size
- maximal LUKS2 metadata size (twice 2 MiBs json area including 128 MiB for
2024-06-06 21:04:05 +02:00
Milan Broz
e806276dca Fix interactive query retry if LUKS2 unbound keyslot is present
If an unbound keyslot is present (e.g.. slot 0 usual slot, slot 1 unbound),
the query loop could return ENOENT (keyslot not valid for segment) and this
will stop epxected retry for slot quewry (--tries option).

If any previous slot rerutned EPERM (no valid passphrase), prefer
this return code.
2024-06-06 21:03:28 +02:00
Milan Broz
7de4782e95 Rename TOKEN to KEY_DESC to be used in different context later. 2024-06-06 21:02:17 +02:00
Milan Broz
0fe16a7cdb Allow "capi:" cipher format for benchmark command.
Note, currently AEAD modes are not supported.
2024-06-06 20:58:14 +02:00
Milan Broz
4c90d7adf9 Fix bad parsing of capi:xts(aes)-plain
Corrent logic confuses it with aes-plain (capi:xts(aes)-plain
does not work in luksFormat).
For CAPI format we need to skip this test.
2024-06-06 20:58:00 +02:00
Milan Broz
7222547d7c Support aes-hctr2 mode.
The HCTR2 encryption was added to Linux kernel for fscrypt,
but as it is length-preserving mode (with sector tweak) it
can be easily used for disk encryption too.

As it need larger IV of size 32 bytes, we need to add exception
for aes-hctr2[-plain64] to be accepted in cryptsetup commands.

Fixes: #883
2024-06-06 20:57:44 +02:00
Milan Broz
04f64dbc02 Use SPDX license identifiers.
This patch switches code to SPDX one-line license identifiers according to
https://spdx.dev/learn/handling-license-info/
and replacing long license text headers.

I used C++ format on the first line in style
// SPDX-License-Identifier: <id>
except exported libcryptsetup.h, when only C comments are used.

The only additional changes are:
- switch backend utf8.c from LGPL2+ to LGPL2.1+ (as in systemd)
- add some additional formatting lines.
2024-06-06 20:56:45 +02:00
Milan Broz
db980ba1c6 Opal: Check for bogus logical size also in activation
For existing devices we only print warning, but the device is
probably completely misconfigured.
2024-06-06 20:51:48 +02:00
Milan Broz
c281241544 Opal: Require locking range attributes in range check function.
The check will be required mandatory in the next patch.
2024-06-06 20:51:30 +02:00
Milan Broz
888da12d17 Opal: Do not allow format if device and Opal logical block size disagrees
Some Opal devices contain a bug that device reports different logical
size for block device and Opal SED layer.

This can happen for NVMe after reformatting with different LBAF (512/4096).

We will not support such configuration as Opal then calculates sizes
differently for locking range (that could lead to data corruption or
a partially unecrypted area).
2024-06-06 20:51:10 +02:00
Daniel Zatovic
49b298f6be CI: Add Samsung 980 PRO OPAL test on trantor machine 2024-06-06 20:50:52 +02:00
Milan Broz
8edf930ec0 Fix string.h, strings.h and stdio.h include in crypto backend.
String.h and stdbool.h are already included in main backend header,
no need to include them again.

Stdio.h is missing for OpenSSL and NSS backed (for sprintf).

Strings.h is missing for cipher_generic, gcrypt and OpoenSSL (strcasecmp).

Fixes: #885
2024-06-06 20:50:35 +02:00
Milan Broz
8c8eb6bc4f Mention need for possible PSID reset for some OPAL drives in man page.
Fixes: #879
2024-06-06 20:50:15 +02:00
Milan Broz
13fa86c62f bitlk: Ignore TPM key metadata
Using TPM entry on Linux is impossible, as we will never have
the same PCRs, so we can quietly ignore these entries without
warnings.
2024-06-06 20:49:57 +02:00
Milan Broz
ef653d00a7 bitlk: Ignore unknown VMK entry 24
This VMK value looks like a password hint (masked email?)
we can safely ignore it.

Fixes: #886
2024-06-06 20:49:39 +02:00
Milan Broz
a92efc358a tests: Use only PBKDF2 in api-test-2 images (FIPS with OpenSSL 3.2+)
For compatimage2 also add keyslot 1 that uses Argon2id PBKDF2 to keep
check for compatibility on non-fips system.
2024-06-06 20:49:21 +02:00
Milan Broz
2c47798cea tests: Use only PBKDF2 in luks2_keyslot_unassigned.img (FIPS with OpenSSL 3.2+) 2024-06-06 20:49:03 +02:00
Milan Broz
32243879f8 tests: Fix redundant test number in compat-test2 2024-06-06 20:48:45 +02:00
Milan Broz
be912143c4 tests: Skip zoned test if kernel does not support it
Zoned block device support can be disabled (as in RHEL8),
skip particular test if scsi_Debug does not create device.
(Modprobe does not return any error code, just kernel message
as parameter is actually supported, but block layer lack
support for zoned device.)
2024-06-06 20:48:29 +02:00
Milan Broz
57c49ef631 tests: Remove leftover debug parameter. 2024-06-06 20:48:10 +02:00
Daniel Zatovic
d8de98d2bc CI: make OPAL tests run at the end
Once OPAL tests run, the whole pipeline gets marked as uninterruptible
(because of the uninterruptible OPAL job). Therefore a duplicate
pipeline gets started on e.g. MR change. Move OPAL jobs to test-opal
stage which runs at the end.
2024-06-06 20:47:51 +02:00
Ondrej Kozina
14c723465f Use crypt_wipe to zero rest of data device. 2024-06-06 20:47:28 +02:00
Ondrej Kozina
799dadc148 Use proper write_buffer in LUKS1 reencryption code.
The raw write() syscal may write less bytes than requested. We
have write_buffer in utils_io.c that handles it properly.
2024-06-06 20:47:09 +02:00
Ondrej Kozina
2796fa1cdd Use proper read_buffer function from utils.
Legacy LUKS1 reencryption used custom read buffer
function. Use implementation from utils_io instead.
2024-06-06 20:46:50 +02:00
Milan Broz
125be1430a Detect unsupported zoned devices for LUKS header device.
Zoned device cannot be written with direct-io
and cannot be used for LUKS header logic without
significant changes. Do not allow to use them for LUKS header
but allow it for data device, as dm-crypt supports it.

Fixes: #877
2024-06-06 20:46:27 +02:00
Ondrej Kozina
92a761e32c Fix various coverity issues.
Mostly INTEGER_OVERFLOW (CWE-190).
2024-06-06 20:46:05 +02:00
Milan Broz
5fb3a0e854 Avoid divide by zero in uint64_mult_overflow.
This function is used with block size, where 0 does
not make sense, so failing the check is the simple way
to avoid sividion by zero.

In reality, this should never happen, but it was seen
in (unreproducible) fuzzing input.
2024-06-06 20:45:35 +02:00
Milan Broz
30af820205 Version 2.7.2 final. 2024-04-09 12:03:57 +02:00
Milan Broz
84d3820a2f Add warning about OPAL admin PIN to man page and release notes. 2024-04-09 11:51:19 +02:00
Milan Broz
53044370e3 Version 2.7.2. 2024-04-08 22:46:47 +02:00
Milan Broz
29d13c4a45 Add 2.7.2 release notes. 2024-04-08 22:37:11 +02:00
Milan Broz
c0735f94c4 tests: print OPAL device parameters in test envirenment if specified 2024-04-08 22:37:02 +02:00
Daniel Zatovic
e15975d4ef CI: add WD PC SN740 OPAL drive job 2024-04-08 22:36:46 +02:00
Antonio Ceballos
7a9afb51ae po: update es.po (from translationproject.org) 2024-04-04 14:56:28 +02:00
Ondrej Kozina
95c7316860 Compile --disable-hw-opal variant. 2024-04-04 14:56:09 +02:00
Ondrej Kozina
29366ae05a Do not check passphrase quality in-before erase.
The passphrase (Admin PIN) already exists and there's no
reason to check quiality of it.
2024-04-04 14:55:56 +02:00
Milan Broz
e52e41d2f7 Relicense older script to LGPL fro GPL2.0 only.
(As I am sole author here.)
2024-04-04 14:55:42 +02:00
Milan Broz
5b10bcfbc4 FAQ: update license version to CC BY-SA 4.0.
With email approval from Arno Wagner dated March 29, 2024:

 From: Arno Wagner
 To: Milan Broz
 Subject: Re: cryuptsetup FAQ license

  Hi Milan,

  fine for me. You can change it directly.

  Arno

  On Wed, Mar 27, 2024 at 13:38:36 CET, Milan Broz wrote:
  > Hi Arno,
  >
  > the FAQ in cryptsetup is licensed under CC-BY-SA-3.0 that is no longer a recent version - https://creativecommons.org/licenses/by-sa/3.0/
  >
  > I use CC-BY-SA-4.0 (https://creativecommons.org/licenses/by-sa/4.0/deed.en) for LUKS2 docs and think it is the best option for docs.
  >
  > Do you agree with updating the license to CC-BY-SA-4.0 for the FAQ.md file? (I, as coauthor, obviously agree :-)
  >
  > Thanks,
  > Milan
2024-04-04 14:55:29 +02:00
Ondrej Kozina
daf6d7402a Fix invalid assert for hw-opal data segment keys.
hw-opal segment does not receive volume key for data
encryption, unlike crypt segment or hw-opal-crypt segment.
It gets key encryption key that is passed to device fw which
later unlocks the locking range key sealed in the device.

The assert may be skipped while volume key is not set.

Fixes: #875.
2024-04-04 14:55:12 +02:00
Ondrej Kozina
37ffd30d07 Fix data segment length compensation on misaligned partitions.
While properly calculated data segment needed compensation due to
misaligned partition (locking range had to be truncated),
we passed wrong value (original partition size) to LUKS2 metadata.

It has to use calculated locking range length in bytes.

Fixes: #873.
2024-04-04 14:54:51 +02:00
Daniel Zatovic
737d8495ad CI: make OPAL jobs uninterruptible 2024-04-04 14:54:36 +02:00
Ondrej Kozina
cde779ccd3 Add --hw-opal-factory-reset switch in erase options explicitly. 2024-04-04 14:54:18 +02:00
Ondrej Kozina
dddb2f7d3c Check HW OPAL range parameters in proper units.
The opal_range_check_attributes_fd function expected both
offset and length parameters of a LR to be passed in sectors (512B).
During format we passed it wrongly in OPAL blocks which caused
bogus check provided OPAL block size was not 512B.

Fixes: #871.
2024-04-04 14:54:02 +02:00
Daniel Zatovic
87fe3fb602 tests: run systemd tests using meson only when requested 2024-04-04 14:53:31 +02:00
Milan Broz
ca50f2cd33 Version 2.7.1. 2024-03-07 15:47:06 +01:00
Milan Broz
d5559df2cc tests: Fix Makefile * Meson to include all fs images. 2024-03-07 15:39:12 +01:00
Milan Broz
a2d820649b Update LUKS2 spec. 2024-03-07 15:27:52 +01:00
Milan Broz
94286c387f Add 2.7.1 release notes. 2024-03-07 15:27:44 +01:00
Milan Broz
2c53e71415 test: Fix tests on RHEL7 clones (no keyring in dm-crypt). 2024-03-07 14:26:46 +01:00
Milan Broz
2f0e804fd1 Add xfs V5 image to tests.
XFS V4 can be disabled in kernel, add image V5.

Minimal 300M xfs size avoided by using QA variables magic in format:
export TEST_DIR=1 TEST_DEV=1 QA_CHECK_FS=1 ; mkfs -t xfs ...
2024-03-07 14:26:34 +01:00
Ondrej Kozina
d478e09f2e tests: fix compat-test-opal bug for empty LUKS2 passphrase.
The bug was hidden due to previously contradicting condition.
2024-03-07 14:26:22 +01:00
Ondrej Kozina
0645219c9d tests: move luks1 decryption resume test.
It cannot be run in fips mode due to empty passphrase
is no longer allowed.
2024-03-07 14:26:09 +01:00
Ondrej Kozina
ba7973236b tests: fix fips mode detection contradiction in various tests. 2024-03-07 14:25:53 +01:00
Yuri Chornoivan
5d6bcc2c3b po: update uk.po (from translationproject.org) 2024-03-06 09:53:01 +01:00
Remus-Gabriel Chelu
05b16f73f9 po: update ro.po (from translationproject.org) 2024-03-06 09:53:01 +01:00
Jakub Bogusz
60274f1fcf po: update pl.po (from translationproject.org) 2024-03-06 09:53:01 +01:00
Hiroshi Takekawa
f8b4931bb1 po: update ja.po (from translationproject.org) 2024-03-06 09:53:01 +01:00
Frédéric Marchal
cb59aeb85a po: update fr.po (from translationproject.org) 2024-03-06 09:53:01 +01:00
Roland Illig
2f72f227b5 po: update de.po (from translationproject.org) 2024-03-06 09:53:01 +01:00
Petr Pisar
004419e1d6 po: update cs.po (from translationproject.org) 2024-03-06 09:53:01 +01:00
Ondrej Kozina
5c3dba8688 Add regression test for resuming LUKS1 decryption. 2024-03-06 09:52:55 +01:00
Ondrej Kozina
25e3adab7e Fix regression in LUKS1 decryption.
With removal of cryptsetup-reencrypt there was
a bug introduced that broke resuming interrupted
LUKS1 decryption operation. LUKS2 code was not
affected.
2024-03-06 09:52:44 +01:00
Milan Broz
bbdf692104 Set version 2.7.1-rc0. 2024-02-29 20:45:28 +01:00
370 changed files with 21417 additions and 35041 deletions

View File

@@ -5,9 +5,9 @@ set -ex
PACKAGES=(
git make autoconf automake autopoint pkg-config libtool libtool-bin
gettext libssl-dev libdevmapper-dev libpopt-dev uuid-dev libsepol-dev
libjson-c-dev libssh-dev libblkid-dev tar libargon2-dev libpwquality-dev
sharutils dmsetup jq xxd expect keyutils netcat-openbsd passwd openssh-client
sshpass asciidoctor meson ninja-build
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 meson ninja-build
)
COMPILER="${COMPILER:?}"

View File

@@ -16,11 +16,11 @@ jobs:
fail-fast: false
matrix:
env:
- { COMPILER: "gcc", COMPILER_VERSION: "14", RUN_SSH_PLUGIN_TEST: "1" }
- { COMPILER: "gcc", COMPILER_VERSION: "13", RUN_SSH_PLUGIN_TEST: "1" }
env: ${{ matrix.env }}
steps:
- name: Repository checkout
uses: actions/checkout@v4
uses: actions/checkout@v1
- name: Ubuntu setup
run: sudo -E .github/workflows/cibuild-setup-ubuntu.sh
- name: Configure & Make

View File

@@ -29,25 +29,21 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
queries: +security-extended,security-and-quality
config-file: .codeql-config.yml
- name: Install dependencies
run: |
sudo -E .github/workflows/cibuild-setup-ubuntu.sh
# Force autoconf for now, meson is broken in analysis step
rm meson.build
env: { COMPILER: "gcc", COMPILER_VERSION: "14", RUN_SSH_PLUGIN_TEST: "1" }
run: sudo -E .github/workflows/cibuild-setup-ubuntu.sh
env: { COMPILER: "gcc", COMPILER_VERSION: "13", RUN_SSH_PLUGIN_TEST: "1" }
- name: Autobuild
uses: github/codeql-action/autobuild@v3
uses: github/codeql-action/autobuild@v2
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
uses: github/codeql-action/analyze@v2

View File

@@ -12,12 +12,12 @@ jobs:
if: github.repository == 'mbroz/cryptsetup'
steps:
- name: Repository checkout
uses: actions/checkout@v4
uses: actions/checkout@v1
- name: Ubuntu setup
run: sudo -E .github/workflows/cibuild-setup-ubuntu.sh
env:
COMPILER: "gcc"
COMPILER_VERSION: "14"
COMPILER_VERSION: "13"
- name: Install Coverity
run: |
wget -q https://scan.coverity.com/download/cxx/linux64 --post-data "token=$TOKEN&project=mbroz/cryptsetup" -O cov-analysis-linux64.tar.gz

1
.gitignore vendored
View File

@@ -17,7 +17,6 @@ ABOUT-NLS
aclocal.m4
autom4te.cache/
compile
compile_commands.json
config.guess
config.h
config.h.in

View File

@@ -10,14 +10,14 @@ include:
- local: .gitlab/ci/debian.yml
- local: .gitlab/ci/fedora.yml
- local: .gitlab/ci/fedora-opal.yml
- local: .gitlab/ci/rhel.yml
- local: .gitlab/ci/centos.yml
# - local: .gitlab/ci/annocheck.yml
- local: .gitlab/ci/annocheck.yml
- local: .gitlab/ci/csmock.yml
- local: .gitlab/ci/gitlab-shared-docker.yml
- local: .gitlab/ci/compilation-various-disables.yml
- local: .gitlab/ci/compilation-gcc.gitlab-ci.yml
- local: .gitlab/ci/compilation-clang.gitlab-ci.yml
- local: .gitlab/ci/compilation-spellcheck.yml
- local: .gitlab/ci/alpinelinux.yml
- local: .gitlab/ci/debian-i686.yml
- local: .gitlab/ci/cifuzz.yml

View File

@@ -7,10 +7,8 @@
- >
sudo apk add
lvm2-dev openssl-dev popt-dev util-linux-dev json-c-dev
argon2-dev device-mapper which sharutils gettext-dev argp-standalone automake
argon2-dev device-mapper which sharutils gettext gettext-dev automake
autoconf libtool build-base keyutils tar jq expect git asciidoctor
# Be sure we have updated basic tools and system
- sudo apk upgrade gcc binutils build-base musl
- ./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

View File

@@ -1,32 +0,0 @@
#!/bin/bash
set -e
SAVED_PWD=$(pwd)
GIT_DIR="$SAVED_PWD/upstream_git"
SPEC="$GIT_DIR/misc/fedora/cryptsetup.spec"
rm -fr $GIT_DIR
git clone -q --depth 1 https://gitlab.com/cryptsetup/cryptsetup.git $GIT_DIR
cd $GIT_DIR
GIT_COMMIT=$(git rev-parse --short=8 HEAD)
[ -z "$GIT_COMMIT" ] && exit 1
sed -i "s/^AC_INIT.*/AC_INIT([cryptsetup],[$GIT_COMMIT])/" $GIT_DIR/configure.ac
sed -i "s/^Version:.*/Version: $GIT_COMMIT/" $SPEC
sed -i "s/%{version_no_tilde}/$GIT_COMMIT/" $SPEC
sed -i "2i %global source_date_epoch_from_changelog 0" $SPEC
sed -i "3i %define _unpackaged_files_terminate_build 0" $SPEC
./autogen.sh
./configure
make -j dist
rpmbuild --define "_sourcedir $GIT_DIR" --define "_srcrpmdir $SAVED_PWD" -bs $SPEC
cd $SAVED_PWD
rm -fr $GIT_DIR
exit 0

View File

@@ -1,16 +1,16 @@
.centos-openssl-backend:
variables:
DISTRO: cryptsetup-centos-stream-9
extends:
- .fail_if_coredump_generated
before_script:
- sudo dnf clean all
- >
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 swtpm swtpm-tools
tpm2-tools
expect gettext git jq keyutils openssl-devel openssl gem
- sudo gem install asciidoctor
- sudo -E git clean -xdf
- ./autogen.sh
@@ -27,9 +27,7 @@ test-main-commit-centos-stream9:
stage: test
interruptible: true
variables:
DISTRO: cryptsetup-centos-stream-9
RUN_SSH_PLUGIN_TEST: "1"
RUN_KEYRING_TRUSTED_TEST: "1"
rules:
- if: $RUN_SYSTEMD_PLUGIN_TEST != null
when: never
@@ -50,55 +48,7 @@ test-mergerq-centos-stream9:
stage: test
interruptible: true
variables:
DISTRO: cryptsetup-centos-stream-9
RUN_SSH_PLUGIN_TEST: "1"
RUN_KEYRING_TRUSTED_TEST: "1"
rules:
- if: $RUN_SYSTEMD_PLUGIN_TEST != null
when: never
- 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-centos-stream10:
extends:
- .centos-openssl-backend
tags:
- libvirt
- cryptsetup-centos-stream-10
stage: test
interruptible: true
variables:
DISTRO: cryptsetup-centos-stream-10
RUN_SSH_PLUGIN_TEST: "1"
RUN_KEYRING_TRUSTED_TEST: "1"
rules:
- if: $RUN_SYSTEMD_PLUGIN_TEST != null
when: never
- 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-stream10:
extends:
- .centos-openssl-backend
tags:
- libvirt
- cryptsetup-centos-stream-10
stage: test
interruptible: true
variables:
DISTRO: cryptsetup-centos-stream-10
RUN_SSH_PLUGIN_TEST: "1"
RUN_KEYRING_TRUSTED_TEST: "1"
rules:
- if: $RUN_SYSTEMD_PLUGIN_TEST != null
when: never

View File

@@ -5,7 +5,7 @@ set -ex
PACKAGES=(
git make autoconf automake autopoint pkg-config libtool libtool-bin
gettext libssl-dev libdevmapper-dev libpopt-dev uuid-dev libsepol-dev
libjson-c-dev libssh-dev libblkid-dev tar libargon2-dev libpwquality-dev
libjson-c-dev libssh-dev libblkid-dev tar libargon2-0-dev libpwquality-dev
sharutils dmsetup jq xxd expect keyutils netcat-openbsd passwd openssh-client
sshpass asciidoctor
)
@@ -13,12 +13,9 @@ PACKAGES=(
COMPILER="${COMPILER:?}"
COMPILER_VERSION="${COMPILER_VERSION:?}"
sed -i 's/^Types: deb$/Types: deb deb-src/' /etc/apt/sources.list.d/ubuntu.sources
# use this on older Ubuntu
# grep -E '^deb' /etc/apt/sources.list > /etc/apt/sources.list~
# sed -Ei 's/^deb /deb-src /' /etc/apt/sources.list~
# cat /etc/apt/sources.list~ >> /etc/apt/sources.list
grep -E '^deb' /etc/apt/sources.list > /etc/apt/sources.list~
sed -Ei 's/^deb /deb-src /' /etc/apt/sources.list~
cat /etc/apt/sources.list~ >> /etc/apt/sources.list
apt-get -y update --fix-missing
DEBIAN_FRONTEND=noninteractive apt-get -yq install software-properties-common wget lsb-release
@@ -31,7 +28,7 @@ if [[ $COMPILER == "gcc" ]]; then
PACKAGES+=(gcc-$COMPILER_VERSION)
elif [[ $COMPILER == "clang" ]]; then
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
add-apt-repository -n "deb http://apt.llvm.org/${RELEASE}/ llvm-toolchain-${RELEASE}-${COMPILER_VERSION} main"
add-apt-repository "deb http://apt.llvm.org/${RELEASE}/ llvm-toolchain-${RELEASE}-${COMPILER_VERSION} main"
# scan-build
PACKAGES+=(clang-tools-$COMPILER_VERSION clang-$COMPILER_VERSION lldb-$COMPILER_VERSION lld-$COMPILER_VERSION clangd-$COMPILER_VERSION)
@@ -40,8 +37,14 @@ else
exit 1
fi
#apt-get -y update --fix-missing
(r=3;while ! apt-get -y update --fix-missing ; do ((--r))||exit;sleep 5;echo "Retrying";done)
apt-get -y update --fix-missing
DEBIAN_FRONTEND=noninteractive apt-get -yq install "${PACKAGES[@]}"
apt-get -y build-dep cryptsetup
echo "====================== VERSIONS ==================="
if [[ $COMPILER == "clang" ]]; then
echo "Using scan-build${COMPILER_VERSION:+-$COMPILER_VERSION}"
fi
${COMPILER}-$COMPILER_VERSION -v
echo "====================== END VERSIONS ==================="

View File

@@ -4,85 +4,27 @@ test-clang-compilation:
script:
- export CFLAGS="-Wall -Werror"
- ./autogen.sh
- $CC --version
- ./configure
- make -j
- make -j check-programs
test-clang-Wall-script-ubuntu:
test-clang-Wall-script:
extends:
- .gitlab-shared-clang
script:
- export CFLAGS="-g -O0"
- export CC="$CI_PROJECT_DIR/.gitlab/ci/clang-Wall"
- ./autogen.sh
- $CC --version
- ./configure
- make -j CFLAGS="-g -O0 -Werror"
- make -j CFLAGS="-g -O0 -Werror" check-programs
test-clang-Wall-script-alpine:
extends:
- .gitlab-shared-clang-alpine
allow_failure: true
script:
- export CFLAGS="-g -O0"
- export CC="$CI_PROJECT_DIR/.gitlab/ci/clang-Wall"
- ./autogen.sh
- $CC --version
- ./configure
- make -j CFLAGS="-g -O0 -Werror"
- make -j CFLAGS="-g -O0 -Werror" check-programs
test-scan-build-ubuntu:
test-scan-build:
extends:
- .gitlab-shared-clang
script:
- ./autogen.sh
- echo "scan-build${COMPILER_VERSION:+-$COMPILER_VERSION}"
- scan-build${COMPILER_VERSION:+-$COMPILER_VERSION} -V ./configure CFLAGS="-g -O0"
- 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
test-scan-build-alpine:
extends:
- .gitlab-shared-clang-alpine
allow_failure: true
script:
- ./autogen.sh
- echo "scan-build${COMPILER_VERSION:+-$COMPILER_VERSION}"
- scan-build${COMPILER_VERSION:+-$COMPILER_VERSION} -V ./configure CFLAGS="-g -O0"
- 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
test-scan-build-backends:
extends:
- .gitlab-shared-clang
parallel:
matrix:
- BACKENDS: [
"openssl",
"gcrypt",
"nss",
"kernel",
"nettle",
"mbedtls"
]
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$/
changes:
- lib/crypto_backend/*
script:
- DEBIAN_FRONTEND=noninteractive apt-get -yq install libgcrypt20-dev libnss3-dev nettle-dev libmbedtls-dev
- ./autogen.sh
- echo "Configuring with crypto backend $BACKENDS"
- echo "scan-build${COMPILER_VERSION:+-$COMPILER_VERSION}"
- scan-build${COMPILER_VERSION:+-$COMPILER_VERSION} -V ./configure CFLAGS="-g -O0" --with-crypto_backend=$BACKENDS
- 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
- ./tests/vectors-test

View File

@@ -4,82 +4,27 @@ test-gcc-compilation:
script:
- export CFLAGS="-Wall -Werror"
- ./autogen.sh
- $CC --version
- ./configure
- make -j
- make -j check-programs
test-gcc-Wall-script-ubuntu:
test-gcc-Wall-script:
extends:
- .gitlab-shared-gcc
script:
- export CFLAGS="-g -O0"
- export CC="$CI_PROJECT_DIR/.gitlab/ci/gcc-Wall"
- ./autogen.sh
- $CC --version
- ./configure
- make -j CFLAGS="-g -O0 -Werror"
- make -j CFLAGS="-g -O0 -Werror" check-programs
test-gcc-Wall-script-alpine:
test-gcc-fanalyzer:
extends:
- .gitlab-shared-gcc-alpine
allow_failure: true
- .gitlab-shared-gcc
script:
- export CFLAGS="-g -O0"
- export CC="$CI_PROJECT_DIR/.gitlab/ci/gcc-Wall"
- export CFLAGS="-Wall -Werror -g -O0 -fanalyzer -fdiagnostics-path-format=separate-events"
- ./autogen.sh
- $CC --version
- ./configure
- make -j CFLAGS="-g -O0 -Werror"
- make -j CFLAGS="-g -O0 -Werror" check-programs
test-gcc-fanalyzer-ubuntu:
extends:
- .gitlab-shared-gcc
script:
- ./autogen.sh
- $CC --version
- ./configure CFLAGS="-Wall -Werror -g -O0 -fanalyzer -fdiagnostics-path-format=separate-events" --host=x86_64
- make -j
- make -j check-programs
test-gcc-fanalyzer-alpine:
extends:
- .gitlab-shared-gcc-alpine
allow_failure: true
script:
- ./autogen.sh
- $CC --version
- ./configure CFLAGS="-Wall -Werror -g -O0 -fanalyzer -fdiagnostics-path-format=separate-events -Wno-analyzer-fd-leak" --host=x86_64
- make -j
- make -j check-programs
test-gcc-fanalyzer-backends:
extends:
- .gitlab-shared-gcc
parallel:
matrix:
- BACKENDS: [
"openssl",
"gcrypt",
"nss",
"kernel",
"nettle",
"mbedtls"
]
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$/
changes:
- lib/crypto_backend/*
script:
- DEBIAN_FRONTEND=noninteractive apt-get -yq install libgcrypt20-dev libnss3-dev nettle-dev libmbedtls-dev
- ./autogen.sh
- $CC --version
- echo "Configuring with crypto backend $BACKENDS"
- ./configure CFLAGS="-Wall -Werror -g -O0 -fanalyzer -fdiagnostics-path-format=separate-events" --host=x86_64 --with-crypto_backend=$BACKENDS
- make -j
- make -j check-programs
- ./tests/vectors-test

View File

@@ -1,20 +0,0 @@
test-run-spellcheck:
image: ubuntu:noble
tags:
- gitlab-org-docker
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$/
artifacts:
name: "spellcheck-$CI_COMMIT_REF_NAME"
paths:
- _spellcheck
before_script:
- apt-get -y update --fix-missing
- apt-get -y install git lintian codespell
script:
- echo "Running spellcheck"
- .gitlab/ci/spellcheck

View File

@@ -1,36 +1,25 @@
.dnf-csmock:
variables:
DISTRO: cryptsetup-fedora-rawhide
DISK_SIZE: 20
extends:
- .fail_if_coredump_generated
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.x86_64 pkgconfig tar uuid-devel git
openssl-devel asciidoctor meson ninja-build
rpm-build csmock
test-commit-job-csmock:
extends:
- .dnf-csmock
- .fail_if_coredump_generated
tags:
- libvirt
- cryptsetup-fedora-rawhide
- cryptsetup-rhel-9
stage: test
interruptible: true
allow_failure: true
variables:
DISTRO: cryptsetup-rhel-9
RUN_SSH_PLUGIN_TEST: "1"
DISK_SIZE: 20
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:
- .gitlab/ci/build_srpm
- .gitlab/ci/run_csmock
- sudo /opt/run-csmock.sh
artifacts:
# Upload artifacts when a crash makes the job fail.
when: always
paths:
- cryptsetup-csmock-results.tar.xz
- cryptsetup-csmock-results

View File

@@ -3,14 +3,16 @@
- .fail_if_coredump_generated
before_script:
- sudo apt-get -y update
- >
[ -z "$RUN_SYSTEMD_PLUGIN_TEST" ] ||
sudo apt-get -y install -y -qq swtpm meson ninja-build python3-jinja2
gperf libcap-dev libtss2-dev libmount-dev swtpm-tools
- >
sudo apt-get -y install -y -qq git gcc make autoconf automake autopoint
pkgconf libtool libtool-bin gettext libssl-dev libdevmapper-dev
libpopt-dev uuid-dev libsepol-dev libjson-c-dev libssh-dev libblkid-dev
tar libargon2-dev libpwquality-dev sharutils dmsetup jq xxd expect
keyutils netcat-openbsd passwd openssh-client sshpass asciidoctor
swtpm meson ninja-build python3-jinja2 gperf libcap-dev libtss2-dev
libmount-dev swtpm-tools tpm2-tools
- sudo apt-get -y build-dep cryptsetup
- sudo -E git clean -xdf
- ./autogen.sh
@@ -27,7 +29,6 @@ test-mergerq-job-debian:
variables:
DISTRO: cryptsetup-debian-12
RUN_SSH_PLUGIN_TEST: "1"
RUN_KEYRING_TRUSTED_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
@@ -48,7 +49,6 @@ test-main-commit-job-debian:
variables:
DISTRO: cryptsetup-debian-12
RUN_SSH_PLUGIN_TEST: "1"
RUN_KEYRING_TRUSTED_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
@@ -70,7 +70,6 @@ test-mergerq-job-debian-meson:
variables:
DISTRO: cryptsetup-debian-12
RUN_SSH_PLUGIN_TEST: "1"
RUN_KEYRING_TRUSTED_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
@@ -92,7 +91,6 @@ test-main-commit-job-debian-meson:
variables:
DISTRO: cryptsetup-debian-12
RUN_SSH_PLUGIN_TEST: "1"
RUN_KEYRING_TRUSTED_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never

View File

@@ -27,7 +27,6 @@ test-commit-rawhide-samsung980:
- .opal-template-fedora
tags:
- tiber
resource_group: samsung980-on-tiber
interruptible: false
variables:
PCI_PASSTHROUGH_VENDOR_ID: "144d"
@@ -42,43 +41,39 @@ test-mergerq-rawhide-samsung980:
- .opal-template-fedora
tags:
- tiber
resource_group: samsung980-on-tiber
interruptible: false
variables:
PCI_PASSTHROUGH_VENDOR_ID: "144d"
PCI_PASSTHROUGH_DEVICE_ID: "a809"
# WD PC SN740 SDDQNQD-512G-1014 (on tiber machine)
# Disabled on 2025-03-20, seems broken
#test-commit-rawhide-sn740:
# rules:
# - if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
# when: never
# - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
# extends:
# - .opal-template-fedora
# tags:
# - tiber
# resource_group: sn740-on-tiber
# interruptible: false
# variables:
# PCI_PASSTHROUGH_VENDOR_ID: "15b7"
# PCI_PASSTHROUGH_DEVICE_ID: "5017"
#
#test-mergerq-rawhide-sn740:
# rules:
# - if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
# when: never
# - if: $CI_PIPELINE_SOURCE == "merge_request_event"
# extends:
# - .opal-template-fedora
# tags:
# - tiber
# resource_group: sn740-on-tiber
# interruptible: false
# variables:
# PCI_PASSTHROUGH_VENDOR_ID: "15b7"
# PCI_PASSTHROUGH_DEVICE_ID: "5017"
test-commit-rawhide-sn740:
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
extends:
- .opal-template-fedora
tags:
- tiber
interruptible: false
variables:
PCI_PASSTHROUGH_VENDOR_ID: "15b7"
PCI_PASSTHROUGH_DEVICE_ID: "5017"
test-mergerq-rawhide-sn740:
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
extends:
- .opal-template-fedora
tags:
- tiber
interruptible: false
variables:
PCI_PASSTHROUGH_VENDOR_ID: "15b7"
PCI_PASSTHROUGH_DEVICE_ID: "5017"
# Samsung SSD 980 PRO 1TB (on trantor machine)
test-commit-rawhide-samsung980pro:
@@ -90,7 +85,6 @@ test-commit-rawhide-samsung980pro:
- .opal-template-fedora
tags:
- trantor
resource_group: samsung980pro-on-trantor
interruptible: false
variables:
PCI_PASSTHROUGH_VENDOR_ID: "144d"
@@ -105,7 +99,6 @@ test-mergerq-rawhide-samsung980pro:
- .opal-template-fedora
tags:
- trantor
resource_group: samsung980pro-on-trantor
interruptible: false
variables:
PCI_PASSTHROUGH_VENDOR_ID: "144d"
@@ -121,7 +114,6 @@ test-mergerq-rawhide-samsung980pro:
# - .opal-template-fedora
# tags:
# - tiber
# resource_group: umis-on-tiber
# stage: test
# interruptible: false
# variables:
@@ -137,7 +129,6 @@ test-mergerq-rawhide-samsung980pro:
# - .opal-template-fedora
# tags:
# - tiber
# resource_group: umis-on-tiber
# stage: test
# interruptible: false
# variables:

View File

@@ -1,19 +1,22 @@
.dnf-openssl-backend:
variables:
DISTRO: cryptsetup-fedora-rawhide
PKGS: >-
extends:
- .fail_if_coredump_generated
before_script:
- >
[ -z "$RUN_SYSTEMD_PLUGIN_TEST" ] ||
sudo dnf -y -q install
swtpm meson ninja-build python3-jinja2 gperf libcap-devel tpm2-tss-devel
libmount-devel swtpm-tools
- >
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 swtpm meson ninja-build
python3-jinja2 gperf libcap-devel tpm2-tss-devel libmount-devel swtpm-tools
extends:
- .fail_if_coredump_generated
before_script:
- sudo dnf clean all
- (r=3;while ! sudo dnf -y -q install $PKGS ; do ((--r))||exit;sleep 5;echo "Retrying";done)
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
@@ -29,8 +32,6 @@ test-main-commit-job-rawhide:
allow_failure: true
variables:
RUN_SSH_PLUGIN_TEST: "1"
RUN_KEYRING_TRUSTED_TEST: "1"
RUN_SYSTEMD_PLUGIN_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
@@ -51,8 +52,6 @@ test-mergerq-job-rawhide:
allow_failure: true
variables:
RUN_SSH_PLUGIN_TEST: "1"
RUN_KEYRING_TRUSTED_TEST: "1"
RUN_SYSTEMD_PLUGIN_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never

View File

@@ -36,8 +36,7 @@ EXTRA="-Wextra \
-Wmaybe-uninitialized \
-Wvla \
-Wformat-overflow \
-Wformat-truncation \
-Wstringop-overread"
-Wformat-truncation"
exec $GCC $PEDANTIC $CONVERSION \
-Wall $Wuninitialized \

View File

@@ -1,6 +1,5 @@
# Ubuntu
.gitlab-shared-docker-ubuntu:
image: ubuntu:noble
.gitlab-shared-docker:
image: ubuntu:lunar
tags:
- gitlab-org-docker
stage: test
@@ -14,48 +13,18 @@
- export CC="${COMPILER}${COMPILER_VERSION:+-$COMPILER_VERSION}"
- export CXX="${COMPILER}++${COMPILER_VERSION:+-$COMPILER_VERSION}"
# Alpine
.gitlab-shared-docker-alpine:
image: alpine:latest
tags:
- gitlab-org-docker
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$/
before_script:
- apk add bash build-base clang clang-analyzer argp-standalone lvm2-dev openssl-dev popt-dev util-linux-dev json-c-dev device-mapper gettext-dev libssh-dev automake autoconf libtool tar asciidoctor
- export CC="${COMPILER}${COMPILER_VERSION:+-$COMPILER_VERSION}"
- export CXX="${COMPILER}++${COMPILER_VERSION:+-$COMPILER_VERSION}"
.gitlab-shared-gcc:
extends:
- .gitlab-shared-docker-ubuntu
- .gitlab-shared-docker
variables:
COMPILER: "gcc"
COMPILER_VERSION: "14"
CC: "gcc-14"
COMPILER_VERSION: "11"
RUN_SSH_PLUGIN_TEST: "1"
.gitlab-shared-clang:
extends:
- .gitlab-shared-docker-ubuntu
- .gitlab-shared-docker
variables:
COMPILER: "clang"
COMPILER_VERSION: "20"
CC: "clang-20"
.gitlab-shared-gcc-alpine:
extends:
- .gitlab-shared-docker-alpine
variables:
COMPILER: "gcc"
CC: "gcc"
.gitlab-shared-clang-alpine:
extends:
- .gitlab-shared-docker-alpine
variables:
COMPILER: "clang"
CC: "clang"
COMPILER_VERSION: "17"
RUN_SSH_PLUGIN_TEST: "1"

110
.gitlab/ci/rhel.yml Normal file
View File

@@ -0,0 +1,110 @@
.rhel-openssl-backend:
extends:
- .fail_if_coredump_generated
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
- cryptsetup-rhel-8
stage: test
interruptible: true
variables:
DISTRO: cryptsetup-rhel-8
RUN_SSH_PLUGIN_TEST: "1"
rules:
- if: $RUN_SYSTEMD_PLUGIN_TEST != null
when: never
- 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
- cryptsetup-rhel-9
stage: test
interruptible: true
variables:
DISTRO: cryptsetup-rhel-9
RUN_SSH_PLUGIN_TEST: "1"
rules:
- if: $RUN_SYSTEMD_PLUGIN_TEST != null
when: never
- 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
- cryptsetup-rhel-8-fips
stage: test
interruptible: true
variables:
DISTRO: cryptsetup-rhel-8-fips
RUN_SSH_PLUGIN_TEST: "1"
rules:
- if: $RUN_SYSTEMD_PLUGIN_TEST != null
when: never
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
script:
- fips-mode-setup --check || exit 1
- make -j
- make -j -C tests check-programs
- sudo -E make check
test-main-commit-rhel9-fips:
extends:
- .rhel-openssl-backend
tags:
- libvirt
- cryptsetup-rhel-9-fips
stage: test
interruptible: true
allow_failure: true
variables:
DISTRO: cryptsetup-rhel-9-fips
RUN_SSH_PLUGIN_TEST: "1"
rules:
- if: $RUN_SYSTEMD_PLUGIN_TEST != null
when: never
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
script:
- fips-mode-setup --check || exit 1
- make -j
- make -j -C tests check-programs
- sudo -E make check

View File

@@ -1,22 +0,0 @@
#!/bin/bash
CSMOCK="sudo /usr/bin/csmock"
CSMOCK_TOOLS="gcc,clang,cppcheck,shellcheck"
CSMOCK_TXZ="cryptsetup-csmock-results.tar.xz"
CSMOCK_ERR="cryptsetup-csmock-results/scan-results.err"
$CSMOCK cryptsetup-*.src.rpm \
--keep-going --force \
--cswrap-timeout 300 \
--skip-patches \
--tools $CSMOCK_TOOLS \
--output $CSMOCK_TXZ \
--gcc-analyze \
--cppcheck-add-flag=--check-level=exhaustive \
|| { echo "csmock command failed"; exit 2; }
tar xJf $CSMOCK_TXZ $CSMOCK_ERR --strip-components 1 \
&& test -s $CSMOCK_ERR \
&& { echo "csmock discovered important errors"; echo 3; }
exit 0

View File

@@ -1,31 +0,0 @@
#!/bin/bash
set -e
DIR="_spellcheck"
[ ! -d $DIR ] && mkdir $DIR
echo "[SPELLINTIAN]"
git ls-tree -rz --name-only HEAD | grep -Evz -e '\.(pdf|xz)$' -e ^po/ | \
xargs -r0 spellintian | \
grep -v "(duplicate word)" | \
grep -v "docs/" | tee $DIR/spell1.txt
echo "[CODESPELL]"
git ls-tree -rz --name-only HEAD | grep -Evz -e '\.(pdf|xz)$' -e ^po/ | \
xargs -r0 codespell | \
grep -v "EXPCT" | \
grep -v "params, prams" | \
grep -v "pad, padded" | \
grep -v "CIPHER, CHIP" | \
grep -v "gost" | \
grep -v "userA" | \
grep -v "re-use" | \
grep -v "fo ==" | \
grep -v "docs/" | tee $DIR/spell2.txt
[ -s $DIR/spell1.txt ] && exit 1
[ -s $DIR/spell2.txt ] && exit 2
exit 0

View File

@@ -119,7 +119,7 @@ libtool --mode=execute gdb --args ./cryptsetup --debug $@
This will ensure that a properly compiled libcryptsetup file is used.
### Coding style
Cryptsetup uses [Linux kernel coding style](https://cdn.kernel.org/doc/html/latest/process/coding-style.html) for libcryptsetup and tools (where applicable) with some additional notes:
Cryptsetup uses [Linux kernel coding style](https://www.kernel.org/doc/html/latest/process/coding-style.html) for libcryptsetup and tools (where applicable) with some additional notes:
- Use tabulators for indentation; the line should not exceed 100 characters with an 8-character tabulator. Otherwise, use a tab of any length. :-).
- The minimal C standard required is C99.
- The ``goto`` use is allowed only for error path (``goto out`` for common code path, ``goto err`` for specific error code path).
@@ -127,8 +127,7 @@ Cryptsetup uses [Linux kernel coding style](https://cdn.kernel.org/doc/html/late
- Use an elaborative description in the patch header.
- No need to use sign-off-by lines.
- Use name prefixes (``crypt_``, ``LUKS2_`` and similar).
- Avoid extensive preprocessor use (specifically conditional ``#if`` or ``#ifdef`` sections).
- To check detected configuration options stored in config.h, always use ``#if SOMETHING`` (do NOT use ``#ifdef``).
- Avoid extensive preprocessor use (specifically ``#ifdef`` sections).
- Use output only through ``log_err, log_std, log_verbose, log_dbg`` macros.
The ``log_dbg`` is always in English; the others should be wrapped in the ``_()`` macro for translation.
- Use ``assert()`` but only for simple invariants and variables (avoid calling functions).

19
FAQ.md
View File

@@ -38,7 +38,7 @@
LUKS1 and LUKS2.
The LUKS1 on-disk format specification is at
https://cdn.kernel.org/pub/linux/utils/cryptsetup/LUKS_docs/on-disk-format.pdf
https://www.kernel.org/pub/linux/utils/cryptsetup/LUKS_docs/on-disk-format.pdf
The LUKS2 on-disk format specification is at
https://gitlab.com/cryptsetup/LUKS2-docs
@@ -705,12 +705,9 @@
this. The only legitimate reason I can think of is if you want to have
two LUKS devices with the same volume key. Even then, I think it would
be preferable to just use key-slots with the same passphrase, or to use
plain dm-crypt instead.
plain dm-crypt instead. If you really have a good reason, please tell
me. If I am convinced, I will add how to do this here.
Use the --volume-key-file option, like this:
```
cryptsetup luksFormat --volume-key-file keyfile /dev/loop0
```
* **2.12 What are the security requirements for a key read from file?**
@@ -1926,6 +1923,10 @@
Hence, LUKS has no kill option because it would do much more harm than
good.
Still, if you have a good use-case (i.e. non-abstract real-world
situation) where a Nuke-Option would actually be beneficial, please let
me know.
* **5.22 Does cryptsetup open network connections to websites, etc. ?**
@@ -2679,7 +2680,8 @@ can be converted to the raw volume key for example via:
Note that at the time this FAQ item was written, 1.5.4 was the latest
1.5.x version and it has the flaw, i.e. works with the old Whirlpool
version. Possibly later 1.5.x versions will work as well.
version. Possibly later 1.5.x versions will work as well. If not,
please let me know.
The only two ways to access older LUKS containers created with Whirlpool
are to either decrypt with an old gcrypt version that has the flaw or to
@@ -2795,7 +2797,8 @@ can be converted to the raw volume key for example via:
03) Creating your own initrd
The two examples below should give you most of what is needed. This is
tested with LUKS1 and should work with LUKS2 as well.
tested with LUKS1 and should work with LUKS2 as well. If not, please
let me know.
Here is a really minimal example. It does nothing but set up some
things and then drop to an interactive shell. It is perfect to try out

View File

@@ -1,4 +1,4 @@
EXTRA_DIST = README.md SECURITY.md README.licensing CONTRIBUTING.md FAQ.md docs misc autogen.sh
EXTRA_DIST = README.md SECURITY.md COPYING.LGPL CONTRIBUTING.md FAQ.md docs misc autogen.sh
EXTRA_DIST += meson_options.txt \
meson.build \
lib/crypto_backend/argon2/meson.build \
@@ -9,7 +9,6 @@ EXTRA_DIST += meson_options.txt \
scripts/meson.build \
src/meson.build \
tests/meson.build \
tests/fuzz/meson.build \
tokens/meson.build \
tokens/ssh/meson.build
@@ -25,7 +24,8 @@ AM_CPPFLAGS = \
-DLIBDIR=\""$(libdir)"\" \
-DPREFIX=\""$(prefix)"\" \
-DSYSCONFDIR=\""$(sysconfdir)"\" \
-DVERSION=\""$(VERSION)"\"
-DVERSION=\""$(VERSION)"\" \
-DEXTERNAL_LUKS2_TOKENS_PATH=\"${EXTERNAL_LUKS2_TOKENS_PATH}\"
AM_CFLAGS = -Wall
AM_CXXFLAGS = -Wall
AM_LDFLAGS =

View File

@@ -1,20 +0,0 @@
The cryptsetup project does not use the same license for all of the code and documentation.
There is code and documentation under:
* GPL-2.0-or-later - GNU General Public License version 2, or any later version
* LGPL-2.1-or-later WITH cryptsetup-OpenSSL-exception
* LGPL-2.1-or-later - GNU Lesser General Public License 2.1 or any later version,
(with cryptsetup-OpenSSL-exception where applicable)
* Apache-2.0 - Apache License 2.0
* CC-BY-SA-4.0 - Creative Commons Attribution Share Alike 4.0 International
* Public Domain
Please, check the source code for more details.
The ./COPYING file (GPL-2.0-or-later) is the default license for code without
an explicitly defined license.

View File

@@ -30,22 +30,28 @@ which enables users to transport or migrate data seamlessly.
* The latest version of the
[LUKS2 format specification](https://gitlab.com/cryptsetup/LUKS2-docs).
* The latest version of the
[LUKS1 format specification](https://cdn.kernel.org/pub/linux/utils/cryptsetup/LUKS_docs/on-disk-format.pdf).
[LUKS1 format specification](https://www.kernel.org/pub/linux/utils/cryptsetup/LUKS_docs/on-disk-format.pdf).
* [Project home page](https://gitlab.com/cryptsetup/cryptsetup/).
* [Frequently asked questions (FAQ)](https://gitlab.com/cryptsetup/cryptsetup/wikis/FrequentlyAskedQuestions)
Download
--------
Release notes and tarballs are available at
[kernel.org](https://cdn.kernel.org/pub/linux/utils/cryptsetup/).
[kernel.org](https://www.kernel.org/pub/linux/utils/cryptsetup/).
**The latest stable cryptsetup release version is 2.8.1**
* [cryptsetup-2.8.1.tar.xz](https://cdn.kernel.org/pub/linux/utils/cryptsetup/v2.8/cryptsetup-2.8.1.tar.xz)
* Signature [cryptsetup-2.8.1.tar.sign](https://cdn.kernel.org/pub/linux/utils/cryptsetup/v2.8/cryptsetup-2.8.1.tar.sign)
**The latest stable cryptsetup release version is 2.7.3**
* [cryptsetup-2.7.3.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.7/cryptsetup-2.7.3.tar.xz)
* Signature [cryptsetup-2.7.3.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.7/cryptsetup-2.7.3.tar.sign)
_(You need to decompress file first to check signature.)_
* [Cryptsetup 2.8.1 Release Notes](https://cdn.kernel.org/pub/linux/utils/cryptsetup/v2.8/v2.8.1-ReleaseNotes).
* [Cryptsetup 2.7.3 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.7/v2.7.3-ReleaseNotes).
[Previous versions](https://cdn.kernel.org/pub/linux/utils/cryptsetup)
Previous versions
* [Version 2.6.1](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.6/cryptsetup-2.6.1.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.6/cryptsetup-2.6.1.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.5/v2.5.0-ReleaseNotes).
* [Version 1.7.5](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.5.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.5.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/v1.7.5-ReleaseNotes).
Source and API documentation
----------------------------
@@ -70,7 +76,8 @@ Below are the packages needed to build for certain Linux 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 rubygem-asciidoctor
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
```
@@ -81,13 +88,14 @@ sharutils device-mapper jq vim-common expect keyutils netcat shadow-utils openss
**For Debian and Ubuntu**:
```
git gcc make autoconf automake autopoint pkg-config libtool gettext libssl-dev libdevmapper-dev libpopt-dev uuid-dev libsepol-dev libjson-c-dev libssh-dev libblkid-dev tar asciidoctor
git gcc make autoconf automake autopoint pkg-config libtool gettext libssl-dev libdevmapper-dev
libpopt-dev uuid-dev libsepol1-dev libjson-c-dev libssh-dev libblkid-dev tar
Optionally: libargon2-0-dev libpwquality-dev
```
To run the internal testsuite (make check) you also need to install
```
sharutils dmsetup jq xxd expect keyutils netcat-openbsd passwd openssh-client sshpass
sharutils dmsetup jq xxd expect keyutils netcat passwd openssh-client sshpass
```
Note that the list may change as Linux distributions evolve.

View File

@@ -1,9 +1,9 @@
AC_PREREQ([2.67])
AC_INIT([cryptsetup],[2.9.0-git])
AC_INIT([cryptsetup],[2.7.3])
dnl library version from <major>.<minor>.<release>[-<suffix>]
LIBCRYPTSETUP_VERSION=$(echo $PACKAGE_VERSION | cut -f1 -d-)
LIBCRYPTSETUP_VERSION_INFO=23:0:11
LIBCRYPTSETUP_VERSION_INFO=22:0:10
AM_SILENT_RULES([yes])
AC_CONFIG_SRCDIR(src/cryptsetup.c)
@@ -132,6 +132,7 @@ AC_C_BIGENDIAN
AC_TYPE_OFF_T
AC_SYS_LARGEFILE
AC_FUNC_FSEEKO
AC_PROG_GCC_TRADITIONAL
AC_FUNC_STRERROR_R
dnl ==========================================================================
@@ -399,23 +400,6 @@ AC_DEFUN([CONFIGURE_NETTLE], [
NO_FIPS([])
])
AC_DEFUN([CONFIGURE_MBEDTLS], [
AC_CHECK_HEADERS(mbedtls/version.h,,
[AC_MSG_ERROR([You need mbedTLS cryptographic library.])])
saved_LIBS=$LIBS
AC_CHECK_LIB(mbedcrypto, mbedtls_md_init,,
[AC_MSG_ERROR([You need mbedTLS cryptographic library.])])
AC_CHECK_FUNCS(mbedtls_pkcs5_pbkdf2_hmac_ext)
CRYPTO_LIBS=$LIBS
LIBS=$saved_LIBS
CRYPTO_STATIC_LIBS=$CRYPTO_LIBS
use_internal_pbkdf2=0
use_internal_argon2=1
NO_FIPS([])
])
dnl ==========================================================================
saved_LIBS=$LIBS
@@ -498,7 +482,7 @@ fi
dnl Crypto backend configuration.
AC_ARG_WITH([crypto_backend],
AS_HELP_STRING([--with-crypto_backend=BACKEND], [crypto backend (gcrypt/openssl/nss/kernel/nettle/mbedtls) [openssl]]),
AS_HELP_STRING([--with-crypto_backend=BACKEND], [crypto backend (gcrypt/openssl/nss/kernel/nettle) [openssl]]),
[], [with_crypto_backend=openssl])
dnl Kernel crypto API backend needed for benchmark and tcrypt
@@ -518,7 +502,6 @@ case $with_crypto_backend in
nss) CONFIGURE_NSS([]) ;;
kernel) CONFIGURE_KERNEL([]) ;;
nettle) CONFIGURE_NETTLE([]) ;;
mbedtls) CONFIGURE_MBEDTLS([]) ;;
*) AC_MSG_ERROR([Unknown crypto backend.]) ;;
esac
AM_CONDITIONAL(CRYPTO_BACKEND_GCRYPT, test "$with_crypto_backend" = "gcrypt")
@@ -526,7 +509,6 @@ AM_CONDITIONAL(CRYPTO_BACKEND_OPENSSL, test "$with_crypto_backend" = "openssl")
AM_CONDITIONAL(CRYPTO_BACKEND_NSS, test "$with_crypto_backend" = "nss")
AM_CONDITIONAL(CRYPTO_BACKEND_KERNEL, test "$with_crypto_backend" = "kernel")
AM_CONDITIONAL(CRYPTO_BACKEND_NETTLE, test "$with_crypto_backend" = "nettle")
AM_CONDITIONAL(CRYPTO_BACKEND_MBEDTLS, test "$with_crypto_backend" = "mbedtls")
AM_CONDITIONAL(CRYPTO_INTERNAL_PBKDF2, test $use_internal_pbkdf2 = 1)
AC_DEFINE_UNQUOTED(USE_INTERNAL_PBKDF2, [$use_internal_pbkdf2], [Use internal PBKDF2])
@@ -680,36 +662,8 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
])
CFLAGS=$saved_CFLAGS
dnl Force compiler to use zero_call_used_regs("used") to check for the function attribute support.
dnl Otherwise the compiler may falsely advertise it with __has_attribute operator, even though
dnl it does not implement it on some archs.
AC_MSG_CHECKING([for zero_call_used_regs(user)])
saved_CFLAGS=$CFLAGS
CFLAGS="-O0 -Werror"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
void _test_function(void);
__attribute__((zero_call_used_regs("used"))) void _test_function(void) {
volatile int *i; volatile int j = 0; if (j) *i = 0;
}
]],
[[ _test_function() ]]
)],[
AC_DEFINE([HAVE_ATTRIBUTE_ZEROCALLUSEDREGS], 1, [Define to 1 to use __attribute__((zero_call_used_regs("used")))])
AC_MSG_RESULT([yes])
], [
AC_MSG_RESULT([no])
])
CFLAGS=$saved_CFLAGS
AC_MSG_CHECKING([for systemd tmpfiles config directory])
if test "x$prefix" != "xNONE"; then
saved_PKG_CONFIG=$PKG_CONFIG
PKG_CONFIG="$PKG_CONFIG --define-variable=prefix='${prefix}'"
PKG_CHECK_VAR([systemd_tmpfilesdir], [systemd], [tmpfilesdir], [], [systemd_tmpfilesdir=no])
PKG_CONFIG=$saved_PKG_CONFIG
else
PKG_CHECK_VAR([systemd_tmpfilesdir], [systemd], [tmpfilesdir], [], [systemd_tmpfilesdir=no])
fi
PKG_CHECK_VAR([systemd_tmpfilesdir], [systemd], [tmpfilesdir], [], [systemd_tmpfilesdir=no])
AC_MSG_RESULT([$systemd_tmpfilesdir])
AC_SUBST([DEVMAPPER_LIBS])
@@ -823,9 +777,8 @@ CS_NUM_WITH([verity-hash-block], [hash block size for verity mode], [4096])
CS_NUM_WITH([verity-salt-size], [salt size for verity mode], [32])
CS_NUM_WITH([verity-fec-roots], [parity bytes for verity FEC], [2])
AC_ARG_WITH([tmpfilesdir],
AS_HELP_STRING([--with-tmpfilesdir=DIR], [override default path to directory with systemd temporary files]),
[], [with_tmpfilesdir=$systemd_tmpfilesdir])
CS_STR_WITH([tmpfilesdir], [override default path to directory with systemd temporary files], [])
test -z "$with_tmpfilesdir" && with_tmpfilesdir=$systemd_tmpfilesdir
test "x$with_tmpfilesdir" = "xno" || {
CS_ABSPATH([${with_tmpfilesdir}],[with-tmpfilesdir])
DEFAULT_TMPFILESDIR=$with_tmpfilesdir
@@ -844,9 +797,7 @@ test -z "$with_luks2_lock_dir_perms" && with_luks2_lock_dir_perms=0700
DEFAULT_LUKS2_LOCK_DIR_PERMS=$with_luks2_lock_dir_perms
AC_SUBST(DEFAULT_LUKS2_LOCK_DIR_PERMS)
AC_ARG_WITH([luks2-external-tokens-path],
AS_HELP_STRING([--with-luks2-external-tokens-path=DIR], [path to directory with LUKSv2 external token handlers (plugins)]),
[], [with_luks2_external_tokens_path=""])
CS_STR_WITH([luks2-external-tokens-path], [path to directory with LUKSv2 external token handlers (plugins)], [LIBDIR/cryptsetup])
if test -n "$with_luks2_external_tokens_path"; then
CS_ABSPATH([${with_luks2_external_tokens_path}],[with-luks2-external-tokens-path])
EXTERNAL_LUKS2_TOKENS_PATH=$with_luks2_external_tokens_path
@@ -854,17 +805,6 @@ else
EXTERNAL_LUKS2_TOKENS_PATH="\${libdir}/cryptsetup"
fi
AC_SUBST(EXTERNAL_LUKS2_TOKENS_PATH)
dnl We need to define expanded EXTERNAL_LUKS2_TOKENS_PATH, but some other code can depend on prefix=NONE.
dnl Pretend you do not see this hack :-)
saved_prefix=$prefix
saved_exec_prefix=$exec_prefix
test "x$prefix" = "xNONE" && prefix="$ac_default_prefix"
test "x$exec_prefix" = "xNONE" && exec_prefix="$prefix"
expanded_EXTERNAL_LUKS2_TOKENS_PATH=$(eval echo "$EXTERNAL_LUKS2_TOKENS_PATH")
expanded_EXTERNAL_LUKS2_TOKENS_PATH=$(eval echo "$expanded_EXTERNAL_LUKS2_TOKENS_PATH")
AC_DEFINE_UNQUOTED([EXTERNAL_LUKS2_TOKENS_PATH], ["$expanded_EXTERNAL_LUKS2_TOKENS_PATH"], [path to directory with LUKSv2 external token handlers (plugins)])
prefix=$saved_prefix
exec_prefix=$saved_exec_prefix
dnl Override default LUKS format version (for cryptsetup or cryptsetup-reencrypt format actions only).
AC_ARG_WITH([default_luks_format],

View File

@@ -2,7 +2,7 @@
/*
* libcryptsetup API log example
*
* Copyright (C) 2011-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2024 Red Hat, Inc. All rights reserved.
*/
#include <stdio.h>

View File

@@ -2,7 +2,7 @@
/*
* libcryptsetup API - using LUKS device example
*
* Copyright (C) 2011-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2024 Red Hat, Inc. All rights reserved.
*/
#include <stdio.h>

View File

@@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -1,428 +0,0 @@
Attribution-ShareAlike 4.0 International
=======================================================================
Creative Commons Corporation ("Creative Commons") is not a law firm and
does not provide legal services or legal advice. Distribution of
Creative Commons public licenses does not create a lawyer-client or
other relationship. Creative Commons makes its licenses and related
information available on an "as-is" basis. Creative Commons gives no
warranties regarding its licenses, any material licensed under their
terms and conditions, or any related information. Creative Commons
disclaims all liability for damages resulting from their use to the
fullest extent possible.
Using Creative Commons Public Licenses
Creative Commons public licenses provide a standard set of terms and
conditions that creators and other rights holders may use to share
original works of authorship and other material subject to copyright
and certain other rights specified in the public license below. The
following considerations are for informational purposes only, are not
exhaustive, and do not form part of our licenses.
Considerations for licensors: Our public licenses are
intended for use by those authorized to give the public
permission to use material in ways otherwise restricted by
copyright and certain other rights. Our licenses are
irrevocable. Licensors should read and understand the terms
and conditions of the license they choose before applying it.
Licensors should also secure all rights necessary before
applying our licenses so that the public can reuse the
material as expected. Licensors should clearly mark any
material not subject to the license. This includes other CC-
licensed material, or material used under an exception or
limitation to copyright. More considerations for licensors:
wiki.creativecommons.org/Considerations_for_licensors
Considerations for the public: By using one of our public
licenses, a licensor grants the public permission to use the
licensed material under specified terms and conditions. If
the licensor's permission is not necessary for any reason--for
example, because of any applicable exception or limitation to
copyright--then that use is not regulated by the license. Our
licenses grant only permissions under copyright and certain
other rights that a licensor has authority to grant. Use of
the licensed material may still be restricted for other
reasons, including because others have copyright or other
rights in the material. A licensor may make special requests,
such as asking that all changes be marked or described.
Although not required by our licenses, you are encouraged to
respect those requests where reasonable. More considerations
for the public:
wiki.creativecommons.org/Considerations_for_licensees
=======================================================================
Creative Commons Attribution-ShareAlike 4.0 International Public
License
By exercising the Licensed Rights (defined below), You accept and agree
to be bound by the terms and conditions of this Creative Commons
Attribution-ShareAlike 4.0 International Public License ("Public
License"). To the extent this Public License may be interpreted as a
contract, You are granted the Licensed Rights in consideration of Your
acceptance of these terms and conditions, and the Licensor grants You
such rights in consideration of benefits the Licensor receives from
making the Licensed Material available under these terms and
conditions.
Section 1 -- Definitions.
a. Adapted Material means material subject to Copyright and Similar
Rights that is derived from or based upon the Licensed Material
and in which the Licensed Material is translated, altered,
arranged, transformed, or otherwise modified in a manner requiring
permission under the Copyright and Similar Rights held by the
Licensor. For purposes of this Public License, where the Licensed
Material is a musical work, performance, or sound recording,
Adapted Material is always produced where the Licensed Material is
synched in timed relation with a moving image.
b. Adapter's License means the license You apply to Your Copyright
and Similar Rights in Your contributions to Adapted Material in
accordance with the terms and conditions of this Public License.
c. BY-SA Compatible License means a license listed at
creativecommons.org/compatiblelicenses, approved by Creative
Commons as essentially the equivalent of this Public License.
d. Copyright and Similar Rights means copyright and/or similar rights
closely related to copyright including, without limitation,
performance, broadcast, sound recording, and Sui Generis Database
Rights, without regard to how the rights are labeled or
categorized. For purposes of this Public License, the rights
specified in Section 2(b)(1)-(2) are not Copyright and Similar
Rights.
e. Effective Technological Measures means those measures that, in the
absence of proper authority, may not be circumvented under laws
fulfilling obligations under Article 11 of the WIPO Copyright
Treaty adopted on December 20, 1996, and/or similar international
agreements.
f. Exceptions and Limitations means fair use, fair dealing, and/or
any other exception or limitation to Copyright and Similar Rights
that applies to Your use of the Licensed Material.
g. License Elements means the license attributes listed in the name
of a Creative Commons Public License. The License Elements of this
Public License are Attribution and ShareAlike.
h. Licensed Material means the artistic or literary work, database,
or other material to which the Licensor applied this Public
License.
i. Licensed Rights means the rights granted to You subject to the
terms and conditions of this Public License, which are limited to
all Copyright and Similar Rights that apply to Your use of the
Licensed Material and that the Licensor has authority to license.
j. Licensor means the individual(s) or entity(ies) granting rights
under this Public License.
k. Share means to provide material to the public by any means or
process that requires permission under the Licensed Rights, such
as reproduction, public display, public performance, distribution,
dissemination, communication, or importation, and to make material
available to the public including in ways that members of the
public may access the material from a place and at a time
individually chosen by them.
l. Sui Generis Database Rights means rights other than copyright
resulting from Directive 96/9/EC of the European Parliament and of
the Council of 11 March 1996 on the legal protection of databases,
as amended and/or succeeded, as well as other essentially
equivalent rights anywhere in the world.
m. You means the individual or entity exercising the Licensed Rights
under this Public License. Your has a corresponding meaning.
Section 2 -- Scope.
a. License grant.
1. Subject to the terms and conditions of this Public License,
the Licensor hereby grants You a worldwide, royalty-free,
non-sublicensable, non-exclusive, irrevocable license to
exercise the Licensed Rights in the Licensed Material to:
a. reproduce and Share the Licensed Material, in whole or
in part; and
b. produce, reproduce, and Share Adapted Material.
2. Exceptions and Limitations. For the avoidance of doubt, where
Exceptions and Limitations apply to Your use, this Public
License does not apply, and You do not need to comply with
its terms and conditions.
3. Term. The term of this Public License is specified in Section
6(a).
4. Media and formats; technical modifications allowed. The
Licensor authorizes You to exercise the Licensed Rights in
all media and formats whether now known or hereafter created,
and to make technical modifications necessary to do so. The
Licensor waives and/or agrees not to assert any right or
authority to forbid You from making technical modifications
necessary to exercise the Licensed Rights, including
technical modifications necessary to circumvent Effective
Technological Measures. For purposes of this Public License,
simply making modifications authorized by this Section 2(a)
(4) never produces Adapted Material.
5. Downstream recipients.
a. Offer from the Licensor -- Licensed Material. Every
recipient of the Licensed Material automatically
receives an offer from the Licensor to exercise the
Licensed Rights under the terms and conditions of this
Public License.
b. Additional offer from the Licensor -- Adapted Material.
Every recipient of Adapted Material from You
automatically receives an offer from the Licensor to
exercise the Licensed Rights in the Adapted Material
under the conditions of the Adapter's License You apply.
c. No downstream restrictions. You may not offer or impose
any additional or different terms or conditions on, or
apply any Effective Technological Measures to, the
Licensed Material if doing so restricts exercise of the
Licensed Rights by any recipient of the Licensed
Material.
6. No endorsement. Nothing in this Public License constitutes or
may be construed as permission to assert or imply that You
are, or that Your use of the Licensed Material is, connected
with, or sponsored, endorsed, or granted official status by,
the Licensor or others designated to receive attribution as
provided in Section 3(a)(1)(A)(i).
b. Other rights.
1. Moral rights, such as the right of integrity, are not
licensed under this Public License, nor are publicity,
privacy, and/or other similar personality rights; however, to
the extent possible, the Licensor waives and/or agrees not to
assert any such rights held by the Licensor to the limited
extent necessary to allow You to exercise the Licensed
Rights, but not otherwise.
2. Patent and trademark rights are not licensed under this
Public License.
3. To the extent possible, the Licensor waives any right to
collect royalties from You for the exercise of the Licensed
Rights, whether directly or through a collecting society
under any voluntary or waivable statutory or compulsory
licensing scheme. In all other cases the Licensor expressly
reserves any right to collect such royalties.
Section 3 -- License Conditions.
Your exercise of the Licensed Rights is expressly made subject to the
following conditions.
a. Attribution.
1. If You Share the Licensed Material (including in modified
form), You must:
a. retain the following if it is supplied by the Licensor
with the Licensed Material:
i. identification of the creator(s) of the Licensed
Material and any others designated to receive
attribution, in any reasonable manner requested by
the Licensor (including by pseudonym if
designated);
ii. a copyright notice;
iii. a notice that refers to this Public License;
iv. a notice that refers to the disclaimer of
warranties;
v. a URI or hyperlink to the Licensed Material to the
extent reasonably practicable;
b. indicate if You modified the Licensed Material and
retain an indication of any previous modifications; and
c. indicate the Licensed Material is licensed under this
Public License, and include the text of, or the URI or
hyperlink to, this Public License.
2. You may satisfy the conditions in Section 3(a)(1) in any
reasonable manner based on the medium, means, and context in
which You Share the Licensed Material. For example, it may be
reasonable to satisfy the conditions by providing a URI or
hyperlink to a resource that includes the required
information.
3. If requested by the Licensor, You must remove any of the
information required by Section 3(a)(1)(A) to the extent
reasonably practicable.
b. ShareAlike.
In addition to the conditions in Section 3(a), if You Share
Adapted Material You produce, the following conditions also apply.
1. The Adapter's License You apply must be a Creative Commons
license with the same License Elements, this version or
later, or a BY-SA Compatible License.
2. You must include the text of, or the URI or hyperlink to, the
Adapter's License You apply. You may satisfy this condition
in any reasonable manner based on the medium, means, and
context in which You Share Adapted Material.
3. You may not offer or impose any additional or different terms
or conditions on, or apply any Effective Technological
Measures to, Adapted Material that restrict exercise of the
rights granted under the Adapter's License You apply.
Section 4 -- Sui Generis Database Rights.
Where the Licensed Rights include Sui Generis Database Rights that
apply to Your use of the Licensed Material:
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
to extract, reuse, reproduce, and Share all or a substantial
portion of the contents of the database;
b. if You include all or a substantial portion of the database
contents in a database in which You have Sui Generis Database
Rights, then the database in which You have Sui Generis Database
Rights (but not its individual contents) is Adapted Material,
including for purposes of Section 3(b); and
c. You must comply with the conditions in Section 3(a) if You Share
all or a substantial portion of the contents of the database.
For the avoidance of doubt, this Section 4 supplements and does not
replace Your obligations under this Public License where the Licensed
Rights include other Copyright and Similar Rights.
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
c. The disclaimer of warranties and limitation of liability provided
above shall be interpreted in a manner that, to the extent
possible, most closely approximates an absolute disclaimer and
waiver of all liability.
Section 6 -- Term and Termination.
a. This Public License applies for the term of the Copyright and
Similar Rights licensed here. However, if You fail to comply with
this Public License, then Your rights under this Public License
terminate automatically.
b. Where Your right to use the Licensed Material has terminated under
Section 6(a), it reinstates:
1. automatically as of the date the violation is cured, provided
it is cured within 30 days of Your discovery of the
violation; or
2. upon express reinstatement by the Licensor.
For the avoidance of doubt, this Section 6(b) does not affect any
right the Licensor may have to seek remedies for Your violations
of this Public License.
c. For the avoidance of doubt, the Licensor may also offer the
Licensed Material under separate terms or conditions or stop
distributing the Licensed Material at any time; however, doing so
will not terminate this Public License.
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
License.
Section 7 -- Other Terms and Conditions.
a. The Licensor shall not be bound by any additional or different
terms or conditions communicated by You unless expressly agreed.
b. Any arrangements, understandings, or agreements regarding the
Licensed Material not stated herein are separate from and
independent of the terms and conditions of this Public License.
Section 8 -- Interpretation.
a. For the avoidance of doubt, this Public License does not, and
shall not be interpreted to, reduce, limit, restrict, or impose
conditions on any use of the Licensed Material that could lawfully
be made without permission under this Public License.
b. To the extent possible, if any provision of this Public License is
deemed unenforceable, it shall be automatically reformed to the
minimum extent necessary to make it enforceable. If the provision
cannot be reformed, it shall be severed from this Public License
without affecting the enforceability of the remaining terms and
conditions.
c. No term or condition of this Public License will be waived and no
failure to comply consented to unless expressly agreed to by the
Licensor.
d. Nothing in this Public License constitutes or may be interpreted
as a limitation upon, or waiver of, any privileges and immunities
that apply to the Licensor or You, including from the legal
processes of any jurisdiction or authority.
=======================================================================
Creative Commons is not a party to its public
licenses. Notwithstanding, Creative Commons may elect to apply one of
its public licenses to material it publishes and in those instances
will be considered the “Licensor.” The text of the Creative Commons
public licenses is dedicated to the public domain under the CC0 Public
Domain Dedication. Except for the limited purpose of indicating that
material is shared under a Creative Commons public license or as
otherwise permitted by the Creative Commons policies published at
creativecommons.org/policies, Creative Commons does not authorize the
use of the trademark "Creative Commons" or any other trademark or logo
of Creative Commons without its prior written consent including,
without limitation, in connection with any unauthorized modifications
to any of its public licenses or any other arrangements,
understandings, or agreements concerning use of licensed material. For
the avoidance of doubt, this paragraph does not form part of the
public licenses.
Creative Commons may be contacted at creativecommons.org.

View File

@@ -1,354 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
-----
In addition, as a special exception, the copyright holders give
permission to link the code of portions of this program with the
OpenSSL library under certain conditions as described in each
individual source file, and distribute linked combinations
including the two.
You must obey the GNU General Public License in all respects
for all of the code used other than OpenSSL. If you modify
file(s) with this exception, you may extend this exception to your
version of the file(s), but you are not obligated to do so. If you
do not wish to do so, delete this exception statement from your
version. If you delete this exception statement from all source
files in the program, then also delete it here.

Binary file not shown.

View File

@@ -1,62 +0,0 @@
Cryptsetup 2.7.4 Release Notes
==============================
Stable bug-fix release.
All users of cryptsetup 2.7 should upgrade to this version.
Changes since version 2.7.3
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Detect device busy failure for device-mapper table-referenced devices.
Some device-mapper ioctl failures can disappear in libdevmapper,
causing the libcryptsetup wrapper to return an invalid error (EINVAL)
instead of EEXIST or EBUSY. One such case is when there is a device
creation race, and the device-mapper device name is created, but
the following mapping table load fails. This can happen because some
block devices used in table mapping have already been claimed by
another process (the kernel needs exclusive access).
The kernel ioctl properly returns EBUSY; this errno is lost in
libdevmapper (dm_task_get_errno returns 0). It should be fixed by
libdevmapper in the future.
Such behavior was seen in the systemd way of handling dm-verity
devices. With these changes, the code should react for EEXIST and
EBUSY, as another process has already activated the device.
Code calling libcryptsetup also must not check the underlying device
with an exclusive open flag (O_EXCL). Otherwise, it could cause a race
in the kernel device-mapper, resulting in no process succeeding device
activation (see also CRYPT_ACTIVATE_SHARED flag below).
* Fix shared activation for dm-verity devices.
The CRYPT_ACTIVATE_SHARED flag was silently ignored when activating
dm-verity devices. Dm-verity shared activation is generally safe
since all verity devices are read-only.
The shared flag is a way to skip the exclusive access check for the
device, allowing it to create multiple mappings with the same device or
properly handle a racy concurrent activation of devices with the same
name from different processes.
* Add --shared option for veritysetup open action.
The option allows the data device to be used in multiple device-mapper
table mappings (skip exclusive access check) or to allow concurrent
dm-verity device activation of the same device (only one process
succeeds in this case; the other will return EEXIST or EBUSY).
* Do not use exclusive flag for the allocated backing loop files.
Using this flag is an undefined operation for opening an existing file.
The flag should be used only for allocated loop (block) devices.
* Fixes for problems found by static analyzers and Valgrind.
These include fixes for non-default libgcrypt, NSS, and Nettle
cryptographic backends, buffer operations to avoid partial read/write,
and several other workarounds for mostly false positive warnings.
* Fixes to tests and CI scripts.

View File

@@ -1,23 +0,0 @@
Cryptsetup 2.7.5 Release Notes
==============================
Stable bug-fix release.
All users of cryptsetup 2.7 must upgrade to this version.
Changes since version 2.7.4
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Fix possible online reencryption data corruption (only in 2.7.x).
In some situations (initializing a suspended device-mapper device),
cryptsetup disabled direct-io device access. This caused unsafe
online reencryption operations that could lead to data corruption.
The code now adds strict checks (and aborts the operation) and
changes direct-io detection code to prevent data corruption.
* Fix a clang compilation error in SSH token plugin.
As clang linker treats missing symbols as errors, the linker phase
for the SSH token failed as the optional cryptsetup_token_buffer_free
was not defined.
* Fix crypto backend initialization in crypt_format_luks2_opal API call.

View File

@@ -1,328 +0,0 @@
Cryptsetup 2.8.0 Release Notes
==============================
Stable release with new features and bug fixes
All users of cryptsetup 2.7 must upgrade to this version.
Changes since version 2.7.5
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Introduce support for inline mode (use HW sectors with additional hardware metadata space).
Some enterprise NVMe drives allow formatting sector size with additional metadata space,
for example, sector size 4096 bytes + 64 bytes for metadata.
We hope common firmware will soon support such features in more recent models.
If this metadata space is available (not internally used by a data integrity profile),
it removes the need to use the dm-integrity layer for sector metadata allocation.
This means that the performance bottleneck caused by the dm-integrity journal is eliminated.
Note: such drive must be reformatted with an external nvme tool.
You can check for support (reported as LBA format) by running the command
"nvme id-ns -H <nvme device>" and then you can reformat to the selected profile
(with complete data loss) with "nvme format -l <lbaf>.
This way, you can also reformat NVMe drive to 4096-byte sectors,which is strongly recommended
for encryption performance.
The required device mapper for inline mode was introduced in Linux kernel version 6.11.
The inline mode can be used with the new --integrity-inline option.
For integritysetup, the kernel dm-integrity layer is still used, but it directly maps metadata
to the hardware (eliminating the journal).
For cryptsetup, the dm-integrity layer is eliminated, and only the dm-crypt kernel driver is used.
The libcryptsetup exports a new crypt_format_inline API call.
Examples (underlying device must provide inline HW metadata space):
Use integritysetup format with inline mode with default CRC32 checksums:
# integritysetup format --sector-size 4096 --integrity-inline <device> [--no-wipe]
# integritysetup open <device> test
# integritysetup status test
/dev/mapper/test is active.
type: INTEGRITY
tag size: 4 [bytes]
integrity: crc32c
device: <device>
sector size: 4096 [bytes]
...
inline mode
journal: not active
Use LUKS2 with authenticated encryption (here with AEGIS AEAD cipher):
# cryptsetup luksFormat --integrity-inline --integrity aead --sector-size 4096 \
-c aegis128-random --key-size 128 <device> [--integrity-no-wipe]
# cryptsetup open <device> test
# cryptsetup luksDump <device>
...
Requirements: inline-hw-tags
After format, the inline mode is used automatically, and no special options are needed.
Please check the manual pages for more details about used options.
Note that the LUKS2 authenticated encryption is still an experimental feature.
The inline mode only improves performance by removing the dm-integrity layer.
* Finalize use of keyslot context API.
Keyslot context is a generic abstraction over keyslot manipulation.
It extends many exiting commands by additional functions like tokens in activation, resume,
reencryption and similar commands without introducing new specific API functions.
* Make all keyslot context types fully self-contained.
In the previous version, the caller is responsible for releasing of some allocated memory.
In this version, all memory is allocated internally. The existing keyslot context API function
provides backward compatibility through versioned symbols.
* Add --key-description and --new-key-description cryptsetup options.
These can be used for the specification of the keyring with passphrase retrieval in the open,
resize, luksResume, luksFormat, luksAddKey and luksDump.
* Support more precise keyslot selection in reencryption initialization.
Reencryption must update stored keys in keyslots, so it needs to unlock all keyslots first.
When no specific keyslot is selected by the --key-slot option, all active keyslots are updated.
Users may narrow down the selection of keyslots by specifying either --token-id, --token-type
or --token-only option. Only keyslots associated with the specific token (--token-id) or
a specific type (--token-type) or any token (--token-only) will be updated.
All other keyslots will be erased after reencryption is finished.
During reencryption, there are two volume keys (old and new).
For very specific use cases, reencryption can also be initialized by providing
volume keys directly by --volume-key-file, --new-volume-key-file, --volume-key-keyring
or --new-volume-key-keyring options. These options allow reencryption of the device with
no active keyslots (these can be added later).
If the --force-no-keyslots option is specified, all active keyslots will be erased after
the reencryption operation is finished.
* Allow reencryption to resume using token and volume keys.
The reencryption can be resumed using tokens (similar to initialization described above).
For very specific use cases, reencryption can be resumed by providing volume keys.
* Cryptsetup repair command now tries to check LUKS keyslot areas for corruption.
A keyslot binary area contains an encrypted volume key diffused to a larger area by
the anti-forensic splitter. If this area is corrupted, the keyslot can no longer be unlocked,
even with the correct password.
Active keyslot area should look like random data, so some specific corruption can be detected
by randomness analysis.
Cryptsetup repair command now tries to analyze the area expecting a uniform distribution
of bytes in 4096-byte blocks. If a problem is detected, it tries to localize corruption
in a smaller block (using the expected bit count).
Both tests are based on the Chi-squared statistical test.
This analysis can replace the external keyslot check program and usually is more sensitive.
However, it cannot detect all corruptions and can produce false positives.
Please use it as a hint when your password is no longer accepted, and you suspect
header corruption. This is the example output of the analysis:
# cryptsetup repair <device>
Keyslot 2 binary data could be corrupted.
Suspected offset: 0x88000
You can use hexdump -v -C -n 128 -s <offset_0xXXXX> <device> to inspect the data.
The test does not modify the header. A keyslot corruption cannot be repaired.
You have to use a backup header.
* Opal2 SED: PSID keyfile is now expected to be 32 alphanumeric characters.
If the keyfile size is not explicitly set, it uses only first 32 bytes.
All Opal2 manufacturers seem to use PSID of this length.
* Opal2: Avoid the Erase method and use Secure Erase for locking range.
The Erase method is defined for Single-user mode (SUM) and works on SUM-enabled locking ranges.
As we do not use SUM yet, this always fails and falls back to Secure erase anyway.
* Opal2: Fix some error description (in debug only).
Some Opal error messages were incorrect.
Cryptsetup now use all codes according to TCG specifications.
* Opal2: Do not allow deferred deactivation.
The self-encrypting drive must be locked immediately; deferred deactivation is not supported.
* Allow --reduce-device-size and --device-size combination for reencryption (encrypt) action.
For some very specific cases, this can be used to encrypt only part of the device together
with allocation a new space for the LUKS header.
* Fix the userspace storage backend to support kernel "capi:" cipher specification format.
This avoids unnecessary fallback to the device-mapper instead of the userspace crypto library
in luksFormat. The "capi:" is Linux kernel cryptographic format.
For example, capi:xts(aes)-plain64 is equivalent of aes-xts-plain64.
* Disallow conversion from LUKS2 to LUKS1 if kernel "capi:" cipher specification is used.
LUKS1 never officially supported this cipher specification format.
Such devices cannot be converted to LUKS1 (while existing devices can still be activated).
* Explicitly disallow kernel "capi:" cipher specification format for LUKS2 keyslot encryption.
This specification is intended to be used for data encryption, not for keyslots.
* Do not allow conversion of LUKS2 to LUKS1 if an unbound keyslot is present.
LUKS1 does not support unbound keyslots. Such devices cannot be converted.
* cryptsetup: Adjust the XTS key size for kernel "capi:" cipher specification.
Double key size as there are two keys the same way as for dm-crypt format.
* Remove keyslot warning about possible failure due to low memory.
This check was intended to warn users about possible out-of-memory situations
but produced many false positives.
* Do not limit Argon2 KDF memory cost on systems with more than 4GB of available memory.
The memory cost is intended to be limited only in low-memory situations (like virtual machines
without swap), not on systems with plenty of RAM.
* Properly report out of memory error for cryptographic backends implementing Argon2.
* Avoid KDF2 memory cost overflow on 32-bit platforms.
* Do not use page size as a fallback for device block size.
This check produced wrong values if used on platforms with larger page sizes (64kB)
and specific underlying storage (like ZFS).
* veritysetup: Check hash device size in advance.
If hashes are stored in a file image, allocate the size in advance.
For a block device, check if hashes (Merkle tree) fits the device.
* Print a better error message for unsupported LUKS2 AEAD device resize.
* Optimize LUKS2 metadata writes.
LUKS2 supports several JSON area length configurations. Do not write full metadata
(including padding), as it may generate noticeable overhead with LUKS2.
* veritysetup: support --error-as-corruption option.
The panic/restart_on_error options were introduced in Linux kernel 6.12 and process errors
(like media read error) the same way as data corruption.
Use this flag in combination with --panic-on-corruption or --restart-on-corruption.
* Report all sizes in status and dump command output in the correct units.
Since the support of --sector-size option, the meaning of "sectors" became ambiguous as it
usually means 512-byte sectors (device-mapper unit). Confusion occurs when the sector size
is 4096 bytes while units used for display are 512-byte sectors.
All status commands in tools now display units explicitly to avoid confusion.
For example:
# cryptsetup status test
...
sector size: 4096 [bytes]
offset: 32768 [512-byte units] (134217728 [bytes])
size: 7501443760 [512-byte units] (30725913640960 [bytes])
If you parse the output of status commands, please check your scripts to ensure they work
with the new output properly.
* Add --integrity-key-size option to cryptsetup.
This option can be used to set up non-standard integrity key size (e.g. for HMAC).
It adds a new (optional) JSON "key_size" attribute in the segment.integrity JSON object
(see updated LUKS2 specification). If not set, the code uses selected hash length size.
* Support trusted & encrypted keyrings for plain devices.
* Support plain format resize with a keyring key.
If a plain dm-crypt device references the keyring, cryptsetup now allows resizing.
The user must ensure that the key in the keyring is unchanged since activation.
Otherwise, reloading the key can cause data corruption after an unexpected key change.
* TCRYPT: Clear mapping of system-encrypted partitions.
TrueCrypt/VeraCrypt supports full system encryption (only a partition table is not encrypted)
or system partition encryption (only a system partition is encrypted).
The metadata header then contains the offset and size of the encrypted area.
Cryptsetup needs to know the specific partition offset to calculate encryption parameters.
To properly map a partition, the user must specify a real partition device so cryptsetup
can calculate this offset. As the partition can be an image in a file, cryptsetup now tries
to determine proper parameters and use device size stored in VeraCrypt metadata.
Please see the manual page description (TCRYPT section) for a detailed description.
* TCRYPT: Print all information from the decrypted metadata header in the tcryptDump command.
Print also volume sizes (if present) and flags.
* Always lock the volume key structure in memory.
Some memory for safe allocation was not allocated from locked (unswappable) memory.
Older cryptsetup locked all memory. Selective locking was introduced in version 2.6.0.
* Do not run direct-io read check on block devices.
Block devices always support direct-io.
This check produced unnecessary error with locked Opal2 devices.
* Fix a possible segfault in deferred deactivation.
Thanks Clément Guérin for the report.
* Exclude cipher allocation time from the cryptsetup benchmark.
* Add Mbed-TLS optional crypto backend.
Mbed-TLS is a tiny TLS implementation designed for embedded environments.
The backend can be enabled with the --with-crypto_backend=mbedtls configure option.
* Fix the wrong preprocessor use of #ifdef for config.h processed by Meson.
Cryptsetup supports Autoconf and, optionally, Meson configuration.
Part of the code wrongly used #ifdef instead of #if conditional sections.
This caused problems with Meson-generated config.h.
* Reorganize license files.
The license text files are now in docs/licenses.
The COPYING file in the root directory is the default license.
Libcryptsetup API extensions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The libcryptsetup API is backward compatible with all existing symbols.
Due to the self-contained memory allocation, these symbols have the new version
crypt_keyslot_context_init_by_passphrase;
crypt_keyslot_context_init_by_keyfile;
crypt_keyslot_context_init_by_token;
crypt_keyslot_context_init_by_volume_key;
crypt_keyslot_context_init_by_signed_key;
crypt_keyslot_context_init_by_keyring;
crypt_keyslot_context_init_by_vk_in_keyring;
New symbols:
crypt_format_inline
crypt_get_old_volume_key_size
crypt_reencrypt_init_by_keyslot_context
crypt_safe_memcpy
New defines:
CRYPT_ACTIVATE_HIGH_PRIORITY
CRYPT_ACTIVATE_ERROR_AS_CORRUPTION
CRYPT_ACTIVATE_INLINE_MODE
CRYPT_REENCRYPT_CREATE_NEW_DIGEST
New requirement flag:
CRYPT_REQUIREMENT_INLINE_HW_TAGS

View File

@@ -1,40 +0,0 @@
Cryptsetup 2.8.1 Release Notes
==============================
Stable bug-fix release with minor extensions.
All users of cryptsetup 2.8.0 must upgrade to this version.
Changes since version 2.8.0
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Fix status and deactivation of TCRYPT (VeraCrypt compatible) devices that use chained ciphers.
* Fix unlocking BITLK (BitLocker compatible) devices with multibyte UTF8 characters in the passphrase.
* Do not allow activation of the LUKS2 device if the used keyslot is not encrypted (it uses a null cipher).
Such a configuration cannot be created by cryptsetup, but can be crafted outside of it.
Null cipher is sometimes used to create an empty container for later reencryption.
Only an empty passphrase can activate such a container (the same as in LUKS1).
* Do not silently decrease PBKDF parallel cost (threads) if set by an option.
The maximum parallel cost is limited to 4 threads.
* Fixes to configuration and installation scripts.
Meson and autoconf tools now properly support --prefix option for temporary directory installation.
Multiple fixes and cleanups to config.h for compatibility between Meson and autoconf.
Fix the luks2-external-tokens-path Meson option to work the same as in autoconf.
Fix Meson install for tool binaries, install fvault2Open man page and include test/fuzz/meson.build in release.
* Major update to manual pages.
Try to explain the PBKDF hardcoded limits.
Add a better explanation for automatic integrity tag recalculation.
Mention crypt/verity/integritytab.
Remove or reformulate some misleading warnings present only with old and no longer supported kernels.
Clarify that some commands do not wipe data and unify OPAL reset wording.
Clarify the --label option.
There are also many other grammar and stylistic fixes to unify the man-page style.
* Fixes for false-positive and annoying (optional) warnings added in recent compilers.

View File

@@ -2,9 +2,9 @@
/*
* BITLK (BitLocker-compatible) volume handling
*
* Copyright (C) 2019-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2019-2025 Milan Broz
* Copyright (C) 2019-2025 Vojtech Trefny
* Copyright (C) 2019-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2019-2024 Milan Broz
* Copyright (C) 2019-2024 Vojtech Trefny
*/
#include <errno.h>
@@ -111,7 +111,6 @@ struct bitlk_superblock {
struct bitlk_fve_metadata {
/* FVE metadata block header */
uint8_t signature[8];
/* size of this block (in 16-byte units) */
uint16_t fve_size;
uint16_t fve_version;
uint16_t curr_state;
@@ -133,32 +132,6 @@ struct bitlk_fve_metadata {
uint64_t creation_time;
} __attribute__ ((packed));
struct bitlk_validation_hash {
uint16_t size;
uint16_t role;
uint16_t type;
uint16_t flags;
/* likely a hash type code, anything other than 0x2005 isn't supported */
uint16_t hash_type;
uint16_t unknown1;
/* SHA-256 */
uint8_t hash[32];
} __attribute__ ((packed));
struct bitlk_fve_metadata_validation {
/* FVE metadata validation block header */
uint16_t validation_size;
uint16_t validation_version;
uint32_t fve_crc32;
/* this is a single nested structure's header defined here for simplicity */
uint16_t nested_struct_size;
uint16_t nested_struct_role;
uint16_t nested_struct_type;
uint16_t nested_struct_flags;
/* datum containing a similar nested structure (encrypted using VMK) with hash (SHA256) */
uint8_t nested_struct_data[BITLK_VALIDATION_VMK_DATA_SIZE];
} __attribute__ ((packed));
struct bitlk_entry_header_block {
uint64_t offset;
uint64_t size;
@@ -388,54 +361,6 @@ static int parse_vmk_entry(struct crypt_device *cd, uint8_t *data, int start, in
return 0;
}
static bool check_fve_metadata(struct bitlk_fve_metadata *fve)
{
if (memcmp(fve->signature, BITLK_SIGNATURE, sizeof(fve->signature)) || le16_to_cpu(fve->fve_version) != 2 ||
(fve->fve_size << 4) > BITLK_FVE_METADATA_SIZE)
return false;
return true;
}
static bool check_fve_metadata_validation(struct bitlk_fve_metadata_validation *validation)
{
/* only check if there is room for CRC-32, the actual size must be larger */
if (le16_to_cpu(validation->validation_size) < 8 || le16_to_cpu(validation->validation_version > 2))
return false;
return true;
}
static bool parse_fve_metadata_validation(struct bitlk_metadata *params, struct bitlk_fve_metadata_validation *validation)
{
/* extra checks for a nested structure (MAC) and BITLK FVE metadata */
if (le16_to_cpu(validation->validation_size) < sizeof(struct bitlk_fve_metadata_validation))
return false;
if (le16_to_cpu(validation->nested_struct_size != BITLK_VALIDATION_VMK_HEADER_SIZE + BITLK_VALIDATION_VMK_DATA_SIZE) ||
le16_to_cpu(validation->nested_struct_role) != 0 ||
le16_to_cpu(validation->nested_struct_type) != 5)
return false;
/* nonce */
memcpy(params->validation->nonce,
validation->nested_struct_data,
BITLK_NONCE_SIZE);
/* MAC tag */
memcpy(params->validation->mac_tag,
validation->nested_struct_data + BITLK_NONCE_SIZE,
BITLK_VMK_MAC_TAG_SIZE);
/* AES-CCM encrypted datum with SHA256 hash */
memcpy(params->validation->enc_datum,
validation->nested_struct_data + BITLK_NONCE_SIZE + BITLK_VMK_MAC_TAG_SIZE,
BITLK_VALIDATION_VMK_DATA_SIZE - BITLK_NONCE_SIZE - BITLK_VMK_MAC_TAG_SIZE);
return true;
}
void BITLK_bitlk_fvek_free(struct bitlk_fvek *fvek)
{
if (!fvek)
@@ -450,8 +375,10 @@ void BITLK_bitlk_vmk_free(struct bitlk_vmk *vmk)
struct bitlk_vmk *vmk_next = NULL;
while (vmk) {
free(vmk->guid);
free(vmk->name);
if (vmk->guid)
free(vmk->guid);
if (vmk->name)
free(vmk->name);
crypt_free_volume_key(vmk->vk);
vmk_next = vmk->next;
free(vmk);
@@ -465,8 +392,8 @@ void BITLK_bitlk_metadata_free(struct bitlk_metadata *metadata)
return;
free(metadata->guid);
free(metadata->description);
free(metadata->validation);
if (metadata->description)
free(metadata->description);
BITLK_bitlk_vmk_free(metadata->vmks);
BITLK_bitlk_fvek_free(metadata->fvek);
}
@@ -478,25 +405,20 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
struct bitlk_signature sig = {};
struct bitlk_superblock sb = {};
struct bitlk_fve_metadata fve = {};
struct bitlk_fve_metadata_validation validation = {};
struct bitlk_entry_vmk entry_vmk = {};
uint8_t *fve_entries = NULL;
uint8_t *fve_validated_block = NULL;
size_t fve_entries_size = 0;
uint32_t fve_metadata_size = 0;
uint32_t fve_size_real = 0;
int fve_offset = 0;
char guid_buf[UUID_STR_LEN] = {0};
uint16_t entry_size = 0;
uint16_t entry_type = 0;
int i = 0;
int r = 0;
int valid_fve_metadata_idx = -1;
int start = 0;
size_t key_size = 0;
const char *key = NULL;
char *description = NULL;
struct crypt_hash *hash;
struct bitlk_vmk *vmk = NULL;
struct bitlk_vmk *vmk_p = params->vmks;
@@ -571,80 +493,15 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
for (i = 0; i < 3; i++)
params->metadata_offset[i] = le64_to_cpu(sb.fve_offset[i]);
fve_validated_block = malloc(BITLK_FVE_METADATA_SIZE);
if (fve_validated_block == NULL) {
r = -ENOMEM;
goto out;
}
log_dbg(cd, "Reading BITLK FVE metadata of size %zu on device %s, offset %" PRIu64 ".",
sizeof(fve), device_path(device), params->metadata_offset[0]);
for (i = 0; i < 3; i++) {
/* iterate over FVE metadata copies and pick the valid one */
log_dbg(cd, "Reading BITLK FVE metadata copy #%d of size %zu on device %s, offset %" PRIu64 ".",
i, sizeof(fve), device_path(device), params->metadata_offset[i]);
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
device_alignment(device), &fve, sizeof(fve), params->metadata_offset[i]) != sizeof(fve) ||
!check_fve_metadata(&fve) ||
(fve_size_real = le16_to_cpu(fve.fve_size) << 4, read_lseek_blockwise(devfd, device_block_size(cd, device),
device_alignment(device), &validation, sizeof(validation), params->metadata_offset[i] + fve_size_real) != sizeof(validation)) ||
!check_fve_metadata_validation(&validation) ||
/* double-fetch is here, but we aren't validating MAC */
read_lseek_blockwise(devfd, device_block_size(cd, device), device_alignment(device), fve_validated_block, fve_size_real,
params->metadata_offset[i]) != fve_size_real ||
(crypt_crc32(~0, fve_validated_block, fve_size_real) ^ ~0) != le32_to_cpu(validation.fve_crc32)) {
/* found an invalid FVE metadata copy, log and skip */
log_dbg(cd, _("Failed to read or validate BITLK FVE metadata copy #%d from %s."), i, device_path(device));
} else {
/* found a valid FVE metadata copy, use it */
valid_fve_metadata_idx = i;
break;
}
}
if (valid_fve_metadata_idx < 0) {
/* all FVE metadata copies are invalid, fail */
log_err(cd, _("Failed to read and validate BITLK FVE metadata from %s."), device_path(device));
r = -EINVAL;
goto out;
}
/* check that a valid FVE metadata block is in its expected location */
if (params->metadata_offset[valid_fve_metadata_idx] != le64_to_cpu(fve.fve_offset[valid_fve_metadata_idx])) {
log_err(cd, _("Failed to validate the location of BITLK FVE metadata from %s."), device_path(device));
r = -EINVAL;
goto out;
}
/* update offsets from a valid FVE metadata copy */
for (i = 0; i < 3; i++)
params->metadata_offset[i] = le64_to_cpu(fve.fve_offset[i]);
/* check that the FVE metadata hasn't changed between reads, because we are preparing for the MAC check */
if (memcmp(&fve, fve_validated_block, sizeof(fve)) != 0) {
log_err(cd, _("BITLK FVE metadata changed between reads from %s."), device_path(device));
r = -EINVAL;
goto out;
}
crypt_backend_memzero(&params->sha256_fve, 32);
if (crypt_hash_init(&hash, "sha256")) {
log_err(cd, _("Failed to hash BITLK FVE metadata read from %s."), device_path(device));
r = -EINVAL;
goto out;
}
crypt_hash_write(hash, (const char *)fve_validated_block, fve_size_real);
crypt_hash_final(hash, (char *)&params->sha256_fve, 32);
crypt_hash_destroy(hash);
/* do some extended checks against FVE metadata, but not including MAC verification */
params->validation = malloc(sizeof(struct bitlk_validation));
if (!params->validation) {
r = -ENOMEM;
goto out;
}
if (!parse_fve_metadata_validation(params, &validation)) {
log_err(cd, _("Failed to parse BITLK FVE validation metadata from %s."), device_path(device));
/* read FVE metadata from the first metadata area */
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
device_alignment(device), &fve, sizeof(fve), params->metadata_offset[0]) != sizeof(fve) ||
memcmp(fve.signature, BITLK_SIGNATURE, sizeof(fve.signature)) ||
le16_to_cpu(fve.fve_version) != 2) {
log_err(cd, _("Failed to read BITLK FVE metadata from %s."), device_path(device));
r = -EINVAL;
goto out;
}
@@ -729,18 +586,17 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
}
memset(fve_entries, 0, fve_entries_size);
log_dbg(cd, "Getting BITLK FVE metadata entries of size %zu on device %s, offset %" PRIu64 ".",
fve_entries_size, device_path(device), params->metadata_offset[valid_fve_metadata_idx] + BITLK_FVE_METADATA_HEADERS_LEN);
log_dbg(cd, "Reading BITLK FVE metadata entries of size %zu on device %s, offset %" PRIu64 ".",
fve_entries_size, device_path(device), params->metadata_offset[0] + BITLK_FVE_METADATA_HEADERS_LEN);
if (BITLK_FVE_METADATA_HEADERS_LEN + fve_entries_size > fve_size_real) {
log_err(cd, _("Failed to check BITLK metadata entries previously read from %s."), device_path(device));
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
device_alignment(device), fve_entries, fve_entries_size,
params->metadata_offset[0] + BITLK_FVE_METADATA_HEADERS_LEN) != (ssize_t)fve_entries_size) {
log_err(cd, _("Failed to read BITLK metadata entries from %s."), device_path(device));
r = -EINVAL;
goto out;
}
/* fetch these entries from validated buffer to avoid double-fetch */
memcpy(fve_entries, fve_validated_block + BITLK_FVE_METADATA_HEADERS_LEN, fve_entries_size);
while ((fve_entries_size - start) >= (sizeof(entry_size) + sizeof(entry_type))) {
/* size of this entry */
@@ -861,10 +717,10 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
start += entry_size;
}
out:
free(fve_entries);
free(fve_validated_block);
out:
if (fve_entries)
free(fve_entries);
return r;
}
@@ -886,7 +742,7 @@ int BITLK_dump(struct crypt_device *cd, struct device *device, struct bitlk_meta
log_std(cd, "Description: \t%s\n", params->description);
log_std(cd, "Cipher name: \t%s\n", params->cipher);
log_std(cd, "Cipher mode: \t%s\n", params->cipher_mode);
log_std(cd, "Cipher key: \t%u [bits]\n", params->key_size);
log_std(cd, "Cipher key: \t%u bits\n", params->key_size);
log_std(cd, "\n");
@@ -905,15 +761,15 @@ int BITLK_dump(struct crypt_device *cd, struct device *device, struct bitlk_meta
vk_p = vmk_p->vk;
while (vk_p) {
log_std(cd, "\tKey data size:\t%zu [bytes]\n", crypt_volume_key_length(vk_p));
vk_p = crypt_volume_key_next(vk_p);
log_std(cd, "\tKey data size:\t%zu [bytes]\n", vk_p->keylength);
vk_p = vk_p->next;
}
vmk_p = vmk_p->next;
next_id++;
}
log_std(cd, " %d: FVEK\n", next_id);
log_std(cd, "\tKey data size:\t%zu [bytes]\n", crypt_volume_key_length(params->fvek->vk));
log_std(cd, "\tKey data size:\t%zu [bytes]\n", params->fvek->vk->keylength);
log_std(cd, "\n");
@@ -1131,7 +987,6 @@ static int bitlk_kdf(const char *password,
struct crypt_hash *hd = NULL;
int len = 0;
char16_t *utf16Password = NULL;
size_t utf16Len = 0;
int i = 0;
int r = 0;
@@ -1157,8 +1012,7 @@ static int bitlk_kdf(const char *password,
if (r < 0)
goto out;
utf16Len = crypt_char16_strlen(utf16Password);
crypt_hash_write(hd, (char*)utf16Password, utf16Len * 2);
crypt_hash_write(hd, (char*)utf16Password, passwordLen * 2);
r = crypt_hash_final(hd, kdf.initial_sha256, len);
if (r < 0)
goto out;
@@ -1204,14 +1058,11 @@ static int decrypt_key(struct crypt_device *cd,
int r;
uint16_t key_size = 0;
outbuf = crypt_safe_alloc(crypt_volume_key_length(enc_key));
outbuf = crypt_safe_alloc(enc_key->keylength);
if (!outbuf)
return -ENOMEM;
r = crypt_bitlk_decrypt_key(crypt_volume_key_get_key(key),
crypt_volume_key_length(key),
crypt_volume_key_get_key(enc_key), outbuf,
crypt_volume_key_length(enc_key),
r = crypt_bitlk_decrypt_key(key->key, key->keylength, enc_key->key, outbuf, enc_key->keylength,
(const char*)iv, iv_size, (const char*)tag, tag_size);
if (r < 0) {
if (r == -ENOTSUP)
@@ -1222,10 +1073,9 @@ static int decrypt_key(struct crypt_device *cd,
/* key_data has it's size as part of the metadata */
memcpy(&key_size, outbuf, 2);
key_size = le16_to_cpu(key_size);
if (crypt_volume_key_length(enc_key) != key_size) {
if (enc_key->keylength != key_size) {
log_err(cd, _("Unexpected key data size."));
log_dbg(cd, "Expected key data size: %zu, got %" PRIu16 "",
crypt_volume_key_length(enc_key), key_size);
log_dbg(cd, "Expected key data size: %zu, got %" PRIu16 "", enc_key->keylength, key_size);
r = -EINVAL;
goto out;
@@ -1235,7 +1085,7 @@ static int decrypt_key(struct crypt_device *cd,
crypt_get_volume_key_size(cd) == 32) {
/* 128bit AES-CBC with Elephant -- key size is 256 bit (2 keys) but key data is 512 bits,
data: 16B CBC key, 16B empty, 16B elephant key, 16B empty */
crypt_safe_memcpy(outbuf + 16 + BITLK_OPEN_KEY_METADATA_LEN,
memcpy(outbuf + 16 + BITLK_OPEN_KEY_METADATA_LEN,
outbuf + 2 * 16 + BITLK_OPEN_KEY_METADATA_LEN, 16);
key_size = 32 + BITLK_OPEN_KEY_METADATA_LEN;
}
@@ -1259,7 +1109,6 @@ int BITLK_get_volume_key(struct crypt_device *cd,
struct volume_key *open_vmk_key = NULL;
struct volume_key *vmk_dec_key = NULL;
struct volume_key *recovery_key = NULL;
struct bitlk_validation_hash dec_hash = {};
const struct bitlk_vmk *next_vmk = NULL;
next_vmk = params->vmks;
@@ -1285,8 +1134,7 @@ int BITLK_get_volume_key(struct crypt_device *cd,
continue;
}
log_dbg(cd, "Trying to use given password as a recovery key.");
r = bitlk_kdf(crypt_volume_key_get_key(recovery_key),
crypt_volume_key_length(recovery_key),
r = bitlk_kdf(recovery_key->key, recovery_key->keylength,
true, next_vmk->salt, &vmk_dec_key);
crypt_free_volume_key(recovery_key);
if (r)
@@ -1322,36 +1170,6 @@ int BITLK_get_volume_key(struct crypt_device *cd,
}
crypt_free_volume_key(vmk_dec_key);
log_dbg(cd, "Trying to decrypt validation metadata using VMK.");
r = crypt_bitlk_decrypt_key(crypt_volume_key_get_key(open_vmk_key),
crypt_volume_key_length(open_vmk_key),
(const char*)params->validation->enc_datum,
(char *)&dec_hash,
BITLK_VALIDATION_VMK_DATA_SIZE - BITLK_NONCE_SIZE - BITLK_VMK_MAC_TAG_SIZE,
(const char*)params->validation->nonce, BITLK_NONCE_SIZE,
(const char*)params->validation->mac_tag, BITLK_VMK_MAC_TAG_SIZE);
if (r < 0) {
log_dbg(cd, "Failed to decrypt validation metadata using VMK.");
crypt_free_volume_key(open_vmk_key);
if (r == -ENOTSUP)
return r;
break;
}
/* now, do the MAC validation */
if (le16_to_cpu(dec_hash.role) != 0 ||le16_to_cpu(dec_hash.type) != 1 ||
(le16_to_cpu(dec_hash.hash_type) != 0x2005)) {
log_dbg(cd, "Failed to parse decrypted validation metadata.");
crypt_free_volume_key(open_vmk_key);
return -ENOTSUP;
}
if (memcmp(dec_hash.hash, params->sha256_fve, sizeof(dec_hash.hash)) != 0) {
log_dbg(cd, "Failed MAC validation of BITLK FVE metadata.");
crypt_free_volume_key(open_vmk_key);
return -EINVAL;
}
r = decrypt_key(cd, open_fvek_key, params->fvek->vk, open_vmk_key,
params->fvek->mac_tag, BITLK_VMK_MAC_TAG_SIZE,
params->fvek->nonce, BITLK_NONCE_SIZE, true);
@@ -1394,7 +1212,7 @@ static int _activate_check(struct crypt_device *cd,
next_vmk = params->vmks;
while (next_vmk) {
if (next_vmk->protection == BITLK_PROTECTION_CLEAR_KEY) {
log_err(cd, _("Activation of BITLK device with clear key protection is not supported."));
log_err(cd, _("Activation of partially decrypted BITLK device is not supported."));
return -ENOTSUP;
}
next_vmk = next_vmk->next;
@@ -1423,7 +1241,7 @@ static int _activate(struct crypt_device *cd,
uint64_t next_start = 0;
uint64_t next_end = 0;
uint64_t last_segment = 0;
uint64_t dmt_flags = 0;
uint32_t dmt_flags = 0;
r = _activate_check(cd, params);
if (r)
@@ -1547,7 +1365,7 @@ static int _activate(struct crypt_device *cd,
crypt_get_cipher_spec(cd),
segments[i].iv_offset,
segments[i].iv_offset,
NULL, 0, 0,
NULL, 0,
params->sector_size);
if (r)
goto out;
@@ -1583,17 +1401,54 @@ out:
return r;
}
int BITLK_activate_by_volume_key(struct crypt_device *cd,
int BITLK_activate_by_passphrase(struct crypt_device *cd,
const char *name,
struct volume_key *vk,
const char *password,
size_t passwordLen,
const struct bitlk_metadata *params,
uint32_t flags)
{
int r;
int r = 0;
struct volume_key *open_fvek_key = NULL;
r = _activate_check(cd, params);
if (r)
return r;
return _activate(cd, name, vk, params, flags);
r = BITLK_get_volume_key(cd, password, passwordLen, params, &open_fvek_key);
if (r < 0)
goto out;
/* Password verify only */
if (!name)
goto out;
r = _activate(cd, name, open_fvek_key, params, flags);
out:
crypt_free_volume_key(open_fvek_key);
return r;
}
int BITLK_activate_by_volume_key(struct crypt_device *cd,
const char *name,
const char *volume_key,
size_t volume_key_size,
const struct bitlk_metadata *params,
uint32_t flags)
{
int r = 0;
struct volume_key *open_fvek_key = NULL;
r = _activate_check(cd, params);
if (r)
return r;
open_fvek_key = crypt_alloc_volume_key(volume_key_size, volume_key);
if (!open_fvek_key)
return -ENOMEM;
r = _activate(cd, name, open_fvek_key, params, flags);
crypt_free_volume_key(open_fvek_key);
return r;
}

View File

@@ -2,9 +2,9 @@
/*
* BITLK (BitLocker-compatible) header definition
*
* Copyright (C) 2019-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2019-2025 Milan Broz
* Copyright (C) 2019-2025 Vojtech Trefny
* Copyright (C) 2019-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2019-2024 Milan Broz
* Copyright (C) 2019-2024 Vojtech Trefny
*/
#ifndef _CRYPTSETUP_BITLK_H
@@ -21,8 +21,6 @@ struct volume_key;
#define BITLK_NONCE_SIZE 12
#define BITLK_SALT_SIZE 16
#define BITLK_VMK_MAC_TAG_SIZE 16
#define BITLK_VALIDATION_VMK_HEADER_SIZE 8
#define BITLK_VALIDATION_VMK_DATA_SIZE 72
#define BITLK_STATE_NORMAL 0x0004
@@ -87,13 +85,6 @@ struct bitlk_fvek {
struct volume_key *vk;
};
struct bitlk_validation {
uint8_t mac_tag[BITLK_VMK_MAC_TAG_SIZE];
uint8_t nonce[BITLK_NONCE_SIZE];
/* technically, this is not "VMK", but some sources call it this way */
uint8_t enc_datum[BITLK_VALIDATION_VMK_DATA_SIZE];
};
struct bitlk_metadata {
uint16_t sector_size;
uint64_t volume_size;
@@ -110,10 +101,8 @@ struct bitlk_metadata {
uint32_t metadata_version;
uint64_t volume_header_offset;
uint64_t volume_header_size;
const char *sha256_fve[32];
struct bitlk_vmk *vmks;
struct bitlk_fvek *fvek;
struct bitlk_validation *validation;
};
int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params);
@@ -126,9 +115,17 @@ int BITLK_get_volume_key(struct crypt_device *cd,
const struct bitlk_metadata *params,
struct volume_key **open_fvek_key);
int BITLK_activate_by_passphrase(struct crypt_device *cd,
const char *name,
const char *password,
size_t passwordLen,
const struct bitlk_metadata *params,
uint32_t flags);
int BITLK_activate_by_volume_key(struct crypt_device *cd,
const char *name,
struct volume_key *vk,
const char *volume_key,
size_t volume_key_size,
const struct bitlk_metadata *params,
uint32_t flags);

View File

@@ -10,13 +10,13 @@
#include <stdint.h>
#include <sys/param.h>
#if HAVE_BYTESWAP_H
#if defined(HAVE_BYTESWAP_H)
# include <byteswap.h>
#endif
#if HAVE_ENDIAN_H
#if defined(HAVE_ENDIAN_H)
# include <endian.h>
#elif HAVE_SYS_ENDIAN_H /* BSDs have them here */
#elif defined(HAVE_SYS_ENDIAN_H) /* BSDs have them here */
# include <sys/endian.h>
#endif

View File

@@ -3,8 +3,8 @@
* cryptsetup plain device helper functions
*
* Copyright (C) 2004 Jana Saout <jana@saout.de>
* Copyright (C) 2010-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2025 Milan Broz
* Copyright (C) 2010-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2024 Milan Broz
*/
#include <string.h>
@@ -92,7 +92,7 @@ int crypt_plain_hash(struct crypt_device *cd,
log_dbg(cd, "Too short plain passphrase.");
return -EINVAL;
}
crypt_safe_memcpy(key, passphrase, hash_size);
memcpy(key, passphrase, hash_size);
r = 0;
} else
r = hash(hash_name_buf, hash_size, key, passphrase_size, passphrase);

View File

@@ -13,8 +13,7 @@ libcrypto_backend_la_SOURCES = \
lib/crypto_backend/utf8.c \
lib/crypto_backend/argon2_generic.c \
lib/crypto_backend/cipher_generic.c \
lib/crypto_backend/cipher_check.c \
lib/crypto_backend/memutils.c
lib/crypto_backend/cipher_check.c
if CRYPTO_BACKEND_GCRYPT
libcrypto_backend_la_SOURCES += lib/crypto_backend/crypto_gcrypt.c
@@ -31,9 +30,6 @@ endif
if CRYPTO_BACKEND_NETTLE
libcrypto_backend_la_SOURCES += lib/crypto_backend/crypto_nettle.c
endif
if CRYPTO_BACKEND_MBEDTLS
libcrypto_backend_la_SOURCES += lib/crypto_backend/crypto_mbedtls.c
endif
if CRYPTO_INTERNAL_PBKDF2
libcrypto_backend_la_SOURCES += lib/crypto_backend/pbkdf2_generic.c

View File

@@ -360,7 +360,7 @@ int blake2b_long(void *pout, size_t outlen, const void *in, size_t inlen) {
TRY(blake2b_final(&blake_state, out, outlen));
} else {
uint32_t toproduce;
uint8_t out_buffer[BLAKE2B_OUTBYTES] = {0};
uint8_t out_buffer[BLAKE2B_OUTBYTES];
uint8_t in_buffer[BLAKE2B_OUTBYTES];
TRY(blake2b_init(&blake_state, BLAKE2B_OUTBYTES));
TRY(blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes)));

View File

@@ -128,7 +128,7 @@ void secure_wipe_memory(void *v, size_t n) {
void secure_wipe_memory(void *v, size_t n) {
memset_s(v, n, 0, n);
}
#elif HAVE_EXPLICIT_BZERO
#elif defined(HAVE_EXPLICIT_BZERO)
void secure_wipe_memory(void *v, size_t n) {
explicit_bzero(v, n);
}
@@ -356,9 +356,12 @@ static int fill_memory_blocks_mt(argon2_instance_t *instance) {
}
fail:
free(thread);
free(thr_data);
if (thread != NULL) {
free(thread);
}
if (thr_data != NULL) {
free(thr_data);
}
return rc;
}

View File

@@ -83,7 +83,7 @@
static int b64_byte_to_char(unsigned x) {
return (LT(x, 26) & (x + 'A')) |
(GE(x, 26) & LT(x, 52) & (x + ('a' - 26))) |
(GE(x, 52) & LT(x, 62) & (x - (52 - '0'))) | (EQ(x, 62) & '+') |
(GE(x, 52) & LT(x, 62) & (x + ('0' - 52))) | (EQ(x, 62) & '+') |
(EQ(x, 63) & '/');
}

View File

@@ -2,8 +2,8 @@
/*
* Argon2 PBKDF2 library wrapper
*
* Copyright (C) 2016-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2025 Milan Broz
* Copyright (C) 2016-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2024 Milan Broz
*/
#include <errno.h>

View File

@@ -5,7 +5,7 @@
* Copyright (C) 2010 Lennart Poettering
*
* cryptsetup related changes
* Copyright (C) 2021-2025 Milan Broz
* Copyright (C) 2021-2024 Milan Broz
*/
#include <errno.h>
@@ -19,7 +19,7 @@
/* https://tools.ietf.org/html/rfc4648#section-4 */
static char base64char(int x)
{
static const char table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
return table[x & 63];

View File

@@ -2,8 +2,8 @@
/*
* Cipher performance check
*
* Copyright (C) 2018-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2018-2025 Milan Broz
* Copyright (C) 2018-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2018-2024 Milan Broz
*/
#include <errno.h>
@@ -42,36 +42,43 @@ static int time_ms(struct timespec *start, struct timespec *end, double *ms)
return 0;
}
static int cipher_perf_one(struct crypt_cipher_kernel *cipher, char *buffer, size_t buffer_size,
const char *iv, size_t iv_size, int enc)
static int cipher_perf_one(const char *name, const char *mode, char *buffer, size_t buffer_size,
const char *key, size_t key_size, const char *iv, size_t iv_size, int enc)
{
struct crypt_cipher_kernel cipher;
size_t done = 0, block = CIPHER_BLOCK_BYTES;
int r;
if (buffer_size < block)
block = buffer_size;
r = crypt_cipher_init_kernel(&cipher, name, mode, key, key_size);
if (r < 0)
return r;
while (done < buffer_size) {
if ((done + block) > buffer_size)
block = buffer_size - done;
if (enc)
r = crypt_cipher_encrypt_kernel(cipher, &buffer[done], &buffer[done],
r = crypt_cipher_encrypt_kernel(&cipher, &buffer[done], &buffer[done],
block, iv, iv_size);
else
r = crypt_cipher_decrypt_kernel(cipher, &buffer[done], &buffer[done],
r = crypt_cipher_decrypt_kernel(&cipher, &buffer[done], &buffer[done],
block, iv, iv_size);
if (r < 0)
return r;
break;
done += block;
}
return 0;
}
crypt_cipher_destroy_kernel(&cipher);
static int cipher_measure(struct crypt_cipher_kernel *cipher, char *buffer, size_t buffer_size,
const char *iv, size_t iv_size, int encrypt, double *ms)
return r;
}
static int cipher_measure(const char *name, const char *mode, char *buffer, size_t buffer_size,
const char *key, size_t key_size, const char *iv, size_t iv_size,
int encrypt, double *ms)
{
struct timespec start, end;
int r;
@@ -83,7 +90,7 @@ static int cipher_measure(struct crypt_cipher_kernel *cipher, char *buffer, size
if (clock_gettime(CLOCK_MONOTONIC_RAW, &start) < 0)
return -EINVAL;
r = cipher_perf_one(cipher, buffer, buffer_size, iv, iv_size, encrypt);
r = cipher_perf_one(name, mode, buffer, buffer_size, key, key_size, iv, iv_size, encrypt);
if (r < 0)
return r;
@@ -111,20 +118,15 @@ int crypt_cipher_perf_kernel(const char *name, const char *mode, char *buffer, s
const char *key, size_t key_size, const char *iv, size_t iv_size,
double *encryption_mbs, double *decryption_mbs)
{
struct crypt_cipher_kernel cipher;
double ms_enc, ms_dec, ms;
int r, repeat_enc, repeat_dec;
r = crypt_cipher_init_kernel(&cipher, name, mode, key, key_size);
if (r < 0)
return r;
ms_enc = 0.0;
repeat_enc = 1;
while (ms_enc < 1000.0) {
r = cipher_measure(&cipher, buffer, buffer_size, iv, iv_size, 1, &ms);
r = cipher_measure(name, mode, buffer, buffer_size, key, key_size, iv, iv_size, 1, &ms);
if (r < 0)
goto out;
return r;
ms_enc += ms;
repeat_enc++;
}
@@ -132,9 +134,9 @@ int crypt_cipher_perf_kernel(const char *name, const char *mode, char *buffer, s
ms_dec = 0.0;
repeat_dec = 1;
while (ms_dec < 1000.0) {
r = cipher_measure(&cipher, buffer, buffer_size, iv, iv_size, 0, &ms);
r = cipher_measure(name, mode, buffer, buffer_size, key, key_size, iv, iv_size, 0, &ms);
if (r < 0)
goto out;
return r;
ms_dec += ms;
repeat_dec++;
}
@@ -142,8 +144,5 @@ int crypt_cipher_perf_kernel(const char *name, const char *mode, char *buffer, s
*encryption_mbs = speed_mbs(buffer_size * repeat_enc, ms_enc);
*decryption_mbs = speed_mbs(buffer_size * repeat_dec, ms_dec);
r = 0;
out:
crypt_cipher_destroy_kernel(&cipher);
return r;
return 0;
}

View File

@@ -2,14 +2,12 @@
/*
* Linux kernel cipher generic utilities
*
* Copyright (C) 2018-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2018-2025 Milan Broz
* Copyright (C) 2018-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2018-2024 Milan Broz
*/
#include <errno.h>
#include <strings.h>
#include <unistd.h>
#include <fcntl.h>
#include "crypto_backend.h"
struct cipher_alg {
@@ -79,21 +77,3 @@ int crypt_cipher_wrapped_key(const char *name, const char *mode)
return ca ? (int)ca->wrapped_key : 0;
}
bool crypt_fips_mode_kernel(void)
{
int fd;
char buf = 0;
fd = open("/proc/sys/crypto/fips_enabled", O_RDONLY);
if (fd < 0)
return false;
if (read(fd, &buf, 1) != 1)
buf = '0';
close(fd);
return (buf == '1');
}

View File

@@ -2,8 +2,8 @@
/*
* crypto backend implementation
*
* Copyright (C) 2010-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2025 Milan Broz
* Copyright (C) 2010-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2024 Milan Broz
*/
#ifndef _CRYPTO_BACKEND_H
@@ -14,23 +14,19 @@
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#if HAVE_UCHAR_H
#ifdef HAVE_UCHAR_H
#include <uchar.h>
#else
#define char32_t uint32_t
#define char16_t uint16_t
#endif
# ifdef __cplusplus
extern "C" {
# endif
struct crypt_hash;
struct crypt_hmac;
struct crypt_cipher;
struct crypt_storage;
int crypt_backend_init(void);
int crypt_backend_init(bool fips);
void crypt_backend_destroy(void);
#define CRYPT_BACKEND_KERNEL (1 << 0) /* Crypto uses kernel part, for benchmark */
@@ -93,7 +89,6 @@ int crypt_base64_decode(char **out, size_t *out_length, const char *in, size_t i
/* 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);
size_t crypt_char16_strlen(const char16_t *s);
/* Block ciphers */
int crypt_cipher_ivsize(const char *name, const char *mode);
@@ -137,10 +132,15 @@ int crypt_bitlk_decrypt_key(const void *key, size_t key_length,
const char *tag, size_t tag_length);
/* Memzero helper (memset on stack can be optimized out) */
void crypt_backend_memzero(void *s, size_t n);
/* Memcpy helper to avoid spilling sensitive data through additional registers */
void *crypt_backend_memcpy(void *dst, const void *src, size_t n);
static inline void crypt_backend_memzero(void *s, size_t n)
{
#ifdef HAVE_EXPLICIT_BZERO
explicit_bzero(s, n);
#else
volatile uint8_t *p = (volatile uint8_t *)s;
while(n--) *p++ = 0;
#endif
}
/* Memcmp helper (memcmp in constant time) */
int crypt_backend_memeq(const void *m1, const void *m2, size_t n);
@@ -148,11 +148,4 @@ int crypt_backend_memeq(const void *m1, const void *m2, size_t n);
/* crypto backend running in FIPS mode */
bool crypt_fips_mode(void);
/* kernel running in FIPS mode */
bool crypt_fips_mode_kernel(void);
# ifdef __cplusplus
}
# endif
#endif /* _CRYPTO_BACKEND_H */

View File

@@ -2,8 +2,8 @@
/*
* crypto backend implementation
*
* Copyright (C) 2010-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2025 Milan Broz
* Copyright (C) 2010-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2024 Milan Broz
*/
#ifndef _CRYPTO_BACKEND_INTERNAL_H
@@ -11,7 +11,7 @@
#include "crypto_backend.h"
/* Internal PBKDF2 implementation */
/* internal PBKDF2 implementation */
int pkcs5_pbkdf2(const char *hash,
const char *P, size_t Plen,
const char *S, size_t Slen,
@@ -47,6 +47,17 @@ int crypt_bitlk_decrypt_key_kernel(const void *key, size_t key_length,
const char *tag, size_t tag_length);
/* Internal implementation for constant time memory comparison */
int crypt_internal_memeq(const void *m1, const void *m2, size_t n);
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

@@ -2,8 +2,8 @@
/*
* Linux kernel userspace API crypto backend implementation (skcipher)
*
* Copyright (C) 2012-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2025 Milan Broz
* Copyright (C) 2012-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2024 Milan Broz
*/
#include <stdlib.h>
@@ -14,7 +14,7 @@
#include <sys/stat.h>
#include "crypto_backend_internal.h"
#if ENABLE_AF_ALG
#ifdef ENABLE_AF_ALG
#include <linux/if_alg.h>
@@ -40,8 +40,6 @@ static int _crypt_cipher_init(struct crypt_cipher_kernel *ctx,
const void *key, size_t key_length,
size_t tag_length, struct sockaddr_alg *sa)
{
void *optval = NULL;
if (!ctx)
return -EINVAL;
@@ -62,7 +60,7 @@ static int _crypt_cipher_init(struct crypt_cipher_kernel *ctx,
return -EINVAL;
}
if (tag_length && setsockopt(ctx->tfmfd, SOL_ALG, ALG_SET_AEAD_AUTHSIZE, &optval, tag_length) < 0) {
if (tag_length && setsockopt(ctx->tfmfd, SOL_ALG, ALG_SET_AEAD_AUTHSIZE, NULL, tag_length) < 0) {
crypt_cipher_destroy_kernel(ctx);
return -EINVAL;
}
@@ -99,20 +97,6 @@ int crypt_cipher_init_kernel(struct crypt_cipher_kernel *ctx, const char *name,
return _crypt_cipher_init(ctx, key, key_length, 0, &sa);
}
/* musl has broken CMSG_NXTHDR macro in system headers */
static inline struct cmsghdr *_CMSG_NXTHDR(struct msghdr* mhdr, struct cmsghdr* cmsg)
{
#if !defined(__GLIBC__) && defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wcast-align"
#pragma clang diagnostic ignored "-Wsign-compare"
return CMSG_NXTHDR(mhdr, cmsg);
#pragma clang diagnostic pop
#else
return CMSG_NXTHDR(mhdr, cmsg);
#endif
}
/* The in/out should be aligned to page boundary */
/* coverity[ -taint_source : arg-3 ] */
static int _crypt_cipher_crypt(struct crypt_cipher_kernel *ctx,
@@ -160,7 +144,7 @@ static int _crypt_cipher_crypt(struct crypt_cipher_kernel *ctx,
/* Set IV */
if (iv) {
header = _CMSG_NXTHDR(&msg, header);
header = CMSG_NXTHDR(&msg, header);
if (!header)
return -EINVAL;
@@ -169,7 +153,7 @@ static int _crypt_cipher_crypt(struct crypt_cipher_kernel *ctx,
header->cmsg_len = iv_msg_size;
alg_iv = (void*)CMSG_DATA(header);
alg_iv->ivlen = iv_length;
crypt_backend_memcpy(alg_iv->iv, iv, iv_length);
memcpy(alg_iv->iv, iv, iv_length);
}
len = sendmsg(ctx->opfd, &msg, 0);
@@ -216,8 +200,8 @@ int crypt_cipher_check_kernel(const char *name, const char *mode,
const char *integrity, size_t key_length)
{
struct crypt_cipher_kernel c;
char mode_name[64], tmp_salg_name[180], *cipher_iv = NULL, *key;
const char *salg_type, *real_mode;
char mode_name[64], tmp_salg_name[180], *real_mode = NULL, *cipher_iv = NULL, *key;
const char *salg_type;
bool aead;
int r;
struct sockaddr_alg sa = {
@@ -225,7 +209,6 @@ int crypt_cipher_check_kernel(const char *name, const char *mode,
};
aead = integrity && strcmp(integrity, "none");
real_mode = NULL;
/* Remove IV if present */
if (mode) {
@@ -246,22 +229,14 @@ int crypt_cipher_check_kernel(const char *name, const char *mode,
memset(tmp_salg_name, 0, sizeof(tmp_salg_name));
/* FIXME: this is duplicating a part of devmapper backend */
if (aead) {
/* In AEAD, mode parameter can be just IV like "random" */
if (!strcmp(integrity, "poly1305"))
r = snprintf(tmp_salg_name, sizeof(tmp_salg_name), "rfc7539(%s,%s)", name, integrity);
else if (!real_mode)
r = snprintf(tmp_salg_name, sizeof(tmp_salg_name), "%s", name);
else if (!strcmp(real_mode, "ccm"))
r = snprintf(tmp_salg_name, sizeof(tmp_salg_name), "rfc4309(%s(%s))", real_mode, name);
else
r = snprintf(tmp_salg_name, sizeof(tmp_salg_name), "%s(%s)", real_mode, name);
} else {
if (!mode)
r = snprintf(tmp_salg_name, sizeof(tmp_salg_name), "%s", name);
else
r = snprintf(tmp_salg_name, sizeof(tmp_salg_name), "%s(%s)", real_mode ?: mode_name, name);
}
if (aead && !strcmp(integrity, "poly1305"))
r = snprintf(tmp_salg_name, sizeof(tmp_salg_name), "rfc7539(%s,%s)", name, integrity);
else if (!real_mode)
r = snprintf(tmp_salg_name, sizeof(tmp_salg_name), "%s", name);
else if (aead && !strcmp(real_mode, "ccm"))
r = snprintf(tmp_salg_name, sizeof(tmp_salg_name), "rfc4309(%s(%s))", real_mode, name);
else
r = snprintf(tmp_salg_name, sizeof(tmp_salg_name), "%s(%s)", real_mode, name);
if (r < 0 || (size_t)r >= sizeof(tmp_salg_name))
return -EINVAL;

View File

@@ -2,8 +2,8 @@
/*
* GCRYPT crypto backend implementation
*
* Copyright (C) 2010-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2025 Milan Broz
* Copyright (C) 2010-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2024 Milan Broz
*/
#include <stdio.h>
@@ -51,6 +51,7 @@ static void crypt_hash_test_whirlpool_bug(void)
{
struct crypt_hash *h;
char buf[2] = "\0\0", hash_out1[64], hash_out2[64];
int r;
if (crypto_backend_whirlpool_bug >= 0)
return;
@@ -60,16 +61,16 @@ static void crypt_hash_test_whirlpool_bug(void)
return;
/* One shot */
if (crypt_hash_write(h, &buf[0], 2) ||
crypt_hash_final(h, hash_out1, 64)) {
if ((r = crypt_hash_write(h, &buf[0], 2)) ||
(r = crypt_hash_final(h, hash_out1, 64))) {
crypt_hash_destroy(h);
return;
}
/* Split buf (crypt_hash_final resets hash state) */
if (crypt_hash_write(h, &buf[0], 1) ||
crypt_hash_write(h, &buf[1], 1) ||
crypt_hash_final(h, hash_out2, 64)) {
if ((r = crypt_hash_write(h, &buf[0], 1)) ||
(r = crypt_hash_write(h, &buf[1], 1)) ||
(r = crypt_hash_final(h, hash_out2, 64))) {
crypt_hash_destroy(h);
return;
}
@@ -80,7 +81,7 @@ static void crypt_hash_test_whirlpool_bug(void)
crypto_backend_whirlpool_bug = 1;
}
int crypt_backend_init(void)
int crypt_backend_init(bool fips __attribute__((unused)))
{
int r;
@@ -249,7 +250,7 @@ int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
if (!hash)
return -EINVAL;
crypt_backend_memcpy(buffer, hash, length);
memcpy(buffer, hash, length);
crypt_hash_restart(ctx);
return 0;
@@ -323,7 +324,7 @@ int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
if (!hash)
return -EINVAL;
crypt_backend_memcpy(buffer, hash, length);
memcpy(buffer, hash, length);
crypt_hmac_restart(ctx);
return 0;
@@ -451,7 +452,6 @@ static int gcrypt_argon2(const char *type,
.dispatch_job = gcrypt_dispatch_job,
.wait_all_jobs = gcrypt_wait_all_jobs
};
gpg_error_t err;
if (!strcmp(type, "argon2i"))
atype = GCRY_KDF_ARGON2I;
@@ -465,11 +465,12 @@ static int gcrypt_argon2(const char *type,
param[2] = memory;
param[3] = parallel;
err = gcry_kdf_open(&hd, GCRY_KDF_ARGON2, atype, param, 4,
if (gcry_kdf_open(&hd, GCRY_KDF_ARGON2, atype, param, 4,
password, password_length, salt, salt_length,
NULL, 0, NULL, 0);
if (err)
return ((err & GPG_ERR_CODE_MASK) == GPG_ERR_ENOMEM) ? -ENOMEM : -EINVAL;
NULL, 0, NULL, 0)) {
free(threads.jobs_ctx);
return -EINVAL;
}
if (parallel == 1) {
/* Do not use threads here */
@@ -684,7 +685,7 @@ bool crypt_fips_mode(void)
if (fips_checked)
return fips_mode;
if (crypt_backend_init())
if (crypt_backend_init(false /* ignored */))
return false;
fips_mode = gcry_fips_mode_active();

View File

@@ -2,8 +2,8 @@
/*
* Linux kernel userspace API crypto backend implementation
*
* Copyright (C) 2010-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2025 Milan Broz
* Copyright (C) 2010-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2024 Milan Broz
*/
#include <stdlib.h>
@@ -103,7 +103,7 @@ static int crypt_kernel_socket_init(struct sockaddr_alg *sa, int *tfmfd, int *op
return 0;
}
int crypt_backend_init(void)
int crypt_backend_init(bool fips __attribute__((unused)))
{
struct utsname uts;
struct sockaddr_alg sa = {
@@ -408,5 +408,5 @@ int crypt_backend_memeq(const void *m1, const void *m2, size_t n)
bool crypt_fips_mode(void)
{
return crypt_fips_mode_kernel();
return false;
}

View File

@@ -1,532 +0,0 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* Mbed TLS crypto backend implementation
*
* Copyright (C) 2024-2025 Yiyuan Zhong
*/
#include "crypto_backend.h"
#include <errno.h>
#include <stdlib.h>
#include <mbedtls/ccm.h>
#include <mbedtls/constant_time.h>
#include <mbedtls/cipher.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>
#include <mbedtls/md.h>
#include <mbedtls/pkcs5.h>
#include <mbedtls/version.h>
#include "crypto_backend_internal.h"
struct crypt_hash {
const mbedtls_md_info_t *info;
mbedtls_md_context_t md;
};
struct crypt_hmac {
const mbedtls_md_info_t *info;
mbedtls_md_context_t md;
};
struct crypt_cipher {
const mbedtls_cipher_info_t *info;
mbedtls_cipher_context_t enc;
mbedtls_cipher_context_t dec;
int ecb;
};
static bool g_initialized = false;
static char g_backend_version[32];
static mbedtls_entropy_context g_entropy;
static mbedtls_ctr_drbg_context g_ctr_drbg;
static const mbedtls_md_info_t *crypt_get_hash(const char *name)
{
static const struct hash_alg {
const char *name;
mbedtls_md_type_t type;
} kHash[] = {
{"sha1", MBEDTLS_MD_SHA1 },
{"sha224", MBEDTLS_MD_SHA224 },
{"sha256", MBEDTLS_MD_SHA256 },
{"sha384", MBEDTLS_MD_SHA384 },
{"sha512", MBEDTLS_MD_SHA512 },
{"ripemd160", MBEDTLS_MD_RIPEMD160},
{NULL, 0, }
};
size_t i = 0;
while (name && kHash[i].name) {
if (strcmp(kHash[i].name, name) == 0)
return mbedtls_md_info_from_type(kHash[i].type);
i++;
}
return NULL;
}
int crypt_backend_init(void)
{
int ret;
if (g_initialized)
return 0;
mbedtls_version_get_string_full(g_backend_version);
mbedtls_entropy_init(&g_entropy);
mbedtls_ctr_drbg_init(&g_ctr_drbg);
ret = mbedtls_ctr_drbg_seed(
&g_ctr_drbg, mbedtls_entropy_func,
&g_entropy, NULL, MBEDTLS_CTR_DRBG_ENTROPY_LEN);
if (ret)
return -EINVAL;
g_initialized = true;
return 0;
}
void crypt_backend_destroy(void)
{
if (!g_initialized)
return;
mbedtls_ctr_drbg_free(&g_ctr_drbg);
mbedtls_entropy_free(&g_entropy);
g_initialized = false;
}
uint32_t crypt_backend_flags(void)
{
return 0;
}
const char *crypt_backend_version(void)
{
return g_backend_version;
}
bool crypt_fips_mode(void)
{
return false;
}
int crypt_backend_memeq(const void *m1, const void *m2, size_t n)
{
return mbedtls_ct_memcmp(m1, m2, n);
}
/* HASH */
int crypt_hash_size(const char *name)
{
const mbedtls_md_info_t *info;
info = crypt_get_hash(name);
return info ? mbedtls_md_get_size(info) : -ENOENT;
}
int crypt_hash_init(struct crypt_hash **ctx, const char *name)
{
struct crypt_hash *h;
h = malloc(sizeof(*h));
if (!h)
return -ENOMEM;
h->info = crypt_get_hash(name);
if (!h->info) {
free(h);
return -ENOENT;
}
mbedtls_md_init(&h->md);
if (mbedtls_md_setup(&h->md, h->info, 0)) {
mbedtls_md_free(&h->md);
free(h);
return -EINVAL;
}
if (mbedtls_md_starts(&h->md)) {
mbedtls_md_free(&h->md);
free(h);
return -EINVAL;
}
*ctx = h;
return 0;
}
int crypt_hash_write(struct crypt_hash *ctx, const char *buffer, size_t length)
{
if (mbedtls_md_update(&ctx->md, (const unsigned char *)buffer, length))
return -EINVAL;
return 0;
}
int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
{
unsigned char tmp[MBEDTLS_MD_MAX_SIZE];
if (length > mbedtls_md_get_size(ctx->info))
return -EINVAL;
if (mbedtls_md_finish(&ctx->md, tmp))
return -EINVAL;
crypt_backend_memcpy(buffer, tmp, length);
crypt_backend_memzero(tmp, sizeof(tmp));
if (mbedtls_md_starts(&ctx->md))
return -EINVAL;
return 0;
}
void crypt_hash_destroy(struct crypt_hash *ctx)
{
mbedtls_md_free(&ctx->md);
crypt_backend_memzero(ctx, sizeof(*ctx));
free(ctx);
}
/* HMAC */
int crypt_hmac_size(const char *name)
{
return crypt_hash_size(name);
}
int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
const void *key, size_t key_length)
{
struct crypt_hmac *h;
h = malloc(sizeof(*h));
if (!h)
return -ENOMEM;
h->info = crypt_get_hash(name);
if (!h->info) {
free(h);
return -ENOENT;
}
mbedtls_md_init(&h->md);
if (mbedtls_md_setup(&h->md, h->info, 1)) {
mbedtls_md_free(&h->md);
free(h);
return -EINVAL;
}
if (mbedtls_md_hmac_starts(&h->md, key, key_length)) {
mbedtls_md_free(&h->md);
free(h);
return -EINVAL;
}
*ctx = h;
return 0;
}
int crypt_hmac_write(struct crypt_hmac *ctx, const char *buffer, size_t length)
{
if (mbedtls_md_hmac_update(&ctx->md, (const unsigned char *)buffer, length))
return -EINVAL;
return 0;
}
int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
{
unsigned char tmp[MBEDTLS_MD_MAX_SIZE];
if (length > mbedtls_md_get_size(ctx->info))
return -EINVAL;
if (mbedtls_md_hmac_finish(&ctx->md, tmp))
return -EINVAL;
crypt_backend_memcpy(buffer, tmp, length);
crypt_backend_memzero(tmp, sizeof(tmp));
if (mbedtls_md_hmac_reset(&ctx->md))
return -EINVAL;
return 0;
}
void crypt_hmac_destroy(struct crypt_hmac *ctx)
{
mbedtls_md_free(&ctx->md);
crypt_backend_memzero(ctx, sizeof(*ctx));
free(ctx);
}
/* RNG */
int crypt_backend_rng(char *buffer, size_t length, int quality, int fips)
{
if (fips)
return -ENOTSUP;
/* Allow skipping reseeding for non-cryptographic strong random numbers */
if (quality == CRYPT_RND_NORMAL || quality == CRYPT_RND_SALT)
mbedtls_ctr_drbg_set_prediction_resistance(&g_ctr_drbg, MBEDTLS_CTR_DRBG_PR_OFF);
else
mbedtls_ctr_drbg_set_prediction_resistance(&g_ctr_drbg, MBEDTLS_CTR_DRBG_PR_ON);
if (mbedtls_ctr_drbg_random(&g_ctr_drbg, (unsigned char *)buffer, length))
return -EINVAL;
return 0;
}
/* CIPHER */
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
const char *mode, const void *key, size_t key_length)
{
static const struct {
const char *name;
mbedtls_cipher_id_t id;
} kCipher[] = {
{ "aes", MBEDTLS_CIPHER_ID_AES },
{ "aria", MBEDTLS_CIPHER_ID_ARIA },
{ "camellia", MBEDTLS_CIPHER_ID_CAMELLIA },
{ NULL, 0 }
};
static const struct {
const char *name;
mbedtls_cipher_mode_t mode;
} kMode[] = {
{ "ecb", MBEDTLS_MODE_ECB },
{ "cbc", MBEDTLS_MODE_CBC },
{ "cfb", MBEDTLS_MODE_CFB },
{ "ofb", MBEDTLS_MODE_OFB },
{ "ctr", MBEDTLS_MODE_CTR },
{ "xts", MBEDTLS_MODE_XTS },
{ NULL, 0 }
};
mbedtls_cipher_id_t cid = MBEDTLS_CIPHER_ID_NONE;
mbedtls_cipher_mode_t cmode = MBEDTLS_MODE_NONE;
struct crypt_cipher *h;
size_t i;
int bits;
for (i = 0; kCipher[i].name; i++) {
if (strcmp(kCipher[i].name, name) == 0) {
cid = kCipher[i].id;
break;
}
}
for (i = 0; kMode[i].name; i++) {
if (strcmp(kMode[i].name, mode) == 0) {
cmode = kMode[i].mode;
break;
}
}
if (cid == MBEDTLS_CIPHER_ID_NONE || cmode == MBEDTLS_MODE_NONE)
return -ENOENT;
h = malloc(sizeof(*h));
if (!h)
return -ENOMEM;
bits = key_length * 8;
h->info = mbedtls_cipher_info_from_values(cid, bits, cmode);
if (!h->info) {
free(h);
return -ENOENT;
}
mbedtls_cipher_init(&h->enc);
mbedtls_cipher_init(&h->dec);
if (mbedtls_cipher_setup(&h->enc, h->info) ||
mbedtls_cipher_setup(&h->dec, h->info) ||
mbedtls_cipher_setkey(&h->enc, key, bits, MBEDTLS_ENCRYPT) ||
mbedtls_cipher_setkey(&h->dec, key, bits, MBEDTLS_DECRYPT)) {
mbedtls_cipher_free(&h->dec);
mbedtls_cipher_free(&h->enc);
free(h);
return -EINVAL;
}
if (cmode == MBEDTLS_MODE_CBC) {
if (mbedtls_cipher_set_padding_mode(&h->enc, MBEDTLS_PADDING_NONE) ||
mbedtls_cipher_set_padding_mode(&h->dec, MBEDTLS_PADDING_NONE)) {
mbedtls_cipher_free(&h->dec);
mbedtls_cipher_free(&h->enc);
free(h);
return -EINVAL;
}
}
h->ecb = cmode == MBEDTLS_MODE_ECB;
*ctx = h;
return 0;
}
void crypt_cipher_destroy(struct crypt_cipher *ctx)
{
mbedtls_cipher_free(&ctx->dec);
mbedtls_cipher_free(&ctx->enc);
free(ctx);
}
static int crypt_cipher_crypt(
mbedtls_cipher_context_t *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length,
int ecb)
{
const unsigned char *input;
unsigned char *output;
size_t outlen;
size_t block;
size_t len;
if (ecb) /* ECB requires exactly block length input */
block = mbedtls_cipher_get_block_size(ctx);
else
block = length;
input = (const unsigned char *)in;
output = (unsigned char *)out;
if (mbedtls_cipher_set_iv(ctx, (const unsigned char *)iv, iv_length))
return -EINVAL;
if (mbedtls_cipher_reset(ctx))
return -EINVAL;
while (length) {
len = length < block ? length : block;
if (mbedtls_cipher_update(ctx, input, len, output, &outlen))
return -EINVAL;
output += outlen;
length -= len;
input += len;
}
if (mbedtls_cipher_finish(ctx, output, &outlen))
return -EINVAL;
return 0;
}
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
{
return crypt_cipher_crypt(&ctx->enc, in, out, length, iv, iv_length, ctx->ecb);
}
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
{
return crypt_cipher_crypt(&ctx->dec, in, out, length, iv, iv_length, ctx->ecb);
}
bool crypt_cipher_kernel_only(struct crypt_cipher *ctx __attribute__((unused)))
{
return false;
}
int crypt_pbkdf(const char *kdf, const char *hash,
const char *password, size_t password_length,
const char *salt, size_t salt_length,
char *key, size_t key_length,
uint32_t iterations, uint32_t memory, uint32_t parallel)
{
const mbedtls_md_info_t *info;
#if !HAVE_MBEDTLS_PKCS5_PBKDF2_HMAC_EXT
mbedtls_md_context_t md;
#endif
if (!kdf)
return -EINVAL;
if (strcmp(kdf, "pbkdf2") == 0) {
info = crypt_get_hash(hash);
if (!info)
return -EINVAL;
#if HAVE_MBEDTLS_PKCS5_PBKDF2_HMAC_EXT
if (mbedtls_pkcs5_pbkdf2_hmac_ext(mbedtls_md_get_type(info),
(const unsigned char *)password, password_length,
(const unsigned char *)salt, salt_length,
iterations, key_length, (unsigned char *)key)) {
return -EINVAL;
}
#else
mbedtls_md_init(&md);
if (mbedtls_md_setup(&md, info, 1))
return -EINVAL;
if (mbedtls_pkcs5_pbkdf2_hmac(&md,
(const unsigned char *)password, password_length,
(const unsigned char *)salt, salt_length,
iterations, key_length, (unsigned char *)key)) {
mbedtls_md_free(&md);
return -EINVAL;
}
mbedtls_md_free(&md);
#endif
return 0;
} else if (strncmp(kdf, "argon2", 6) == 0) {
return argon2(kdf, password, password_length, salt, salt_length,
key, key_length, iterations, memory, parallel);
}
return -EINVAL;
}
int crypt_bitlk_decrypt_key(const void *key, size_t key_length,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length,
const char *tag, size_t tag_length)
{
const unsigned char *tagptr;
const unsigned char *input;
const unsigned char *ivptr;
mbedtls_ccm_context ctx;
unsigned char *output;
tagptr = (const unsigned char *)tag;
ivptr = (const unsigned char *)iv;
input = (const unsigned char *)in;
output = (unsigned char *)out;
mbedtls_ccm_init(&ctx);
if (mbedtls_ccm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, key, key_length * 8)) {
mbedtls_ccm_free(&ctx);
return -EINVAL;
}
if (mbedtls_ccm_auth_decrypt(&ctx, length, ivptr, iv_length, NULL, 0,
input, output, tagptr, tag_length)) {
mbedtls_ccm_free(&ctx);
return -EINVAL;
}
mbedtls_ccm_free(&ctx);
return 0;
}

View File

@@ -2,8 +2,8 @@
/*
* Nettle crypto backend implementation
*
* Copyright (C) 2011-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2025 Milan Broz
* Copyright (C) 2011-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2024 Milan Broz
*/
#include <stdlib.h>
@@ -200,7 +200,7 @@ static struct hash_alg *_get_alg(const char *name)
return NULL;
}
int crypt_backend_init(void)
int crypt_backend_init(bool fips __attribute__((unused)))
{
return 0;
}
@@ -284,7 +284,8 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
h = malloc(sizeof(*h));
if (!h)
return -ENOMEM;
memset(h, 0, sizeof(*h));
memset(ctx, 0, sizeof(*ctx));
h->hash = _get_alg(name);
if (!h->hash) {
@@ -298,7 +299,7 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
return -ENOMEM;
}
crypt_backend_memcpy(h->key, key, key_length);
memcpy(h->key, key, key_length);
h->key_length = key_length;
h->hash->init(&h->nettle_ctx);

View File

@@ -2,8 +2,8 @@
/*
* NSS crypto backend implementation
*
* Copyright (C) 2010-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2025 Milan Broz
* Copyright (C) 2010-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2024 Milan Broz
*/
#include <stdio.h>
@@ -62,7 +62,7 @@ static struct hash_alg *_get_alg(const char *name)
return NULL;
}
int crypt_backend_init(void)
int crypt_backend_init(bool fips __attribute__((unused)))
{
int r;
@@ -164,7 +164,7 @@ int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
if (PK11_DigestFinal(ctx->md, tmp, &tmp_len, length) != SECSuccess)
return -EINVAL;
crypt_backend_memcpy(buffer, tmp, length);
memcpy(buffer, tmp, length);
crypt_backend_memzero(tmp, sizeof(tmp));
if (tmp_len < length)
@@ -207,7 +207,8 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
h = malloc(sizeof(*h));
if (!h)
return -ENOMEM;
memset(h, 0, sizeof(*h));
memset(ctx, 0, sizeof(*ctx));
h->hash = _get_alg(name);
if (!h->hash)
@@ -264,7 +265,7 @@ int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
if (PK11_DigestFinal(ctx->md, tmp, &tmp_len, length) != SECSuccess)
return -EINVAL;
crypt_backend_memcpy(buffer, tmp, length);
memcpy(buffer, tmp, length);
crypt_backend_memzero(tmp, sizeof(tmp));
if (tmp_len < length)

View File

@@ -2,8 +2,8 @@
/*
* OPENSSL crypto backend implementation
*
* Copyright (C) 2010-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2025 Milan Broz
* Copyright (C) 2010-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2024 Milan Broz
*/
#include <stdio.h>
@@ -19,7 +19,6 @@
#include <openssl/provider.h>
#include <openssl/kdf.h>
#include <openssl/core_names.h>
#include <openssl/err.h>
static OSSL_PROVIDER *ossl_legacy = NULL;
static OSSL_PROVIDER *ossl_default = NULL;
static OSSL_LIB_CTX *ossl_ctx = NULL;
@@ -205,12 +204,12 @@ static const char *openssl_backend_version(void)
}
#endif
int crypt_backend_init(void)
int crypt_backend_init(bool fips)
{
if (crypto_backend_initialised)
return 0;
if (openssl_backend_init(crypt_fips_mode()))
if (openssl_backend_init(fips))
return -EINVAL;
crypto_backend_initialised = 1;
@@ -382,7 +381,7 @@ int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
if (EVP_DigestFinal_ex(ctx->md, tmp, &tmp_len) != 1)
return -EINVAL;
crypt_backend_memcpy(buffer, tmp, length);
memcpy(buffer, tmp, length);
crypt_backend_memzero(tmp, sizeof(tmp));
if (tmp_len < length)
@@ -511,7 +510,7 @@ int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
HMAC_Final(ctx->md, tmp, &tmp_len);
#endif
crypt_backend_memcpy(buffer, tmp, length);
memcpy(buffer, tmp, length);
crypt_backend_memzero(tmp, sizeof(tmp));
if (tmp_len < length)
@@ -625,7 +624,7 @@ static int openssl_argon2(const char *type, const char *password, size_t passwor
ctx = EVP_KDF_CTX_new(argon2);
if (!ctx) {
EVP_KDF_free(argon2);
return -EINVAL;
return -EINVAL;;
}
if (EVP_KDF_CTX_set_params(ctx, params) != 1) {
@@ -639,10 +638,6 @@ static int openssl_argon2(const char *type, const char *password, size_t passwor
EVP_KDF_CTX_free(ctx);
EVP_KDF_free(argon2);
/* Memory allocation is common issue with memory-hard Argon2 */
if (r == 0 && ERR_GET_REASON(ERR_get_error()) == ERR_R_MALLOC_FAILURE)
return -ENOMEM;
/* _derive() returns 0 or negative value on error, 1 on success */
return r == 1 ? 0 : -EINVAL;
#else

View File

@@ -3,19 +3,16 @@
* Generic wrapper for storage encryption modes and Initial Vectors
* (reimplementation of some functions from Linux dm-crypt kernel)
*
* Copyright (C) 2014-2025 Milan Broz
* Copyright (C) 2014-2024 Milan Broz
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <strings.h>
#include "bitops.h"
#include "crypto_backend.h"
#define SECTOR_SHIFT 9
#define MAX_CAPI_LEN 64
#define MAX_CAPI_LEN_STR "63"
#define SECTOR_SHIFT 9
/*
* Internal IV helper
@@ -215,49 +212,36 @@ int crypt_storage_init(struct crypt_storage **ctx,
bool large_iv)
{
struct crypt_storage *s;
char cipher_name[MAX_CAPI_LEN], mode_name[MAX_CAPI_LEN], mode_tmp[MAX_CAPI_LEN];
char mode_name[64];
char *cipher_iv = NULL;
int r;
int r = -EIO;
if (sector_size < (1 << SECTOR_SHIFT) ||
sector_size > (1 << (SECTOR_SHIFT + 3)) ||
sector_size & (sector_size - 1))
return -EINVAL;
/* Convert from capi mode */
if (!strncmp(cipher, "capi:", 5)) {
r = sscanf(cipher, "capi:%" MAX_CAPI_LEN_STR "[^(](%" MAX_CAPI_LEN_STR "[^)])", mode_tmp, cipher_name);
if (r != 2)
return -EINVAL;
r = snprintf(mode_name, sizeof(mode_name), "%s-%s", mode_tmp, cipher_mode);
if (r < 0 || (size_t)r >= sizeof(mode_name))
return -EINVAL;
} else {
strncpy(cipher_name, cipher, sizeof(cipher_name));
cipher_name[sizeof(cipher_name) - 1] = 0;
strncpy(mode_name, cipher_mode, sizeof(mode_name));
mode_name[sizeof(mode_name) - 1] = 0;
}
s = malloc(sizeof(*s));
if (!s)
return -ENOMEM;
memset(s, 0, sizeof(*s));
/* Remove IV if present */
strncpy(mode_name, cipher_mode, sizeof(mode_name));
mode_name[sizeof(mode_name) - 1] = 0;
cipher_iv = strchr(mode_name, '-');
if (cipher_iv) {
*cipher_iv = '\0';
cipher_iv++;
}
s = malloc(sizeof(*s));
if (!s)
return -ENOMEM;
memset(s, 0, sizeof(*s));
r = crypt_cipher_init(&s->cipher, cipher_name, mode_name, key, key_length);
r = crypt_cipher_init(&s->cipher, cipher, mode_name, key, key_length);
if (r) {
crypt_storage_destroy(s);
return r;
}
r = crypt_sector_iv_init(&s->cipher_iv, cipher_name, mode_name, cipher_iv, key, key_length, sector_size);
r = crypt_sector_iv_init(&s->cipher_iv, cipher, mode_name, cipher_iv, key, key_length, sector_size);
if (r) {
crypt_storage_destroy(s);
return r;

View File

@@ -1,61 +0,0 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* Safe memory utilities
*
* Copyright (C) 2024-2025 Milan Broz
*/
#include "crypto_backend_internal.h"
#define ATTR_NOINLINE __attribute__ ((noinline))
#define ATTR_ZERO_REGS
#if HAVE_ATTRIBUTE_ZEROCALLUSEDREGS
# undef ATTR_ZERO_REGS
# define ATTR_ZERO_REGS __attribute__ ((zero_call_used_regs("used")))
#endif
/* Workaround for https://github.com/google/sanitizers/issues/1507 */
#if defined __has_feature
# if __has_feature (memory_sanitizer)
# undef HAVE_EXPLICIT_BZERO
# endif
#endif
/* Memzero helper (memset on stack can be optimized out) */
ATTR_NOINLINE ATTR_ZERO_REGS
void crypt_backend_memzero(void *s, size_t n)
{
#if HAVE_EXPLICIT_BZERO
explicit_bzero(s, n);
#else
volatile uint8_t *p = (volatile uint8_t *)s;
while(n--) *p++ = 0;
#endif
}
/* Memcpy helper to avoid spilling sensitive data through additional registers */
ATTR_NOINLINE ATTR_ZERO_REGS
void *crypt_backend_memcpy(void *dst, const void *src, size_t n)
{
volatile uint8_t *d = (volatile uint8_t *)dst;
const volatile uint8_t *s = (const volatile uint8_t *)src;
while(n--) *d++ = *s++;
return dst;
}
/* Internal implementation for constant time memory comparison */
ATTR_NOINLINE ATTR_ZERO_REGS
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;
}

View File

@@ -11,7 +11,6 @@ libcrypto_backend_link_with = []
libcrypto_backend_sources = files(
'argon2_generic.c',
'base64.c',
'memutils.c',
'cipher_check.c',
'cipher_generic.c',
'crc32.c',

View File

@@ -5,8 +5,8 @@
* Copyright (C) 2004 Free Software Foundation
*
* cryptsetup related changes
* Copyright (C) 2012-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2025 Milan Broz
* Copyright (C) 2012-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2024 Milan Broz
*/
#include <errno.h>

View File

@@ -1,8 +1,8 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* PBKDF performance check
* Copyright (C) 2012-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2025 Milan Broz
* Copyright (C) 2012-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2024 Milan Broz
* Copyright (C) 2016-2020 Ondrej Mosnacek
*/
@@ -300,7 +300,6 @@ static int crypt_argon2_check(const char *kdf, const char *password,
} while (ms < ms_atleast || ms > ms_atmost);
out:
if (key) {
/* Key can be derived from a real provided password */
crypt_backend_memzero(key, key_length);
free(key);
}
@@ -382,7 +381,6 @@ static int crypt_pbkdf_check(const char *kdf, const char *hash,
}
out:
if (key) {
/* Key can be derived from a real provided password */
crypt_backend_memzero(key, key_length);
free(key);
}
@@ -408,9 +406,6 @@ int crypt_pbkdf_perf(const char *kdf, const char *hash,
if (r < 0)
return r;
if (parallel_threads > pbkdf_limits.max_parallel)
return -EINVAL;
min_memory = pbkdf_limits.min_bench_memory;
if (min_memory > max_memory_kb)
min_memory = max_memory_kb;

View File

@@ -5,7 +5,7 @@
* Copyright (C) 2010 Lennart Poettering
*
* cryptsetup related changes
* Copyright (C) 2021-2025 Vojtech Trefny
* Copyright (C) 2021-2024 Vojtech Trefny
* Parts of the original systemd implementation are based on the GLIB utf8
* validation functions.
@@ -274,20 +274,3 @@ int crypt_utf8_to_utf16(char16_t **out, const char *s, size_t length)
*p = 0;
return 0;
}
/**
* crypt_char16_strlen()
* @s: string to get length of
*
* Returns: number of 16-bit words in the string
*/
size_t crypt_char16_strlen(const char16_t *s) {
size_t n = 0;
assert(s);
while (*s != 0)
n++, s++;
return n;
}

View File

@@ -513,7 +513,6 @@ static int _read_volume_header(
int r = 0;
struct device *dev = crypt_metadata_device(cd);
struct volume_header *vol_header = NULL;
void *enc_key = NULL;
assert(sizeof(*vol_header) == FVAULT2_VOL_HEADER_SIZE);
@@ -558,8 +557,8 @@ static int _read_volume_header(
goto out;
}
enc_key = crypt_safe_alloc(FVAULT2_XTS_KEY_SIZE);
if (!enc_key) {
*enc_md_key = crypt_alloc_volume_key(FVAULT2_XTS_KEY_SIZE, NULL);
if (*enc_md_key == NULL) {
r = -ENOMEM;
goto out;
}
@@ -567,15 +566,9 @@ static int _read_volume_header(
*block_size = le32_to_cpu(vol_header->block_size);
*disklbl_blkoff = le64_to_cpu(vol_header->disklbl_blkoff);
uuid_unparse(vol_header->ph_vol_uuid, ph_vol_uuid);
crypt_safe_memcpy(enc_key, vol_header->key_data, FVAULT2_AES_KEY_SIZE);
crypt_safe_memcpy((char *)enc_key + FVAULT2_AES_KEY_SIZE,
memcpy((*enc_md_key)->key, vol_header->key_data, FVAULT2_AES_KEY_SIZE);
memcpy((*enc_md_key)->key + FVAULT2_AES_KEY_SIZE,
vol_header->ph_vol_uuid, FVAULT2_AES_KEY_SIZE);
*enc_md_key = crypt_alloc_volume_key_by_safe_alloc(&enc_key);
if (*enc_md_key == NULL) {
crypt_safe_free(enc_key);
r = -ENOMEM;
}
out:
free(vol_header);
return r;
@@ -711,7 +704,7 @@ static int _read_encrypted_metadata(
goto out;
}
r = crypt_cipher_init(&cipher, "aes", "xts", crypt_volume_key_get_key(key), FVAULT2_XTS_KEY_SIZE);
r = crypt_cipher_init(&cipher, "aes", "xts", key->key, FVAULT2_XTS_KEY_SIZE);
if (r < 0)
goto out;
@@ -842,7 +835,8 @@ static int _activate(
r = dm_crypt_target_set(&dm_dev.segment, 0, dm_dev.size,
crypt_data_device(cd), vol_key, cipher,
crypt_get_iv_offset(cd), crypt_get_data_offset(cd),
NULL, 0, 0, crypt_get_sector_size(cd));
crypt_get_integrity(cd), crypt_get_integrity_tag_size(cd),
crypt_get_sector_size(cd));
if (!r)
r = dm_create_device(cd, name, CRYPT_FVAULT2, &dm_dev);
@@ -899,14 +893,15 @@ int FVAULT2_get_volume_key(
const char *passphrase,
size_t passphrase_len,
const struct fvault2_params *params,
struct volume_key **r_vol_key)
struct volume_key **vol_key)
{
int r = 0;
uint8_t family_uuid_bin[FVAULT2_UUID_BIN_SIZE];
struct volume_key *passphrase_key = NULL;
struct volume_key *kek = NULL;
struct crypt_hash *hash = NULL;
void *passphrase_key = NULL, *kek = NULL, *vol_key= NULL;
*r_vol_key = NULL;
*vol_key = NULL;
if (uuid_parse(params->family_uuid, family_uuid_bin) < 0) {
log_dbg(cd, "Could not parse logical volume family UUID: %s.",
@@ -915,62 +910,61 @@ int FVAULT2_get_volume_key(
goto out;
}
passphrase_key = crypt_safe_alloc(FVAULT2_AES_KEY_SIZE);
passphrase_key = crypt_alloc_volume_key(FVAULT2_AES_KEY_SIZE, NULL);
if (passphrase_key == NULL) {
r = -ENOMEM;
goto out;
}
r = crypt_pbkdf("pbkdf2", "sha256", passphrase, passphrase_len,
params->pbkdf2_salt, FVAULT2_PBKDF2_SALT_SIZE, passphrase_key,
params->pbkdf2_salt, FVAULT2_PBKDF2_SALT_SIZE, passphrase_key->key,
FVAULT2_AES_KEY_SIZE, params->pbkdf2_iters, 0, 0);
if (r < 0)
goto out;
kek = crypt_safe_alloc(FVAULT2_AES_KEY_SIZE);
kek = crypt_alloc_volume_key(FVAULT2_AES_KEY_SIZE, NULL);
if (kek == NULL) {
r = -ENOMEM;
goto out;
}
r = _unwrap_key(passphrase_key, FVAULT2_AES_KEY_SIZE, params->wrapped_kek,
FVAULT2_WRAPPED_KEY_SIZE, kek, FVAULT2_AES_KEY_SIZE);
r = _unwrap_key(passphrase_key->key, FVAULT2_AES_KEY_SIZE, params->wrapped_kek,
FVAULT2_WRAPPED_KEY_SIZE, kek->key, FVAULT2_AES_KEY_SIZE);
if (r < 0)
goto out;
vol_key = crypt_safe_alloc(FVAULT2_XTS_KEY_SIZE);
if (vol_key == NULL) {
*vol_key = crypt_alloc_volume_key(FVAULT2_XTS_KEY_SIZE, NULL);
if (*vol_key == NULL) {
r = -ENOMEM;
goto out;
}
r = _unwrap_key(kek, FVAULT2_AES_KEY_SIZE, params->wrapped_vk,
FVAULT2_WRAPPED_KEY_SIZE, vol_key, FVAULT2_AES_KEY_SIZE);
r = _unwrap_key(kek->key, FVAULT2_AES_KEY_SIZE, params->wrapped_vk,
FVAULT2_WRAPPED_KEY_SIZE, (*vol_key)->key, FVAULT2_AES_KEY_SIZE);
if (r < 0)
goto out;
r = crypt_hash_init(&hash, "sha256");
if (r < 0)
goto out;
r = crypt_hash_write(hash, vol_key, FVAULT2_AES_KEY_SIZE);
r = crypt_hash_write(hash, (*vol_key)->key, FVAULT2_AES_KEY_SIZE);
if (r < 0)
goto out;
r = crypt_hash_write(hash, (char *)family_uuid_bin,
FVAULT2_UUID_BIN_SIZE);
if (r < 0)
goto out;
r = crypt_hash_final(hash, (char *)vol_key + FVAULT2_AES_KEY_SIZE,
r = crypt_hash_final(hash, (*vol_key)->key + FVAULT2_AES_KEY_SIZE,
FVAULT2_AES_KEY_SIZE);
if (r < 0)
goto out;
*r_vol_key = crypt_alloc_volume_key_by_safe_alloc(&vol_key);
if (!*r_vol_key)
r = -ENOMEM;
out:
crypt_safe_free(passphrase_key);
crypt_safe_free(kek);
crypt_safe_free(vol_key);
crypt_free_volume_key(passphrase_key);
crypt_free_volume_key(kek);
if (r < 0) {
crypt_free_volume_key(*vol_key);
*vol_key = NULL;
}
if (hash != NULL)
crypt_hash_destroy(hash);
return r;
@@ -1003,19 +997,48 @@ int FVAULT2_dump(
return 0;
}
int FVAULT2_activate_by_volume_key(
int FVAULT2_activate_by_passphrase(
struct crypt_device *cd,
const char *name,
struct volume_key *vk,
const char *passphrase,
size_t passphrase_len,
const struct fvault2_params *params,
uint32_t flags)
{
assert(crypt_volume_key_length(vk) == FVAULT2_XTS_KEY_SIZE);
int r;
struct volume_key *vol_key = NULL;
return _activate(cd, name, vk, params, flags);
r = FVAULT2_get_volume_key(cd, passphrase, passphrase_len, params, &vol_key);
if (r < 0)
return r;
if (name)
r = _activate(cd, name, vol_key, params, flags);
crypt_free_volume_key(vol_key);
return r;
}
size_t FVAULT2_volume_key_size(void)
int FVAULT2_activate_by_volume_key(
struct crypt_device *cd,
const char *name,
const char *key,
size_t key_size,
const struct fvault2_params *params,
uint32_t flags)
{
return FVAULT2_XTS_KEY_SIZE;
int r = 0;
struct volume_key *vol_key = NULL;
if (key_size != FVAULT2_XTS_KEY_SIZE)
return -EINVAL;
vol_key = crypt_alloc_volume_key(FVAULT2_XTS_KEY_SIZE, key);
if (vol_key == NULL)
return -ENOMEM;
r = _activate(cd, name, vol_key, params, flags);
crypt_free_volume_key(vol_key);
return r;
}

View File

@@ -41,20 +41,27 @@ int FVAULT2_get_volume_key(
const char *passphrase,
size_t passphrase_len,
const struct fvault2_params *params,
struct volume_key **r_vol_key);
struct volume_key **vol_key);
int FVAULT2_dump(
struct crypt_device *cd,
struct device *device,
const struct fvault2_params *params);
int FVAULT2_activate_by_volume_key(
int FVAULT2_activate_by_passphrase(
struct crypt_device *cd,
const char *name,
struct volume_key *vk,
const char *passphrase,
size_t passphrase_len,
const struct fvault2_params *params,
uint32_t flags);
size_t FVAULT2_volume_key_size(void);
int FVAULT2_activate_by_volume_key(
struct crypt_device *cd,
const char *name,
const char *key,
size_t key_size,
const struct fvault2_params *params,
uint32_t flags);
#endif

View File

@@ -2,7 +2,7 @@
/*
* Integrity volume handling
*
* Copyright (C) 2016-2025 Milan Broz
* Copyright (C) 2016-2024 Milan Broz
*/
#include <errno.h>
@@ -31,22 +31,16 @@ static int INTEGRITY_read_superblock(struct crypt_device *cd,
{
int devfd, r;
log_dbg(cd, "Reading kernel dm-integrity metadata on %s.", device_path(device));
devfd = device_open(cd, device, O_RDONLY);
if(devfd < 0)
return -EINVAL;
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
device_alignment(device), sb, sizeof(*sb), offset) != sizeof(*sb)) {
log_dbg(cd, "Cannot read kernel dm-integrity metadata on %s.", device_path(device));
return -EINVAL;
}
if (memcmp(sb->magic, SB_MAGIC, sizeof(sb->magic))) {
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_6) {
} 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));
r = -EINVAL;
@@ -73,10 +67,8 @@ int INTEGRITY_read_sb(struct crypt_device *cd,
if (r)
return r;
if (params) {
params->sector_size = SECTOR_SIZE << sb.log2_sectors_per_block;
params->tag_size = sb.integrity_tag_size;
}
params->sector_size = SECTOR_SIZE << sb.log2_sectors_per_block;
params->tag_size = sb.integrity_tag_size;
if (flags)
*flags = sb.flags;
@@ -87,32 +79,28 @@ int INTEGRITY_read_sb(struct crypt_device *cd,
int INTEGRITY_dump(struct crypt_device *cd, struct device *device, uint64_t offset)
{
struct superblock sb;
uint64_t sector_size;
int r;
r = INTEGRITY_read_superblock(cd, device, offset, &sb);
if (r)
return r;
sector_size = (uint64_t)SECTOR_SIZE << sb.log2_sectors_per_block;
log_std(cd, "INTEGRITY header information for %s.\n", device_path(device));
log_std(cd, "version: %d\n", (unsigned)sb.version);
log_std(cd, "tag size: %u [bytes]\n", sb.integrity_tag_size);
log_std(cd, "sector size: %" PRIu64 " [bytes]\n", sector_size);
log_std(cd, "data size: %" PRIu64 " [512-byte units] (%" PRIu64 " [bytes])\n",
sb.provided_data_sectors, sb.provided_data_sectors * SECTOR_SIZE);
log_std(cd, "Info for integrity device %s.\n", device_path(device));
log_std(cd, "superblock_version %d\n", (unsigned)sb.version);
log_std(cd, "log2_interleave_sectors %d\n", sb.log2_interleave_sectors);
log_std(cd, "integrity_tag_size %u\n", sb.integrity_tag_size);
log_std(cd, "journal_sections %u\n", sb.journal_sections);
log_std(cd, "provided_data_sectors %" PRIu64 "\n", sb.provided_data_sectors);
log_std(cd, "sector_size %u\n", SECTOR_SIZE << sb.log2_sectors_per_block);
if (sb.version >= SB_VERSION_2 && (sb.flags & SB_FLAG_RECALCULATING))
log_std(cd, "recalculate sector: %" PRIu64 "\n", sb.recalc_sector);
log_std(cd, "journal sections: %u\n", sb.journal_sections);
log_std(cd, "log2 interleave sectors: %d\n", sb.log2_interleave_sectors);
log_std(cd, "log2 blocks per bitmap: %u\n", sb.log2_blocks_per_bitmap_bit);
log_std(cd, "flags: %s%s%s%s%s%s\n",
log_std(cd, "recalc_sector %" PRIu64 "\n", sb.recalc_sector);
log_std(cd, "log2_blocks_per_bitmap %u\n", sb.log2_blocks_per_bitmap_bit);
log_std(cd, "flags %s%s%s%s%s\n",
sb.flags & SB_FLAG_HAVE_JOURNAL_MAC ? "have_journal_mac " : "",
sb.flags & SB_FLAG_RECALCULATING ? "recalculating " : "",
sb.flags & SB_FLAG_DIRTY_BITMAP ? "dirty_bitmap " : "",
sb.flags & SB_FLAG_FIXED_PADDING ? "fix_padding " : "",
sb.flags & SB_FLAG_FIXED_HMAC ? "fix_hmac " : "",
sb.flags & SB_FLAG_INLINE ? "inline " : "");
sb.flags & SB_FLAG_FIXED_HMAC ? "fix_hmac " : "");
return 0;
}
@@ -132,42 +120,26 @@ int INTEGRITY_data_sectors(struct crypt_device *cd,
return 0;
}
int INTEGRITY_key_size(const char *integrity, int required_key_size)
int INTEGRITY_key_size(const char *integrity)
{
int ks = 0;
if (!integrity && required_key_size)
return -EINVAL;
if (!integrity)
return 0;
//FIXME: use crypto backend hash size
if (!strcmp(integrity, "aead"))
ks = 0;
return 0;
else if (!strcmp(integrity, "hmac(sha1)"))
ks = required_key_size ?: 20;
return 20;
else if (!strcmp(integrity, "hmac(sha256)"))
ks = required_key_size ?: 32;
return 32;
else if (!strcmp(integrity, "hmac(sha512)"))
ks = required_key_size ?: 64;
else if (!strcmp(integrity, "phmac(sha1)"))
ks = required_key_size ?: -EINVAL;
else if (!strcmp(integrity, "phmac(sha256)"))
ks = required_key_size ?: -EINVAL;
else if (!strcmp(integrity, "phmac(sha512)"))
ks = required_key_size ?: -EINVAL;
return 64;
else if (!strcmp(integrity, "poly1305"))
ks = 0;
return 0;
else if (!strcmp(integrity, "none"))
ks = 0;
else
return -EINVAL;
return 0;
if (required_key_size && ks != required_key_size)
return -EINVAL;
return ks;
return -EINVAL;
}
/* Return hash or hmac(hash) size, if known */
@@ -186,8 +158,6 @@ int INTEGRITY_hash_tag_size(const char *integrity)
return 8;
r = sscanf(integrity, "hmac(%" MAX_CIPHER_LEN_STR "[^)]s", hash);
if (r != 1)
r = sscanf(integrity, "phmac(%" MAX_CIPHER_LEN_STR "[^)]s", hash);
if (r == 1)
r = crypt_hash_size(hash);
else
@@ -230,12 +200,6 @@ int INTEGRITY_tag_size(const char *integrity,
auth_tag_size = 32;
else if (!strcmp(integrity, "hmac(sha512)"))
auth_tag_size = 64;
else if (!strcmp(integrity, "phmac(sha1)"))
auth_tag_size = 20;
else if (!strcmp(integrity, "phmac(sha256)"))
auth_tag_size = 32;
else if (!strcmp(integrity, "phmac(sha512)"))
auth_tag_size = 64;
else if (!strcmp(integrity, "poly1305")) {
if (iv_tag_size)
iv_tag_size = 12;
@@ -266,9 +230,6 @@ int INTEGRITY_create_dmd_device(struct crypt_device *cd,
if (sb_flags & SB_FLAG_RECALCULATING)
dmd->flags |= CRYPT_ACTIVATE_RECALCULATE;
if (sb_flags & SB_FLAG_INLINE)
dmd->flags |= (CRYPT_ACTIVATE_NO_JOURNAL | CRYPT_ACTIVATE_INLINE_MODE);
r = INTEGRITY_data_sectors(cd, INTEGRITY_metadata_device(cd),
crypt_get_data_offset(cd) * SECTOR_SIZE, &dmd->size);
if (r < 0)
@@ -288,15 +249,14 @@ int INTEGRITY_activate_dmd_device(struct crypt_device *cd,
uint32_t sb_flags)
{
int r;
uint64_t dmi_flags;
uint32_t dmi_flags;
struct dm_target *tgt = &dmd->segment;
if (!single_segment(dmd) || tgt->type != DM_INTEGRITY)
return -EINVAL;
log_dbg(cd, "Trying to activate INTEGRITY device on top of %s, using name %s, tag size %d%s, provided sectors %" PRIu64".",
device_path(tgt->data_device), name, tgt->u.integrity.tag_size,
(sb_flags & SB_FLAG_INLINE) ? " (inline)" :"", dmd->size);
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);
@@ -320,12 +280,6 @@ int INTEGRITY_activate_dmd_device(struct crypt_device *cd,
return -ENOTSUP;
}
if (r < 0 && (sb_flags & SB_FLAG_INLINE) && !dm_flags(cd, DM_INTEGRITY, &dmi_flags) &&
!(dmi_flags & DM_INTEGRITY_INLINE_MODE_SUPPORTED)) {
log_err(cd, _("Kernel does not support dm-integrity inline mode."));
return -ENOTSUP;
}
return r;
}
@@ -418,14 +372,11 @@ static int _create_reduced_device(struct crypt_device *cd,
int INTEGRITY_format(struct crypt_device *cd,
const struct crypt_params_integrity *params,
struct volume_key *integrity_key,
struct volume_key *journal_crypt_key,
struct volume_key *journal_mac_key,
uint64_t backing_device_sectors,
uint32_t *sb_flags,
bool integrity_inline)
uint64_t backing_device_sectors)
{
uint64_t dmi_flags;
uint32_t dmi_flags;
char reduced_device_name[70], tmp_name[64], tmp_uuid[40];
struct crypt_dm_active_device dmdi = {
.size = 8,
@@ -436,6 +387,7 @@ int INTEGRITY_format(struct crypt_device *cd,
uuid_t tmp_uuid_bin;
uint64_t data_offset_sectors;
struct device *p_metadata_device, *p_data_device, *reduced_device = NULL;
struct volume_key *vk = NULL;
uuid_generate(tmp_uuid_bin);
uuid_unparse(tmp_uuid_bin, tmp_uuid);
@@ -470,18 +422,19 @@ int INTEGRITY_format(struct crypt_device *cd,
p_data_device = crypt_data_device(cd);
}
if (integrity_inline)
dmdi.flags |= (CRYPT_ACTIVATE_NO_JOURNAL | CRYPT_ACTIVATE_INLINE_MODE);
/* There is no data area, we can actually use fake zeroed key */
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, p_metadata_device,
p_data_device, crypt_get_integrity_tag_size(cd),
data_offset_sectors, crypt_get_sector_size(cd), integrity_key,
data_offset_sectors, crypt_get_sector_size(cd), vk,
journal_crypt_key, journal_mac_key, params);
if (r < 0)
goto err;
log_dbg(cd, "Trying to format INTEGRITY device on top of %s, tmp name %s, tag size %d%s.",
device_path(tgt->data_device), tmp_name, tgt->u.integrity.tag_size, integrity_inline ? " (inline)" : "");
log_dbg(cd, "Trying to format INTEGRITY device on top of %s, tmp name %s, tag size %d.",
device_path(tgt->data_device), tmp_name, tgt->u.integrity.tag_size);
r = device_block_adjust(cd, tgt->data_device, DEV_EXCL, tgt->u.integrity.offset, NULL, NULL);
if (r < 0 && (dm_flags(cd, DM_INTEGRITY, &dmi_flags) || !(dmi_flags & DM_INTEGRITY_SUPPORTED))) {
@@ -502,14 +455,9 @@ int INTEGRITY_format(struct crypt_device *cd,
goto err;
r = dm_remove_device(cd, tmp_name, CRYPT_DEACTIVATE_FORCE);
if (r)
goto err;
/* reload sb_flags from superblock (important for SB_FLAG_INLINE) */
if (sb_flags)
r = INTEGRITY_read_sb(cd, NULL, sb_flags);
err:
dm_targets_free(cd, &dmdi);
crypt_free_volume_key(vk);
if (reduced_device) {
dm_remove_device(cd, reduced_device_name, CRYPT_DEACTIVATE_FORCE);
device_free(cd, reduced_device);

View File

@@ -2,14 +2,13 @@
/*
* Integrity header definition
*
* Copyright (C) 2016-2025 Milan Broz
* Copyright (C) 2016-2024 Milan Broz
*/
#ifndef _CRYPTSETUP_INTEGRITY_H
#define _CRYPTSETUP_INTEGRITY_H
#include <stdint.h>
#include <stdbool.h>
struct crypt_device;
struct device;
@@ -24,14 +23,12 @@ struct crypt_dm_active_device;
#define SB_VERSION_3 3
#define SB_VERSION_4 4
#define SB_VERSION_5 5
#define SB_VERSION_6 6
#define SB_FLAG_HAVE_JOURNAL_MAC (1 << 0)
#define SB_FLAG_RECALCULATING (1 << 1) /* V2 only */
#define SB_FLAG_DIRTY_BITMAP (1 << 2) /* V3 only */
#define SB_FLAG_FIXED_PADDING (1 << 3) /* V4 only */
#define SB_FLAG_FIXED_HMAC (1 << 4) /* V5 only */
#define SB_FLAG_INLINE (1 << 5) /* V6 only */
struct superblock {
uint8_t magic[8];
@@ -43,10 +40,8 @@ struct superblock {
uint32_t flags;
uint8_t log2_sectors_per_block;
uint8_t log2_blocks_per_bitmap_bit; /* V3 only */
uint8_t pad[2]; /* (padding) */
uint8_t pad[2];
uint64_t recalc_sector; /* V2 only */
uint8_t pad2[8]; /* (padding) */
uint8_t salt[16]; /* for fixed hmac, V5 only */
} __attribute__ ((packed));
int INTEGRITY_read_sb(struct crypt_device *cd,
@@ -58,7 +53,7 @@ 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 required_key_size);
int INTEGRITY_key_size(const char *integrity);
int INTEGRITY_tag_size(const char *integrity,
const char *cipher,
const char *cipher_mode);
@@ -66,12 +61,9 @@ int INTEGRITY_hash_tag_size(const char *integrity);
int INTEGRITY_format(struct crypt_device *cd,
const struct crypt_params_integrity *params,
struct volume_key *integrity_key,
struct volume_key *journal_crypt_key,
struct volume_key *journal_mac_key,
uint64_t backing_device_sectors,
uint32_t *sb_flags,
bool integrity_inline);
uint64_t backing_device_sectors);
int INTEGRITY_activate(struct crypt_device *cd,
const char *name,

View File

@@ -4,8 +4,8 @@
*
* Copyright (C) 2004 Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2025 Milan Broz
* Copyright (C) 2009-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2024 Milan Broz
*/
#ifndef INTERNAL_H
@@ -48,36 +48,24 @@
struct crypt_device;
struct luks2_reencrypt;
struct volume_key;
typedef enum {
KEY_QUALITY_KEY = 0,
KEY_QUALITY_NORMAL,
KEY_QUALITY_EMPTY
} key_quality_info;
struct volume_key {
int id;
size_t keylength;
const char *key_description;
struct volume_key *next;
char key[];
};
struct volume_key *crypt_alloc_volume_key(size_t keylength, const char *key);
struct volume_key *crypt_alloc_volume_key_by_safe_alloc(void **safe_alloc);
struct volume_key *crypt_generate_volume_key(struct crypt_device *cd, size_t keylength,
key_quality_info quality);
struct volume_key *crypt_generate_volume_key(struct crypt_device *cd, size_t keylength);
void crypt_free_volume_key(struct volume_key *vk);
const char *crypt_volume_key_get_key(const struct volume_key *vk);
size_t crypt_volume_key_length(const struct volume_key *vk);
int crypt_volume_key_set_description(struct volume_key *key,
const char *key_description, key_type_t keyring_key_type);
int crypt_volume_key_set_description_by_name(struct volume_key *vk, const char *key_name);
key_type_t crypt_volume_key_kernel_key_type(const struct volume_key *vk);
const char *crypt_volume_key_description(const struct volume_key *vk);
int crypt_volume_key_set_description(struct volume_key *key, const char *key_description);
void crypt_volume_key_set_id(struct volume_key *vk, int id);
int crypt_volume_key_get_id(const struct volume_key *vk);
void crypt_volume_key_add_next(struct volume_key **vks, struct volume_key *vk);
struct volume_key *crypt_volume_key_next(struct volume_key *vk);
struct volume_key *crypt_volume_key_by_id(struct volume_key *vk, int id);
void crypt_volume_key_pass_safe_alloc(struct volume_key *vk, void **safe_alloc);
bool crypt_volume_key_is_set(const struct volume_key *vk);
bool crypt_volume_key_upload_kernel_key(struct volume_key *vk);
void crypt_volume_key_drop_uploaded_kernel_key(struct crypt_device *cd, struct volume_key *vk);
void crypt_volume_key_drop_kernel_key(struct crypt_device *cd, struct volume_key *vk);
struct crypt_pbkdf_type *crypt_get_pbkdf(struct crypt_device *cd);
int init_pbkdf_type(struct crypt_device *cd,
@@ -98,6 +86,7 @@ int device_alloc_no_check(struct device **device, const char *path);
void device_close(struct crypt_device *cd, struct device *device);
void device_free(struct crypt_device *cd, struct device *device);
const char *device_path(const struct device *device);
const char *device_dm_name(const struct device *device);
const char *device_block_path(const struct device *device);
void device_topology_alignment(struct crypt_device *cd,
struct device *device,
@@ -115,7 +104,6 @@ int device_is_identical(struct device *device1, struct device *device2);
int device_is_rotational(struct device *device);
int device_is_dax(struct device *device);
int device_is_zoned(struct device *device);
int device_is_nop_dif(struct device *device, uint32_t *tag_size);
size_t device_alignment(struct device *device);
int device_direct_io(const struct device *device);
int device_fallocate(struct device *device, uint64_t size);
@@ -167,7 +155,6 @@ char *crypt_lookup_dev(const char *dev_id);
int crypt_dev_is_rotational(int major, int minor);
int crypt_dev_is_dax(int major, int minor);
int crypt_dev_is_zoned(int major, int minor);
int crypt_dev_is_nop_dif(int major, int minor, uint32_t *tag_size);
int crypt_dev_is_partition(const char *dev_path);
char *crypt_get_partition_device(const char *dev_path, uint64_t offset, uint64_t size);
int crypt_dev_get_partition_number(const char *dev_path);
@@ -175,6 +162,8 @@ char *crypt_get_base_device(const char *dev_path);
uint64_t crypt_dev_partition_offset(const char *dev_path);
int lookup_by_disk_id(const char *dm_uuid);
int lookup_by_sysfs_uuid_field(const char *dm_uuid);
int crypt_uuid_cmp(const char *dm_uuid, const char *hdr_uuid);
int crypt_uuid_type_cmp(const char *dm_uuid, const char *type);
size_t crypt_getpagesize(void);
unsigned crypt_cpusonline(void);
@@ -228,7 +217,7 @@ int crypt_wipe_device(struct crypt_device *cd,
/* Internal integrity helpers */
const char *crypt_get_integrity(struct crypt_device *cd);
int crypt_get_integrity_key_size(struct crypt_device *cd, bool dm_compat);
int crypt_get_integrity_key_size(struct crypt_device *cd);
int crypt_get_integrity_tag_size(struct crypt_device *cd);
int crypt_key_in_keyring(struct crypt_device *cd);
@@ -242,18 +231,9 @@ int crypt_keyring_get_key_by_name(struct crypt_device *cd,
const char *key_description,
char **key,
size_t *key_size);
int crypt_keyring_get_keysize_by_name(struct crypt_device *cd,
const char *key_description,
size_t *r_key_size);
int crypt_use_keyring_for_vk(struct crypt_device *cd);
void crypt_unlink_key_from_thread_keyring(struct crypt_device *cd,
key_serial_t key_id);
void crypt_unlink_key_by_description_from_thread_keyring(struct crypt_device *cd,
const char *key_description,
key_type_t ktype);
void crypt_drop_uploaded_keyring_key(struct crypt_device *cd, struct volume_key *vks);
void crypt_drop_keyring_key_by_description(struct crypt_device *cd, const char *key_description, key_type_t ktype);
void crypt_drop_keyring_key(struct crypt_device *cd, struct volume_key *vks);
static inline uint64_t compact_version(uint16_t major, uint16_t minor, uint16_t patch, uint16_t release)
{
@@ -286,6 +266,4 @@ static inline bool uint64_mult_overflow(uint64_t *u, uint64_t b, size_t size)
#define KEY_EXTERNAL_VERIFICATION -1
#define KEY_VERIFIED 0
size_t crypt_safe_alloc_size(const void *data);
#endif /* INTERNAL_H */

View File

@@ -2,14 +2,12 @@
/*
* LUKS - Linux Unified Key Setup, keyslot unlock helpers
*
* Copyright (C) 2022-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2022-2025 Ondrej Kozina
* Copyright (C) 2022-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2022-2024 Ondrej Kozina
*/
#include <errno.h>
#include "bitlk/bitlk.h"
#include "fvault2/fvault2.h"
#include "luks1/luks.h"
#include "luks2/luks2.h"
#include "keyslot_context.h"
@@ -60,44 +58,6 @@ static int get_luks2_volume_key_by_passphrase(struct crypt_device *cd,
return get_luks2_key_by_passphrase(cd, kc, keyslot, CRYPT_DEFAULT_SEGMENT, r_vk);
}
static int get_bitlk_volume_key_by_passphrase(struct crypt_device *cd,
struct crypt_keyslot_context *kc,
const struct bitlk_metadata *params,
struct volume_key **r_vk)
{
int r;
assert(cd);
assert(kc && kc->type == CRYPT_KC_TYPE_PASSPHRASE);
assert(params);
assert(r_vk);
r = BITLK_get_volume_key(cd, kc->u.p.passphrase, kc->u.p.passphrase_size, params, r_vk);
if (r < 0)
kc->error = r;
return r;
}
static int get_fvault2_volume_key_by_passphrase(struct crypt_device *cd,
struct crypt_keyslot_context *kc,
const struct fvault2_params *params,
struct volume_key **r_vk)
{
int r;
assert(cd);
assert(kc && kc->type == CRYPT_KC_TYPE_PASSPHRASE);
assert(params);
assert(r_vk);
r = FVAULT2_get_volume_key(cd, kc->u.p.passphrase, kc->u.p.passphrase_size, params, r_vk);
if (r < 0)
kc->error = r;
return r;
}
static int get_passphrase_by_passphrase(struct crypt_device *cd,
struct crypt_keyslot_context *kc,
const char **r_passphrase,
@@ -200,56 +160,6 @@ static int get_luks1_volume_key_by_keyfile(struct crypt_device *cd,
return r;
}
static int get_bitlk_volume_key_by_keyfile(struct crypt_device *cd,
struct crypt_keyslot_context *kc,
const struct bitlk_metadata *params,
struct volume_key **r_vk)
{
int r;
const char *passphrase;
size_t passphrase_size;
assert(cd);
assert(kc && kc->type == CRYPT_KC_TYPE_KEYFILE);
assert(params);
assert(r_vk);
r = get_passphrase_by_keyfile(cd, kc, &passphrase, &passphrase_size);
if (r < 0)
return r;
r = BITLK_get_volume_key(cd, passphrase, passphrase_size, params, r_vk);
if (r < 0)
kc->error = r;
return r;
}
static int get_fvault2_volume_key_by_keyfile(struct crypt_device *cd,
struct crypt_keyslot_context *kc,
const struct fvault2_params *params,
struct volume_key **r_vk)
{
int r;
const char *passphrase;
size_t passphrase_size;
assert(cd);
assert(kc && kc->type == CRYPT_KC_TYPE_KEYFILE);
assert(params);
assert(r_vk);
r = get_passphrase_by_keyfile(cd, kc, &passphrase, &passphrase_size);
if (r < 0)
return r;
r = FVAULT2_get_volume_key(cd, passphrase, passphrase_size, params, r_vk);
if (r < 0)
kc->error = r;
return r;
}
static int get_key_by_key(struct crypt_device *cd __attribute__((unused)),
struct crypt_keyslot_context *kc,
int keyslot __attribute__((unused)),
@@ -288,22 +198,6 @@ static int get_generic_volume_key_by_key(struct crypt_device *cd,
return get_key_by_key(cd, kc, -2 /* unused */, -2 /* unused */, r_vk);
}
static int get_bitlk_volume_key_by_key(struct crypt_device *cd,
struct crypt_keyslot_context *kc,
const struct bitlk_metadata *params __attribute__((unused)),
struct volume_key **r_vk)
{
return get_key_by_key(cd, kc, -2 /* unused */, -2 /* unused */, r_vk);
}
static int get_fvault2_volume_key_by_key(struct crypt_device *cd,
struct crypt_keyslot_context *kc,
const struct fvault2_params *params __attribute__((unused)),
struct volume_key **r_vk)
{
return get_key_by_key(cd, kc, -2 /* unused */, -2 /* unused */, r_vk);
}
static int get_generic_signed_key_by_key(struct crypt_device *cd,
struct crypt_keyslot_context *kc,
struct volume_key **r_vk,
@@ -460,7 +354,7 @@ static int get_luks2_key_by_keyring(struct crypt_device *cd,
if (r < 0)
kc->error = r;
return r;
return 0;
}
static int get_luks2_volume_key_by_keyring(struct crypt_device *cd,
@@ -479,7 +373,7 @@ static int get_luks1_volume_key_by_keyring(struct crypt_device *cd,
int r;
assert(cd);
assert(kc && kc->type == CRYPT_KC_TYPE_KEYRING);
assert(kc && kc->type == CRYPT_KC_TYPE_PASSPHRASE);
assert(r_vk);
r = get_passphrase_by_keyring(cd, kc, CONST_CAST(const char **) &kc->i_passphrase,
@@ -520,9 +414,9 @@ static int get_key_by_vk_in_keyring(struct crypt_device *cd,
return -EINVAL;
}
*r_vk = crypt_alloc_volume_key_by_safe_alloc((void **)&key);
*r_vk = crypt_alloc_volume_key(key_size, key);
crypt_safe_free(key);
if (!*r_vk) {
crypt_safe_free(key);
kc->error = -ENOMEM;
return kc->error;
}
@@ -538,41 +432,16 @@ static int get_volume_key_by_vk_in_keyring(struct crypt_device *cd,
return get_key_by_vk_in_keyring(cd, kc, -2 /* unused */, -2 /* unused */, r_vk);
}
static void crypt_keyslot_context_init_common(struct crypt_keyslot_context *kc)
static void unlock_method_init_internal(struct crypt_keyslot_context *kc)
{
assert(kc);
kc->version = KC_VERSION_BASIC;
kc->error = 0;
kc->i_passphrase = NULL;
kc->i_passphrase_size = 0;
}
static void keyring_context_free(struct crypt_keyslot_context *kc)
{
assert(kc && kc->type == CRYPT_KC_TYPE_KEYRING);
free(kc->u.kr.i_key_description);
}
static int keyring_get_key_size(struct crypt_device *cd, struct crypt_keyslot_context *kc, size_t *r_key_size)
{
int r;
assert(kc && kc->type == CRYPT_KC_TYPE_VK_KEYRING);
assert(r_key_size);
if (!kc->u.vk_kr.i_key_size) {
r = crypt_keyring_get_keysize_by_name(cd, kc->u.vk_kr.key_description, &kc->u.vk_kr.i_key_size);
if (r < 0)
return r;
}
*r_key_size = kc->u.vk_kr.i_key_size;
return 0;
}
void crypt_keyslot_context_init_by_keyring_internal(struct crypt_keyslot_context *kc,
void crypt_keyslot_unlock_by_keyring_internal(struct crypt_keyslot_context *kc,
const char *key_description)
{
assert(kc);
@@ -581,32 +450,18 @@ void crypt_keyslot_context_init_by_keyring_internal(struct crypt_keyslot_context
kc->u.kr.key_description = key_description;
kc->get_luks2_key = get_luks2_key_by_keyring;
kc->get_luks1_volume_key = get_luks1_volume_key_by_keyring;
kc->get_luks2_volume_key = get_luks2_volume_key_by_keyring;
kc->get_luks1_volume_key = get_luks1_volume_key_by_keyring;
kc->get_passphrase = get_passphrase_by_keyring;
kc->context_free = keyring_context_free;
crypt_keyslot_context_init_common(kc);
kc->get_plain_volume_key = NULL;
kc->get_bitlk_volume_key = NULL;
kc->get_fvault2_volume_key = NULL;
kc->get_verity_volume_key = NULL;
kc->get_integrity_volume_key = NULL;
unlock_method_init_internal(kc);
}
static void key_context_free(struct crypt_keyslot_context *kc)
{
assert(kc && kc->type == CRYPT_KC_TYPE_KEY);
crypt_free_volume_key(kc->u.k.i_vk);
}
static int key_get_key_size(struct crypt_device *cd __attribute__((unused)),
struct crypt_keyslot_context *kc,
size_t *r_key_size)
{
assert(kc && kc->type == CRYPT_KC_TYPE_KEY);
assert(r_key_size);
*r_key_size = kc->u.k.volume_key_size;
return 0;
}
void crypt_keyslot_context_init_by_key_internal(struct crypt_keyslot_context *kc,
void crypt_keyslot_unlock_by_key_init_internal(struct crypt_keyslot_context *kc,
const char *volume_key,
size_t volume_key_size)
{
@@ -615,29 +470,19 @@ void crypt_keyslot_context_init_by_key_internal(struct crypt_keyslot_context *kc
kc->type = CRYPT_KC_TYPE_KEY;
kc->u.k.volume_key = volume_key;
kc->u.k.volume_key_size = volume_key_size;
kc->get_luks2_key = get_key_by_key;
kc->get_luks1_volume_key = get_volume_key_by_key;
kc->get_luks2_volume_key = get_volume_key_by_key;
kc->get_luks1_volume_key = get_volume_key_by_key;
kc->get_passphrase = NULL; /* keyslot key context does not provide passphrase */
kc->get_plain_volume_key = get_generic_volume_key_by_key;
kc->get_bitlk_volume_key = get_bitlk_volume_key_by_key;
kc->get_fvault2_volume_key = get_fvault2_volume_key_by_key;
kc->get_bitlk_volume_key = get_generic_volume_key_by_key;
kc->get_fvault2_volume_key = get_generic_volume_key_by_key;
kc->get_verity_volume_key = get_generic_signed_key_by_key;
kc->get_integrity_volume_key = get_generic_volume_key_by_key;
kc->get_key_size = key_get_key_size;
kc->context_free = key_context_free;
crypt_keyslot_context_init_common(kc);
unlock_method_init_internal(kc);
}
static void signed_key_context_free(struct crypt_keyslot_context *kc)
{
assert(kc && kc->type == CRYPT_KC_TYPE_SIGNED_KEY);
crypt_free_volume_key(kc->u.ks.i_vk);
crypt_free_volume_key(kc->u.ks.i_vk_sig);
}
void crypt_keyslot_context_init_by_signed_key_internal(struct crypt_keyslot_context *kc,
void crypt_keyslot_unlock_by_signed_key_init_internal(struct crypt_keyslot_context *kc,
const char *volume_key,
size_t volume_key_size,
const char *signature,
@@ -650,13 +495,19 @@ void crypt_keyslot_context_init_by_signed_key_internal(struct crypt_keyslot_cont
kc->u.ks.volume_key_size = volume_key_size;
kc->u.ks.signature = signature;
kc->u.ks.signature_size = signature_size;
kc->get_luks2_key = NULL;
kc->get_luks2_volume_key = NULL;
kc->get_luks1_volume_key = NULL;
kc->get_passphrase = NULL;
kc->get_plain_volume_key = NULL;
kc->get_bitlk_volume_key = NULL;
kc->get_fvault2_volume_key = NULL;
kc->get_verity_volume_key = get_generic_signed_key_by_key;
kc->context_free = signed_key_context_free;
crypt_keyslot_context_init_common(kc);
kc->get_integrity_volume_key = NULL;
unlock_method_init_internal(kc);
}
void crypt_keyslot_context_init_by_passphrase_internal(struct crypt_keyslot_context *kc,
void crypt_keyslot_unlock_by_passphrase_init_internal(struct crypt_keyslot_context *kc,
const char *passphrase,
size_t passphrase_size)
{
@@ -665,24 +516,19 @@ void crypt_keyslot_context_init_by_passphrase_internal(struct crypt_keyslot_cont
kc->type = CRYPT_KC_TYPE_PASSPHRASE;
kc->u.p.passphrase = passphrase;
kc->u.p.passphrase_size = passphrase_size;
kc->get_luks2_key = get_luks2_key_by_passphrase;
kc->get_luks1_volume_key = get_luks1_volume_key_by_passphrase;
kc->get_luks2_volume_key = get_luks2_volume_key_by_passphrase;
kc->get_bitlk_volume_key = get_bitlk_volume_key_by_passphrase;
kc->get_fvault2_volume_key = get_fvault2_volume_key_by_passphrase;
kc->get_luks1_volume_key = get_luks1_volume_key_by_passphrase;
kc->get_passphrase = get_passphrase_by_passphrase;
crypt_keyslot_context_init_common(kc);
kc->get_plain_volume_key = NULL;
kc->get_bitlk_volume_key = NULL;
kc->get_fvault2_volume_key = NULL;
kc->get_verity_volume_key = NULL;
kc->get_integrity_volume_key = NULL;
unlock_method_init_internal(kc);
}
static void keyfile_context_free(struct crypt_keyslot_context *kc)
{
assert(kc && kc->type == CRYPT_KC_TYPE_KEYFILE);
free(kc->u.kf.i_keyfile);
}
void crypt_keyslot_context_init_by_keyfile_internal(struct crypt_keyslot_context *kc,
void crypt_keyslot_unlock_by_keyfile_init_internal(struct crypt_keyslot_context *kc,
const char *keyfile,
size_t keyfile_size,
uint64_t keyfile_offset)
@@ -691,28 +537,21 @@ void crypt_keyslot_context_init_by_keyfile_internal(struct crypt_keyslot_context
kc->type = CRYPT_KC_TYPE_KEYFILE;
kc->u.kf.keyfile = keyfile;
kc->u.kf.keyfile_offset = keyfile_offset;
kc->u.kf.keyfile_size = keyfile_size;
kc->u.kf.keyfile_offset = keyfile_offset;
kc->get_luks2_key = get_luks2_key_by_keyfile;
kc->get_luks1_volume_key = get_luks1_volume_key_by_keyfile;
kc->get_luks2_volume_key = get_luks2_volume_key_by_keyfile;
kc->get_bitlk_volume_key = get_bitlk_volume_key_by_keyfile;
kc->get_fvault2_volume_key = get_fvault2_volume_key_by_keyfile;
kc->get_luks1_volume_key = get_luks1_volume_key_by_keyfile;
kc->get_passphrase = get_passphrase_by_keyfile;
kc->context_free = keyfile_context_free;
crypt_keyslot_context_init_common(kc);
kc->get_plain_volume_key = NULL;
kc->get_bitlk_volume_key = NULL;
kc->get_fvault2_volume_key = NULL;
kc->get_verity_volume_key = NULL;
kc->get_integrity_volume_key = NULL;
unlock_method_init_internal(kc);
}
static void token_context_free(struct crypt_keyslot_context *kc)
{
assert(kc && kc->type == CRYPT_KC_TYPE_TOKEN);
free(kc->u.t.i_type);
crypt_safe_free(kc->u.t.i_pin);
}
void crypt_keyslot_context_init_by_token_internal(struct crypt_keyslot_context *kc,
void crypt_keyslot_unlock_by_token_init_internal(struct crypt_keyslot_context *kc,
int token,
const char *type,
const char *pin,
@@ -727,30 +566,47 @@ void crypt_keyslot_context_init_by_token_internal(struct crypt_keyslot_context *
kc->u.t.pin = pin;
kc->u.t.pin_size = pin_size;
kc->u.t.usrptr = usrptr;
kc->get_luks2_key = get_luks2_key_by_token;
kc->get_luks2_volume_key = get_luks2_volume_key_by_token;
kc->get_luks1_volume_key = NULL; /* LUKS1 is not supported */
kc->get_passphrase = get_passphrase_by_token;
kc->context_free = token_context_free;
crypt_keyslot_context_init_common(kc);
kc->get_plain_volume_key = NULL;
kc->get_bitlk_volume_key = NULL;
kc->get_fvault2_volume_key = NULL;
kc->get_verity_volume_key = NULL;
kc->get_integrity_volume_key = NULL;
unlock_method_init_internal(kc);
}
static void vk_in_keyring_context_free(struct crypt_keyslot_context *kc)
void crypt_keyslot_unlock_by_vk_in_keyring_internal(struct crypt_keyslot_context *kc,
const char *key_description)
{
assert(kc && kc->type == CRYPT_KC_TYPE_VK_KEYRING);
assert(kc);
free(kc->u.vk_kr.i_key_description);
kc->type = CRYPT_KC_TYPE_VK_KEYRING;
kc->u.vk_kr.key_description = key_description;
kc->get_luks2_key = get_key_by_vk_in_keyring;
kc->get_luks2_volume_key = get_volume_key_by_vk_in_keyring;
kc->get_luks1_volume_key = NULL;
kc->get_passphrase = NULL; /* keyslot key context does not provide passphrase */
kc->get_plain_volume_key = NULL;
kc->get_bitlk_volume_key = NULL;
kc->get_fvault2_volume_key = NULL;
kc->get_verity_volume_key = NULL;
kc->get_integrity_volume_key = NULL;
unlock_method_init_internal(kc);
}
void crypt_keyslot_context_destroy_internal(struct crypt_keyslot_context *kc)
{
if (!kc)
return;
if (kc->context_free)
kc->context_free(kc);
crypt_safe_free(kc->i_passphrase);
kc->i_passphrase = NULL;
kc->i_passphrase_size = 0;
}
void crypt_keyslot_context_free(struct crypt_keyslot_context *kc)
@@ -759,443 +615,157 @@ void crypt_keyslot_context_free(struct crypt_keyslot_context *kc)
free(kc);
}
static int _crypt_keyslot_context_init_by_passphrase(const char *passphrase,
int crypt_keyslot_context_init_by_passphrase(struct crypt_device *cd __attribute__((unused)),
const char *passphrase,
size_t passphrase_size,
struct crypt_keyslot_context **kc,
bool self_contained)
struct crypt_keyslot_context **kc)
{
struct crypt_keyslot_context *tmp;
char *i_passphrase = NULL;
if (!kc || !passphrase)
return -EINVAL;
tmp = crypt_zalloc(sizeof(*tmp));
tmp = malloc(sizeof(*tmp));
if (!tmp)
return -ENOMEM;
if (self_contained) {
if (passphrase_size) {
i_passphrase = crypt_safe_alloc(passphrase_size);
if (!i_passphrase) {
free(tmp);
return -ENOMEM;
}
crypt_safe_memcpy(i_passphrase, passphrase, passphrase_size);
passphrase = i_passphrase;
} else
/*
* some crypto backend libraries expect a pointer even though
* passed passphrase size is set to zero.
*/
passphrase = "";
}
crypt_keyslot_context_init_by_passphrase_internal(tmp, passphrase, passphrase_size);
if (self_contained) {
tmp->i_passphrase = i_passphrase;
tmp->i_passphrase_size = passphrase_size;
tmp->version = KC_VERSION_SELF_CONTAINED;
}
crypt_keyslot_unlock_by_passphrase_init_internal(tmp, passphrase, passphrase_size);
*kc = tmp;
return 0;
}
CRYPT_SYMBOL_EXPORT_NEW(int, crypt_keyslot_context_init_by_passphrase, 2, 8,
/* crypt_keyslot_context_init_by_passphrase parameters follows */
struct crypt_device *cd __attribute__((unused)),
const char *passphrase,
size_t passphrase_size,
struct crypt_keyslot_context **kc)
{
return _crypt_keyslot_context_init_by_passphrase(passphrase, passphrase_size, kc, true);
}
CRYPT_SYMBOL_EXPORT_OLD(int, crypt_keyslot_context_init_by_passphrase, 2, 6,
/* crypt_keyslot_context_init_by_passphrase parameters follows */
struct crypt_device *cd __attribute__((unused)),
const char *passphrase,
size_t passphrase_size,
struct crypt_keyslot_context **kc)
{
return _crypt_keyslot_context_init_by_passphrase(passphrase, passphrase_size, kc, false);
}
static int _crypt_keyslot_context_init_by_keyfile(const char *keyfile,
int crypt_keyslot_context_init_by_keyfile(struct crypt_device *cd __attribute__((unused)),
const char *keyfile,
size_t keyfile_size,
uint64_t keyfile_offset,
struct crypt_keyslot_context **kc,
bool self_contained)
struct crypt_keyslot_context **kc)
{
char *i_keyfile;
struct crypt_keyslot_context *tmp;
if (!kc || !keyfile)
return -EINVAL;
tmp = crypt_zalloc(sizeof(*tmp));
tmp = malloc(sizeof(*tmp));
if (!tmp)
return -ENOMEM;
if (self_contained) {
i_keyfile = strdup(keyfile);
if (!i_keyfile) {
free(tmp);
return -ENOMEM;
}
keyfile = i_keyfile;
}
crypt_keyslot_context_init_by_keyfile_internal(tmp, keyfile, keyfile_size, keyfile_offset);
if (self_contained) {
tmp->u.kf.i_keyfile = i_keyfile;
tmp->version = KC_VERSION_SELF_CONTAINED;
}
crypt_keyslot_unlock_by_keyfile_init_internal(tmp, keyfile, keyfile_size, keyfile_offset);
*kc = tmp;
return 0;
}
CRYPT_SYMBOL_EXPORT_NEW(int, crypt_keyslot_context_init_by_keyfile, 2, 8,
/* crypt_keyslot_context_init_by_keyfile parameters follows */
struct crypt_device *cd __attribute__((unused)),
const char *keyfile,
size_t keyfile_size,
uint64_t keyfile_offset,
struct crypt_keyslot_context **kc)
{
return _crypt_keyslot_context_init_by_keyfile(keyfile, keyfile_size, keyfile_offset, kc, true);
}
CRYPT_SYMBOL_EXPORT_OLD(int, crypt_keyslot_context_init_by_keyfile, 2, 6,
/* crypt_keyslot_context_init_by_keyfile parameters follows */
struct crypt_device *cd __attribute__((unused)),
const char *keyfile,
size_t keyfile_size,
uint64_t keyfile_offset,
struct crypt_keyslot_context **kc)
{
return _crypt_keyslot_context_init_by_keyfile(keyfile, keyfile_size, keyfile_offset, kc, false);
}
static int _crypt_keyslot_context_init_by_token(int token,
int crypt_keyslot_context_init_by_token(struct crypt_device *cd __attribute__((unused)),
int token,
const char *type,
const char *pin, size_t pin_size,
void *usrptr,
struct crypt_keyslot_context **kc,
bool self_contained)
struct crypt_keyslot_context **kc)
{
char *i_type = NULL, *i_pin = NULL;
struct crypt_keyslot_context *tmp;
if (!kc || (token < 0 && token != CRYPT_ANY_TOKEN) ||
(pin && !pin_size))
if (!kc || (token < 0 && token != CRYPT_ANY_TOKEN))
return -EINVAL;
tmp = crypt_zalloc(sizeof(*tmp));
tmp = malloc(sizeof(*tmp));
if (!tmp)
return -ENOMEM;
if (self_contained && type) {
if (!(i_type = strdup(type)))
goto err;
type = i_type;
}
if (self_contained && pin) {
if (!(i_pin = crypt_safe_alloc(pin_size)))
goto err;
crypt_safe_memcpy(i_pin, pin, pin_size);
pin = i_pin;
}
crypt_keyslot_context_init_by_token_internal(tmp, token, type, pin, pin_size, usrptr);
if (self_contained) {
tmp->u.t.i_pin = i_pin;
tmp->u.t.i_type = i_type;
tmp->version = KC_VERSION_SELF_CONTAINED;
}
crypt_keyslot_unlock_by_token_init_internal(tmp, token, type, pin, pin_size, usrptr);
*kc = tmp;
return 0;
err:
crypt_safe_free(i_pin);
free(i_type);
free(tmp);
return -ENOMEM;
}
CRYPT_SYMBOL_EXPORT_NEW(int, crypt_keyslot_context_init_by_token, 2, 8,
/* crypt_keyslot_context_init_by_token parameters follows */
struct crypt_device *cd __attribute__((unused)),
int token,
const char *type,
const char *pin, size_t pin_size,
void *usrptr,
struct crypt_keyslot_context **kc)
{
return _crypt_keyslot_context_init_by_token(token, type, pin, pin_size, usrptr, kc, true);
}
CRYPT_SYMBOL_EXPORT_OLD(int, crypt_keyslot_context_init_by_token, 2, 6,
/* crypt_keyslot_context_init_by_token parameters follows */
struct crypt_device *cd __attribute__((unused)),
int token,
const char *type,
const char *pin, size_t pin_size,
void *usrptr,
struct crypt_keyslot_context **kc)
{
return _crypt_keyslot_context_init_by_token(token, type, pin, pin_size, usrptr, kc, false);
}
static int _crypt_keyslot_context_init_by_volume_key(const char *volume_key,
int crypt_keyslot_context_init_by_volume_key(struct crypt_device *cd __attribute__((unused)),
const char *volume_key,
size_t volume_key_size,
struct crypt_keyslot_context **kc,
bool self_contained)
struct crypt_keyslot_context **kc)
{
struct volume_key *i_vk = NULL;
struct crypt_keyslot_context *tmp;
if (!kc)
return -EINVAL;
tmp = crypt_zalloc(sizeof(*tmp));
tmp = malloc(sizeof(*tmp));
if (!tmp)
return -ENOMEM;
if (self_contained && volume_key) {
if (!(i_vk = crypt_alloc_volume_key(volume_key_size, volume_key))) {
free(tmp);
return -ENOMEM;
}
volume_key = crypt_volume_key_get_key(i_vk);
}
crypt_keyslot_context_init_by_key_internal(tmp, volume_key, volume_key_size);
if (self_contained) {
tmp->u.k.i_vk = i_vk;
tmp->version = KC_VERSION_SELF_CONTAINED;
}
crypt_keyslot_unlock_by_key_init_internal(tmp, volume_key, volume_key_size);
*kc = tmp;
return 0;
}
CRYPT_SYMBOL_EXPORT_NEW(int, crypt_keyslot_context_init_by_volume_key, 2, 8,
/* crypt_keyslot_context_init_by_volume_key parameters follows */
struct crypt_device *cd __attribute__((unused)),
int crypt_keyslot_context_init_by_signed_key(struct crypt_device *cd __attribute__((unused)),
const char *volume_key,
size_t volume_key_size,
struct crypt_keyslot_context **kc)
{
return _crypt_keyslot_context_init_by_volume_key(volume_key, volume_key_size, kc, true);
}
CRYPT_SYMBOL_EXPORT_OLD(int, crypt_keyslot_context_init_by_volume_key, 2, 6,
/* crypt_keyslot_context_init_by_volume_key parameters follows */
struct crypt_device *cd __attribute__((unused)),
const char *volume_key,
size_t volume_key_size,
struct crypt_keyslot_context **kc)
{
return _crypt_keyslot_context_init_by_volume_key(volume_key, volume_key_size, kc, false);
}
static int _crypt_keyslot_context_init_by_signed_key(const char *volume_key,
size_t volume_key_size,
const char *signature,
size_t signature_size,
struct crypt_keyslot_context **kc,
bool self_contained)
struct crypt_keyslot_context **kc)
{
struct volume_key *i_vk = NULL, *i_vk_sig = NULL;
struct crypt_keyslot_context *tmp;
if (!kc)
return -EINVAL;
tmp = crypt_zalloc(sizeof(*tmp));
tmp = malloc(sizeof(*tmp));
if (!tmp)
return -ENOMEM;
if (self_contained && volume_key) {
if (!(i_vk = crypt_alloc_volume_key(volume_key_size, volume_key)))
goto err;
volume_key = crypt_volume_key_get_key(i_vk);
}
if (self_contained && signature) {
if (!(i_vk_sig = crypt_alloc_volume_key(signature_size, signature)))
goto err;
signature = crypt_volume_key_get_key(i_vk_sig);
}
crypt_keyslot_context_init_by_signed_key_internal(tmp, volume_key, volume_key_size,
crypt_keyslot_unlock_by_signed_key_init_internal(tmp, volume_key, volume_key_size,
signature, signature_size);
if (self_contained) {
tmp->u.ks.i_vk = i_vk;
tmp->u.ks.i_vk_sig = i_vk_sig;
tmp->version = KC_VERSION_SELF_CONTAINED;
}
*kc = tmp;
return 0;
err:
crypt_free_volume_key(i_vk);
crypt_free_volume_key(i_vk_sig);
free(tmp);
return -ENOMEM;
}
CRYPT_SYMBOL_EXPORT_NEW(int, crypt_keyslot_context_init_by_signed_key, 2, 8,
/* crypt_keyslot_context_init_by_signed_key parameters follows */
struct crypt_device *cd __attribute__((unused)),
const char *volume_key,
size_t volume_key_size,
const char *signature,
size_t signature_size,
int crypt_keyslot_context_init_by_keyring(struct crypt_device *cd __attribute__((unused)),
const char *key_description,
struct crypt_keyslot_context **kc)
{
return _crypt_keyslot_context_init_by_signed_key(volume_key, volume_key_size, signature, signature_size, kc, true);
}
CRYPT_SYMBOL_EXPORT_OLD(int, crypt_keyslot_context_init_by_signed_key, 2, 7,
/* crypt_keyslot_context_init_by_signed_key parameters follows */
struct crypt_device *cd __attribute__((unused)),
const char *volume_key,
size_t volume_key_size,
const char *signature,
size_t signature_size,
struct crypt_keyslot_context **kc)
{
return _crypt_keyslot_context_init_by_signed_key(volume_key, volume_key_size, signature, signature_size, kc, false);
}
static int _crypt_keyslot_context_init_by_keyring(const char *key_description,
struct crypt_keyslot_context **kc,
bool self_contained)
{
char *i_key_description;
struct crypt_keyslot_context *tmp;
if (!kc || !key_description)
if (!kc)
return -EINVAL;
tmp = crypt_zalloc(sizeof(*tmp));
tmp = malloc(sizeof(*tmp));
if (!tmp)
return -ENOMEM;
if (self_contained) {
if (!(i_key_description = strdup(key_description))) {
free(tmp);
return -ENOMEM;
}
key_description = i_key_description;
}
crypt_keyslot_context_init_by_keyring_internal(tmp, key_description);
if (self_contained) {
tmp->u.kr.i_key_description = i_key_description;
tmp->version = KC_VERSION_SELF_CONTAINED;
}
crypt_keyslot_unlock_by_keyring_internal(tmp, key_description);
*kc = tmp;
return 0;
}
CRYPT_SYMBOL_EXPORT_NEW(int, crypt_keyslot_context_init_by_keyring, 2, 8,
/* crypt_keyslot_context_init_by_keyring parameters follows */
struct crypt_device *cd __attribute__((unused)),
int crypt_keyslot_context_init_by_vk_in_keyring(struct crypt_device *cd __attribute__((unused)),
const char *key_description,
struct crypt_keyslot_context **kc)
{
return _crypt_keyslot_context_init_by_keyring(key_description, kc, true);
}
CRYPT_SYMBOL_EXPORT_OLD(int, crypt_keyslot_context_init_by_keyring, 2, 7,
/* crypt_keyslot_context_init_by_keyring parameters follows */
struct crypt_device *cd __attribute__((unused)),
const char *key_description,
struct crypt_keyslot_context **kc)
{
return _crypt_keyslot_context_init_by_keyring(key_description, kc, false);
}
static int _crypt_keyslot_context_init_by_vk_in_keyring(const char *key_description,
struct crypt_keyslot_context **kc,
bool self_contained)
{
char *i_key_description;
struct crypt_keyslot_context *tmp;
if (!kc || !key_description)
if (!kc)
return -EINVAL;
tmp = crypt_zalloc(sizeof(*tmp));
tmp = malloc(sizeof(*tmp));
if (!tmp)
return -ENOMEM;
if (self_contained) {
if (!(i_key_description = strdup(key_description))) {
free(tmp);
return -ENOMEM;
}
key_description = i_key_description;
}
tmp->type = CRYPT_KC_TYPE_VK_KEYRING;
tmp->u.vk_kr.key_description = key_description;
tmp->get_luks2_key = get_key_by_vk_in_keyring;
tmp->get_luks2_volume_key = get_volume_key_by_vk_in_keyring;
tmp->get_key_size = keyring_get_key_size;
tmp->context_free = vk_in_keyring_context_free;
crypt_keyslot_context_init_common(tmp);
if (self_contained) {
tmp->u.vk_kr.i_key_description = i_key_description;
tmp->version = KC_VERSION_SELF_CONTAINED;
}
crypt_keyslot_unlock_by_vk_in_keyring_internal(tmp, key_description);
*kc = tmp;
return 0;
}
CRYPT_SYMBOL_EXPORT_NEW(int, crypt_keyslot_context_init_by_vk_in_keyring, 2, 8,
/* crypt_keyslot_context_init_by_vk_in_keyring parameters follows */
struct crypt_device *cd __attribute__((unused)),
const char *key_description,
struct crypt_keyslot_context **kc)
{
return _crypt_keyslot_context_init_by_vk_in_keyring(key_description, kc, true);
}
CRYPT_SYMBOL_EXPORT_OLD(int, crypt_keyslot_context_init_by_vk_in_keyring, 2, 7,
/* crypt_keyslot_context_init_by_vk_in_keyring parameters follows */
struct crypt_device *cd __attribute__((unused)),
const char *key_description,
struct crypt_keyslot_context **kc)
{
return _crypt_keyslot_context_init_by_vk_in_keyring(key_description, kc, false);
}
int crypt_keyslot_context_get_error(struct crypt_keyslot_context *kc)
{
return kc ? kc->error : -EINVAL;
@@ -1205,21 +775,10 @@ int crypt_keyslot_context_set_pin(struct crypt_device *cd __attribute__((unused)
const char *pin, size_t pin_size,
struct crypt_keyslot_context *kc)
{
char *i_pin = NULL;
if (!kc || kc->type != CRYPT_KC_TYPE_TOKEN)
return -EINVAL;
if (kc->version >= KC_VERSION_SELF_CONTAINED && pin) {
if (!(i_pin = crypt_safe_alloc(pin_size)))
return -ENOMEM;
crypt_safe_memcpy(i_pin, pin, pin_size);
}
crypt_safe_free(kc->u.t.i_pin);
kc->u.t.i_pin = i_pin;
kc->u.t.pin = i_pin ?: pin;
kc->u.t.pin = pin;
kc->u.t.pin_size = pin_size;
kc->error = 0;

View File

@@ -2,8 +2,8 @@
/*
* LUKS - Linux Unified Key Setup, keyslot unlock helpers
*
* Copyright (C) 2022-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2022-2025 Ondrej Kozina
* Copyright (C) 2022-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2022-2024 Ondrej Kozina
*/
#ifndef KEYSLOT_CONTEXT_H
@@ -14,9 +14,6 @@
#include "internal.h"
struct bitlk_metadata;
struct fvault2_params;
typedef int (*keyslot_context_get_key) (
struct crypt_device *cd,
struct crypt_keyslot_context *kc,
@@ -35,19 +32,6 @@ typedef int (*keyslot_context_get_generic_volume_key) (
struct crypt_keyslot_context *kc,
struct volume_key **r_vk);
typedef int (*keyslot_context_get_bitlk_volume_key) (
struct crypt_device *cd,
struct crypt_keyslot_context *kc,
const struct bitlk_metadata *params,
struct volume_key **r_vk);
typedef int (*keyslot_context_get_fvault2_volume_key) (
struct crypt_device *cd,
struct crypt_keyslot_context *kc,
const struct fvault2_params *params,
struct volume_key **r_vk);
typedef int (*keyslot_context_get_generic_signed_key) (
struct crypt_device *cd,
struct crypt_keyslot_context *kc,
@@ -60,28 +44,10 @@ typedef int (*keyslot_context_get_passphrase) (
const char **r_passphrase,
size_t *r_passphrase_size);
typedef void (*keyslot_context_free) (
struct crypt_keyslot_context *kc);
typedef int (*keyslot_context_get_key_size) (
struct crypt_device *cd,
struct crypt_keyslot_context *kc,
size_t *r_key_size);
#define KC_VERSION_BASIC UINT8_C(1)
#define KC_VERSION_SELF_CONTAINED UINT8_C(2)
/* crypt_keyslot_context */
struct crypt_keyslot_context {
int type;
/* versions:
* v1: All passed pointers (e.g.: type, passphrase, keyfile,...) must
* be valid after ctx initialization.
* v2: Fully self-contained
*/
uint8_t version;
union {
struct {
const char *passphrase;
@@ -89,40 +55,31 @@ struct crypt_keyslot_context {
} p;
struct {
const char *keyfile;
char *i_keyfile;
uint64_t keyfile_offset;
size_t keyfile_size;
} kf;
struct {
int id;
const char *type;
char *i_type;
const char *pin;
char *i_pin;
size_t pin_size;
void *usrptr;
} t;
struct {
const char *volume_key;
size_t volume_key_size;
struct volume_key *i_vk;
} k;
struct {
const char *volume_key;
size_t volume_key_size;
struct volume_key *i_vk;
const char *signature;
size_t signature_size;
struct volume_key *i_vk_sig;
} ks;
struct {
const char *key_description;
char *i_key_description;
} kr;
struct {
const char *key_description;
char *i_key_description;
size_t i_key_size;
} vk_kr;
} u;
@@ -135,44 +92,45 @@ struct crypt_keyslot_context {
keyslot_context_get_volume_key get_luks1_volume_key;
keyslot_context_get_volume_key get_luks2_volume_key;
keyslot_context_get_generic_volume_key get_plain_volume_key;
keyslot_context_get_bitlk_volume_key get_bitlk_volume_key;
keyslot_context_get_fvault2_volume_key get_fvault2_volume_key;
keyslot_context_get_generic_volume_key get_bitlk_volume_key;
keyslot_context_get_generic_volume_key get_fvault2_volume_key;
keyslot_context_get_generic_signed_key get_verity_volume_key;
keyslot_context_get_generic_volume_key get_integrity_volume_key;
keyslot_context_get_passphrase get_passphrase;
keyslot_context_get_key_size get_key_size;
keyslot_context_free context_free;
};
void crypt_keyslot_context_destroy_internal(struct crypt_keyslot_context *method);
void crypt_keyslot_context_init_by_key_internal(struct crypt_keyslot_context *kc,
void crypt_keyslot_unlock_by_key_init_internal(struct crypt_keyslot_context *kc,
const char *volume_key,
size_t volume_key_size);
void crypt_keyslot_context_init_by_signed_key_internal(struct crypt_keyslot_context *kc,
void crypt_keyslot_unlock_by_signed_key_init_internal(struct crypt_keyslot_context *kc,
const char *volume_key,
size_t volume_key_size,
const char *signature,
size_t signature_size);
void crypt_keyslot_context_init_by_passphrase_internal(struct crypt_keyslot_context *kc,
void crypt_keyslot_unlock_by_passphrase_init_internal(struct crypt_keyslot_context *kc,
const char *passphrase,
size_t passphrase_size);
void crypt_keyslot_context_init_by_keyfile_internal(struct crypt_keyslot_context *kc,
void crypt_keyslot_unlock_by_keyfile_init_internal(struct crypt_keyslot_context *kc,
const char *keyfile,
size_t keyfile_size,
uint64_t keyfile_offset);
void crypt_keyslot_context_init_by_token_internal(struct crypt_keyslot_context *kc,
void crypt_keyslot_unlock_by_token_init_internal(struct crypt_keyslot_context *kc,
int token,
const char *type,
const char *pin,
size_t pin_size,
void *usrptr);
void crypt_keyslot_context_init_by_keyring_internal(struct crypt_keyslot_context *kc,
void crypt_keyslot_unlock_by_keyring_internal(struct crypt_keyslot_context *kc,
const char *key_description);
void crypt_keyslot_unlock_by_vk_in_keyring_internal(struct crypt_keyslot_context *kc,
const char *key_description);
const char *keyslot_context_type_string(const struct crypt_keyslot_context *kc);

View File

@@ -4,8 +4,8 @@
*
* Copyright (C) 2004 Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2025 Milan Broz
* Copyright (C) 2009-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2024 Milan Broz
*/
/**
@@ -594,7 +594,7 @@ struct crypt_params_integrity {
uint32_t sector_size; /**< sector size in bytes */
uint32_t buffer_sectors; /**< number of sectors in one buffer */
const char *integrity; /**< integrity algorithm, NULL for LUKS2 */
uint32_t integrity_key_size; /**< integrity key size in bytes, info only */
uint32_t integrity_key_size; /**< integrity key size in bytes, info only, 0 for LUKS2 */
const char *journal_integrity; /**< journal integrity algorithm */
const char *journal_integrity_key; /**< journal integrity key, only for crypt_load */
@@ -703,35 +703,6 @@ int crypt_format_luks2_opal(struct crypt_device *cd,
struct crypt_params_luks2 *params,
struct crypt_params_hw_opal *opal_params);
/**
* Create (format) new integrity-protected device using integrity inline mode (HW sector tags).
* This can be used for @e INTEGRITY and @e LUKS2 with integrity protection
*
* @pre @e cd contains initialized and not formatted device context (device type must @b not be set)
*
* @param cd crypt device handle
* @param type type of device (optional params struct must be of this type)
* @param cipher (e.g. "aes") or @e NULL for @e INTEGRITY
* @param cipher_mode including IV specification (e.g. "xts-plain") or @e NULL for @e INTEGRITY
* @param uuid requested UUID or @e NULL if it should be generated
* @param volume_key pre-generated integrity/volume key (if needed) or @e NULL
* @param volume_key_size size of volume/integrity key in bytes.
* @param params crypt type specific parameters (see @link crypt-type @endlink)
*
* @returns @e 0 on success or negative errno value otherwise.
*
* @note Journal parameters must be set to zero in integrity part of @e params.
* Only tag_size, sector_size, buffer_sectors, integrity options should be set.
*/
int crypt_format_inline(struct crypt_device *cd,
const char *type,
const char *cipher,
const char *cipher_mode,
const char *uuid,
const char *volume_key,
size_t volume_key_size,
void *params);
/**
* Set format compatibility flags.
*
@@ -1233,10 +1204,6 @@ void crypt_keyslot_context_free(struct crypt_keyslot_context *kc);
* @param kc returns crypt keyslot context handle type CRYPT_KC_TYPE_PASSPHRASE
*
* @return zero on success or negative errno otherwise.
*
* @note The original buffer containing passphrase passed in parameters does
* not have to be valid after context initialization. The context
* contains copy of the original before freed with @link crypt_keyslot_context_free @endlink.
*/
int crypt_keyslot_context_init_by_passphrase(struct crypt_device *cd,
const char *passphrase,
@@ -1537,12 +1504,6 @@ int crypt_keyslot_destroy(struct crypt_device *cd, int keyslot);
#define CRYPT_ACTIVATE_RECALCULATE_RESET (UINT32_C(1) << 26)
/** dm-verity: try to use tasklets */
#define CRYPT_ACTIVATE_TASKLETS (UINT32_C(1) << 27)
/** dm-crypt: use high-priority workqueues */
#define CRYPT_ACTIVATE_HIGH_PRIORITY (UINT32_C(1) << 28)
/** dm-verity: also restart/panic on error, use with RESTART_ON_CORRUPTION or PANIC_ON_CORRUPTION */
#define CRYPT_ACTIVATE_ERROR_AS_CORRUPTION (UINT32_C(1) << 29)
/** dm-integrity: inline mode for compatible hardware profile */
#define CRYPT_ACTIVATE_INLINE_MODE (UINT32_C(1) << 30)
/**
* Active device runtime attributes
@@ -1596,8 +1557,6 @@ uint64_t crypt_get_active_integrity_failures(struct crypt_device *cd,
#define CRYPT_REQUIREMENT_ONLINE_REENCRYPT (UINT32_C(1) << 1)
/** Device configured with OPAL support */
#define CRYPT_REQUIREMENT_OPAL (UINT32_C(1) << 2)
/** Device configured with inline HW tags */
#define CRYPT_REQUIREMENT_INLINE_HW_TAGS (UINT32_C(1) << 3)
/** unknown requirement in header (output only) */
#define CRYPT_REQUIREMENT_UNKNOWN (UINT32_C(1) << 31)
@@ -1620,11 +1579,9 @@ typedef enum {
*
* @note Valid only for LUKS2.
*
* @note Not all activation flags can be stored. Only CRYPT_ACTIVATE_ALLOW_DISCARDS,
* CRYPT_ACTIVATE_SAME_CPU_CRYPT, CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS,
* CRYPT_ACTIVATE_NO_JOURNAL, CRYPT_ACTIVATE_NO_READ_WORKQUEUE,
* CRYPT_ACTIVATE_NO_WRITE_WORKQUEUE and CRYPT_ACTIVATE_HIGH_PRIORITY
* can be stored persistently.
* @note Not all activation flags can be stored. Only ALLOW_DISCARD,
* SAME_CPU_CRYPT, SUBMIT_FROM_CRYPT_CPU and NO_JOURNAL can be
* stored persistently.
*
* @note Only requirements flags recognised by current library may be set.
* CRYPT_REQUIREMENT_UNKNOWN is illegal (output only) in set operation.
@@ -2067,19 +2024,6 @@ uint64_t crypt_get_iv_offset(struct crypt_device *cd);
*/
int crypt_get_volume_key_size(struct crypt_device *cd);
/**
* Get size (in bytes) of old volume key for LUKS2 device in reencryption.
*
* @param cd crypt LUKS2 device handle
*
* @return old volume key size when device is in reencryption state
*
* @note For LUKS2, this function can be used only if there is at least
* one keyslot assigned to old data segment. Also with reencryption
* mode 'encrypt' there's no old volume key.
*/
int crypt_get_old_volume_key_size(struct crypt_device *cd);
/**
* Get size (in bytes) of encryption sector for crypt device.
*
@@ -2117,18 +2061,6 @@ int crypt_header_is_detached(struct crypt_device *cd);
int crypt_get_verity_info(struct crypt_device *cd,
struct crypt_params_verity *vp);
/**
* Get FEC repaired block count for VERITY device.
*
* @param cd crypt device handle
* @param name verity device name
* @param repaired FEC repaired blocks
*
* @return @e 0 on success or negative errno value otherwise.
*/
int crypt_get_verity_repaired(struct crypt_device *cd, const char *name,
uint64_t *repaired);
/**
* Get device parameters for INTEGRITY device.
*
@@ -2663,11 +2595,11 @@ int crypt_token_luks2_keyring_get(struct crypt_device *cd,
* (There can be more keyslots assigned to one token id.)
*
* @param cd crypt device handle
* @param token specific token id
* @param token token id
* @param keyslot keyslot to be assigned to token (CRYPT_ANY SLOT
* assigns all active keyslots to token)
*
* @return requested token id to be assigned or negative errno otherwise.
* @return allocated token id or negative errno otherwise.
*/
int crypt_token_assign_keyslot(struct crypt_device *cd,
int token,
@@ -2678,11 +2610,11 @@ int crypt_token_assign_keyslot(struct crypt_device *cd,
* (There can be more keyslots assigned to one token id.)
*
* @param cd crypt device handle
* @param token specific token id
* @param token token id
* @param keyslot keyslot to be unassigned from token (CRYPT_ANY SLOT
* unassigns all active keyslots from token)
*
* @return requested token id to be unassigned or negative errno otherwise.
* @return allocated token id or negative errno otherwise.
*/
int crypt_token_unassign_keyslot(struct crypt_device *cd,
int token,
@@ -2967,12 +2899,6 @@ int crypt_activate_by_token_pin(struct crypt_device *cd,
#define CRYPT_REENCRYPT_RECOVERY (UINT32_C(1) << 3)
/** Reencryption requires metadata protection. (in/out) */
#define CRYPT_REENCRYPT_REPAIR_NEEDED (UINT32_C(1) << 4)
/**
* Calculate new (future) volume key digest directly during
* reencryption initialization. The keyslot context for new
* volume key must be CRYPT_KC_TYPE_KEY or
* CRYPT_KC_TYPE_VK_KEYRING. (in) */
#define CRYPT_REENCRYPT_CREATE_NEW_DIGEST (UINT32_C(1) << 5)
/**
* Reencryption direction
@@ -3069,71 +2995,6 @@ int crypt_reencrypt_init_by_keyring(struct crypt_device *cd,
const char *cipher_mode,
const struct crypt_params_reencrypt *params);
/**
*
* Initialize or reload LUKS2 reencryption operation using keyslot contexts.
*
* The function can initialize reencryption on-disk metadata or reload reencryption
* context from on-disk LUSK2 metadata to resume interrupted operation.
*
* If the device is not in reencryption state (@link crypt_reencrypt_status @endlink
* returns @link CRYPT_REENCRYPT_NONE @endlink) the function initializes on-disk
* metadata to include all necessary reencryption segments and new encryption
* parameters (cipher, cipher mode, encryption sector size) according to the
* provided parameters.
*
* If on-disk metadata already describes reencryption operation
* (@link crypt_reencrypt_status @endlink returns @link CRYPT_REENCRYPT_CLEAN @endlink),
* it loads these parameters and internally initializes reencryption context. It also verifies
* if the device is eligible to resume reencryption operation. Some reencryption parameters
* (@link crypt_params_reencrypt @endlink) may be modified depending on the original values in
* the initialization call. When resuming the operation, all parameters may be omitted except
* @e cd, @e name (offline/online),@e kc_old and @e kc_new.
*
* If on-disk metadata describes reencryption operation requiring recovery
* (@link crypt_reencrypt_status @endlink returns @link CRYPT_REENCRYPT_CRASH @endlink),
* it can be recovered by adding @link CRYPT_REENCRYPT_RECOVERY @endlink flag in @link
* crypt_params_reencrypt @endlink parameter.
*
* @param cd crypt device handle
* @param name name of the active device or @e NULL for offline reencryption
* @param kc_old keyslot context providing access to volume key in keyslot id @e keyslot_old.
* @param kc_new keyslot context providing access to volume key in keyslot id @e keyslot_new.
* @param keyslot_old keyslot id containing current volume key for the device or CRYPT_ANY_SLOT
* @param keyslot_new keyslot id containing (unbound) future volume key in encryption or reencryption
* operation. It must be set in the initialization call except when initializing the decrypt
* operation. In reencryption operation it may contain also the current volume key in case the
* volume key change is not requested.
* @param cipher new cipher specification (e.g. "aes") or @e NULL in decryption. Relevant only
* during metadata initialization.
* @param cipher_mode cipher mode and IV (e.g. "xts-plain64") or @e NULL in decryption.
* Relevant only during metadata initialization.
* @param params reencryption parameters @link crypt_params_reencrypt @endlink.
*
* @return reencryption key slot number or negative errno otherwise.
*
* @note Only after successful reencryption initialization you may run the operation with
* @link crypt_reencrypt_run @endlink.
*
* @note During @link CRYPT_REENCRYPT_REENCRYPT @endlink operation it is highly recommended
* to use same keyslot context (same passphrase, token, keyfile, etc) in both @e kc_old
* and @e kc_new parameters for at least one keyslot containing future volume key and one
* keyslot containing current volume key. If the same keyslot context can not be used
* to unlock any current or any future volume key it would be impossible to perform reencryption
* crash recovery during device activation for example after system reboot. Any keyslot
* passphrase may be changed in-before initializing reencryption operation via @link
* crypt_keyslot_change_by_passphrase @endlink.
*/
int crypt_reencrypt_init_by_keyslot_context(struct crypt_device *cd,
const char *name,
struct crypt_keyslot_context *kc_old,
struct crypt_keyslot_context *kc_new,
int keyslot_old,
int keyslot_new,
const char *cipher,
const char *cipher_mode,
const struct crypt_params_reencrypt *params);
/**
* Legacy data reencryption function.
*
@@ -3158,8 +3019,6 @@ __attribute__((deprecated));
* @param usrptr progress specific data
*
* @return @e 0 on success or negative errno value otherwise.
*
* @note A @e progress callback can interrupt reencryption process by returning non-zero code.
*/
int crypt_reencrypt_run(struct crypt_device *cd,
int (*progress)(uint64_t size, uint64_t offset, void *usrptr),
@@ -3228,15 +3087,6 @@ void *crypt_safe_realloc(void *data, size_t size);
*/
void crypt_safe_memzero(void *data, size_t size);
/**
* Memcpy helper to avoid spilling sensitive data through additional registers
*
* @param dst pointer to memory to be written
* @param src pointer to memory to be copied
* @param size size of memory in bytes
*/
void *crypt_safe_memcpy(void *dst, const void *src, size_t size);
/** @} */
/**

View File

@@ -180,23 +180,3 @@ CRYPTSETUP_2.7 {
crypt_set_keyring_to_link;
crypt_wipe_hw_opal;
} CRYPTSETUP_2.6;
CRYPTSETUP_2.8 {
global:
crypt_safe_memcpy;
crypt_keyslot_context_init_by_passphrase;
crypt_keyslot_context_init_by_keyfile;
crypt_keyslot_context_init_by_token;
crypt_keyslot_context_init_by_volume_key;
crypt_keyslot_context_init_by_signed_key;
crypt_keyslot_context_init_by_keyring;
crypt_keyslot_context_init_by_vk_in_keyring;
crypt_reencrypt_init_by_keyslot_context;
crypt_get_old_volume_key_size;
crypt_format_inline;
} CRYPTSETUP_2.7;
CRYPTSETUP_2.9 {
global:
crypt_get_verity_repaired;
} CRYPTSETUP_2.8;

View File

@@ -2,8 +2,8 @@
/*
* Definitions of common constant and generic macros of libcryptsetup
*
* Copyright (C) 2009-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2025 Milan Broz
* Copyright (C) 2009-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2024 Milan Broz
*/
#ifndef _LIBCRYPTSETUP_MACROS_H
@@ -49,17 +49,9 @@
#define DEFAULT_MEM_ALIGNMENT 4096
#define DM_UUID_LEN 129
#define DM_NAME_LEN 128
#define DM_BY_ID_PREFIX "dm-uuid-"
#define DM_BY_ID_PREFIX_LEN 8
#define DM_UUID_PREFIX "CRYPT-"
#define DM_UUID_PREFIX_LEN 6
#define OPAL_PSID_LEN 32
/* LUKS AF stripes, never set to any other value than 4000 */
#ifndef LUKS_STRIPES
# define LUKS_STRIPES 4000
#endif
#endif /* _LIBCRYPTSETUP_MACROS_H */

View File

@@ -2,7 +2,7 @@
/*
* Helpers for defining versioned symbols
*
* Copyright (C) 2021-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2021-2024 Red Hat, Inc. All rights reserved.
*/
#ifndef _LIBCRYPTSETUP_SYMVER_H

File diff suppressed because it is too large Load Diff

View File

@@ -2,8 +2,8 @@
/*
* loop-AES compatible volume handling
*
* Copyright (C) 2011-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2025 Milan Broz
* Copyright (C) 2011-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2024 Milan Broz
*/
#include <errno.h>
@@ -69,7 +69,6 @@ static int hash_keys(struct crypt_device *cd,
char tweak, *key_ptr;
unsigned int i;
int r = 0;
void *key = NULL;
hash_name = hash_override ?: get_hash(key_len_output);
tweak = get_tweak(keys_count);
@@ -80,30 +79,24 @@ static int hash_keys(struct crypt_device *cd,
return -EINVAL;
}
key = crypt_safe_alloc((size_t)key_len_output * keys_count);
if (!key)
*vk = crypt_alloc_volume_key((size_t)key_len_output * keys_count, NULL);
if (!*vk)
return -ENOMEM;
for (i = 0; i < keys_count; i++) {
key_ptr = &((char *)key)[i * key_len_output];
key_ptr = &(*vk)->key[i * key_len_output];
r = hash_key(input_keys[i], key_len_input, key_ptr,
key_len_output, hash_name);
if (r < 0)
goto err;
break;
key_ptr[0] ^= tweak;
}
*vk = crypt_alloc_volume_key_by_safe_alloc(&key);
if (!*vk) {
r = -ENOMEM;
goto err;
if (r < 0 && *vk) {
crypt_free_volume_key(*vk);
*vk = NULL;
}
return 0;
err:
crypt_safe_free(key);
*vk = NULL;
return r;
}
@@ -152,7 +145,7 @@ int LOOPAES_parse_keyfile(struct crypt_device *cd,
key_lengths[0] = 0;
while (offset < buffer_len && key_index < LOOPAES_KEYS_MAX) {
keys[key_index] = &buffer[offset];
key_lengths[key_index] = 0;
key_lengths[key_index] = 0;;
while (offset < buffer_len && buffer[offset]) {
offset++;
key_lengths[key_index]++;
@@ -198,7 +191,7 @@ int LOOPAES_activate(struct crypt_device *cd,
uint32_t flags)
{
int r;
uint64_t req_flags, dmc_flags;
uint32_t req_flags, dmc_flags;
char *cipher = NULL;
struct crypt_dm_active_device dmd = {
.flags = flags,
@@ -220,8 +213,9 @@ int LOOPAES_activate(struct crypt_device *cd,
return -ENOMEM;
r = dm_crypt_target_set(&dmd.segment, 0, dmd.size, crypt_data_device(cd),
vk, cipher, crypt_get_iv_offset(cd), crypt_get_data_offset(cd),
NULL, 0, 0, crypt_get_sector_size(cd));
vk, cipher, 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) {
free(cipher);

View File

@@ -2,8 +2,8 @@
/*
* loop-AES compatible volume handling
*
* Copyright (C) 2011-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2025 Milan Broz
* Copyright (C) 2011-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2024 Milan Broz
*/
#ifndef _LOOPAES_H

View File

@@ -3,7 +3,7 @@
* AFsplitter - Anti forensic information splitter
*
* Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2024 Red Hat, Inc. All rights reserved.
*
* AFsplitter diffuses information over a large stripe of data,
* therefore supporting secure data destruction.

View File

@@ -3,7 +3,7 @@
* AFsplitter - Anti forensic information splitter
*
* Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2024 Red Hat, Inc. All rights reserved.
*/
#ifndef INCLUDED_CRYPTSETUP_LUKS_AF_H

View File

@@ -3,8 +3,8 @@
* LUKS - Linux Unified Key Setup
*
* Copyright (C) 2004-2006 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2025 Milan Broz
* Copyright (C) 2009-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2024 Milan Broz
*/
#include <stdio.h>
@@ -88,7 +88,7 @@ static int LUKS_endec_template(char *src, size_t srcLength,
r = dm_crypt_target_set(&dmd.segment, 0, dmd.size,
crypt_metadata_device(ctx), vk, cipher_spec, 0, sector,
NULL, 0, 0, SECTOR_SIZE);
NULL, 0, SECTOR_SIZE);
if (r)
goto out;
@@ -96,7 +96,7 @@ static int LUKS_endec_template(char *src, size_t srcLength,
if (r < 0) {
if (r != -EACCES && r != -ENOTSUP)
_error_hint(ctx, device_path(crypt_metadata_device(ctx)),
cipher, cipher_mode, crypt_volume_key_length(vk) * 8);
cipher, cipher_mode, vk->keylength * 8);
r = -EIO;
goto out;
}
@@ -140,8 +140,7 @@ int LUKS_encrypt_to_storage(char *src, size_t srcLength,
return -EINVAL;
/* Encrypt buffer */
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode, crypt_volume_key_get_key(vk),
crypt_volume_key_length(vk), false);
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode, vk->key, vk->keylength, false);
if (r)
log_dbg(ctx, "Userspace crypto wrapper cannot use %s-%s (%d).",
@@ -154,7 +153,7 @@ int LUKS_encrypt_to_storage(char *src, size_t srcLength,
if (r) {
_error_hint(ctx, device_path(device), cipher, cipher_mode,
crypt_volume_key_length(vk) * 8);
vk->keylength * 8);
return r;
}
@@ -206,8 +205,7 @@ int LUKS_decrypt_from_storage(char *dst, size_t dstLength,
if (MISALIGNED_512(dstLength))
return -EINVAL;
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode, crypt_volume_key_get_key(vk),
crypt_volume_key_length(vk), false);
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode, vk->key, vk->keylength, false);
if (r)
log_dbg(ctx, "Userspace crypto wrapper cannot use %s-%s (%d).",
@@ -220,7 +218,7 @@ int LUKS_decrypt_from_storage(char *dst, size_t dstLength,
if (r) {
_error_hint(ctx, device_path(device), cipher, cipher_mode,
crypt_volume_key_length(vk) * 8);
vk->keylength * 8);
return r;
}

View File

@@ -3,8 +3,8 @@
* LUKS - Linux Unified Key Setup
*
* Copyright (C) 2004-2006 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2013-2025 Milan Broz
* Copyright (C) 2009-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2013-2024 Milan Broz
*/
#include <sys/types.h>
@@ -378,7 +378,7 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
{
struct luks_phdr temp_phdr;
const unsigned char *sector = (const unsigned char*)phdr;
struct volume_key *fake_vk;
struct volume_key *vk;
int i, bad, r, need_write = 0;
if (phdr->keyBytes != 16 && phdr->keyBytes != 32 && phdr->keyBytes != 64) {
@@ -424,8 +424,8 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
if (r < 0)
return -EINVAL;
fake_vk = crypt_generate_volume_key(ctx, phdr->keyBytes, KEY_QUALITY_EMPTY);
if (!fake_vk)
vk = crypt_alloc_volume_key(phdr->keyBytes, NULL);
if (!vk)
return -ENOMEM;
log_verbose(ctx, _("Repairing keyslots."));
@@ -433,7 +433,7 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
log_dbg(ctx, "Generating second header with the same parameters for check.");
/* cipherName, cipherMode, hashSpec, uuid are already null terminated */
/* payloadOffset - cannot check */
r = LUKS_generate_phdr(&temp_phdr, fake_vk, phdr->cipherName, phdr->cipherMode,
r = LUKS_generate_phdr(&temp_phdr, vk, phdr->cipherName, phdr->cipherMode,
phdr->hashSpec, phdr->uuid,
phdr->payloadOffset * SECTOR_SIZE, 0, 0, ctx);
if (r < 0)
@@ -492,7 +492,7 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
out:
if (r)
log_err(ctx, _("Repair failed."));
crypt_free_volume_key(fake_vk);
crypt_free_volume_key(vk);
crypt_safe_memzero(&temp_phdr, sizeof(temp_phdr));
return r;
}
@@ -710,12 +710,14 @@ int LUKS_check_cipher(struct crypt_device *ctx, size_t keylength, const char *ci
log_dbg(ctx, "Checking if cipher %s-%s is usable.", cipher, cipher_mode);
/* No need to get KEY quality random but it must avoid known weak keys. */
empty_key = crypt_generate_volume_key(ctx, keylength, KEY_QUALITY_NORMAL);
empty_key = crypt_alloc_volume_key(keylength, NULL);
if (!empty_key)
return -ENOMEM;
r = LUKS_decrypt_from_storage(buf, sizeof(buf), cipher, cipher_mode, empty_key, 0, ctx);
/* No need to get KEY quality random but it must avoid known weak keys. */
r = crypt_random_get(ctx, empty_key->key, empty_key->keylength, CRYPT_RND_NORMAL);
if (!r)
r = LUKS_decrypt_from_storage(buf, sizeof(buf), cipher, cipher_mode, empty_key, 0, ctx);
crypt_free_volume_key(empty_key);
crypt_safe_memzero(buf, sizeof(buf));
@@ -746,7 +748,7 @@ int LUKS_generate_phdr(struct luks_phdr *header,
memset(header, 0, sizeof(struct luks_phdr));
keyslot_sectors = AF_split_sectors(crypt_volume_key_length(vk), LUKS_STRIPES);
keyslot_sectors = AF_split_sectors(vk->keylength, LUKS_STRIPES);
header_sectors = LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE;
for (i = 0; i < LUKS_NUMKEYS; i++) {
@@ -793,7 +795,7 @@ int LUKS_generate_phdr(struct luks_phdr *header,
strncpy(header->hashSpec,hashSpec,LUKS_HASHSPEC_L-1);
_to_lower(header->hashSpec, LUKS_HASHSPEC_L);
header->keyBytes = crypt_volume_key_length(vk);
header->keyBytes=vk->keylength;
log_dbg(ctx, "Generating LUKS header version %d using hash %s, %s, %s, MK %d bytes",
header->version, header->hashSpec ,header->cipherName, header->cipherMode,
@@ -807,7 +809,7 @@ int LUKS_generate_phdr(struct luks_phdr *header,
/* Compute volume key digest */
pbkdf = crypt_get_pbkdf(ctx);
r = crypt_benchmark_pbkdf_internal(ctx, pbkdf, crypt_volume_key_length(vk));
r = crypt_benchmark_pbkdf_internal(ctx, pbkdf, vk->keylength);
if (r < 0)
return r;
assert(pbkdf->iterations);
@@ -822,9 +824,7 @@ int LUKS_generate_phdr(struct luks_phdr *header,
header->mkDigestIterations = AT_LEAST((uint32_t)PBKDF2_temp, LUKS_MKD_ITERATIONS_MIN);
assert(header->mkDigestIterations);
r = crypt_pbkdf(CRYPT_KDF_PBKDF2, header->hashSpec,
crypt_volume_key_get_key(vk),
crypt_volume_key_length(vk),
r = crypt_pbkdf(CRYPT_KDF_PBKDF2, header->hashSpec, vk->key,vk->keylength,
header->mkDigestSalt, LUKS_SALTSIZE,
header->mkDigest,LUKS_DIGESTSIZE,
header->mkDigestIterations, 0, 0);
@@ -866,9 +866,8 @@ int LUKS_set_key(unsigned int keyIndex,
struct luks_phdr *hdr, struct volume_key *vk,
struct crypt_device *ctx)
{
struct volume_key *derived_vk = NULL;
struct volume_key *derived_key;
char *AfKey = NULL;
void *derived_key = NULL;
size_t AFEKSize;
struct crypt_pbkdf_type *pbkdf;
int r;
@@ -887,7 +886,7 @@ int LUKS_set_key(unsigned int keyIndex,
log_dbg(ctx, "Calculating data for key slot %d", keyIndex);
pbkdf = crypt_get_pbkdf(ctx);
r = crypt_benchmark_pbkdf_internal(ctx, pbkdf, crypt_volume_key_length(vk));
r = crypt_benchmark_pbkdf_internal(ctx, pbkdf, vk->keylength);
if (r < 0)
return r;
assert(pbkdf->iterations);
@@ -900,11 +899,9 @@ int LUKS_set_key(unsigned int keyIndex,
log_dbg(ctx, "Key slot %d use %" PRIu32 " password iterations.", keyIndex,
hdr->keyblock[keyIndex].passwordIterations);
derived_key = crypt_safe_alloc(hdr->keyBytes);
if (!derived_key) {
r = -ENOMEM;
goto out;
}
derived_key = crypt_alloc_volume_key(hdr->keyBytes, NULL);
if (!derived_key)
return -ENOMEM;
r = crypt_random_get(ctx, hdr->keyblock[keyIndex].passwordSalt,
LUKS_SALTSIZE, CRYPT_RND_SALT);
@@ -913,7 +910,7 @@ int LUKS_set_key(unsigned int keyIndex,
r = crypt_pbkdf(CRYPT_KDF_PBKDF2, hdr->hashSpec, password, passwordLen,
hdr->keyblock[keyIndex].passwordSalt, LUKS_SALTSIZE,
derived_key, hdr->keyBytes,
derived_key->key, hdr->keyBytes,
hdr->keyblock[keyIndex].passwordIterations, 0, 0);
if (r < 0) {
if ((crypt_backend_flags() & CRYPT_BACKEND_PBKDF2_INT) &&
@@ -922,17 +919,11 @@ int LUKS_set_key(unsigned int keyIndex,
goto out;
}
derived_vk = crypt_alloc_volume_key_by_safe_alloc(&derived_key);
if (!derived_vk) {
r = -ENOMEM;
goto out;
}
/*
* AF splitting, the volume key stored in vk->key is split to AfKey
*/
assert(crypt_volume_key_length(vk) == hdr->keyBytes);
AFEKSize = AF_split_sectors(crypt_volume_key_length(vk), hdr->keyblock[keyIndex].stripes) * SECTOR_SIZE;
assert(vk->keylength == hdr->keyBytes);
AFEKSize = AF_split_sectors(vk->keylength, hdr->keyblock[keyIndex].stripes) * SECTOR_SIZE;
AfKey = crypt_safe_alloc(AFEKSize);
if (!AfKey) {
r = -ENOMEM;
@@ -941,8 +932,7 @@ int LUKS_set_key(unsigned int keyIndex,
log_dbg(ctx, "Using hash %s for AF in key slot %d, %d stripes",
hdr->hashSpec, keyIndex, hdr->keyblock[keyIndex].stripes);
r = AF_split(ctx, crypt_volume_key_get_key(vk), AfKey, crypt_volume_key_length(vk),
hdr->keyblock[keyIndex].stripes, hdr->hashSpec);
r = AF_split(ctx, vk->key, AfKey, vk->keylength, hdr->keyblock[keyIndex].stripes, hdr->hashSpec);
if (r < 0)
goto out;
@@ -952,7 +942,7 @@ int LUKS_set_key(unsigned int keyIndex,
r = LUKS_encrypt_to_storage(AfKey,
AFEKSize,
hdr->cipherName, hdr->cipherMode,
derived_vk,
derived_key,
hdr->keyblock[keyIndex].keyMaterialOffset,
ctx);
if (r < 0)
@@ -970,8 +960,7 @@ int LUKS_set_key(unsigned int keyIndex,
r = 0;
out:
crypt_safe_free(AfKey);
crypt_safe_free(derived_key);
crypt_free_volume_key(derived_vk);
crypt_free_volume_key(derived_key);
return r;
}
@@ -981,8 +970,7 @@ int LUKS_verify_volume_key(const struct luks_phdr *hdr,
{
char checkHashBuf[LUKS_DIGESTSIZE];
if (crypt_pbkdf(CRYPT_KDF_PBKDF2, hdr->hashSpec, crypt_volume_key_get_key(vk),
crypt_volume_key_length(vk),
if (crypt_pbkdf(CRYPT_KDF_PBKDF2, hdr->hashSpec, vk->key, vk->keylength,
hdr->mkDigestSalt, LUKS_SALTSIZE,
checkHashBuf, LUKS_DIGESTSIZE,
hdr->mkDigestIterations, 0, 0) < 0)
@@ -999,13 +987,12 @@ static int LUKS_open_key(unsigned int keyIndex,
const char *password,
size_t passwordLen,
struct luks_phdr *hdr,
struct volume_key **r_vk,
struct volume_key **vk,
struct crypt_device *ctx)
{
crypt_keyslot_info ki = LUKS_keyslot_info(hdr, keyIndex);
struct volume_key *derived_vk = NULL, *vk = NULL;
struct volume_key *derived_key;
char *AfKey = NULL;
void *key = NULL, *derived_key = NULL;
size_t AFEKSize;
int r;
@@ -1015,12 +1002,12 @@ static int LUKS_open_key(unsigned int keyIndex,
if (ki < CRYPT_SLOT_ACTIVE)
return -ENOENT;
derived_key = crypt_safe_alloc(hdr->keyBytes);
derived_key = crypt_alloc_volume_key(hdr->keyBytes, NULL);
if (!derived_key)
return -ENOMEM;
key = crypt_safe_alloc(hdr->keyBytes);
if (!key) {
*vk = crypt_alloc_volume_key(hdr->keyBytes, NULL);
if (!*vk) {
r = -ENOMEM;
goto out;
}
@@ -1034,57 +1021,39 @@ static int LUKS_open_key(unsigned int keyIndex,
r = crypt_pbkdf(CRYPT_KDF_PBKDF2, hdr->hashSpec, password, passwordLen,
hdr->keyblock[keyIndex].passwordSalt, LUKS_SALTSIZE,
derived_key, hdr->keyBytes,
derived_key->key, hdr->keyBytes,
hdr->keyblock[keyIndex].passwordIterations, 0, 0);
if (r < 0) {
log_err(ctx, _("Cannot open keyslot (using hash %s)."), hdr->hashSpec);
goto out;
}
derived_vk = crypt_alloc_volume_key_by_safe_alloc(&derived_key);
if (!derived_vk) {
r = -ENOMEM;
goto out;
}
log_dbg(ctx, "Reading key slot %d area.", keyIndex);
r = LUKS_decrypt_from_storage(AfKey,
AFEKSize,
hdr->cipherName, hdr->cipherMode,
derived_vk,
derived_key,
hdr->keyblock[keyIndex].keyMaterialOffset,
ctx);
if (r < 0)
goto out;
r = AF_merge(AfKey, key, hdr->keyBytes, hdr->keyblock[keyIndex].stripes, hdr->hashSpec);
r = AF_merge(AfKey, (*vk)->key, (*vk)->keylength, hdr->keyblock[keyIndex].stripes, hdr->hashSpec);
if (r < 0)
goto out;
vk = crypt_alloc_volume_key_by_safe_alloc(&key);
if (!vk) {
r = -ENOMEM;
goto out;
}
r = LUKS_verify_volume_key(hdr, vk);
if (r < 0)
goto out;
r = LUKS_verify_volume_key(hdr, *vk);
/* Allow only empty passphrase with null cipher */
if (crypt_is_cipher_null(hdr->cipherName) && passwordLen)
if (!r && crypt_is_cipher_null(hdr->cipherName) && passwordLen)
r = -EPERM;
else
*r_vk = vk;
out:
if (r < 0) {
crypt_free_volume_key(vk);
*r_vk = NULL;
crypt_free_volume_key(*vk);
*vk = NULL;
}
crypt_safe_free(AfKey);
crypt_safe_free(key);
crypt_safe_free(derived_key);
crypt_free_volume_key(derived_vk);
crypt_free_volume_key(derived_key);
return r;
}
@@ -1235,7 +1204,8 @@ int LUKS1_activate(struct crypt_device *cd,
r = dm_crypt_target_set(&dmd.segment, 0, dmd.size, crypt_data_device(cd),
vk, crypt_get_cipher_spec(cd), crypt_get_iv_offset(cd),
crypt_get_data_offset(cd), NULL, 0, 0, crypt_get_sector_size(cd));
crypt_get_data_offset(cd), crypt_get_integrity(cd),
crypt_get_integrity_tag_size(cd), crypt_get_sector_size(cd));
if (!r)
r = create_or_reload_device(cd, name, CRYPT_LUKS1, &dmd);

View File

@@ -3,7 +3,7 @@
* LUKS - Linux Unified Key Setup
*
* Copyright (C) 2004-2006 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2024 Red Hat, Inc. All rights reserved.
*/
#ifndef INCLUDED_CRYPTSETUP_LUKS_LUKS_H

View File

@@ -3,8 +3,7 @@
* OPAL utilities
*
* Copyright (C) 2022-2023 Luca Boccassi <bluca@debian.org>
* Copyright (C) 2023-2025 Ondrej Kozina <okozina@redhat.com>
* Copyright (C) 2024-2025 Milan Broz
* 2023 Ondrej Kozina <okozina@redhat.com>
*/
#include <stdio.h>
@@ -17,7 +16,7 @@
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#if HAVE_SYS_SYSMACROS_H
#ifdef HAVE_SYS_SYSMACROS_H
# include <sys/sysmacros.h> /* for major, minor */
#endif
@@ -36,38 +35,33 @@
* Section 5.1.5: Method Status Codes
* Names and values from table 166 */
typedef enum OpalStatus {
OPAL_STATUS_SUCCESS = 0x00,
OPAL_STATUS_NOT_AUTHORIZED = 0x01,
OPAL_STATUS_OBSOLETE0 = 0x02, /* Undefined but possible return values are called 'obsolete' */
OPAL_STATUS_SP_BUSY = 0x03,
OPAL_STATUS_SP_FAILED = 0x04,
OPAL_STATUS_SP_DISABLED = 0x05,
OPAL_STATUS_SP_FROZEN = 0x06,
OPAL_STATUS_NO_SESSIONS_AVAILABLE = 0x07,
OPAL_STATUS_UNIQUENESS_CONFLICT = 0x08,
OPAL_STATUS_INSUFFICIENT_SPACE = 0x09,
OPAL_STATUS_INSUFFICIENT_ROWS = 0x0a,
OPAL_STATUS_OBSOLETE1 = 0x0b, /* Undefined but possible return values are called 'obsolete' */
OPAL_STATUS_INVALID_PARAMETER = 0x0c,
OPAL_STATUS_OBSOLETE2 = 0x0d,
OPAL_STATUS_OBSOLETE3 = 0x0e,
OPAL_STATUS_TPER_MALFUNCTION = 0x0f,
OPAL_STATUS_TRANSACTION_FAILURE = 0x10,
OPAL_STATUS_RESPONSE_OVERFLOW = 0x11,
OPAL_STATUS_AUTHORITY_LOCKED_OUT = 0x12,
_OPAL_STATUS_MAX = 0x13,
OPAL_STATUS_SUCCESS,
OPAL_STATUS_NOT_AUTHORIZED,
OPAL_STATUS_OBSOLETE0, /* Undefined but possible return values are called 'obsolete' */
OPAL_STATUS_SP_BUSY,
OPAL_STATUS_SP_FAILED,
OPAL_STATUS_SP_DISABLED,
OPAL_STATUS_SP_FROZEN,
OPAL_STATUS_NO_SESSIONS_AVAILABLE,
OPAL_STATUS_UNIQUENESS_CONFLICT,
OPAL_STATUS_INSUFFICIENT_SPACE,
OPAL_STATUS_INSUFFICIENT_ROWS,
OPAL_STATUS_INVALID_PARAMETER,
OPAL_STATUS_OBSOLETE1,
OPAL_STATUS_OBSOLETE2,
OPAL_STATUS_TPER_MALFUNCTION,
OPAL_STATUS_TRANSACTION_FAILURE,
OPAL_STATUS_RESPONSE_OVERFLOW,
OPAL_STATUS_AUTHORITY_LOCKED_OUT,
OPAL_STATUS_FAIL = 0x3F, /* As defined by specification */
_OPAL_STATUS_MAX,
_OPAL_STATUS_INVALID = -EINVAL,
} OpalStatus;
/*
* Also defined in TCG Core spec Section 5.1.5 but
* do not inflate the opal_status_table below
*/
#define OPAL_STATUS_FAIL 0x3f
static const char* const opal_status_table[_OPAL_STATUS_MAX] = {
[OPAL_STATUS_SUCCESS] = "success",
[OPAL_STATUS_NOT_AUTHORIZED] = "not authorized",
[OPAL_STATUS_OBSOLETE0] = "obsolete (0x02)",
[OPAL_STATUS_OBSOLETE0] = "obsolete",
[OPAL_STATUS_SP_BUSY] = "SP busy",
[OPAL_STATUS_SP_FAILED] = "SP failed",
[OPAL_STATUS_SP_DISABLED] = "SP disabled",
@@ -76,14 +70,14 @@ static const char* const opal_status_table[_OPAL_STATUS_MAX] = {
[OPAL_STATUS_UNIQUENESS_CONFLICT] = "uniqueness conflict",
[OPAL_STATUS_INSUFFICIENT_SPACE] = "insufficient space",
[OPAL_STATUS_INSUFFICIENT_ROWS] = "insufficient rows",
[OPAL_STATUS_OBSOLETE1] = "obsolete (0x0b)",
[OPAL_STATUS_INVALID_PARAMETER] = "invalid parameter",
[OPAL_STATUS_OBSOLETE2] = "obsolete (0x0d)",
[OPAL_STATUS_OBSOLETE3] = "obsolete (0x0e)",
[OPAL_STATUS_OBSOLETE1] = "obsolete",
[OPAL_STATUS_OBSOLETE2] = "obsolete",
[OPAL_STATUS_TPER_MALFUNCTION] = "TPer malfunction",
[OPAL_STATUS_TRANSACTION_FAILURE] = "transaction failure",
[OPAL_STATUS_RESPONSE_OVERFLOW] = "response overflow",
[OPAL_STATUS_AUTHORITY_LOCKED_OUT] = "authority locked out",
[OPAL_STATUS_FAIL] = "unknown failure",
};
static const char *opal_status_to_string(int t)
@@ -91,10 +85,6 @@ static const char *opal_status_to_string(int t)
if (t < 0)
return strerror(-t);
/* This will be checked upon 'Reactivate' method */
if (t == OPAL_STATUS_FAIL)
return "FAIL status";
if (t >= _OPAL_STATUS_MAX)
return "unknown error";
@@ -242,8 +232,6 @@ static int opal_ioctl(struct crypt_device *cd, int fd, unsigned long rq, void *a
opal_ioctl_debug(cd, rq, args, false, 0);
r = ioctl(fd, rq, args);
if (r < 0)
r = -errno;
opal_ioctl_debug(cd, rq, args, true, r);
return r;
@@ -318,13 +306,12 @@ static int opal_range_check_attributes_fd(struct crypt_device *cd,
.session = {
.who = segment_number + 1,
.opal_key = {
.key_len = crypt_volume_key_length(vk),
.key_len = vk->keylength,
.lr = segment_number
}
}
};
crypt_safe_memcpy(lrs->session.opal_key.key, crypt_volume_key_get_key(vk),
crypt_volume_key_length(vk));
memcpy(lrs->session.opal_key.key, vk->key, vk->keylength);
r = opal_ioctl(cd, fd, IOC_OPAL_GET_LR_STATUS, lrs);
if (r != OPAL_STATUS_SUCCESS) {
@@ -404,194 +391,6 @@ static int opal_enabled(struct crypt_device *cd, struct device *dev)
return opal_query_status(cd, dev, OPAL_FL_LOCKING_ENABLED);
}
static int opal_activate_lsp(struct crypt_device *cd, int fd,
const void *admin_key, size_t admin_key_len)
{
int r;
struct opal_lr_act *activate = crypt_safe_alloc(sizeof(*activate));
if (!activate)
return -ENOMEM;
*activate = (struct opal_lr_act) {
.key = {
.key_len = admin_key_len,
},
/* useless but due to kernel bug it requires (num_lrs > 0 && num_lrs <= 9) */
.num_lrs = 1,
};
crypt_safe_memcpy(activate->key.key, admin_key, admin_key_len);
r = opal_ioctl(cd, fd, IOC_OPAL_TAKE_OWNERSHIP, &activate->key);
if (r < 0) {
r = -ENOTSUP;
log_dbg(cd, "OPAL not supported on this kernel version, refusing.");
goto out;
}
if (r == OPAL_STATUS_NOT_AUTHORIZED) /* We'll try again with a different key. */ {
r = -EPERM;
log_dbg(cd, "Failed to take ownership of OPAL device '%s': permission denied",
crypt_get_device_name(cd));
goto out;
}
if (r != OPAL_STATUS_SUCCESS) {
log_dbg(cd, "Failed to take ownership of OPAL device '%s': %s",
crypt_get_device_name(cd), opal_status_to_string(r));
r = -EINVAL;
goto out;
}
r = opal_ioctl(cd, fd, IOC_OPAL_ACTIVATE_LSP, activate);
if (r < 0)
goto out;
if (r != OPAL_STATUS_SUCCESS) {
log_dbg(cd, "Failed to activate OPAL device '%s': %s",
crypt_get_device_name(cd), opal_status_to_string(r));
r = -EINVAL;
}
out:
crypt_safe_free(activate);
return r;
}
static int opal_reuse_active_lsp(struct crypt_device *cd, int fd,
uint32_t segment_number,
const void *admin_key, size_t admin_key_len)
{
int r;
struct opal_session_info *user_session = crypt_safe_alloc(sizeof(*user_session));
if (!user_session)
return -ENOMEM;
*user_session = (struct opal_session_info) {
.who = OPAL_ADMIN1, /* irrelevant in SUM */
.opal_key = {
.lr = segment_number,
.key_len = admin_key_len,
},
};
/* If it is already enabled, wipe the locking range first */
crypt_safe_memcpy(user_session->opal_key.key, admin_key, admin_key_len);
r = opal_ioctl(cd, fd, IOC_OPAL_SECURE_ERASE_LR, user_session);
if (r < 0)
goto out;
if (r != OPAL_STATUS_SUCCESS) {
log_dbg(cd, "Failed to reset (secure erase) OPAL locking range %u on device '%s': %s",
segment_number, crypt_get_device_name(cd), opal_status_to_string(r));
r = -EINVAL;
}
out:
crypt_safe_free(user_session);
return r;
}
static int opal_setup_range(struct crypt_device *cd, int fd, uint32_t segment_number,
uint64_t range_start_blocks, uint64_t range_length_blocks,
const void *admin_key, size_t admin_key_len)
{
int r;
struct opal_user_lr_setup *setup = crypt_safe_alloc(sizeof(*setup));
if (!setup)
return -ENOMEM;
*setup = (struct opal_user_lr_setup) {
.range_start = range_start_blocks,
.range_length = range_length_blocks,
/* Some drives do not enable Locking Ranges on setup. This have some
* interesting consequences: Lock command called later below will pass,
* but locking range will _not_ be locked at all.
*/
.RLE = 1,
.WLE = 1,
.session = {
.who = OPAL_ADMIN1,
.opal_key = {
.key_len = admin_key_len,
.lr = segment_number,
},
},
};
crypt_safe_memcpy(setup->session.opal_key.key, admin_key, admin_key_len);
r = opal_ioctl(cd, fd, IOC_OPAL_LR_SETUP, setup);
if (r < 0)
goto out;
if (r != OPAL_STATUS_SUCCESS) {
log_dbg(cd, "Failed to setup locking range of length %llu at offset %llu on OPAL device '%s': %s",
setup->range_length, setup->range_start, crypt_get_device_name(cd),
opal_status_to_string(r));
r = -EINVAL;
}
out:
crypt_safe_free(setup);
return r;
}
static int opal_setup_user(struct crypt_device *cd, int fd, uint32_t segment_number,
const void *admin_key, size_t admin_key_len)
{
int r;
struct opal_lock_unlock *user_add_to_lr = crypt_safe_alloc(sizeof(*user_add_to_lr));
if (!user_add_to_lr)
return -ENOMEM;
*user_add_to_lr = (struct opal_lock_unlock) {
.session = {
.who = segment_number + 1,
.opal_key = {
.lr = segment_number,
.key_len = admin_key_len,
},
},
.l_state = OPAL_RO,
};
crypt_safe_memcpy(user_add_to_lr->session.opal_key.key, admin_key, admin_key_len);
r = opal_ioctl(cd, fd, IOC_OPAL_ACTIVATE_USR, &user_add_to_lr->session);
if (r < 0)
goto out;
if (r != OPAL_STATUS_SUCCESS) {
log_dbg(cd, "Failed to activate OPAL user on device '%s': %s",
crypt_get_device_name(cd), opal_status_to_string(r));
r = -EINVAL;
goto out;
}
r = opal_ioctl(cd, fd, IOC_OPAL_ADD_USR_TO_LR, user_add_to_lr);
if (r < 0)
goto out;
if (r != OPAL_STATUS_SUCCESS) {
log_dbg(cd, "Failed to add OPAL user to locking range %u (RO) on device '%s': %s",
segment_number, crypt_get_device_name(cd), opal_status_to_string(r));
r = -EINVAL;
goto out;
}
user_add_to_lr->l_state = OPAL_RW;
r = opal_ioctl(cd, fd, IOC_OPAL_ADD_USR_TO_LR, user_add_to_lr);
if (r < 0)
goto out;
if (r != OPAL_STATUS_SUCCESS) {
log_dbg(cd, "Failed to add OPAL user to locking range %u (RW) on device '%s': %s",
segment_number, crypt_get_device_name(cd), opal_status_to_string(r));
r = -EINVAL;
}
out:
crypt_safe_free(user_add_to_lr);
return r;
}
/* requires opal lock */
int opal_setup_ranges(struct crypt_device *cd,
struct device *dev,
@@ -603,15 +402,18 @@ int opal_setup_ranges(struct crypt_device *cd,
const void *admin_key,
size_t admin_key_len)
{
struct opal_lock_unlock *lock = NULL;
struct opal_lr_act *activate = NULL;
struct opal_session_info *user_session = NULL;
struct opal_lock_unlock *user_add_to_lr = NULL, *lock = NULL;
struct opal_new_pw *new_pw = NULL;
struct opal_user_lr_setup *setup = NULL;
int r, fd;
assert(cd);
assert(dev);
assert(vk);
assert(admin_key);
assert(crypt_volume_key_length(vk) <= OPAL_KEY_MAX);
assert(vk->keylength <= OPAL_KEY_MAX);
assert(opal_block_bytes >= SECTOR_SIZE);
if (admin_key_len > OPAL_KEY_MAX)
@@ -630,16 +432,135 @@ int opal_setup_ranges(struct crypt_device *cd,
return r;
/* If OPAL has never been enabled, we need to take ownership and do basic setup first */
if (r == 0)
r = opal_activate_lsp(cd, fd, admin_key, admin_key_len);
else
r = opal_reuse_active_lsp(cd, fd, segment_number, admin_key, admin_key_len);
if (r < 0)
goto out;
if (r == 0) {
activate = crypt_safe_alloc(sizeof(struct opal_lr_act));
if (!activate) {
r = -ENOMEM;
goto out;
}
*activate = (struct opal_lr_act) {
.key = {
.key_len = admin_key_len,
},
.num_lrs = 8,
/* A max of 9 segments are supported, enable them all as there's no reason not to
* (0 is whole-volume)
*/
.lr = { 1, 2, 3, 4, 5, 6, 7, 8 },
};
memcpy(activate->key.key, admin_key, admin_key_len);
r = opal_setup_user(cd, fd, segment_number, admin_key, admin_key_len);
if (r < 0)
r = opal_ioctl(cd, fd, IOC_OPAL_TAKE_OWNERSHIP, &activate->key);
if (r < 0) {
r = -ENOTSUP;
log_dbg(cd, "OPAL not supported on this kernel version, refusing.");
goto out;
}
if (r == OPAL_STATUS_NOT_AUTHORIZED) /* We'll try again with a different key. */ {
r = -EPERM;
log_dbg(cd, "Failed to take ownership of OPAL device '%s': permission denied",
crypt_get_device_name(cd));
goto out;
}
if (r != OPAL_STATUS_SUCCESS) {
log_dbg(cd, "Failed to take ownership of OPAL device '%s': %s",
crypt_get_device_name(cd), opal_status_to_string(r));
r = -EINVAL;
goto out;
}
r = opal_ioctl(cd, fd, IOC_OPAL_ACTIVATE_LSP, activate);
if (r != OPAL_STATUS_SUCCESS) {
log_dbg(cd, "Failed to activate OPAL device '%s': %s",
crypt_get_device_name(cd), opal_status_to_string(r));
r = -EINVAL;
goto out;
}
} else {
/* If it is already enabled, wipe the locking range first */
user_session = crypt_safe_alloc(sizeof(struct opal_session_info));
if (!user_session) {
r = -ENOMEM;
goto out;
}
*user_session = (struct opal_session_info) {
.who = OPAL_ADMIN1,
.opal_key = {
.lr = segment_number,
.key_len = admin_key_len,
},
};
memcpy(user_session->opal_key.key, admin_key, admin_key_len);
r = opal_ioctl(cd, fd, IOC_OPAL_ERASE_LR, user_session);
if (r != OPAL_STATUS_SUCCESS) {
log_dbg(cd, "Failed to reset (erase) OPAL locking range %u on device '%s': %s",
segment_number, crypt_get_device_name(cd), opal_status_to_string(r));
r = opal_ioctl(cd, fd, IOC_OPAL_SECURE_ERASE_LR, user_session);
if (r != OPAL_STATUS_SUCCESS) {
log_dbg(cd, "Failed to reset (secure erase) OPAL locking range %u on device '%s': %s",
segment_number, crypt_get_device_name(cd), opal_status_to_string(r));
r = -EINVAL;
goto out;
}
}
}
crypt_safe_free(user_session);
user_session = crypt_safe_alloc(sizeof(struct opal_session_info));
if (!user_session) {
r = -ENOMEM;
goto out;
}
*user_session = (struct opal_session_info) {
.who = segment_number + 1,
.opal_key = {
.key_len = admin_key_len,
},
};
memcpy(user_session->opal_key.key, admin_key, admin_key_len);
r = opal_ioctl(cd, fd, IOC_OPAL_ACTIVATE_USR, user_session);
if (r != OPAL_STATUS_SUCCESS) {
log_dbg(cd, "Failed to activate OPAL user on device '%s': %s",
crypt_get_device_name(cd), opal_status_to_string(r));
r = -EINVAL;
goto out;
}
user_add_to_lr = crypt_safe_alloc(sizeof(struct opal_lock_unlock));
if (!user_add_to_lr) {
r = -ENOMEM;
goto out;
}
*user_add_to_lr = (struct opal_lock_unlock) {
.session = {
.who = segment_number + 1,
.opal_key = {
.lr = segment_number,
.key_len = admin_key_len,
},
},
.l_state = OPAL_RO,
};
memcpy(user_add_to_lr->session.opal_key.key, admin_key, admin_key_len);
r = opal_ioctl(cd, fd, IOC_OPAL_ADD_USR_TO_LR, user_add_to_lr);
if (r != OPAL_STATUS_SUCCESS) {
log_dbg(cd, "Failed to add OPAL user to locking range %u (RO) on device '%s': %s",
segment_number, crypt_get_device_name(cd), opal_status_to_string(r));
r = -EINVAL;
goto out;
}
user_add_to_lr->l_state = OPAL_RW;
r = opal_ioctl(cd, fd, IOC_OPAL_ADD_USR_TO_LR, user_add_to_lr);
if (r != OPAL_STATUS_SUCCESS) {
log_dbg(cd, "Failed to add OPAL user to locking range %u (RW) on device '%s': %s",
segment_number, crypt_get_device_name(cd), opal_status_to_string(r));
r = -EINVAL;
goto out;
}
new_pw = crypt_safe_alloc(sizeof(struct opal_new_pw));
if (!new_pw) {
@@ -657,18 +578,15 @@ int opal_setup_ranges(struct crypt_device *cd,
.new_user_pw = {
.who = segment_number + 1,
.opal_key = {
.key_len = crypt_volume_key_length(vk),
.key_len = vk->keylength,
.lr = segment_number,
},
},
};
crypt_safe_memcpy(new_pw->new_user_pw.opal_key.key, crypt_volume_key_get_key(vk),
crypt_volume_key_length(vk));
crypt_safe_memcpy(new_pw->session.opal_key.key, admin_key, admin_key_len);
memcpy(new_pw->new_user_pw.opal_key.key, vk->key, vk->keylength);
memcpy(new_pw->session.opal_key.key, admin_key, admin_key_len);
r = opal_ioctl(cd, fd, IOC_OPAL_SET_PW, new_pw);
if (r < 0)
goto out;
if (r != OPAL_STATUS_SUCCESS) {
log_dbg(cd, "Failed to set OPAL user password on device '%s': (%d) %s",
crypt_get_device_name(cd), r, opal_status_to_string(r));
@@ -676,10 +594,37 @@ int opal_setup_ranges(struct crypt_device *cd,
goto out;
}
r = opal_setup_range(cd, fd, segment_number, range_start_blocks, range_length_blocks,
admin_key, admin_key_len);
if (r < 0)
setup = crypt_safe_alloc(sizeof(struct opal_user_lr_setup));
if (!setup) {
r = -ENOMEM;
goto out;
}
*setup = (struct opal_user_lr_setup) {
.range_start = range_start_blocks,
.range_length = range_length_blocks,
/* Some drives do not enable Locking Ranges on setup. This have some
* interesting consequences: Lock command called later below will pass,
* but locking range will _not_ be locked at all.
*/
.RLE = 1,
.WLE = 1,
.session = {
.who = OPAL_ADMIN1,
.opal_key = {
.key_len = admin_key_len,
.lr = segment_number,
},
},
};
memcpy(setup->session.opal_key.key, admin_key, admin_key_len);
r = opal_ioctl(cd, fd, IOC_OPAL_LR_SETUP, setup);
if (r != OPAL_STATUS_SUCCESS) {
log_dbg(cd, "Failed to setup locking range of length %llu at offset %llu on OPAL device '%s': %s",
setup->range_length, setup->range_start, crypt_get_device_name(cd), opal_status_to_string(r));
r = -EINVAL;
goto out;
}
/* After setup an OPAL device is unlocked, but the expectation with cryptsetup is that it needs
* to be activated separately, so lock it immediately. */
@@ -693,17 +638,14 @@ int opal_setup_ranges(struct crypt_device *cd,
.session = {
.who = segment_number + 1,
.opal_key = {
.key_len = crypt_volume_key_length(vk),
.key_len = vk->keylength,
.lr = segment_number,
},
}
};
crypt_safe_memcpy(lock->session.opal_key.key, crypt_volume_key_get_key(vk),
crypt_volume_key_length(vk));
memcpy(lock->session.opal_key.key, vk->key, vk->keylength);
r = opal_ioctl(cd, fd, IOC_OPAL_LOCK_UNLOCK, lock);
if (r < 0)
goto out;
if (r != OPAL_STATUS_SUCCESS) {
log_dbg(cd, "Failed to lock OPAL device '%s': %s",
crypt_get_device_name(cd), opal_status_to_string(r));
@@ -717,7 +659,11 @@ int opal_setup_ranges(struct crypt_device *cd,
&(uint64_t) {range_length_blocks * opal_block_bytes / SECTOR_SIZE},
&(bool) {true}, &(bool){true}, NULL, NULL);
out:
crypt_safe_free(activate);
crypt_safe_free(user_session);
crypt_safe_free(user_add_to_lr);
crypt_safe_free(new_pw);
crypt_safe_free(setup);
crypt_safe_free(lock);
return r;
@@ -750,11 +696,10 @@ static int opal_lock_unlock(struct crypt_device *cd,
return -EIO;
if (!lock) {
assert(crypt_volume_key_length(vk) <= OPAL_KEY_MAX);
assert(vk->keylength <= OPAL_KEY_MAX);
unlock.session.opal_key.key_len = crypt_volume_key_length(vk);
crypt_safe_memcpy(unlock.session.opal_key.key, crypt_volume_key_get_key(vk),
crypt_volume_key_length(vk));
unlock.session.opal_key.key_len = vk->keylength;
memcpy(unlock.session.opal_key.key, vk->key, vk->keylength);
}
r = opal_ioctl(cd, fd, IOC_OPAL_LOCK_UNLOCK, &unlock);
@@ -789,8 +734,6 @@ static int opal_lock_unlock(struct crypt_device *cd,
unlock.flags = OPAL_SAVE_FOR_LOCK;
r = opal_ioctl(cd, fd, IOC_OPAL_SAVE, &unlock);
if (r < 0)
goto out;
if (r != OPAL_STATUS_SUCCESS) {
if (!lock)
log_std(cd, "Failed to prepare OPAL device '%s' for sleep resume, be aware before suspending: %s",
@@ -844,15 +787,11 @@ int opal_factory_reset(struct crypt_device *cd,
if (password_len > OPAL_KEY_MAX)
return -EINVAL;
/*
* Submit PSID reset on R/W file descriptor so it
* triggers blkid rescan after we close it.
*/
fd = device_open(cd, dev, O_RDWR);
fd = device_open(cd, dev, O_RDONLY);
if (fd < 0)
return -EIO;
crypt_safe_memcpy(reset.key, password, password_len);
memcpy(reset.key, password, password_len);
r = opal_ioctl(cd, fd, IOC_OPAL_PSID_REVERT_TPR, &reset);
if (r < 0) {
@@ -909,7 +848,7 @@ int opal_reset_segment(struct crypt_device *cd,
.key_len = password_len,
},
};
crypt_safe_memcpy(user_session->opal_key.key, password, password_len);
memcpy(user_session->opal_key.key, password, password_len);
fd = device_open(cd, dev, O_RDONLY);
if (fd < 0) {
@@ -917,39 +856,42 @@ int opal_reset_segment(struct crypt_device *cd,
goto out;
}
r = opal_ioctl(cd, fd, IOC_OPAL_SECURE_ERASE_LR, user_session);
if (r < 0)
goto out;
r = opal_ioctl(cd, fd, IOC_OPAL_ERASE_LR, user_session);
if (r != OPAL_STATUS_SUCCESS) {
log_dbg(cd, "Failed to reset (secure erase) OPAL locking range %u on device '%s': %s",
log_dbg(cd, "Failed to reset (erase) OPAL locking range %u on device '%s': %s",
segment_number, crypt_get_device_name(cd), opal_status_to_string(r));
r = -EINVAL;
goto out;
}
r = opal_ioctl(cd, fd, IOC_OPAL_SECURE_ERASE_LR, user_session);
if (r != OPAL_STATUS_SUCCESS) {
log_dbg(cd, "Failed to reset (secure erase) OPAL locking range %u on device '%s': %s",
segment_number, crypt_get_device_name(cd), opal_status_to_string(r));
r = -EINVAL;
goto out;
}
/* Disable the locking range */
setup = crypt_safe_alloc(sizeof(struct opal_user_lr_setup));
if (!setup) {
r = -ENOMEM;
goto out;
}
*setup = (struct opal_user_lr_setup) {
.range_start = 0,
.range_length = 0,
.session = {
.who = OPAL_ADMIN1,
.opal_key = user_session->opal_key,
},
};
/* Unlike IOC_OPAL_ERASE_LR, IOC_OPAL_SECURE_ERASE_LR does not disable the locking range,
* we have to do that by hand.
*/
setup = crypt_safe_alloc(sizeof(struct opal_user_lr_setup));
if (!setup) {
r = -ENOMEM;
goto out;
}
*setup = (struct opal_user_lr_setup) {
.range_start = 0,
.range_length = 0,
.session = {
.who = OPAL_ADMIN1,
.opal_key = user_session->opal_key,
},
};
r = opal_ioctl(cd, fd, IOC_OPAL_LR_SETUP, setup);
if (r < 0)
goto out;
if (r != OPAL_STATUS_SUCCESS) {
log_dbg(cd, "Failed to disable locking range on OPAL device '%s': %s",
crypt_get_device_name(cd), opal_status_to_string(r));
r = -EINVAL;
goto out;
r = opal_ioctl(cd, fd, IOC_OPAL_LR_SETUP, setup);
if (r != OPAL_STATUS_SUCCESS) {
log_dbg(cd, "Failed to disable locking range on OPAL device '%s': %s",
crypt_get_device_name(cd), opal_status_to_string(r));
r = -EINVAL;
goto out;
}
}
out:
crypt_safe_free(user_session);

View File

@@ -3,8 +3,7 @@
* OPAL utilities
*
* Copyright (C) 2022-2023 Luca Boccassi <bluca@debian.org>
* Copyright (C) 2023-2025 Ondrej Kozina <okozina@redhat.com>
* Copyright (C) 2024-2025 Milan Broz
* 2023 Ondrej Kozina <okozina@redhat.com>
*/
#ifndef _UTILS_OPAL

View File

@@ -2,8 +2,8 @@
/*
* LUKS - Linux Unified Key Setup v2
*
* Copyright (C) 2015-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2025 Milan Broz
* Copyright (C) 2015-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2024 Milan Broz
*/
#ifndef _CRYPTSETUP_LUKS2_ONDISK_H
@@ -37,8 +37,6 @@
#define LUKS2_DIGEST_MAX 8
#define LUKS2_MIN_INTEGRITY_KEY_BYTES 16
#define CRYPT_ANY_SEGMENT -1
#define CRYPT_DEFAULT_SEGMENT -2
#define CRYPT_ONE_SEGMENT -3
@@ -111,7 +109,6 @@ struct luks2_hdr {
char uuid[LUKS2_UUID_L];
void *jobj;
void *jobj_rollback;
size_t on_disk_json_end_offset;
};
struct luks2_keyslot_params {
@@ -199,11 +196,11 @@ int LUKS2_keyslot_open(struct crypt_device *cd,
size_t password_len,
struct volume_key **vk);
int LUKS2_keyslot_context_open_all_segments(struct crypt_device *cd,
int LUKS2_keyslot_open_all_segments(struct crypt_device *cd,
int keyslot_old,
int keyslot_new,
struct crypt_keyslot_context *kc_old,
struct crypt_keyslot_context *kc_new,
const char *password,
size_t password_len,
struct volume_key **vks);
int LUKS2_keyslot_store(struct crypt_device *cd,
@@ -231,24 +228,6 @@ int LUKS2_keyslot_swap(struct crypt_device *cd,
int keyslot,
int keyslot2);
/*
* Segments
*/
bool LUKS2_segment_set_size(struct luks2_hdr *hdr,
int segment,
const uint64_t *segment_size_bytes);
bool LUKS2_segment_is_hw_opal(struct luks2_hdr *hdr, int segment);
bool LUKS2_segment_is_hw_opal_crypt(struct luks2_hdr *hdr, int segment);
bool LUKS2_segment_is_hw_opal_only(struct luks2_hdr *hdr, int segment);
int LUKS2_get_opal_segment_number(struct luks2_hdr *hdr, int segment,
uint32_t *ret_opal_segment_number);
int LUKS2_get_opal_key_size(struct luks2_hdr *hdr, int segment);
bool LUKS2_segments_dynamic_size(struct luks2_hdr *hdr);
/*
* Generic LUKS2 token
*/
@@ -284,6 +263,17 @@ crypt_token_info LUKS2_token_status(struct crypt_device *cd,
int token,
const char **type);
int LUKS2_token_open_and_activate(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
int token,
const char *name,
const char *type,
const char *pin,
size_t pin_size,
uint32_t flags,
void *usrptr);
int LUKS2_token_unlock_key(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
@@ -317,7 +307,8 @@ void crypt_token_unload_external_all(struct crypt_device *cd);
/*
* Generic LUKS2 digest
*/
int LUKS2_digest_verify_by_any_matching(struct crypt_device *cd,
int LUKS2_digest_any_matching(struct crypt_device *cd,
struct luks2_hdr *hdr,
const struct volume_key *vk);
int LUKS2_digest_verify_by_segment(struct crypt_device *cd,
@@ -380,7 +371,6 @@ int LUKS2_generate_hdr(
const struct volume_key *vk,
const char *cipher_spec,
const char *integrity,
uint32_t integrity_key_size, /* in bytes, only if separate (HMAC) */
const char *uuid,
unsigned int sector_size,
uint64_t data_offset,
@@ -408,10 +398,8 @@ int LUKS2_get_data_size(struct luks2_hdr *hdr, uint64_t *size, bool *dynamic);
uint32_t 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_get_integrity_key_size(struct luks2_hdr *hdr, int segment);
int LUKS2_keyslot_params_default(struct crypt_device *cd, struct luks2_hdr *hdr,
struct luks2_keyslot_params *params);
int LUKS2_get_old_volume_key_size(struct luks2_hdr *hdr);
int LUKS2_get_volume_key_size(struct luks2_hdr *hdr, int segment);
int LUKS2_get_keyslot_stored_key_size(struct luks2_hdr *hdr, int keyslot);
const char *LUKS2_get_keyslot_cipher(struct luks2_hdr *hdr, int keyslot, size_t *key_size);
@@ -439,7 +427,7 @@ int LUKS2_config_set_flags(struct crypt_device *cd, struct luks2_hdr *hdr, uint3
/*
* Requirements for device activation or header modification
*/
void LUKS2_config_get_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t *reqs);
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);
@@ -447,10 +435,12 @@ int LUKS2_config_get_reencrypt_version(struct luks2_hdr *hdr, uint8_t *version);
bool LUKS2_reencrypt_requirement_candidate(struct luks2_hdr *hdr);
int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint64_t reqs_mask, int quiet);
int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs_mask, int quiet);
int LUKS2_key_description_by_segment(struct crypt_device *cd,
struct luks2_hdr *hdr, struct volume_key *vk, int segment);
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);
@@ -464,6 +454,13 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd,
/*
* LUKS2 reencryption
*/
int LUKS2_reencrypt_locked_recovery_by_passphrase(struct crypt_device *cd,
int keyslot_old,
int keyslot_new,
const char *passphrase,
size_t passphrase_size,
struct volume_key **vks);
int LUKS2_reencrypt_locked_recovery_by_vks(struct crypt_device *cd,
struct volume_key *vks);
@@ -492,10 +489,20 @@ int LUKS2_reencrypt_check_device_size(struct crypt_device *cd,
bool device_exclusive_check,
bool dynamic);
void LUKS2_reencrypt_lookup_key_ids(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct volume_key *vk);
int LUKS2_reencrypt_digest_verify(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct volume_key *vks);
unsigned LUKS2_reencrypt_vks_count(struct luks2_hdr *hdr);
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

@@ -2,8 +2,8 @@
/*
* LUKS - Linux Unified Key Setup v2, digest handling
*
* Copyright (C) 2015-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2025 Milan Broz
* Copyright (C) 2015-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2024 Milan Broz
*/
#include "luks2_internal.h"
@@ -75,7 +75,7 @@ int LUKS2_digest_create(struct crypt_device *cd,
log_dbg(cd, "Creating new digest %d (%s).", digest, type);
return dh->store(cd, digest, crypt_volume_key_get_key(vk), crypt_volume_key_length(vk)) ?: digest;
return dh->store(cd, digest, vk->key, vk->keylength) ?: digest;
}
int LUKS2_digest_by_keyslot(struct luks2_hdr *hdr, int keyslot)
@@ -108,7 +108,7 @@ int LUKS2_digest_verify_by_digest(struct crypt_device *cd,
if (!h)
return -EINVAL;
r = h->verify(cd, digest, crypt_volume_key_get_key(vk), crypt_volume_key_length(vk));
r = h->verify(cd, digest, vk->key, vk->keylength);
if (r < 0) {
log_dbg(cd, "Digest %d (%s) verify failed with %d.", digest, h->name, r);
return r;
@@ -143,7 +143,8 @@ int LUKS2_digest_dump(struct crypt_device *cd, int digest)
return h->dump(cd, digest);
}
int LUKS2_digest_verify_by_any_matching(struct crypt_device *cd,
int LUKS2_digest_any_matching(struct crypt_device *cd,
struct luks2_hdr *hdr __attribute__((unused)),
const struct volume_key *vk)
{
int digest;
@@ -160,7 +161,7 @@ int LUKS2_digest_verify_by_segment(struct crypt_device *cd,
int segment,
const struct volume_key *vk)
{
int r;
int r = -EINVAL;
unsigned s;
if (segment == CRYPT_ANY_SEGMENT) {
@@ -172,11 +173,7 @@ int LUKS2_digest_verify_by_segment(struct crypt_device *cd,
return -EPERM;
}
r = LUKS2_digest_by_segment(hdr, segment);
if (r < 0)
return r;
return LUKS2_digest_verify_by_digest(cd, r, vk);
return LUKS2_digest_verify_by_digest(cd, LUKS2_digest_by_segment(hdr, segment), vk);
}
/* FIXME: segment can have more digests */
@@ -423,7 +420,21 @@ int LUKS2_key_description_by_segment(struct crypt_device *cd,
char *desc = get_key_description_by_digest(cd, LUKS2_digest_by_segment(hdr, segment));
int r;
r = crypt_volume_key_set_description(vk, desc, LOGON_KEY);
r = crypt_volume_key_set_description(vk, desc);
free(desc);
return r;
}
int LUKS2_volume_key_load_in_keyring_by_keyslot(struct crypt_device *cd,
struct luks2_hdr *hdr, struct volume_key *vk, int keyslot)
{
char *desc = get_key_description_by_digest(cd, LUKS2_digest_by_keyslot(hdr, keyslot));
int r;
r = crypt_volume_key_set_description(vk, desc);
if (!r)
r = crypt_volume_key_load_in_keyring(cd, vk);
free(desc);
return r;
}
@@ -434,7 +445,7 @@ int LUKS2_volume_key_load_in_keyring_by_digest(struct crypt_device *cd,
char *desc = get_key_description_by_digest(cd, digest);
int r;
r = crypt_volume_key_set_description(vk, desc, LOGON_KEY);
r = crypt_volume_key_set_description(vk, desc);
if (!r)
r = crypt_volume_key_load_in_keyring(cd, vk);

View File

@@ -2,8 +2,8 @@
/*
* LUKS - Linux Unified Key Setup v2, PBKDF2 digest handler (LUKS1 compatible)
*
* Copyright (C) 2015-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2025 Milan Broz
* Copyright (C) 2015-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2024 Milan Broz
*/
#include "luks2_internal.h"

View File

@@ -2,8 +2,8 @@
/*
* LUKS - Linux Unified Key Setup v2
*
* Copyright (C) 2015-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2025 Milan Broz
* Copyright (C) 2015-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2024 Milan Broz
*/
#include "luks2_internal.h"
@@ -15,7 +15,7 @@ static json_object *parse_json_len(struct crypt_device *cd, const char *json_are
uint64_t max_length, int *json_len)
{
json_object *jobj;
json_tokener *jtok;
struct json_tokener *jtok;
/* INT32_MAX is internal (json-c) json_tokener_parse_ex() limit */
if (!json_area || max_length > INT32_MAX)
@@ -289,25 +289,22 @@ static int hdr_read_disk(struct crypt_device *cd,
*/
static int hdr_write_disk(struct crypt_device *cd,
struct device *device, struct luks2_hdr *hdr,
const char *json_area, size_t write_area_len,
int secondary)
const char *json_area, int secondary)
{
struct luks2_hdr_disk hdr_disk;
uint64_t offset = secondary ? hdr->hdr_size : 0;
size_t hdr_json_len;
int devfd, r;
hdr_json_len = hdr->hdr_size - LUKS2_HDR_BIN_LEN;
assert(write_area_len <= hdr_json_len);
log_dbg(cd, "Trying to write LUKS2 header (%zu bytes) at offset %" PRIu64 ".",
write_area_len, offset);
hdr->hdr_size, offset);
devfd = device_open_locked(cd, device, O_RDWR);
if (devfd < 0)
return devfd == -1 ? -EINVAL : devfd;
hdr_json_len = hdr->hdr_size - LUKS2_HDR_BIN_LEN;
hdr_to_disk(hdr, &hdr_disk, secondary, offset);
/*
@@ -324,8 +321,8 @@ static int hdr_write_disk(struct crypt_device *cd,
*/
if (write_lseek_blockwise(devfd, device_block_size(cd, device),
device_alignment(device),
CONST_CAST(char*)json_area, write_area_len,
LUKS2_HDR_BIN_LEN + offset) < (ssize_t)write_area_len) {
CONST_CAST(char*)json_area, hdr_json_len,
LUKS2_HDR_BIN_LEN + offset) < (ssize_t)hdr_json_len) {
return -EIO;
}
@@ -404,7 +401,7 @@ int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct
{
char *json_area;
const char *json_text;
size_t json_data_len, json_area_len, json_area_write_len;
size_t json_area_len;
int r;
if (hdr->version != 2) {
@@ -416,47 +413,29 @@ int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct
if (r)
return r;
/*
* Generate text space-efficient JSON representation to json area.
*/
json_text = crypt_jobj_to_string_on_disk(hdr->jobj);
if (!json_text || !*json_text) {
log_dbg(cd, "Cannot parse JSON object to text representation.");
return -ENOMEM;
}
json_area_len = hdr->hdr_size - LUKS2_HDR_BIN_LEN;
json_area_write_len = json_data_len = strlen(json_text);
if (json_data_len > (json_area_len - 1)) {
log_dbg(cd, "JSON is too large (%zu > %zu).", json_data_len, json_area_len - 1);
return -EINVAL;
}
/*
* Allocate and zero JSON area (of proper header size).
*/
json_area_len = hdr->hdr_size - LUKS2_HDR_BIN_LEN;
json_area = crypt_zalloc(json_area_len);
if (!json_area)
return -ENOMEM;
/*
* If the metadata in 'json_area' buffer is smaller than last on-disk
* metadata we also have to erase the remaining bytes between the tail
* of current metadata and the on-disk metadata end pointer. Set write
* area length large enough to overwrite it.
*
* If seqid_check is turned off (during LUKS2 format) write entire
* LUKS2 metadata size instead.
*
* Turn off the optimization also during metadata upconversion
* (hdr->on_disk_json_end_offset == 0).
* Generate text space-efficient JSON representation to json area.
*/
if (seqid_check && (json_data_len < hdr->on_disk_json_end_offset))
json_area_write_len = hdr->on_disk_json_end_offset;
else if (!seqid_check || !hdr->on_disk_json_end_offset)
json_area_write_len = json_area_len;
json_text = json_object_to_json_string_ext(hdr->jobj,
JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE);
if (!json_text || !*json_text) {
log_dbg(cd, "Cannot parse JSON object to text representation.");
free(json_area);
return -ENOMEM;
}
if (strlen(json_text) > (json_area_len - 1)) {
log_dbg(cd, "JSON is too large (%zu > %zu).", strlen(json_text), json_area_len);
free(json_area);
return -EINVAL;
}
strncpy(json_area, json_text, json_area_len);
if (seqid_check)
@@ -472,16 +451,13 @@ int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct
hdr->seqid++;
/* Write primary and secondary header */
r = hdr_write_disk(cd, device, hdr, json_area, json_area_write_len, 0);
r = hdr_write_disk(cd, device, hdr, json_area, 0);
if (!r)
r = hdr_write_disk(cd, device, hdr, json_area, json_area_write_len, 1);
r = hdr_write_disk(cd, device, hdr, json_area, 1);
if (r)
log_dbg(cd, "LUKS2 header write failed (%d).", r);
/* store new json end pointer or reset it on error */
hdr->on_disk_json_end_offset = r ? 0 : json_data_len;
device_write_unlock(cd, device);
free(json_area);
@@ -549,15 +525,12 @@ static int validate_luks2_json_object(struct crypt_device *cd, json_object *jobj
}
static json_object *parse_and_validate_json(struct crypt_device *cd,
const char *json_area, uint64_t hdr_size,
uint64_t *json_area_end)
const char *json_area, uint64_t hdr_size)
{
int json_len, r;
json_object *jobj;
uint64_t max_length;
assert(json_area_end);
if (hdr_size <= LUKS2_HDR_BIN_LEN || hdr_size > LUKS2_HDR_OFFSET_MAX) {
log_dbg(cd, "LUKS2 header JSON has bogus size 0x%04" PRIx64 ".", hdr_size);
return NULL;
@@ -581,8 +554,6 @@ static json_object *parse_and_validate_json(struct crypt_device *cd,
jobj = NULL;
}
*json_area_end = json_len;
return jobj;
}
@@ -646,7 +617,7 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
json_object *jobj_hdr1 = NULL, *jobj_hdr2 = NULL;
unsigned int i;
int r;
uint64_t hdr_size, json_area_end1 = 0, json_area_end2 = 0;
uint64_t hdr_size;
uint64_t hdr2_offsets[] = LUKS2_HDR2_OFFSETS;
/* Skip auto-recovery if locks are disabled and we're not doing LUKS2 explicit repair */
@@ -661,7 +632,7 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
state_hdr1 = HDR_FAIL;
r = hdr_read_disk(cd, device, &hdr_disk1, &json_area1, 0, 0);
if (r == 0) {
jobj_hdr1 = parse_and_validate_json(cd, json_area1, be64_to_cpu(hdr_disk1.hdr_size), &json_area_end1);
jobj_hdr1 = parse_and_validate_json(cd, json_area1, be64_to_cpu(hdr_disk1.hdr_size));
state_hdr1 = jobj_hdr1 ? HDR_OK : HDR_OBSOLETE;
} else if (r == -EIO)
state_hdr1 = HDR_FAIL_IO;
@@ -673,7 +644,7 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
if (state_hdr1 != HDR_FAIL && state_hdr1 != HDR_FAIL_IO) {
r = hdr_read_disk(cd, device, &hdr_disk2, &json_area2, be64_to_cpu(hdr_disk1.hdr_size), 1);
if (r == 0) {
jobj_hdr2 = parse_and_validate_json(cd, json_area2, be64_to_cpu(hdr_disk2.hdr_size), &json_area_end2);
jobj_hdr2 = parse_and_validate_json(cd, json_area2, be64_to_cpu(hdr_disk2.hdr_size));
state_hdr2 = jobj_hdr2 ? HDR_OK : HDR_OBSOLETE;
} else if (r == -EIO)
state_hdr2 = HDR_FAIL_IO;
@@ -686,7 +657,7 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
r = hdr_read_disk(cd, device, &hdr_disk2, &json_area2, hdr2_offsets[i], 1);
if (r == 0) {
jobj_hdr2 = parse_and_validate_json(cd, json_area2, be64_to_cpu(hdr_disk2.hdr_size), &json_area_end2);
jobj_hdr2 = parse_and_validate_json(cd, json_area2, be64_to_cpu(hdr_disk2.hdr_size));
state_hdr2 = jobj_hdr2 ? HDR_OK : HDR_OBSOLETE;
} else if (r == -EIO)
state_hdr2 = HDR_FAIL_IO;
@@ -735,7 +706,7 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
log_dbg(cd, "Cannot generate header salt.");
else {
hdr_from_disk(&hdr_disk1, &hdr_disk2, hdr, 0);
r = hdr_write_disk(cd, device, hdr, json_area1, hdr->hdr_size - LUKS2_HDR_BIN_LEN, 1);
r = hdr_write_disk(cd, device, hdr, json_area1, 1);
}
if (r)
log_dbg(cd, "Secondary LUKS2 header recovery failed.");
@@ -756,7 +727,7 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
log_dbg(cd, "Cannot generate header salt.");
else {
hdr_from_disk(&hdr_disk2, &hdr_disk1, hdr, 1);
r = hdr_write_disk(cd, device, hdr, json_area2, hdr->hdr_size - LUKS2_HDR_BIN_LEN, 0);
r = hdr_write_disk(cd, device, hdr, json_area2, 0);
}
if (r)
log_dbg(cd, "Primary LUKS2 header recovery failed.");
@@ -785,11 +756,6 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
json_object_put(jobj_hdr1);
}
if (json_area_end1 > json_area_end2)
hdr->on_disk_json_end_offset = json_area_end1;
else
hdr->on_disk_json_end_offset = json_area_end2;
/*
* FIXME: should this fail? At least one header was read correctly.
* r = (state_hdr1 == HDR_FAIL_IO || state_hdr2 == HDR_FAIL_IO) ? -EIO : -EINVAL;

View File

@@ -1,9 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* LUKS - Linux Unified Key Setup v2 (with JSON internals)
* LUKS - Linux Unified Key Setup v2
*
* Copyright (C) 2015-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2025 Milan Broz
* Copyright (C) 2015-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2024 Milan Broz
*/
#ifndef _CRYPTSETUP_LUKS2_INTERNAL_H
@@ -48,16 +48,6 @@ uint64_t crypt_jobj_get_uint64(json_object *jobj);
uint32_t crypt_jobj_get_uint32(json_object *jobj);
json_object *crypt_jobj_new_uint64(uint64_t value);
/*
* Generate json format string representation libcryptsetup uses
* to store json metadata on disk.
*/
static inline const char *crypt_jobj_to_string_on_disk(json_object *jobj)
{
return json_object_to_json_string_ext(jobj,
JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE);
}
int json_object_object_add_by_uint(json_object *jobj, unsigned key, json_object *jobj_val);
int json_object_object_add_by_uint_by_ref(json_object *jobj, unsigned key, json_object **jobj_val_ref);
void json_object_object_del_by_uint(json_object *jobj, unsigned key);
@@ -99,7 +89,7 @@ json_object *LUKS2_array_remove(json_object *array, const char *num);
*/
/**
* LUKS2 keyslots handlers
* LUKS2 keyslots handlers (EXPERIMENTAL)
*/
typedef int (*keyslot_alloc_func)(struct crypt_device *cd, int keyslot,
size_t volume_key_len,
@@ -162,7 +152,7 @@ struct reenc_protection {
};
/**
* LUKS2 digest handlers
* LUKS2 digest handlers (EXPERIMENTAL)
*/
typedef int (*digest_verify_func)(struct crypt_device *cd, int digest,
const char *volume_key, size_t volume_key_len);
@@ -302,7 +292,7 @@ void json_segment_remove_flag(json_object *jobj_segment, const char *flag);
uint64_t json_segments_get_minimal_offset(json_object *jobj_segments, unsigned blockwise);
json_object *json_segment_create_linear(uint64_t offset, const uint64_t *length, unsigned reencryption);
json_object *json_segment_create_crypt(uint64_t offset, uint64_t iv_offset, const uint64_t *length,
const char *cipher, const char *integrity, uint32_t integrity_key_size,
const char *cipher, const char *integrity,
uint32_t sector_size, unsigned reencryption);
json_object *json_segment_create_opal(uint64_t offset, const uint64_t *length,
uint32_t segment_number, uint32_t key_size);
@@ -347,6 +337,10 @@ uint64_t LUKS2_segment_size(struct luks2_hdr *hdr,
int segment,
unsigned blockwise);
bool LUKS2_segment_set_size(struct luks2_hdr *hdr,
int segment,
const uint64_t *segment_size_bytes);
uint64_t LUKS2_opal_segment_size(struct luks2_hdr *hdr,
int segment,
unsigned blockwise);
@@ -355,6 +349,14 @@ int LUKS2_segment_is_type(struct luks2_hdr *hdr,
int segment,
const char *type);
bool LUKS2_segment_is_hw_opal(struct luks2_hdr *hdr, int segment);
bool LUKS2_segment_is_hw_opal_crypt(struct luks2_hdr *hdr, int segment);
bool LUKS2_segment_is_hw_opal_only(struct luks2_hdr *hdr, int segment);
int LUKS2_get_opal_segment_number(struct luks2_hdr *hdr, int segment,
uint32_t *ret_opal_segment_number);
int LUKS2_get_opal_key_size(struct luks2_hdr *hdr, int segment);
int LUKS2_segment_by_type(struct luks2_hdr *hdr,
const char *type);
@@ -363,20 +365,13 @@ int LUKS2_last_segment_by_type(struct luks2_hdr *hdr,
int LUKS2_get_default_segment(struct luks2_hdr *hdr);
bool LUKS2_segments_dynamic_size(struct luks2_hdr *hdr);
int LUKS2_reencrypt_digest_new(struct luks2_hdr *hdr);
int LUKS2_reencrypt_digest_old(struct luks2_hdr *hdr);
int LUKS2_reencrypt_segment_new(struct luks2_hdr *hdr);
int LUKS2_reencrypt_segment_old(struct luks2_hdr *hdr);
unsigned LUKS2_reencrypt_vks_count(struct luks2_hdr *hdr);
int LUKS2_reencrypt_data_offset(struct luks2_hdr *hdr, bool blockwise);
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);
/*
* Generic LUKS2 digest
*/

View File

@@ -2,8 +2,8 @@
/*
* LUKS - Linux Unified Key Setup v2, LUKS2 header format code
*
* Copyright (C) 2015-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2025 Milan Broz
* Copyright (C) 2015-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2024 Milan Broz
*/
#include "luks2_internal.h"
@@ -193,7 +193,6 @@ int LUKS2_generate_hdr(
const struct volume_key *vk,
const char *cipher_spec,
const char *integrity,
uint32_t integrity_key_size, /* in bytes, only if separate (HMAC) */
const char *uuid,
unsigned int sector_size, /* in bytes */
uint64_t data_offset, /* in bytes */
@@ -203,7 +202,7 @@ int LUKS2_generate_hdr(
uint32_t opal_segment_number,
uint32_t opal_key_size)
{
json_object *jobj_segment, *jobj_keyslots, *jobj_segments, *jobj_config;
struct json_object *jobj_segment, *jobj_keyslots, *jobj_segments, *jobj_config;
uuid_t partitionUuid;
int r, digest;
@@ -280,8 +279,8 @@ int LUKS2_generate_hdr(
if (!opal_key_size)
jobj_segment = json_segment_create_crypt(data_offset, 0,
NULL, cipher_spec,
integrity, integrity_key_size,
sector_size, 0);
integrity, sector_size,
0);
else if (opal_key_size && cipher_spec)
jobj_segment = json_segment_create_opal_crypt(data_offset, &device_size_bytes,
opal_segment_number, opal_key_size, 0,

View File

@@ -2,9 +2,9 @@
/*
* LUKS - Linux Unified Key Setup v2
*
* Copyright (C) 2015-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2025 Milan Broz
* Copyright (C) 2015-2025 Ondrej Kozina
* Copyright (C) 2015-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2024 Milan Broz
* Copyright (C) 2015-2024 Ondrej Kozina
*/
#include "luks2_internal.h"
@@ -13,6 +13,8 @@
#include <ctype.h>
#include <uuid/uuid.h>
#define LUKS_STRIPES 4000
struct interval {
uint64_t offset;
uint64_t length;
@@ -49,9 +51,9 @@ void JSON_DBG(struct crypt_device *cd, json_object *jobj, const char *desc)
/*
* JSON array helpers
*/
json_object *LUKS2_array_jobj(json_object *array, const char *num)
struct json_object *LUKS2_array_jobj(struct json_object *array, const char *num)
{
json_object *jobj1;
struct json_object *jobj1;
int i;
for (i = 0; i < (int) json_object_array_length(array); i++) {
@@ -63,9 +65,9 @@ json_object *LUKS2_array_jobj(json_object *array, const char *num)
return NULL;
}
json_object *LUKS2_array_remove(json_object *array, const char *num)
struct json_object *LUKS2_array_remove(struct json_object *array, const char *num)
{
json_object *jobj1, *jobj_removing = NULL, *array_new;
struct json_object *jobj1, *jobj_removing = NULL, *array_new;
int i;
jobj_removing = LUKS2_array_jobj(array, num);
@@ -465,7 +467,8 @@ static int hdr_validate_json_size(struct crypt_device *cd, json_object *hdr_jobj
json_object_object_get_ex(hdr_jobj, "config", &jobj);
json_object_object_get_ex(jobj, "json_size", &jobj1);
json = crypt_jobj_to_string_on_disk(hdr_jobj);
json = json_object_to_json_string_ext(hdr_jobj,
JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE);
if (!json)
return 1;
@@ -633,11 +636,6 @@ static int reqs_opal(uint32_t reqs)
return reqs & CRYPT_REQUIREMENT_OPAL;
}
static int reqs_inline_hw_tags(uint32_t reqs)
{
return reqs & CRYPT_REQUIREMENT_INLINE_HW_TAGS;
}
/*
* Config section requirements object must be valid.
* Also general segments section must be validated first.
@@ -646,12 +644,14 @@ static int validate_reencrypt_segments(struct crypt_device *cd, json_object *hdr
{
json_object *jobj, *jobj_backup_previous = NULL, *jobj_backup_final = NULL;
uint32_t reqs;
int i;
int i, r;
struct luks2_hdr dummy = {
.jobj = hdr_jobj
};
LUKS2_config_get_requirements(cd, &dummy, &reqs);
r = LUKS2_config_get_requirements(cd, &dummy, &reqs);
if (r)
return 1;
if (reqs_reencrypt_online(reqs)) {
for (i = first_backup; i < segments_count; i++) {
@@ -1272,11 +1272,7 @@ int LUKS2_hdr_uuid(struct crypt_device *cd, struct luks2_hdr *hdr, const char *u
int LUKS2_hdr_labels(struct crypt_device *cd, struct luks2_hdr *hdr,
const char *label, const char *subsystem, int commit)
{
if ((label && strlen(label) >= LUKS2_LABEL_L) ||
(subsystem && strlen(subsystem) >= LUKS2_LABEL_L)) {
log_err(cd, _("Label is too long."));
return -EINVAL;
}
//FIXME: check if the labels are the same and skip this.
memset(hdr->label, 0, LUKS2_LABEL_L);
if (label)
@@ -1430,8 +1426,7 @@ int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr,
}
/* do not allow header restore from backup with unmet requirements */
if (LUKS2_unmet_requirements(cd, &hdr_file,
CRYPT_REQUIREMENT_ONLINE_REENCRYPT | CRYPT_REQUIREMENT_INLINE_HW_TAGS, 1)) {
if (LUKS2_unmet_requirements(cd, &hdr_file, CRYPT_REQUIREMENT_ONLINE_REENCRYPT, 1)) {
log_err(cd, _("Forbidden LUKS2 requirements detected in backup %s."),
backup_file);
r = -ETXTBSY;
@@ -1463,7 +1458,9 @@ int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr,
r = LUKS2_hdr_read(cd, &tmp_hdr, 0);
if (r == 0) {
log_dbg(cd, "Device %s already contains LUKS2 header, checking UUID and requirements.", device_path(device));
LUKS2_config_get_requirements(cd, &tmp_hdr, &reqs);
r = LUKS2_config_get_requirements(cd, &tmp_hdr, &reqs);
if (r)
goto out;
if (memcmp(tmp_hdr.uuid, hdr_file.uuid, LUKS2_UUID_L))
diff_uuid = 1;
@@ -1547,7 +1544,7 @@ out:
* Persistent config flags
*/
static const struct {
uint64_t flag;
uint32_t flag;
const char *description;
} persistent_flags[] = {
{ CRYPT_ACTIVATE_ALLOW_DISCARDS, "allow-discards" },
@@ -1556,7 +1553,6 @@ static const struct {
{ CRYPT_ACTIVATE_NO_JOURNAL, "no-journal" },
{ CRYPT_ACTIVATE_NO_READ_WORKQUEUE, "no-read-workqueue" },
{ CRYPT_ACTIVATE_NO_WRITE_WORKQUEUE, "no-write-workqueue" },
{ CRYPT_ACTIVATE_HIGH_PRIORITY, "high_priority" },
{ 0, NULL }
};
@@ -1646,7 +1642,6 @@ static const struct requirement_flag requirements_flags[] = {
{ CRYPT_REQUIREMENT_ONLINE_REENCRYPT, 2, "online-reencrypt-v2" },
{ CRYPT_REQUIREMENT_ONLINE_REENCRYPT, 3, "online-reencrypt-v3" },
{ CRYPT_REQUIREMENT_ONLINE_REENCRYPT, 1, "online-reencrypt" },
{ CRYPT_REQUIREMENT_INLINE_HW_TAGS, 1, "inline-hw-tags" },
{ CRYPT_REQUIREMENT_OPAL, 1, "opal" },
{ 0, 0, NULL }
};
@@ -1769,7 +1764,7 @@ static const struct requirement_flag *stored_requirement_name_by_id(struct luks2
/*
* returns count of requirements (past cryptsetup 2.0 release)
*/
void LUKS2_config_get_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t *reqs)
int LUKS2_config_get_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t *reqs)
{
json_object *jobj_mandatory, *jobj;
int i, len;
@@ -1782,11 +1777,11 @@ void LUKS2_config_get_requirements(struct crypt_device *cd, struct luks2_hdr *hd
jobj_mandatory = mandatory_requirements_jobj(hdr);
if (!jobj_mandatory)
return;
return 0;
len = (int) json_object_array_length(jobj_mandatory);
if (len <= 0)
return;
return 0;
log_dbg(cd, "LUKS2 requirements detected:");
@@ -1797,6 +1792,8 @@ void LUKS2_config_get_requirements(struct crypt_device *cd, struct luks2_hdr *hd
reqs_unknown(req->flag) ? "un" : "");
*reqs |= req->flag;
}
return 0;
}
int LUKS2_config_set_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs, bool commit)
@@ -1804,7 +1801,7 @@ int LUKS2_config_set_requirements(struct crypt_device *cd, struct luks2_hdr *hdr
json_object *jobj_config, *jobj_requirements, *jobj_mandatory, *jobj;
int i, r = -EINVAL;
const struct requirement_flag *req;
uint64_t req_id;
uint32_t req_id;
if (!hdr)
return -EINVAL;
@@ -2131,10 +2128,6 @@ static void hdr_dump_segments(struct crypt_device *cd, json_object *hdr_jobj)
json_object_object_get_ex(jobj1, "type", &jobj2))
log_std(cd, "\tintegrity: %s\n", json_object_get_string(jobj2));
if (json_object_object_get_ex(jobj_segment, "integrity", &jobj1) &&
json_object_object_get_ex(jobj1, "key_size", &jobj2))
log_std(cd, "\tintegrity key size: %" PRIu32 " [bits]\n", crypt_jobj_get_uint32(jobj2) * 8);
if (json_object_object_get_ex(jobj_segment, "flags", &jobj1) &&
(flags = (int)json_object_array_length(jobj1)) > 0) {
jobj2 = json_object_array_get_idx(jobj1, 0);
@@ -2311,7 +2304,12 @@ crypt_reencrypt_info LUKS2_reencrypt_status(struct luks2_hdr *hdr)
{
uint32_t reqs;
LUKS2_config_get_requirements(NULL, hdr, &reqs);
/*
* Any unknown requirement or offline reencryption should abort
* anything related to online-reencryption handling
*/
if (LUKS2_config_get_requirements(NULL, hdr, &reqs))
return CRYPT_REENCRYPT_INVALID;
if (!reqs_reencrypt_online(reqs))
return CRYPT_REENCRYPT_NONE;
@@ -2365,24 +2363,6 @@ const char *LUKS2_get_integrity(struct luks2_hdr *hdr, int segment)
return json_object_get_string(jobj3);
}
int LUKS2_get_integrity_key_size(struct luks2_hdr *hdr, int segment)
{
json_object *jobj1, *jobj2, *jobj3;
jobj1 = LUKS2_get_segment_jobj(hdr, segment);
if (!jobj1)
return -1;
if (!json_object_object_get_ex(jobj1, "integrity", &jobj2))
return -1;
/* The value is optional, do not fail if not present */
if (!json_object_object_get_ex(jobj2, "key_size", &jobj3))
return 0;
return json_object_get_int(jobj3);
}
/* FIXME: this only ensures that once we have journal encryption, it is not ignored. */
/* implement segment count and type restrictions (crypt and only single crypt) */
static int LUKS2_integrity_compatible(struct luks2_hdr *hdr)
@@ -2470,19 +2450,6 @@ int LUKS2_get_volume_key_size(struct luks2_hdr *hdr, int segment)
return -1;
}
int LUKS2_get_old_volume_key_size(struct luks2_hdr *hdr)
{
int old_segment;
assert(hdr);
old_segment = LUKS2_reencrypt_segment_old(hdr);
if (old_segment < 0)
return old_segment;
return LUKS2_get_volume_key_size(hdr, old_segment);
}
uint32_t LUKS2_get_sector_size(struct luks2_hdr *hdr)
{
return json_segment_get_sector_size(LUKS2_get_segment_jobj(hdr, CRYPT_DEFAULT_SEGMENT));
@@ -2551,7 +2518,7 @@ int LUKS2_assembly_multisegment_dmd(struct crypt_device *cd,
crypt_data_device(cd), vk,
json_segment_get_cipher(jobj),
json_segment_get_iv_offset(jobj),
segment_offset, "none", 0, 0,
segment_offset, "none", 0,
json_segment_get_sector_size(jobj));
if (r) {
log_err(cd, _("Failed to set dm-crypt segment."));
@@ -2665,7 +2632,7 @@ int LUKS2_activate(struct crypt_device *cd,
{
int r;
bool dynamic, read_lock, write_lock, opal_lock_on_error = false;
uint32_t opal_segment_number, req_flags;
uint32_t opal_segment_number;
uint64_t range_offset_sectors, range_length_sectors, device_length_bytes;
struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
struct crypt_dm_active_device dmdi = {}, dmd = {
@@ -2674,8 +2641,7 @@ int LUKS2_activate(struct crypt_device *cd,
struct crypt_lock_handle *opal_lh = NULL;
/* do not allow activation when particular requirements detected */
if ((r = LUKS2_unmet_requirements(cd, hdr,
CRYPT_REQUIREMENT_OPAL | CRYPT_REQUIREMENT_INLINE_HW_TAGS, 0)))
if ((r = LUKS2_unmet_requirements(cd, hdr, CRYPT_REQUIREMENT_OPAL, 0)))
return r;
/* Check that cipher is in compatible format */
@@ -2748,7 +2714,7 @@ int LUKS2_activate(struct crypt_device *cd,
crypt_key, crypt_get_cipher_spec(cd),
crypt_get_iv_offset(cd), crypt_get_data_offset(cd),
crypt_get_integrity(cd) ?: "none",
crypt_get_integrity_key_size(cd, true), crypt_get_integrity_tag_size(cd),
crypt_get_integrity_tag_size(cd),
crypt_get_sector_size(cd));
} else
r = dm_linear_target_set(&dmd.segment, 0,
@@ -2764,13 +2730,7 @@ int LUKS2_activate(struct crypt_device *cd,
dmd.flags |= flags;
if (crypt_persistent_flags_get(cd, CRYPT_FLAGS_REQUIREMENTS, &req_flags)) {
r = -EINVAL;
goto out;
}
if (crypt_get_integrity_tag_size(cd) &&
!(req_flags & CRYPT_REQUIREMENT_INLINE_HW_TAGS)) {
if (crypt_get_integrity_tag_size(cd)) {
if (!LUKS2_integrity_compatible(hdr)) {
log_err(cd, _("Unsupported device integrity configuration."));
r = -EINVAL;
@@ -2850,14 +2810,14 @@ int LUKS2_deactivate(struct crypt_device *cd, const char *name, struct luks2_hdr
struct crypt_dm_active_device dmdc;
uint32_t opal_segment_number;
char **dep, deps_uuid_prefix[40], *deps[MAX_DM_DEPS+1] = { 0 };
char *iname = NULL;
const char *namei = NULL;
struct crypt_lock_handle *reencrypt_lock = NULL, *opal_lh = NULL;
if (!dmd || !dmd->uuid || strncmp(CRYPT_LUKS2, dmd->uuid, sizeof(CRYPT_LUKS2)-1))
return -EINVAL;
/* uuid mismatch with metadata (if available) */
if (hdr && dm_uuid_cmp(dmd->uuid, hdr->uuid))
if (hdr && crypt_uuid_cmp(dmd->uuid, hdr->uuid))
return -EINVAL;
r = snprintf(deps_uuid_prefix, sizeof(deps_uuid_prefix), CRYPT_SUBDEV "-%.32s", dmd->uuid + 6);
@@ -2865,15 +2825,15 @@ int LUKS2_deactivate(struct crypt_device *cd, const char *name, struct luks2_hdr
return -EINVAL;
/* check if active device has LUKS2-OPAL dm uuid prefix */
dm_opal_uuid = !dm_uuid_type_cmp(dmd->uuid, CRYPT_LUKS2_HW_OPAL);
dm_opal_uuid = !crypt_uuid_type_cmp(dmd->uuid, CRYPT_LUKS2_HW_OPAL);
if (dm_opal_uuid && hdr && !LUKS2_segment_is_hw_opal(hdr, CRYPT_DEFAULT_SEGMENT))
return -EINVAL;
tgt = &dmd->segment;
/* TODO: We have LUKS2 dependencies now */
if (tgt->type == DM_CRYPT && tgt->u.crypt.tag_size)
iname = dm_get_active_iname(cd, name);
if (single_segment(dmd) && tgt->type == DM_CRYPT && tgt->u.crypt.tag_size)
namei = device_dm_name(tgt->data_device);
r = dm_device_deps(cd, name, deps_uuid_prefix, deps, ARRAY_SIZE(deps));
if (r < 0)
@@ -2911,34 +2871,23 @@ int LUKS2_deactivate(struct crypt_device *cd, const char *name, struct luks2_hdr
tgt = &dmdc.segment;
while (tgt) {
if (tgt->type == DM_CRYPT)
crypt_volume_key_drop_kernel_key(cd, tgt->u.crypt.vk);
crypt_drop_keyring_key_by_description(cd, tgt->u.crypt.vk->key_description,
LOGON_KEY);
tgt = tgt->next;
}
}
dm_targets_free(cd, &dmdc);
/* TODO: We have LUKS2 dependencies now */
if (r >= 0 && iname) {
log_dbg(cd, "Deactivating integrity device %s.", iname);
r = dm_remove_device(cd, iname, 0);
if (r >= 0 && namei) {
log_dbg(cd, "Deactivating integrity device %s.", namei);
r = dm_remove_device(cd, namei, 0);
}
if (!r) {
ret = 0;
dep = deps;
while (*dep) {
/*
* FIXME: dm-integrity has now proper SUBDEV prefix so
* it would be deactivated here, but due to specific
* dm_remove_device(iname) above the iname device
* is no longer active. This will be fixed when
* we switch to SUBDEV deactivation after 2.8 release.
*/
if (iname && !strcmp(*dep, iname)) {
dep++;
continue;
}
log_dbg(cd, "Deactivating LUKS2 dependent device %s.", *dep);
r = dm_query_device(cd, *dep, DM_ACTIVE_CRYPT_KEY | DM_ACTIVE_CRYPT_KEYSIZE, &dmdc);
if (r < 0) {
@@ -2958,7 +2907,8 @@ int LUKS2_deactivate(struct crypt_device *cd, const char *name, struct luks2_hdr
tgt = &dmdc.segment;
while (tgt) {
if (tgt->type == DM_CRYPT)
crypt_volume_key_drop_kernel_key(cd, tgt->u.crypt.vk);
crypt_drop_keyring_key_by_description(cd, tgt->u.crypt.vk->key_description,
LOGON_KEY);
tgt = tgt->next;
}
}
@@ -3000,7 +2950,6 @@ int LUKS2_deactivate(struct crypt_device *cd, const char *name, struct luks2_hdr
out:
opal_exclusive_unlock(cd, opal_lh);
LUKS2_reencrypt_unlock(cd, reencrypt_lock);
free(iname);
dep = deps;
while (*dep)
free(*dep++);
@@ -3008,11 +2957,16 @@ out:
return r;
}
int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint64_t reqs_mask, int quiet)
int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs_mask, int quiet)
{
uint32_t reqs;
int r = LUKS2_config_get_requirements(cd, hdr, &reqs);
LUKS2_config_get_requirements(cd, hdr, &reqs);
if (r) {
if (!quiet)
log_err(cd, _("Failed to read LUKS2 requirements."));
return r;
}
/* do not mask unknown requirements check */
if (reqs_unknown(reqs)) {
@@ -3030,8 +2984,6 @@ int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uin
log_err(cd, _("Operation incompatible with device marked for LUKS2 reencryption. Aborting."));
if (reqs_opal(reqs) && !quiet)
log_err(cd, _("Operation incompatible with device using OPAL. Aborting."));
if (reqs_inline_hw_tags(reqs) && !quiet)
log_err(cd, _("Operation incompatible with device using inline HW tags. Aborting."));
/* any remaining unmasked requirement fails the check */
return reqs ? -EINVAL : 0;
@@ -3140,22 +3092,22 @@ int LUKS2_split_crypt_and_opal_keys(struct crypt_device *cd __attribute__((unuse
if (r < 0)
return -EINVAL;
if (crypt_volume_key_length(vk) < opal_user_key_size)
if (vk->keylength < opal_user_key_size)
return -EINVAL;
/* OPAL SEGMENT only */
if (crypt_volume_key_length(vk) == opal_user_key_size) {
if (vk->keylength == opal_user_key_size) {
*ret_crypt_key = NULL;
*ret_opal_key = NULL;
return 0;
}
opal_key = crypt_alloc_volume_key(opal_user_key_size, crypt_volume_key_get_key(vk));
opal_key = crypt_alloc_volume_key(opal_user_key_size, vk->key);
if (!opal_key)
return -ENOMEM;
crypt_key = crypt_alloc_volume_key(crypt_volume_key_length(vk) - opal_user_key_size,
crypt_volume_key_get_key(vk) + opal_user_key_size);
crypt_key = crypt_alloc_volume_key(vk->keylength - opal_user_key_size,
vk->key + opal_user_key_size);
if (!crypt_key) {
crypt_free_volume_key(opal_key);
return -ENOMEM;

View File

@@ -2,12 +2,11 @@
/*
* LUKS - Linux Unified Key Setup v2, keyslot handling
*
* Copyright (C) 2015-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2025 Milan Broz
* Copyright (C) 2015-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2024 Milan Broz
*/
#include "luks2_internal.h"
#include "keyslot_context.h"
/* Internal implementations */
extern const keyslot_handler luks2_keyslot;
@@ -76,38 +75,8 @@ int LUKS2_keyslot_find_empty(struct crypt_device *cd, struct luks2_hdr *hdr, siz
/* Check if a keyslot is assigned to specific segment */
static int _keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment)
{
json_object *jobj_keyslots, *jobj;
crypt_keyslot_priority slot_priority;
unsigned s;
int keyslot_digest, count = 0;
/*
* Must not be called with both keyslot == CRYPT_ANY_SLOT
* and segment == CRYPT_ONE_SEGMENT. The CRYPT_DEFAULT_SEGMENT
* and CRYPT_ANY_SEGMENT are handled properly in upper layer.
*/
assert(keyslot >= 0 || segment >= 0);
if (keyslot == CRYPT_ANY_SLOT) {
json_object_object_get_ex(hdr->jobj, "keyslots", &jobj_keyslots);
json_object_object_foreach(jobj_keyslots, slot, val) {
if (!json_object_object_get_ex(val, "priority", &jobj))
slot_priority = CRYPT_SLOT_PRIORITY_NORMAL;
else
slot_priority = json_object_get_int(jobj);
if (slot_priority < CRYPT_SLOT_PRIORITY_NORMAL)
continue;
keyslot_digest = LUKS2_digest_by_keyslot(hdr, atoi(slot));
if (keyslot_digest >= 0 &&
keyslot_digest == LUKS2_digest_by_segment(hdr, segment))
return 1;
}
return 0;
}
unsigned s;
keyslot_digest = LUKS2_digest_by_keyslot(hdr, keyslot);
if (keyslot_digest < 0)
@@ -124,6 +93,16 @@ static int _keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment)
return count;
}
static int _keyslot_for_digest(struct luks2_hdr *hdr, int keyslot, int digest)
{
int r = -EINVAL;
r = LUKS2_digest_by_keyslot(hdr, keyslot);
if (r < 0)
return r;
return r == digest ? 0 : -ENOENT;
}
int LUKS2_keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment)
{
int r = -EINVAL;
@@ -165,17 +144,7 @@ int LUKS2_keyslot_cipher_incompatible(struct crypt_device *cd, const char *ciphe
{
char cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
if (!cipher_spec)
return 1;
/*
* Do not allow capi format for keyslots
* Note: It always failed in ivsize check later anyway.
*/
if (!strncmp(cipher_spec, "capi:", 5))
return 1;
if (crypt_is_cipher_null(cipher_spec))
if (!cipher_spec || crypt_is_cipher_null(cipher_spec))
return 1;
if (crypt_parse_name_and_mode(cipher_spec, cipher, NULL, cipher_mode) < 0)
@@ -349,43 +318,61 @@ static int _open_and_verify(struct crypt_device *cd,
int keyslot,
const char *password,
size_t password_len,
struct volume_key **r_vk)
struct volume_key **vk)
{
int r, key_size = LUKS2_get_keyslot_stored_key_size(hdr, keyslot);
struct volume_key *vk = NULL;
void *key = NULL;
if (key_size < 0)
return -EINVAL;
key = crypt_safe_alloc(key_size);
if (!key)
*vk = crypt_alloc_volume_key(key_size, NULL);
if (!*vk)
return -ENOMEM;
r = h->open(cd, keyslot, password, password_len, key, key_size);
if (r < 0) {
log_dbg(cd, "Keyslot %d (%s) open failed with %d.", keyslot, h->name, r);
goto err;
}
vk = crypt_alloc_volume_key_by_safe_alloc(&key);
if (!vk) {
r = -ENOMEM;
goto err;
}
r = LUKS2_digest_verify(cd, hdr, vk, keyslot);
r = h->open(cd, keyslot, password, password_len, (*vk)->key, (*vk)->keylength);
if (r < 0)
goto err;
log_dbg(cd, "Keyslot %d (%s) open failed with %d.", keyslot, h->name, r);
else
r = LUKS2_digest_verify(cd, hdr, *vk, keyslot);
crypt_volume_key_set_id(vk, r);
*r_vk = vk;
return keyslot;
err:
crypt_safe_free(key);
crypt_free_volume_key(vk);
if (r < 0) {
crypt_free_volume_key(*vk);
*vk = NULL;
}
return r;
crypt_volume_key_set_id(*vk, r);
return r < 0 ? r : keyslot;
}
static int LUKS2_open_and_verify_by_digest(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
int digest,
const char *password,
size_t password_len,
struct volume_key **vk)
{
const keyslot_handler *h;
int r;
if (!(h = LUKS2_keyslot_handler(cd, keyslot)))
return -ENOENT;
r = h->validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot));
if (r) {
log_dbg(cd, "Keyslot %d validation failed.", keyslot);
return r;
}
r = _keyslot_for_digest(hdr, keyslot, digest);
if (r) {
if (r == -ENOENT)
log_dbg(cd, "Keyslot %d unusable for digest %d.", keyslot, digest);
return r;
}
return _open_and_verify(cd, hdr, h, keyslot, password, password_len, vk);
}
static int LUKS2_open_and_verify(struct crypt_device *cd,
@@ -418,6 +405,49 @@ static int LUKS2_open_and_verify(struct crypt_device *cd,
return _open_and_verify(cd, hdr, h, keyslot, password, password_len, vk);
}
static int LUKS2_keyslot_open_priority_digest(struct crypt_device *cd,
struct luks2_hdr *hdr,
crypt_keyslot_priority priority,
const char *password,
size_t password_len,
int digest,
struct volume_key **vk)
{
json_object *jobj_keyslots, *jobj;
crypt_keyslot_priority slot_priority;
int keyslot, r = -ENOENT, r_old;
json_object_object_get_ex(hdr->jobj, "keyslots", &jobj_keyslots);
json_object_object_foreach(jobj_keyslots, slot, val) {
r_old = r;
if (!json_object_object_get_ex(val, "priority", &jobj))
slot_priority = CRYPT_SLOT_PRIORITY_NORMAL;
else
slot_priority = json_object_get_int(jobj);
keyslot = atoi(slot);
if (slot_priority != priority) {
log_dbg(cd, "Keyslot %d priority %d != %d (required), skipped.",
keyslot, slot_priority, priority);
continue;
}
r = LUKS2_open_and_verify_by_digest(cd, hdr, keyslot, digest, password, password_len, vk);
/* Do not retry for errors that are no -EPERM or -ENOENT,
former meaning password wrong, latter key slot unusable for segment */
if ((r != -EPERM) && (r != -ENOENT))
break;
/* If a previous keyslot failed with EPERM (bad password) prefer it */
if (r_old == -EPERM && r == -ENOENT)
r = -EPERM;
}
return r;
}
static int LUKS2_keyslot_open_priority(struct crypt_device *cd,
struct luks2_hdr *hdr,
crypt_keyslot_priority priority,
@@ -461,83 +491,70 @@ static int LUKS2_keyslot_open_priority(struct crypt_device *cd,
return r;
}
static int keyslot_context_open_all_segments(struct crypt_device *cd,
static int LUKS2_keyslot_open_by_digest(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
int digest,
const char *password,
size_t password_len,
struct volume_key **vk)
{
int r_prio, r = -EINVAL;
if (digest < 0)
return r;
if (keyslot == CRYPT_ANY_SLOT) {
r_prio = LUKS2_keyslot_open_priority_digest(cd, hdr, CRYPT_SLOT_PRIORITY_PREFER,
password, password_len, digest, vk);
if (r_prio >= 0)
r = r_prio;
else if (r_prio != -EPERM && r_prio != -ENOENT)
r = r_prio;
else
r = LUKS2_keyslot_open_priority_digest(cd, hdr, CRYPT_SLOT_PRIORITY_NORMAL,
password, password_len, digest, vk);
/* Prefer password wrong to no entry from priority slot */
if (r_prio == -EPERM && r == -ENOENT)
r = r_prio;
} else
r = LUKS2_open_and_verify_by_digest(cd, hdr, keyslot, digest, password, password_len, vk);
return r;
}
int LUKS2_keyslot_open_all_segments(struct crypt_device *cd,
int keyslot_old,
int keyslot_new,
struct crypt_keyslot_context *kc_old,
struct crypt_keyslot_context *kc_new,
struct volume_key **r_vks)
const char *password,
size_t password_len,
struct volume_key **vks)
{
int segment_old, segment_new, digest_old = -1, digest_new = -1, r = -ENOENT;
struct luks2_hdr *hdr;
struct volume_key *vk = NULL;
int digest_old, digest_new, r = -EINVAL;
struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
assert(cd);
assert(!kc_old || kc_old->get_luks2_key);
assert(!kc_new || kc_new->get_luks2_key);
assert(r_vks);
hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
segment_old = LUKS2_reencrypt_segment_old(hdr);
segment_new = LUKS2_reencrypt_segment_new(hdr);
if (segment_old < 0 || segment_new < 0)
return -EINVAL;
digest_old = LUKS2_digest_by_segment(hdr, segment_old);
digest_new = LUKS2_digest_by_segment(hdr, segment_new);
if (digest_old >= 0 && digest_new >= 0 && digest_old != digest_new && (!kc_old || !kc_new))
return -ESRCH;
if (digest_old >= 0 && kc_old) {
log_dbg(cd, "Checking current volume key (digest %d, segment: %d) using keyslot %d.",
digest_old, segment_old, keyslot_old);
/* key and key in keyring types do not have association with any keyslot */
if (kc_old->type != CRYPT_KC_TYPE_KEY && kc_old->type != CRYPT_KC_TYPE_VK_KEYRING) {
r = LUKS2_keyslot_for_segment(hdr, keyslot_old, segment_old);
if (r < 0)
goto out;
}
r = kc_old->get_luks2_key(cd, kc_old, keyslot_old, segment_old, &vk);
digest_old = LUKS2_reencrypt_digest_old(hdr);
if (digest_old >= 0) {
log_dbg(cd, "Trying to unlock volume key (digest: %d) using keyslot %d.", digest_old, keyslot_old);
r = LUKS2_keyslot_open_by_digest(cd, hdr, keyslot_old, digest_old, password, password_len, &vk);
if (r < 0)
goto out;
crypt_volume_key_add_next(r_vks, vk);
if (crypt_volume_key_get_id(vk) < 0 && LUKS2_digest_verify_by_digest(cd, digest_old, vk) == digest_old)
crypt_volume_key_set_id(vk, digest_old);
if (crypt_volume_key_get_id(vk) != digest_old) {
r = -EPERM;
goto out;
}
crypt_volume_key_add_next(vks, vk);
}
if (digest_new >= 0 && digest_old != digest_new && kc_new) {
log_dbg(cd, "Checking new volume key (digest %d, segment: %d) using keyslot %d.",
digest_new, segment_new, keyslot_new);
/* key and key in keyring types do not have association with any keyslot */
if (kc_new->type != CRYPT_KC_TYPE_KEY && kc_new->type != CRYPT_KC_TYPE_VK_KEYRING) {
r = LUKS2_keyslot_for_segment(hdr, keyslot_new, segment_new);
if (r < 0)
goto out;
}
r = kc_new->get_luks2_key(cd, kc_new, keyslot_new, segment_new, &vk);
digest_new = LUKS2_reencrypt_digest_new(hdr);
if (digest_new >= 0 && digest_old != digest_new) {
log_dbg(cd, "Trying to unlock volume key (digest: %d) using keyslot %d.", digest_new, keyslot_new);
r = LUKS2_keyslot_open_by_digest(cd, hdr, keyslot_new, digest_new, password, password_len, &vk);
if (r < 0)
goto out;
crypt_volume_key_add_next(r_vks, vk);
if (crypt_volume_key_get_id(vk) < 0 && LUKS2_digest_verify_by_digest(cd, digest_new, vk) == digest_new)
crypt_volume_key_set_id(vk, digest_new);
if (crypt_volume_key_get_id(vk) != digest_new)
r = -EPERM;
crypt_volume_key_add_next(vks, vk);
}
out:
if (r < 0) {
crypt_free_volume_key(*r_vks);
*r_vks = NULL;
crypt_free_volume_key(*vks);
*vks = NULL;
if (r == -ENOMEM)
log_err(cd, _("Not enough available memory to open a keyslot."));
@@ -547,25 +564,6 @@ out:
return r;
}
int LUKS2_keyslot_context_open_all_segments(struct crypt_device *cd,
int keyslot1,
int keyslot2,
struct crypt_keyslot_context *kc1,
struct crypt_keyslot_context *kc2,
struct volume_key **r_vks)
{
int r, r2;
r = keyslot_context_open_all_segments(cd, keyslot1, keyslot2, kc1, kc2, r_vks);
if (r == -EPERM || r == -ENOENT) {
r2 = keyslot_context_open_all_segments(cd, keyslot2, keyslot1, kc2, kc1, r_vks);
if (r2 != -ENOENT)
r = r2;
}
return r;
}
int LUKS2_keyslot_open(struct crypt_device *cd,
int keyslot,
int segment,
@@ -648,7 +646,7 @@ int LUKS2_keyslot_store(struct crypt_device *cd,
if (!h)
return -EINVAL;
r = h->alloc(cd, keyslot, crypt_volume_key_length(vk), params);
r = h->alloc(cd, keyslot, vk->keylength, params);
if (r)
return r;
} else {
@@ -672,7 +670,7 @@ int LUKS2_keyslot_store(struct crypt_device *cd,
return -EINVAL;
return h->store(cd, keyslot, password, password_len,
crypt_volume_key_get_key(vk), crypt_volume_key_length(vk));
vk->key, vk->keylength);
}
int LUKS2_keyslot_wipe(struct crypt_device *cd,
@@ -863,7 +861,8 @@ int LUKS2_keyslots_validate(struct crypt_device *cd, json_object *hdr_jobj)
if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
return -EINVAL;
LUKS2_config_get_requirements(cd, &dummy, &reqs);
if (LUKS2_config_get_requirements(cd, &dummy, &reqs))
return -EINVAL;
json_object_object_foreach(jobj_keyslots, slot, val) {
keyslot = atoi(slot);

View File

@@ -2,8 +2,8 @@
/*
* LUKS - Linux Unified Key Setup v2, LUKS2 type keyslot handler
*
* Copyright (C) 2015-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2025 Milan Broz
* Copyright (C) 2015-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2024 Milan Broz
*/
#include <limits.h>
@@ -14,6 +14,7 @@
#define LUKS_SALTSIZE 32
#define LUKS_SLOT_ITERATIONS_MIN 1000
#define LUKS_STRIPES 4000
/* Serialize memory-hard keyslot access: optional workaround for parallel processing */
#define MIN_MEMORY_FOR_SERIALIZE_LOCK_KB 32*1024 /* 32MB */
@@ -24,7 +25,7 @@ static int luks2_encrypt_to_storage(char *src, size_t srcLength,
struct volume_key *vk, unsigned int sector,
struct crypt_device *cd)
{
#if !ENABLE_AF_ALG /* Support for old kernel without Crypto API */
#ifndef ENABLE_AF_ALG /* Support for old kernel without Crypto API */
return LUKS_encrypt_to_storage(src, srcLength, cipher, cipher_mode, vk, sector, cd);
#else
struct crypt_storage *s;
@@ -36,8 +37,7 @@ static int luks2_encrypt_to_storage(char *src, size_t srcLength,
return -EINVAL;
/* Encrypt buffer */
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode,
crypt_volume_key_get_key(vk), crypt_volume_key_length(vk), false);
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode, vk->key, vk->keylength, false);
if (r) {
log_err(cd, _("Cannot use %s-%s cipher for keyslot encryption."), cipher, cipher_mode);
return r;
@@ -75,7 +75,7 @@ static int luks2_decrypt_from_storage(char *dst, size_t dstLength,
unsigned int sector, struct crypt_device *cd)
{
struct device *device = crypt_metadata_device(cd);
#if !ENABLE_AF_ALG /* Support for old kernel without Crypto API */
#ifndef ENABLE_AF_ALG /* Support for old kernel without Crypto API */
int r = device_read_lock(cd, device);
if (r) {
log_err(cd, _("Failed to acquire read lock on device %s."), device_path(device));
@@ -92,9 +92,7 @@ static int luks2_decrypt_from_storage(char *dst, size_t dstLength,
if (MISALIGNED_512(dstLength))
return -EINVAL;
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode,
crypt_volume_key_get_key(vk),
crypt_volume_key_length(vk), false);
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode, vk->key, vk->keylength, false);
if (r) {
log_err(cd, _("Cannot use %s-%s cipher for keyslot encryption."), cipher, cipher_mode);
return r;
@@ -192,6 +190,7 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
const char *password, size_t passwordLen,
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 *AfKey = NULL;
const char *af_hash = NULL;
@@ -200,8 +199,6 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
uint64_t area_offset;
struct crypt_pbkdf_type pbkdf;
int r;
struct volume_key *derived_vk = NULL;
void *derived_key = NULL;
if (!json_object_object_get_ex(jobj_keyslot, "kdf", &jobj_kdf) ||
!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af) ||
@@ -239,7 +236,7 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
/*
* Allocate derived key storage.
*/
derived_key = crypt_safe_alloc(keyslot_key_len);
derived_key = crypt_alloc_volume_key(keyslot_key_len, NULL);
if (!derived_key) {
free(salt);
return -ENOMEM;
@@ -250,7 +247,7 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
log_dbg(cd, "Running keyslot key derivation.");
r = crypt_pbkdf(pbkdf.type, pbkdf.hash, password, passwordLen,
salt, LUKS_SALTSIZE,
derived_key, keyslot_key_len,
derived_key->key, derived_key->keylength,
pbkdf.iterations, pbkdf.max_memory_kb,
pbkdf.parallel_threads);
free(salt);
@@ -258,17 +255,16 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
if ((crypt_backend_flags() & CRYPT_BACKEND_PBKDF2_INT) &&
pbkdf.iterations > INT_MAX)
log_err(cd, _("PBKDF2 iteration value overflow."));
if (r == -ENOMEM)
log_err(cd, _("Not enough memory for keyslot key derivation."));
goto out;
crypt_free_volume_key(derived_key);
return r;
}
// FIXME: verity key_size to AFEKSize
AFEKSize = AF_split_sectors(volume_key_len, LUKS_STRIPES) * SECTOR_SIZE;
AfKey = crypt_safe_alloc(AFEKSize);
if (!AfKey) {
r = -ENOMEM;
goto out;
crypt_free_volume_key(derived_key);
return -ENOMEM;
}
r = crypt_hash_size(af_hash);
@@ -277,23 +273,15 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
else
r = AF_split(cd, volume_key, AfKey, volume_key_len, LUKS_STRIPES, af_hash);
if (r < 0)
goto out;
derived_vk = crypt_alloc_volume_key_by_safe_alloc(&derived_key);
if (!derived_vk) {
r = -ENOMEM;
goto out;
if (r == 0) {
log_dbg(cd, "Updating keyslot area [0x%04" PRIx64 "].", area_offset);
/* FIXME: sector_offset should be size_t, fix LUKS_encrypt... accordingly */
r = luks2_encrypt_to_storage(AfKey, AFEKSize, cipher, cipher_mode,
derived_key, (unsigned)(area_offset / SECTOR_SIZE), cd);
}
log_dbg(cd, "Updating keyslot area [0x%04" PRIx64 "].", area_offset);
/* FIXME: sector_offset should be size_t, fix LUKS_encrypt... accordingly */
r = luks2_encrypt_to_storage(AfKey, AFEKSize, cipher, cipher_mode,
derived_vk, (unsigned)(area_offset / SECTOR_SIZE), cd);
out:
crypt_safe_free(AfKey);
crypt_safe_free(derived_key);
crypt_free_volume_key(derived_vk);
crypt_free_volume_key(derived_key);
if (r < 0)
return r;
@@ -305,7 +293,8 @@ 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 crypt_pbkdf_type pbkdf;
struct volume_key *derived_key = NULL;
struct crypt_pbkdf_type pbkdf, *cd_pbkdf;
char *AfKey = NULL;
size_t AFEKSize;
const char *af_hash = NULL;
@@ -315,8 +304,6 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
size_t keyslot_key_len;
bool try_serialize_lock = false;
int r;
struct volume_key *derived_vk = NULL;
void *derived_key = NULL;
if (!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af) ||
!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
@@ -336,10 +323,6 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
if (r < 0)
return r;
/* Allow only empty passphrase with null cipher */
if (crypt_is_cipher_null(cipher) && passwordLen)
return -EPERM;
if (!json_object_object_get_ex(jobj_area, "key_size", &jobj2))
return -EINVAL;
keyslot_key_len = json_object_get_int(jobj2);
@@ -351,7 +334,7 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
/*
* Allocate derived key storage space.
*/
derived_key = crypt_safe_alloc(keyslot_key_len);
derived_key = crypt_alloc_volume_key(keyslot_key_len, NULL);
if (!derived_key) {
r = -ENOMEM;
goto out;
@@ -364,6 +347,16 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
goto out;
}
/*
* Print warning when keyslot requires more memory than available
* (if maximum memory was adjusted - no swap, not enough memory),
* but be silent if user set keyslot memory cost above default limit intentionally.
*/
cd_pbkdf = crypt_get_pbkdf(cd);
if (cd_pbkdf->max_memory_kb && pbkdf.max_memory_kb > cd_pbkdf->max_memory_kb &&
pbkdf.max_memory_kb <= DEFAULT_LUKS2_MEMORY_KB)
log_std(cd, _("Warning: keyslot operation could fail as it requires more than available memory.\n"));
/*
* If requested, serialize unlocking for memory-hard KDF. Usually NOOP.
*/
@@ -378,27 +371,20 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
log_dbg(cd, "Running keyslot key derivation.");
r = crypt_pbkdf(pbkdf.type, pbkdf.hash, password, passwordLen,
salt, LUKS_SALTSIZE,
derived_key, keyslot_key_len,
derived_key->key, derived_key->keylength,
pbkdf.iterations, pbkdf.max_memory_kb,
pbkdf.parallel_threads);
if (try_serialize_lock)
crypt_serialize_unlock(cd);
if (r < 0)
goto out;
derived_vk = crypt_alloc_volume_key_by_safe_alloc(&derived_key);
if (!derived_vk) {
r = -ENOMEM;
goto out;
if (r == 0) {
log_dbg(cd, "Reading keyslot area [0x%04" PRIx64 "].", area_offset);
/* FIXME: sector_offset should be size_t, fix LUKS_decrypt... accordingly */
r = luks2_decrypt_from_storage(AfKey, AFEKSize, cipher, cipher_mode,
derived_key, (unsigned)(area_offset / SECTOR_SIZE), cd);
}
log_dbg(cd, "Reading keyslot area [0x%04" PRIx64 "].", area_offset);
/* FIXME: sector_offset should be size_t, fix LUKS_decrypt... accordingly */
r = luks2_decrypt_from_storage(AfKey, AFEKSize, cipher, cipher_mode,
derived_vk, (unsigned)(area_offset / SECTOR_SIZE), cd);
if (r == 0) {
r = crypt_hash_size(af_hash);
if (r < 0)
@@ -408,9 +394,8 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
}
out:
free(salt);
crypt_free_volume_key(derived_vk);
crypt_free_volume_key(derived_key);
crypt_safe_free(AfKey);
crypt_safe_free(derived_key);
return r;
}

View File

@@ -2,8 +2,8 @@
/*
* LUKS - Linux Unified Key Setup v2, reencryption keyslot handler
*
* Copyright (C) 2016-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2025 Ondrej Kozina
* Copyright (C) 2016-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2024 Ondrej Kozina
*/
#include "luks2_internal.h"

View File

@@ -2,9 +2,9 @@
/*
* LUKS - Linux Unified Key Setup v2, LUKS1 conversion code
*
* Copyright (C) 2015-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2025 Ondrej Kozina
* Copyright (C) 2015-2025 Milan Broz
* Copyright (C) 2015-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2024 Ondrej Kozina
* Copyright (C) 2015-2024 Milan Broz
*/
#include "luks2_internal.h"
@@ -45,11 +45,11 @@ out:
return r;
}
static int json_luks1_keyslot(const struct luks_phdr *hdr_v1, int keyslot, json_object **keyslot_object)
static int json_luks1_keyslot(const struct luks_phdr *hdr_v1, int keyslot, struct json_object **keyslot_object)
{
char *base64_str, cipher[LUKS_CIPHERNAME_L+LUKS_CIPHERMODE_L];
size_t base64_len;
json_object *keyslot_obj, *field, *jobj_kdf, *jobj_af, *jobj_area;
struct json_object *keyslot_obj, *field, *jobj_kdf, *jobj_af, *jobj_area;
uint64_t offset, area_size, length;
int r;
@@ -136,10 +136,10 @@ err:
return r;
}
static int json_luks1_keyslots(const struct luks_phdr *hdr_v1, json_object **keyslots_object)
static int json_luks1_keyslots(const struct luks_phdr *hdr_v1, struct json_object **keyslots_object)
{
int keyslot, r;
json_object *keyslot_obj, *field;
struct json_object *keyslot_obj, *field;
keyslot_obj = json_object_new_object();
if (!keyslot_obj)
@@ -165,11 +165,11 @@ static int json_luks1_keyslots(const struct luks_phdr *hdr_v1, json_object **key
return 0;
}
static int json_luks1_segment(const struct luks_phdr *hdr_v1, json_object **segment_object)
static int json_luks1_segment(const struct luks_phdr *hdr_v1, struct json_object **segment_object)
{
const char *c;
char cipher[LUKS_CIPHERNAME_L+LUKS_CIPHERMODE_L];
json_object *segment_obj, *field;
struct json_object *segment_obj, *field;
uint64_t number;
segment_obj = json_object_new_object();
@@ -239,10 +239,10 @@ static int json_luks1_segment(const struct luks_phdr *hdr_v1, json_object **segm
return 0;
}
static int json_luks1_segments(const struct luks_phdr *hdr_v1, json_object **segments_object)
static int json_luks1_segments(const struct luks_phdr *hdr_v1, struct json_object **segments_object)
{
int r;
json_object *segments_obj, *field;
struct json_object *segments_obj, *field;
segments_obj = json_object_new_object();
if (!segments_obj)
@@ -264,12 +264,12 @@ static int json_luks1_segments(const struct luks_phdr *hdr_v1, json_object **seg
return 0;
}
static int json_luks1_digest(const struct luks_phdr *hdr_v1, json_object **digest_object)
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;
size_t base64_len;
json_object *digest_obj, *array, *field;
struct json_object *digest_obj, *array, *field;
digest_obj = json_object_new_object();
if (!digest_obj)
@@ -380,10 +380,10 @@ static int json_luks1_digest(const struct luks_phdr *hdr_v1, json_object **diges
return 0;
}
static int json_luks1_digests(const struct luks_phdr *hdr_v1, json_object **digests_object)
static int json_luks1_digests(const struct luks_phdr *hdr_v1, struct json_object **digests_object)
{
int r;
json_object *digests_obj, *field;
struct json_object *digests_obj, *field;
digests_obj = json_object_new_object();
if (!digests_obj)
@@ -400,10 +400,10 @@ static int json_luks1_digests(const struct luks_phdr *hdr_v1, json_object **dige
return 0;
}
static int json_luks1_object(struct luks_phdr *hdr_v1, json_object **luks1_object, uint64_t keyslots_size)
static int json_luks1_object(struct luks_phdr *hdr_v1, struct json_object **luks1_object, uint64_t keyslots_size)
{
int r;
json_object *luks1_obj, *field;
struct json_object *luks1_obj, *field;
uint64_t json_size;
luks1_obj = json_object_new_object();
@@ -570,7 +570,6 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
json_object *jobj = NULL;
size_t buf_size, buf_offset, luks1_size, luks1_shift = 2 * LUKS2_HDR_16K_LEN - LUKS_ALIGN_KEYSLOTS;
uint64_t required_size, max_size = crypt_get_data_offset(cd) * SECTOR_SIZE;
char cipher_spec[MAX_CAPI_LEN];
/* for detached headers max size == device size */
if (!max_size && (r = device_size(crypt_metadata_device(cd), &max_size)))
@@ -592,15 +591,6 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
return -EINVAL;
}
r = snprintf(cipher_spec, sizeof(cipher_spec), "%s-%s", hdr1->cipherName, hdr1->cipherMode);
if (r < 0 || (size_t)r >= sizeof(cipher_spec))
return -EINVAL;
if (LUKS2_keyslot_cipher_incompatible(cd, cipher_spec)) {
log_err(cd, _("Unable to use cipher specification %s-%s for LUKS2 keyslot."),
hdr1->cipherName, hdr1->cipherMode);
return -EINVAL;
}
if (luksmeta_header_present(cd, luks1_size))
return -EINVAL;
@@ -697,54 +687,30 @@ static int keyslot_LUKS1_compatible(struct crypt_device *cd, struct luks2_hdr *h
if (!jobj_keyslot)
return 1;
/* Keyslot type */
if (!json_object_object_get_ex(jobj_keyslot, "type", &jobj))
if (!json_object_object_get_ex(jobj_keyslot, "type", &jobj) ||
strcmp(json_object_get_string(jobj), "luks2"))
return 0;
if (strcmp(json_object_get_string(jobj), "luks2")) {
log_dbg(cd, "Keyslot %d type %s is not compatible.",
keyslot, json_object_get_string(jobj));
return 0;
}
/* Keyslot uses PBKDF2, this implies memory and parallel is not used. */
/* Using PBKDF2, this implies memory and parallel is not used. */
jobj = NULL;
if (!json_object_object_get_ex(jobj_keyslot, "kdf", &jobj_kdf) ||
!json_object_object_get_ex(jobj_kdf, "type", &jobj))
!json_object_object_get_ex(jobj_kdf, "type", &jobj) ||
strcmp(json_object_get_string(jobj), CRYPT_KDF_PBKDF2) ||
!json_object_object_get_ex(jobj_kdf, "hash", &jobj) ||
strcmp(json_object_get_string(jobj), hash))
return 0;
if (strcmp(json_object_get_string(jobj), CRYPT_KDF_PBKDF2)) {
log_dbg(cd, "Keyslot %d does not use PBKDF2.", keyslot);
return 0;
}
/* Keyslot KDF hash is the same as the digest hash. */
jobj = NULL;
if (!json_object_object_get_ex(jobj_kdf, "hash", &jobj))
return 0;
if (strcmp(json_object_get_string(jobj), hash)) {
log_dbg(cd, "Keyslot %d PBKDF uses different hash %s than digest hash %s.",
keyslot, json_object_get_string(jobj), hash);
return 0;
}
/* Keyslot AF use compatible striptes. */
jobj = NULL;
if (!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af) ||
!json_object_object_get_ex(jobj_af, "stripes", &jobj))
!json_object_object_get_ex(jobj_af, "stripes", &jobj) ||
json_object_get_int(jobj) != LUKS_STRIPES)
return 0;
if (json_object_get_int(jobj) != LUKS_STRIPES) {
log_dbg(cd, "Keyslot %d AF uses incompatible stripes count.", keyslot);
return 0;
}
/* Keyslot AF hash is the same as the digest hash. */
jobj = NULL;
if (!json_object_object_get_ex(jobj_af, "hash", &jobj))
if (!json_object_object_get_ex(jobj_af, "hash", &jobj) ||
(crypt_hash_size(json_object_get_string(jobj)) < 0) ||
strcmp(json_object_get_string(jobj), hash))
return 0;
if (strcmp(json_object_get_string(jobj), hash)) {
log_dbg(cd, "Keyslot %d AF uses different hash %s than digest hash %s.",
keyslot, json_object_get_string(jobj), hash);
return 0;
}
ks_cipher = LUKS2_get_keyslot_cipher(hdr, keyslot, &ks_key_size);
data_cipher = LUKS2_get_cipher(hdr, CRYPT_DEFAULT_SEGMENT);
@@ -777,7 +743,6 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
int i, r, last_active = 0;
uint64_t offset, area_length;
char *buf, luksMagic[] = LUKS_MAGIC;
crypt_keyslot_info ki;
jobj_digest = LUKS2_get_digest_jobj(hdr2, 0);
if (!jobj_digest)
@@ -802,8 +767,6 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
if (!json_object_object_get_ex(jobj_digest, "hash", &jobj2))
return -EINVAL;
hash = json_object_get_string(jobj2);
if (crypt_hash_size(hash) < 0)
return -EINVAL;
r = crypt_parse_name_and_mode(LUKS2_get_cipher(hdr2, CRYPT_DEFAULT_SEGMENT), cipher, NULL, cipher_mode);
if (r < 0)
@@ -828,28 +791,19 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
}
r = LUKS2_get_volume_key_size(hdr2, 0);
if (r < 0) {
log_err(cd, _("Cannot convert to LUKS1 format - there are no active keyslots."), r);
if (r < 0)
return -EINVAL;
}
key_size = r;
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) {
ki = LUKS2_keyslot_info(hdr2, i);
if (ki == CRYPT_SLOT_INACTIVE)
if (LUKS2_keyslot_info(hdr2, i) == CRYPT_SLOT_INACTIVE)
continue;
if (ki == CRYPT_SLOT_INVALID) {
if (LUKS2_keyslot_info(hdr2, i) == CRYPT_SLOT_INVALID) {
log_err(cd, _("Cannot convert to LUKS1 format - keyslot %u is in invalid state."), i);
return -EINVAL;
}
if (ki == CRYPT_SLOT_UNBOUND) {
log_err(cd, _("Cannot convert to LUKS1 format - keyslot %u is unbound."), i);
return -EINVAL;
}
if (i >= LUKS_NUMKEYS) {
log_err(cd, _("Cannot convert to LUKS1 format - slot %u (over maximum slots) is still active."), i);
return -EINVAL;

View File

@@ -2,13 +2,12 @@
/*
* LUKS - Linux Unified Key Setup v2, reencryption helpers
*
* Copyright (C) 2015-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2025 Ondrej Kozina
* Copyright (C) 2015-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2024 Ondrej Kozina
*/
#include "luks2_internal.h"
#include "utils_device_locking.h"
#include "keyslot_context.h"
struct luks2_reencrypt {
/* reencryption window attributes */
@@ -34,7 +33,7 @@ struct luks2_reencrypt {
/* already running reencryption */
json_object *jobj_segs_hot;
json_object *jobj_segs_post;
struct json_object *jobj_segs_post;
/* backup segments */
json_object *jobj_segment_new;
@@ -54,8 +53,6 @@ struct luks2_reencrypt {
uint32_t wflags1;
uint32_t wflags2;
struct device *hotzone_device;
struct crypt_lock_handle *reenc_lock;
};
#if USE_LUKS2_REENCRYPTION
@@ -173,16 +170,6 @@ int LUKS2_reencrypt_digest_old(struct luks2_hdr *hdr)
return reencrypt_digest(hdr, 0);
}
int LUKS2_reencrypt_segment_new(struct luks2_hdr *hdr)
{
return LUKS2_get_segment_id_by_flag(hdr, "backup-final");
}
int LUKS2_reencrypt_segment_old(struct luks2_hdr *hdr)
{
return LUKS2_get_segment_id_by_flag(hdr, "backup-previous");
}
unsigned LUKS2_reencrypt_vks_count(struct luks2_hdr *hdr)
{
int digest_old, digest_new;
@@ -312,7 +299,7 @@ static json_object *reencrypt_make_hot_segments_encrypt_shift(struct luks2_hdr *
rh->offset >> SECTOR_SHIFT,
&rh->length,
reencrypt_segment_cipher_new(hdr),
NULL, 0, /* integrity */
NULL, /* integrity */
reencrypt_get_sector_size_new(hdr),
1);
@@ -368,7 +355,7 @@ static json_object *reencrypt_make_segment_new(struct crypt_device *cd,
crypt_get_iv_offset(cd) + (iv_offset >> SECTOR_SHIFT),
segment_length,
reencrypt_segment_cipher_new(hdr),
NULL, 0, /* integrity */
NULL, /* integrity */
reencrypt_get_sector_size_new(hdr), 0);
case CRYPT_REENCRYPT_DECRYPT:
return json_segment_create_linear(data_offset + segment_offset, segment_length, 0);
@@ -480,7 +467,7 @@ static json_object *reencrypt_make_segment_reencrypt(struct crypt_device *cd,
crypt_get_iv_offset(cd) + (iv_offset >> SECTOR_SHIFT),
segment_length,
reencrypt_segment_cipher_new(hdr),
NULL, 0, /* integrity */
NULL, /* integrity */
reencrypt_get_sector_size_new(hdr), 1);
case CRYPT_REENCRYPT_DECRYPT:
return json_segment_create_linear(data_offset + segment_offset, segment_length, 1);
@@ -505,7 +492,7 @@ static json_object *reencrypt_make_segment_old(struct crypt_device *cd,
crypt_get_iv_offset(cd) + (segment_offset >> SECTOR_SHIFT),
segment_length,
reencrypt_segment_cipher_old(hdr),
NULL, 0, /* integrity */
NULL, /* integrity */
reencrypt_get_sector_size_old(hdr),
0);
break;
@@ -884,13 +871,11 @@ void LUKS2_reencrypt_free(struct crypt_device *cd, struct luks2_reencrypt *rh)
rh->cw1 = NULL;
crypt_storage_wrapper_destroy(rh->cw2);
rh->cw2 = NULL;
device_free(cd, rh->hotzone_device);
rh->hotzone_device = NULL;
free(rh->device_name);
free(rh->overlay_name);
free(rh->hotzone_name);
crypt_drop_uploaded_keyring_key(cd, rh->vks);
crypt_drop_keyring_key(cd, rh->vks);
crypt_free_volume_key(rh->vks);
device_release_excl(cd, crypt_data_device(cd));
crypt_unlock_internal(cd, rh->reenc_lock);
@@ -1486,7 +1471,8 @@ static int reencrypt_update_flag(struct crypt_device *cd, uint8_t version,
return LUKS2_config_set_requirement_version(cd, hdr, CRYPT_REQUIREMENT_ONLINE_REENCRYPT, version, commit);
}
LUKS2_config_get_requirements(cd, hdr, &reqs);
if (LUKS2_config_get_requirements(cd, hdr, &reqs))
return -EINVAL;
reqs &= ~CRYPT_REQUIREMENT_ONLINE_REENCRYPT;
@@ -1934,13 +1920,14 @@ static int reencrypt_assign_segments(struct crypt_device *cd,
}
static int reencrypt_set_encrypt_segments(struct crypt_device *cd, struct luks2_hdr *hdr,
uint64_t dev_size, uint64_t data_size, uint64_t data_shift, bool move_first_segment,
uint64_t dev_size, uint64_t data_shift, bool move_first_segment,
crypt_reencrypt_direction_info di)
{
int r;
uint64_t first_segment_offset, first_segment_length,
second_segment_offset, second_segment_length,
data_offset = LUKS2_get_data_offset(hdr) << SECTOR_SHIFT;
data_offset = LUKS2_get_data_offset(hdr) << SECTOR_SHIFT,
data_size = dev_size - data_shift;
json_object *jobj_segment_first = NULL, *jobj_segment_second = NULL, *jobj_segments;
if (dev_size < data_shift)
@@ -2007,17 +1994,13 @@ static int reencrypt_set_decrypt_shift_segments(struct crypt_device *cd,
uint64_t moved_segment_length,
crypt_reencrypt_direction_info di)
{
int digest, r;
int r;
uint64_t data_offset = LUKS2_get_data_offset(hdr) << SECTOR_SHIFT;
json_object *jobj_segment_first = NULL, *jobj_segment_second = NULL, *jobj_segments;
if (di == CRYPT_REENCRYPT_BACKWARD)
return -ENOTSUP;
digest = LUKS2_digest_by_segment(hdr, CRYPT_DEFAULT_SEGMENT);
if (digest < 0)
return -EINVAL;
/*
* future data_device layout:
* [encrypted first segment (max data shift size)][gap (data shift size)][second encrypted data segment]
@@ -2029,7 +2012,7 @@ static int reencrypt_set_decrypt_shift_segments(struct crypt_device *cd,
r = -EINVAL;
jobj_segment_first = json_segment_create_crypt(0, crypt_get_iv_offset(cd),
&moved_segment_length, crypt_get_cipher_spec(cd),
NULL, 0, crypt_get_sector_size(cd), 0);
NULL, crypt_get_sector_size(cd), 0);
if (!jobj_segment_first) {
log_dbg(cd, "Failed generate 1st segment.");
@@ -2045,7 +2028,7 @@ static int reencrypt_set_decrypt_shift_segments(struct crypt_device *cd,
crypt_get_iv_offset(cd) + (moved_segment_length >> SECTOR_SHIFT),
NULL,
crypt_get_cipher_spec(cd),
NULL, 0, /* integrity */
NULL, /* integrity */
crypt_get_sector_size(cd), 0);
if (!jobj_segment_second) {
r = -EINVAL;
@@ -2059,7 +2042,7 @@ static int reencrypt_set_decrypt_shift_segments(struct crypt_device *cd,
}
if (!(r = LUKS2_segments_set(cd, hdr, jobj_segments, 0)))
return LUKS2_digest_segment_assign(cd, hdr, CRYPT_ANY_SEGMENT, digest, 1, 0);
return LUKS2_digest_segment_assign(cd, hdr, CRYPT_ANY_SEGMENT, 0, 1, 0);
err:
json_object_put(jobj_segment_first);
json_object_put(jobj_segment_second);
@@ -2116,7 +2099,8 @@ static int reencrypt_make_targets(struct crypt_device *cd,
json_segment_get_cipher(jobj),
json_segment_get_iv_offset(jobj),
segment_offset,
"none", 0, 0,
"none",
0,
json_segment_get_sector_size(jobj));
if (r) {
log_err(cd, _("Failed to set dm-crypt segment."));
@@ -2146,22 +2130,34 @@ static int reencrypt_make_targets(struct crypt_device *cd,
* 2) can't we derive hotzone device name from crypt context? (unlocked name, device uuid, etc?)
*/
static int reencrypt_load_overlay_device(struct crypt_device *cd, struct luks2_hdr *hdr,
const char *overlay, struct device *hotzone_device, struct volume_key *vks, uint64_t size,
const char *overlay, const char *hotzone, struct volume_key *vks, uint64_t size,
uint32_t flags)
{
char hz_path[PATH_MAX];
int r;
struct device *hz_dev = NULL;
struct crypt_dm_active_device dmd = {
.flags = flags,
};
log_dbg(cd, "Loading new table for overlay device %s.", overlay);
r = snprintf(hz_path, PATH_MAX, "%s/%s", dm_get_dir(), hotzone);
if (r < 0 || r >= PATH_MAX) {
r = -EINVAL;
goto out;
}
r = device_alloc(cd, &hz_dev, hz_path);
if (r)
goto out;
r = dm_targets_allocate(&dmd.segment, LUKS2_segments_count(hdr));
if (r)
goto out;
r = reencrypt_make_targets(cd, hdr, hotzone_device, vks, &dmd.segment, size);
r = reencrypt_make_targets(cd, hdr, hz_dev, vks, &dmd.segment, size);
if (r < 0)
goto out;
@@ -2170,6 +2166,7 @@ static int reencrypt_load_overlay_device(struct crypt_device *cd, struct luks2_h
/* what else on error here ? */
out:
dm_targets_free(cd, &dmd);
device_free(cd, hz_dev);
return r;
}
@@ -2178,7 +2175,7 @@ static int reencrypt_replace_device(struct crypt_device *cd, const char *target,
{
int r, exists = 1;
struct crypt_dm_active_device dmd_source, dmd_target = {};
uint64_t dmflags = DM_SUSPEND_SKIP_LOCKFS | DM_SUSPEND_NOFLUSH;
uint32_t dmflags = DM_SUSPEND_SKIP_LOCKFS | DM_SUSPEND_NOFLUSH;
log_dbg(cd, "Replacing table in device %s with table from device %s.", target, source);
@@ -2296,13 +2293,9 @@ out:
}
static int reencrypt_init_device_stack(struct crypt_device *cd,
struct luks2_reencrypt *rh)
const struct luks2_reencrypt *rh)
{
int r;
char hz_path[PATH_MAX];
assert(rh);
assert(!rh->hotzone_device);
/* Activate hotzone device 1:1 linear mapping to data_device */
r = reencrypt_activate_hotzone_device(cd, rh->hotzone_name, rh->device_size, CRYPT_ACTIVATE_PRIVATE);
@@ -2311,18 +2304,6 @@ static int reencrypt_init_device_stack(struct crypt_device *cd,
return r;
}
r = snprintf(hz_path, PATH_MAX, "%s/%s", dm_get_dir(), rh->hotzone_name);
if (r < 0 || r >= PATH_MAX) {
r = -EINVAL;
goto err;
}
r = device_alloc(cd, &rh->hotzone_device, hz_path);
if (r) {
log_err(cd, _("Failed to allocate hotzone device %s."), rh->hotzone_name);
goto err;
}
/*
* Activate overlay device with exactly same table as original 'name' mapping.
* Note that within this step the 'name' device may already include a table
@@ -2402,12 +2383,11 @@ static int reencrypt_refresh_overlay_devices(struct crypt_device *cd,
struct luks2_hdr *hdr,
const char *overlay,
const char *hotzone,
struct device *hotzone_device,
struct volume_key *vks,
uint64_t device_size,
uint32_t flags)
{
int r = reencrypt_load_overlay_device(cd, hdr, overlay, hotzone_device, vks, device_size, flags);
int r = reencrypt_load_overlay_device(cd, hdr, overlay, hotzone, vks, device_size, flags);
if (r) {
log_err(cd, _("Failed to reload device %s."), overlay);
return REENC_ERR;
@@ -2475,20 +2455,23 @@ out:
static int reencrypt_make_backup_segments(struct crypt_device *cd,
struct luks2_hdr *hdr,
int digest_new,
int keyslot_new,
const char *cipher,
uint64_t data_offset,
const struct crypt_params_reencrypt *params)
{
const char *type;
int r, segment, moved_segment = -1, digest_old = -1;
int r, segment, moved_segment = -1, digest_old = -1, digest_new = -1;
json_object *jobj_tmp, *jobj_segment_new = NULL, *jobj_segment_old = NULL, *jobj_segment_bcp = NULL;
uint32_t sector_size = params->luks2 ? params->luks2->sector_size : SECTOR_SIZE;
uint64_t segment_offset, tmp, data_shift = params->data_shift << SECTOR_SHIFT,
device_size = params->device_size << SECTOR_SHIFT;
if (params->mode != CRYPT_REENCRYPT_DECRYPT && digest_new < 0)
return -EINVAL;
if (params->mode != CRYPT_REENCRYPT_DECRYPT) {
digest_new = LUKS2_digest_by_keyslot(hdr, keyslot_new);
if (digest_new < 0)
return -EINVAL;
}
if (params->mode != CRYPT_REENCRYPT_ENCRYPT) {
digest_old = LUKS2_digest_by_segment(hdr, CRYPT_DEFAULT_SEGMENT);
@@ -2535,7 +2518,7 @@ static int reencrypt_make_backup_segments(struct crypt_device *cd,
json_segment_get_iv_offset(jobj_tmp),
device_size ? &device_size : NULL,
json_segment_get_cipher(jobj_tmp),
NULL, 0, /* integrity */
NULL, /* integrity */
json_segment_get_sector_size(jobj_tmp),
0);
} else {
@@ -2582,7 +2565,7 @@ static int reencrypt_make_backup_segments(struct crypt_device *cd,
}
jobj_segment_new = json_segment_create_crypt(segment_offset,
crypt_get_iv_offset(cd),
NULL, cipher, NULL, 0, sector_size, 0);
NULL, cipher, NULL, sector_size, 0);
} else if (params->mode == CRYPT_REENCRYPT_DECRYPT) {
segment_offset = data_offset;
if (modify_offset(&segment_offset, data_shift, params->direction)) {
@@ -2685,7 +2668,7 @@ static int reencrypt_upload_keys(struct crypt_device *cd,
if (digest_old >= 0 && !crypt_is_cipher_null(reencrypt_segment_cipher_old(hdr)) &&
(r = reencrypt_upload_single_key(cd, digest_old, vks))) {
crypt_drop_uploaded_keyring_key(cd, vks);
crypt_drop_keyring_key(cd, vks);
return r;
}
@@ -2796,7 +2779,8 @@ static int reencrypt_decrypt_with_datashift_init(struct crypt_device *cd,
uint32_t sector_size,
uint64_t data_size,
uint64_t data_offset,
struct crypt_keyslot_context *kc_old,
const char *passphrase,
size_t passphrase_size,
int keyslot_old,
const struct crypt_params_reencrypt *params,
struct volume_key **vks)
@@ -2855,7 +2839,7 @@ static int reencrypt_decrypt_with_datashift_init(struct crypt_device *cd,
if (r)
goto out;
r = reencrypt_make_backup_segments(cd, hdr, CRYPT_ANY_DIGEST, NULL, data_offset, params);
r = reencrypt_make_backup_segments(cd, hdr, CRYPT_ANY_SLOT, NULL, data_offset, params);
if (r) {
log_dbg(cd, "Failed to create reencryption backup device segments.");
goto out;
@@ -2891,8 +2875,8 @@ static int reencrypt_decrypt_with_datashift_init(struct crypt_device *cd,
goto out;
}
r = LUKS2_keyslot_context_open_all_segments(cd, keyslot_old, CRYPT_ANY_SLOT,
kc_old, NULL, vks);
r = LUKS2_keyslot_open_all_segments(cd, keyslot_old, CRYPT_ANY_SLOT,
passphrase, passphrase_size, vks);
if (r < 0)
goto out;
@@ -2916,8 +2900,6 @@ static int reencrypt_decrypt_with_datashift_init(struct crypt_device *cd,
jobj_segments_old = reencrypt_segments_old(hdr);
if (!jobj_segments_old) {
dm_targets_free(cd, &dmd_target);
free(CONST_CAST(void*)dmd_target.uuid);
r = -EINVAL;
goto out;
}
@@ -2989,8 +2971,8 @@ out:
static int reencrypt_init(struct crypt_device *cd,
const char *name,
struct luks2_hdr *hdr,
struct crypt_keyslot_context *kc_old,
struct crypt_keyslot_context *kc_new,
const char *passphrase,
size_t passphrase_size,
int keyslot_old,
int keyslot_new,
const char *cipher,
@@ -3001,9 +2983,8 @@ static int reencrypt_init(struct crypt_device *cd,
bool move_first_segment;
char _cipher[128];
uint32_t check_sector_size, new_sector_size, old_sector_size;
int digest_new, r, reencrypt_keyslot, devfd = -1;
uint64_t data_offset_bytes, data_size_bytes, data_shift_bytes, device_size_bytes;
struct volume_key *vk;
int r, reencrypt_keyslot, devfd = -1;
uint64_t data_offset, data_size = 0;
struct crypt_dm_active_device dmd_target, dmd_source = {
.uuid = crypt_get_uuid(cd),
.flags = CRYPT_ACTIVATE_SHARED /* turn off exclusive open checks */
@@ -3016,8 +2997,7 @@ static int reencrypt_init(struct crypt_device *cd,
return -EINVAL;
if (params->mode != CRYPT_REENCRYPT_DECRYPT &&
(!params->luks2 || !(cipher && cipher_mode) ||
(keyslot_new < 0 && !(params->flags & CRYPT_REENCRYPT_CREATE_NEW_DIGEST))))
(!params->luks2 || !(cipher && cipher_mode) || keyslot_new < 0))
return -EINVAL;
log_dbg(cd, "Initializing reencryption (mode: %s) in LUKS2 metadata.",
@@ -3044,54 +3024,31 @@ static int reencrypt_init(struct crypt_device *cd,
if (r < 0 || (size_t)r >= sizeof(_cipher))
return -EINVAL;
data_offset_bytes = LUKS2_get_data_offset(hdr) << SECTOR_SHIFT;
data_offset = LUKS2_get_data_offset(hdr) << SECTOR_SHIFT;
r = device_check_access(cd, crypt_data_device(cd), DEV_OK);
if (r)
return r;
r = device_check_size(cd, crypt_data_device(cd), data_offset_bytes, 1);
r = device_check_size(cd, crypt_data_device(cd), data_offset, 1);
if (r)
return r;
r = device_size(crypt_data_device(cd), &device_size_bytes);
r = device_size(crypt_data_device(cd), &data_size);
if (r)
return r;
if (move_first_segment && params->mode == CRYPT_REENCRYPT_ENCRYPT &&
params->data_shift < LUKS2_get_data_offset(hdr)) {
log_err(cd, _("Data shift (%" PRIu64 " sectors) is less than future data offset (%" PRIu64 " sectors)."),
params->data_shift, LUKS2_get_data_offset(hdr));
return -EINVAL;
}
data_size -= data_offset;
device_size_bytes -= data_offset_bytes;
data_shift_bytes = params->data_shift << SECTOR_SHIFT;
data_size_bytes = params->device_size << SECTOR_SHIFT;
if (device_size_bytes < data_shift_bytes && params->direction == CRYPT_REENCRYPT_BACKWARD) {
log_err(cd, _("Device %s is too small."), device_path(crypt_data_device(cd)));
return -EINVAL;
}
if (data_size_bytes > device_size_bytes) {
log_err(cd, _("Reduced data size is larger than real device size."));
return -EINVAL;
}
if (data_size_bytes && params->mode == CRYPT_REENCRYPT_ENCRYPT &&
move_first_segment && data_shift_bytes) {
if (data_size_bytes > device_size_bytes - data_shift_bytes) {
if (params->device_size) {
if ((params->device_size << SECTOR_SHIFT) > data_size) {
log_err(cd, _("Reduced data size is larger than real device size."));
return -EINVAL;
}
} else if (!data_size_bytes && params->mode == CRYPT_REENCRYPT_ENCRYPT &&
move_first_segment && data_shift_bytes)
data_size_bytes = device_size_bytes - data_shift_bytes;
else if (!data_size_bytes)
data_size_bytes = device_size_bytes;
} else
data_size = params->device_size << SECTOR_SHIFT;
}
if (MISALIGNED(data_size_bytes, check_sector_size)) {
if (MISALIGNED(data_size, check_sector_size)) {
log_err(cd, _("Data device is not aligned to encryption sector size (%" PRIu32 " bytes)."), check_sector_size);
return -EINVAL;
}
@@ -3102,23 +3059,34 @@ static int reencrypt_init(struct crypt_device *cd,
return -EINVAL;
}
if (params->mode == CRYPT_REENCRYPT_DECRYPT && data_shift_bytes && move_first_segment)
if (params->mode == CRYPT_REENCRYPT_DECRYPT && (params->data_shift > 0) && move_first_segment)
return reencrypt_decrypt_with_datashift_init(cd, name, hdr,
reencrypt_keyslot,
check_sector_size,
data_size_bytes,
data_offset_bytes,
kc_old,
data_size,
data_offset,
passphrase,
passphrase_size,
keyslot_old,
params,
vks);
/*
* We must perform data move with exclusive open data device
* to exclude another cryptsetup process to colide with
* encryption initialization (or mount)
*/
if (move_first_segment) {
if (data_size < (params->data_shift << SECTOR_SHIFT)) {
log_err(cd, _("Device %s is too small."), device_path(crypt_data_device(cd)));
return -EINVAL;
}
if (params->data_shift < LUKS2_get_data_offset(hdr)) {
log_err(cd, _("Data shift (%" PRIu64 " sectors) is less than future data offset (%" PRIu64 " sectors)."),
params->data_shift, LUKS2_get_data_offset(hdr));
return -EINVAL;
}
devfd = device_open_excl(cd, crypt_data_device(cd), O_RDWR);
if (devfd < 0) {
if (devfd == -EBUSY)
@@ -3130,33 +3098,15 @@ static int reencrypt_init(struct crypt_device *cd,
if (params->mode == CRYPT_REENCRYPT_ENCRYPT) {
/* in-memory only */
r = reencrypt_set_encrypt_segments(cd, hdr, device_size_bytes, data_size_bytes,
data_shift_bytes,
r = reencrypt_set_encrypt_segments(cd, hdr, data_size,
params->data_shift << SECTOR_SHIFT,
move_first_segment,
params->direction);
if (r)
goto out;
}
if (params->flags & CRYPT_REENCRYPT_CREATE_NEW_DIGEST) {
assert(kc_new->get_luks2_key);
r = kc_new->get_luks2_key(cd, kc_new, CRYPT_ANY_SLOT, CRYPT_ANY_SEGMENT, &vk);
if (r < 0)
goto out;
/* do not create new digest in case it matches the current one */
r = LUKS2_digest_verify_by_segment(cd, hdr, CRYPT_DEFAULT_SEGMENT, vk);
if (r == -EPERM || r == -ENOENT)
r = LUKS2_digest_create(cd, "pbkdf2", hdr, vk);
crypt_free_volume_key(vk);
if (r < 0)
goto out;
digest_new = r;
} else
digest_new = LUKS2_digest_by_keyslot(hdr, keyslot_new);
r = reencrypt_make_backup_segments(cd, hdr, digest_new, _cipher, data_offset_bytes, params);
r = reencrypt_make_backup_segments(cd, hdr, keyslot_new, _cipher, data_offset, params);
if (r) {
log_dbg(cd, "Failed to create reencryption backup device segments.");
goto out;
@@ -3171,7 +3121,7 @@ static int reencrypt_init(struct crypt_device *cd,
if (r < 0)
goto out;
r = LUKS2_keyslot_context_open_all_segments(cd, keyslot_old, keyslot_new, kc_old, kc_new, vks);
r = LUKS2_keyslot_open_all_segments(cd, keyslot_old, keyslot_new, passphrase, passphrase_size, vks);
if (r < 0)
goto out;
@@ -3205,12 +3155,12 @@ static int reencrypt_init(struct crypt_device *cd,
goto out;
}
if (move_first_segment && reencrypt_move_data(cd, devfd, data_shift_bytes, params->mode)) {
if (move_first_segment && reencrypt_move_data(cd, devfd, params->data_shift << SECTOR_SHIFT, params->mode)) {
r = -EIO;
goto out;
}
/* This must be first and only write in LUKS2 metadata during reencrypt_init */
/* This must be first and only write in LUKS2 metadata during _reencrypt_init */
r = reencrypt_update_flag(cd, LUKS2_REENCRYPT_REQ_VERSION, true, true);
if (r) {
log_dbg(cd, "Failed to set online-reencryption requirement.");
@@ -3347,7 +3297,7 @@ static int reencrypt_load(struct crypt_device *cd, struct luks2_hdr *hdr,
if (r < 0 || !tmp) {
log_err(cd, _("Failed to load LUKS2 reencryption context."));
return r < 0 ? r : -EINVAL;
return r;
}
*rh = tmp;
@@ -3406,7 +3356,7 @@ int LUKS2_reencrypt_lock_by_dm_uuid(struct crypt_device *cd, const char *dm_uuid
dm_uuid + 6, dm_uuid + 14, dm_uuid + 18, dm_uuid + 22, dm_uuid + 26);
if (r < 0 || (size_t)r != (sizeof(hdr_uuid) - 1))
return -EINVAL;
} else if (dm_uuid_cmp(dm_uuid, uuid))
} else if (crypt_uuid_cmp(dm_uuid, uuid))
return -EINVAL;
return reencrypt_lock_internal(cd, uuid, reencrypt_lock);
@@ -3435,8 +3385,10 @@ static int reencrypt_lock_and_verify(struct crypt_device *cd, struct luks2_hdr *
struct crypt_lock_handle *h;
ri = LUKS2_reencrypt_status(hdr);
if (ri == CRYPT_REENCRYPT_INVALID)
if (ri == CRYPT_REENCRYPT_INVALID) {
log_err(cd, _("Failed to get reencryption state."));
return -EINVAL;
}
if (ri < CRYPT_REENCRYPT_CLEAN) {
log_err(cd, _("Device is not in reencryption."));
return -EINVAL;
@@ -3469,10 +3421,10 @@ static int reencrypt_lock_and_verify(struct crypt_device *cd, struct luks2_hdr *
return -EINVAL;
}
static int reencrypt_load_by_keyslot_context(struct crypt_device *cd,
static int reencrypt_load_by_passphrase(struct crypt_device *cd,
const char *name,
struct crypt_keyslot_context *kc_old,
struct crypt_keyslot_context *kc_new,
const char *passphrase,
size_t passphrase_size,
int keyslot_old,
int keyslot_new,
struct volume_key **vks,
@@ -3552,8 +3504,7 @@ static int reencrypt_load_by_keyslot_context(struct crypt_device *cd,
r = reencrypt_verify_keys(cd, LUKS2_reencrypt_digest_old(hdr), LUKS2_reencrypt_digest_new(hdr), *vks);
if (r == -ENOENT) {
log_dbg(cd, "Keys are not ready. Unlocking all volume keys.");
r = LUKS2_keyslot_context_open_all_segments(cd, keyslot_old, keyslot_new,
kc_old, kc_new, vks);
r = LUKS2_keyslot_open_all_segments(cd, keyslot_old, keyslot_new, passphrase, passphrase_size, vks);
}
if (r < 0)
@@ -3579,7 +3530,7 @@ static int reencrypt_load_by_keyslot_context(struct crypt_device *cd,
* above. The code checks if new VK is eligible for keyring.
*/
vk = crypt_volume_key_by_id(*vks, LUKS2_reencrypt_digest_new(hdr));
if (vk && crypt_volume_key_description(vk) && crypt_is_cipher_null(reencrypt_segment_cipher_old(hdr))) {
if (vk && vk->key_description && crypt_is_cipher_null(reencrypt_segment_cipher_old(hdr))) {
flags |= CRYPT_ACTIVATE_KEYRING_KEY;
dmd_source.flags |= CRYPT_ACTIVATE_KEYRING_KEY;
}
@@ -3678,37 +3629,12 @@ err:
return r;
}
static int reencrypt_locked_recovery(struct crypt_device *cd,
int keyslot_old,
int keyslot_new,
struct crypt_keyslot_context *kc_old,
struct crypt_keyslot_context *kc_new,
struct volume_key **r_vks)
{
int keyslot, r = -EINVAL;
struct volume_key *_vks = NULL;
r = LUKS2_keyslot_context_open_all_segments(cd, keyslot_old, keyslot_new,
kc_old, kc_new, &_vks);
if (r < 0)
return r;
keyslot = r;
r = LUKS2_reencrypt_locked_recovery_by_vks(cd, _vks);
if (!r && r_vks)
MOVE_REF(*r_vks, _vks);
crypt_free_volume_key(_vks);
return r < 0 ? r : keyslot;
}
static int reencrypt_recovery_by_keyslot_context(struct crypt_device *cd,
static int reencrypt_recovery_by_passphrase(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot_old,
int keyslot_new,
struct crypt_keyslot_context *kc_old,
struct crypt_keyslot_context *kc_new)
const char *passphrase,
size_t passphrase_size)
{
int r;
crypt_reencrypt_info ri;
@@ -3735,8 +3661,8 @@ static int reencrypt_recovery_by_keyslot_context(struct crypt_device *cd,
}
if (ri == CRYPT_REENCRYPT_CRASH) {
r = reencrypt_locked_recovery(cd, keyslot_old, keyslot_new,
kc_old, kc_new, NULL);
r = LUKS2_reencrypt_locked_recovery_by_passphrase(cd, keyslot_old, keyslot_new,
passphrase, passphrase_size, NULL);
if (r < 0)
log_err(cd, _("LUKS2 reencryption recovery failed."));
} else {
@@ -3748,13 +3674,13 @@ static int reencrypt_recovery_by_keyslot_context(struct crypt_device *cd,
return r;
}
static int reencrypt_repair(
static int reencrypt_repair_by_passphrase(
struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot_old,
int keyslot_new,
struct crypt_keyslot_context *kc_old,
struct crypt_keyslot_context *kc_new)
const char *passphrase,
size_t passphrase_size)
{
int r;
struct crypt_lock_handle *reencrypt_lock;
@@ -3819,7 +3745,7 @@ static int reencrypt_repair(
else
requirement_version = LUKS2_REENCRYPT_REQ_VERSION;
r = LUKS2_keyslot_context_open_all_segments(cd, keyslot_old, keyslot_new, kc_old, kc_new, &vks);
r = LUKS2_keyslot_open_all_segments(cd, keyslot_old, keyslot_new, passphrase, passphrase_size, &vks);
if (r < 0)
goto out;
@@ -3838,10 +3764,10 @@ out:
}
static int reencrypt_init_by_keyslot_context(struct crypt_device *cd,
static int reencrypt_init_by_passphrase(struct crypt_device *cd,
const char *name,
struct crypt_keyslot_context *kc_old,
struct crypt_keyslot_context *kc_new,
const char *passphrase,
size_t passphrase_size,
int keyslot_old,
int keyslot_new,
const char *cipher,
@@ -3850,42 +3776,23 @@ static int reencrypt_init_by_keyslot_context(struct crypt_device *cd,
{
int r;
crypt_reencrypt_info ri;
size_t key_length;
struct volume_key *vks = NULL;
uint32_t flags = params ? params->flags : 0;
struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
if (params && (params->flags & CRYPT_REENCRYPT_CREATE_NEW_DIGEST) &&
(!kc_new || !kc_new->get_luks2_key || !kc_new->get_key_size ||
(params->flags & CRYPT_REENCRYPT_RESUME_ONLY)))
return -EINVAL;
/* short-circuit in reencryption metadata update and finish immediately. */
if (flags & CRYPT_REENCRYPT_REPAIR_NEEDED)
return reencrypt_repair(cd, hdr, keyslot_old, keyslot_new, kc_old, kc_new);
return reencrypt_repair_by_passphrase(cd, hdr, keyslot_old, keyslot_new, passphrase, passphrase_size);
/* short-circuit in recovery and finish immediately. */
if (flags & CRYPT_REENCRYPT_RECOVERY)
return reencrypt_recovery_by_keyslot_context(cd, hdr, keyslot_old, keyslot_new, kc_old, kc_new);
if (name && !device_direct_io(crypt_data_device(cd))) {
log_dbg(cd, "Device %s does not support direct I/O.", device_path(crypt_data_device(cd)));
/* FIXME: Add more specific error message for translation later. */
log_err(cd, _("Failed to initialize reencryption device stack."));
return -EINVAL;
}
return reencrypt_recovery_by_passphrase(cd, hdr, keyslot_old, keyslot_new, passphrase, passphrase_size);
if (cipher && !crypt_cipher_wrapped_key(cipher, cipher_mode)) {
if (keyslot_new == CRYPT_ANY_SLOT && kc_new && kc_new->get_key_size)
r = kc_new->get_key_size(cd, kc_new, &key_length);
else {
r = crypt_keyslot_get_key_size(cd, keyslot_new);
if (r >= 0)
key_length = r;
}
r = crypt_keyslot_get_key_size(cd, keyslot_new);
if (r < 0)
return r;
r = LUKS2_check_cipher(cd, key_length, cipher, cipher_mode);
r = LUKS2_check_cipher(cd, r, cipher, cipher_mode);
if (r < 0) {
log_err(cd, _("Unable to use cipher specification %s-%s for LUKS2."), cipher, cipher_mode);
return r;
@@ -3909,8 +3816,7 @@ static int reencrypt_init_by_keyslot_context(struct crypt_device *cd,
}
if (ri == CRYPT_REENCRYPT_NONE && !(flags & CRYPT_REENCRYPT_RESUME_ONLY)) {
r = reencrypt_init(cd, name, hdr, kc_old, kc_new, keyslot_old,
keyslot_new, cipher, cipher_mode, params, &vks);
r = reencrypt_init(cd, name, hdr, passphrase, passphrase_size, keyslot_old, keyslot_new, cipher, cipher_mode, params, &vks);
if (r < 0)
log_err(cd, _("Failed to initialize LUKS2 reencryption in metadata."));
} else if (ri > CRYPT_REENCRYPT_NONE) {
@@ -3923,19 +3829,18 @@ static int reencrypt_init_by_keyslot_context(struct crypt_device *cd,
if (r < 0 || (flags & CRYPT_REENCRYPT_INITIALIZE_ONLY))
goto out;
r = reencrypt_load_by_keyslot_context(cd, name, kc_old, kc_new, keyslot_old,
keyslot_new, &vks, params);
r = reencrypt_load_by_passphrase(cd, name, passphrase, passphrase_size, keyslot_old, keyslot_new, &vks, params);
out:
if (r < 0)
crypt_drop_uploaded_keyring_key(cd, vks);
crypt_drop_keyring_key(cd, vks);
crypt_free_volume_key(vks);
return r < 0 ? r : LUKS2_find_keyslot(hdr, "reencrypt");
}
#else
static int reencrypt_init_by_keyslot_context(struct crypt_device *cd,
static int reencrypt_init_by_passphrase(struct crypt_device *cd,
const char *name __attribute__((unused)),
struct crypt_keyslot_context *kc_old __attribute__((unused)),
struct crypt_keyslot_context *kc_new __attribute__((unused)),
const char *passphrase __attribute__((unused)),
size_t passphrase_size __attribute__((unused)),
int keyslot_old __attribute__((unused)),
int keyslot_new __attribute__((unused)),
const char *cipher __attribute__((unused)),
@@ -3957,7 +3862,8 @@ int crypt_reencrypt_init_by_keyring(struct crypt_device *cd,
const struct crypt_params_reencrypt *params)
{
int r;
struct crypt_keyslot_context kc = {0};
char *passphrase;
size_t passphrase_size;
if (onlyLUKS2reencrypt(cd) || !passphrase_description)
return -EINVAL;
@@ -3969,11 +3875,17 @@ int crypt_reencrypt_init_by_keyring(struct crypt_device *cd,
return -EINVAL;
}
crypt_keyslot_context_init_by_keyring_internal(&kc, passphrase_description);
r = reencrypt_init_by_keyslot_context(cd, name, &kc, &kc, keyslot_old,
keyslot_new, cipher, cipher_mode, params);
r = crypt_keyring_get_user_key(cd, passphrase_description, &passphrase, &passphrase_size);
if (r < 0) {
log_dbg(cd, "crypt_keyring_get_user_key failed (error %d)", r);
log_err(cd, _("Failed to read passphrase from keyring."));
return -EINVAL;
}
crypt_keyslot_context_destroy_internal(&kc);
r = reencrypt_init_by_passphrase(cd, name, passphrase, passphrase_size, keyslot_old, keyslot_new, cipher, cipher_mode, params);
crypt_safe_memzero(passphrase, passphrase_size);
free(passphrase);
return r;
}
@@ -3988,9 +3900,6 @@ int crypt_reencrypt_init_by_passphrase(struct crypt_device *cd,
const char *cipher_mode,
const struct crypt_params_reencrypt *params)
{
int r;
struct crypt_keyslot_context kc = {0};
if (onlyLUKS2reencrypt(cd) || !passphrase)
return -EINVAL;
if (params && (params->flags & CRYPT_REENCRYPT_INITIALIZE_ONLY) && (params->flags & CRYPT_REENCRYPT_RESUME_ONLY))
@@ -4001,37 +3910,7 @@ int crypt_reencrypt_init_by_passphrase(struct crypt_device *cd,
return -EINVAL;
}
crypt_keyslot_context_init_by_passphrase_internal(&kc, passphrase, passphrase_size);
r = reencrypt_init_by_keyslot_context(cd, name, &kc, &kc, keyslot_old,
keyslot_new, cipher, cipher_mode, params);
crypt_keyslot_context_destroy_internal(&kc);
return r;
}
int crypt_reencrypt_init_by_keyslot_context(struct crypt_device *cd,
const char *name,
struct crypt_keyslot_context *kc_old,
struct crypt_keyslot_context *kc_new,
int keyslot_old,
int keyslot_new,
const char *cipher,
const char *cipher_mode,
const struct crypt_params_reencrypt *params)
{
if (onlyLUKS2reencrypt(cd) || (!kc_old && !kc_new))
return -EINVAL;
if (params && (params->flags & CRYPT_REENCRYPT_INITIALIZE_ONLY) && (params->flags & CRYPT_REENCRYPT_RESUME_ONLY))
return -EINVAL;
if (device_is_dax(crypt_data_device(cd)) > 0) {
log_err(cd, _("Reencryption is not supported for DAX (persistent memory) devices."));
return -EINVAL;
}
return reencrypt_init_by_keyslot_context(cd, name, kc_old, kc_new, keyslot_old, keyslot_new, cipher, cipher_mode, params);
return reencrypt_init_by_passphrase(cd, name, passphrase, passphrase_size, keyslot_old, keyslot_new, cipher, cipher_mode, params);
}
#if USE_LUKS2_REENCRYPTION
@@ -4091,8 +3970,7 @@ static reenc_status_t reencrypt_step(struct crypt_device *cd,
}
if (online) {
r = reencrypt_refresh_overlay_devices(cd, hdr, rh->overlay_name, rh->hotzone_name,
rh->hotzone_device, rh->vks, rh->device_size, rh->flags);
r = reencrypt_refresh_overlay_devices(cd, hdr, rh->overlay_name, rh->hotzone_name, rh->vks, rh->device_size, rh->flags);
/* Teardown overlay devices with dm-error. None bio shall pass! */
if (r != REENC_OK)
return r;
@@ -4218,7 +4096,7 @@ static int reencrypt_wipe_unused_device_area(struct crypt_device *cd, struct luk
static int reencrypt_teardown_ok(struct crypt_device *cd, struct luks2_hdr *hdr, struct luks2_reencrypt *rh)
{
int i, r;
uint64_t dmt_flags;
uint32_t dmt_flags;
bool finished = !(rh->device_size > rh->progress);
if (rh->rp.type == REENC_PROTECTION_NONE &&
@@ -4345,14 +4223,9 @@ int crypt_reencrypt_run(
log_dbg(cd, "Resuming LUKS2 reencryption.");
if (rh->online) {
/* This is last resort to avoid data corruption. Abort is justified here. */
assert(device_direct_io(crypt_data_device(cd)));
if (reencrypt_init_device_stack(cd, rh)) {
log_err(cd, _("Failed to initialize reencryption device stack."));
return -EINVAL;
}
if (rh->online && reencrypt_init_device_stack(cd, rh)) {
log_err(cd, _("Failed to initialize reencryption device stack."));
return -EINVAL;
}
log_dbg(cd, "Progress %" PRIu64 ", device_size %" PRIu64, rh->progress, rh->device_size);
@@ -4501,17 +4374,76 @@ int LUKS2_reencrypt_check_device_size(struct crypt_device *cd, struct luks2_hdr
}
#if USE_LUKS2_REENCRYPTION
/* returns keyslot number on success (>= 0) or negative errnor otherwise */
int LUKS2_reencrypt_locked_recovery_by_passphrase(struct crypt_device *cd,
int keyslot_old,
int keyslot_new,
const char *passphrase,
size_t passphrase_size,
struct volume_key **vks)
{
uint64_t minimal_size, device_size;
int keyslot, r = -EINVAL;
struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
struct volume_key *vk = NULL, *_vks = NULL;
log_dbg(cd, "Entering reencryption crash recovery.");
if (LUKS2_get_data_size(hdr, &minimal_size, NULL))
return r;
r = LUKS2_keyslot_open_all_segments(cd, keyslot_old, keyslot_new,
passphrase, passphrase_size, &_vks);
if (r < 0)
goto out;
keyslot = r;
if (crypt_use_keyring_for_vk(cd))
vk = _vks;
while (vk) {
r = LUKS2_volume_key_load_in_keyring_by_digest(cd, vk, crypt_volume_key_get_id(vk));
if (r < 0)
goto out;
vk = crypt_volume_key_next(vk);
}
if (LUKS2_reencrypt_check_device_size(cd, hdr, minimal_size, &device_size, true, false))
goto out;
r = reencrypt_recovery(cd, hdr, device_size, _vks);
if (!r && vks)
MOVE_REF(*vks, _vks);
out:
if (r < 0)
crypt_drop_keyring_key(cd, _vks);
crypt_free_volume_key(_vks);
return r < 0 ? r : keyslot;
}
int LUKS2_reencrypt_locked_recovery_by_vks(struct crypt_device *cd,
struct volume_key *vks)
{
uint64_t minimal_size, device_size;
int r = -EINVAL;
struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
struct volume_key *vk = NULL;
log_dbg(cd, "Entering reencryption crash recovery.");
if (LUKS2_get_data_size(hdr, &minimal_size, NULL))
return r;
if (crypt_use_keyring_for_vk(cd))
vk = vks;
while (vk) {
r = LUKS2_volume_key_load_in_keyring_by_digest(cd, vk, crypt_volume_key_get_id(vk));
if (r < 0)
goto out;
vk = crypt_volume_key_next(vk);
}
if (LUKS2_reencrypt_check_device_size(cd, hdr, minimal_size, &device_size, true, false))
goto out;
@@ -4519,7 +4451,7 @@ int LUKS2_reencrypt_locked_recovery_by_vks(struct crypt_device *cd,
out:
if (r < 0)
crypt_drop_uploaded_keyring_key(cd, vks);
crypt_drop_keyring_key(cd, vks);
return r;
}
#endif

View File

@@ -2,9 +2,9 @@
/*
* LUKS - Linux Unified Key Setup v2, reencryption digest helpers
*
* Copyright (C) 2022-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2022-2025 Ondrej Kozina
* Copyright (C) 2022-2025 Milan Broz
* Copyright (C) 2022-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2022-2024 Ondrej Kozina
* Copyright (C) 2022-2024 Milan Broz
*/
#include "luks2_internal.h"
@@ -240,10 +240,10 @@ static size_t reenc_keyslot_serialize(struct luks2_hdr *hdr, uint8_t *buffer)
return srs(j, buffer);
}
static size_t blob_serialize(const void *blob, size_t length, uint8_t *buffer)
static size_t blob_serialize(void *blob, size_t length, uint8_t *buffer)
{
if (buffer)
crypt_safe_memcpy(buffer, blob, length);
memcpy(buffer, blob, length);
return length;
}
@@ -252,13 +252,12 @@ static int reencrypt_assembly_verification_data(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct volume_key *vks,
uint8_t version,
struct volume_key **r_verification_data)
struct volume_key **verification_data)
{
uint8_t *ptr;
int digest_new, digest_old, r = -EINVAL;
struct volume_key *verification_data = NULL, *vk_old = NULL, *vk_new = NULL;
int digest_new, digest_old;
struct volume_key *data = NULL, *vk_old = NULL, *vk_new = NULL;
size_t keyslot_data_len, segments_data_len, data_len = 2;
void *data = NULL;
/*
* This works up to (including) version v207.
@@ -275,7 +274,7 @@ static int reencrypt_assembly_verification_data(struct crypt_device *cd,
log_dbg(cd, "Key (digest id %d) required but not unlocked.", digest_old);
return -EINVAL;
}
data_len += blob_serialize(crypt_volume_key_get_key(vk_old), crypt_volume_key_length(vk_old), NULL);
data_len += blob_serialize(vk_old->key, vk_old->keylength, NULL);
}
if (digest_new >= 0 && digest_old != digest_new) {
@@ -284,7 +283,7 @@ static int reencrypt_assembly_verification_data(struct crypt_device *cd,
log_dbg(cd, "Key (digest id %d) required but not unlocked.", digest_new);
return -EINVAL;
}
data_len += blob_serialize(crypt_volume_key_get_key(vk_new), crypt_volume_key_length(vk_new), NULL);
data_len += blob_serialize(vk_new->key, vk_new->keylength, NULL);
}
if (data_len == 2)
@@ -300,22 +299,20 @@ static int reencrypt_assembly_verification_data(struct crypt_device *cd,
data_len += segments_data_len;
/* Alloc and fill serialization data */
data = crypt_safe_alloc(data_len);
data = crypt_alloc_volume_key(data_len, NULL);
if (!data)
return -ENOMEM;
ptr = (uint8_t*)data;
ptr = (uint8_t*)data->key;
*ptr++ = 0x76;
*ptr++ = 0x30 + version;
if (vk_old)
ptr += blob_serialize(crypt_volume_key_get_key(vk_old),
crypt_volume_key_length(vk_old), ptr);
ptr += blob_serialize(vk_old->key, vk_old->keylength, ptr);
if (vk_new)
ptr += blob_serialize(crypt_volume_key_get_key(vk_new),
crypt_volume_key_length(vk_new), ptr);
ptr += blob_serialize(vk_new->key, vk_new->keylength, ptr);
if (!reenc_keyslot_serialize(hdr, ptr))
goto bad;
@@ -325,20 +322,14 @@ static int reencrypt_assembly_verification_data(struct crypt_device *cd,
goto bad;
ptr += segments_data_len;
assert((size_t)(ptr - (uint8_t*)data) == data_len);
assert((size_t)(ptr - (uint8_t*)data->key) == data_len);
verification_data = crypt_alloc_volume_key_by_safe_alloc(&data);
if (!verification_data) {
r = -ENOMEM;
goto bad;
}
*r_verification_data = verification_data;
*verification_data = data;
return 0;
bad:
crypt_safe_free(data);
crypt_free_volume_key(verification_data);
return r;
crypt_free_volume_key(data);
return -EINVAL;
}
int LUKS2_keyslot_reencrypt_digest_create(struct crypt_device *cd,
@@ -371,6 +362,22 @@ int LUKS2_keyslot_reencrypt_digest_create(struct crypt_device *cd,
return LUKS2_digest_assign(cd, hdr, keyslot_reencrypt, digest_reencrypt, 1, 0);
}
void LUKS2_reencrypt_lookup_key_ids(struct crypt_device *cd, struct luks2_hdr *hdr, struct volume_key *vk)
{
int digest_old, digest_new;
digest_old = LUKS2_reencrypt_digest_old(hdr);
digest_new = LUKS2_reencrypt_digest_new(hdr);
while (vk) {
if (digest_old >= 0 && LUKS2_digest_verify_by_digest(cd, digest_old, vk) == digest_old)
crypt_volume_key_set_id(vk, digest_old);
if (digest_new >= 0 && LUKS2_digest_verify_by_digest(cd, digest_new, vk) == digest_new)
crypt_volume_key_set_id(vk, digest_new);
vk = vk->next;
}
}
int LUKS2_reencrypt_digest_verify(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct volume_key *vks)

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