Compare commits

..

153 Commits

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

crypt_reencrypt_init_by_passphrase() with same flag applied
repairs (upgrade) reencryption metadata so that
automatic reencryption recovery during activation
is again possible and reencryption operation can be resumed
post CVE-2021-4122 fix.
2022-01-12 18:41:58 +01:00
Milan Broz
7ef0d9c73a Add reencryption mangle test 2022-01-12 18:41:55 +01:00
Ondrej Kozina
8ced413876 Make reencryption flag and keyslot inseparable.
LUKS2 validation code now requires reencrypt keyslot together with
online-reencryption flag or none of those.
2022-01-12 18:41:50 +01:00
Ondrej Kozina
80a77bce2a Rename LUKS2_keyslot_reencrypt_create function.
The function never writes on-disk. Also removed validation
function call-in since it will be called later before
writing on-disk and metadata does not have to be complete
at the moment of LUKS2_keyslot_reencrypt_allocate call.
2022-01-12 18:41:46 +01:00
Ondrej Kozina
334606b6aa Add segments validation for reencryption.
Effective segments during LUKS2 reencryption must
match key characteristics of backup segment
(cipher, sector_size, segment type).
2022-01-12 18:41:39 +01:00
Ondrej Kozina
1162f1e1e3 Split requirements validation from config section validation. 2022-01-12 14:49:11 +01:00
Ondrej Kozina
47a1d9a6d6 Expose json_segment_contains_flag to internal library. 2022-01-12 14:49:11 +01:00
Ondrej Kozina
c257ae1eb4 Move requirement helpers for later changes. 2022-01-12 14:49:11 +01:00
Milan Broz
d37c3f0db2 Add disable-luks2 reencryption configure option.
The option --disable-luks2-reencryption completely disable
LUKS2 reencryption code.

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

Devices with online reencryption in progress cannot be activated.

This option can cause some incompatibilities. Please use with care.
2022-01-12 14:49:11 +01:00
Milan Broz
4a974ec582 Print better error if resilience hash is not available. 2022-01-12 14:49:11 +01:00
Milan Broz
c95a88f815 Do not run reencryption recovery when not needed. 2022-01-12 14:49:11 +01:00
Milan Broz
4af4a4a631 Reenc keyslot must have key_size == 1. 2022-01-12 14:49:11 +01:00
Milan Broz
3d269a5ae3 Fix debug message. 2022-01-12 14:49:11 +01:00
Ondrej Kozina
de98f01141 Fix CVE-2021-4122 - LUKS2 reencryption crash recovery attack
Fix possible attacks against data confidentiality through LUKS2 online
reencryption extension crash recovery.

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

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

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

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

The fix introduces additional digest protection of reencryption
metadata. The digest is calculated from known keys and critical
reencryption metadata. Now an attacker cannot create correct metadata
digest without knowledge of a passphrase for used keyslots.
For more details, see LUKS2 On-Disk Format Specification version 1.1.0.
2022-01-12 14:49:11 +01:00
Vojtech Trefny
4d28153e53 bitlk: Fix support for startup key with new metadata entry
Windows 11 now includes the BitLocker volume GUID in the BEK file
metadata entries. This was previously not included so cryptsetup
refused to open the file because there was an unknown metadata
entry in the startup key.

Fixes: #690
2022-01-10 21:29:50 +01:00
Ondrej Kozina
dd864f5a61 Remove LUKS2 encryption data size restriction.
LUKS2 encryption with data shift required remaining
data size (size remaining after substracting --reduce-data-size value)
to be at least --reduce-data-size. This was wrong. Remaining
data size restriction should be correctly at least single sector
(whatever sector size is selected or auto-detected).
2022-01-10 21:29:32 +01:00
Josef Andersson
ca54398eec po: update sv.po (from translationproject.org) 2022-01-10 21:26:04 +01:00
Мирослав Николић
97cd16b8b9 po: update sr.po (from translationproject.org) 2022-01-10 21:25:55 +01:00
Antonio Ceballos
86d0d4f68e po: update es.po (from translationproject.org) 2022-01-10 21:25:44 +01:00
Tianjia Zhang
1a7d98b3ba Fix manual typo. 2022-01-10 21:25:30 +01:00
Sean
025a96df73 Update README.md 2022-01-10 21:25:17 +01:00
Milan Broz
e6edbc1fe5 Run CI on stable branches.
The stable branch is named "v2.<minor>.x".
2021-12-01 22:50:37 +01:00
Milan Broz
ed68b51526 Do not mix tabs and spaces in GitHub CI script. 2021-12-01 22:50:37 +01:00
Milan Broz
bcace16aa2 Do not mix tabs and spaces in Gitlab CI script. 2021-12-01 22:50:37 +01:00
Milan Broz
97aa31d32f Fix tabs in GitLab CI scripts and remove gcc comment.
The -Wall changes according to gcc versions.
2021-12-01 22:50:37 +01:00
Milan Broz
36a78ed17b Fix missing backslash in CI. 2021-12-01 22:50:37 +01:00
Milan Broz
0d4ecd92f1 Add limitation to cryptsetup group again in CI. 2021-12-01 22:50:37 +01:00
daniel.zatovic
94143c3428 Remove LLVM repo script 2021-12-01 22:50:37 +01:00
Daniel Zaťovič
af17d2256d Add compilation tests and static analysis on the Gitlab shared runner. 2021-12-01 22:50:37 +01:00
Milan Broz
ff51d5a8fa Version 2.4.2. 2021-11-18 11:35:45 +01:00
Jakub Bogusz
949ed8c9e2 po: update pl.po (from translationproject.org) 2021-11-18 10:57:02 +01:00
Milan Broz
31698f8388 LUKS convert: also check sysfs for device activity.
On some "broken" systems, udev directory (where we try to check
if device is active) is present, but the symlink is missing.

Let's fallback in this case on sysfs scanning also, otherwise
possible conversion of an active device can cause data corruption.
2021-11-18 08:15:09 +00:00
Milan Broz
c400a84987 Add 2.4.2 release notes. 2021-11-17 13:11:26 +01:00
Yuri Chornoivan
ce52bb2f5a po: update uk.po (from translationproject.org) 2021-11-16 16:53:12 +01:00
Yuri Kozlov
bf374ca9e6 po: update ru.po (from translationproject.org) 2021-11-16 16:53:12 +01:00
Hiroshi Takekawa
17ca463767 po: update ja.po (from translationproject.org) 2021-11-16 16:53:12 +01:00
Frédéric Marchal
aa8d8ec0ae po: update fr.po (from translationproject.org) 2021-11-16 16:53:12 +01:00
Roland Illig
1b08d47045 po: update de.po (from translationproject.org) 2021-11-16 16:53:12 +01:00
Petr Pisar
0f656105e2 po: update cs.po (from translationproject.org) 2021-11-16 16:53:12 +01:00
Milan Broz
0b3a7ecd01 Update cryptsetup.pot. 2021-11-16 16:52:22 +01:00
Milan Broz
a364355c16 Fix missing translation macros. 2021-11-10 15:29:29 +00:00
Milan Broz
7086c414bc Avoid casting of uint64_t to unsigned int in debug messages. 2021-11-10 13:39:54 +00:00
Milan Broz
0bb193d487 Fix code style.
We do not use curly brackets in this context.
2021-11-10 13:39:54 +00:00
Milan Broz
80b57c6e24 Free json buffer on error path.
Code should not return allocated buffer if validation fails.

(But this does not fix a leak, memory is freed later, it is just more readable.)
2021-11-10 13:39:54 +00:00
Milan Broz
9576549fee Fix bogus memory allocation if LUKS2 header size is invalid.
LUKS2 code read the whole header to buffer to verify checksum,
so malloc is called on unvalidated input size parameter.

This can cause out of memory or unintentional device reads.
(Header validation will fail later anyway - the size is unsupported.)

Just do not allow too small and too big allocations here and fail quickly.

Fixes: #683.
2021-11-10 13:39:54 +00:00
Milan Broz
0cc5f2fdf9 Fix debug message printing LUKS2 checksum.
The trailing NUL is written already by snprintf, moreover,
it is written on wrong place here.

Just rely on snprintf here.

Fixes: #685.
2021-11-10 12:56:20 +01:00
Abhijit Menon-Sen
26a3f3b058 Fix typo ("Veryfing") 2021-11-02 08:08:28 +01:00
Milan Broz
e03f3bb36e Set devel version. 2021-11-01 17:11:33 +01:00
Daniel Zaťovič
be5ab79c9d Switch GitLab CI tags for the libvirt custom runner. 2021-10-26 19:28:42 +02:00
Milan Broz
083cdb9310 Add a debug message before running keyslot PBKDF.
This is useful for debugging if the process is killed by OOM.
2021-10-15 19:17:45 +02:00
leongross
ca30d3cda9 fix minor README.md issues 2021-10-12 14:55:16 +00:00
Мирослав Николић
5c17722854 po: update sr.po (from translationproject.org) 2021-10-12 16:54:00 +02:00
Milan Broz
49177aac46 Add test vector for empty password for Argon2.
While it is insecure, we need crypto backend to support this :)
2021-10-06 21:54:49 +02:00
Milan Broz
d20beacba0 Remove redundant link to uuid lib for static build.
Veritysetup does not need to link this library at all, for others
we have link already in flags.
2021-10-06 13:02:51 +02:00
Milan Broz
26cc1644b4 Do not link integritysetup and veritysetup with pwquality.
These tools do not read passphrases, no need to link to these libraries.

Just move the helper code that introduced this dependence as a side-effect.

Fixes: #677
2021-10-06 13:02:19 +02:00
Milan Broz
9ed0036286 CI: comment out fixed project rule for merge request jobs.
We need pipeline to be created here, seems GitLab does not
allow it otherwise.
2021-09-29 15:20:54 +02:00
Milan Broz
00f7d92514 OpenSSL backend: no need to use strlen for KDF param length. 2021-09-29 10:24:45 +00:00
Milan Broz
43674b2903 OpenSSL3 backend: avoid remaining deprecated calls in API.
Implement HMAC through new API.

In reality, these calls are never used (the only user is internal PBKDF2
that is never called with OpenSSL backend).
2021-09-29 10:24:45 +00:00
Milan Broz
5cfd5fc4cd Crypt vectors test: add test for hash/hmac context reset.
The crypto API expects that after final() call the context is reset,
let's test if backend properly supports it.
2021-09-29 10:24:45 +00:00
Milan Broz
9f252d4bf8 Install openssl binary for CI test. 2021-09-27 22:31:34 +02:00
Ondrej Kozina
321057eed5 Add Fedora rawhide runner to CI. 2021-09-27 17:25:13 +02:00
Ondrej Kozina
1a3d049454 Add tags for currently available runners. 2021-09-27 17:09:21 +02:00
Milan Broz
9d1f29a9fd OpenSSL backend: separate KDF wrappers.
Prepare code for later to add Argon2 OpenSSL wrapper more easily.
2021-09-22 08:25:19 +00:00
Milan Broz
da31341d5d OpenSSL3 backend: use predefined macros to construct KDF params. 2021-09-22 08:25:19 +00:00
Milan Broz
10b1d6493e Check if DM create device failed in an early phase.
This happens when concurrent creation of DM devices meets
in the very early state (no device node exists but creation fails).

Return -ENODEV here instead of -EINVAL.

(Should "fix" random verity concurrent test failure.)
2021-09-21 17:58:34 +02:00
Milan Broz
a76310b53f Do not try to set compiler optimization flag if wipe is implemented in libc.
If zeroing memory is implemented through libc call (like memset_bzero),
compiler should never remove such call. It is not needed to set O0
optimization flag explicitly.

Various checkers like annocheck causes problems with these flags,
just remove it where it makes no sense.

(Moreover, we use the same pattern without compiler magic
in crypt_backend_memzero() already.)
2021-09-20 17:42:20 +02:00
Yuri Kozlov
26d26d7134 po: update ru.po (from translationproject.org) 2021-09-17 18:52:18 +02:00
Hector Martin
a1b577c085 Do not attempt to unload external tokens if USE_EXTERNAL_TOKENS is disabled.
This allows building a static binary as long as --disable-external-tokens is used
2021-09-17 05:44:18 +00:00
Milan Broz
8a0682650e Version 2.4.1. 2021-09-15 11:29:09 +02:00
Milan Broz
85e5ccec17 Update cryptsetup.pot. 2021-09-15 11:26:57 +02:00
Milan Broz
3da5352b89 Fix compatible OpenSSL backend constructor definition. 2021-09-15 08:13:49 +02:00
Ondrej Kozina
1569558503 Fix offset bug in LUKS2 encryption code.
The code did not account for data offset when
set via --offset when creating new header in-before
LUKS2 encryption took place.
2021-09-14 16:10:24 +02:00
Ondrej Kozina
ce704859b8 Fix offset error in decryption hotzone.
The hotzone segment offset has to be altered
accordingly no matter the segment type.

Note for testing: This feature is currently
blocked in cli but it should be tested via
API tests anyway.
2021-09-14 15:21:07 +02:00
Milan Broz
fd18e0b1c9 Fix integrity test & non-fips algorithms.
Apparently algorithms can be in /proc/crypto despite they are not available.
Just limit failure of the test to sha and crc algorithms.
2021-09-14 14:51:50 +02:00
Milan Broz
ba4d5680d6 Fix typo and EOL in vector test. 2021-09-14 10:33:38 +02:00
Milan Broz
75e45462f0 Cache FIPS mode check.
We do not support switch while the crypto backend is already initialized,
so it does not make sense to check repeatedly for the FIPS mode status.
2021-09-14 09:56:05 +02:00
Milan Broz
f8eb7b225a Do not load own OpenSSL backend context in FIPS mode.
In the FIPS mode keep configuration up to the system wide config.
2021-09-13 21:56:59 +02:00
Milan Broz
29ea07ef66 OpenSSL backend: make legacy for OpenSSL3 optional and report loaded providers 2021-09-13 21:56:54 +02:00
Ondrej Kozina
6c9d386303 Adapt crypto backend to openssl3 lib context.
Fully leverage openssl custom library context for various
providers (default, legacy). It can be used to properly
free all openssl resources used by libcryptsetup when
libcryptsetup is unloaded (and destructor is triggered).
2021-09-13 16:54:40 +02:00
Arno Wagner
bf84ead85c sync to Wiki 2021-09-13 11:03:15 +02:00
Yuri Chornoivan
ca2ba1a6f5 po: update uk.po (from translationproject.org) 2021-09-07 12:41:48 +02:00
Jakub Bogusz
284d1615c8 po: update pl.po (from translationproject.org) 2021-09-07 12:41:48 +02:00
Hiroshi Takekawa
b4181ffa3b po: update ja.po (from translationproject.org) 2021-09-07 12:41:48 +02:00
Frédéric Marchal
8c0caf9a1f po: update fr.po (from translationproject.org) 2021-09-07 12:41:48 +02:00
Roland Illig
d2682c4841 po: update de.po (from translationproject.org) 2021-09-07 12:41:48 +02:00
Petr Pisar
39ddcfaaa0 po: update cs.po (from translationproject.org) 2021-09-07 12:41:48 +02:00
Milan Broz
669ad1933a Fix possible use of unallocated parameter.
(Introduced in previous patches.)
2021-08-30 12:39:17 +02:00
Milan Broz
84fa6ffbde Remove some Doxygen docs warnings. 2021-08-30 12:32:42 +02:00
Milan Broz
2206f7f108 Prepare version for translation. 2021-08-30 11:57:11 +02:00
JT Moree
ec946b17eb add headers
add headers for Help: documentation and mailing list
2021-08-27 14:39:03 +00:00
JT Moree
a619cc1757 rename reference to specifications 2021-08-27 14:39:03 +00:00
JT Moree
6c3e2e2bee rework Help section 2021-08-27 14:39:03 +00:00
Ondrej Kozina
621dcea8ee Do not init LUKS2 decryption for devices with data offset.
Currently LUKS2 decryption cannot perform data decryption
with data shift. Even though we can decrypt devices with
data offset > 0 in LUKS2 metadata it does not make much
sense. Such devices cannot be easily mounted after decryption
is finished due to said data offset (fs superblock is moved
typicaly by 16MiBs).
2021-08-27 16:26:37 +02:00
Milan Broz
f6fb530121 Repair also lowercase hash in LUKS1 header.
This patch removes magic for backup load that quietly
run lowecase conversion and add this possibility to repair command.

Most of crypto backends allow uppercase though.
2021-08-25 16:45:00 +00:00
Milan Broz
0066f9dd83 Fix LUKS1 repair to repair wrong ECB mode.
1) Crypsetup repair should try to call crypt_repair() even
if crypt_load is ok - it has no validate system unlike LUKS2
and some errors cannot be hard load errors.

2) Move ECB fix to repair code, do not try magic on load that
no longer works.

And do not use ECB :)

Fixes: #664
2021-08-25 16:45:00 +00:00
Ondrej Kozina
46b70d7317 Add error message when assigning token to inactive keyslot.
While adding or importing new token and assigning immediately to
keyslot it would be useful to provide specific error message
directly from cryptsetup utility when keyslot does not exist.
2021-08-25 16:11:00 +00:00
Milan Broz
8c28774917 Fix vector test print message additional parameter. 2021-08-25 18:09:56 +02:00
Milan Broz
e5d84156e4 Fix linker to use -ldl if external tokens are used.
Also run check for symbols only if external modules are really used.
2021-08-25 13:50:33 +02:00
Milan Broz
5f2c751dd8 Use dlsym() for token load if dlvsym() is not available.
To be discussed. Anyway, we need to support distros with musl...
2021-08-25 13:39:07 +02:00
Ondrej Kozina
53b22cc32e Fix deferred remove test failure on non-udev systems.
Deferred remove non-udev enabled libdevmapper removes
device mapper symlinks immediately. We have to check
device size from sysfs attributes.
2021-08-25 13:39:03 +02:00
Milan Broz
26679e223c Trigger read event for verity test to mark device as corrupted.
If distro does not use udev/blkid, there is no IO event after activation.
Kernel does not mark the device corrupted then (it happens on the
first IO). Just add a simple read to trigger it.
2021-08-25 13:38:58 +02:00
Milan Broz
9b7d3be5c6 Skip UUID= cryptsetup activation test if /dev has no uuid links.
There are still distros that tries to reinvent the wheel, let just
ignore if /dev is not propagated by symlinks that we depend on.
2021-08-25 13:38:54 +02:00
Milan Broz
358dec19b2 Use compatible flags for BusyBox diff command. 2021-08-25 13:38:50 +02:00
Milan Broz
863fd08305 Skip test if incompatible tar from BusyBox is installed.
We depend on sparse images that BusyBox tar cannot handle.
Just install the full tar package for tests.
2021-08-25 13:38:46 +02:00
Milan Broz
93481d1566 Use compatible flags for BusyBox free command. 2021-08-25 13:38:41 +02:00
Milan Broz
3a79b2b09b Fix gettext (-lintl) linker flags.
The external gettext library should be used on main libcryptsetup,
not later for programs (these do not call any translations).

(Also it was in the wrong order there failing compilation.)
2021-08-25 13:38:23 +02:00
Milan Broz
246d306eeb Check for argp library that can be standalone.
Some systems without glibc provides standalone package for argp.
2021-08-25 13:37:33 +02:00
Milan Broz
03943acbb1 Remove obsolete AC_HEADER_STDC macro.
This should be no longer used.
We do not support systems without standard headers anyway.
2021-08-25 13:37:29 +02:00
Milan Broz
20b678c9f3 Fix symbol version test if dlvsym() is not available.
If we have no dlvsym(), just run dlsym() test.
2021-08-25 13:37:25 +02:00
Milan Broz
e008a88b98 Test Coverity action. 2021-08-19 14:29:53 +02:00
Milan Broz
5efa782567 Ignore default algorithm test in FIPS mode.
This can cause unexpected failures (despite it is kind of misconfiguration).
2021-08-19 13:36:13 +02:00
Milan Broz
ab37ad0dc9 Update doxyfile. 2021-08-19 10:31:21 +02:00
Milan Broz
03208167b2 Fix release notes. 2021-08-18 17:19:50 +02:00
Milan Broz
0f8e7f317f Version 2.4.0. 2021-08-18 16:50:50 +02:00
Milan Broz
c5b0a4dd32 Remove Travis CI config. So long, and thanks for all the builds. 2021-08-18 16:01:36 +02:00
Ondrej Kozina
5c5551d1d3 Update release notes. 2021-08-18 15:11:18 +02:00
Vojtech Trefny
aa324567a8 ssh-plugin-test: Fix running the test in GitHub actions 2021-08-18 14:18:55 +02:00
Milan Broz
0ee752c42d Update 2.4.0 release notes. 2021-08-18 14:09:32 +02:00
Milan Broz
4746717b75 Update Fedora spec.
Rebuild configure suite locally, so we do not need to patch generated
scripts because of RPATH issues.
2021-08-18 14:02:28 +02:00
Milan Broz
3ad942e338 Add autogen.sh to distributions.
Allow dowsntream packagers to rebuild the whole buildsystem.
2021-08-18 14:01:09 +02:00
Milan Broz
b5190da581 Update cryptsetup.pot. 2021-08-18 14:00:29 +02:00
Ondrej Kozina
5fa8e84ef0 Also install directory for external plugins.
And remove custom target from reference .spec file.
2021-08-18 12:08:14 +02:00
Milan Broz
63adb3b0cf Fix LDFLAGS for all-symbols-test.
Option -ldl is for LDFLAGS, not for CFLAGS (fixes clang warning).
2021-08-17 21:45:49 +02:00
Milan Broz
20774374a9 Fail if default compiled hash is not implemented.
If crypto backend does not provide configured hash,
fail crypto backend tests.

(User has to use configure option if backend does not provide seclected algorithm.)

Seen recently with RIPEMD160.
Note: NSS does not provide RIPEMD, use --with-plain-hash etc.
2021-08-17 19:16:35 +00:00
Milan Broz
d169020001 Limit GitLab CI only to parent cryptsetup project. 2021-08-17 18:22:21 +02:00
Yuri Chornoivan
76766f11c0 po: update uk.po (from translationproject.org) 2021-08-17 13:48:13 +02:00
Мирослав Николић
5d6d65ce86 po: update sr.po (from translationproject.org) 2021-08-17 13:48:13 +02:00
Yuri Kozlov
24ab0871e7 po: update ru.po (from translationproject.org) 2021-08-17 13:48:13 +02:00
Jakub Bogusz
11e325a112 po: update pl.po (from translationproject.org) 2021-08-17 13:48:13 +02:00
Hiroshi Takekawa
6ea32db1fa po: update ja.po (from translationproject.org) 2021-08-17 13:48:13 +02:00
Frédéric Marchal
49c8a8b9ef po: update fr.po (from translationproject.org) 2021-08-17 13:48:13 +02:00
Roland Illig
a480c388b8 po: update de.po (from translationproject.org) 2021-08-17 13:48:13 +02:00
Petr Pisar
5406064f55 po: update cs.po (from translationproject.org) 2021-08-17 13:48:13 +02:00
Milan Broz
9b66d0d039 Add experimental GitLab CI config. 2021-08-15 21:52:37 +02:00
Milan Broz
adff844c46 Remove test image in SSH test if ssh config fails. 2021-08-15 21:50:56 +02:00
Milan Broz
f702246d78 Remove test images dir once test is finished.
THsi allows another user to run test later without permission collision..
2021-08-15 21:46:28 +02:00
Milan Broz
8606342b53 Limit GitHub Actions job to this repository. 2021-08-15 11:29:37 +02:00
Milan Broz
ccb0f7c0b2 Fix typo in CI configure. 2021-08-15 11:24:13 +02:00
Milan Broz
72384b43bd Add simple GitHub Action CI.
This runs only on push in selected branches.

(Not for push requests, we do not use PR on GitHub.)
2021-08-14 22:36:30 +02:00
Milan Broz
5ef3de8945 Add separate check-programs target. 2021-08-14 22:34:27 +02:00
Milan Broz
ad913cf437 Require only libtoolize in autogen.sh. 2021-08-12 21:30:02 +02:00
Milan Broz
7820f07e85 Fix libtool detection in autogen.sh.
The macro disappeared in 2.67 autoconf update (2010).

Fixes: #663.
2021-08-12 19:13:52 +02:00
JT Moree
01bda280ee man page
add note about searching the man page
2021-08-12 16:48:36 +00:00
JT Moree
b40f31fb8c FAQ
add memory FAQ
add non root FAQs
2021-08-11 05:18:05 -07:00
Milan Broz
066d651210 Fix a possible memory leak of verity signature description.
The signature description should be allocated only if params field is used,
otherwise we can leak the string value.

(Moreover, the query path is currently used only for flag, not for the value.)
2021-08-04 13:06:14 +02:00
Yuri Chornoivan
b00946d449 Fix minor typo: assing -> assign 2021-07-30 16:19:36 +00:00
Guilhem Moulin
6a14f52e5d Fix minor spelling errors.
(Found by Lintian.)
2021-07-30 02:56:38 +02:00
97 changed files with 12485 additions and 6788 deletions

28
.github/workflows/cibuild-setup-ubuntu.sh vendored Executable file
View File

@@ -0,0 +1,28 @@
#!/bin/bash
set -ex
PACKAGES=(
git make autoconf automake autopoint pkg-config libtool libtool-bin
gettext libssl-dev libdevmapper-dev libpopt-dev uuid-dev libsepol1-dev
libjson-c-dev libssh-dev libblkid-dev tar libargon2-0-dev libpwquality-dev
sharutils dmsetup jq xxd expect keyutils netcat passwd openssh-client sshpass
)
COMPILER="${COMPILER:?}"
COMPILER_VERSION="${COMPILER_VERSION:?}"
RELEASE="$(lsb_release -cs)"
bash -c "echo 'deb-src http://archive.ubuntu.com/ubuntu/ $RELEASE main restricted universe multiverse' >>/etc/apt/sources.list"
# Latest gcc stack deb packages provided by
# https://launchpad.net/~ubuntu-toolchain-r/+archive/ubuntu/test
add-apt-repository -y ppa:ubuntu-toolchain-r/test
PACKAGES+=(gcc-$COMPILER_VERSION)
# scsi_debug, gost crypto
PACKAGES+=(dkms linux-headers-$(uname -r) linux-modules-extra-$(uname -r) gost-crypto-dkms)
apt-get -y update --fix-missing
apt-get -y install "${PACKAGES[@]}"
apt-get -y build-dep cryptsetup

