Compare commits

...

35 Commits

Author SHA1 Message Date
Milan Broz
8b3eb37046 tests: Add new trcypt images for Argon2 PBKDF.
Also modify test to use longer PIM password, as VeraCrypt
requires at least 20 character password with lower PIM values.
2025-11-20 19:07:47 +01:00
Milan Broz
e9bd43a8fa tests: Add PBKDF check for crypto helper.
This can be used in FIPS mode to skip Argon2 if not available.
2025-11-20 19:07:47 +01:00
Milan Broz
8311a8a903 tcrypt: Support Argon2id PBKDF introduced in VeraCrypt 1.26.27.
It uses Argon2id only, with maximal memory cost 1024 MiB.
Parallel cost is always 1.

Default parameters (no PIM) is 416 MiB, 6 iterations (same as PIM 12).

In PIM mode, iterations and memory costs are calculated according
to the specific formula. Memory cost is always limited as above.
2025-11-20 19:07:47 +01:00
Milan Broz
8da66c3066 verity: Support status info about FEC repaired events
Kernel 6.19 will support additional info on dm-verity status
line that contains number of FEC successful repair events.

This patch adds support to libcryptsetup and veritysetup status command.

Ref. https://lore.kernel.org/dm-devel/074e1ecc-6690-1c22-0dba-454e191e1b6f@redhat.com/T/#m1af31c9c4263fe2b1fb58dee2fd7f0bdf045c463
2025-11-20 17:18:37 +01:00
Milan Broz
11a4fc6790 tests: use utility to detect FIPS mode
Also try to use crypto lib/kernel check where appropriate.

This can be useful for local testing (non-FIPS kernel) byt
should not break real FIPS systems.
2025-11-19 22:09:27 +01:00
Milan Broz
e4c498d15b Remove fips argument from crypt_backend_init()
It is really not needed, as it is detected automagically.
2025-11-19 22:09:27 +01:00
Milan Broz
e609c47916 tests: Add fips mode detection to crypt check tool 2025-11-19 22:09:27 +01:00
Milan Broz
ccc0c69cd7 Add fips_mode check for kernel.
Akso add a separate function so we can detect that kernel and crypto
lib is in different FIPS state (only for testing).
2025-11-19 22:09:27 +01:00
Milan Broz
7fba92260a ci: Fix Alpine runner dependences
gettext-dev install asli gettext.
argp-standalone is needed for with musl
This ensures that we can later use simplified package mappings.
2025-11-19 18:16:17 +01:00
Milan Broz
76ea8f13cf tests: Fix coding style (tabs) 2025-11-18 19:39:18 +01:00
Ondrej Kozina
bbc053682a Do not read test hotzone device repeatadly.
While allocating internal data structure for a device
overlaying reencryption hotzone we accidentally read
tested the device in each reencryption step. This
was suboptimal so now the device is read only once
while initializing the reencryption device-mapper stack.
2025-11-17 13:56:39 +01:00
Milan Broz
c9fd8b5ed4 Set devel version. 2025-11-17 13:55:40 +01:00
Kristina Hanicova
fbd295259c ci: remove ubuntu 2025-11-14 15:47:28 +01:00
Ondrej Kozina
5490d28aa4 Drop never used code in storage wrapper utils.
It was never used...
2025-11-13 15:24:12 +01:00
Ingo Franzki
296eb39c60 Changes to support PHMAC with integritysetup and cryptsetup
Make the PHMAC integrity algorithm know to libcryptsetup.

The size of a key for PHMAC is not known, because PHMAC gets an opaque
blob as key, who's physical size has nothing to do with the cryptographic
size. Thus, let INTEGRITY_key_size() and crypt_parse_integrity_mode()
return the required_key_size as key size for PHMAC, or -EINVAL if
required_key_size is zero, to indicate that the size is unknown.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
2025-11-13 09:21:40 +01:00
Ondrej Kozina
917b6836a9 Always use json-c types in internal code.
Sometimes we used "struct json_foo_bar" and sometimes "json_foo_bar"
json-c defined type. Stick with one notation in internal code.
2025-11-12 13:13:02 +01:00
Ondrej Kozina
b36d4be8fa opal: supress confusing debug messages.
Do not print sed-opal spefic debug messages with confusing
error codes if ioctl() call failed with -1. Usually that means
the kernel does not support sed-opal interface or the requested
ioctl number is not implemented.
2025-11-06 11:14:56 +01:00
Ondrej Kozina
0a8e7da7ae opal: fix debug message on failed sed-opal ioctl.
ioctl syscall always returns -1 on error (see ioctl(2)).
On error the actual reason is reported via errno varible.
Let's store the original errno code in the variable
so that it can be printed out in debug mode.

Before this fix the debug message always reported "Operation not
permited" (the translation of errno EPERM (1)).
2025-11-06 11:09:43 +01:00
Ondrej Kozina
83a7310ca2 opal: do not initialize LRs array in activation.
The lr member in opal_lr_act kernel structure is
ingnored unless the device is being activated in SUM
mode.

See kernel implementation of IOC_OPAL_ACTIVATE_LSP
in block/sed-opal.c
2025-11-03 16:05:08 +01:00
Ondrej Kozina
441802773f opal: simplify User setup routine.
Reduce memory copying by reusing nested structure in opal_lock.
2025-11-03 16:05:08 +01:00
Ondrej Kozina
cc66b1fa52 opal: pull User setup in separate function. 2025-11-03 16:05:08 +01:00
Ondrej Kozina
a0d5d2bf5e opal: pull individual range setup in separate function. 2025-11-03 16:05:08 +01:00
Ondrej Kozina
61dbb69319 opal: pull reuse of active device in separate function. 2025-11-03 16:05:08 +01:00
Ondrej Kozina
32b33541a8 opal: pull LSP activation in separate function. 2025-11-03 16:05:08 +01:00
Ondrej Kozina
346db2e42a opal: add a named constant for TCG FAIL status.
Will be checked upon later when we add support
for OPAL2 SUM Reactivate method.
2025-11-03 16:05:08 +01:00
Milan Broz
0d07e80077 Fix typo in volume-key-file help.
Fixes: #966
2025-11-03 10:58:15 +01:00
Milan Broz
dc2251b88d man: Fix typo in integritysetup man page. 2025-10-31 08:31:21 +01:00
Ondrej Kozina
a8e8e39007 Fix possible use of uninitialized variable.
device_tag_size variable was not initialized and used
when device_is_nop_dif returned negative error code.
2025-10-30 13:59:54 +01:00
Kristina Hanicova
bcef385346 ci: Add Centos Stream 10 runner 2025-10-19 22:20:47 +02:00
Ondrej Kozina
9810c6fb2f Read integrity profile info from top level device.
When formating device with --integrity-inline option
there's a check if underlying device properly advertise
integrity profile support. The check did not work
properly for partition device nodes. We have to read
integrity profile info from top level block device.

Fixes: #964.
2025-10-17 15:25:32 +02:00
Ondrej Kozina
4d98add260 opal: Submit PSID reset command to R/W file descriptor.
The PSID reset erases the block device it's submitted to
succesfully.

By submitting the command to read-only fd previously
there were partition device nodes still visible in
the /dev directory because kernel does not trigger rescan
after OPAL2 PSID reset. Even though all the partition were
actually erased (including the partition table).

We workaround the issue by submitting the PSID reset
to R/W fd so that it triggers rescan event on close.
2025-10-06 10:37:37 +02:00
Milan Broz
0eaaa4553e Fix handling of too long label and subsystem fields
These LUKS2 labels are stored in the binary header area that has limited size.

While we have been silently truncating strings here, it is something that
is not expected, as the final label is then different than expected.

Let's fix the code to explicitly print and return error here.

Also remove the comment about duplicate check. It is incorrect  optimization,
as some users will expect a real write on disk, we should no skip it.

Fixes: #958
2025-10-01 21:41:55 +02:00
Ondrej Kozina
3a8feb8be7 Improve check for a function attribute support.
The compiler may advertise function attribute support
with __has_attribute operator even though it does
not implement the feature on some architecture.

This fixes the issue with  GCC 11 on ppc64le with
__attribute__((zero_call_used_regs("used"))).

Fixes: #959.
2025-09-11 14:18:39 +02:00
Kristina Hanicova
2b9523a1ef ci: Remove rhel runner 2025-08-29 15:21:26 +02:00
Maxim Suhanov
68d4749d8a bitlk: implement validation of FVE metadata
This commit implements FVE metadata block validation based on:
* CRC-32 (to detect random corruption);
* AES-CCM-encrypted SHA-256 (to detect malicious manipulations).

The hash-based validation requires us to decrypt the VMK first, so
it's only performed when obtaining the volume key.

This allows us to detect corrupted/altered FVE metadata blocks and
pick the valid one (before this commit: the first FVE metadata block
is always selected).

Fixes: #953

tests: add BitLocker image with corrupted headers

The image contains 2 manually corrupted metadata blocks (out of 3),
the library should use the third one to correctly load the volume.

Signed-off-by: Maxim Suhanov <dfirblog@gmail.com>
2025-08-29 15:16:36 +02:00
56 changed files with 947 additions and 695 deletions

View File

@@ -10,7 +10,6 @@ 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/csmock.yml
@@ -22,4 +21,3 @@ include:
- local: .gitlab/ci/alpinelinux.yml
- local: .gitlab/ci/debian-i686.yml
- local: .gitlab/ci/cifuzz.yml
- local: .gitlab/ci/ubuntu.yml

View File

@@ -7,7 +7,7 @@
- >
sudo apk add
lvm2-dev openssl-dev popt-dev util-linux-dev json-c-dev
argon2-dev device-mapper which sharutils gettext gettext-dev automake
argon2-dev device-mapper which sharutils gettext-dev argp-standalone 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

