Compare commits

..

59 Commits

Author SHA1 Message Date
Milan Broz
1fae09d607 Update README. 2022-01-13 10:33:46 +01:00
Milan Broz
b1ef7cc3cd Fix reencrypt mangle test for older jq. 2022-01-13 10:12:45 +01:00
Milan Broz
bc2b38991b Version 2.3.7. 2022-01-13 07:08:03 +01:00
Milan Broz
3b35e438bc Add Release Notes 2022-01-13 07:08:03 +01:00
Milan Broz
4c0ae43f3a Update LUKS2 on-disk description. 2022-01-13 07:08:03 +01:00
Ondrej Kozina
d6649293a5 Allow reencryption metadata repair from cryptsetup. 2022-01-13 07:08:03 +01:00
Ondrej Kozina
624f3220a1 Add CRYPT_REENCRYPT_REPAIR_NEEDED flag.
crypt_reencrypt_status() returns this flag if old
online-reencrypt requirement is detected and reencryption
keyslot digest is missing.

crypt_reencrypt_init_by_passphrase() with same flag applied
repairs (upgrade) reencryption metadata so that
automatic reencryption recovery during activation
is again possible and reencryption operation can be resumed
post CVE-2021-4122 fix.
2022-01-13 07:08:03 +01:00
Milan Broz
2e44267891 Add reencryption mangle test 2022-01-13 07:08:03 +01:00
Ondrej Kozina
c75d740f9a Make reencryption flag and keyslot inseparable.
LUKS2 validation code now requires reencrypt keyslot together with
online-reencryption flag or none of those.
2022-01-13 07:08:03 +01:00
Ondrej Kozina
bc26c764c6 Rename LUKS2_keyslot_reencrypt_create function.
The function never writes on-disk. Also removed validation
function call-in since it will be called later before
writing on-disk and metadata does not have to be complete
at the moment of LUKS2_keyslot_reencrypt_allocate call.
2022-01-13 07:08:03 +01:00
Ondrej Kozina
ce8aab39ca Add segments validation for reencryption.
Effective segments during LUKS2 reencryption must
match key characteristics of backup segment
(cipher, sector_size, segment type).
2022-01-13 07:08:03 +01:00
Ondrej Kozina
d0169a303d Split requirements validation from config section validation. 2022-01-13 07:08:03 +01:00
Ondrej Kozina
f83e56e43e Expose json_segment_contains_flag to internal library. 2022-01-13 07:08:03 +01:00
Ondrej Kozina
4e98b65c04 Move requirement helpers for later changes. 2022-01-13 07:08:03 +01:00
Milan Broz
d45e6788e8 Add disable-luks2 reencryption configure option.
The option --disable-luks2-reencryption completely disable
LUKS2 reencryption code.

When used, the libcryptsetup library can read metadata with
reencryption code, but all reencryption API calls and cryptsetup
reencrypt commands are disabled.

Devices with online reencryption in progress cannot be activated.

This option can cause some incompatibilities. Please use with care.
2022-01-13 07:07:37 +01:00
Milan Broz
18cb1eeeb9 Do not run reencryption recovery when not needed. 2022-01-12 20:49:34 +01:00
Milan Broz
7eeb45537a Reenc keyslot must have key_size == 1. 2022-01-12 20:49:34 +01:00
Ondrej Kozina
60addcffa6 Fix CVE-2021-4122 - LUKS2 reencryption crash recovery attack
Fix possible attacks against data confidentiality through LUKS2 online
reencryption extension crash recovery.

An attacker can modify on-disk metadata to simulate decryption in
progress with crashed (unfinished) reencryption step and persistently
decrypt part of the LUKS device.

This attack requires repeated physical access to the LUKS device but
no knowledge of user passphrases.

The decryption step is performed after a valid user activates
the device with a correct passphrase and modified metadata.
There are no visible warnings for the user that such recovery happened
(except using the luksDump command). The attack can also be reversed
afterward (simulating crashed encryption from a plaintext) with
possible modification of revealed plaintext.

The problem was caused by reusing a mechanism designed for actual
reencryption operation without reassessing the security impact for new
encryption and decryption operations. While the reencryption requires
calculating and verifying both key digests, no digest was needed to
initiate decryption recovery if the destination is plaintext (no
encryption key). Also, some metadata (like encryption cipher) is not
protected, and an attacker could change it. Note that LUKS2 protects
visible metadata only when a random change occurs. It does not protect
against intentional modification but such modification must not cause
a violation of data confidentiality.

The fix introduces additional digest protection of reencryption
metadata. The digest is calculated from known keys and critical
reencryption metadata. Now an attacker cannot create correct metadata
digest without knowledge of a passphrase for used keyslots.
For more details, see LUKS2 On-Disk Format Specification version 1.1.0.
2022-01-12 20:49:34 +01:00
Milan Broz
e71c151ebb Rename reenc_keyslot_update to reencrypt_keyslot_update. 2022-01-12 20:49:34 +01:00
Milan Broz
6f2df7cd01 Rename luks2_reenc_context to luks2_reecrypt. 2022-01-12 20:49:34 +01:00
Milan Broz
8a7f590891 Rename crypt_get/set reenc_context to luks2_reencrypt. 2022-01-12 20:49:34 +01:00
Milan Broz
7319be8dad Rename LUKS2_reenc_status to LUKS2_reencrypt_status. 2022-01-12 20:49:34 +01:00
Milan Broz
5b07968c2d Rename LUKS2_reencrypt_status to LUKS2_reencrypt_get_params to avoid confusion. 2022-01-12 20:49:34 +01:00
Milan Broz
dc0ecd4288 Use LUKS2_reencrypt prefix for function defined in luks2.h.
This should clean up prefixes a little bit.
2022-01-12 20:49:34 +01:00
Milan Broz
286784c934 Do not expose json_object in luks2.h.
Later we can use different implementation of JSON parser.
Also define structs in one place.
2022-01-12 20:49:34 +01:00
Milan Broz
4b24e8e052 Remove json_object argument from area size checks.
These functions are internal to LUKS2 implementation.
2022-01-12 20:49:34 +01:00
Milan Broz
3f217dcacf Move LUKS2 internal functions to internal header.
This is the first step to remove json_object from internal API.
2022-01-12 20:48:07 +01:00
Milan Broz
c80fce5f47 Remove obsolete AC_HEADER_STDC macro.
This should be no longer used.
We do not support systems without standard headers anyway.
2022-01-12 18:50:12 +01:00
Milan Broz
3f4ce5d2b0 Update Readme.md. 2021-05-28 12:27:08 +02:00
Milan Broz
f95336e116 Prepare version 2.3.6.
Add Release notes.
2021-05-28 11:57:08 +02:00
Yuri Chornoivan
3753614517 po: update uk.po (from translationproject.org) 2021-05-28 09:59:30 +02:00
Yuri Kozlov
5fd96b75d3 po: update ru.po (from translationproject.org) 2021-05-28 09:59:30 +02:00
Jakub Bogusz
44aac4e5a3 po: update pl.po (from translationproject.org) 2021-05-28 09:59:30 +02:00
Hiroshi Takekawa
fbea879d1e po: update ja.po (from translationproject.org) 2021-05-28 09:59:30 +02:00
Frédéric Marchal
7012d031b6 po: update fr.po (from translationproject.org) 2021-05-28 09:59:30 +02:00
Roland Illig
a7f3065f6f po: update de.po (from translationproject.org) 2021-05-28 09:59:30 +02:00
Petr Pisar
f7fabbe141 po: update cs.po (from translationproject.org) 2021-05-28 09:59:30 +02:00
Klaus Zipfel
ac9a2c08e3 Fixing incorrect offsets for data/IV with TCRYPT system-encryption with a detached header
Related: #587
2021-05-26 09:36:32 +02:00
Milan Broz
bee77b2f35 Add note about --header use in TCRYPT format to man page.
Related: #587
2021-05-24 10:46:29 +02:00
Milan Broz
2d03ba3f4d Do not use Whirlpool hash in tests (some crypto backends do not implement it). 2021-05-23 11:13:44 +02:00
Milan Broz
29e4bca24b Increase interactive expect test timeout if runing under valgrind. 2021-05-22 10:27:00 +02:00
Milan Broz
2f9b22f5ff Update cryptsetup.pot. 2021-05-21 17:42:52 +02:00
Milan Broz
bbb6739d41 Set 2.3.6-rc0 version. 2021-05-21 17:30:40 +02:00
Мирослав Николић
d0c6eeea81 po: update sr.po (from translationproject.org) 2021-05-21 17:29:45 +02:00
Antonio Ceballos
4f982e9708 po: update es.po (from translationproject.org) 2021-05-21 17:29:28 +02:00
Milan Broz
df8135dfdf Check exit value for snprintf where it makes sense. 2021-05-21 14:54:00 +02:00
Milan Broz
280c821b9b Add some fixes and workarounds for gcc-11 static analyzer.
Not everything is a real bug (false positive rate is very high here),
but the code is actually more readable.
2021-05-21 14:44:15 +02:00
Ondrej Kozina
28dd0f5c05 Avoid LUKS2 decryption without detached header.
This is temporary hotfix for stable 2.3.6 release. The full
fix that requires new API will be provided in later 2.4.0
release.

For more info see issue #614.
2021-05-21 14:27:24 +02:00
Milan Broz
c7789719d8 integritysetup: mention maximal allowed key size
The error message and man page should contain this information.
2021-05-19 19:44:56 +02:00
Milan Broz
97e709788e Fix description of maximum passphrase size. 2021-05-19 19:40:59 +02:00
Milan Broz
3dbbc005d3 Add test for longer integritysetup keys. 2021-05-19 19:40:51 +02:00
Milan Broz
e1e3430c2c devmapper: avoid truncation of table features
This patch fixes several problems:
 - some optional features for dm-verity can be larger than pre-allocated buffer
 - device paths and other strings can be allocated dynamically
 - featured options with keys in dm-integrity are not wiped on stack
 - get rid of strncat()
 - always check return code of snprintf

Related #648
2021-05-19 19:35:51 +02:00
Andrii Pravorskyi
b354cdd9ad Add a note about CRC32 and other non-cryptographic checksums 2021-05-19 13:44:28 +02:00
Milan Broz
ed24d033d4 Allow CRYPT_BUSY also a a valid check for active device.
In ideal system nothing should touch test devices, but to make tests
more robust, we should expect that something is still scanning devices
after activation. So replace all checks for CRYPT_ACTIVE to allow
also CRYPT_BUSY.