38
.github/workflows/cibuild.sh vendored Executable file
View File

@@ -0,0 +1,38 @@
#!/bin/bash
PHASES=(${@:-CONFIGURE MAKE CHECK})
COMPILER="${COMPILER:?}"
COMPILER_VERSION="${COMPILER_VERSION}"
CFLAGS=(-O1 -g)
CXXFLAGS=(-O1 -g)
CC="gcc${COMPILER_VERSION:+-$COMPILER_VERSION}"
CXX="g++${COMPILER_VERSION:+-$COMPILER_VERSION}"
set -ex
for phase in "${PHASES[@]}"; do
case $phase in
CONFIGURE)
opts=(
--enable-libargon2
)
sudo -E git clean -xdf
./autogen.sh
CC="$CC" CXX="$CXX" CFLAGS="${CFLAGS[@]}" CXXFLAGS="${CXXFLAGS[@]}" ./configure "${opts[@]}"
;;
MAKE)
make -j
make -j -C tests check-programs
;;
CHECK)
make check
;;
*)
echo >&2 "Unknown phase '$phase'"
exit 1
esac
done

29
.github/workflows/cibuild.yml vendored Normal file
View File

@@ -0,0 +1,29 @@
name: Build test
on:
push:
branches:
- 'master'
- 'wip-luks2'
- 'v2.3.x'
paths-ignore:
- 'docs/**'
jobs:
build:
runs-on: ubuntu-latest
if: github.repository == 'mbroz/cryptsetup'
strategy:
fail-fast: false
matrix:
env:
- { COMPILER: "gcc", COMPILER_VERSION: "11", RUN_SSH_PLUGIN_TEST: "1" }
env: ${{ matrix.env }}
steps:
- name: Repository checkout
uses: actions/checkout@v1
- name: Ubuntu setup
run: sudo -E .github/workflows/cibuild-setup-ubuntu.sh
- name: Configure & Make
run: .github/workflows/cibuild.sh CONFIGURE MAKE
- name: Check
run: sudo -E .github/workflows/cibuild.sh CHECK

48
.github/workflows/coverity.yml vendored Normal file
View File

@@ -0,0 +1,48 @@
name: Coverity test
on:
push:
branches:
- 'coverity_scan'
paths-ignore:
- 'docs/**'
jobs:
latest:
runs-on: ubuntu-latest
if: github.repository == 'mbroz/cryptsetup'
steps:
- name: Repository checkout
uses: actions/checkout@v1
- name: Ubuntu setup
run: sudo -E .github/workflows/cibuild-setup-ubuntu.sh
env:
COMPILER: "gcc"
COMPILER_VERSION: "11"
- name: Install Coverity
run: |
wget -q https://scan.coverity.com/download/cxx/linux64 --post-data "token=$TOKEN&project=mbroz/cryptsetup" -O cov-analysis-linux64.tar.gz
mkdir cov-analysis-linux64
tar xzf cov-analysis-linux64.tar.gz --strip 1 -C cov-analysis-linux64
env:
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
- name: Run autoconf & configure
run: |
./autogen.sh
./configure
- name: Run cov-build
run: |
export PATH=`pwd`/cov-analysis-linux64/bin:$PATH
cov-build --dir cov-int make
- name: Submit to Coverity Scan
run: |
tar czvf cryptsetup.tgz cov-int
curl \
--form project=mbroz/cryptsetup \
--form token=$TOKEN \
--form email=gmazyland@gmail.com \
--form file=@cryptsetup.tgz \
--form version=trunk \
--form description="`./cryptsetup --version`" \
https://scan.coverity.com/builds?project=mbroz/cryptsetup
env:
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}

113
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,113 @@
stages:
- test
.debian-prep:
before_script:
- sudo apt-get -y update --fix-missing
- >
sudo apt-get -y install -y -qq git gcc make
autoconf automake autopoint pkg-config libtool libtool-bin gettext
libssl-dev libdevmapper-dev libpopt-dev uuid-dev libsepol1-dev
libjson-c-dev libssh-dev libblkid-dev tar libargon2-0-dev
libpwquality-dev sharutils dmsetup jq xxd expect keyutils
netcat passwd openssh-client sshpass
- sudo apt-get -y build-dep cryptsetup
- sudo -E git clean -xdf
- ./autogen.sh
- ./configure --enable-libargon2
.dnf-openssl-backend:
before_script:
- >
sudo dnf -y -q install
autoconf automake device-mapper-devel gcc gettext-devel json-c-devel
libargon2-devel libblkid-devel libpwquality-devel libselinux-devel
libssh-devel libtool libuuid-devel make popt-devel
libsepol-devel.x86_64 netcat openssh-clients passwd pkgconfig sharutils
sshpass tar uuid-devel vim-common device-mapper expect gettext git jq
keyutils openssl-devel openssl
- sudo -E git clean -xdf
- ./autogen.sh
- ./configure --enable-fips --enable-pwquality --enable-libargon2 --with-crypto_backend=openssl
# Merge request: Build and run only non-root tests
test-mergerq-job-debian-noroot:
extends:
- .debian-prep
tags:
- libvirt
- debian10
stage: test
interruptible: true
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
script:
- make -j
- make -j -C tests check-programs
- make check
# For main branch commit, run all tests as root
test-main-commit-job-debian:
extends:
- .debian-prep
tags:
- libvirt
- debian10
stage: test
interruptible: true
variables:
RUN_SSH_PLUGIN_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
script:
- make -j
- make -j -C tests check-programs
- sudo -E make check
- sudo -E make clean
test-main-commit-job-dnf:
extends:
- .dnf-openssl-backend
tags:
- libvirt
- fedora-rawhide
stage: test
interruptible: true
variables:
RUN_SSH_PLUGIN_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
script:
- make -j
- make -j -C tests check-programs
- sudo -E make check
test-mergerq-job-dnf:
extends:
- .dnf-openssl-backend
tags:
- libvirt
- fedora-rawhide
stage: test
interruptible: true
variables:
RUN_SSH_PLUGIN_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
script:
- make -j
- make -j -C tests check-programs
- sudo -E make check
include:
- local: .gitlab/ci/gitlab-shared-docker.yml
- local: .gitlab/ci/compilation-gcc.gitlab-ci.yml
- local: .gitlab/ci/compilation-clang.gitlab-ci.yml

View File

@@ -0,0 +1,49 @@
#!/bin/bash
set -ex
PACKAGES=(
git make autoconf automake autopoint pkg-config libtool libtool-bin
gettext libssl-dev libdevmapper-dev libpopt-dev uuid-dev libsepol1-dev
libjson-c-dev libssh-dev libblkid-dev tar libargon2-0-dev libpwquality-dev
sharutils dmsetup jq xxd expect keyutils netcat passwd openssh-client sshpass
)
COMPILER="${COMPILER:?}"
COMPILER_VERSION="${COMPILER_VERSION:?}"
grep -E '^deb' /etc/apt/sources.list > /etc/apt/sources.list~
sed -Ei 's/^deb /deb-src /' /etc/apt/sources.list~
cat /etc/apt/sources.list~ >> /etc/apt/sources.list
apt-get -y update --fix-missing
DEBIAN_FRONTEND=noninteractive apt-get -yq install software-properties-common wget lsb-release
RELEASE="$(lsb_release -cs)"
if [[ $COMPILER == "gcc" ]]; then
# Latest gcc stack deb packages provided by
# https://launchpad.net/~ubuntu-toolchain-r/+archive/ubuntu/test
add-apt-repository -y ppa:ubuntu-toolchain-r/test
PACKAGES+=(gcc-$COMPILER_VERSION)
elif [[ $COMPILER == "clang" ]]; then
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
add-apt-repository "deb http://apt.llvm.org/${RELEASE}/ llvm-toolchain-${RELEASE}-${COMPILER_VERSION} main"
# scan-build
PACKAGES+=(clang-tools-$COMPILER_VERSION clang-$COMPILER_VERSION lldb-$COMPILER_VERSION lld-$COMPILER_VERSION clangd-$COMPILER_VERSION)
PACKAGES+=(perl)
else
exit 1
fi
apt-get -y update --fix-missing
DEBIAN_FRONTEND=noninteractive apt-get -yq install "${PACKAGES[@]}"
apt-get -y build-dep cryptsetup
echo "====================== VERSIONS ==================="
if [[ $COMPILER == "clang" ]]; then
scan-build${COMPILER_VERSION:+-$COMPILER_VERSION} --help
fi
${COMPILER}-$COMPILER_VERSION -v
echo "====================== END VERSIONS ==================="

55
.gitlab/ci/clang-Wall Executable file
View File

@@ -0,0 +1,55 @@
#!/bin/bash
# clang -Wall plus other important warnings not included in -Wall
for arg in "$@"
do
case $arg in
-O*) Wuninitialized=-Wuninitialized;; # only makes sense with `-O'
esac
done
CLANG="clang${COMPILER_VERSION:+-$COMPILER_VERSION}"
#PEDANTIC="-std=gnu99"
#PEDANTIC="-pedantic -std=gnu99"
#PEDANTIC="-pedantic -std=gnu99 -Wno-variadic-macros"
#CONVERSION="-Wconversion"
EXTRA="-Wextra \
-Wsign-compare \
-Werror-implicit-function-declaration \
-Wpointer-arith \
-Wwrite-strings \
-Wswitch \
-Wmissing-format-attribute \
-Winit-self \
-Wdeclaration-after-statement \
-Wold-style-definition \
-Wno-missing-field-initializers \
-Wno-unused-parameter \
-Wno-attributes \
-Wno-long-long"
exec $CLANG $PEDANTIC $CONVERSION \
-Wall $Wuninitialized \
-Wno-switch \
-Wdisabled-optimization \
-Wwrite-strings \
-Wpointer-arith \
-Wbad-function-cast \
-Wmissing-prototypes \
-Wmissing-declarations \
-Wstrict-prototypes \
-Wnested-externs \
-Wcomment \
-Winline \
-Wcast-align \
-Wcast-qual \
-Wredundant-decls $EXTRA \
"$@" 2>&1 | {
if [[ $USE_FILTER -eq 1 ]]; then
.gitlab/ci/warnings_filter.py
else
cat
fi
}

View File

@@ -0,0 +1,25 @@
test-clang-compilation:
extends:
- .gitlab-shared-clang
script:
- export CFLAGS="-Wall -Werror"
- ./configure --enable-pwquality --enable-libargon2
- make -j
# Clang doesn't support json output, so we cannot use the warnings filter
# test-clang-Wall-script:
# extends:
# - .gitlab-shared-clang
# script:
# - export CFLAGS="-g -O0"
# - export CC=".gitlab/ci/clang-Wall"
# - ./configure --enable-pwquality --enable-libargon2
# - make -j CFLAGS="-g -O0 -Werror"
test-scan-build:
extends:
- .gitlab-shared-clang
script:
- scan-build${COMPILER_VERSION:+-$COMPILER_VERSION} -V ./configure CFLAGS="-g -O0" --enable-internal-sse-argon2 --enable-pwquality --enable-libargon2
- make clean
- scan-build${COMPILER_VERSION:+-$COMPILER_VERSION} -maxloop 10 make -j

View File

@@ -0,0 +1,24 @@
test-gcc-compilation:
extends:
- .gitlab-shared-gcc
script:
- export CFLAGS="-Wall -Werror"
- ./configure --enable-pwquality --enable-libargon2
- make -j
test-gcc-Wall-script:
extends:
- .gitlab-shared-gcc
script:
- export CFLAGS="-g -O0"
- export CC=".gitlab/ci/gcc-Wall"
- USE_FILTER=0 ./configure --enable-pwquality --enable-libargon2
- USE_FILTER=1 make -j CFLAGS="-g -O0 -fdiagnostics-format=json"
test-gcc-fanalyzer:
extends:
- .gitlab-shared-gcc
script:
- export CFLAGS="-Wall -Werror -g -O0 -fanalyzer -fdiagnostics-path-format=separate-events"
- ./configure --enable-pwquality --enable-libargon2
- make -j

61
.gitlab/ci/gcc-Wall Executable file
View File

@@ -0,0 +1,61 @@
#!/bin/bash
# gcc -Wall plus other important warnings not included in -Wall
for arg in "$@"
do
case $arg in
-O*) Wuninitialized=-Wuninitialized;; # only makes sense with `-O'
esac
done
GCC="gcc${COMPILER_VERSION:+-$COMPILER_VERSION}"
#PEDANTIC="-std=gnu99"
#PEDANTIC="-pedantic -std=gnu99"
#PEDANTIC="-pedantic -std=gnu99 -Wno-variadic-macros"
#CONVERSION="-Wconversion"
# -Wpacked \
EXTRA="-Wextra \
-Wsign-compare \
-Werror-implicit-function-declaration \
-Wpointer-arith \
-Wwrite-strings \
-Wswitch \
-Wmissing-format-attribute \
-Wstrict-aliasing=3 \
-Winit-self \
-Wunsafe-loop-optimizations \
-Wdeclaration-after-statement \
-Wold-style-definition \
-Wno-missing-field-initializers \
-Wno-unused-parameter \
-Wno-attributes \
-Wno-long-long \
-Wmaybe-uninitialized \
-Wvla"
exec $GCC $PEDANTIC $CONVERSION \
-Wall $Wuninitialized \
-Wno-switch \
-Wdisabled-optimization \
-Wwrite-strings \
-Wpointer-arith \
-Wbad-function-cast \
-Wmissing-prototypes \
-Wmissing-declarations \
-Wstrict-prototypes \
-Wnested-externs \
-Wcomment \
-Winline \
-Wcast-align \
-Wcast-qual \
-Wredundant-decls $EXTRA \
"$@" 2>&1 | {
if [[ $USE_FILTER -eq 1 ]]; then
.gitlab/ci/warnings_filter.py
else
cat
fi
}

View File

@@ -0,0 +1,29 @@
.gitlab-shared-docker:
image: ubuntu:focal
tags:
- gitlab-org-docker
stage: test
interruptible: true
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
before_script:
- .gitlab/ci/cibuild-setup-ubuntu.sh
- export CC="${COMPILER}${COMPILER_VERSION:+-$COMPILER_VERSION}"
- export CXX="${COMPILER}++${COMPILER_VERSION:+-$COMPILER_VERSION}"
- ./autogen.sh
.gitlab-shared-gcc:
extends:
- .gitlab-shared-docker
variables:
COMPILER: "gcc"
COMPILER_VERSION: "11"
RUN_SSH_PLUGIN_TEST: "1"
.gitlab-shared-clang:
extends:
- .gitlab-shared-docker
variables:
COMPILER: "clang"
COMPILER_VERSION: "13"
RUN_SSH_PLUGIN_TEST: "1"

31
.gitlab/ci/warnings_filter.py Executable file
View File

@@ -0,0 +1,31 @@
#!/usr/bin/python3
import sys
import json
import linecache
if __name__ == "__main__":
json_string = sys.stdin.read()
if json_string in [None, ""]:
sys.exit(0)
parsed = json.loads(json_string)
#print(json.dumps(parsed, indent=4, sort_keys=True))
r = 0
for o in parsed:
kind = o["kind"]
start = o["locations"][0]["caret"]
l = linecache.getline(start["file"], int(start["line"]))
ignored = "json_object_object_foreach" in l
print(f"{o['kind']} {'ignored' if ignored else 'FOUND'} in {start['file']}:{start['line']}:{start['column']} {o['message']}")
print(f"line contains:\n\t{l}", end="")
if not ignored:
r = 1
sys.exit(r)

View File

@@ -1,174 +0,0 @@
#!/bin/bash
#
# .travis-functions.sh:
# - helper functions to be sourced from .travis.yml
# - designed to respect travis' environment but testing locally is possible
# - modified copy from util-linux project
#
if [ ! -f "configure.ac" ]; then
echo ".travis-functions.sh must be sourced from source dir" >&2
return 1 || exit 1
fi
## some config settings
# travis docs say we get 1.5 CPUs
MAKE="make -j2"
DUMP_CONFIG_LOG="short"
export TS_OPT_parsable="yes"
export RUN_SSH_PLUGIN_TEST=1
function configure_travis
{
./configure "$@"
err=$?
if [ "$DUMP_CONFIG_LOG" = "short" ]; then
grep -B1 -A10000 "^## Output variables" config.log | grep -v "_FALSE="
elif [ "$DUMP_CONFIG_LOG" = "full" ]; then
cat config.log
fi
return $err
}
function check_nonroot
{
local cfg_opts="$1"
[ -z "$cfg_opts" ] && return
configure_travis \
--enable-cryptsetup-reencrypt \
--enable-internal-sse-argon2 \
--enable-external-tokens \
--enable-ssh-token \
"$cfg_opts" \
|| return
$MAKE || return
make check
}
function check_root
{
local cfg_opts="$1"
[ -z "$cfg_opts" ] && return
configure_travis \
--enable-cryptsetup-reencrypt \
--enable-internal-sse-argon2 \
--enable-external-tokens \
--enable-ssh-token \
"$cfg_opts" \
|| return
$MAKE || return
# FIXME: we should use -E option here
sudo make check
}
function check_nonroot_compile_only
{
local cfg_opts="$1"
[ -z "$cfg_opts" ] && return
configure_travis \
--enable-cryptsetup-reencrypt \
--enable-internal-sse-argon2 \
"$cfg_opts" \
|| return
$MAKE
}
function travis_install_script
{
# install some packages from Ubuntu's default sources
sudo apt-get -qq update
sudo apt-get install -qq >/dev/null \
sharutils \
libgcrypt20-dev \
libssl-dev \
libdevmapper-dev \
libpopt-dev \
uuid-dev \
libsepol1-dev \
libtool \
dmsetup \
autoconf \
automake \
pkg-config \
autopoint \
gettext \
expect \
keyutils \
libjson-c-dev \
libblkid-dev \
dkms \
linux-headers-$(uname -r) \
linux-modules-extra-$(uname -r) \
libssh-dev \
sshpass \
|| return
# For VeraCrypt test
sudo apt-get install gost-crypto-dkms
}
function travis_before_script
{
set -o xtrace
./autogen.sh
ret=$?
set +o xtrace
return $ret
}
function travis_script
{
local ret
set -o xtrace
case "$MAKE_CHECK" in
gcrypt)
check_nonroot "--with-crypto_backend=gcrypt" && \
check_root "--with-crypto_backend=gcrypt"
;;
gcrypt_compile)
check_nonroot_compile_only "--with-crypto_backend=gcrypt"
;;
openssl)
check_nonroot "--with-crypto_backend=openssl" && \
check_root "--with-crypto_backend=openssl"
;;
openssl_compile)
check_nonroot_compile_only "--with-crypto_backend=openssl"
;;
kernel)
check_nonroot "--with-crypto_backend=kernel" && \
check_root "--with-crypto_backend=kernel"
;;
kernel_compile)
check_nonroot_compile_only "--with-crypto_backend=kernel"
;;
*)
echo "error, check environment (travis.yml)" >&2
false
;;
esac
ret=$?
set +o xtrace
return $ret
}
function travis_after_script
{
return 0
}

View File

@@ -1,42 +0,0 @@
language: c
sudo: required
os: linux
dist: focal
group: edge
compiler:
- gcc
env:
# MAKE_CHECK="gcrypt"
- MAKE_CHECK="openssl"
# MAKE_CHECK="kernel"
branches:
only:
- master
- wip-luks2
- v2.3.x
before_install:
- uname -a
- $CC --version
- which $CC
# workaround clang not system wide, fail on sudo make install
- export CC=`which $CC`
# workaround travis-ci issue #5301
- unset PYTHON_CFLAGS
install:
- source ./.travis-functions.sh
- travis_install_script
before_script:
- travis_before_script
script:
- travis_script
after_script:
- travis_after_script

88
FAQ
View File

@@ -51,7 +51,7 @@ A. Contributors
security model BEFORE you face such a disaster! In particular, make
sure you have a current header backup before doing any potentially
dangerous operations. The LUKS2 header should be a bit more resilient
as critical data starts later and is stored twice, but you can decidedly
as critical data starts later and is stored twice, but you can decidely
still destroy it or a keyslot permanently by accident.
DEBUG COMMANDS: While the --debug and --debug-json options should not
@@ -235,6 +235,31 @@ A. Contributors
nothing and are sure you did not confirm, then you should look into a
possible compromise of your email account.
* 1.9 What can I do if cryptsetup is running out of memory?
Memory issues are generally related to the key derivation function. You may
be able to tune usage with the options --pbkdf-memory or --pbkdf pbkdf2.
* 1.10 Can cryptsetup be run without root access?
Elevated privileges are required to use cryptsetup and LUKS. Some operations
require root access. There are a few features which will work without root
access with the right switches but there are caveats.
* 1.11 What are the problems with running as non root?
The first issue is one of permissions to devices. Generally, root or a group
such as disk has ownership of the storage devices. The non root user will
need write access to the block device used for LUKS.
Next, file locking is managed in /run/cryptsetup. You may use
--disable-locks but cryptsetup will no longer protect you from race
conditions and problems with concurrent access to the same devices.
Also, device mapper requires root access. cryptsetup uses device mapper to
manage the decrypted container.
2. Setup
@@ -399,6 +424,14 @@ A. Contributors
it in some other way. The PC is just not set-up for a really secure
boot-chain (whatever some people may claim).
That said, if you want an encrypted root partition, you have to store
an initrd with cryptsetup somewhere else. The traditional approach is
to have a separate partition under /boot for that. You can also put that
initrd on a bootable memory stick, bootable CD or bootable external
drive as well. The kernel and Grub typically go to the same location
as that initrd. A minimal example what such an initrd can look like is
given in Section 9.
(2) Fully encrypted raw block device: For this, put LUKS on the raw
device (e.g. /dev/sdb) and put a filesystem into the LUKS container, no
partitioning whatsoever involved. This is very suitable for things like
@@ -818,7 +851,7 @@ A. Contributors
* 2.20 How do I wipe only the LUKS header?
This does _not_ describe an emergency wipe procedure, see Item 5.4 for
that. This procedure here is intended to be used when the data should
stay intact, e.g. when you change your LUKS container to use a detached
@@ -831,20 +864,26 @@ A. Contributors
cryptsetup luksDump <device with LUKS container>
-> ...
Payload offset: <number>
Payload offset: <number> [of 512 byte sectors]
...
02) Take the result number, multiply by 512 zeros and write to
the start of the device, e.g. like this:
the start of the device, e.g. using one of the following alternatives:
dd bs=512 count=<number> if=/dev/zero of=<device>
LUKS2: (warning, untested! Remember that backup?) This assumes the
head -c <number * 512> /dev/zero > /dev/<device>
LUKS2:
(warning, untested! Remember that backup?) This assumes the
LUKS2 container uses the defaults, in particular there is only one data
segment. 01) Determine the data-segment offset using luksDump, same
segment.
01) Determine the data-segment offset using luksDump, same
as above for LUKS1:
cryptsetup luksDump <device with LUKS container>
-> ...
Data segments:
0: crypt
@@ -854,7 +893,7 @@ A. Contributors
02) Overwrite the stated number of bytes from the start of the device.
Just to give yet another way to get a defined number of zeros:
head -c /dev/zero > /dev/<device>
head -c <number> /dev/zero > /dev/<device>
3. Common Problems
@@ -969,7 +1008,7 @@ A. Contributors
that is intact.
In order to find out whether a key-slot is damaged one has to look for
"non-random looking" data in it. There is a tool that automates this
"non-random looking" data in it. There is a tool that automatizes this
for LUKS1 in the cryptsetup distribution from version 1.6.0 onwards. It
is located in misc/keyslot_checker/. Instructions how to use and how to
interpret results are in the README file. Note that this tool requires
@@ -1207,6 +1246,17 @@ A. Contributors
countries like the US or the UK are not civilized and do not have fair
laws.
As a side-note, standards for biometrics (fingerprint, retina,
vein-pattern, etc.) are often different and much lower. If you put
your LUKS passphrase into a device that can be unlocked using biometrics,
they may force a biometric sample in many countries where they could not
force you to give them a passphrase you solely have in your memory and
can claim to have forgotten if needed (it happens). If you need protection
on this level, make sure you know what the respective legal situation is,
also while traveling, and make sure you decide beforehand what you
will do if push comes to shove as they will definitely put you under
as much pressure as they can legally apply.
This means that if you have a large set of random-looking data, they can
already lock you up. Hidden containers (encryption hidden within
encryption), as possible with Truecrypt, do not help either. They will
@@ -1608,9 +1658,8 @@ A. Contributors
cryptsetup -c aes-xts-plain64 luksFormat <device>
There is a potential security issue with XTS mode and blocks larger
than 2^20 bytes or so. LUKS and dm-crypt always use smaller blocks
and the issue does not apply.
There is a potential security issue with XTS mode and large blocks.
LUKS and dm-crypt always use 512B blocks and the issue does not apply.
* 5.17 Is LUKS FIPS-140-2 certified?
@@ -2629,7 +2678,7 @@ offset length name data type description
safe under these circumstances, then you have bigger problems than this
somewhat expected behavior.
The CVE was exaggerated and should not be assigned to upstream
The CVE was exagerrated and should not be assigned to upstream
cryptsetup in the first place (it is a distro specific initrd issue).
It was driven more by a try to make a splash for self-aggrandizement,
than by any actual security concerns. Ignore it.
@@ -2953,9 +3002,24 @@ offset length name data type description
start of the device, nothing gets stored somewhere in the middle or at
the end.
* 10.12 What is a LUKS2 Token?
A LUKS2 token is an object that describes "how to get a passphrase or
key" to unlock particular keyslot. A LUKS2 token is stored as json data
in the LUKS2 header. The token can be related to all keyslots or a
specific one. As the token is stored in JSON formay it is text by
default but binary data can be encoded into it according to the JSON
conventions.
Documentation on the last changes to LUKS2 tokens can be found in the
release notes. As of version 2.4 of cryptsetup, there are significant
features. The standard documentation for working with tokens is
in the luks2 reference available as PDF on the project page.
11. References and Further Reading
* Purpose of this Section
The purpose of this section is to collect references to all materials