View File

@@ -1,6 +1,4 @@
.centos-openssl-backend:
variables:
DISTRO: cryptsetup-centos-stream-9
extends:
- .fail_if_coredump_generated
before_script:
@@ -29,6 +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:
@@ -51,6 +50,53 @@ 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:

View File

@@ -1,157 +0,0 @@
.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
- 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
test-main-commit-rhel10:
extends:
- .rhel-openssl-backend
tags:
- libvirt
- cryptsetup-rhel-10
stage: test
interruptible: true
allow_failure: true
variables:
DISTRO: cryptsetup-rhel-10
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:
- grep -q fips=1 /proc/cmdline || 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:
- grep -q fips=1 /proc/cmdline || exit 1
- make -j
- make -j -C tests check-programs
- sudo -E make check
test-main-commit-rhel10-fips:
extends:
- .rhel-openssl-backend
tags:
- libvirt
- cryptsetup-rhel-10-fips
stage: test
interruptible: true
allow_failure: true
variables:
DISTRO: cryptsetup-rhel-10-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:
- grep -q fips=1 /proc/cmdline || exit 1
- make -j
- make -j -C tests check-programs
- sudo -E make check

View File

@@ -1,106 +0,0 @@
.ubuntu-prep:
extends:
- .fail_if_coredump_generated
before_script:
- sudo apt-get -y update
- >
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
# scsi_debug, gost crypto
- sudo apt-get -y install dkms linux-headers-$(uname -r) linux-modules-extra-$(uname -r) gost-crypto-dkms
- sudo apt-get -y build-dep cryptsetup
- sudo -E git clean -xdf
- ./autogen.sh
- ./configure --enable-libargon2 --enable-asciidoc
test-mergerq-job-ubuntu:
extends:
- .ubuntu-prep
tags:
- libvirt
- cryptsetup-ubuntu-2404
stage: test
interruptible: true
variables:
DISTRO: cryptsetup-ubuntu-2404
RUN_SSH_PLUGIN_TEST: "1"
RUN_KEYRING_TRUSTED_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
script:
- make -j
- make -j -C tests check-programs
- sudo -E make check
test-main-commit-job-ubuntu:
extends:
- .ubuntu-prep
tags:
- libvirt
- cryptsetup-ubuntu-2404
stage: test
interruptible: true
variables:
DISTRO: cryptsetup-ubuntu-2404
RUN_SSH_PLUGIN_TEST: "1"
RUN_KEYRING_TRUSTED_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
script:
- make -j
- make -j -C tests check-programs
- sudo -E make check
# meson tests
test-mergerq-job-ubuntu-meson:
extends:
- .ubuntu-prep
tags:
- libvirt
- cryptsetup-ubuntu-2404
stage: test
interruptible: true
variables:
DISTRO: cryptsetup-ubuntu-2404
RUN_SSH_PLUGIN_TEST: "1"
RUN_KEYRING_TRUSTED_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
script:
- sudo apt-get -y install -y -qq meson ninja-build
- meson setup build
- ninja -C build
- cd build && sudo -E meson test --verbose --print-errorlogs
test-main-commit-job-ubuntu-meson:
extends:
- .ubuntu-prep
tags:
- libvirt
- cryptsetup-ubuntu-2404
stage: test
interruptible: true
variables:
DISTRO: cryptsetup-ubuntu-2404
RUN_SSH_PLUGIN_TEST: "1"
RUN_KEYRING_TRUSTED_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
script:
- sudo apt-get -y install -y -qq meson ninja-build
- meson setup build
- ninja -C build
- cd build && sudo -E meson test --verbose --print-errorlogs

View File

@@ -1,5 +1,5 @@
AC_PREREQ([2.67])
AC_INIT([cryptsetup],[2.8.1])
AC_INIT([cryptsetup],[2.9.0-git])
dnl library version from <major>.<minor>.<release>[-<suffix>]
LIBCRYPTSETUP_VERSION=$(echo $PACKAGE_VERSION | cut -f1 -d-)
@@ -680,6 +680,27 @@ 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

View File

@@ -111,6 +111,7 @@ 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;
@@ -132,6 +133,32 @@ 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;
@@ -361,6 +388,54 @@ 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)
@@ -391,6 +466,7 @@ void BITLK_bitlk_metadata_free(struct bitlk_metadata *metadata)
free(metadata->guid);
free(metadata->description);
free(metadata->validation);
BITLK_bitlk_vmk_free(metadata->vmks);
BITLK_bitlk_fvek_free(metadata->fvek);
}
@@ -402,20 +478,25 @@ 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;
@@ -490,15 +571,80 @@ 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]);
log_dbg(cd, "Reading BITLK FVE metadata of size %zu on device %s, offset %" PRIu64 ".",
sizeof(fve), device_path(device), params->metadata_offset[0]);
fve_validated_block = malloc(BITLK_FVE_METADATA_SIZE);
if (fve_validated_block == NULL) {
r = -ENOMEM;
goto out;
}
/* 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));
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));
r = -EINVAL;
goto out;
}
@@ -583,17 +729,18 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
}
memset(fve_entries, 0, fve_entries_size);
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);
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);
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));
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));
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 */
@@ -716,6 +863,8 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
}
out:
free(fve_entries);
free(fve_validated_block);
return r;
}
@@ -1110,6 +1259,7 @@ 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;
@@ -1172,6 +1322,36 @@ 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);

View File

@@ -21,6 +21,8 @@ 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
@@ -85,6 +87,13 @@ 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;
@@ -101,8 +110,10 @@ 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);

View File

@@ -8,6 +8,8 @@
#include <errno.h>
#include <strings.h>
#include <unistd.h>
#include <fcntl.h>
#include "crypto_backend.h"
struct cipher_alg {
@@ -77,3 +79,21 @@ 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

@@ -30,7 +30,7 @@ struct crypt_hmac;
struct crypt_cipher;
struct crypt_storage;
int crypt_backend_init(bool fips);
int crypt_backend_init(void);
void crypt_backend_destroy(void);
#define CRYPT_BACKEND_KERNEL (1 << 0) /* Crypto uses kernel part, for benchmark */
@@ -148,6 +148,9 @@ 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

View File

@@ -80,7 +80,7 @@ static void crypt_hash_test_whirlpool_bug(void)
crypto_backend_whirlpool_bug = 1;
}
int crypt_backend_init(bool fips __attribute__((unused)))
int crypt_backend_init(void)
{
int r;
@@ -684,7 +684,7 @@ bool crypt_fips_mode(void)
if (fips_checked)
return fips_mode;
if (crypt_backend_init(false /* ignored */))
if (crypt_backend_init())
return false;
fips_mode = gcry_fips_mode_active();

View File

@@ -103,7 +103,7 @@ static int crypt_kernel_socket_init(struct sockaddr_alg *sa, int *tfmfd, int *op
return 0;
}
int crypt_backend_init(bool fips __attribute__((unused)))
int crypt_backend_init(void)
{
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 false;
return crypt_fips_mode_kernel();
}

View File

@@ -69,16 +69,13 @@ static const mbedtls_md_info_t *crypt_get_hash(const char *name)
return NULL;
}
int crypt_backend_init(bool fips)
int crypt_backend_init(void)
{
int ret;
if (g_initialized)
return 0;
if (fips)
return -ENOTSUP;
mbedtls_version_get_string_full(g_backend_version);
mbedtls_entropy_init(&g_entropy);

View File

@@ -200,7 +200,7 @@ static struct hash_alg *_get_alg(const char *name)
return NULL;
}
int crypt_backend_init(bool fips __attribute__((unused)))
int crypt_backend_init(void)
{
return 0;
}

View File