(Fixes some problems seen in #633)
2021-05-19 13:44:25 +02:00
Milan Broz
5da8f5e710 Fix broken loopaes test.
We actually try to write file in /dev because the device is deactivated.

Broken since 2018 in 8728ba08e2
2021-05-19 13:44:21 +02:00
Milan Broz
800a8a4d5d Fix libintl detection for compiled tests.
Commit 99c4e83994 was incomplete.

See #633.
2021-05-19 13:44:19 +02:00
Milan Broz
0a06947e14 Add Blake2b and Blake2s hash support for crypto backend.
We support most recent crypto algorithms, so this
is only addition of the Blake hash family.

Kernel and gcrypt crypto backend supports all variants,
OpenSSL only Blake2b-512 and Blake2s-256.

There is no useable support for NSS and Nettle yet.

Crypto backend supports kernel notation e.g. "blake2b-512"
that is translated to the library backend names.
2021-05-19 13:44:15 +02:00
Milan Broz
418d068470 Allow to use backup header for tcrypt format.
TrueCrypt/VeraCrypt supports backup header, it seems to have
the same format as normal header.

Let's use --header option here, it can be used to unlock data partition
with header backup (open and dump commands).

Fixes: #587.
2021-05-19 13:43:37 +02:00
Milan Broz
9abe126016 Set devel 2.3.x version. 2021-05-19 13:08:46 +02:00
61 changed files with 7991 additions and 5999 deletions

View File

@@ -44,16 +44,16 @@ Download
--------
All release tarballs and release notes are hosted on [kernel.org](https://www.kernel.org/pub/linux/utils/cryptsetup/).
**The latest stable cryptsetup version is 2.3.5**
* [cryptsetup-2.3.5.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/cryptsetup-2.3.5.tar.xz)
* Signature [cryptsetup-2.3.5.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/cryptsetup-2.3.5.tar.sign)
**The latest stable cryptsetup version is 2.4.3**
* [cryptsetup-2.4.3.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.4/cryptsetup-2.4.3.tar.xz)
* Signature [cryptsetup-2.4.3.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.4/cryptsetup-2.4.3.tar.sign)
_(You need to decompress file first to check signature.)_
* [Cryptsetup 2.3.5 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/v2.3.5-ReleaseNotes).
* [Cryptsetup 2.4.3 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.4/v2.4.3-ReleaseNotes).
Previous versions
* [Version 2.0.6](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.6.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.6.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.6-ReleaseNotes).
* [Version 2.3.7](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/cryptsetup-2.3.7.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/cryptsetup-2.3.7.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/v2.3.7-ReleaseNotes).
* [Version 1.7.5](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.5.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.5.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/v1.7.5-ReleaseNotes).

View File

@@ -1,5 +1,5 @@
AC_PREREQ([2.67])
AC_INIT([cryptsetup],[2.3.5])
AC_INIT([cryptsetup],[2.3.7])
dnl library version from <major>.<minor>.<release>[-<suffix>]
LIBCRYPTSETUP_VERSION=$(echo $PACKAGE_VERSION | cut -f1 -d-)
@@ -57,7 +57,6 @@ dnl ==========================================================================
AC_C_RESTRICT
AC_HEADER_DIRENT
AC_HEADER_STDC
AC_CHECK_HEADERS(fcntl.h malloc.h inttypes.h sys/ioctl.h sys/mman.h \
sys/sysmacros.h sys/statvfs.h ctype.h unistd.h locale.h byteswap.h endian.h stdint.h)
AC_CHECK_DECLS([O_CLOEXEC],,[AC_DEFINE([O_CLOEXEC],[0], [Defined to 0 if not provided])],
@@ -146,6 +145,14 @@ AC_DEFUN([NO_FIPS], [
fi
])
dnl LUKS2 online reencryption
AC_ARG_ENABLE([luks2-reencryption],
AS_HELP_STRING([--disable-luks2-reencryption], [disable LUKS2 online reencryption extension]),
[], [enable_luks2_reencryption=yes])
if test "x$enable_luks2_reencryption" = "xyes"; then
AC_DEFINE(USE_LUKS2_REENCRYPTION, 1, [Use LUKS2 online reencryption extension])
fi
dnl ==========================================================================
dnl pwquality library (cryptsetup CLI only)
AC_ARG_ENABLE([pwquality],
@@ -604,7 +611,8 @@ CS_STR_WITH([loopaes-cipher], [cipher for loop-AES mode], [aes])
CS_NUM_WITH([loopaes-keybits],[key length in bits for loop-AES mode], [256])
CS_NUM_WITH([keyfile-size-maxkb],[maximum keyfile size (in KiB)], [8192])
CS_NUM_WITH([passphrase-size-max],[maximum keyfile size (in characters)], [512])
CS_NUM_WITH([integrity-keyfile-size-maxkb],[maximum integritysetup keyfile size (in KiB)], [4])
CS_NUM_WITH([passphrase-size-max],[maximum passphrase size (in characters)], [512])
CS_STR_WITH([verity-hash], [hash function for verity mode], [sha256])
CS_NUM_WITH([verity-data-block], [data block size for verity mode], [4096])

Binary file not shown.

56
docs/v2.3.6-ReleaseNotes Normal file
View File

@@ -0,0 +1,56 @@
Cryptsetup 2.3.6 Release Notes
==============================
Stable bug-fix release with minor extensions.
All users of cryptsetup 2.x and later should upgrade to this version.
Changes since version 2.3.5
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* integritysetup: Fix possible dm-integrity mapping table truncation.
While integritysetup in standalone mode (no encryption) was not
designed to provide keyed (and cryptographically strong) data
integrity protection, some options can use such algorithms (HMAC).
If a key is used, it is directly sent to the kernel dm-integrity as
a mapping table option (no key derivation is performed).
For HMAC, such a key could be quite long (up to 4096 bytes in
integritysetup CLI).
Unfortunately, due to fixed buffers and not correctly checking string
truncation, some parameter combinations could cause truncation
of the dm-integrity mapping table.
In most cases, the table was rejected by the kernel.
The worst possible case was key truncation for HMAC options
(internal_hash and journal_mac dm-integrity table options).
This release fixes possible truncation and also adds more sanity
checks to reject truncated options.
Also, integritysetup now mentions maximal allowed key size
in --help output.
For old standalone dm-integrity devices where the key length was
truncated, you have to modify (shorten) --integrity-key-size
resp. --journal-integrity-key-size option now.
This bug is _not_ present for dm-crypt/LUKS, LUKS2 (including
integrity protection), or dm-verity devices; it affects only
standalone dm-integrity with HMAC integrity protection.
* cryptsetup: Backup header can be used to activate TCRYPT device.
Use --header option to specify the header.
* cryptsetup: Avoid LUKS2 decryption without detached header.
This feature will be added later and is currently not supported.
* Additional fixes and workarounds for common warnings produced
by some static analysis tools (like gcc-11 analyzer) and additional
code hardening.
* Fix standalone libintl detection for compiled tests.
* Add Blake2b and Blake2s hash support for crypto backends.
Kernel and gcrypt crypto backend support all variants.
OpenSSL supports only Blake2b-512 and Blake2s-256.
Crypto backend supports kernel notation e.g. "blake2b-512".

95
docs/v2.3.7-ReleaseNotes Normal file
View File

@@ -0,0 +1,95 @@
Cryptsetup 2.3.7 Release Notes
==============================
Stable security bug-fix release that fixes CVE-2021-4122.
All users of cryptsetup 2.3.x must upgrade to this version.
Changes since version 2.3.6
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Fix possible attacks against data confidentiality through LUKS2 online
reencryption extension crash recovery (CVE-2021-4122).
An attacker can modify on-disk metadata to simulate decryption in
progress with crashed (unfinished) reencryption step and persistently
decrypt part of the LUKS device.
This attack requires repeated physical access to the LUKS device but
no knowledge of user passphrases.
The decryption step is performed after a valid user activates
the device with a correct passphrase and modified metadata.
There are no visible warnings for the user that such recovery happened
(except using the luksDump command). The attack can also be reversed
afterward (simulating crashed encryption from a plaintext) with
possible modification of revealed plaintext.
The size of possible decrypted data depends on configured LUKS2 header
size (metadata size is configurable for LUKS2).
With the default parameters (16 MiB LUKS2 header) and only one
allocated keyslot (512 bit key for AES-XTS), simulated decryption with
checksum resilience SHA1 (20 bytes checksum for 4096-byte blocks),
the maximal decrypted size can be over 3GiB.
The attack is not applicable to LUKS1 format, but the attacker can
update metadata in place to LUKS2 format as an additional step.
For such a converted LUKS2 header, the keyslot area is limited to
decrypted size (with SHA1 checksums) over 300 MiB.
The issue is present in all cryptsetup releases since 2.2.0.
Versions 1.x, 2.0.x, and 2.1.x are not affected, as these do not
contain LUKS2 reencryption extension.
The problem was caused by reusing a mechanism designed for actual
reencryption operation without reassessing the security impact for new
encryption and decryption operations. While the reencryption requires
calculating and verifying both key digests, no digest was needed to
initiate decryption recovery if the destination is plaintext (no
encryption key). Also, some metadata (like encryption cipher) is not
protected, and an attacker could change it. Note that LUKS2 protects
visible metadata only when a random change occurs. It does not protect
against intentional modification but such modification must not cause
a violation of data confidentiality.
The fix introduces additional digest protection of reencryption
metadata. The digest is calculated from known keys and critical
reencryption metadata. Now an attacker cannot create correct metadata
digest without knowledge of a passphrase for used keyslots.
For more details, see LUKS2 On-Disk Format Specification version 1.1.0.
The former reencryption operation (without the additional digest) is no
longer supported (reencryption with the digest is not backward
compatible). You need to finish in-progress reencryption before
updating to new packages. The alternative approach is to perform
a repair command from the updated package to recalculate reencryption
digest and fix metadata.
The reencryption repair operation always require a user passphrase.
WARNING: Devices with older reencryption in progress can be no longer
activated without performing the action mentioned above.
Encryption in progress can be detected by running the luksDump command
(output includes reencrypt keyslot with reencryption parameters). Also,
during the active reencryption, no keyslot operations are available
(change of passphrases, etc.).
The issue was found by Milan Broz as cryptsetup maintainer.
Other changes
~~~~~~~~~~~~~
* Add configure option --disable-luks2-reencryption to completely disable
LUKS2 reencryption code.
When used, the libcryptsetup library can read metadata with
reencryption code, but all reencryption API calls and cryptsetup
reencrypt commands are disabled.
Devices with online reencryption in progress cannot be activated.
This option can cause some incompatibilities. Please use with care.
* Improve internal metadata validation code for reencryption metadata.
* Add updated documentation for LUKS2 On-Disk Format Specification
version 1.1.0 (with reencryption extension description and updated
metadata description). See docs/on-disk-format-luks2.pdf or online
version in https://gitlab.com/cryptsetup/LUKS2-docs repository.

View File

@@ -104,6 +104,7 @@ libcryptsetup_la_SOURCES = \
lib/luks2/luks2_keyslot_luks2.c \
lib/luks2/luks2_keyslot_reenc.c \
lib/luks2/luks2_reencrypt.c \
lib/luks2/luks2_reencrypt_digest.c \
lib/luks2/luks2_segment.c \
lib/luks2/luks2_token_keyring.c \
lib/luks2/luks2_token.c \

View File

@@ -450,6 +450,8 @@ const char *argon2_error_message(int error_code) {
size_t argon2_encodedlen(uint32_t t_cost, uint32_t m_cost, uint32_t parallelism,
uint32_t saltlen, uint32_t hashlen, argon2_type type) {
if (!argon2_type2string(type, 0))
return 0;
return strlen("$$v=$m=,t=,p=$$") + strlen(argon2_type2string(type, 0)) +
numlen(t_cost) + numlen(m_cost) + numlen(parallelism) +
b64len(saltlen) + b64len(hashlen) + numlen(ARGON2_VERSION_NUMBER) + 1;

View File

@@ -96,11 +96,14 @@ int crypt_cipher_init_kernel(struct crypt_cipher_kernel *ctx, const char *name,
.salg_family = AF_ALG,
.salg_type = "skcipher",
};
int r;
if (!strcmp(name, "cipher_null"))
key_length = 0;
snprintf((char *)sa.salg_name, sizeof(sa.salg_name), "%s(%s)", mode, name);
r = snprintf((char *)sa.salg_name, sizeof(sa.salg_name), "%s(%s)", mode, name);
if (r < 0 || (size_t)r >= sizeof(sa.salg_name))
return -EINVAL;
return _crypt_cipher_init(ctx, key, key_length, 0, &sa);
}
@@ -230,7 +233,10 @@ int crypt_cipher_check_kernel(const char *name, const char *mode,
}
salg_type = aead ? "aead" : "skcipher";
snprintf((char *)sa.salg_type, sizeof(sa.salg_type), "%s", salg_type);
r = snprintf((char *)sa.salg_type, sizeof(sa.salg_type), "%s", salg_type);
if (r < 0 || (size_t)r >= sizeof(sa.salg_name))
return -EINVAL;
memset(tmp_salg_name, 0, sizeof(tmp_salg_name));
/* FIXME: this is duplicating a part of devmapper backend */
@@ -243,7 +249,7 @@ int crypt_cipher_check_kernel(const char *name, const char *mode,
else
r = snprintf(tmp_salg_name, sizeof(tmp_salg_name), "%s(%s)", real_mode, name);
if (r <= 0 || r > (int)(sizeof(sa.salg_name) - 1))
if (r < 0 || (size_t)r >= sizeof(tmp_salg_name))
return -EINVAL;
memcpy(sa.salg_name, tmp_salg_name, sizeof(sa.salg_name));

View File

@@ -51,6 +51,11 @@ struct crypt_cipher {
} u;
};
struct hash_alg {
const char *name;
const char *gcrypt_name;
};
/*
* Test for wrong Whirlpool variant,
* Ref: https://lists.gnupg.org/pipermail/gcrypt-devel/2014-January/002889.html
@@ -91,6 +96,8 @@ static void crypt_hash_test_whirlpool_bug(void)
int crypt_backend_init(void)
{
int r;
if (crypto_backend_initialised)
return 0;
@@ -120,11 +127,12 @@ int crypt_backend_init(void)
crypto_backend_initialised = 1;
crypt_hash_test_whirlpool_bug();
snprintf(version, 64, "gcrypt %s%s%s",
r = snprintf(version, sizeof(version), "gcrypt %s%s%s",
gcry_check_version(NULL),
crypto_backend_secmem ? "" : ", secmem disabled",
crypto_backend_whirlpool_bug > 0 ? ", flawed whirlpool" : ""
);
crypto_backend_whirlpool_bug > 0 ? ", flawed whirlpool" : "");
if (r < 0 || (size_t)r >= sizeof(version))
return -EINVAL;
return 0;
}
@@ -150,10 +158,24 @@ uint32_t crypt_backend_flags(void)
static const char *crypt_hash_compat_name(const char *name, unsigned int *flags)
{
const char *hash_name = name;
int i;
static struct hash_alg hash_algs[] = {
{ "blake2b-160", "blake2b_160" },
{ "blake2b-256", "blake2b_256" },
{ "blake2b-384", "blake2b_384" },
{ "blake2b-512", "blake2b_512" },
{ "blake2s-128", "blake2s_128" },
{ "blake2s-160", "blake2s_160" },
{ "blake2s-224", "blake2s_224" },
{ "blake2s-256", "blake2s_256" },
{ NULL, NULL, }};
if (!name)
return NULL;
/* "whirlpool_gcryptbug" is out shortcut to flawed whirlpool
* in libgcrypt < 1.6.0 */
if (name && !strcasecmp(name, "whirlpool_gcryptbug")) {
if (!strcasecmp(name, "whirlpool_gcryptbug")) {
#if GCRYPT_VERSION_NUMBER >= 0x010601
if (flags)
*flags |= GCRY_MD_FLAG_BUGEMU1;
@@ -161,6 +183,15 @@ static const char *crypt_hash_compat_name(const char *name, unsigned int *flags)
hash_name = "whirlpool";
}
i = 0;
while (hash_algs[i].name) {
if (!strcasecmp(name, hash_algs[i].name)) {
hash_name = hash_algs[i].gcrypt_name;
break;
}
i++;
}
return hash_name;
}

View File

@@ -62,6 +62,14 @@ static struct hash_alg hash_algs[] = {
{ "stribog256","streebog256", 32, 64 },
{ "stribog512","streebog512", 64, 64 },
{ "sm3", "sm3", 32, 64 },
{ "blake2b-160","blake2b-160",20, 128 },
{ "blake2b-256","blake2b-256",32, 128 },
{ "blake2b-384","blake2b-384",48, 128 },
{ "blake2b-512","blake2b-512",64, 128 },
{ "blake2s-128","blake2s-128",16, 64 },
{ "blake2s-160","blake2s-160",20, 64 },
{ "blake2s-224","blake2s-224",28, 64 },
{ "blake2s-256","blake2s-256",32, 64 },
{ NULL, NULL, 0, 0 }
};
@@ -118,7 +126,7 @@ int crypt_backend_init(void)
.salg_type = "hash",
.salg_name = "sha256",
};
int tfmfd = -1, opfd = -1;
int r, tfmfd = -1, opfd = -1;
if (crypto_backend_initialised)
return 0;
@@ -126,15 +134,17 @@ int crypt_backend_init(void)
if (uname(&uts) == -1 || strcmp(uts.sysname, "Linux"))
return -EINVAL;
r = snprintf(version, sizeof(version), "%s %s kernel cryptoAPI",
uts.sysname, uts.release);
if (r < 0 || (size_t)r >= sizeof(version))
return -EINVAL;
if (crypt_kernel_socket_init(&sa, &tfmfd, &opfd, NULL, 0) < 0)
return -EINVAL;
close(tfmfd);
close(opfd);
snprintf(version, sizeof(version), "%s %s kernel cryptoAPI",
uts.sysname, uts.release);
crypto_backend_initialised = 1;
return 0;
}
@@ -255,6 +265,7 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
.salg_family = AF_ALG,
.salg_type = "hash",
};
int r;
h = malloc(sizeof(*h));
if (!h)
@@ -267,8 +278,12 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
}
h->hash_len = ha->length;
snprintf((char *)sa.salg_name, sizeof(sa.salg_name),
r = snprintf((char *)sa.salg_name, sizeof(sa.salg_name),
"hmac(%s)", ha->kernel_name);
if (r < 0 || (size_t)r >= sizeof(sa.salg_name)) {
free(h);
return -EINVAL;
}
if (crypt_kernel_socket_init(&sa, &h->tfmfd, &h->opfd, key, key_length) < 0) {
free(h);

View File

@@ -77,6 +77,8 @@ static struct hash_alg *_get_alg(const char *name)
int crypt_backend_init(void)
{
int r;
if (crypto_backend_initialised)
return 0;
@@ -84,10 +86,13 @@ int crypt_backend_init(void)
return -EINVAL;
#if HAVE_DECL_NSS_GETVERSION
snprintf(version, 64, "NSS %s", NSS_GetVersion());
r = snprintf(version, sizeof(version), "NSS %s", NSS_GetVersion());
#else
snprintf(version, 64, "NSS");
r = snprintf(version, sizeof(version), "NSS");
#endif
if (r < 0 || (size_t)r >= sizeof(version))
return -EINVAL;
crypto_backend_initialised = 1;
return 0;
}

View File

@@ -63,6 +63,11 @@ struct crypt_cipher {
} u;
};
struct hash_alg {
const char *name;
const char *openssl_name;
};
/*
* Compatible wrappers for OpenSSL < 1.1.0 and LibreSSL < 2.7.0
*/
@@ -147,11 +152,36 @@ const char *crypt_backend_version(void)
return openssl_backend_version();
}
static const char *crypt_hash_compat_name(const char *name)
{
const char *hash_name = name;
int i;
static struct hash_alg hash_algs[] = {
{ "blake2b-512", "blake2b512" },
{ "blake2s-256", "blake2s256" },
{ NULL, NULL, }};
if (!name)
return NULL;
i = 0;
while (hash_algs[i].name) {
if (!strcasecmp(name, hash_algs[i].name)) {
hash_name = hash_algs[i].openssl_name;
break;
}
i++;
}
return hash_name;
}
/* HASH */
int crypt_hash_size(const char *name)
{
const EVP_MD *hash_id = EVP_get_digestbyname(name);
const EVP_MD *hash_id;
hash_id = EVP_get_digestbyname(crypt_hash_compat_name(name));
if (!hash_id)
return -EINVAL;
@@ -172,7 +202,7 @@ int crypt_hash_init(struct crypt_hash **ctx, const char *name)
return -ENOMEM;
}
h->hash_id = EVP_get_digestbyname(name);
h->hash_id = EVP_get_digestbyname(crypt_hash_compat_name(name));
if (!h->hash_id) {
EVP_MD_CTX_free(h->md);
free(h);
@@ -257,7 +287,7 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
return -ENOMEM;
}
h->hash_id = EVP_get_digestbyname(name);
h->hash_id = EVP_get_digestbyname(crypt_hash_compat_name(name));
if (!h->hash_id) {
HMAC_CTX_free(h->md);
free(h);
@@ -333,7 +363,7 @@ int crypt_pbkdf(const char *kdf, const char *hash,
return -EINVAL;
if (!strcmp(kdf, "pbkdf2")) {
hash_id = EVP_get_digestbyname(hash);
hash_id = EVP_get_digestbyname(crypt_hash_compat_name(hash));
if (!hash_id)
return -EINVAL;
@@ -372,7 +402,7 @@ static int _cipher_init(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec, const
key_bits /= 2;
r = snprintf(cipher_name, sizeof(cipher_name), "%s-%d-%s", name, key_bits, mode);
if (r < 0 || r >= (int)sizeof(cipher_name))
if (r < 0 || (size_t)r >= sizeof(cipher_name))
return -EINVAL;
type = EVP_get_cipherbyname(cipher_name);

View File

@@ -330,7 +330,9 @@ int INTEGRITY_format(struct crypt_device *cd,
uuid_generate(tmp_uuid_bin);
uuid_unparse(tmp_uuid_bin, tmp_uuid);
snprintf(tmp_name, sizeof(tmp_name), "temporary-cryptsetup-%s", tmp_uuid);
r = snprintf(tmp_name, sizeof(tmp_name), "temporary-cryptsetup-%s", tmp_uuid);
if (r < 0 || (size_t)r >= sizeof(tmp_name))
return -EINVAL;
/* There is no data area, we can actually use fake zeroed key */
if (params && params->integrity_key_size)

View File

@@ -83,7 +83,7 @@
#endif
struct crypt_device;
struct luks2_reenc_context;
struct luks2_reencrypt;
struct volume_key {
int id;
@@ -222,8 +222,8 @@ int PLAIN_activate(struct crypt_device *cd,
uint32_t flags);
void *crypt_get_hdr(struct crypt_device *cd, const char *type);
void crypt_set_reenc_context(struct crypt_device *cd, struct luks2_reenc_context *rh);
struct luks2_reenc_context *crypt_get_reenc_context(struct crypt_device *cd);
void crypt_set_luks2_reencrypt(struct crypt_device *cd, struct luks2_reencrypt *rh);
struct luks2_reencrypt *crypt_get_luks2_reencrypt(struct crypt_device *cd);
int onlyLUKS2(struct crypt_device *cd);
int onlyLUKS2mask(struct crypt_device *cd, uint32_t mask);

View File

@@ -2204,6 +2204,8 @@ int crypt_activate_by_token(struct crypt_device *cd,
#define CRYPT_REENCRYPT_RESUME_ONLY (1 << 2)
/** Run reencryption recovery only. (in) */
#define CRYPT_REENCRYPT_RECOVERY (1 << 3)
/** Reencryption requires metadata protection. (in/out) */
#define CRYPT_REENCRYPT_REPAIR_NEEDED (1 << 4)
/**
* Reencryption direction

View File

@@ -33,7 +33,7 @@
#ifdef HAVE_SYS_SYSMACROS_H
# include <sys/sysmacros.h> /* for major, minor */
#endif
#include <assert.h>
#include "internal.h"
#define DM_UUID_LEN 129
@@ -590,9 +590,14 @@ static int cipher_dm2c(char **org_c, char **org_i, const char *c_dm, const char
i = sscanf(capi, "%" CLENS "[^(](%" CLENS "[^)])", mode, cipher);
if (i == 2)
snprintf(dmcrypt_tmp, sizeof(dmcrypt_tmp), "%s-%s-%s", cipher, mode, iv);
i = snprintf(dmcrypt_tmp, sizeof(dmcrypt_tmp), "%s-%s-%s", cipher, mode, iv);
else
snprintf(dmcrypt_tmp, sizeof(dmcrypt_tmp), "%s-%s", capi, iv);
i = snprintf(dmcrypt_tmp, sizeof(dmcrypt_tmp), "%s-%s", capi, iv);
if (i < 0 || (size_t)i >= sizeof(dmcrypt_tmp)) {
free(*org_i);
*org_i = NULL;
return -EINVAL;
}
if (!(*org_c = strdup(dmcrypt_tmp))) {
free(*org_i);
@@ -603,11 +608,18 @@ static int cipher_dm2c(char **org_c, char **org_i, const char *c_dm, const char
return 0;
}
static char *_uf(char *buf, size_t buf_size, const char *s, unsigned u)
{
size_t r = snprintf(buf, buf_size, " %s:%u", s, u);
assert(r > 0 && r < buf_size);
return buf;
}
/* https://gitlab.com/cryptsetup/cryptsetup/wikis/DMCrypt */
static char *get_dm_crypt_params(const struct dm_target *tgt, uint32_t flags)
{
int r, max_size, null_cipher = 0, num_options = 0, keystr_len = 0;
char *params, *hexkey;
char *params = NULL, *hexkey = NULL;
char sector_feature[32], features[512], integrity_dm[256], cipher_dm[256];
if (!tgt)
@@ -632,22 +644,22 @@ static char *get_dm_crypt_params(const struct dm_target *tgt, uint32_t flags)
num_options++;
if (tgt->u.crypt.integrity)
num_options++;
if (tgt->u.crypt.sector_size != SECTOR_SIZE) {
if (tgt->u.crypt.sector_size != SECTOR_SIZE)
num_options++;
snprintf(sector_feature, sizeof(sector_feature), " sector_size:%u", tgt->u.crypt.sector_size);
} else
*sector_feature = '\0';
if (num_options) {
snprintf(features, sizeof(features)-1, " %d%s%s%s%s%s%s%s%s", num_options,
if (num_options) { /* MAX length int32 + 15 + 15 + 23 + 18 + 19 + 17 + 13 + int32 + integrity_str */
r = snprintf(features, sizeof(features), " %d%s%s%s%s%s%s%s%s", num_options,
(flags & CRYPT_ACTIVATE_ALLOW_DISCARDS) ? " allow_discards" : "",
(flags & CRYPT_ACTIVATE_SAME_CPU_CRYPT) ? " same_cpu_crypt" : "",
(flags & CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS) ? " submit_from_crypt_cpus" : "",
(flags & CRYPT_ACTIVATE_NO_READ_WORKQUEUE) ? " no_read_workqueue" : "",
(flags & CRYPT_ACTIVATE_NO_WRITE_WORKQUEUE) ? " no_write_workqueue" : "",
(flags & CRYPT_ACTIVATE_IV_LARGE_SECTORS) ? " iv_large_sectors" : "",
sector_feature, integrity_dm);
(tgt->u.crypt.sector_size != SECTOR_SIZE) ?
_uf(sector_feature, sizeof(sector_feature), "sector_size", tgt->u.crypt.sector_size) : "",
integrity_dm);
if (r < 0 || (size_t)r >= sizeof(features))
goto out;
} else
*features = '\0';
@@ -663,16 +675,14 @@ static char *get_dm_crypt_params(const struct dm_target *tgt, uint32_t flags)
hexkey = crypt_safe_alloc(tgt->u.crypt.vk->keylength * 2 + 1);
if (!hexkey)
return NULL;
goto out;
if (null_cipher)
strncpy(hexkey, "-", 2);
else if (flags & CRYPT_ACTIVATE_KEYRING_KEY) {
r = snprintf(hexkey, keystr_len, ":%zu:logon:%s", tgt->u.crypt.vk->keylength, tgt->u.crypt.vk->key_description);
if (r < 0 || r >= keystr_len) {
params = NULL;
if (r < 0 || r >= keystr_len)
goto out;
}
} else
hex_key(hexkey, tgt->u.crypt.vk->keylength, tgt->u.crypt.vk->key);
@@ -699,10 +709,10 @@ out:
/* https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity */
static char *get_dm_verity_params(const struct dm_target *tgt, uint32_t flags)
{
int max_size, r, num_options = 0;
int max_size, max_fec_size, max_verify_size, r, num_options = 0;
struct crypt_params_verity *vp;
char *params = NULL, *hexroot = NULL, *hexsalt = NULL;
char features[256], fec_features[256], verity_verify_args[512+32];
char features[256], *fec_features = NULL, *verity_verify_args = NULL;
if (!tgt || !tgt->u.verity.vp)
return NULL;
@@ -728,30 +738,45 @@ static char *get_dm_verity_params(const struct dm_target *tgt, uint32_t flags)
if (flags & CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE)
num_options++;
if (tgt->u.verity.fec_device) {
max_fec_size = (tgt->u.verity.fec_device ? strlen(device_block_path(tgt->u.verity.fec_device)) : 0) + 256;
fec_features = crypt_safe_alloc(max_fec_size);
if (!fec_features)
goto out;
if (tgt->u.verity.fec_device) { /* MAX length 21 + path + 11 + int64 + 12 + int64 + 11 + int32 */
num_options += 8;
snprintf(fec_features, sizeof(fec_features)-1,
r = snprintf(fec_features, max_fec_size,
" use_fec_from_device %s fec_start %" PRIu64 " fec_blocks %" PRIu64 " fec_roots %" PRIu32,
device_block_path(tgt->u.verity.fec_device), tgt->u.verity.fec_offset,
tgt->u.verity.fec_blocks, vp->fec_roots);
if (r < 0 || r >= max_fec_size)
goto out;
} else
*fec_features = '\0';
if (tgt->u.verity.root_hash_sig_key_desc) {
max_verify_size = (tgt->u.verity.root_hash_sig_key_desc ? strlen(tgt->u.verity.root_hash_sig_key_desc) : 0) + 32;
verity_verify_args = crypt_safe_alloc(max_verify_size);
if (!verity_verify_args)
goto out;
if (tgt->u.verity.root_hash_sig_key_desc) { /* MAX length 24 + key_str */
num_options += 2;
snprintf(verity_verify_args, sizeof(verity_verify_args)-1,
r = snprintf(verity_verify_args, max_verify_size,
" root_hash_sig_key_desc %s", tgt->u.verity.root_hash_sig_key_desc);
if (r < 0 || r >= max_verify_size)
goto out;
} else
*verity_verify_args = '\0';
if (num_options)
snprintf(features, sizeof(features)-1, " %d%s%s%s%s%s", num_options,
if (num_options) { /* MAX length int32 + 18 + 22 + 20 + 19 + 19 */
r = snprintf(features, sizeof(features), " %d%s%s%s%s%s", num_options,
(flags & CRYPT_ACTIVATE_IGNORE_CORRUPTION) ? " ignore_corruption" : "",
(flags & CRYPT_ACTIVATE_RESTART_ON_CORRUPTION) ? " restart_on_corruption" : "",
(flags & CRYPT_ACTIVATE_PANIC_ON_CORRUPTION) ? " panic_on_corruption" : "",
(flags & CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS) ? " ignore_zero_blocks" : "",
(flags & CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE) ? " check_at_most_once" : "");
else
if (r < 0 || (size_t)r >= sizeof(features))
goto out;
} else
*features = '\0';
hexroot = crypt_safe_alloc(tgt->u.verity.root_hash_size * 2 + 1);
@@ -785,12 +810,13 @@ static char *get_dm_verity_params(const struct dm_target *tgt, uint32_t flags)
vp->data_size, tgt->u.verity.hash_offset,
vp->hash_name, hexroot, hexsalt, features, fec_features,
verity_verify_args);
if (r < 0 || r >= max_size) {
crypt_safe_free(params);
params = NULL;
}
out:
crypt_safe_free(fec_features);
crypt_safe_free(verity_verify_args);
crypt_safe_free(hexroot);
crypt_safe_free(hexsalt);
return params;
@@ -798,162 +824,143 @@ out:
static char *get_dm_integrity_params(const struct dm_target *tgt, uint32_t flags)
{
int r, max_size, num_options = 0;
char *params, *hexkey, mode;
char features[512], feature[256];
int r, max_size, max_integrity, max_journal_integrity, max_journal_crypt, num_options = 0;
char *params_out = NULL, *params, *hexkey, mode, feature[6][32];
char *features, *integrity, *journal_integrity, *journal_crypt;
if (!tgt)
return NULL;
max_integrity = (tgt->u.integrity.integrity && tgt->u.integrity.vk ? tgt->u.integrity.vk->keylength * 2 : 0) +
(tgt->u.integrity.integrity ? strlen(tgt->u.integrity.integrity) : 0) + 32;
max_journal_integrity = (tgt->u.integrity.journal_integrity && tgt->u.integrity.journal_integrity_key ?
tgt->u.integrity.journal_integrity_key->keylength * 2 : 0) +
(tgt->u.integrity.journal_integrity ? strlen(tgt->u.integrity.journal_integrity) : 0) + 32;
max_journal_crypt = (tgt->u.integrity.journal_crypt && tgt->u.integrity.journal_crypt_key ?
tgt->u.integrity.journal_crypt_key->keylength * 2 : 0) +
(tgt->u.integrity.journal_crypt ? strlen(tgt->u.integrity.journal_crypt) : 0) + 32;
max_size = strlen(device_block_path(tgt->data_device)) +
(tgt->u.integrity.meta_device ? strlen(device_block_path(tgt->u.integrity.meta_device)) : 0) +
(tgt->u.integrity.vk ? tgt->u.integrity.vk->keylength * 2 : 0) +
(tgt->u.integrity.journal_integrity_key ? tgt->u.integrity.journal_integrity_key->keylength * 2 : 0) +
(tgt->u.integrity.journal_crypt_key ? tgt->u.integrity.journal_crypt_key->keylength * 2 : 0) +
(tgt->u.integrity.integrity ? strlen(tgt->u.integrity.integrity) : 0) +
(tgt->u.integrity.journal_integrity ? strlen(tgt->u.integrity.journal_integrity) : 0) +
(tgt->u.integrity.journal_crypt ? strlen(tgt->u.integrity.journal_crypt) : 0) + 128;
(tgt->u.integrity.meta_device ? strlen(device_block_path(tgt->u.integrity.meta_device)) : 0) +
max_integrity + max_journal_integrity + max_journal_crypt + 512;
params = crypt_safe_alloc(max_size);
if (!params)
return NULL;
features = crypt_safe_alloc(max_size);
integrity = crypt_safe_alloc(max_integrity);
journal_integrity = crypt_safe_alloc(max_journal_integrity);
journal_crypt = crypt_safe_alloc(max_journal_crypt);
if (!params || !features || !integrity || !journal_integrity || !journal_crypt)
goto out;
*features = '\0';
if (tgt->u.integrity.journal_size) {
num_options++;
snprintf(feature, sizeof(feature), "journal_sectors:%u ",
(unsigned)(tgt->u.integrity.journal_size / SECTOR_SIZE));
strncat(features, feature, sizeof(features) - strlen(features) - 1);
}
if (tgt->u.integrity.journal_watermark) {
num_options++;
snprintf(feature, sizeof(feature),
/* bitmap overloaded values */
(flags & CRYPT_ACTIVATE_NO_JOURNAL_BITMAP) ? "sectors_per_bit:%u " : "journal_watermark:%u ",
tgt->u.integrity.journal_watermark);
strncat(features, feature, sizeof(features) - strlen(features) - 1);
}
if (tgt->u.integrity.journal_commit_time) {
num_options++;
snprintf(feature, sizeof(feature),
/* bitmap overloaded values */
(flags & CRYPT_ACTIVATE_NO_JOURNAL_BITMAP) ? "bitmap_flush_interval:%u " : "commit_time:%u ",
tgt->u.integrity.journal_commit_time);
strncat(features, feature, sizeof(features) - strlen(features) - 1);
}
if (tgt->u.integrity.interleave_sectors) {
num_options++;
snprintf(feature, sizeof(feature), "interleave_sectors:%u ",
tgt->u.integrity.interleave_sectors);
strncat(features, feature, sizeof(features) - strlen(features) - 1);
}
if (tgt->u.integrity.sector_size) {
num_options++;
snprintf(feature, sizeof(feature), "block_size:%u ",
tgt->u.integrity.sector_size);
strncat(features, feature, sizeof(features) - strlen(features) - 1);
}
if (tgt->u.integrity.buffer_sectors) {
num_options++;
snprintf(feature, sizeof(feature), "buffer_sectors:%u ",
tgt->u.integrity.buffer_sectors);
strncat(features, feature, sizeof(features) - strlen(features) - 1);
}
if (tgt->u.integrity.integrity) {
if (tgt->u.integrity.integrity) { /* MAX length 16 + str_integrity + str_key */
num_options++;
if (tgt->u.integrity.vk) {
hexkey = crypt_safe_alloc(tgt->u.integrity.vk->keylength * 2 + 1);
if (!hexkey) {
crypt_safe_free(params);
return NULL;
}
if (!hexkey)
goto out;
hex_key(hexkey, tgt->u.integrity.vk->keylength, tgt->u.integrity.vk->key);
} else
hexkey = NULL;
snprintf(feature, sizeof(feature), "internal_hash:%s%s%s ",
r = snprintf(integrity, max_integrity, " internal_hash:%s%s%s",
tgt->u.integrity.integrity, hexkey ? ":" : "", hexkey ?: "");
strncat(features, feature, sizeof(features) - strlen(features) - 1);
crypt_safe_free(hexkey);
if (r < 0 || r >= max_integrity)
goto out;
}
if (tgt->u.integrity.journal_integrity) {
if (tgt->u.integrity.journal_integrity) { /* MAX length 14 + str_journal_integrity + str_key */
num_options++;
if (tgt->u.integrity.journal_integrity_key) {
hexkey = crypt_safe_alloc(tgt->u.integrity.journal_integrity_key->keylength * 2 + 1);
if (!hexkey) {
crypt_safe_free(params);
return NULL;
}
if (!hexkey)
goto out;
hex_key(hexkey, tgt->u.integrity.journal_integrity_key->keylength,
tgt->u.integrity.journal_integrity_key->key);
} else
hexkey = NULL;
snprintf(feature, sizeof(feature), "journal_mac:%s%s%s ",
r = snprintf(journal_integrity, max_journal_integrity, " journal_mac:%s%s%s",
tgt->u.integrity.journal_integrity, hexkey ? ":" : "", hexkey ?: "");
strncat(features, feature, sizeof(features) - strlen(features) - 1);
crypt_safe_free(hexkey);
if (r < 0 || r >= max_journal_integrity)
goto out;
}
if (tgt->u.integrity.journal_crypt) {
if (tgt->u.integrity.journal_crypt) { /* MAX length 15 + str_journal_crypt + str_key */
num_options++;
if (tgt->u.integrity.journal_crypt_key) {
hexkey = crypt_safe_alloc(tgt->u.integrity.journal_crypt_key->keylength * 2 + 1);
if (!hexkey) {
crypt_safe_free(params);
return NULL;
}
if (!hexkey)
goto out;
hex_key(hexkey, tgt->u.integrity.journal_crypt_key->keylength,
tgt->u.integrity.journal_crypt_key->key);
} else
hexkey = NULL;
snprintf(feature, sizeof(feature), "journal_crypt:%s%s%s ",
r = snprintf(journal_crypt, max_journal_crypt, " journal_crypt:%s%s%s",
tgt->u.integrity.journal_crypt, hexkey ? ":" : "", hexkey ?: "");
strncat(features, feature, sizeof(features) - strlen(features) - 1);
crypt_safe_free(hexkey);
if (r < 0 || r >= max_journal_crypt)
goto out;
}
if (tgt->u.integrity.fix_padding) {
if (tgt->u.integrity.journal_size)
num_options++;
if (tgt->u.integrity.journal_watermark)
num_options++;
if (tgt->u.integrity.journal_commit_time)
num_options++;
if (tgt->u.integrity.interleave_sectors)
num_options++;
if (tgt->u.integrity.sector_size)
num_options++;
if (tgt->u.integrity.buffer_sectors)
num_options++;
if (tgt->u.integrity.fix_padding)
num_options++;
if (tgt->u.integrity.fix_hmac)
num_options++;
if (tgt->u.integrity.legacy_recalc)
num_options++;
if (tgt->u.integrity.meta_device)
num_options++;
if (flags & CRYPT_ACTIVATE_RECALCULATE)
num_options++;
if (flags & CRYPT_ACTIVATE_ALLOW_DISCARDS)
num_options++;
snprintf(feature, sizeof(feature), "fix_padding ");
strncat(features, feature, sizeof(features) - strlen(features) - 1);
}
if (tgt->u.integrity.fix_hmac) {
num_options++;
snprintf(feature, sizeof(feature), "fix_hmac ");
strncat(features, feature, sizeof(features) - strlen(features) - 1);
}
if (tgt->u.integrity.legacy_recalc) {
num_options++;
snprintf(feature, sizeof(feature), "legacy_recalculate ");
strncat(features, feature, sizeof(features) - strlen(features) - 1);
}
if (flags & CRYPT_ACTIVATE_RECALCULATE) {
num_options++;
snprintf(feature, sizeof(feature), "recalculate ");
strncat(features, feature, sizeof(features) - strlen(features) - 1);
}
if (flags & CRYPT_ACTIVATE_ALLOW_DISCARDS) {
num_options++;
snprintf(feature, sizeof(feature), "allow_discards ");
strncat(features, feature, sizeof(features) - strlen(features) - 1);
}
if (tgt->u.integrity.meta_device) {
num_options++;
snprintf(feature, sizeof(feature), "meta_device:%s ",
device_block_path(tgt->u.integrity.meta_device));
strncat(features, feature, sizeof(features) - strlen(features) - 1);
}
r = snprintf(features, max_size, "%d%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", num_options,
tgt->u.integrity.journal_size ? _uf(feature[0], sizeof(feature[0]), /* MAX length 17 + int32 */
"journal_sectors", (unsigned)(tgt->u.integrity.journal_size / SECTOR_SIZE)) : "",
tgt->u.integrity.journal_watermark ? _uf(feature[1], sizeof(feature[1]), /* MAX length 19 + int32 */
/* bitmap overloaded values */
(flags & CRYPT_ACTIVATE_NO_JOURNAL_BITMAP) ? "sectors_per_bit" : "journal_watermark",
tgt->u.integrity.journal_watermark) : "",
tgt->u.integrity.journal_commit_time ? _uf(feature[2], sizeof(feature[2]), /* MAX length 23 + int32 */
/* bitmap overloaded values */
(flags & CRYPT_ACTIVATE_NO_JOURNAL_BITMAP) ? "bitmap_flush_interval" : "commit_time",
tgt->u.integrity.journal_commit_time) : "",
tgt->u.integrity.interleave_sectors ? _uf(feature[3], sizeof(feature[3]), /* MAX length 20 + int32 */
"interleave_sectors", tgt->u.integrity.interleave_sectors) : "",
tgt->u.integrity.sector_size ? _uf(feature[4], sizeof(feature[4]), /* MAX length 12 + int32 */
"block_size", tgt->u.integrity.sector_size) : "",
tgt->u.integrity.buffer_sectors ? _uf(feature[5], sizeof(feature[5]), /* MAX length 16 + int32 */
"buffer_sectors", tgt->u.integrity.buffer_sectors) : "",
tgt->u.integrity.integrity ? integrity : "",
tgt->u.integrity.journal_integrity ? journal_integrity : "",
tgt->u.integrity.journal_crypt ? journal_crypt : "",
tgt->u.integrity.fix_padding ? " fix_padding" : "", /* MAX length 12 */
tgt->u.integrity.fix_hmac ? " fix_hmac" : "", /* MAX length 9 */
tgt->u.integrity.legacy_recalc ? " legacy_recalculate" : "", /* MAX length 19 */
flags & CRYPT_ACTIVATE_RECALCULATE ? " recalculate" : "", /* MAX length 12 */
flags & CRYPT_ACTIVATE_ALLOW_DISCARDS ? " allow_discards" : "", /* MAX length 15 */
tgt->u.integrity.meta_device ? " meta_device:" : "", /* MAX length 13 + str_device */
tgt->u.integrity.meta_device ? device_block_path(tgt->u.integrity.meta_device) : "");
if (r < 0 || r >= max_size)
goto out;
if (flags & CRYPT_ACTIVATE_NO_JOURNAL_BITMAP)
mode = 'B';
@@ -964,16 +971,22 @@ static char *get_dm_integrity_params(const struct dm_target *tgt, uint32_t flags
else
mode = 'J';
r = snprintf(params, max_size, "%s %" PRIu64 " %d %c %d %s",
r = snprintf(params, max_size, "%s %" PRIu64 " %d %c %s",
device_block_path(tgt->data_device), tgt->u.integrity.offset,
tgt->u.integrity.tag_size, mode,
num_options, *features ? features : "");
if (r < 0 || r >= max_size) {
crypt_safe_free(params);
params = NULL;
}
tgt->u.integrity.tag_size, mode, features);
if (r < 0 || r >= max_size)
goto out;
return params;
params_out = params;
out:
crypt_safe_free(features);
crypt_safe_free(integrity);
crypt_safe_free(journal_integrity);
crypt_safe_free(journal_crypt);
if (!params_out)
crypt_safe_free(params);
return params_out;
}
static char *get_dm_linear_params(const struct dm_target *tgt, uint32_t flags)
@@ -1208,7 +1221,7 @@ static int dm_prepare_uuid(struct crypt_device *cd, const char *name, const char
{
char *ptr, uuid2[UUID_LEN] = {0};
uuid_t uu;
unsigned i = 0;
int i = 0;
/* Remove '-' chars */
if (uuid) {
@@ -1228,9 +1241,11 @@ static int dm_prepare_uuid(struct crypt_device *cd, const char *name, const char
type ?: "", type ? "-" : "",
uuid2[0] ? uuid2 : "", uuid2[0] ? "-" : "",
name);
if (i < 0)
return 0;
log_dbg(cd, "DM-UUID is %s", buf);
if (i >= buflen)
if ((size_t)i >= buflen)
log_err(cd, _("DM-UUID for device %s was truncated."), name);
return 1;
@@ -2295,8 +2310,13 @@ static int _dm_target_query_verity(struct crypt_device *cd,
str = strsep(&params, " ");
if (!str)
goto err;
if (!root_hash_sig_key_desc)
if (!root_hash_sig_key_desc) {
root_hash_sig_key_desc = strdup(str);
if (!root_hash_sig_key_desc) {
r = -ENOMEM;
goto err;
}
}
i++;
if (vp)
vp->flags |= CRYPT_VERITY_ROOT_HASH_SIGNATURE;

View File

@@ -61,6 +61,10 @@
#define LUKS2_REENCRYPT_MAX_HOTZONE_LENGTH 0x40000000
struct device;
struct luks2_reencrypt;
struct crypt_lock_handle;
struct crypt_dm_active_device;
struct luks_phdr; /* LUKS1 for conversion */
/*
* LUKS2 header on-disk.
@@ -96,7 +100,6 @@ struct luks2_hdr_disk {
/*
* LUKS2 header in-memory.
*/
typedef struct json_object json_object;
struct luks2_hdr {
size_t hdr_size;
uint64_t seqid;
@@ -107,7 +110,7 @@ struct luks2_hdr {
uint8_t salt1[LUKS2_SALT_L];
uint8_t salt2[LUKS2_SALT_L];
char uuid[LUKS2_UUID_L];
json_object *jobj;
void *jobj;
};
struct luks2_keyslot_params {
@@ -129,77 +132,6 @@ struct luks2_keyslot_params {
} area;
};
struct reenc_protection {
enum { REENC_PROTECTION_NONE = 0, /* none should be 0 always */
REENC_PROTECTION_CHECKSUM,
REENC_PROTECTION_JOURNAL,
REENC_PROTECTION_DATASHIFT } type;
union {
struct {
} none;
struct {
char hash[LUKS2_CHECKSUM_ALG_L]; // or include luks.h
struct crypt_hash *ch;
size_t hash_size;
/* buffer for checksums */
void *checksums;
size_t checksums_len;
} csum;
struct {
} ds;
} p;
};
struct luks2_reenc_context {
/* reencryption window attributes */
uint64_t offset;
uint64_t progress;
uint64_t length;
uint64_t data_shift;
size_t alignment;
uint64_t device_size;
bool online;
bool fixed_length;
crypt_reencrypt_direction_info direction;
crypt_reencrypt_mode_info mode;
char *device_name;
char *hotzone_name;
char *overlay_name;
uint32_t flags;
/* reencryption window persistence attributes */
struct reenc_protection rp;
int reenc_keyslot;
/* already running reencryption */
json_object *jobj_segs_hot;
json_object *jobj_segs_post;
/* backup segments */
json_object *jobj_segment_new;
int digest_new;
json_object *jobj_segment_old;
int digest_old;
json_object *jobj_segment_moved;
struct volume_key *vks;
void *reenc_buffer;
ssize_t read;
struct crypt_storage_wrapper *cw1;
struct crypt_storage_wrapper *cw2;
uint32_t wflags1;
uint32_t wflags2;
struct crypt_lock_handle *reenc_lock;
};
crypt_reencrypt_info LUKS2_reenc_status(struct luks2_hdr *hdr);
/*
* Supportable header sizes (hdr_disk + JSON area)
* Also used as offset for the 2nd header.
@@ -222,9 +154,6 @@ crypt_reencrypt_info LUKS2_reenc_status(struct luks2_hdr *hdr);
int LUKS2_hdr_version_unlocked(struct crypt_device *cd,
const char *backup_file);
int LUKS2_device_write_lock(struct crypt_device *cd,
struct luks2_hdr *hdr, struct device *device);
int LUKS2_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr, int repair);
int LUKS2_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr);
int LUKS2_hdr_write_force(struct crypt_device *cd, struct luks2_hdr *hdr);
@@ -249,9 +178,9 @@ int LUKS2_hdr_restore(struct crypt_device *cd,
struct luks2_hdr *hdr,
const char *backup_file);
uint64_t LUKS2_hdr_and_areas_size(json_object *jobj);
uint64_t LUKS2_keyslots_size(json_object *jobj);
uint64_t LUKS2_metadata_size(json_object *jobj);
uint64_t LUKS2_hdr_and_areas_size(struct luks2_hdr *hdr);
uint64_t LUKS2_keyslots_size(struct luks2_hdr *hdr);
uint64_t LUKS2_metadata_size(struct luks2_hdr *hdr);
int LUKS2_keyslot_cipher_incompatible(struct crypt_device *cd, const char *cipher_spec);
@@ -280,28 +209,11 @@ int LUKS2_keyslot_store(struct crypt_device *cd,
const struct volume_key *vk,
const struct luks2_keyslot_params *params);
int LUKS2_keyslot_reencrypt_store(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const void *buffer,
size_t buffer_length);
int LUKS2_keyslot_reencrypt_create(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const struct crypt_params_reencrypt *params);
int reenc_keyslot_update(struct crypt_device *cd,
const struct luks2_reenc_context *rh);
int LUKS2_keyslot_wipe(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
int wipe_area_only);
int LUKS2_keyslot_dump(struct crypt_device *cd,
int keyslot);
crypt_keyslot_priority LUKS2_keyslot_priority_get(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot);
@@ -374,65 +286,6 @@ int LUKS2_token_open_and_activate_any(struct crypt_device *cd,
const char *name,
uint32_t flags);
int LUKS2_tokens_count(struct luks2_hdr *hdr);
/*
* Generic LUKS2 segment
*/
uint64_t json_segment_get_offset(json_object *jobj_segment, unsigned blockwise);
const char *json_segment_type(json_object *jobj_segment);
uint64_t json_segment_get_iv_offset(json_object *jobj_segment);
uint64_t json_segment_get_size(json_object *jobj_segment, unsigned blockwise);
const char *json_segment_get_cipher(json_object *jobj_segment);
int json_segment_get_sector_size(json_object *jobj_segment);
bool json_segment_is_backup(json_object *jobj_segment);
json_object *json_segments_get_segment(json_object *jobj_segments, int segment);
unsigned json_segments_count(json_object *jobj_segments);
void json_segment_remove_flag(json_object *jobj_segment, const char *flag);
uint64_t json_segments_get_minimal_offset(json_object *jobj_segments, unsigned blockwise);
json_object *json_segment_create_linear(uint64_t offset, const uint64_t *length, unsigned reencryption);
json_object *json_segment_create_crypt(uint64_t offset, uint64_t iv_offset, const uint64_t *length, const char *cipher, uint32_t sector_size, unsigned reencryption);
int json_segments_segment_in_reencrypt(json_object *jobj_segments);
int LUKS2_segments_count(struct luks2_hdr *hdr);
int LUKS2_segment_first_unused_id(struct luks2_hdr *hdr);
int LUKS2_segment_set_flag(json_object *jobj_segment, const char *flag);
json_object *LUKS2_get_segment_by_flag(struct luks2_hdr *hdr, const char *flag);
int LUKS2_get_segment_id_by_flag(struct luks2_hdr *hdr, const char *flag);
int LUKS2_segments_set(struct crypt_device *cd,
struct luks2_hdr *hdr,
json_object *jobj_segments,
int commit);
uint64_t LUKS2_segment_offset(struct luks2_hdr *hdr,
int segment,
unsigned blockwise);
uint64_t LUKS2_segment_size(struct luks2_hdr *hdr,
int segment,
unsigned blockwise);
int LUKS2_segment_is_type(struct luks2_hdr *hdr,
int segment,
const char *type);
int LUKS2_segment_by_type(struct luks2_hdr *hdr,
const char *type);
int LUKS2_last_segment_by_type(struct luks2_hdr *hdr,
const char *type);
int LUKS2_get_default_segment(struct luks2_hdr *hdr);
int LUKS2_reencrypt_digest_new(struct luks2_hdr *hdr);
int LUKS2_reencrypt_digest_old(struct luks2_hdr *hdr);
int LUKS2_reencrypt_data_offset(struct luks2_hdr *hdr, bool blockwise);
/*
* Generic LUKS2 digest
*/
@@ -440,29 +293,16 @@ int LUKS2_digest_any_matching(struct crypt_device *cd,
struct luks2_hdr *hdr,
const struct volume_key *vk);
int LUKS2_digest_by_segment(struct luks2_hdr *hdr, int segment);
int LUKS2_digest_verify_by_digest(struct crypt_device *cd,
struct luks2_hdr *hdr,
int digest,
const struct volume_key *vk);
int LUKS2_digest_verify_by_segment(struct crypt_device *cd,
struct luks2_hdr *hdr,
int segment,
const struct volume_key *vk);
void LUKS2_digests_erase_unused(struct crypt_device *cd,
struct luks2_hdr *hdr);
int LUKS2_digest_verify(struct crypt_device *cd,
struct luks2_hdr *hdr,
const struct volume_key *vk,
int keyslot);
int LUKS2_digest_dump(struct crypt_device *cd,
int digest);
int LUKS2_digest_assign(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
@@ -479,6 +319,8 @@ int LUKS2_digest_segment_assign(struct crypt_device *cd,
int LUKS2_digest_by_keyslot(struct luks2_hdr *hdr, int keyslot);
int LUKS2_digest_by_segment(struct luks2_hdr *hdr, int segment);
int LUKS2_digest_create(struct crypt_device *cd,
const char *type,
struct luks2_hdr *hdr,
@@ -498,20 +340,12 @@ int LUKS2_activate_multi(struct crypt_device *cd,
uint64_t device_size,
uint32_t flags);
struct crypt_dm_active_device;
int LUKS2_deactivate(struct crypt_device *cd,
const char *name,
struct luks2_hdr *hdr,
struct crypt_dm_active_device *dmd,
uint32_t flags);
int LUKS2_reload(struct crypt_device *cd,
const char *name,
struct volume_key *vks,
uint64_t device_size,
uint32_t flags);
int LUKS2_generate_hdr(
struct crypt_device *cd,
struct luks2_hdr *hdr,
@@ -545,17 +379,12 @@ int LUKS2_get_keyslot_stored_key_size(struct luks2_hdr *hdr, int keyslot);
const char *LUKS2_get_keyslot_cipher(struct luks2_hdr *hdr, int keyslot, size_t *key_size);
int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr);
int LUKS2_keyslot_active_count(struct luks2_hdr *hdr, int segment);
int LUKS2_keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment);
int LUKS2_find_keyslot(struct luks2_hdr *hdr, const char *type);
crypt_keyslot_info LUKS2_keyslot_info(struct luks2_hdr *hdr, int keyslot);
int LUKS2_keyslot_area(struct luks2_hdr *hdr,
int keyslot,
uint64_t *offset,
uint64_t *length);
int LUKS2_keyslot_pbkdf(struct luks2_hdr *hdr, int keyslot, struct crypt_pbkdf_type *pbkdf);
int LUKS2_set_keyslots_size(struct crypt_device *cd,
struct luks2_hdr *hdr,
uint64_t data_offset);
/*
* Permanent activation flags stored in header
@@ -569,6 +398,8 @@ int LUKS2_config_set_flags(struct crypt_device *cd, struct luks2_hdr *hdr, uint3
int LUKS2_config_get_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t *reqs);
int LUKS2_config_set_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs, bool commit);
int LUKS2_config_get_reencrypt_version(struct luks2_hdr *hdr, uint32_t *version);
int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs_mask, int quiet);
int LUKS2_key_description_by_segment(struct crypt_device *cd,
@@ -578,7 +409,6 @@ int LUKS2_volume_key_load_in_keyring_by_keyslot(struct crypt_device *cd,
int LUKS2_volume_key_load_in_keyring_by_digest(struct crypt_device *cd,
struct luks2_hdr *hdr, struct volume_key *vk, int digest);
struct luks_phdr;
int LUKS2_luks1_to_luks2(struct crypt_device *cd,
struct luks_phdr *hdr1,
struct luks2_hdr *hdr2);
@@ -597,21 +427,33 @@ int LUKS2_reencrypt_locked_recovery_by_passphrase(struct crypt_device *cd,
uint32_t flags,
struct volume_key **vks);
void LUKS2_reenc_context_free(struct crypt_device *cd, struct luks2_reenc_context *rh);
void LUKS2_reencrypt_free(struct crypt_device *cd,
struct luks2_reencrypt *rh);
int LUKS2_assembly_multisegment_dmd(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct volume_key *vks,
json_object *jobj_segments,
struct crypt_dm_active_device *dmd);
crypt_reencrypt_info LUKS2_reencrypt_status(struct luks2_hdr *hdr);
crypt_reencrypt_info LUKS2_reencrypt_status(struct crypt_device *cd,
crypt_reencrypt_info LUKS2_reencrypt_get_params(struct luks2_hdr *hdr,
struct crypt_params_reencrypt *params);
int crypt_reencrypt_lock(struct crypt_device *cd, struct crypt_lock_handle **reencrypt_lock);
int crypt_reencrypt_lock_by_dm_uuid(struct crypt_device *cd, const char *dm_uuid, struct crypt_lock_handle **reencrypt_lock);
void crypt_reencrypt_unlock(struct crypt_device *cd, struct crypt_lock_handle *reencrypt_lock);
int LUKS2_reencrypt_lock(struct crypt_device *cd,
struct crypt_lock_handle **reencrypt_lock);
int luks2_check_device_size(struct crypt_device *cd, struct luks2_hdr *hdr, uint64_t check_size, uint64_t *dev_size, bool activation, bool dynamic);
int LUKS2_reencrypt_lock_by_dm_uuid(struct crypt_device *cd,
const char *dm_uuid,
struct crypt_lock_handle **reencrypt_lock);
void LUKS2_reencrypt_unlock(struct crypt_device *cd,
struct crypt_lock_handle *reencrypt_lock);
int LUKS2_reencrypt_check_device_size(struct crypt_device *cd,
struct luks2_hdr *hdr,
uint64_t check_size,
uint64_t *dev_size,
bool activation,
bool dynamic);
int LUKS2_reencrypt_digest_verify(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct volume_key *vks);
#endif

View File

@@ -219,7 +219,9 @@ static int assign_one_digest(struct crypt_device *cd, struct luks2_hdr *hdr,
if (!jobj_digest_keyslots)
return -EINVAL;
snprintf(num, sizeof(num), "%d", keyslot);
if (snprintf(num, sizeof(num), "%d", keyslot) < 0)
return -EINVAL;
if (assign) {
jobj1 = LUKS2_array_jobj(jobj_digest_keyslots, num);
if (!jobj1)
@@ -304,7 +306,9 @@ static int assign_one_segment(struct crypt_device *cd, struct luks2_hdr *hdr,
if (!jobj_digest_segments)
return -EINVAL;
snprintf(num, sizeof(num), "%d", segment);
if (snprintf(num, sizeof(num), "%d", segment) < 0)
return -EINVAL;
if (assign) {
jobj1 = LUKS2_array_jobj(jobj_digest_segments, num);
if (!jobj1)

View File

@@ -385,7 +385,7 @@ int LUKS2_device_write_lock(struct crypt_device *cd, struct luks2_hdr *hdr, stru
}
/* run sequence id check only on first write lock (r == 1) and w/o LUKS2 reencryption in-progress */
if (r == 1 && !crypt_get_reenc_context(cd)) {
if (r == 1 && !crypt_get_luks2_reencrypt(cd)) {
log_dbg(cd, "Checking context sequence id matches value stored on disk.");
if (LUKS2_check_sequence_id(cd, hdr, device)) {
device_write_unlock(cd, device);
@@ -413,7 +413,7 @@ int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct
return -EINVAL;
}
r = device_check_size(cd, crypt_metadata_device(cd), LUKS2_hdr_and_areas_size(hdr->jobj), 1);
r = device_check_size(cd, crypt_metadata_device(cd), LUKS2_hdr_and_areas_size(hdr), 1);
if (r)
return r;
@@ -669,9 +669,9 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
/* check header with keyslots to fit the device */
if (state_hdr1 == HDR_OK)
hdr_size = LUKS2_hdr_and_areas_size(jobj_hdr1);
hdr_size = LUKS2_hdr_and_areas_size_jobj(jobj_hdr1);
else if (state_hdr2 == HDR_OK)
hdr_size = LUKS2_hdr_and_areas_size(jobj_hdr2);
hdr_size = LUKS2_hdr_and_areas_size_jobj(jobj_hdr2);
else {
r = (state_hdr1 == HDR_FAIL_IO && state_hdr2 == HDR_FAIL_IO) ? -EIO : -EINVAL;
goto err;

View File

@@ -44,6 +44,8 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
struct device *device, int do_recovery, int do_blkprobe);
int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr,
struct device *device, bool seqid_check);
int LUKS2_device_write_lock(struct crypt_device *cd,
struct luks2_hdr *hdr, struct device *device);
/*
* JSON struct access helpers
@@ -92,8 +94,8 @@ void LUKS2_keyslots_repair(struct crypt_device *cd, json_object *jobj_hdr);
/*
* JSON array helpers
*/
struct json_object *LUKS2_array_jobj(struct json_object *array, const char *num);
struct json_object *LUKS2_array_remove(struct json_object *array, const char *num);
json_object *LUKS2_array_jobj(json_object *array, const char *num);
json_object *LUKS2_array_remove(json_object *array, const char *num);
/*
* Plugins API
@@ -184,6 +186,8 @@ int LUKS2_find_area_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
int LUKS2_find_area_max_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
uint64_t *area_offset, uint64_t *area_length);
uint64_t LUKS2_hdr_and_areas_size_jobj(json_object *jobj);
int LUKS2_check_cipher(struct crypt_device *cd,
size_t keylength,
const char *cipher,
@@ -200,4 +204,127 @@ static inline const char *crypt_reencrypt_mode_to_str(crypt_reencrypt_mode_info
return "<unknown>";
}
/*
* Generic LUKS2 keyslot
*/
int LUKS2_keyslot_reencrypt_store(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const void *buffer,
size_t buffer_length);
int LUKS2_keyslot_reencrypt_allocate(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const struct crypt_params_reencrypt *params);
int LUKS2_keyslot_reencrypt_digest_create(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct volume_key *vks);
int LUKS2_keyslot_dump(struct crypt_device *cd,
int keyslot);
int LUKS2_keyslot_jobj_area(json_object *jobj_keyslot, uint64_t *offset, uint64_t *length);
/* JSON helpers */
uint64_t json_segment_get_offset(json_object *jobj_segment, unsigned blockwise);
const char *json_segment_type(json_object *jobj_segment);
uint64_t json_segment_get_iv_offset(json_object *jobj_segment);
uint64_t json_segment_get_size(json_object *jobj_segment, unsigned blockwise);
const char *json_segment_get_cipher(json_object *jobj_segment);
int json_segment_get_sector_size(json_object *jobj_segment);
bool json_segment_is_backup(json_object *jobj_segment);
json_object *json_segments_get_segment(json_object *jobj_segments, int segment);
unsigned json_segments_count(json_object *jobj_segments);
void json_segment_remove_flag(json_object *jobj_segment, const char *flag);
uint64_t json_segments_get_minimal_offset(json_object *jobj_segments, unsigned blockwise);
json_object *json_segment_create_linear(uint64_t offset, const uint64_t *length, unsigned reencryption);
json_object *json_segment_create_crypt(uint64_t offset, uint64_t iv_offset, const uint64_t *length, const char *cipher, uint32_t sector_size, unsigned reencryption);
int json_segments_segment_in_reencrypt(json_object *jobj_segments);
bool json_segment_cmp(json_object *jobj_segment_1, json_object *jobj_segment_2);
bool json_segment_contains_flag(json_object *jobj_segment, const char *flag_str, size_t len);
int LUKS2_assembly_multisegment_dmd(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct volume_key *vks,
json_object *jobj_segments,
struct crypt_dm_active_device *dmd);
/*
* Generic LUKS2 segment
*/
int LUKS2_segments_count(struct luks2_hdr *hdr);
int LUKS2_segment_first_unused_id(struct luks2_hdr *hdr);
int LUKS2_segment_set_flag(json_object *jobj_segment, const char *flag);
json_object *LUKS2_get_segment_by_flag(struct luks2_hdr *hdr, const char *flag);
int LUKS2_get_segment_id_by_flag(struct luks2_hdr *hdr, const char *flag);
int LUKS2_segments_set(struct crypt_device *cd,
struct luks2_hdr *hdr,
json_object *jobj_segments,
int commit);
uint64_t LUKS2_segment_offset(struct luks2_hdr *hdr,
int segment,
unsigned blockwise);
uint64_t LUKS2_segment_size(struct luks2_hdr *hdr,
int segment,
unsigned blockwise);
int LUKS2_segment_is_type(struct luks2_hdr *hdr,
int segment,
const char *type);
int LUKS2_segment_by_type(struct luks2_hdr *hdr,
const char *type);
int LUKS2_last_segment_by_type(struct luks2_hdr *hdr,
const char *type);
int LUKS2_get_default_segment(struct luks2_hdr *hdr);
int LUKS2_reencrypt_digest_new(struct luks2_hdr *hdr);
int LUKS2_reencrypt_digest_old(struct luks2_hdr *hdr);
int LUKS2_reencrypt_data_offset(struct luks2_hdr *hdr, bool blockwise);
/*
* Generic LUKS2 digest
*/
int LUKS2_digest_verify_by_digest(struct crypt_device *cd,
struct luks2_hdr *hdr,
int digest,
const struct volume_key *vk);
void LUKS2_digests_erase_unused(struct crypt_device *cd,
struct luks2_hdr *hdr);
int LUKS2_digest_dump(struct crypt_device *cd,
int digest);
/*
* Generic LUKS2 token
*/
int LUKS2_tokens_count(struct luks2_hdr *hdr);
/*
* LUKS2 generic
*/
int LUKS2_reload(struct crypt_device *cd,
const char *name,
struct volume_key *vks,
uint64_t device_size,
uint32_t flags);
int LUKS2_keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment);
int LUKS2_find_keyslot(struct luks2_hdr *hdr, const char *type);
int LUKS2_set_keyslots_size(struct crypt_device *cd,
struct luks2_hdr *hdr,
uint64_t data_offset);
#endif

View File

@@ -41,7 +41,7 @@ static size_t get_min_offset(struct luks2_hdr *hdr)
static size_t get_max_offset(struct luks2_hdr *hdr)
{
return LUKS2_hdr_and_areas_size(hdr->jobj);
return LUKS2_hdr_and_areas_size(hdr);
}
int LUKS2_find_area_max_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
@@ -216,7 +216,7 @@ int LUKS2_generate_hdr(
struct json_object *jobj_segment, *jobj_integrity, *jobj_keyslots, *jobj_segments, *jobj_config;
char cipher[128];
uuid_t partitionUuid;
int digest;
int r, digest;
uint64_t mdev_size;
if (!metadata_size)
@@ -290,9 +290,11 @@ int LUKS2_generate_hdr(
uuid_unparse(partitionUuid, hdr->uuid);
if (*cipherMode != '\0')
snprintf(cipher, sizeof(cipher), "%s-%s", cipherName, cipherMode);
r = snprintf(cipher, sizeof(cipher), "%s-%s", cipherName, cipherMode);
else
snprintf(cipher, sizeof(cipher), "%s", cipherName);
r = snprintf(cipher, sizeof(cipher), "%s", cipherName);
if (r < 0 || (size_t)r >= sizeof(cipher))
return -EINVAL;
hdr->jobj = json_object_new_object();
@@ -369,7 +371,7 @@ int LUKS2_wipe_header_areas(struct crypt_device *cd,
/* Wipe keyslot area */
wipe_block = 1024 * 1024;
offset = get_min_offset(hdr);
length = LUKS2_keyslots_size(hdr->jobj);
length = LUKS2_keyslots_size(hdr);
log_dbg(cd, "Wiping keyslots area (0x%06" PRIx64 " - 0x%06" PRIx64") with random data.",
offset, length + offset);

View File

@@ -591,6 +591,78 @@ static bool validate_segment_intervals(struct crypt_device *cd,
return true;
}
static int reqs_unknown(uint32_t reqs)
{
return reqs & CRYPT_REQUIREMENT_UNKNOWN;
}
static int reqs_reencrypt(uint32_t reqs)
{
return reqs & CRYPT_REQUIREMENT_OFFLINE_REENCRYPT;
}
static int reqs_reencrypt_online(uint32_t reqs)
{
return reqs & CRYPT_REQUIREMENT_ONLINE_REENCRYPT;
}
/*
* Config section requirements object must be valid.
* Also general segments section must be validated first.
*/
static int validate_reencrypt_segments(struct crypt_device *cd, json_object *hdr_jobj, json_object *jobj_segments, int first_backup, int segments_count)
{
json_object *jobj, *jobj_backup_previous = NULL, *jobj_backup_final = NULL;
uint32_t reqs;
int i, r;
struct luks2_hdr dummy = {
.jobj = hdr_jobj
};
r = LUKS2_config_get_requirements(cd, &dummy, &reqs);
if (r)
return 1;
if (reqs_reencrypt_online(reqs)) {
for (i = first_backup; i < segments_count; i++) {
jobj = json_segments_get_segment(jobj_segments, i);
if (!jobj)
return 1;
if (json_segment_contains_flag(jobj, "backup-final", 0))
jobj_backup_final = jobj;
else if (json_segment_contains_flag(jobj, "backup-previous", 0))
jobj_backup_previous = jobj;
}
if (!jobj_backup_final || !jobj_backup_previous) {
log_dbg(cd, "Backup segment is missing.");
return 1;
}
for (i = 0; i < first_backup; i++) {
jobj = json_segments_get_segment(jobj_segments, i);
if (!jobj)
return 1;
if (json_segment_contains_flag(jobj, "in-reencryption", 0)) {
if (!json_segment_cmp(jobj, jobj_backup_final)) {
log_dbg(cd, "Segment in reencryption does not match backup final segment.");
return 1;
}
continue;
}
if (!json_segment_cmp(jobj, jobj_backup_final) &&
!json_segment_cmp(jobj, jobj_backup_previous)) {
log_dbg(cd, "Segment does not match neither backup final or backup previous segment.");
return 1;
}
}
}
return 0;
}
static int hdr_validate_segments(struct crypt_device *cd, json_object *hdr_jobj)
{
json_object *jobj_segments, *jobj_digests, *jobj_offset, *jobj_size, *jobj_type, *jobj_flags, *jobj;
@@ -717,10 +789,10 @@ static int hdr_validate_segments(struct crypt_device *cd, json_object *hdr_jobj)
}
}
return 0;
return validate_reencrypt_segments(cd, hdr_jobj, jobj_segments, first_backup, count);
}
uint64_t LUKS2_metadata_size(json_object *jobj)
static uint64_t LUKS2_metadata_size_jobj(json_object *jobj)
{
json_object *jobj1, *jobj2;
uint64_t json_size;
@@ -732,6 +804,11 @@ uint64_t LUKS2_metadata_size(json_object *jobj)
return json_size + LUKS2_HDR_BIN_LEN;
}
uint64_t LUKS2_metadata_size(struct luks2_hdr *hdr)
{
return LUKS2_metadata_size_jobj(hdr->jobj);
}
static int hdr_validate_areas(struct crypt_device *cd, json_object *hdr_jobj)
{
struct interval *intervals;
@@ -747,7 +824,7 @@ static int hdr_validate_areas(struct crypt_device *cd, json_object *hdr_jobj)
return 1;
/* config is already validated */
metadata_size = LUKS2_metadata_size(hdr_jobj);
metadata_size = LUKS2_metadata_size_jobj(hdr_jobj);
length = json_object_object_length(jobj_keyslots);
@@ -793,7 +870,7 @@ static int hdr_validate_areas(struct crypt_device *cd, json_object *hdr_jobj)
return 1;
}
ret = validate_intervals(cd, length, intervals, metadata_size, LUKS2_hdr_and_areas_size(hdr_jobj)) ? 0 : 1;
ret = validate_intervals(cd, length, intervals, metadata_size, LUKS2_hdr_and_areas_size_jobj(hdr_jobj)) ? 0 : 1;
free(intervals);
@@ -835,9 +912,10 @@ static int hdr_validate_digests(struct crypt_device *cd, json_object *hdr_jobj)
return 0;
}
/* requirements being validated in stand-alone routine */
static int hdr_validate_config(struct crypt_device *cd, json_object *hdr_jobj)
{
json_object *jobj_config, *jobj, *jobj1;
json_object *jobj_config, *jobj;
int i;
uint64_t keyslots_size, metadata_size, segment_offset;
@@ -892,6 +970,19 @@ static int hdr_validate_config(struct crypt_device *cd, json_object *hdr_jobj)
return 1;
}
return 0;
}
static int hdr_validate_requirements(struct crypt_device *cd, json_object *hdr_jobj)
{
int i;
json_object *jobj_config, *jobj, *jobj1;
if (!json_object_object_get_ex(hdr_jobj, "config", &jobj_config)) {
log_dbg(cd, "Missing config section.");
return 1;
}
/* Requirements object is optional */
if (json_object_object_get_ex(jobj_config, "requirements", &jobj)) {
if (!json_contains(cd, jobj_config, "section", "Config", "requirements", json_type_object))
@@ -917,6 +1008,7 @@ int LUKS2_hdr_validate(struct crypt_device *cd, json_object *hdr_jobj, uint64_t
struct {
int (*validate)(struct crypt_device *, json_object *);
} checks[] = {
{ hdr_validate_requirements },
{ hdr_validate_tokens },
{ hdr_validate_digests },
{ hdr_validate_segments },
@@ -1041,7 +1133,7 @@ void LUKS2_hdr_free(struct crypt_device *cd, struct luks2_hdr *hdr)
log_dbg(cd, "LUKS2 header still in use");
}
uint64_t LUKS2_keyslots_size(json_object *jobj)
static uint64_t LUKS2_keyslots_size_jobj(json_object *jobj)
{
json_object *jobj1, *jobj2;
uint64_t keyslots_size;
@@ -1053,9 +1145,19 @@ uint64_t LUKS2_keyslots_size(json_object *jobj)
return keyslots_size;
}
uint64_t LUKS2_hdr_and_areas_size(json_object *jobj)
uint64_t LUKS2_keyslots_size(struct luks2_hdr *hdr)
{
return 2 * LUKS2_metadata_size(jobj) + LUKS2_keyslots_size(jobj);
return LUKS2_keyslots_size_jobj(hdr->jobj);
}
uint64_t LUKS2_hdr_and_areas_size_jobj(json_object *jobj)
{
return 2 * LUKS2_metadata_size_jobj(jobj) + LUKS2_keyslots_size_jobj(jobj);
}
uint64_t LUKS2_hdr_and_areas_size(struct luks2_hdr *hdr)
{
return LUKS2_hdr_and_areas_size_jobj(hdr->jobj);
}
int LUKS2_hdr_backup(struct crypt_device *cd, struct luks2_hdr *hdr,
@@ -1067,7 +1169,7 @@ int LUKS2_hdr_backup(struct crypt_device *cd, struct luks2_hdr *hdr,
ssize_t ret, buffer_size;
char *buffer = NULL;
hdr_size = LUKS2_hdr_and_areas_size(hdr->jobj);
hdr_size = LUKS2_hdr_and_areas_size(hdr);
buffer_size = size_round_up(hdr_size, crypt_getpagesize());
buffer = crypt_safe_alloc(buffer_size);
@@ -1123,21 +1225,6 @@ int LUKS2_hdr_backup(struct crypt_device *cd, struct luks2_hdr *hdr,
return r;
}
static int reqs_unknown(uint32_t reqs)
{
return reqs & CRYPT_REQUIREMENT_UNKNOWN;
}
static int reqs_reencrypt(uint32_t reqs)
{
return reqs & CRYPT_REQUIREMENT_OFFLINE_REENCRYPT;
}
static int reqs_reencrypt_online(uint32_t reqs)
{
return reqs & CRYPT_REQUIREMENT_ONLINE_REENCRYPT;
}
int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr,
const char *backup_file)
{
@@ -1178,7 +1265,7 @@ int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr,
goto out;
}
buffer_size = LUKS2_hdr_and_areas_size(hdr_file.jobj);
buffer_size = LUKS2_hdr_and_areas_size(&hdr_file);
buffer = crypt_safe_alloc(buffer_size);
if (!buffer) {
r = -ENOMEM;
@@ -1218,7 +1305,7 @@ int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr,
goto out;
}
/* FIXME: what could go wrong? Erase if we're fine with consequences */
if (buffer_size != (ssize_t) LUKS2_hdr_and_areas_size(tmp_hdr.jobj)) {
if (buffer_size != (ssize_t) LUKS2_hdr_and_areas_size(&tmp_hdr)) {
log_err(cd, _("Binary header with keyslot areas size differ on device and backup, restore failed."));
r = -EINVAL;
goto out;
@@ -1373,24 +1460,106 @@ int LUKS2_config_set_flags(struct crypt_device *cd, struct luks2_hdr *hdr, uint3
*/
/* LUKS2 library requirements */
static const struct {
struct requirement_flag {
uint32_t flag;
uint32_t version;
const char *description;
} requirements_flags[] = {
{ CRYPT_REQUIREMENT_OFFLINE_REENCRYPT, "offline-reencrypt" },
{ CRYPT_REQUIREMENT_ONLINE_REENCRYPT, "online-reencrypt" },
{ 0, NULL }
};
static uint32_t get_requirement_by_name(const char *requirement)
static const struct requirement_flag unknown_requirement_flag = { CRYPT_REQUIREMENT_UNKNOWN, 0, NULL };
static const struct requirement_flag requirements_flags[] = {
{ CRYPT_REQUIREMENT_OFFLINE_REENCRYPT,1, "offline-reencrypt" },
{ CRYPT_REQUIREMENT_ONLINE_REENCRYPT, 2, "online-reencrypt-v2" },
{ CRYPT_REQUIREMENT_ONLINE_REENCRYPT, 1, "online-reencrypt" },
{ 0, 0, NULL }
};
static const struct requirement_flag *get_requirement_by_name(const char *requirement)
{
int i;
for (i = 0; requirements_flags[i].description; i++)
if (!strcmp(requirement, requirements_flags[i].description))
return requirements_flags[i].flag;
return requirements_flags + i;
return CRYPT_REQUIREMENT_UNKNOWN;
return &unknown_requirement_flag;
}
int LUKS2_config_get_reencrypt_version(struct luks2_hdr *hdr, uint32_t *version)
{
json_object *jobj_config, *jobj_requirements, *jobj_mandatory, *jobj;
int i, len;
const struct requirement_flag *req;
assert(hdr && version);
if (!hdr || !version)
return -EINVAL;
if (!json_object_object_get_ex(hdr->jobj, "config", &jobj_config))
return -EINVAL;
if (!json_object_object_get_ex(jobj_config, "requirements", &jobj_requirements))
return -ENOENT;
if (!json_object_object_get_ex(jobj_requirements, "mandatory", &jobj_mandatory))
return -ENOENT;
len = (int) json_object_array_length(jobj_mandatory);
if (len <= 0)
return -ENOENT;
for (i = 0; i < len; i++) {
jobj = json_object_array_get_idx(jobj_mandatory, i);
/* search for requirements prefixed with "online-reencrypt" */
if (strncmp(json_object_get_string(jobj), "online-reencrypt", 16))
continue;
/* check current library is aware of the requirement */
req = get_requirement_by_name(json_object_get_string(jobj));
if (req->flag == (uint32_t)CRYPT_REQUIREMENT_UNKNOWN)
continue;
*version = req->version;
return 0;
}
return -ENOENT;
}
static const struct requirement_flag *stored_requirement_name_by_id(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t req_id)
{
json_object *jobj_config, *jobj_requirements, *jobj_mandatory, *jobj;
int i, len;
const struct requirement_flag *req;
assert(hdr);
if (!hdr)
return NULL;
if (!json_object_object_get_ex(hdr->jobj, "config", &jobj_config))
return NULL;
if (!json_object_object_get_ex(jobj_config, "requirements", &jobj_requirements))
return NULL;
if (!json_object_object_get_ex(jobj_requirements, "mandatory", &jobj_mandatory))
return NULL;
len = (int) json_object_array_length(jobj_mandatory);
if (len <= 0)
return 0;
for (i = 0; i < len; i++) {
jobj = json_object_array_get_idx(jobj_mandatory, i);
req = get_requirement_by_name(json_object_get_string(jobj));
if (req->flag == req_id)
return req;
}
return NULL;
}
/*
@@ -1400,7 +1569,7 @@ int LUKS2_config_get_requirements(struct crypt_device *cd, struct luks2_hdr *hdr
{
json_object *jobj_config, *jobj_requirements, *jobj_mandatory, *jobj;
int i, len;
uint32_t req;
const struct requirement_flag *req;
assert(hdr);
if (!hdr || !reqs)
@@ -1427,8 +1596,8 @@ int LUKS2_config_get_requirements(struct crypt_device *cd, struct luks2_hdr *hdr
jobj = json_object_array_get_idx(jobj_mandatory, i);
req = get_requirement_by_name(json_object_get_string(jobj));
log_dbg(cd, "%s - %sknown", json_object_get_string(jobj),
reqs_unknown(req) ? "un" : "");
*reqs |= req;
reqs_unknown(req->flag) ? "un" : "");
*reqs |= req->flag;
}
return 0;
@@ -1438,6 +1607,8 @@ int LUKS2_config_set_requirements(struct crypt_device *cd, struct luks2_hdr *hdr
{
json_object *jobj_config, *jobj_requirements, *jobj_mandatory, *jobj;
int i, r = -EINVAL;
const struct requirement_flag *req;
uint32_t req_id;
if (!hdr)
return -EINVAL;
@@ -1447,8 +1618,14 @@ int LUKS2_config_set_requirements(struct crypt_device *cd, struct luks2_hdr *hdr
return -ENOMEM;
for (i = 0; requirements_flags[i].description; i++) {
if (reqs & requirements_flags[i].flag) {
jobj = json_object_new_string(requirements_flags[i].description);
req_id = reqs & requirements_flags[i].flag;
if (req_id) {
/* retain already stored version of requirement flag */
req = stored_requirement_name_by_id(cd, hdr, req_id);
if (req)
jobj = json_object_new_string(req->description);
else
jobj = json_object_new_string(requirements_flags[i].description);
if (!jobj) {
r = -ENOMEM;
goto err;
@@ -1714,8 +1891,8 @@ int LUKS2_hdr_dump(struct crypt_device *cd, struct luks2_hdr *hdr)
log_std(cd, "LUKS header information\n");
log_std(cd, "Version: \t%u\n", hdr->version);
log_std(cd, "Epoch: \t%" PRIu64 "\n", hdr->seqid);
log_std(cd, "Metadata area: \t%" PRIu64 " [bytes]\n", LUKS2_metadata_size(hdr->jobj));
log_std(cd, "Keyslots area: \t%" PRIu64 " [bytes]\n", LUKS2_keyslots_size(hdr->jobj));
log_std(cd, "Metadata area: \t%" PRIu64 " [bytes]\n", LUKS2_metadata_size(hdr));
log_std(cd, "Keyslots area: \t%" PRIu64 " [bytes]\n", LUKS2_keyslots_size(hdr));
log_std(cd, "UUID: \t%s\n", *hdr->uuid ? hdr->uuid : "(no UUID)");
log_std(cd, "Label: \t%s\n", *hdr->label ? hdr->label : "(no label)");
log_std(cd, "Subsystem: \t%s\n", *hdr->subsystem ? hdr->subsystem : "(no subsystem)");
@@ -1774,7 +1951,7 @@ uint64_t LUKS2_get_data_offset(struct luks2_hdr *hdr)
crypt_reencrypt_info ri;
json_object *jobj;
ri = LUKS2_reenc_status(hdr);
ri = LUKS2_reencrypt_status(hdr);
if (ri == CRYPT_REENCRYPT_CLEAN || ri == CRYPT_REENCRYPT_CRASH) {
jobj = LUKS2_get_segment_by_flag(hdr, "backup-final");
if (jobj)
@@ -1802,7 +1979,7 @@ const char *LUKS2_get_cipher(struct luks2_hdr *hdr, int segment)
return json_segment_get_cipher(jobj_segment) ?: "null";
}
crypt_reencrypt_info LUKS2_reenc_status(struct luks2_hdr *hdr)
crypt_reencrypt_info LUKS2_reencrypt_status(struct luks2_hdr *hdr)
{
uint32_t reqs;
@@ -2245,7 +2422,7 @@ int LUKS2_deactivate(struct crypt_device *cd, const char *name, struct luks2_hdr
goto out;
if (contains_reencryption_helper(deps)) {
r = crypt_reencrypt_lock_by_dm_uuid(cd, dmd->uuid, &reencrypt_lock);
r = LUKS2_reencrypt_lock_by_dm_uuid(cd, dmd->uuid, &reencrypt_lock);
if (r) {
if (r == -EBUSY)
log_err(cd, _("Reencryption in-progress. Cannot deactivate device."));
@@ -2324,7 +2501,7 @@ int LUKS2_deactivate(struct crypt_device *cd, const char *name, struct luks2_hdr
}
out:
crypt_reencrypt_unlock(cd, reencrypt_lock);
LUKS2_reencrypt_unlock(cd, reencrypt_lock);
dep = deps;
while (*dep)
free(*dep++);

View File

@@ -27,7 +27,9 @@ extern const keyslot_handler reenc_keyslot;
static const keyslot_handler *keyslot_handlers[LUKS2_KEYSLOTS_MAX] = {
&luks2_keyslot,
#if USE_LUKS2_REENCRYPTION
&reenc_keyslot,
#endif
NULL
};
@@ -281,19 +283,9 @@ crypt_keyslot_info LUKS2_keyslot_info(struct luks2_hdr *hdr, int keyslot)
return CRYPT_SLOT_ACTIVE;
}
int LUKS2_keyslot_area(struct luks2_hdr *hdr,
int keyslot,
uint64_t *offset,
uint64_t *length)
int LUKS2_keyslot_jobj_area(json_object *jobj_keyslot, uint64_t *offset, uint64_t *length)
{
json_object *jobj_keyslot, *jobj_area, *jobj;
if(LUKS2_keyslot_info(hdr, keyslot) == CRYPT_SLOT_INVALID)
return -EINVAL;
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
if (!jobj_keyslot)
return -ENOENT;
json_object *jobj_area, *jobj;
if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
return -EINVAL;
@@ -309,6 +301,23 @@ int LUKS2_keyslot_area(struct luks2_hdr *hdr,
return 0;
}
int LUKS2_keyslot_area(struct luks2_hdr *hdr,
int keyslot,
uint64_t *offset,
uint64_t *length)
{
json_object *jobj_keyslot;
if (LUKS2_keyslot_info(hdr, keyslot) == CRYPT_SLOT_INVALID)
return -EINVAL;
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
if (!jobj_keyslot)
return -ENOENT;
return LUKS2_keyslot_jobj_area(jobj_keyslot, offset, length);
}
static int _open_and_verify(struct crypt_device *cd,
struct luks2_hdr *hdr,
const keyslot_handler *h,
@@ -589,7 +598,7 @@ int LUKS2_keyslot_open(struct crypt_device *cd,
return r;
}
int LUKS2_keyslot_reencrypt_create(struct crypt_device *cd,
int LUKS2_keyslot_reencrypt_allocate(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const struct crypt_params_reencrypt *params)
@@ -619,9 +628,6 @@ int LUKS2_keyslot_reencrypt_create(struct crypt_device *cd,
return r;
}
if (LUKS2_hdr_validate(cd, hdr->jobj, hdr->hdr_size - LUKS2_HDR_BIN_LEN))
return -EINVAL;
return 0;
}
@@ -872,10 +878,17 @@ int LUKS2_keyslots_validate(struct crypt_device *cd, json_object *hdr_jobj)
const keyslot_handler *h;
int keyslot;
json_object *jobj_keyslots, *jobj_type;
uint32_t reqs, reencrypt_count = 0;
struct luks2_hdr dummy = {
.jobj = hdr_jobj
};
if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
return -EINVAL;
if (LUKS2_config_get_requirements(cd, &dummy, &reqs))
return -EINVAL;
json_object_object_foreach(jobj_keyslots, slot, val) {
keyslot = atoi(slot);
json_object_object_get_ex(val, "type", &jobj_type);
@@ -891,6 +904,24 @@ int LUKS2_keyslots_validate(struct crypt_device *cd, json_object *hdr_jobj)
log_dbg(cd, "Keyslot %d is not assigned to exactly 1 digest.", keyslot);
return -EINVAL;
}
if (!strcmp(h->name, "reencrypt"))
reencrypt_count++;
}
if ((reqs & CRYPT_REQUIREMENT_ONLINE_REENCRYPT) && reencrypt_count == 0) {
log_dbg(cd, "Missing reencryption keyslot.");
return -EINVAL;
}
if (!(reqs & CRYPT_REQUIREMENT_ONLINE_REENCRYPT) && reencrypt_count) {
log_dbg(cd, "Missing reencryption requirement flag.");
return -EINVAL;
}
if (reencrypt_count > 1) {
log_dbg(cd, "Too many reencryption keyslots.");
return -EINVAL;
}
return 0;

View File

@@ -176,43 +176,17 @@ static int reenc_keyslot_store(struct crypt_device *cd,
return r < 0 ? r : keyslot;
}
int reenc_keyslot_update(struct crypt_device *cd,
const struct luks2_reenc_context *rh)
static int reenc_keyslot_wipe(struct crypt_device *cd,
int keyslot)
{
json_object *jobj_keyslot, *jobj_area, *jobj_area_type;
struct luks2_hdr *hdr;
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
return -EINVAL;
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, rh->reenc_keyslot);
if (!jobj_keyslot)
return -EINVAL;
/* remove reencryption verification data */
LUKS2_digest_assign(cd, hdr, keyslot, CRYPT_ANY_DIGEST, 0, 0);
json_object_object_get_ex(jobj_keyslot, "area", &jobj_area);
json_object_object_get_ex(jobj_area, "type", &jobj_area_type);
if (rh->rp.type == REENC_PROTECTION_CHECKSUM) {
log_dbg(cd, "Updating reencrypt keyslot for checksum protection.");
json_object_object_add(jobj_area, "type", json_object_new_string("checksum"));
json_object_object_add(jobj_area, "hash", json_object_new_string(rh->rp.p.csum.hash));
json_object_object_add(jobj_area, "sector_size", json_object_new_int64(rh->alignment));
} else if (rh->rp.type == REENC_PROTECTION_NONE) {
log_dbg(cd, "Updating reencrypt keyslot for none protection.");
json_object_object_add(jobj_area, "type", json_object_new_string("none"));
json_object_object_del(jobj_area, "hash");
} else if (rh->rp.type == REENC_PROTECTION_JOURNAL) {
log_dbg(cd, "Updating reencrypt keyslot for journal protection.");
json_object_object_add(jobj_area, "type", json_object_new_string("journal"));
json_object_object_del(jobj_area, "hash");
} else
log_dbg(cd, "No update of reencrypt keyslot needed.");
return 0;
}
static int reenc_keyslot_wipe(struct crypt_device *cd, int keyslot)
{
return 0;
}
@@ -256,7 +230,7 @@ static int reenc_keyslot_dump(struct crypt_device *cd, int keyslot)
static int reenc_keyslot_validate(struct crypt_device *cd, json_object *jobj_keyslot)
{
json_object *jobj_mode, *jobj_area, *jobj_type, *jobj_shift_size, *jobj_hash, *jobj_sector_size, *jobj_direction;
json_object *jobj_mode, *jobj_area, *jobj_type, *jobj_shift_size, *jobj_hash, *jobj_sector_size, *jobj_direction, *jobj_key_size;
const char *mode, *type, *direction;
uint32_t sector_size;
uint64_t shift_size;
@@ -276,12 +250,18 @@ static int reenc_keyslot_validate(struct crypt_device *cd, json_object *jobj_key
!json_object_object_get_ex(jobj_area, "type", &jobj_type))
return -EINVAL;
jobj_key_size = json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "key_size", json_type_int);
jobj_mode = json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "mode", json_type_string);
jobj_direction = json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "direction", json_type_string);
if (!jobj_mode || !jobj_direction)
if (!jobj_mode || !jobj_direction || !jobj_key_size)
return -EINVAL;
if (!validate_json_uint32(jobj_key_size) || crypt_jobj_get_uint32(jobj_key_size) != 1) {
log_dbg(cd, "Illegal reencrypt key size.");
return -EINVAL;
}
mode = json_object_get_string(jobj_mode);
type = json_object_get_string(jobj_type);
direction = json_object_get_string(jobj_direction);

View File

@@ -573,7 +573,7 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
* It duplicates check in LUKS2_hdr_write() but we don't want to move
* keyslot areas in case it would fail later
*/
if (max_size < LUKS2_hdr_and_areas_size(hdr2->jobj)) {
if (max_size < LUKS2_hdr_and_areas_size(hdr2)) {
r = -EINVAL;
goto out;
}
@@ -595,7 +595,7 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
buf_size = luks1_size - LUKS_ALIGN_KEYSLOTS;
/* check future LUKS2 keyslots area is at least as large as LUKS1 keyslots area */
if (buf_size > LUKS2_keyslots_size(hdr2->jobj)) {
if (buf_size > LUKS2_keyslots_size(hdr2)) {
log_err(cd, _("Unable to move keyslot area. LUKS2 keyslots area too small."));
r = -EINVAL;
goto out;
@@ -883,7 +883,7 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
// move keyslots 32k -> 4k offset
buf_offset = 2 * LUKS2_HDR_16K_LEN;
buf_size = LUKS2_keyslots_size(hdr2->jobj);
buf_size = LUKS2_keyslots_size(hdr2);
r = move_keyslot_areas(cd, buf_offset, 8 * SECTOR_SIZE, buf_size);
if (r < 0) {
log_err(cd, _("Unable to move keyslot area."));

View File

@@ -22,6 +22,116 @@
#include "luks2_internal.h"
#include "utils_device_locking.h"
struct reenc_protection {
enum { REENC_PROTECTION_NONE = 0, /* none should be 0 always */
REENC_PROTECTION_CHECKSUM,
REENC_PROTECTION_JOURNAL,
REENC_PROTECTION_DATASHIFT } type;
union {
struct {
} none;
struct {
char hash[LUKS2_CHECKSUM_ALG_L]; // or include luks.h
struct crypt_hash *ch;
size_t hash_size;
/* buffer for checksums */
void *checksums;
size_t checksums_len;
} csum;
struct {
} ds;
} p;
};
struct luks2_reencrypt {
/* reencryption window attributes */
uint64_t offset;
uint64_t progress;
uint64_t length;
uint64_t data_shift;
size_t alignment;
uint64_t device_size;
bool online;
bool fixed_length;
crypt_reencrypt_direction_info direction;
crypt_reencrypt_mode_info mode;
char *device_name;
char *hotzone_name;
char *overlay_name;
uint32_t flags;
/* reencryption window persistence attributes */
struct reenc_protection rp;
int reenc_keyslot;
/* already running reencryption */
json_object *jobj_segs_hot;
struct json_object *jobj_segs_post;
/* backup segments */
json_object *jobj_segment_new;
int digest_new;
json_object *jobj_segment_old;
int digest_old;
json_object *jobj_segment_moved;
struct volume_key *vks;
void *reenc_buffer;
ssize_t read;
struct crypt_storage_wrapper *cw1;
struct crypt_storage_wrapper *cw2;
uint32_t wflags1;
uint32_t wflags2;
struct crypt_lock_handle *reenc_lock;
};
#if USE_LUKS2_REENCRYPTION
static int reencrypt_keyslot_update(struct crypt_device *cd,
const struct luks2_reencrypt *rh)
{
int r;
json_object *jobj_keyslot, *jobj_area, *jobj_area_type;
struct luks2_hdr *hdr;
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
return -EINVAL;
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, rh->reenc_keyslot);
if (!jobj_keyslot)
return -EINVAL;
json_object_object_get_ex(jobj_keyslot, "area", &jobj_area);
json_object_object_get_ex(jobj_area, "type", &jobj_area_type);
if (rh->rp.type == REENC_PROTECTION_CHECKSUM) {
log_dbg(cd, "Updating reencrypt keyslot for checksum protection.");
json_object_object_add(jobj_area, "type", json_object_new_string("checksum"));
json_object_object_add(jobj_area, "hash", json_object_new_string(rh->rp.p.csum.hash));
json_object_object_add(jobj_area, "sector_size", json_object_new_int64(rh->alignment));
} else if (rh->rp.type == REENC_PROTECTION_NONE) {
log_dbg(cd, "Updating reencrypt keyslot for none protection.");
json_object_object_add(jobj_area, "type", json_object_new_string("none"));
json_object_object_del(jobj_area, "hash");
} else if (rh->rp.type == REENC_PROTECTION_JOURNAL) {
log_dbg(cd, "Updating reencrypt keyslot for journal protection.");
json_object_object_add(jobj_area, "type", json_object_new_string("journal"));
json_object_object_del(jobj_area, "hash");
} else
log_dbg(cd, "No update of reencrypt keyslot needed.");
r = LUKS2_keyslot_reencrypt_digest_create(cd, hdr, rh->vks);
if (r < 0)
log_err(cd, "Failed to refresh reencryption verification digest.");
return r;
}
static json_object *reencrypt_segment(struct luks2_hdr *hdr, unsigned new)
{
return LUKS2_get_segment_by_flag(hdr, new ? "backup-final" : "backup-previous");
@@ -85,7 +195,7 @@ static uint64_t reencrypt_get_data_offset_old(struct luks2_hdr *hdr)
{
return reencrypt_data_offset(hdr, 0);
}
#endif
static int reencrypt_digest(struct luks2_hdr *hdr, unsigned new)
{
int segment = LUKS2_get_segment_id_by_flag(hdr, new ? "backup-final" : "backup-previous");
@@ -144,7 +254,7 @@ static const char *reencrypt_resilience_hash(struct luks2_hdr *hdr)
return json_object_get_string(jobj_hash);
}
#if USE_LUKS2_REENCRYPTION
static uint32_t reencrypt_alignment(struct luks2_hdr *hdr)
{
json_object *jobj_keyslot, *jobj_area, *jobj_type, *jobj_hash, *jobj_sector_size;
@@ -170,7 +280,7 @@ static uint32_t reencrypt_alignment(struct luks2_hdr *hdr)
static json_object *_enc_create_segments_shift_after(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct luks2_reenc_context *rh,
struct luks2_reencrypt *rh,
uint64_t data_offset)
{
int reenc_seg, i = 0;
@@ -217,7 +327,7 @@ err:
static json_object *reencrypt_make_hot_segments_encrypt_shift(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct luks2_reenc_context *rh,
struct luks2_reencrypt *rh,
uint64_t data_offset)
{
int sg, crypt_seg, i = 0;
@@ -281,7 +391,7 @@ err:
static json_object *reencrypt_make_segment_new(struct crypt_device *cd,
struct luks2_hdr *hdr,
const struct luks2_reenc_context *rh,
const struct luks2_reencrypt *rh,
uint64_t data_offset,
uint64_t segment_offset,
uint64_t iv_offset,
@@ -304,7 +414,7 @@ static json_object *reencrypt_make_segment_new(struct crypt_device *cd,
static json_object *reencrypt_make_post_segments_forward(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct luks2_reenc_context *rh,
struct luks2_reencrypt *rh,
uint64_t data_offset)
{
int reenc_seg;
@@ -350,7 +460,7 @@ err:
static json_object *reencrypt_make_post_segments_backward(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct luks2_reenc_context *rh,
struct luks2_reencrypt *rh,
uint64_t data_offset)
{
int reenc_seg;
@@ -386,7 +496,7 @@ err:
static json_object *reencrypt_make_segment_reencrypt(struct crypt_device *cd,
struct luks2_hdr *hdr,
const struct luks2_reenc_context *rh,
const struct luks2_reencrypt *rh,
uint64_t data_offset,
uint64_t segment_offset,
uint64_t iv_offset,
@@ -409,7 +519,7 @@ static json_object *reencrypt_make_segment_reencrypt(struct crypt_device *cd,
static json_object *reencrypt_make_segment_old(struct crypt_device *cd,
struct luks2_hdr *hdr,
const struct luks2_reenc_context *rh,
const struct luks2_reencrypt *rh,
uint64_t data_offset,
uint64_t segment_offset,
const uint64_t *segment_length)
@@ -435,7 +545,7 @@ static json_object *reencrypt_make_segment_old(struct crypt_device *cd,
static json_object *reencrypt_make_hot_segments_forward(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct luks2_reenc_context *rh,
struct luks2_reencrypt *rh,
uint64_t device_size,
uint64_t data_offset)
{
@@ -476,7 +586,7 @@ err:
static json_object *reencrypt_make_hot_segments_backward(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct luks2_reenc_context *rh,
struct luks2_reencrypt *rh,
uint64_t device_size,
uint64_t data_offset)
{
@@ -518,7 +628,7 @@ err:
static int reencrypt_make_hot_segments(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct luks2_reenc_context *rh,
struct luks2_reencrypt *rh,
uint64_t device_size,
uint64_t data_offset)
{
@@ -541,7 +651,7 @@ static int reencrypt_make_hot_segments(struct crypt_device *cd,
static int reencrypt_make_post_segments(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct luks2_reenc_context *rh,
struct luks2_reencrypt *rh,
uint64_t data_offset)
{
rh->jobj_segs_post = NULL;
@@ -560,7 +670,7 @@ static int reencrypt_make_post_segments(struct crypt_device *cd,
return rh->jobj_segs_post ? 0 : -EINVAL;
}
#endif
static uint64_t reencrypt_data_shift(struct luks2_hdr *hdr)
{
json_object *jobj_keyslot, *jobj_area, *jobj_data_shift;
@@ -622,7 +732,7 @@ static crypt_reencrypt_direction_info reencrypt_direction(struct luks2_hdr *hdr)
typedef enum { REENC_OK = 0, REENC_ERR, REENC_ROLLBACK, REENC_FATAL } reenc_status_t;
void LUKS2_reenc_context_free(struct crypt_device *cd, struct luks2_reenc_context *rh)
void LUKS2_reencrypt_free(struct crypt_device *cd, struct luks2_reencrypt *rh)
{
if (!rh)
return;
@@ -666,7 +776,7 @@ void LUKS2_reenc_context_free(struct crypt_device *cd, struct luks2_reenc_contex
crypt_unlock_internal(cd, rh->reenc_lock);
free(rh);
}
#if USE_LUKS2_REENCRYPTION
static size_t reencrypt_get_alignment(struct crypt_device *cd,
struct luks2_hdr *hdr)
{
@@ -685,7 +795,7 @@ static size_t reencrypt_get_alignment(struct crypt_device *cd,
/* returns void because it must not fail on valid LUKS2 header */
static void _load_backup_segments(struct luks2_hdr *hdr,
struct luks2_reenc_context *rh)
struct luks2_reencrypt *rh)
{
int segment = LUKS2_get_segment_id_by_flag(hdr, "backup-final");
@@ -819,7 +929,7 @@ static int reencrypt_offset(struct luks2_hdr *hdr,
static uint64_t reencrypt_length(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct luks2_reenc_context *rh,
struct luks2_reencrypt *rh,
uint64_t keyslot_area_length,
uint64_t length_max)
{
@@ -867,7 +977,7 @@ static uint64_t reencrypt_length(struct crypt_device *cd,
return length;
}
static int reencrypt_context_init(struct crypt_device *cd, struct luks2_hdr *hdr, struct luks2_reenc_context *rh, uint64_t device_size, const struct crypt_params_reencrypt *params)
static int reencrypt_context_init(struct crypt_device *cd, struct luks2_hdr *hdr, struct luks2_reencrypt *rh, uint64_t device_size, const struct crypt_params_reencrypt *params)
{
int r;
uint64_t dummy, area_length;
@@ -987,7 +1097,7 @@ static int reencrypt_context_init(struct crypt_device *cd, struct luks2_hdr *hdr
return rh->length < 512 ? -EINVAL : 0;
}
static size_t reencrypt_buffer_length(struct luks2_reenc_context *rh)
static size_t reencrypt_buffer_length(struct luks2_reencrypt *rh)
{
if (rh->data_shift)
return rh->data_shift;
@@ -997,7 +1107,7 @@ static size_t reencrypt_buffer_length(struct luks2_reenc_context *rh)
static int reencrypt_load_clean(struct crypt_device *cd,
struct luks2_hdr *hdr,
uint64_t device_size,
struct luks2_reenc_context **rh,
struct luks2_reencrypt **rh,
const struct crypt_params_reencrypt *params)
{
int r;
@@ -1006,7 +1116,7 @@ static int reencrypt_load_clean(struct crypt_device *cd,
.hash = reencrypt_resilience_hash(hdr),
.device_size = params ? params->device_size : 0
};
struct luks2_reenc_context *tmp = crypt_zalloc(sizeof (*tmp));
struct luks2_reencrypt *tmp = crypt_zalloc(sizeof (*tmp));
if (!tmp)
return -ENOMEM;
@@ -1038,14 +1148,14 @@ static int reencrypt_load_clean(struct crypt_device *cd,
return 0;
err:
LUKS2_reenc_context_free(cd, tmp);
LUKS2_reencrypt_free(cd, tmp);
return r;
}
static int reencrypt_make_segments(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct luks2_reenc_context *rh,
struct luks2_reencrypt *rh,
uint64_t device_size)
{
int r;
@@ -1068,7 +1178,7 @@ static int reencrypt_make_segments(struct crypt_device *cd,
static int reencrypt_make_segments_crashed(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct luks2_reenc_context *rh)
struct luks2_reencrypt *rh)
{
int r;
uint64_t data_offset = crypt_get_data_offset(cd) << SECTOR_SHIFT;
@@ -1096,7 +1206,7 @@ static int reencrypt_make_segments_crashed(struct crypt_device *cd,
}
static int reencrypt_load_crashed(struct crypt_device *cd,
struct luks2_hdr *hdr, uint64_t device_size, struct luks2_reenc_context **rh)
struct luks2_hdr *hdr, uint64_t device_size, struct luks2_reencrypt **rh)
{
bool dynamic;
uint64_t minimal_size;
@@ -1132,7 +1242,7 @@ static int reencrypt_load_crashed(struct crypt_device *cd,
r = reencrypt_make_segments_crashed(cd, hdr, *rh);
if (r) {
LUKS2_reenc_context_free(cd, *rh);
LUKS2_reencrypt_free(cd, *rh);
*rh = NULL;
}
return r;
@@ -1140,7 +1250,7 @@ static int reencrypt_load_crashed(struct crypt_device *cd,
static int reencrypt_init_storage_wrappers(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct luks2_reenc_context *rh,
struct luks2_reencrypt *rh,
struct volume_key *vks)
{
int r;
@@ -1178,7 +1288,7 @@ static int reencrypt_init_storage_wrappers(struct crypt_device *cd,
return 0;
}
static int reencrypt_context_set_names(struct luks2_reenc_context *rh, const char *name)
static int reencrypt_context_set_names(struct luks2_reencrypt *rh, const char *name)
{
if (!rh | !name)
return -EINVAL;
@@ -1251,7 +1361,7 @@ static int reencrypt_update_flag(struct crypt_device *cd, int enable, bool commi
static int reencrypt_recover_segment(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct luks2_reenc_context *rh,
struct luks2_reencrypt *rh,
struct volume_key *vks)
{
struct volume_key *vk_old, *vk_new;
@@ -1467,7 +1577,7 @@ out:
static int reencrypt_add_moved_segment(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct luks2_reenc_context *rh)
struct luks2_reencrypt *rh)
{
int s = LUKS2_segment_first_unused_id(hdr);
@@ -1487,7 +1597,7 @@ static int reencrypt_add_moved_segment(struct crypt_device *cd,
static int reencrypt_add_backup_segment(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct luks2_reenc_context *rh,
struct luks2_reencrypt *rh,
unsigned final)
{
int digest, s = LUKS2_segment_first_unused_id(hdr);
@@ -1512,7 +1622,7 @@ static int reencrypt_add_backup_segment(struct crypt_device *cd,
static int reencrypt_assign_segments_simple(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct luks2_reenc_context *rh,
struct luks2_reencrypt *rh,
unsigned hot,
unsigned commit)
{
@@ -1570,7 +1680,7 @@ static int reencrypt_assign_segments_simple(struct crypt_device *cd,
static int reencrypt_assign_segments(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct luks2_reenc_context *rh,
struct luks2_reencrypt *rh,
unsigned hot,
unsigned commit)
{
@@ -1955,7 +2065,7 @@ err:
}
static int reencrypt_init_device_stack(struct crypt_device *cd,
const struct luks2_reenc_context *rh)
const struct luks2_reencrypt *rh)
{
int r;
@@ -2310,9 +2420,11 @@ static int reencrypt_init(struct crypt_device *cd,
}
if (!cipher_mode || *cipher_mode == '\0')
snprintf(_cipher, sizeof(_cipher), "%s", cipher);
r = snprintf(_cipher, sizeof(_cipher), "%s", cipher);
else
snprintf(_cipher, sizeof(_cipher), "%s-%s", cipher, cipher_mode);
r = snprintf(_cipher, sizeof(_cipher), "%s-%s", cipher, cipher_mode);
if (r < 0 || (size_t)r >= sizeof(_cipher))
return -EINVAL;
if (MISALIGNED(params->data_shift, sector_size >> SECTOR_SHIFT)) {
log_err(cd, _("Data shift is not aligned to requested encryption sector size (%" PRIu32 " bytes)."), sector_size);
@@ -2375,7 +2487,7 @@ static int reencrypt_init(struct crypt_device *cd,
goto err;
}
r = LUKS2_keyslot_reencrypt_create(cd, hdr, reencrypt_keyslot,
r = LUKS2_keyslot_reencrypt_allocate(cd, hdr, reencrypt_keyslot,
params);
if (r < 0)
goto err;
@@ -2390,6 +2502,10 @@ static int reencrypt_init(struct crypt_device *cd,
if (r < 0)
goto err;
r = LUKS2_keyslot_reencrypt_digest_create(cd, hdr, *vks);
if (r < 0)
goto err;
if (name && params->mode != CRYPT_REENCRYPT_ENCRYPT) {
r = reencrypt_verify_and_upload_keys(cd, hdr, LUKS2_reencrypt_digest_old(hdr), LUKS2_reencrypt_digest_new(hdr), *vks);
if (r)
@@ -2437,7 +2553,7 @@ err:
}
static int reencrypt_hotzone_protect_final(struct crypt_device *cd,
struct luks2_hdr *hdr, struct luks2_reenc_context *rh,
struct luks2_hdr *hdr, struct luks2_reencrypt *rh,
const void *buffer, size_t buffer_len)
{
const void *pbuffer;
@@ -2479,7 +2595,7 @@ static int reencrypt_hotzone_protect_final(struct crypt_device *cd,
}
static int reencrypt_context_update(struct crypt_device *cd,
struct luks2_reenc_context *rh)
struct luks2_reencrypt *rh)
{
if (rh->read < 0)
return -EINVAL;
@@ -2520,20 +2636,28 @@ static int reencrypt_context_update(struct crypt_device *cd,
static int reencrypt_load(struct crypt_device *cd, struct luks2_hdr *hdr,
uint64_t device_size,
const struct crypt_params_reencrypt *params,
struct luks2_reenc_context **rh)
struct volume_key *vks,
struct luks2_reencrypt **rh)
{
int r;
struct luks2_reenc_context *tmp = NULL;
crypt_reencrypt_info ri = LUKS2_reenc_status(hdr);
struct luks2_reencrypt *tmp = NULL;
crypt_reencrypt_info ri = LUKS2_reencrypt_status(hdr);
if (ri == CRYPT_REENCRYPT_NONE) {
log_err(cd, _("Device not marked for LUKS2 reencryption."));
return -EINVAL;
} else if (ri == CRYPT_REENCRYPT_INVALID)
return -EINVAL;
r = LUKS2_reencrypt_digest_verify(cd, hdr, vks);
if (r < 0)
return r;
if (ri == CRYPT_REENCRYPT_CLEAN)
r = reencrypt_load_clean(cd, hdr, device_size, &tmp, params);
else if (ri == CRYPT_REENCRYPT_CRASH)
r = reencrypt_load_crashed(cd, hdr, device_size, &tmp);
else if (ri == CRYPT_REENCRYPT_NONE) {
log_err(cd, _("Device not marked for LUKS2 reencryption."));
return -EINVAL;
} else
else
r = -EINVAL;
if (r < 0 || !tmp) {
@@ -2545,7 +2669,7 @@ static int reencrypt_load(struct crypt_device *cd, struct luks2_hdr *hdr,
return 0;
}
#endif
static int reencrypt_lock_internal(struct crypt_device *cd, const char *uuid, struct crypt_lock_handle **reencrypt_lock)
{
int r;
@@ -2572,7 +2696,8 @@ out:
}
/* internal only */
int crypt_reencrypt_lock_by_dm_uuid(struct crypt_device *cd, const char *dm_uuid, struct crypt_lock_handle **reencrypt_lock)
int LUKS2_reencrypt_lock_by_dm_uuid(struct crypt_device *cd, const char *dm_uuid,
struct crypt_lock_handle **reencrypt_lock)
{
int r;
char hdr_uuid[37];
@@ -2593,7 +2718,7 @@ int crypt_reencrypt_lock_by_dm_uuid(struct crypt_device *cd, const char *dm_uuid
}
/* internal only */
int crypt_reencrypt_lock(struct crypt_device *cd, struct crypt_lock_handle **reencrypt_lock)
int LUKS2_reencrypt_lock(struct crypt_device *cd, struct crypt_lock_handle **reencrypt_lock)
{
if (!cd || !crypt_get_type(cd) || strcmp(crypt_get_type(cd), CRYPT_LUKS2))
return -EINVAL;
@@ -2602,11 +2727,11 @@ int crypt_reencrypt_lock(struct crypt_device *cd, struct crypt_lock_handle **ree
}
/* internal only */
void crypt_reencrypt_unlock(struct crypt_device *cd, struct crypt_lock_handle *reencrypt_lock)
void LUKS2_reencrypt_unlock(struct crypt_device *cd, struct crypt_lock_handle *reencrypt_lock)
{
crypt_unlock_internal(cd, reencrypt_lock);
}
#if USE_LUKS2_REENCRYPTION
static int reencrypt_lock_and_verify(struct crypt_device *cd, struct luks2_hdr *hdr,
struct crypt_lock_handle **reencrypt_lock)
{
@@ -2614,7 +2739,7 @@ static int reencrypt_lock_and_verify(struct crypt_device *cd, struct luks2_hdr *
crypt_reencrypt_info ri;
struct crypt_lock_handle *h;
ri = LUKS2_reenc_status(hdr);
ri = LUKS2_reencrypt_status(hdr);
if (ri == CRYPT_REENCRYPT_INVALID) {
log_err(cd, _("Failed to get reencryption state."));
return -EINVAL;
@@ -2624,7 +2749,7 @@ static int reencrypt_lock_and_verify(struct crypt_device *cd, struct luks2_hdr *
return -EINVAL;
}
r = crypt_reencrypt_lock(cd, &h);
r = LUKS2_reencrypt_lock(cd, &h);
if (r < 0) {
if (r == -EBUSY)
log_err(cd, _("Reencryption process is already running."));
@@ -2636,17 +2761,17 @@ static int reencrypt_lock_and_verify(struct crypt_device *cd, struct luks2_hdr *
/* With reencryption lock held, reload device context and verify metadata state */
r = crypt_load(cd, CRYPT_LUKS2, NULL);
if (r) {
crypt_reencrypt_unlock(cd, h);
LUKS2_reencrypt_unlock(cd, h);
return r;
}
ri = LUKS2_reenc_status(hdr);
ri = LUKS2_reencrypt_status(hdr);
if (ri == CRYPT_REENCRYPT_CLEAN) {
*reencrypt_lock = h;
return 0;
}
crypt_reencrypt_unlock(cd, h);
LUKS2_reencrypt_unlock(cd, h);
log_err(cd, _("Cannot proceed with reencryption. Run reencryption recovery first."));
return -EINVAL;
}
@@ -2663,7 +2788,7 @@ static int reencrypt_load_by_passphrase(struct crypt_device *cd,
int r, old_ss, new_ss;
struct luks2_hdr *hdr;
struct crypt_lock_handle *reencrypt_lock;
struct luks2_reenc_context *rh;
struct luks2_reencrypt *rh;
const struct volume_key *vk;
struct crypt_dm_active_device dmd_target, dmd_source = {
.uuid = crypt_get_uuid(cd),
@@ -2681,10 +2806,10 @@ static int reencrypt_load_by_passphrase(struct crypt_device *cd,
log_dbg(cd, "Loading LUKS2 reencryption context.");
rh = crypt_get_reenc_context(cd);
rh = crypt_get_luks2_reencrypt(cd);
if (rh) {
LUKS2_reenc_context_free(cd, rh);
crypt_set_reenc_context(cd, NULL);
LUKS2_reencrypt_free(cd, rh);
crypt_set_luks2_reencrypt(cd, NULL);
rh = NULL;
}
@@ -2700,7 +2825,7 @@ static int reencrypt_load_by_passphrase(struct crypt_device *cd,
return -EINVAL;
/* some configurations provides fixed device size */
r = luks2_check_device_size(cd, hdr, minimal_size, &device_size, false, dynamic);
r = LUKS2_reencrypt_check_device_size(cd, hdr, minimal_size, &device_size, false, dynamic);
if (r) {
r = -EINVAL;
goto err;
@@ -2781,7 +2906,7 @@ static int reencrypt_load_by_passphrase(struct crypt_device *cd,
rparams.device_size = required_size;
}
r = reencrypt_load(cd, hdr, device_size, &rparams, &rh);
r = reencrypt_load(cd, hdr, device_size, &rparams, *vks, &rh);
if (r < 0 || !rh)
goto err;
@@ -2822,12 +2947,12 @@ static int reencrypt_load_by_passphrase(struct crypt_device *cd,
MOVE_REF(rh->vks, *vks);
MOVE_REF(rh->reenc_lock, reencrypt_lock);
crypt_set_reenc_context(cd, rh);
crypt_set_luks2_reencrypt(cd, rh);
return 0;
err:
crypt_reencrypt_unlock(cd, reencrypt_lock);
LUKS2_reenc_context_free(cd, rh);
LUKS2_reencrypt_unlock(cd, reencrypt_lock);
LUKS2_reencrypt_free(cd, rh);
return r;
}
@@ -2842,7 +2967,7 @@ static int reencrypt_recovery_by_passphrase(struct crypt_device *cd,
crypt_reencrypt_info ri;
struct crypt_lock_handle *reencrypt_lock;
r = crypt_reencrypt_lock(cd, &reencrypt_lock);
r = LUKS2_reencrypt_lock(cd, &reencrypt_lock);
if (r) {
if (r == -EBUSY)
log_err(cd, _("Reencryption in-progress. Cannot perform recovery."));
@@ -2852,13 +2977,13 @@ static int reencrypt_recovery_by_passphrase(struct crypt_device *cd,
}
if ((r = crypt_load(cd, CRYPT_LUKS2, NULL))) {
crypt_reencrypt_unlock(cd, reencrypt_lock);
LUKS2_reencrypt_unlock(cd, reencrypt_lock);
return r;
}
ri = LUKS2_reenc_status(hdr);
ri = LUKS2_reencrypt_status(hdr);
if (ri == CRYPT_REENCRYPT_INVALID) {
crypt_reencrypt_unlock(cd, reencrypt_lock);
LUKS2_reencrypt_unlock(cd, reencrypt_lock);
return -EINVAL;
}
@@ -2872,10 +2997,89 @@ static int reencrypt_recovery_by_passphrase(struct crypt_device *cd,
r = 0;
}
crypt_reencrypt_unlock(cd, reencrypt_lock);
LUKS2_reencrypt_unlock(cd, reencrypt_lock);
return r;
}
static int reencrypt_repair_by_passphrase(
struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot_old,
int keyslot_new,
const char *passphrase,
size_t passphrase_size)
{
int r;
struct crypt_lock_handle *reencrypt_lock;
struct luks2_reencrypt *rh;
crypt_reencrypt_info ri;
struct volume_key *vks = NULL;
log_dbg(cd, "Loading LUKS2 reencryption context for metadata repair.");
rh = crypt_get_luks2_reencrypt(cd);
if (rh) {
LUKS2_reencrypt_free(cd, rh);
crypt_set_luks2_reencrypt(cd, NULL);
rh = NULL;
}
ri = LUKS2_reencrypt_status(hdr);
if (ri == CRYPT_REENCRYPT_INVALID)
return -EINVAL;
if (ri < CRYPT_REENCRYPT_CLEAN) {
log_err(cd, _("Device is not in reencryption."));
return -EINVAL;
}
r = LUKS2_reencrypt_lock(cd, &reencrypt_lock);
if (r < 0) {
if (r == -EBUSY)
log_err(cd, _("Reencryption process is already running."));
else
log_err(cd, _("Failed to acquire reencryption lock."));
return r;
}
/* With reencryption lock held, reload device context and verify metadata state */
r = crypt_load(cd, CRYPT_LUKS2, NULL);
if (r)
goto out;
ri = LUKS2_reencrypt_status(hdr);
if (ri == CRYPT_REENCRYPT_INVALID) {
r = -EINVAL;
goto out;
}
if (ri == CRYPT_REENCRYPT_NONE) {
r = 0;
goto out;
}
r = LUKS2_keyslot_open_all_segments(cd, keyslot_old, keyslot_new, passphrase, passphrase_size, &vks);
if (r < 0)
goto out;
r = LUKS2_keyslot_reencrypt_digest_create(cd, hdr, vks);
crypt_free_volume_key(vks);
vks = NULL;
if (r < 0)
goto out;
/* removes online-reencrypt flag v1 */
if ((r = reencrypt_update_flag(cd, 0, false)))
goto out;
/* adds online-reencrypt flag v2 and commits metadata */
r = reencrypt_update_flag(cd, 1, true);
out:
LUKS2_reencrypt_unlock(cd, reencrypt_lock);
crypt_free_volume_key(vks);
return r;
}
#endif
static int reencrypt_init_by_passphrase(struct crypt_device *cd,
const char *name,
const char *passphrase,
@@ -2886,12 +3090,17 @@ static int reencrypt_init_by_passphrase(struct crypt_device *cd,
const char *cipher_mode,
const struct crypt_params_reencrypt *params)
{
#if USE_LUKS2_REENCRYPTION
int r;
crypt_reencrypt_info ri;
struct volume_key *vks = NULL;
uint32_t flags = params ? params->flags : 0;
struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
/* short-circuit in reencryption metadata update and finish immediately. */
if (flags & CRYPT_REENCRYPT_REPAIR_NEEDED)
return reencrypt_repair_by_passphrase(cd, hdr, keyslot_old, keyslot_new, passphrase, passphrase_size);
/* short-circuit in recovery and finish immediately. */
if (flags & CRYPT_REENCRYPT_RECOVERY)
return reencrypt_recovery_by_passphrase(cd, hdr, keyslot_old, keyslot_new, passphrase, passphrase_size);
@@ -2909,7 +3118,7 @@ static int reencrypt_init_by_passphrase(struct crypt_device *cd,
if (r)
return r;
ri = LUKS2_reenc_status(hdr);
ri = LUKS2_reencrypt_status(hdr);
if (ri == CRYPT_REENCRYPT_INVALID) {
device_write_unlock(cd, crypt_metadata_device(cd));
return -EINVAL;
@@ -2941,6 +3150,10 @@ out:
crypt_drop_keyring_key(cd, vks);
crypt_free_volume_key(vks);
return r < 0 ? r : LUKS2_find_keyslot(hdr, "reencrypt");
#else
log_err(cd, _("This operation is not supported for this device type."));
return -ENOTSUP;
#endif
}
int crypt_reencrypt_init_by_keyring(struct crypt_device *cd,
@@ -2993,21 +3206,15 @@ int crypt_reencrypt_init_by_passphrase(struct crypt_device *cd,
return reencrypt_init_by_passphrase(cd, name, passphrase, passphrase_size, keyslot_old, keyslot_new, cipher, cipher_mode, params);
}
#if USE_LUKS2_REENCRYPTION
static reenc_status_t reencrypt_step(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct luks2_reenc_context *rh,
struct luks2_reencrypt *rh,
uint64_t device_size,
bool online)
{
int r;
/* update reencrypt keyslot protection parameters in memory only */
r = reenc_keyslot_update(cd, rh);
if (r < 0) {
log_dbg(cd, "Keyslot update failed.");
return REENC_ERR;
}
/* in memory only */
r = reencrypt_make_segments(cd, hdr, rh, device_size);
if (r)
@@ -3124,7 +3331,7 @@ static int reencrypt_erase_backup_segments(struct crypt_device *cd,
return 0;
}
static int reencrypt_wipe_moved_segment(struct crypt_device *cd, struct luks2_hdr *hdr, struct luks2_reenc_context *rh)
static int reencrypt_wipe_moved_segment(struct crypt_device *cd, struct luks2_hdr *hdr, struct luks2_reencrypt *rh)
{
int r = 0;
uint64_t offset, length;
@@ -3141,7 +3348,7 @@ static int reencrypt_wipe_moved_segment(struct crypt_device *cd, struct luks2_hd
return r;
}
static int reencrypt_teardown_ok(struct crypt_device *cd, struct luks2_hdr *hdr, struct luks2_reenc_context *rh)
static int reencrypt_teardown_ok(struct crypt_device *cd, struct luks2_hdr *hdr, struct luks2_reencrypt *rh)
{
int i, r;
uint32_t dmt_flags;
@@ -3177,21 +3384,26 @@ static int reencrypt_teardown_ok(struct crypt_device *cd, struct luks2_hdr *hdr,
log_dbg(cd, "Failed to set new keyslots area size.");
if (rh->digest_old >= 0 && rh->digest_new != rh->digest_old)
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++)
if (LUKS2_digest_by_keyslot(hdr, i) == rh->digest_old)
crypt_keyslot_destroy(cd, i);
crypt_keyslot_destroy(cd, rh->reenc_keyslot);
if (LUKS2_digest_by_keyslot(hdr, i) == rh->digest_old && crypt_keyslot_destroy(cd, i))
log_err(cd, _("Failed to remove unused (unbound) keyslot %d."), i);
if (reencrypt_erase_backup_segments(cd, hdr))
log_dbg(cd, "Failed to erase backup segments");
/* do we need atomic erase? */
if (reencrypt_update_flag(cd, 0, true))
log_err(cd, _("Failed to disable reencryption requirement flag."));
if (reencrypt_update_flag(cd, 0, false))
log_dbg(cd, "Failed to disable reencryption requirement flag.");
/* metadata commit point also removing reencryption flag on-disk */
if (crypt_keyslot_destroy(cd, rh->reenc_keyslot)) {
log_err(cd, _("Failed to remove reencryption keyslot."));
return -EINVAL;
}
}
return 0;
}
static void reencrypt_teardown_fatal(struct crypt_device *cd, struct luks2_hdr *hdr, struct luks2_reenc_context *rh)
static void reencrypt_teardown_fatal(struct crypt_device *cd, struct luks2_hdr *hdr, struct luks2_reencrypt *rh)
{
log_err(cd, _("Fatal error while reencrypting chunk starting at %" PRIu64 ", %" PRIu64 " sectors long."),
(rh->offset >> SECTOR_SHIFT) + crypt_get_data_offset(cd), rh->length >> SECTOR_SHIFT);
@@ -3209,7 +3421,7 @@ static void reencrypt_teardown_fatal(struct crypt_device *cd, struct luks2_hdr *
}
static int reencrypt_teardown(struct crypt_device *cd, struct luks2_hdr *hdr,
struct luks2_reenc_context *rh, reenc_status_t rs, bool interrupted,
struct luks2_reencrypt *rh, reenc_status_t rs, bool interrupted,
int (*progress)(uint64_t size, uint64_t offset, void *usrptr))
{
int r;
@@ -3228,19 +3440,20 @@ static int reencrypt_teardown(struct crypt_device *cd, struct luks2_hdr *hdr,
}
/* this frees reencryption lock */
LUKS2_reenc_context_free(cd, rh);
crypt_set_reenc_context(cd, NULL);
LUKS2_reencrypt_free(cd, rh);
crypt_set_luks2_reencrypt(cd, NULL);
return r;
}
#endif
int crypt_reencrypt(struct crypt_device *cd,
int (*progress)(uint64_t size, uint64_t offset, void *usrptr))
{
#if USE_LUKS2_REENCRYPTION
int r;
crypt_reencrypt_info ri;
struct luks2_hdr *hdr;
struct luks2_reenc_context *rh;
struct luks2_reencrypt *rh;
reenc_status_t rs;
bool quit = false;
@@ -3249,13 +3462,13 @@ int crypt_reencrypt(struct crypt_device *cd,
hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
ri = LUKS2_reenc_status(hdr);
ri = LUKS2_reencrypt_status(hdr);
if (ri > CRYPT_REENCRYPT_CLEAN) {
log_err(cd, _("Cannot proceed with reencryption. Unexpected reencryption status."));
return -EINVAL;
}
rh = crypt_get_reenc_context(cd);
rh = crypt_get_luks2_reencrypt(cd);
if (!rh || (!rh->reenc_lock && crypt_metadata_locking_enabled())) {
log_err(cd, _("Missing or invalid reencrypt context."));
return -EINVAL;
@@ -3272,6 +3485,15 @@ int crypt_reencrypt(struct crypt_device *cd,
rs = REENC_OK;
/* update reencrypt keyslot protection parameters in memory only */
if (!quit && (rh->device_size > rh->progress)) {
r = reencrypt_keyslot_update(cd, rh);
if (r < 0) {
log_dbg(cd, "Keyslot update failed.");
return reencrypt_teardown(cd, hdr, rh, REENC_ERR, quit, progress);
}
}
while (!quit && (rh->device_size > rh->progress)) {
rs = reencrypt_step(cd, hdr, rh, rh->device_size, rh->online);
if (rs != REENC_OK)
@@ -3294,17 +3516,22 @@ int crypt_reencrypt(struct crypt_device *cd,
r = reencrypt_teardown(cd, hdr, rh, rs, quit, progress);
return r;
#else
log_err(cd, _("This operation is not supported for this device type."));
return -ENOTSUP;
#endif
}
#if USE_LUKS2_REENCRYPTION
static int reencrypt_recovery(struct crypt_device *cd,
struct luks2_hdr *hdr,
uint64_t device_size,
struct volume_key *vks)
{
int r;
struct luks2_reenc_context *rh = NULL;
struct luks2_reencrypt *rh = NULL;
r = reencrypt_load(cd, hdr, device_size, NULL, &rh);
r = reencrypt_load(cd, hdr, device_size, NULL, vks, &rh);
if (r < 0) {
log_err(cd, _("Failed to load LUKS2 reencryption context."));
return r;
@@ -3327,18 +3554,18 @@ static int reencrypt_recovery(struct crypt_device *cd,
if (!r)
r = LUKS2_hdr_write(cd, hdr);
err:
LUKS2_reenc_context_free(cd, rh);
LUKS2_reencrypt_free(cd, rh);
return r;
}
#endif
/*
* use only for calculation of minimal data device size.
* The real data offset is taken directly from segments!
*/
int LUKS2_reencrypt_data_offset(struct luks2_hdr *hdr, bool blockwise)
{
crypt_reencrypt_info ri = LUKS2_reenc_status(hdr);
crypt_reencrypt_info ri = LUKS2_reencrypt_status(hdr);
uint64_t data_offset = LUKS2_get_data_offset(hdr);
if (ri == CRYPT_REENCRYPT_CLEAN && reencrypt_direction(hdr) == CRYPT_REENCRYPT_FORWARD)
@@ -3348,7 +3575,8 @@ int LUKS2_reencrypt_data_offset(struct luks2_hdr *hdr, bool blockwise)
}
/* internal only */
int luks2_check_device_size(struct crypt_device *cd, struct luks2_hdr *hdr, uint64_t check_size, uint64_t *dev_size, bool activation, bool dynamic)
int LUKS2_reencrypt_check_device_size(struct crypt_device *cd, struct luks2_hdr *hdr,
uint64_t check_size, uint64_t *dev_size, bool activation, bool dynamic)
{
int r;
uint64_t data_offset, real_size = 0;
@@ -3386,7 +3614,7 @@ int luks2_check_device_size(struct crypt_device *cd, struct luks2_hdr *hdr, uint
return 0;
}
#if USE_LUKS2_REENCRYPTION
/* returns keyslot number on success (>= 0) or negative errnor otherwise */
int LUKS2_reencrypt_locked_recovery_by_passphrase(struct crypt_device *cd,
int keyslot_old,
@@ -3422,7 +3650,7 @@ int LUKS2_reencrypt_locked_recovery_by_passphrase(struct crypt_device *cd,
vk = crypt_volume_key_next(vk);
}
if (luks2_check_device_size(cd, hdr, minimal_size, &device_size, true, false))
if (LUKS2_reencrypt_check_device_size(cd, hdr, minimal_size, &device_size, true, false))
goto err;
r = reencrypt_recovery(cd, hdr, device_size, _vks);
@@ -3436,16 +3664,32 @@ err:
return r < 0 ? r : keyslot;
}
crypt_reencrypt_info LUKS2_reencrypt_status(struct crypt_device *cd, struct crypt_params_reencrypt *params)
#endif
crypt_reencrypt_info LUKS2_reencrypt_get_params(struct luks2_hdr *hdr,
struct crypt_params_reencrypt *params)
{
crypt_reencrypt_info ri;
struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
int digest;
uint32_t version;
ri = LUKS2_reenc_status(hdr);
ri = LUKS2_reencrypt_status(hdr);
if (ri == CRYPT_REENCRYPT_NONE || ri == CRYPT_REENCRYPT_INVALID || !params)
return ri;
digest = LUKS2_digest_by_keyslot(hdr, LUKS2_find_keyslot(hdr, "reencrypt"));
if (digest < 0 && digest != -ENOENT)
return CRYPT_REENCRYPT_INVALID;
/*
* In case there's an old "online-reencrypt" requirement or reencryption
* keyslot digest is missing inform caller reencryption metadata requires repair.
*/
if (!LUKS2_config_get_reencrypt_version(hdr, &version) &&
(version < 2 || digest == -ENOENT)) {
params->flags |= CRYPT_REENCRYPT_REPAIR_NEEDED;
return ri;
}
params->mode = reencrypt_mode(hdr);
params->direction = reencrypt_direction(hdr);
params->resilience = reencrypt_resilience_type(hdr);

View File

@@ -0,0 +1,381 @@
/*
* LUKS - Linux Unified Key Setup v2, reencryption digest helpers
*
* Copyright (C) 2022, Red Hat, Inc. All rights reserved.
* Copyright (C) 2022, Ondrej Kozina
* Copyright (C) 2022, Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "luks2_internal.h"
#include <assert.h>
#define MAX_STR 64
struct jtype {
enum { JNONE = 0, JSTR, JU64, JX64, JU32 } type;
json_object *jobj;
const char *id;
};
static size_t sr(struct jtype *j, uint8_t *ptr)
{
json_object *jobj;
size_t len = 0;
uint64_t u64;
uint32_t u32;
if (!json_object_is_type(j->jobj, json_type_object))
return 0;
if (!json_object_object_get_ex(j->jobj, j->id, &jobj))
return 0;
switch(j->type) {
case JSTR: /* JSON string */
if (!json_object_is_type(jobj, json_type_string))
return 0;
len = strlen(json_object_get_string(jobj));
if (len > MAX_STR)
return 0;
if (ptr)
memcpy(ptr, json_object_get_string(jobj), len);
break;
case JU64: /* Unsigned 64bit integer stored as string */
if (!json_object_is_type(jobj, json_type_string))
break;
len = sizeof(u64);
if (ptr) {
u64 = cpu_to_be64(crypt_jobj_get_uint64(jobj));
memcpy(ptr, &u64, len);
}
break;
case JX64: /* Unsigned 64bit segment size (allows "dynamic") */
if (!json_object_is_type(jobj, json_type_string))
break;
if (!strcmp(json_object_get_string(jobj), "dynamic")) {
len = strlen("dynamic");
if (ptr)
memcpy(ptr, json_object_get_string(jobj), len);
} else {
len = sizeof(u64);
u64 = cpu_to_be64(crypt_jobj_get_uint64(jobj));
if (ptr)
memcpy(ptr, &u64, len);
}
break;
case JU32: /* Unsigned 32bit integer, stored as JSON int */
if (!json_object_is_type(jobj, json_type_int))
return 0;
len = sizeof(u32);
if (ptr) {
u32 = cpu_to_be32(crypt_jobj_get_uint32(jobj));
memcpy(ptr, &u32, len);
}
break;
case JNONE:
return 0;
};
return len;
}
static size_t srs(struct jtype j[], uint8_t *ptr)
{
size_t l, len = 0;
while(j->jobj) {
l = sr(j, ptr);
if (!l)
return 0;
len += l;
if (ptr)
ptr += l;
j++;
}
return len;
}
static size_t segment_linear_serialize(json_object *jobj_segment, uint8_t *buffer)
{
struct jtype j[] = {
{ JSTR, jobj_segment, "type" },
{ JU64, jobj_segment, "offset" },
{ JX64, jobj_segment, "size" },
{}
};
return srs(j, buffer);
}
static size_t segment_crypt_serialize(json_object *jobj_segment, uint8_t *buffer)
{
struct jtype j[] = {
{ JSTR, jobj_segment, "type" },
{ JU64, jobj_segment, "offset" },
{ JX64, jobj_segment, "size" },
{ JU64, jobj_segment, "iv_tweak" },
{ JSTR, jobj_segment, "encryption" },
{ JU32, jobj_segment, "sector_size" },
{}
};
return srs(j, buffer);
}
static size_t segment_serialize(json_object *jobj_segment, uint8_t *buffer)
{
json_object *jobj_type;
const char *segment_type;
if (!json_object_object_get_ex(jobj_segment, "type", &jobj_type))
return 0;
if (!(segment_type = json_object_get_string(jobj_type)))
return 0;
if (!strcmp(segment_type, "crypt"))
return segment_crypt_serialize(jobj_segment, buffer);
else if (!strcmp(segment_type, "linear"))
return segment_linear_serialize(jobj_segment, buffer);
return 0;
}
static size_t backup_segments_serialize(struct luks2_hdr *hdr, uint8_t *buffer)
{
json_object *jobj_segment;
size_t l, len = 0;
jobj_segment = LUKS2_get_segment_by_flag(hdr, "backup-previous");
if (!jobj_segment || !(l = segment_serialize(jobj_segment, buffer)))
return 0;
len += l;
if (buffer)
buffer += l;
jobj_segment = LUKS2_get_segment_by_flag(hdr, "backup-final");
if (!jobj_segment || !(l = segment_serialize(jobj_segment, buffer)))
return 0;
len += l;
if (buffer)
buffer += l;
jobj_segment = LUKS2_get_segment_by_flag(hdr, "backup-moved-segment");
if (jobj_segment) {
if (!(l = segment_serialize(jobj_segment, buffer)))
return 0;
len += l;
}
return len;
}
static size_t reenc_keyslot_serialize(struct luks2_hdr *hdr, uint8_t *buffer)
{
json_object *jobj_keyslot, *jobj_area, *jobj_type;
const char *area_type;
int keyslot_reencrypt;
keyslot_reencrypt = LUKS2_find_keyslot(hdr, "reencrypt");
if (keyslot_reencrypt < 0)
return 0;
if (!(jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot_reencrypt)))
return 0;
if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
return 0;
if (!json_object_object_get_ex(jobj_area, "type", &jobj_type))
return 0;
if (!(area_type = json_object_get_string(jobj_type)))
return 0;
struct jtype j[] = {
{ JSTR, jobj_keyslot, "mode" },
{ JSTR, jobj_keyslot, "direction" },
{ JSTR, jobj_area, "type" },
{ JU64, jobj_area, "offset" },
{ JU64, jobj_area, "size" },
{}
};
struct jtype j_datashift[] = {
{ JSTR, jobj_keyslot, "mode" },
{ JSTR, jobj_keyslot, "direction" },
{ JSTR, jobj_area, "type" },
{ JU64, jobj_area, "offset" },
{ JU64, jobj_area, "size" },
{ JU64, jobj_area, "shift_size" },
{}
};
struct jtype j_checksum[] = {
{ JSTR, jobj_keyslot, "mode" },
{ JSTR, jobj_keyslot, "direction" },
{ JSTR, jobj_area, "type" },
{ JU64, jobj_area, "offset" },
{ JU64, jobj_area, "size" },
{ JSTR, jobj_area, "hash" },
{ JU32, jobj_area, "sector_size" },
{}
};
if (!strcmp(area_type, "datashift"))
return srs(j_datashift, buffer);
else if (!strcmp(area_type, "checksum"))
return srs(j_checksum, buffer);
return srs(j, buffer);
}
static size_t blob_serialize(void *blob, size_t length, uint8_t *buffer)
{
if (buffer)
memcpy(buffer, blob, length);
return length;
}
static int reencrypt_assembly_verification_data(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct volume_key *vks,
struct volume_key **verification_data)
{
uint8_t *ptr;
int digest_new, digest_old;
struct volume_key *data = NULL, *vk_old = NULL, *vk_new = NULL;
size_t keyslot_data_len, segments_data_len, data_len = 2;
/* Keys - calculate length */
digest_new = LUKS2_reencrypt_digest_new(hdr);
digest_old = LUKS2_reencrypt_digest_old(hdr);
if (digest_old >= 0) {
vk_old = crypt_volume_key_by_id(vks, digest_old);
if (!vk_old)
return -EINVAL;
data_len += blob_serialize(vk_old->key, vk_old->keylength, NULL);
}
if (digest_new >= 0 && digest_old != digest_new) {
vk_new = crypt_volume_key_by_id(vks, digest_new);
if (!vk_new)
return -EINVAL;
data_len += blob_serialize(vk_new->key, vk_new->keylength, NULL);
}
if (data_len == 2)
return -EINVAL;
/* Metadata - calculate length */
if (!(keyslot_data_len = reenc_keyslot_serialize(hdr, NULL)))
return -EINVAL;
data_len += keyslot_data_len;
if (!(segments_data_len = backup_segments_serialize(hdr, NULL)))
return -EINVAL;
data_len += segments_data_len;
/* Alloc and fill serialization data */
data = crypt_alloc_volume_key(data_len, NULL);
if (!data)
return -ENOMEM;
ptr = (uint8_t*)data->key;
/* v2 */
*ptr++ = 0x76;
*ptr++ = 0x32;
if (vk_old)
ptr += blob_serialize(vk_old->key, vk_old->keylength, ptr);
if (vk_new)
ptr += blob_serialize(vk_new->key, vk_new->keylength, ptr);
if (!reenc_keyslot_serialize(hdr, ptr))
goto bad;
ptr += keyslot_data_len;
if (!backup_segments_serialize(hdr, ptr))
goto bad;
ptr += segments_data_len;
assert((size_t)(ptr - (uint8_t*)data->key) == data_len);
*verification_data = data;
return 0;
bad:
crypt_free_volume_key(data);
return -EINVAL;
}
int LUKS2_keyslot_reencrypt_digest_create(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct volume_key *vks)
{
int digest_reencrypt, keyslot_reencrypt, r;
struct volume_key *data;
keyslot_reencrypt = LUKS2_find_keyslot(hdr, "reencrypt");
if (keyslot_reencrypt < 0)
return keyslot_reencrypt;
r = reencrypt_assembly_verification_data(cd, hdr, vks, &data);
if (r < 0)
return r;
r = LUKS2_digest_create(cd, "pbkdf2", hdr, data);
crypt_free_volume_key(data);
if (r < 0)
return r;
digest_reencrypt = r;
r = LUKS2_digest_assign(cd, hdr, keyslot_reencrypt, CRYPT_ANY_DIGEST, 0, 0);
if (r < 0)
return r;
return LUKS2_digest_assign(cd, hdr, keyslot_reencrypt, digest_reencrypt, 1, 0);
}
int LUKS2_reencrypt_digest_verify(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct volume_key *vks)
{
int r, keyslot_reencrypt;
struct volume_key *data;
keyslot_reencrypt = LUKS2_find_keyslot(hdr, "reencrypt");
if (keyslot_reencrypt < 0)
return keyslot_reencrypt;
r = reencrypt_assembly_verification_data(cd, hdr, vks, &data);
if (r < 0)
return r;
r = LUKS2_digest_verify(cd, hdr, data, keyslot_reencrypt);
crypt_free_volume_key(data);
if (r < 0) {
if (r == -ENOENT)
log_dbg(cd, "Reencryption digest is missing.");
log_err(cd, _("Reencryption metadata is invalid."));
} else
log_dbg(cd, "Reencryption metadata verified.");
return r;
}

View File

@@ -123,7 +123,7 @@ static json_object *json_segment_get_flags(json_object *jobj_segment)
return jobj;
}
static bool json_segment_contains_flag(json_object *jobj_segment, const char *flag_str, size_t len)
bool json_segment_contains_flag(json_object *jobj_segment, const char *flag_str, size_t len)
{
int r, i;
json_object *jobj, *jobj_flags = json_segment_get_flags(jobj_segment);
@@ -410,3 +410,23 @@ json_object *LUKS2_get_segment_by_flag(struct luks2_hdr *hdr, const char *flag)
return jobj_segment;
}
/* compares key characteristics of both segments */
bool json_segment_cmp(json_object *jobj_segment_1, json_object *jobj_segment_2)
{
const char *type = json_segment_type(jobj_segment_1);
const char *type2 = json_segment_type(jobj_segment_2);
if (!type || !type2)
return false;
if (strcmp(type, type2))
return false;
if (!strcmp(type, "crypt"))
return (json_segment_get_sector_size(jobj_segment_1) == json_segment_get_sector_size(jobj_segment_2) &&
!strcmp(json_segment_get_cipher(jobj_segment_1),
json_segment_get_cipher(jobj_segment_2)));
return true;
}

View File

@@ -147,7 +147,8 @@ int LUKS2_token_create(struct crypt_device *cd,
if (!json_object_object_get_ex(hdr->jobj, "tokens", &jobj_tokens))
return -EINVAL;
snprintf(num, sizeof(num), "%d", token);
if (snprintf(num, sizeof(num), "%d", token) < 0)
return -EINVAL;
/* Remove token */
if (!json)
@@ -517,7 +518,9 @@ static int assign_one_keyslot(struct crypt_device *cd, struct luks2_hdr *hdr,
if (!jobj_token_keyslots)
return -EINVAL;
snprintf(num, sizeof(num), "%d", keyslot);
if (snprintf(num, sizeof(num), "%d", keyslot) < 0)
return -EINVAL;
if (assign) {
jobj1 = LUKS2_array_jobj(jobj_token_keyslots, num);
if (!jobj1)

View File

@@ -78,7 +78,7 @@ struct crypt_device {
char cipher_mode[MAX_CIPHER_LEN]; /* only for compatibility */
char *keyslot_cipher;
unsigned int keyslot_key_size;
struct luks2_reenc_context *rh;
struct luks2_reencrypt *rh;
} luks2;
struct { /* used in CRYPT_PLAIN */
struct crypt_params_plain hdr;
@@ -657,12 +657,12 @@ int crypt_set_data_device(struct crypt_device *cd, const char *device)
log_dbg(cd, "Setting ciphertext data device to %s.", device ?: "(none)");
if (!isLUKS1(cd->type) && !isLUKS2(cd->type) && !isVERITY(cd->type) &&
!isINTEGRITY(cd->type)) {
!isINTEGRITY(cd->type) && !isTCRYPT(cd->type)) {
log_err(cd, _("This operation is not supported for this device type."));
return -EINVAL;
}
if (isLUKS2(cd->type) && crypt_get_reenc_context(cd)) {
if (isLUKS2(cd->type) && crypt_get_luks2_reencrypt(cd)) {
log_err(cd, _("Illegal operation with reencryption in-progress."));
return -EINVAL;
}
@@ -845,11 +845,6 @@ static int _crypt_load_tcrypt(struct crypt_device *cd, struct crypt_params_tcryp
if (!params)
return -EINVAL;
if (cd->metadata_device) {
log_err(cd, _("Detached metadata device is not supported for this crypt type."));
return -EINVAL;
}
r = init_crypto(cd);
if (r < 0)
return r;
@@ -1084,10 +1079,15 @@ static int _init_by_name_crypt_none(struct crypt_device *cd)
_mode);
if (!r) {
snprintf(cd->u.none.cipher_spec, sizeof(cd->u.none.cipher_spec),
r = snprintf(cd->u.none.cipher_spec, sizeof(cd->u.none.cipher_spec),
"%s-%s", cd->u.none.cipher, _mode);
cd->u.none.cipher_mode = cd->u.none.cipher_spec + strlen(cd->u.none.cipher) + 1;
cd->u.none.key_size = tgt->u.crypt.vk->keylength;
if (r < 0 || (size_t)r >= sizeof(cd->u.none.cipher_spec))
r = -EINVAL;
else {
cd->u.none.cipher_mode = cd->u.none.cipher_spec + strlen(cd->u.none.cipher) + 1;
cd->u.none.key_size = tgt->u.crypt.vk->keylength;
r = 0;
}
}
dm_targets_free(cd, &dmd);
@@ -1113,7 +1113,7 @@ static void crypt_free_type(struct crypt_device *cd)
free(cd->u.plain.cipher);
free(cd->u.plain.cipher_spec);
} else if (isLUKS2(cd->type)) {
LUKS2_reenc_context_free(cd, cd->u.luks2.rh);
LUKS2_reencrypt_free(cd, cd->u.luks2.rh);
LUKS2_hdr_free(cd, &cd->u.luks2.hdr);
free(cd->u.luks2.keyslot_cipher);
} else if (isLUKS1(cd->type)) {
@@ -1850,13 +1850,13 @@ static int _crypt_format_luks2(struct crypt_device *cd,
if (dev_size < (crypt_get_data_offset(cd) * SECTOR_SIZE))
log_std(cd, _("WARNING: Data offset is outside of currently available data device.\n"));
if (cd->metadata_size && (cd->metadata_size != LUKS2_metadata_size(cd->u.luks2.hdr.jobj)))
if (cd->metadata_size && (cd->metadata_size != LUKS2_metadata_size(&cd->u.luks2.hdr)))
log_std(cd, _("WARNING: LUKS2 metadata size changed to %" PRIu64 " bytes.\n"),
LUKS2_metadata_size(cd->u.luks2.hdr.jobj));
LUKS2_metadata_size(&cd->u.luks2.hdr));
if (cd->keyslots_size && (cd->keyslots_size != LUKS2_keyslots_size(cd->u.luks2.hdr.jobj)))
if (cd->keyslots_size && (cd->keyslots_size != LUKS2_keyslots_size(&cd->u.luks2.hdr)))
log_std(cd, _("WARNING: LUKS2 keyslots area size changed to %" PRIu64 " bytes.\n"),
LUKS2_keyslots_size(cd->u.luks2.hdr.jobj));
LUKS2_keyslots_size(&cd->u.luks2.hdr));
if (!integrity && sector_size > SECTOR_SIZE) {
dev_size -= (crypt_get_data_offset(cd) * SECTOR_SIZE);
@@ -1878,7 +1878,7 @@ static int _crypt_format_luks2(struct crypt_device *cd,
if (r < 0) {
log_err(cd, _("Cannot wipe header on device %s."),
mdata_device_path(cd));
if (dev_size < LUKS2_hdr_and_areas_size(cd->u.luks2.hdr.jobj))
if (dev_size < LUKS2_hdr_and_areas_size(&cd->u.luks2.hdr))
log_err(cd, _("Device %s is too small."), device_path(crypt_metadata_device(cd)));
goto out;
}
@@ -3857,21 +3857,6 @@ out:
return r;
}
static int load_all_keys(struct crypt_device *cd, struct luks2_hdr *hdr, struct volume_key *vks)
{
int r;
struct volume_key *vk = vks;
while (vk) {
r = LUKS2_volume_key_load_in_keyring_by_digest(cd, hdr, vk, crypt_volume_key_get_id(vk));
if (r < 0)
return r;
vk = crypt_volume_key_next(vk);
}
return 0;
}
/* See fixmes in _open_and_activate_luks2 */
int update_reencryption_flag(struct crypt_device *cd, int enable, bool commit);
@@ -3919,6 +3904,22 @@ out:
return r < 0 ? r : keyslot;
}
#if USE_LUKS2_REENCRYPTION
static int load_all_keys(struct crypt_device *cd, struct luks2_hdr *hdr, struct volume_key *vks)
{
int r;
struct volume_key *vk = vks;
while (vk) {
r = LUKS2_volume_key_load_in_keyring_by_digest(cd, hdr, vk, crypt_volume_key_get_id(vk));
if (r < 0)
return r;
vk = crypt_volume_key_next(vk);
}
return 0;
}
static int _open_all_keys(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
@@ -3929,7 +3930,7 @@ static int _open_all_keys(struct crypt_device *cd,
{
int r, segment;
struct volume_key *_vks = NULL;
crypt_reencrypt_info ri = LUKS2_reenc_status(hdr);
crypt_reencrypt_info ri = LUKS2_reencrypt_status(hdr);
segment = (flags & CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY) ? CRYPT_ANY_SEGMENT : CRYPT_DEFAULT_SEGMENT;
@@ -3985,7 +3986,7 @@ static int _open_and_activate_reencrypt_device(struct crypt_device *cd,
if (crypt_use_keyring_for_vk(cd))
flags |= CRYPT_ACTIVATE_KEYRING_KEY;
r = crypt_reencrypt_lock(cd, &reencrypt_lock);
r = LUKS2_reencrypt_lock(cd, &reencrypt_lock);
if (r) {
if (r == -EBUSY)
log_err(cd, _("Reencryption in-progress. Cannot activate device."));
@@ -3997,7 +3998,7 @@ static int _open_and_activate_reencrypt_device(struct crypt_device *cd,
if ((r = crypt_load(cd, CRYPT_LUKS2, NULL)))
goto err;
ri = LUKS2_reenc_status(hdr);
ri = LUKS2_reencrypt_status(hdr);
if (ri == CRYPT_REENCRYPT_CRASH) {
r = LUKS2_reencrypt_locked_recovery_by_passphrase(cd, keyslot,
@@ -4008,14 +4009,14 @@ static int _open_and_activate_reencrypt_device(struct crypt_device *cd,
}
keyslot = r;
ri = LUKS2_reenc_status(hdr);
ri = LUKS2_reencrypt_status(hdr);
}
/* recovery finished reencryption or it's already finished */
if (ri == CRYPT_REENCRYPT_NONE) {
crypt_drop_keyring_key(cd, vks);
crypt_free_volume_key(vks);
crypt_reencrypt_unlock(cd, reencrypt_lock);
LUKS2_reencrypt_unlock(cd, reencrypt_lock);
return _open_and_activate(cd, keyslot, name, passphrase, passphrase_size, flags);
}
@@ -4033,15 +4034,21 @@ static int _open_and_activate_reencrypt_device(struct crypt_device *cd,
keyslot = r;
}
if (r >= 0) {
r = LUKS2_reencrypt_digest_verify(cd, hdr, vks);
if (r < 0)
goto err;
}
log_dbg(cd, "Entering clean reencryption state mode.");
if (r >= 0)
r = luks2_check_device_size(cd, hdr, minimal_size, &device_size, true, dynamic_size);
r = LUKS2_reencrypt_check_device_size(cd, hdr, minimal_size, &device_size, true, dynamic_size);
if (r >= 0)
r = LUKS2_activate_multi(cd, name, vks, device_size >> SECTOR_SHIFT, flags);
err:
crypt_reencrypt_unlock(cd, reencrypt_lock);
LUKS2_reencrypt_unlock(cd, reencrypt_lock);
if (r < 0)
crypt_drop_keyring_key(cd, vks);
crypt_free_volume_key(vks);
@@ -4060,10 +4067,11 @@ static int _open_and_activate_luks2(struct crypt_device *cd,
uint32_t flags)
{
crypt_reencrypt_info ri;
int r;
int r, rv;
struct luks2_hdr *hdr = &cd->u.luks2.hdr;
struct volume_key *vks = NULL;
ri = LUKS2_reenc_status(hdr);
ri = LUKS2_reencrypt_status(hdr);
if (ri == CRYPT_REENCRYPT_INVALID)
return -EINVAL;
@@ -4071,15 +4079,45 @@ static int _open_and_activate_luks2(struct crypt_device *cd,
if (name)
r = _open_and_activate_reencrypt_device(cd, hdr, keyslot, name, passphrase,
passphrase_size, flags);
else
else {
r = _open_all_keys(cd, hdr, keyslot, passphrase,
passphrase_size, flags, NULL);
passphrase_size, flags, &vks);
if (r < 0)
return r;
rv = LUKS2_reencrypt_digest_verify(cd, hdr, vks);
crypt_free_volume_key(vks);
if (rv < 0)
return rv;
}
} else
r = _open_and_activate(cd, keyslot, name, passphrase,
passphrase_size, flags);
return r;
}
#else
static int _open_and_activate_luks2(struct crypt_device *cd,
int keyslot,
const char *name,
const char *passphrase,
size_t passphrase_size,
uint32_t flags)
{
crypt_reencrypt_info ri;
ri = LUKS2_reencrypt_status(&cd->u.luks2.hdr);
if (ri == CRYPT_REENCRYPT_INVALID)
return -EINVAL;
if (ri > CRYPT_REENCRYPT_NONE) {
log_err(cd, _("This operation is not supported for this device type."));
return -ENOTSUP;
}
return _open_and_activate(cd, keyslot, name, passphrase, passphrase_size, flags);
}
#endif
static int _activate_by_passphrase(struct crypt_device *cd,
const char *name,
@@ -4976,6 +5014,9 @@ const char *crypt_get_cipher_mode(struct crypt_device *cd)
/* INTERNAL only */
const char *crypt_get_integrity(struct crypt_device *cd)
{
if (!cd)
return NULL;
if (isINTEGRITY(cd->type))
return cd->u.integrity.params.integrity;
@@ -5255,8 +5296,8 @@ int crypt_get_metadata_size(struct crypt_device *cd,
msize = LUKS_ALIGN_KEYSLOTS;
ksize = LUKS_device_sectors(&cd->u.luks1.hdr) * SECTOR_SIZE - msize;
} else if (isLUKS2(cd->type)) {
msize = LUKS2_metadata_size(cd->u.luks2.hdr.jobj);
ksize = LUKS2_keyslots_size(cd->u.luks2.hdr.jobj);
msize = LUKS2_metadata_size(&cd->u.luks2.hdr);
ksize = LUKS2_keyslots_size(&cd->u.luks2.hdr);
} else
return -EINVAL;
@@ -5530,13 +5571,13 @@ void *crypt_get_hdr(struct crypt_device *cd, const char *type)
}
/* internal only */
struct luks2_reenc_context *crypt_get_reenc_context(struct crypt_device *cd)
struct luks2_reencrypt *crypt_get_luks2_reencrypt(struct crypt_device *cd)
{
return cd->u.luks2.rh;
}
/* internal only */
void crypt_set_reenc_context(struct crypt_device *cd, struct luks2_reenc_context *rh)
void crypt_set_luks2_reencrypt(struct crypt_device *cd, struct luks2_reencrypt *rh)
{
cd->u.luks2.rh = rh;
}
@@ -6059,7 +6100,7 @@ crypt_reencrypt_info crypt_reencrypt_status(struct crypt_device *cd,
if (_onlyLUKS2(cd, CRYPT_CD_QUIET, CRYPT_REQUIREMENT_ONLINE_REENCRYPT))
return CRYPT_REENCRYPT_INVALID;
return LUKS2_reencrypt_status(cd, params);
return LUKS2_reencrypt_get_params(&cd->u.luks2.hdr, params);
}
static void __attribute__((destructor)) libcryptsetup_exit(void)

View File

@@ -1028,7 +1028,7 @@ uint64_t TCRYPT_get_data_offset(struct crypt_device *cd,
/* Mapping through whole device, not partition! */
if (params->flags & CRYPT_TCRYPT_SYSTEM_HEADER) {
if (crypt_dev_is_partition(device_path(crypt_metadata_device(cd))))
if (crypt_dev_is_partition(device_path(crypt_data_device(cd))))
return 0;
goto hdr_offset;
}
@@ -1073,7 +1073,7 @@ uint64_t TCRYPT_get_iv_offset(struct crypt_device *cd,
iv_offset = hdr->d.mk_offset / SECTOR_SIZE;
if (params->flags & CRYPT_TCRYPT_SYSTEM_HEADER)
iv_offset += crypt_dev_partition_offset(device_path(crypt_metadata_device(cd)));
iv_offset += crypt_dev_partition_offset(device_path(crypt_data_device(cd)));
return iv_offset;
}

View File

@@ -86,7 +86,7 @@ int crypt_parse_hash_integrity_mode(const char *s, char *integrity)
else
return -EINVAL;
if (r < 0 || r == MAX_CIPHER_LEN)
if (r < 0 || r >= MAX_CIPHER_LEN)
return -EINVAL;
return 0;

View File

@@ -162,6 +162,9 @@ static int device_ready(struct crypt_device *cd, struct device *device)
struct stat st;
size_t tmp_size;
if (!device)
return -EINVAL;
if (device->o_direct) {
log_dbg(cd, "Trying to open and read device %s with direct-io.",
device_path(device));
@@ -217,6 +220,9 @@ static int _open_locked(struct crypt_device *cd, struct device *device, int flag
{
int fd;
if (!device)
return -EINVAL;
log_dbg(cd, "Opening locked device %s", device_path(device));
if ((flags & O_ACCMODE) != O_RDONLY && device_locked_readonly(device->lh)) {

View File

@@ -367,7 +367,9 @@ char *crypt_get_base_device(const char *dev_path)
if (dm_is_dm_kernel_name(devname))
return NULL;
snprintf(part_path, sizeof(part_path), "/dev/%s", devname);
if (snprintf(part_path, sizeof(part_path), "/dev/%s", devname) < 0)
return NULL;
return strdup(part_path);
}

View File

@@ -234,8 +234,9 @@ static char *_sysfs_backing_file(const char *loop)
if (stat(loop, &st) || !S_ISBLK(st.st_mode))
return NULL;
snprintf(buf, sizeof(buf), "/sys/dev/block/%d:%d/loop/backing_file",
major(st.st_rdev), minor(st.st_rdev));
if (snprintf(buf, sizeof(buf), "/sys/dev/block/%d:%d/loop/backing_file",
major(st.st_rdev), minor(st.st_rdev)) < 0)
return NULL;
fd = open(buf, O_RDONLY);
if (fd < 0)

View File

@@ -717,12 +717,17 @@ a mapping <name>.
\fB<options>\fR can be [\-\-key\-file, \-\-tcrypt\-hidden,
\-\-tcrypt\-system, \-\-tcrypt\-backup, \-\-readonly, \-\-test\-passphrase,
\-\-allow-discards, \-\-veracrypt, \-\-veracrypt\-pim, \-\-veracrypt\-query\-pim].
\-\-allow-discards, \-\-veracrypt, \-\-veracrypt\-pim, \-\-veracrypt\-query\-pim,
\-\-header].
The keyfile parameter allows a combination of file content with the
passphrase and can be repeated. Note that using keyfiles is compatible
with TCRYPT and is different from LUKS keyfile logic.
If you use \fB\-\-header\fR in combination with hidden or system options,
the header file must contain specific headers on the same positions as the original
encrypted container.
\fBWARNING:\fR Option \fB\-\-allow\-discards\fR cannot be combined with
option \fB\-\-tcrypt\-hidden\fR. For normal mapping, it can cause
the \fBdestruction of hidden volume\fR (hidden volume appears as unused space
@@ -806,6 +811,13 @@ are fixable. This command will only change the LUKS header, not
any key-slot data. You may enforce LUKS version by adding \-\-type
option.
It also repairs (upgrades) LUKS2 reencryption metadata by adding
metadata digest that protects it against malicious changes.
If LUKS2 reencryption was interrupted in the middle of writting
reencryption segment the repair command can be used to perform
reencryption recovery so that reencryption can continue later.
\fBWARNING:\fR Always create a binary backup of the original
header before calling this command.
.PP
@@ -1688,7 +1700,10 @@ and for authentication). Both these keys are stored in one LUKS keyslot.
\fBWARNING:\fR All support for authenticated modes is experimental
and there are only some modes available for now. Note that there
are a very few authenticated encryption algorithms that are suitable
for disk encryption.
for disk encryption. You also cannot use CRC32 or any other non-cryptographic
checksums (other than the special integrity mode "none"). If for some reason
you want to have integrity control without using authentication mode, then you
should separately configure dm-integrity independently of LUKS2.
.SH NOTES ON LOOPBACK DEVICE USE
Cryptsetup is usually used directly on a block device (disk

View File

@@ -118,7 +118,7 @@ The integrity algorithm can be CRC (crc32c/crc32) or hash function (sha1, sha256
For HMAC (hmac-sha256) you have also to specify an integrity key and its size.
.TP
.B "\-\-integrity\-key\-size BYTES"
The size of the data integrity key.
The size of the data integrity key. Maximum is 4096 bytes.
.TP
.B "\-\-integrity\-key\-file FILE"
The file with the integrity key.
@@ -158,7 +158,7 @@ Integrity algorithm for journal area.
See \-\-integrity option for detailed specification.
.TP
.B "\-\-journal\-integrity\-key\-size BYTES"
The size of the journal integrity key.
The size of the journal integrity key. Maximum is 4096 bytes.
.TP
.B "\-\-journal\-integrity\-key\-file FILE"
The file with the integrity key.
@@ -169,7 +169,7 @@ You can use a block cipher here such as cbc-aes or
a stream cipher, for example, chacha20 or ctr-aes.
.TP
.B "\-\-journal\-crypt\-key\-size BYTES"
The size of the journal encryption key.
The size of the journal encryption key. Maximum is 4096 bytes.
.TP
.B "\-\-journal\-crypt\-key\-file FILE"
The file with the journal encryption key.

View File

@@ -37,6 +37,7 @@ lib/luks2/luks2_keyslot_luks2.c
lib/luks2/luks2_keyslot_reenc.c
lib/luks2/luks2_luks1_convert.c
lib/luks2/luks2_reencrypt.c
lib/luks2/luks2_reencrypt_digest.c
lib/luks2/luks2_segment.c
lib/luks2/luks2_token.c
lib/luks2/luks2_token_keyring.c

File diff suppressed because it is too large Load Diff

956
po/cs.po

File diff suppressed because it is too large Load Diff

955
po/de.po

File diff suppressed because it is too large Load Diff

1540
po/es.po

File diff suppressed because it is too large Load Diff

953
po/fr.po

File diff suppressed because it is too large Load Diff

953
po/ja.po

File diff suppressed because it is too large Load Diff

955
po/pl.po

File diff suppressed because it is too large Load Diff

953
po/ru.po

File diff suppressed because it is too large Load Diff

1538
po/sr.po

File diff suppressed because it is too large Load Diff

955
po/uk.po

File diff suppressed because it is too large Load Diff

View File

@@ -544,7 +544,8 @@ static int action_open_tcrypt(void)
activated_name = opt_test_passphrase ? NULL : action_argv[1];
if ((r = crypt_init(&cd, action_argv[0])))
r = crypt_init_data_device(&cd, opt_header_device ?: action_argv[0], action_argv[0]);
if (r < 0)
goto out;
r = tcrypt_load(cd, &params);
@@ -657,8 +658,8 @@ static int action_tcryptDump(void)
.veracrypt_pim = (opt_veracrypt_pim > 0) ? opt_veracrypt_pim : 0,
};
int r;
if ((r = crypt_init(&cd, action_argv[0])))
r = crypt_init_data_device(&cd, opt_header_device ?: action_argv[0], action_argv[0]);
if (r < 0)
goto out;
r = tcrypt_load(cd, &params);
@@ -1039,8 +1040,10 @@ static int action_benchmark(void)
/* TRANSLATORS: The string is header of a table and must be exactly (right side) aligned. */
log_std(_("# Algorithm | Key | Encryption | Decryption\n"));
snprintf(cipher, MAX_CIPHER_LEN, "%s-%s",
bciphers[i].cipher, bciphers[i].mode);
if (snprintf(cipher, MAX_CIPHER_LEN, "%s-%s",
bciphers[i].cipher, bciphers[i].mode) < 0)
r = -EINVAL;
if (!r)
log_std("%15s %9zub %10.1f MiB/s %10.1f MiB/s\n",
cipher, bciphers[i].key_size*8, enc_mbr, dec_mbr);
@@ -1118,24 +1121,63 @@ static int set_keyslot_params(struct crypt_device *cd, int keyslot)
return crypt_set_pbkdf_type(cd, &pbkdf);
}
static int _do_luks2_reencrypt_recovery(struct crypt_device *cd)
static int reencrypt_metadata_repair(struct crypt_device *cd)
{
char *password;
size_t passwordLen;
int r;
struct crypt_params_reencrypt params = {
.flags = CRYPT_REENCRYPT_REPAIR_NEEDED
};
if (!opt_batch_mode &&
!yesDialog(_("Unprotected LUKS2 reencryption metadata detected. "
"Please verify the reencryption operation is desirable (see luksDump output)\n"
"and continue (upgrade metadata) only if you acknowledge the operation as genuine."),
_("Operation aborted.\n")))
return -EINVAL;
r = tools_get_key(_("Enter passphrase to protect and uppgrade reencryption metadata: "),
&password, &passwordLen, opt_keyfile_offset,
opt_keyfile_size, opt_key_file, opt_timeout,
_verify_passphrase(0), 0, cd);
if (r < 0)
return r;
r = crypt_reencrypt_init_by_passphrase(cd, NULL, password, passwordLen,
opt_key_slot, opt_key_slot, NULL, NULL, &params);
tools_passphrase_msg(r);
if (r < 0)
goto out;
r = crypt_activate_by_passphrase(cd, NULL, opt_key_slot,
password, passwordLen, 0);
tools_passphrase_msg(r);
if (r >= 0)
r = 0;
out:
crypt_safe_free(password);
return r;
}
static int luks2_reencrypt_repair(struct crypt_device *cd)
{
int r;
size_t passwordLen;
const char *msg;
char *password = NULL;
struct crypt_params_reencrypt recovery_params = {
.flags = CRYPT_REENCRYPT_RECOVERY
};
struct crypt_params_reencrypt params = {};
crypt_reencrypt_info ri = crypt_reencrypt_status(cd, &params);
if (params.flags & CRYPT_REENCRYPT_REPAIR_NEEDED)
return reencrypt_metadata_repair(cd);
crypt_reencrypt_info ri = crypt_reencrypt_status(cd, NULL);
switch (ri) {
case CRYPT_REENCRYPT_NONE:
/* fall through */
return 0;
case CRYPT_REENCRYPT_CLEAN:
r = noDialog(_("Seems device does not require reencryption recovery.\n"
"Do you want to proceed anyway?"), NULL);
if (!r)
return 0;
break;
case CRYPT_REENCRYPT_CRASH:
r = yesDialog(_("Really proceed with LUKS2 reencryption recovery?"),
@@ -1147,8 +1189,12 @@ static int _do_luks2_reencrypt_recovery(struct crypt_device *cd)
return -EINVAL;
}
r = tools_get_key(_("Enter passphrase for reencryption recovery: "),
&password, &passwordLen, opt_keyfile_offset,
if (ri == CRYPT_REENCRYPT_CLEAN)
msg = _("Enter passphrase to verify reencryption metadata digest: ");
else
msg = _("Enter passphrase for reencryption recovery: ");
r = tools_get_key(msg, &password, &passwordLen, opt_keyfile_offset,
opt_keyfile_size, opt_key_file, opt_timeout,
_verify_passphrase(0), 0, cd);
if (r < 0)
@@ -1159,8 +1205,14 @@ static int _do_luks2_reencrypt_recovery(struct crypt_device *cd)
if (r < 0)
goto out;
if (ri == CRYPT_REENCRYPT_CLEAN) {
r = 0;
goto out;
}
r = crypt_reencrypt_init_by_passphrase(cd, NULL, password, passwordLen,
opt_key_slot, opt_key_slot, NULL, NULL, &recovery_params);
opt_key_slot, opt_key_slot, NULL, NULL,
&(struct crypt_params_reencrypt){ .flags = CRYPT_REENCRYPT_RECOVERY });
if (r > 0)
r = 0;
out:
@@ -1195,8 +1247,9 @@ static int action_luksRepair(void)
if (r == 0)
r = crypt_repair(cd, luksType(device_type), NULL);
skip_repair:
/* Header is ok, check if reencryption metadata needs repair/recovery. */
if (!r && crypt_get_type(cd) && !strcmp(crypt_get_type(cd), CRYPT_LUKS2))
r = _do_luks2_reencrypt_recovery(cd);
r = luks2_reencrypt_repair(cd);
out:
crypt_free(cd);
return r;
@@ -2887,7 +2940,10 @@ static int action_encrypt_luks2(struct crypt_device **cd)
}
if (!opt_header_device) {
snprintf(header_file, sizeof(header_file), "LUKS2-temp-%s.new", opt_uuid);
r = snprintf(header_file, sizeof(header_file), "LUKS2-temp-%s.new", opt_uuid);
if (r < 0 || (size_t)r >= sizeof(header_file))
return -EINVAL;
fd = open(header_file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR);
if (fd == -1) {
if (errno == EEXIST)
@@ -3002,6 +3058,12 @@ static int action_decrypt_luks2(struct crypt_device *cd)
};
size_t passwordLen;
if (!crypt_get_metadata_device_name(cd) || !crypt_get_device_name(cd) ||
!strcmp(crypt_get_metadata_device_name(cd), crypt_get_device_name(cd))) {
log_err(_("LUKS2 decryption is supported with detached header device only."));
return -ENOTSUP;
}
_set_reencryption_flags(&params.flags);
r = tools_get_key(NULL, &password, &passwordLen,
@@ -3166,7 +3228,8 @@ static int fill_keyslot_passwords(struct crypt_device *cd,
if (opt_key_slot == CRYPT_ANY_SLOT) {
for (i = 0; (size_t)i < kp_size; i++) {
snprintf(msg, sizeof(msg), _("Enter passphrase for key slot %d: "), i);
if (snprintf(msg, sizeof(msg), _("Enter passphrase for key slot %d: "), i) < 0)
return -EINVAL;
r = init_passphrase(kp, kp_size, cd, msg, i);
if (r == -ENOENT)
r = 0;
@@ -3174,7 +3237,8 @@ static int fill_keyslot_passwords(struct crypt_device *cd,
break;
}
} else {
snprintf(msg, sizeof(msg), _("Enter passphrase for key slot %u: "), opt_key_slot);
if (snprintf(msg, sizeof(msg), _("Enter passphrase for key slot %u: "), opt_key_slot) < 0)
return -EINVAL;
r = init_passphrase(kp, kp_size, cd, msg, opt_key_slot);
}

View File

@@ -25,7 +25,6 @@
#define PACKAGE_INTEGRITY "integritysetup"
#define DEFAULT_ALG_NAME "crc32c"
#define MAX_KEY_SIZE 4096
static char *opt_data_device = NULL;
static char *opt_integrity = NULL; /* DEFAULT_ALG_NAME */
@@ -82,8 +81,8 @@ static int _read_mk(const char *file, char **key, int keysize)
{
int fd;
if (keysize <= 0 || keysize > MAX_KEY_SIZE) {
log_err(_("Invalid key size."));
if (keysize <= 0 || keysize > (DEFAULT_INTEGRITY_KEYFILE_SIZE_MAXKB * 1024)) {
log_err(_("Invalid key size. Maximum is %u bytes."), DEFAULT_INTEGRITY_KEYFILE_SIZE_MAXKB * 1024);
return -EINVAL;
}
@@ -519,7 +518,9 @@ static void help(poptContext popt_context,
crypt_get_dir());
log_std(_("\nDefault compiled-in dm-integrity parameters:\n"
"\tChecksum algorithm: %s\n"), DEFAULT_ALG_NAME);
"\tChecksum algorithm: %s\n"
"\tMaximum keyfile size: %dkB\n"),
DEFAULT_ALG_NAME, DEFAULT_INTEGRITY_KEYFILE_SIZE_MAXKB);
tools_cleanup();
poptFreeContext(popt_context);
exit(EXIT_SUCCESS);

View File

@@ -25,7 +25,7 @@ TESTS += verity-compat-test
endif
if REENCRYPT
TESTS += reencryption-compat-test reencryption-compat-test2 luks2-reencryption-test
TESTS += reencryption-compat-test reencryption-compat-test2 luks2-reencryption-test luks2-reencryption-mangle-test
endif
if INTEGRITYSETUP
@@ -57,6 +57,7 @@ EXTRA_DIST = compatimage.img.xz compatv10image.img.xz \
reencryption-compat-test \
reencryption-compat-test2 \
luks2-reencryption-test \
luks2-reencryption-mangle-test \
tcrypt-compat-test \
luks1-compat-test \
luks2-validation-test generators \
@@ -76,6 +77,8 @@ CLEANFILES = cryptsetup-tst* valglog* *-fail-*.log
clean-local:
-rm -rf tcrypt-images luks1-images luks2-images bitlk-images conversion_imgs luks2_valid_hdr.img blkid-luks2-pv-img blkid-luks2-pv-img.bcp
LDADD = $(LTLIBINTL)
differ_SOURCES = differ.c
differ_CFLAGS = $(AM_CFLAGS) -Wall -O2
@@ -120,6 +123,7 @@ valgrind-check: api-test api-test-2 differ
@INFOSTRING="api-test-000" ./valg-api.sh ./api-test
@INFOSTRING="api-test-002" ./valg-api.sh ./api-test-2
@VALG=1 ./luks2-reencryption-test
@VALG=1 ./luks2-reencryption-mangle-test
@VALG=1 ./bitlk-compat-test
@grep -l "ERROR SUMMARY: [^0] errors" valglog* || echo "No leaks detected."

View File

@@ -493,7 +493,7 @@ static void UseLuks2Device(void)
OK_(crypt_activate_by_passphrase(cd, NULL, CRYPT_ANY_SLOT, KEY1, strlen(KEY1), 0));
OK_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEY1, strlen(KEY1), 0));
FAIL_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEY1, strlen(KEY1), 0), "already open");
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
OK_(crypt_deactivate(cd, CDEVICE_1));
FAIL_(crypt_deactivate(cd, CDEVICE_1), "no such device");
@@ -525,7 +525,7 @@ static void UseLuks2Device(void)
OK_(crypt_volume_key_verify(cd, key, key_size));
OK_(crypt_activate_by_volume_key(cd, NULL, key, key_size, 0));
OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0));
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
OK_(crypt_deactivate(cd, CDEVICE_1));
key[1] = ~key[1];
@@ -748,7 +748,7 @@ static void AddDeviceLuks2(void)
OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, &params));
EQ_(crypt_get_data_offset(cd), r_payload_offset);
OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0));
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
OK_(t_device_size(DMDIR CDEVICE_1, &r_size_1));
EQ_(r_size_1, SECTOR_SIZE);
OK_(crypt_deactivate(cd, CDEVICE_1));
@@ -788,11 +788,11 @@ static void AddDeviceLuks2(void)
CRYPT_FREE(cd);
OK_(crypt_init_by_name_and_header(&cd, CDEVICE_1, DMDIR H_DEVICE));
FAIL_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, &params), "Context is already formatted");
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
CRYPT_FREE(cd);
// check active status without header
OK_(crypt_init_by_name_and_header(&cd, CDEVICE_1, NULL));
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
NULL_(crypt_get_type(cd));
OK_(strcmp(cipher, crypt_get_cipher(cd)));
OK_(strcmp(cipher_mode, crypt_get_cipher_mode(cd)));
@@ -815,7 +815,7 @@ static void AddDeviceLuks2(void)
CRYPT_FREE(cd);
// there we've got uuid mismatch
OK_(crypt_init_by_name_and_header(&cd, CDEVICE_1, DMDIR H_DEVICE));
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
NULL_(crypt_get_type(cd));
FAIL_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0), "Device is active");
FAIL_(crypt_activate_by_volume_key(cd, CDEVICE_2, key, key_size, 0), "Device is active");
@@ -831,14 +831,14 @@ static void AddDeviceLuks2(void)
// even with no keyslots defined it can be activated by volume key
OK_(crypt_volume_key_verify(cd, key, key_size));
OK_(crypt_activate_by_volume_key(cd, CDEVICE_2, key, key_size, 0));
EQ_(crypt_status(cd, CDEVICE_2), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_2), CRYPT_ACTIVE);
OK_(crypt_deactivate(cd, CDEVICE_2));
// now with keyslot
EQ_(7, crypt_keyslot_add_by_volume_key(cd, 7, key, key_size, passphrase, strlen(passphrase)));
EQ_(CRYPT_SLOT_ACTIVE_LAST, crypt_keyslot_status(cd, 7));
EQ_(7, crypt_activate_by_passphrase(cd, CDEVICE_2, CRYPT_ANY_SLOT, passphrase, strlen(passphrase), 0));
EQ_(crypt_status(cd, CDEVICE_2), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_2), CRYPT_ACTIVE);
OK_(crypt_deactivate(cd, CDEVICE_2));
crypt_set_iteration_time(cd, 1);
@@ -1110,7 +1110,7 @@ static void UseTempVolumes(void)
FAIL_(crypt_activate_by_volume_key(cd, CDEVICE_2, NULL, 0, 0), "not yet formatted");
OK_(crypt_format(cd, CRYPT_LUKS2, "aes", "cbc-essiv:sha256", NULL, NULL, 16, NULL));
OK_(crypt_activate_by_volume_key(cd, CDEVICE_2, NULL, 0, 0));
EQ_(crypt_status(cd, CDEVICE_2), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_2), CRYPT_ACTIVE);
CRYPT_FREE(cd);
OK_(crypt_init_by_name(&cd, CDEVICE_2));
@@ -1196,7 +1196,7 @@ static void Luks2HeaderRestore(void)
OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0));
FAIL_(crypt_header_restore(cd, CRYPT_PLAIN, NO_REQS_LUKS2_HEADER), "Cannot restore header to PLAIN type device");
FAIL_(crypt_header_restore(cd, CRYPT_LUKS2, NO_REQS_LUKS2_HEADER), "Cannot restore header over PLAIN type device");
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
OK_(crypt_deactivate(cd, CDEVICE_1));
CRYPT_FREE(cd);
@@ -1317,7 +1317,7 @@ static void Luks2HeaderLoad(void)
OK_(crypt_load(cd, CRYPT_LUKS2, NULL));
OK_(crypt_set_data_device(cd, DMDIR L_DEVICE_OK));
OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0));
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
OK_(!crypt_get_metadata_device_name(cd));
EQ_(strcmp(DMDIR H_DEVICE, crypt_get_metadata_device_name(cd)), 0);
OK_(crypt_deactivate(cd, CDEVICE_1));
@@ -1439,7 +1439,7 @@ static void Luks2HeaderBackup(void)
OK_(crypt_header_restore(cd, CRYPT_LUKS2, BACKUP_FILE));
OK_(crypt_load(cd, CRYPT_LUKS2, NULL));
OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0));
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
OK_(crypt_deactivate(cd, CDEVICE_1));
CRYPT_FREE(cd);
@@ -1448,7 +1448,7 @@ static void Luks2HeaderBackup(void)
OK_(crypt_load(cd, CRYPT_LUKS2, NULL));
OK_(crypt_set_data_device(cd, DMDIR L_DEVICE_OK));
EQ_(crypt_activate_by_passphrase(cd, CDEVICE_1, 0, passphrase, strlen(passphrase), 0), 0);
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
OK_(crypt_deactivate(cd, CDEVICE_1));
CRYPT_FREE(cd);
@@ -1456,7 +1456,7 @@ static void Luks2HeaderBackup(void)
OK_(crypt_load(cd, CRYPT_LUKS2, NULL));
OK_(crypt_set_data_device(cd, DMDIR L_DEVICE_OK));
EQ_(crypt_activate_by_passphrase(cd, CDEVICE_1, 7, passphrase, strlen(passphrase), 0), 7);
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
OK_(crypt_deactivate(cd, CDEVICE_1));
CRYPT_FREE(cd);
@@ -1468,7 +1468,7 @@ static void Luks2HeaderBackup(void)
OK_(crypt_load(cd, CRYPT_LUKS2, NULL));
OK_(crypt_set_data_device(cd, DMDIR L_DEVICE_OK));
EQ_(crypt_activate_by_passphrase(cd, CDEVICE_1, 0, passphrase, strlen(passphrase), 0), 0);
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
OK_(crypt_deactivate(cd, CDEVICE_1));
CRYPT_FREE(cd);
@@ -1476,7 +1476,7 @@ static void Luks2HeaderBackup(void)
OK_(crypt_load(cd, CRYPT_LUKS2, NULL));
OK_(crypt_set_data_device(cd, DMDIR L_DEVICE_OK));
EQ_(crypt_activate_by_passphrase(cd, CDEVICE_1, 7, passphrase, strlen(passphrase), 0), 7);
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
OK_(crypt_deactivate(cd, CDEVICE_1));
CRYPT_FREE(cd);
@@ -1540,7 +1540,7 @@ static void ResizeDeviceLuks2(void)
FAIL_(crypt_resize(cd, CDEVICE_1, 1001), "Device too small");
if (!t_device_size(DMDIR CDEVICE_1, &r_size))
EQ_(1000, r_size >> SECTOR_SHIFT);
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
OK_(crypt_deactivate(cd, CDEVICE_1));
CRYPT_FREE(cd);
@@ -1560,7 +1560,7 @@ static void ResizeDeviceLuks2(void)
FAIL_(crypt_resize(cd, CDEVICE_1, 1001), "Device too small");
if (!t_device_size(DMDIR CDEVICE_1, &r_size))
EQ_(1000, r_size >> SECTOR_SHIFT);
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
OK_(crypt_deactivate(cd, CDEVICE_1));
CRYPT_FREE(cd);
@@ -2541,7 +2541,7 @@ static void Pbkdf(void)
.size = 0
};
struct crypt_params_luks1 luks1 = {
.hash = "whirlpool", // test non-standard hash
.hash = "sha512", // test non-standard hash
.data_alignment = 2048,
};
@@ -3082,7 +3082,7 @@ static void Luks2ActivateByKeyring(void)
OK_(crypt_load(cd, CRYPT_LUKS2, NULL));
EQ_(crypt_activate_by_keyring(cd, NULL, KEY_DESC_TEST0, 0, 0), 0);
EQ_(crypt_activate_by_keyring(cd, CDEVICE_1, KEY_DESC_TEST0, 0, 0), 0);
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
FAIL_(crypt_activate_by_keyring(cd, CDEVICE_1, KEY_DESC_TEST0, 0, 0), "already open");
OK_(crypt_deactivate(cd, CDEVICE_1));
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_INACTIVE);
@@ -3090,7 +3090,7 @@ static void Luks2ActivateByKeyring(void)
EQ_(crypt_activate_by_keyring(cd, NULL, KEY_DESC_TEST1, 2, 0), 2);
FAIL_(crypt_activate_by_keyring(cd, CDEVICE_1, KEY_DESC_TEST1, 1, 0), "Keyslot not assigned to volume");
EQ_(crypt_activate_by_keyring(cd, CDEVICE_1, KEY_DESC_TEST1, 2, 0), 2);
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
OK_(crypt_deactivate(cd, CDEVICE_1));
EQ_(crypt_activate_by_keyring(cd, CDEVICE_1, KEY_DESC_TEST1, CRYPT_ANY_SLOT, 0), 2);
OK_(crypt_deactivate(cd, CDEVICE_1));
@@ -3420,7 +3420,7 @@ static void Luks2Requirements(void)
/* crypt_resize (restricted) */
FAIL_((r = crypt_resize(cd, CDEVICE_1, 1)), "Unmet requirements detected");
EQ_(r, -ETXTBSY);
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
/* crypt_get_active_device (unrestricted) */
OK_(crypt_get_active_device(cd, CDEVICE_1, &cad));
@@ -3468,7 +3468,7 @@ static void Luks2Integrity(void)
EQ_(crypt_keyslot_add_by_volume_key(cd, 7, NULL, key_size, passphrase, strlen(passphrase)), 7);
EQ_(crypt_activate_by_passphrase(cd, CDEVICE_2, 7, passphrase, strlen(passphrase) ,0), 7);
EQ_(crypt_status(cd, CDEVICE_2), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_2), CRYPT_ACTIVE);
CRYPT_FREE(cd);
OK_(crypt_init_by_name_and_header(&cd, CDEVICE_2, NULL));
@@ -3692,6 +3692,7 @@ static void Luks2Flags(void)
CRYPT_FREE(cd);
}
#if KERNEL_KEYRING && USE_LUKS2_REENCRYPTION
static int test_progress(uint64_t size, uint64_t offset, void *usrptr)
{
while (--test_progress_steps)
@@ -3702,7 +3703,6 @@ static int test_progress(uint64_t size, uint64_t offset, void *usrptr)
static void Luks2Reencryption(void)
{
/* reencryption currently depends on kernel keyring support */
#if KERNEL_KEYRING
/* NOTES:
* - reencryption requires luks2 parameters. can we avoid it?
*/
@@ -4404,8 +4404,8 @@ static void Luks2Reencryption(void)
crypt_free(cd);
_cleanup_dmdevices();
#endif
}
#endif
static void Luks2Repair(void)
{
@@ -4521,7 +4521,9 @@ int main(int argc, char *argv[])
RUN_(Luks2Integrity, "LUKS2 with data integrity");
RUN_(Luks2Refresh, "Active device table refresh");
RUN_(Luks2Flags, "LUKS2 persistent flags");
#if KERNEL_KEYRING && USE_LUKS2_REENCRYPTION
RUN_(Luks2Reencryption, "LUKS2 reencryption");
#endif
RUN_(Luks2Repair, "LUKS2 repair"); // test disables metadata locking. Run always last!
_cleanup();

View File

@@ -357,7 +357,7 @@ static void AddDevicePlain(void)
OK_(crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode, NULL, NULL, key_size, NULL));
FAIL_(crypt_activate_by_volume_key(cd, NULL, key, key_size, 0), "cannot verify key with plain");
OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0));
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
OK_(crypt_deactivate(cd, CDEVICE_1));
CRYPT_FREE(cd);
@@ -379,7 +379,7 @@ static void AddDevicePlain(void)
OK_(crypt_init(&cd, DEVICE_1));
OK_(crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode, NULL, NULL, key_size, &params));
OK_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, passphrase, strlen(passphrase), 0));
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
snprintf(path, sizeof(path), "%s/%s", crypt_get_dir(), CDEVICE_1);
if (t_device_size(path, &r_size) >= 0)
EQ_(r_size>>SECTOR_SHIFT, 1);
@@ -428,7 +428,7 @@ static void AddDevicePlain(void)
crypt_init(&cd, DEVICE_1);
OK_(crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode, NULL, NULL, key_size, &params));
OK_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, passphrase, strlen(passphrase), 0));
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
if (!t_device_size(path, &r_size))
EQ_((r_size >> SECTOR_SHIFT),params.size);
OK_(crypt_deactivate(cd,CDEVICE_1));
@@ -447,7 +447,7 @@ static void AddDevicePlain(void)
OK_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, passphrase, strlen(passphrase), 0));
// device status check
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
snprintf(path, sizeof(path), "%s/%s", crypt_get_dir(), CDEVICE_1);
fd = open(path, O_RDONLY);
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_BUSY);
@@ -492,7 +492,7 @@ static void AddDevicePlain(void)
OK_(strcmp(crypt_get_type(cd),CRYPT_PLAIN));
OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0));
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
// crypt_resize()
OK_(crypt_resize(cd,CDEVICE_1,size>>SECTOR_SHIFT)); // same size
@@ -531,7 +531,7 @@ static void AddDevicePlain(void)
FAIL_(crypt_resize(cd,CDEVICE_1,params.size + 11), "new device size overlaps backing device"); // with respect to offset
if (!t_device_size(path,&r_size))
EQ_(r_size>>SECTOR_SHIFT, params.size + 10);
EQ_(crypt_status(cd,CDEVICE_1),CRYPT_ACTIVE);
GE_(crypt_status(cd,CDEVICE_1),CRYPT_ACTIVE);
fd = open(path, O_RDONLY);
NOTFAIL_(fd, "Bad loop device.");
close(fd);
@@ -555,9 +555,9 @@ static void AddDevicePlain(void)
// suspend/resume tests
FAIL_(crypt_suspend(cd,CDEVICE_1),"cannot suspend plain device");
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
FAIL_(crypt_resume_by_passphrase(cd,CDEVICE_1,CRYPT_ANY_SLOT,passphrase, strlen(passphrase)),"cannot resume plain device");
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
// retrieve volume key check
memset(key2, 0, key_size);
@@ -579,7 +579,7 @@ static void AddDevicePlain(void)
OK_(prepare_keyfile(KEYFILE2, KEY2, strlen(KEY2)));
FAIL_(crypt_activate_by_keyfile(cd, NULL, CRYPT_ANY_SLOT, KEYFILE1, 0, 0), "cannot verify key with plain");
EQ_(0, crypt_activate_by_keyfile(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEYFILE1, 0, 0));
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
OK_(crypt_deactivate(cd, CDEVICE_1));
FAIL_(crypt_activate_by_keyfile_offset(cd, NULL, CRYPT_ANY_SLOT, KEYFILE1, 0, strlen(KEY1) + 1, 0), "cannot seek");
FAIL_(crypt_activate_by_keyfile_device_offset(cd, NULL, CRYPT_ANY_SLOT, KEYFILE1, 0, strlen(KEY1) + 1, 0), "cannot seek");
@@ -631,7 +631,7 @@ static void CallbacksTest(void)
EQ_(new_messages, 0);
OK_(crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode, NULL, NULL, key_size, &params));
OK_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, passphrase, strlen(passphrase), 0));
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
EQ_(new_messages, 0);
FAIL_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, passphrase, strlen(passphrase), 0), "already exists");
EQ_(new_messages, 1);
@@ -651,7 +651,7 @@ static void UseLuksDevice(void)
OK_(crypt_activate_by_passphrase(cd, NULL, CRYPT_ANY_SLOT, KEY1, strlen(KEY1), 0));
OK_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEY1, strlen(KEY1), 0));
FAIL_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEY1, strlen(KEY1), 0), "already open");
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
OK_(crypt_deactivate(cd, CDEVICE_1));
FAIL_(crypt_deactivate(cd, CDEVICE_1), "no such device");
@@ -666,7 +666,7 @@ static void UseLuksDevice(void)
OK_(crypt_volume_key_verify(cd, key, key_size));
OK_(crypt_activate_by_volume_key(cd, NULL, key, key_size, 0));
OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0));
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
OK_(crypt_deactivate(cd, CDEVICE_1));
key[1] = ~key[1];
@@ -875,7 +875,7 @@ static void AddDeviceLuks(void)
OK_(crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode, NULL, key, key_size, &params));
EQ_(crypt_get_data_offset(cd), params.data_alignment);
OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0));
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
OK_(t_device_size(DMDIR CDEVICE_1, &r_size_1));
EQ_(r_size_1, SECTOR_SIZE);
OK_(crypt_deactivate(cd, CDEVICE_1));
@@ -902,11 +902,11 @@ static void AddDeviceLuks(void)
CRYPT_FREE(cd);
OK_(crypt_init_by_name_and_header(&cd, CDEVICE_1, DMDIR H_DEVICE));
FAIL_(crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode, NULL, key, key_size, &params), "Context is already formatted");
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
CRYPT_FREE(cd);
// check active status without header
OK_(crypt_init_by_name_and_header(&cd, CDEVICE_1, NULL));
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
NULL_(crypt_get_type(cd));
OK_(strcmp(cipher, crypt_get_cipher(cd)));
OK_(strcmp(cipher_mode, crypt_get_cipher_mode(cd)));
@@ -929,7 +929,7 @@ static void AddDeviceLuks(void)
CRYPT_FREE(cd);
// there we've got uuid mismatch
OK_(crypt_init_by_name_and_header(&cd, CDEVICE_1, DMDIR H_DEVICE));
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
NULL_(crypt_get_type(cd));
FAIL_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0), "Device is active");
FAIL_(crypt_activate_by_volume_key(cd, CDEVICE_2, key, key_size, 0), "Device is active");
@@ -945,14 +945,14 @@ static void AddDeviceLuks(void)
// even with no keyslots defined it can be activated by volume key
OK_(crypt_volume_key_verify(cd, key, key_size));
OK_(crypt_activate_by_volume_key(cd, CDEVICE_2, key, key_size, 0));
EQ_(crypt_status(cd, CDEVICE_2), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_2), CRYPT_ACTIVE);
OK_(crypt_deactivate(cd, CDEVICE_2));
// now with keyslot
EQ_(7, crypt_keyslot_add_by_volume_key(cd, 7, key, key_size, passphrase, strlen(passphrase)));
EQ_(CRYPT_SLOT_ACTIVE_LAST, crypt_keyslot_status(cd, 7));
EQ_(7, crypt_activate_by_passphrase(cd, CDEVICE_2, CRYPT_ANY_SLOT, passphrase, strlen(passphrase), 0));
EQ_(crypt_status(cd, CDEVICE_2), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_2), CRYPT_ACTIVE);
OK_(crypt_deactivate(cd, CDEVICE_2));
crypt_set_iteration_time(cd, 1);
@@ -1054,7 +1054,7 @@ static void UseTempVolumes(void)
FAIL_(crypt_activate_by_volume_key(cd, CDEVICE_2, NULL, 0, 0), "not yet formatted");
OK_(crypt_format(cd, CRYPT_LUKS1, "aes", "cbc-essiv:sha256", NULL, NULL, 16, NULL));
OK_(crypt_activate_by_volume_key(cd, CDEVICE_2, NULL, 0, 0));
EQ_(crypt_status(cd, CDEVICE_2), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_2), CRYPT_ACTIVE);
CRYPT_FREE(cd);
OK_(crypt_init_by_name(&cd, CDEVICE_2));
@@ -1096,7 +1096,7 @@ static void UseTempVolumes(void)
FAIL_(crypt_volume_key_verify(cd, "xxx", 3), "cannot verify key with plain");
FAIL_(crypt_activate_by_volume_key(cd, CDEVICE_2, "xxx", 3, 0), "wrong key length");
OK_(crypt_activate_by_volume_key(cd, CDEVICE_2, "volumekeyvolumek", 16, 0));
EQ_(crypt_status(cd, CDEVICE_2), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_2), CRYPT_ACTIVE);
OK_(crypt_deactivate(cd, CDEVICE_2));
CRYPT_FREE(cd);
}
@@ -1132,7 +1132,7 @@ static void LuksHeaderRestore(void)
OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0));
FAIL_(crypt_header_restore(cd, CRYPT_PLAIN, VALID_HEADER), "Cannot restore header to PLAIN type device");
FAIL_(crypt_header_restore(cd, CRYPT_LUKS1, VALID_HEADER), "Cannot restore header over PLAIN type device");
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
OK_(crypt_deactivate(cd, CDEVICE_1));
CRYPT_FREE(cd);
@@ -1238,7 +1238,7 @@ static void LuksHeaderLoad(void)
OK_(crypt_load(cd, CRYPT_LUKS1, NULL));
OK_(crypt_set_data_device(cd, DMDIR L_DEVICE_OK));
OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0));
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
OK_(!crypt_get_metadata_device_name(cd));
EQ_(strcmp(DMDIR H_DEVICE, crypt_get_metadata_device_name(cd)), 0);
OK_(crypt_deactivate(cd, CDEVICE_1));
@@ -1340,7 +1340,7 @@ static void LuksHeaderBackup(void)
OK_(crypt_header_restore(cd, CRYPT_LUKS1, BACKUP_FILE));
OK_(crypt_load(cd, CRYPT_LUKS1, NULL));
OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0));
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
OK_(crypt_deactivate(cd, CDEVICE_1));
CRYPT_FREE(cd);
@@ -1349,7 +1349,7 @@ static void LuksHeaderBackup(void)
OK_(crypt_load(cd, CRYPT_LUKS1, NULL));
OK_(crypt_set_data_device(cd, DMDIR L_DEVICE_OK));
EQ_(crypt_activate_by_passphrase(cd, CDEVICE_1, 0, passphrase, strlen(passphrase), 0), 0);
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
OK_(crypt_deactivate(cd, CDEVICE_1));
CRYPT_FREE(cd);
@@ -1357,7 +1357,7 @@ static void LuksHeaderBackup(void)
OK_(crypt_load(cd, CRYPT_LUKS1, NULL));
OK_(crypt_set_data_device(cd, DMDIR L_DEVICE_OK));
EQ_(crypt_activate_by_passphrase(cd, CDEVICE_1, 7, passphrase, strlen(passphrase), 0), 7);
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
OK_(crypt_deactivate(cd, CDEVICE_1));
CRYPT_FREE(cd);
@@ -1369,7 +1369,7 @@ static void LuksHeaderBackup(void)
OK_(crypt_load(cd, CRYPT_LUKS1, NULL));
OK_(crypt_set_data_device(cd, DMDIR L_DEVICE_OK));
EQ_(crypt_activate_by_passphrase(cd, CDEVICE_1, 0, passphrase, strlen(passphrase), 0), 0);
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
OK_(crypt_deactivate(cd, CDEVICE_1));
CRYPT_FREE(cd);
@@ -1377,7 +1377,7 @@ static void LuksHeaderBackup(void)
OK_(crypt_load(cd, CRYPT_LUKS1, NULL));
OK_(crypt_set_data_device(cd, DMDIR L_DEVICE_OK));
EQ_(crypt_activate_by_passphrase(cd, CDEVICE_1, 7, passphrase, strlen(passphrase), 0), 7);
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
OK_(crypt_deactivate(cd, CDEVICE_1));
CRYPT_FREE(cd);
@@ -1422,7 +1422,7 @@ static void ResizeDeviceLuks(void)
FAIL_(crypt_resize(cd, CDEVICE_1, 1001), "Device too small");
if (!t_device_size(DMDIR CDEVICE_1, &r_size))
EQ_(1000, r_size >> SECTOR_SHIFT);
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
OK_(crypt_deactivate(cd, CDEVICE_1));
CRYPT_FREE(cd);
@@ -1442,7 +1442,7 @@ static void ResizeDeviceLuks(void)
FAIL_(crypt_resize(cd, CDEVICE_1, 1001), "Device too small");
if (!t_device_size(DMDIR CDEVICE_1, &r_size))
EQ_(1000, r_size >> SECTOR_SHIFT);
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
OK_(crypt_deactivate(cd, CDEVICE_1));
CRYPT_FREE(cd);
@@ -1777,7 +1777,7 @@ static void TcryptTest(void)
CRYPT_FREE(cd);
OK_(crypt_init_by_name_and_header(&cd, CDEVICE_1, NULL));
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
FAIL_(crypt_volume_key_get(cd, CRYPT_ANY_SLOT, key, &key_size, NULL, 0), "Need crypt_load");
@@ -1864,7 +1864,7 @@ static void IntegrityTest(void)
params.tag_size = 4;
OK_(crypt_load(cd, CRYPT_INTEGRITY, &params));
OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, NULL, 0, 0));
EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
GE_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE);
CRYPT_FREE(cd);
memset(&ip, 0, sizeof(ip));

View File

@@ -61,6 +61,7 @@ void check_ok(int status, int line, const char *func);
void check_ok_return(int status, int line, const char *func);
void check_ko(int status, int line, const char *func);
void check_equal(int line, const char *func, int64_t x, int64_t y);
void check_ge_equal(int line, const char *func, int64_t x, int64_t y);
void check_null(int line, const char *func, const void *x);
void check_notnull(int line, const char *func, const void *x);
void xlog(const char *msg, const char *tst, const char *func, int line, const char *txt);
@@ -79,6 +80,10 @@ void xlog(const char *msg, const char *tst, const char *func, int line, const ch
xlog("(equal) ", #x " == " #y, __FUNCTION__, __LINE__, NULL); \
if (_x != _y) check_equal(__LINE__, __FUNCTION__, _x, _y); \
} while(0)
#define GE_(x, y) do { int64_t _x = (x), _y = (y); \
xlog("(g_equal)", #x " == " #y, __FUNCTION__, __LINE__, NULL); \
if (_x < _y) check_ge_equal(__LINE__, __FUNCTION__, _x, _y); \
} while(0)
#define NULL_(x) do { xlog("(null) ", #x, __FUNCTION__, __LINE__, NULL); \
check_null(__LINE__, __FUNCTION__, (x)); \
} while(0)

View File

@@ -816,10 +816,12 @@ which expect >/dev/null 2>&1 || skip "WARNING: expect tool missing, interactive
prepare "[32] Interactive password retry from terminal." new
EXPECT_DEV=$(losetup $LOOPDEV | sed -e "s/.*(\(.*\))/\1/")
EXPECT_TIMEOUT=10
[ -n "$VALG" ] && EXPECT_TIMEOUT=60
expect_run - >/dev/null <<EOF
proc abort {} { send_error "Timeout. "; exit 2 }
set timeout 10
set timeout $EXPECT_TIMEOUT
eval spawn $CRYPTSETUP_RAW luksOpen -v -T 2 $LOOPDEV $DEV_NAME
expect timeout abort "Enter passphrase for $EXPECT_DEV:"
sleep 0.1
@@ -840,7 +842,7 @@ $CRYPTSETUP -q luksClose $DEV_NAME || fail
prepare "[33] Interactive unsuccessful password retry from terminal." new
expect_run - >/dev/null <<EOF
proc abort {} { send_error "Timeout. "; exit 2 }
set timeout 10
set timeout $EXPECT_TIMEOUT
eval spawn $CRYPTSETUP_RAW luksOpen -v -T 2 $LOOPDEV $DEV_NAME
expect timeout abort "Enter passphrase for $EXPECT_DEV:"
sleep 0.1
@@ -858,7 +860,7 @@ EOF
prepare "[34] Interactive kill of last key slot." new
expect_run - >/dev/null <<EOF
proc abort {} { send_error "Timeout. "; exit 2 }
set timeout 10
set timeout $EXPECT_TIMEOUT
eval spawn $CRYPTSETUP_RAW luksKillSlot -v $LOOPDEV 0
expect timeout abort "Are you sure? (Type 'yes' in capital letters):"
send "YES\n"
@@ -877,7 +879,7 @@ EOF
prepare "[35] Interactive format of device." wipe
expect_run - >/dev/null <<EOF
proc abort {} { send_error "Timeout. "; exit 2 }
set timeout 10
set timeout $EXPECT_TIMEOUT
eval spawn $CRYPTSETUP_RAW luksFormat --type luks1 $FAST_PBKDF_OPT -v $LOOPDEV
expect timeout abort "Are you sure? (Type 'yes' in capital letters):"
send "YES\n"
@@ -902,7 +904,7 @@ EOF
prepare "[36] Interactive unsuccessful format of device." new
expect_run - >/dev/null <<EOF
proc abort {} { send_error "Timeout. "; exit 2 }
set timeout 10
set timeout $EXPECT_TIMEOUT
eval spawn $CRYPTSETUP_RAW erase -v $LOOPDEV
expect timeout abort "Are you sure? (Type 'yes' in capital letters):"
send "YES\n"
@@ -932,7 +934,7 @@ EOF
prepare "[37] Interactive add key." new
expect_run - >/dev/null <<EOF
proc abort {} { send_error "Timeout. "; exit 2 }
set timeout 10
set timeout $EXPECT_TIMEOUT
eval spawn $CRYPTSETUP_RAW luksAddKey -S 2 $FAST_PBKDF_OPT -v $LOOPDEV
expect timeout abort "Enter any existing passphrase:"
sleep 0.1
@@ -967,7 +969,7 @@ EOF
prepare "[38] Interactive change key." new
expect_run - >/dev/null <<EOF
proc abort {} { send_error "Timeout. "; exit 2 }
set timeout 10
set timeout $EXPECT_TIMEOUT
eval spawn $CRYPTSETUP_RAW luksChangeKey $FAST_PBKDF_OPT -v $LOOPDEV
expect timeout abort "Enter passphrase to be changed:"
sleep 0.1
@@ -994,7 +996,7 @@ prepare "[39] Interactive suspend and resume." new
echo $PWD0 | $CRYPTSETUP luksOpen $LOOPDEV $DEV_NAME || fail
expect_run - >/dev/null <<EOF
proc abort {} { send_error "Timeout. "; exit 2 }
set timeout 10
set timeout $EXPECT_TIMEOUT
eval spawn $CRYPTSETUP_RAW luksSuspend -v $DEV_NAME
expect timeout abort "Command successful."
expect timeout abort eof
@@ -1041,7 +1043,7 @@ echo -n "$LONG_PWD" >$KEYE
expect_run - >/dev/null <<EOF
proc abort {} { send_error "Timeout. "; exit 2 }
set timeout 10
set timeout $EXPECT_TIMEOUT
eval spawn $CRYPTSETUP_RAW luksFormat --type luks1 $FAST_PBKDF_OPT -v $LOOPDEV
expect timeout abort "Are you sure? (Type 'yes' in capital letters):"
send "YES\n"

View File

@@ -251,7 +251,7 @@ struct hash_test_vector {
const char *name;
unsigned int length;
const char *out;
} out[6];
} out[8];
};
static struct hash_test_vector hash_test_vectors[] = {
@@ -270,6 +270,12 @@ static struct hash_test_vector hash_test_vectors[] = {
"\xc5\x30\x23\x21\x30\xd4\x07\xf8\x9a\xfe\xe0\x96\x49\x97\xf7\xa7"
"\x3e\x83\xbe\x69\x8b\x28\x8f\xeb\xcf\x88\xe3\xe0\x3c\x4f\x07\x57"
"\xea\x89\x64\xe5\x9b\x63\xd9\x37\x08\xb1\x38\xcc\x42\xa6\x6e\xb3" },
{ "blake2b-512",64,"\x78\x6a\x02\xf7\x42\x01\x59\x03\xc6\xc6\xfd\x85\x25\x52\xd2\x72"
"\x91\x2f\x47\x40\xe1\x58\x47\x61\x8a\x86\xe2\x17\xf7\x1f\x54\x19"
"\xd2\x5e\x10\x31\xaf\xee\x58\x53\x13\x89\x64\x44\x93\x4e\xb0\x4b"
"\x90\x3a\x68\x5b\x14\x48\xb7\x55\xd5\x6f\x70\x1a\xfe\x9b\xe2\xce" },
{ "blake2s-256",32,"\x69\x21\x7a\x30\x79\x90\x80\x94\xe1\x11\x21\xd0\x42\x35\x4a\x7c"
"\x1f\x55\xb6\x48\x2c\xa1\xa5\x1e\x1b\x25\x0d\xfd\x1e\xd0\xee\xf9" },
}},{
"a", 1, {
{ "crc32", 4, "\xe8\xb7\xbe\x43" },
@@ -285,6 +291,12 @@ static struct hash_test_vector hash_test_vectors[] = {
"\xf0\xdf\xf5\x94\x13\x14\x5e\x69\x73\xc4\x50\x01\xd0\x08\x7b\x42"
"\xd1\x1b\xc6\x45\x41\x3a\xef\xf6\x3a\x42\x39\x1a\x39\x14\x5a\x59"
"\x1a\x92\x20\x0d\x56\x01\x95\xe5\x3b\x47\x85\x84\xfd\xae\x23\x1a" },
{ "blake2b-512",64,"\x33\x3f\xcb\x4e\xe1\xaa\x7c\x11\x53\x55\xec\x66\xce\xac\x91\x7c"
"\x8b\xfd\x81\x5b\xf7\x58\x7d\x32\x5a\xec\x18\x64\xed\xd2\x4e\x34"
"\xd5\xab\xe2\xc6\xb1\xb5\xee\x3f\xac\xe6\x2f\xed\x78\xdb\xef\x80"
"\x2f\x2a\x85\xcb\x91\xd4\x55\xa8\xf5\x24\x9d\x33\x08\x53\xcb\x3c" },
{ "blake2s-256",32,"\x4a\x0d\x12\x98\x73\x40\x30\x37\xc2\xcd\x9b\x90\x48\x20\x36\x87"
"\xf6\x23\x3f\xb6\x73\x89\x56\xe0\x34\x9b\xd4\x32\x0f\xec\x3e\x90" },
}},{
"abc", 3, {
{ "crc32", 4, "\x35\x24\x41\xc2" },
@@ -300,6 +312,12 @@ static struct hash_test_vector hash_test_vectors[] = {
"\xf3\x04\x3e\x3a\x73\x1b\xce\x72\x1a\xe1\xb3\x03\xd9\x7e\x6d\x4c"
"\x71\x81\xee\xbd\xb6\xc5\x7e\x27\x7d\x0e\x34\x95\x71\x14\xcb\xd6"
"\xc7\x97\xfc\x9d\x95\xd8\xb5\x82\xd2\x25\x29\x20\x76\xd4\xee\xf5" },
{ "blake2b-512",64,"\xba\x80\xa5\x3f\x98\x1c\x4d\x0d\x6a\x27\x97\xb6\x9f\x12\xf6\xe9"
"\x4c\x21\x2f\x14\x68\x5a\xc4\xb7\x4b\x12\xbb\x6f\xdb\xff\xa2\xd1"
"\x7d\x87\xc5\x39\x2a\xab\x79\x2d\xc2\x52\xd5\xde\x45\x33\xcc\x95"
"\x18\xd3\x8a\xa8\xdb\xf1\x92\x5a\xb9\x23\x86\xed\xd4\x00\x99\x23" },
{ "blake2s-256",32,"\x50\x8c\x5e\x8c\x32\x7c\x14\xe2\xe1\xa7\x2b\xa3\x4e\xeb\x45\x2f"
"\x37\x45\x8b\x20\x9e\xd6\x3a\x29\x4d\x99\x9b\x4c\x86\x67\x59\x82" },
}},{
"abcdefghijklmnopqrstuvwxyz", 26, {
{ "crc32", 4, "\x4c\x27\x50\xbd" },
@@ -315,6 +333,12 @@ static struct hash_test_vector hash_test_vectors[] = {
"\x8d\x38\x63\x1e\xad\x42\x38\xf5\x44\x2e\xe1\x3b\x80\x54\xe4\x1b"
"\x08\xbf\x2a\x92\x51\xc3\x0b\x6a\x0b\x8a\xae\x86\x17\x7a\xb4\xa6"
"\xf6\x8f\x67\x3e\x72\x07\x86\x5d\x5d\x98\x19\xa3\xdb\xa4\xeb\x3b" },
{ "blake2b-512",64,"\xc6\x8e\xde\x14\x3e\x41\x6e\xb7\xb4\xaa\xae\x0d\x8e\x48\xe5\x5d"
"\xd5\x29\xea\xfe\xd1\x0b\x1d\xf1\xa6\x14\x16\x95\x3a\x2b\x0a\x56"
"\x66\xc7\x61\xe7\xd4\x12\xe6\x70\x9e\x31\xff\xe2\x21\xb7\xa7\xa7"
"\x39\x08\xcb\x95\xa4\xd1\x20\xb8\xb0\x90\xa8\x7d\x1f\xbe\xdb\x4c" },
{ "blake2s-256",32,"\xbd\xf8\x8e\xb1\xf8\x6a\x0c\xdf\x0e\x84\x0b\xa8\x8f\xa1\x18\x50"
"\x83\x69\xdf\x18\x6c\x73\x55\xb4\xb1\x6c\xf7\x9f\xa2\x71\x0a\x12" },
}},{
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 62, {
{ "crc32", 4, "\x1f\xc2\xe6\xd2" },
@@ -330,6 +354,12 @@ static struct hash_test_vector hash_test_vectors[] = {
"\x1d\xd7\xc2\x8c\xde\xc0\x66\xcc\x6a\xf4\x2e\x40\xf8\x2f\x3a\x1e"
"\x08\xeb\xa2\x66\x29\x12\x9d\x8f\xb7\xcb\x57\x21\x1b\x92\x81\xa6"
"\x55\x17\xcc\x87\x9d\x7b\x96\x21\x42\xc6\x5f\x5a\x7a\xf0\x14\x67" },
{ "blake2b-512",64,"\x99\x96\x48\x02\xe5\xc2\x5e\x70\x37\x22\x90\x5d\x3f\xb8\x00\x46"
"\xb6\xbc\xa6\x98\xca\x9e\x2c\xc7\xe4\x9b\x4f\xe1\xfa\x08\x7c\x2e"
"\xdf\x03\x12\xdf\xbb\x27\x5c\xf2\x50\xa1\xe5\x42\xfd\x5d\xc2\xed"
"\xd3\x13\xf9\xc4\x91\x12\x7c\x2e\x8c\x0c\x9b\x24\x16\x8e\x2d\x50" },
{ "blake2s-256",32,"\xc7\x54\x39\xea\x17\xe1\xde\x6f\xa4\x51\x0c\x33\x5d\xc3\xd3\xf3"
"\x43\xe6\xf9\xe1\xce\x27\x73\xe2\x5b\x41\x74\xf1\xdf\x8b\x11\x9b" },
}},{
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56, {
{ "crc32", 4, "\x17\x1a\x3f\x5f" },
@@ -345,6 +375,12 @@ static struct hash_test_vector hash_test_vectors[] = {
"\x02\x7f\x61\x36\x6a\x14\x07\x26\x2d\xc2\xa6\xa3\x45\xd9\xe2\x40"
"\xc0\x17\xc1\x83\x3d\xb1\xe6\xdb\x6a\x46\xbd\x44\x4b\x0c\x69\x52"
"\x0c\x85\x6e\x7c\x6e\x9c\x36\x6d\x15\x0a\x7d\xa3\xae\xb1\x60\xd1" },
{ "blake2b-512",64,"\x72\x85\xff\x3e\x8b\xd7\x68\xd6\x9b\xe6\x2b\x3b\xf1\x87\x65\xa3"
"\x25\x91\x7f\xa9\x74\x4a\xc2\xf5\x82\xa2\x08\x50\xbc\x2b\x11\x41"
"\xed\x1b\x3e\x45\x28\x59\x5a\xcc\x90\x77\x2b\xdf\x2d\x37\xdc\x8a"
"\x47\x13\x0b\x44\xf3\x3a\x02\xe8\x73\x0e\x5a\xd8\xe1\x66\xe8\x88" },
{ "blake2s-256",32,"\x6f\x4d\xf5\x11\x6a\x6f\x33\x2e\xda\xb1\xd9\xe1\x0e\xe8\x7d\xf6"
"\x55\x7b\xea\xb6\x25\x9d\x76\x63\xf3\xbc\xd5\x72\x2c\x13\xf1\x89" },
}},{
"message digest", 14, {
{ "crc32", 4, "\x20\x15\x9d\x7f" },
@@ -360,6 +396,12 @@ static struct hash_test_vector hash_test_vectors[] = {
"\x83\x8d\x00\x03\x22\x30\xf5\x3c\xe1\xf5\x70\x0c\x0f\xfb\x4d\x3b"
"\x84\x21\x55\x76\x59\xef\x55\xc1\x06\xb4\xb5\x2a\xc5\xa4\xaa\xa6"
"\x92\xed\x92\x00\x52\x83\x8f\x33\x62\xe8\x6d\xbd\x37\xa8\x90\x3e" },
{ "blake2b-512",64,"\x3c\x26\xce\x48\x7b\x1c\x0f\x06\x23\x63\xaf\xa3\xc6\x75\xeb\xdb"
"\xf5\xf4\xef\x9b\xdc\x02\x2c\xfb\xef\x91\xe3\x11\x1c\xdc\x28\x38"
"\x40\xd8\x33\x1f\xc3\x0a\x8a\x09\x06\xcf\xf4\xbc\xdb\xcd\x23\x0c"
"\x61\xaa\xec\x60\xfd\xfa\xd4\x57\xed\x96\xb7\x09\xa3\x82\x35\x9a" },
{ "blake2s-256",32,"\xfa\x10\xab\x77\x5a\xcf\x89\xb7\xd3\xc8\xa6\xe8\x23\xd5\x86\xf6"
"\xb6\x7b\xdb\xac\x4c\xe2\x07\xfe\x14\x5b\x7d\x3a\xc2\x5c\xd2\x8c" },
}}};
/*

View File

@@ -68,7 +68,7 @@ function dm_integrity_features()
add_device() {
cleanup
dd if=/dev/urandom of=$KEY_FILE bs=1 count=512 >/dev/null 2>&1
dd if=/dev/urandom of=$KEY_FILE bs=4096 count=1 >/dev/null 2>&1
dd if=/dev/urandom of=$KEY_FILE2 bs=1 count=32 >/dev/null 2>&1
dd if=/dev/zero of=$DEV bs=1M count=32 >/dev/null 2>&1
dd if=/dev/zero of=$DEV2 bs=1M count=32 >/dev/null 2>&1
@@ -161,10 +161,12 @@ intformat() # alg alg_out tagsize outtagsize sector_size csum [keyfile keysize]
fi
echo -n "[INTEGRITY:$2:$4:$5]"
[ -n "$8" ] && echo -n "[KEYFILE:$8]"
echo -n "[FORMAT]"
$INTSETUP format --integrity-legacy-padding -q --integrity $1 $TAG_PARAMS --sector-size $5 $KEY_PARAMS $DEV >/dev/null 2>&1
if [ $? -ne 0 ] ; then
if ! grep -q $1 /proc/crypto ; then
ALG=$(echo $1 | sed -e 's/hmac-//')
if ! grep -q $ALG /proc/crypto ; then
echo "[N/A]"
return
fi
@@ -175,6 +177,11 @@ intformat() # alg alg_out tagsize outtagsize sector_size csum [keyfile keysize]
dump_check "sector_size" $5
echo -n "[ACTIVATE]"
$INTSETUP open $DEV $DEV_NAME --integrity $1 $KEY_PARAMS || fail "Cannot activate device."
if [ -n "$8" ]; then
KEY_HEX=$(xxd -c 4096 -l $8 -p $7)
[ -z "$KEY_HEX" ] && fail "Cannot decode key."
dmsetup table --showkeys $DEV_NAME | grep -q $KEY_HEX || fail "Key mismatch."
fi
status_check "tag size" $4
status_check "integrity" $2
status_check "sector size" "$5 bytes"
@@ -238,7 +245,7 @@ int_error_detection() # mode alg tagsize outtagsize sector_size key_file key_siz
int_journal() # 1 alg, 2 tagsize, 3 sector_size, 4 watermark, 5 commit_time, 6 journal_integrity, 7 key-file, 8 key-size, 9 journal_integrity_out
{
echo -n "[INTEGRITY JOURNAL:$6:${4}%:${5}ms]"
echo -n "[INTEGRITY JOURNAL:$6:${4}%:${5}ms:$8]"
echo -n "[FORMAT]"
ARGS="--integrity $1 --journal-watermark $4 --journal-commit-time $5 --journal-integrity $6 --journal-integrity-key-file $7 --journal-integrity-key-size $8"
$INTSETUP format -q --tag-size $2 --sector-size $3 $ARGS $DEV || fail "Cannot format device."
@@ -248,7 +255,7 @@ int_journal() # 1 alg, 2 tagsize, 3 sector_size, 4 watermark, 5 commit_time, 6 j
$INTSETUP open $DEV $DEV_NAME $ARGS || fail "Cannot activate device."
echo -n "[KEYED HASH]"
KEY_HEX=$(xxd -c 256 -l $8 -p $7)
KEY_HEX=$(xxd -c 4096 -l $8 -p $7)
[ -z "$KEY_HEX" ] && fail "Cannot decode key."
dmsetup table --showkeys $DEV_NAME | grep -q $KEY_HEX || fail "Key mismatch."
@@ -339,6 +346,7 @@ intformat sha256 sha256 0 32 512 8e5fe4119558e117bfc40e3b0f13ade3
intformat hmac-sha256 hmac\(sha256\) 0 32 512 8e5fe4119558e117bfc40e3b0f13ade3abe497b52604d4c7cca0cfd6c7f4cf11 $KEY_FILE 32
intformat sha256 sha256 0 32 4096 33f7dfa5163ca9f740383fb8b0919574e38a7b20a94a4170fde4238196b7c4b4
intformat hmac-sha256 hmac\(sha256\) 0 32 4096 33f7dfa5163ca9f740383fb8b0919574e38a7b20a94a4170fde4238196b7c4b4 $KEY_FILE 32
intformat hmac-sha256 hmac\(sha256\) 0 32 4096 33f7dfa5163ca9f740383fb8b0919574e38a7b20a94a4170fde4238196b7c4b4 $KEY_FILE 4096
echo "Error detection tests:"
int_error_detection J crc32c 0 4 512
@@ -360,6 +368,7 @@ echo "Journal parameters tests:"
int_journal crc32 4 512 66 1000 hmac-sha256 $KEY_FILE 32 hmac\(sha256\)
int_journal sha256 32 4096 34 5000 hmac-sha1 $KEY_FILE 16 hmac\(sha1\)
int_journal sha1 20 512 75 9999 hmac-sha256 $KEY_FILE 32 hmac\(sha256\)
int_journal sha1 20 512 75 9999 hmac-sha256 $KEY_FILE 4096 hmac\(sha256\)
echo "Journal encryption tests:"
int_journal_crypt cbc-aes cbc\(aes\) $KEY_FILE 32

View File

@@ -91,10 +91,7 @@ function get_expsum() # $offset
function check_sum() # $key $keysize $offset [stdin|keyfile]
{
# Fill device with zeroes and reopen it
dd if=/dev/zero of=/dev/mapper/$DEV_NAME bs=1k $LOOP_DD_PARAM >/dev/null 2>&1
sync
dmremove $DEV_NAME
$CRYPTSETUP close $DEV_NAME || fail
EXPSUM=$(get_expsum $3)
if [ "$4" == "stdin" ] ; then
@@ -163,8 +160,9 @@ for key_size in $KEY_SIZES ; do
2>/dev/null
[ $? -ne 0 ] && echo "[SKIPPED]" && continue
check_exists
# Fill device with zeroes and reopen it
dd if=/dev/zero of=/dev/mapper/$DEV_NAME $LOOP_DD_PARAM >/dev/null 2>&1
check_sum $key $key_size $offset keyfile
$CRYPTSETUP loopaesClose $DEV_NAME || fail
check_sum $key $key_size $offset stdin
$CRYPTSETUP loopaesClose $DEV_NAME || fail
check_sum_losetup $key AES$key_size $offset

View File

@@ -0,0 +1,506 @@
#!/bin/bash
PS4='$LINENO:'
[ -z "$CRYPTSETUP_PATH" ] && CRYPTSETUP_PATH=".."
CRYPTSETUP=$CRYPTSETUP_PATH/cryptsetup
CRYPTSETUP_RAW=$CRYPTSETUP
CRYPTSETUP_VALGRIND=../.libs/cryptsetup
CRYPTSETUP_LIB_VALGRIND=../.libs
IMG=reenc-mangle-data
IMG_HDR=$IMG.hdr
IMG_JSON=$IMG.json
KEY1=key1
DEV_NAME=reenc3492834
FAST_PBKDF2="--pbkdf pbkdf2 --pbkdf-force-iterations 1000"
CS_PWPARAMS="--disable-keyring --key-file $KEY1"
CS_PARAMS="-q --disable-locks $CS_PWPARAMS"
JSON_MSIZE=16384
function remove_mapping()
{
[ -b /dev/mapper/$DEV_NAME ] && dmsetup remove --retry $DEV_NAME
rm -f $IMG $IMG_HDR $IMG_JSON $KEY1 >/dev/null 2>&1
}
function fail()
{
local frame=0
[ -n "$1" ] && echo "$1"
echo "FAILED backtrace:"
while caller $frame; do ((frame++)); done
remove_mapping
exit 2
}
function skip()
{
[ -n "$1" ] && echo "$1"
remove_mapping
exit 77
}
function bin_check()
{
which $1 >/dev/null 2>&1 || skip "WARNING: test require $1 binary, test skipped."
}
function img_json_save()
{
# FIXME: why --json-file cannot be used?
#$CRYPTSETUP luksDump --dump-json-metadata $IMG | jq -c -M | tr -d '\n' >$IMG_JSON
local LUKS2_JSON_SIZE=$(($JSON_MSIZE - 4096))
_dd if=$IMG count=$LUKS2_JSON_SIZE skip=4096 | jq -c -M . | tr -d '\n' >$IMG_JSON
}
function img_json_dump()
{
img_json_save
jq . $IMG_JSON
}
function img_hash_save()
{
IMG_HASH=$(sha256sum $IMG | cut -d' ' -f 1)
}
function img_hash_unchanged()
{
local IMG_HASH2=$(sha256sum $IMG | cut -d' ' -f 1)
[ "$IMG_HASH" != "$IMG_HASH2" ] && fail "Image changed!"
}
function img_prepare_raw() # $1 options
{
remove_mapping
if [ ! -e $KEY1 ]; then
dd if=/dev/urandom of=$KEY1 count=1 bs=32 >/dev/null 2>&1
fi
truncate -s 32M $IMG || fail
$CRYPTSETUP luksFormat $FAST_PBKDF2 $CS_PARAMS --luks2-metadata-size $JSON_MSIZE $IMG $1 || fail
}
function img_prepare() # $1 options
{
img_prepare_raw
# FIXME: resilience is not saved here (always none)?
$CRYPTSETUP reencrypt $IMG $CS_PARAMS -q --init-only --resilience none $1 >/dev/null 2>&1
[ $? -ne 0 ] && skip "Reencryption unsupported, test skipped."
img_json_save
img_hash_save
}
function _dd()
{
dd $@ status=none conv=notrunc bs=1
}
# header mangle functions
function img_update_json()
{
local LUKS2_BIN1_OFFSET=448
local LUKS2_BIN2_OFFSET=$((LUKS2_BIN1_OFFSET + $JSON_MSIZE))
local LUKS2_JSON_SIZE=$(($JSON_MSIZE - 4096))
# if present jq script, mangle JSON
if [ -n "$1" ]; then
local JSON=$(cat $IMG_JSON)
echo $JSON | jq -M -c "$1" >$IMG_JSON || fail
local JSON=$(cat $IMG_JSON)
echo $JSON | tr -d '\n' >$IMG_JSON || fail
fi
# wipe JSON areas
_dd if=/dev/zero of=$IMG count=$LUKS2_JSON_SIZE seek=4096
_dd if=/dev/zero of=$IMG count=$LUKS2_JSON_SIZE seek=$(($JSON_MSIZE + 4096))
# write JSON data
_dd if=$IMG_JSON of=$IMG count=$LUKS2_JSON_SIZE seek=4096
_dd if=$IMG_JSON of=$IMG count=$LUKS2_JSON_SIZE seek=$(($JSON_MSIZE + 4096))
# erase sha256 checksums
_dd if=/dev/zero of=$IMG count=64 seek=$LUKS2_BIN1_OFFSET
_dd if=/dev/zero of=$IMG count=64 seek=$LUKS2_BIN2_OFFSET
# calculate sha256 and write chexksums
local SUM1_HEX=$(_dd if=$IMG count=$JSON_MSIZE | sha256sum | cut -d ' ' -f 1)
echo $SUM1_HEX | xxd -r -p | _dd of=$IMG seek=$LUKS2_BIN1_OFFSET count=64 || fail
local SUM2_HEX=$(_dd if=$IMG skip=$JSON_MSIZE count=$JSON_MSIZE | sha256sum | cut -d ' ' -f 1)
echo $SUM2_HEX | xxd -r -p | _dd of=$IMG seek=$LUKS2_BIN2_OFFSET count=64 || fail
img_hash_save
}
function img_check_ok()
{
if [ $(id -u) == 0 ]; then
$CRYPTSETUP open $CS_PWPARAMS $IMG $DEV_NAME || fail
$CRYPTSETUP close $DEV_NAME || fail
fi
$CRYPTSETUP repair $IMG $CS_PARAMS || fail
}
function img_check_fail()
{
if [ $(id -u) == 0 ]; then
$CRYPTSETUP open $CS_PWPARAMS $IMG $DEV_NAME 2>/dev/null && fail
fi
$CRYPTSETUP repair $IMG $CS_PARAMS 2>/dev/null && fail
img_hash_unchanged
}
function img_run_reenc_ok()
{
local EXPECT_TIMEOUT=5
[ -n "$VALG" ] && EXPECT_TIMEOUT=60
# For now, we cannot run reencryption in batch mode for non-block device. Just fake the terminal here.
expect_run - >/dev/null <<EOF
proc abort {} { send_error "Timeout. "; exit 2 }
set timeout $EXPECT_TIMEOUT
eval spawn $CRYPTSETUP_RAW reencrypt $IMG $CS_PWPARAMS --disable-locks --resilience none
expect timeout abort "Are you sure? (Type 'yes' in capital letters):"
send "YES\n"
expect timeout abort eof
exit
EOF
[ $? -eq 0 ] || fail "Expect script failed."
}
function img_run_reenc_fail()
{
local EXPECT_TIMEOUT=5
[ -n "$VALG" ] && EXPECT_TIMEOUT=60
# For now, we cannot run reencryption in batch mode for non-block device. Just fake the terminal here.
expect_run - >/dev/null <<EOF
proc abort {} { send_error "Timeout. "; exit 42 }
set timeout $EXPECT_TIMEOUT
eval spawn $CRYPTSETUP_RAW reencrypt $IMG $CS_PWPARAMS --disable-locks
expect timeout abort "Are you sure? (Type 'yes' in capital letters):"
send "YES\n"
expect timeout abort eof
catch wait result
exit [lindex \$result 3]
EOF
local ret=$?
[ $ret -eq 0 ] && fail "Reencryption passed (should have failed)."
[ $ret -eq 42 ] && fail "Expect script failed."
img_hash_unchanged
}
function img_check_fail_repair_ok()
{
if [ $(id -u) == 0 ]; then
$CRYPTSETUP open $CS_PWPARAMS $IMG $DEV_NAME 2>/dev/null && fail
fi
img_run_reenc_fail
# repair metadata
$CRYPTSETUP repair $IMG $CS_PARAMS || fail
img_check_ok
img_run_reenc_ok
}
function valgrind_setup()
{
bin_check valgrind
[ ! -f $CRYPTSETUP_VALGRIND ] && fail "Unable to get location of cryptsetup executable."
export LD_LIBRARY_PATH="$CRYPTSETUP_LIB_VALGRIND:$LD_LIBRARY_PATH"
CRYPTSETUP=valgrind_run
CRYPTSETUP_RAW="./valg.sh ${CRYPTSETUP_VALGRIND}"
}
function valgrind_run()
{
INFOSTRING="$(basename ${BASH_SOURCE[1]})-line-${BASH_LINENO[0]}" ./valg.sh ${CRYPTSETUP_VALGRIND} "$@"
}
function expect_run()
{
export INFOSTRING="$(basename ${BASH_SOURCE[1]})-line-${BASH_LINENO[0]}"
expect "$@"
}
bin_check jq
bin_check sha256sum
bin_check xxd
bin_check expect
export LANG=C
[ -n "$VALG" ] && valgrind_setup && CRYPTSETUP=valgrind_run
#while false; do
echo "[1] Reencryption with old flag is rejected"
img_prepare
img_update_json '.config.requirements.mandatory = ["online-reencryptx"]'
img_check_fail
img_update_json '.config.requirements.mandatory = ["online-reencrypt-v2"]'
img_check_ok
img_run_reenc_ok
img_check_ok
# Simulate old reencryption with no digest (repairable)
img_prepare
img_update_json 'del(.digests."2") | .config.requirements.mandatory = ["online-reencrypt"]'
img_check_fail_repair_ok
# This must fail for new releases
echo "[2] Old reencryption in-progress (journal)"
img_prepare
img_update_json '
del(.digests."2") |
.keyslots."2".area.type = "journal" |
.segments = {
"0" : (.segments."0" +
{"size" : .keyslots."2".area.size} +
{"flags" : ["in-reencryption"]}),
"1" : (.segments."0" +
{"offset" : ((.segments."0".offset|tonumber) +
(.keyslots."2".area.size|tonumber))|tostring}),
"2" : .segments."1",
"3" : .segments."2"
} |
.digests."0".segments = ["1","2"] |
.digests."1".segments = ["0","3"] |
.config.requirements.mandatory = ["online-reencrypt"]'
img_check_fail_repair_ok
echo "[3] Old reencryption in-progress (checksum)"
img_prepare
img_update_json '
del(.digests."2") |
.keyslots."2".area.type = "checksum" |
.keyslots."2".area.hash = "sha256" |
.keyslots."2".area.sector_size = 4096 |
.segments = {
"0" : (.segments."0" +
{"size" : .keyslots."2".area.size} +
{"flags" : ["in-reencryption"]}),
"1" : (.segments."0" +
{"offset": ((.segments."0".offset|tonumber) +
(.keyslots."2".area.size|tonumber))|tostring}),
"2" : .segments."1",
"3" : .segments."2"
} |
.digests."0".segments = ["1","2"] |
.digests."1".segments = ["0","3"] |
.config.requirements.mandatory = ["online-reencrypt"]'
img_check_fail_repair_ok
# Note: older tools cannot create this from commandline
echo "[4] Old decryption in-progress (journal)"
img_prepare
img_update_json '
del(.digests."1") |
del(.digests."2") |
del(.keyslots."1") |
.keyslots."2".mode = "decrypt" |
.keyslots."2".area.type = "journal" |
.segments = {
"0" : {
"type" : "linear",
"offset" : .segments."0".offset,
"size" : .keyslots."2".area.size,
"flags" : ["in-reencryption"]
},
"1" : (.segments."0" +
{"offset" : ((.segments."0".offset|tonumber) +
(.keyslots."2".area.size|tonumber))|tostring}),
"2" : .segments."1",
"3" : {
"type" : "linear",
"offset" : .segments."0".offset,
"size" : "dynamic",
"flags" : ["backup-final"]
}
} |
.digests."0".segments = ["1","2"] |
.config.requirements.mandatory = ["online-reencrypt"]'
img_check_fail_repair_ok
echo "[5] Old decryption in-progress (checksum)"
img_prepare
img_update_json '
del(.digests."1") |
del(.digests."2") |
del(.keyslots."1") |
.keyslots."2".mode = "decrypt" |
.keyslots."2".area.type = "checksum" |
.keyslots."2".area.hash = "sha256" |
.keyslots."2".area.sector_size = 4096 |
.segments = {
"0" : {
"type" : "linear",
"offset" : .segments."0".offset,
"size" : .keyslots."2".area.size,
"flags" : ["in-reencryption"]
},
"1" : (.segments."0" +
{"offset" : ((.segments."0".offset|tonumber) +
(.keyslots."2".area.size|tonumber))|tostring}),
"2" : .segments."1",
"3" : {
"type" : "linear",
"offset" : .segments."0".offset,
"size" : "dynamic",
"flags" : ["backup-final"]
}
} |
.digests."0".segments = ["1","2"] |
.config.requirements.mandatory = ["online-reencrypt"]'
img_check_fail_repair_ok
# Note - offset is set to work with the old version (with a datashift bug)
echo "[6] Old reencryption in-progress (datashift)"
img_prepare
img_update_json '
del(.digests."2") |
.keyslots."2".direction = "backward" |
.keyslots."2".area.type = "datashift" |
.keyslots."2".area.size = "4096" |
.keyslots."2".area.shift_size = ((1 * 1024 * 1024)|tostring) |
.segments = {
"0" : (.segments."0" +
{"size" : ((13 * 1024 * 1024)|tostring)}),
"1" : (.segments."0" +
{"offset" : ((30 * 1024 * 1024)|tostring)}),
"2" : .segments."1",
"3" : (.segments."2" +
{"offset" : ((17 * 1024 * 1024)|tostring)}),
} |
.digests."0".segments = ["0","2"] |
.digests."1".segments = ["1","3"] |
.config.requirements.mandatory = ["online-reencrypt"]'
img_check_fail_repair_ok
#
# NEW metadata (with reenc digest)
#
echo "[7] Reencryption with various mangled metadata"
# Normal situation
img_prepare
img_run_reenc_ok
img_check_ok
# The same in various steps.
# Repair must validate not only metadata, but also reencryption digest.
img_prepare
img_update_json 'del(.digests."2")'
img_check_fail_repair_ok
img_prepare '--reduce-device-size 2M'
img_update_json '.keyslots."2".area.shift_size = ((.keyslots."2".area.shift_size|tonumber / 2)|tostring)'
img_check_fail
#FIXME: cannot check with correct digest for now (--init-only does not store area type)
img_prepare
img_update_json '
.keyslots."2".area.type = "checksum" |
.keyslots."2".area.hash = "sha256" |
.keyslots."2".area.sector_size = 4096'
img_check_fail
img_prepare
img_update_json '.keyslots."2".area.type = "journal"'
img_check_fail
img_prepare
img_update_json '.keyslots."2".mode = "decrypt"'
img_check_fail
img_prepare
img_update_json '.keyslots."2".direction = "backward"'
img_check_fail
# key_size must be 1
img_prepare
img_update_json '.keyslots."2".key_size = 16'
img_check_fail
# Mangling segments
img_prepare
img_update_json 'del(.segments."1")'
img_check_fail
img_prepare
img_update_json '.segments."0".encryption = "aes-cbc-null"'
img_check_fail
img_prepare
img_update_json '.segments."1".encryption = "aes-cbc-null"'
img_check_fail
img_prepare
img_update_json '.segments."2".encryption = "aes-cbc-null"'
img_check_fail
# Mangling digests
img_prepare
img_update_json '
.digests."2" = .digests."0" |
.digests."2".keyslots = ["2"] |
.digests."2".segments = []'
img_check_fail
img_prepare
img_update_json '.digests."2".iterations = 1111'
img_check_fail
# Simulate correct progress
img_prepare
img_update_json '
.segments = {
"0" : (.segments."0" +
{"size" : ((1 * 1024 * 1024)|tostring)}),
"1" : (.segments."0" +
{"offset" : ((17 * 1024 * 1024)|tostring)}),
"2" : .segments."1",
"3" : .segments."2"
} |
.digests."0".segments = ["1","2"] |
.digests."1".segments = ["0","3"]'
img_check_ok
# Mangling keyslots
# Set reencrypt slot to non-ignore priority
# This should be benign, just avoid noisy messages
img_prepare
img_update_json 'del(.keyslots."2".priority)'
img_check_ok
# Flags
# Remove mandatory reenc flag, but keep reenc metadata
img_prepare
img_update_json '.config.requirements.mandatory = []'
img_check_fail
# Unknown segment flag, should be ignored
img_prepare
img_update_json '.segments."0".flags = ["dead-parrot"]'
img_check_ok
echo "[8] Reencryption with AEAD is not supported"
img_prepare_raw
img_json_save
img_update_json '
.segments."0".integrity = {
"type" : "hmac(sha256)",
"journal_encryption": "none",
"journal_integrity": "none"
}'
$CRYPTSETUP reencrypt $IMG $CS_PARAMS >/dev/null 2>&1 && fail
remove_mapping
exit 0

View File

@@ -115,6 +115,7 @@ function fail()
function skip()
{
[ -n "$1" ] && echo "$1"
remove_mapping
exit 77
}
@@ -726,6 +727,7 @@ echo -n "[512 sector]"
echo $PWD1 | $CRYPTSETUP -q luksFormat --type luks2 -s 128 -c aes-cbc-essiv:sha256 --offset 8192 $FAST_PBKDF_ARGON $DEV || fail
wipe $PWD1
check_hash $PWD1 $HASH1
echo $PWD1 | $CRYPTSETUP reencrypt $DEV -q $FAST_PBKDF_ARGON 2>&1 | tail -1 | grep -q "not supported" && skip " No reenryption support, test skipped."
echo $PWD1 | $CRYPTSETUP reencrypt $DEV -q $FAST_PBKDF_ARGON || fail
check_hash $PWD1 $HASH1
echo $PWD1 | $CRYPTSETUP reencrypt $DEV -q -s 256 -c twofish-cbc-essiv:sha256 --resilience journal $FAST_PBKDF_ARGON || fail
@@ -942,6 +944,17 @@ $CRYPTSETUP status $DEV_NAME >/dev/null || fail
dmsetup remove --retry $DEV_NAME2
$CRYPTSETUP status $DEV_NAME >/dev/null 2>&1 && fail
# check tool can block some funny user ideas
preparebig 64
echo $PWD1 | $CRYPTSETUP luksFormat --type luks2 -c serpent-xts-plain -q $FAST_PBKDF_ARGON $DEV || fail
echo $PWD1 | $CRYPTSETUP reencrypt --decrypt $DEV -q 2>/dev/null && fail
echo $PWD1 | $CRYPTSETUP reencrypt --decrypt $DEV --header $DEV -q 2>/dev/null && fail
open_crypt $PWD1
echo $PWD1 | $CRYPTSETUP reencrypt --decrypt --active-name $DEV_NAME -q 2>/dev/null && fail
echo $PWD1 | $CRYPTSETUP reencrypt --decrypt --active-name $DEV_NAME --header $DEV -q 2>/dev/null && fail
$CRYPTSETUP status $DEV_NAME | grep -q "reencryption: in-progress" && fail
$CRYPTSETUP close $DEV_NAME
if ! dm_delay_features; then
echo "dm-delay target is missing, skipping recovery tests."
remove_mapping

View File

@@ -95,6 +95,14 @@ void check_equal(int line, const char *func, int64_t x, int64_t y)
exit(-1);
}
void check_ge_equal(int line, const char *func, int64_t x, int64_t y)
{
printf("FAIL line %d [%s]: expected greater or equal values differs: %"
PRIi64 " < %" PRIi64 "\n", line, func, x, y);
_cleanup();
exit(-1);
}
void check_null(int line, const char *func, const void *x)
{
if (x) {