View File

@@ -1,4 +1,4 @@
EXTRA_DIST = README.md COPYING.LGPL FAQ docs misc
EXTRA_DIST = README.md COPYING.LGPL FAQ docs misc autogen.sh
SUBDIRS = po tests
CLEANFILES =
DISTCLEAN_TARGETS =
@@ -54,3 +54,9 @@ distclean-local:
clean-local:
-rm -rf docs/doxygen_api_docs libargon2.la
install-data-local:
$(MKDIR_P) -m 0755 $(DESTDIR)/${EXTERNAL_LUKS2_TOKENS_PATH}
uninstall-local:
rmdir $(DESTDIR)/${EXTERNAL_LUKS2_TOKENS_PATH} 2>/dev/null || :

View File

@@ -20,6 +20,8 @@ LUKS Design
only facilitate compatibility among distributions, but also provides secure management of multiple user passwords.
LUKS stores all necessary setup information in the partition header, enabling to transport or migrate data seamlessly.
### Specifications
Last version of the LUKS2 format specification is
[available here](https://gitlab.com/cryptsetup/LUKS2-docs).
@@ -44,22 +46,16 @@ Download
--------
All release tarballs and release notes are hosted on [kernel.org](https://www.kernel.org/pub/linux/utils/cryptsetup/).
**The latest release candidate cryptsetup version is 2.4.0-rc1**
* [cryptsetup-2.4.0-rc1.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.4/cryptsetup-2.4.0-rc1.tar.xz)
* Signature [cryptsetup-2.4.0-rc1.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.4/cryptsetup-2.4.0-rc1.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.4.0-rc1 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.4/v2.4.0-rc1-ReleaseNotes).
**The latest stable cryptsetup version is 2.3.6**
* [cryptsetup-2.3.6.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/cryptsetup-2.3.6.tar.xz)
* Signature [cryptsetup-2.3.6.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/cryptsetup-2.3.6.tar.sign)
_(You need to decompress file first to check signature.)_
* [Cryptsetup 2.3.6 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/v2.3.6-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).
@@ -77,22 +73,35 @@ NLS PO files are maintained by [TranslationProject](https://translationproject.o
Required packages
-----------------
All distributions provide cryptsetup as distro package. If you need to compile cryptsetup youfself, some packages are required for compilation. Please always prefer distro specific build tools to manually configuring cryptsetup.
Fo available compile options, check ``configure --help`` for more info. If you are using a git snapshot, you need to generate configure script with ``autogen.sh`` script.
All distributions provide cryptsetup as distro package. If you need to compile cryptsetup yourself, some packages are required for compilation. Please always prefer distro specific build tools to manually configuring cryptsetup.
For available compile options, check ``configure --help`` for more info. If you are using a git snapshot, you need to generate a configure script with ``autogen.sh`` script.
Here is the list of packages needed for the compilation of project for particular distributions:
* For Fedora: `git gcc make autoconf automake gettext-devel pkgconfig openssl-devel popt-devel device-mapper-devel libuuid-devel json-c-devel libblkid-devel findutils libtool libssh-devel tar`. Optionally `libargon2-devel libpwquality-devel`. To run internal testsuite you also need `sharutils device-mapper jq vim-common expect keyutils netcat shadow-utils openssh-clients openssh sshpass`.
* For Fedora: `git gcc make autoconf automake gettext-devel pkgconfig openssl-devel popt-devel device-mapper-devel libuuid-devel json-c-devel libblkid-devel findutils libtool libssh-devel tar`. Optionally `libargon2-devel libpwquality-devel`. To run the internal testsuite you also need to install `sharutils device-mapper jq vim-common expect keyutils netcat shadow-utils openssh-clients openssh sshpass`.
* For Debian and Ubuntu: `git gcc make autoconf automake autopoint pkg-config libtool gettext libssl-dev libdevmapper-dev libpopt-dev uuid-dev libsepol1-dev libjson-c-dev libssh-dev libblkid-dev tar`. Optionally `libargon2-0-dev libpwquality-dev`. To run internal testsuite you also need `sharutils dmsetup jq xxd expect keyutils netcat passwd openssh-client sshpass`
* For Debian and Ubuntu: `git gcc make autoconf automake autopoint pkg-config libtool gettext libssl-dev libdevmapper-dev libpopt-dev uuid-dev libsepol1-dev libjson-c-dev libssh-dev libblkid-dev tar`. Optionally `libargon2-0-dev libpwquality-dev`. To run the internal testsuite you also need to install `sharutils dmsetup jq xxd expect keyutils netcat passwd openssh-client sshpass`
Note that the list could change as distributions evolve.
Note that the list could change as the distributions evolve.
Help!
-----
Please always read [FAQ](https://gitlab.com/cryptsetup/cryptsetup/wikis/FrequentlyAskedQuestions) first.
For cryptsetup and LUKS related questions, please use the dm-crypt mailing list, [dm-crypt@saout.de](mailto:dm-crypt@saout.de).
If you want to subscribe just send an empty mail to [dm-crypt-subscribe@saout.de](mailto:dm-crypt-subscribe@saout.de).
### Documentation
You can also browse [list archive](https://www.saout.de/pipermail/dm-crypt/) or read and search it through
[web interface on lore.kernel.org](https://lore.kernel.org/dm-crypt/) or alternatively on [marc.info](https://marc.info/?l=dm-crypt).
Please read the following documentation before posting questions in the mailing list. You will be able to ask better questions and better understand the answers.
* [FAQ](https://gitlab.com/cryptsetup/cryptsetup/wikis/FrequentlyAskedQuestions)
* LUKS Specifications
* manuals (aka man page, man pages, man-page)
The FAQ is online and in the source code for the project. The Specifications are referenced above in this document. The man pages are in source and should be available after installation using standard man commands. e.g. man cryptsetup
### Mailing List
For cryptsetup and LUKS related questions, please use the dm-crypt mailing list, [dm-crypt@saout.de](mailto:dm-crypt@saout.de). To subscribe send an empty mail to [dm-crypt-subscribe@saout.de](mailto:dm-crypt-subscribe@saout.de).
You can also browse and/or search the mailing list archives using the following resources:
* [list archive](https://www.saout.de/pipermail/dm-crypt/)
* [web interface on lore.kernel.org](https://lore.kernel.org/dm-crypt/)
* [marc.info](https://marc.info/?l=dm-crypt).

View File

@@ -29,10 +29,10 @@ DIE=0
DIE=1
}
(grep "^AM_PROG_LIBTOOL" $srcdir/configure.ac >/dev/null) && {
(libtool --version) < /dev/null > /dev/null 2>&1 || {
(grep "^LT_INIT" $srcdir/configure.ac >/dev/null) && {
(libtoolize --version) < /dev/null > /dev/null 2>&1 || {
echo
echo "**Error**: You must have libtool installed."
echo "**Error**: You must have libtoolize installed."
echo "Download the appropriate package for your distribution."
DIE=1
}

View File

@@ -1,5 +1,5 @@
AC_PREREQ([2.67])
AC_INIT([cryptsetup],[2.4.0-rc1])
AC_INIT([cryptsetup],[2.4.3])
dnl library version from <major>.<minor>.<release>[-<suffix>]
LIBCRYPTSETUP_VERSION=$(echo $PACKAGE_VERSION | cut -f1 -d-)
@@ -30,6 +30,7 @@ AM_PROG_CC_C_O
AC_PROG_CPP
AC_PROG_INSTALL
AC_PROG_MAKE_SET
AC_PROG_MKDIR_P
AC_ENABLE_STATIC(no)
LT_INIT
PKG_PROG_PKG_CONFIG
@@ -57,7 +58,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])],
@@ -123,6 +123,12 @@ AC_ARG_ENABLE([external-tokens],
[], [enable_external_tokens=yes])
if test "x$enable_external_tokens" = "xyes"; then
AC_DEFINE(USE_EXTERNAL_TOKENS, 1, [Use external tokens])
dnl we need dynamic library loading here
saved_LIBS=$LIBS
AC_SEARCH_LIBS([dlsym],[dl])
AC_CHECK_FUNCS([dlvsym])
AC_SUBST(DL_LIBS, $LIBS)
LIBS=$saved_LIBS
fi
AC_ARG_ENABLE([ssh-token],
@@ -134,6 +140,14 @@ if test "x$enable_ssh_token" = "xyes" -a "x$enable_external_tokens" = "xno"; the
AC_MSG_ERROR([Requested LUKS2 ssh-token build, but external tokens are disabled.])
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 ==========================================================================
AM_GNU_GETTEXT([external],[need-ngettext])
@@ -399,10 +413,15 @@ PKG_CHECK_MODULES([JSON_C], [json-c])
AC_CHECK_DECLS([json_object_object_add_ex], [], [], [#include <json-c/json.h>])
AC_CHECK_DECLS([json_object_deep_copy], [], [], [#include <json-c/json.h>])
dnl Check for libssh for SSH plugin
dnl Check for libssh and argp for SSH plugin
if test "x$enable_ssh_token" = "xyes"; then
PKG_CHECK_MODULES([LIBSSH], [libssh])
AC_CHECK_DECLS([ssh_session_is_known_server], [], [], [#include <libssh/libssh.h>])
AC_CHECK_HEADER([argp.h], [], AC_MSG_ERROR([You need argp library.]))
saved_LIBS=$LIBS
AC_SEARCH_LIBS([argp_usage],[argp])
AC_SUBST(ARGP_LIBS, $LIBS)
LIBS=$saved_LIBS
fi
dnl Crypto backend configuration.

View File

@@ -1,4 +1,4 @@
# Doxyfile 1.8.8
# Doxyfile 1.9.1
#---------------------------------------------------------------------------
# Project related configuration options
@@ -12,6 +12,7 @@ OUTPUT_DIRECTORY = doxygen_api_docs
CREATE_SUBDIRS = NO
ALLOW_UNICODE_NAMES = NO
OUTPUT_LANGUAGE = English
OUTPUT_TEXT_DIRECTION = None
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ABBREVIATE_BRIEF =
@@ -22,40 +23,47 @@ STRIP_FROM_PATH =
STRIP_FROM_INC_PATH =
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = NO
JAVADOC_BANNER = NO
QT_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
PYTHON_DOCSTRING = YES
INHERIT_DOCS = YES
SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 8
ALIASES =
TCL_SUBST =
OPTIMIZE_OUTPUT_FOR_C = YES
OPTIMIZE_OUTPUT_JAVA = NO
OPTIMIZE_FOR_FORTRAN = NO
OPTIMIZE_OUTPUT_VHDL = NO
OPTIMIZE_OUTPUT_SLICE = NO
EXTENSION_MAPPING =
MARKDOWN_SUPPORT = YES
TOC_INCLUDE_HEADINGS = 5
AUTOLINK_SUPPORT = YES
BUILTIN_STL_SUPPORT = NO
CPP_CLI_SUPPORT = NO
SIP_SUPPORT = NO
IDL_PROPERTY_SUPPORT = YES
DISTRIBUTE_GROUP_DOC = NO
GROUP_NESTED_COMPOUNDS = NO
SUBGROUPING = YES
INLINE_GROUPED_CLASSES = NO
INLINE_SIMPLE_STRUCTS = NO
TYPEDEF_HIDES_STRUCT = YES
LOOKUP_CACHE_SIZE = 0
NUM_PROC_THREADS = 1
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
EXTRACT_ALL = NO
EXTRACT_PRIVATE = NO
EXTRACT_PRIV_VIRTUAL = NO
EXTRACT_PACKAGE = NO
EXTRACT_STATIC = NO
EXTRACT_LOCAL_CLASSES = YES
EXTRACT_LOCAL_METHODS = NO
EXTRACT_ANON_NSPACES = NO
RESOLVE_UNNAMED_PARAMS = YES
HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO
HIDE_FRIEND_COMPOUNDS = NO
@@ -63,6 +71,7 @@ HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
CASE_SENSE_NAMES = YES
HIDE_SCOPE_NAMES = NO
HIDE_COMPOUND_REFERENCE= NO
SHOW_INCLUDE_FILES = YES
SHOW_GROUPED_MEMB_INC = NO
FORCE_LOCAL_INCLUDES = NO
@@ -93,13 +102,14 @@ WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = NO
WARN_AS_ERROR = NO
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE =
#---------------------------------------------------------------------------
# Configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = "doxygen_index.h" \
"../lib/libcryptsetup.h"
INPUT = doxygen_index.h \
../lib/libcryptsetup.h
INPUT_ENCODING = UTF-8
FILE_PATTERNS =
RECURSIVE = NO
@@ -107,7 +117,7 @@ EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS =
EXCLUDE_SYMBOLS =
EXAMPLE_PATH = "examples"
EXAMPLE_PATH = examples
EXAMPLE_PATTERNS =
EXAMPLE_RECURSIVE = NO
IMAGE_PATH =
@@ -129,12 +139,13 @@ SOURCE_TOOLTIPS = YES
USE_HTAGS = NO
VERBATIM_HEADERS = YES
CLANG_ASSISTED_PARSING = NO
CLANG_ADD_INC_PATHS = YES
CLANG_OPTIONS =
CLANG_DATABASE_PATH =
#---------------------------------------------------------------------------
# Configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = YES
COLS_IN_ALPHA_INDEX = 5
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the HTML output
@@ -151,6 +162,7 @@ HTML_COLORSTYLE_HUE = 220
HTML_COLORSTYLE_SAT = 100
HTML_COLORSTYLE_GAMMA = 80
HTML_TIMESTAMP = YES
HTML_DYNAMIC_MENUS = YES
HTML_DYNAMIC_SECTIONS = NO
HTML_INDEX_NUM_ENTRIES = 100
GENERATE_DOCSET = NO
@@ -180,8 +192,10 @@ GENERATE_TREEVIEW = NO
ENUM_VALUES_PER_LINE = 4
TREEVIEW_WIDTH = 250
EXT_LINKS_IN_WINDOW = NO
HTML_FORMULA_FORMAT = png
FORMULA_FONTSIZE = 10
FORMULA_TRANSPARENT = YES
FORMULA_MACROFILE =
USE_MATHJAX = NO
MATHJAX_FORMAT = HTML-CSS
MATHJAX_RELPATH = http://www.mathjax.org/mathjax
@@ -201,11 +215,13 @@ GENERATE_LATEX = YES
LATEX_OUTPUT = latex
LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
LATEX_MAKEINDEX_CMD = makeindex
COMPACT_LATEX = NO
PAPER_TYPE = a4
EXTRA_PACKAGES =
LATEX_HEADER =
LATEX_FOOTER =
LATEX_EXTRA_STYLESHEET =
LATEX_EXTRA_FILES =
PDF_HYPERLINKS = YES
USE_PDFLATEX = YES
@@ -213,6 +229,8 @@ LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
LATEX_SOURCE_CODE = NO
LATEX_BIB_STYLE = plain
LATEX_TIMESTAMP = NO
LATEX_EMOJI_DIRECTORY =
#---------------------------------------------------------------------------
# Configuration options related to the RTF output
#---------------------------------------------------------------------------
@@ -222,6 +240,7 @@ COMPACT_RTF = NO
RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
RTF_SOURCE_CODE = NO
#---------------------------------------------------------------------------
# Configuration options related to the man page output
#---------------------------------------------------------------------------
@@ -236,6 +255,7 @@ MAN_LINKS = NO
GENERATE_XML = NO
XML_OUTPUT = xml
XML_PROGRAMLISTING = YES
XML_NS_MEMB_FILE_SCOPE = NO
#---------------------------------------------------------------------------
# Configuration options related to the DOCBOOK output
#---------------------------------------------------------------------------
@@ -273,12 +293,10 @@ GENERATE_TAGFILE =
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
EXTERNAL_PAGES = YES
PERL_PATH =
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
CLASS_DIAGRAMS = YES
MSCGEN_PATH =
DIA_PATH =
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = NO
@@ -291,6 +309,8 @@ COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
UML_LOOK = NO
UML_LIMIT_NUM_FIELDS = 10
DOT_UML_DETAILS = NO
DOT_WRAP_THRESHOLD = 17
TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
@@ -305,6 +325,8 @@ DOTFILE_DIRS =
MSCFILE_DIRS =
DIAFILE_DIRS =
PLANTUML_JAR_PATH =
PLANTUML_CFG_FILE =
PLANTUML_INCLUDE_PATH =
DOT_GRAPH_MAX_NODES = 50
MAX_DOT_GRAPH_DEPTH = 0
DOT_TRANSPARENT = NO

Binary file not shown.

View File

@@ -1,31 +1,10 @@
Cryptsetup 2.4.0-rc1 Release Notes
==================================
Stable release candidate with new features and bug fixes.
Cryptsetup 2.4.0 Release Notes
==============================
Stable release with new features and bug fixes.
This version introduces support for external libraries
(plugins) for handling LUKS2 token objects.
Changes since version 2.4.0-rc0
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Add cryptsetup --token-type parameter.
It restricts token type to the parameter value in case no specific
token-id is selected.
* Do not retry token operations if PIN entry failed.
* Respect keyslot priority with token-based activation.
* veritysetup: add --root-hash-file option
Allow passing the root hash via a file, rather than verbatim on
the command line, for the open, verify, and format actions.
* Add crypt_reencrypt_run superseding now deprecated crypt_reencrypt
API call (fixes API break in rc0 release).
* Respect keyslot priority with token-based activation.
Changes since version 2.3.6
~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -39,7 +18,13 @@ Changes since version 2.3.6
in external libraries (possibly provided by other projects).
A token library allows cryptsetup to understand metadata and provide
basic operations (activate, resize, dump metadata, handle keyslots).
basic operations. Currently external tokens may be used to unlock
keyslots for following CLI actions: open (luksOpen),
refresh (open --refresh), resize and dump (prints token specific
content).
LUKS2 devices cannot be resumed (luksResume action) via tokens yet.
Support for resume and other actions will be added later.
The library now provides an interface that automatically tries to load
an external library for a token object in LUKS2 metadata.
@@ -61,8 +46,14 @@ Changes since version 2.3.6
External projects can use this interface to handle specific hardware
without introducing additional dependencies to libcryptsetup core.
Examples of such tokens are already available for the systemd project
for TPM2 and FIDO2 interfaces.
As of cryptsetup 2.4.0 release systemd project already merged upstream
native cryptsetup token handler for its systemd-tpm2 LUKS2 token
released originally in systemd-v248. The token can be created using
systemd-cryptenroll utility and devices may be manipulated either by
systemd-cryptsetup cli or by cryptsetup for actions listed above.
Other tokens like systemd-fido2 and systemd-pkcs11 are currently
in-review.
* Experimental SSH token
@@ -119,6 +110,19 @@ Example (how to activate LUKS2 through remote keyfile):
Please note SSH token is just demonstration of plugin interface API,
it is an EXPERIMENTAL feature.
* Add cryptsetup --token-type parameter.
It restricts token type to the parameter value in case no specific
token-id is selected.
* Support for token based activation with PIN.
If specific token requires PIN to unlock keyslot passphrase and
--token-only parameter was used cryptsetup asks for additional
token PIN.
* Respect keyslot priority with token-based activation.
* Default LUKS2 PBKDF is now Argon2id
Cryptsetup LUKS2 was using Argon2 while there were two versions,
@@ -266,6 +270,10 @@ Example (how to activate LUKS2 through remote keyfile):
Note that it cannot detect unknown algorithm names and similar where
we need call API functions.
* veritysetup: add --root-hash-file option
Allow passing the root hash via a file, rather than verbatim on
the command line, for the open, verify, and format actions.
* libcryptsetup C API extensions (see libcryptsetup.h for details)
- crypt_logf - a printf like log function
@@ -275,7 +283,7 @@ Example (how to activate LUKS2 through remote keyfile):
- crypt_token_external_path - get path for plugins (or NULL)
- crypt_token_external_disable - disable runtime support for plugins
- crypt_activate_by_token_pin - activate by token with additional PIN
- crypt_reencrypt - fixed prototype
- crypt_reencrypt_run - fixed API for deprecated crypt_reencrypt
The token plugin library interface cosists from these versioned
exported symbols (for details see header file and SSH token example):

47
docs/v2.4.1-ReleaseNotes Normal file
View File

@@ -0,0 +1,47 @@
Cryptsetup 2.4.1 Release Notes
==============================
Stable bug-fix release with minor extensions.
All users of cryptsetup 2.4.0 should upgrade to this version.
Changes since version 2.4.0
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Fix compilation for libc implementations without dlvsym().
Some alternative libc implementations (like musl) do not provide
versioned symbols dlvsym function. Code now fallbacks to dlsym
operation for dynamic LUKS2 token load.
It is up to maintainers to ensure that LUKS2 token plugins are
compiled for the supported version.
* Fix compilation and tests on systems with non-standard libraries
(standalone argp library, external gettext library, BusyBox
implementations of standard tools).
* Try to workaround some issues on systems without udev support.
NOTE: non-udev systems cannot provide all functionality for kernel
device-mapper, and some operations can fail.
* Fixes for OpenSSL3 crypto backend (including FIPS mode).
Because cryptsetup still requires some hash functions implemented
in OpenSSL3 legacy provider, crypto backend now uses its library
context and tries to load both default and legacy OpenSSL3 providers.
If FIPS mode is detected, no library context is used, and it is up
to the OpenSSL system-wide policy to load proper providers.
NOTE: We still use some deprecated API in the OpenSSL3 backend,
and there are some known problems in OpenSSL 3.0.0.
* Print error message when assigning a token to an inactive keyslot.
* Fix offset bug in LUKS2 encryption code if --offset option was used.
* Do not allow LUKS2 decryption for devices with data offset.
Such devices cannot be used after decryption.
* Fix LUKS1 cryptsetup repair command for some specific problems.
Repair code can now fix wrongly used initialization vector
specification in ECB mode (that is insecure anyway!) and repair
the upper-case hash specification in the LUKS1 header.

37
docs/v2.4.2-ReleaseNotes Normal file
View File

@@ -0,0 +1,37 @@
Cryptsetup 2.4.2 Release Notes
==============================
Stable bug-fix release.
All users of cryptsetup 2.4.1 should upgrade to this version.
Changes since version 2.4.1
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Fix possible large memory allocation if LUKS2 header size is invalid.
LUKS2 code read the full header to buffer to verify the checksum.
The maximal supported header size now limits the memory allocation.
* Fix memory corruption in debug message printing LUKS2 checksum.
* veritysetup: remove link to the UUID library for the static build.
* Remove link to pwquality library for integritysetup and veritysetup.
These tools do not read passphrases.
* OpenSSL3 backend: avoid remaining deprecated calls in API.
Crypto backend no longer use API deprecated in OpenSSL 3.0
* Check if kernel device-mapper create device failed in an early phase.
This happens when a concurrent creation of device-mapper devices
meets in the very early state.
* Do not set compiler optimization flag for Argon2 KDF if the memory
wipe is implemented in libc.
* Do not attempt to unload LUKS2 tokens if external tokens are disabled.
This allows building a static binary with --disable-external-tokens.
* LUKS convert: also check sysfs for device activity.
If udev symlink is missing, code fallbacks to sysfs scan to prevent
data corruption for the active device.

101
docs/v2.4.3-ReleaseNotes Normal file
View File

@@ -0,0 +1,101 @@
Cryptsetup 2.4.3 Release Notes
==============================
Stable security bug-fix release that fixes CVE-2021-4122.
All users of cryptsetup 2.4.x must upgrade to this version.
Changes since version 2.4.2
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* 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.
* Fix support for bitlk (BitLocker compatible) startup key with new
metadata entry introduced in Windows 11.
* Fix space restriction for LUKS2 reencryption with data shift.
The code required more space than was needed.

View File

@@ -32,7 +32,9 @@ libcryptsetup_la_LIBADD = \
@LIBARGON2_LIBS@ \
@JSON_C_LIBS@ \
@BLKID_LIBS@ \
@DL_LIBS@ \
$(LTLIBICONV) \
$(LTLIBINTL) \
libcrypto_backend.la \
libutils_io.la
@@ -98,6 +100,7 @@ libcryptsetup_la_SOURCES = \
lib/luks2/luks2_keyslot_luks2.c \
lib/luks2/luks2_keyslot_reenc.c \
lib/luks2/luks2_reencrypt.c \
lib/luks2/luks2_reencrypt_digest.c \
lib/luks2/luks2_segment.c \
lib/luks2/luks2_token_keyring.c \
lib/luks2/luks2_token.c \

View File

@@ -869,13 +869,20 @@ static int get_recovery_key(struct crypt_device *cd,
return 0;
}
static int parse_external_key_entry(struct crypt_device *cd, const char *data, int start, int end, struct volume_key **vk)
static int parse_external_key_entry(struct crypt_device *cd,
const char *data,
int start,
int end,
struct volume_key **vk,
const struct bitlk_metadata *params)
{
uint16_t key_entry_size = 0;
uint16_t key_entry_type = 0;
uint16_t key_entry_value = 0;
size_t key_size = 0;
const char *key = NULL;
struct bitlk_guid guid;
char guid_buf[UUID_STR_LEN] = {0};
while (end - start > 2) {
/* size of this entry */
@@ -892,8 +899,7 @@ static int parse_external_key_entry(struct crypt_device *cd, const char *data, i
key_entry_type = le16_to_cpu(key_entry_type);
key_entry_value = le16_to_cpu(key_entry_value);
/* only properties should be in this entry */
if (key_entry_type != BITLK_ENTRY_TYPE_PROPERTY) {
if (key_entry_type != BITLK_ENTRY_TYPE_PROPERTY && key_entry_type != BITLK_ENTRY_TYPE_VOLUME_GUID) {
log_err(cd, _("Unexpected metadata entry type '%u' found when parsing external key."), key_entry_type);
return -EINVAL;
}
@@ -908,7 +914,15 @@ static int parse_external_key_entry(struct crypt_device *cd, const char *data, i
/* optional "ExternalKey" string, we can safely ignore it */
} else if (key_entry_value == BITLK_ENTRY_VALUE_STRING)
;
else {
/* GUID of the BitLocker device we are trying to open with this key */
else if (key_entry_value == BITLK_ENTRY_VALUE_GUID) {
memcpy(&guid, data + start + BITLK_ENTRY_HEADER_LEN, sizeof(struct bitlk_guid));
guid_to_string(&guid, guid_buf);
if (strcmp(guid_buf, params->guid) != 0) {
log_err(cd, _("BEK file GUID '%s' does not match GUID of the volume."), guid_buf);
return -EINVAL;
}
} else {
log_err(cd, _("Unexpected metadata entry value '%u' found when parsing external key."), key_entry_value);
return -EINVAL;
}
@@ -925,7 +939,8 @@ static int get_startup_key(struct crypt_device *cd,
const char *password,
size_t passwordLen,
const struct bitlk_vmk *vmk,
struct volume_key **su_key)
struct volume_key **su_key,
const struct bitlk_metadata *params)
{
struct bitlk_bek_header bek_header = {0};
char guid_buf[UUID_STR_LEN] = {0};
@@ -947,12 +962,12 @@ static int get_startup_key(struct crypt_device *cd,
return -EPERM;
if (bek_header.metadata_version != 1) {
log_err(cd, "Unsupported BEK metadata version %" PRIu32 "", bek_header.metadata_version);
log_err(cd, _("Unsupported BEK metadata version %" PRIu32), bek_header.metadata_version);
return -ENOTSUP;
}
if (bek_header.metadata_size != passwordLen) {
log_err(cd, "Unexpected BEK metadata size %" PRIu32 " does not match BEK file length", bek_header.metadata_size);
log_err(cd, _("Unexpected BEK metadata size %" PRIu32 " does not match BEK file length"), bek_header.metadata_size);
return -EINVAL;
}
@@ -975,7 +990,7 @@ static int get_startup_key(struct crypt_device *cd,
if (key_entry_type == BITLK_ENTRY_TYPE_STARTUP_KEY && key_entry_value == BITLK_ENTRY_VALUE_EXTERNAL_KEY) {
return parse_external_key_entry(cd, password,
BITLK_BEK_FILE_HEADER_LEN + BITLK_ENTRY_HEADER_LEN + BITLK_STARTUP_KEY_HEADER_LEN,
passwordLen, su_key);
passwordLen, su_key, params);
} else {
log_err(cd, _("Unexpected metadata entry found when parsing startup key."));
log_dbg(cd, "Entry type: %u, entry value: %u", key_entry_type, key_entry_value);
@@ -1142,7 +1157,7 @@ int BITLK_get_volume_key(struct crypt_device *cd,
if (r)
return r;
} else if (next_vmk->protection == BITLK_PROTECTION_STARTUP_KEY) {
r = get_startup_key(cd, password, passwordLen, next_vmk, &vmk_dec_key);
r = get_startup_key(cd, password, passwordLen, next_vmk, &vmk_dec_key, params);
if (r) {
next_vmk = next_vmk->next;
continue;

View File

@@ -61,6 +61,7 @@ typedef enum {
BITLK_ENTRY_TYPE_STARTUP_KEY = 0x0006,
BITLK_ENTRY_TYPE_DESCRIPTION = 0x0007,
BITLK_ENTRY_TYPE_VOLUME_HEADER = 0x000f,
BITLK_ENTRY_TYPE_VOLUME_GUID = 0x0019,
} BITLKFVEEntryType;
typedef enum {
@@ -76,6 +77,7 @@ typedef enum {
BITLK_ENTRY_VALUE_EXTERNAL_KEY = 0x0009,
BITLK_ENTRY_VALUE_OFFSET_SIZE = 0x000f,
BITLK_ENTRY_VALUE_RECOVERY_TIME = 0x015,
BITLK_ENTRY_VALUE_GUID = 0x0017,
} BITLKFVEEntryValue;
struct bitlk_vmk {

View File

@@ -120,18 +120,24 @@ void free_memory(const argon2_context *context, uint8_t *memory,
}
}
void NOT_OPTIMIZED secure_wipe_memory(void *v, size_t n) {
#if defined(_MSC_VER) && VC_GE_2005(_MSC_VER)
void secure_wipe_memory(void *v, size_t n) {
SecureZeroMemory(v, n);
}
#elif defined memset_s
void secure_wipe_memory(void *v, size_t n) {
memset_s(v, n, 0, n);
}
#elif defined(HAVE_EXPLICIT_BZERO)
void secure_wipe_memory(void *v, size_t n) {
explicit_bzero(v, n);
}
#else
void NOT_OPTIMIZED secure_wipe_memory(void *v, size_t n) {
static void *(*const volatile memset_sec)(void *, int, size_t) = &memset;
memset_sec(v, 0, n);
#endif
}
#endif
/* Memory clear flag defaults to true. */
int FLAG_clear_internal_memory = 1;

View File

@@ -31,7 +31,7 @@ struct crypt_hmac;
struct crypt_cipher;
struct crypt_storage;
int crypt_backend_init(void);
int crypt_backend_init(bool fips);
void crypt_backend_destroy(void);
#define CRYPT_BACKEND_KERNEL (1 << 0) /* Crypto uses kernel part, for benchmark */

View File

@@ -94,7 +94,7 @@ static void crypt_hash_test_whirlpool_bug(void)
crypto_backend_whirlpool_bug = 1;
}
int crypt_backend_init(void)
int crypt_backend_init(bool fips __attribute__((unused)))
{
int r;

View File

@@ -117,7 +117,7 @@ static int crypt_kernel_socket_init(struct sockaddr_alg *sa, int *tfmfd, int *op
return 0;
}
int crypt_backend_init(void)
int crypt_backend_init(bool fips __attribute__((unused)))
{
struct utsname uts;
struct sockaddr_alg sa = {

View File

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

View File

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

View File

@@ -28,11 +28,6 @@
* for all of the code used other than OpenSSL.
*/
/*
* HMAC will be later rewritten to a new API from OpenSSL 3
*/
#define OPENSSL_SUPPRESS_DEPRECATED
#include <string.h>
#include <errno.h>
#include <openssl/evp.h>
@@ -41,8 +36,12 @@
#include "crypto_backend_internal.h"
#if OPENSSL_VERSION_MAJOR >= 3
#include <openssl/provider.h>
#include <openssl/kdf.h>
#include <openssl/core_names.h>
static OSSL_PROVIDER *ossl_legacy = NULL;
static OSSL_PROVIDER *ossl_default = NULL;
static OSSL_LIB_CTX *ossl_ctx = NULL;
static char backend_version[256] = "OpenSSL";
#endif
#define CONST_CAST(x) (x)(uintptr_t)
@@ -56,8 +55,14 @@ struct crypt_hash {
};
struct crypt_hmac {
#if OPENSSL_VERSION_MAJOR >= 3
EVP_MAC *mac;
EVP_MAC_CTX *md;
EVP_MAC_CTX *md_org;
#else
HMAC_CTX *md;
const EVP_MD *hash_id;
#endif
int hash_len;
};
@@ -68,6 +73,7 @@ struct crypt_cipher {
struct {
EVP_CIPHER_CTX *hd_enc;
EVP_CIPHER_CTX *hd_dec;
const EVP_CIPHER *cipher_type;
size_t iv_length;
} lib;
} u;
@@ -84,9 +90,10 @@ struct hash_alg {
#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
static void openssl_backend_init(void)
static int openssl_backend_init(bool fips __attribute__((unused)))
{
OpenSSL_add_all_algorithms();
return 0;
}
static void openssl_backend_exit(void)
@@ -130,46 +137,79 @@ static void HMAC_CTX_free(HMAC_CTX *md)
free(md);
}
#else
static void openssl_backend_init(void)
static void openssl_backend_exit(void)
{
#if OPENSSL_VERSION_MAJOR >= 3
if (ossl_legacy)
OSSL_PROVIDER_unload(ossl_legacy);
if (ossl_default)
OSSL_PROVIDER_unload(ossl_default);
if (ossl_ctx)
OSSL_LIB_CTX_free(ossl_ctx);
ossl_legacy = NULL;
ossl_default = NULL;
ossl_ctx = NULL;
#endif
}
static int openssl_backend_init(bool fips)
{
/*
* OpenSSL >= 3.0.0 provides some algorithms in legacy provider
*/
#if OPENSSL_VERSION_MAJOR >= 3
OPENSSL_init_crypto(OPENSSL_INIT_NO_ATEXIT, NULL);
ossl_legacy = OSSL_PROVIDER_try_load(NULL, "legacy", 0);
ossl_default = OSSL_PROVIDER_try_load(NULL, "default", 0);
#endif
}
int r;
static void openssl_backend_exit(void)
{
#if OPENSSL_VERSION_MAJOR >= 3
/*
* If Destructor was already called, we must not call it again
* In FIPS mode we keep default OpenSSL context & global config
*/
if (OPENSSL_init_crypto(0, NULL) != 0) {
OSSL_PROVIDER_unload(ossl_legacy);
OSSL_PROVIDER_unload(ossl_default);
OPENSSL_cleanup();
if (!fips) {
ossl_ctx = OSSL_LIB_CTX_new();
if (!ossl_ctx)
return -EINVAL;
ossl_default = OSSL_PROVIDER_try_load(ossl_ctx, "default", 0);
if (!ossl_default) {
OSSL_LIB_CTX_free(ossl_ctx);
return -EINVAL;
}
/* Optional */
ossl_legacy = OSSL_PROVIDER_try_load(ossl_ctx, "legacy", 0);
}
r = snprintf(backend_version, sizeof(backend_version), "%s %s%s%s",
OpenSSL_version(OPENSSL_VERSION),
ossl_default ? "[default]" : "",
ossl_legacy ? "[legacy]" : "",
fips ? "[fips]" : "");
if (r < 0 || (size_t)r >= sizeof(backend_version)) {
openssl_backend_exit();
return -EINVAL;
}
ossl_legacy = NULL;
ossl_default = NULL;
#endif
return 0;
}
static const char *openssl_backend_version(void)
{
return OpenSSL_version(OPENSSL_VERSION);
#if OPENSSL_VERSION_MAJOR >= 3
return backend_version;
#else
return OpenSSL_version(OPENSSL_VERSION);
#endif
}
#endif
int crypt_backend_init(void)
int crypt_backend_init(bool fips)
{
if (crypto_backend_initialised)
return 0;
openssl_backend_init();
if (openssl_backend_init(fips))
return -EINVAL;
crypto_backend_initialised = 1;
return 0;
@@ -177,7 +217,14 @@ int crypt_backend_init(void)
void crypt_backend_destroy(void)
{
/*
* If Destructor was already called, we must not call it again
*/
if (!crypto_backend_initialised)
return;
crypto_backend_initialised = 0;
openssl_backend_exit();
}
@@ -215,16 +262,51 @@ static const char *crypt_hash_compat_name(const char *name)
return hash_name;
}
static const EVP_MD *hash_id_get(const char *name)
{
#if OPENSSL_VERSION_MAJOR >= 3
return EVP_MD_fetch(ossl_ctx, crypt_hash_compat_name(name), NULL);
#else
return EVP_get_digestbyname(crypt_hash_compat_name(name));
#endif
}
static void hash_id_free(const EVP_MD *hash_id)
{
#if OPENSSL_VERSION_MAJOR >= 3
EVP_MD_free(CONST_CAST(EVP_MD*)hash_id);
#endif
}
static const EVP_CIPHER *cipher_type_get(const char *name)
{
#if OPENSSL_VERSION_MAJOR >= 3
return EVP_CIPHER_fetch(ossl_ctx, name, NULL);
#else
return EVP_get_cipherbyname(name);
#endif
}
static void cipher_type_free(const EVP_CIPHER *cipher_type)
{
#if OPENSSL_VERSION_MAJOR >= 3
EVP_CIPHER_free(CONST_CAST(EVP_CIPHER*)cipher_type);
#endif
}
/* HASH */
int crypt_hash_size(const char *name)
{
int size;
const EVP_MD *hash_id;
hash_id = EVP_get_digestbyname(crypt_hash_compat_name(name));
hash_id = hash_id_get(name);
if (!hash_id)
return -EINVAL;
return EVP_MD_size(hash_id);
size = EVP_MD_size(hash_id);
hash_id_free(hash_id);
return size;
}
int crypt_hash_init(struct crypt_hash **ctx, const char *name)
@@ -241,7 +323,7 @@ int crypt_hash_init(struct crypt_hash **ctx, const char *name)
return -ENOMEM;
}
h->hash_id = EVP_get_digestbyname(crypt_hash_compat_name(name));
h->hash_id = hash_id_get(name);
if (!h->hash_id) {
EVP_MD_CTX_free(h->md);
free(h);
@@ -249,6 +331,7 @@ int crypt_hash_init(struct crypt_hash **ctx, const char *name)
}
if (EVP_DigestInit_ex(h->md, h->hash_id, NULL) != 1) {
hash_id_free(h->hash_id);
EVP_MD_CTX_free(h->md);
free(h);
return -EINVAL;
@@ -300,6 +383,7 @@ int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
void crypt_hash_destroy(struct crypt_hash *ctx)
{
hash_id_free(ctx->hash_id);
EVP_MD_CTX_free(ctx->md);
memset(ctx, 0, sizeof(*ctx));
free(ctx);
@@ -315,7 +399,39 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
const void *key, size_t key_length)
{
struct crypt_hmac *h;
#if OPENSSL_VERSION_MAJOR >= 3
OSSL_PARAM params[] = {
OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, CONST_CAST(void*)name, 0),
OSSL_PARAM_END
};
h = malloc(sizeof(*h));
if (!h)
return -ENOMEM;
h->mac = EVP_MAC_fetch(ossl_ctx, OSSL_MAC_NAME_HMAC, NULL);
if (!h->mac) {
free(h);
return -EINVAL;
}
h->md = EVP_MAC_CTX_new(h->mac);
if (!h->md) {
EVP_MAC_free(h->mac);
free(h);
return -ENOMEM;
}
if (EVP_MAC_init(h->md, key, key_length, params) != 1) {
EVP_MAC_CTX_free(h->md);
EVP_MAC_free(h->mac);
free(h);
return -EINVAL;
}
h->hash_len = EVP_MAC_CTX_get_mac_size(h->md);
h->md_org = EVP_MAC_CTX_dup(h->md);
#else
h = malloc(sizeof(*h));
if (!h)
return -ENOMEM;
@@ -326,7 +442,7 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
return -ENOMEM;
}
h->hash_id = EVP_get_digestbyname(crypt_hash_compat_name(name));
h->hash_id = hash_id_get(name);
if (!h->hash_id) {
HMAC_CTX_free(h->md);
free(h);
@@ -336,45 +452,75 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
HMAC_Init_ex(h->md, key, key_length, h->hash_id, NULL);
h->hash_len = EVP_MD_size(h->hash_id);
#endif
*ctx = h;
return 0;
}
static void crypt_hmac_restart(struct crypt_hmac *ctx)
static int crypt_hmac_restart(struct crypt_hmac *ctx)
{
#if OPENSSL_VERSION_MAJOR >= 3
EVP_MAC_CTX_free(ctx->md);
ctx->md = EVP_MAC_CTX_dup(ctx->md_org);
if (!ctx->md)
return -EINVAL;
#else
HMAC_Init_ex(ctx->md, NULL, 0, ctx->hash_id, NULL);
#endif
return 0;
}
int crypt_hmac_write(struct crypt_hmac *ctx, const char *buffer, size_t length)
{
#if OPENSSL_VERSION_MAJOR >= 3
return EVP_MAC_update(ctx->md, (const unsigned char *)buffer, length) == 1 ? 0 : -EINVAL;
#else
HMAC_Update(ctx->md, (const unsigned char *)buffer, length);
return 0;
#endif
}
int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
{
unsigned char tmp[EVP_MAX_MD_SIZE];
#if OPENSSL_VERSION_MAJOR >= 3
size_t tmp_len = 0;
if (length > (size_t)ctx->hash_len)
return -EINVAL;
if (EVP_MAC_final(ctx->md, tmp, &tmp_len, sizeof(tmp)) != 1)
return -EINVAL;
#else
unsigned int tmp_len = 0;
if (length > (size_t)ctx->hash_len)
return -EINVAL;
HMAC_Final(ctx->md, tmp, &tmp_len);
#endif
memcpy(buffer, tmp, length);
crypt_backend_memzero(tmp, sizeof(tmp));
if (tmp_len < length)
return -EINVAL;
crypt_hmac_restart(ctx);
if (crypt_hmac_restart(ctx))
return -EINVAL;
return 0;
}
void crypt_hmac_destroy(struct crypt_hmac *ctx)
{
#if OPENSSL_VERSION_MAJOR >= 3
EVP_MAC_CTX_free(ctx->md);
EVP_MAC_CTX_free(ctx->md_org);
EVP_MAC_free(ctx->mac);
#else
hash_id_free(ctx->hash_id);
HMAC_CTX_free(ctx->md);
#endif
memset(ctx, 0, sizeof(*ctx));
free(ctx);
}
@@ -389,48 +535,91 @@ int crypt_backend_rng(char *buffer, size_t length,
return 0;
}
static int openssl_pbkdf2(const char *password, size_t password_length,
const char *salt, size_t salt_length, uint32_t iterations,
const char *hash, char *key, size_t key_length)
{
int r;
#if OPENSSL_VERSION_MAJOR >= 3
EVP_KDF_CTX *ctx;
EVP_KDF *pbkdf2;
OSSL_PARAM params[] = {
OSSL_PARAM_octet_string(OSSL_KDF_PARAM_PASSWORD,
CONST_CAST(void*)password, password_length),
OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SALT,
CONST_CAST(void*)salt, salt_length),
OSSL_PARAM_uint32(OSSL_KDF_PARAM_ITER, &iterations),
OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_DIGEST,
CONST_CAST(void*)hash, 0),
OSSL_PARAM_END
};
pbkdf2 = EVP_KDF_fetch(ossl_ctx, "pbkdf2", NULL);
if (!pbkdf2)
return -EINVAL;
ctx = EVP_KDF_CTX_new(pbkdf2);
if (!ctx) {
EVP_KDF_free(pbkdf2);
return -EINVAL;
}
r = EVP_KDF_derive(ctx, (unsigned char*)key, key_length, params);
EVP_KDF_CTX_free(ctx);
EVP_KDF_free(pbkdf2);
#else
const EVP_MD *hash_id = EVP_get_digestbyname(crypt_hash_compat_name(hash));
if (!hash_id)
return -EINVAL;
r = PKCS5_PBKDF2_HMAC(password, (int)password_length, (const unsigned char *)salt,
(int)salt_length, iterations, hash_id, (int)key_length, (unsigned char*) key);
#endif
return r == 1 ? 0 : -EINVAL;
}
static int openssl_argon2(const char *type, const char *password, size_t password_length,
const char *salt, size_t salt_length, char *key, size_t key_length,
uint32_t iterations, uint32_t memory, uint32_t parallel)
{
return argon2(type, password, password_length, salt, salt_length,
key, key_length, iterations, memory, parallel);
}
/* PBKDF */
int crypt_pbkdf(const char *kdf, const char *hash,
const char *password, size_t password_length,
const char *salt, size_t salt_length,
char *key, size_t key_length,
uint32_t iterations, uint32_t memory, uint32_t parallel)
{
const EVP_MD *hash_id;
if (!kdf)
return -EINVAL;
if (!strcmp(kdf, "pbkdf2")) {
hash_id = EVP_get_digestbyname(crypt_hash_compat_name(hash));
if (!hash_id)
return -EINVAL;
if (!PKCS5_PBKDF2_HMAC(password, (int)password_length,
(const unsigned char *)salt, (int)salt_length,
(int)iterations, hash_id, (int)key_length, (unsigned char *)key))
return -EINVAL;
return 0;
} else if (!strncmp(kdf, "argon2", 6)) {
return argon2(kdf, password, password_length, salt, salt_length,
key, key_length, iterations, memory, parallel);
}
if (!strcmp(kdf, "pbkdf2"))
return openssl_pbkdf2(password, password_length, salt, salt_length,
iterations, hash, key, key_length);
if (!strncmp(kdf, "argon2", 6))
return openssl_argon2(kdf, password, password_length, salt, salt_length,
key, key_length, iterations, memory, parallel);
return -EINVAL;
}
/* Block ciphers */
static void _cipher_destroy(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec)
static void _cipher_destroy(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec, const EVP_CIPHER **cipher_type)
{
EVP_CIPHER_CTX_free(*hd_enc);
*hd_enc = NULL;
EVP_CIPHER_CTX_free(*hd_dec);
*hd_dec = NULL;
cipher_type_free(*cipher_type);
*cipher_type = NULL;
}
static int _cipher_init(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec, const char *name,
static int _cipher_init(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec, const EVP_CIPHER **cipher_type, const char *name,
const char *mode, const void *key, size_t key_length, size_t *iv_length)
{
char cipher_name[256];
@@ -445,32 +634,38 @@ static int _cipher_init(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec, const
if (r < 0 || (size_t)r >= sizeof(cipher_name))
return -EINVAL;
type = EVP_get_cipherbyname(cipher_name);
type = cipher_type_get(cipher_name);
if (!type)
return -ENOENT;
if (EVP_CIPHER_key_length(type) != (int)key_length)
if (EVP_CIPHER_key_length(type) != (int)key_length) {
cipher_type_free(type);
return -EINVAL;
}
*hd_enc = EVP_CIPHER_CTX_new();
*hd_dec = EVP_CIPHER_CTX_new();
*iv_length = EVP_CIPHER_iv_length(type);
if (!*hd_enc || !*hd_dec)
if (!*hd_enc || !*hd_dec) {
cipher_type_free(type);
return -EINVAL;
}
if (EVP_EncryptInit_ex(*hd_enc, type, NULL, key, NULL) != 1 ||
EVP_DecryptInit_ex(*hd_dec, type, NULL, key, NULL) != 1) {
_cipher_destroy(hd_enc, hd_dec);
_cipher_destroy(hd_enc, hd_dec, &type);
return -EINVAL;
}
if (EVP_CIPHER_CTX_set_padding(*hd_enc, 0) != 1 ||
EVP_CIPHER_CTX_set_padding(*hd_dec, 0) != 1) {
_cipher_destroy(hd_enc, hd_dec);
_cipher_destroy(hd_enc, hd_dec, &type);
return -EINVAL;
}
*cipher_type = type;
return 0;
}
@@ -484,7 +679,7 @@ int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
if (!h)
return -ENOMEM;
if (!_cipher_init(&h->u.lib.hd_enc, &h->u.lib.hd_dec, name, mode, key,
if (!_cipher_init(&h->u.lib.hd_enc, &h->u.lib.hd_dec, &h->u.lib.cipher_type, name, mode, key,
key_length, &h->u.lib.iv_length)) {
h->use_kernel = false;
*ctx = h;
@@ -507,7 +702,7 @@ void crypt_cipher_destroy(struct crypt_cipher *ctx)
if (ctx->use_kernel)
crypt_cipher_destroy_kernel(&ctx->u.kernel);
else
_cipher_destroy(&ctx->u.lib.hd_enc, &ctx->u.lib.hd_dec);
_cipher_destroy(&ctx->u.lib.hd_enc, &ctx->u.lib.hd_dec, &ctx->u.lib.cipher_type);
free(ctx);
}

View File

@@ -129,9 +129,10 @@ void crypt_free(struct crypt_device *cd);
* other values mean accepted.
*
* @param cd crypt device handle
* @param confirm user defined confirm callback reference
* @param confirm user defined confirm callback reference; use
* @p msg for message for user to confirm and
* @p usrptr for identification in callback
* @param usrptr provided identification in callback
* @param msg Message for user to confirm
*
* @note Current version of cryptsetup API requires confirmation for UUID change and
* LUKS header restore only.
@@ -196,10 +197,11 @@ int crypt_set_data_offset(struct crypt_device *cd, uint64_t data_offset);
* Set log function.
*
* @param cd crypt device handle (can be @e NULL to set default log function)
* @param log user defined log function reference
* @param log user defined log function reference; use
* @p level for log level,
* @p msg for message, and
* @p usrptr for identification in callback
* @param usrptr provided identification in callback
* @param level log level below (debug messages can uses other levels)
* @param msg log message
*/
void crypt_set_log_callback(struct crypt_device *cd,
void (*log)(int level, const char *msg, void *usrptr),
@@ -2285,15 +2287,20 @@ const char *crypt_token_external_path(void);
*/
void crypt_token_external_disable(void);
/** ABI version for external token in libcryptsetup-token-<name>.so */
/** ABI version for external token in libcryptsetup-token-[name].so */
#define CRYPT_TOKEN_ABI_VERSION1 "CRYPTSETUP_TOKEN_1.0"
/** ABI exported symbol for external token */
#define CRYPT_TOKEN_ABI_OPEN "cryptsetup_token_open" /* mandatory */
/** open by token - ABI exported symbol for external token (mandatory) */
#define CRYPT_TOKEN_ABI_OPEN "cryptsetup_token_open"
/** open by token with PIN - ABI exported symbol for external token */
#define CRYPT_TOKEN_ABI_OPEN_PIN "cryptsetup_token_open_pin"
/** deallocate callback - ABI exported symbol for external token */
#define CRYPT_TOKEN_ABI_BUFFER_FREE "cryptsetup_token_buffer_free"
/** validate token metadata - ABI exported symbol for external token */
#define CRYPT_TOKEN_ABI_VALIDATE "cryptsetup_token_validate"
/** dump token metadata - ABI exported symbol for external token */
#define CRYPT_TOKEN_ABI_DUMP "cryptsetup_token_dump"
/** token version - ABI exported symbol for external token */
#define CRYPT_TOKEN_ABI_VERSION "cryptsetup_token_version"
/**
@@ -2319,7 +2326,7 @@ void crypt_token_external_disable(void);
* @note Negative EAGAIN errno means token handler requires additional hardware
* not present in the system.
*
* @note with @param token set to CRYPT_ANY_TOKEN libcryptsetup runs best effort loop
* @note with @e token set to CRYPT_ANY_TOKEN libcryptsetup runs best effort loop
* to unlock device using any available token. It may happen that various token handlers
* return different error codes. At the end loop returns error codes in the following
* order (from the most significant to the least) any negative errno except those
@@ -2357,7 +2364,7 @@ int crypt_activate_by_token(struct crypt_device *cd,
* @note Negative EAGAIN errno means token handler requires additional hardware
* not present in the system.
*
* @note with @param token set to CRYPT_ANY_TOKEN libcryptsetup runs best effort loop
* @note with @e token set to CRYPT_ANY_TOKEN libcryptsetup runs best effort loop
* to unlock device using any available token. It may happen that various token handlers
* return different error codes. At the end loop returns error codes in the following
* order (from the most significant to the least) any negative errno except those
@@ -2390,6 +2397,8 @@ int crypt_activate_by_token_pin(struct crypt_device *cd,
#define CRYPT_REENCRYPT_RESUME_ONLY (1 << 2)
/** Run reencryption recovery only. (in) */
#define CRYPT_REENCRYPT_RECOVERY (1 << 3)
/** Reencryption requires metadata protection. (in/out) */
#define CRYPT_REENCRYPT_REPAIR_NEEDED (1 << 4)
/**
* Reencryption direction

View File

@@ -1243,7 +1243,7 @@ static int dm_prepare_uuid(struct crypt_device *cd, const char *name, const char
int lookup_dm_dev_by_uuid(struct crypt_device *cd, const char *uuid, const char *type)
{
int r;
int r_udev, r;
char *c;
char dev_uuid[DM_UUID_LEN + DM_BY_ID_PREFIX_LEN] = DM_BY_ID_PREFIX;
@@ -1257,13 +1257,16 @@ int lookup_dm_dev_by_uuid(struct crypt_device *cd, const char *uuid, const char
/* cut of dm name */
*c = '\0';
/* Either udev or sysfs can report that device is active. */
r = lookup_by_disk_id(dev_uuid);
if (r == -ENOENT) {
log_dbg(cd, "Search by disk id not available. Using sysfs instead.");
r = lookup_by_sysfs_uuid_field(dev_uuid + DM_BY_ID_PREFIX_LEN);
}
if (r > 0)
return r;
return r;
r_udev = r;
if (r_udev <= 0)
r = lookup_by_sysfs_uuid_field(dev_uuid + DM_BY_ID_PREFIX_LEN);
return r == -ENOENT ? r_udev : r;
}
static int _add_dm_targets(struct dm_task *dmt, struct crypt_dm_active_device *dmd)
@@ -1346,12 +1349,6 @@ err:
return r;
}
static bool dm_device_exists(struct crypt_device *cd, const char *name)
{
int r = dm_status_device(cd, name);
return (r >= 0 || r == -EEXIST);
}
static int _dm_create_device(struct crypt_device *cd, const char *name, const char *type,
struct crypt_dm_active_device *dmd)
{
@@ -1402,8 +1399,11 @@ static int _dm_create_device(struct crypt_device *cd, const char *name, const ch
goto out;
if (!dm_task_run(dmt)) {
if (dm_device_exists(cd, name))
r = dm_status_device(cd, name);;
if (r >= 0)
r = -EEXIST;
if (r != -EEXIST && r != -ENODEV)
r = -EINVAL;
goto out;
}
@@ -2303,16 +2303,16 @@ static int _dm_target_query_verity(struct crypt_device *cd,
str = strsep(&params, " ");
if (!str)
goto err;
if (!root_hash_sig_key_desc) {
if (vp && !root_hash_sig_key_desc) {
root_hash_sig_key_desc = strdup(str);
if (!root_hash_sig_key_desc) {
r = -ENOMEM;
goto err;
}
/* not stored in params, but cannot be used without vp */
vp->flags |= CRYPT_VERITY_ROOT_HASH_SIGNATURE;
}
i++;
if (vp)
vp->flags |= CRYPT_VERITY_ROOT_HASH_SIGNATURE;
} else /* unknown option */
goto err;
}

View File

@@ -65,6 +65,27 @@ static void LUKS_sort_keyslots(const struct luks_phdr *hdr, int *array)
}
}
static int _is_not_lower(char *str, unsigned max_len)
{
for(; *str && max_len; str++, max_len--)
if (isupper(*str))
return 1;
return 0;
}
static int _to_lower(char *str, unsigned max_len)
{
int r = 0;
for(; *str && max_len; str++, max_len--)
if (isupper(*str)) {
*str = tolower(*str);
r = 1;
}
return r;
}
size_t LUKS_device_sectors(const struct luks_phdr *hdr)
{
int sorted_areas[LUKS_NUMKEYS] = { 0, 1, 2, 3, 4, 5, 6, 7 };
@@ -385,6 +406,30 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
return -EINVAL;
}
/*
* ECB mode does not use IV but legacy dmcrypt silently allows it.
* Today device cannot be activated anyway, so we need to fix it here.
*/
if (!strncmp(phdr->cipherMode, "ecb-", 4)) {
log_err(ctx, _("Cipher mode repaired (%s -> %s)."), phdr->cipherMode, "ecb");
memset(phdr->cipherMode, 0, LUKS_CIPHERMODE_L);
strcpy(phdr->cipherMode, "ecb");
need_write = 1;
}
/*
* Old cryptsetup expects "sha1", gcrypt allows case insensitive names,
* so always convert hash to lower case in header
*/
if (_to_lower(phdr->hashSpec, LUKS_HASHSPEC_L)) {
log_err(ctx, _("Cipher hash repaired to lowercase (%s)."), phdr->hashSpec);
if (crypt_hmac_size(phdr->hashSpec) < LUKS_DIGESTSIZE) {
log_err(ctx, _("Requested LUKS hash %s is not supported."), phdr->hashSpec);
return -EINVAL;
}
need_write = 1;
}
r = LUKS_check_cipher(ctx, phdr->keyBytes, phdr->cipherName, phdr->cipherMode);
if (r < 0)
return -EINVAL;
@@ -486,7 +531,7 @@ static int _check_and_convert_hdr(const char *device,
hdr->hashSpec[LUKS_HASHSPEC_L - 1] = '\0';
if (crypt_hmac_size(hdr->hashSpec) < LUKS_DIGESTSIZE) {
log_err(ctx, _("Requested LUKS hash %s is not supported."), hdr->hashSpec);
return -EINVAL;
r = -EINVAL;
}
/* Header detected */
@@ -510,6 +555,16 @@ static int _check_and_convert_hdr(const char *device,
hdr->uuid[UUID_STRING_L - 1] = '\0';
if (repair) {
if (!strncmp(hdr->cipherMode, "ecb-", 4)) {
log_err(ctx, _("LUKS cipher mode %s is invalid."), hdr->cipherMode);
r = -EINVAL;
}
if (_is_not_lower(hdr->hashSpec, LUKS_HASHSPEC_L)) {
log_err(ctx, _("LUKS hash %s is invalid."), hdr->hashSpec);
r = -EINVAL;
}
if (r == -EINVAL)
r = _keyslot_repair(hdr, ctx);
else
@@ -519,27 +574,6 @@ static int _check_and_convert_hdr(const char *device,
return r;
}
static void _to_lower(char *str, unsigned max_len)
{
for(; *str && max_len; str++, max_len--)
if (isupper(*str))
*str = tolower(*str);
}
static void LUKS_fix_header_compatible(struct luks_phdr *header)
{
/* Old cryptsetup expects "sha1", gcrypt allows case insensitive names,
* so always convert hash to lower case in header */
_to_lower(header->hashSpec, LUKS_HASHSPEC_L);
/* ECB mode does not use IV but dmcrypt silently allows it.
* Drop any IV here if ECB is used (that is not secure anyway).*/
if (!strncmp(header->cipherMode, "ecb-", 4)) {
memset(header->cipherMode, 0, LUKS_CIPHERMODE_L);
strcpy(header->cipherMode, "ecb");
}
}
int LUKS_read_phdr_backup(const char *backup_file,
struct luks_phdr *hdr,
int require_luks_device,
@@ -559,11 +593,9 @@ int LUKS_read_phdr_backup(const char *backup_file,
if (read_buffer(devfd, hdr, hdr_size) < hdr_size)
r = -EIO;
else {
LUKS_fix_header_compatible(hdr);
else
r = _check_and_convert_hdr(backup_file, hdr,
require_luks_device, 0, ctx);
}
close(devfd);
return r;
@@ -771,11 +803,10 @@ int LUKS_generate_phdr(struct luks_phdr *header,
strncpy(header->cipherName,cipherName,LUKS_CIPHERNAME_L-1);
strncpy(header->cipherMode,cipherMode,LUKS_CIPHERMODE_L-1);
strncpy(header->hashSpec,hashSpec,LUKS_HASHSPEC_L-1);
_to_lower(header->hashSpec, LUKS_HASHSPEC_L);
header->keyBytes=vk->keylength;
LUKS_fix_header_compatible(header);
log_dbg(ctx, "Generating LUKS header version %d using hash %s, %s, %s, MK %d bytes",
header->version, header->hashSpec ,header->cipherName, header->cipherMode,
header->keyBytes);

View File

@@ -401,6 +401,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,
@@ -453,4 +455,8 @@ int LUKS2_reencrypt_check_device_size(struct crypt_device *cd,
bool activation,
bool dynamic);
int LUKS2_reencrypt_digest_verify(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct volume_key *vks);
#endif

View File

@@ -62,8 +62,8 @@ static void log_dbg_checksum(struct crypt_device *cd,
int i;
for (i = 0; i < crypt_hash_size(csum_alg); i++)
snprintf(&csum_txt[i*2], 3, "%02hhx", (const char)csum[i]);
csum_txt[i*2+1] = '\0'; /* Just to be safe, sprintf should write \0 there. */
if (snprintf(&csum_txt[i*2], 3, "%02hhx", (const char)csum[i]) != 2)
return;
log_dbg(cd, "Checksum:%s (%s)", &csum_txt[0], info);
}
@@ -195,6 +195,8 @@ static int hdr_disk_sanity_check_pre(struct crypt_device *cd,
size_t *hdr_json_size, int secondary,
uint64_t offset)
{
uint64_t hdr_size;
if (memcmp(hdr->magic, secondary ? LUKS2_MAGIC_2ND : LUKS2_MAGIC_1ST, LUKS2_MAGIC_L))
return -EINVAL;
@@ -204,24 +206,31 @@ static int hdr_disk_sanity_check_pre(struct crypt_device *cd,
}
if (offset != be64_to_cpu(hdr->hdr_offset)) {
log_dbg(cd, "LUKS2 offset 0x%04x on device differs to expected offset 0x%04x.",
(unsigned)be64_to_cpu(hdr->hdr_offset), (unsigned)offset);
log_dbg(cd, "LUKS2 offset 0x%04" PRIx64 " on device differs to expected offset 0x%04" PRIx64 ".",
be64_to_cpu(hdr->hdr_offset), offset);
return -EINVAL;
}
if (secondary && (offset != be64_to_cpu(hdr->hdr_size))) {
log_dbg(cd, "LUKS2 offset 0x%04x in secondary header does not match size 0x%04x.",
(unsigned)offset, (unsigned)be64_to_cpu(hdr->hdr_size));
hdr_size = be64_to_cpu(hdr->hdr_size);
if (hdr_size < LUKS2_HDR_16K_LEN || hdr_size > LUKS2_HDR_OFFSET_MAX) {
log_dbg(cd, "LUKS2 header has bogus size 0x%04" PRIx64 ".", hdr_size);
return -EINVAL;
}
if (secondary && (offset != hdr_size)) {
log_dbg(cd, "LUKS2 offset 0x%04" PRIx64 " in secondary header does not match size 0x%04" PRIx64 ".",
offset, hdr_size);
return -EINVAL;
}
/* FIXME: sanity check checksum alg. */
log_dbg(cd, "LUKS2 header version %u of size %u bytes, checksum %s.",
(unsigned)be16_to_cpu(hdr->version), (unsigned)be64_to_cpu(hdr->hdr_size),
log_dbg(cd, "LUKS2 header version %u of size %" PRIu64 " bytes, checksum %s.",
be16_to_cpu(hdr->version), hdr_size,
hdr->checksum_alg);
*hdr_json_size = be64_to_cpu(hdr->hdr_size) - LUKS2_HDR_BIN_LEN;
*hdr_json_size = hdr_size - LUKS2_HDR_BIN_LEN;
return 0;
}
@@ -252,18 +261,19 @@ static int hdr_read_disk(struct crypt_device *cd,
return -EIO;
}
/*
* hdr_json_size is validated if this call succeeds
*/
r = hdr_disk_sanity_check_pre(cd, hdr_disk, &hdr_json_size, secondary, offset);
if (r < 0) {
if (r < 0)
return r;
}
/*
* Allocate and read JSON area. Always the whole area must be read.
*/
*json_area = malloc(hdr_json_size);
if (!*json_area) {
if (!*json_area)
return -ENOMEM;
}
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
device_alignment(device), *json_area, hdr_json_size,
@@ -279,6 +289,8 @@ static int hdr_read_disk(struct crypt_device *cd,
if (hdr_checksum_check(cd, hdr_disk->checksum_alg, hdr_disk,
*json_area, hdr_json_size)) {
log_dbg(cd, "LUKS2 header checksum error (offset %" PRIu64 ").", offset);
free(*json_area);
*json_area = NULL;
r = -EINVAL;
}
memset(hdr_disk->csum, 0, LUKS2_CHECKSUM_L);

View File

@@ -234,14 +234,20 @@ int LUKS2_keyslot_reencrypt_store(struct crypt_device *cd,
const void *buffer,
size_t buffer_length);
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);
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);
@@ -257,6 +263,8 @@ uint64_t json_segments_get_minimal_offset(json_object *jobj_segments, unsigned b
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,

View File

@@ -592,6 +592,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;
@@ -718,7 +790,7 @@ 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);
}
static uint64_t LUKS2_metadata_size_jobj(json_object *jobj)
@@ -841,9 +913,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;
@@ -898,6 +971,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))
@@ -923,6 +1009,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 },
@@ -1139,21 +1226,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)
{
@@ -1389,24 +1461,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;
}
/*
@@ -1416,7 +1570,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)
@@ -1443,8 +1597,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;
@@ -1454,6 +1608,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;
@@ -1463,8 +1619,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;

View File

@@ -27,7 +27,9 @@ extern const keyslot_handler reenc_keyslot;
static const keyslot_handler *keyslot_handlers[LUKS2_KEYSLOTS_MAX] = {
&luks2_keyslot,
#if USE_LUKS2_REENCRYPTION
&reenc_keyslot,
#endif
NULL
};
@@ -288,19 +290,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;
@@ -316,6 +308,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,
@@ -596,7 +605,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)
@@ -625,9 +634,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;
}
@@ -878,10 +884,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);
@@ -897,6 +910,24 @@ int LUKS2_keyslots_validate(struct crypt_device *cd, json_object *hdr_jobj)
log_dbg(cd, "Keyslot %d is not assigned to exactly 1 digest.", keyslot);
return -EINVAL;
}
if (!strcmp(h->name, "reencrypt"))
reencrypt_count++;
}
if ((reqs & CRYPT_REQUIREMENT_ONLINE_REENCRYPT) && reencrypt_count == 0) {
log_dbg(cd, "Missing reencryption keyslot.");
return -EINVAL;
}
if (!(reqs & CRYPT_REQUIREMENT_ONLINE_REENCRYPT) && reencrypt_count) {
log_dbg(cd, "Missing reencryption requirement flag.");
return -EINVAL;
}
if (reencrypt_count > 1) {
log_dbg(cd, "Too many reencryption keyslots.");
return -EINVAL;
}
return 0;

View File

@@ -248,6 +248,7 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
/*
* Calculate keyslot content, split and store it to keyslot area.
*/
log_dbg(cd, "Running keyslot key derivation.");
r = crypt_pbkdf(pbkdf.type, pbkdf.hash, password, passwordLen,
salt, LUKS_SALTSIZE,
derived_key->key, derived_key->keylength,
@@ -269,7 +270,7 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
r = AF_split(cd, volume_key, AfKey, volume_key_len, LUKS_STRIPES, af_hash);
if (r == 0) {
log_dbg(cd, "Updating keyslot area [0x%04x].", (unsigned)area_offset);
log_dbg(cd, "Updating keyslot area [0x%04" PRIx64 "].", area_offset);
/* FIXME: sector_offset should be size_t, fix LUKS_encrypt... accordingly */
r = luks2_encrypt_to_storage(AfKey, AFEKSize, cipher, cipher_mode,
derived_key, (unsigned)(area_offset / SECTOR_SIZE), cd);
@@ -350,6 +351,7 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
/*
* Calculate derived key, decrypt keyslot content and merge it.
*/
log_dbg(cd, "Running keyslot key derivation.");
r = crypt_pbkdf(pbkdf.type, pbkdf.hash, password, passwordLen,
salt, LUKS_SALTSIZE,
derived_key->key, derived_key->keylength,
@@ -360,7 +362,7 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
crypt_serialize_unlock(cd);
if (r == 0) {
log_dbg(cd, "Reading keyslot area [0x%04x].", (unsigned)area_offset);
log_dbg(cd, "Reading keyslot area [0x%04" PRIx64 "].", area_offset);
/* FIXME: sector_offset should be size_t, fix LUKS_decrypt... accordingly */
r = luks2_decrypt_from_storage(AfKey, AFEKSize, cipher, cipher_mode,
derived_key, (unsigned)(area_offset / SECTOR_SIZE), cd);

View File

@@ -176,9 +176,17 @@ static int reenc_keyslot_store(struct crypt_device *cd,
return r < 0 ? r : keyslot;
}
static int reenc_keyslot_wipe(struct crypt_device *cd __attribute__((unused)),
int keyslot __attribute__((unused)))
static int reenc_keyslot_wipe(struct crypt_device *cd,
int keyslot)
{
struct luks2_hdr *hdr;
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
return -EINVAL;
/* remove reencryption verification data */
LUKS2_digest_assign(cd, hdr, keyslot, CRYPT_ANY_DIGEST, 0, 0);
return 0;
}
@@ -222,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;
@@ -242,12 +250,18 @@ static int reenc_keyslot_validate(struct crypt_device *cd, json_object *jobj_key
!json_object_object_get_ex(jobj_area, "type", &jobj_type))
return -EINVAL;
jobj_key_size = json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "key_size", json_type_int);
jobj_mode = json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "mode", json_type_string);
jobj_direction = json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "direction", json_type_string);
if (!jobj_mode || !jobj_direction)
if (!jobj_mode || !jobj_direction || !jobj_key_size)
return -EINVAL;
if (!validate_json_uint32(jobj_key_size) || crypt_jobj_get_uint32(jobj_key_size) != 1) {
log_dbg(cd, "Illegal reencrypt key size.");
return -EINVAL;
}
mode = json_object_get_string(jobj_mode);
type = json_object_get_string(jobj_type);
direction = json_object_get_string(jobj_direction);

View File

@@ -91,10 +91,11 @@ struct luks2_reencrypt {
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;
@@ -124,7 +125,11 @@ static int reencrypt_keyslot_update(struct crypt_device *cd,
} else
log_dbg(cd, "No update of reencrypt keyslot needed.");
return 0;
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)
@@ -190,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");
@@ -249,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;
@@ -661,7 +666,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;
@@ -767,7 +772,7 @@ void LUKS2_reencrypt_free(struct crypt_device *cd, struct luks2_reencrypt *rh)
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)
{
@@ -825,7 +830,7 @@ static int reencrypt_offset_backward_moved(struct luks2_hdr *hdr, json_object *j
linear_length += LUKS2_segment_size(hdr, sg, 0);
/* all active linear segments length */
if (linear_length) {
if (linear_length && segs > 1) {
if (linear_length < data_shift)
return -EINVAL;
tmp = linear_length - data_shift;
@@ -1020,7 +1025,7 @@ static int reencrypt_context_init(struct crypt_device *cd, struct luks2_hdr *hdr
}
if (crypt_hash_init(&rh->rp.p.csum.ch, params->hash)) {
log_dbg(cd, "Failed to initialize checksum resilience hash %s", params->hash);
log_err(cd, _("Hash algorithm %s not supported."), params->hash);
return -EINVAL;
}
@@ -1745,7 +1750,8 @@ static int reencrypt_set_encrypt_segments(struct crypt_device *cd, struct luks2_
int r;
uint64_t first_segment_offset, first_segment_length,
second_segment_offset, second_segment_length,
data_offset = LUKS2_get_data_offset(hdr) << SECTOR_SHIFT;
data_offset = LUKS2_get_data_offset(hdr) << SECTOR_SHIFT,
data_size = dev_size - data_shift;
json_object *jobj_segment_first = NULL, *jobj_segment_second = NULL, *jobj_segments;
if (dev_size < data_shift)
@@ -1760,9 +1766,14 @@ static int reencrypt_set_encrypt_segments(struct crypt_device *cd, struct luks2_
* [future LUKS2 header (data shift size)][second data segment][gap (data shift size)][first data segment (data shift size)]
*/
first_segment_offset = dev_size;
first_segment_length = data_shift;
second_segment_offset = data_shift;
second_segment_length = dev_size - 2 * data_shift;
if (data_size < data_shift) {
first_segment_length = data_size;
second_segment_length = second_segment_offset = 0;
} else {
first_segment_length = data_shift;
second_segment_offset = data_shift;
second_segment_length = data_size - data_shift;
}
} else if (data_shift) {
first_segment_offset = data_offset;
first_segment_length = dev_size;
@@ -1834,6 +1845,9 @@ static int reencrypt_make_targets(struct crypt_device *cd,
return -EINVAL;
}
if (reenc_seg)
segment_offset -= crypt_get_data_offset(cd);
if (!strcmp(json_segment_type(jobj), "crypt")) {
vk = crypt_volume_key_by_id(vks, reenc_seg ? LUKS2_reencrypt_digest_new(hdr) : LUKS2_digest_by_segment(hdr, s));
if (!vk) {
@@ -1841,9 +1855,6 @@ static int reencrypt_make_targets(struct crypt_device *cd,
return -EINVAL;
}
if (reenc_seg)
segment_offset -= crypt_get_data_offset(cd);
r = dm_crypt_target_set(result, segment_start, segment_size,
reenc_seg ? hz_device : crypt_data_device(cd),
vk,
@@ -2163,17 +2174,10 @@ static int reencrypt_move_data(struct crypt_device *cd, int devfd, uint64_t data
log_dbg(cd, "Going to move data from head of data device.");
buffer_len = data_shift;
if (!buffer_len)
return -EINVAL;
offset = json_segment_get_offset(LUKS2_get_segment_jobj(hdr, 0), 0);
/* this is nonsense anyway */
if (buffer_len != json_segment_get_size(LUKS2_get_segment_jobj(hdr, 0), 0)) {
log_dbg(cd, "buffer_len %" PRIu64", segment size %" PRIu64, buffer_len, json_segment_get_size(LUKS2_get_segment_jobj(hdr, 0), 0));
buffer_len = json_segment_get_size(LUKS2_get_segment_jobj(hdr, 0), 0);
if (!buffer_len || buffer_len > data_shift)
return -EINVAL;
}
if (posix_memalign(&buffer, device_alignment(crypt_data_device(cd)), buffer_len))
return -ENOMEM;
@@ -2249,7 +2253,11 @@ static int reencrypt_make_backup_segments(struct crypt_device *cd,
r = LUKS2_get_data_size(hdr, &tmp, NULL);
if (r)
goto err;
jobj_segment_old = json_segment_create_linear(0, tmp ? &tmp : NULL, 0);
if (params->flags & CRYPT_REENCRYPT_MOVE_FIRST_SEGMENT)
jobj_segment_old = json_segment_create_linear(0, tmp ? &tmp : NULL, 0);
else
jobj_segment_old = json_segment_create_linear(data_offset, tmp ? &tmp : NULL, 0);
}
if (!jobj_segment_old) {
@@ -2443,7 +2451,7 @@ static int reencrypt_init(struct crypt_device *cd,
* encryption initialization (or mount)
*/
if (move_first_segment) {
if (dev_size < 2 * (params->data_shift << SECTOR_SHIFT)) {
if (dev_size < (params->data_shift << SECTOR_SHIFT)) {
log_err(cd, _("Device %s is too small."), device_path(crypt_data_device(cd)));
return -EINVAL;
}
@@ -2466,7 +2474,7 @@ static int reencrypt_init(struct crypt_device *cd,
goto out;
}
r = LUKS2_keyslot_reencrypt_create(cd, hdr, reencrypt_keyslot,
r = LUKS2_keyslot_reencrypt_allocate(cd, hdr, reencrypt_keyslot,
params);
if (r < 0)
goto out;
@@ -2481,6 +2489,10 @@ static int reencrypt_init(struct crypt_device *cd,
if (r < 0)
goto out;
r = LUKS2_keyslot_reencrypt_digest_create(cd, hdr, *vks);
if (r < 0)
goto out;
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)
@@ -2611,20 +2623,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 volume_key *vks,
struct luks2_reencrypt **rh)
{
int r;
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) {
@@ -2636,7 +2656,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;
@@ -2698,7 +2718,7 @@ void LUKS2_reencrypt_unlock(struct crypt_device *cd, struct crypt_lock_handle *r
{
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)
{
@@ -2873,7 +2893,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;
@@ -2968,6 +2988,85 @@ static int reencrypt_recovery_by_passphrase(struct crypt_device *cd,
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,
@@ -2978,12 +3077,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);
@@ -3033,6 +3137,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,
@@ -3085,6 +3193,7 @@ 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_reencrypt *rh,
@@ -3093,13 +3202,6 @@ static reenc_status_t reencrypt_step(struct crypt_device *cd,
{
int r;
/* update reencrypt keyslot protection parameters in memory only */
r = reencrypt_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)
@@ -3269,15 +3371,20 @@ 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;
@@ -3289,7 +3396,7 @@ static void reencrypt_teardown_fatal(struct crypt_device *cd, struct luks2_reenc
(rh->offset >> SECTOR_SHIFT) + crypt_get_data_offset(cd), rh->length >> SECTOR_SHIFT);
if (rh->online) {
log_err(cd, "Reencryption was run in online mode.");
log_err(cd, _("Online reencryption failed."));
if (dm_status_suspended(cd, rh->hotzone_name) > 0) {
log_dbg(cd, "Hotzone device %s suspended, replacing with dm-error.", rh->hotzone_name);
if (dm_error_device(cd, rh->hotzone_name)) {
@@ -3326,12 +3433,14 @@ static int reencrypt_teardown(struct crypt_device *cd, struct luks2_hdr *hdr,
return r;
}
#endif
int crypt_reencrypt_run(
struct crypt_device *cd,
int (*progress)(uint64_t size, uint64_t offset, void *usrptr),
void *usrptr)
{
#if USE_LUKS2_REENCRYPTION
int r;
crypt_reencrypt_info ri;
struct luks2_hdr *hdr;
@@ -3367,6 +3476,15 @@ int crypt_reencrypt_run(
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, usrptr);
}
}
while (!quit && (rh->device_size > rh->progress)) {
rs = reencrypt_step(cd, hdr, rh, rh->device_size, rh->online);
if (rs != REENC_OK)
@@ -3389,6 +3507,10 @@ int crypt_reencrypt_run(
r = reencrypt_teardown(cd, hdr, rh, rs, quit, progress, usrptr);
return r;
#else
log_err(cd, _("This operation is not supported for this device type."));
return -ENOTSUP;
#endif
}
int crypt_reencrypt(
@@ -3397,7 +3519,7 @@ int crypt_reencrypt(
{
return crypt_reencrypt_run(cd, progress, NULL);
}
#if USE_LUKS2_REENCRYPTION
static int reencrypt_recovery(struct crypt_device *cd,
struct luks2_hdr *hdr,
uint64_t device_size,
@@ -3406,7 +3528,7 @@ static int reencrypt_recovery(struct crypt_device *cd,
int r;
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;
@@ -3433,7 +3555,7 @@ out:
return r;
}
#endif
/*
* use only for calculation of minimal data device size.
* The real data offset is taken directly from segments!
@@ -3475,12 +3597,12 @@ int LUKS2_reencrypt_check_device_size(struct crypt_device *cd, struct luks2_hdr
return r;
log_dbg(cd, "Required minimal device size: %" PRIu64 " (%" PRIu64 " sectors)"
", real device size: %" PRIu64 " (%" PRIu64 " sectors)\n"
", real device size: %" PRIu64 " (%" PRIu64 " sectors) "
"calculated device size: %" PRIu64 " (%" PRIu64 " sectors)",
check_size, check_size >> SECTOR_SHIFT, real_size, real_size >> SECTOR_SHIFT,
real_size - data_offset, (real_size - data_offset) >> SECTOR_SHIFT);
if (real_size < data_offset || (check_size && (real_size - data_offset) < check_size)) {
if (real_size < data_offset || (check_size && real_size < check_size)) {
log_err(cd, _("Device %s is too small."), device_path(crypt_data_device(cd)));
return -EINVAL;
}
@@ -3489,7 +3611,7 @@ int LUKS2_reencrypt_check_device_size(struct crypt_device *cd, struct luks2_hdr
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,
@@ -3539,16 +3661,32 @@ out:
return r < 0 ? r : keyslot;
}
#endif
crypt_reencrypt_info LUKS2_reencrypt_get_params(struct luks2_hdr *hdr,
struct crypt_params_reencrypt *params)
{
crypt_reencrypt_info ri;
int digest;
uint32_t version;
ri = LUKS2_reencrypt_status(hdr);
if (ri == CRYPT_REENCRYPT_NONE || ri == CRYPT_REENCRYPT_INVALID || !params)
return ri;
digest = LUKS2_digest_by_keyslot(hdr, LUKS2_find_keyslot(hdr, "reencrypt"));
if (digest < 0 && digest != -ENOENT)
return CRYPT_REENCRYPT_INVALID;
/*
* In case there's an old "online-reencrypt" requirement or reencryption
* keyslot digest is missing inform caller reencryption metadata requires repair.
*/
if (!LUKS2_config_get_reencrypt_version(hdr, &version) &&
(version < 2 || digest == -ENOENT)) {
params->flags |= CRYPT_REENCRYPT_REPAIR_NEEDED;
return ri;
}
params->mode = reencrypt_mode(hdr);
params->direction = reencrypt_direction(hdr);
params->resilience = reencrypt_resilience_type(hdr);

View File

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

View File

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

View File

@@ -63,9 +63,13 @@ static void *token_dlvsym(struct crypt_device *cd,
char *error;
void *sym;
#ifdef HAVE_DLVSYM
log_dbg(cd, "Loading symbol %s@%s.", symbol, version);
sym = dlvsym(handle, symbol, version);
#else
log_dbg(cd, "Loading default version of symbol %s.", symbol);
sym = dlsym(handle, symbol);
#endif
error = dlerror();
if (error)
@@ -182,7 +186,7 @@ crypt_token_load_external(struct crypt_device *cd, const char *name, struct cryp
if (r < 0 || (size_t)r >= sizeof(buf))
*buf = '\0';
log_dbg(cd, "Token handler %s-%s loaded sucessfuly.", token->name, buf);
log_dbg(cd, "Token handler %s-%s loaded successfully.", token->name, buf);
token->dlhandle = h;
ret->version = 2;
@@ -241,6 +245,7 @@ int crypt_token_register(const crypt_token_handler *handler)
void crypt_token_unload_external_all(struct crypt_device *cd)
{
#if USE_EXTERNAL_TOKENS
int i;
for (i = LUKS2_TOKENS_MAX - 1; i >= 0; i--) {
@@ -254,6 +259,7 @@ void crypt_token_unload_external_all(struct crypt_device *cd)
if (dlclose(CONST_CAST(void *)token_handlers[i].u.v2.dlhandle))
log_dbg(cd, "%s", dlerror());
}
#endif
}
static const void

View File

@@ -227,7 +227,7 @@ int init_crypto(struct crypt_device *ctx)
return r;
}
r = crypt_backend_init();
r = crypt_backend_init(crypt_fips_mode());
if (r < 0)
log_err(ctx, _("Cannot initialize crypto backend."));
@@ -1840,7 +1840,7 @@ static int _crypt_format_luks2(struct crypt_device *cd,
if (sector_size_autodetect) {
if (cd->data_offset && MISALIGNED(cd->data_offset, sector_size)) {
log_dbg(cd, "Data offset not alligned to sector size. Reverting to 512 bytes.");
log_dbg(cd, "Data offset not aligned to sector size. Reverting to 512 bytes.");
sector_size = SECTOR_SIZE;
} else if (MISALIGNED(dev_size - (uint64_t)required_alignment - (uint64_t)alignment_offset, sector_size)) {
/* underflow does not affect misalignment checks */
@@ -3955,21 +3955,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);
@@ -4017,6 +4002,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,
@@ -4131,6 +4132,12 @@ 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 out;
}
log_dbg(cd, "Entering clean reencryption state mode.");
if (r >= 0)
@@ -4158,8 +4165,9 @@ 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_reencrypt_status(hdr);
if (ri == CRYPT_REENCRYPT_INVALID)
@@ -4169,15 +4177,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,

View File

@@ -505,11 +505,11 @@ int device_locked_verify(struct crypt_device *cd, int dev_fd, struct crypt_lock_
/* if device handle is regular file the handle must match the lock handle */
if (S_ISREG(dev_st.st_mode)) {
log_dbg(cd, "Veryfing locked device handle (regular file)");
log_dbg(cd, "Verifying locked device handle (regular file)");
if (!same_inode(dev_st, lck_st))
return 1;
} else if (S_ISBLK(dev_st.st_mode)) {
log_dbg(cd, "Veryfing locked device handle (bdev)");
log_dbg(cd, "Verifying locked device handle (bdev)");
if (resource_by_devno(res, sizeof(res), dev_st.st_rdev, 1) ||
stat(res, &st) ||
!same_inode(lck_st, st))

View File

@@ -24,9 +24,12 @@
#include "utils_fips.h"
#if !ENABLE_FIPS
int crypt_fips_mode(void) { return 0; }
bool crypt_fips_mode(void) { return false; }
#else
static int kernel_fips_mode(void)
static bool fips_checked = false;
static bool fips_mode = false;
static bool kernel_fips_mode(void)
{
int fd;
char buf[1] = "";
@@ -36,11 +39,17 @@ static int kernel_fips_mode(void)
close(fd);
}
return (buf[0] == '1') ? 1 : 0;
return (buf[0] == '1');
}
int crypt_fips_mode(void)
bool crypt_fips_mode(void)
{
return kernel_fips_mode() && !access("/etc/system-fips", F_OK);
if (fips_checked)
return fips_mode;
fips_mode = kernel_fips_mode() && !access("/etc/system-fips", F_OK);
fips_checked = true;
return fips_mode;
}
#endif /* ENABLE_FIPS */

View File

@@ -21,6 +21,8 @@
#ifndef _UTILS_FIPS_H
#define _UTILS_FIPS_H
int crypt_fips_mode(void);
#include <stdbool.h>
bool crypt_fips_mode(void);
#endif /* _UTILS_FIPS_H */

View File

@@ -830,6 +830,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
@@ -1568,7 +1575,7 @@ sudo cryptsetup luksAddKey --key-slot 5 /dev/sdX
Example 3: Create LUKS header backup and save it to file.
sudo cryptsetup luksHeaderBackup /dev/sdX --header-backup-file /var/tmp/NameOfBackupFile
.TP
Example 4: Open LUKS contaner on /dev/sdX and map it to sdX_crypt.
Example 4: Open LUKS container on /dev/sdX and map it to sdX_crypt.
sudo cryptsetup open /dev/sdX sdX_crypt
.TP
.B WARNING: The command in example 5 will erase all key slots.

View File

@@ -6,6 +6,7 @@ Version: 2.4.0
Release: 1%{?dist}
License: GPLv2+ and LGPLv2+
URL: https://gitlab.com/cryptsetup/cryptsetup
BuildRequires: autoconf, automake, libtool, gettext-devel,
BuildRequires: openssl-devel, popt-devel, device-mapper-devel
BuildRequires: libuuid-devel, gcc, json-c-devel, libargon2-devel
BuildRequires: libpwquality-devel, libblkid-devel
@@ -13,10 +14,8 @@ BuildRequires: make libssh-devel
Requires: cryptsetup-libs = %{version}-%{release}
Requires: libpwquality >= 1.2.0
%global upstream_version %{version}-git
%global upstream_version %{version_no_tilde}
Source0: https://www.kernel.org/pub/linux/utils/cryptsetup/v2.4/cryptsetup-%{upstream_version}.tar.xz
# Following patch has to applied last
#Patch9999: %{name}-add-system-library-paths.patch
%description
The cryptsetup package contains a utility for setting up
@@ -72,12 +71,12 @@ can be used for offline reencryption of disk in situ.
%autosetup -n cryptsetup-%{upstream_version} -p 1
%build
./autogen.sh
%configure --enable-fips --enable-pwquality --enable-libargon2
%make_build
%install
%make_install
mkdir -p -m 0755 $RPM_BUILD_ROOT%{_libdir}/%{name}/
rm -rf %{buildroot}%{_libdir}/*.la
rm -rf %{buildroot}%{_libdir}/%{name}/*.la

View File

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

File diff suppressed because it is too large Load Diff

1176
po/cs.po

File diff suppressed because it is too large Load Diff

1136
po/de.po

File diff suppressed because it is too large Load Diff

1179
po/es.po

File diff suppressed because it is too large Load Diff

1171
po/fr.po

File diff suppressed because it is too large Load Diff

1149
po/ja.po

File diff suppressed because it is too large Load Diff

1147
po/pl.po

File diff suppressed because it is too large Load Diff

1178
po/ru.po

File diff suppressed because it is too large Load Diff

1167
po/sr.po

File diff suppressed because it is too large Load Diff

3677
po/sv.po

File diff suppressed because it is too large Load Diff

1195
po/uk.po

File diff suppressed because it is too large Load Diff

View File

@@ -52,7 +52,6 @@ veritysetup_SOURCES = \
src/utils_arg_names.h \
src/utils_arg_macros.h \
src/utils_tools.c \
src/utils_password.c \
src/veritysetup.c \
src/veritysetup_args.h \
src/veritysetup_arg_list.h \
@@ -61,8 +60,6 @@ veritysetup_SOURCES = \
veritysetup_LDADD = $(LDADD) \
libcryptsetup.la \
@POPT_LIBS@ \
@PWQUALITY_LIBS@ \
@PASSWDQC_LIBS@ \
@BLKID_LIBS@
sbin_PROGRAMS += veritysetup
@@ -74,8 +71,7 @@ veritysetup_static_LDFLAGS = $(AM_LDFLAGS) -all-static
veritysetup_static_LDADD = \
$(veritysetup_LDADD) \
@CRYPTO_STATIC_LIBS@ \
@DEVMAPPER_STATIC_LIBS@ \
@UUID_LIBS@
@DEVMAPPER_STATIC_LIBS@
endif
endif
@@ -91,7 +87,6 @@ integritysetup_SOURCES = \
src/utils_arg_names.h \
src/utils_arg_macros.h \
src/utils_tools.c \
src/utils_password.c \
src/utils_blockdev.c \
src/integritysetup.c \
src/integritysetup_args.h \
@@ -101,8 +96,6 @@ integritysetup_SOURCES = \
integritysetup_LDADD = $(LDADD) \
libcryptsetup.la \
@POPT_LIBS@ \
@PWQUALITY_LIBS@ \
@PASSWDQC_LIBS@ \
@UUID_LIBS@ \
@BLKID_LIBS@
@@ -115,8 +108,7 @@ integritysetup_static_LDFLAGS = $(AM_LDFLAGS) -all-static
integritysetup_static_LDADD = \
$(integritysetup_LDADD) \
@CRYPTO_STATIC_LIBS@ \
@DEVMAPPER_STATIC_LIBS@ \
@UUID_LIBS@
@DEVMAPPER_STATIC_LIBS@
endif
endif

View File

@@ -1172,24 +1172,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 (!ARG_SET(OPT_BATCH_MODE_ID) &&
!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, ARG_UINT64(OPT_KEYFILE_OFFSET_ID),
ARG_UINT32(OPT_KEYFILE_SIZE_ID), ARG_STR(OPT_KEY_FILE_ID), ARG_UINT32(OPT_TIMEOUT_ID),
_verify_passphrase(0), 0, cd);
if (r < 0)
return r;
r = crypt_reencrypt_init_by_passphrase(cd, NULL, password, passwordLen,
ARG_INT32(OPT_KEY_SLOT_ID), ARG_INT32(OPT_KEY_SLOT_ID), NULL, NULL, &params);
tools_passphrase_msg(r);
if (r < 0)
goto out;
r = crypt_activate_by_passphrase(cd, NULL, ARG_INT32(OPT_KEY_SLOT_ID),
password, passwordLen, 0);
tools_passphrase_msg(r);
if (r >= 0)
r = 0;
out:
crypt_safe_free(password);
return r;
}
static int luks2_reencrypt_repair(struct crypt_device *cd)
{
int r;
size_t passwordLen;
const char *msg;
char *password = NULL;
struct crypt_params_reencrypt recovery_params = {
.flags = CRYPT_REENCRYPT_RECOVERY
};
struct crypt_params_reencrypt params = {};
crypt_reencrypt_info ri = crypt_reencrypt_status(cd, &params);
if (params.flags & CRYPT_REENCRYPT_REPAIR_NEEDED)
return reencrypt_metadata_repair(cd);
crypt_reencrypt_info ri = crypt_reencrypt_status(cd, NULL);
switch (ri) {
case CRYPT_REENCRYPT_NONE:
/* fall through */
return 0;
case CRYPT_REENCRYPT_CLEAN:
if (ARG_SET(OPT_BATCH_MODE_ID) ||
!noDialog(_("Seems device does not require reencryption recovery.\n"
"Do you want to proceed anyway?"), NULL))
return 0;
break;
case CRYPT_REENCRYPT_CRASH:
if (!ARG_SET(OPT_BATCH_MODE_ID) &&
@@ -1201,8 +1240,12 @@ static int _do_luks2_reencrypt_recovery(struct crypt_device *cd)
return -EINVAL;
}
r = tools_get_key(_("Enter passphrase for reencryption recovery: "),
&password, &passwordLen, ARG_UINT64(OPT_KEYFILE_OFFSET_ID),
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, ARG_UINT64(OPT_KEYFILE_OFFSET_ID),
ARG_UINT32(OPT_KEYFILE_SIZE_ID), ARG_STR(OPT_KEY_FILE_ID), ARG_UINT32(OPT_TIMEOUT_ID),
_verify_passphrase(0), 0, cd);
if (r < 0)
@@ -1213,8 +1256,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,
ARG_INT32(OPT_KEY_SLOT_ID), ARG_INT32(OPT_KEY_SLOT_ID), NULL, NULL, &recovery_params);
ARG_INT32(OPT_KEY_SLOT_ID), ARG_INT32(OPT_KEY_SLOT_ID), NULL, NULL,
&(struct crypt_params_reencrypt){ .flags = CRYPT_REENCRYPT_RECOVERY });
if (r > 0)
r = 0;
out:
@@ -1235,7 +1284,11 @@ static int action_luksRepair(void)
crypt_set_log_callback(cd, quiet_log, &log_parms);
r = crypt_load(cd, luksType(device_type), NULL);
crypt_set_log_callback(cd, tool_log, &log_parms);
if (r == 0) {
if (r == 0 && isLUKS2(crypt_get_type(cd))) {
/*
* LUKS2 triggers autorepair in crypt_load() above
* LUKS1 need to call crypt_repair() even if crypt_load() is ok
*/
log_verbose(_("No known problems detected for LUKS header."));
goto out;
}
@@ -1251,9 +1304,9 @@ static int action_luksRepair(void)
else
r = crypt_repair(cd, luksType(device_type), NULL);
out:
/* Header is ok, check if possible interrupted reencryption need repairs. */
/* Header is ok, check if reencryption metadata needs repair/recovery. */
if (!r && isLUKS2(crypt_get_type(cd)))
r = _do_luks2_reencrypt_recovery(cd);
r = luks2_reencrypt_repair(cd);
crypt_free(cd);
return r;
@@ -2624,6 +2677,11 @@ static int _token_add(struct crypt_device *cd)
}
}
if (crypt_keyslot_status(cd, ARG_INT32(OPT_KEY_SLOT_ID)) == CRYPT_SLOT_INACTIVE) {
log_err(_("Keyslot %d is not active."), ARG_INT32(OPT_KEY_SLOT_ID));
return -EINVAL;
}
r = crypt_token_luks2_keyring_set(cd, ARG_INT32(OPT_TOKEN_ID_ID), &params);
if (r < 0) {
log_err(_("Failed to add luks2-keyring token %d."), ARG_INT32(OPT_TOKEN_ID_ID));
@@ -2676,6 +2734,11 @@ static int _token_import(struct crypt_device *cd)
}
}
if (crypt_keyslot_status(cd, ARG_INT32(OPT_KEY_SLOT_ID)) == CRYPT_SLOT_INACTIVE) {
log_err(_("Keyslot %d is not active."), ARG_INT32(OPT_KEY_SLOT_ID));
return -EINVAL;
}
r = tools_read_json_file(ARG_STR(OPT_JSON_FILE_ID), &json, &json_length, ARG_SET(OPT_BATCH_MODE_ID));
if (r)
return r;
@@ -2958,7 +3021,7 @@ static int action_encrypt_luks2(struct crypt_device **cd)
if (!ARG_SET(OPT_LUKS2_KEYSLOTS_SIZE_ID))
ARG_SET_UINT64(OPT_LUKS2_KEYSLOTS_SIZE_ID, -data_shift - 2 * ARG_UINT64(OPT_LUKS2_METADATA_SIZE_ID));
if (2 * ARG_UINT64(OPT_LUKS2_METADATA_SIZE_ID) + ARG_UINT64(OPT_LUKS2_KEYSLOTS_SIZE_ID) > (uint64_t)-data_shift) {
log_err("LUKS2 metadata size is larger than data shift value.");
log_err(_("LUKS2 metadata size is larger than data shift value."));
return -EINVAL;
}
}
@@ -2990,7 +3053,7 @@ static int action_encrypt_luks2(struct crypt_device **cd)
r = crypt_header_restore(*cd, CRYPT_LUKS2, header_file);
if (r) {
log_err("Failed to place new header at head of device %s.", action_argv[0]);
log_err(_("Failed to place new header at head of device %s."), action_argv[0]);
goto out;
}
}
@@ -3036,8 +3099,9 @@ static int action_decrypt_luks2(struct crypt_device *cd)
};
size_t passwordLen;
if (!crypt_get_metadata_device_name(cd) || crypt_header_is_detached(cd) <= 0) {
log_err(_("LUKS2 decryption is supported with detached header device only."));
if (!crypt_get_metadata_device_name(cd) || crypt_header_is_detached(cd) <= 0 ||
crypt_get_data_offset(cd) > 0) {
log_err(_("LUKS2 decryption is supported with detached header device only (with data offset set to 0)."));
return -ENOTSUP;
}

View File

@@ -350,7 +350,7 @@ static int parse_log(struct reenc_ctx *rc)
if (end) {
*end++ = '\0';
if (parse_line_log(rc, start)) {
log_err("Wrong log format.");
log_err(_("Wrong log format."));
return -EINVAL;
}
}

View File

@@ -291,10 +291,10 @@ int tools_wipe_all_signatures(const char *path)
while ((pr = blk_probe(h)) < PRB_EMPTY) {
if (blk_is_partition(h))
log_verbose("Existing '%s' partition signature on device %s will be wiped.",
log_verbose(_("Existing '%s' partition signature on device %s will be wiped."),
blk_get_partition_type(h), path);
if (blk_is_superblock(h))
log_verbose("Existing '%s' superblock signature on device %s will be wiped.",
log_verbose(_("Existing '%s' superblock signature on device %s will be wiped."),
blk_get_superblock_type(h), path);
if (blk_do_wipe(h)) {
log_err(_("Failed to wipe device signature."));

View File

@@ -318,59 +318,3 @@ void tools_passphrase_msg(int r)
else if (r == -ENOENT)
log_err(_("No usable keyslot is available."));
}
int tools_read_mk(const char *file, char **key, int keysize)
{
int fd = -1, r = -EINVAL;
if (keysize <= 0 || !key)
return -EINVAL;
*key = crypt_safe_alloc(keysize);
if (!*key)
return -ENOMEM;
fd = open(file, O_RDONLY);
if (fd == -1) {
log_err(_("Cannot read keyfile %s."), file);
goto out;
}
if (read_buffer(fd, *key, keysize) != keysize) {
log_err(_("Cannot read %d bytes from keyfile %s."), keysize, file);
goto out;
}
r = 0;
out:
if (fd != -1)
close(fd);
if (r) {
crypt_safe_free(*key);
*key = NULL;
}
return r;
}
int tools_write_mk(const char *file, const char *key, int keysize)
{
int fd, r = -EINVAL;
if (keysize <= 0 || !key)
return -EINVAL;
fd = open(file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR);
if (fd < 0) {
log_err(_("Cannot open keyfile %s for write."), file);
return r;
}
if (write_buffer(fd, key, keysize) == keysize)
r = 0;
else
log_err(_("Cannot write to keyfile %s."), file);
close(fd);
return r;
}

View File

@@ -116,8 +116,9 @@ static int _dialog(const char *msg, void *usrptr, int default_answer)
set_int_block(0);
if (isatty(STDIN_FILENO)) {
log_std("\nWARNING!\n========\n");
log_std("%s\n\nAre you sure? (Type 'yes' in capital letters): ", msg);
log_std(_("\nWARNING!\n========\n"));
/* TRANSLATORS: User must type "YES" (in capital letters), do not translate this word. */
log_std(_("%s\n\nAre you sure? (Type 'yes' in capital letters): "), msg);
fflush(stdout);
if(getline(&answer, &size, stdin) == -1) {
r = 0;
@@ -493,3 +494,59 @@ int tools_reencrypt_progress(uint64_t size, uint64_t offset, void *usrptr)
return r;
}
int tools_read_mk(const char *file, char **key, int keysize)
{
int fd = -1, r = -EINVAL;
if (keysize <= 0 || !key)
return -EINVAL;
*key = crypt_safe_alloc(keysize);
if (!*key)
return -ENOMEM;
fd = open(file, O_RDONLY);
if (fd == -1) {
log_err(_("Cannot read keyfile %s."), file);
goto out;
}
if (read_buffer(fd, *key, keysize) != keysize) {
log_err(_("Cannot read %d bytes from keyfile %s."), keysize, file);
goto out;
}
r = 0;
out:
if (fd != -1)
close(fd);
if (r) {
crypt_safe_free(*key);
*key = NULL;
}
return r;
}
int tools_write_mk(const char *file, const char *key, int keysize)
{
int fd, r = -EINVAL;
if (keysize <= 0 || !key)
return -EINVAL;
fd = open(file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR);
if (fd < 0) {
log_err(_("Cannot open keyfile %s for write."), file);
return r;
}
if (write_buffer(fd, key, keysize) == keysize)
r = 0;
else
log_err(_("Cannot write to keyfile %s."), file);
close(fd);
return r;
}

View File

@@ -23,7 +23,7 @@ if [ -f /etc/os-release ] ; then
fi
echo "Memory"
free -h
free -m
pversion cryptsetup
pversion veritysetup

View File

@@ -27,7 +27,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
@@ -36,6 +36,7 @@ endif
if SSHPLUGIN_TOKEN
TESTS += ssh-plugin-test
endif
ssh-plugin-test: fake_token_path.so
@@ -44,7 +45,6 @@ fake_token_path.so:
-Wl,--version-script=$(top_srcdir)/lib/libcryptsetup.sym \
-o fake_token_path.so $(top_srcdir)/tests/fake_token_path.c \
-DBUILD_DIR=\"$(abs_top_srcdir)/.libs/\"
endif
EXTRA_DIST = compatimage.img.xz compatv10image.img.xz \
compatimage2.img.xz \
@@ -72,6 +72,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 \
@@ -95,19 +96,17 @@ CLEANFILES = cryptsetup-tst* valglog* *-fail-*.log test-symbols-list.h fake_toke
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
api_test_SOURCES = api-test.c api_test.h test_utils.c
api_test_LDADD = $(LDADD) ../libcryptsetup.la
api_test_LDADD = ../libcryptsetup.la
api_test_LDFLAGS = $(AM_LDFLAGS) -static
api_test_CFLAGS = -g -Wall -O0 $(AM_CFLAGS) -I$(top_srcdir)/lib
api_test_CPPFLAGS = $(AM_CPPFLAGS) -include config.h
api_test_2_SOURCES = api-test-2.c api_test.h test_utils.c
api_test_2_LDADD = $(LDADD) ../libcryptsetup.la
api_test_2_LDADD = ../libcryptsetup.la
api_test_2_LDFLAGS = $(AM_LDFLAGS) -static
api_test_2_CFLAGS = -g -Wall -O0 $(AM_CFLAGS) -I$(top_srcdir)/lib
api_test_2_CPPFLAGS = $(AM_CPPFLAGS) -include config.h
@@ -132,11 +131,14 @@ test-symbols-list.h: $(top_srcdir)/lib/libcryptsetup.sym generate-symbols-list
all_symbols_test_SOURCES = all-symbols-test.c
nodist_all_symbols_test_SOURCES = test-symbols-list.h
all_symbols_test.$(OBJEXT): test-symbols-list.h
all_symbols_test_CFLAGS = -ldl
all_symbols_test_LDFLAGS = $(AM_LDFLAGS) -ldl
all_symbols_test_CFLAGS = $(AM_CFLAGS)
all_symbols_test_CPPFLAGS = $(AM_CPPFLAGS) -D_GNU_SOURCE
check_PROGRAMS = api-test api-test-2 differ vectors-test unit-utils-io all-symbols-test
check-programs: $(check_PROGRAMS) fake_token_path.so
conversion_imgs:
@tar xJf conversion_imgs.tar.xz
@@ -153,6 +155,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
@VALG=1 ./tcrypt-compat-test
@grep -l "ERROR SUMMARY: [^0] errors" valglog* || echo "No leaks detected."

View File

@@ -68,34 +68,57 @@ static void test_logf(int level, const char *format, ...)
#define log_std(x...) test_logf(LOG_NORMAL, x)
#define log_err(x...) test_logf(LOG_ERROR, x)
static int check_all_symbols(void *h)
static int check_dlvsym(void *h, const char *symbol, const char *version)
{
#ifdef HAVE_DLVSYM
void *sym;
char *err;
log_dbg("Checking %s@%s...", symbol, version);
sym = dlvsym(h, symbol, version);
UNUSED(sym);
err = dlerror();
if (err) {
log_err("%s.", err);
return 1;
}
log_dbg("OK\n");
#endif
return 0;
}
static int check_dlsym(void *h, const char *symbol)
{
void *sym;
char *err;
log_dbg("Checking %s...", symbol);
sym = dlsym(h, symbol);
UNUSED(sym);
err = dlerror();
if (err) {
log_err("%s", err);
return 1;
}
log_dbg("OK\n");
return 0;
}
static int check_all_symbols(void *h)
{
unsigned scount = 0;
#define CHECK_SYMBOL(SYM, VER) \
do { \
log_dbg("Checking " #SYM "@" #VER "..."); \
sym = dlvsym(h, #SYM, #VER); \
UNUSED(sym); \
err = dlerror(); \
\
if (err) { \
log_err("%s.", err); \
return 1; \
} \
\
log_dbg("OK\nChecking " #SYM "..."); \
sym = dlsym(h, #SYM); \
UNUSED(sym); \
err = dlerror(); \
if (err) { \
log_err("%s", err); \
return 1; \
} \
log_dbg("OK\n"); \
scount++; \
#define CHECK_SYMBOL(SYM, VER) \
do { \
if (check_dlvsym(h, #SYM, #VER)) \
return 1; \
if (check_dlsym(h, #SYM)) \
return 1; \
scount++; \
} while (0);
#include "test-symbols-list.h"
@@ -106,7 +129,7 @@ do { \
return 1;
}
log_std("Performed %u symbol checks in total\n.", scount);
log_std("Performed %u symbol checks in total.\n", scount);
return 0;
}

View File

@@ -44,8 +44,6 @@ typedef int32_t key_serial_t;
#include "luks1/luks.h"
#include "libcryptsetup.h"
#define DMDIR "/dev/mapper/"
#define DEVICE_1_UUID "28632274-8c8a-493f-835b-da802e1c576b"
#define DEVICE_EMPTY_name "crypt_zero"
#define DEVICE_EMPTY DMDIR DEVICE_EMPTY_name
@@ -3807,6 +3805,7 @@ static void Luks2Flags(void)
CRYPT_FREE(cd);
}
#if KERNEL_KEYRING && USE_LUKS2_REENCRYPTION
static int test_progress(uint64_t size __attribute__((unused)),
uint64_t offset __attribute__((unused)),
void *usrptr __attribute__((unused)))
@@ -3819,7 +3818,6 @@ static int test_progress(uint64_t size __attribute__((unused)),
static void Luks2Reencryption(void)
{
/* reencryption currently depends on kernel keyring support */
#if KERNEL_KEYRING
/* NOTES:
* - reencryption requires luks2 parameters. can we avoid it?
*/
@@ -3844,6 +3842,7 @@ static void Luks2Reencryption(void)
.hash = "sha1",
.luks2 = &params2,
};
dev_t devno;
const char *mk_hex = "bb21babe733229347bd4e681891e213d94c685be6a5b84818afe7a78a6de7a1a";
size_t key_size = strlen(mk_hex) / 2;
@@ -4239,7 +4238,7 @@ static void Luks2Reencryption(void)
_cleanup_dmdevices();
OK_(create_dmdevice_over_loop(H_DEVICE, r_header_size));
OK_(create_dmdevice_over_loop(L_DEVICE_OK, 12*1024*2+1));
OK_(create_dmdevice_over_loop(L_DEVICE_OK, 8*1024*2+1));
/* encryption with datashift and moved segment (data shift + 1 sector) */
OK_(crypt_init(&cd, DMDIR H_DEVICE));
@@ -4259,11 +4258,11 @@ static void Luks2Reencryption(void)
_cleanup_dmdevices();
OK_(create_dmdevice_over_loop(H_DEVICE, r_header_size));
OK_(create_dmdevice_over_loop(L_DEVICE_OK, 12*1024*2));
OK_(create_dmdevice_over_loop(L_DEVICE_OK, 2*8200));
OK_(crypt_init(&cd, DMDIR H_DEVICE));
/* encryption with datashift and moved segment (data shift + data offset > device size) */
/* encryption with datashift and moved segment (data shift + data offset <= device size) */
memset(&rparams, 0, sizeof(rparams));
params2.sector_size = 512;
params2.data_device = DMDIR L_DEVICE_OK;
@@ -4320,6 +4319,22 @@ static void Luks2Reencryption(void)
OK_(crypt_reencrypt_run(cd, NULL, NULL));
CRYPT_FREE(cd);
/* decryption forward (online) */
OK_(crypt_init(&cd, DMDIR L_DEVICE_OK));
params2.data_device = NULL;
OK_(crypt_format(cd, CRYPT_LUKS2, "aes", "cbc-essiv:sha256", NULL, NULL, 32, &params2));
OK_(crypt_set_pbkdf_type(cd, &pbkdf));
EQ_(crypt_keyslot_add_by_volume_key(cd, 6, NULL, 32, PASSPHRASE, strlen(PASSPHRASE)), 6);
EQ_(crypt_activate_by_passphrase(cd, CDEVICE_2, 6, PASSPHRASE, strlen(PASSPHRASE), 0), 6);
memset(&rparams, 0, sizeof(rparams));
rparams.mode = CRYPT_REENCRYPT_DECRYPT;
rparams.direction = CRYPT_REENCRYPT_FORWARD;
rparams.resilience = "none";
rparams.max_hotzone_size = 2048;
OK_(crypt_reencrypt_init_by_passphrase(cd, CDEVICE_2, PASSPHRASE, strlen(PASSPHRASE), 6, CRYPT_ANY_SLOT, NULL, NULL, &rparams));
OK_(crypt_reencrypt_run(cd, NULL, NULL));
CRYPT_FREE(cd);
/* decryption with data shift */
OK_(crypt_init(&cd, DMDIR L_DEVICE_OK));
params2.data_device = NULL;
@@ -4354,6 +4369,8 @@ static void Luks2Reencryption(void)
EQ_(crypt_activate_by_passphrase(cd, CDEVICE_2, 6, PASSPHRASE, strlen(PASSPHRASE), 0), 6);
OK_(t_device_size(DMDIR CDEVICE_2, &r_size_1));
EQ_(r_size_1, 512);
// store devno for later size check
OK_(t_get_devno(CDEVICE_2, &devno));
// create placeholder device to block automatic deactivation after decryption
OK_(_system("dmsetup create " CDEVICE_1 " --table \"0 1 linear " DMDIR CDEVICE_2 " 0\"", 1));
remove(BACKUP_FILE);
@@ -4373,7 +4390,7 @@ static void Luks2Reencryption(void)
EQ_(crypt_get_data_offset(cd), 0);
OK_(crypt_reencrypt_run(cd, NULL, NULL));
remove(BACKUP_FILE);
OK_(t_device_size(DMDIR CDEVICE_2, &r_size_1));
OK_(t_device_size_by_devno(devno, &r_size_1));
EQ_(r_size_1, 512);
OK_(_system("dmsetup remove " DM_RETRY CDEVICE_1 DM_NOSTDERR, 0));
CRYPT_FREE(cd);
@@ -4521,8 +4538,8 @@ static void Luks2Reencryption(void)
crypt_free(cd);
_cleanup_dmdevices();
#endif
}
#endif
static void Luks2Repair(void)
{
@@ -4638,7 +4655,9 @@ int main(int argc, char *argv[])
RUN_(Luks2Integrity, "LUKS2 with data integrity");
RUN_(Luks2Refresh, "Active device table refresh");
RUN_(Luks2Flags, "LUKS2 persistent flags");
#if KERNEL_KEYRING && USE_LUKS2_REENCRYPTION
RUN_(Luks2Reencryption, "LUKS2 reencryption");
#endif
RUN_(Luks2Repair, "LUKS2 repair"); // test disables metadata locking. Run always last!
_cleanup();

View File

@@ -34,8 +34,6 @@
#include "luks1/luks.h"
#include "libcryptsetup.h"
#define DMDIR "/dev/mapper/"
#define DEVICE_1_UUID "28632274-8c8a-493f-835b-da802e1c576b"
#define DEVICE_EMPTY_name "crypt_zero"
#define DEVICE_EMPTY DMDIR DEVICE_EMPTY_name

View File

@@ -96,6 +96,8 @@ void xlog(const char *msg, const char *tst, const char *func, int line, const ch
#define CRYPT_FREE(x) do { crypt_free(x); x = NULL; } while (0)
#define DMDIR "/dev/mapper/"
#define TST_SECTOR_SHIFT 9L
#define TST_SECTOR_SIZE 512
#define TST_LOOP_FILE_SIZE (((1 << 20) * 100) >> TST_SECTOR_SHIFT)
@@ -124,4 +126,7 @@ int loop_attach(char **loop, const char *file, int offset,
int autoclear, int *readonly);
int loop_detach(const char *loop);
int t_device_size_by_devno(dev_t devno, uint64_t *retval);
int t_get_devno(const char *dev, dev_t *devno);
#endif

View File

@@ -16,6 +16,7 @@ CRYPTSETUP_LIB_VALGRIND=../.libs
function remove_mapping()
{
[ -b /dev/mapper/$MAP ] && dmsetup remove --retry $MAP
rm -rf $TST_DIR
}
function fail()
@@ -32,6 +33,7 @@ function skip()
{
[ -n "$1" ] && echo "$1"
echo "Test skipped."
remove_mapping
exit 77
}
@@ -92,7 +94,7 @@ function valgrind_run()
}
export LANG=C
[ ! -d $TST_DIR ] && tar xJSf $srcdir/bitlk-images.tar.xz --no-same-owner
[ ! -d $TST_DIR ] && tar xJSf $srcdir/bitlk-images.tar.xz --no-same-owner 2>/dev/null || skip "Incompatible tar."
[ -n "$VALG" ] && valgrind_setup && CRYPTSETUP=valgrind_run
@@ -106,11 +108,10 @@ done
if [ $(id -u) != 0 ]; then
echo "WARNING: You must be root to run activation part of test, test skipped."
remove_mapping
exit 0
fi
remove_mapping
echo "ACTIVATION FS UUID CHECK"
for file in $(ls $TST_DIR/bitlk-*) ; do
# load variables for this image from config file
@@ -185,3 +186,6 @@ for file in $(ls $TST_DIR/bitlk-*) ; do
fi
done
remove_mapping
exit 0

Binary file not shown.

View File

@@ -434,10 +434,12 @@ $CRYPTSETUP -q luksFormat --type luks1 $FAST_PBKDF_OPT --master-key-file /dev/ur
$CRYPTSETUP luksOpen -d $KEY1 $LOOPDEV $DEV_NAME || fail
$CRYPTSETUP -q luksClose $DEV_NAME || fail
# open by UUID
force_uevent # some systems do not update loop by-uuid
$CRYPTSETUP luksOpen -d $KEY1 UUID=X$TEST_UUID $DEV_NAME 2>/dev/null && fail
$CRYPTSETUP luksOpen -d $KEY1 UUID=$TEST_UUID $DEV_NAME || fail
$CRYPTSETUP -q luksClose $DEV_NAME || fail
if [ -d /dev/disk/by-uuid ] ; then
force_uevent # some systems do not update loop by-uuid
$CRYPTSETUP luksOpen -d $KEY1 UUID=X$TEST_UUID $DEV_NAME 2>/dev/null && fail
$CRYPTSETUP luksOpen -d $KEY1 UUID=$TEST_UUID $DEV_NAME || fail
$CRYPTSETUP -q luksClose $DEV_NAME || fail
fi
# empty keyfile
$CRYPTSETUP -q luksFormat --type luks1 $FAST_PBKDF_OPT $LOOPDEV $KEYE || fail
$CRYPTSETUP luksOpen -d $KEYE $LOOPDEV $DEV_NAME || fail
@@ -788,6 +790,17 @@ $CRYPTSETUP luksOpen -d $KEY1 $LOOPDEV $DEV_NAME >/dev/null 2>&1 && fail
$CRYPTSETUP -q repair $LOOPDEV >/dev/null 2>&1 || fail
$CRYPTSETUP luksOpen -d $KEY1 $LOOPDEV $DEV_NAME || fail
$CRYPTSETUP luksClose $DEV_NAME || fail
# fix ecb-plain
$CRYPTSETUP -q luksFormat --type luks1 $FAST_PBKDF_OPT $LOOPDEV $KEY1 --hash sha256 -c aes-ecb || fail
echo -n "ecb-xxx" | dd of=$LOOPDEV bs=1 seek=40 >/dev/null 2>&1
$CRYPTSETUP -q repair $LOOPDEV >/dev/null 2>&1 || fail
$CRYPTSETUP luksOpen -d $KEY1 $LOOPDEV $DEV_NAME || fail
$CRYPTSETUP luksClose $DEV_NAME || fail
# fix uppercase hash
echo -n "SHA256" | dd of=$LOOPDEV bs=1 seek=72 >/dev/null 2>&1
$CRYPTSETUP -q repair $LOOPDEV >/dev/null 2>&1 || fail
$CRYPTSETUP luksOpen -d $KEY1 $LOOPDEV $DEV_NAME || fail
$CRYPTSETUP luksClose $DEV_NAME || fail
prepare "[30] LUKS erase" wipe
$CRYPTSETUP -q luksFormat --type luks1 $FAST_PBKDF_OPT $LOOPDEV $KEY5 --key-slot 5 || fail

View File

@@ -415,10 +415,12 @@ $CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --master-key-file /dev/urandom -s 256
$CRYPTSETUP luksOpen -d $KEY1 $LOOPDEV $DEV_NAME || fail
$CRYPTSETUP -q luksClose $DEV_NAME || fail
# open by UUID
force_uevent # some systems do not update loop by-uuid
$CRYPTSETUP luksOpen -d $KEY1 UUID=X$TEST_UUID $DEV_NAME 2>/dev/null && fail
$CRYPTSETUP luksOpen -d $KEY1 UUID=$TEST_UUID $DEV_NAME || fail
$CRYPTSETUP -q luksClose $DEV_NAME || fail
if [ -d /dev/disk/by-uuid ] ; then
force_uevent # some systems do not update loop by-uuid
$CRYPTSETUP luksOpen -d $KEY1 UUID=X$TEST_UUID $DEV_NAME 2>/dev/null && fail
$CRYPTSETUP luksOpen -d $KEY1 UUID=$TEST_UUID $DEV_NAME || fail
$CRYPTSETUP -q luksClose $DEV_NAME || fail
fi
# empty keyfile
$CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV $KEYE || fail
$CRYPTSETUP luksOpen -d $KEYE $LOOPDEV $DEV_NAME || fail
@@ -872,9 +874,12 @@ echo -n "$IMPORT_TOKEN" | $CRYPTSETUP token import $LOOPDEV --token-id 11 --json
echo -n "$IMPORT_TOKEN" > $TOKEN_FILE0
$CRYPTSETUP token import $LOOPDEV --token-id 12 --json-file $TOKEN_FILE0 || fail
$CRYPTSETUP token import $LOOPDEV --token-id 12 --json-file $TOKEN_FILE0 2>/dev/null && fail
$CRYPTSETUP token export $LOOPDEV --token-id 10 | diff --from-file - $TOKEN_FILE0 || fail
$CRYPTSETUP token export $LOOPDEV --token-id 11 | diff --from-file - $TOKEN_FILE0 || fail
$CRYPTSETUP token export $LOOPDEV --token-id 12 | diff --from-file - $TOKEN_FILE0 || fail
$CRYPTSETUP token export $LOOPDEV --token-id 10 >$TOKEN_FILE1 || fail
diff $TOKEN_FILE0 $TOKEN_FILE1 || fail
$CRYPTSETUP token export $LOOPDEV --token-id 11 >$TOKEN_FILE1 || fail
diff $TOKEN_FILE0 $TOKEN_FILE1 || fail
$CRYPTSETUP token export $LOOPDEV --token-id 12 >$TOKEN_FILE1 || fail
diff $TOKEN_FILE0 $TOKEN_FILE1 || fail
$CRYPTSETUP token export $LOOPDEV --token-id 12 --json-file $TOKEN_FILE1 || fail
diff $TOKEN_FILE0 $TOKEN_FILE1 || fail
$CRYPTSETUP token export $LOOPDEV --token-id 12 > $TOKEN_FILE1 || fail
@@ -1002,7 +1007,8 @@ for mda in 16 32 64 128 256 512 1024 2048 4096 ; do
echo $PWD4 | $CRYPTSETUP open --test-passphrase test_image_$mda || fail
echo $PWD3 | $CRYPTSETUP open -S9 --test-passphrase test_image_$mda || fail
echo -n "$IMPORT_TOKEN" | $CRYPTSETUP token import test_image_$mda --token-id 10 || fail
$CRYPTSETUP token export test_image_$mda --token-id 10 | diff --from-file - $TOKEN_FILE0 || fail
$CRYPTSETUP token export test_image_$mda --token-id 10 >$TOKEN_FILE1 || fail
diff $TOKEN_FILE1 $TOKEN_FILE0 || fail
echo -n "[OK]"
done
echo

View File

@@ -22,6 +22,8 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include "crypto_backend/crypto_backend.h"
@@ -40,6 +42,24 @@ static void printhex(const char *s, const char *buf, size_t len)
fflush(stdout);
}
static bool fips_mode(void)
{
int fd;
char buf = 0;
fd = open("/proc/sys/crypto/fips_enabled", O_RDONLY);
if (fd < 0)
return false;
if (read(fd, &buf, 1) != 1)
buf = '0';
close(fd);
return (buf == '1');
}
/*
* KDF tests
*/
@@ -104,6 +124,27 @@ static struct kdf_test_vector kdf_test_vectors[] = {
// "\xd0\x1e\xf0\x45\x2d\x75\xb6\x5e"
// "\xb5\x25\x20\xe9\x6b\x01\xe6\x59", 32
},
/* empty password */
{
"argon2i", NULL, 0, 3, 128, 1,
"", 0,
"\x00\x01\x02\x03\x04\x05\x06\x07"
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", 16,
"\xbb\x1f\xf2\xb9\x9f\xd4\x4a\xd9"
"\xdf\x7f\xb9\x54\x55\x9e\xb8\xeb"
"\xb5\x9d\xab\xce\x2e\x62\x9f\x9b"
"\x89\x09\xfe\xde\x57\xcc\x63\x86", 32
},
{
"argon2id", NULL, 0, 3, 128, 1,
"", 0,
"\x00\x01\x02\x03\x04\x05\x06\x07"
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", 16,
"\x09\x2f\x38\x35\xac\xb2\x43\x92"
"\x93\xeb\xcd\xe8\x04\x16\x6a\x31"
"\xce\x14\xd4\x55\xdb\xd8\xf7\xe6"
"\xb4\xf5\x9d\x64\x8e\xd0\x3a\xdb", 32
},
/* RFC 3962 */
{
"pbkdf2", "sha1", 64, 1, 0, 0,
@@ -918,7 +959,7 @@ static int pbkdf_test_vectors(void)
unsigned int i;
const struct kdf_test_vector *vec;
for (i = 0; i < (sizeof(kdf_test_vectors) / sizeof(*kdf_test_vectors)); i++) {
for (i = 0; i < ARRAY_SIZE(kdf_test_vectors); i++) {
crypt_backend_memzero(result, sizeof(result));
vec = &kdf_test_vectors[i];
printf("PBKDF vector %02d %s ", i, vec->type);
@@ -1012,17 +1053,37 @@ static int hash_test(void)
if (!r)
r = crypt_hash_final(h, result, vector->out[j].length);
crypt_hash_destroy(h);
if (r)
if (r) {
crypt_hash_destroy(h);
return EXIT_FAILURE;
}
if (memcmp(result, vector->out[j].out, vector->out[j].length)) {
printf("[FAILED]\n");
printhex(" got", result, vector->out[j].length);
printhex("want", vector->out[j].out, vector->out[j].length);
crypt_hash_destroy(h);
return EXIT_FAILURE;
}
/*
* After crypt_hash_final() the context must be reset, repeat
*/
crypt_backend_memzero(result, sizeof(result));
r = crypt_hash_write(h, vector->data, vector->data_length);
if (!r)
r = crypt_hash_final(h, result, vector->out[j].length);
if (r || memcmp(result, vector->out[j].out, vector->out[j].length)) {
printf("[FAILED (RESET CONTEXT)]\n");
printhex(" got", result, vector->out[j].length);
printhex("want", vector->out[j].out, vector->out[j].length);
crypt_hash_destroy(h);
return EXIT_FAILURE;
}
crypt_hash_destroy(h);
}
printf("\n");
}
@@ -1065,17 +1126,36 @@ static int hmac_test(void)
if (!r)
r = crypt_hmac_final(hmac, result, vector->out[j].length);
crypt_hmac_destroy(hmac);
if (r)
if (r) {
crypt_hmac_destroy(hmac);
return EXIT_FAILURE;
}
if (memcmp(result, vector->out[j].out, vector->out[j].length)) {
printf("[FAILED]\n");
printhex(" got", result, vector->out[j].length);
printhex("want", vector->out[j].out, vector->out[j].length);
crypt_hmac_destroy(hmac);
return EXIT_FAILURE;
}
/*
* After crypt_hmac_final() the context must be reset, repeat
*/
crypt_backend_memzero(result, sizeof(result));
r = crypt_hmac_write(hmac, vector->data, vector->data_length);
if (!r)
r = crypt_hmac_final(hmac, result, vector->out[j].length);
if (r || memcmp(result, vector->out[j].out, vector->out[j].length)) {
printf("[FAILED (RESET CONTEXT)]\n");
printhex(" got", result, vector->out[j].length);
printhex("want", vector->out[j].out, vector->out[j].length);
crypt_hmac_destroy(hmac);
return EXIT_FAILURE;
}
crypt_hmac_destroy(hmac);
}
printf("\n");
}
@@ -1231,6 +1311,39 @@ static int cipher_iv_test(void)
return EXIT_SUCCESS;
}
static int check_hash(const char *hash)
{
struct crypt_hash *h;
if (crypt_hash_size(hash) < 0)
return EXIT_FAILURE;
if (crypt_hash_init(&h, hash))
return EXIT_FAILURE;
crypt_hash_destroy(h);
return EXIT_SUCCESS;
}
static int default_alg_test(void)
{
printf("Defaults: [LUKS1 hash %s] ", DEFAULT_LUKS1_HASH);
if (check_hash(DEFAULT_LUKS1_HASH))
return EXIT_FAILURE;
printf("[PLAIN hash %s] ", DEFAULT_PLAIN_HASH);
if (check_hash(DEFAULT_PLAIN_HASH))
return EXIT_FAILURE;
printf("[VERITY hash %s] ", DEFAULT_VERITY_HASH);
if (check_hash(DEFAULT_VERITY_HASH))
return EXIT_FAILURE;
printf("[OK]\n");
return EXIT_SUCCESS;
}
static void __attribute__((noreturn)) exit_test(const char *msg, int r)
{
if (msg)
@@ -1248,7 +1361,7 @@ int main(__attribute__ ((unused)) int argc, __attribute__ ((unused))char *argv[]
exit(77);
}
if (crypt_backend_init())
if (crypt_backend_init(fips_mode()))
exit_test("Crypto backend init error.", EXIT_FAILURE);
printf("Test vectors using %s crypto backend.\n", crypt_backend_version());
@@ -1268,5 +1381,12 @@ int main(__attribute__ ((unused)) int argc, __attribute__ ((unused))char *argv[]
if (cipher_iv_test())
exit_test("IV test failed.", EXIT_FAILURE);
if (default_alg_test()) {
if (fips_mode())
printf("\nDefault compiled-in algorithms test ignored (FIPS mode on).\n");
else
exit_test("\nDefault compiled-in algorithms test failed.", EXIT_FAILURE);
}
exit_test(NULL, EXIT_SUCCESS);
}

View File

@@ -0,0 +1,96 @@
#!/bin/bash
. lib.sh
#
# *** Description ***
#
# generate primary with predefined json_size. There's only limited
# set of values allowed as json size in config section of LUKS2
# metadata
#
# secondary header is corrupted on purpose as well
#
# $1 full target dir
# $2 full source luks2 image
function prepare()
{
cp $SRC_IMG $TGT_IMG
test -d $TMPDIR || mkdir $TMPDIR
read_luks2_json0 $TGT_IMG $TMPDIR/json0
read_luks2_bin_hdr0 $TGT_IMG $TMPDIR/hdr0
read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr1
}
function generate()
{
TEST_MDA_SIZE=$LUKS2_HDR_SIZE_1M
TEST_MDA_SIZE_BYTES=$((TEST_MDA_SIZE*512))
TEST_MDA_SIZE_BOGUS_BYTES=$((TEST_MDA_SIZE*512*2*1024))
TEST_JSN_SIZE=$((TEST_MDA_SIZE-LUKS2_BIN_HDR_SIZE))
KEYSLOTS_OFFSET=$((TEST_MDA_SIZE*1024))
JSON_DIFF=$(((TEST_MDA_SIZE-LUKS2_HDR_SIZE)*1024))
JSON_SIZE=$((TEST_JSN_SIZE*512))
DATA_OFFSET=16777216
json_str=$(jq -c --arg jdiff $JSON_DIFF --arg jsize $JSON_SIZE --arg off $DATA_OFFSET \
'.keyslots[].area.offset |= ( . | tonumber + ($jdiff | tonumber) | tostring) |
.config.json_size = $jsize |
.segments."0".offset = $off' $TMPDIR/json0)
test -n "$json_str" || exit 2
test ${#json_str} -lt $((LUKS2_JSON_SIZE*512)) || exit 2
write_luks2_json "$json_str" $TMPDIR/json0 $TEST_JSN_SIZE
write_bin_hdr_size $TMPDIR/hdr0 $TEST_MDA_SIZE_BYTES
write_bin_hdr_size $TMPDIR/hdr1 $TEST_MDA_SIZE_BOGUS_BYTES
write_bin_hdr_offset $TMPDIR/hdr1 $TEST_MDA_SIZE_BYTES
merge_bin_hdr_with_json $TMPDIR/hdr0 $TMPDIR/json0 $TMPDIR/area0 $TEST_JSN_SIZE
merge_bin_hdr_with_json $TMPDIR/hdr1 $TMPDIR/json0 $TMPDIR/area1 $TEST_JSN_SIZE
erase_checksum $TMPDIR/area0
chks0=$(calc_sha256_checksum_file $TMPDIR/area0)
write_checksum $chks0 $TMPDIR/area0
erase_checksum $TMPDIR/area1
chks0=$(calc_sha256_checksum_file $TMPDIR/area1)
write_checksum $chks0 $TMPDIR/area1
kill_bin_hdr $TMPDIR/area0
write_luks2_hdr0 $TMPDIR/area0 $TGT_IMG $TEST_MDA_SIZE
write_luks2_hdr1 $TMPDIR/area1 $TGT_IMG $TEST_MDA_SIZE
}
function check()
{
read_luks2_bin_hdr0 $TGT_IMG $TMPDIR/hdr_res0 $TEST_MDA_SIZE
local str_res0=$(head -c 6 $TMPDIR/hdr_res0)
test "$str_res0" = "VACUUM" || exit 2
read_luks2_json1 $TGT_IMG $TMPDIR/json_res1 $TEST_JSN_SIZE
jq -c --arg koff $KEYSLOTS_OFFSET --arg jsize $JSON_SIZE \
'if ([.keyslots[].area.offset] | map(tonumber) | min | tostring != $koff) or
(.config.json_size != $jsize)
then error("Unexpected value in result json") else empty end' $TMPDIR/json_res1 || exit 5
}
function cleanup()
{
rm -f $TMPDIR/*
rm -fd $TMPDIR
}
test $# -eq 2 || exit 1
TGT_IMG=$1/$(test_img_name $0)
SRC_IMG=$2
prepare
generate
check
cleanup

View File

@@ -0,0 +1,94 @@
#!/bin/bash
. lib.sh
#
# *** Description ***
#
# generate primary with predefined json_size. There's only limited
# set of values allowed as json size in config section of LUKS2
# metadata
#
# secondary header is corrupted on purpose as well
#
# $1 full target dir
# $2 full source luks2 image
function prepare()
{
cp $SRC_IMG $TGT_IMG
test -d $TMPDIR || mkdir $TMPDIR
read_luks2_json0 $TGT_IMG $TMPDIR/json0
read_luks2_bin_hdr0 $TGT_IMG $TMPDIR/hdr0
read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr1
}
function generate()
{
TEST_MDA_SIZE=$LUKS2_HDR_SIZE_1M
TEST_MDA_SIZE_BYTES=$((TEST_MDA_SIZE*512))
TEST_MDA_SIZE_BOGUS_BYTES=$((TEST_MDA_SIZE*512*2*1024))
TEST_JSN_SIZE=$((TEST_MDA_SIZE-LUKS2_BIN_HDR_SIZE))
KEYSLOTS_OFFSET=$((TEST_MDA_SIZE*1024))
JSON_DIFF=$(((TEST_MDA_SIZE-LUKS2_HDR_SIZE)*1024))
JSON_SIZE=$((TEST_JSN_SIZE*512))
DATA_OFFSET=16777216
json_str=$(jq -c --arg jdiff $JSON_DIFF --arg jsize $JSON_SIZE --arg off $DATA_OFFSET \
'.keyslots[].area.offset |= ( . | tonumber + ($jdiff | tonumber) | tostring) |
.config.json_size = $jsize |
.segments."0".offset = $off' $TMPDIR/json0)
test -n "$json_str" || exit 2
test ${#json_str} -lt $((LUKS2_JSON_SIZE*512)) || exit 2
write_luks2_json "$json_str" $TMPDIR/json0 $TEST_JSN_SIZE
write_bin_hdr_size $TMPDIR/hdr0 $TEST_MDA_SIZE_BOGUS_BYTES
write_bin_hdr_size $TMPDIR/hdr1 $TEST_MDA_SIZE_BOGUS_BYTES
merge_bin_hdr_with_json $TMPDIR/hdr0 $TMPDIR/json0 $TMPDIR/area0 $TEST_JSN_SIZE
merge_bin_hdr_with_json $TMPDIR/hdr1 $TMPDIR/json0 $TMPDIR/area1 $TEST_JSN_SIZE
erase_checksum $TMPDIR/area0
chks0=$(calc_sha256_checksum_file $TMPDIR/area0)
write_checksum $chks0 $TMPDIR/area0
erase_checksum $TMPDIR/area1
chks0=$(calc_sha256_checksum_file $TMPDIR/area1)
write_checksum $chks0 $TMPDIR/area1
kill_bin_hdr $TMPDIR/area1
write_luks2_hdr0 $TMPDIR/area0 $TGT_IMG $TEST_MDA_SIZE
write_luks2_hdr1 $TMPDIR/area1 $TGT_IMG $TEST_MDA_SIZE
}
function check()
{
read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr_res1 $TEST_MDA_SIZE
local str_res1=$(head -c 6 $TMPDIR/hdr_res1)
test "$str_res1" = "VACUUM" || exit 2
read_luks2_json0 $TGT_IMG $TMPDIR/json_res0 $TEST_JSN_SIZE
jq -c --arg koff $KEYSLOTS_OFFSET --arg jsize $JSON_SIZE \
'if ([.keyslots[].area.offset] | map(tonumber) | min | tostring != $koff) or
(.config.json_size != $jsize)
then error("Unexpected value in result json") else empty end' $TMPDIR/json_res0 || exit 5
}
function cleanup()
{
rm -f $TMPDIR/*
rm -fd $TMPDIR
}
test $# -eq 2 || exit 1
TGT_IMG=$1/$(test_img_name $0)
SRC_IMG=$2
prepare
generate
check
cleanup

View File

@@ -168,12 +168,11 @@ intformat() # alg alg_out tagsize outtagsize sector_size csum [keyfile keysize]
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
ALG=$(echo $1 | sed -e 's/hmac-//')
if ! grep -q $ALG /proc/crypto ; then
echo "[N/A]"
return
if [[ $1 =~ "sha" || $1 =~ "crc" ]] ; then
fail "Cannot format device."
fi
fail "Cannot format device."
echo "[N/A]"
return
fi
dump_check "tag_size" $4
@@ -335,6 +334,7 @@ which blockdev >/dev/null || skip "Cannot find blockdev utility, test skipped."
[ -n "$VALG" ] && valgrind_setup && INTSETUP=valgrind_run
which hexdump >/dev/null 2>&1 || skip "WARNING: hexdump tool required."
which xxd >/dev/null 2>&1 || skip "WARNING: xxd tool required."
modprobe dm-integrity >/dev/null 2>&1
dm_integrity_features

View File

@@ -17,6 +17,7 @@ KEYFILE=keyfile1
function remove_mapping()
{
[ -b /dev/mapper/$MAP ] && dmsetup remove --retry $MAP
rm -rf $TST_DIR
}
function fail()
@@ -33,6 +34,7 @@ function skip()
{
[ -n "$1" ] && echo "$1"
echo "Test skipped."
remove_mapping
exit 77
}
@@ -80,6 +82,7 @@ done
if [ $(id -u) != 0 ]; then
echo "WARNING: You must be root to run activation part of test, test skipped."
remove_mapping
exit 0
fi
@@ -102,3 +105,6 @@ for file in $(ls $TST_DIR/luks1_*) ; do
[ "$UUID" != "DEAD-BABE" ] && fail "UUID check failed."
echo " [OK]"
done
remove_mapping
exit 0

View File

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

View File

@@ -116,6 +116,7 @@ function fail()
function skip()
{
[ -n "$1" ] && echo "$1"
remove_mapping
exit 77
}
@@ -152,14 +153,30 @@ function open_crypt() # $1 pwd, $2 hdr
fi
}
function wipe_dev_head() # $1 dev, $2 length (in MiBs)
{
dd if=/dev/zero of=$1 bs=1M count=$2 conv=notrunc >/dev/null 2>&1
}
function wipe_dev() # $1 dev
{
if [ -b $1 ] ; then
blkdiscard --zeroout $1 2>/dev/null || dd if=/dev/zero of=$1 bs=1M conv=notrunc >/dev/null 2>&1
if [ $# -gt 2 ]; then
dd if=/dev/urandom of=$1 bs=1M seek=$2 conv=notrunc >/dev/null 2>&1
fi
else
local size=$(stat --printf="%s" $1)
truncate -s 0 $1
truncate -s $size $1
if [ $# -gt 2 ]; then
local diff=$((size-$2*1024*1024))
echo "size: $size, diff: $diff"
truncate -s $diff $1
# wipe_dev_head $1 $((diff/(1024*1024)))
dd if=/dev/urandom of=$1 bs=1M seek=$2 size=$((diff/(1024*1024))) conv=notrunc >/dev/null 2>&1
else
truncate -s $size $1
fi
fi
}
@@ -214,15 +231,16 @@ function check_hash() # $1 pwd, $2 hash, $3 hdr
$CRYPTSETUP remove $DEV_NAME || fail
}
function check_hash_dev_head() # $1 dev, $2 len, $3 hash
{
local hash=$(dd if=$1 bs=512 count=$2 2>/dev/null | sha256sum | cut -d' ' -f1)
[ $hash != "$3" ] && fail "HASH differs (expected: $3) (result $hash)"
}
function check_hash_head() # $1 pwd, $2 len, $3 hash, $4 hdr
{
open_crypt $1 $4
if [ -n "$4" ]; then
echo $1 | $CRYPTSETUP resize $DEV_NAME --size $2 --header $4 || fail
else
echo $1 | $CRYPTSETUP resize $DEV_NAME --size $2 || fail
fi
check_hash_dev /dev/mapper/$DEV_NAME $3
check_hash_dev_head /dev/mapper/$DEV_NAME $2 $3
$CRYPTSETUP remove $DEV_NAME || fail
}
@@ -722,6 +740,8 @@ HASH6=39f7c6d38af574fe2c90ef400dfaba8ef8edccd11bdac998a3f8143a86837331
HASH7=18a393d1a505e22ccf3e29effe3005ea8627e4c36b7cca0e53f58121f49b67e1
# 60 MiBs of zeroes
HASH8=cf5ac69ca412f9b3b1a8b8de27d368c5c05ed4b1b6aa40e6c38d9cbf23711342
# 240 MiBs of zeroes (256MiBs - 16MiBs default LUKS2 header size)
HASH9=17088b031491a37e0ee9e1025a3938f55ee94ae27653370ad2fe5b0b32e35334
prepare dev_size_mb=32
setup_luks2_env
@@ -731,6 +751,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
@@ -863,6 +884,21 @@ $CRYPTSETUP status $DEV_NAME >/dev/null 2>&1 || fail
$CRYPTSETUP close $DEV_NAME
echo $PWD1 | $CRYPTSETUP open $DEV --test-passphrase || fail
# Small device encryption test
preparebig 65
# wipe only 1st MiB (final data size after encryption)
wipe_dev $DEV 1
check_hash_dev_head $DEV 2048 $HASH2
echo $PWD1 | $CRYPTSETUP reencrypt $DEV --encrypt --reduce-device-size 64M -q $FAST_PBKDF_ARGON || fail
check_hash_head $PWD1 2048 $HASH2
wipe_dev_head $DEV 1
check_hash_dev_head $DEV 2048 $HASH2
echo $PWD1 | $CRYPTSETUP reencrypt $DEV --encrypt --reduce-device-size 64M --init-only -q $FAST_PBKDF_ARGON $DEV_NAME >/dev/null || fail
check_hash_dev_head /dev/mapper/$DEV_NAME 2048 $HASH2
echo $PWD1 | $CRYPTSETUP reencrypt $DEV -q || fail
check_hash_dev_head /dev/mapper/$DEV_NAME 2048 $HASH2
echo "[3] Encryption with detached header"
preparebig 256
wipe_dev $DEV
@@ -889,6 +925,12 @@ echo $PWD1 | $CRYPTSETUP reencrypt $DEV --encrypt -c aes-cbc-essiv:sha256 -s 128
$CRYPTSETUP close $DEV_NAME
check_hash $PWD1 $HASH3 $IMG_HDR
# Device encryption with data offset set in detached header
wipe_dev $DEV
dd if=/dev/urandom of=$DEV bs=512 count=32768 >/dev/null 2>&1
echo $PWD1 | $CRYPTSETUP reencrypt --encrypt --header $IMG_HDR --offset 32768 -q $FAST_PBKDF_ARGON $DEV || fail
check_hash $PWD1 $HASH9 $IMG_HDR
# Device activation using key file
wipe_dev $DEV
echo -n $PWD1 > $KEY1
@@ -961,6 +1003,18 @@ echo $PWD1 | $CRYPTSETUP reencrypt --decrypt --active-name $DEV_NAME --header $D
$CRYPTSETUP status $DEV_NAME | grep -q "reencryption: in-progress" && fail
$CRYPTSETUP close $DEV_NAME
# yet another funny idea
rm -f $IMG_HDR
$CRYPTSETUP luksHeaderBackup --header-backup-file $IMG_HDR $DEV || fail
chmod +w $IMG_HDR || fail
which wipefs >/dev/null 2>&1 && {
wipefs -a $DEV >/dev/null 2>&1 || fail
}
open_crypt $PWD1 $IMG_HDR
echo $PWD1 | $CRYPTSETUP reencrypt --active-name $DEV_NAME --decrypt --header $IMG_HDR -q 2>/dev/null && fail
$CRYPTSETUP status $DEV_NAME | grep -q "reencryption: in-progress" && fail
$CRYPTSETUP close $DEV_NAME || fail
if ! dm_delay_features; then
echo "dm-delay target is missing, skipping recovery tests."
remove_mapping

View File

@@ -229,6 +229,8 @@ RUN luks2-metadata-size-512k-secondary.img "R" "Valid 512KiB metadata size in s
RUN luks2-metadata-size-1m-secondary.img "R" "Valid 1MiB metadata size in secondary hdr failed to validate"
RUN luks2-metadata-size-2m-secondary.img "R" "Valid 2MiB metadata size in secondary hdr failed to validate"
RUN luks2-metadata-size-4m-secondary.img "R" "Valid 4MiB metadata size in secondary hdr failed to validate"
RUN luks2-metadata-size-invalid.img "F" "Invalid metadata size in secondary hdr not rejected"
RUN luks2-metadata-size-invalid-secondary.img "F" "Invalid metadata size in secondary hdr not rejected"
remove_mapping

View File

@@ -41,7 +41,7 @@ function create_user()
[ $? -eq 0 ] && skip "User account $USER exists, aborting."
[ -f $SSH_KEY_PATH ] && skip "SSH key $SSH_KEY_PATH already exists, aborting."
useradd -m $USER -p $(openssl passwd -crypt $PASSWD) || skip "Failed to add user for SSH plugin test."
useradd -m $USER -p $(openssl passwd $PASSWD) || skip "Failed to add user for SSH plugin test."
ssh-keygen -f $SSH_KEY_PATH -q -N "" >/dev/null 2>&1
[ $? -ne 0 ] && remove_user && skip "Failed to create SSH key."
@@ -60,10 +60,18 @@ function bin_check()
function ssh_setup()
{
# .ssh is used by ssh-copy-id for temp files so it must exist even if key is not there
[ -d "$HOME/.ssh" ] || mkdir -m 700 $HOME/.ssh
# ssh-copy-id
sshpass -p $PASSWD ssh-copy-id -i $SSH_KEY_PATH $SSH_OPTIONS $USER@$SSH_SERVER >/dev/null 2>&1
[ $? -ne 0 ] && remove_user && skip "Failed to copy SSH key."
# make sure /home/sshtest/.ssh and /home/sshtest/.ssh/authorized_keys have correct permissions
chown -R $USER:$USER /home/$USER/.ssh
chmod 700 /home/$USER/.ssh
chmod 644 /home/$USER/.ssh/authorized_keys
# try to ssh and also create keyfile
ssh -i $SSH_KEY_PATH $SSH_OPTIONS -o BatchMode=yes -n $USER@$SSH_SERVER -f "echo -n $PASSWD > $SSH_PATH" >/dev/null 2>&1
[ $? -ne 0 ] && remove_user && skip "Failed to connect using SSH."
@@ -83,6 +91,7 @@ function fail()
function skip()
{
[ -n "$1" ] && echo "$1"
remove_mapping
exit 77
}
@@ -133,6 +142,7 @@ bin_check useradd
bin_check ssh
bin_check ssh-keygen
bin_check sshpass
bin_check openssl
format

View File

@@ -21,6 +21,7 @@ function remove_mapping()
[ -b /dev/mapper/$MAP ] && dmsetup remove --retry $MAP
[ -b /dev/mapper/"$MAP"_1 ] && dmsetup remove --retry "$MAP"_1
[ -b /dev/mapper/"$MAP"_2 ] && dmsetup remove --retry "$MAP"_2
rm -rf $TST_DIR
}
function fail()
@@ -37,6 +38,7 @@ function skip()
{
[ -n "$1" ] && echo "$1"
echo "Test skipped."
remove_mapping
exit 77
}
@@ -166,6 +168,7 @@ done
if [ $(id -u) != 0 ]; then
echo "WARNING: You must be root to run activation part of test, test skipped."
remove_mapping
exit 0
fi
@@ -202,3 +205,6 @@ for file in $(ls $TST_DIR/[tv]c_*-hidden) ; do
[ "$UUID" != "CAFE-BABE" ] && fail "UUID check failed."
echo " [OK]"
done
remove_mapping
exit 0

View File

@@ -684,3 +684,60 @@ int loop_detach(const char *loop)
close(loop_fd);
return r;
}
int t_get_devno(const char *name, dev_t *devno)
{
char path[PATH_MAX];
int r;
struct stat st;
r = snprintf(path, sizeof(path), DMDIR "%s", name);
if (r < 0 || (size_t)r >= sizeof(path))
return 1;
if (stat(path, &st) || !S_ISBLK(st.st_mode))
return 1;
*devno = st.st_rdev;
return 0;
}
static int _read_uint64(const char *sysfs_path, uint64_t *value)
{
char tmp[64] = {0};
int fd, r;
if ((fd = open(sysfs_path, O_RDONLY)) < 0)
return 0;
r = read(fd, tmp, sizeof(tmp));
close(fd);
if (r <= 0)
return 0;
if (sscanf(tmp, "%" PRIu64, value) != 1)
return 0;
return 1;
}
static int _sysfs_get_uint64(int major, int minor, uint64_t *value, const char *attr)
{
char path[PATH_MAX];
if (snprintf(path, sizeof(path), "/sys/dev/block/%d:%d/%s",
major, minor, attr) < 0)
return 0;
return _read_uint64(path, value);
}
int t_device_size_by_devno(dev_t devno, uint64_t *retval)
{
if (!_sysfs_get_uint64(major(devno), minor(devno), retval, "size"))
return 1;
*retval *= 512;
return 0;
}

View File

@@ -99,11 +99,13 @@ function check_root_hash_fail()
$VERITYSETUP open $IMG $DEV_NAME $IMG_HASH $ROOT_HASH || fail
check_exists
dd if=/dev/mapper/$DEV_NAME of=/dev/null bs=4096 count=1 >/dev/null 2>&1
dmsetup status $DEV_NAME | grep "verity V" >/dev/null || fail
$VERITYSETUP close $DEV_NAME >/dev/null 2>&1 || fail
$VERITYSETUP open $IMG $DEV_NAME $IMG_HASH $ROOT_HASH_BAD >/dev/null 2>&1 || fail
check_exists
dd if=/dev/mapper/$DEV_NAME of=/dev/null bs=4096 count=1 >/dev/null 2>&1
dmsetup status $DEV_NAME | grep "verity C" >/dev/null || fail
$VERITYSETUP close $DEV_NAME >/dev/null 2>&1 || fail
@@ -260,7 +262,7 @@ function check_fec()
return 3
fi
udevadm settle
udevadm settle > /dev/null 2>&1
dd if=/dev/mapper/$DEV_NAME of=$IMG_TMP > /dev/null 2>&1
ARR=(`sha256sum $IMG_TMP`)

View File

@@ -21,7 +21,7 @@ cryptsetup_ssh_SOURCES = tokens/ssh/cryptsetup-ssh.c \
lib/utils_io.c \
lib/utils_loop.c
cryptsetup_ssh_LDADD = -lm libcryptsetup.la @LIBSSH_LIBS@ @JSON_C_LIBS@ @POPT_LIBS@ \
@PWQUALITY_LIBS@ @PASSWDQC_LIBS@
@PWQUALITY_LIBS@ @PASSWDQC_LIBS@ @ARGP_LIBS@
cryptsetup_ssh_CFLAGS = $(AM_CFLAGS)

View File

@@ -141,7 +141,7 @@ static struct argp_option options[] = {
{"ssh-user", OPT_SSH_USER, "STRING", 0, N_("Username used for the remote server")},
{"ssh-path", OPT_SSH_PATH, "STRING", 0, N_("Path to the key file on the remote server")},
{"ssh-keypath", OPT_KEY_PATH, "STRING", 0, N_("Path to the SSH key for connecting to the remote server")},
{"key-slot", OPT_KEY_SLOT, "NUM", 0, N_("Keyslot to assing the token to. If not specified, token will "\
{"key-slot", OPT_KEY_SLOT, "NUM", 0, N_("Keyslot to assign the token to. If not specified, token will "\
"be assigned to the first keyslot matching provided passphrase.")},
{0, 0, 0, 0, N_("Generic options:")},
{"verbose", 'v', 0, 0, N_("Shows more detailed error messages")},