@@ -62,7 +62,7 @@ static struct hash_alg *_get_alg(const char *name)
return NULL;
}
int crypt_backend_init(bool fips __attribute__((unused)))
int crypt_backend_init(void)
{
int r;

View File

@@ -205,12 +205,12 @@ static const char *openssl_backend_version(void)
}
#endif
int crypt_backend_init(bool fips)
int crypt_backend_init(void)
{
if (crypto_backend_initialised)
return 0;
if (openssl_backend_init(fips))
if (openssl_backend_init(crypt_fips_mode()))
return -EINVAL;
crypto_backend_initialised = 1;

View File

@@ -9,11 +9,9 @@
#define ATTR_NOINLINE __attribute__ ((noinline))
#define ATTR_ZERO_REGS
#if defined __has_attribute
# if __has_attribute (zero_call_used_regs)
#if HAVE_ATTRIBUTE_ZEROCALLUSEDREGS
# undef ATTR_ZERO_REGS
# define ATTR_ZERO_REGS __attribute__ ((zero_call_used_regs("used")))
# endif
#endif
/* Workaround for https://github.com/google/sanitizers/issues/1507 */

View File

@@ -151,6 +151,12 @@ int INTEGRITY_key_size(const char *integrity, int required_key_size)
ks = required_key_size ?: 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;
else if (!strcmp(integrity, "poly1305"))
ks = 0;
else if (!strcmp(integrity, "none"))
@@ -180,6 +186,8 @@ 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
@@ -222,6 +230,12 @@ 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;

View File

@@ -2117,6 +2117,18 @@ 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.
*

View File

@@ -195,3 +195,8 @@ CRYPTSETUP_2.8 {
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

@@ -1992,6 +1992,40 @@ int dm_status_verity_ok(struct crypt_device *cd, const char *name)
return r;
}
int dm_status_verity_repaired(struct crypt_device *cd, const char *name, uint64_t *repaired)
{
int r;
struct dm_info dmi;
char *status_line = NULL, *p;
uint64_t val64;
if (dm_init_context(cd, DM_VERITY))
return -ENOTSUP;
r = dm_status_dmi(name, &dmi, DM_VERITY_TARGET, &status_line);
dm_exit_context();
if (r < 0 || !status_line || !*status_line) {
free(status_line);
return r;
}
p = status_line + 1;
while (*p == ' ')
p++;
if (!*p || *p == '-' || sscanf(p, "%" PRIu64, &val64) != 1) {
free(status_line);
return -ENOTSUP;
}
log_dbg(cd, "Verity volume %s status is %s.", name, status_line ?: "");
if (repaired)
*repaired = val64;
free(status_line);
return 0;
}
int dm_status_integrity_failures(struct crypt_device *cd, const char *name, uint64_t *count)
{
int r;

View File

@@ -58,6 +58,12 @@ typedef enum OpalStatus {
_OPAL_STATUS_MAX = 0x13,
} 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",
@@ -85,9 +91,9 @@ static const char *opal_status_to_string(int t)
if (t < 0)
return strerror(-t);
/* Fail, as defined by specification */
if (t == 0x3f)
return "unknown failure";
/* This will be checked upon 'Reactivate' method */
if (t == OPAL_STATUS_FAIL)
return "FAIL status";
if (t >= _OPAL_STATUS_MAX)
return "unknown error";
@@ -236,6 +242,8 @@ 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;
@@ -396,6 +404,194 @@ 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,
@@ -407,11 +603,8 @@ int opal_setup_ranges(struct crypt_device *cd,
const void *admin_key,
size_t admin_key_len)
{
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_lock_unlock *lock = NULL;
struct opal_new_pw *new_pw = NULL;
struct opal_user_lr_setup *setup = NULL;
int r, fd;
assert(cd);
@@ -437,130 +630,16 @@ 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) {
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 },
};
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 != 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,
},
};
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 != 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;
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;
}
*user_session = (struct opal_session_info) {
.who = segment_number + 1,
.opal_key = {
.key_len = admin_key_len,
},
};
crypt_safe_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;
r = opal_setup_user(cd, fd, segment_number, admin_key, admin_key_len);
if (r < 0)
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,
};
crypt_safe_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) {
@@ -588,6 +667,8 @@ int opal_setup_ranges(struct crypt_device *cd,
crypt_safe_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));
@@ -595,37 +676,10 @@ int opal_setup_ranges(struct crypt_device *cd,
goto out;
}
setup = crypt_safe_alloc(sizeof(struct opal_user_lr_setup));
if (!setup) {
r = -ENOMEM;
r = opal_setup_range(cd, fd, segment_number, range_start_blocks, range_length_blocks,
admin_key, admin_key_len);
if (r < 0)
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,
},
},
};
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 != 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. */
@@ -648,6 +702,8 @@ int opal_setup_ranges(struct crypt_device *cd,
crypt_volume_key_length(vk));
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));
@@ -661,11 +717,7 @@ 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;
@@ -737,6 +789,8 @@ 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",
@@ -790,7 +844,11 @@ int opal_factory_reset(struct crypt_device *cd,
if (password_len > OPAL_KEY_MAX)
return -EINVAL;
fd = device_open(cd, dev, O_RDONLY);
/*
* Submit PSID reset on R/W file descriptor so it
* triggers blkid rescan after we close it.
*/
fd = device_open(cd, dev, O_RDWR);
if (fd < 0)
return -EIO;
@@ -860,6 +918,8 @@ int opal_reset_segment(struct crypt_device *cd,
}
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));
@@ -883,6 +943,8 @@ int opal_reset_segment(struct crypt_device *cd,
};
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));

View File

@@ -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;
struct json_tokener *jtok;
json_tokener *jtok;
/* INT32_MAX is internal (json-c) json_tokener_parse_ex() limit */
if (!json_area || max_length > INT32_MAX)

View File

@@ -203,7 +203,7 @@ int LUKS2_generate_hdr(
uint32_t opal_segment_number,
uint32_t opal_key_size)
{
struct json_object *jobj_segment, *jobj_keyslots, *jobj_segments, *jobj_config;
json_object *jobj_segment, *jobj_keyslots, *jobj_segments, *jobj_config;
uuid_t partitionUuid;
int r, digest;

View File

@@ -49,9 +49,9 @@ void JSON_DBG(struct crypt_device *cd, json_object *jobj, const char *desc)
/*
* JSON array helpers
*/
struct json_object *LUKS2_array_jobj(struct json_object *array, const char *num)
json_object *LUKS2_array_jobj(json_object *array, const char *num)
{
struct json_object *jobj1;
json_object *jobj1;
int i;
for (i = 0; i < (int) json_object_array_length(array); i++) {
@@ -63,9 +63,9 @@ struct json_object *LUKS2_array_jobj(struct json_object *array, const char *num)
return NULL;
}
struct json_object *LUKS2_array_remove(struct json_object *array, const char *num)
json_object *LUKS2_array_remove(json_object *array, const char *num)
{
struct json_object *jobj1, *jobj_removing = NULL, *array_new;
json_object *jobj1, *jobj_removing = NULL, *array_new;
int i;
jobj_removing = LUKS2_array_jobj(array, num);
@@ -1272,7 +1272,11 @@ 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)
{
//FIXME: check if the labels are the same and skip this.
if ((label && strlen(label) >= LUKS2_LABEL_L) ||
(subsystem && strlen(subsystem) >= LUKS2_LABEL_L)) {
log_err(cd, _("Label is too long."));
return -EINVAL;
}
memset(hdr->label, 0, LUKS2_LABEL_L);
if (label)

View File

@@ -45,11 +45,11 @@ out:
return r;
}
static int json_luks1_keyslot(const struct luks_phdr *hdr_v1, int keyslot, struct json_object **keyslot_object)
static int json_luks1_keyslot(const struct luks_phdr *hdr_v1, int keyslot, json_object **keyslot_object)
{
char *base64_str, cipher[LUKS_CIPHERNAME_L+LUKS_CIPHERMODE_L];
size_t base64_len;
struct json_object *keyslot_obj, *field, *jobj_kdf, *jobj_af, *jobj_area;
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, struct json_object **keyslots_object)
static int json_luks1_keyslots(const struct luks_phdr *hdr_v1, json_object **keyslots_object)
{
int keyslot, r;
struct json_object *keyslot_obj, *field;
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, struct json_objec
return 0;
}
static int json_luks1_segment(const struct luks_phdr *hdr_v1, struct json_object **segment_object)
static int json_luks1_segment(const struct luks_phdr *hdr_v1, json_object **segment_object)
{
const char *c;
char cipher[LUKS_CIPHERNAME_L+LUKS_CIPHERMODE_L];
struct json_object *segment_obj, *field;
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, struct json_object
return 0;
}
static int json_luks1_segments(const struct luks_phdr *hdr_v1, struct json_object **segments_object)
static int json_luks1_segments(const struct luks_phdr *hdr_v1, json_object **segments_object)
{
int r;
struct json_object *segments_obj, *field;
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, struct json_objec
return 0;
}
static int json_luks1_digest(const struct luks_phdr *hdr_v1, struct json_object **digest_object)
static int json_luks1_digest(const struct luks_phdr *hdr_v1, json_object **digest_object)
{
char keyslot_str[16], *base64_str;
int r, ks;
size_t base64_len;
struct json_object *digest_obj, *array, *field;
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, struct json_object
return 0;
}
static int json_luks1_digests(const struct luks_phdr *hdr_v1, struct json_object **digests_object)
static int json_luks1_digests(const struct luks_phdr *hdr_v1, json_object **digests_object)
{
int r;
struct json_object *digests_obj, *field;
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, struct json_object
return 0;
}
static int json_luks1_object(struct luks_phdr *hdr_v1, struct json_object **luks1_object, uint64_t keyslots_size)
static int json_luks1_object(struct luks_phdr *hdr_v1, json_object **luks1_object, uint64_t keyslots_size)
{
int r;
struct json_object *luks1_obj, *field;
json_object *luks1_obj, *field;
uint64_t json_size;
luks1_obj = json_object_new_object();

View File

@@ -34,7 +34,7 @@ struct luks2_reencrypt {
/* already running reencryption */
json_object *jobj_segs_hot;
struct json_object *jobj_segs_post;
json_object *jobj_segs_post;
/* backup segments */
json_object *jobj_segment_new;
@@ -54,6 +54,8 @@ struct luks2_reencrypt {
uint32_t wflags1;
uint32_t wflags2;
struct device *hotzone_device;
struct crypt_lock_handle *reenc_lock;
};
#if USE_LUKS2_REENCRYPTION
@@ -882,6 +884,8 @@ 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);
@@ -2142,34 +2146,22 @@ 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, const char *hotzone, struct volume_key *vks, uint64_t size,
const char *overlay, struct device *hotzone_device, 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, hz_dev, vks, &dmd.segment, size);
r = reencrypt_make_targets(cd, hdr, hotzone_device, vks, &dmd.segment, size);
if (r < 0)
goto out;
@@ -2178,7 +2170,6 @@ 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;
}
@@ -2305,9 +2296,13 @@ out:
}
static int reencrypt_init_device_stack(struct crypt_device *cd,
const struct luks2_reencrypt *rh)
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);
@@ -2316,6 +2311,18 @@ 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
@@ -2395,11 +2402,12 @@ 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, vks, device_size, flags);
int r = reencrypt_load_overlay_device(cd, hdr, overlay, hotzone_device, vks, device_size, flags);
if (r) {
log_err(cd, _("Failed to reload device %s."), overlay);
return REENC_ERR;
@@ -4083,7 +4091,8 @@ 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->vks, rh->device_size, rh->flags);
r = reencrypt_refresh_overlay_devices(cd, hdr, rh->overlay_name, rh->hotzone_name,
rh->hotzone_device, rh->vks, rh->device_size, rh->flags);
/* Teardown overlay devices with dm-error. None bio shall pass! */
if (r != REENC_OK)
return r;

