mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-06 00:10:04 +01:00
Compare commits
59 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1fae09d607 | ||
|
|
b1ef7cc3cd | ||
|
|
bc2b38991b | ||
|
|
3b35e438bc | ||
|
|
4c0ae43f3a | ||
|
|
d6649293a5 | ||
|
|
624f3220a1 | ||
|
|
2e44267891 | ||
|
|
c75d740f9a | ||
|
|
bc26c764c6 | ||
|
|
ce8aab39ca | ||
|
|
d0169a303d | ||
|
|
f83e56e43e | ||
|
|
4e98b65c04 | ||
|
|
d45e6788e8 | ||
|
|
18cb1eeeb9 | ||
|
|
7eeb45537a | ||
|
|
60addcffa6 | ||
|
|
e71c151ebb | ||
|
|
6f2df7cd01 | ||
|
|
8a7f590891 | ||
|
|
7319be8dad | ||
|
|
5b07968c2d | ||
|
|
dc0ecd4288 | ||
|
|
286784c934 | ||
|
|
4b24e8e052 | ||
|
|
3f217dcacf | ||
|
|
c80fce5f47 | ||
|
|
3f4ce5d2b0 | ||
|
|
f95336e116 | ||
|
|
3753614517 | ||
|
|
5fd96b75d3 | ||
|
|
44aac4e5a3 | ||
|
|
fbea879d1e | ||
|
|
7012d031b6 | ||
|
|
a7f3065f6f | ||
|
|
f7fabbe141 | ||
|
|
ac9a2c08e3 | ||
|
|
bee77b2f35 | ||
|
|
2d03ba3f4d | ||
|
|
29e4bca24b | ||
|
|
2f9b22f5ff | ||
|
|
bbb6739d41 | ||
|
|
d0c6eeea81 | ||
|
|
4f982e9708 | ||
|
|
df8135dfdf | ||
|
|
280c821b9b | ||
|
|
28dd0f5c05 | ||
|
|
c7789719d8 | ||
|
|
97e709788e | ||
|
|
3dbbc005d3 | ||
|
|
e1e3430c2c | ||
|
|
b354cdd9ad | ||
|
|
ed24d033d4 | ||
|
|
5da8f5e710 | ||
|
|
800a8a4d5d | ||
|
|
0a06947e14 | ||
|
|
418d068470 | ||
|
|
9abe126016 |
14
README.md
14
README.md
@@ -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).
|
||||
|
||||
14
configure.ac
14
configure.ac
@@ -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
56
docs/v2.3.6-ReleaseNotes
Normal 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
95
docs/v2.3.7-ReleaseNotes
Normal 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.
|
||||
@@ -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 \
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(¶ms, " ");
|
||||
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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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++);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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."));
|
||||
|
||||
@@ -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);
|
||||
|
||||
381
lib/luks2/luks2_reencrypt_digest.c
Normal file
381
lib/luks2/luks2_reencrypt_digest.c
Normal file
@@ -0,0 +1,381 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2, reencryption digest helpers
|
||||
*
|
||||
* Copyright (C) 2022, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2022, Ondrej Kozina
|
||||
* Copyright (C) 2022, Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "luks2_internal.h"
|
||||
#include <assert.h>
|
||||
|
||||
#define MAX_STR 64
|
||||
|
||||
struct jtype {
|
||||
enum { JNONE = 0, JSTR, JU64, JX64, JU32 } type;
|
||||
json_object *jobj;
|
||||
const char *id;
|
||||
};
|
||||
|
||||
static size_t sr(struct jtype *j, uint8_t *ptr)
|
||||
{
|
||||
json_object *jobj;
|
||||
size_t len = 0;
|
||||
uint64_t u64;
|
||||
uint32_t u32;
|
||||
|
||||
if (!json_object_is_type(j->jobj, json_type_object))
|
||||
return 0;
|
||||
|
||||
if (!json_object_object_get_ex(j->jobj, j->id, &jobj))
|
||||
return 0;
|
||||
|
||||
switch(j->type) {
|
||||
case JSTR: /* JSON string */
|
||||
if (!json_object_is_type(jobj, json_type_string))
|
||||
return 0;
|
||||
len = strlen(json_object_get_string(jobj));
|
||||
if (len > MAX_STR)
|
||||
return 0;
|
||||
if (ptr)
|
||||
memcpy(ptr, json_object_get_string(jobj), len);
|
||||
break;
|
||||
case JU64: /* Unsigned 64bit integer stored as string */
|
||||
if (!json_object_is_type(jobj, json_type_string))
|
||||
break;
|
||||
len = sizeof(u64);
|
||||
if (ptr) {
|
||||
u64 = cpu_to_be64(crypt_jobj_get_uint64(jobj));
|
||||
memcpy(ptr, &u64, len);
|
||||
}
|
||||
break;
|
||||
case JX64: /* Unsigned 64bit segment size (allows "dynamic") */
|
||||
if (!json_object_is_type(jobj, json_type_string))
|
||||
break;
|
||||
if (!strcmp(json_object_get_string(jobj), "dynamic")) {
|
||||
len = strlen("dynamic");
|
||||
if (ptr)
|
||||
memcpy(ptr, json_object_get_string(jobj), len);
|
||||
} else {
|
||||
len = sizeof(u64);
|
||||
u64 = cpu_to_be64(crypt_jobj_get_uint64(jobj));
|
||||
if (ptr)
|
||||
memcpy(ptr, &u64, len);
|
||||
}
|
||||
break;
|
||||
case JU32: /* Unsigned 32bit integer, stored as JSON int */
|
||||
if (!json_object_is_type(jobj, json_type_int))
|
||||
return 0;
|
||||
len = sizeof(u32);
|
||||
if (ptr) {
|
||||
u32 = cpu_to_be32(crypt_jobj_get_uint32(jobj));
|
||||
memcpy(ptr, &u32, len);
|
||||
}
|
||||
break;
|
||||
case JNONE:
|
||||
return 0;
|
||||
};
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static size_t srs(struct jtype j[], uint8_t *ptr)
|
||||
{
|
||||
size_t l, len = 0;
|
||||
|
||||
while(j->jobj) {
|
||||
l = sr(j, ptr);
|
||||
if (!l)
|
||||
return 0;
|
||||
len += l;
|
||||
if (ptr)
|
||||
ptr += l;
|
||||
j++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static size_t segment_linear_serialize(json_object *jobj_segment, uint8_t *buffer)
|
||||
{
|
||||
struct jtype j[] = {
|
||||
{ JSTR, jobj_segment, "type" },
|
||||
{ JU64, jobj_segment, "offset" },
|
||||
{ JX64, jobj_segment, "size" },
|
||||
{}
|
||||
};
|
||||
return srs(j, buffer);
|
||||
}
|
||||
|
||||
static size_t segment_crypt_serialize(json_object *jobj_segment, uint8_t *buffer)
|
||||
{
|
||||
struct jtype j[] = {
|
||||
{ JSTR, jobj_segment, "type" },
|
||||
{ JU64, jobj_segment, "offset" },
|
||||
{ JX64, jobj_segment, "size" },
|
||||
{ JU64, jobj_segment, "iv_tweak" },
|
||||
{ JSTR, jobj_segment, "encryption" },
|
||||
{ JU32, jobj_segment, "sector_size" },
|
||||
{}
|
||||
};
|
||||
return srs(j, buffer);
|
||||
}
|
||||
|
||||
static size_t segment_serialize(json_object *jobj_segment, uint8_t *buffer)
|
||||
{
|
||||
json_object *jobj_type;
|
||||
const char *segment_type;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_segment, "type", &jobj_type))
|
||||
return 0;
|
||||
|
||||
if (!(segment_type = json_object_get_string(jobj_type)))
|
||||
return 0;
|
||||
|
||||
if (!strcmp(segment_type, "crypt"))
|
||||
return segment_crypt_serialize(jobj_segment, buffer);
|
||||
else if (!strcmp(segment_type, "linear"))
|
||||
return segment_linear_serialize(jobj_segment, buffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t backup_segments_serialize(struct luks2_hdr *hdr, uint8_t *buffer)
|
||||
{
|
||||
json_object *jobj_segment;
|
||||
size_t l, len = 0;
|
||||
|
||||
jobj_segment = LUKS2_get_segment_by_flag(hdr, "backup-previous");
|
||||
if (!jobj_segment || !(l = segment_serialize(jobj_segment, buffer)))
|
||||
return 0;
|
||||
len += l;
|
||||
if (buffer)
|
||||
buffer += l;
|
||||
|
||||
jobj_segment = LUKS2_get_segment_by_flag(hdr, "backup-final");
|
||||
if (!jobj_segment || !(l = segment_serialize(jobj_segment, buffer)))
|
||||
return 0;
|
||||
len += l;
|
||||
if (buffer)
|
||||
buffer += l;
|
||||
|
||||
jobj_segment = LUKS2_get_segment_by_flag(hdr, "backup-moved-segment");
|
||||
if (jobj_segment) {
|
||||
if (!(l = segment_serialize(jobj_segment, buffer)))
|
||||
return 0;
|
||||
len += l;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static size_t reenc_keyslot_serialize(struct luks2_hdr *hdr, uint8_t *buffer)
|
||||
{
|
||||
json_object *jobj_keyslot, *jobj_area, *jobj_type;
|
||||
const char *area_type;
|
||||
int keyslot_reencrypt;
|
||||
|
||||
keyslot_reencrypt = LUKS2_find_keyslot(hdr, "reencrypt");
|
||||
if (keyslot_reencrypt < 0)
|
||||
return 0;
|
||||
|
||||
if (!(jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot_reencrypt)))
|
||||
return 0;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
|
||||
return 0;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_area, "type", &jobj_type))
|
||||
return 0;
|
||||
|
||||
if (!(area_type = json_object_get_string(jobj_type)))
|
||||
return 0;
|
||||
|
||||
struct jtype j[] = {
|
||||
{ JSTR, jobj_keyslot, "mode" },
|
||||
{ JSTR, jobj_keyslot, "direction" },
|
||||
{ JSTR, jobj_area, "type" },
|
||||
{ JU64, jobj_area, "offset" },
|
||||
{ JU64, jobj_area, "size" },
|
||||
{}
|
||||
};
|
||||
struct jtype j_datashift[] = {
|
||||
{ JSTR, jobj_keyslot, "mode" },
|
||||
{ JSTR, jobj_keyslot, "direction" },
|
||||
{ JSTR, jobj_area, "type" },
|
||||
{ JU64, jobj_area, "offset" },
|
||||
{ JU64, jobj_area, "size" },
|
||||
{ JU64, jobj_area, "shift_size" },
|
||||
{}
|
||||
};
|
||||
struct jtype j_checksum[] = {
|
||||
{ JSTR, jobj_keyslot, "mode" },
|
||||
{ JSTR, jobj_keyslot, "direction" },
|
||||
{ JSTR, jobj_area, "type" },
|
||||
{ JU64, jobj_area, "offset" },
|
||||
{ JU64, jobj_area, "size" },
|
||||
{ JSTR, jobj_area, "hash" },
|
||||
{ JU32, jobj_area, "sector_size" },
|
||||
{}
|
||||
};
|
||||
|
||||
if (!strcmp(area_type, "datashift"))
|
||||
return srs(j_datashift, buffer);
|
||||
else if (!strcmp(area_type, "checksum"))
|
||||
return srs(j_checksum, buffer);
|
||||
|
||||
return srs(j, buffer);
|
||||
}
|
||||
|
||||
static size_t blob_serialize(void *blob, size_t length, uint8_t *buffer)
|
||||
{
|
||||
if (buffer)
|
||||
memcpy(buffer, blob, length);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
static int reencrypt_assembly_verification_data(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
struct volume_key *vks,
|
||||
struct volume_key **verification_data)
|
||||
{
|
||||
uint8_t *ptr;
|
||||
int digest_new, digest_old;
|
||||
struct volume_key *data = NULL, *vk_old = NULL, *vk_new = NULL;
|
||||
size_t keyslot_data_len, segments_data_len, data_len = 2;
|
||||
|
||||
/* Keys - calculate length */
|
||||
digest_new = LUKS2_reencrypt_digest_new(hdr);
|
||||
digest_old = LUKS2_reencrypt_digest_old(hdr);
|
||||
|
||||
if (digest_old >= 0) {
|
||||
vk_old = crypt_volume_key_by_id(vks, digest_old);
|
||||
if (!vk_old)
|
||||
return -EINVAL;
|
||||
data_len += blob_serialize(vk_old->key, vk_old->keylength, NULL);
|
||||
}
|
||||
|
||||
if (digest_new >= 0 && digest_old != digest_new) {
|
||||
vk_new = crypt_volume_key_by_id(vks, digest_new);
|
||||
if (!vk_new)
|
||||
return -EINVAL;
|
||||
data_len += blob_serialize(vk_new->key, vk_new->keylength, NULL);
|
||||
}
|
||||
|
||||
if (data_len == 2)
|
||||
return -EINVAL;
|
||||
|
||||
/* Metadata - calculate length */
|
||||
if (!(keyslot_data_len = reenc_keyslot_serialize(hdr, NULL)))
|
||||
return -EINVAL;
|
||||
data_len += keyslot_data_len;
|
||||
|
||||
if (!(segments_data_len = backup_segments_serialize(hdr, NULL)))
|
||||
return -EINVAL;
|
||||
data_len += segments_data_len;
|
||||
|
||||
/* Alloc and fill serialization data */
|
||||
data = crypt_alloc_volume_key(data_len, NULL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
ptr = (uint8_t*)data->key;
|
||||
|
||||
/* v2 */
|
||||
*ptr++ = 0x76;
|
||||
*ptr++ = 0x32;
|
||||
|
||||
if (vk_old)
|
||||
ptr += blob_serialize(vk_old->key, vk_old->keylength, ptr);
|
||||
|
||||
if (vk_new)
|
||||
ptr += blob_serialize(vk_new->key, vk_new->keylength, ptr);
|
||||
|
||||
if (!reenc_keyslot_serialize(hdr, ptr))
|
||||
goto bad;
|
||||
ptr += keyslot_data_len;
|
||||
|
||||
if (!backup_segments_serialize(hdr, ptr))
|
||||
goto bad;
|
||||
ptr += segments_data_len;
|
||||
|
||||
assert((size_t)(ptr - (uint8_t*)data->key) == data_len);
|
||||
|
||||
*verification_data = data;
|
||||
|
||||
return 0;
|
||||
bad:
|
||||
crypt_free_volume_key(data);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_reencrypt_digest_create(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
struct volume_key *vks)
|
||||
{
|
||||
int digest_reencrypt, keyslot_reencrypt, r;
|
||||
struct volume_key *data;
|
||||
|
||||
keyslot_reencrypt = LUKS2_find_keyslot(hdr, "reencrypt");
|
||||
if (keyslot_reencrypt < 0)
|
||||
return keyslot_reencrypt;
|
||||
|
||||
r = reencrypt_assembly_verification_data(cd, hdr, vks, &data);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = LUKS2_digest_create(cd, "pbkdf2", hdr, data);
|
||||
crypt_free_volume_key(data);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
digest_reencrypt = r;
|
||||
|
||||
r = LUKS2_digest_assign(cd, hdr, keyslot_reencrypt, CRYPT_ANY_DIGEST, 0, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return LUKS2_digest_assign(cd, hdr, keyslot_reencrypt, digest_reencrypt, 1, 0);
|
||||
}
|
||||
|
||||
int LUKS2_reencrypt_digest_verify(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
struct volume_key *vks)
|
||||
{
|
||||
int r, keyslot_reencrypt;
|
||||
struct volume_key *data;
|
||||
|
||||
keyslot_reencrypt = LUKS2_find_keyslot(hdr, "reencrypt");
|
||||
if (keyslot_reencrypt < 0)
|
||||
return keyslot_reencrypt;
|
||||
|
||||
r = reencrypt_assembly_verification_data(cd, hdr, vks, &data);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = LUKS2_digest_verify(cd, hdr, data, keyslot_reencrypt);
|
||||
crypt_free_volume_key(data);
|
||||
|
||||
if (r < 0) {
|
||||
if (r == -ENOENT)
|
||||
log_dbg(cd, "Reencryption digest is missing.");
|
||||
log_err(cd, _("Reencryption metadata is invalid."));
|
||||
} else
|
||||
log_dbg(cd, "Reencryption metadata verified.");
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -123,7 +123,7 @@ static json_object *json_segment_get_flags(json_object *jobj_segment)
|
||||
return jobj;
|
||||
}
|
||||
|
||||
static bool json_segment_contains_flag(json_object *jobj_segment, const char *flag_str, size_t len)
|
||||
bool json_segment_contains_flag(json_object *jobj_segment, const char *flag_str, size_t len)
|
||||
{
|
||||
int r, i;
|
||||
json_object *jobj, *jobj_flags = json_segment_get_flags(jobj_segment);
|
||||
@@ -410,3 +410,23 @@ json_object *LUKS2_get_segment_by_flag(struct luks2_hdr *hdr, const char *flag)
|
||||
|
||||
return jobj_segment;
|
||||
}
|
||||
|
||||
/* compares key characteristics of both segments */
|
||||
bool json_segment_cmp(json_object *jobj_segment_1, json_object *jobj_segment_2)
|
||||
{
|
||||
const char *type = json_segment_type(jobj_segment_1);
|
||||
const char *type2 = json_segment_type(jobj_segment_2);
|
||||
|
||||
if (!type || !type2)
|
||||
return false;
|
||||
|
||||
if (strcmp(type, type2))
|
||||
return false;
|
||||
|
||||
if (!strcmp(type, "crypt"))
|
||||
return (json_segment_get_sector_size(jobj_segment_1) == json_segment_get_sector_size(jobj_segment_2) &&
|
||||
!strcmp(json_segment_get_cipher(jobj_segment_1),
|
||||
json_segment_get_cipher(jobj_segment_2)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
137
lib/setup.c
137
lib/setup.c
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
108
src/cryptsetup.c
108
src/cryptsetup.c
@@ -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, ¶ms);
|
||||
@@ -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, ¶ms);
|
||||
@@ -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, ¶ms);
|
||||
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, ¶ms);
|
||||
|
||||
if (params.flags & CRYPT_REENCRYPT_REPAIR_NEEDED)
|
||||
return reencrypt_metadata_repair(cd);
|
||||
|
||||
crypt_reencrypt_info ri = crypt_reencrypt_status(cd, NULL);
|
||||
switch (ri) {
|
||||
case CRYPT_REENCRYPT_NONE:
|
||||
/* fall through */
|
||||
return 0;
|
||||
case CRYPT_REENCRYPT_CLEAN:
|
||||
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(¶ms.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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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."
|
||||
|
||||
|
||||
@@ -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, ¶ms));
|
||||
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, ¶ms), "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();
|
||||
|
||||
@@ -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, ¶ms));
|
||||
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, ¶ms));
|
||||
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, ¶ms));
|
||||
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, ¶ms));
|
||||
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, ¶ms), "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, ¶ms));
|
||||
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));
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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" },
|
||||
}}};
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
506
tests/luks2-reencryption-mangle-test
Executable file
506
tests/luks2-reencryption-mangle-test
Executable 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
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user