View File

@@ -267,7 +267,7 @@ int init_crypto(struct crypt_device *ctx)
return r;
}
r = crypt_backend_init(crypt_fips_mode());
r = crypt_backend_init();
if (r < 0)
log_err(ctx, _("Cannot initialize crypto backend."));
@@ -3045,7 +3045,11 @@ int crypt_format_inline(struct crypt_device *cd,
iparams->journal_integrity_key_size))
return -EINVAL;
if (!device_is_nop_dif(idevice, &device_tag_size)) {
r = device_is_nop_dif(idevice, &device_tag_size);
if (r < 0)
return r;
if (!r) {
log_err(cd, _("Device %s does not provide inline integrity data fields."), mdata_device_path(cd));
return -EINVAL;
}
@@ -6786,6 +6790,16 @@ int crypt_get_verity_info(struct crypt_device *cd,
return 0;
}
int crypt_get_verity_repaired(struct crypt_device *cd, const char *name,
uint64_t *repaired)
{
if (!cd || !isVERITY(cd->type) || !name || !repaired)
return -EINVAL;
return dm_status_verity_repaired(cd, name, repaired);
}
int crypt_get_integrity_info(struct crypt_device *cd,
struct crypt_params_integrity *ip)
{

View File

@@ -22,25 +22,28 @@ static const struct {
const char *name;
const char *hash;
unsigned int iterations;
uint32_t parallel_cost;
uint32_t memory_cost;
uint32_t veracrypt_pim_const;
uint32_t veracrypt_pim_mult;
} tcrypt_kdf[] = {
{ false, false, "pbkdf2", "ripemd160", 2000, 0, 0 },
{ false, false, "pbkdf2", "ripemd160", 1000, 0, 0 },
{ false, false, "pbkdf2", "sha512", 1000, 0, 0 },
{ false, false, "pbkdf2", "whirlpool", 1000, 0, 0 },
{ true, false, "pbkdf2", "sha1", 2000, 0, 0 },
{ false, true, "pbkdf2", "sha512", 500000, 15000, 1000 },
{ false, true, "pbkdf2", "whirlpool", 500000, 15000, 1000 },
{ false, true, "pbkdf2", "sha256", 500000, 15000, 1000 }, // VeraCrypt 1.0f
{ false, true, "pbkdf2", "sha256", 200000, 0, 2048 }, // boot only
{ false, true, "pbkdf2", "blake2s-256", 500000, 15000, 1000 }, // VeraCrypt 1.26.2
{ false, true, "pbkdf2", "blake2s-256", 200000, 0, 2048 }, // boot only
{ false, true, "pbkdf2", "ripemd160", 655331, 15000, 1000 },
{ false, true, "pbkdf2", "ripemd160", 327661, 0, 2048 }, // boot only
{ false, true, "pbkdf2", "stribog512",500000, 15000, 1000 },
// { false, true, "pbkdf2", "stribog512",200000, 0, 2048 }, // boot only
{ false, false, NULL, NULL, 0, 0, 0 }
{ false, false, "pbkdf2", "ripemd160", 2000, 0, 0, 0, 0 },
{ false, false, "pbkdf2", "ripemd160", 1000, 0, 0, 0, 0 },
{ false, false, "pbkdf2", "sha512", 1000, 0, 0, 0, 0 },
{ false, false, "pbkdf2", "whirlpool", 1000, 0, 0, 0, 0 },
{ true, false, "pbkdf2", "sha1", 2000, 0, 0, 0, 0 },
{ false, true, "pbkdf2", "sha512", 500000, 0, 0, 15000, 1000 },
{ false, true, "pbkdf2", "whirlpool", 500000, 0, 0, 15000, 1000 },
{ false, true, "pbkdf2", "sha256", 500000, 0, 0, 15000, 1000 }, // VeraCrypt 1.0f
{ false, true, "pbkdf2", "sha256", 200000, 0, 0, 0, 2048 }, // boot only
{ false, true, "argon2id", NULL, 6, 1, 425984, 0, 0 }, // VeraCrypt 1.26.27
{ false, true, "pbkdf2", "blake2s-256", 500000, 0, 0, 15000, 1000 }, // VeraCrypt 1.26.2
{ false, true, "pbkdf2", "blake2s-256", 200000, 0, 0, 0, 2048 }, // boot only
{ false, true, "pbkdf2", "ripemd160", 655331, 0, 0, 15000, 1000 },
{ false, true, "pbkdf2", "ripemd160", 327661, 0, 0, 0, 2048 }, // boot only
{ false, true, "pbkdf2", "stribog512", 500000, 0, 0, 15000, 1000 },
// { false, true, "pbkdf2", "stribog512", 200000, 0, 0, 0, 2048 }, // boot only
{ false, false, NULL, NULL, 0, 0, 0, 0, 0 }
};
struct tcrypt_alg {
@@ -239,7 +242,8 @@ static int TCRYPT_hdr_from_disk(struct crypt_device *cd,
/* Set params */
params->passphrase = NULL;
params->passphrase_size = 0;
params->hash_name = tcrypt_kdf[kdf_index].hash;
/* For Argon2, overload hash_name */
params->hash_name = tcrypt_kdf[kdf_index].hash ?: tcrypt_kdf[kdf_index].name;
params->key_size = tcrypt_cipher[cipher_index].chain_key_size;
params->cipher = tcrypt_cipher[cipher_index].long_name;
params->mode = tcrypt_cipher[cipher_index].mode;
@@ -522,7 +526,8 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
unsigned char pwd[VCRYPT_KEY_POOL_LEN] = {};
size_t passphrase_size, max_passphrase_size;
char *key;
unsigned int i, skipped = 0, iterations;
unsigned int i, skipped = 0;
uint32_t iterations, memory;
int r = -EPERM, keyfiles_pool_length;
if (posix_memalign((void*)&key, crypt_getpagesize(), TCRYPT_HDR_KEY_LEN))
@@ -561,7 +566,9 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
pwd[i] += params->passphrase[i];
for (i = 0; tcrypt_kdf[i].name; i++) {
if (params->hash_name && !strstr(tcrypt_kdf[i].hash, params->hash_name))
if (params->hash_name && tcrypt_kdf[i].hash && !strstr(tcrypt_kdf[i].hash, params->hash_name))
continue;
if (params->hash_name && !tcrypt_kdf[i].hash && !strstr(tcrypt_kdf[i].name, params->hash_name))
continue;
if (!(params->flags & CRYPT_TCRYPT_LEGACY_MODES) && tcrypt_kdf[i].legacy)
continue;
@@ -572,19 +579,36 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
if (!tcrypt_kdf[i].veracrypt)
continue;
/* adjust iterations to given PIM cmdline parameter */
iterations = tcrypt_kdf[i].veracrypt_pim_const +
(tcrypt_kdf[i].veracrypt_pim_mult * params->veracrypt_pim);
} else
if (!strcmp(tcrypt_kdf[i].name, "argon2id")) {
if (params->veracrypt_pim <= 31) {
iterations = (params->veracrypt_pim - 1) / 3 + 3;
memory = 1024 * (64 + (params->veracrypt_pim - 1) * 32);
} else{
iterations = params->veracrypt_pim - 18;
memory = 1024 * 1024;
}
} else {
iterations = tcrypt_kdf[i].veracrypt_pim_const +
(tcrypt_kdf[i].veracrypt_pim_mult * params->veracrypt_pim);
memory = 0;
}
} else {
iterations = tcrypt_kdf[i].iterations;
memory = tcrypt_kdf[i].memory_cost;
}
/* Derive header key */
log_dbg(cd, "TCRYPT: trying KDF: %s-%s-%d%s.",
tcrypt_kdf[i].name, tcrypt_kdf[i].hash, tcrypt_kdf[i].iterations,
params->veracrypt_pim && tcrypt_kdf[i].veracrypt ? "-PIM" : "");
if (!strcmp(tcrypt_kdf[i].name, "argon2id"))
log_dbg(cd, "TCRYPT: trying KDF: %s%s.", tcrypt_kdf[i].name,
params->veracrypt_pim && tcrypt_kdf[i].veracrypt ? "-PIM" : "");
else
log_dbg(cd, "TCRYPT: trying KDF: %s-%s-%d%s.",
tcrypt_kdf[i].name, tcrypt_kdf[i].hash, tcrypt_kdf[i].iterations,
params->veracrypt_pim && tcrypt_kdf[i].veracrypt ? "-PIM" : "");
r = crypt_pbkdf(tcrypt_kdf[i].name, tcrypt_kdf[i].hash,
(char*)pwd, passphrase_size,
hdr->salt, TCRYPT_HDR_SALT_LEN,
key, TCRYPT_HDR_KEY_LEN,
iterations, 0, 0);
iterations, memory, tcrypt_kdf[i].parallel_cost);
if (r < 0) {
log_verbose(cd, _("PBKDF2 hash algorithm %s not available, skipping."),
tcrypt_kdf[i].hash);
@@ -1187,7 +1211,11 @@ int TCRYPT_dump(struct crypt_device *cd,
log_std(cd, "Volume size:\t%" PRIu64 " [bytes]\n", hdr->d.volume_size);
if (hdr->d.hidden_volume_size)
log_std(cd, "Hidden size:\t%" PRIu64 " [bytes]\n", hdr->d.hidden_volume_size);
log_std(cd, "PBKDF2 hash:\t%s\n", params->hash_name);
if (strcmp(params->hash_name, "argon2id")) {
log_std(cd, "PBKDF:\t\tPBKDF2\n");
log_std(cd, "PBKDF2 hash:\t%s\n", params->hash_name);
} else
log_std(cd, "PBKDF:\t\tArgon2id\n");
}
log_std(cd, "Cipher chain:\t%s\n", params->cipher);
log_std(cd, "Cipher mode:\t%s\n", params->mode);

View File

@@ -119,6 +119,21 @@ int crypt_parse_integrity_mode(const char *s, char *integrity,
} else if (!strcmp(s, "hmac-sha512")) {
strncpy(integrity, "hmac(sha512)", MAX_CIPHER_LEN);
ks = required_key_size ?: 64;
} else if (!strcmp(s, "phmac-sha1")) {
strncpy(integrity, "phmac(sha1)", MAX_CIPHER_LEN);
ks = required_key_size;
if (!required_key_size)
r = -EINVAL;
} else if (!strcmp(s, "phmac-sha256")) {
strncpy(integrity, "phmac(sha256)", MAX_CIPHER_LEN);
ks = required_key_size;
if (!required_key_size)
r = -EINVAL;
} else if (!strcmp(s, "phmac-sha512")) {
strncpy(integrity, "phmac(sha512)", MAX_CIPHER_LEN);
ks = required_key_size;
if (!required_key_size)
r = -EINVAL;
} else if (!strcmp(s, "cmac-aes")) {
strncpy(integrity, "cmac(aes)", MAX_CIPHER_LEN);
ks = 16;

View File

@@ -1004,12 +1004,26 @@ int device_is_zoned(struct device *device)
int device_is_nop_dif(struct device *device, uint32_t *tag_size)
{
char *base_device_path;
int r;
struct stat st;
if (!device)
return -EINVAL;
if (stat(device_path(device), &st) < 0)
/*
* For partition devices, check integrity profile on the base device.
* Partition device nodes don't advertise integrity profile directly
* via sysfs attributes.
*/
base_device_path = crypt_get_base_device(device_path(device));
if (base_device_path) {
r = stat(base_device_path, &st);
free(base_device_path);
} else
r = stat(device_path(device), &st);
if (r < 0)
return -EINVAL;
if (!S_ISBLK(st.st_mode))

View File

@@ -205,6 +205,7 @@ int dm_status_device(struct crypt_device *cd, const char *name);
int dm_status_suspended(struct crypt_device *cd, const char *name);
int dm_status_verity_ok(struct crypt_device *cd, const char *name);
int dm_status_integrity_failures(struct crypt_device *cd, const char *name, uint64_t *count);
int dm_status_verity_repaired(struct crypt_device *cd, const char *name, uint64_t *repaired);
int dm_query_device(struct crypt_device *cd, const char *name,
uint64_t get_flags, struct crypt_dm_active_device *dmd);
int dm_device_deps(struct crypt_device *cd, const char *name, const char *prefix,

View File

@@ -327,24 +327,6 @@ ssize_t crypt_storage_wrapper_encrypt_write(struct crypt_storage_wrapper *cw,
cw->data_offset + offset);
}
ssize_t crypt_storage_wrapper_encrypt(struct crypt_storage_wrapper *cw,
off_t offset, void *buffer, size_t buffer_length)
{
if (cw->type == NONE)
return 0;
if (cw->type == DMCRYPT)
return -ENOTSUP;
if (crypt_storage_encrypt(cw->u.cb.s,
cw->u.cb.iv_start + (offset >> SECTOR_SHIFT),
buffer_length,
buffer))
return -EINVAL;
return 0;
}
void crypt_storage_wrapper_destroy(struct crypt_storage_wrapper *cw)
{
if (!cw)

View File

@@ -53,8 +53,6 @@ ssize_t crypt_storage_wrapper_write(struct crypt_storage_wrapper *cw,
off_t offset, void *buffer, size_t buffer_length);
ssize_t crypt_storage_wrapper_encrypt_write(struct crypt_storage_wrapper *cw,
off_t offset, void *buffer, size_t buffer_length);
ssize_t crypt_storage_wrapper_encrypt(struct crypt_storage_wrapper *cw,
off_t offset, void *buffer, size_t buffer_length);
int crypt_storage_wrapper_datasync(const struct crypt_storage_wrapper *cw);

View File

@@ -201,7 +201,7 @@ The file with the integrity key.
The size of the journal integrity key.
Maximum is 4096 bytes.
*--journal-size*, *-j* _butes_::
*--journal-size*, *-j* _bytes_::
Size of the journal.
*--journal-watermark* _percent_::

View File

@@ -2,7 +2,7 @@ project('cryptsetup',
'c',
default_options: [ 'prefix=/usr' ],
meson_version: '>=0.64',
version: '2.8.1')
version: '2.9.0-git')
libcryptsetup_version = '12.11.0'
@@ -697,6 +697,21 @@ if cc.links(
description: 'Define to 1 to use __attribute__((symver))')
endif
# ==========================================================================
# Check compiler support for zero_called_used_regs("used") function attribute
if cc.links(
'''void _test_fn(void);
__attribute__((zero_call_used_regs("used"))) void _test_fn(void) {
volatile int *i; volatile int j = 0; if (j) *i = 0;
}
int main(void) { _test_fn(); return 0; }''',
args: ['-O0', '-Werror' ],
name: 'for zero_call_used_regs("used") attribute support')
conf.set10('HAVE_ATTRIBUTE_ZEROCALLUSEDREGS', true,
description: 'Define to 1 to use __attribute__((zero_call_used_regs("used")))')
endif
# ==========================================================================
if get_option('dev-random')

View File

@@ -246,4 +246,4 @@ ARG(OPT_WRITE_LOG, '\0', POPT_ARG_NONE, N_("Update log file after every block"),
ARG(OPT_DUMP_MASTER_KEY, '\0', POPT_ARG_NONE, N_("Alias for --dump-volume-key"), NULL, CRYPT_ARG_ALIAS, { .o.id = OPT_DUMP_VOLUME_KEY_ID}, {})
ARG(OPT_MASTER_KEY_FILE, '\0', POPT_ARG_STRING, N_("Alias for --dump-volume-key-file"), NULL, CRYPT_ARG_ALIAS, { .o.id = OPT_VOLUME_KEY_FILE_ID}, {})
ARG(OPT_MASTER_KEY_FILE, '\0', POPT_ARG_STRING, N_("Alias for --volume-key-file"), NULL, CRYPT_ARG_ALIAS, { .o.id = OPT_VOLUME_KEY_FILE_ID}, {})

View File

@@ -333,6 +333,7 @@ static int action_status(void)
size_t root_hash_size;
unsigned path = 0;
int r = 0;
uint64_t repaired;
/* perhaps a path, not a dm device name */
if (strchr(action_argv[0], '/') && !stat(action_argv[0], &st))
@@ -415,6 +416,8 @@ static int action_status(void)
log_std(" FEC offset: %" PRIu64 " [512-byte units] (%" PRIu64 " [bytes])\n",
vp.fec_area_offset * vp.hash_block_size / SECTOR_SIZE, vp.fec_area_offset * vp.hash_block_size);
log_std(" FEC roots: %u\n", vp.fec_roots);
if (!crypt_get_verity_repaired(cd, action_argv[0], &repaired))
log_std(" FEC repaired: %" PRIu64 " [events]\n", repaired);
}
root_hash_size = crypt_get_volume_key_size(cd);

View File

@@ -17,6 +17,9 @@ if [ "$(cat /proc/sys/crypto/fips_enabled 2>/dev/null)" = "1" ] ; then
echo "Kernel running in FIPS mode."
fi
./crypto-check fips_mode && echo "Crypto backend running in FIPS mode."
./crypto-check fips_mode_kernel && echo "Kernel running in FIPS mode."
if [ -f /etc/os-release ] ; then
source /etc/os-release
echo "$PRETTY_NAME ($NAME) $VERSION"

View File

@@ -10,8 +10,6 @@ PWD1="93R4P4pIqAH8"
PWD2="mymJeD8ivEhE"
FAST_PBKDF="--pbkdf-force-iterations 1000"
FIPS_MODE=$(cat /proc/sys/crypto/fips_enabled 2>/dev/null)
if [ -n "$CRYPTSETUP_TESTS_RUN_IN_MESON" ]; then
CRYPTSETUP_VALGRIND=$CRYPTSETUP
else
@@ -22,7 +20,7 @@ fi
fips_mode()
{
[ -n "$FIPS_MODE" ] && [ "$FIPS_MODE" -gt 0 ]
./crypto-check fips_mode
}
cleanup() {

View File

@@ -4059,6 +4059,7 @@ static void Luks2Refresh(void)
static void Luks2Flags(void)
{
uint32_t flags = 42;
const char *longlabel = "0123456789abcedf0123456789abcedf0123456789abcedf";
OK_(crypt_init(&cd, DEVICE_1));
OK_(crypt_load(cd, CRYPT_LUKS2, NULL));
@@ -4089,6 +4090,9 @@ static void Luks2Flags(void)
OK_(strcmp("", crypt_get_label(cd)));
OK_(strcmp("", crypt_get_subsystem(cd)));
FAIL_(crypt_set_label(cd, longlabel, NULL), "long label");
FAIL_(crypt_set_label(cd, NULL, longlabel), "long subsystem");
CRYPT_FREE(cd);
}

View File

@@ -64,6 +64,7 @@
#define LUKS_PHDR_SIZE_B 1024
static int _fips_mode = 0;
static int _fips_mode_kernel = 0;
static char *DEVICE_1 = NULL;
static char *DEVICE_2 = NULL;
@@ -293,8 +294,9 @@ static int _setup(void)
return 1;
_fips_mode = fips_mode();
_fips_mode_kernel = fips_mode_kernel();
if (_debug)
printf("FIPS MODE: %d\n", _fips_mode);
printf("FIPS MODE: LIB %d, KERNEL %d\n", _fips_mode, _fips_mode_kernel);
/* Use default log callback */
crypt_set_log_callback(NULL, &global_log_callback, NULL);
@@ -1833,7 +1835,7 @@ static void TcryptTest(void)
CRYPT_FREE(cd);
// Following test uses non-FIPS algorithms in the cipher chain
if(_fips_mode)
if(_fips_mode || _fips_mode_kernel)
return;
OK_(crypt_init(&cd, tcrypt_dev2));

View File

@@ -31,6 +31,7 @@ int t_dm_capi_string_supported(void);
int t_set_readahead(const char *device, unsigned value);
int fips_mode(void);
int fips_mode_kernel(void);
int create_dmdevice_over_device(const char *dm_name, const char *device, uint64_t size, uint64_t offset);

Binary file not shown.

View File

@@ -50,7 +50,6 @@ KEY_MATERIAL5_EXT="S331776-395264"
TEST_UUID="12345678-1234-1234-1234-123456789abc"
LOOPDEV=$(losetup -f 2>/dev/null)
FIPS_MODE=$(cat /proc/sys/crypto/fips_enabled 2>/dev/null)
remove_mapping()
{
@@ -83,7 +82,7 @@ trap _sigchld CHLD
fips_mode()
{
[ -n "$FIPS_MODE" ] && [ "$FIPS_MODE" -gt 0 ]
./crypto-check fips_mode
}
can_fail_fips()

View File

@@ -42,8 +42,6 @@ FAST_PBKDF_OPT="--pbkdf pbkdf2 --pbkdf-force-iterations 1000"
TEST_UUID="12345678-1234-1234-1234-123456789abc"
FIPS_MODE=$(cat /proc/sys/crypto/fips_enabled 2>/dev/null)
remove_mapping()
{
[ -b /dev/mapper/$DEV_NAME2 ] && dmsetup remove --retry $DEV_NAME2
@@ -73,7 +71,7 @@ trap _sigchld CHLD
fips_mode()
{
[ -n "$FIPS_MODE" ] && [ "$FIPS_MODE" -gt 0 ]
./crypto-check fips_mode
}
can_fail_fips()

View File

@@ -48,7 +48,6 @@ FAST_PBKDF_OPT="--pbkdf pbkdf2 --pbkdf-force-iterations 1000"
TEST_UUID="12345678-1234-1234-1234-123456789abc"
LOOPDEV=$(losetup -f 2>/dev/null)
FIPS_MODE=$(cat /proc/sys/crypto/fips_enabled 2>/dev/null)
remove_mapping()
{
@@ -88,7 +87,7 @@ trap _sigchld CHLD
fips_mode()
{
[ -n "$FIPS_MODE" ] && [ "$FIPS_MODE" -gt 0 ]
./crypto-check fips_mode
}
can_fail_fips()
@@ -1278,6 +1277,8 @@ $CRYPTSETUP luksDump $LOOPDEV | grep "Label:" | grep -q "(no label)" || fail
$CRYPTSETUP config $LOOPDEV --subsystem SatelliteThree --label TheLabel
$CRYPTSETUP luksDump $LOOPDEV | grep "Subsystem:" | grep -q "SatelliteThree" || fail
$CRYPTSETUP luksDump $LOOPDEV | grep "Label:" | grep -q "TheLabel" || fail
$CRYPTSETUP config $LOOPDEV --label 0123456789abcdef0123456789abcdef0123456789abcdef 2>/dev/null && fail
$CRYPTSETUP config $LOOPDEV --subsystem 0123456789abcdef0123456789abcdef0123456789abcdef 2>/dev/null && fail
prepare "[36] LUKS PBKDF setting" wipe
echo $PWD1 | $CRYPTSETUP luksFormat --type luks2 --pbkdf bla $LOOPDEV >/dev/null 2>&1 && fail

View File

@@ -12,24 +12,6 @@
#include "crypto_backend/crypto_backend.h"
static bool fips_mode(void)
{
int fd;
char buf = 0;
fd = open("/proc/sys/crypto/fips_enabled", O_RDONLY);
if (fd < 0)
return false;
if (read(fd, &buf, 1) != 1)
buf = '0';
close(fd);
return (buf == '1');
}
static int check_cipher(const char *alg, const char *mode, unsigned long key_bits)
{
struct crypt_cipher *cipher;
@@ -65,9 +47,36 @@ static int check_hash(const char *hash)
return EXIT_SUCCESS;
}
static int check_pbkdf(const char *pbkdf)
{
const char *hash;
uint32_t iterations, memory, parallel;
char out[32];
if (!strcmp(pbkdf, "pbkdf2")) {
hash = "sha256";
iterations = 1000;
memory = 0;
parallel = 0;
} else if (!strncmp(pbkdf, "argon2", 6)) {
hash = NULL;
iterations = 3;
memory = 256;
parallel = 1;
} else
return EXIT_FAILURE;
if (!crypt_pbkdf(pbkdf, hash, "01234567890abcdef01234567890abcdef", 32,
"11234567890abcdef11234567890abcdef", 32, out, sizeof(out),
iterations, memory, parallel))
return EXIT_SUCCESS;
return EXIT_FAILURE;
}
static void __attribute__((noreturn)) exit_help(bool destroy_backend)
{
printf("Use: crypto_check version | hash <alg> | cipher <alg> <mode> [key_bits]\n");
printf("Use: crypto_check version | fips_mode | fips_mode_kernel | hash <alg> | cipher <alg> <mode> [key_bits] | pbkdf <alg>\n");
if (destroy_backend)
crypt_backend_destroy();
exit(EXIT_FAILURE);
@@ -80,13 +89,21 @@ int main(int argc, char *argv[])
if (argc < 2)
exit_help(false);
if (crypt_backend_init(fips_mode())) {
if (!strcmp(argv[1], "fips_mode"))
return crypt_fips_mode() ? EXIT_SUCCESS : EXIT_FAILURE;
if (!strcmp(argv[1], "fips_mode_kernel"))
return crypt_fips_mode_kernel() ? EXIT_SUCCESS : EXIT_FAILURE;
if (crypt_backend_init()) {
printf("Crypto backend init error.");
return EXIT_FAILURE;
}
if (!strcmp(argv[1], "version")) {
printf("%s%s\n", crypt_backend_version(), fips_mode() ? " (FIPS mode)" : "" );
printf("%s%s%s\n", crypt_backend_version(),
crypt_fips_mode() ? " (FIPS mode)" : "",
crypt_fips_mode_kernel() ? " (FIPS kernel)" : "");
} else if (!strcmp(argv[1], "hash")) {
if (argc != 3)
exit_help(true);
@@ -102,6 +119,10 @@ int main(int argc, char *argv[])
exit_help(true);
}
r = check_cipher(argv[2], argv[3], ul);
} else if (!strcmp(argv[1], "pbkdf")) {
if (argc != 3)
exit_help(true);
r = check_pbkdf(argv[2]);
}
crypt_backend_destroy();

View File

@@ -18,8 +18,6 @@
# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#endif
static bool fips_active = false;
static void printhex(const char *s, const char *buf, size_t len)
{
size_t i;
@@ -31,24 +29,6 @@ static void printhex(const char *s, const char *buf, size_t len)
fflush(stdout);
}
static bool fips_mode(void)
{
int fd;
char buf = 0;
fd = open("/proc/sys/crypto/fips_enabled", O_RDONLY);
if (fd < 0)
return false;
if (read(fd, &buf, 1) != 1)
buf = '0';
close(fd);
return (buf == '1');
}
/*
* KDF tests
*/
@@ -1043,7 +1023,7 @@ static int pbkdf_test_vectors(void)
vec->salt, vec->salt_length,
result, vec->output_length,
vec->iterations, vec->memory, vec->parallelism) < 0) {
if (vec->can_fail_fips && fips_mode()) {
if (vec->can_fail_fips && crypt_fips_mode()) {
printf("[API FAILED, IGNORED (FIPS mode)]\n");
continue;
}
@@ -1552,7 +1532,7 @@ static int kernel_capi_check_test(void)
if (!r)
printf("[OK]\n");
else if (r == -ENOENT || r == -ENOTSUP ||
(fips_active && !capi_test_vectors[i].fips))
(crypt_fips_mode_kernel() && !capi_test_vectors[i].fips))
printf("[N/A]\n");
else
return EXIT_FAILURE;
@@ -1580,9 +1560,7 @@ int main(__attribute__ ((unused)) int argc, __attribute__ ((unused))char *argv[]
}
#endif
fips_active = fips_mode();
if (crypt_backend_init(fips_active))
if (crypt_backend_init())
exit_test("Crypto backend init error.", EXIT_FAILURE);
printf("Test vectors using %s crypto backend.\n", crypt_backend_version());
@@ -1615,7 +1593,7 @@ int main(__attribute__ ((unused)) int argc, __attribute__ ((unused))char *argv[]
exit_test("Kernel CAPI test failed.", EXIT_FAILURE);
if (default_alg_test()) {
if (fips_mode())
if (crypt_fips_mode())
printf("\nDefault compiled-in algorithms test ignored (FIPS mode on).\n");
else
exit_test("\nDefault compiled-in algorithms test failed.", EXIT_FAILURE);

View File

@@ -33,8 +33,6 @@ else
CRYPTSETUP_LIB_VALGRIND=../.libs
fi
FIPS_MODE=$(cat /proc/sys/crypto/fips_enabled 2>/dev/null)
remove_mapping()
{
[ -b /dev/mapper/$NAME ] && dmsetup remove --retry $NAME
@@ -115,9 +113,9 @@ test_and_prepare_keyring() {
load_key "$HEXKEY_16" user test_key "$TEST_KEYRING" || skip "Kernel keyring service is useless on this system, test skipped."
}
fips_mode()
fips_mode_kernel()
{
[ -n "$FIPS_MODE" ] && [ "$FIPS_MODE" -gt 0 ]
./crypto-check fips_mode_kernel
}
add_device() {
@@ -205,7 +203,7 @@ diff $CHKS_DMCRYPT $CHKS_KEYRING || fail "Plaintext checksums mismatch (corrupti
echo "OK"
#test serpent cipher, cbc mode, tcw IV
fips_mode || {
fips_mode_kernel || {
echo -n "Testing $CIPHER_CBC_TCW..."
dmsetup create $NAME --table "0 $DEVSECTORS crypt $CIPHER_CBC_TCW $HEXKEY_64 0 $DEV 0" || fail
sha256sum /dev/mapper/$NAME > $CHKS_DMCRYPT || fail

View File

@@ -54,8 +54,6 @@ HAVE_KEYRING=0
JSON_MSIZE=16384
IMG_JSON=luks2-digest-1.json
FIPS_MODE=$(cat /proc/sys/crypto/fips_enabled 2>/dev/null)
dm_crypt_features()
{
VER_STR=$(dmsetup targets | grep crypt | cut -f2 -dv)
@@ -163,7 +161,7 @@ skip()
fips_mode()
{
[ -n "$FIPS_MODE" ] && [ "$FIPS_MODE" -gt 0 ]
./crypto-check fips_mode || ./crypto-check fips_mode_kernel
}
add_scsi_device() {

View File

@@ -30,11 +30,10 @@ LUKS1_DECRYPT="LUKS-$LUKS1_DECRYPT_UUID"
MNT_DIR=./mnt_luks
START_DIR=$(pwd)
FIPS_MODE=$(cat /proc/sys/crypto/fips_enabled 2>/dev/null)
fips_mode()
{
[ -n "$FIPS_MODE" ] && [ "$FIPS_MODE" -gt 0 ]
./crypto-check fips_mode || ./crypto-check fips_mode_kernel
}
del_scsi_device()

View File

@@ -9,7 +9,7 @@ MAP=tctst
PASSWORD="aaaaaaaaaaaa"
PASSWORD_HIDDEN="bbbbbbbbbbbb"
PASSWORD_72C="aaaaaaaaaaaabbbbbbbbbbbbccccccccccccddddddddddddeeeeeeeeeeeeffffffffffff"
PIM=1234
PASSWORD_PIM="cccccccccccccccccccc"
LOOP_SYS=""
PART_IMG=tctst-part-img
@@ -77,11 +77,40 @@ test_kdf() # hash img_hash
fi
}
get_HASH_CIPHER() # filename
test_pbkdf() # pbkdf img_hash
{
$CRYPTOCHECK pbkdf $1
if [ $? -ne 0 ] ; then
echo "$1 [N/A]"
IMGS=$(ls $TST_DIR/[tv]c* | grep "$2")
[ -n "$IMGS" ] && rm $IMGS
else
echo "$1 [OK]"
fi
}
get_PARAMS() # filename
{
# speed up the test by limiting options for hash and (first) cipher
HASH=$(echo $file | cut -d'-' -f3)
CIPHER=$(echo $file | cut -d'-' -f5)
if [[ $file =~ vcpim.* ]] ; then
PIM=$(echo $file | sed -r s/.*vcpim_1_\([[:digit:]]+\).*/\\1/)
PIM_OPT="--veracrypt-pim $PIM"
PWD=$PASSWORD_PIM
else
PIM=""
PIM_OPT=""
PWD=$PASSWORD
fi
SYS_OPT=""
if [[ $file =~ sys_.* ]] ; then
SYS_OPT="--tcrypt-system"
else
SYS_OPT=""
fi
}
test_required()
@@ -97,6 +126,8 @@ test_required()
test_kdf whirlpool whirlpool
test_kdf stribog512 stribog
test_pbkdf argon2id argon2id
echo "REQUIRED CIPHERS TEST"
test_one aes cbc 256 cbc-aes
test_one aes lrw 384 lrw-aes
@@ -155,16 +186,12 @@ test_required
echo "HEADER CHECK"
for file in $(ls $TST_DIR/[tv]c_* $TST_DIR/vcpim_* $TST_DIR/sys_[tv]c_*) ; do
echo -n " $file"
PIM_OPT=""
[[ $file =~ vcpim.* ]] && PIM_OPT="--veracrypt-pim $PIM"
SYS_OPT=""
[[ $file =~ sys_.* ]] && SYS_OPT="--tcrypt-system"
get_HASH_CIPHER $file
echo $PASSWORD | $CRYPTSETUP tcryptDump $SYS_OPT $PIM_OPT -h $HASH -c $CIPHER $file >/dev/null || fail
get_PARAMS $file
echo $PWD | $CRYPTSETUP tcryptDump $SYS_OPT $PIM_OPT -h $HASH -c $CIPHER $file >/dev/null || fail
if [[ $file =~ .*-sha512-xts-aes$ ]] ; then
echo $PASSWORD | $CRYPTSETUP tcryptDump $SYS_OPT $PIM_OPT -h sha512 -c aes $file >/dev/null || fail
echo $PASSWORD | $CRYPTSETUP tcryptDump $SYS_OPT $PIM_OPT -h xxxx $file 2>/dev/null && fail
echo $PASSWORD | $CRYPTSETUP tcryptDump $SYS_OPT $PIM_OPT -h sha512 -c xxx $file 2>/dev/null && fail
echo $PWD | $CRYPTSETUP tcryptDump $SYS_OPT $PIM_OPT -h sha512 -c aes $file >/dev/null || fail
echo $PWD | $CRYPTSETUP tcryptDump $SYS_OPT $PIM_OPT -h xxxx $file 2>/dev/null && fail
echo $PWD | $CRYPTSETUP tcryptDump $SYS_OPT $PIM_OPT -h sha512 -c xxx $file 2>/dev/null && fail
fi
echo " [OK]"
done
@@ -172,17 +199,15 @@ done
echo "HEADER CHECK (TCRYPT only)"
for file in $(ls $TST_DIR/vc_* $TST_DIR/vcpim_*) ; do
echo -n " $file"
PIM_OPT=""
[[ $file =~ vcpim.* ]] && PIM_OPT="--veracrypt-pim $PIM"
get_HASH_CIPHER $file
echo $PASSWORD | $CRYPTSETUP tcryptDump --disable-veracrypt $PIM_OPT -h $HASH -c $CIPHER $file >/dev/null 2>&1 && fail
get_PARAMS $file
echo $PWD | $CRYPTSETUP tcryptDump --disable-veracrypt $PIM_OPT -h $HASH -c $CIPHER $file >/dev/null 2>&1 && fail
echo " [OK]"
done
echo "HEADER CHECK (HIDDEN)"
for file in $(ls $TST_DIR/[tv]c_*-hidden) ; do
echo -n " $file (hidden)"
get_HASH_CIPHER $file
get_PARAMS $file
echo $PASSWORD_HIDDEN | $CRYPTSETUP tcryptDump --tcrypt-hidden -h $HASH -c $CIPHER $file >/dev/null || fail
echo " [OK]"
done
@@ -190,10 +215,10 @@ done
echo "HEADER KEYFILES CHECK"
for file in $(ls $TST_DIR/[tv]ck_*) ; do
echo -n " $file"
get_PARAMS $file
PWD=$PASSWORD
[[ $file =~ vck_1_nopw.* ]] && PWD=""
[[ $file =~ vck_1_pw72.* ]] && PWD=$PASSWORD_72C
get_HASH_CIPHER $file
echo $PWD | $CRYPTSETUP tcryptDump -d $TST_DIR/keyfile1 -d $TST_DIR/keyfile2 -h $HASH -c $CIPHER $file >/dev/null || fail
echo " [OK]"
done
@@ -207,10 +232,8 @@ fi
echo "ACTIVATION FS UUID CHECK"
for file in $(ls $TST_DIR/[tv]c_* $TST_DIR/vcpim_*) ; do
echo -n " $file"
PIM_OPT=""
[[ $file =~ vcpim.* ]] && PIM_OPT="--veracrypt-pim $PIM"
get_HASH_CIPHER $file
out=$(echo $PASSWORD | $CRYPTSETUP tcryptOpen $PIM_OPT -r -h $HASH -c $CIPHER $file $MAP 2>&1)
get_PARAMS $file
out=$(echo $PWD | $CRYPTSETUP tcryptOpen $PIM_OPT -r -h $HASH -c $CIPHER $file $MAP 2>&1)
ret=$?
[ $ret -eq 1 ] && ( echo "$out" | grep -q -e "TCRYPT legacy mode" ) && echo " [N/A]" && continue
[ $ret -eq 1 ] && ( echo "$out" | grep -q -e "TCRYPT compatible mapping" ) && echo " [N/A]" && continue
@@ -241,28 +264,28 @@ for file in $(ls $TST_DIR/sys_[tv]c_*) ; do
LOOP_SYS=""
continue
fi
get_HASH_CIPHER $file
get_PARAMS $file
# map through partition name
echo -n " [PART]"
echo $PASSWORD | $CRYPTSETUP tcryptOpen --tcrypt-system -r -h $HASH -c $CIPHER $LOOP_PART $MAP || fail
echo $PWD | $CRYPTSETUP tcryptOpen --tcrypt-system -r -h $HASH -c $CIPHER $LOOP_PART $MAP || fail
check_uuid DEAD-BABE
$CRYPTSETUP close $MAP || fail
if [[ $file =~ _part ]]; then
# map through image only (TCRYPT hdr contains partition offset and size)
echo -n "[IMG]"
echo $PASSWORD | $CRYPTSETUP tcryptOpen --tcrypt-system -r -h $HASH -c $CIPHER $file $MAP 2>/dev/null || fail
echo $PWD | $CRYPTSETUP tcryptOpen --tcrypt-system -r -h $HASH -c $CIPHER $file $MAP 2>/dev/null || fail
check_uuid DEAD-BABE
$CRYPTSETUP close $MAP || fail
# map through full device (TCRYPT hdr contains partition offset and size)
echo -n "[DRIVE]"
echo $PASSWORD | $CRYPTSETUP tcryptOpen --tcrypt-system -r -h $HASH -c $CIPHER $LOOP_SYS $MAP || fail
echo $PWD | $CRYPTSETUP tcryptOpen --tcrypt-system -r -h $HASH -c $CIPHER $LOOP_SYS $MAP || fail
check_uuid DEAD-BABE
$CRYPTSETUP close $MAP || fail
elif [[ $file =~ _full ]]; then
# map through image + header in real partition (whole system)
dd if=$LOOP_PART of=$PART_IMG bs=1M >/dev/null 2>&1
echo -n "[PART+IMG]"
echo $PASSWORD | $CRYPTSETUP tcryptOpen --tcrypt-system -r -h $HASH -c $CIPHER --header $LOOP_PART $PART_IMG $MAP || fail
echo $PWD | $CRYPTSETUP tcryptOpen --tcrypt-system -r -h $HASH -c $CIPHER --header $LOOP_PART $PART_IMG $MAP || fail
check_uuid DEAD-BABE
$CRYPTSETUP close $MAP || fail
rm $PART_IMG
@@ -275,7 +298,7 @@ done
echo "ACTIVATION FS UUID (HIDDEN) CHECK"
for file in $(ls $TST_DIR/[tv]c_*-hidden) ; do
echo -n " $file"
get_HASH_CIPHER $file
get_PARAMS $file
out=$(echo $PASSWORD_HIDDEN | $CRYPTSETUP tcryptOpen -r -h $HASH -c $CIPHER $file $MAP --tcrypt-hidden 2>&1)
ret=$?
[ $ret -eq 1 ] && ( echo "$out" | grep -q -e "TCRYPT legacy mode" ) && echo " [N/A]" && continue

Binary file not shown.

View File

@@ -32,10 +32,10 @@
#ifndef LOOP_CONFIGURE
#define LOOP_CONFIGURE 0x4C0A
struct loop_config {
__u32 fd;
__u32 block_size;
struct loop_info64 info;
__u64 __reserved[8];
__u32 fd;
__u32 block_size;
struct loop_info64 info;
__u64 __reserved[8];
};
#endif
@@ -165,20 +165,12 @@ int t_set_readahead(const char *device, unsigned value)
int fips_mode(void)
{
int fd;
char buf = 0;
return _system("./crypto-check fips_mode", 1) == 0;
}
fd = open("/proc/sys/crypto/fips_enabled", O_RDONLY);
if (fd < 0)
return 0;
if (read(fd, &buf, 1) != 1)
buf = '0';
close(fd);
return (buf == '1');
int fips_mode_kernel(void)
{
return _system("./crypto-check fips_mode_kernel", 1) == 0;
}
/*
@@ -897,7 +889,7 @@ int loop_detach(const char *loop)
loop_fd = open(loop, O_RDONLY);
if (loop_fd < 0)
return 1;
return 1;
if (!ioctl(loop_fd, LOOP_CLR_FD, 0))
r = 0;
@@ -926,32 +918,31 @@ int t_get_devno(const char *name, dev_t *devno)
static int _read_uint64(const char *sysfs_path, uint64_t *value)
{
char tmp[64] = {0};
int fd, r;
char tmp[64] = {0};
int fd, r;
if ((fd = open(sysfs_path, O_RDONLY)) < 0)
return 0;
r = read(fd, tmp, sizeof(tmp));
close(fd);
if ((fd = open(sysfs_path, O_RDONLY)) < 0)
return 0;
r = read(fd, tmp, sizeof(tmp));
close(fd);
if (r <= 0)
return 0;
if (r <= 0)
return 0;
if (sscanf(tmp, "%" PRIu64, value) != 1)
return 0;
if (sscanf(tmp, "%" PRIu64, value) != 1)
return 0;
return 1;
return 1;
}
static int _sysfs_get_uint64(int major, int minor, uint64_t *value, const char *attr)
{
char path[PATH_MAX];
char path[PATH_MAX];
if (snprintf(path, sizeof(path), "/sys/dev/block/%d:%d/%s",
major, minor, attr) < 0)
return 0;
if (snprintf(path, sizeof(path), "/sys/dev/block/%d:%d/%s", major, minor, attr) < 0)
return 0;
return _read_uint64(path, value);
return _read_uint64(path, value);
}
int t_device_size_by_devno(dev_t devno, uint64_t *retval)

View File

@@ -241,6 +241,7 @@ corrupt_device() # $1 device, $2 device_size(in bytes), $3 #{corrupted_bytes}
# $1 data_device, $2 hash_device, $3 fec_device, $4 data/hash_block_size(in bytes),
# $5 data_size(in blocks), $6 device_size(in blocks), $7 hash_offset(in bytes),
# $8 fec_offset(in bytes), $9 fec_roots, ${10} corrupted_bytes, [${11} superblock(y/n), ${12} salt]
# NOTE: do not use fail() in this function, use RET code
check_fec()
{
INDEX=25
@@ -292,18 +293,32 @@ check_fec()
dd if=/dev/mapper/$DEV_NAME of=$IMG_TMP > /dev/null 2>&1
HASH_REPAIRED=$(sha256sum $IMG_TMP | cut -d' ' -f 1)
# If empty, status not supported
REPAIRED=$(dmsetup status $DEV_NAME |sed -e s/.*verity\ \[VC\]\ *//)
if [ -n "$REPAIRED" -a "$REPAIRED" != "-" ] ; then
echo -n "[EC events: $REPAIRED]"
else
REPAIRED=""
fi
$VERITYSETUP close $DEV_NAME
if [ "$HASH_ORIG" != "$HASH_REPAIRED" ]; then
echo -n "[kernel correction failed]"
$VERITYSETUP verify $1 $2 $ROOT_HASH --fec-device=$3 $PARAMS >/dev/null 2>&1 && fail "Userspace verify should fail"
echo -n "[userspace verify failed]"
RET=1
if [ -n "$REPAIRED" ]; then
[ "$REPAIRED" -eq 0 ] || { RET=4; echo "FEC repaired events should be 0."; }
fi
echo -n "[kernel correction failed]"
$VERITYSETUP verify $1 $2 $ROOT_HASH --fec-device=$3 $PARAMS >/dev/null 2>&1 && { RET=5; echo "Userspace verify should fail"; }
echo -n "[userspace verify failed]"
else
echo -n "[repaired in kernel]"
$VERITYSETUP verify $1 $2 $ROOT_HASH --fec-device=$3 $PARAMS >/dev/null 2>&1 || fail "Userspace verify failed"
echo "[userspace verify][OK]"
RET=0
echo -n "[repaired in kernel]"
if [ -n "$REPAIRED" ]; then
[ "$REPAIRED" -gt 0 ] || { RET=4; echo "FEC repaired events should be greater than 0."; }
fi
$VERITYSETUP verify $1 $2 $ROOT_HASH --fec-device=$3 $PARAMS >/dev/null 2>&1 || { RET=5; echo "Userspace verify failed"; }
echo "[userspace verify][OK]"
fi
rm $1 $2 $3 $IMG_TMP > /dev/null 2>&1
return $RET
@@ -531,10 +546,10 @@ if check_version 1 3; then
echo "Veritysetup [FEC tests]"
for INDEX in {1..4}; do
# in the first iteration check if we can use FEC (it can be compiled-out)
(check_fec $IMG $IMG $IMG 4096 30 150 163840 409600 $(($RANDOM % 23 + 2)) $(($INDEX * 4)) )
(check_fec $IMG $IMG $IMG 4096 30 150 163840 409600 $(($RANDOM % 23 + 2)) $(($INDEX * 4)))
RET=$?
[ "$RET" -eq "3" ] && break
[ "$RET" -eq "0" ] || fail "FEC repair failed"
[ "$RET" -eq 3 ] && break
[ "$RET" -eq 0 ] || fail "FEC repair failed"
(check_fec $IMG $IMG $IMG 512 500 50000 2457600 4915200 $(($RANDOM % 23 + 2)) $(($INDEX * 4)) 'n' $SALT) || fail "FEC repair failed"
(check_fec $IMG $IMG $IMG 512 500 50000 2457600 4915200 $(($RANDOM % 23 + 2)) $(($INDEX * 4)) 'y' $SALT) || fail "FEC repair failed"
@@ -546,7 +561,9 @@ if check_version 1 3; then
(check_fec $IMG $IMG_HASH $FEC_DEV 512 2000 2000 0 0 $(($RANDOM % 23 + 2)) $(($INDEX * 4))) || fail "FEC repair failed"
(check_fec $IMG $IMG_HASH $FEC_DEV 1024 2000 2000 0 0 $(($RANDOM % 23 + 2)) $(($INDEX * 4))) || fail "FEC repair failed"
# this test should fail
(check_fec $IMG $IMG_HASH $FEC_DEV 4096 30 30 0 0 $(($RANDOM % 23 + 2)) $(($RANDOM % 200 + 200))) && fail "FEC repair must fail"
(check_fec $IMG $IMG_HASH $FEC_DEV 4096 30 30 0 0 $(($RANDOM % 23 + 2)) $(($RANDOM % 200 + 200)))
RET=$?
[ "$RET" -eq 1 ] || fail "FEC repair must fail"
echo "[OK]"
done
fi