Compare commits

..

452 Commits

Author SHA1 Message Date
Milan Broz
d3d1e30c7c Prepare version 2.3.0. 2020-02-02 16:58:29 +01:00
Ondrej Kozina
47d0cf495d Fail crypt_keyslot_get_pbkdf for inactive LUKS1 keyslot.
With LUKS1 we returned pbkdf values even for inactive keyslot.
Only iterations count was wrong. Remaining values are not
specific keyslot bound with LUKS1.

Fixes: #528.
2020-01-31 13:52:38 +01:00
Ondrej Kozina
2e883f9d91 Fix misleading hint in integritysetup man page.
--journal-crypt example values are not accepted by
crurrent integritysetup.

Fixes: #510.
2020-01-30 17:58:54 +01:00
Vojtech Trefny
af0c30e3ea bitlk: Add a test image for the EOW format
The image was created by pausing the encryption in progress.
2020-01-30 09:57:43 +01:00
Vojtech Trefny
da5a35356a bitlk: Remove unused constant 2020-01-30 09:57:43 +01:00
Vojtech Trefny
d98cc3bb6c bitlk: Do not allow activation of EOW and unknown devices
We currently do not support these BITLK devices.
2020-01-30 09:57:43 +01:00
Vojtech Trefny
9697f17b9d bitlk: Do not allow to activate devices in an unknown state
According to Dislocker, two unknown numbers in the FVE metadata
indicate "state" of the BITLK device. We were able to identify
only one of the states and we shouldn't allow activating devices
in other states for now.
2020-01-30 09:57:43 +01:00
Vojtech Trefny
ce3a9d172d bitlk: Fix reading metadata entries total length
FVE metadata header contains size of the header itself + size of
the metadata entries so we need to take this value and substract
48 (length of the FVE metadata header).
2020-01-30 09:57:39 +01:00
Yuri Kozlov
4448ddc488 po: update ru.po (from translationproject.org) 2020-01-26 10:15:41 +01:00
Yuri Chornoivan
b77d3c66ae po: update uk.po (from translationproject.org) 2020-01-17 14:34:16 +01:00
Jakub Bogusz
2debdfead5 po: update pl.po (from translationproject.org) 2020-01-17 14:34:16 +01:00
Benno Schulenberg
b168c65fa1 po: update nl.po (from translationproject.org) 2020-01-17 14:34:16 +01:00
Hiroshi Takekawa
2b46d171db po: update ja.po (from translationproject.org) 2020-01-17 14:34:16 +01:00
Frédéric Marchal
64c131d132 po: update fr.po (from translationproject.org) 2020-01-17 14:34:16 +01:00
Roland Illig
678a251858 po: update de.po (from translationproject.org) 2020-01-17 14:34:16 +01:00
Petr Pisar
bf9d2f6cb0 po: update cs.po (from translationproject.org) 2020-01-17 14:34:16 +01:00
Vojtěch Trefný
61f5dcb11e Return correct data offset for BITLK in crypt_get_data_offset
First part of the encrypted data will be always directly after
the header.

Fixes: #518
2020-01-17 14:02:12 +01:00
Milan Broz
e4387d2bd1 Update Readme.md. 2020-01-12 12:48:19 +01:00
Milan Broz
48906f354e Remove EOL in debug message. 2020-01-12 12:30:36 +01:00
Milan Broz
1ddc098e43 Prepare version 2.3.0-rc0. 2020-01-12 12:14:27 +01:00
Milan Broz
165e6c234c Fix some error and debug messages.
Use BITLK as format name.

Avoid using doesn't -> does not.
2020-01-11 22:10:59 +01:00
Milan Broz
1be631f43f Add status flag for verity device with signature.
This patch adds CRYPT_VERITY_ROOT_HASH_SIGNATURE flag to verity info.

Veritysetup status now display "with signature" if an active
device was activated with root hash signature.
2020-01-11 19:57:39 +01:00
Vojtěch Trefný
f5f34c2f50 bitlk: Add recovery passphrases for Elephant test images 2020-01-08 09:23:06 +01:00
Vojtěch Trefný
33f3619e98 bitlk: Update testing images for AES-CBC with Elephant
Images now contain valid NTFS filesystem after opening and the
test data also contain sha256sum of the opened device.
2020-01-05 17:09:16 +01:00
Vojtěch Trefný
3720b66d00 bitlk: Fix getting FVEK for AES-CBC 128 bit with Elephant
For this 128 bit Elephant the key data is 512 bit (2 * 156 bit,
same as for 256 bit Elephant) so we need to adjust reading the
key to not include the empty "parts" of the key.
2020-01-05 17:07:15 +01:00
Milan Broz
864bbc5472 Fix string leak in BITLK attribute name handling. 2020-01-03 13:44:57 +01:00
Milan Broz
080566a1fd Update copyright year. 2020-01-03 13:04:55 +01:00
Milan Broz
d9766037a3 Fix some extended compiler warnings. 2020-01-03 12:29:49 +01:00
Milan Broz
02821adc47 Fix a signed/unsigned comparison compiler warning. 2020-01-03 11:26:44 +01:00
Milan Broz
7b08fd4b7d Remove undeeded version test for BITLK compat tests.
Otherwise it starts failing with dm-crypt version bump.
2020-01-03 10:23:28 +01:00
Milan Broz
0505c70be2 Implement BITLK status info.
Cryptsetup status <device> should print info about active device.

Also fix mistake in BITLK volume key size (should return bytes, not bits).
2020-01-03 10:14:47 +01:00
Jaskaran Khurana
f247038e65 Add --root-hash-signature parameter to veritysetup
Optional parameter root hash signature is added that can be added to
veritysetup.

The signature file is opened and the signature is added to the keyring.

The kernel will use the signature to validate the roothash.

Usage: veritysetup open <data_device> name <hash_device> <root_hash> --root-hash-signature=<roothash_p7_sig_file>

Signed-off-by: Jaskaran Khurana <jaskarankhurana@linux.microsoft.com>
Signed-off-by: Luca Boccassi <luca.boccassi@microsoft.com>

[Original patch rewritten by Milan Broz]
2020-01-02 13:08:21 +01:00
jbit
d7667e9e6e bitlk: Support for name strings in VMK metadata 2020-01-02 08:54:19 +00:00
Luca Boccassi
188cb114af Add support for verity in crypt_volume_key_get and use it in status
Other APIs use the root hash in place of keys when using verity
devices, so do the same for crypt_volume_key_get to allow users
to retrieve the root hash of an active verity device.
Use it in veritysetup status to print the root hash.

[Patch slightly modified by Milan Broz]
2019-12-31 21:44:50 +01:00
Milan Broz
35c49ababf Fix some compiler warnings. 2019-12-31 17:49:38 +01:00
Ondrej Kozina
faafe09bd0 Use crypt_volume_key_next where appropriate. 2019-12-31 17:37:33 +01:00
Milan Broz
a0e87c9420 Calculate hash integrity size instead of requiring an explicit tag size.
When integritysetup formats a device with hash or HMAC integrity checksums,
it requires explicitly tag size entry from a user (or default value).

This leads to confusion and shortened tags.

This patch calculates tag size according to real hash output, and
if tag size is specified, it warns if these values differ.

Fixes: #492.
2019-12-31 17:37:33 +01:00
Milan Broz
d9d39f1812 po: update pot file 2019-12-31 12:36:39 +01:00
Milan Broz
82af225742 Add bitlk compat test to distro tar. 2019-12-31 12:30:44 +01:00
Milan Broz
919f4df1a7 Remove wip-bitlocker branch from CI. 2019-12-31 12:20:06 +01:00
Milan Broz
71a1698bf2 Add bitlk.c to translation. 2019-12-31 11:16:01 +01:00
Milan Broz
a987dd95b8 Remove unused bitlk params structure. 2019-12-30 21:57:42 +01:00
Milan Broz
ab6ab8e65c Fix BITLK command aliases descriptions. 2019-12-30 21:53:06 +01:00
Milan Broz
3b28d66410 Add BitLocker man page extentsion. 2019-12-30 21:53:06 +01:00
Milan Broz
eee46ef2f4 Detect support for BitLocker EBOIV and Elephant diffuser.
If kernel is missing support, print a more friendly error.
2019-12-30 21:53:06 +01:00
Vojtěch Trefný
3c189b4183 bitlk: Fix displaying key length in bitlkDump 2019-12-30 21:53:06 +01:00
Vojtěch Trefný
fd5ab0edf7 bitlk: Add Smart Card protected VMKs
Test image protected with smart card is included.
2019-12-30 21:53:06 +01:00
Vojtěch Trefný
420387a7a5 bitlk: Ignore unknown metadata entries for unsupported VMKs
VMKs (keyslots) protected with a smart card or TPM have some
additional metadata entries that are currently unkwnon. We can
safely ignore these because we don't support unlocking the device
using these VMKs so we should still be able to parse the metadata
and unlock the device using other VMKs like the recovery password.
2019-12-30 21:53:06 +01:00
Milan Broz
fc740f8b6d Simplify bitlk test and be sure to load dm-crypt module. 2019-12-30 21:53:06 +01:00
Vojtech Trefny
834059ddfa Do not hardcode number of DM segments for BitLocker devices
Sometimes there is no gap between the metadata so we don't want to
create a dm-crypt segment there.
2019-12-30 21:53:06 +01:00
Vojtěch Trefný
5ec2fbcd38 Allow empty passphrases when opening BitLocker devices
It's probably not possible to create a BitLocker device with an
empty passphrase but we want to support it. And it's definitely
better to ask for the passphrase again instead of returning
ENOMEM.
2019-12-30 21:53:06 +01:00
Vojtěch Trefný
2fbf5cd79f Covert the BitLocker test images to sparse images 2019-12-30 21:53:06 +01:00
Vojtěch Trefný
64ebe95751 Check sha256 sums of the bitlk images in tests 2019-12-30 21:53:06 +01:00
Vojtěch Trefný
77109b3a33 Edit BitLocker test images to be compatible with older blkid
We need to keep the mirror NTFS MFT too because older versions of
blkid check it too.
2019-12-30 21:53:06 +01:00
Vojtěch Trefný
b43429e684 Fix parsing BitLocker metadata on Big Endian architectures 2019-12-30 21:53:06 +01:00
Vojtěch Trefný
97e39f0744 Fix displaying error for not supported BitLocker key decryption
'crypt_bitlk_decrypt_key' can also fail because of wrong
passphrase and other reasons.
2019-12-30 21:53:06 +01:00
Vojtěch Trefný
fad592b512 Fix open on devices with no supported VMKs 2019-12-30 21:53:06 +01:00
Milan Broz
565de3c536 Fix check for bitlk iv overflow in crypto backend. 2019-12-30 21:53:06 +01:00
Milan Broz
c802269ea3 Bitlk: fix some additional gcc warnings. 2019-12-30 21:53:06 +01:00
Milan Broz
06268963fb Bitlk: clean up some inlcudes and warnings. 2019-12-30 21:53:06 +01:00
Milan Broz
2227797691 Bitlk: move test for older blkid. 2019-12-30 21:53:06 +01:00
Milan Broz
f0888c1fe0 Add AEAD define on older kernel headers. 2019-12-30 21:53:06 +01:00
Milan Broz
eda2e62589 Add other backends (Nettle, NSS) for Bitlk decryption (through kernel wrapper). 2019-12-30 21:53:06 +01:00
Milan Broz
494d8ec04c Add kernel backend for Bitlk key decryption. 2019-12-30 21:53:06 +01:00
Milan Broz
bb8088ca0f Another fix for ancient systems. 2019-12-30 21:53:06 +01:00
Milan Broz
26f4bc39fc Fix tes for very old bash. 2019-12-30 21:53:06 +01:00
Milan Broz
025e4d9fc6 Fix bitlk test on older systems. 2019-12-30 21:53:06 +01:00
Milan Broz
b2774d57ba Bitlk: Propagare errno from key decryption. 2019-12-30 21:53:06 +01:00
Milan Broz
51edfb4ec9 Bitlk: add gcrypt key backend. 2019-12-30 21:53:06 +01:00
Milan Broz
79019b1ced Bitlk: Move crypt key handling to crypto backend. 2019-12-30 21:53:06 +01:00
Vojtěch Trefný
bc87140b5b Do not declare control variables in for loops
C89 doesn't like this.
2019-12-30 21:53:06 +01:00
Vojtěch Trefný
1c5251069b Define UUID_STR_LEN not defined in older versions of libuuid 2019-12-30 21:53:06 +01:00
Vojtěch Trefný
0b6dfefcec Add tests and test images for BitLocker 2019-12-30 21:53:06 +01:00
Vojtěch Trefný
a9e32c55c0 Fix parsing BitLocker metadata from latest Windows
Newest version added a new metadata entry to the recovery
passphrase protected VMK containing two new timestamps. We are
ignoring these for now.
2019-12-30 21:53:06 +01:00
Vojtěch Trefný
a494228407 Do not try to activate partially decrypted BitLocker devices 2019-12-30 21:53:06 +01:00
Vojtěch Trefný
9932b5fc5c Do not try to activate BitLocker devices with diffuser
The CBC mode with Elephant Diffuser is currently not supported
by DM crypt.
2019-12-30 21:53:06 +01:00
Vojtěch Trefný
966ba44a33 Add support for opening of BitLocker devices
It's now possible to open/activate the device using passphrase or
recovery passphrase. Support is limited to devices using encryption
modes supported in the DM crypt module (AES-XTS and AES-CBC).
2019-12-30 21:53:06 +01:00
Vojtěch Trefný
62c872eb49 Add support for parsing BitLocker metadata
Currently only support for metadata version 2 is implemented.
2019-12-30 21:53:06 +01:00
Milan Broz
434fee2e13 Add empty template for BITLK device type.
Also add DM_ZERO type for multi-segment mapping.
2019-12-30 21:53:06 +01:00
Andrei Shevchuk
d3f829c065 Add note on integrity mode not supporting discards (TRIM) 2019-12-23 14:31:46 +00:00
Ondrej Kozina
83934bdcf3 Clarify LUKS2 error message related to reencryption.
Original messages could evoke reencryption is currently
in progress. That was inaccurate because code only
detected flag marking such device is in transition state
from metadata pov. We should not imply anything about
running processes. That's detected via reencryption locks.
2019-11-28 16:38:53 +01:00
Ondrej Kozina
3691add163 Minor code cleanup. 2019-11-28 16:38:53 +01:00
Ondrej Kozina
cc7a9e4607 Fix lookup function for keyslot-segment assignment.
In reencryption we can have more than 3 segments.
2019-11-28 16:38:53 +01:00
Ondrej Kozina
943fa69da6 Reduce code duplication in LUKS2 keyslot handling. 2019-11-28 16:38:53 +01:00
Ondrej Kozina
3bef291184 Unify low level LUKS2 keyslot unlock and verify code.
Function is now unused, see later commit
2019-11-28 16:38:53 +01:00
Ondrej Kozina
7316c53b04 Remove redundant digest id to key assignement. 2019-11-28 16:38:52 +01:00
Ondrej Kozina
5e1d1e1850 Add missing validation when unlocking keys for reencryption.
We missed keyslot json validation when unlocking all keys necessary
for reencryption. Also assign appropriate verified digest id to
keys in volume key structure.
2019-11-28 16:38:52 +01:00
Ondrej Kozina
e52c8e148c Remove unnecessary query for volume key size.
In fact we need only stored key size in examined keyslot. It's valid for
default segment volume keys and in case of non-default segment
keys it always returns -1 and fallbacks to stored key size query
instead.
2019-11-28 16:38:52 +01:00
Ondrej Kozina
7eb47f3db1 Split reencryption locking in two variants. 2019-11-28 16:38:52 +01:00
Milan Broz
ec59d31d04 Remove AEAD tests dor MORUS and AEGIS ciphers.
These variants were removed from mainline kernel.
2019-11-25 23:16:53 +01:00
Milan Broz
ddd15b63b2 Add backward compatibility flags API.
We need to have some way hot to configure old integrity devices
with legacy padding.

For now, also use in tests to not fail checksum with new kernel.
2019-11-25 23:14:58 +01:00
Milan Broz
e91b35a53d Print info and warning if dm-integrity fix_padding is set.
The dump operation prints the fix_padding flag if set.

Also try to print warning if an old kernel is used and th edevice
cannot be activated because of missing fix padding support.
2019-11-25 19:48:54 +01:00
Mikulas Patocka
fb4079aa4d cryptsetup: add support for the "fix_padding" option
This patch adds support for fixed padding to cryptsetup.

* Cryptsetup will accept superblocks version 4.
* If the dm-integrity target version is greater than 1.4, cryptsetup will
  add a flag "fix_padding" to the dm-integrity target arguments.

There is still one quirk: if we have an old libdm without
DM_DEVICE_GET_TARGET_VERSION and if dm-integrity module is not loaded,
cryptsetup will not detect that it can use the "fix_padding" option.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
2019-11-24 20:58:47 +01:00
Milan Broz
48b203a134 Add crypt_resume_by_volume_key() function.
If user has volume key available, LUKS device can be resumed
directly using provided volume key.
No keyslot derivation is needed, only key digest is checked.

Fixes: #502.
2019-11-24 18:04:41 +01:00
Milan Broz
2746fd708f Implement active device suspend info.
Add CRYPT_ACTIVATE_SUSPENDED bit to crypt_get_active_device() flags
that informs the caller that device is suspended (luksSuspend).

Fixes: #501.
2019-11-24 16:56:26 +01:00
Ondrej Kozina
684f43d84d Clarify confirmation prompt text.
Fixes: #473
2019-11-22 15:34:16 +01:00
Milan Broz
6b1be52e6b Fix LUKS1 format if pkbdf benchamr is disabled.
We use minimum iteration for key digest in this case
(the same already used in LUKS2).

Fixes: #478.
2019-11-22 13:02:41 +01:00
Ondrej Kozina
de6258d366 Allow --test-passphrase for detached header alone.
Before this fix we required data device specified on cmd line
even though it was not necessary for testing passphrase.

Fixes: #487.
2019-11-19 14:36:06 +01:00
Ondrej Kozina
5e4dbf33be Allow --key-file option in legacy offline encryption.
The option was ignored for LUKS1 encryption initialization.

Fixes: #491.
2019-11-19 12:41:14 +01:00
Milan Broz
b03cb3f3d8 Export memory safe functions.
Make crypt_safe_alloc/realloc/free and memzero part of API.
2019-11-16 21:28:54 +01:00
Ondrej Kozina
e08401a2ec Properly fix encryption initialization message. 2019-11-08 13:15:37 +01:00
Ondrej Kozina
0a9e7028ae Fix LUKS2 encryption initialization with non-zero keyslot.
Positive keyslot number was interpreted as a failure.
2019-11-08 13:15:37 +01:00
Milan Broz
ba0ecc54df Test Bionic distro in Travis. 2019-11-05 22:09:05 +01:00
Milan Broz
6920f9dc27 Set devel version. 2019-11-05 17:56:58 +01:00
Milan Broz
ba2547212e Allow bitlk branch for CI tests. 2019-11-05 17:53:07 +01:00
Milan Broz
bbe1a8a5b6 Update Readme.md for 2.2.2. 2019-11-01 10:16:05 +01:00
Milan Broz
c82728f04d Version 2.2.2. 2019-11-01 09:02:46 +01:00
Milan Broz
cc0d33bca7 Fix DM_DEVICE_GET_TARGET_VERSION detection.
Stable libdevampper used changed name for dm task, let's fix it.
2019-10-31 20:35:46 +01:00
Milan Broz
3933ec7dce Add Ondra to authors. 2019-10-31 20:02:51 +01:00
Petr Pisar
f8c9507612 po: update cs.po (from translationproject.org) 2019-10-31 20:01:51 +01:00
Yuri Kozlov
7c5c9ae8fd po: update ru.po (from translationproject.org) 2019-10-31 12:10:04 +01:00
Frédéric Marchal
cd00792fe9 po: update fr.po (from translationproject.org) 2019-10-31 12:10:04 +01:00
Ondrej Kozina
df390509b2 Hotfix missing new line character in translated string.
Without this fix the message gets immediately overwritten with
reencryption progress bar.
2019-10-31 12:02:55 +01:00
Ondrej Kozina
dd6abe9375 Add luks2-reencryption-test to valgrind checks. 2019-10-22 15:07:57 +02:00
Milan Broz
a3f199d0a3 po: update pot file 2019-10-20 10:40:12 +02:00
Yuri Chornoivan
8e3b85ee12 po: update uk.po (from translationproject.org) 2019-10-20 10:35:43 +02:00
Jakub Bogusz
e60fbfc865 po: update pl.po (from translationproject.org) 2019-10-20 10:35:43 +02:00
Hiroshi Takekawa
a512488fd7 po: update ja.po (from translationproject.org) 2019-10-20 10:35:43 +02:00
Antonio Ceballos
1981d909cf po: update es.po (from translationproject.org) 2019-10-20 10:35:43 +02:00
Roland Illig
ea14f2c98c po: update de.po (from translationproject.org) 2019-10-20 10:35:43 +02:00
Milan Broz
c81becf10d Prepare version tag, and sync po files.
(For some reason I unsynced all po files again,
this patch reverts them to the translationproject versions...)
2019-10-18 10:52:33 +02:00
dofrupisla
1433d040ae Fix luksHeaderRestore occuring twice 2019-10-17 11:07:32 +02:00
Milan Broz
206b70c837 Explicitly print error message if keyslot open failed.
The only quiet message now is EPERM (wrong password) that is
processed by the caller.

Fixes #488.
2019-10-11 14:06:49 +02:00
Ondrej Kozina
bb857dcef2 Silence reencryption compat test. 2019-10-11 12:40:14 +02:00
Ondrej Kozina
5568a780a9 Add missing error message to translation. 2019-10-11 12:40:09 +02:00
Ondrej Kozina
7c2086967b Add various units for progress speed reporting.
The progress function remained silent unless the speed was higher
than minimal delta for double type in MiB/s. That could confuse
users that progress got stucked, but it in fact it was only slow.

Now wipe and reencryption progess functions can report speeds
in B/s up to GiB/s.
2019-10-11 12:40:03 +02:00
Ondrej Kozina
f7fbf4d38c Fix bogus speed reports after resuming tracked operation.
When resuming reencryption operation (both LUKS2 and legacy offline
code) speeds were incorectly calculated from whole progress including
range already reencrypted in previous runs. Now we track speed only
for currently running session.
2019-10-11 12:39:59 +02:00
Ondrej Kozina
0c8cf5c1e0 Switch cryptsetup-reencrypt to use tools_reencrypt_progress. 2019-10-11 12:39:51 +02:00
Milan Broz
33f2af1c09 Change --version option handling and support -V short option.
Fixes #480.
2019-10-10 10:51:04 +02:00
Ondrej Kozina
c9a7e6e4ec Add blkid wipe report messages to translations. 2019-10-08 15:31:57 +02:00
Ondrej Kozina
86bb4ea8f2 Report offsets when wiping device signatures.
Fixes: #489.
2019-10-08 15:31:57 +02:00
Milan Broz
99c4e83994 Properly support LTLIBINTL setting in Makefiles.
Fixes #479.
2019-10-08 15:26:13 +02:00
Milan Broz
ca2f5a8160 Fix tests in previous commits. 2019-10-08 14:58:07 +02:00
Milan Broz
7af304251e Fix activation message during encryption process. 2019-10-08 14:57:15 +02:00
Milan Broz
15f5126296 Support new DM_GET_TARGET_VERSION ioctl.
This way we can load kernel device-mapper target module before
table create ioctl.

Target version is available since kernel 5.4.
2019-10-08 14:05:30 +02:00
Ondrej Kozina
21edd66892 Allow LUKS2 reencryption to run on systems w/o kernel keyring service. 2019-10-07 14:08:41 +02:00
Ondrej Kozina
3e9d6b6960 Temporarily disable test failing due to deferred remove after decryption. 2019-10-04 13:46:13 +02:00
Ondrej Kozina
62b580904b Move check for loop device inside crypt_loop_backing_file.
It also fixes minor regression where we return backing file
for partition on top of loop device when prompting for passphrase.
Partition on loop has different major number so it should not be
considered loop device at all.
2019-10-04 13:46:13 +02:00
Ondrej Kozina
c4c4f9d159 Mark active device for deferred remove after decryption gets finished. 2019-10-04 12:20:34 +02:00
Ondrej Kozina
67a5ec1567 Abort reencryption initialization sooner on error. 2019-10-04 12:20:29 +02:00
Ondrej Kozina
c646832bfe Add hard and soft memory limit to reencrypt hotzone size.
Currently hard memory limit is 1 GiB. Soft limit is
1/4 of system memory.

Note that --hotzone-size cryptsetup parameter can only further
lower hard and soft memory limit on hotzone size and not bypass
it.
2019-10-04 12:20:22 +02:00
Ondrej Kozina
539d4756f2 Do not flush and freeze fs while swapping in/out overlay device. 2019-10-04 12:20:16 +02:00
Ondrej Kozina
8714e115ad Remove unused parameter from reencrypt_swap_backing_device.
It always loads dm-linear mapping in original device that maps 1:1
to helper overlay device (holding original table).
2019-10-04 12:20:12 +02:00
Ondrej Kozina
9c38e09ad3 Retain activation flags during and after online reencryption. 2019-10-04 12:20:06 +02:00
Ondrej Kozina
5628d7d8b5 Drop duplicite flag in LUKS2 device reload after reencryption.
Reload operation implicictly requires shared flag anyway and it's
added later.
2019-10-04 12:19:39 +02:00
Ondrej Kozina
5f2e8d6062 Allow LUKS2 device activation after encryption initialization.
It may be useful to activate device right after LUKS2 encryption
is initialized:

device is ready to use immediately even if data encryption runs in
the background for a long time

It simplifies encryption initialization during reboot.
2019-10-04 12:19:34 +02:00
Ondrej Kozina
630e336ea0 Do not allocate data device when identical with metadata device.
we do not need to allocate separate data device if it's equal
to metadata device during initialization.
2019-10-04 12:19:14 +02:00
Ondrej Kozina
430852736d Cleanup crypt_init_data_device.
data_device can not be NULL
2019-10-04 12:19:09 +02:00
Milan Broz
4eeb741358 Report kernel FIPS mode in module version test. 2019-10-03 14:01:27 +02:00
Ondrej Kozina
bb1ce4a069 Check plain crypt device is properly aligned on activation. 2019-10-02 13:40:10 +02:00
Ondrej Kozina
5e3e4a225e Check resize operation is aligned to device logical size.
Fixes #486.
2019-10-01 12:41:43 +02:00
Ondrej Kozina
583d05e32a Fix upconversion to LUKS2 with detached header.
The check for enough space before moving keyslots data did not expect real
detached header size to be less than aligned LUKS1 header size.

Also if detached header is placed in regular file we can grow so that
moved keyslots area fit the file.

Fixes #445.
2019-09-09 19:01:01 +02:00
Ondrej Kozina
2c0914b2ba Fix LUKS2 reencryption recovery test.
Fix corner case when head or tail of test device is remapped
to error target for writes.
2019-09-09 14:07:30 +02:00
Milan Broz
3ebedfe7b0 Update readme.md. 2019-09-06 13:13:44 +02:00
Milan Broz
1af2f85d43 Fix Release notes. 2019-09-06 12:49:31 +02:00
Milan Broz
0395e8935a Version 2.2.1. 2019-09-06 11:21:15 +02:00
Milan Broz
7ffd182197 Re-add cryptsetup.pot to git. 2019-09-06 10:53:34 +02:00
Milan Broz
fae1abdea9 Update gitignore (remove pot file). 2019-09-06 10:48:18 +02:00
Milan Broz
f17b8ad550 Update po files. 2019-09-06 10:02:15 +02:00
Milan Broz
883b600617 Update po files. 2019-09-02 11:22:06 +02:00
Yuri Chornoivan
f26a9abddb Fix minor typos 2019-09-02 09:20:47 +00:00
Milan Broz
4a7180a4f2 Clarify comments in API examples. 2019-08-30 16:24:56 +02:00
Milan Broz
af0c5c3ccb Set version to 2.2.1-rc0. 2019-08-30 13:15:17 +02:00
Milan Broz
a6e8db99b3 Fix test for very old kernels that truncate loop backing file info. 2019-08-30 10:41:04 +02:00
Milan Broz
e4684752c2 Update po file. 2019-08-30 09:42:27 +02:00
Milan Broz
4d6269a42d Fix some gcc warnings on 32bit systems. 2019-08-30 09:41:04 +02:00
Ondrej Kozina
593f5ee569 Reinstate missing backing file hint for loop device.
This regression was introduced in cryptsetup 2.0.0 release
with refactoring "Enter passphrase for (dev)" prompt.

With cryptsetup 1.7.5, "cryptsetup open /dev/loop0" printed
following prompt:

"Enter passphrase for /path/to/loop/backing_file:"

Whereas cryptsetup 2.0.0 and on printed following one:

"Enter passphrase for /dev/loop:"

Reported in https://bugzilla.redhat.com/show_bug.cgi?id=1726287

Fixes: 39698fa6b7 ("Remove terminal input from libcryptsetup API calls.")
Fixes: c80acbe4c8 ("Add back "Passphrase for (dev):" prompt.")
Fixes: 5171f65c05 ("tests only: Return back password retry support for luksOpen.")
2019-08-30 09:39:41 +02:00
Ondrej Kozina
4862e22cd0 Add opt-io size parameter to LUKS2 reencrypt test device.
So that we can test recovery is not broken for optimal io size
optimization added to reencryption code.
2019-08-30 09:39:38 +02:00
Ondrej Kozina
d13a6f7487 Take optimal io size in account with LUKS2 reencryption.
If device properly exposes optimal io size, let's align
reencryption hotzone to it. Otherwise device-mapper driver
complaints about misaligned tables and reencryption performance
is not optimal.
2019-08-30 09:39:35 +02:00
Milan Broz
09066b1ba6 Simplify API example and use LUKS2. 2019-08-29 13:07:32 +02:00
Milan Broz
8f8f0b3258 Fix mapped segments overflow on 32bit architectures.
All set_segment funcions must use uin64_t everywhere,
not size_t that is platform dependent.

The code later uses it correctly, it is just wrong function
prototype definitions.

Reported in
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=935702

(TODO: add a test for other segment types.)
2019-08-26 10:04:07 +02:00
Milan Broz
d9283970a5 Fix API test in FIPS mode. 2019-08-22 23:35:28 +02:00
Milan Broz
994afad279 Add veracrypt system encryption image. 2019-08-22 15:38:35 +02:00
Ondrej Kozina
b72ea28540 Fix regression in veracrypt system partition unlock.
Do not close base device file descriptor before reading from it.

Fixes #472.
2019-08-22 13:57:16 +02:00
Ondrej Kozina
fc69c6fac4 Add hint for online reencryption in cryptsetup-reencrypt man page.
command "man cryptsetup reencrypt" gets redirected to
cryptsetup-reencrypt man page. This may confuse users that LUKS2 online
reencryption is managed by offline utility.
2019-08-20 13:14:01 +02:00
Milan Broz
4100fd2817 Update Readme.md for 2.2.0. 2019-08-15 08:48:25 +02:00
Milan Broz
686744e48e Prepare version 2.2.0. 2019-08-14 20:38:23 +02:00
Milan Broz
0f49221f57 Add ja.po translation. 2019-08-14 20:37:40 +02:00
Milan Broz
725720dfc3 Fix volume key file if no LUKS2 keyslots are present.
If all keyslots are removed, LUKS2 has no longer information about
the volume key size (there is only key digest present).

If user wants to open or add new keyslot, it must get information
about key size externally.

We do not want to guess key size from the file size (it does not
work for block devices for example), so require explicit --keyfil
option in these cases.

Fixes #470.
2019-08-14 12:31:40 +02:00
Milan Broz
96cdb8edb7 Return error if keysize is 0.
Also use read_buffer to support partial read.
2019-08-14 12:18:04 +02:00
Milan Broz
7aa197be7d Print better warning if online reencrypt is called over LUKS1. 2019-08-14 08:14:02 +02:00
Ondrej Kozina
ea1dbfe961 Fix minimal size check for device in LUKS2 reencryption.
Commit 4c73da31 exposed another bug in minimal device size check.
During reencryption initialization wrong data offset value was used
and adjusted as if device was already undergoing reencryption. The
bug fixed by commit 4c73da31 hid this bug.

This is hotfix only and following functions needs more review:

- LUKS2_reencrypt_data_offset
- LUKS2_get_data_offset
- luks2_check_device_size
- LUKS2_get_data_size
2019-08-13 20:34:14 +02:00
Milan Broz
4c73da31ba Fix bugs found by Coverity. 2019-08-13 12:20:18 +02:00
Milan Broz
5febae8ad0 Fix warnings and flock access to test file in tests. 2019-08-13 10:36:41 +02:00
Milan Broz
d06f01a7d7 Update po files. 2019-08-13 09:26:04 +02:00
Ondrej Kozina
54d757a4c7 Fix illegal access to deallocated memory.
When deallocating context with LUKS2 reencryption handle
we access data device structure after being free'd.
2019-08-09 12:43:23 +02:00
Ondrej Kozina
a23e1cf729 LUKS2 code cleanup.
- drop unused code
- drop unused function declarations
- remove local routines from internal api
2019-08-05 18:29:37 +02:00
Ondrej Kozina
91879960e6 Move most of crypt_reencrypt_status to reencryption file. 2019-08-05 18:29:37 +02:00
Ondrej Kozina
270e6959b8 Make crypt_reencrypt_status return 'none' value for non-LUKS2 devices. 2019-08-05 18:29:37 +02:00
Ondrej Kozina
cbb3ca01f4 Reencryption code cleanup.
- Remove all 'LUKS2_' name prefixes from internal routines
- Make all internal routines prefixed with 'reencrypt_' instead
- Drop few static routines by refactoring
- Rename all variables and routines containing 'pre' prefix to
  contain 'hot' prefix instead (when referring to segments
  undergoing reencryption)
- Rename all variables and routines containing 'after' prefix to
  contain 'post' prefix instead
- Rename all routines prefixed with '_' to 'reencrypt_' instead
2019-08-05 18:29:35 +02:00
Ondrej Kozina
9845d6fd40 Shorten reencryption parameters debug message. 2019-08-05 18:28:15 +02:00
Ondrej Kozina
e5a59d6925 Remove json debug reencryption metadata fragments. 2019-08-05 18:28:15 +02:00
Ondrej Kozina
574170488c Update LUKS2 reencryption api tests. 2019-08-02 16:57:03 +02:00
Ondrej Kozina
9ea99efe13 Add test for absolute path passed to --active-name parameter. 2019-08-02 16:57:03 +02:00
Ondrej Kozina
b3af88708d Change reencryption mode parameter type to enum. 2019-08-01 15:40:53 +02:00
Ondrej Kozina
b96ce0b764 Add LUKS2 reencryption test for detached header misuse. 2019-08-01 10:43:57 +02:00
Ondrej Kozina
97ea39404a Allow reencryption to parse names prefixed with /dev. 2019-08-01 10:43:57 +02:00
Ondrej Kozina
4054f26c4d Add dm_device_name helper.
Gets dm name from absolute device path.
2019-08-01 10:43:57 +02:00
Ondrej Kozina
7380731bf7 Do not fail reencryption silently when --active-name is not LUKS2. 2019-08-01 10:43:57 +02:00
Ondrej Kozina
3bea349f9e Optionaly check device table before reencryption initialization. 2019-08-01 10:43:57 +02:00
Ondrej Kozina
98e0c8d609 Extend device table check in-before reencryption. 2019-08-01 10:43:57 +02:00
Ondrej Kozina
71f7385fcb Add support for linear segment in device comparison. 2019-08-01 10:43:57 +02:00
Ondrej Kozina
fbedf0ba6b Improve dm-crypt segments comparison function.
Check key descriptions are identical if both targets
were constructed using keys in kernel keyring service.
2019-08-01 10:40:37 +02:00
Ondrej Kozina
cf710eab13 Add internal crypt_compare_dm_devices. 2019-08-01 10:40:37 +02:00
Ondrej Kozina
b216a6a30e Introduce crypt_strcmp function (allows NULL). 2019-07-31 14:58:55 +02:00
Ondrej Kozina
b79086b3e9 Refactor assembly of multi-segment LUKS2 devices. 2019-07-31 14:58:55 +02:00
Ondrej Kozina
b551bdb0ce Make json_segments_count fn return unsigned value. 2019-07-31 14:58:55 +02:00
Ondrej Kozina
0886bc7afd Check for error sooner while assigning reencryption segments.
Also wraps function parameters definition.
2019-07-31 14:58:55 +02:00
Milan Broz
e7027e3d40 Revert back last cleanup call in api-test.
Removed by a mistake.
2019-07-31 12:15:49 +02:00
Milan Broz
243690b5ab Disalble luks2-reencryption-test in FIPE mode for now. 2019-07-31 12:03:44 +02:00
Milan Broz
5b5f76002e Fix various tests to run again in FIPS OpenSSL mode. 2019-07-31 10:27:58 +02:00
Milan Broz
fc03f1a1e6 Fix TCRYPT KDF failyure in FIPS mode.
SOme crypto backends now supports plain hash, but not PBKDF2 with
the same hash in FIPS mode.

Let's continue scanning other KDF if this error happens.
2019-07-31 10:25:54 +02:00
Milan Broz
1d59ae9aa9 Remove FIPS mode restriction for crypt_volume_key_get.
It is an application responsibility to use this API in the proper
context.
2019-07-30 14:12:50 +02:00
Milan Broz
8fde1b9f2c Mark API tests as skipped if setup phase fails. 2019-07-30 13:18:34 +02:00
Milan Broz
5e03f8c725 Always close context before failing API test.
Some devices could be still open delaying removal in cleanup.
2019-07-30 13:14:12 +02:00
Milan Broz
d6d4a50f7c Rename cd1-> cd in api test2. 2019-07-30 10:48:08 +02:00
Milan Broz
fe4e1de566 Mention limitiation of crypt_get_volume_key_size(). 2019-07-29 14:32:13 +02:00
Ondrej Kozina
e0d34b8f47 Add basic LUKS2 reencryption api test. 2019-07-26 16:20:36 +02:00
Ondrej Kozina
17c9d35449 Update reencryption flags description. 2019-07-26 16:09:38 +02:00
Ondrej Kozina
0e994265c6 Report data segment is moved in crypt_reencrypt_status. 2019-07-26 16:09:38 +02:00
Ondrej Kozina
e16319a290 Fail encryption initialization when data device too small. 2019-07-26 16:09:38 +02:00
Ondrej Kozina
c033643f07 Fix corner case bug in encryption with data shift.
If we initialized encryption with data shift and only single
segment the resulting metadata were missing
CRYPT_REENCRYPT_MOVE_FIRST_SEGMENT flag and also segments json section was
invalid.
2019-07-26 16:06:03 +02:00
Ondrej Kozina
607e2248c8 Simplify LUKS2_reencrypt_direction function. 2019-07-26 16:06:03 +02:00
Ondrej Kozina
a1111c7aa0 Tighten reencryption direction field validation. 2019-07-26 16:06:03 +02:00
Ondrej Kozina
1b82e70fc1 Fix bug in minimal device size calculation for reencryption. 2019-07-26 16:06:03 +02:00
Ondrej Kozina
35068c2e6e Fix broken segments calculation for backward data shift reencryption. 2019-07-26 16:06:03 +02:00
Ondrej Kozina
212703edf8 crypt_get_data_offset() must always return new offset value. 2019-07-26 16:06:03 +02:00
Ondrej Kozina
7460d1a446 Fix backward reencryption with data shift.
The device has to be shrunk the data shift size during activation.
Otherwise the online reencryption would fail with incorrect device
size.
2019-07-26 16:04:27 +02:00
Ondrej Kozina
c851205f83 Fix bug in reencryption digest to segment assignement. 2019-07-23 17:28:26 +02:00
Ondrej Kozina
dd0e073159 Fill direction field in crypt_reencrypt_status. 2019-07-23 17:28:26 +02:00
Ondrej Kozina
193b477086 Report reencryption data shift value in sectors. 2019-07-23 17:28:26 +02:00
Ondrej Kozina
3f85da0098 Fix datashift calculation in reencryption initialization. 2019-07-23 17:28:25 +02:00
Ondrej Kozina
dad28f3dfe Move exclusive open for offline reencryption in initialization. 2019-07-23 17:28:25 +02:00
Ondrej Kozina
e8e1da3fb5 Do not callback progress twice in reencryption loop. 2019-07-23 17:28:25 +02:00
Ondrej Kozina
4a24311161 Extend offline reencryption test for other keyslot numbers. 2019-07-15 14:36:36 +02:00
Ondrej Kozina
4f8c6b7773 Fix offline reencryption bug in header backup phase.
If first active keyslot number was different from zero the
decryption always failed.
2019-07-15 14:36:36 +02:00
Milan Broz
26fc2c24bd Update po files. 2019-07-15 10:26:13 +02:00
Ondrej Kozina
330f9daade Pass max_hotzone_size inside reencryption parameters in sectors. 2019-07-12 15:37:18 +02:00
Ondrej Kozina
4a232bc868 Pass device size inside reencryption parameters in sectors.
it was mistake in reencryption API. All other device sizes
related to device mapper devices are always in 512b setctors.
2019-07-12 15:37:18 +02:00
Ondrej Kozina
61dff96474 Reencryption keyslot must report as unbound. 2019-07-12 15:37:18 +02:00
Ondrej Kozina
bda28bbf38 Fix bug in crypt_keyslot_add_by_key. 2019-07-12 15:37:18 +02:00
Ondrej Kozina
66bedfd8e4 Fix LUKS2 reencryption recovery test.
Detect properly the case when recovery actually completed
encryption action for detached header case.
2019-07-12 15:37:18 +02:00
Ondrej Kozina
c18f968d84 Extend LUKS2 metadata size api tests. 2019-07-12 15:37:18 +02:00
Ondrej Kozina
5dfbc57117 Move LUKS2 metadata size api tests in separate routine. 2019-07-12 15:37:18 +02:00
Ondrej Kozina
e3fb6771d6 Re-enable mode test for LUKS2.
Since release 2.1.0 mode test for LUKS2 is skipped due to small test image.
Enforce smaller LUKS2 metadata via --offset to reenable the test.

Also detect failure for open action if format pass earlier.
2019-07-12 15:37:18 +02:00
Ondrej Kozina
f4da3c7f1b Add warning when changing explicitly requested LUKS2 metadata size. 2019-07-12 15:37:18 +02:00
Ondrej Kozina
81dbc9c070 Reduce implicit keyslots size when header device is too small.
Unless user explicitly asks for keyslots areas size
(either via --luks2-keyslots-size or --offset) reduce keyslots
size so that it fits in metadata device.
2019-07-12 15:37:08 +02:00
Ondrej Kozina
431bc87f85 Add LUKS2 error message hint when device too small.
If we format LUKS2 device with parameters unsuitable
for current metadata device size we usually fail during header areas
wipe. It was not clear what the reason actually was.
2019-07-12 15:12:46 +02:00
Milan Broz
b0e224a9f8 Update po file. 2019-07-01 10:19:14 +02:00
Ondrej Kozina
e3e6e75d40 Improvements to LUKS2 reencryption error messages.
- make error messages propagated to users more comprehensible
- drop some error messages completely
- replace many error messages with debug logs only

Fixes #458.
2019-07-01 10:18:55 +02:00
Ondrej Kozina
ed856f2ab8 Add tests for reencryption status reporting. 2019-07-01 10:18:52 +02:00
Ondrej Kozina
6425e1c52f Fix data device lookup among dm dependecies in crypt_init_by_name.
Also remove overlooked temporary debug message.
2019-07-01 10:18:49 +02:00
Ondrej Kozina
c842087cc1 Drop identical tests (already in compat-test). 2019-07-01 10:18:45 +02:00
Milan Broz
2651b381bb Update po files. 2019-06-29 10:43:28 +02:00
Yuri Chornoivan
4143d9871e Fix minor typos 2019-06-28 12:02:39 +00:00
Ondrej Kozina
fb9e467147 Add resize tests with --device-size parameter. 2019-06-27 14:40:06 +02:00
Ondrej Kozina
8b959158e3 Make resize action accept --device-size parameter (supports units).
Fixes #368.
2019-06-27 14:40:01 +02:00
Ondrej Kozina
ecb898c7ff Device size parameter must be always aligned to 512. 2019-06-27 14:39:59 +02:00
Milan Broz
c2b2b1ab5c Resync po files with the last translation.
(to be updated later)
2019-06-27 12:15:28 +02:00
Ondrej Kozina
d4682b3b38 Cleanup translated messages id.
- minimize count of almost identical message ids
- unify style for some messages
- remove some useless messages
2019-06-27 10:23:42 +02:00
Ondrej Kozina
2f4a50064f Add direction hint in reencryption hotzone device name. 2019-06-27 10:23:36 +02:00
Ondrej Kozina
6851535fe7 Add info about reencrytpion in LUKS2 status. 2019-06-27 10:23:08 +02:00
Ondrej Kozina
292a5f50b2 Allow offline reencryption on files without root privileges.
If userspace block ciphers are not available try kcapi first.
2019-06-27 10:19:23 +02:00
Ondrej Kozina
c25ce7c585 Allow disabling of reencryption locks via crypt_metadata_locking() 2019-06-27 10:19:18 +02:00
Ondrej Kozina
b22c9a86a9 Add internal crypt_zalloc routine (calloc wrapper). 2019-06-27 10:19:14 +02:00
Ondrej Kozina
767bb952a5 Enable crypt_init_by_name() for LUKS2 device on top of reencryption stack. 2019-06-27 10:19:12 +02:00
Ondrej Kozina
32e7178bbb Allow crypt_get_active_device for multi-segment devices. 2019-06-27 10:19:05 +02:00
Ondrej Kozina
614f671b92 Introduce SUBDEV internal device type.
LUKS2 and other device types allow stacking of dm devices
underneath public top level device.

The new type identifies clearly those private devices in respective
device stack so that they can be easily removed while removing
top level public device.

Switch LUKS2 reencryption device stack to use SUBDEV type immmediately
for hotzone and overlay devices. Other devices will follow in later
releases.
2019-06-27 10:19:01 +02:00
Ondrej Kozina
af62dbf3d3 Add internal limit for count of dm dependencies.
32 should be enough (+1 for terminating NULL byte)
2019-06-27 10:18:58 +02:00
Ondrej Kozina
249e6af3a6 Add LUKS2 uuid component in underlying dm-integrity device. 2019-06-27 10:18:56 +02:00
Ondrej Kozina
59bed375d0 Add type parameter to INTEGRITY_activate_dmd. 2019-06-27 10:18:54 +02:00
Ondrej Kozina
aba95b00aa Activate underlying dm-integrity privately for LUKS2 w/ auth. encryption. 2019-06-27 10:18:50 +02:00
Ondrej Kozina
011ee5b180 Introduce crypt_string_in internal helper.
And replace custom name_in_list function with new helper.
2019-06-27 10:18:47 +02:00
Ondrej Kozina
4e19719bdd Check hotzone size and device size alignment earlier.
It failed later but it was difficult to understand what went wrong.
2019-06-27 10:18:44 +02:00
Ondrej Kozina
fa469aaf41 Update struct crypt_params_reencrypt documentation. 2019-06-27 10:18:41 +02:00
Ondrej Kozina
3cabf608ca Unify reencryption context load error messages. 2019-06-27 10:18:37 +02:00
Milan Broz
2e841622f8 Print proper error message if LUKS2 slot encryption fail. 2019-06-26 17:30:30 +02:00
Milan Broz
9b5e3797b1 Fis status command to display only specific device types.
Cryptsetup, veritysetup and integrity setup should ignore other
device mappings in status command (it should display only
basic type information).
2019-06-25 15:03:04 +02:00
Seong-Joong Kim
07df177332 Fix a typo of comment 2019-06-24 22:31:52 -07:00
Milan Broz
ff364347cf Add FAIL backtrace to all bash tests. 2019-06-20 15:11:56 +02:00
Milan Broz
4c74ff5e5a Add ESSIV test in combination with AEAD data integrity protection. 2019-06-20 14:48:59 +02:00
Milan Broz
2ebd19c9bc Fix another EOL in api-test debug log. 2019-06-20 14:28:32 +02:00
Milan Broz
875ffa49b3 Fix log_dbg EOL in tools. 2019-06-19 12:12:02 +02:00
Ondrej Kozina
ff0030d74f Add missing --retry parameter in tests cleanup. 2019-06-18 13:26:20 +02:00
Ondrej Kozina
7a71feed8c Remove overlooked config scratching from reencryption tests. 2019-06-18 13:26:20 +02:00
Guilhem Moulin
70c4ce199d Fix minor spelling errors in manpage and messages.
Reported by lintian(1) - Static analysis tool for Debian packages:

accidentaly -> accidentally
trigerring -> triggering
alocate -> allocate
alignemnt -> alignment
initalize -> initialize
2019-06-18 09:42:28 +02:00
Alexander Neumann
ed0f8ccbaf Document all options for the --type parameter 2019-06-14 21:28:05 +02:00
Milan Broz
3e5ca2e168 Update readme.md. 2019-06-14 16:30:37 +02:00
Milan Broz
d0dc59e792 Update po file. 2019-06-14 13:54:23 +02:00
Ondrej Kozina
0106c64369 Fix issues reported by valgrind.
keyslot_cipher member leaked after existing LUKS2 context reload.

crypt_keyslot_set_encryption may access freed memory if
crypt_keyslot_get_encryption was previously called with
CRYPT_ANY_SLOT parameter.
2019-06-14 13:50:09 +02:00
Ondrej Kozina
69fdb41934 Add tests for LUKS2 reencryption with multiple active keyslots. 2019-06-14 09:10:28 +02:00
Ondrej Kozina
550b3ee1d3 Fix off-by-one error in reencryption keyslots count check. 2019-06-14 09:10:28 +02:00
Milan Broz
961cc6a6d3 Prepare version 2.2.0-rc1. 2019-06-14 08:20:04 +02:00
Ondrej Kozina
05091ab656 Improve reencryption when dealing with multiple keyslots.
It's possible to retain all keyslots (passphrases) when
performing LUKS2 reencryption provided there's enough
space in LUKS2 json metadata.

When specific keyslot is selected all other keyslots
bound to old volume key get deleted after reencryption
is finished.

Existing tokens are assigned to new keyslots.
2019-06-13 17:04:34 +02:00
Ondrej Kozina
272505b99d If no hash is specified in pbkdf use default value for keyslot AF. 2019-06-13 17:04:21 +02:00
Ondrej Kozina
60a769955b Rename hash data parameter in reencrypt keyslot dump. 2019-06-12 12:36:51 +02:00
Ondrej Kozina
34bec53474 Drop excessive nested locking in LUKS2 keyslot store path.
Since commit 80a435f it's not needed to call device_write_lock
in function luks2_encrypt_to_storage. It's handled correctly on
upper layer.
2019-06-12 12:36:51 +02:00
Ondrej Kozina
c77ae65a0d Wipe both keyslot data and metadata holding single write lock. 2019-06-12 12:36:51 +02:00
Ondrej Kozina
1ed0430b82 Move LUKS2 write lock upper when storing reencryption keyslot. 2019-06-12 12:36:51 +02:00
Ondrej Kozina
82f640e360 Open device in locked mode for wipe when necessary. 2019-06-12 12:36:51 +02:00
Ondrej Kozina
44aabc3ae4 Drop reload of metadata in reencryption initialization. 2019-06-12 12:36:50 +02:00
Ondrej Kozina
bbdf9b2745 Read and compare metadata sequence id after taking write lock. 2019-06-12 12:36:46 +02:00
Ondrej Kozina
96a87170f7 Return usage count from device locking functions. 2019-06-12 11:51:08 +02:00
Ondrej Kozina
281323db42 Fix condition for printing debug message. 2019-06-12 11:51:08 +02:00
Milan Broz
32258ee8ae Fix debugging messages callback.
The debug messages should contain EOL char.

Also check string lengths in internal logging macros.
2019-06-11 15:26:53 +02:00
Milan Broz
df0faef9ca Add integritysetup bitmap mode test. 2019-06-04 20:05:13 +02:00
Ondrej Kozina
9c3a020ecf Remove useless debug message from keyslot dump. 2019-05-27 16:23:56 +02:00
Ondrej Kozina
4c4cc55bb7 Wipe backup segment data after reencryption is finished. 2019-05-27 16:05:21 +02:00
Ondrej Kozina
f4c2e7e629 Implement LUKS2 reencrypt keyslot dump. 2019-05-27 15:27:23 +02:00
Ondrej Kozina
eadef08fd5 Extend LUKS2 reencryption recovery tests.
- test repair commad for reencryption recovery.
- test close command is able to teardown leftover device stack after
  crash.
- test open performs recovery by default (to be able to open root
  volume).
2019-05-24 17:29:56 +02:00
Ondrej Kozina
0c725a257d Compare moved segment specific size against real device size only. 2019-05-24 17:29:56 +02:00
Ondrej Kozina
6f35fb5f80 Silence query error messages for unsupported target types. 2019-05-24 17:29:56 +02:00
Ondrej Kozina
cd1fe75987 Close all device handlers after failed internal load. 2019-05-24 17:29:56 +02:00
Ondrej Kozina
e92e320956 Add explicit device_close routine. 2019-05-24 17:29:56 +02:00
Ondrej Kozina
0e4757e0fb Add LUKS2 reencryption recovery in repair command. 2019-05-24 17:29:56 +02:00
Ondrej Kozina
bd6af68bc5 Add support for explicit reencryption recovery in request. 2019-05-24 17:07:37 +02:00
Ondrej Kozina
13050f73c1 Properly finished reencryption after recovery. 2019-05-24 17:07:37 +02:00
Ondrej Kozina
5472fb0c56 Refactor reencryption recovery during activation. 2019-05-24 17:07:36 +02:00
Ondrej Kozina
73c2424b24 Refactor LUKS2 device activation (in reencryption). 2019-05-24 17:07:36 +02:00
Milan Broz
5117eda688 Switch to Xenial distro in Travis. 2019-05-24 08:33:20 +02:00
Ondrej Kozina
cfbef51d3d Add interactive dialog in case active device auto-detection fails. 2019-05-22 12:50:18 +02:00
Ondrej Kozina
09cb2d76ef Add dialog with default 'no' answer. 2019-05-22 12:50:17 +02:00
Ondrej Kozina
3f549ad0df Refactor yesDialog utility. 2019-05-22 12:50:17 +02:00
Ondrej Kozina
60d26be325 Load volume key in keyring when activated by token.
LUKS2 should use keyring for dm-crypt volume keys by default
when possible. crypt_activate_by_token didn't load keys in
keyring by default. It was a bug.
2019-05-21 18:08:00 +02:00
Ondrej Kozina
013d0d3753 Rename internal reencrypt enum to REENC_PROTECTION_NONE. 2019-05-21 18:08:00 +02:00
Ondrej Kozina
97da67c6a8 Add tests for reencryption with fixed device size. 2019-05-21 18:08:00 +02:00
Ondrej Kozina
f74072ba28 Silence active device detection message in batch mode. 2019-05-21 16:05:23 +02:00
Ondrej Kozina
19eac239b7 Add --device-size parameter for use in LUKS2 reencryption.
Currently it's used only in LUKS2 reencryption code
for reencrypting initial part of data device only.

It may be used to encrypt/reencrypt only initial part
of data device if user is aware that rest of the device
is empty.
2019-05-21 15:54:43 +02:00
Ondrej Kozina
31cd41bfe4 Add support for reencryption of initial device part.
It's useful to reencrypt only initial device part only.
For example with golden image reencryption it may be useful
to reencrypt only first X bytes of device because we know
the rest of device is empty.
2019-05-21 15:54:07 +02:00
Ondrej Kozina
af6c321395 Set default length for reencryption with resilience 'none' only. 2019-05-21 15:54:07 +02:00
Milan Broz
448fca1fdf Integritysetup: implement new bitmap mode. 2019-05-21 15:54:07 +02:00
Ondrej Kozina
1923928fdc Drop duplicate error message from reencrypt load. 2019-05-21 15:54:07 +02:00
Ondrej Kozina
bee5574656 Add --resume-only parameter to reencrypt command. 2019-05-21 15:54:07 +02:00
Ondrej Kozina
8c8a68d850 Add CRYPT_REENCRYPT_RESUME_ONLY flag. 2019-05-13 18:23:20 +02:00
Ondrej Kozina
9159b5b120 Add coverity toctou annotation in device_open_excl.
We can't avoid this race due to undefined behaviour if called with
O_EXCL flag on regular file.

Let's double-check fd with O_EXCL flag is actually open block device.
2019-05-13 18:23:20 +02:00
Ondrej Kozina
2d0079905e Adapt device_open_excl to reusing of fds. 2019-05-10 21:05:31 +02:00
Ondrej Kozina
83c227d53c Sync device using internal write enabled descriptor. 2019-05-10 21:05:31 +02:00
Ondrej Kozina
ee57b865b0 Reuse device file desriptors. 2019-05-10 21:05:31 +02:00
Milan Broz
ecbb9cfa90 Use upstream gnulib patch for Coverity warning fixed by previous patch. 2019-05-10 21:03:22 +02:00
Ondrej Kozina
8545e8496b Fix memleak in reencryption with moved segment. 2019-05-07 17:17:34 +02:00
Kamil Dudka
75b2610e85 Fix TAINTED_SCALAR false positives of Coverity
Coverity Analysis 2019.03 incorrectly marks the input argument
of base64_encode(), and conseuqnetly base64_encode_alloc(), as
tainted_data_sink because it sees byte-level operations on the input.
This one-line annotation makes Coverity suppress the following false
positives:

Error: TAINTED_SCALAR:
lib/luks2/luks2_digest_pbkdf2.c:117: tainted_data_argument: Calling function "crypt_random_get" taints argument "salt".
lib/luks2/luks2_digest_pbkdf2.c:157: tainted_data: Passing tainted variable "salt" to a tainted sink.

Error: TAINTED_SCALAR:
lib/luks2/luks2_keyslot_luks2.c:445: tainted_data_argument: Calling function "crypt_random_get" taints argument "salt".
lib/luks2/luks2_keyslot_luks2.c:448: tainted_data: Passing tainted variable "salt" to a tainted sink.
2019-05-07 15:35:55 +02:00
Milan Broz
237021ec15 Fix some warnings in static analysis. 2019-05-07 13:44:43 +02:00
Ondrej Kozina
4f5c25d0dd Add HAVE_DECL_DM_TASK_RETRY_REMOVE define in local tests. 2019-05-06 15:42:11 +02:00
Ondrej Kozina
4c33ab1997 Remove internal config file scratching (breaks local tests.) 2019-05-06 15:41:37 +02:00
Ondrej Kozina
5bb65aca8f Remove all test dm devices with retry option if available. 2019-05-06 15:37:35 +02:00
Milan Broz
3fd7babacc Update Readme.md. 2019-05-03 15:50:39 +02:00
Ondrej Kozina
caea8a9588 Update rc release notes. 2019-05-03 15:16:12 +02:00
Ondrej Kozina
e1d6cba014 Add reencryption action man page. 2019-05-03 15:00:33 +02:00
Milan Broz
1f91fe7a2c Use JSON-debug wrappers. 2019-05-03 14:02:43 +02:00
Milan Broz
dc53261c3b Fix data leak in format and reencrypt command. 2019-05-03 13:06:58 +02:00
Milan Broz
b3e90a93b0 Add test release notes and increase ABI version. 2019-05-03 12:57:29 +02:00
Milan Broz
1f3e2b770c Fix offline reencryption tool name. 2019-05-02 21:05:22 +02:00
Ondrej Kozina
d310e896cb Add basic offline tests for LUKS2 reencryption. 2019-05-02 17:23:59 +02:00
Ondrej Kozina
a36245cef6 Add new reencrypt cryptsetup action.
The new reencryption code is enabled via cryptsetup cli
and works with LUKS2 devices only.
2019-05-02 16:45:43 +02:00
Ondrej Kozina
092ef90f29 Add autodetection code for active dm device. 2019-05-02 16:44:23 +02:00
Ondrej Kozina
64f59ff71e Add reencryption progress function. 2019-05-02 16:44:23 +02:00
Ondrej Kozina
a7f80a2770 Add resilient LUKS2 reencryption library code. 2019-05-02 16:44:23 +02:00
Ondrej Kozina
a5c5e3e876 Add dm_device_deps for quering dm device dependencies. 2019-05-02 15:23:29 +02:00
Ondrej Kozina
8e4fb993c0 Add error target support in dm_query_device. 2019-05-02 15:23:29 +02:00
Ondrej Kozina
846567275a Move dm_query_device body in static function. 2019-05-02 15:23:28 +02:00
Ondrej Kozina
741c972935 Remove unused minor number from dm_is_dm_device. 2019-05-02 15:23:28 +02:00
Ondrej Kozina
6c2760c9cd Report data sync errors from storage wrapper. 2019-04-29 16:48:20 +02:00
Ondrej Kozina
b35a5ee4a3 Replace table with error mapping even when in use. 2019-04-29 16:10:57 +02:00
Ondrej Kozina
345385376a Add missing validation check for area type specification. 2019-04-29 16:10:57 +02:00
Milan Broz
dbe9db26fc Never serialize memory-hard KDF for small amount of memory. 2019-04-29 16:10:57 +02:00
Milan Broz
91ba22b157 Do not try to remove device that was not succesfully activated. 2019-04-29 16:10:57 +02:00
Ondrej Kozina
86b2736480 Drop unused type parameter from LUKS2_keyslot_find_empty() 2019-04-23 10:41:56 +02:00
Milan Broz
cfe2fb66ab Fix some untranslated error messages. 2019-04-23 10:41:06 +02:00
Milan Broz
428e61253c Fix dm_error_device() to properly use error device. 2019-04-10 15:06:07 +02:00
Milan Broz
95bcd0c9d5 Fix previous patch locking to return EBUSY. 2019-04-10 14:27:42 +02:00
Milan Broz
23bada3c5a Fix several issues found by Coverity scan. 2019-04-10 12:30:09 +02:00
Stig Otnes Kolstad
de0cf8433b Add pbkdf options to all key operations in manpage 2019-04-09 17:19:41 +02:00
Milan Broz
1b49ea4061 Add global serialization lock for memory hard PBKDF.
This is very ugly workaround for situation when multiple
devices are being activated in parallel (systemd crypttab)
and system  instead of returning ENOMEM use OOM killer
to randomly kill processes.

This flag is intended to be used only in very specific situations.
2019-03-29 11:58:12 +01:00
Ondrej Kozina
29b94d6ba3 Add arbitrary resource locking (named locks).
It's complementary to current device locking. It'll be used
for mutual exclusion of two or more reencryption resume processes
2019-03-26 14:48:27 +01:00
Ondrej Kozina
80a435f00b Write keyslot binary data and metadata holding single lock. 2019-03-25 11:37:32 +01:00
Ondrej Kozina
fdcd5806b1 Allow to change requirements flag in-memory only. 2019-03-25 11:37:32 +01:00
Ondrej Kozina
9ddcfce915 Refactor locking code. 2019-03-25 11:37:32 +01:00
Ondrej Kozina
6ba358533b Modify crypt lock handle internal structure.
makes it ready for future lock handle type
2019-03-25 11:37:32 +01:00
TrueDoctor
73aa329d57 fixed Grammar in manpage cryptsetup-reencrypt(8) 2019-03-22 23:20:13 +00:00
Ondrej Kozina
379016fd78 Add no flush internal suspend/resume flag. 2019-03-22 08:01:21 +01:00
Ondrej Kozina
ea4b586c77 Add tests for CRYPT_VOLUME_KEY_DIGEST_REUSE flag.
Tests commit 7569519530
2019-03-22 08:01:21 +01:00
Ondrej Kozina
6961f2caae Switch crypt_suspend() to DM_SUSPEND_WIPE_KEY flag. 2019-03-22 08:01:21 +01:00
Ondrej Kozina
4df2ce4409 Add wipe key flag for internal device suspend. 2019-03-22 08:01:21 +01:00
Ondrej Kozina
052a4f432c Add internal option to skip fs freeze in device suspend. 2019-03-22 08:01:21 +01:00
Ondrej Kozina
de86ff051e Introduce support for internal dm suspend/resume flags. 2019-03-22 08:01:21 +01:00
Ondrej Kozina
f5feeab48d Add experimental storage wrappers. 2019-03-22 08:01:21 +01:00
Milan Broz
1317af028e Use compatible switch for free command. 2019-03-21 15:32:22 +01:00
Milan Broz
cdcd4ddd35 Print free memory in tests. 2019-03-21 15:16:33 +01:00
Milan Broz
2960164cf8 Fix localtest if the last test is skipped. 2019-03-21 15:12:39 +01:00
Milan Broz
a98ef9787c Set devel version. 2019-03-20 21:58:27 +01:00
Milan Broz
b6d406fbc8 Add fixed Makefile that can run tests outside of compiled tree. 2019-03-20 21:58:07 +01:00
Ondrej Kozina
e3488292ba Fix typo in --disable-keyring description. 2019-03-13 15:24:45 +01:00
Ondrej Kozina
fea2e0be4f Add algorithm for searching largest gap in keyslots area. 2019-03-13 14:56:31 +01:00
Milan Broz
751f5dfda3 Move error message for a keyslot area search. 2019-03-13 14:56:31 +01:00
Ondrej Kozina
d5f71e66f9 Allow digest segment (un)binding for all segments at once. 2019-03-13 14:56:31 +01:00
Ondrej Kozina
03e810ec72 Split crypt_drop_keyring_key in two different routines.
crypt_drop_keyring_key function allow to drop all keys in keyring
assocatiated with passed volume key list.

crypt_drop_keyring_key_by_description is used to drop independent key.
2019-03-13 14:56:31 +01:00
Ondrej Kozina
6c6f4bcd45 Add signed int64 json helpers. 2019-03-13 14:56:31 +01:00
Ondrej Kozina
304942302b Introduce CRYPT_DEFAULT_SEGMENT abstraction.
Default segment is no longer constant segment with id 0.
2019-03-13 14:56:31 +01:00
Ondrej Kozina
8dc1a74df8 Adapt existing code to future reencryption changes. 2019-03-13 14:56:31 +01:00
Ondrej Kozina
e295d01505 Adding new functions later used in reencryption. 2019-03-13 14:56:31 +01:00
Ondrej Kozina
aa1b29ea0e Add volume key next helper. 2019-03-13 14:56:31 +01:00
Ondrej Kozina
cef857fbbd Add routine for adding volume key in a list. 2019-03-13 14:56:31 +01:00
Ondrej Kozina
6bba8ce0dc Allow vk insert in linked list.
Also adds search function crypt_volume_key_by_id.
2019-03-13 14:56:31 +01:00
Ondrej Kozina
b0330d62e5 Add id member in volume_key structure.
Also adds set/get helper routines.
2019-03-13 14:56:31 +01:00
Frederik Nnaji
fc0c857cfe Update README.md 2019-03-13 13:52:40 +00:00
Milan Broz
238b18b8ac Upstream fixes to bundled Argon2 code.
Wait for already running threads if a thread creation failed.
Use explicit_bzero() on recent glibc versions.
(Without fixed logic, we have already macro definition through automake.)

Fixes #444.
2019-03-13 08:26:40 +01:00
Ondrej Kozina
6a2d023b7b Make keyring utilities ready for additional kernel key types. 2019-03-08 09:03:35 +01:00
Ondrej Kozina
4bb1fff15d Add new functions for kernel keyring handling. 2019-03-08 08:54:09 +01:00
Ondrej Kozina
37f5bda227 Add explicit key type name in keyring functions. 2019-03-08 08:53:33 +01:00
Ondrej Kozina
56b571fcaa Use const before vk in all digest verify functions. 2019-03-08 08:52:47 +01:00
Ondrej Kozina
46bf3c9e9c Add segment create helpers. 2019-03-08 08:44:51 +01:00
Ondrej Kozina
361fb22954 Remove helper get_first_data_offset completely. 2019-03-08 08:43:19 +01:00
Ondrej Kozina
203fe0f4bf Move get_first_data_offset to luks2_segment.c 2019-03-08 08:42:23 +01:00
Ondrej Kozina
36ac5fe735 Move LUKS2 segments handling in separate file. 2019-03-08 08:39:32 +01:00
Ondrej Kozina
7569519530 Allow unbound keyslots to be assigned to existing digest.
If passed key matches any existing digest we will not create
new digest but assign the keyslot to already existing one.

Because reencryption should be able to create more than one
keyslot assigned to new key digest.

TODO: Tests for the new feature
2019-03-08 08:37:27 +01:00
Ondrej Kozina
a848179286 Add json_object_copy wrapper. 2019-03-08 08:27:18 +01:00
Milan Broz
456ab38caa Allow to set CRYPTSETUP_PATH in tests for system installed cryptsetup tools.
Run: make check CRYPTSETUP_PATH=/sbin
2019-03-08 08:16:45 +01:00
Milan Broz
c71b5c0426 Update po files. 2019-03-08 08:15:57 +01:00
Ondrej Kozina
868cc52415 Abort conversion to LUKS1 with incompatible sector size. 2019-03-05 17:08:05 +01:00
Ondrej Kozina
8c168cc337 Introduce file for luks2 segments handling. 2019-03-05 17:08:02 +01:00
Ondrej Kozina
f9fa4cc099 Add kernel only detection in crypt storage API. 2019-03-05 17:07:57 +01:00
Ondrej Kozina
a0540cafb3 alter crypt_storage interface
rename sector_start -> iv_start (it's now a iv shift for subsequent
en/decrypt operations)

rename count -> length. We accept length in bytes now and perform sanity
checks at the crypt_storage_init and crypt_storage_decrypt (or encrypt)
respectively.

rename sector -> offset. It's in bytes as well. Sanity checks inside
crypt_storage functions.
2019-03-05 17:07:45 +01:00
Ondrej Kozina
88b3924132 Update LUKS2 locks for atomic operations.
Atomic operation requires to hold a lock for longer period than
single metadata I/O. Update locks so that we can:

- lock a device more than once (lock ref counting)
- reaquire read lock on already held write lock (write lock
  is stronger than read lock)
2019-03-05 17:07:31 +01:00
Ondrej Kozina
3023f26911 Always allocate new header file of 4KiB.
All issues related to header wiping and smaller
files were resolved. It's no longer needed to allocate
files larger than 4KiB.
2019-03-05 16:55:17 +01:00
Milan Broz
c9347d3d7d Fix a gcc warning when accessing packed struct member. 2019-03-05 16:50:24 +01:00
Ondrej Kozina
d85c7d06af Do not fail tests if benchmarked >= 1000 iterations with -i1. 2019-03-01 21:43:35 +01:00
Ondrej Kozina
e229f79741 Open device in locked mode if needed. 2019-03-01 21:43:31 +01:00
Ondrej Kozina
a4d236eebe Add device_is_locked function. 2019-03-01 21:43:25 +01:00
Milan Broz
1192fd27c6 Add query for cipher implementation is used through kernel API. 2019-03-01 21:43:10 +01:00
Milan Broz
cd1cb40033 Use crypto library for ciphers if algorithms are available. 2019-03-01 21:34:22 +01:00
Milan Broz
14e085f70e Move cipher performance check to crypto backend. 2019-03-01 21:16:05 +01:00
Milan Broz
fc37d81144 Move crypt_cipher to per-lib implementation.
For now, it calls kernel fallback only.
2019-03-01 21:14:13 +01:00
Milan Broz
a859455aad Move block ciphers backend wrappers to per-library files.
For now it always fallbacks to kernel crypto API.
2019-03-01 21:10:50 +01:00
Milan Broz
93d596ace2 Introduce internal backend header.
And remove commented-out test vectors (moved to tests).
2019-03-01 20:39:33 +01:00
Ondrej Kozina
c03e3fe88a Fix getting default LUKS2 keyslot encryption parameters.
When information about original keyslot size is missing (no active
keyslot assigned to default segment) we have to fallback to
default luks2 encryption parameters even though we know default
segment cipher and mode.

Fixes: #442.
2019-03-01 20:39:06 +01:00
Ondrej Kozina
a90a5c9244 Avoid double free corruption after failed crypt_init_data_device. 2019-03-01 20:31:00 +01:00
Ondrej Kozina
26772f8184 Return NULL explicitly if keyslot is missing.
json_object_object_get_ex return parameter is
undefined if function returns false.
2019-03-01 20:30:21 +01:00
Ondrej Kozina
8f8ad83861 Validate metadata before writting binary keyslot area. 2019-03-01 20:29:49 +01:00
Ondrej Kozina
d111b42cf1 Fix keyslot area gap find algorithm.
get_max_offset must use value calculated from LUKS2 metadata
boundaries. Data offset didn't have to match end of LUKS2 metadata
area.
2019-03-01 20:29:40 +01:00
Ondrej Kozina
821c965b45 Drop commented code block. 2019-03-01 20:28:56 +01:00
Ondrej Kozina
4acac9a294 Properly handle DM_LINEAR type while checking version or dmflags. 2019-03-01 20:28:43 +01:00
Ondrej Kozina
4adb06ae91 Add missing direction flag in dm_crypt_target_set.
This bug may have caused memory corruption in dm_targets_free
later.
2019-03-01 20:27:53 +01:00
Milan Broz
dce7a1e2aa Fix gcc warning in tests. 2019-02-24 12:35:54 +01:00
Milan Broz
a354b72546 Add some symmetric block ciphers vector tests for crypto backend. 2019-02-24 12:35:50 +01:00
Milan Broz
ac8f41404b Simplify and reformat hash/HMAC test vectors test. 2019-02-24 12:35:45 +01:00
Milan Broz
fc7b257bab Silence dmsetup removal messages. 2019-02-13 13:34:39 +01:00
Milan Broz
787066c292 Report error if no LUKS keyslots are available.
Also fix LUKS1 keyslot function to proper return -ENOENT errno in this case.

This change means, that user can distinguish between bad passphrase and
no keyslot available. (But this information was avalilable with luksDump
even before the change.)
2019-02-13 13:19:48 +01:00
Milan Broz
71ab6cb818 Fix other tests to not fail if keyring support is missing in kernel. 2019-02-12 16:16:56 +01:00
Milan Broz
1158ba453e Use better test for a bad loop descriptor. 2019-02-12 14:54:56 +01:00
Milan Broz
2e3f764272 Fix api-test-2 to properly detect missing keyring in kernel.
Also properly cleanup after some failures.
2019-02-12 14:49:21 +01:00
Milan Broz
2172f1d2cd Print PBKDF debug log in a better format.
Fixes #439.
2019-02-11 12:37:33 +01:00
Milan Broz
6efc1eae9f Update Readme.md. 2019-02-08 15:37:17 +01:00
164 changed files with 41513 additions and 11220 deletions

1
.gitignore vendored
View File

@@ -36,7 +36,6 @@ missing
po/Makevars.template
po/POTFILES
po/Rules-quot
po/*.pot
po/*.header
po/*.sed
po/*.sin

View File

@@ -1,7 +1,7 @@
language: c
sudo: required
dist: trusty
dist: bionic
compiler:
- gcc
@@ -15,7 +15,6 @@ branches:
only:
- master
- wip-luks2
- v2_0_x
before_install:
- uname -a

View File

@@ -1,3 +1,4 @@
Jana Saout <jana@saout.de>
Clemens Fruhwirth <clemens@endorphin.org>
Milan Broz <gmazyland@gmail.com>
Ondrej Kozina <okozina@redhat.com>

View File

@@ -15,6 +15,8 @@ AM_CPPFLAGS = \
AM_CFLAGS = -Wall
AM_LDFLAGS =
LDADD = $(LTLIBINTL) -lm
tmpfilesddir = @DEFAULT_TMPFILESDIR@
noinst_LTLIBRARIES =

View File

@@ -2,13 +2,13 @@
What the ...?
=============
**Cryptsetup** is utility used to conveniently setup disk encryption based
on [DMCrypt](https://gitlab.com/cryptsetup/cryptsetup/wikis/DMCrypt) kernel module.
**Cryptsetup** is a utility used to conveniently set up disk encryption based
on the [DMCrypt](https://gitlab.com/cryptsetup/cryptsetup/wikis/DMCrypt) kernel module.
These include **plain** **dm-crypt** volumes, **LUKS** volumes, **loop-AES**
and **TrueCrypt** (including **VeraCrypt** extension) format.
These include **plain** **dm-crypt** volumes, **LUKS** volumes, **loop-AES**,
**TrueCrypt** (including **VeraCrypt** extension) and BitLocker formats.
Project also includes **veritysetup** utility used to conveniently setup
The project also includes a **veritysetup** utility used to conveniently setup
[DMVerity](https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity) block integrity checking kernel module
and, since version 2.0, **integritysetup** to setup
[DMIntegrity](https://gitlab.com/cryptsetup/cryptsetup/wikis/DMIntegrity) block integrity kernel module.
@@ -20,7 +20,10 @@ 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.
Last version of the LUKS format specification is
Last version of the LUKS2 format specification is
[available here](https://gitlab.com/cryptsetup/LUKS2-docs).
Last version of the LUKS1 format specification is
[available here](https://www.kernel.org/pub/linux/utils/cryptsetup/LUKS_docs/on-disk-format.pdf).
Why LUKS?
@@ -41,49 +44,28 @@ Download
--------
All release tarballs and release notes are hosted on [kernel.org](https://www.kernel.org/pub/linux/utils/cryptsetup/).
**The latest cryptsetup version is 2.0.6**
* [cryptsetup-2.0.6.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.6.tar.xz)
* Signature [cryptsetup-2.0.6.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.6.tar.sign)
**The latest testing cryptsetup version is 2.3.0-rc0**
* [cryptsetup-2.3.0-rc0.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/cryptsetup-2.3.0-rc0.tar.xz)
* Signature [cryptsetup-2.3.0-rc0.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/cryptsetup-2.3.0-rc0.tar.sign)
_(You need to decompress file first to check signature.)_
* [Cryptsetup 2.0.6 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.6-ReleaseNotes).
* [Cryptsetup 2.3.0-rc0 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/v2.3.0-rc0-ReleaseNotes).
**The latest stable cryptsetup version is 2.2.2**
* [cryptsetup-2.2.2.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.2/cryptsetup-2.2.2.tar.xz)
* Signature [cryptsetup-2.2.2.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.2/cryptsetup-2.2.2.tar.sign)
_(You need to decompress file first to check signature.)_
* [Cryptsetup 2.2.2 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.2/v2.2.2-ReleaseNotes).
Previous versions
* [Version 2.0.5](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.5.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.5.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.5-ReleaseNotes).
* [Version 2.0.4](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.4.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.4.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.4-ReleaseNotes).
* [Version 2.0.3](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.3.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.3.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.3-ReleaseNotes).
* [Version 2.0.2](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.2.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.2.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.2-ReleaseNotes).
* [Version 2.0.1](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.1.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.1.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.1-ReleaseNotes).
* [Version 2.0.0](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.0.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.0.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.0-ReleaseNotes).
* [Version 2.2.1](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.2/cryptsetup-2.2.1.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.2/cryptsetup-2.2.1.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.2/v2.2.0-ReleaseNotes).
* [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 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).
* [Version 1.7.4](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.4.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.4.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/v1.7.4-ReleaseNotes).
* [Version 1.7.3](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.3.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.3.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/v1.7.3-ReleaseNotes).
* [Version 1.7.2](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.2.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.2.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/v1.7.2-ReleaseNotes).
* [Version 1.7.1](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.1.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.1.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/v1.7.1-ReleaseNotes).
* [Version 1.7.0](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.0.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.0.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/v1.7.0-ReleaseNotes).
Source and API docs
-------------------

View File

@@ -1,9 +1,9 @@
AC_PREREQ([2.67])
AC_INIT([cryptsetup],[2.1.0])
AC_INIT([cryptsetup],[2.3.0])
dnl library version from <major>.<minor>.<release>[-<suffix>]
LIBCRYPTSETUP_VERSION=$(echo $PACKAGE_VERSION | cut -f1 -d-)
LIBCRYPTSETUP_VERSION_INFO=16:0:4
LIBCRYPTSETUP_VERSION_INFO=18:0:6
AM_SILENT_RULES([yes])
AC_CONFIG_SRCDIR(src/cryptsetup.c)
@@ -209,6 +209,8 @@ AC_DEFUN([CONFIGURE_GCRYPT], [
NO_FIPS([])
fi
AC_CHECK_DECLS([GCRY_CIPHER_MODE_XTS], [], [], [#include <gcrypt.h>])
if test "x$enable_static_cryptsetup" = "xyes"; then
saved_LIBS=$LIBS
LIBS="$saved_LIBS $LIBGCRYPT_LIBS -static"
@@ -346,6 +348,7 @@ AC_CHECK_DECLS([dm_task_retry_remove], [], [], [#include <libdevmapper.h>])
AC_CHECK_DECLS([dm_task_deferred_remove], [], [], [#include <libdevmapper.h>])
AC_CHECK_DECLS([dm_device_has_mounted_fs], [], [], [#include <libdevmapper.h>])
AC_CHECK_DECLS([dm_device_has_holders], [], [], [#include <libdevmapper.h>])
AC_CHECK_DECLS([DM_DEVICE_GET_TARGET_VERSION], [], [], [#include <libdevmapper.h>])
AC_CHECK_DECLS([DM_UDEV_DISABLE_DISK_RULES_FLAG], [have_cookie=yes], [have_cookie=no], [#include <libdevmapper.h>])
if test "x$enable_udev" = xyes; then
if test "x$have_cookie" = xno; then
@@ -359,6 +362,7 @@ LIBS=$saved_LIBS
dnl Check for JSON-C used in LUKS2
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 Crypto backend configuration.
AC_ARG_WITH([crypto_backend],

View File

@@ -1,7 +1,7 @@
/*
* An example of using logging through libcryptsetup API
* libcryptsetup API log example
*
* Copyright (C) 2011-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2020 Red Hat, Inc. All rights reserved.
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -25,10 +25,8 @@
#include <libcryptsetup.h>
/*
* This is an example of function that can be registered using crypt_set_log_callback API.
* This is an example of crypt_set_log_callback API callback.
*
* Its prototype is void (*log)(int level, const char *msg, void *usrptr) as defined
* in crypt_set_log_callback
*/
static void simple_syslog_wrapper(int level, const char *msg, void *usrptr)
{
@@ -71,7 +69,7 @@ int main(void)
return 2;
}
/* crypt_set_log_callback() - register a log function for crypt context */
/* crypt_set_log_callback() - register a log callback for crypt context */
crypt_set_log_callback(cd, &simple_syslog_wrapper, (void *)usrprefix);
/* send messages ithrough the crypt_log() interface */
@@ -83,7 +81,7 @@ int main(void)
/* release crypt context */
crypt_free(cd);
/* Initialize default (global) log function */
/* Initialize default (global) log callback */
crypt_set_log_callback(NULL, &simple_syslog_wrapper, NULL);
crypt_log(NULL, CRYPT_LOG_NORMAL, "This is normal log message");

View File

@@ -1,7 +1,7 @@
/*
* An example of using LUKS device through libcryptsetup API
* libcryptsetup API - using LUKS device example
*
* Copyright (C) 2011-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2020 Red Hat, Inc. All rights reserved.
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -29,23 +29,18 @@
static int format_and_add_keyslots(const char *path)
{
struct crypt_device *cd;
struct crypt_params_luks1 params;
int r;
/*
* crypt_init() call precedes most of operations of cryptsetup API. The call is used
* to initialize crypt device context stored in structure referenced by _cd_ in
* the example. Second parameter is used to pass underlaying device path.
* The crypt_init() call is used to initialize crypt_device context,
* The path parameter specifies a device path.
*
* Note:
* If path refers to a regular file it'll be attached to a first free loop device.
* crypt_init() operation fails in case there's no more loop device available.
* Also, loop device will have the AUTOCLEAR flag set, so the file loopback will
* be detached automatically.
* For path, you can use either link to a file or block device.
* The loopback device will be detached automatically.
*/
r = crypt_init(&cd, path);
if (r < 0 ) {
if (r < 0) {
printf("crypt_init() failed for %s.\n", path);
return r;
}
@@ -53,73 +48,37 @@ static int format_and_add_keyslots(const char *path)
printf("Context is attached to block device %s.\n", crypt_get_device_name(cd));
/*
* So far no data were written on your device. This will change with call of
* crypt_format() only if you specify CRYPT_LUKS1 as device type.
* So far, no data were written to the device.
*/
printf("Device %s will be formatted to LUKS device after 5 seconds.\n"
printf("Device %s will be formatted as a LUKS device after 5 seconds.\n"
"Press CTRL+C now if you want to cancel this operation.\n", path);
sleep(5);
/*
* Prepare LUKS format parameters
*
* hash parameter defines PBKDF2 hash algorithm used in LUKS header.
* For compatibility reason we use SHA1 here.
*/
params.hash = "sha1";
/*
* data_alignment parameter is relevant only in case of the luks header
* and the payload are both stored on same device.
*
* if you set data_alignment = 0, cryptsetup will autodetect
* data_alignment according to underlaying device topology.
*/
params.data_alignment = 0;
/*
* data_device parameter defines that no external device
* for luks header will be used
*/
params.data_device = NULL;
/*
* NULLs for uuid and volume_key means that these attributes will be
* generated during crypt_format(). Volume key is generated with respect
* to key size parameter passed to function.
*
* crypt_format() checks device size (LUKS header must fit there).
* generated during crypt_format().
*/
r = crypt_format(cd, /* crypt context */
CRYPT_LUKS1, /* LUKS1 is standard LUKS header */
CRYPT_LUKS2, /* LUKS2 is a new LUKS format; use CRYPT_LUKS1 for LUKS1 */
"aes", /* used cipher */
"xts-plain64", /* used block mode and IV generator*/
"xts-plain64", /* used block mode and IV */
NULL, /* generate UUID */
NULL, /* generate volume key from RNG */
256 / 8, /* 256bit key - here AES-128 in XTS mode, size is in bytes */
&params); /* parameters above */
512 / 8, /* 512bit key - here AES-256 in XTS mode, size is in bytes */
NULL); /* default parameters */
if(r < 0) {
if (r < 0) {
printf("crypt_format() failed on device %s\n", crypt_get_device_name(cd));
crypt_free(cd);
return r;
}
/*
* The device now contains LUKS1 header, but there is
* no active keyslot with encrypted volume key yet.
*/
/*
* cryptt_kesylot_add_* call stores volume_key in encrypted form into keyslot.
* Without keyslot you can't manipulate with LUKS device after the context will be freed.
* The device now contains a LUKS header, but there is no active keyslot.
*
* To create a new keyslot you need to supply the existing one (to get the volume key from) or
* you need to supply the volume key.
* crypt_keyslot_add_* call stores the volume_key in the encrypted form into the keyslot.
*
* After format, we have volume key stored internally in context so add new keyslot
* using this internal volume key.
* After format, the volume key is stored internally.
*/
r = crypt_keyslot_add_by_volume_key(cd, /* crypt context */
CRYPT_ANY_SLOT, /* just use first free slot */
@@ -137,8 +96,8 @@ static int format_and_add_keyslots(const char *path)
printf("The first keyslot is initialized.\n");
/*
* Add another keyslot, now using the first keyslot.
* It will decrypt volume key from the first keyslot and creates new one with another passphrase.
* Add another keyslot, now authenticating with the first keyslot.
* It decrypts the volume key from the first keyslot and creates a new one with the specified passphrase.
*/
r = crypt_keyslot_add_by_passphrase(cd, /* crypt context */
CRYPT_ANY_SLOT, /* just use first free slot */
@@ -164,21 +123,18 @@ static int activate_and_check_status(const char *path, const char *device_name)
/*
* LUKS device activation example.
* It's sequence of sub-steps: device initialization, LUKS header load
* and the device activation itself.
*/
r = crypt_init(&cd, path);
if (r < 0 ) {
if (r < 0) {
printf("crypt_init() failed for %s.\n", path);
return r;
}
/*
* crypt_load() is used to load the LUKS header from block device
* into crypt_device context.
* crypt_load() is used to load existing LUKS header from a block device
*/
r = crypt_load(cd, /* crypt context */
CRYPT_LUKS1, /* requested type */
CRYPT_LUKS, /* requested type - here LUKS of any type */
NULL); /* additional parameters (not used) */
if (r < 0) {
@@ -188,11 +144,11 @@ static int activate_and_check_status(const char *path, const char *device_name)
}
/*
* Device activation creates device-mapper devie mapping with name device_name.
* Device activation creates a device-mapper device with the specified name.
*/
r = crypt_activate_by_passphrase(cd, /* crypt context */
device_name, /* device name to activate */
CRYPT_ANY_SLOT,/* which slot use (ANY - try all) */
CRYPT_ANY_SLOT,/* the keyslot use (try all here) */
"foo", 3, /* passphrase */
CRYPT_ACTIVATE_READONLY); /* flags */
if (r < 0) {
@@ -201,13 +157,13 @@ static int activate_and_check_status(const char *path, const char *device_name)
return r;
}
printf("LUKS device %s/%s is active.\n", crypt_get_dir(), device_name);
printf("%s device %s/%s is active.\n", crypt_get_type(cd), crypt_get_dir(), device_name);
printf("\tcipher used: %s\n", crypt_get_cipher(cd));
printf("\tcipher mode: %s\n", crypt_get_cipher_mode(cd));
printf("\tdevice UUID: %s\n", crypt_get_uuid(cd));
/*
* Get info about active device (query DM backend)
* Get info about the active device.
*/
r = crypt_get_active_device(cd, device_name, &cad);
if (r < 0) {
@@ -235,7 +191,7 @@ static int handle_active_device(const char *device_name)
int r;
/*
* crypt_init_by_name() initializes device context and loads LUKS header from backing device
* crypt_init_by_name() initializes context by an active device-mapper name
*/
r = crypt_init_by_name(&cd, device_name);
if (r < 0) {
@@ -252,7 +208,7 @@ static int handle_active_device(const char *device_name)
}
/*
* crypt_deactivate() is used to deactivate device
* crypt_deactivate() is used to deactivate a device
*/
r = crypt_deactivate(cd, device_name);
if (r < 0) {

View File

@@ -46,7 +46,7 @@ Side effect of reencryption is that final device will contain
only ciphertext (for all sectors) so even if device was not properly
wiped by random data, after reencryption you cannot distinguish
which sectors are used.
(Reecryption is done always for the whole device.)
(Reencryption is done always for the whole device.)
There are for sure bugs, please TEST IT IN TEST ENVIRONMENT before
use for your data.

279
docs/v2.2.0-ReleaseNotes Normal file
View File

@@ -0,0 +1,279 @@
Cryptsetup 2.2.0 Release Notes
==============================
Stable release with new experimental features and bug fixes.
Cryptsetup 2.2 version introduces a new LUKS2 online reencryption
extension that allows reencryption of mounted LUKS2 devices
(device in use) in the background.
Online reencryption is a complex feature. Please be sure you
have a full data backup before using this feature.
Changes since version 2.1.0
~~~~~~~~~~~~~~~~~~~~~~~~~~~
LUKS2 online reencryption
~~~~~~~~~~~~~~~~~~~~~~~~~
The reencryption is intended to provide a reliable way to change
volume key or an algorithm change while the encrypted device is still
in use.
It is based on userspace-only approach (no kernel changes needed)
that uses the device-mapper subsystem to remap active devices on-the-fly
dynamically. The device is split into several segments (encrypted by old
key, new key and so-called hotzone, where reencryption is actively running).
The flexible LUKS2 metadata format is used to store intermediate states
(segment mappings) and both version of keyslots (old and new keys).
Also, it provides a binary area (in the unused keyslot area space)
to provide recovery metadata in the case of unexpected failure during
reencryption. LUKS2 header is during the reencryption marked with
"online-reencryption" keyword. After the reencryption is finished,
this keyword is removed, and the device is backward compatible with all
older cryptsetup tools (that support LUKS2).
The recovery supports three resilience modes:
- checksum: default mode, where individual checksums of ciphertext hotzone
sectors are stored, so the recovery process can detect which sectors were
already reencrypted. It requires that the device sector write is atomic.
- journal: the hotzone is journaled in the binary area
(so the data are written twice)
- none: performance mode; there is no protection
(similar to old offline reencryption)
These resilience modes are not available if reencryption uses data shift.
Note: until we have full documentation (both of the process and metadata),
please refer to Ondrej's slides (some slight details are no longer relevant)
https://okozina.fedorapeople.org/online-disk-reencryption-with-luks2-compact.pdf
The offline reencryption tool (cryptsetup-reencrypt) is still supported
for both LUKS1 and LUKS2 format.
Cryptsetup examples for reencryption
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The reencryption feature is integrated directly into cryptsetup utility
as the new "reencrypt" action (command).
There are three basic modes - to perform reencryption (change of already
existing LUKS2 device), to add encryption to plaintext device and to remove
encryption from a device (decryption).
In all cases, if existing LUKS2 metadata contains information about
the ongoing reencryption process, following reencrypt command continues
with the ongoing reencryption process until it is finished.
You can activate a device with ongoing reencryption as the standard LUKS2
device, but the reencryption process will not continue until the cryptsetup
reencrypt command is issued.
1) Reencryption
~~~~~~~~~~~~~~~
This mode is intended to change any attribute of the data encryption
(change of the volume key, algorithm or sector size).
Note that authenticated encryption is not yet supported.
You can start the reencryption process by specifying a LUKS2 device or with
a detached LUKS2 header.
The code should automatically recognize if the device is in use (and if it
should use online mode of reencryption).
If you do not specify parameters, only volume key is changed
(a new random key is generated).
# cryptsetup reencrypt <device> [--header <hdr>]
You can also start reencryption using active mapped device name:
# cryptsetup reencrypt --active-name <name>
You can also specify the resilience mode (none, checksum, journal) with
--resilience=<mode> option, for checksum mode also the hash algorithm with
--resilience-hash=<alg> (only hash algorithms supported by cryptographic
backend are available).
The maximal size of reencryption hotzone can be limited by
--hotzone-size=<size> option and applies to all reencryption modes.
Note that for checksum and journal mode hotzone size is also limited
by available space in binary keyslot area.
2) Encryption
~~~~~~~~~~~~~
This mode provides a way to encrypt a plaintext device to LUKS2 format.
This option requires reduction of device size (for LUKS2 header) or new
detached header.
# cryptsetup reencrypt <device> --encrypt --reduce-device-size <size>
Or with detached header:
# cryptsetup reencrypt <device> --encrypt --header <hdr>
3) Decryption
~~~~~~~~~~~~~
This mode provides the removal of existing LUKS2 encryption and replacing
a device with plaintext content only.
For now, we support only decryption with a detached header.
# cryptsetup reencrypt <device> --decrypt --header <hdr>
For all three modes, you can split the process to metadata initialization
(prepare keyslots and segments but do not run reencryption yet) and the data
reencryption step by using --init-only option.
Prepares metadata:
# cryptsetup reencrypt --init-only <parameters>
Starts the data processing:
# cryptsetup reencrypt <device>
Please note, that due to the Linux kernel limitation, the encryption or
decryption process cannot be run entirely online - there must be at least
short offline window where operation adds/removes device-mapper crypt (LUKS2) layer.
This step should also include modification of /etc/crypttab and fstab UUIDs,
but it is out of the scope of cryptsetup tools.
Limitations
~~~~~~~~~~~
Most of these limitations will be (hopefully) fixed in next versions.
* Only one active keyslot is supported (all old keyslots will be removed
after reencryption).
* Only block devices are now supported as parameters. As a workaround
for images in a file, please explicitly map a loop device over the image
and use the loop device as the parameter.
* Devices with authenticated encryption are not supported. (Later it will
be limited by the fixed per-sector metadata, per-sector metadata size
cannot be changed without a new device format operation.)
* The reencryption uses userspace crypto library, with fallback to
the kernel (if available). There can be some specific configurations
where the fallback does not provide optimal performance.
* There are no translations of error messages until the final release
(some messages can be rephrased as well).
* The repair command is not finished; the recovery of interrupted
reencryption is made automatically on the first device activation.
* Reencryption triggers too many udev scans on metadata updates (on closing
write enabled file descriptors). This has a negative performance impact on the whole
reencryption and generates excessive I/O load on the system.
New libcryptsetup reencryption API
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The libcryptsetup contains new API calls that are used to setup and
run the reencryption.
Note that there can be some changes in API implementation of these functions
and/or some new function can be introduced in final cryptsetup 2.2 release.
New API symbols (see documentation in libcryptsetup.h)
* struct crypt_params_reencrypt - reencryption parameters
* crypt_reencrypt_init_by_passphrase
* crypt_reencrypt_init_by_keyring
- function to configure LUKS2 metadata for reencryption;
if metadata already exists, it configures the context from this metadata
* crypt_reencrypt
- run the reencryption process (processing the data)
- the optional callback function can be used to interrupt the reencryption
or report the progress.
* crypt_reencrypt_status
- function to query LUKS2 metadata about the reencryption state
Other changes and fixes
~~~~~~~~~~~~~~~~~~~~~~~
* Add optional global serialization lock for memory hard PBKDF.
(The --serialize-memory-hard-pbkdf option in cryptsetup and
CRYPT_ACTIVATE_SERIALIZE_MEMORY_HARD_PBKDF in activation flag.)
This is an "ugly" optional workaround for a situation when multiple devices
are being activated in parallel (like systemd crypttab activation).
The system instead of returning ENOMEM (no memory available) starts
out-of-memory (OOM) killer to kill processes randomly.
Until we find a reliable way how to work with memory-hard function
in these situations, cryptsetup provide a way how to serialize memory-hard
unlocking among parallel cryptsetup instances to workaround this problem.
This flag is intended to be used only in very specific situations,
never use it directly :-)
* Abort conversion to LUKS1 with incompatible sector size that is
not supported in LUKS1.
* Report error (-ENOENT) if no LUKS keyslots are available. User can now
distinguish between a wrong passphrase and no keyslot available.
* Fix a possible segfault in detached header handling (double free).
* Add integritysetup support for bitmap mode introduced in Linux kernel 5.2.
Integritysetup now supports --integrity-bitmap-mode option and
--bitmap-sector-per-bit and --bitmap-flush-time commandline options.
In the bitmap operation mode, if a bit in the bitmap is 1, the corresponding
region's data and integrity tags are not synchronized - if the machine
crashes, the unsynchronized regions will be recalculated.
The bitmap mode is faster than the journal mode because we don't have
to write the data twice, but it is also less reliable, because if data
corruption happens when the machine crashes, it may not be detected.
This can be used only for standalone devices, not with dm-crypt.
* The libcryptsetup now keeps all file descriptors to underlying device
open during the whole lifetime of crypt device context to avoid excessive
scanning in udev (udev run scan on every descriptor close).
* The luksDump command now prints more info for reencryption keyslot
(when a device is in-reencryption).
* New --device-size parameter is supported for LUKS2 reencryption.
It may be used to encrypt/reencrypt only the initial part of the data
device if the user is aware that the rest of the device is empty.
Note: This change causes API break since the last rc0 release
(crypt_params_reencrypt structure contains additional field).
* New --resume-only parameter is supported for LUKS2 reencryption.
This flag resumes reencryption process if it exists (not starting
new reencryption).
* The repair command now tries LUKS2 reencryption recovery if needed.
* If reencryption device is a file image, an interactive dialog now
asks if reencryption should be run safely in offline mode
(if autodetection of active devices failed).
* Fix activation through a token where dm-crypt volume key was not
set through keyring (but using old device-mapper table parameter mode).
* Online reencryption can now retain all keyslots (if all passphrases
are provided). Note that keyslot numbers will change in this case.
* Allow volume key file to be used if no LUKS2 keyslots are present.
If all keyslots are removed, LUKS2 has no longer information about
the volume key size (there is only key digest present).
Please use --key-size option to open the device or add a new keyslot
in these cases.
* Print a warning if online reencrypt is called over LUKS1 (not supported).
* Fix TCRYPT KDF failure in FIPS mode.
Some crypto backends support plain hash in FIPS mode but not for PBKDF2.
* Remove FIPS mode restriction for crypt_volume_key_get.
It is an application responsibility to use this API in the proper context.
* Reduce keyslots area size in luksFormat when the header device is too small.
Unless user explicitly asks for keyslots areas size (either via
--luks2-keyslots-size or --offset) reduce keyslots size so that it fits
in metadata device.
* Make resize action accept --device-size parameter (supports units suffix).

36
docs/v2.2.1-ReleaseNotes Normal file
View File

@@ -0,0 +1,36 @@
Cryptsetup 2.2.1 Release Notes
==============================
Stable bug-fix release.
This version contains a fix for a possible data corruption bug
on 32-bit platforms.
All users of cryptsetup 2.1 and 2.2 should upgrade to this version.
Changes since version 2.2.0
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Fix possible data length and IV offset overflow on 32bit architectures.
Other 64-bit architectures are not affected.
The flawed helper function prototypes (introduced in version 2.1.0) used
size_t type, that is 32-bit integer on 32-bit systems.
This patch fixes the problem to properly use 64-bit types.
If the offset parameter addresses devices larger than 2TB, the value
overflows and stores incorrect information in the metadata.
For example, integrity device is smaller than expected size if used
over large disk on 32-bit architecture.
This issue is not present with the standard LUKS1/LUKS2 devices without
integrity extensions.
* Fix a regression in TrueCrypt/VeraCrypt system partition activation.
* Reinstate missing backing file hint for loop device.
If the encrypted device is backed by a file (loopback), cryptsetup now
shows the path to the backing file in passphrase query (as in 1.x version).
* LUKS2 reencryption block size is now aligned to reported optimal IO size.
This change eliminates possible non-aligned device warnings in kernel log
during reencryption.

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

@@ -0,0 +1,56 @@
Cryptsetup 2.2.2 Release Notes
==============================
Stable bug-fix release.
All users of cryptsetup 2.1 and 2.2 should upgrade to this version.
Changes since version 2.2.1
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Print error message if a keyslot open failed for a different reason
than wrong passwords (for example there is not enough memory).
Only an exit code was present in this case.
* The progress function switches unit sizes (B/s to GiB/s) according
to the actual speed. Also, it properly calculates speed in the case
of a resumed reencryption operation.
* The --version now supports short -V short option and better handles
common option priorities.
* If cryptsetup wipes signatures during format actions through blkid,
it also prints signature device offsets.
* Compilation now properly uses LTLIBINTL gettext setting in Makefiles.
* Device-mapper backend now supports new DM_GET_TARGET_VERSION ioctl
(available since Linux kernel 5.4).
This should help to detect some kernel/userspace incompatibilities
earlier later after a failed device activation.
* Fixes LUKS2 reencryption on systems without kernel keyring.
* Fixes unlocking prompt for partitions mapped through loop devices
(to properly show the backing device).
* For LUKS2 decryption, a device is now marked for deferred removal
to be automatically deactivated.
* Reencryption now limits hotzone size to be maximal 1 GiB or 1/4
system memory (if lower).
* Reencryption now retains activation flags during online reencryption.
* Reencryption now allows LUKS2 device to activate device right after
LUKS2 encryption is initialized through optional active device name
for cryptsetup reencrypt --encrypt command.
This could help with automated encryption during boot.
NOTE: It means that part of the device is still not encrypted during
activation. Use with care!
* Fixes failure in resize and plain format activation if activated device
size was not aligned to underlying logical device size.
* Fixes conversion to LUKS2 format with detached header if a detached
header size was smaller than the expected aligned LUKS1 header size.

209
docs/v2.3.0-ReleaseNotes Normal file
View File

@@ -0,0 +1,209 @@
Cryptsetup 2.3.0 Release Notes
==============================
Stable release with new experimental features and bug fixes.
Cryptsetup 2.3 version introduces support for BitLocker-compatible
devices (BITLK format). This format is used in Windows systems,
and in combination with a filesystem driver, cryptsetup now provides
native read-write access to BitLocker Full Disk Encryption devices.
The BITLK implementation is based on publicly available information
and it is an independent and opensource implementation that allows
to access this proprietary disk encryption.
Changes since version 2.2.2
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* BITLK (Windows BitLocker compatible) device access
BITLK userspace implementation is based on the master thesis and code
provided by Vojtech Trefny. Also, thanks to other opensource projects
like libbde (that provide alternative approach to decode this format)
we were able to verify cryptsetup implementation.
NOTE: Support for the BITLK device is EXPERIMENTAL and will require
a lot of testing. If you get some error message (mainly unsupported
metadata in the on-disk header), please help us by submitting an issue
to cryptsetup project, so we can fix it. Thank you!
Cryptsetup supports BITLK activation through passphrase or recovery
passphrase for existing devices (BitLocker and Bitlocker to Go).
Activation through TPM, SmartCard, or any other key protector
is not supported. And in some situations, mainly for TPM bind to some
PCR registers, it could be even impossible on Linux in the future.
All metadata (key protectors) are handled read-only, cryptsetup cannot
create or modify them. Except for old devices (created in old Vista
systems), all format variants should be recognized.
Data devices can be activated read-write (followed by mounting through
the proper filesystem driver). To access filesystem on the decrypted device
you need properly installed driver (vfat, NTFS or exFAT).
Foe AES-XTS, activation is supported on all recent Linux kernels.
For older AES-CBC encryption, Linux Kernel version 5.3 is required
(support for special IV variant); for AES-CBC with Elephant diffuser,
Linux Kernel 5.6 is required.
Please note that CBC variants are legacy, and we provide it only
for backward compatibility (to be able to access old drives).
Cryptsetup command now supports the new "bitlk" format and implement dump,
open, status, and close actions.
To activate a BITLK device, use
# cryptsetup open --type bitlk <device> <name>
or with alias
# cryptsetup bitlkOpen <device> <name>
Then with properly installed fs driver (usually NTFS, vfat or exFAT),
you can mount the plaintext device /dev/mapper<name> device as a common
filesystem.
To print metadata information about BITLK device, use
# crypotsetup bitlkDump <device>
To print information about the active device, use
# cryptsetup status <name>
Example (activation of disk image):
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Recent blkid recognizes BitLocker device,just to verity
# blkid bitlocker_xts_ntfs.img
bitlocker_xts_ntfs.img: TYPE="BitLocker"
# Print visible metadata information (on-disk, form the image)
# cryptsetup bitlkDump bitlocker_xts_ntfs.img
Info for BITLK device bitlocker_xts_ntfs.img.
Version: 2
GUID: ...
Created: Wed Oct 23 17:38:15 2019
Description: DESKTOP-xxxxxxx E: 23.10.2019
Cipher name: aes
Cipher mode: xts-plain64
Cipher key: 128 bits
Keyslots:
0: VMK
GUID: ...
Protection: VMK protected with passphrase
Salt: ...
Key data size: 44 [bytes]
1: VMK
GUID: ...
Protection: VMK protected with recovery passphrase
Salt: ...
Key data size: 44 [bytes]
2: FVEK
Key data size: 44 [bytes]
# Activation (recovery passphrase works the same as password)
# cryptsetup bitlkOpen bitlocker_xts_ntfs.img test -v
Enter passphrase for bitlocker_xts_ntfs.img:
Command successful.
# Information about the active device
# cryptsetup status test
/dev/mapper/test is active.
type: BITLK
cipher: aes-xts-plain64
keysize: 128 bits
...
# Plaintext device should now contain decrypted NTFS filesystem
# blkid /dev/mapper/test
/dev/mapper/test: UUID="..." TYPE="ntfs"
# And can be mounted
# mount /dev/mapper/test /mnt/tst
# Deactivation
# umount /mnt/tst
# cryptsetup close test
* Veritysetup now supports activation with additional PKCS7 signature
of root hash through --root-hash-signature option.
The signature uses an in-kernel trusted key to validate the signature
of the root hash during activation. This option requires Linux kernel
5.4 with DM_VERITY_VERIFY_ROOTHASH_SIG option.
Verity devices activated with signature now has a special flag
(with signature) active in device status (veritysetup status <name>).
Usage:
# veritysetup open <data_device> name <hash_device> <root_hash> \
--root-hash-signature=<roothash_p7_sig_file>
* Integritysetup now calculates hash integrity size according to algorithm
instead of requiring an explicit tag size.
Previously, when integritysetup formats a device with hash or
HMAC integrity checksums, it required explicitly tag size entry from
a user (or used default value).
This led to confusion and unexpected shortened tag sizes.
Now, libcryptsetup calculates tag size according to real hash output.
Tag size can also be specified, then it warns if these values differ.
* Integritysetup now supports fixed padding for dm-integrity devices.
There was an in-kernel bug that wasted a lot of space when using metadata
areas for integrity-protected devices if a larger sector size than
512 bytes was used.
This problem affects both stand-alone dm-integrity and also LUKS2 with
authenticated encryption and larger sector size.
The new extension to dm-integrity superblock is needed, so devices
with the new optimal padding cannot be activated on older systems.
Integritysetup/Cryptsetup will use new padding automatically if it
detects the proper kernel. To create a compatible device with
the old padding, use --integrity-legacy-padding option.
* A lot of fixes to online LUKS2 reecryption.
* Add crypt_resume_by_volume_key() function to libcryptsetup.
If a user has a volume key available, the LUKS device can be resumed
directly using the provided volume key.
No keyslot derivation is needed, only the key digest is checked.
* Implement active device suspend info.
Add CRYPT_ACTIVATE_SUSPENDED bit to crypt_get_active_device() flags
that informs the caller that device is suspended (luksSuspend).
* Allow --test-passphrase for a detached header.
Before this fix, we required a data device specified on the command
line even though it was not necessary for the passphrase check.
* Allow --key-file option in legacy offline encryption.
The option was ignored for LUKS1 encryption initialization.
* Export memory safe functions.
To make developing of some extensions simpler, we now export
functions to handle memory with proper wipe on deallocation.
* Fail crypt_keyslot_get_pbkdf for inactive LUKS1 keyslot.
Libcryptsetup API extensions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The libcryptsetup API is backward compatible for existing symbols.
New symbols
crypt_set_compatibility
crypt_get_compatibility;
crypt_resume_by_volume_key;
crypt_activate_by_signed_key;
crypt_safe_alloc;
crypt_safe_realloc;
crypt_safe_free;
crypt_safe_memzero;
New defines introduced :
CRYPT_BITLK "BITLK" - BITLK (BitLocker-compatible mode
CRYPT_COMPAT_LEGACY_INTEGRITY_PADDING - dm-integrity legacy padding
CRYPT_VERITY_ROOT_HASH_SIGNATURE - dm-verity root hash signature
CRYPT_ACTIVATE_SUSPENDED - device suspended info flag

View File

@@ -22,7 +22,8 @@ libcryptsetup_la_CPPFLAGS = $(AM_CPPFLAGS) \
-I $(top_srcdir)/lib/loopaes \
-I $(top_srcdir)/lib/verity \
-I $(top_srcdir)/lib/tcrypt \
-I $(top_srcdir)/lib/integrity
-I $(top_srcdir)/lib/integrity \
-I $(top_srcdir)/lib/bitlk
libcryptsetup_la_DEPENDENCIES = libutils_io.la libcrypto_backend.la lib/libcryptsetup.sym
@@ -64,6 +65,9 @@ libcryptsetup_la_SOURCES = \
lib/utils_device_locking.c \
lib/utils_device_locking.h \
lib/utils_pbkdf.c \
lib/utils_safe_memory.c \
lib/utils_storage_wrappers.c \
lib/utils_storage_wrappers.h \
lib/libdevmapper.c \
lib/utils_dm.h \
lib/volumekey.c \
@@ -97,9 +101,14 @@ libcryptsetup_la_SOURCES = \
lib/luks2/luks2_digest_pbkdf2.c \
lib/luks2/luks2_keyslot.c \
lib/luks2/luks2_keyslot_luks2.c \
lib/luks2/luks2_keyslot_reenc.c \
lib/luks2/luks2_reencrypt.c \
lib/luks2/luks2_segment.c \
lib/luks2/luks2_token_keyring.c \
lib/luks2/luks2_token.c \
lib/luks2/luks2_internal.h \
lib/luks2/luks2.h \
lib/utils_blkid.c \
lib/utils_blkid.h
lib/utils_blkid.h \
lib/bitlk/bitlk.h \
lib/bitlk/bitlk.c

View File

@@ -1,5 +1,5 @@
/* base64.c -- Encode binary data using printable characters.
Copyright (C) 1999-2001, 2004-2006, 2009-2018 Free Software Foundation, Inc.
Copyright (C) 1999-2001, 2004-2006, 2009-2019 Free Software Foundation, Inc.
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
@@ -70,7 +70,7 @@ base64_encode_fast (const char *restrict in, size_t inlen, char *restrict out)
{
while (inlen)
{
*out++ = b64c[to_uchar (in[0]) >> 2];
*out++ = b64c[(to_uchar (in[0]) >> 2) & 0x3f];
*out++ = b64c[((to_uchar (in[0]) << 4) + (to_uchar (in[1]) >> 4)) & 0x3f];
*out++ = b64c[((to_uchar (in[1]) << 2) + (to_uchar (in[2]) >> 6)) & 0x3f];
*out++ = b64c[to_uchar (in[2]) & 0x3f];
@@ -103,7 +103,7 @@ base64_encode (const char *restrict in, size_t inlen,
while (inlen && outlen)
{
*out++ = b64c[to_uchar (in[0]) >> 2];
*out++ = b64c[(to_uchar (in[0]) >> 2) & 0x3f];
if (!--outlen)
break;
*out++ = b64c[((to_uchar (in[0]) << 4)

View File

@@ -1,5 +1,5 @@
/* base64.h -- Encode binary data using printable characters.
Copyright (C) 2004-2006, 2009-2018 Free Software Foundation, Inc.
Copyright (C) 2004-2006, 2009-2019 Free Software Foundation, Inc.
Written by Simon Josefsson.
This program is free software; you can redistribute it and/or modify

1199
lib/bitlk/bitlk.c Normal file

File diff suppressed because it is too large Load Diff

130
lib/bitlk/bitlk.h Normal file
View File

@@ -0,0 +1,130 @@
/*
* BITLK (BitLocker-compatible) header definition
*
* Copyright (C) 2019-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2019-2020 Milan Broz
* Copyright (C) 2019-2020 Vojtech Trefny
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef _CRYPTSETUP_BITLK_H
#define _CRYPTSETUP_BITLK_H
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
struct crypt_device;
struct device;
#define BITLK_NONCE_SIZE 12
#define BITLK_SALT_SIZE 16
#define BITLK_VMK_MAC_TAG_SIZE 16
#define BITLK_STATE_NORMAL 0x0004
typedef enum {
BITLK_ENCRYPTION_TYPE_NORMAL = 0,
BITLK_ENCRYPTION_TYPE_EOW,
BITLK_ENCRYPTION_TYPE_UNKNOWN,
} BITLKEncryptionType;
typedef enum {
BITLK_PROTECTION_CLEAR_KEY = 0,
BITLK_PROTECTION_TPM,
BITLK_PROTECTION_STARTUP_KEY,
BITLK_PROTECTION_TPM_PIN,
BITLK_PROTECTION_RECOVERY_PASSPHRASE,
BITLK_PROTECTION_PASSPHRASE,
BITLK_PROTECTION_SMART_CARD,
BITLK_PROTECTION_UNKNOWN,
} BITLKVMKProtection;
typedef enum {
BITLK_ENTRY_TYPE_PROPERTY = 0x0000,
BITLK_ENTRY_TYPE_VMK = 0x0002,
BITLK_ENTRY_TYPE_FVEK = 0x0003,
BITLK_ENTRY_TYPE_STARTUP_KEY = 0x0006,
BITLK_ENTRY_TYPE_DESCRIPTION = 0x0007,
BITLK_ENTRY_TYPE_VOLUME_HEADER = 0x000f,
} BITLKFVEEntryType;
typedef enum {
BITLK_ENTRY_VALUE_ERASED = 0x0000,
BITLK_ENTRY_VALUE_KEY = 0x0001,
BITLK_ENTRY_VALUE_STRING = 0x0002,
BITLK_ENTRY_VALUE_STRETCH_KEY = 0x0003,
BITLK_ENTRY_VALUE_USE_KEY = 0x0004,
BITLK_ENTRY_VALUE_ENCRYPTED_KEY = 0x0005,
BITLK_ENTRY_VALUE_TPM_KEY = 0x0006,
BITLK_ENTRY_VALUE_VALIDATION = 0x0007,
BITLK_ENTRY_VALUE_VMK = 0x0008,
BITLK_ENTRY_VALUE_EXTERNAL_KEY = 0x0009,
BITLK_ENTRY_VALUE_OFFSET_SIZE = 0x000f,
BITLK_ENTRY_VALUE_RECOVERY_TIME = 0x015,
} BITLKFVEEntryValue;
struct bitlk_vmk {
char *guid;
char *name;
BITLKVMKProtection protection;
uint8_t salt[BITLK_SALT_SIZE];
uint8_t mac_tag[BITLK_VMK_MAC_TAG_SIZE];
uint8_t nonce[BITLK_NONCE_SIZE];
struct volume_key *vk;
struct bitlk_vmk *next;
};
struct bitlk_fvek {
uint8_t mac_tag[BITLK_VMK_MAC_TAG_SIZE];
uint8_t nonce[BITLK_NONCE_SIZE];
struct volume_key *vk;
};
struct bitlk_metadata {
bool togo;
bool state;
BITLKEncryptionType type;
const char *cipher;
const char *cipher_mode;
uint16_t key_size;
char *guid;
uint64_t creation_time;
char *description;
uint64_t metadata_offset[3];
uint32_t metadata_version;
uint64_t volume_header_offset;
uint64_t volume_header_size;
struct bitlk_vmk *vmks;
struct bitlk_fvek *fvek;
};
int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params);
int BITLK_dump(struct crypt_device *cd, struct device *device, struct bitlk_metadata *params);
int BITLK_activate(struct crypt_device *cd,
const char *name,
const char *password,
size_t passwordLen,
const struct bitlk_metadata *params,
uint32_t flags);
void BITLK_bitlk_fvek_free(struct bitlk_fvek *fvek);
void BITLK_bitlk_vmk_free(struct bitlk_vmk *vmk);
void BITLK_bitlk_metadata_free(struct bitlk_metadata *params);
#endif

View File

@@ -2,8 +2,8 @@
* cryptsetup plain device helper functions
*
* Copyright (C) 2004 Jana Saout <jana@saout.de>
* Copyright (C) 2010-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2019 Milan Broz
* Copyright (C) 2010-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2020 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

View File

@@ -4,12 +4,14 @@ libcrypto_backend_la_CFLAGS = $(AM_CFLAGS) @CRYPTO_CFLAGS@
libcrypto_backend_la_SOURCES = \
lib/crypto_backend/crypto_backend.h \
lib/crypto_backend/crypto_backend_internal.h \
lib/crypto_backend/crypto_cipher_kernel.c \
lib/crypto_backend/crypto_storage.c \
lib/crypto_backend/pbkdf_check.c \
lib/crypto_backend/crc32.c \
lib/crypto_backend/argon2_generic.c \
lib/crypto_backend/cipher_generic.c
lib/crypto_backend/cipher_generic.c \
lib/crypto_backend/cipher_check.c
if CRYPTO_BACKEND_GCRYPT
libcrypto_backend_la_SOURCES += lib/crypto_backend/crypto_gcrypt.c

View File

@@ -125,7 +125,7 @@ void NOT_OPTIMIZED secure_wipe_memory(void *v, size_t n) {
SecureZeroMemory(v, n);
#elif defined memset_s
memset_s(v, n, 0, n);
#elif defined(__OpenBSD__)
#elif defined(HAVE_EXPLICIT_BZERO)
explicit_bzero(v, n);
#else
static void *(*const volatile memset_sec)(void *, int, size_t) = &memset;
@@ -299,7 +299,7 @@ static int fill_memory_blocks_mt(argon2_instance_t *instance) {
for (r = 0; r < instance->passes; ++r) {
for (s = 0; s < ARGON2_SYNC_POINTS; ++s) {
uint32_t l;
uint32_t l, ll;
/* 2. Calling threads */
for (l = 0; l < instance->lanes; ++l) {
@@ -324,6 +324,9 @@ static int fill_memory_blocks_mt(argon2_instance_t *instance) {
sizeof(argon2_position_t));
if (argon2_thread_create(&thread[l], &fill_segment_thr,
(void *)&thr_data[l])) {
/* Wait for already running threads */
for (ll = 0; ll < l; ++ll)
argon2_thread_join(thread[ll]);
rc = ARGON2_THREAD_FAIL;
goto fail;
}

View File

@@ -1,8 +1,8 @@
/*
* Argon2 PBKDF2 library wrapper
*
* Copyright (C) 2016-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2019 Milan Broz
* Copyright (C) 2016-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2020 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -20,7 +20,7 @@
*/
#include <errno.h>
#include "crypto_backend.h"
#include "crypto_backend_internal.h"
#if HAVE_ARGON2_H
#include <argon2.h>
#else
@@ -77,117 +77,3 @@ int argon2(const char *type, const char *password, size_t password_length,
return r;
#endif
}
#if 0
#include <stdio.h>
struct test_vector {
argon2_type type;
unsigned int memory;
unsigned int iterations;
unsigned int parallelism;
const char *password;
unsigned int password_length;
const char *salt;
unsigned int salt_length;
const char *key;
unsigned int key_length;
const char *ad;
unsigned int ad_length;
const char *output;
unsigned int output_length;
};
struct test_vector test_vectors[] = {
/* Argon2 RFC */
{
Argon2_i, 32, 3, 4,
"\x01\x01\x01\x01\x01\x01\x01\x01"
"\x01\x01\x01\x01\x01\x01\x01\x01"
"\x01\x01\x01\x01\x01\x01\x01\x01"
"\x01\x01\x01\x01\x01\x01\x01\x01", 32,
"\x02\x02\x02\x02\x02\x02\x02\x02"
"\x02\x02\x02\x02\x02\x02\x02\x02", 16,
"\x03\x03\x03\x03\x03\x03\x03\x03", 8,
"\x04\x04\x04\x04\x04\x04\x04\x04"
"\x04\x04\x04\x04", 12,
"\xc8\x14\xd9\xd1\xdc\x7f\x37\xaa"
"\x13\xf0\xd7\x7f\x24\x94\xbd\xa1"
"\xc8\xde\x6b\x01\x6d\xd3\x88\xd2"
"\x99\x52\xa4\xc4\x67\x2b\x6c\xe8", 32
},
{
Argon2_id, 32, 3, 4,
"\x01\x01\x01\x01\x01\x01\x01\x01"
"\x01\x01\x01\x01\x01\x01\x01\x01"
"\x01\x01\x01\x01\x01\x01\x01\x01"
"\x01\x01\x01\x01\x01\x01\x01\x01", 32,
"\x02\x02\x02\x02\x02\x02\x02\x02"
"\x02\x02\x02\x02\x02\x02\x02\x02", 16,
"\x03\x03\x03\x03\x03\x03\x03\x03", 8,
"\x04\x04\x04\x04\x04\x04\x04\x04"
"\x04\x04\x04\x04", 12,
"\x0d\x64\x0d\xf5\x8d\x78\x76\x6c"
"\x08\xc0\x37\xa3\x4a\x8b\x53\xc9"
"\xd0\x1e\xf0\x45\x2d\x75\xb6\x5e"
"\xb5\x25\x20\xe9\x6b\x01\xe6\x59", 32
}
};
static void printhex(const char *s, const char *buf, size_t len)
{
size_t i;
printf("%s: ", s);
for (i = 0; i < len; i++)
printf("\\x%02x", (unsigned char)buf[i]);
printf("\n");
fflush(stdout);
}
static int argon2_test_vectors(void)
{
char result[64];
int i, r;
struct test_vector *vec;
argon2_context context;
printf("Argon2 running test vectors\n");
for (i = 0; i < (sizeof(test_vectors) / sizeof(*test_vectors)); i++) {
vec = &test_vectors[i];
memset(result, 0, sizeof(result));
memset(&context, 0, sizeof(context));
context.flags = ARGON2_DEFAULT_FLAGS;
context.version = ARGON2_VERSION_NUMBER;
context.out = (uint8_t *)result;
context.outlen = (uint32_t)vec->output_length;
context.pwd = (uint8_t *)vec->password;
context.pwdlen = (uint32_t)vec->password_length;
context.salt = (uint8_t *)vec->salt;
context.saltlen = (uint32_t)vec->salt_length;
context.secret = (uint8_t *)vec->key;
context.secretlen = (uint32_t)vec->key_length;;
context.ad = (uint8_t *)vec->ad;
context.adlen = (uint32_t)vec->ad_length;
context.t_cost = vec->iterations;
context.m_cost = vec->memory;
context.lanes = vec->parallelism;
context.threads = vec->parallelism;
r = argon2_ctx(&context, vec->type);
if (r != ARGON2_OK) {
printf("Argon2 failed %i, vector %d\n", r, i);
return -EINVAL;
}
if (memcmp(result, vec->output, vec->output_length) != 0) {
printf("vector %u\n", i);
printhex(" got", result, vec->output_length);
printhex("want", vec->output, vec->output_length);
return -EINVAL;
}
}
return 0;
}
#endif

View File

@@ -0,0 +1,157 @@
/*
* Cipher performance check
*
* Copyright (C) 2018-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2018-2020 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <errno.h>
#include <time.h>
#include "crypto_backend_internal.h"
/*
* This is not simulating storage, so using disk block causes extreme overhead.
* Let's use some fixed block size where results are more reliable...
*/
#define CIPHER_BLOCK_BYTES 65536
/*
* If the measured value is lower, encrypted buffer is probably too small
* and calculated values are not reliable.
*/
#define CIPHER_TIME_MIN_MS 0.001
/*
* The whole test depends on Linux kernel usermode crypto API for now.
* (The same implementations are used in dm-crypt though.)
*/
static int time_ms(struct timespec *start, struct timespec *end, double *ms)
{
double start_ms, end_ms;
start_ms = start->tv_sec * 1000.0 + start->tv_nsec / (1000.0 * 1000);
end_ms = end->tv_sec * 1000.0 + end->tv_nsec / (1000.0 * 1000);
*ms = end_ms - start_ms;
return 0;
}
static int cipher_perf_one(const char *name, const char *mode, char *buffer, size_t buffer_size,
const char *key, size_t key_size, const char *iv, size_t iv_size, int enc)
{
struct crypt_cipher_kernel cipher;
size_t done = 0, block = CIPHER_BLOCK_BYTES;
int r;
if (buffer_size < block)
block = buffer_size;
r = crypt_cipher_init_kernel(&cipher, name, mode, key, key_size);
if (r < 0)
return r;
while (done < buffer_size) {
if ((done + block) > buffer_size)
block = buffer_size - done;
if (enc)
r = crypt_cipher_encrypt_kernel(&cipher, &buffer[done], &buffer[done],
block, iv, iv_size);
else
r = crypt_cipher_decrypt_kernel(&cipher, &buffer[done], &buffer[done],
block, iv, iv_size);
if (r < 0)
break;
done += block;
}
crypt_cipher_destroy_kernel(&cipher);
return r;
}
static int cipher_measure(const char *name, const char *mode, char *buffer, size_t buffer_size,
const char *key, size_t key_size, const char *iv, size_t iv_size,
int encrypt, double *ms)
{
struct timespec start, end;
int r;
/*
* Using getrusage would be better here but the precision
* is not adequate, so better stick with CLOCK_MONOTONIC
*/
if (clock_gettime(CLOCK_MONOTONIC_RAW, &start) < 0)
return -EINVAL;
r = cipher_perf_one(name, mode, buffer, buffer_size, key, key_size, iv, iv_size, encrypt);
if (r < 0)
return r;
if (clock_gettime(CLOCK_MONOTONIC_RAW, &end) < 0)
return -EINVAL;
r = time_ms(&start, &end, ms);
if (r < 0)
return r;
if (*ms < CIPHER_TIME_MIN_MS)
return -ERANGE;
return 0;
}
static double speed_mbs(unsigned long bytes, double ms)
{
double speed = bytes, s = ms / 1000.;
return speed / (1024 * 1024) / s;
}
int crypt_cipher_perf_kernel(const char *name, const char *mode, char *buffer, size_t buffer_size,
const char *key, size_t key_size, const char *iv, size_t iv_size,
double *encryption_mbs, double *decryption_mbs)
{
double ms_enc, ms_dec, ms;
int r, repeat_enc, repeat_dec;
ms_enc = 0.0;
repeat_enc = 1;
while (ms_enc < 1000.0) {
r = cipher_measure(name, mode, buffer, buffer_size, key, key_size, iv, iv_size, 1, &ms);
if (r < 0)
return r;
ms_enc += ms;
repeat_enc++;
}
ms_dec = 0.0;
repeat_dec = 1;
while (ms_dec < 1000.0) {
r = cipher_measure(name, mode, buffer, buffer_size, key, key_size, iv, iv_size, 0, &ms);
if (r < 0)
return r;
ms_dec += ms;
repeat_dec++;
}
*encryption_mbs = speed_mbs(buffer_size * repeat_enc, ms_enc);
*decryption_mbs = speed_mbs(buffer_size * repeat_dec, ms_dec);
return 0;
}

View File

@@ -1,8 +1,8 @@
/*
* Linux kernel cipher generic utilities
*
* Copyright (C) 2018-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2018-2019 Milan Broz
* Copyright (C) 2018-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2018-2020 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

View File

@@ -19,7 +19,7 @@
* order from highest-order term to lowest-order term. UARTs transmit
* characters in order from LSB to MSB. By storing the CRC this way,
* we hand it to the UART in the order low-byte to high-byte; the UART
* sends each low-bit to hight-bit; and the result is transmission bit
* sends each low-bit to high-bit; and the result is transmission bit
* by bit from highest- to lowest-order term without requiring any bit
* shuffling on our part. Reception works similarly.
*
@@ -42,7 +42,6 @@
#include "crypto_backend.h"
static const uint32_t crc32_tab[] = {
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
@@ -113,4 +112,3 @@ uint32_t crypt_crc32(uint32_t seed, const unsigned char *buf, size_t len)
return crc;
}

View File

@@ -1,8 +1,8 @@
/*
* crypto backend implementation
*
* Copyright (C) 2010-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2019 Milan Broz
* Copyright (C) 2010-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2020 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -22,6 +22,7 @@
#define _CRYPTO_BACKEND_H
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
@@ -58,14 +59,15 @@ void crypt_hmac_destroy(struct crypt_hmac *ctx);
enum { CRYPT_RND_NORMAL = 0, CRYPT_RND_KEY = 1, CRYPT_RND_SALT = 2 };
int crypt_backend_rng(char *buffer, size_t length, int quality, int fips);
/* PBKDF*/
struct crypt_pbkdf_limits {
uint32_t min_iterations, max_iterations;
uint32_t min_memory, max_memory;
uint32_t min_parallel, max_parallel;
};
int crypt_pbkdf_get_limits(const char *kdf, struct crypt_pbkdf_limits *l);
/* PBKDF*/
int crypt_pbkdf_get_limits(const char *kdf, struct crypt_pbkdf_limits *l);
int crypt_pbkdf(const char *kdf, const char *hash,
const char *password, size_t password_length,
const char *salt, size_t salt_length,
@@ -79,26 +81,10 @@ int crypt_pbkdf_perf(const char *kdf, const char *hash,
uint32_t *iterations_out, uint32_t *memory_out,
int (*progress)(uint32_t time_ms, void *usrptr), void *usrptr);
#if USE_INTERNAL_PBKDF2
/* internal PBKDF2 implementation */
int pkcs5_pbkdf2(const char *hash,
const char *P, size_t Plen,
const char *S, size_t Slen,
unsigned int c,
unsigned int dkLen, char *DK,
unsigned int hash_block_size);
#endif
/* Argon2 implementation wrapper */
int 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);
/* CRC32 */
uint32_t crypt_crc32(uint32_t seed, const unsigned char *buf, size_t len);
/* ciphers */
/* Block ciphers */
int crypt_cipher_ivsize(const char *name, const char *mode);
int crypt_cipher_wrapped_key(const char *name, const char *mode);
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
@@ -110,20 +96,34 @@ int crypt_cipher_encrypt(struct crypt_cipher *ctx,
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length);
bool crypt_cipher_kernel_only(struct crypt_cipher *ctx);
/* Check availability of a cipher */
int crypt_cipher_check(const char *name, const char *mode,
const char *integrity, size_t key_length);
/* Benchmark of kernel cipher performance */
int crypt_cipher_perf_kernel(const char *name, const char *mode, char *buffer, size_t buffer_size,
const char *key, size_t key_size, const char *iv, size_t iv_size,
double *encryption_mbs, double *decryption_mbs);
/* storage encryption wrappers */
int crypt_storage_init(struct crypt_storage **ctx, uint64_t sector_start,
/* Check availability of a cipher (in kernel only) */
int crypt_cipher_check_kernel(const char *name, const char *mode,
const char *integrity, size_t key_length);
/* Storage encryption wrappers */
int crypt_storage_init(struct crypt_storage **ctx, size_t sector_size,
const char *cipher, const char *cipher_mode,
const void *key, size_t key_length);
void crypt_storage_destroy(struct crypt_storage *ctx);
int crypt_storage_decrypt(struct crypt_storage *ctx, uint64_t sector,
size_t count, char *buffer);
int crypt_storage_encrypt(struct crypt_storage *ctx, uint64_t sector,
size_t count, char *buffer);
int crypt_storage_decrypt(struct crypt_storage *ctx, uint64_t iv_offset,
uint64_t length, char *buffer);
int crypt_storage_encrypt(struct crypt_storage *ctx, uint64_t iv_offset,
uint64_t length, char *buffer);
bool crypt_storage_kernel_only(struct crypt_storage *ctx);
/* Temporary Bitlk helper */
int crypt_bitlk_decrypt_key(const void *key, size_t key_length,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length,
const char *tag, size_t tag_length);
/* Memzero helper (memset on stack can be optimized out) */
static inline void crypt_backend_memzero(void *s, size_t n)

View File

@@ -0,0 +1,63 @@
/*
* crypto backend implementation
*
* Copyright (C) 2010-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2020 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef _CRYPTO_BACKEND_INTERNAL_H
#define _CRYPTO_BACKEND_INTERNAL_H
#include "crypto_backend.h"
#if USE_INTERNAL_PBKDF2
/* internal PBKDF2 implementation */
int pkcs5_pbkdf2(const char *hash,
const char *P, size_t Plen,
const char *S, size_t Slen,
unsigned int c,
unsigned int dkLen, char *DK,
unsigned int hash_block_size);
#endif
/* Argon2 implementation wrapper */
int 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);
/* Block ciphers: fallback to kernel crypto API */
struct crypt_cipher_kernel {
int tfmfd;
int opfd;
};
int crypt_cipher_init_kernel(struct crypt_cipher_kernel *ctx, const char *name,
const char *mode, const void *key, size_t key_length);
int crypt_cipher_encrypt_kernel(struct crypt_cipher_kernel *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length);
int crypt_cipher_decrypt_kernel(struct crypt_cipher_kernel *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length);
void crypt_cipher_destroy_kernel(struct crypt_cipher_kernel *ctx);
int crypt_bitlk_decrypt_key_kernel(const void *key, size_t key_length,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length,
const char *tag, size_t tag_length);
#endif /* _CRYPTO_BACKEND_INTERNAL_H */

View File

@@ -1,8 +1,8 @@
/*
* Linux kernel userspace API crypto backend implementation (skcipher)
*
* Copyright (C) 2012-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2019 Milan Broz
* Copyright (C) 2012-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2020 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -27,7 +27,7 @@
#include <unistd.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include "crypto_backend.h"
#include "crypto_backend_internal.h"
#ifdef ENABLE_AF_ALG
@@ -40,10 +40,9 @@
#define SOL_ALG 279
#endif
struct crypt_cipher {
int tfmfd;
int opfd;
};
#ifndef ALG_SET_AEAD_AUTHSIZE
#define ALG_SET_AEAD_AUTHSIZE 5
#endif
/*
* ciphers
@@ -52,45 +51,46 @@ struct crypt_cipher {
* ENOTSUP - AF_ALG family not available
* (but cannot check specifically for skcipher API)
*/
static int _crypt_cipher_init(struct crypt_cipher **ctx,
static int _crypt_cipher_init(struct crypt_cipher_kernel *ctx,
const void *key, size_t key_length,
struct sockaddr_alg *sa)
size_t tag_length, struct sockaddr_alg *sa)
{
struct crypt_cipher *h;
if (!ctx)
return -EINVAL;
h = malloc(sizeof(*h));
if (!h)
return -ENOMEM;
h->opfd = -1;
h->tfmfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
if (h->tfmfd < 0) {
crypt_cipher_destroy(h);
ctx->opfd = -1;
ctx->tfmfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
if (ctx->tfmfd < 0) {
crypt_cipher_destroy_kernel(ctx);
return -ENOTSUP;
}
if (bind(h->tfmfd, (struct sockaddr *)sa, sizeof(*sa)) < 0) {
crypt_cipher_destroy(h);
if (bind(ctx->tfmfd, (struct sockaddr *)sa, sizeof(*sa)) < 0) {
crypt_cipher_destroy_kernel(ctx);
return -ENOENT;
}
if (setsockopt(h->tfmfd, SOL_ALG, ALG_SET_KEY, key, key_length) < 0) {
crypt_cipher_destroy(h);
if (setsockopt(ctx->tfmfd, SOL_ALG, ALG_SET_KEY, key, key_length) < 0) {
crypt_cipher_destroy_kernel(ctx);
return -EINVAL;
}
h->opfd = accept(h->tfmfd, NULL, 0);
if (h->opfd < 0) {
crypt_cipher_destroy(h);
if (tag_length && setsockopt(ctx->tfmfd, SOL_ALG, ALG_SET_AEAD_AUTHSIZE, NULL, tag_length) < 0) {
crypt_cipher_destroy_kernel(ctx);
return -EINVAL;
}
ctx->opfd = accept(ctx->tfmfd, NULL, 0);
if (ctx->opfd < 0) {
crypt_cipher_destroy_kernel(ctx);
return -EINVAL;
}
*ctx = h;
return 0;
}
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
const char *mode, const void *key, size_t key_length)
int crypt_cipher_init_kernel(struct crypt_cipher_kernel *ctx, const char *name,
const char *mode, const void *key, size_t key_length)
{
struct sockaddr_alg sa = {
.salg_family = AF_ALG,
@@ -102,14 +102,15 @@ int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
snprintf((char *)sa.salg_name, sizeof(sa.salg_name), "%s(%s)", mode, name);
return _crypt_cipher_init(ctx, key, key_length, &sa);
return _crypt_cipher_init(ctx, key, key_length, 0, &sa);
}
/* The in/out should be aligned to page boundary */
static int crypt_cipher_crypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length,
uint32_t direction)
static int _crypt_cipher_crypt(struct crypt_cipher_kernel *ctx,
const char *in, size_t in_length,
char *out, size_t out_length,
const char *iv, size_t iv_length,
uint32_t direction)
{
int r = 0;
ssize_t len;
@@ -118,7 +119,7 @@ static int crypt_cipher_crypt(struct crypt_cipher *ctx,
uint32_t *type;
struct iovec iov = {
.iov_base = (void*)(uintptr_t)in,
.iov_len = length,
.iov_len = in_length,
};
int iv_msg_size = iv ? CMSG_SPACE(sizeof(*alg_iv) + iv_length) : 0;
char buffer[CMSG_SPACE(sizeof(*type)) + iv_msg_size];
@@ -129,7 +130,7 @@ static int crypt_cipher_crypt(struct crypt_cipher *ctx,
.msg_iovlen = 1,
};
if (!in || !out || !length)
if (!in || !out || !in_length)
return -EINVAL;
if ((!iv && iv_length) || (iv && !iv_length))
@@ -160,49 +161,50 @@ static int crypt_cipher_crypt(struct crypt_cipher *ctx,
}
len = sendmsg(ctx->opfd, &msg, 0);
if (len != (ssize_t)length) {
if (len != (ssize_t)(in_length)) {
r = -EIO;
goto bad;
}
len = read(ctx->opfd, out, length);
if (len != (ssize_t)length)
len = read(ctx->opfd, out, out_length);
if (len != (ssize_t)out_length)
r = -EIO;
bad:
crypt_backend_memzero(buffer, sizeof(buffer));
return r;
}
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
int crypt_cipher_encrypt_kernel(struct crypt_cipher_kernel *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
{
return crypt_cipher_crypt(ctx, in, out, length,
iv, iv_length, ALG_OP_ENCRYPT);
return _crypt_cipher_crypt(ctx, in, length, out, length,
iv, iv_length, ALG_OP_ENCRYPT);
}
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
int crypt_cipher_decrypt_kernel(struct crypt_cipher_kernel *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
{
return crypt_cipher_crypt(ctx, in, out, length,
iv, iv_length, ALG_OP_DECRYPT);
return _crypt_cipher_crypt(ctx, in, length, out, length,
iv, iv_length, ALG_OP_DECRYPT);
}
void crypt_cipher_destroy(struct crypt_cipher *ctx)
void crypt_cipher_destroy_kernel(struct crypt_cipher_kernel *ctx)
{
if (ctx->tfmfd >= 0)
close(ctx->tfmfd);
if (ctx->opfd >= 0)
close(ctx->opfd);
memset(ctx, 0, sizeof(*ctx));
free(ctx);
ctx->tfmfd = -1;
ctx->opfd = -1;
}
int crypt_cipher_check(const char *name, const char *mode,
const char *integrity, size_t key_length)
int crypt_cipher_check_kernel(const char *name, const char *mode,
const char *integrity, size_t key_length)
{
struct crypt_cipher *c = NULL;
struct crypt_cipher_kernel c;
char mode_name[64], tmp_salg_name[180], *real_mode = NULL, *cipher_iv = NULL, *key;
const char *salg_type;
bool aead;
@@ -251,41 +253,91 @@ int crypt_cipher_check(const char *name, const char *mode,
memset(key, 0xab, key_length);
*key = 0xef;
r = _crypt_cipher_init(&c, key, key_length, &sa);
if (c)
crypt_cipher_destroy(c);
r = _crypt_cipher_init(&c, key, key_length, 0, &sa);
crypt_cipher_destroy_kernel(&c);
free(key);
return r;
}
int crypt_bitlk_decrypt_key_kernel(const void *key, size_t key_length,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length,
const char *tag, size_t tag_length)
{
struct crypt_cipher_kernel c;
struct sockaddr_alg sa = {
.salg_family = AF_ALG,
.salg_type = "aead",
.salg_name = "ccm(aes)",
};
int r;
char buffer[128], ccm_iv[16];
if (length + tag_length > sizeof(buffer))
return -EINVAL;
if (iv_length > sizeof(ccm_iv) - 2)
return -EINVAL;
r = _crypt_cipher_init(&c, key, key_length, tag_length, &sa);
if (r < 0)
return r;
memcpy(buffer, in, length);
memcpy(buffer + length, tag, tag_length);
/* CCM IV - RFC3610 */
memset(ccm_iv, 0, sizeof(ccm_iv));
ccm_iv[0] = 15 - iv_length - 1;
memcpy(ccm_iv + 1, iv, iv_length);
memset(ccm_iv + 1 + iv_length, 0, ccm_iv[0] + 1);
iv_length = sizeof(ccm_iv);
r = _crypt_cipher_crypt(&c, buffer, length + tag_length, out, length,
ccm_iv, iv_length, ALG_OP_DECRYPT);
crypt_cipher_destroy_kernel(&c);
crypt_backend_memzero(buffer, sizeof(buffer));
return r;
}
#else /* ENABLE_AF_ALG */
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
const char *mode, const void *buffer, size_t length)
int crypt_cipher_init_kernel(struct crypt_cipher_kernel *ctx, const char *name,
const char *mode, const void *key, size_t key_length)
{
return -ENOTSUP;
}
void crypt_cipher_destroy(struct crypt_cipher *ctx)
void crypt_cipher_destroy_kernel(struct crypt_cipher_kernel *ctx)
{
return;
}
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
int crypt_cipher_encrypt_kernel(struct crypt_cipher_kernel *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
{
return -EINVAL;
}
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
int crypt_cipher_decrypt_kernel(struct crypt_cipher_kernel *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
{
return -EINVAL;
}
int crypt_cipher_check(const char *name, const char *mode,
const char *integrity, size_t key_length)
int crypt_cipher_check_kernel(const char *name, const char *mode,
const char *integrity, size_t key_length)
{
/* Cannot check, expect success. */
return 0;
}
int crypt_bitlk_decrypt_key_kernel(const void *key, size_t key_length,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length,
const char *tag, size_t tag_length)
{
return -ENOTSUP;
}
#endif

View File

@@ -1,8 +1,8 @@
/*
* GCRYPT crypto backend implementation
*
* Copyright (C) 2010-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2019 Milan Broz
* Copyright (C) 2010-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2020 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -24,7 +24,7 @@
#include <errno.h>
#include <assert.h>
#include <gcrypt.h>
#include "crypto_backend.h"
#include "crypto_backend_internal.h"
static int crypto_backend_initialised = 0;
static int crypto_backend_secmem = 1;
@@ -43,6 +43,14 @@ struct crypt_hmac {
int hash_len;
};
struct crypt_cipher {
bool use_kernel;
union {
struct crypt_cipher_kernel kernel;
gcry_cipher_hd_t hd;
} u;
};
/*
* Test for wrong Whirlpool variant,
* Ref: http://lists.gnupg.org/pipermail/gcrypt-devel/2014-January/002889.html
@@ -366,3 +374,148 @@ int crypt_pbkdf(const char *kdf, const char *hash,
key, key_length, iterations, memory, parallel);
return -EINVAL;
}
/* Block ciphers */
static int _cipher_init(gcry_cipher_hd_t *hd, const char *name,
const char *mode, const void *buffer, size_t length)
{
int cipher_id, mode_id;
cipher_id = gcry_cipher_map_name(name);
if (cipher_id == GCRY_CIPHER_MODE_NONE)
return -ENOENT;
if (!strcmp(mode, "ecb"))
mode_id = GCRY_CIPHER_MODE_ECB;
else if (!strcmp(mode, "cbc"))
mode_id = GCRY_CIPHER_MODE_CBC;
#if HAVE_DECL_GCRY_CIPHER_MODE_XTS
else if (!strcmp(mode, "xts"))
mode_id = GCRY_CIPHER_MODE_XTS;
#endif
else
return -ENOENT;
if (gcry_cipher_open(hd, cipher_id, mode_id, 0))
return -EINVAL;
if (gcry_cipher_setkey(*hd, buffer, length)) {
gcry_cipher_close(*hd);
return -EINVAL;
}
return 0;
}
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
const char *mode, const void *key, size_t key_length)
{
struct crypt_cipher *h;
int r;
h = malloc(sizeof(*h));
if (!h)
return -ENOMEM;
if (!_cipher_init(&h->u.hd, name, mode, key, key_length)) {
h->use_kernel = false;
*ctx = h;
return 0;
}
r = crypt_cipher_init_kernel(&h->u.kernel, name, mode, key, key_length);
if (r < 0) {
free(h);
return r;
}
h->use_kernel = true;
*ctx = h;
return 0;
}
void crypt_cipher_destroy(struct crypt_cipher *ctx)
{
if (ctx->use_kernel)
crypt_cipher_destroy_kernel(&ctx->u.kernel);
else
gcry_cipher_close(ctx->u.hd);
free(ctx);
}
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
{
if (ctx->use_kernel)
return crypt_cipher_encrypt_kernel(&ctx->u.kernel, in, out, length, iv, iv_length);
if (iv && gcry_cipher_setiv(ctx->u.hd, iv, iv_length))
return -EINVAL;
if (gcry_cipher_encrypt(ctx->u.hd, out, length, in, length))
return -EINVAL;
return 0;
}
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
{
if (ctx->use_kernel)
return crypt_cipher_decrypt_kernel(&ctx->u.kernel, in, out, length, iv, iv_length);
if (iv && gcry_cipher_setiv(ctx->u.hd, iv, iv_length))
return -EINVAL;
if (gcry_cipher_decrypt(ctx->u.hd, out, length, in, length))
return -EINVAL;
return 0;
}
bool crypt_cipher_kernel_only(struct crypt_cipher *ctx)
{
return ctx->use_kernel;
}
int crypt_bitlk_decrypt_key(const void *key, size_t key_length,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length,
const char *tag, size_t tag_length)
{
#ifdef GCRY_CCM_BLOCK_LEN
gcry_cipher_hd_t hd;
uint64_t l[3];
int r = -EINVAL;
if (gcry_cipher_open(&hd, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CCM, 0))
return -EINVAL;
if (gcry_cipher_setkey(hd, key, key_length))
goto out;
if (gcry_cipher_setiv(hd, iv, iv_length))
goto out;
l[0] = length;
l[1] = 0;
l[2] = tag_length;
if (gcry_cipher_ctl(hd, GCRYCTL_SET_CCM_LENGTHS, l, sizeof(l)))
goto out;
if (gcry_cipher_decrypt(hd, out, length, in, length))
goto out;
if (gcry_cipher_checktag(hd, tag, tag_length))
goto out;
r = 0;
out:
gcry_cipher_close(hd);
return r;
#else
return -ENOTSUP;
#endif
}

View File

@@ -1,8 +1,8 @@
/*
* Linux kernel userspace API crypto backend implementation
*
* Copyright (C) 2010-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2019 Milan Broz
* Copyright (C) 2010-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2020 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -27,7 +27,7 @@
#include <sys/socket.h>
#include <sys/utsname.h>
#include <linux/if_alg.h>
#include "crypto_backend.h"
#include "crypto_backend_internal.h"
/* FIXME: remove later */
#ifndef AF_ALG
@@ -77,6 +77,10 @@ struct crypt_hmac {
int hash_len;
};
struct crypt_cipher {
struct crypt_cipher_kernel ck;
};
static int crypt_kernel_socket_init(struct sockaddr_alg *sa, int *tfmfd, int *opfd,
const void *key, size_t key_length)
{
@@ -342,3 +346,58 @@ int crypt_pbkdf(const char *kdf, const char *hash,
return -EINVAL;
}
/* Block ciphers */
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
const char *mode, const void *key, size_t key_length)
{
struct crypt_cipher *h;
int r;
h = malloc(sizeof(*h));
if (!h)
return -ENOMEM;
r = crypt_cipher_init_kernel(&h->ck, name, mode, key, key_length);
if (r < 0) {
free(h);
return r;
}
*ctx = h;
return 0;
}
void crypt_cipher_destroy(struct crypt_cipher *ctx)
{
crypt_cipher_destroy_kernel(&ctx->ck);
free(ctx);
}
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
{
return crypt_cipher_encrypt_kernel(&ctx->ck, in, out, length, iv, iv_length);
}
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
{
return crypt_cipher_decrypt_kernel(&ctx->ck, in, out, length, iv, iv_length);
}
bool crypt_cipher_kernel_only(struct crypt_cipher *ctx)
{
return true;
}
int crypt_bitlk_decrypt_key(const void *key, size_t key_length,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length,
const char *tag, size_t tag_length)
{
return crypt_bitlk_decrypt_key_kernel(key, key_length, in, out, length,
iv, iv_length, tag, tag_length);
}

View File

@@ -1,8 +1,8 @@
/*
* Nettle crypto backend implementation
*
* Copyright (C) 2011-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2019 Milan Broz
* Copyright (C) 2011-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2020 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -26,7 +26,7 @@
#include <nettle/sha3.h>
#include <nettle/hmac.h>
#include <nettle/pbkdf2.h>
#include "crypto_backend.h"
#include "crypto_backend_internal.h"
#if HAVE_NETTLE_VERSION_H
#include <nettle/version.h>
@@ -192,6 +192,10 @@ struct crypt_hmac {
uint8_t *key;
};
struct crypt_cipher {
struct crypt_cipher_kernel ck;
};
uint32_t crypt_backend_flags(void)
{
return 0;
@@ -383,3 +387,58 @@ int crypt_pbkdf(const char *kdf, const char *hash,
return -EINVAL;
}
/* Block ciphers */
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
const char *mode, const void *key, size_t key_length)
{
struct crypt_cipher *h;
int r;
h = malloc(sizeof(*h));
if (!h)
return -ENOMEM;
r = crypt_cipher_init_kernel(&h->ck, name, mode, key, key_length);
if (r < 0) {
free(h);
return r;
}
*ctx = h;
return 0;
}
void crypt_cipher_destroy(struct crypt_cipher *ctx)
{
crypt_cipher_destroy_kernel(&ctx->ck);
free(ctx);
}
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
{
return crypt_cipher_encrypt_kernel(&ctx->ck, in, out, length, iv, iv_length);
}
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
{
return crypt_cipher_decrypt_kernel(&ctx->ck, in, out, length, iv, iv_length);
}
bool crypt_cipher_kernel_only(struct crypt_cipher *ctx)
{
return true;
}
int crypt_bitlk_decrypt_key(const void *key, size_t key_length,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length,
const char *tag, size_t tag_length)
{
return crypt_bitlk_decrypt_key_kernel(key, key_length, in, out, length,
iv, iv_length, tag, tag_length);
}

View File

@@ -1,8 +1,8 @@
/*
* NSS crypto backend implementation
*
* Copyright (C) 2010-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2019 Milan Broz
* Copyright (C) 2010-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2020 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -23,7 +23,7 @@
#include <errno.h>
#include <nss.h>
#include <pk11pub.h>
#include "crypto_backend.h"
#include "crypto_backend_internal.h"
#define CONST_CAST(x) (x)(uintptr_t)
@@ -59,6 +59,10 @@ struct crypt_hmac {
const struct hash_alg *hash;
};
struct crypt_cipher {
struct crypt_cipher_kernel ck;
};
static struct hash_alg *_get_alg(const char *name)
{
int i = 0;
@@ -331,3 +335,58 @@ int crypt_pbkdf(const char *kdf, const char *hash,
return -EINVAL;
}
/* Block ciphers */
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
const char *mode, const void *key, size_t key_length)
{
struct crypt_cipher *h;
int r;
h = malloc(sizeof(*h));
if (!h)
return -ENOMEM;
r = crypt_cipher_init_kernel(&h->ck, name, mode, key, key_length);
if (r < 0) {
free(h);
return r;
}
*ctx = h;
return 0;
}
void crypt_cipher_destroy(struct crypt_cipher *ctx)
{
crypt_cipher_destroy_kernel(&ctx->ck);
free(ctx);
}
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
{
return crypt_cipher_encrypt_kernel(&ctx->ck, in, out, length, iv, iv_length);
}
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
{
return crypt_cipher_decrypt_kernel(&ctx->ck, in, out, length, iv, iv_length);
}
bool crypt_cipher_kernel_only(struct crypt_cipher *ctx)
{
return true;
}
int crypt_bitlk_decrypt_key(const void *key, size_t key_length,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length,
const char *tag, size_t tag_length)
{
return crypt_bitlk_decrypt_key_kernel(key, key_length, in, out, length,
iv, iv_length, tag, tag_length);
}

View File

@@ -1,8 +1,8 @@
/*
* OPENSSL crypto backend implementation
*
* Copyright (C) 2010-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2019 Milan Broz
* Copyright (C) 2010-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2020 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -33,7 +33,9 @@
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/rand.h>
#include "crypto_backend.h"
#include "crypto_backend_internal.h"
#define CONST_CAST(x) (x)(uintptr_t)
static int crypto_backend_initialised = 0;
@@ -49,6 +51,18 @@ struct crypt_hmac {
int hash_len;
};
struct crypt_cipher {
bool use_kernel;
union {
struct crypt_cipher_kernel kernel;
struct {
EVP_CIPHER_CTX *hd_enc;
EVP_CIPHER_CTX *hd_dec;
size_t iv_length;
} lib;
} u;
};
/*
* Compatible wrappers for OpenSSL < 1.1.0 and LibreSSL < 2.7.0
*/
@@ -335,3 +349,198 @@ int crypt_pbkdf(const char *kdf, const char *hash,
return -EINVAL;
}
/* Block ciphers */
static void _cipher_destroy(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec)
{
EVP_CIPHER_CTX_free(*hd_enc);
*hd_enc = NULL;
EVP_CIPHER_CTX_free(*hd_dec);
*hd_dec = NULL;
}
static int _cipher_init(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec, const char *name,
const char *mode, const void *key, size_t key_length, size_t *iv_length)
{
char cipher_name[256];
const EVP_CIPHER *type;
int r, key_bits;
key_bits = key_length * 8;
if (!strcmp(mode, "xts"))
key_bits /= 2;
r = snprintf(cipher_name, sizeof(cipher_name), "%s-%d-%s", name, key_bits, mode);
if (r < 0 || r >= (int)sizeof(cipher_name))
return -EINVAL;
type = EVP_get_cipherbyname(cipher_name);
if (!type)
return -ENOENT;
if (EVP_CIPHER_key_length(type) != (int)key_length)
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)
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);
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);
return -EINVAL;
}
return 0;
}
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
const char *mode, const void *key, size_t key_length)
{
struct crypt_cipher *h;
int r;
h = malloc(sizeof(*h));
if (!h)
return -ENOMEM;
if (!_cipher_init(&h->u.lib.hd_enc, &h->u.lib.hd_dec, name, mode, key,
key_length, &h->u.lib.iv_length)) {
h->use_kernel = false;
*ctx = h;
return 0;
}
r = crypt_cipher_init_kernel(&h->u.kernel, name, mode, key, key_length);
if (r < 0) {
free(h);
return r;
}
h->use_kernel = true;
*ctx = h;
return 0;
}
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);
free(ctx);
}
static int _cipher_encrypt(struct crypt_cipher *ctx, const unsigned char *in, unsigned char *out,
int length, const unsigned char *iv, size_t iv_length)
{
int len;
if (ctx->u.lib.iv_length != iv_length)
return -EINVAL;
if (EVP_EncryptInit_ex(ctx->u.lib.hd_enc, NULL, NULL, NULL, iv) != 1)
return -EINVAL;
if (EVP_EncryptUpdate(ctx->u.lib.hd_enc, out, &len, in, length) != 1)
return -EINVAL;
if (EVP_EncryptFinal(ctx->u.lib.hd_enc, out + len, &len) != 1)
return -EINVAL;
return 0;
}
static int _cipher_decrypt(struct crypt_cipher *ctx, const unsigned char *in, unsigned char *out,
int length, const unsigned char *iv, size_t iv_length)
{
int len;
if (ctx->u.lib.iv_length != iv_length)
return -EINVAL;
if (EVP_DecryptInit_ex(ctx->u.lib.hd_dec, NULL, NULL, NULL, iv) != 1)
return -EINVAL;
if (EVP_DecryptUpdate(ctx->u.lib.hd_dec, out, &len, in, length) != 1)
return -EINVAL;
if (EVP_DecryptFinal(ctx->u.lib.hd_dec, out + len, &len) != 1)
return -EINVAL;
return 0;
}
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
{
if (ctx->use_kernel)
return crypt_cipher_encrypt_kernel(&ctx->u.kernel, in, out, length, iv, iv_length);
return _cipher_encrypt(ctx, (const unsigned char*)in,
(unsigned char *)out, length, (const unsigned char*)iv, iv_length);
}
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
{
if (ctx->use_kernel)
return crypt_cipher_decrypt_kernel(&ctx->u.kernel, in, out, length, iv, iv_length);
return _cipher_decrypt(ctx, (const unsigned char*)in,
(unsigned char *)out, length, (const unsigned char*)iv, iv_length);
}
bool crypt_cipher_kernel_only(struct crypt_cipher *ctx)
{
return ctx->use_kernel;
}
int crypt_bitlk_decrypt_key(const void *key, size_t key_length,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length,
const char *tag, size_t tag_length)
{
#ifdef EVP_CTRL_CCM_SET_IVLEN
EVP_CIPHER_CTX *ctx;
int len = 0, r = -EINVAL;
ctx = EVP_CIPHER_CTX_new();
if (!ctx)
return -EINVAL;
if (EVP_DecryptInit_ex(ctx, EVP_aes_256_ccm(), NULL, NULL, NULL) != 1)
goto out;
//EVP_CIPHER_CTX_key_length(ctx)
//EVP_CIPHER_CTX_iv_length(ctx)
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, iv_length, NULL) != 1)
goto out;
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, tag_length, CONST_CAST(void*)tag) != 1)
goto out;
if (EVP_DecryptInit_ex(ctx, NULL, NULL, key, (const unsigned char*)iv) != 1)
goto out;
if (EVP_DecryptUpdate(ctx, (unsigned char*)out, &len, (const unsigned char*)in, length) == 1)
r = 0;
out:
EVP_CIPHER_CTX_free(ctx);
return r;
#else
return -ENOTSUP;
#endif
}

View File

@@ -2,7 +2,7 @@
* Generic wrapper for storage encryption modes and Initial Vectors
* (reimplementation of some functions from Linux dm-crypt kernel)
*
* Copyright (C) 2014-2019 Milan Broz
* Copyright (C) 2014-2020 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -25,7 +25,6 @@
#include "crypto_backend.h"
#define SECTOR_SHIFT 9
#define SECTOR_SIZE (1 << SECTOR_SHIFT)
/*
* Internal IV helper
@@ -41,7 +40,8 @@ struct crypt_sector_iv {
/* Block encryption storage context */
struct crypt_storage {
uint64_t sector_start;
unsigned sector_shift;
unsigned iv_shift;
struct crypt_cipher *cipher;
struct crypt_sector_iv cipher_iv;
};
@@ -194,7 +194,7 @@ static void crypt_sector_iv_destroy(struct crypt_sector_iv *ctx)
/* Block encryption storage wrappers */
int crypt_storage_init(struct crypt_storage **ctx,
uint64_t sector_start,
size_t sector_size,
const char *cipher,
const char *cipher_mode,
const void *key, size_t key_length)
@@ -204,6 +204,11 @@ int crypt_storage_init(struct crypt_storage **ctx,
char *cipher_iv = NULL;
int r = -EIO;
if (sector_size < (1 << SECTOR_SHIFT) ||
sector_size > (1 << (SECTOR_SHIFT + 3)) ||
sector_size & (sector_size - 1))
return -EINVAL;
s = malloc(sizeof(*s));
if (!s)
return -ENOMEM;
@@ -230,27 +235,33 @@ int crypt_storage_init(struct crypt_storage **ctx,
return r;
}
s->sector_start = sector_start;
s->sector_shift = int_log2(sector_size);
s->iv_shift = s->sector_shift - SECTOR_SHIFT;
*ctx = s;
return 0;
}
int crypt_storage_decrypt(struct crypt_storage *ctx,
uint64_t sector, size_t count,
char *buffer)
uint64_t iv_offset,
uint64_t length, char *buffer)
{
unsigned int i;
uint64_t i;
int r = 0;
for (i = 0; i < count; i++) {
r = crypt_sector_iv_generate(&ctx->cipher_iv, sector + i);
if (length & ((1 << ctx->sector_shift) - 1))
return -EINVAL;
length >>= ctx->sector_shift;
for (i = 0; i < length; i++) {
r = crypt_sector_iv_generate(&ctx->cipher_iv, iv_offset + (uint64_t)(i << ctx->iv_shift));
if (r)
break;
r = crypt_cipher_decrypt(ctx->cipher,
&buffer[i * SECTOR_SIZE],
&buffer[i * SECTOR_SIZE],
SECTOR_SIZE,
&buffer[i << ctx->sector_shift],
&buffer[i << ctx->sector_shift],
1 << ctx->sector_shift,
ctx->cipher_iv.iv,
ctx->cipher_iv.iv_size);
if (r)
@@ -261,20 +272,25 @@ int crypt_storage_decrypt(struct crypt_storage *ctx,
}
int crypt_storage_encrypt(struct crypt_storage *ctx,
uint64_t sector, size_t count,
char *buffer)
uint64_t iv_offset,
uint64_t length, char *buffer)
{
unsigned int i;
uint64_t i;
int r = 0;
for (i = 0; i < count; i++) {
r = crypt_sector_iv_generate(&ctx->cipher_iv, sector + i);
if (length & ((1 << ctx->sector_shift) - 1))
return -EINVAL;
length >>= ctx->sector_shift;
for (i = 0; i < length; i++) {
r = crypt_sector_iv_generate(&ctx->cipher_iv, iv_offset + (i << ctx->iv_shift));
if (r)
break;
r = crypt_cipher_encrypt(ctx->cipher,
&buffer[i * SECTOR_SIZE],
&buffer[i * SECTOR_SIZE],
SECTOR_SIZE,
&buffer[i << ctx->sector_shift],
&buffer[i << ctx->sector_shift],
1 << ctx->sector_shift,
ctx->cipher_iv.iv,
ctx->cipher_iv.iv_size);
if (r)
@@ -297,3 +313,8 @@ void crypt_storage_destroy(struct crypt_storage *ctx)
memset(ctx, 0, sizeof(*ctx));
free(ctx);
}
bool crypt_storage_kernel_only(struct crypt_storage *ctx)
{
return crypt_cipher_kernel_only(ctx->cipher);
}

View File

@@ -4,8 +4,8 @@
* Copyright (C) 2004 Free Software Foundation
*
* cryptsetup related changes
* Copyright (C) 2012-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2019 Milan Broz
* Copyright (C) 2012-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2020 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -25,7 +25,7 @@
#include <errno.h>
#include <alloca.h>
#include "crypto_backend.h"
#include "crypto_backend_internal.h"
static int hash_buf(const char *src, size_t src_len,
char *dst, size_t dst_len,
@@ -230,197 +230,3 @@ out:
return rc;
}
#if 0
#include <stdio.h>
struct test_vector {
const char *hash;
unsigned int hash_block_length;
unsigned int iterations;
const char *password;
unsigned int password_length;
const char *salt;
unsigned int salt_length;
const char *output;
unsigned int output_length;
};
struct test_vector test_vectors[] = {
/* RFC 3962 */
{
"sha1", 64, 1,
"password", 8,
"ATHENA.MIT.EDUraeburn", 21,
"\xcd\xed\xb5\x28\x1b\xb2\xf8\x01"
"\x56\x5a\x11\x22\xb2\x56\x35\x15"
"\x0a\xd1\xf7\xa0\x4b\xb9\xf3\xa3"
"\x33\xec\xc0\xe2\xe1\xf7\x08\x37", 32
}, {
"sha1", 64, 2,
"password", 8,
"ATHENA.MIT.EDUraeburn", 21,
"\x01\xdb\xee\x7f\x4a\x9e\x24\x3e"
"\x98\x8b\x62\xc7\x3c\xda\x93\x5d"
"\xa0\x53\x78\xb9\x32\x44\xec\x8f"
"\x48\xa9\x9e\x61\xad\x79\x9d\x86", 32
}, {
"sha1", 64, 1200,
"password", 8,
"ATHENA.MIT.EDUraeburn", 21,
"\x5c\x08\xeb\x61\xfd\xf7\x1e\x4e"
"\x4e\xc3\xcf\x6b\xa1\xf5\x51\x2b"
"\xa7\xe5\x2d\xdb\xc5\xe5\x14\x2f"
"\x70\x8a\x31\xe2\xe6\x2b\x1e\x13", 32
}, {
"sha1", 64, 5,
"password", 8,
"\0224VxxV4\022", 8, // "\x1234567878563412
"\xd1\xda\xa7\x86\x15\xf2\x87\xe6"
"\xa1\xc8\xb1\x20\xd7\x06\x2a\x49"
"\x3f\x98\xd2\x03\xe6\xbe\x49\xa6"
"\xad\xf4\xfa\x57\x4b\x6e\x64\xee", 32
}, {
"sha1", 64, 1200,
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 64,
"pass phrase equals block size", 29,
"\x13\x9c\x30\xc0\x96\x6b\xc3\x2b"
"\xa5\x5f\xdb\xf2\x12\x53\x0a\xc9"
"\xc5\xec\x59\xf1\xa4\x52\xf5\xcc"
"\x9a\xd9\x40\xfe\xa0\x59\x8e\xd1", 32
}, {
"sha1", 64, 1200,
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 65,
"pass phrase exceeds block size", 30,
"\x9c\xca\xd6\xd4\x68\x77\x0c\xd5"
"\x1b\x10\xe6\xa6\x87\x21\xbe\x61"
"\x1a\x8b\x4d\x28\x26\x01\xdb\x3b"
"\x36\xbe\x92\x46\x91\x5e\xc8\x2a", 32
}, {
"sha1", 64, 50,
"\360\235\204\236", 4, // g-clef ("\xf09d849e)
"EXAMPLE.COMpianist", 18,
"\x6b\x9c\xf2\x6d\x45\x45\x5a\x43"
"\xa5\xb8\xbb\x27\x6a\x40\x3b\x39"
"\xe7\xfe\x37\xa0\xc4\x1e\x02\xc2"
"\x81\xff\x30\x69\xe1\xe9\x4f\x52", 32
}, {
/* RFC-6070 */
"sha1", 64, 1,
"password", 8,
"salt", 4,
"\x0c\x60\xc8\x0f\x96\x1f\x0e\x71\xf3\xa9"
"\xb5\x24\xaf\x60\x12\x06\x2f\xe0\x37\xa6", 20
}, {
"sha1", 64, 2,
"password", 8,
"salt", 4,
"\xea\x6c\x01\x4d\xc7\x2d\x6f\x8c\xcd\x1e"
"\xd9\x2a\xce\x1d\x41\xf0\xd8\xde\x89\x57", 20
}, {
"sha1", 64, 4096,
"password", 8,
"salt", 4,
"\x4b\x00\x79\x01\xb7\x65\x48\x9a\xbe\xad"
"\x49\xd9\x26\xf7\x21\xd0\x65\xa4\x29\xc1", 20
}, {
"sha1", 64, 16777216,
"password", 8,
"salt", 4,
"\xee\xfe\x3d\x61\xcd\x4d\xa4\xe4\xe9\x94"
"\x5b\x3d\x6b\xa2\x15\x8c\x26\x34\xe9\x84", 20
}, {
"sha1", 64, 4096,
"passwordPASSWORDpassword", 24,
"saltSALTsaltSALTsaltSALTsaltSALTsalt", 36,
"\x3d\x2e\xec\x4f\xe4\x1c\x84\x9b\x80\xc8"
"\xd8\x36\x62\xc0\xe4\x4a\x8b\x29\x1a\x96"
"\x4c\xf2\xf0\x70\x38", 25
}, {
"sha1", 64, 4096,
"pass\0word", 9,
"sa\0lt", 5,
"\x56\xfa\x6a\xa7\x55\x48\x09\x9d\xcc\x37"
"\xd7\xf0\x34\x25\xe0\xc3", 16
}, {
/* empty password test */
"sha1", 64, 2,
"", 0,
"salt", 4,
"\x13\x3a\x4c\xe8\x37\xb4\xd2\x52\x1e\xe2"
"\xbf\x03\xe1\x1c\x71\xca\x79\x4e\x07\x97", 20
}, {
/* Password exceeds block size test */
"sha256", 64, 1200,
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 65,
"pass phrase exceeds block size", 30,
"\x22\x34\x4b\xc4\xb6\xe3\x26\x75"
"\xa8\x09\x0f\x3e\xa8\x0b\xe0\x1d"
"\x5f\x95\x12\x6a\x2c\xdd\xc3\xfa"
"\xcc\x4a\x5e\x6d\xca\x04\xec\x58", 32
}, {
"sha512", 128, 1200,
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 129,
"pass phrase exceeds block size", 30,
"\x0f\xb2\xed\x2c\x0e\x6e\xfb\x7d"
"\x7d\x8e\xdd\x58\x01\xb4\x59\x72"
"\x99\x92\x16\x30\x5e\xa4\x36\x8d"
"\x76\x14\x80\xf3\xe3\x7a\x22\xb9", 32
}, {
"whirlpool", 64, 1200,
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 65,
"pass phrase exceeds block size", 30,
"\x9c\x1c\x74\xf5\x88\x26\xe7\x6a"
"\x53\x58\xf4\x0c\x39\xe7\x80\x89"
"\x07\xc0\x31\x19\x9a\x50\xa2\x48"
"\xf1\xd9\xfe\x78\x64\xe5\x84\x50", 32
}
};
static void printhex(const char *s, const char *buf, size_t len)
{
size_t i;
printf("%s: ", s);
for (i = 0; i < len; i++)
printf("\\x%02x", (unsigned char)buf[i]);
printf("\n");
fflush(stdout);
}
static int pkcs5_pbkdf2_test_vectors(void)
{
char result[64];
unsigned int i, j;
struct test_vector *vec;
for (i = 0; i < (sizeof(test_vectors) / sizeof(*test_vectors)); i++) {
vec = &test_vectors[i];
for (j = 1; j <= vec->output_length; j++) {
if (pkcs5_pbkdf2(vec->hash,
vec->password, vec->password_length,
vec->salt, vec->salt_length,
vec->iterations,
j, result, vec->hash_block_length)) {
printf("pbkdf2 failed, vector %d\n", i);
return -EINVAL;
}
if (memcmp(result, vec->output, j) != 0) {
printf("vector %u\n", i);
printhex(" got", result, j);
printhex("want", vec->output, j);
return -EINVAL;
}
memset(result, 0, sizeof(result));
}
}
return 0;
}
#endif

View File

@@ -1,8 +1,8 @@
/*
* PBKDF performance check
* Copyright (C) 2012-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2019 Milan Broz
* Copyright (C) 2016-2019 Ondrej Mosnacek
* Copyright (C) 2012-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2020 Milan Broz
* Copyright (C) 2016-2020 Ondrej Mosnacek
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -151,7 +151,7 @@ static int next_argon2_params(uint32_t *t_cost, uint32_t *m_cost,
old_t_cost = *t_cost;
old_m_cost = *m_cost;
if (ms > target_ms) {
if ((uint32_t)ms > target_ms) {
/* decreasing, first try to lower t_cost, then m_cost */
num = (uint64_t)*t_cost * (uint64_t)target_ms;
denom = (uint64_t)ms;

View File

@@ -1,7 +1,7 @@
/*
* Integrity volume handling
*
* Copyright (C) 2016-2019 Milan Broz
* Copyright (C) 2016-2020 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -35,14 +35,13 @@ static int INTEGRITY_read_superblock(struct crypt_device *cd,
int devfd, r;
devfd = device_open(cd, device, O_RDONLY);
if(devfd < 0) {
if(devfd < 0)
return -EINVAL;
}
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
device_alignment(device), sb, sizeof(*sb), offset) != sizeof(*sb) ||
memcmp(sb->magic, SB_MAGIC, sizeof(sb->magic)) ||
(sb->version != SB_VERSION_1 && sb->version != SB_VERSION_2)) {
sb->version < SB_VERSION_1 || sb->version > SB_VERSION_4) {
log_std(cd, "No integrity superblock detected on %s.\n",
device_path(device));
r = -EINVAL;
@@ -55,11 +54,12 @@ static int INTEGRITY_read_superblock(struct crypt_device *cd,
r = 0;
}
close(devfd);
return r;
}
int INTEGRITY_read_sb(struct crypt_device *cd, struct crypt_params_integrity *params)
int INTEGRITY_read_sb(struct crypt_device *cd,
struct crypt_params_integrity *params,
uint32_t *flags)
{
struct superblock sb;
int r;
@@ -71,6 +71,9 @@ int INTEGRITY_read_sb(struct crypt_device *cd, struct crypt_params_integrity *pa
params->sector_size = SECTOR_SIZE << sb.log2_sectors_per_block;
params->tag_size = sb.integrity_tag_size;
if (flags)
*flags = sb.flags;
return 0;
}
@@ -92,9 +95,12 @@ int INTEGRITY_dump(struct crypt_device *cd, struct device *device, uint64_t offs
log_std(cd, "sector_size %u\n", SECTOR_SIZE << sb.log2_sectors_per_block);
if (sb.version == SB_VERSION_2 && (sb.flags & SB_FLAG_RECALCULATING))
log_std(cd, "recalc_sector %" PRIu64 "\n", sb.recalc_sector);
log_std(cd, "flags %s%s\n",
log_std(cd, "log2_blocks_per_bitmap %u\n", sb.log2_blocks_per_bitmap_bit);
log_std(cd, "flags %s%s%s%s\n",
sb.flags & SB_FLAG_HAVE_JOURNAL_MAC ? "have_journal_mac " : "",
sb.flags & SB_FLAG_RECALCULATING ? "recalculating " : "");
sb.flags & SB_FLAG_RECALCULATING ? "recalculating " : "",
sb.flags & SB_FLAG_DIRTY_BITMAP ? "dirty_bitmap " : "",
sb.flags & SB_FLAG_FIXED_PADDING ? "fix_padding " : "");
return 0;
}
@@ -136,6 +142,27 @@ int INTEGRITY_key_size(struct crypt_device *cd, const char *integrity)
return -EINVAL;
}
/* Return hash or hmac(hash) size, if known */
int INTEGRITY_hash_tag_size(const char *integrity)
{
char hash[MAX_CIPHER_LEN];
int r;
if (!integrity)
return 0;
if (!strcmp(integrity, "crc32") || !strcmp(integrity, "crc32c"))
return 4;
r = sscanf(integrity, "hmac(%" MAX_CIPHER_LEN_STR "[^)]s", hash);
if (r == 1)
r = crypt_hash_size(hash);
else
r = crypt_hash_size(integrity);
return r < 0 ? 0 : r;
}
int INTEGRITY_tag_size(struct crypt_device *cd,
const char *integrity,
const char *cipher,
@@ -202,7 +229,7 @@ int INTEGRITY_create_dmd_device(struct crypt_device *cd,
if (r < 0)
return r;
return dm_integrity_target_set(&dmd->segment, 0, dmd->size,
return dm_integrity_target_set(cd, &dmd->segment, 0, dmd->size,
crypt_metadata_device(cd), crypt_data_device(cd),
crypt_get_integrity_tag_size(cd), crypt_get_data_offset(cd),
crypt_get_sector_size(cd), vk, journal_crypt_key,
@@ -211,7 +238,9 @@ int INTEGRITY_create_dmd_device(struct crypt_device *cd,
int INTEGRITY_activate_dmd_device(struct crypt_device *cd,
const char *name,
struct crypt_dm_active_device *dmd)
const char *type,
struct crypt_dm_active_device *dmd,
uint32_t sb_flags)
{
int r;
uint32_t dmi_flags;
@@ -234,9 +263,15 @@ int INTEGRITY_activate_dmd_device(struct crypt_device *cd,
return r;
}
r = dm_create_device(cd, name, "INTEGRITY", dmd);
r = dm_create_device(cd, name, type, dmd);
if (r < 0 && (dm_flags(cd, DM_INTEGRITY, &dmi_flags) || !(dmi_flags & DM_INTEGRITY_SUPPORTED))) {
log_err(cd, _("Kernel doesn't support dm-integrity mapping."));
log_err(cd, _("Kernel does not support dm-integrity mapping."));
return -ENOTSUP;
}
if (r < 0 && (sb_flags & SB_FLAG_FIXED_PADDING) && !dm_flags(cd, DM_INTEGRITY, &dmi_flags) &&
!(dmi_flags & DM_INTEGRITY_FIX_PADDING_SUPPORTED)) {
log_err(cd, _("Kernel does not support dm-integrity fixed metadata alignment."));
return -ENOTSUP;
}
@@ -249,7 +284,7 @@ int INTEGRITY_activate(struct crypt_device *cd,
struct volume_key *vk,
struct volume_key *journal_crypt_key,
struct volume_key *journal_mac_key,
uint32_t flags)
uint32_t flags, uint32_t sb_flags)
{
struct crypt_dm_active_device dmd = {};
int r = INTEGRITY_create_dmd_device(cd, params, vk, journal_crypt_key, journal_mac_key, &dmd, flags);
@@ -257,7 +292,7 @@ int INTEGRITY_activate(struct crypt_device *cd,
if (r < 0)
return r;
r = INTEGRITY_activate_dmd_device(cd, name, &dmd);
r = INTEGRITY_activate_dmd_device(cd, name, CRYPT_INTEGRITY, &dmd, sb_flags);
dm_targets_free(cd, &dmd);
return r;
}
@@ -287,7 +322,7 @@ int INTEGRITY_format(struct crypt_device *cd,
if (params && params->integrity_key_size)
vk = crypt_alloc_volume_key(params->integrity_key_size, NULL);
r = dm_integrity_target_set(tgt, 0, dmdi.size, crypt_metadata_device(cd),
r = dm_integrity_target_set(cd, tgt, 0, dmdi.size, crypt_metadata_device(cd),
crypt_data_device(cd), crypt_get_integrity_tag_size(cd),
crypt_get_data_offset(cd), crypt_get_sector_size(cd), vk,
journal_crypt_key, journal_mac_key, params);
@@ -301,7 +336,7 @@ int INTEGRITY_format(struct crypt_device *cd,
r = device_block_adjust(cd, tgt->data_device, DEV_EXCL, tgt->u.integrity.offset, NULL, NULL);
if (r < 0 && (dm_flags(cd, DM_INTEGRITY, &dmi_flags) || !(dmi_flags & DM_INTEGRITY_SUPPORTED))) {
log_err(cd, _("Kernel doesn't support dm-integrity mapping."));
log_err(cd, _("Kernel does not support dm-integrity mapping."));
r = -ENOTSUP;
}
if (r) {
@@ -317,7 +352,7 @@ int INTEGRITY_format(struct crypt_device *cd,
}
}
r = dm_create_device(cd, tmp_name, "INTEGRITY", &dmdi);
r = dm_create_device(cd, tmp_name, CRYPT_INTEGRITY, &dmdi);
crypt_free_volume_key(vk);
dm_targets_free(cd, &dmdi);
if (r)

View File

@@ -1,7 +1,7 @@
/*
* Integrity header defitinion
* Integrity header definition
*
* Copyright (C) 2016-2019 Milan Broz
* Copyright (C) 2016-2020 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -33,9 +33,13 @@ struct crypt_dm_active_device;
#define SB_MAGIC "integrt"
#define SB_VERSION_1 1
#define SB_VERSION_2 2
#define SB_VERSION_3 3
#define SB_VERSION_4 4
#define SB_FLAG_HAVE_JOURNAL_MAC (1 << 0)
#define SB_FLAG_RECALCULATING (1 << 1) /* V2 only */
#define SB_FLAG_DIRTY_BITMAP (1 << 2) /* V3 only */
#define SB_FLAG_FIXED_PADDING (1 << 3) /* V4 only */
struct superblock {
uint8_t magic[8];
@@ -46,11 +50,14 @@ struct superblock {
uint64_t provided_data_sectors;
uint32_t flags;
uint8_t log2_sectors_per_block;
uint8_t pad[3];
uint64_t recalc_sector; /* V2 only */
uint8_t log2_blocks_per_bitmap_bit; /* V3 only */
uint8_t pad[2];
uint64_t recalc_sector; /* V2 only */
} __attribute__ ((packed));
int INTEGRITY_read_sb(struct crypt_device *cd, struct crypt_params_integrity *params);
int INTEGRITY_read_sb(struct crypt_device *cd,
struct crypt_params_integrity *params,
uint32_t *flags);
int INTEGRITY_dump(struct crypt_device *cd, struct device *device, uint64_t offset);
@@ -63,6 +70,7 @@ int INTEGRITY_tag_size(struct crypt_device *cd,
const char *integrity,
const char *cipher,
const char *cipher_mode);
int INTEGRITY_hash_tag_size(const char *integrity);
int INTEGRITY_format(struct crypt_device *cd,
const struct crypt_params_integrity *params,
@@ -75,7 +83,7 @@ int INTEGRITY_activate(struct crypt_device *cd,
struct volume_key *vk,
struct volume_key *journal_crypt_key,
struct volume_key *journal_mac_key,
uint32_t flags);
uint32_t flags, uint32_t sb_flags);
int INTEGRITY_create_dmd_device(struct crypt_device *cd,
const struct crypt_params_integrity *params,
@@ -87,5 +95,7 @@ int INTEGRITY_create_dmd_device(struct crypt_device *cd,
int INTEGRITY_activate_dmd_device(struct crypt_device *cd,
const char *name,
struct crypt_dm_active_device *dmd);
const char *type,
struct crypt_dm_active_device *dmd,
uint32_t sb_flags);
#endif

View File

@@ -3,8 +3,8 @@
*
* Copyright (C) 2004 Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2019 Milan Broz
* Copyright (C) 2009-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2020 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -27,6 +27,7 @@
#include <stdint.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
#include <inttypes.h>
@@ -40,6 +41,7 @@
#include "utils_keyring.h"
#include "utils_io.h"
#include "crypto_backend.h"
#include "utils_storage_wrappers.h"
#include "libcryptsetup.h"
@@ -53,6 +55,9 @@
#define DEFAULT_DISK_ALIGNMENT 1048576 /* 1MiB */
#define DEFAULT_MEM_ALIGNMENT 4096
#define LOG_MAX_LEN 4096
#define MAX_DM_DEPS 32
#define CRYPT_SUBDEV "SUBDEV" /* prefix for sublayered devices underneath public crypt types */
#define at_least(a, b) ({ __typeof__(a) __at_least = (a); (__at_least >= (b))?__at_least:(b); })
@@ -73,10 +78,13 @@
} while (0)
struct crypt_device;
struct luks2_reenc_context;
struct volume_key {
int id;
size_t keylength;
const char *key_description;
struct volume_key *next;
char key[];
};
@@ -84,6 +92,11 @@ struct volume_key *crypt_alloc_volume_key(size_t keylength, const char *key);
struct volume_key *crypt_generate_volume_key(struct crypt_device *cd, size_t keylength);
void crypt_free_volume_key(struct volume_key *vk);
int crypt_volume_key_set_description(struct volume_key *key, const char *key_description);
void crypt_volume_key_set_id(struct volume_key *vk, int id);
int crypt_volume_key_get_id(const struct volume_key *vk);
void crypt_volume_key_add_next(struct volume_key **vks, struct volume_key *vk);
struct volume_key *crypt_volume_key_next(struct volume_key *vk);
struct volume_key *crypt_volume_key_by_id(struct volume_key *vk, int id);
struct crypt_pbkdf_type *crypt_get_pbkdf(struct crypt_device *cd);
int init_pbkdf_type(struct crypt_device *cd,
@@ -100,6 +113,7 @@ const char *crypt_get_cipher_spec(struct crypt_device *cd);
struct device;
int device_alloc(struct crypt_device *cd, struct device **device, const char *path);
int device_alloc_no_check(struct device **device, const char *path);
void device_close(struct crypt_device *cd, struct device *device);
void device_free(struct crypt_device *cd, struct device *device);
const char *device_path(const struct device *device);
const char *device_dm_name(const struct device *device);
@@ -113,13 +127,15 @@ size_t device_block_size(struct crypt_device *cd, struct device *device);
int device_read_ahead(struct device *device, uint32_t *read_ahead);
int device_size(struct device *device, uint64_t *size);
int device_open(struct crypt_device *cd, struct device *device, int flags);
int device_open_excl(struct crypt_device *cd, struct device *device, int flags);
void device_release_excl(struct crypt_device *cd, struct device *device);
void device_disable_direct_io(struct device *device);
int device_is_identical(struct device *device1, struct device *device2);
int device_is_rotational(struct device *device);
size_t device_alignment(struct device *device);
int device_direct_io(const struct device *device);
int device_fallocate(struct device *device, uint64_t size);
void device_sync(struct crypt_device *cd, struct device *device, int devfd);
void device_sync(struct crypt_device *cd, struct device *device);
int device_check_size(struct crypt_device *cd,
struct device *device,
uint64_t req_offset, int falloc);
@@ -129,6 +145,7 @@ int device_read_lock(struct crypt_device *cd, struct device *device);
int device_write_lock(struct crypt_device *cd, struct device *device);
void device_read_unlock(struct crypt_device *cd, struct device *device);
void device_write_unlock(struct crypt_device *cd, struct device *device);
bool device_is_locked(struct device *device);
enum devcheck { DEV_OK = 0, DEV_EXCL = 1 };
int device_check_access(struct crypt_device *cd,
@@ -163,6 +180,7 @@ char *crypt_get_base_device(const char *dev_path);
uint64_t crypt_dev_partition_offset(const char *dev_path);
int lookup_by_disk_id(const char *dm_uuid);
int lookup_by_sysfs_uuid_field(const char *dm_uuid, size_t max_len);
int crypt_uuid_cmp(const char *dm_uuid, const char *hdr_uuid);
size_t crypt_getpagesize(void);
unsigned crypt_cpusonline(void);
@@ -199,6 +217,11 @@ int PLAIN_activate(struct crypt_device *cd,
uint32_t flags);
void *crypt_get_hdr(struct crypt_device *cd, const char *type);
void crypt_set_reenc_context(struct crypt_device *cd, struct luks2_reenc_context *rh);
struct luks2_reenc_context *crypt_get_reenc_context(struct crypt_device *cd);
int onlyLUKS2(struct crypt_device *cd);
int onlyLUKS2mask(struct crypt_device *cd, uint32_t mask);
int crypt_wipe_device(struct crypt_device *cd,
struct device *device,
@@ -218,7 +241,8 @@ int crypt_key_in_keyring(struct crypt_device *cd);
void crypt_set_key_in_keyring(struct crypt_device *cd, unsigned key_in_keyring);
int crypt_volume_key_load_in_keyring(struct crypt_device *cd, struct volume_key *vk);
int crypt_use_keyring_for_vk(struct crypt_device *cd);
void crypt_drop_keyring_key(struct crypt_device *cd, const char *key_description);
void crypt_drop_keyring_key_by_description(struct crypt_device *cd, const char *key_description, key_type_t ktype);
void crypt_drop_keyring_key(struct crypt_device *cd, struct volume_key *vks);
static inline uint64_t version(uint16_t major, uint16_t minor, uint16_t patch, uint16_t release)
{
@@ -227,4 +251,14 @@ static inline uint64_t version(uint16_t major, uint16_t minor, uint16_t patch, u
int kernel_version(uint64_t *kversion);
int crypt_serialize_lock(struct crypt_device *cd);
void crypt_serialize_unlock(struct crypt_device *cd);
bool crypt_string_in(const char *str, char **list, size_t list_size);
int crypt_strcmp(const char *a, const char *b);
int crypt_compare_dm_devices(struct crypt_device *cd,
const struct crypt_dm_active_device *src,
const struct crypt_dm_active_device *tgt);
static inline void *crypt_zalloc(size_t size) { return calloc(1, size); }
#endif /* INTERNAL_H */

View File

@@ -3,8 +3,8 @@
*
* Copyright (C) 2004 Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2019 Milan Broz
* Copyright (C) 2009-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2020 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -414,6 +414,8 @@ int crypt_get_metadata_size(struct crypt_device *cd,
#define CRYPT_TCRYPT "TCRYPT"
/** INTEGRITY dm-integrity device */
#define CRYPT_INTEGRITY "INTEGRITY"
/** BITLK (BitLocker-compatible mode) */
#define CRYPT_BITLK "BITLK"
/** LUKS any version */
#define CRYPT_LUKS NULL
@@ -505,6 +507,8 @@ struct crypt_params_verity {
#define CRYPT_VERITY_CHECK_HASH (1 << 1)
/** Create hash - format hash device */
#define CRYPT_VERITY_CREATE_HASH (1 << 2)
/** Root hash signature required for activation */
#define CRYPT_VERITY_ROOT_HASH_SIGNATURE (1 << 3)
/**
*
@@ -546,11 +550,15 @@ struct crypt_params_tcrypt {
*
* @see crypt_format, crypt_load
*
* @note In bitmap tracking mode, the journal is implicitly disabled.
* As an ugly workaround for compatibility, journal_watermark is overloaded
* to mean 512-bytes sectors-per-bit and journal_commit_time means bitmap flush time.
* All other journal parameters are not applied in the bitmap mode.
*/
struct crypt_params_integrity {
uint64_t journal_size; /**< size of journal in bytes */
unsigned int journal_watermark; /**< journal flush watermark in percents */
unsigned int journal_commit_time; /**< journal commit time in ms */
unsigned int journal_watermark; /**< journal flush watermark in percents; in bitmap mode sectors-per-bit */
unsigned int journal_commit_time; /**< journal commit time (or bitmap flush time) in ms */
uint32_t interleave_sectors; /**< number of interleave sectors (power of two) */
uint32_t tag_size; /**< tag size per-sector in bytes */
uint32_t sector_size; /**< sector size in bytes */
@@ -625,6 +633,26 @@ int crypt_format(struct crypt_device *cd,
size_t volume_key_size,
void *params);
/**
* Set format compatibility flags.
*
* @param cd crypt device handle
* @param flags CRYPT_COMPATIBILITY_* flags
*/
void crypt_set_compatibility(struct crypt_device *cd, uint32_t flags);
/**
* Get compatibility flags.
*
* @param cd crypt device handle
*
* @returns compatibility flags
*/
uint32_t crypt_get_compatibility(struct crypt_device *cd);
/** dm-integrity device uses less effective (legacy) padding (old kernels) */
#define CRYPT_COMPAT_LEGACY_INTEGRITY_PADDING (1 << 0)
/**
* Convert to new type for already existing device.
*
@@ -824,6 +852,20 @@ int crypt_resume_by_keyfile(struct crypt_device *cd,
int keyslot,
const char *keyfile,
size_t keyfile_size);
/**
* Resume crypt device using provided volume key.
*
* @param cd crypt device handle
* @param name name of device to resume
* @param volume_key provided volume key
* @param volume_key_size size of volume_key
*
* @return @e 0 on success or negative errno value otherwise.
*/
int crypt_resume_by_volume_key(struct crypt_device *cd,
const char *name,
const char *volume_key,
size_t volume_key_size);
/** @} */
/**
@@ -870,10 +912,6 @@ int crypt_keyslot_add_by_passphrase(struct crypt_device *cd,
* @param new_passphrase_size size of @e new_passphrase (binary data)
*
* @return allocated key slot number or negative errno otherwise.
*
* @note This function is just internal implementation of luksChange
* command to avoid reading of volume key outside libcryptsetup boundary
* in FIPS mode.
*/
int crypt_keyslot_change_by_passphrase(struct crypt_device *cd,
int keyslot_old,
@@ -957,6 +995,9 @@ int crypt_keyslot_add_by_volume_key(struct crypt_device *cd,
/** create keyslot with new volume key and assign it to current dm-crypt segment */
#define CRYPT_VOLUME_KEY_SET (1 << 1)
/** Assign key to first matching digest before creating new digest */
#define CRYPT_VOLUME_KEY_DIGEST_REUSE (1 << 2)
/**
* Add key slot using provided key.
*
@@ -1054,6 +1095,12 @@ int crypt_keyslot_destroy(struct crypt_device *cd, int keyslot);
#define CRYPT_ACTIVATE_RECALCULATE (1 << 17)
/** reactivate existing and update flags, input only */
#define CRYPT_ACTIVATE_REFRESH (1 << 18)
/** Use global lock to serialize memory hard KDF on activation (OOM workaround) */
#define CRYPT_ACTIVATE_SERIALIZE_MEMORY_HARD_PBKDF (1 << 19)
/** dm-integrity: direct writes, use bitmap to track dirty sectors */
#define CRYPT_ACTIVATE_NO_JOURNAL_BITMAP (1 << 20)
/** device is suspended (key should be wiped from memory), output only */
#define CRYPT_ACTIVATE_SUSPENDED (1 << 21)
/**
* Active device runtime attributes
@@ -1103,6 +1150,8 @@ uint64_t crypt_get_active_integrity_failures(struct crypt_device *cd,
*/
/** Unfinished offline reencryption */
#define CRYPT_REQUIREMENT_OFFLINE_REENCRYPT (1 << 0)
/** Online reencryption in-progress */
#define CRYPT_REQUIREMENT_ONLINE_REENCRYPT (1 << 1)
/** unknown requirement in header (output only) */
#define CRYPT_REQUIREMENT_UNKNOWN (1 << 31)
@@ -1243,6 +1292,31 @@ int crypt_activate_by_volume_key(struct crypt_device *cd,
size_t volume_key_size,
uint32_t flags);
/**
* Activate VERITY device using provided key and optional signature).
*
* @param cd crypt device handle
* @param name name of device to create
* @param volume_key provided volume key
* @param volume_key_size size of volume_key
* @param signature buffer with signature for the key
* @param signature_size bsize of signature buffer
* @param flags activation flags
*
* @return @e 0 on success or negative errno value otherwise.
*
* @note For VERITY the volume key means root hash required for activation.
* Because kernel dm-verity is always read only, you have to provide
* CRYPT_ACTIVATE_READONLY flag always.
*/
int crypt_activate_by_signed_key(struct crypt_device *cd,
const char *name,
const char *volume_key,
size_t volume_key_size,
const char *signature,
size_t signature_size,
uint32_t flags);
/**
* Activate device using passphrase stored in kernel keyring.
*
@@ -1313,6 +1387,7 @@ int crypt_deactivate(struct crypt_device *cd, const char *name);
*
* @note For TCRYPT cipher chain is the volume key concatenated
* for all ciphers in chain.
* @note For VERITY the volume key means root hash used for activation.
*/
int crypt_volume_key_get(struct crypt_device *cd,
int keyslot,
@@ -1448,6 +1523,8 @@ uint64_t crypt_get_iv_offset(struct crypt_device *cd);
*
* @return volume key size
*
* @note For LUKS2, this function can be used only if there is at least
* one keyslot assigned to data segment.
*/
int crypt_get_volume_key_size(struct crypt_device *cd);
@@ -1739,7 +1816,7 @@ int crypt_header_restore(struct crypt_device *cd,
/** Debug all */
#define CRYPT_DEBUG_ALL -1
/** Debug all with adidtional JSON dump (for LUKS2) */
/** Debug all with additional JSON dump (for LUKS2) */
#define CRYPT_DEBUG_JSON -2
/** Debug none */
#define CRYPT_DEBUG_NONE 0
@@ -2098,6 +2175,195 @@ int crypt_activate_by_token(struct crypt_device *cd,
uint32_t flags);
/** @} */
/**
* @defgroup crypt-reencryption LUKS2 volume reencryption support
*
* Set of functions to handling LUKS2 volume reencryption
*
* @addtogroup crypt-reencryption
* @{
*/
/** Initialize reencryption metadata but do not run reencryption yet. (in) */
#define CRYPT_REENCRYPT_INITIALIZE_ONLY (1 << 0)
/** Move the first segment, used only with data shift. (in/out) */
#define CRYPT_REENCRYPT_MOVE_FIRST_SEGMENT (1 << 1)
/** Resume already initialized reencryption only. (in) */
#define CRYPT_REENCRYPT_RESUME_ONLY (1 << 2)
/** Run reencryption recovery only. (in) */
#define CRYPT_REENCRYPT_RECOVERY (1 << 3)
/**
* Reencryption direction
*/
typedef enum {
CRYPT_REENCRYPT_FORWARD = 0, /**< forward direction */
CRYPT_REENCRYPT_BACKWARD /**< backward direction */
} crypt_reencrypt_direction_info;
/**
* Reencryption mode
*/
typedef enum {
CRYPT_REENCRYPT_REENCRYPT = 0, /**< Reencryption mode */
CRYPT_REENCRYPT_ENCRYPT, /**< Encryption mode */
CRYPT_REENCRYPT_DECRYPT, /**< Decryption mode */
} crypt_reencrypt_mode_info;
/**
* LUKS2 reencryption options.
*/
struct crypt_params_reencrypt {
crypt_reencrypt_mode_info mode; /**< Reencryption mode, immutable after first init. */
crypt_reencrypt_direction_info direction; /**< Reencryption direction, immutable after first init. */
const char *resilience; /**< Resilience mode: "none", "checksum", "journal" or "shift" (only "shift" is immutable after init) */
const char *hash; /**< Used hash for "checksum" resilience type, ignored otherwise. */
uint64_t data_shift; /**< Used in "shift" mode, must be non-zero, immutable after first init. */
uint64_t max_hotzone_size; /**< Exact hotzone size for "none" mode. Maximum hotzone size for "checksum" and "journal" modes. */
uint64_t device_size; /**< Reencrypt only initial part of the data device. */
const struct crypt_params_luks2 *luks2; /**< LUKS2 parameters for the final reencryption volume.*/
uint32_t flags; /**< Reencryption flags. */
};
/**
* Initialize reencryption metadata using passphrase.
*
* This function initializes on-disk metadata to include all reencryption segments,
* according to the provided options.
* If metadata already contains ongoing reencryption metadata, it loads these parameters
* (in this situation all parameters except @e name and @e passphrase can be omitted).
*
* @param cd crypt device handle
* @param name name of active device or @e NULL for offline reencryption
* @param passphrase passphrase used to unlock volume key
* @param passphrase_size size of @e passphrase (binary data)
* @param keyslot_old keyslot to unlock existing device or CRYPT_ANY_SLOT
* @param keyslot_new existing (unbound) reencryption keyslot; must be set except for decryption
* @param cipher cipher specification (e.g. "aes")
* @param cipher_mode cipher mode and IV (e.g. "xts-plain64")
* @param params reencryption parameters @link crypt_params_reencrypt @endlink.
*
* @return reencryption key slot number or negative errno otherwise.
*/
int crypt_reencrypt_init_by_passphrase(struct crypt_device *cd,
const char *name,
const char *passphrase,
size_t passphrase_size,
int keyslot_old,
int keyslot_new,
const char *cipher,
const char *cipher_mode,
const struct crypt_params_reencrypt *params);
/**
* Initialize reencryption metadata using passphrase in keyring.
*
* This function initializes on-disk metadata to include all reencryption segments,
* according to the provided options.
* If metadata already contains ongoing reencryption metadata, it loads these parameters
* (in this situation all parameters except @e name and @e key_description can be omitted).
*
* @param cd crypt device handle
* @param name name of active device or @e NULL for offline reencryption
* @param key_description passphrase (key) identification in keyring
* @param keyslot_old keyslot to unlock existing device or CRYPT_ANY_SLOT
* @param keyslot_new existing (unbound) reencryption keyslot; must be set except for decryption
* @param cipher cipher specification (e.g. "aes")
* @param cipher_mode cipher mode and IV (e.g. "xts-plain64")
* @param params reencryption parameters @link crypt_params_reencrypt @endlink.
*
* @return reencryption key slot number or negative errno otherwise.
*/
int crypt_reencrypt_init_by_keyring(struct crypt_device *cd,
const char *name,
const char *key_description,
int keyslot_old,
int keyslot_new,
const char *cipher,
const char *cipher_mode,
const struct crypt_params_reencrypt *params);
/**
* Run data reencryption.
*
* @param cd crypt device handle
* @param progress is a callback funtion reporting device \b size,
* current \b offset of reencryption and provided \b usrptr identification
*
* @return @e 0 on success or negative errno value otherwise.
*/
int crypt_reencrypt(struct crypt_device *cd,
int (*progress)(uint64_t size, uint64_t offset, void *usrptr));
/**
* Reencryption status info
*/
typedef enum {
CRYPT_REENCRYPT_NONE = 0, /**< No reencryption in progress */
CRYPT_REENCRYPT_CLEAN, /**< Ongoing reencryption in a clean state. */
CRYPT_REENCRYPT_CRASH, /**< Aborted reencryption that need internal recovery. */
CRYPT_REENCRYPT_INVALID /**< Invalid state. */
} crypt_reencrypt_info;
/**
* LUKS2 reencryption status.
*
* @param cd crypt device handle
* @param params reencryption parameters
*
* @return reencryption status info and parameters.
*/
crypt_reencrypt_info crypt_reencrypt_status(struct crypt_device *cd,
struct crypt_params_reencrypt *params);
/** @} */
/**
* @defgroup crypt-memory Safe memory helpers functions
* @addtogroup crypt-memory
* @{
*/
/**
* Allocate safe memory (content is safely wiped on deallocation).
*
* @param size size of memory in bytes
*
* @return pointer to allocate memory or @e NULL.
*/
void *crypt_safe_alloc(size_t size);
/**
* Release safe memory, content is safely wiped
* The pointer must be allocated with @link crypt_safe_alloc @endlink
*
* @param data pointer to memory to be deallocated
*
* @return pointer to allocate memory or @e NULL.
*/
void crypt_safe_free(void *data);
/**
* Reallocate safe memory (content is copied and safely wiped on deallocation).
*
* @param data pointer to memory to be deallocated
* @param size new size of memory in bytes
*
* @return pointer to allocate memory or @e NULL.
*/
void *crypt_safe_realloc(void *data, size_t size);
/**
* Safe clear memory area (compile should not compile this call out).
*
* @param data pointer to memory to cleared
* @param size new size of memory in bytes
*
* @return pointer to allocate memory or @e NULL.
*/
void crypt_safe_memzero(void *data, size_t size);
/** @} */
#ifdef __cplusplus
}
#endif

View File

@@ -12,6 +12,9 @@ CRYPTSETUP_2.0 {
crypt_set_label;
crypt_set_data_device;
crypt_set_compatibility;
crypt_get_compatibility;
crypt_memory_lock;
crypt_metadata_locking;
crypt_format;
@@ -24,6 +27,7 @@ CRYPTSETUP_2.0 {
crypt_resume_by_keyfile;
crypt_resume_by_keyfile_offset;
crypt_resume_by_keyfile_device_offset;
crypt_resume_by_volume_key;
crypt_free;
crypt_keyslot_add_by_passphrase;
@@ -55,6 +59,7 @@ CRYPTSETUP_2.0 {
crypt_activate_by_keyfile_offset;
crypt_activate_by_keyfile_device_offset;
crypt_activate_by_volume_key;
crypt_activate_by_signed_key;
crypt_activate_by_keyring;
crypt_deactivate;
crypt_deactivate_by_name;
@@ -113,6 +118,16 @@ CRYPTSETUP_2.0 {
crypt_keyfile_device_read;
crypt_wipe;
crypt_reencrypt_init_by_passphrase;
crypt_reencrypt_init_by_keyring;
crypt_reencrypt;
crypt_reencrypt_status;
crypt_safe_alloc;
crypt_safe_realloc;
crypt_safe_free;
crypt_safe_memzero;
local:
*;
};

View File

@@ -3,8 +3,8 @@
*
* Copyright (C) 2004 Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2019 Milan Broz
* Copyright (C) 2009-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2020 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -31,6 +31,9 @@
#include <linux/fs.h>
#include <uuid/uuid.h>
#include <sys/stat.h>
#ifdef HAVE_SYS_SYSMACROS_H
# include <sys/sysmacros.h> /* for major, minor */
#endif
#include "internal.h"
@@ -43,6 +46,8 @@
#define DM_VERITY_TARGET "verity"
#define DM_INTEGRITY_TARGET "integrity"
#define DM_LINEAR_TARGET "linear"
#define DM_ERROR_TARGET "error"
#define DM_ZERO_TARGET "zero"
#define RETRY_COUNT 5
/* Set if DM target versions were probed */
@@ -164,6 +169,12 @@ static void _dm_set_crypt_compat(struct crypt_device *cd,
_dm_flags |= DM_CAPI_STRING_SUPPORTED;
}
if (_dm_satisfies_version(1, 19, 0, crypt_maj, crypt_min, crypt_patch))
_dm_flags |= DM_BITLK_EBOIV_SUPPORTED;
if (_dm_satisfies_version(1, 20, 0, crypt_maj, crypt_min, crypt_patch))
_dm_flags |= DM_BITLK_ELEPHANT_SUPPORTED;
_dm_crypt_checked = true;
}
@@ -192,6 +203,9 @@ static void _dm_set_verity_compat(struct crypt_device *cd,
_dm_flags |= DM_VERITY_FEC_SUPPORTED;
}
if (_dm_satisfies_version(1, 5, 0, verity_maj, verity_min, verity_patch))
_dm_flags |= DM_VERITY_SIGNATURE_SUPPORTED;
_dm_verity_checked = true;
}
@@ -211,9 +225,48 @@ static void _dm_set_integrity_compat(struct crypt_device *cd,
if (_dm_satisfies_version(1, 2, 0, integrity_maj, integrity_min, integrity_patch))
_dm_flags |= DM_INTEGRITY_RECALC_SUPPORTED;
if (_dm_satisfies_version(1, 3, 0, integrity_maj, integrity_min, integrity_patch))
_dm_flags |= DM_INTEGRITY_BITMAP_SUPPORTED;
if (_dm_satisfies_version(1, 4, 0, integrity_maj, integrity_min, integrity_patch))
_dm_flags |= DM_INTEGRITY_FIX_PADDING_SUPPORTED;
_dm_integrity_checked = true;
}
/* We use this for loading target module */
static void _dm_check_target(dm_target_type target_type)
{
#if HAVE_DECL_DM_DEVICE_GET_TARGET_VERSION
struct dm_task *dmt;
const char *target_name = NULL;
if (!(_dm_flags & DM_GET_TARGET_VERSION_SUPPORTED))
return;
if (target_type == DM_CRYPT)
target_name = DM_CRYPT_TARGET;
else if (target_type == DM_VERITY)
target_name = DM_VERITY_TARGET;
else if (target_type == DM_INTEGRITY)
target_name = DM_INTEGRITY_TARGET;
else
return;
if (!(dmt = dm_task_create(DM_DEVICE_GET_TARGET_VERSION)))
goto out;
if (!dm_task_set_name(dmt, target_name))
goto out;
if (!dm_task_run(dmt))
goto out;
out:
if (dmt)
dm_task_destroy(dmt);
#endif
}
static int _dm_check_versions(struct crypt_device *cd, dm_target_type target_type)
{
struct dm_task *dmt;
@@ -222,15 +275,18 @@ static int _dm_check_versions(struct crypt_device *cd, dm_target_type target_typ
unsigned dm_maj, dm_min, dm_patch;
int r = 0;
if (((target_type == DM_CRYPT || target_type == DM_LINEAR) && _dm_crypt_checked) ||
if ((target_type == DM_CRYPT && _dm_crypt_checked) ||
(target_type == DM_VERITY && _dm_verity_checked) ||
(target_type == DM_INTEGRITY && _dm_integrity_checked) ||
(target_type == DM_LINEAR) || (target_type == DM_ZERO) ||
(_dm_crypt_checked && _dm_verity_checked && _dm_integrity_checked))
return 1;
/* Shut up DM while checking */
_quiet_log = 1;
_dm_check_target(target_type);
/* FIXME: add support to DM so it forces crypt target module load here */
if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS)))
goto out;
@@ -251,6 +307,10 @@ static int _dm_check_versions(struct crypt_device *cd, dm_target_type target_typ
#if HAVE_DECL_DM_TASK_DEFERRED_REMOVE
if (_dm_satisfies_version(4, 27, 0, dm_maj, dm_min, dm_patch))
_dm_flags |= DM_DEFERRED_SUPPORTED;
#endif
#if HAVE_DECL_DM_DEVICE_GET_TARGET_VERSION
if (_dm_satisfies_version(4, 41, 0, dm_maj, dm_min, dm_patch))
_dm_flags |= DM_GET_TARGET_VERSION_SUPPORTED;
#endif
}
@@ -296,9 +356,10 @@ int dm_flags(struct crypt_device *cd, dm_target_type target, uint32_t *flags)
_dm_crypt_checked && _dm_verity_checked && _dm_integrity_checked)
return 0;
if (((target == DM_CRYPT || target == DM_LINEAR) && _dm_crypt_checked) ||
if ((target == DM_CRYPT && _dm_crypt_checked) ||
(target == DM_VERITY && _dm_verity_checked) ||
(target == DM_INTEGRITY && _dm_integrity_checked))
(target == DM_INTEGRITY && _dm_integrity_checked) ||
(target == DM_LINEAR) || (target == DM_ZERO)) /* nothing to check */
return 0;
return -ENODEV;
@@ -374,6 +435,16 @@ char *dm_device_path(const char *prefix, int major, int minor)
return strdup(path);
}
char *dm_device_name(const char *path)
{
struct stat st;
if (stat(path, &st) < 0 || !S_ISBLK(st.st_mode))
return NULL;
return dm_device_path(NULL, major(st.st_rdev), minor(st.st_rdev));
}
static void hex_key(char *hexkey, size_t key_size, const char *key)
{
unsigned i;
@@ -609,7 +680,7 @@ static char *get_dm_verity_params(const struct dm_target *tgt, uint32_t flags)
int max_size, r, num_options = 0;
struct crypt_params_verity *vp;
char *params = NULL, *hexroot = NULL, *hexsalt = NULL;
char features[256], fec_features[256];
char features[256], fec_features[256], verity_verify_args[512+32];
if (!tgt || !tgt->u.verity.vp)
return NULL;
@@ -639,6 +710,13 @@ static char *get_dm_verity_params(const struct dm_target *tgt, uint32_t flags)
} else
*fec_features = '\0';
if (tgt->u.verity.root_hash_sig_key_desc) {
num_options += 2;
snprintf(verity_verify_args, sizeof(verity_verify_args)-1,
" root_hash_sig_key_desc %s", tgt->u.verity.root_hash_sig_key_desc);
} else
*verity_verify_args = '\0';
if (num_options)
snprintf(features, sizeof(features)-1, " %d%s%s%s%s", num_options,
(flags & CRYPT_ACTIVATE_IGNORE_CORRUPTION) ? " ignore_corruption" : "",
@@ -664,19 +742,22 @@ static char *get_dm_verity_params(const struct dm_target *tgt, uint32_t flags)
max_size = strlen(hexroot) + strlen(hexsalt) +
strlen(device_block_path(tgt->data_device)) +
strlen(device_block_path(tgt->u.verity.hash_device)) +
strlen(vp->hash_name) + strlen(features) + strlen(fec_features) + 128;
strlen(vp->hash_name) + strlen(features) + strlen(fec_features) + 128 +
strlen(verity_verify_args);
params = crypt_safe_alloc(max_size);
if (!params)
goto out;
r = snprintf(params, max_size,
"%u %s %s %u %u %" PRIu64 " %" PRIu64 " %s %s %s%s%s",
"%u %s %s %u %u %" PRIu64 " %" PRIu64 " %s %s %s%s%s%s",
vp->hash_type, device_block_path(tgt->data_device),
device_block_path(tgt->u.verity.hash_device),
vp->data_block_size, vp->hash_block_size,
vp->data_size, tgt->u.verity.hash_offset,
vp->hash_name, hexroot, hexsalt, features, fec_features);
vp->hash_name, hexroot, hexsalt, features, fec_features,
verity_verify_args);
if (r < 0 || r >= max_size) {
crypt_safe_free(params);
params = NULL;
@@ -703,7 +784,7 @@ static char *get_dm_integrity_params(const struct dm_target *tgt, uint32_t flags
(tgt->u.integrity.journal_crypt_key ? tgt->u.integrity.journal_crypt_key->keylength * 2 : 0) +
(tgt->u.integrity.integrity ? strlen(tgt->u.integrity.integrity) : 0) +
(tgt->u.integrity.journal_integrity ? strlen(tgt->u.integrity.journal_integrity) : 0) +
(tgt->u.integrity.journal_crypt ? strlen(tgt->u.integrity.journal_crypt) : 0) + 128;
(tgt->u.integrity.journal_crypt ? strlen(tgt->u.integrity.journal_crypt) : 0) + 128;
params = crypt_safe_alloc(max_size);
if (!params)
@@ -718,13 +799,17 @@ static char *get_dm_integrity_params(const struct dm_target *tgt, uint32_t flags
}
if (tgt->u.integrity.journal_watermark) {
num_options++;
snprintf(feature, sizeof(feature), "journal_watermark:%u ",
snprintf(feature, sizeof(feature),
/* bitmap overloaded values */
(flags & CRYPT_ACTIVATE_NO_JOURNAL_BITMAP) ? "sectors_per_bit:%u " : "journal_watermark:%u ",
tgt->u.integrity.journal_watermark);
strncat(features, feature, sizeof(features) - strlen(features) - 1);
}
if (tgt->u.integrity.journal_commit_time) {
num_options++;
snprintf(feature, sizeof(feature), "commit_time:%u ",
snprintf(feature, sizeof(feature),
/* bitmap overloaded values */
(flags & CRYPT_ACTIVATE_NO_JOURNAL_BITMAP) ? "bitmap_flush_interval:%u " : "commit_time:%u ",
tgt->u.integrity.journal_commit_time);
strncat(features, feature, sizeof(features) - strlen(features) - 1);
}
@@ -804,6 +889,11 @@ static char *get_dm_integrity_params(const struct dm_target *tgt, uint32_t flags
strncat(features, feature, sizeof(features) - strlen(features) - 1);
crypt_safe_free(hexkey);
}
if (tgt->u.integrity.fix_padding) {
num_options++;
snprintf(feature, sizeof(feature), "fix_padding ");
strncat(features, feature, sizeof(features) - strlen(features) - 1);
}
if (flags & CRYPT_ACTIVATE_RECALCULATE) {
num_options++;
@@ -818,7 +908,9 @@ static char *get_dm_integrity_params(const struct dm_target *tgt, uint32_t flags
strncat(features, feature, sizeof(features) - strlen(features) - 1);
}
if (flags & CRYPT_ACTIVATE_RECOVERY)
if (flags & CRYPT_ACTIVATE_NO_JOURNAL_BITMAP)
mode = 'B';
else if (flags & CRYPT_ACTIVATE_RECOVERY)
mode = 'R';
else if (flags & CRYPT_ACTIVATE_NO_JOURNAL)
mode = 'D';
@@ -858,6 +950,16 @@ static char *get_dm_linear_params(const struct dm_target *tgt, uint32_t flags)
return params;
}
static char *get_dm_zero_params(const struct dm_target *tgt, uint32_t flags)
{
char *params = crypt_safe_alloc(1);
if (!params)
return NULL;
params[0] = 0;
return params;
}
/* DM helpers */
static int _dm_remove(const char *name, int udev_wait, int deferred)
{
@@ -894,7 +996,7 @@ out:
return r;
}
static int _dm_simple(int task, const char *name)
static int _dm_simple(int task, const char *name, uint32_t dmflags)
{
int r = 0;
struct dm_task *dmt;
@@ -905,6 +1007,14 @@ static int _dm_simple(int task, const char *name)
if (name && !dm_task_set_name(dmt, name))
goto out;
if (task == DM_DEVICE_SUSPEND &&
(dmflags & DM_SUSPEND_SKIP_LOCKFS) && !dm_task_skip_lockfs(dmt))
goto out;
if (task == DM_DEVICE_SUSPEND &&
(dmflags & DM_SUSPEND_NOFLUSH) && !dm_task_no_flush(dmt))
goto out;
r = dm_task_run(dmt);
out:
dm_task_destroy(dmt);
@@ -937,7 +1047,7 @@ static int _error_device(const char *name, size_t size)
goto error;
if (_dm_resume_device(name, 0)) {
_dm_simple(DM_DEVICE_CLEAR, name);
_dm_simple(DM_DEVICE_CLEAR, name, 0);
goto error;
}
@@ -959,7 +1069,7 @@ int dm_error_device(struct crypt_device *cd, const char *name)
if (dm_init_context(cd, DM_UNKNOWN))
return -ENOTSUP;
if (dm_query_device(cd, name, 0, &dmd) && _error_device(name, dmd.size))
if ((dm_query_device(cd, name, 0, &dmd) >= 0) && _error_device(name, dmd.size))
r = 0;
else
r = -EINVAL;
@@ -981,7 +1091,7 @@ int dm_clear_device(struct crypt_device *cd, const char *name)
if (dm_init_context(cd, DM_UNKNOWN))
return -ENOTSUP;
if (_dm_simple(DM_DEVICE_CLEAR, name))
if (_dm_simple(DM_DEVICE_CLEAR, name, 0))
r = 0;
else
r = -EINVAL;
@@ -1123,6 +1233,9 @@ static int _add_dm_targets(struct dm_task *dmt, struct crypt_dm_active_device *d
case DM_LINEAR:
target = DM_LINEAR_TARGET;
break;
case DM_ZERO:
target = DM_ZERO_TARGET;
break;
default:
return -ENOTSUP;
}
@@ -1161,6 +1274,8 @@ static int _create_dm_targets_params(struct crypt_dm_active_device *dmd)
tgt->params = get_dm_integrity_params(tgt, dmd->flags);
else if (tgt->type == DM_LINEAR)
tgt->params = get_dm_linear_params(tgt, dmd->flags);
else if (tgt->type == DM_ZERO)
tgt->params = get_dm_zero_params(tgt, dmd->flags);
else {
r = -ENOTSUP;
goto err;
@@ -1259,14 +1374,14 @@ out:
return r;
}
static int _dm_resume_device(const char *name, uint32_t flags)
static int _dm_resume_device(const char *name, uint32_t dmflags)
{
struct dm_task *dmt;
int r = -EINVAL;
uint32_t cookie = 0;
uint16_t udev_flags = DM_UDEV_DISABLE_LIBRARY_FALLBACK;
if (flags & CRYPT_ACTIVATE_PRIVATE)
if (dmflags & DM_RESUME_PRIVATE)
udev_flags |= CRYPT_TEMP_UDEV_FLAGS;
if (!(dmt = dm_task_create(DM_DEVICE_RESUME)))
@@ -1275,6 +1390,12 @@ static int _dm_resume_device(const char *name, uint32_t flags)
if (!dm_task_set_name(dmt, name))
goto out;
if ((dmflags & DM_SUSPEND_SKIP_LOCKFS) && !dm_task_skip_lockfs(dmt))
goto out;
if ((dmflags & DM_SUSPEND_NOFLUSH) && !dm_task_no_flush(dmt))
goto out;
if (_dm_use_udev() && !_dm_task_set_cookie(dmt, &cookie, udev_flags))
goto out;
@@ -1376,11 +1497,16 @@ static void _dm_target_free_query_path(struct crypt_device *cd, struct dm_target
crypt_free_verity_params(tgt->u.verity.vp);
device_free(cd, tgt->u.verity.hash_device);
free(CONST_CAST(void*)tgt->u.verity.root_hash);
free(CONST_CAST(void*)tgt->u.verity.root_hash_sig_key_desc);
/* fall through */
case DM_LINEAR:
/* fall through */
case DM_ERROR:
/* fall through */
case DM_ZERO:
break;
default:
log_err(NULL, "Unknown dm target type.");
log_err(cd, _("Unknown dm target type."));
return;
}
@@ -1418,10 +1544,9 @@ int dm_targets_allocate(struct dm_target *first, unsigned count)
return -EINVAL;
while (--count) {
first->next = malloc(sizeof(*first));
first->next = crypt_zalloc(sizeof(*first));
if (!first->next)
return -ENOMEM;
memset(first->next, 0, sizeof(*first));
first = first->next;
}
@@ -1443,7 +1568,7 @@ static int check_retry(struct crypt_device *cd, uint32_t *dmd_flags, uint32_t dm
/* If kernel keyring is not supported load key directly in dm-crypt */
if ((*dmd_flags & CRYPT_ACTIVATE_KEYRING_KEY) &&
!(dmt_flags & DM_KERNEL_KEYRING_SUPPORTED)) {
log_dbg(cd, "dm-crypt doesn't support kernel keyring");
log_dbg(cd, "dm-crypt does not support kernel keyring");
*dmd_flags = *dmd_flags & ~CRYPT_ACTIVATE_KEYRING_KEY;
ret = 1;
}
@@ -1451,7 +1576,7 @@ static int check_retry(struct crypt_device *cd, uint32_t *dmd_flags, uint32_t dm
/* Drop performance options if not supported */
if ((*dmd_flags & (CRYPT_ACTIVATE_SAME_CPU_CRYPT | CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS)) &&
!(dmt_flags & (DM_SAME_CPU_CRYPT_SUPPORTED | DM_SUBMIT_FROM_CRYPT_CPUS_SUPPORTED))) {
log_dbg(cd, "dm-crypt doesn't support performance options");
log_dbg(cd, "dm-crypt does not support performance options");
*dmd_flags = *dmd_flags & ~(CRYPT_ACTIVATE_SAME_CPU_CRYPT | CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS);
ret = 1;
}
@@ -1477,7 +1602,8 @@ int dm_create_device(struct crypt_device *cd, const char *name,
if (r < 0 && dm_flags(cd, dmd->segment.type, &dmt_flags))
goto out;
if (r && (dmd->segment.type == DM_CRYPT || dmd->segment.type == DM_LINEAR) && check_retry(cd, &dmd->flags, dmt_flags))
if (r && (dmd->segment.type == DM_CRYPT || dmd->segment.type == DM_LINEAR || dmd->segment.type == DM_ZERO) &&
check_retry(cd, &dmd->flags, dmt_flags))
r = _dm_create_device(cd, name, type, dmd->uuid, dmd);
if (r == -EINVAL &&
@@ -1506,13 +1632,17 @@ int dm_create_device(struct crypt_device *cd, const char *name,
if (r == -EINVAL && dmd->segment.type == DM_INTEGRITY && (dmd->flags & CRYPT_ACTIVATE_RECALCULATE) &&
!(dmt_flags & DM_INTEGRITY_RECALC_SUPPORTED))
log_err(cd, _("Requested automatic recalculation of integrity tags is not supported."));
if (r == -EINVAL && dmd->segment.type == DM_INTEGRITY && (dmd->flags & CRYPT_ACTIVATE_NO_JOURNAL_BITMAP) &&
!(dmt_flags & DM_INTEGRITY_BITMAP_SUPPORTED))
log_err(cd, _("Requested dm-integrity bitmap mode is not supported."));
out:
dm_exit_context();
return r;
}
int dm_reload_device(struct crypt_device *cd, const char *name,
struct crypt_dm_active_device *dmd, unsigned resume)
struct crypt_dm_active_device *dmd, uint32_t dmflags, unsigned resume)
{
int r;
uint32_t dmt_flags;
@@ -1531,14 +1661,14 @@ int dm_reload_device(struct crypt_device *cd, const char *name,
if (r == -EINVAL && (dmd->segment.type == DM_CRYPT || dmd->segment.type == DM_LINEAR)) {
if ((dmd->flags & (CRYPT_ACTIVATE_SAME_CPU_CRYPT|CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS)) &&
!dm_flags(cd, DM_CRYPT, &dmt_flags) && !(dmt_flags & (DM_SAME_CPU_CRYPT_SUPPORTED|DM_SUBMIT_FROM_CRYPT_CPUS_SUPPORTED)))
log_err(cd, _("Requested dmcrypt performance options are not supported."));
log_err(cd, _("Requested dm-crypt performance options are not supported."));
if ((dmd->flags & CRYPT_ACTIVATE_ALLOW_DISCARDS) &&
!dm_flags(cd, DM_CRYPT, &dmt_flags) && !(dmt_flags & DM_DISCARDS_SUPPORTED))
log_err(cd, _("Discard/TRIM is not supported."));
}
if (!r && resume)
r = _dm_resume_device(name, dmd->flags);
r = _dm_resume_device(name, dmflags | act2dmflags(dmd->flags));
dm_exit_context();
return r;
@@ -1585,7 +1715,9 @@ static int dm_status_dmi(const char *name, struct dm_info *dmi,
if (!target && (strcmp(target_type, DM_CRYPT_TARGET) &&
strcmp(target_type, DM_VERITY_TARGET) &&
strcmp(target_type, DM_INTEGRITY_TARGET) &&
strcmp(target_type, DM_LINEAR_TARGET)))
strcmp(target_type, DM_LINEAR_TARGET) &&
strcmp(target_type, DM_ZERO_TARGET) &&
strcmp(target_type, DM_ERROR_TARGET)))
goto out;
r = 0;
out:
@@ -1873,12 +2005,12 @@ static int _dm_target_query_verity(struct crypt_device *cd,
int r;
struct device *data_device = NULL, *hash_device = NULL, *fec_device = NULL;
char *hash_name = NULL, *root_hash = NULL, *salt = NULL, *fec_dev_str = NULL;
char *root_hash_sig_key_desc = NULL;
if (get_flags & DM_ACTIVE_VERITY_PARAMS) {
vp = malloc(sizeof(*vp));
vp = crypt_zalloc(sizeof(*vp));
if (!vp)
return -ENOMEM;
memset(vp, 0, sizeof(*vp));
}
tgt->type = DM_VERITY;
@@ -2057,6 +2189,15 @@ static int _dm_target_query_verity(struct crypt_device *cd,
if (vp)
vp->fec_roots = val32;
i++;
} else if (!strcasecmp(arg, "root_hash_sig_key_desc")) {
str = strsep(&params, " ");
if (!str)
goto err;
if (!root_hash_sig_key_desc)
root_hash_sig_key_desc = strdup(str);
i++;
if (vp)
vp->flags |= CRYPT_VERITY_ROOT_HASH_SIGNATURE;
} else /* unknown option */
goto err;
}
@@ -2082,11 +2223,15 @@ static int _dm_target_query_verity(struct crypt_device *cd,
vp->salt = salt;
if (vp && fec_dev_str)
vp->fec_device = fec_dev_str;
if (root_hash_sig_key_desc)
tgt->u.verity.root_hash_sig_key_desc = root_hash_sig_key_desc;
return 0;
err:
device_free(cd, data_device);
device_free(cd, hash_device);
device_free(cd, fec_device);
free(root_hash_sig_key_desc);
free(root_hash);
free(hash_name);
free(salt);
@@ -2142,12 +2287,16 @@ static int _dm_target_query_integrity(struct crypt_device *cd,
/* journal */
c = toupper(*(++params));
if (!*params || *(++params) != ' ' || (c != 'D' && c != 'J' && c != 'R'))
if (!*params || *(++params) != ' ' || (c != 'D' && c != 'J' && c != 'R' && c != 'B'))
goto err;
if (c == 'D')
*act_flags |= CRYPT_ACTIVATE_NO_JOURNAL;
if (c == 'R')
*act_flags |= CRYPT_ACTIVATE_RECOVERY;
if (c == 'B') {
*act_flags |= CRYPT_ACTIVATE_NO_JOURNAL;
*act_flags |= CRYPT_ACTIVATE_NO_JOURNAL_BITMAP;
}
tgt->u.integrity.sector_size = SECTOR_SIZE;
@@ -2169,7 +2318,15 @@ static int _dm_target_query_integrity(struct crypt_device *cd,
tgt->u.integrity.journal_size = val * SECTOR_SIZE;
else if (sscanf(arg, "journal_watermark:%u", &val) == 1)
tgt->u.integrity.journal_watermark = val;
else if (sscanf(arg, "commit_time:%u", &val) == 1)
else if (sscanf(arg, "sectors_per_bit:%" PRIu64, &val64) == 1) {
if (val64 > UINT_MAX)
goto err;
/* overloaded value for bitmap mode */
tgt->u.integrity.journal_watermark = (unsigned int)val64;
} else if (sscanf(arg, "commit_time:%u", &val) == 1)
tgt->u.integrity.journal_commit_time = val;
else if (sscanf(arg, "bitmap_flush_interval:%u", &val) == 1)
/* overloaded value for bitmap mode */
tgt->u.integrity.journal_commit_time = val;
else if (sscanf(arg, "interleave_sectors:%u", &val) == 1)
tgt->u.integrity.interleave_sectors = val;
@@ -2239,6 +2396,8 @@ static int _dm_target_query_integrity(struct crypt_device *cd,
}
} else if (!strcmp(arg, "recalculate")) {
*act_flags |= CRYPT_ACTIVATE_RECALCULATE;
} else if (!strcmp(arg, "fix_padding")) {
tgt->u.integrity.fix_padding = true;
} else /* unknown option */
goto err;
}
@@ -2313,6 +2472,22 @@ err:
return r;
}
static int _dm_target_query_error(struct crypt_device *cd, struct dm_target *tgt)
{
tgt->type = DM_ERROR;
tgt->direction = TARGET_QUERY;
return 0;
}
static int _dm_target_query_zero(struct crypt_device *cd, struct dm_target *tgt)
{
tgt->type = DM_ZERO;
tgt->direction = TARGET_QUERY;
return 0;
}
/*
* on error retval has to be negative
*
@@ -2322,7 +2497,7 @@ static int dm_target_query(struct crypt_device *cd, struct dm_target *tgt, const
const uint64_t *length, const char *target_type,
char *params, uint32_t get_flags, uint32_t *act_flags)
{
int r = -EINVAL;
int r = -ENOTSUP;
if (!strcmp(target_type, DM_CRYPT_TARGET))
r = _dm_target_query_crypt(cd, get_flags, params, tgt, act_flags);
@@ -2332,6 +2507,10 @@ static int dm_target_query(struct crypt_device *cd, struct dm_target *tgt, const
r = _dm_target_query_integrity(cd, get_flags, params, tgt, act_flags);
else if (!strcmp(target_type, DM_LINEAR_TARGET))
r = _dm_target_query_linear(cd, tgt, get_flags, params);
else if (!strcmp(target_type, DM_ERROR_TARGET))
r = _dm_target_query_error(cd, tgt);
else if (!strcmp(target_type, DM_ZERO_TARGET))
r = _dm_target_query_zero(cd, tgt);
if (!r) {
tgt->offset = *start;
@@ -2341,7 +2520,7 @@ static int dm_target_query(struct crypt_device *cd, struct dm_target *tgt, const
return r;
}
int dm_query_device(struct crypt_device *cd, const char *name,
static int _dm_query_device(struct crypt_device *cd, const char *name,
uint32_t get_flags, struct crypt_dm_active_device *dmd)
{
struct dm_target *t;
@@ -2353,17 +2532,10 @@ int dm_query_device(struct crypt_device *cd, const char *name,
void *next = NULL;
int r = -EINVAL;
if (dm_init_context(cd, DM_UNKNOWN))
return -ENOTSUP;
if (!dmd)
return -EINVAL;
t = &dmd->segment;
memset(dmd, 0, sizeof(*dmd));
if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
goto out;
return r;
if (!dm_task_secure_data(dmt))
goto out;
if (!dm_task_set_name(dmt, name))
@@ -2409,7 +2581,8 @@ int dm_query_device(struct crypt_device *cd, const char *name,
}
if (r < 0) {
log_err(cd, _("Failed to query dm-%s segment."), target_type);
if (r != -ENOTSUP)
log_err(cd, _("Failed to query dm-%s segment."), target_type);
goto out;
}
@@ -2420,6 +2593,9 @@ int dm_query_device(struct crypt_device *cd, const char *name,
if (dmi.read_only)
dmd->flags |= CRYPT_ACTIVATE_READONLY;
if (dmi.suspended)
dmd->flags |= CRYPT_ACTIVATE_SUSPENDED;
tmp_uuid = dm_task_get_uuid(dmt);
if (!tmp_uuid)
dmd->flags |= CRYPT_ACTIVATE_NO_UUID;
@@ -2443,6 +2619,126 @@ out:
if (r < 0)
dm_targets_free(cd, dmd);
return r;
}
int dm_query_device(struct crypt_device *cd, const char *name,
uint32_t get_flags, struct crypt_dm_active_device *dmd)
{
int r;
if (!dmd)
return -EINVAL;
memset(dmd, 0, sizeof(*dmd));
if (dm_init_context(cd, DM_UNKNOWN))
return -ENOTSUP;
r = _dm_query_device(cd, name, get_flags, dmd);
dm_exit_context();
return r;
}
static int _process_deps(struct crypt_device *cd, const char *prefix, struct dm_deps *deps, char **names, size_t names_offset, size_t names_length)
{
struct crypt_dm_active_device dmd;
char dmname[PATH_MAX];
unsigned i;
int r, major, minor, count = 0;
if (!prefix || !deps)
return -EINVAL;
for (i = 0; i < deps->count; i++) {
major = major(deps->device[i]);
if (!dm_is_dm_major(major))
continue;
minor = minor(deps->device[i]);
if (!dm_device_get_name(major, minor, 0, dmname, PATH_MAX))
return -EINVAL;
memset(&dmd, 0, sizeof(dmd));
r = _dm_query_device(cd, dmname, DM_ACTIVE_UUID, &dmd);
if (r < 0)
continue;
if (!dmd.uuid ||
strncmp(prefix, dmd.uuid, strlen(prefix)) ||
crypt_string_in(dmname, names, names_length))
*dmname = '\0';
dm_targets_free(cd, &dmd);
free(CONST_CAST(void*)dmd.uuid);
if ((size_t)count >= (names_length - names_offset))
return -ENOMEM;
if (*dmname && !(names[names_offset + count++] = strdup(dmname)))
return -ENOMEM;
}
return count;
}
int dm_device_deps(struct crypt_device *cd, const char *name, const char *prefix, char **names, size_t names_length)
{
struct dm_task *dmt;
struct dm_info dmi;
struct dm_deps *deps;
int r = -EINVAL;
size_t i, last = 0, offset = 0;
if (!name || !names_length || !names)
return -EINVAL;
if (dm_init_context(cd, DM_UNKNOWN))
return -ENOTSUP;
while (name) {
if (!(dmt = dm_task_create(DM_DEVICE_DEPS)))
goto out;
if (!dm_task_set_name(dmt, name))
goto out;
r = -ENODEV;
if (!dm_task_run(dmt))
goto out;
r = -EINVAL;
if (!dm_task_get_info(dmt, &dmi))
goto out;
if (!(deps = dm_task_get_deps(dmt)))
goto out;
r = -ENODEV;
if (!dmi.exists)
goto out;
r = _process_deps(cd, prefix, deps, names, offset, names_length - 1);
if (r < 0)
goto out;
dm_task_destroy(dmt);
dmt = NULL;
offset += r;
name = names[last++];
}
r = 0;
out:
if (r < 0) {
for (i = 0; i < names_length - 1; i++)
free(names[i]);
*names = NULL;
}
if (dmt)
dm_task_destroy(dmt);
dm_exit_context();
return r;
}
@@ -2473,61 +2769,48 @@ out:
return r;
}
int dm_suspend_device(struct crypt_device *cd, const char *name)
{
int r;
if (dm_init_context(cd, DM_UNKNOWN))
return -ENOTSUP;
if (!_dm_simple(DM_DEVICE_SUSPEND, name))
r = -EINVAL;
else
r = 0;
dm_exit_context();
return r;
}
int dm_suspend_and_wipe_key(struct crypt_device *cd, const char *name)
int dm_suspend_device(struct crypt_device *cd, const char *name, uint32_t dmflags)
{
uint32_t dmt_flags;
int r = -ENOTSUP;
if (dm_init_context(cd, DM_CRYPT))
return -ENOTSUP;
if (dm_init_context(cd, DM_UNKNOWN))
return r;
if (dm_flags(cd, DM_CRYPT, &dmt_flags))
goto out;
if (dmflags & DM_SUSPEND_WIPE_KEY) {
if (dm_flags(cd, DM_CRYPT, &dmt_flags))
goto out;
if (!(dmt_flags & DM_KEY_WIPE_SUPPORTED))
goto out;
if (!_dm_simple(DM_DEVICE_SUSPEND, name)) {
r = -EINVAL;
goto out;
if (!(dmt_flags & DM_KEY_WIPE_SUPPORTED))
goto out;
}
if (!_dm_message(name, "key wipe")) {
_dm_resume_device(name, 0);
r = -EINVAL;
r = -EINVAL;
if (!_dm_simple(DM_DEVICE_SUSPEND, name, dmflags))
goto out;
if (dmflags & DM_SUSPEND_WIPE_KEY) {
if (!_dm_message(name, "key wipe")) {
_dm_resume_device(name, 0);
goto out;
}
}
r = 0;
out:
dm_exit_context();
return r;
}
int dm_resume_device(struct crypt_device *cd, const char *name, uint32_t flags)
int dm_resume_device(struct crypt_device *cd, const char *name, uint32_t dmflags)
{
int r;
if (dm_init_context(cd, DM_UNKNOWN))
return -ENOTSUP;
r = _dm_resume_device(name, flags);
r = _dm_resume_device(name, dmflags);
dm_exit_context();
@@ -2582,7 +2865,7 @@ const char *dm_get_dir(void)
return dm_dir();
}
int dm_is_dm_device(int major, int minor)
int dm_is_dm_device(int major)
{
return dm_is_dm_major((uint32_t)major);
}
@@ -2592,9 +2875,9 @@ int dm_is_dm_kernel_name(const char *name)
return strncmp(name, "dm-", 3) ? 0 : 1;
}
int dm_crypt_target_set(struct dm_target *tgt, size_t seg_offset, size_t seg_size,
int dm_crypt_target_set(struct dm_target *tgt, uint64_t seg_offset, uint64_t seg_size,
struct device *data_device, struct volume_key *vk, const char *cipher,
size_t iv_offset, size_t data_offset, const char *integrity, uint32_t tag_size,
uint64_t iv_offset, uint64_t data_offset, const char *integrity, uint32_t tag_size,
uint32_t sector_size)
{
int r = -EINVAL;
@@ -2614,6 +2897,7 @@ int dm_crypt_target_set(struct dm_target *tgt, size_t seg_offset, size_t seg_siz
tgt->data_device = data_device;
tgt->type = DM_CRYPT;
tgt->direction = TARGET_SET;
tgt->u.crypt.vk = vk;
tgt->offset = seg_offset;
tgt->size = seg_size;
@@ -2632,10 +2916,10 @@ err:
return r;
}
int dm_verity_target_set(struct dm_target *tgt, size_t seg_offset, size_t seg_size,
int dm_verity_target_set(struct dm_target *tgt, uint64_t seg_offset, uint64_t seg_size,
struct device *data_device, struct device *hash_device, struct device *fec_device,
const char *root_hash, uint32_t root_hash_size, uint64_t hash_offset_block,
uint64_t hash_blocks, struct crypt_params_verity *vp)
const char *root_hash, uint32_t root_hash_size, const char *root_hash_sig_key_desc,
uint64_t hash_offset_block, uint64_t hash_blocks, struct crypt_params_verity *vp)
{
if (!data_device || !hash_device || !vp)
return -EINVAL;
@@ -2650,6 +2934,7 @@ int dm_verity_target_set(struct dm_target *tgt, size_t seg_offset, size_t seg_si
tgt->u.verity.fec_device = fec_device;
tgt->u.verity.root_hash = root_hash;
tgt->u.verity.root_hash_size = root_hash_size;
tgt->u.verity.root_hash_sig_key_desc = root_hash_sig_key_desc;
tgt->u.verity.hash_offset = hash_offset_block;
tgt->u.verity.fec_offset = vp->fec_area_offset / vp->hash_block_size;
tgt->u.verity.hash_blocks = hash_blocks;
@@ -2658,16 +2943,21 @@ int dm_verity_target_set(struct dm_target *tgt, size_t seg_offset, size_t seg_si
return 0;
}
int dm_integrity_target_set(struct dm_target *tgt, size_t seg_offset, size_t seg_size,
int dm_integrity_target_set(struct crypt_device *cd,
struct dm_target *tgt, uint64_t seg_offset, uint64_t seg_size,
struct device *meta_device,
struct device *data_device, uint64_t tag_size, uint64_t offset,
uint32_t sector_size, struct volume_key *vk,
struct volume_key *journal_crypt_key, struct volume_key *journal_mac_key,
const struct crypt_params_integrity *ip)
{
uint32_t dmi_flags;
if (!data_device)
return -EINVAL;
_dm_check_versions(cd, DM_INTEGRITY);
tgt->type = DM_INTEGRITY;
tgt->direction = TARGET_SET;
tgt->offset = seg_offset;
@@ -2683,6 +2973,11 @@ int dm_integrity_target_set(struct dm_target *tgt, size_t seg_offset, size_t seg
tgt->u.integrity.journal_crypt_key = journal_crypt_key;
tgt->u.integrity.journal_integrity_key = journal_mac_key;
if (!dm_flags(cd, DM_INTEGRITY, &dmi_flags) &&
(dmi_flags & DM_INTEGRITY_FIX_PADDING_SUPPORTED) &&
!(crypt_get_compatibility(cd) & CRYPT_COMPAT_LEGACY_INTEGRITY_PADDING))
tgt->u.integrity.fix_padding = true;
if (ip) {
tgt->u.integrity.journal_size = ip->journal_size;
tgt->u.integrity.journal_watermark = ip->journal_watermark;
@@ -2697,8 +2992,8 @@ int dm_integrity_target_set(struct dm_target *tgt, size_t seg_offset, size_t seg
return 0;
}
int dm_linear_target_set(struct dm_target *tgt, size_t seg_offset, size_t seg_size,
struct device *data_device, size_t data_offset)
int dm_linear_target_set(struct dm_target *tgt, uint64_t seg_offset, uint64_t seg_size,
struct device *data_device, uint64_t data_offset)
{
if (!data_device)
return -EINVAL;
@@ -2713,3 +3008,13 @@ int dm_linear_target_set(struct dm_target *tgt, size_t seg_offset, size_t seg_si
return 0;
}
int dm_zero_target_set(struct dm_target *tgt, uint64_t seg_offset, uint64_t seg_size)
{
tgt->type = DM_ZERO;
tgt->direction = TARGET_SET;
tgt->offset = seg_offset;
tgt->size = seg_size;
return 0;
}

View File

@@ -1,8 +1,8 @@
/*
* loop-AES compatible volume handling
*
* Copyright (C) 2011-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2019 Milan Broz
* Copyright (C) 2011-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2020 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -242,7 +242,7 @@ int LOOPAES_activate(struct crypt_device *cd,
if (r < 0 && !dm_flags(cd, DM_CRYPT, &dmc_flags) &&
(dmc_flags & req_flags) != req_flags) {
log_err(cd, _("Kernel doesn't support loop-AES compatible mapping."));
log_err(cd, _("Kernel does not support loop-AES compatible mapping."));
r = -ENOTSUP;
}

View File

@@ -1,8 +1,8 @@
/*
* loop-AES compatible volume handling
*
* Copyright (C) 2011-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2019 Milan Broz
* Copyright (C) 2011-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2020 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

View File

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

View File

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

View File

@@ -2,8 +2,8 @@
* LUKS - Linux Unified Key Setup
*
* Copyright (C) 2004-2006 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2019 Milan Broz
* Copyright (C) 2009-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2020 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -60,7 +60,7 @@ static int LUKS_endec_template(char *src, size_t srcLength,
struct crypt_dm_active_device dmd = {
.flags = CRYPT_ACTIVATE_PRIVATE,
};
int r, devfd = -1;
int r, devfd = -1, remove_dev = 0;
size_t bsize, keyslot_alignment, alignment;
log_dbg(ctx, "Using dmcrypt to access keyslot area.");
@@ -89,7 +89,7 @@ static int LUKS_endec_template(char *src, size_t srcLength,
r = device_block_adjust(ctx, crypt_metadata_device(ctx), DEV_OK,
sector, &dmd.size, &dmd.flags);
if (r < 0) {
log_err(ctx, _("Device %s doesn't exist or access denied."),
log_err(ctx, _("Device %s does not exist or access denied."),
device_path(crypt_metadata_device(ctx)));
return -EIO;
}
@@ -114,6 +114,7 @@ static int LUKS_endec_template(char *src, size_t srcLength,
r = -EIO;
goto out;
}
remove_dev = 1;
devfd = open(path, mode | O_DIRECT | O_SYNC);
if (devfd == -1) {
@@ -132,7 +133,8 @@ static int LUKS_endec_template(char *src, size_t srcLength,
dm_targets_free(ctx, &dmd);
if (devfd != -1)
close(devfd);
dm_remove_device(ctx, name, CRYPT_DEACTIVATE_FORCE);
if (remove_dev)
dm_remove_device(ctx, name, CRYPT_DEACTIVATE_FORCE);
return r;
}
@@ -143,17 +145,16 @@ int LUKS_encrypt_to_storage(char *src, size_t srcLength,
unsigned int sector,
struct crypt_device *ctx)
{
struct device *device = crypt_metadata_device(ctx);
struct crypt_storage *s;
int devfd = -1, r = 0;
int devfd, r = 0;
/* Only whole sector writes supported */
if (MISALIGNED_512(srcLength))
return -EINVAL;
/* Encrypt buffer */
r = crypt_storage_init(&s, 0, cipher, cipher_mode, vk->key, vk->keylength);
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode, vk->key, vk->keylength);
if (r)
log_dbg(ctx, "Userspace crypto wrapper cannot use %s-%s (%d).",
@@ -172,7 +173,7 @@ int LUKS_encrypt_to_storage(char *src, size_t srcLength,
log_dbg(ctx, "Using userspace crypto wrapper to access keyslot area.");
r = crypt_storage_encrypt(s, 0, srcLength / SECTOR_SIZE, src);
r = crypt_storage_encrypt(s, 0, srcLength, src);
crypt_storage_destroy(s);
if (r)
@@ -181,7 +182,10 @@ int LUKS_encrypt_to_storage(char *src, size_t srcLength,
r = -EIO;
/* Write buffer to device */
devfd = device_open(ctx, device, O_RDWR);
if (device_is_locked(device))
devfd = device_open_locked(ctx, device, O_RDWR);
else
devfd = device_open(ctx, device, O_RDWR);
if (devfd < 0)
goto out;
@@ -192,10 +196,7 @@ int LUKS_encrypt_to_storage(char *src, size_t srcLength,
r = 0;
out:
if (devfd >= 0) {
device_sync(ctx, device, devfd);
close(devfd);
}
device_sync(ctx, device);
if (r)
log_err(ctx, _("IO error while encrypting keyslot."));
@@ -212,13 +213,13 @@ int LUKS_decrypt_from_storage(char *dst, size_t dstLength,
struct device *device = crypt_metadata_device(ctx);
struct crypt_storage *s;
struct stat st;
int devfd = -1, r = 0;
int devfd, r = 0;
/* Only whole sector reads supported */
if (MISALIGNED_512(dstLength))
return -EINVAL;
r = crypt_storage_init(&s, 0, cipher, cipher_mode, vk->key, vk->keylength);
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode, vk->key, vk->keylength);
if (r)
log_dbg(ctx, "Userspace crypto wrapper cannot use %s-%s (%d).",
@@ -238,7 +239,10 @@ int LUKS_decrypt_from_storage(char *dst, size_t dstLength,
log_dbg(ctx, "Using userspace crypto wrapper to access keyslot area.");
/* Read buffer from device */
devfd = device_open(ctx, device, O_RDONLY);
if (device_is_locked(device))
devfd = device_open_locked(ctx, device, O_RDONLY);
else
devfd = device_open(ctx, device, O_RDONLY);
if (devfd < 0) {
log_err(ctx, _("Cannot open device %s."), device_path(device));
crypt_storage_destroy(s);
@@ -253,15 +257,12 @@ int LUKS_decrypt_from_storage(char *dst, size_t dstLength,
else
log_err(ctx, _("IO error while decrypting keyslot."));
close(devfd);
crypt_storage_destroy(s);
return -EIO;
}
close(devfd);
/* Decrypt buffer */
r = crypt_storage_decrypt(s, 0, dstLength / SECTOR_SIZE, dst);
r = crypt_storage_decrypt(s, 0, dstLength, dst);
crypt_storage_destroy(s);
return r;

View File

@@ -2,8 +2,8 @@
* LUKS - Linux Unified Key Setup
*
* Copyright (C) 2004-2006 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2013-2019 Milan Broz
* Copyright (C) 2009-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2013-2020 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -200,9 +200,10 @@ int LUKS_hdr_backup(const char *backup_file, struct crypt_device *ctx)
{
struct device *device = crypt_metadata_device(ctx);
struct luks_phdr hdr;
int r = 0, devfd = -1;
int fd, devfd, r = 0;
size_t hdr_size;
size_t buffer_size;
ssize_t ret;
char *buffer = NULL;
r = LUKS_read_phdr(&hdr, 1, 0, ctx);
@@ -230,19 +231,18 @@ int LUKS_hdr_backup(const char *backup_file, struct crypt_device *ctx)
goto out;
}
if (read_blockwise(devfd, device_block_size(ctx, device), device_alignment(device),
buffer, hdr_size) < (ssize_t)hdr_size) {
if (read_lseek_blockwise(devfd, device_block_size(ctx, device), device_alignment(device),
buffer, hdr_size, 0) < (ssize_t)hdr_size) {
r = -EIO;
goto out;
}
close(devfd);
/* Wipe unused area, so backup cannot contain old signatures */
if (hdr.keyblock[0].keyMaterialOffset * SECTOR_SIZE == LUKS_ALIGN_KEYSLOTS)
memset(buffer + sizeof(hdr), 0, LUKS_ALIGN_KEYSLOTS - sizeof(hdr));
devfd = open(backup_file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR);
if (devfd == -1) {
fd = open(backup_file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR);
if (fd == -1) {
if (errno == EEXIST)
log_err(ctx, _("Requested header backup file %s already exists."), backup_file);
else
@@ -250,7 +250,9 @@ int LUKS_hdr_backup(const char *backup_file, struct crypt_device *ctx)
r = -EINVAL;
goto out;
}
if (write_buffer(devfd, buffer, buffer_size) < (ssize_t)buffer_size) {
ret = write_buffer(fd, buffer, buffer_size);
close(fd);
if (ret < (ssize_t)buffer_size) {
log_err(ctx, _("Cannot write header backup file %s."), backup_file);
r = -EIO;
goto out;
@@ -258,9 +260,7 @@ int LUKS_hdr_backup(const char *backup_file, struct crypt_device *ctx)
r = 0;
out:
if (devfd >= 0)
close(devfd);
crypt_memzero(&hdr, sizeof(hdr));
crypt_safe_memzero(&hdr, sizeof(hdr));
crypt_safe_free(buffer);
return r;
}
@@ -271,8 +271,8 @@ int LUKS_hdr_restore(
struct crypt_device *ctx)
{
struct device *device = crypt_metadata_device(ctx);
int r = 0, devfd = -1, diff_uuid = 0;
ssize_t buffer_size = 0;
int fd, r = 0, devfd = -1, diff_uuid = 0;
ssize_t ret, buffer_size = 0;
char *buffer = NULL, msg[200];
struct luks_phdr hdr_file;
@@ -284,7 +284,7 @@ int LUKS_hdr_restore(
buffer_size = LUKS_device_sectors(&hdr_file) << SECTOR_SHIFT;
if (r || buffer_size < LUKS_ALIGN_KEYSLOTS) {
log_err(ctx, _("Backup file doesn't contain valid LUKS header."));
log_err(ctx, _("Backup file does not contain valid LUKS header."));
r = -EINVAL;
goto out;
}
@@ -295,20 +295,20 @@ int LUKS_hdr_restore(
goto out;
}
devfd = open(backup_file, O_RDONLY);
if (devfd == -1) {
fd = open(backup_file, O_RDONLY);
if (fd == -1) {
log_err(ctx, _("Cannot open header backup file %s."), backup_file);
r = -EINVAL;
goto out;
}
if (read_buffer(devfd, buffer, buffer_size) < buffer_size) {
ret = read_buffer(fd, buffer, buffer_size);
close(fd);
if (ret < buffer_size) {
log_err(ctx, _("Cannot read header backup file %s."), backup_file);
r = -EIO;
goto out;
}
close(devfd);
devfd = -1;
r = LUKS_read_phdr(hdr, 0, 0, ctx);
if (r == 0) {
@@ -350,21 +350,16 @@ int LUKS_hdr_restore(
goto out;
}
if (write_blockwise(devfd, device_block_size(ctx, device), device_alignment(device),
buffer, buffer_size) < buffer_size) {
if (write_lseek_blockwise(devfd, device_block_size(ctx, device), device_alignment(device),
buffer, buffer_size, 0) < buffer_size) {
r = -EIO;
goto out;
}
close(devfd);
devfd = -1;
/* Be sure to reload new data */
r = LUKS_read_phdr(hdr, 1, 0, ctx);
out:
if (devfd >= 0) {
device_sync(ctx, device, devfd);
close(devfd);
}
device_sync(ctx, device);
crypt_safe_free(buffer);
return r;
}
@@ -458,7 +453,7 @@ out:
if (r)
log_err(ctx, _("Repair failed."));
crypt_free_volume_key(vk);
crypt_memzero(&temp_phdr, sizeof(temp_phdr));
crypt_safe_memzero(&temp_phdr, sizeof(temp_phdr));
return r;
}
@@ -573,9 +568,9 @@ int LUKS_read_phdr(struct luks_phdr *hdr,
int repair,
struct crypt_device *ctx)
{
int devfd, r = 0;
struct device *device = crypt_metadata_device(ctx);
ssize_t hdr_size = sizeof(struct luks_phdr);
int devfd = 0, r = 0;
/* LUKS header starts at offset 0, first keyslot on LUKS_ALIGN_KEYSLOTS */
assert(sizeof(struct luks_phdr) <= LUKS_ALIGN_KEYSLOTS);
@@ -595,8 +590,8 @@ int LUKS_read_phdr(struct luks_phdr *hdr,
return -EINVAL;
}
if (read_blockwise(devfd, device_block_size(ctx, device), device_alignment(device),
hdr, hdr_size) < hdr_size)
if (read_lseek_blockwise(devfd, device_block_size(ctx, device), device_alignment(device),
hdr, hdr_size, 0) < hdr_size)
r = -EIO;
else
r = _check_and_convert_hdr(device_path(device), hdr, require_luks_device,
@@ -615,7 +610,6 @@ int LUKS_read_phdr(struct luks_phdr *hdr,
device_disable_direct_io(device);
}
close(devfd);
return r;
}
@@ -661,13 +655,12 @@ int LUKS_write_phdr(struct luks_phdr *hdr,
convHdr.keyblock[i].stripes = htonl(hdr->keyblock[i].stripes);
}
r = write_blockwise(devfd, device_block_size(ctx, device), device_alignment(device),
&convHdr, hdr_size) < hdr_size ? -EIO : 0;
r = write_lseek_blockwise(devfd, device_block_size(ctx, device), device_alignment(device),
&convHdr, hdr_size, 0) < hdr_size ? -EIO : 0;
if (r)
log_err(ctx, _("Error during update of LUKS header on device %s."), device_path(device));
device_sync(ctx, device, devfd);
close(devfd);
device_sync(ctx, device);
/* Re-read header from disk to be sure that in-memory and on-disk data are the same. */
if (!r) {
@@ -699,7 +692,7 @@ int LUKS_check_cipher(struct crypt_device *ctx, size_t keylength, const char *ci
r = LUKS_decrypt_from_storage(buf, sizeof(buf), cipher, cipher_mode, empty_key, 0, ctx);
crypt_free_volume_key(empty_key);
crypt_memzero(buf, sizeof(buf));
crypt_safe_memzero(buf, sizeof(buf));
return r;
}
@@ -794,10 +787,15 @@ int LUKS_generate_phdr(struct luks_phdr *header,
return r;
assert(pbkdf->iterations);
PBKDF2_temp = (double)pbkdf->iterations * LUKS_MKD_ITERATIONS_MS / pbkdf->time_ms;
if (pbkdf->flags & CRYPT_PBKDF_NO_BENCHMARK && pbkdf->time_ms == 0)
PBKDF2_temp = LUKS_MKD_ITERATIONS_MIN;
else /* iterations per ms * LUKS_MKD_ITERATIONS_MS */
PBKDF2_temp = (double)pbkdf->iterations * LUKS_MKD_ITERATIONS_MS / pbkdf->time_ms;
if (PBKDF2_temp > (double)UINT32_MAX)
return -EINVAL;
header->mkDigestIterations = at_least((uint32_t)PBKDF2_temp, LUKS_MKD_ITERATIONS_MIN);
assert(header->mkDigestIterations);
r = crypt_pbkdf(CRYPT_KDF_PBKDF2, header->hashSpec, vk->key,vk->keylength,
header->mkDigestSalt, LUKS_SALTSIZE,
@@ -1024,7 +1022,7 @@ int LUKS_open_key_with_hdr(int keyIndex,
struct volume_key **vk,
struct crypt_device *ctx)
{
unsigned int i;
unsigned int i, tried = 0;
int r;
*vk = crypt_alloc_volume_key(hdr->keyBytes, NULL);
@@ -1034,7 +1032,7 @@ int LUKS_open_key_with_hdr(int keyIndex,
return (r < 0) ? r : keyIndex;
}
for(i = 0; i < LUKS_NUMKEYS; i++) {
for (i = 0; i < LUKS_NUMKEYS; i++) {
r = LUKS_open_key(i, password, passwordLen, hdr, *vk, ctx);
if(r == 0)
return i;
@@ -1043,9 +1041,11 @@ int LUKS_open_key_with_hdr(int keyIndex,
former meaning password wrong, latter key slot inactive */
if ((r != -EPERM) && (r != -ENOENT))
return r;
if (r == -EPERM)
tried++;
}
/* Warning, early returns above */
return -EPERM;
return tried ? -EPERM : -ENOENT;
}
int LUKS_del_key(unsigned int keyIndex,
@@ -1229,7 +1229,7 @@ int LUKS_wipe_header_areas(struct luks_phdr *hdr,
int LUKS_keyslot_pbkdf(struct luks_phdr *hdr, int keyslot, struct crypt_pbkdf_type *pbkdf)
{
if (keyslot >= LUKS_NUMKEYS || keyslot < 0)
if (LUKS_keyslot_info(hdr, keyslot) < CRYPT_SLOT_ACTIVE)
return -EINVAL;
pbkdf->type = CRYPT_KDF_PBKDF2;

View File

@@ -2,7 +2,7 @@
* LUKS - Linux Unified Key Setup
*
* Copyright (C) 2004-2006 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2020 Red Hat, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2
*
* Copyright (C) 2015-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2019 Milan Broz
* Copyright (C) 2015-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2020 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -22,6 +22,8 @@
#ifndef _CRYPTSETUP_LUKS2_ONDISK_H
#define _CRYPTSETUP_LUKS2_ONDISK_H
#include <stdbool.h>
#include "libcryptsetup.h"
#define LUKS2_MAGIC_1ST "LUKS\xba\xbe"
@@ -45,11 +47,19 @@
#define LUKS2_DIGEST_MAX 8
#define CRYPT_ANY_SEGMENT -1
#define CRYPT_DEFAULT_SEGMENT 0
#define CRYPT_DEFAULT_SEGMENT_STR "0"
#define CRYPT_DEFAULT_SEGMENT -2
#define CRYPT_ONE_SEGMENT -3
#define CRYPT_ANY_DIGEST -1
/* 20 MiBs */
#define LUKS2_DEFAULT_NONE_REENCRYPTION_LENGTH 0x1400000
/* 1 GiB */
#define LUKS2_REENCRYPT_MAX_HOTZONE_LENGTH 0x40000000
struct device;
/*
* LUKS2 header on-disk.
*
@@ -117,6 +127,77 @@ struct luks2_keyslot_params {
} area;
};
struct reenc_protection {
enum { REENC_PROTECTION_NONE = 0, /* none should be 0 always */
REENC_PROTECTION_CHECKSUM,
REENC_PROTECTION_JOURNAL,
REENC_PROTECTION_DATASHIFT } type;
union {
struct {
} none;
struct {
char hash[LUKS2_CHECKSUM_ALG_L]; // or include luks.h
struct crypt_hash *ch;
size_t hash_size;
/* buffer for checksums */
void *checksums;
size_t checksums_len;
} csum;
struct {
} ds;
} p;
};
struct luks2_reenc_context {
/* reencryption window attributes */
uint64_t offset;
uint64_t progress;
uint64_t length;
uint64_t data_shift;
size_t alignment;
uint64_t device_size;
bool online;
bool fixed_length;
crypt_reencrypt_direction_info direction;
crypt_reencrypt_mode_info mode;
char *device_name;
char *hotzone_name;
char *overlay_name;
uint32_t flags;
/* reencryption window persistence attributes */
struct reenc_protection rp;
int reenc_keyslot;
/* already running reencryption */
json_object *jobj_segs_hot;
json_object *jobj_segs_post;
/* backup segments */
json_object *jobj_segment_new;
int digest_new;
json_object *jobj_segment_old;
int digest_old;
json_object *jobj_segment_moved;
struct volume_key *vks;
void *reenc_buffer;
ssize_t read;
struct crypt_storage_wrapper *cw1;
struct crypt_storage_wrapper *cw2;
uint32_t wflags1;
uint32_t wflags2;
struct crypt_lock_handle *reenc_lock;
};
crypt_reencrypt_info LUKS2_reenc_status(struct luks2_hdr *hdr);
/*
* Supportable header sizes (hdr_disk + JSON area)
* Also used as offset for the 2nd header.
@@ -139,8 +220,12 @@ struct luks2_keyslot_params {
int LUKS2_hdr_version_unlocked(struct crypt_device *cd,
const char *backup_file);
int LUKS2_device_write_lock(struct crypt_device *cd,
struct luks2_hdr *hdr, struct device *device);
int LUKS2_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr, int repair);
int LUKS2_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr);
int LUKS2_hdr_write_force(struct crypt_device *cd, struct luks2_hdr *hdr);
int LUKS2_hdr_dump(struct crypt_device *cd, struct luks2_hdr *hdr);
int LUKS2_hdr_uuid(struct crypt_device *cd,
@@ -178,6 +263,13 @@ int LUKS2_keyslot_open(struct crypt_device *cd,
size_t password_len,
struct volume_key **vk);
int LUKS2_keyslot_open_all_segments(struct crypt_device *cd,
int keyslot_old,
int keyslot_new,
const char *password,
size_t password_len,
struct volume_key **vks);
int LUKS2_keyslot_store(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
@@ -186,6 +278,20 @@ int LUKS2_keyslot_store(struct crypt_device *cd,
const struct volume_key *vk,
const struct luks2_keyslot_params *params);
int LUKS2_keyslot_reencrypt_store(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const void *buffer,
size_t buffer_length);
int LUKS2_keyslot_reencrypt_create(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const struct crypt_params_reencrypt *params);
int reenc_keyslot_update(struct crypt_device *cd,
const struct luks2_reenc_context *rh);
int LUKS2_keyslot_wipe(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
@@ -262,11 +368,77 @@ int LUKS2_token_open_and_activate_any(struct crypt_device *cd,
int LUKS2_tokens_count(struct luks2_hdr *hdr);
/*
* Generic LUKS2 segment
*/
uint64_t json_segment_get_offset(json_object *jobj_segment, unsigned blockwise);
const char *json_segment_type(json_object *jobj_segment);
uint64_t json_segment_get_iv_offset(json_object *jobj_segment);
uint64_t json_segment_get_size(json_object *jobj_segment, unsigned blockwise);
const char *json_segment_get_cipher(json_object *jobj_segment);
int json_segment_get_sector_size(json_object *jobj_segment);
bool json_segment_is_backup(json_object *jobj_segment);
json_object *json_segments_get_segment(json_object *jobj_segments, int segment);
unsigned json_segments_count(json_object *jobj_segments);
void json_segment_remove_flag(json_object *jobj_segment, const char *flag);
uint64_t json_segments_get_minimal_offset(json_object *jobj_segments, unsigned blockwise);
json_object *json_segment_create_linear(uint64_t offset, const uint64_t *length, unsigned reencryption);
json_object *json_segment_create_crypt(uint64_t offset, uint64_t iv_offset, const uint64_t *length, const char *cipher, uint32_t sector_size, unsigned reencryption);
int json_segments_segment_in_reencrypt(json_object *jobj_segments);
int LUKS2_segments_count(struct luks2_hdr *hdr);
int LUKS2_segment_first_unused_id(struct luks2_hdr *hdr);
int LUKS2_segment_set_flag(json_object *jobj_segment, const char *flag);
json_object *LUKS2_get_segment_by_flag(struct luks2_hdr *hdr, const char *flag);
int LUKS2_get_segment_id_by_flag(struct luks2_hdr *hdr, const char *flag);
int LUKS2_segments_set(struct crypt_device *cd,
struct luks2_hdr *hdr,
json_object *jobj_segments,
int commit);
uint64_t LUKS2_segment_offset(struct luks2_hdr *hdr,
int segment,
unsigned blockwise);
uint64_t LUKS2_segment_size(struct luks2_hdr *hdr,
int segment,
unsigned blockwise);
int LUKS2_segment_is_type(struct luks2_hdr *hdr,
int segment,
const char *type);
int LUKS2_segment_by_type(struct luks2_hdr *hdr,
const char *type);
int LUKS2_last_segment_by_type(struct luks2_hdr *hdr,
const char *type);
int LUKS2_get_default_segment(struct luks2_hdr *hdr);
int LUKS2_reencrypt_digest_new(struct luks2_hdr *hdr);
int LUKS2_reencrypt_digest_old(struct luks2_hdr *hdr);
int LUKS2_reencrypt_data_offset(struct luks2_hdr *hdr, bool blockwise);
/*
* Generic LUKS2 digest
*/
int LUKS2_digest_any_matching(struct crypt_device *cd,
struct luks2_hdr *hdr,
const struct volume_key *vk);
int LUKS2_digest_by_segment(struct luks2_hdr *hdr, int segment);
int LUKS2_digest_verify_by_digest(struct crypt_device *cd,
struct luks2_hdr *hdr,
int digest,
const struct volume_key *vk);
int LUKS2_digest_verify_by_segment(struct crypt_device *cd,
struct luks2_hdr *hdr,
int segment,
@@ -277,7 +449,7 @@ void LUKS2_digests_erase_unused(struct crypt_device *cd,
int LUKS2_digest_verify(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct volume_key *vk,
const struct volume_key *vk,
int keyslot);
int LUKS2_digest_dump(struct crypt_device *cd,
@@ -312,11 +484,25 @@ int LUKS2_activate(struct crypt_device *cd,
struct volume_key *vk,
uint32_t flags);
int LUKS2_keyslot_luks2_format(struct crypt_device *cd,
int LUKS2_activate_multi(struct crypt_device *cd,
const char *name,
struct volume_key *vks,
uint64_t device_size,
uint32_t flags);
struct crypt_dm_active_device;
int LUKS2_deactivate(struct crypt_device *cd,
const char *name,
struct luks2_hdr *hdr,
int keyslot,
const char *cipher,
size_t keylength);
struct crypt_dm_active_device *dmd,
uint32_t flags);
int LUKS2_reload(struct crypt_device *cd,
const char *name,
struct volume_key *vks,
uint64_t device_size,
uint32_t flags);
int LUKS2_generate_hdr(
struct crypt_device *cd,
@@ -340,6 +526,7 @@ int LUKS2_wipe_header_areas(struct crypt_device *cd,
struct luks2_hdr *hdr);
uint64_t LUKS2_get_data_offset(struct luks2_hdr *hdr);
int LUKS2_get_data_size(struct luks2_hdr *hdr, uint64_t *size, bool *dynamic);
int LUKS2_get_sector_size(struct luks2_hdr *hdr);
const char *LUKS2_get_cipher(struct luks2_hdr *hdr, int segment);
const char *LUKS2_get_integrity(struct luks2_hdr *hdr, int segment);
@@ -348,15 +535,19 @@ int LUKS2_keyslot_params_default(struct crypt_device *cd, struct luks2_hdr *hdr,
int LUKS2_get_volume_key_size(struct luks2_hdr *hdr, int segment);
int LUKS2_get_keyslot_stored_key_size(struct luks2_hdr *hdr, int keyslot);
const char *LUKS2_get_keyslot_cipher(struct luks2_hdr *hdr, int keyslot, size_t *key_size);
int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr, const char *type);
int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr);
int LUKS2_keyslot_active_count(struct luks2_hdr *hdr, int segment);
int LUKS2_keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment);
int LUKS2_find_keyslot(struct luks2_hdr *hdr, const char *type);
crypt_keyslot_info LUKS2_keyslot_info(struct luks2_hdr *hdr, int keyslot);
int LUKS2_keyslot_area(struct luks2_hdr *hdr,
int keyslot,
uint64_t *offset,
uint64_t *length);
int LUKS2_keyslot_pbkdf(struct luks2_hdr *hdr, int keyslot, struct crypt_pbkdf_type *pbkdf);
int LUKS2_set_keyslots_size(struct crypt_device *cd,
struct luks2_hdr *hdr,
uint64_t data_offset);
/*
* Permanent activation flags stored in header
@@ -368,7 +559,7 @@ int LUKS2_config_set_flags(struct crypt_device *cd, struct luks2_hdr *hdr, uint3
* Requirements for device activation or header modification
*/
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);
int LUKS2_config_set_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs, bool commit);
int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs_mask, int quiet);
@@ -376,6 +567,8 @@ int LUKS2_key_description_by_segment(struct crypt_device *cd,
struct luks2_hdr *hdr, struct volume_key *vk, int segment);
int LUKS2_volume_key_load_in_keyring_by_keyslot(struct crypt_device *cd,
struct luks2_hdr *hdr, struct volume_key *vk, int keyslot);
int LUKS2_volume_key_load_in_keyring_by_digest(struct crypt_device *cd,
struct luks2_hdr *hdr, struct volume_key *vk, int digest);
struct luks_phdr;
int LUKS2_luks1_to_luks2(struct crypt_device *cd,
@@ -385,4 +578,32 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd,
struct luks2_hdr *hdr2,
struct luks_phdr *hdr1);
/*
* LUKS2 reencryption
*/
int LUKS2_reencrypt_locked_recovery_by_passphrase(struct crypt_device *cd,
int keyslot_old,
int keyslot_new,
const char *passphrase,
size_t passphrase_size,
uint32_t flags,
struct volume_key **vks);
void LUKS2_reenc_context_free(struct crypt_device *cd, struct luks2_reenc_context *rh);
int LUKS2_assembly_multisegment_dmd(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct volume_key *vks,
json_object *jobj_segments,
struct crypt_dm_active_device *dmd);
crypt_reencrypt_info LUKS2_reencrypt_status(struct crypt_device *cd,
struct crypt_params_reencrypt *params);
int crypt_reencrypt_lock(struct crypt_device *cd, struct crypt_lock_handle **reencrypt_lock);
int crypt_reencrypt_lock_by_dm_uuid(struct crypt_device *cd, const char *dm_uuid, struct crypt_lock_handle **reencrypt_lock);
void crypt_reencrypt_unlock(struct crypt_device *cd, struct crypt_lock_handle *reencrypt_lock);
int luks2_check_device_size(struct crypt_device *cd, struct luks2_hdr *hdr, uint64_t check_size, uint64_t *dev_size, bool activation, bool dynamic);
#endif

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, digest handling
*
* Copyright (C) 2015-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2019 Milan Broz
* Copyright (C) 2015-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2020 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -28,7 +28,7 @@ static const digest_handler *digest_handlers[LUKS2_DIGEST_MAX] = {
NULL
};
const digest_handler *LUKS2_digest_handler_type(struct crypt_device *cd, const char *type)
static const digest_handler *LUKS2_digest_handler_type(struct crypt_device *cd, const char *type)
{
int i;
@@ -110,19 +110,14 @@ int LUKS2_digest_by_keyslot(struct luks2_hdr *hdr, int keyslot)
return -ENOENT;
}
int LUKS2_digest_verify(struct crypt_device *cd,
int LUKS2_digest_verify_by_digest(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct volume_key *vk,
int keyslot)
int digest,
const struct volume_key *vk)
{
const digest_handler *h;
int digest, r;
int r;
digest = LUKS2_digest_by_keyslot(hdr, keyslot);
if (digest < 0)
return digest;
log_dbg(cd, "Verifying key from keyslot %d, digest %d.", keyslot, digest);
h = LUKS2_digest_handler(cd, digest);
if (!h)
return -EINVAL;
@@ -136,6 +131,22 @@ int LUKS2_digest_verify(struct crypt_device *cd,
return digest;
}
int LUKS2_digest_verify(struct crypt_device *cd,
struct luks2_hdr *hdr,
const struct volume_key *vk,
int keyslot)
{
int digest;
digest = LUKS2_digest_by_keyslot(hdr, keyslot);
if (digest < 0)
return digest;
log_dbg(cd, "Verifying key from keyslot %d, digest %d.", keyslot, digest);
return LUKS2_digest_verify_by_digest(cd, hdr, digest, vk);
}
int LUKS2_digest_dump(struct crypt_device *cd, int digest)
{
const digest_handler *h;
@@ -146,31 +157,25 @@ int LUKS2_digest_dump(struct crypt_device *cd, int digest)
return h->dump(cd, digest);
}
int LUKS2_digest_any_matching(struct crypt_device *cd,
struct luks2_hdr *hdr,
const struct volume_key *vk)
{
int digest;
for (digest = 0; digest < LUKS2_DIGEST_MAX; digest++)
if (LUKS2_digest_verify_by_digest(cd, hdr, digest, vk) == digest)
return digest;
return -ENOENT;
}
int LUKS2_digest_verify_by_segment(struct crypt_device *cd,
struct luks2_hdr *hdr,
int segment,
const struct volume_key *vk)
{
const digest_handler *h;
int digest, r;
digest = LUKS2_digest_by_segment(hdr, segment);
if (digest < 0)
return digest;
log_dbg(cd, "Verifying key digest %d.", digest);
h = LUKS2_digest_handler(cd, digest);
if (!h)
return -EINVAL;
r = h->verify(cd, digest, vk->key, vk->keylength);
if (r < 0) {
log_dbg(cd, "Digest %d (%s) verify failed with %d.", digest, h->name, r);
return r;
}
return digest;
return LUKS2_digest_verify_by_digest(cd, hdr, LUKS2_digest_by_segment(hdr, segment), vk);
}
/* FIXME: segment can have more digests */
@@ -179,6 +184,9 @@ int LUKS2_digest_by_segment(struct luks2_hdr *hdr, int segment)
char segment_name[16];
json_object *jobj_digests, *jobj_digest_segments;
if (segment == CRYPT_DEFAULT_SEGMENT)
segment = LUKS2_get_default_segment(hdr);
json_object_object_get_ex(hdr->jobj, "digests", &jobj_digests);
if (snprintf(segment_name, sizeof(segment_name), "%u", segment) < 1)
@@ -250,6 +258,36 @@ int LUKS2_digest_assign(struct crypt_device *cd, struct luks2_hdr *hdr,
return commit ? LUKS2_hdr_write(cd, hdr) : 0;
}
static int assign_all_segments(struct crypt_device *cd, struct luks2_hdr *hdr,
int digest, int assign)
{
json_object *jobj1, *jobj_digest, *jobj_digest_segments;
jobj_digest = LUKS2_get_digest_jobj(hdr, digest);
if (!jobj_digest)
return -EINVAL;
json_object_object_get_ex(jobj_digest, "segments", &jobj_digest_segments);
if (!jobj_digest_segments)
return -EINVAL;
if (assign) {
json_object_object_foreach(LUKS2_get_segments_jobj(hdr), key, value) {
UNUSED(value);
jobj1 = LUKS2_array_jobj(jobj_digest_segments, key);
if (!jobj1)
json_object_array_add(jobj_digest_segments, json_object_new_string(key));
}
} else {
jobj1 = json_object_new_array();
if (!jobj1)
return -ENOMEM;
json_object_object_add(jobj_digest, "segments", jobj1);
}
return 0;
}
static int assign_one_segment(struct crypt_device *cd, struct luks2_hdr *hdr,
int segment, int digest, int assign)
{
@@ -286,17 +324,27 @@ int LUKS2_digest_segment_assign(struct crypt_device *cd, struct luks2_hdr *hdr,
json_object *jobj_digests;
int r = 0;
if (segment == CRYPT_DEFAULT_SEGMENT)
segment = LUKS2_get_default_segment(hdr);
if (digest == CRYPT_ANY_DIGEST) {
json_object_object_get_ex(hdr->jobj, "digests", &jobj_digests);
json_object_object_foreach(jobj_digests, key, val) {
UNUSED(val);
r = assign_one_segment(cd, hdr, segment, atoi(key), assign);
if (segment == CRYPT_ANY_SEGMENT)
r = assign_all_segments(cd, hdr, atoi(key), assign);
else
r = assign_one_segment(cd, hdr, segment, atoi(key), assign);
if (r < 0)
break;
}
} else
r = assign_one_segment(cd, hdr, segment, digest, assign);
} else {
if (segment == CRYPT_ANY_SEGMENT)
r = assign_all_segments(cd, hdr, digest, assign);
else
r = assign_one_segment(cd, hdr, segment, digest, assign);
}
if (r < 0)
return r;
@@ -391,3 +439,17 @@ int LUKS2_volume_key_load_in_keyring_by_keyslot(struct crypt_device *cd,
free(desc);
return r;
}
int LUKS2_volume_key_load_in_keyring_by_digest(struct crypt_device *cd,
struct luks2_hdr *hdr, struct volume_key *vk, int digest)
{
char *desc = get_key_description_by_digest(cd, digest);
int r;
r = crypt_volume_key_set_description(vk, desc);
if (!r)
r = crypt_volume_key_load_in_keyring(cd, vk);
free(desc);
return r;
}

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, PBKDF2 digest handler (LUKS1 compatible)
*
* Copyright (C) 2015-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2019 Milan Broz
* Copyright (C) 2015-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2020 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -131,8 +131,8 @@ static int PBKDF2_digest_store(struct crypt_device *cd,
}
hmac_size = crypt_hmac_size(pbkdf.hash);
if (hmac_size < 0)
return hmac_size;
if (hmac_size < 0 || hmac_size > (int)sizeof(digest_raw))
return -EINVAL;
r = crypt_pbkdf(CRYPT_KDF_PBKDF2, pbkdf.hash, volume_key, volume_key_len,
salt, LUKS_SALTSIZE, digest_raw, hmac_size,

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2
*
* Copyright (C) 2015-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2019 Milan Broz
* Copyright (C) 2015-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2020 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -26,7 +26,7 @@
/*
* Helper functions
*/
json_object *parse_json_len(struct crypt_device *cd, const char *json_area,
static json_object *parse_json_len(struct crypt_device *cd, const char *json_area,
uint64_t max_length, int *json_len)
{
json_object *jobj;
@@ -210,7 +210,7 @@ static int hdr_disk_sanity_check_pre(struct crypt_device *cd,
}
if (secondary && (offset != be64_to_cpu(hdr->hdr_size))) {
log_dbg(cd, "LUKS2 offset 0x%04x in secondary header doesn't match size 0x%04x.",
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));
return -EINVAL;
}
@@ -233,7 +233,7 @@ static int hdr_read_disk(struct crypt_device *cd,
char **json_area, uint64_t offset, int secondary)
{
size_t hdr_json_size = 0;
int devfd = -1, r;
int devfd, r;
log_dbg(cd, "Trying to read %s LUKS2 header at offset 0x%" PRIx64 ".",
secondary ? "secondary" : "primary", offset);
@@ -249,13 +249,11 @@ static int hdr_read_disk(struct crypt_device *cd,
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
device_alignment(device), hdr_disk,
LUKS2_HDR_BIN_LEN, offset) != LUKS2_HDR_BIN_LEN) {
close(devfd);
return -EIO;
}
r = hdr_disk_sanity_check_pre(cd, hdr_disk, &hdr_json_size, secondary, offset);
if (r < 0) {
close(devfd);
return r;
}
@@ -264,21 +262,17 @@ static int hdr_read_disk(struct crypt_device *cd,
*/
*json_area = malloc(hdr_json_size);
if (!*json_area) {
close(devfd);
return -ENOMEM;
}
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
device_alignment(device), *json_area, hdr_json_size,
offset + LUKS2_HDR_BIN_LEN) != (ssize_t)hdr_json_size) {
close(devfd);
free(*json_area);
*json_area = NULL;
return -EIO;
}
close(devfd);
/*
* Calculate and validate checksum and zero it afterwards.
*/
@@ -302,7 +296,7 @@ static int hdr_write_disk(struct crypt_device *cd,
struct luks2_hdr_disk hdr_disk;
uint64_t offset = secondary ? hdr->hdr_size : 0;
size_t hdr_json_len;
int devfd = -1, r;
int devfd, r;
log_dbg(cd, "Trying to write LUKS2 header (%zu bytes) at offset %" PRIu64 ".",
hdr->hdr_size, offset);
@@ -323,7 +317,6 @@ static int hdr_write_disk(struct crypt_device *cd,
if (write_lseek_blockwise(devfd, device_block_size(cd, device),
device_alignment(device), (char *)&hdr_disk,
LUKS2_HDR_BIN_LEN, offset) < (ssize_t)LUKS2_HDR_BIN_LEN) {
close(devfd);
return -EIO;
}
@@ -334,7 +327,6 @@ static int hdr_write_disk(struct crypt_device *cd,
device_alignment(device),
CONST_CAST(char*)json_area, hdr_json_len,
LUKS2_HDR_BIN_LEN + offset) < (ssize_t)hdr_json_len) {
close(devfd);
return -EIO;
}
@@ -344,7 +336,6 @@ static int hdr_write_disk(struct crypt_device *cd,
r = hdr_checksum_calculate(hdr_disk.checksum_alg, &hdr_disk,
json_area, hdr_json_len);
if (r < 0) {
close(devfd);
return r;
}
log_dbg_checksum(cd, hdr_disk.csum, hdr_disk.checksum_alg, "in-memory");
@@ -354,16 +345,63 @@ static int hdr_write_disk(struct crypt_device *cd,
LUKS2_HDR_BIN_LEN, offset) < (ssize_t)LUKS2_HDR_BIN_LEN)
r = -EIO;
device_sync(cd, device, devfd);
close(devfd);
device_sync(cd, device);
return r;
}
static int LUKS2_check_sequence_id(struct crypt_device *cd, struct luks2_hdr *hdr, struct device *device)
{
int devfd;
struct luks2_hdr_disk dhdr;
if (!hdr)
return -EINVAL;
devfd = device_open_locked(cd, device, O_RDONLY);
if (devfd < 0)
return devfd == -1 ? -EINVAL : devfd;
/* we need only first 512 bytes, see luks2_hdr_disk structure */
if ((read_lseek_blockwise(devfd, device_block_size(cd, device),
device_alignment(device), &dhdr, 512, 0) != 512))
return -EIO;
/* there's nothing to check if there's no LUKS2 header */
if ((be16_to_cpu(dhdr.version) != 2) ||
memcmp(dhdr.magic, LUKS2_MAGIC_1ST, LUKS2_MAGIC_L) ||
strcmp(dhdr.uuid, hdr->uuid))
return 0;
return hdr->seqid != be64_to_cpu(dhdr.seqid);
}
int LUKS2_device_write_lock(struct crypt_device *cd, struct luks2_hdr *hdr, struct device *device)
{
int r = device_write_lock(cd, device);
if (r < 0) {
log_err(cd, _("Failed to acquire write lock on device %s."), device_path(device));
return r;
}
/* run sequence id check only on first write lock (r == 1) and w/o LUKS2 reencryption in-progress */
if (r == 1 && !crypt_get_reenc_context(cd)) {
log_dbg(cd, "Checking context sequence id matches value stored on disk.");
if (LUKS2_check_sequence_id(cd, hdr, device)) {
device_write_unlock(cd, device);
log_err(cd, _("Detected attempt for concurrent LUKS2 metadata update. Aborting operation."));
return -EINVAL;
}
}
return 0;
}
/*
* Convert in-memory LUKS2 header and write it to disk.
* This will increase sequence id, write both header copies and calculate checksum.
*/
int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct device *device)
int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct device *device, bool seqid_check)
{
char *json_area;
const char *json_text;
@@ -383,10 +421,9 @@ int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct
* Allocate and zero JSON area (of proper header size).
*/
json_area_len = hdr->hdr_size - LUKS2_HDR_BIN_LEN;
json_area = malloc(json_area_len);
json_area = crypt_zalloc(json_area_len);
if (!json_area)
return -ENOMEM;
memset(json_area, 0, json_area_len);
/*
* Generate text space-efficient JSON representation to json area.
@@ -405,16 +442,18 @@ int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct
}
strncpy(json_area, json_text, json_area_len);
/* Increase sequence id before writing it to disk. */
hdr->seqid++;
r = device_write_lock(cd, device);
if (r) {
log_err(cd, _("Failed to acquire write device lock."));
if (seqid_check)
r = LUKS2_device_write_lock(cd, hdr, device);
else
r = device_write_lock(cd, device);
if (r < 0) {
free(json_area);
return r;
}
/* Increase sequence id before writing it to disk. */
hdr->seqid++;
/* Write primary and secondary header */
r = hdr_write_disk(cd, device, hdr, json_area, 0);
if (!r)
@@ -425,8 +464,6 @@ int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct
device_write_unlock(cd, device);
/* FIXME: try recovery here? */
free(json_area);
return r;
}

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2
*
* Copyright (C) 2015-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2019 Milan Broz
* Copyright (C) 2015-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2020 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -44,7 +44,7 @@
int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
struct device *device, int do_recovery, int do_blkprobe);
int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr,
struct device *device);
struct device *device, bool seqid_check);
/*
* JSON struct access helpers
@@ -54,17 +54,18 @@ json_object *LUKS2_get_token_jobj(struct luks2_hdr *hdr, int token);
json_object *LUKS2_get_digest_jobj(struct luks2_hdr *hdr, int digest);
json_object *LUKS2_get_segment_jobj(struct luks2_hdr *hdr, int segment);
json_object *LUKS2_get_tokens_jobj(struct luks2_hdr *hdr);
json_object *LUKS2_get_segments_jobj(struct luks2_hdr *hdr);
void hexprint_base64(struct crypt_device *cd, json_object *jobj,
const char *sep, const char *line_sep);
json_object *parse_json_len(struct crypt_device *cd, const char *json_area,
uint64_t max_length, int *json_len);
uint64_t json_object_get_uint64(json_object *jobj);
uint32_t json_object_get_uint32(json_object *jobj);
json_object *json_object_new_uint64(uint64_t value);
int json_object_object_add_by_uint(json_object *jobj, unsigned key, json_object *jobj_val);
void json_object_object_del_by_uint(json_object *jobj, unsigned key);
int json_object_copy(json_object *jobj_src, json_object **jobj_dst);
void JSON_DBG(struct crypt_device *cd, json_object *jobj, const char *desc);
@@ -73,12 +74,11 @@ void JSON_DBG(struct crypt_device *cd, json_object *jobj, const char *desc);
*/
/* validation helper */
json_bool validate_json_uint32(json_object *jobj);
json_object *json_contains(struct crypt_device *cd, json_object *jobj, const char *name,
const char *section, const char *key, json_type type);
int LUKS2_hdr_validate(struct crypt_device *cd, json_object *hdr_jobj, uint64_t json_size);
int LUKS2_keyslot_validate(struct crypt_device *cd, json_object *hdr_jobj,
json_object *hdr_keyslot, const char *key);
int LUKS2_check_json_size(struct crypt_device *cd, const struct luks2_hdr *hdr);
int LUKS2_token_validate(struct crypt_device *cd, json_object *hdr_jobj,
json_object *jobj_token, const char *key);
@@ -141,6 +141,12 @@ typedef struct {
keyslot_repair_func repair;
} keyslot_handler;
/* can not fit prototype alloc function */
int reenc_keyslot_alloc(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const struct crypt_params_reencrypt *params);
/**
* LUKS2 digest handlers (EXPERIMENTAL)
*/
@@ -157,8 +163,6 @@ typedef struct {
digest_dump_func dump;
} digest_handler;
const digest_handler *LUKS2_digest_handler_type(struct crypt_device *cd, const char *type);
/**
* LUKS2 token handlers (internal use only)
*/
@@ -178,5 +182,23 @@ int token_keyring_get(json_object *, void *);
int LUKS2_find_area_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
size_t keylength, uint64_t *area_offset, uint64_t *area_length);
int LUKS2_find_area_max_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
uint64_t *area_offset, uint64_t *area_length);
int LUKS2_check_cipher(struct crypt_device *cd,
size_t keylength,
const char *cipher,
const char *cipher_mode);
static inline const char *crypt_reencrypt_mode_to_str(crypt_reencrypt_mode_info mi)
{
if (mi == CRYPT_REENCRYPT_REENCRYPT)
return "reencrypt";
if (mi == CRYPT_REENCRYPT_ENCRYPT)
return "encrypt";
if (mi == CRYPT_REENCRYPT_DECRYPT)
return "decrypt";
return "<unknown>";
}
#endif

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, LUKS2 header format code
*
* Copyright (C) 2015-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2019 Milan Broz
* Copyright (C) 2015-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2020 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -39,9 +39,83 @@ static size_t get_min_offset(struct luks2_hdr *hdr)
return 2 * hdr->hdr_size;
}
static size_t get_max_offset(struct crypt_device *cd)
static size_t get_max_offset(struct luks2_hdr *hdr)
{
return crypt_get_data_offset(cd) * SECTOR_SIZE;
return LUKS2_hdr_and_areas_size(hdr->jobj);
}
int LUKS2_find_area_max_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
uint64_t *area_offset, uint64_t *area_length)
{
struct area areas[LUKS2_KEYSLOTS_MAX], sorted_areas[LUKS2_KEYSLOTS_MAX+1] = {};
int i, j, k, area_i;
size_t valid_offset, offset, length;
/* fill area offset + length table */
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) {
if (!LUKS2_keyslot_area(hdr, i, &areas[i].offset, &areas[i].length))
continue;
areas[i].length = 0;
areas[i].offset = 0;
}
/* sort table */
k = 0; /* index in sorted table */
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) {
offset = get_max_offset(hdr) ?: UINT64_MAX;
area_i = -1;
/* search for the smallest offset in table */
for (j = 0; j < LUKS2_KEYSLOTS_MAX; j++)
if (areas[j].offset && areas[j].offset <= offset) {
area_i = j;
offset = areas[j].offset;
}
if (area_i >= 0) {
sorted_areas[k].length = areas[area_i].length;
sorted_areas[k].offset = areas[area_i].offset;
areas[area_i].length = 0;
areas[area_i].offset = 0;
k++;
}
}
sorted_areas[LUKS2_KEYSLOTS_MAX].offset = get_max_offset(hdr);
sorted_areas[LUKS2_KEYSLOTS_MAX].length = 1;
/* search for the gap we can use */
length = valid_offset = 0;
offset = get_min_offset(hdr);
for (i = 0; i < LUKS2_KEYSLOTS_MAX+1; i++) {
/* skip empty */
if (sorted_areas[i].offset == 0 || sorted_areas[i].length == 0)
continue;
/* found bigger gap than the last one */
if ((offset < sorted_areas[i].offset) && (sorted_areas[i].offset - offset) > length) {
length = sorted_areas[i].offset - offset;
valid_offset = offset;
}
/* move beyond allocated area */
offset = sorted_areas[i].offset + sorted_areas[i].length;
}
/* this search 'algorithm' does not work with unaligned areas */
assert(length == size_round_up(length, 4096));
assert(valid_offset == size_round_up(valid_offset, 4096));
if (!length) {
log_dbg(cd, "Not enough space in header keyslot area.");
return -EINVAL;
}
log_dbg(cd, "Found largest free area %zu -> %zu", valid_offset, length + valid_offset);
*area_offset = valid_offset;
*area_length = length;
return 0;
}
int LUKS2_find_area_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
@@ -62,7 +136,7 @@ int LUKS2_find_area_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
/* sort table */
k = 0; /* index in sorted table */
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) {
offset = get_max_offset(cd) ?: UINT64_MAX;
offset = get_max_offset(hdr) ?: UINT64_MAX;
area_i = -1;
/* search for the smallest offset in table */
for (j = 0; j < LUKS2_KEYSLOTS_MAX; j++)
@@ -96,20 +170,13 @@ int LUKS2_find_area_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
offset = sorted_areas[i].offset + sorted_areas[i].length;
}
if (get_max_offset(cd) && (offset + length) > get_max_offset(cd)) {
log_err(cd, _("No space for new keyslot."));
if ((offset + length) > get_max_offset(hdr)) {
log_dbg(cd, "Not enough space in header keyslot area.");
return -EINVAL;
}
log_dbg(cd, "Found area %zu -> %zu", offset, length + offset);
/*
log_dbg("Area offset min: %zu, max %zu, slots max %u",
get_min_offset(hdr), get_max_offset(cd), LUKS2_KEYSLOTS_MAX);
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++)
log_dbg("SLOT[%02i]: %-8" PRIu64 " -> %-8" PRIu64, i,
sorted_areas[i].offset,
sorted_areas[i].length + sorted_areas[i].offset);
*/
*area_offset = offset;
*area_length = length;
return 0;
@@ -150,6 +217,7 @@ int LUKS2_generate_hdr(
char cipher[128];
uuid_t partitionUuid;
int digest;
uint64_t mdev_size;
if (!metadata_size)
metadata_size = LUKS2_HDR_16K_LEN;
@@ -173,6 +241,11 @@ int LUKS2_generate_hdr(
if (!keyslots_size) {
assert(LUKS2_DEFAULT_HDR_SIZE > 2 * LUKS2_HDR_OFFSET_MAX);
keyslots_size = LUKS2_DEFAULT_HDR_SIZE - get_min_offset(hdr);
/* Decrease keyslots_size due to metadata device being too small */
if (!device_size(crypt_metadata_device(cd), &mdev_size) &&
((keyslots_size + get_min_offset(hdr)) > mdev_size) &&
device_fallocate(crypt_metadata_device(cd), keyslots_size + get_min_offset(hdr)))
keyslots_size = mdev_size - get_min_offset(hdr);
}
/* Decrease keyslots_size if we have smaller data_offset */
@@ -232,25 +305,15 @@ int LUKS2_generate_hdr(
json_object_object_add(hdr->jobj, "config", jobj_config);
digest = LUKS2_digest_create(cd, "pbkdf2", hdr, vk);
if (digest < 0) {
json_object_put(hdr->jobj);
hdr->jobj = NULL;
return -EINVAL;
}
if (digest < 0)
goto err;
if (LUKS2_digest_segment_assign(cd, hdr, CRYPT_DEFAULT_SEGMENT, digest, 1, 0) < 0) {
json_object_put(hdr->jobj);
hdr->jobj = NULL;
return -EINVAL;
}
if (LUKS2_digest_segment_assign(cd, hdr, 0, digest, 1, 0) < 0)
goto err;
jobj_segment = json_object_new_object();
json_object_object_add(jobj_segment, "type", json_object_new_string("crypt"));
json_object_object_add(jobj_segment, "offset", json_object_new_uint64(data_offset));
json_object_object_add(jobj_segment, "iv_tweak", json_object_new_string("0"));
json_object_object_add(jobj_segment, "size", json_object_new_string("dynamic"));
json_object_object_add(jobj_segment, "encryption", json_object_new_string(cipher));
json_object_object_add(jobj_segment, "sector_size", json_object_new_int(sector_size));
jobj_segment = json_segment_create_crypt(data_offset, 0, NULL, cipher, sector_size, 0);
if (!jobj_segment)
goto err;
if (integrity) {
jobj_integrity = json_object_new_object();
@@ -260,13 +323,17 @@ int LUKS2_generate_hdr(
json_object_object_add(jobj_segment, "integrity", jobj_integrity);
}
json_object_object_add_by_uint(jobj_segments, CRYPT_DEFAULT_SEGMENT, jobj_segment);
json_object_object_add_by_uint(jobj_segments, 0, jobj_segment);
json_object_object_add(jobj_config, "json_size", json_object_new_uint64(metadata_size - LUKS2_HDR_BIN_LEN));
json_object_object_add(jobj_config, "keyslots_size", json_object_new_uint64(keyslots_size));
JSON_DBG(cd, hdr->jobj, "Header JSON:");
return 0;
err:
json_object_put(hdr->jobj);
hdr->jobj = NULL;
return -EINVAL;
}
int LUKS2_wipe_header_areas(struct crypt_device *cd,
@@ -309,3 +376,30 @@ int LUKS2_wipe_header_areas(struct crypt_device *cd,
return crypt_wipe_device(cd, crypt_metadata_device(cd), CRYPT_WIPE_RANDOM,
offset, length, wipe_block, NULL, NULL);
}
/* FIXME: what if user wanted to keep original keyslots size? */
int LUKS2_set_keyslots_size(struct crypt_device *cd,
struct luks2_hdr *hdr,
uint64_t data_offset)
{
json_object *jobj_config;
uint64_t keyslots_size;
if (data_offset < get_min_offset(hdr))
return 1;
keyslots_size = data_offset - get_min_offset(hdr);
/* keep keyslots_size reasonable for custom data alignments */
if (keyslots_size > LUKS2_MAX_KEYSLOTS_SIZE)
keyslots_size = LUKS2_MAX_KEYSLOTS_SIZE;
/* keyslots size has to be 4 KiB aligned */
keyslots_size -= (keyslots_size % 4096);
if (!json_object_object_get_ex(hdr->jobj, "config", &jobj_config))
return 1;
json_object_object_add(jobj_config, "keyslots_size", json_object_new_uint64(keyslots_size));
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, keyslot handling
*
* Copyright (C) 2015-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2019 Milan Broz
* Copyright (C) 2015-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2020 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -23,9 +23,11 @@
/* Internal implementations */
extern const keyslot_handler luks2_keyslot;
extern const keyslot_handler reenc_keyslot;
static const keyslot_handler *keyslot_handlers[LUKS2_KEYSLOTS_MAX] = {
&luks2_keyslot,
&reenc_keyslot,
NULL
};
@@ -63,7 +65,7 @@ static const keyslot_handler
return LUKS2_keyslot_handler_type(cd, json_object_get_string(jobj2));
}
int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr, const char *type)
int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr)
{
int i;
@@ -74,24 +76,55 @@ int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr, const char *type)
return -EINVAL;
}
/* Check if a keyslot is asssigned to specific segment */
int LUKS2_keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment)
/* Check if a keyslot is assigned to specific segment */
static int _keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment)
{
int keyslot_digest, segment_digest;
/* no need to check anything */
if (segment == CRYPT_ANY_SEGMENT)
return 0;
int keyslot_digest, count = 0;
unsigned s;
keyslot_digest = LUKS2_digest_by_keyslot(hdr, keyslot);
if (keyslot_digest < 0)
return -EINVAL;
return keyslot_digest;
segment_digest = LUKS2_digest_by_segment(hdr, segment);
if (segment_digest < 0)
return segment_digest;
if (segment >= 0)
return keyslot_digest == LUKS2_digest_by_segment(hdr, segment);
return segment_digest == keyslot_digest ? 0 : -ENOENT;
for (s = 0; s < json_segments_count(LUKS2_get_segments_jobj(hdr)); s++) {
if (keyslot_digest == LUKS2_digest_by_segment(hdr, s))
count++;
}
return count;
}
static int _keyslot_for_digest(struct luks2_hdr *hdr, int keyslot, int digest)
{
int r = -EINVAL;
r = LUKS2_digest_by_keyslot(hdr, keyslot);
if (r < 0)
return r;
return r == digest ? 0 : -ENOENT;
}
int LUKS2_keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment)
{
int r = -EINVAL;
/* no need to check anything */
if (segment == CRYPT_ANY_SEGMENT)
return 0; /* ok */
if (segment == CRYPT_DEFAULT_SEGMENT) {
segment = LUKS2_get_default_segment(hdr);
if (segment < 0)
return segment;
}
r = _keyslot_for_segment(hdr, keyslot, segment);
if (r < 0)
return r;
return r >= 1 ? 0 : -ENOENT;
}
/* Number of keyslots assigned to a segment or all keyslots for CRYPT_ANY_SEGMENT */
@@ -165,7 +198,7 @@ int LUKS2_keyslot_params_default(struct crypt_device *cd, struct luks2_hdr *hdr,
*/
params->af_type = LUKS2_KEYSLOT_AF_LUKS1;
/* currently we use hash for AF from pbkdf settings */
r = snprintf(params->af.luks1.hash, sizeof(params->af.luks1.hash), "%s", pbkdf->hash);
r = snprintf(params->af.luks1.hash, sizeof(params->af.luks1.hash), "%s", pbkdf->hash ?: DEFAULT_LUKS1_HASH);
if (r < 0 || (size_t)r >= sizeof(params->af.luks1.hash))
return -EINVAL;
params->af.luks1.stripes = 4000;
@@ -237,7 +270,8 @@ crypt_keyslot_info LUKS2_keyslot_info(struct luks2_hdr *hdr, int keyslot)
if (!LUKS2_get_keyslot_jobj(hdr, keyslot))
return CRYPT_SLOT_INACTIVE;
if (LUKS2_keyslot_unbound(hdr, keyslot))
if (LUKS2_digest_by_keyslot(hdr, keyslot) < 0 ||
LUKS2_keyslot_unbound(hdr, keyslot))
return CRYPT_SLOT_UNBOUND;
if (LUKS2_keyslot_active_count(hdr, CRYPT_DEFAULT_SEGMENT) == 1 &&
@@ -266,45 +300,25 @@ int LUKS2_keyslot_area(struct luks2_hdr *hdr,
if (!json_object_object_get_ex(jobj_area, "offset", &jobj))
return -EINVAL;
*offset = json_object_get_int64(jobj);
*offset = json_object_get_uint64(jobj);
if (!json_object_object_get_ex(jobj_area, "size", &jobj))
return -EINVAL;
*length = json_object_get_int64(jobj);
*length = json_object_get_uint64(jobj);
return 0;
}
static int LUKS2_open_and_verify(struct crypt_device *cd,
static int _open_and_verify(struct crypt_device *cd,
struct luks2_hdr *hdr,
const keyslot_handler *h,
int keyslot,
int segment,
const char *password,
size_t password_len,
struct volume_key **vk)
{
const keyslot_handler *h;
int key_size, r;
int r, key_size = LUKS2_get_keyslot_stored_key_size(hdr, keyslot);
if (!(h = LUKS2_keyslot_handler(cd, keyslot)))
return -ENOENT;
r = h->validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot));
if (r) {
log_dbg(cd, "Keyslot %d validation failed.", keyslot);
return r;
}
r = LUKS2_keyslot_for_segment(hdr, keyslot, segment);
if (r) {
if (r == -ENOENT)
log_dbg(cd, "Keyslot %d unusable for segment %d.", keyslot, segment);
return r;
}
key_size = LUKS2_get_volume_key_size(hdr, segment);
if (key_size < 0)
key_size = LUKS2_get_keyslot_stored_key_size(hdr, keyslot);
if (key_size < 0)
return -EINVAL;
@@ -323,9 +337,109 @@ static int LUKS2_open_and_verify(struct crypt_device *cd,
*vk = NULL;
}
crypt_volume_key_set_id(*vk, r);
return r < 0 ? r : keyslot;
}
static int LUKS2_open_and_verify_by_digest(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
int digest,
const char *password,
size_t password_len,
struct volume_key **vk)
{
const keyslot_handler *h;
int r;
if (!(h = LUKS2_keyslot_handler(cd, keyslot)))
return -ENOENT;
r = h->validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot));
if (r) {
log_dbg(cd, "Keyslot %d validation failed.", keyslot);
return r;
}
r = _keyslot_for_digest(hdr, keyslot, digest);
if (r) {
if (r == -ENOENT)
log_dbg(cd, "Keyslot %d unusable for digest %d.", keyslot, digest);
return r;
}
return _open_and_verify(cd, hdr, h, keyslot, password, password_len, vk);
}
static int LUKS2_open_and_verify(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
int segment,
const char *password,
size_t password_len,
struct volume_key **vk)
{
const keyslot_handler *h;
int r;
if (!(h = LUKS2_keyslot_handler(cd, keyslot)))
return -ENOENT;
r = h->validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot));
if (r) {
log_dbg(cd, "Keyslot %d validation failed.", keyslot);
return r;
}
r = LUKS2_keyslot_for_segment(hdr, keyslot, segment);
if (r) {
if (r == -ENOENT)
log_dbg(cd, "Keyslot %d unusable for segment %d.", keyslot, segment);
return r;
}
return _open_and_verify(cd, hdr, h, keyslot, password, password_len, vk);
}
static int LUKS2_keyslot_open_priority_digest(struct crypt_device *cd,
struct luks2_hdr *hdr,
crypt_keyslot_priority priority,
const char *password,
size_t password_len,
int digest,
struct volume_key **vk)
{
json_object *jobj_keyslots, *jobj;
crypt_keyslot_priority slot_priority;
int keyslot, r = -ENOENT;
json_object_object_get_ex(hdr->jobj, "keyslots", &jobj_keyslots);
json_object_object_foreach(jobj_keyslots, slot, val) {
if (!json_object_object_get_ex(val, "priority", &jobj))
slot_priority = CRYPT_SLOT_PRIORITY_NORMAL;
else
slot_priority = json_object_get_int(jobj);
keyslot = atoi(slot);
if (slot_priority != priority) {
log_dbg(cd, "Keyslot %d priority %d != %d (required), skipped.",
keyslot, slot_priority, priority);
continue;
}
r = LUKS2_open_and_verify_by_digest(cd, hdr, keyslot, digest, password, password_len, vk);
/* Do not retry for errors that are no -EPERM or -ENOENT,
former meaning password wrong, latter key slot unusable for segment */
if ((r != -EPERM) && (r != -ENOENT))
break;
}
return r;
}
static int LUKS2_keyslot_open_priority(struct crypt_device *cd,
struct luks2_hdr *hdr,
crypt_keyslot_priority priority,
@@ -364,6 +478,79 @@ static int LUKS2_keyslot_open_priority(struct crypt_device *cd,
return r;
}
static int LUKS2_keyslot_open_by_digest(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
int digest,
const char *password,
size_t password_len,
struct volume_key **vk)
{
int r_prio, r = -EINVAL;
if (digest < 0)
return r;
if (keyslot == CRYPT_ANY_SLOT) {
r_prio = LUKS2_keyslot_open_priority_digest(cd, hdr, CRYPT_SLOT_PRIORITY_PREFER,
password, password_len, digest, vk);
if (r_prio >= 0)
r = r_prio;
else if (r_prio != -EPERM && r_prio != -ENOENT)
r = r_prio;
else
r = LUKS2_keyslot_open_priority_digest(cd, hdr, CRYPT_SLOT_PRIORITY_NORMAL,
password, password_len, digest, vk);
/* Prefer password wrong to no entry from priority slot */
if (r_prio == -EPERM && r == -ENOENT)
r = r_prio;
} else
r = LUKS2_open_and_verify_by_digest(cd, hdr, keyslot, digest, password, password_len, vk);
return r;
}
int LUKS2_keyslot_open_all_segments(struct crypt_device *cd,
int keyslot_old,
int keyslot_new,
const char *password,
size_t password_len,
struct volume_key **vks)
{
struct volume_key *vk = NULL;
int digest_old, digest_new, r = -EINVAL;
struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
digest_old = LUKS2_reencrypt_digest_old(hdr);
if (digest_old >= 0) {
log_dbg(cd, "Trying to unlock volume key (digest: %d) using keyslot %d.", digest_old, keyslot_old);
r = LUKS2_keyslot_open_by_digest(cd, hdr, keyslot_old, digest_old, password, password_len, &vk);
if (r < 0)
goto out;
crypt_volume_key_add_next(vks, vk);
}
digest_new = LUKS2_reencrypt_digest_new(hdr);
if (digest_new >= 0 && digest_old != digest_new) {
log_dbg(cd, "Trying to unlock volume key (digest: %d) using keyslot %d.", digest_new, keyslot_new);
r = LUKS2_keyslot_open_by_digest(cd, hdr, keyslot_new, digest_new, password, password_len, &vk);
if (r < 0)
goto out;
crypt_volume_key_add_next(vks, vk);
}
out:
if (r < 0) {
crypt_free_volume_key(*vks);
*vks = NULL;
if (r == -ENOMEM)
log_err(cd, _("Not enough available memory to open a keyslot."));
else if (r != -EPERM)
log_err(cd, _("Keyslot open failed."));
}
return r;
}
int LUKS2_keyslot_open(struct crypt_device *cd,
int keyslot,
int segment,
@@ -392,9 +579,74 @@ int LUKS2_keyslot_open(struct crypt_device *cd,
} else
r = LUKS2_open_and_verify(cd, hdr, keyslot, segment, password, password_len, vk);
if (r < 0) {
if (r == -ENOMEM)
log_err(cd, _("Not enough available memory to open a keyslot."));
else if (r != -EPERM)
log_err(cd, _("Keyslot open failed."));
}
return r;
}
int LUKS2_keyslot_reencrypt_create(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const struct crypt_params_reencrypt *params)
{
const keyslot_handler *h;
int r;
if (keyslot == CRYPT_ANY_SLOT)
return -EINVAL;
/* FIXME: find keyslot by type */
h = LUKS2_keyslot_handler_type(cd, "reencrypt");
if (!h)
return -EINVAL;
r = reenc_keyslot_alloc(cd, hdr, keyslot, params);
if (r < 0)
return r;
r = LUKS2_keyslot_priority_set(cd, hdr, keyslot, CRYPT_SLOT_PRIORITY_IGNORE, 0);
if (r < 0)
return r;
r = h->validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot));
if (r) {
log_dbg(cd, "Keyslot validation failed.");
return r;
}
if (LUKS2_hdr_validate(cd, hdr->jobj, hdr->hdr_size - LUKS2_HDR_BIN_LEN))
return -EINVAL;
return 0;
}
int LUKS2_keyslot_reencrypt_store(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const void *buffer,
size_t buffer_length)
{
const keyslot_handler *h;
int r;
if (!(h = LUKS2_keyslot_handler(cd, keyslot)) || strcmp(h->name, "reencrypt"))
return -EINVAL;
r = h->validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot));
if (r) {
log_dbg(cd, "Keyslot validation failed.");
return r;
}
return h->store(cd, keyslot, NULL, 0,
buffer, buffer_length);
}
int LUKS2_keyslot_store(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
@@ -435,6 +687,9 @@ int LUKS2_keyslot_store(struct crypt_device *cd,
return r;
}
if (LUKS2_hdr_validate(cd, hdr->jobj, hdr->hdr_size - LUKS2_HDR_BIN_LEN))
return -EINVAL;
return h->store(cd, keyslot, password, password_len,
vk->key, vk->keylength);
}
@@ -462,21 +717,15 @@ int LUKS2_keyslot_wipe(struct crypt_device *cd,
if (wipe_area_only)
log_dbg(cd, "Wiping keyslot %d area only.", keyslot);
/* Just check that nobody uses the metadata now */
r = device_write_lock(cd, device);
if (r) {
log_err(cd, _("Failed to acquire write lock on device %s."),
device_path(device));
r = LUKS2_device_write_lock(cd, hdr, device);
if (r)
return r;
}
device_write_unlock(cd, device);
/* secure deletion of possible key material in keyslot area */
r = crypt_keyslot_area(cd, keyslot, &area_offset, &area_length);
if (r && r != -ENOENT)
return r;
goto out;
/* We can destroy the binary keyslot area now without lock */
if (!r) {
r = crypt_wipe_device(cd, device, CRYPT_WIPE_SPECIAL, area_offset,
area_length, area_length, NULL, NULL);
@@ -487,24 +736,27 @@ int LUKS2_keyslot_wipe(struct crypt_device *cd,
r = -EINVAL;
} else
log_err(cd, _("Cannot wipe device %s."), device_path(device));
return r;
goto out;
}
}
if (wipe_area_only)
return r;
goto out;
/* Slot specific wipe */
if (h) {
r = h->wipe(cd, keyslot);
if (r < 0)
return r;
goto out;
} else
log_dbg(cd, "Wiping keyslot %d without specific-slot handler loaded.", keyslot);
json_object_object_del_by_uint(jobj_keyslots, keyslot);
return LUKS2_hdr_write(cd, hdr);
r = LUKS2_hdr_write(cd, hdr);
out:
device_write_unlock(cd, crypt_metadata_device(cd));
return r;
}
int LUKS2_keyslot_dump(struct crypt_device *cd, int keyslot)
@@ -661,3 +913,25 @@ void LUKS2_keyslots_repair(struct crypt_device *cd, json_object *jobj_keyslots)
h->repair(cd, val);
}
}
/* assumes valid header */
int LUKS2_find_keyslot(struct luks2_hdr *hdr, const char *type)
{
int i;
json_object *jobj_keyslot, *jobj_type;
if (!type)
return -EINVAL;
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) {
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, i);
if (!jobj_keyslot)
continue;
json_object_object_get_ex(jobj_keyslot, "type", &jobj_type);
if (!strcmp(json_object_get_string(jobj_type), type))
return i;
}
return -ENOENT;
}

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, LUKS2 type keyslot handler
*
* Copyright (C) 2015-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2019 Milan Broz
* Copyright (C) 2015-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2020 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -28,46 +28,36 @@
#define LUKS_SLOT_ITERATIONS_MIN 1000
#define LUKS_STRIPES 4000
/* Serialize memory-hard keyslot access: optional workaround for parallel processing */
#define MIN_MEMORY_FOR_SERIALIZE_LOCK_KB 32*1024 /* 32MB */
static int luks2_encrypt_to_storage(char *src, size_t srcLength,
const char *cipher, const char *cipher_mode,
struct volume_key *vk, unsigned int sector,
struct crypt_device *cd)
{
struct device *device = crypt_metadata_device(cd);
#ifndef ENABLE_AF_ALG /* Support for old kernel without Crypto API */
int r = device_write_lock(cd, device);
if (r) {
log_err(cd, _("Failed to acquire write lock on device %s."), device_path(device));
return r;
}
r = LUKS_encrypt_to_storage(src, srcLength, cipher, cipher_mode, vk, sector, cd);
device_write_unlock(cd, crypt_metadata_device(cd));
return r;
return LUKS_encrypt_to_storage(src, srcLength, cipher, cipher_mode, vk, sector, cd);
#else
struct crypt_storage *s;
int devfd = -1, r;
int devfd, r;
struct device *device = crypt_metadata_device(cd);
/* Only whole sector writes supported */
if (MISALIGNED_512(srcLength))
return -EINVAL;
/* Encrypt buffer */
r = crypt_storage_init(&s, 0, cipher, cipher_mode, vk->key, vk->keylength);
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode, vk->key, vk->keylength);
if (r) {
log_dbg(cd, "Userspace crypto wrapper cannot use %s-%s (%d).",
cipher, cipher_mode, r);
log_err(cd, _("Cannot use %s-%s cipher for keyslot encryption."), cipher, cipher_mode);
return r;
}
r = crypt_storage_encrypt(s, 0, srcLength / SECTOR_SIZE, src);
r = crypt_storage_encrypt(s, 0, srcLength, src);
crypt_storage_destroy(s);
if (r)
return r;
r = device_write_lock(cd, device);
if (r) {
log_err(cd, _("Failed to acquire write lock on device %s."),
device_path(device));
log_err(cd, _("IO error while encrypting keyslot."));
return r;
}
@@ -80,13 +70,10 @@ static int luks2_encrypt_to_storage(char *src, size_t srcLength,
else
r = 0;
device_sync(cd, device, devfd);
close(devfd);
device_sync(cd, device);
} else
r = -EIO;
device_write_unlock(cd, device);
if (r)
log_err(cd, _("IO error while encrypting keyslot."));
@@ -110,16 +97,15 @@ static int luks2_decrypt_from_storage(char *dst, size_t dstLength,
return r;
#else
struct crypt_storage *s;
int devfd = -1, r;
int devfd, r;
/* Only whole sector writes supported */
if (MISALIGNED_512(dstLength))
return -EINVAL;
r = crypt_storage_init(&s, 0, cipher, cipher_mode, vk->key, vk->keylength);
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode, vk->key, vk->keylength);
if (r) {
log_dbg(cd, "Userspace crypto wrapper cannot use %s-%s (%d).",
cipher, cipher_mode, r);
log_err(cd, _("Cannot use %s-%s cipher for keyslot encryption."), cipher, cipher_mode);
return r;
}
@@ -139,7 +125,6 @@ static int luks2_decrypt_from_storage(char *dst, size_t dstLength,
r = -EIO;
else
r = 0;
close(devfd);
} else
r = -EIO;
@@ -147,7 +132,7 @@ static int luks2_decrypt_from_storage(char *dst, size_t dstLength,
/* Decrypt buffer */
if (!r)
r = crypt_storage_decrypt(s, 0, dstLength / SECTOR_SIZE, dst);
r = crypt_storage_decrypt(s, 0, dstLength, dst);
else
log_err(cd, _("IO error while decrypting keyslot."));
@@ -312,6 +297,7 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
json_object *jobj2, *jobj_af, *jobj_area;
uint64_t area_offset;
size_t keyslot_key_len;
bool try_serialize_lock = false;
int r;
if (!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af) ||
@@ -339,6 +325,13 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
return -EINVAL;
keyslot_key_len = json_object_get_int(jobj2);
/*
* If requested, serialize unlocking for memory-hard KDF. Usually NOOP.
*/
if (pbkdf.max_memory_kb > MIN_MEMORY_FOR_SERIALIZE_LOCK_KB)
try_serialize_lock = true;
if (try_serialize_lock && crypt_serialize_lock(cd))
return -EINVAL;
/*
* Allocate derived key storage space.
*/
@@ -361,6 +354,9 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
pbkdf.iterations, pbkdf.max_memory_kb,
pbkdf.parallel_threads);
if (try_serialize_lock)
crypt_serialize_unlock(cd);
if (r == 0) {
log_dbg(cd, "Reading keyslot area [0x%04x].", (unsigned)area_offset);
/* FIXME: sector_offset should be size_t, fix LUKS_decrypt... accordingly */
@@ -466,7 +462,7 @@ static int luks2_keyslot_alloc(struct crypt_device *cd,
return -EINVAL;
if (keyslot == CRYPT_ANY_SLOT)
keyslot = LUKS2_keyslot_find_empty(hdr, "luks2");
keyslot = LUKS2_keyslot_find_empty(hdr);
if (keyslot < 0 || keyslot >= LUKS2_KEYSLOTS_MAX)
return -ENOMEM;
@@ -480,8 +476,10 @@ static int luks2_keyslot_alloc(struct crypt_device *cd,
return -EINVAL;
r = LUKS2_find_area_gap(cd, hdr, volume_key_len, &area_offset, &area_length);
if (r < 0)
if (r < 0) {
log_err(cd, _("No space for new keyslot."));
return r;
}
jobj_keyslot = json_object_new_object();
json_object_object_add(jobj_keyslot, "type", json_object_new_string("luks2"));
@@ -563,17 +561,19 @@ static int luks2_keyslot_store(struct crypt_device *cd,
if (!jobj_keyslot)
return -EINVAL;
r = LUKS2_device_write_lock(cd, hdr, crypt_metadata_device(cd));
if(r)
return r;
r = luks2_keyslot_set_key(cd, jobj_keyslot,
password, password_len,
volume_key, volume_key_len);
if (r < 0)
return r;
if (!r)
r = LUKS2_hdr_write(cd, hdr);
r = LUKS2_hdr_write(cd, hdr);
if (r < 0)
return r;
device_write_unlock(cd, crypt_metadata_device(cd));
return keyslot;
return r < 0 ? r : keyslot;
}
static int luks2_keyslot_wipe(struct crypt_device *cd, int keyslot)

View File

@@ -0,0 +1,336 @@
/*
* LUKS - Linux Unified Key Setup v2, reencryption keyslot handler
*
* Copyright (C) 2016-2020, Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2020, Ondrej Kozina
*
* 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"
static int reenc_keyslot_open(struct crypt_device *cd,
int keyslot,
const char *password,
size_t password_len,
char *volume_key,
size_t volume_key_len)
{
return -ENOENT;
}
int reenc_keyslot_alloc(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const struct crypt_params_reencrypt *params)
{
int r;
json_object *jobj_keyslots, *jobj_keyslot, *jobj_area;
uint64_t area_offset, area_length;
log_dbg(cd, "Allocating reencrypt keyslot %d.", keyslot);
if (keyslot < 0 || keyslot >= LUKS2_KEYSLOTS_MAX)
return -ENOMEM;
if (!json_object_object_get_ex(hdr->jobj, "keyslots", &jobj_keyslots))
return -EINVAL;
/* encryption doesn't require area (we shift data and backup will be available) */
if (!params->data_shift) {
r = LUKS2_find_area_max_gap(cd, hdr, &area_offset, &area_length);
if (r < 0)
return r;
} else { /* we can't have keyslot w/o area...bug? */
r = LUKS2_find_area_gap(cd, hdr, 1, &area_offset, &area_length);
if (r < 0)
return r;
}
jobj_keyslot = json_object_new_object();
if (!jobj_keyslot)
return -ENOMEM;
jobj_area = json_object_new_object();
if (params->data_shift) {
json_object_object_add(jobj_area, "type", json_object_new_string("datashift"));
json_object_object_add(jobj_area, "shift_size", json_object_new_uint64(params->data_shift << SECTOR_SHIFT));
} else
/* except data shift protection, initial setting is irrelevant. Type can be changed during reencryption */
json_object_object_add(jobj_area, "type", json_object_new_string("none"));
json_object_object_add(jobj_area, "offset", json_object_new_uint64(area_offset));
json_object_object_add(jobj_area, "size", json_object_new_uint64(area_length));
json_object_object_add(jobj_keyslot, "type", json_object_new_string("reencrypt"));
json_object_object_add(jobj_keyslot, "key_size", json_object_new_int(1)); /* useless but mandatory */
json_object_object_add(jobj_keyslot, "mode", json_object_new_string(crypt_reencrypt_mode_to_str(params->mode)));
if (params->direction == CRYPT_REENCRYPT_FORWARD)
json_object_object_add(jobj_keyslot, "direction", json_object_new_string("forward"));
else if (params->direction == CRYPT_REENCRYPT_BACKWARD)
json_object_object_add(jobj_keyslot, "direction", json_object_new_string("backward"));
else
return -EINVAL;
json_object_object_add(jobj_keyslot, "area", jobj_area);
json_object_object_add_by_uint(jobj_keyslots, keyslot, jobj_keyslot);
if (LUKS2_check_json_size(cd, hdr)) {
log_dbg(cd, "New keyslot too large to fit in free metadata space.");
json_object_object_del_by_uint(jobj_keyslots, keyslot);
return -ENOSPC;
}
JSON_DBG(cd, hdr->jobj, "JSON:");
return 0;
}
static int reenc_keyslot_store_data(struct crypt_device *cd,
json_object *jobj_keyslot,
const void *buffer, size_t buffer_len)
{
int devfd, r;
json_object *jobj_area, *jobj_offset, *jobj_length;
uint64_t area_offset, area_length;
struct device *device = crypt_metadata_device(cd);
if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
!json_object_object_get_ex(jobj_area, "offset", &jobj_offset) ||
!json_object_object_get_ex(jobj_area, "size", &jobj_length))
return -EINVAL;
area_offset = json_object_get_uint64(jobj_offset);
area_length = json_object_get_uint64(jobj_length);
if (!area_offset || !area_length || ((uint64_t)buffer_len > area_length))
return -EINVAL;
devfd = device_open_locked(cd, device, O_RDWR);
if (devfd >= 0) {
if (write_lseek_blockwise(devfd, device_block_size(cd, device),
device_alignment(device), CONST_CAST(void *)buffer,
buffer_len, area_offset) < 0)
r = -EIO;
else
r = 0;
} else
r = -EINVAL;
if (r)
log_err(cd, _("IO error while encrypting keyslot."));
return r;
}
static int reenc_keyslot_store(struct crypt_device *cd,
int keyslot,
const char *password __attribute__((unused)),
size_t password_len __attribute__((unused)),
const char *buffer,
size_t buffer_len)
{
struct luks2_hdr *hdr;
json_object *jobj_keyslot;
int r = 0;
if (!cd || !buffer || !buffer_len)
return -EINVAL;
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
return -EINVAL;
log_dbg(cd, "Reencrypt keyslot %d store.", keyslot);
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
if (!jobj_keyslot)
return -EINVAL;
r = LUKS2_device_write_lock(cd, hdr, crypt_metadata_device(cd));
if (r)
return r;
r = reenc_keyslot_store_data(cd, jobj_keyslot, buffer, buffer_len);
if (r < 0) {
device_write_unlock(cd, crypt_metadata_device(cd));
return r;
}
r = LUKS2_hdr_write(cd, hdr);
device_write_unlock(cd, crypt_metadata_device(cd));
return r < 0 ? r : keyslot;
}
int reenc_keyslot_update(struct crypt_device *cd,
const struct luks2_reenc_context *rh)
{
json_object *jobj_keyslot, *jobj_area, *jobj_area_type;
struct luks2_hdr *hdr;
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
return -EINVAL;
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, rh->reenc_keyslot);
if (!jobj_keyslot)
return -EINVAL;
json_object_object_get_ex(jobj_keyslot, "area", &jobj_area);
json_object_object_get_ex(jobj_area, "type", &jobj_area_type);
if (rh->rp.type == REENC_PROTECTION_CHECKSUM) {
log_dbg(cd, "Updating reencrypt keyslot for checksum protection.");
json_object_object_add(jobj_area, "type", json_object_new_string("checksum"));
json_object_object_add(jobj_area, "hash", json_object_new_string(rh->rp.p.csum.hash));
json_object_object_add(jobj_area, "sector_size", json_object_new_int64(rh->alignment));
} else if (rh->rp.type == REENC_PROTECTION_NONE) {
log_dbg(cd, "Updating reencrypt keyslot for none protection.");
json_object_object_add(jobj_area, "type", json_object_new_string("none"));
json_object_object_del(jobj_area, "hash");
} else if (rh->rp.type == REENC_PROTECTION_JOURNAL) {
log_dbg(cd, "Updating reencrypt keyslot for journal protection.");
json_object_object_add(jobj_area, "type", json_object_new_string("journal"));
json_object_object_del(jobj_area, "hash");
} else
log_dbg(cd, "No update of reencrypt keyslot needed.");
return 0;
}
static int reenc_keyslot_wipe(struct crypt_device *cd, int keyslot)
{
return 0;
}
static int reenc_keyslot_dump(struct crypt_device *cd, int keyslot)
{
json_object *jobj_keyslot, *jobj_area, *jobj_direction, *jobj_mode, *jobj_resilience,
*jobj1;
jobj_keyslot = LUKS2_get_keyslot_jobj(crypt_get_hdr(cd, CRYPT_LUKS2), keyslot);
if (!jobj_keyslot)
return -EINVAL;
if (!json_object_object_get_ex(jobj_keyslot, "direction", &jobj_direction) ||
!json_object_object_get_ex(jobj_keyslot, "mode", &jobj_mode) ||
!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
!json_object_object_get_ex(jobj_area, "type", &jobj_resilience))
return -EINVAL;
log_std(cd, "\t%-12s%s\n", "Mode:", json_object_get_string(jobj_mode));
log_std(cd, "\t%-12s%s\n", "Direction:", json_object_get_string(jobj_direction));
log_std(cd, "\t%-12s%s\n", "Resilience:", json_object_get_string(jobj_resilience));
if (!strcmp(json_object_get_string(jobj_resilience), "checksum")) {
json_object_object_get_ex(jobj_area, "hash", &jobj1);
log_std(cd, "\t%-12s%s\n", "Hash:", json_object_get_string(jobj1));
json_object_object_get_ex(jobj_area, "sector_size", &jobj1);
log_std(cd, "\t%-12s%d [bytes]\n", "Hash data:", json_object_get_int(jobj1));
} else if (!strcmp(json_object_get_string(jobj_resilience), "datashift")) {
json_object_object_get_ex(jobj_area, "shift_size", &jobj1);
log_std(cd, "\t%-12s%" PRIu64 "[bytes]\n", "Shift size:", json_object_get_uint64(jobj1));
}
json_object_object_get_ex(jobj_area, "offset", &jobj1);
log_std(cd, "\tArea offset:%" PRIu64 " [bytes]\n", json_object_get_uint64(jobj1));
json_object_object_get_ex(jobj_area, "size", &jobj1);
log_std(cd, "\tArea length:%" PRIu64 " [bytes]\n", json_object_get_uint64(jobj1));
return 0;
}
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;
const char *mode, *type, *direction;
uint32_t sector_size;
uint64_t shift_size;
/* mode (string: encrypt,reencrypt,decrypt)
* direction (string:)
* area {
* type: (string: datashift, journal, checksum, none)
* hash: (string: checksum only)
* sector_size (uint32: checksum only)
* shift_size (uint64: datashift only)
* }
*/
/* area and area type are validated in general validation code */
if (!jobj_keyslot || !json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
!json_object_object_get_ex(jobj_area, "type", &jobj_type))
return -EINVAL;
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)
return -EINVAL;
mode = json_object_get_string(jobj_mode);
type = json_object_get_string(jobj_type);
direction = json_object_get_string(jobj_direction);
if (strcmp(mode, "reencrypt") && strcmp(mode, "encrypt") &&
strcmp(mode, "decrypt")) {
log_dbg(cd, "Illegal reencrypt mode %s.", mode);
return -EINVAL;
}
if (strcmp(direction, "forward") && strcmp(direction, "backward")) {
log_dbg(cd, "Illegal reencrypt direction %s.", direction);
return -EINVAL;
}
if (!strcmp(type, "checksum")) {
jobj_hash = json_contains(cd, jobj_area, "type:checksum", "Keyslot area", "hash", json_type_string);
jobj_sector_size = json_contains(cd, jobj_area, "type:checksum", "Keyslot area", "sector_size", json_type_int);
if (!jobj_hash || !jobj_sector_size)
return -EINVAL;
if (!validate_json_uint32(jobj_sector_size))
return -EINVAL;
sector_size = json_object_get_uint32(jobj_sector_size);
if (sector_size < SECTOR_SIZE || NOTPOW2(sector_size)) {
log_dbg(cd, "Invalid sector_size (%" PRIu32 ") for checksum resilience mode.", sector_size);
return -EINVAL;
}
} else if (!strcmp(type, "datashift")) {
if (!(jobj_shift_size = json_contains(cd, jobj_area, "type:datashift", "Keyslot area", "shift_size", json_type_string)))
return -EINVAL;
shift_size = json_object_get_uint64(jobj_shift_size);
if (!shift_size)
return -EINVAL;
if (MISALIGNED_512(shift_size)) {
log_dbg(cd, "Shift size field has to be aligned to sector size: %" PRIu32, SECTOR_SIZE);
return -EINVAL;
}
}
return 0;
}
const keyslot_handler reenc_keyslot = {
.name = "reencrypt",
.open = reenc_keyslot_open,
.store = reenc_keyslot_store, /* initialization only or also per every chunk write */
.wipe = reenc_keyslot_wipe,
.dump = reenc_keyslot_dump,
.validate = reenc_keyslot_validate
};

View File

@@ -1,9 +1,9 @@
/*
* LUKS - Linux Unified Key Setup v2, LUKS1 conversion code
*
* Copyright (C) 2015-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2019 Ondrej Kozina
* Copyright (C) 2015-2019 Milan Broz
* Copyright (C) 2015-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2020 Ondrej Kozina
* Copyright (C) 2015-2020 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -24,6 +24,14 @@
#include "../luks1/luks.h"
#include "../luks1/af.h"
int LUKS2_check_cipher(struct crypt_device *cd,
size_t keylength,
const char *cipher,
const char *cipher_mode)
{
return LUKS_check_cipher(cd, keylength, cipher, cipher_mode);
}
static int json_luks1_keyslot(const struct luks_phdr *hdr_v1, int keyslot, struct json_object **keyslot_object)
{
char *base64_str, cipher[LUKS_CIPHERNAME_L+LUKS_CIPHERMODE_L];
@@ -200,7 +208,7 @@ static int json_luks1_segments(const struct luks_phdr *hdr_v1, struct json_objec
json_object_put(segments_obj);
return r;
}
json_object_object_add_by_uint(segments_obj, CRYPT_DEFAULT_SEGMENT, field);
json_object_object_add_by_uint(segments_obj, 0, field);
*segments_object = segments_obj;
return 0;
@@ -419,9 +427,9 @@ static void move_keyslot_offset(json_object *jobj, int offset_add)
static int move_keyslot_areas(struct crypt_device *cd, off_t offset_from,
off_t offset_to, size_t buf_size)
{
int devfd, r = -EIO;
struct device *device = crypt_metadata_device(cd);
void *buf = NULL;
int r = -EIO, devfd = -1;
log_dbg(cd, "Moving keyslot areas of size %zu from %jd to %jd.",
buf_size, (intmax_t)offset_from, (intmax_t)offset_to);
@@ -430,7 +438,7 @@ static int move_keyslot_areas(struct crypt_device *cd, off_t offset_from,
return -ENOMEM;
devfd = device_open(cd, device, O_RDWR);
if (devfd == -1) {
if (devfd < 0) {
free(buf);
return -EIO;
}
@@ -457,9 +465,8 @@ static int move_keyslot_areas(struct crypt_device *cd, off_t offset_from,
r = 0;
out:
device_sync(cd, device, devfd);
close(devfd);
crypt_memzero(buf, buf_size);
device_sync(cd, device);
crypt_safe_memzero(buf, buf_size);
free(buf);
return r;
@@ -471,7 +478,7 @@ static int luks_header_in_use(struct crypt_device *cd)
r = lookup_dm_dev_by_uuid(cd, crypt_get_uuid(cd), crypt_get_type(cd));
if (r < 0)
log_err(cd, _("Can not check status of device with uuid: %s."), crypt_get_uuid(cd));
log_err(cd, _("Cannot check status of device with uuid: %s."), crypt_get_uuid(cd));
return r;
}
@@ -479,16 +486,16 @@ static int luks_header_in_use(struct crypt_device *cd)
/* Check if there is a luksmeta area (foreign metadata created by the luksmeta package) */
static int luksmeta_header_present(struct crypt_device *cd, off_t luks1_size)
{
int devfd, r = 0;
static const uint8_t LM_MAGIC[] = { 'L', 'U', 'K', 'S', 'M', 'E', 'T', 'A' };
struct device *device = crypt_metadata_device(cd);
void *buf = NULL;
int devfd, r = 0;
if (posix_memalign(&buf, crypt_getpagesize(), sizeof(LM_MAGIC)))
return -ENOMEM;
devfd = device_open(cd, device, O_RDONLY);
if (devfd == -1) {
if (devfd < 0) {
free(buf);
return -EIO;
}
@@ -501,7 +508,6 @@ static int luksmeta_header_present(struct crypt_device *cd, off_t luks1_size)
r = -EBUSY;
}
close(devfd);
free(buf);
return r;
}
@@ -512,7 +518,7 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
int r;
json_object *jobj = NULL;
size_t buf_size, buf_offset, luks1_size, luks1_shift = 2 * LUKS2_HDR_16K_LEN - LUKS_ALIGN_KEYSLOTS;
uint64_t max_size = crypt_get_data_offset(cd) * SECTOR_SIZE;
uint64_t required_size, max_size = crypt_get_data_offset(cd) * SECTOR_SIZE;
/* for detached headers max size == device size */
if (!max_size && (r = device_size(crypt_metadata_device(cd), &max_size)))
@@ -533,11 +539,18 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
log_dbg(cd, "Max size: %" PRIu64 ", LUKS1 (full) header size %zu , required shift: %zu",
max_size, luks1_size, luks1_shift);
if ((max_size - luks1_size) < luks1_shift) {
required_size = luks1_size + luks1_shift;
if ((max_size < required_size) &&
device_fallocate(crypt_metadata_device(cd), required_size)) {
log_err(cd, _("Unable to move keyslot area. Not enough space."));
return -EINVAL;
}
if (max_size < required_size)
max_size = required_size;
r = json_luks1_object(hdr1, &jobj, max_size - 2 * LUKS2_HDR_16K_LEN);
if (r < 0)
return r;
@@ -665,6 +678,11 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
if (!jobj_segment)
return -EINVAL;
if (json_segment_get_sector_size(jobj_segment) != SECTOR_SIZE) {
log_err(cd, _("Cannot convert to LUKS1 format - default segment encryption sector size is not 512 bytes."));
return -EINVAL;
}
json_object_object_get_ex(hdr2->jobj, "digests", &jobj1);
if (!json_object_object_get_ex(jobj_digest, "type", &jobj2) ||
strcmp(json_object_get_string(jobj2), "pbkdf2") ||

3445
lib/luks2/luks2_reencrypt.c Normal file

File diff suppressed because it is too large Load Diff

412
lib/luks2/luks2_segment.c Normal file
View File

@@ -0,0 +1,412 @@
/*
* LUKS - Linux Unified Key Setup v2, internal segment handling
*
* Copyright (C) 2018-2020, Red Hat, Inc. All rights reserved.
* Copyright (C) 2018-2020, Ondrej Kozina
*
* 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"
/* use only on already validated 'segments' object */
uint64_t json_segments_get_minimal_offset(json_object *jobj_segments, unsigned blockwise)
{
uint64_t tmp, min = blockwise ? UINT64_MAX >> SECTOR_SHIFT : UINT64_MAX;
if (!jobj_segments)
return 0;
json_object_object_foreach(jobj_segments, key, val) {
UNUSED(key);
if (json_segment_is_backup(val))
continue;
tmp = json_segment_get_offset(val, blockwise);
if (!tmp)
return tmp;
if (tmp < min)
min = tmp;
}
return min;
}
uint64_t json_segment_get_offset(json_object *jobj_segment, unsigned blockwise)
{
json_object *jobj;
if (!jobj_segment ||
!json_object_object_get_ex(jobj_segment, "offset", &jobj))
return 0;
return blockwise ? json_object_get_uint64(jobj) >> SECTOR_SHIFT : json_object_get_uint64(jobj);
}
const char *json_segment_type(json_object *jobj_segment)
{
json_object *jobj;
if (!jobj_segment ||
!json_object_object_get_ex(jobj_segment, "type", &jobj))
return NULL;
return json_object_get_string(jobj);
}
uint64_t json_segment_get_iv_offset(json_object *jobj_segment)
{
json_object *jobj;
if (!jobj_segment ||
!json_object_object_get_ex(jobj_segment, "iv_tweak", &jobj))
return 0;
return json_object_get_uint64(jobj);
}
uint64_t json_segment_get_size(json_object *jobj_segment, unsigned blockwise)
{
json_object *jobj;
if (!jobj_segment ||
!json_object_object_get_ex(jobj_segment, "size", &jobj))
return 0;
return blockwise ? json_object_get_uint64(jobj) >> SECTOR_SHIFT : json_object_get_uint64(jobj);
}
const char *json_segment_get_cipher(json_object *jobj_segment)
{
json_object *jobj;
/* FIXME: Pseudo "null" cipher should be handled elsewhere */
if (!jobj_segment ||
!json_object_object_get_ex(jobj_segment, "encryption", &jobj))
return "null";
return json_object_get_string(jobj);
}
int json_segment_get_sector_size(json_object *jobj_segment)
{
json_object *jobj;
if (!jobj_segment ||
!json_object_object_get_ex(jobj_segment, "sector_size", &jobj))
return -1;
return json_object_get_int(jobj);
}
static json_object *json_segment_get_flags(json_object *jobj_segment)
{
json_object *jobj;
if (!jobj_segment || !(json_object_object_get_ex(jobj_segment, "flags", &jobj)))
return NULL;
return jobj;
}
static 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);
if (!jobj_flags)
return false;
for (i = 0; i < (int)json_object_array_length(jobj_flags); i++) {
jobj = json_object_array_get_idx(jobj_flags, i);
if (len)
r = strncmp(json_object_get_string(jobj), flag_str, len);
else
r = strcmp(json_object_get_string(jobj), flag_str);
if (!r)
return true;
}
return false;
}
bool json_segment_is_backup(json_object *jobj_segment)
{
return json_segment_contains_flag(jobj_segment, "backup-", 7);
}
json_object *json_segments_get_segment(json_object *jobj_segments, int segment)
{
json_object *jobj;
char segment_name[16];
if (snprintf(segment_name, sizeof(segment_name), "%u", segment) < 1)
return NULL;
if (!json_object_object_get_ex(jobj_segments, segment_name, &jobj))
return NULL;
return jobj;
}
unsigned json_segments_count(json_object *jobj_segments)
{
unsigned count = 0;
if (!jobj_segments)
return 0;
json_object_object_foreach(jobj_segments, slot, val) {
UNUSED(slot);
if (!json_segment_is_backup(val))
count++;
}
return count;
}
static void _get_segment_or_id_by_flag(json_object *jobj_segments, const char *flag, unsigned id, void *retval)
{
json_object *jobj_flags, **jobj_ret = (json_object **)retval;
int *ret = (int *)retval;
if (!flag)
return;
json_object_object_foreach(jobj_segments, key, value) {
if (!json_object_object_get_ex(value, "flags", &jobj_flags))
continue;
if (LUKS2_array_jobj(jobj_flags, flag)) {
if (id)
*ret = atoi(key);
else
*jobj_ret = value;
return;
}
}
}
void json_segment_remove_flag(json_object *jobj_segment, const char *flag)
{
json_object *jobj_flags, *jobj_flags_new;
if (!jobj_segment)
return;
jobj_flags = json_segment_get_flags(jobj_segment);
if (!jobj_flags)
return;
jobj_flags_new = LUKS2_array_remove(jobj_flags, flag);
if (!jobj_flags_new)
return;
if (json_object_array_length(jobj_flags_new) <= 0) {
json_object_put(jobj_flags_new);
json_object_object_del(jobj_segment, "flags");
} else
json_object_object_add(jobj_segment, "flags", jobj_flags_new);
}
static json_object *_segment_create_generic(const char *type, uint64_t offset, const uint64_t *length)
{
json_object *jobj = json_object_new_object();
if (!jobj)
return NULL;
json_object_object_add(jobj, "type", json_object_new_string(type));
json_object_object_add(jobj, "offset", json_object_new_uint64(offset));
json_object_object_add(jobj, "size", length ? json_object_new_uint64(*length) : json_object_new_string("dynamic"));
return jobj;
}
json_object *json_segment_create_linear(uint64_t offset, const uint64_t *length, unsigned reencryption)
{
json_object *jobj = _segment_create_generic("linear", offset, length);
if (reencryption)
LUKS2_segment_set_flag(jobj, "in-reencryption");
return jobj;
}
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)
{
json_object *jobj = _segment_create_generic("crypt", offset, length);
if (!jobj)
return NULL;
json_object_object_add(jobj, "iv_tweak", json_object_new_uint64(iv_offset));
json_object_object_add(jobj, "encryption", json_object_new_string(cipher));
json_object_object_add(jobj, "sector_size", json_object_new_int(sector_size));
if (reencryption)
LUKS2_segment_set_flag(jobj, "in-reencryption");
return jobj;
}
uint64_t LUKS2_segment_offset(struct luks2_hdr *hdr, int segment, unsigned blockwise)
{
return json_segment_get_offset(LUKS2_get_segment_jobj(hdr, segment), blockwise);
}
int json_segments_segment_in_reencrypt(json_object *jobj_segments)
{
json_object *jobj_flags;
json_object_object_foreach(jobj_segments, slot, val) {
if (!json_object_object_get_ex(val, "flags", &jobj_flags) ||
!LUKS2_array_jobj(jobj_flags, "in-reencryption"))
continue;
return atoi(slot);
}
return -1;
}
uint64_t LUKS2_segment_size(struct luks2_hdr *hdr, int segment, unsigned blockwise)
{
return json_segment_get_size(LUKS2_get_segment_jobj(hdr, segment), blockwise);
}
int LUKS2_segment_is_type(struct luks2_hdr *hdr, int segment, const char *type)
{
return !strcmp(json_segment_type(LUKS2_get_segment_jobj(hdr, segment)) ?: "", type);
}
int LUKS2_last_segment_by_type(struct luks2_hdr *hdr, const char *type)
{
json_object *jobj_segments;
int last_found = -1;
if (!type)
return -1;
if (!json_object_object_get_ex(hdr->jobj, "segments", &jobj_segments))
return -1;
json_object_object_foreach(jobj_segments, slot, val) {
if (json_segment_is_backup(val))
continue;
if (strcmp(type, json_segment_type(val) ?: ""))
continue;
if (atoi(slot) > last_found)
last_found = atoi(slot);
}
return last_found;
}
int LUKS2_segment_by_type(struct luks2_hdr *hdr, const char *type)
{
json_object *jobj_segments;
int first_found = -1;
if (!type)
return -EINVAL;
if (!json_object_object_get_ex(hdr->jobj, "segments", &jobj_segments))
return -EINVAL;
json_object_object_foreach(jobj_segments, slot, val) {
if (json_segment_is_backup(val))
continue;
if (strcmp(type, json_segment_type(val) ?: ""))
continue;
if (first_found < 0)
first_found = atoi(slot);
else if (atoi(slot) < first_found)
first_found = atoi(slot);
}
return first_found;
}
int LUKS2_segment_first_unused_id(struct luks2_hdr *hdr)
{
json_object *jobj_segments;
int id, last_id = -1;
if (!json_object_object_get_ex(hdr->jobj, "segments", &jobj_segments))
return -EINVAL;
json_object_object_foreach(jobj_segments, slot, val) {
UNUSED(val);
id = atoi(slot);
if (id > last_id)
last_id = id;
}
return last_id + 1;
}
int LUKS2_segment_set_flag(json_object *jobj_segment, const char *flag)
{
json_object *jobj_flags;
if (!jobj_segment || !flag)
return -EINVAL;
if (!json_object_object_get_ex(jobj_segment, "flags", &jobj_flags)) {
jobj_flags = json_object_new_array();
if (!jobj_flags)
return -ENOMEM;
json_object_object_add(jobj_segment, "flags", jobj_flags);
}
if (LUKS2_array_jobj(jobj_flags, flag))
return 0;
json_object_array_add(jobj_flags, json_object_new_string(flag));
return 0;
}
int LUKS2_segments_set(struct crypt_device *cd, struct luks2_hdr *hdr,
json_object *jobj_segments, int commit)
{
json_object_object_add(hdr->jobj, "segments", jobj_segments);
return commit ? LUKS2_hdr_write(cd, hdr) : 0;
}
int LUKS2_get_segment_id_by_flag(struct luks2_hdr *hdr, const char *flag)
{
int ret = -ENOENT;
json_object *jobj_segments = LUKS2_get_segments_jobj(hdr);
if (jobj_segments)
_get_segment_or_id_by_flag(jobj_segments, flag, 1, &ret);
return ret;
}
json_object *LUKS2_get_segment_by_flag(struct luks2_hdr *hdr, const char *flag)
{
json_object *jobj_segment = NULL,
*jobj_segments = LUKS2_get_segments_jobj(hdr);
if (jobj_segments)
_get_segment_or_id_by_flag(jobj_segments, flag, 0, &jobj_segment);
return jobj_segment;
}

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, token handling
*
* Copyright (C) 2016-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2019 Milan Broz
* Copyright (C) 2016-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2020 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -332,7 +332,7 @@ static void LUKS2_token_buffer_free(struct crypt_device *cd,
if (h->buffer_free)
h->buffer_free(buffer, buffer_len);
else {
crypt_memzero(buffer, buffer_len);
crypt_safe_memzero(buffer, buffer_len);
free(buffer);
}
}
@@ -347,7 +347,7 @@ static int LUKS2_keyslot_open_by_token(struct crypt_device *cd,
{
const crypt_token_handler *h;
json_object *jobj_token, *jobj_token_keyslots, *jobj;
const char *num = NULL;
unsigned int num = 0;
int i, r;
if (!(h = LUKS2_token_handler(cd, token)))
@@ -365,15 +365,15 @@ static int LUKS2_keyslot_open_by_token(struct crypt_device *cd,
r = -EINVAL;
for (i = 0; i < (int) json_object_array_length(jobj_token_keyslots) && r < 0; i++) {
jobj = json_object_array_get_idx(jobj_token_keyslots, i);
num = json_object_get_string(jobj);
log_dbg(cd, "Trying to open keyslot %s with token %d (type %s).", num, token, h->name);
r = LUKS2_keyslot_open(cd, atoi(num), segment, buffer, buffer_len, vk);
num = atoi(json_object_get_string(jobj));
log_dbg(cd, "Trying to open keyslot %u with token %d (type %s).", num, token, h->name);
r = LUKS2_keyslot_open(cd, num, segment, buffer, buffer_len, vk);
}
if (r >= 0 && num)
return atoi(num);
if (r < 0)
return r;
return r;
return num;
}
int LUKS2_token_open_and_activate(struct crypt_device *cd,
@@ -404,14 +404,16 @@ int LUKS2_token_open_and_activate(struct crypt_device *cd,
keyslot = r;
if ((name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd))
r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd, hdr, vk, keyslot);
if ((name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd)) {
if (!(r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd, hdr, vk, keyslot)))
flags |= CRYPT_ACTIVATE_KEYRING_KEY;
}
if (r >= 0 && name)
r = LUKS2_activate(cd, name, vk, flags);
if (r < 0 && vk)
crypt_drop_keyring_key(cd, vk->key_description);
if (r < 0)
crypt_drop_keyring_key(cd, vk);
crypt_free_volume_key(vk);
return r < 0 ? r : keyslot;
@@ -449,14 +451,16 @@ int LUKS2_token_open_and_activate_any(struct crypt_device *cd,
keyslot = r;
if (r >= 0 && (name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd))
r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd, hdr, vk, keyslot);
if (r >= 0 && (name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd)) {
if (!(r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd, hdr, vk, keyslot)))
flags |= CRYPT_ACTIVATE_KEYRING_KEY;
}
if (r >= 0 && name)
r = LUKS2_activate(cd, name, vk, flags);
if (r < 0 && vk)
crypt_drop_keyring_key(cd, vk->key_description);
if (r < 0)
crypt_drop_keyring_key(cd, vk);
crypt_free_volume_key(vk);
return r < 0 ? r : keyslot;

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, kernel keyring token
*
* Copyright (C) 2016-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2019 Ondrej Kozina
* Copyright (C) 2016-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2020 Ondrej Kozina
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

View File

@@ -1,7 +1,7 @@
/*
* cryptsetup kernel RNG access functions
*
* Copyright (C) 2010-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2020 Red Hat, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
/*
* TCRYPT (TrueCrypt-compatible) and VeraCrypt volume handling
*
* Copyright (C) 2012-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2019 Milan Broz
* Copyright (C) 2012-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2020 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -301,8 +301,8 @@ static int decrypt_blowfish_le_cbc(struct tcrypt_alg *alg,
}
crypt_cipher_destroy(cipher);
crypt_memzero(iv, bs);
crypt_memzero(iv_old, bs);
crypt_safe_memzero(iv, bs);
crypt_safe_memzero(iv_old, bs);
return r;
}
@@ -369,8 +369,8 @@ static int TCRYPT_decrypt_hdr_one(struct tcrypt_alg *alg, const char *mode,
crypt_cipher_destroy(cipher);
}
crypt_memzero(backend_key, sizeof(backend_key));
crypt_memzero(iv, TCRYPT_HDR_IV_LEN);
crypt_safe_memzero(backend_key, sizeof(backend_key));
crypt_safe_memzero(iv, TCRYPT_HDR_IV_LEN);
return r;
}
@@ -420,8 +420,8 @@ out:
if (cipher[j])
crypt_cipher_destroy(cipher[j]);
crypt_memzero(iv, bs);
crypt_memzero(iv_old, bs);
crypt_safe_memzero(iv, bs);
crypt_safe_memzero(iv_old, bs);
return r;
}
@@ -474,7 +474,7 @@ static int TCRYPT_decrypt_hdr(struct crypt_device *cd, struct tcrypt_phdr *hdr,
r = -EPERM;
}
crypt_memzero(&hdr2, sizeof(hdr2));
crypt_safe_memzero(&hdr2, sizeof(hdr2));
return r;
}
@@ -516,8 +516,8 @@ static int TCRYPT_pool_keyfile(struct crypt_device *cd,
}
r = 0;
out:
crypt_memzero(&crc, sizeof(crc));
crypt_memzero(data, TCRYPT_KEYFILE_LEN);
crypt_safe_memzero(&crc, sizeof(crc));
crypt_safe_memzero(data, TCRYPT_KEYFILE_LEN);
free(data);
return r;
@@ -582,13 +582,11 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
hdr->salt, TCRYPT_HDR_SALT_LEN,
key, TCRYPT_HDR_KEY_LEN,
iterations, 0, 0);
if (r < 0 && crypt_hash_size(tcrypt_kdf[i].hash) < 0) {
if (r < 0) {
log_verbose(cd, _("PBKDF2 hash algorithm %s not available, skipping."),
tcrypt_kdf[i].hash);
continue;
}
if (r < 0)
break;
/* Decrypt header */
r = TCRYPT_decrypt_hdr(cd, hdr, key, params->flags);
@@ -621,9 +619,9 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
params->cipher, params->mode, params->key_size);
}
out:
crypt_memzero(pwd, TCRYPT_KEY_POOL_LEN);
crypt_safe_memzero(pwd, TCRYPT_KEY_POOL_LEN);
if (key)
crypt_memzero(key, TCRYPT_HDR_KEY_LEN);
crypt_safe_memzero(key, TCRYPT_HDR_KEY_LEN);
free(key);
return r;
}
@@ -632,10 +630,10 @@ int TCRYPT_read_phdr(struct crypt_device *cd,
struct tcrypt_phdr *hdr,
struct crypt_params_tcrypt *params)
{
struct device *base_device, *device = crypt_metadata_device(cd);
struct device *base_device = NULL, *device = crypt_metadata_device(cd);
ssize_t hdr_size = sizeof(struct tcrypt_phdr);
char *base_device_path;
int devfd = 0, r;
int devfd, r;
assert(sizeof(struct tcrypt_phdr) == 512);
@@ -655,11 +653,11 @@ int TCRYPT_read_phdr(struct crypt_device *cd,
if (r < 0)
return r;
devfd = device_open(cd, base_device, O_RDONLY);
device_free(cd, base_device);
} else
devfd = device_open(cd, device, O_RDONLY);
if (devfd < 0) {
device_free(cd, base_device);
log_err(cd, _("Cannot open device %s."), device_path(device));
return -EINVAL;
}
@@ -692,11 +690,11 @@ int TCRYPT_read_phdr(struct crypt_device *cd,
device_alignment(device), hdr, hdr_size,
TCRYPT_HDR_OFFSET_BCK) == hdr_size)
r = TCRYPT_init_hdr(cd, hdr, params);
} else if (read_blockwise(devfd, device_block_size(cd, device),
device_alignment(device), hdr, hdr_size) == hdr_size)
} else if (read_lseek_blockwise(devfd, device_block_size(cd, device),
device_alignment(device), hdr, hdr_size, 0) == hdr_size)
r = TCRYPT_init_hdr(cd, hdr, params);
close(devfd);
device_free(cd, base_device);
if (r < 0)
memset(hdr, 0, sizeof (*hdr));
return r;
@@ -749,7 +747,7 @@ int TCRYPT_activate(struct crypt_device *cd,
}
if (strstr(params->mode, "-tcrypt")) {
log_err(cd, _("Kernel doesn't support activation for this TCRYPT legacy mode."));
log_err(cd, _("Kernel does not support activation for this TCRYPT legacy mode."));
return -ENOTSUP;
}
@@ -861,7 +859,7 @@ int TCRYPT_activate(struct crypt_device *cd,
if (r < 0 &&
(dm_flags(cd, DM_CRYPT, &dmc_flags) || ((dmc_flags & req_flags) != req_flags))) {
log_err(cd, _("Kernel doesn't support TCRYPT compatible mapping."));
log_err(cd, _("Kernel does not support TCRYPT compatible mapping."));
r = -ENOTSUP;
}
@@ -920,9 +918,10 @@ out:
}
static int TCRYPT_status_one(struct crypt_device *cd, const char *name,
const char *base_uuid, int index,
size_t *key_size, char *cipher,
uint64_t *data_offset, struct device **device)
const char *base_uuid, int index,
size_t *key_size, char *cipher,
struct tcrypt_phdr *tcrypt_hdr,
struct device **device)
{
struct crypt_dm_active_device dmd;
struct dm_target *tgt = &dmd.segment;
@@ -955,7 +954,7 @@ static int TCRYPT_status_one(struct crypt_device *cd, const char *name,
strcat(cipher, "-");
strncat(cipher, tgt->u.crypt.cipher, MAX_CIPHER_LEN);
*key_size += tgt->u.crypt.vk->keylength;
*data_offset = tgt->u.crypt.offset * SECTOR_SIZE;
tcrypt_hdr->d.mk_offset = tgt->u.crypt.offset * SECTOR_SIZE;
device_free(cd, *device);
MOVE_REF(*device, tgt->data_device);
} else
@@ -993,10 +992,10 @@ int TCRYPT_init_by_name(struct crypt_device *cd, const char *name,
key_size = tgt->u.crypt.vk->keylength;
r = TCRYPT_status_one(cd, name, uuid, 1, &key_size,
cipher, &tcrypt_hdr->d.mk_offset, device);
cipher, tcrypt_hdr, device);
if (!r)
r = TCRYPT_status_one(cd, name, uuid, 2, &key_size,
cipher, &tcrypt_hdr->d.mk_offset, device);
cipher, tcrypt_hdr, device);
if (r < 0 && r != -ENODEV)
return r;

View File

@@ -1,8 +1,8 @@
/*
* TCRYPT (TrueCrypt-compatible) header defitinion
* TCRYPT (TrueCrypt-compatible) header definition
*
* Copyright (C) 2012-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2019 Milan Broz
* Copyright (C) 2012-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2020 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

View File

@@ -3,8 +3,8 @@
*
* Copyright (C) 2004 Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2019 Milan Broz
* Copyright (C) 2009-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2020 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -130,7 +130,7 @@ static int keyfile_seek(int fd, uint64_t bytes)
if (errno == EINTR)
continue;
crypt_memzero(tmp, sizeof(tmp));
crypt_safe_memzero(tmp, sizeof(tmp));
/* read error */
return -1;
}
@@ -142,7 +142,7 @@ static int keyfile_seek(int fd, uint64_t bytes)
bytes -= bytes_r;
}
crypt_memzero(tmp, sizeof(tmp));
crypt_safe_memzero(tmp, sizeof(tmp));
return bytes == 0 ? 0 : -1;
}
@@ -181,7 +181,7 @@ int crypt_keyfile_device_read(struct crypt_device *cd, const char *keyfile,
key_size = DEFAULT_KEYFILE_SIZE_MAXKB * 1024 + 1;
unlimited_read = 1;
/* use 4k for buffer (page divisor but avoid huge pages) */
buflen = 4096 - sizeof(struct safe_allocation);
buflen = 4096 - sizeof(size_t); // sizeof(struct safe_allocation);
} else
buflen = key_size;
@@ -323,3 +323,24 @@ int kernel_version(uint64_t *kversion)
return r;
}
bool crypt_string_in(const char *str, char **list, size_t list_size)
{
size_t i;
for (i = 0; *list && i < list_size; i++, list++)
if (!strcmp(str, *list))
return true;
return false;
}
/* compare two strings (allows NULL values) */
int crypt_strcmp(const char *a, const char *b)
{
if (!a && !b)
return 0;
else if (!a || !b)
return 1;
return strcmp(a, b);
}

View File

@@ -1,8 +1,8 @@
/*
* libcryptsetup - cryptsetup library, cipher benchmark
*
* Copyright (C) 2012-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2019 Milan Broz
* Copyright (C) 2012-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2020 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -21,167 +21,9 @@
#include <stdlib.h>
#include <errno.h>
#include <time.h>
#include "internal.h"
/*
* This is not simulating storage, so using disk block causes extreme overhead.
* Let's use some fixed block size where results are more reliable...
*/
#define CIPHER_BLOCK_BYTES 65536
/*
* If the measured value is lower, encrypted buffer is probably too small
* and calculated values are not reliable.
*/
#define CIPHER_TIME_MIN_MS 0.001
/*
* The whole test depends on Linux kernel usermode crypto API for now.
* (The same implementations are used in dm-crypt though.)
*/
struct cipher_perf {
char name[32];
char mode[32];
char *key;
size_t key_length;
char *iv;
size_t iv_length;
size_t buffer_size;
};
static int time_ms(struct timespec *start, struct timespec *end, double *ms)
{
double start_ms, end_ms;
start_ms = start->tv_sec * 1000.0 + start->tv_nsec / (1000.0 * 1000);
end_ms = end->tv_sec * 1000.0 + end->tv_nsec / (1000.0 * 1000);
*ms = end_ms - start_ms;
return 0;
}
static int cipher_perf_one(struct crypt_device *cd,
struct cipher_perf *cp, char *buf,
size_t buf_size, int enc)
{
struct crypt_cipher *cipher = NULL;
size_t done = 0, block = CIPHER_BLOCK_BYTES;
int r;
if (buf_size < block)
block = buf_size;
r = crypt_cipher_init(&cipher, cp->name, cp->mode, cp->key, cp->key_length);
if (r < 0) {
log_dbg(cd, "Cannot initialise cipher %s, mode %s.", cp->name, cp->mode);
return r;
}
while (done < buf_size) {
if ((done + block) > buf_size)
block = buf_size - done;
if (enc)
r = crypt_cipher_encrypt(cipher, &buf[done], &buf[done],
block, cp->iv, cp->iv_length);
else
r = crypt_cipher_decrypt(cipher, &buf[done], &buf[done],
block, cp->iv, cp->iv_length);
if (r < 0)
break;
done += block;
}
crypt_cipher_destroy(cipher);
return r;
}
static int cipher_measure(struct crypt_device *cd,
struct cipher_perf *cp, char *buf,
size_t buf_size, int encrypt, double *ms)
{
struct timespec start, end;
int r;
/*
* Using getrusage would be better here but the precision
* is not adequate, so better stick with CLOCK_MONOTONIC
*/
if (clock_gettime(CLOCK_MONOTONIC, &start) < 0)
return -EINVAL;
r = cipher_perf_one(cd, cp, buf, buf_size, encrypt);
if (r < 0)
return r;
if (clock_gettime(CLOCK_MONOTONIC, &end) < 0)
return -EINVAL;
r = time_ms(&start, &end, ms);
if (r < 0)
return r;
if (*ms < CIPHER_TIME_MIN_MS) {
log_dbg(cd, "Measured cipher runtime (%1.6f) is too low.", *ms);
return -ERANGE;
}
return 0;
}
static double speed_mbs(unsigned long bytes, double ms)
{
double speed = bytes, s = ms / 1000.;
return speed / (1024 * 1024) / s;
}
static int cipher_perf(struct crypt_device *cd, struct cipher_perf *cp,
double *encryption_mbs, double *decryption_mbs)
{
double ms_enc, ms_dec, ms;
int r, repeat_enc, repeat_dec;
void *buf = NULL;
if (posix_memalign(&buf, crypt_getpagesize(), cp->buffer_size))
return -ENOMEM;
ms_enc = 0.0;
repeat_enc = 1;
while (ms_enc < 1000.0) {
r = cipher_measure(cd, cp, buf, cp->buffer_size, 1, &ms);
if (r < 0) {
free(buf);
return r;
}
ms_enc += ms;
repeat_enc++;
}
ms_dec = 0.0;
repeat_dec = 1;
while (ms_dec < 1000.0) {
r = cipher_measure(cd, cp, buf, cp->buffer_size, 0, &ms);
if (r < 0) {
free(buf);
return r;
}
ms_dec += ms;
repeat_dec++;
}
free(buf);
*encryption_mbs = speed_mbs(cp->buffer_size * repeat_enc, ms_enc);
*decryption_mbs = speed_mbs(cp->buffer_size * repeat_dec, ms_dec);
return 0;
}
int crypt_benchmark(struct crypt_device *cd,
const char *cipher,
const char *cipher_mode,
@@ -191,12 +33,8 @@ int crypt_benchmark(struct crypt_device *cd,
double *encryption_mbs,
double *decryption_mbs)
{
struct cipher_perf cp = {
.key_length = volume_key_size,
.iv_length = iv_size,
.buffer_size = buffer_size,
};
char *c;
void *buffer = NULL;
char *iv = NULL, *key = NULL, mode[MAX_CIPHER_LEN], *c;
int r;
if (!cipher || !cipher_mode || !volume_key_size || !encryption_mbs || !decryption_mbs)
@@ -207,29 +45,40 @@ int crypt_benchmark(struct crypt_device *cd,
return r;
r = -ENOMEM;
if (iv_size) {
cp.iv = malloc(iv_size);
if (!cp.iv)
goto out;
crypt_random_get(cd, cp.iv, iv_size, CRYPT_RND_NORMAL);
}
cp.key = malloc(volume_key_size);
if (!cp.key)
if (posix_memalign(&buffer, crypt_getpagesize(), buffer_size))
goto out;
crypt_random_get(cd, cp.key, volume_key_size, CRYPT_RND_NORMAL);
strncpy(cp.name, cipher, sizeof(cp.name)-1);
strncpy(cp.mode, cipher_mode, sizeof(cp.mode)-1);
if (iv_size) {
iv = malloc(iv_size);
if (!iv)
goto out;
crypt_random_get(cd, iv, iv_size, CRYPT_RND_NORMAL);
}
key = malloc(volume_key_size);
if (!key)
goto out;
crypt_random_get(cd, key, volume_key_size, CRYPT_RND_NORMAL);
strncpy(mode, cipher_mode, sizeof(mode)-1);
/* Ignore IV generator */
if ((c = strchr(cp.mode, '-')))
if ((c = strchr(mode, '-')))
*c = '\0';
r = cipher_perf(cd, &cp, encryption_mbs, decryption_mbs);
r = crypt_cipher_perf_kernel(cipher, cipher_mode, buffer, buffer_size, key, volume_key_size,
iv, iv_size, encryption_mbs, decryption_mbs);
if (r == -ERANGE)
log_dbg(cd, "Measured cipher runtime is too low.");
else if (r == -ENOTSUP || r == -ENOENT)
log_dbg(cd, "Cannot initialize cipher %s, mode %s.", cipher, cipher_mode);
out:
free(cp.key);
free(cp.iv);
free(buffer);
free(key);
free(iv);
return r;
}

View File

@@ -1,7 +1,7 @@
/*
* blkid probe utilities
*
* Copyright (C) 2018-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2018-2020 Red Hat, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -307,3 +307,17 @@ int blk_supported(void)
#endif
return r;
}
off_t blk_get_offset(struct blkid_handle *h)
{
const char *offset;
off_t offset_value = -1;
#ifdef HAVE_BLKID
if (blk_is_superblock(h)) {
if (!blkid_probe_lookup_value(h->pr, "SBMAGIC_OFFSET", &offset, NULL))
offset_value = strtoll(offset, NULL, 10);
} else if (blk_is_partition(h) && !blkid_probe_lookup_value(h->pr, "PTMAGIC_OFFSET", &offset, NULL))
offset_value = strtoll(offset, NULL, 10);
#endif
return offset_value;
}

View File

@@ -1,7 +1,7 @@
/*
* blkid probe utilities
*
* Copyright (C) 2018-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2018-2020 Red Hat, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -59,4 +59,6 @@ int blk_do_wipe(struct blkid_handle *h);
int blk_supported(void);
off_t blk_get_offset(struct blkid_handle *h);
#endif

View File

@@ -2,8 +2,8 @@
* utils_crypt - cipher utilities for cryptsetup
*
* Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2019 Milan Broz
* Copyright (C) 2009-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2020 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -149,79 +149,6 @@ int crypt_parse_pbkdf(const char *s, const char **pbkdf)
return 0;
}
/*
* Replacement for memset(s, 0, n) on stack that can be optimized out
* Also used in safe allocations for explicit memory wipe.
*/
void crypt_memzero(void *s, size_t n)
{
#ifdef HAVE_EXPLICIT_BZERO
explicit_bzero(s, n);
#else
volatile uint8_t *p = (volatile uint8_t *)s;
while(n--)
*p++ = 0;
#endif
}
/* safe allocations */
void *crypt_safe_alloc(size_t size)
{
struct safe_allocation *alloc;
if (!size || size > (SIZE_MAX - offsetof(struct safe_allocation, data)))
return NULL;
alloc = malloc(size + offsetof(struct safe_allocation, data));
if (!alloc)
return NULL;
alloc->size = size;
crypt_memzero(&alloc->data, size);
/* coverity[leaked_storage] */
return &alloc->data;
}
void crypt_safe_free(void *data)
{
struct safe_allocation *alloc;
if (!data)
return;
alloc = (struct safe_allocation *)
((char *)data - offsetof(struct safe_allocation, data));
crypt_memzero(data, alloc->size);
alloc->size = 0x55aa55aa;
free(alloc);
}
void *crypt_safe_realloc(void *data, size_t size)
{
struct safe_allocation *alloc;
void *new_data;
new_data = crypt_safe_alloc(size);
if (new_data && data) {
alloc = (struct safe_allocation *)
((char *)data - offsetof(struct safe_allocation, data));
if (size > alloc->size)
size = alloc->size;
memcpy(new_data, data, size);
}
crypt_safe_free(data);
return new_data;
}
ssize_t crypt_hex_to_bytes(const char *hex, char **result, int safe_alloc)
{
char buf[3] = "xx\0", *endp, *bytes;

View File

@@ -2,8 +2,8 @@
* utils_crypt - cipher utilities for cryptsetup
*
* Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2019 Milan Broz
* Copyright (C) 2009-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2020 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -29,14 +29,6 @@
#define MAX_CIPHER_LEN_STR "31"
#define MAX_KEYFILES 32
struct crypt_device;
/* Not to be used directly */
struct safe_allocation {
size_t size;
char data[0];
};
int crypt_parse_name_and_mode(const char *s, char *cipher,
int *key_nums, char *cipher_mode);
int crypt_parse_hash_integrity_mode(const char *s, char *integrity);
@@ -44,12 +36,6 @@ int crypt_parse_integrity_mode(const char *s, char *integrity,
int *integrity_key_size);
int crypt_parse_pbkdf(const char *s, const char **pbkdf);
void *crypt_safe_alloc(size_t size);
void crypt_safe_free(void *data);
void *crypt_safe_realloc(void *data, size_t size);
void crypt_memzero(void *s, size_t n);
ssize_t crypt_hex_to_bytes(const char *hex, char **result, int safe_alloc);
#endif /* _UTILS_CRYPT_H */

View File

@@ -3,8 +3,8 @@
*
* Copyright (C) 2004 Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2019 Milan Broz
* Copyright (C) 2009-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2020 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -46,6 +46,10 @@ struct device {
char *file_path;
int loop_fd;
int ro_dev_fd;
int dev_fd;
int dev_fd_excl;
struct crypt_lock_handle *lh;
unsigned int o_direct:1;
@@ -141,14 +145,14 @@ static int device_read_test(int devfd)
if (read_blockwise(devfd, blocksize, alignment, buffer, minsize) == (ssize_t)minsize)
r = 0;
crypt_memzero(buffer, sizeof(buffer));
crypt_safe_memzero(buffer, sizeof(buffer));
return r;
}
/*
* The direct-io is always preferred. The header is usually mapped to the same
* device and can be accessed when the rest of device is mapped to data device.
* Using dirct-io encsures that we do not mess with data in cache.
* Using direct-io ensures that we do not mess with data in cache.
* (But proper alignment should prevent this in the first place.)
* The read test is needed to detect broken configurations (seen with remote
* block devices) that allow open with direct-io but then fails on read.
@@ -181,7 +185,7 @@ static int device_ready(struct crypt_device *cd, struct device *device)
}
if (devfd < 0) {
log_err(cd, _("Device %s doesn't exist or access denied."),
log_err(cd, _("Device %s does not exist or access denied."),
device_path(device));
return -EINVAL;
}
@@ -217,7 +221,7 @@ static int _open_locked(struct crypt_device *cd, struct device *device, int flag
log_dbg(cd, "Opening locked device %s", device_path(device));
if ((flags & O_ACCMODE) != O_RDONLY && device_locked_readonly(device->lh)) {
log_dbg(cd, "Can not open locked device %s in write mode. Read lock held.", device_path(device));
log_dbg(cd, "Cannot open locked device %s in write mode. Read lock held.", device_path(device));
return -EAGAIN;
}
@@ -237,11 +241,13 @@ static int _open_locked(struct crypt_device *cd, struct device *device, int flag
/*
* Common wrapper for device sync.
* FIXME: file descriptor will be in struct later.
*/
void device_sync(struct crypt_device *cd, struct device *device, int devfd)
void device_sync(struct crypt_device *cd, struct device *device)
{
if (fsync(devfd) == -1)
if (!device || device->dev_fd < 0)
return;
if (fsync(device->dev_fd) == -1)
log_dbg(cd, "Cannot sync device %s.", device_path(device));
}
@@ -256,20 +262,39 @@ void device_sync(struct crypt_device *cd, struct device *device, int devfd)
*/
static int device_open_internal(struct crypt_device *cd, struct device *device, int flags)
{
int devfd;
int access, devfd;
if (device->o_direct)
flags |= O_DIRECT;
access = flags & O_ACCMODE;
if (access == O_WRONLY)
access = O_RDWR;
if (access == O_RDONLY && device->ro_dev_fd >= 0) {
log_dbg(cd, "Reusing open r%c fd on device %s", 'o', device_path(device));
return device->ro_dev_fd;
} else if (access == O_RDWR && device->dev_fd >= 0) {
log_dbg(cd, "Reusing open r%c fd on device %s", 'w', device_path(device));
return device->dev_fd;
}
if (device_locked(device->lh))
devfd = _open_locked(cd, device, flags);
else
devfd = open(device_path(device), flags);
if (devfd < 0)
if (devfd < 0) {
log_dbg(cd, "Cannot open device %s%s.",
device_path(device),
(flags & O_ACCMODE) != O_RDONLY ? " for write" : "");
access != O_RDONLY ? " for write" : "");
return devfd;
}
if (access == O_RDONLY)
device->ro_dev_fd = devfd;
else
device->dev_fd = devfd;
return devfd;
}
@@ -280,6 +305,54 @@ int device_open(struct crypt_device *cd, struct device *device, int flags)
return device_open_internal(cd, device, flags);
}
int device_open_excl(struct crypt_device *cd, struct device *device, int flags)
{
const char *path;
struct stat st;
if (!device)
return -EINVAL;
assert(!device_locked(device->lh));
if (device->dev_fd_excl < 0) {
path = device_path(device);
if (stat(path, &st))
return -EINVAL;
if (!S_ISBLK(st.st_mode))
log_dbg(cd, "%s is not a block device. Can't open in exclusive mode.",
path);
else {
/* open(2) with O_EXCL (w/o O_CREAT) on regular file is undefined behaviour according to man page */
/* coverity[toctou] */
device->dev_fd_excl = open(path, O_RDONLY | O_EXCL);
if (device->dev_fd_excl < 0)
return errno == EBUSY ? -EBUSY : device->dev_fd_excl;
if (fstat(device->dev_fd_excl, &st) || !S_ISBLK(st.st_mode)) {
log_dbg(cd, "%s is not a block device. Can't open in exclusive mode.",
path);
close(device->dev_fd_excl);
device->dev_fd_excl = -1;
} else
log_dbg(cd, "Device %s is blocked for exclusive open.", path);
}
}
return device_open_internal(cd, device, flags);
}
void device_release_excl(struct crypt_device *cd, struct device *device)
{
if (device && device->dev_fd_excl >= 0) {
if (close(device->dev_fd_excl))
log_dbg(cd, "Failed to release exclusive handle on device %s.",
device_path(device));
else
log_dbg(cd, "Closed exclusive fd for %s.", device_path(device));
device->dev_fd_excl = -1;
}
}
int device_open_locked(struct crypt_device *cd, struct device *device, int flags)
{
assert(!crypt_metadata_locking_enabled() || device_locked(device->lh));
@@ -307,6 +380,9 @@ int device_alloc_no_check(struct device **device, const char *path)
return -ENOMEM;
}
dev->loop_fd = -1;
dev->ro_dev_fd = -1;
dev->dev_fd = -1;
dev->dev_fd_excl = -1;
dev->o_direct = 1;
*device = dev;
@@ -344,12 +420,19 @@ void device_free(struct crypt_device *cd, struct device *device)
if (!device)
return;
device_close(cd, device);
if (device->dev_fd_excl != -1) {
log_dbg(cd, "Closed exclusive fd for %s.", device_path(device));
close(device->dev_fd_excl);
}
if (device->loop_fd != -1) {
log_dbg(cd, "Closed loop %s (%s).", device->path, device->file_path);
close(device->loop_fd);
}
assert (!device_locked(device->lh));
assert(!device_locked(device->lh));
free(device->file_path);
free(device->path);
@@ -675,7 +758,7 @@ static int device_internal_prepare(struct crypt_device *cd, struct device *devic
log_dbg(cd, "Allocating a free loop device.");
/* Keep the loop open, dettached on last close. */
/* Keep the loop open, detached on last close. */
loop_fd = crypt_loop_attach(&loop_device, device->path, 0, 1, &readonly);
if (loop_fd == -1) {
log_err(cd, _("Attaching loopback device failed "
@@ -829,21 +912,25 @@ size_t device_alignment(struct device *device)
return device->alignment;
}
void device_set_lock_handle(struct device *device, struct crypt_lock_handle *h)
{
device->lh = h;
}
struct crypt_lock_handle *device_get_lock_handle(struct device *device)
{
return device->lh;
}
int device_read_lock(struct crypt_device *cd, struct device *device)
{
if (!crypt_metadata_locking_enabled())
return 0;
assert(!device_locked(device->lh));
if (device_read_lock_internal(cd, device))
return -EBUSY;
device->lh = device_read_lock_handle(cd, device_path(device));
if (device_locked(device->lh)) {
log_dbg(cd, "Device %s READ lock taken.", device_path(device));
return 0;
}
return -EBUSY;
return 0;
}
int device_write_lock(struct crypt_device *cd, struct device *device)
@@ -851,16 +938,9 @@ int device_write_lock(struct crypt_device *cd, struct device *device)
if (!crypt_metadata_locking_enabled())
return 0;
assert(!device_locked(device->lh));
assert(!device_locked(device->lh) || !device_locked_readonly(device->lh));
device->lh = device_write_lock_handle(cd, device_path(device));
if (device_locked(device->lh)) {
log_dbg(cd, "Device %s WRITE lock taken.", device_path(device));
return 0;
}
return -EBUSY;
return device_write_lock_internal(cd, device);
}
void device_read_unlock(struct crypt_device *cd, struct device *device)
@@ -868,13 +948,9 @@ void device_read_unlock(struct crypt_device *cd, struct device *device)
if (!crypt_metadata_locking_enabled())
return;
assert(device_locked(device->lh) && device_locked_readonly(device->lh));
assert(device_locked(device->lh));
device_unlock_handle(cd, device->lh);
log_dbg(cd, "Device %s READ lock released.", device_path(device));
device->lh = NULL;
device_unlock_internal(cd, device);
}
void device_write_unlock(struct crypt_device *cd, struct device *device)
@@ -884,9 +960,30 @@ void device_write_unlock(struct crypt_device *cd, struct device *device)
assert(device_locked(device->lh) && !device_locked_readonly(device->lh));
device_unlock_handle(cd, device->lh);
log_dbg(cd, "Device %s WRITE lock released.", device_path(device));
device->lh = NULL;
device_unlock_internal(cd, device);
}
bool device_is_locked(struct device *device)
{
return device ? device_locked(device->lh) : 0;
}
void device_close(struct crypt_device *cd, struct device *device)
{
if (!device)
return;
if (device->ro_dev_fd != -1) {
log_dbg(cd, "Closing read only fd for %s.", device_path(device));
if (close(device->ro_dev_fd))
log_dbg(cd, "Failed to close read only fd for %s.", device_path(device));
device->ro_dev_fd = -1;
}
if (device->dev_fd != -1) {
log_dbg(cd, "Closing read write fd for %s.", device_path(device));
if (close(device->dev_fd))
log_dbg(cd, "Failed to close read write fd for %s.", device_path(device));
device->dev_fd = -1;
}
}

View File

@@ -1,8 +1,8 @@
/*
* Metadata on-disk locking for processes serialization
*
* Copyright (C) 2016-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2019 Ondrej Kozina
* Copyright (C) 2016-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2020 Ondrej Kozina
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -33,6 +33,7 @@
# include <sys/sysmacros.h> /* for major, minor */
#endif
#include <libgen.h>
#include <assert.h>
#include "internal.h"
#include "utils_device_locking.h"
@@ -41,22 +42,44 @@
((buf1).st_ino == (buf2).st_ino && \
(buf1).st_dev == (buf2).st_dev)
#ifndef __GNUC__
# define __typeof__ typeof
#endif
enum lock_type {
DEV_LOCK_READ = 0,
DEV_LOCK_WRITE
};
enum lock_mode {
DEV_LOCK_FILE = 0,
DEV_LOCK_BDEV,
DEV_LOCK_NAME
};
struct crypt_lock_handle {
dev_t devno;
unsigned refcnt;
int flock_fd;
enum lock_type type;
__typeof__( ((struct stat*)0)->st_mode) mode;
enum lock_mode mode;
union {
struct {
dev_t devno;
} bdev;
struct {
char *name;
} name;
} u;
};
static int resource_by_name(char *res, size_t res_size, const char *name, bool fullpath)
{
int r;
if (fullpath)
r = snprintf(res, res_size, "%s/LN_%s", DEFAULT_LUKS2_LOCK_PATH, name);
else
r = snprintf(res, res_size, "LN_%s", name);
return (r < 0 || (size_t)r >= res_size) ? -EINVAL : 0;
}
static int resource_by_devno(char *res, size_t res_size, dev_t devno, unsigned fullpath)
{
int r;
@@ -121,13 +144,13 @@ static int open_resource(struct crypt_device *cd, const char *res)
return r < 0 ? -err : r;
}
static int acquire_lock_handle(struct crypt_device *cd, const char *device_path, struct crypt_lock_handle *h)
static int acquire_lock_handle(struct crypt_device *cd, struct device *device, struct crypt_lock_handle *h)
{
char res[PATH_MAX];
int dev_fd, fd;
struct stat st;
dev_fd = open(device_path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
dev_fd = open(device_path(device), O_RDONLY | O_NONBLOCK | O_CLOEXEC);
if (dev_fd < 0)
return -EINVAL;
@@ -148,23 +171,49 @@ static int acquire_lock_handle(struct crypt_device *cd, const char *device_path,
return fd;
h->flock_fd = fd;
h->devno = st.st_rdev;
h->u.bdev.devno = st.st_rdev;
h->mode = DEV_LOCK_BDEV;
} else if (S_ISREG(st.st_mode)) {
// FIXME: workaround for nfsv4
fd = open(device_path, O_RDWR | O_NONBLOCK | O_CLOEXEC);
fd = open(device_path(device), O_RDWR | O_NONBLOCK | O_CLOEXEC);
if (fd < 0)
h->flock_fd = dev_fd;
else {
h->flock_fd = fd;
close(dev_fd);
}
h->mode = DEV_LOCK_FILE;
} else {
/* Wrong device type */
close(dev_fd);
return -EINVAL;
}
h->mode = st.st_mode;
return 0;
}
static int acquire_lock_handle_by_name(struct crypt_device *cd, const char *name, struct crypt_lock_handle *h)
{
char res[PATH_MAX];
int fd;
h->u.name.name = strdup(name);
if (!h->u.name.name)
return -ENOMEM;
if (resource_by_name(res, sizeof(res), name, false)) {
free(h->u.name.name);
return -EINVAL;
}
fd = open_resource(cd, res);
if (fd < 0) {
free(h->u.name.name);
return fd;
}
h->flock_fd = fd;
h->mode = DEV_LOCK_NAME;
return 0;
}
@@ -174,9 +223,9 @@ static void release_lock_handle(struct crypt_device *cd, struct crypt_lock_handl
char res[PATH_MAX];
struct stat buf_a, buf_b;
if (S_ISBLK(h->mode) && /* was it block device */
if ((h->mode == DEV_LOCK_NAME) && /* was it name lock */
!flock(h->flock_fd, LOCK_EX | LOCK_NB) && /* lock to drop the file */
!resource_by_devno(res, sizeof(res), h->devno, 1) && /* acquire lock resource name */
!resource_by_name(res, sizeof(res), h->u.name.name, true) && /* acquire lock resource name */
!fstat(h->flock_fd, &buf_a) && /* read inode id referred by fd */
!stat(res, &buf_b) && /* does path file still exist? */
same_inode(buf_a, buf_b)) { /* is it same id as the one referenced by fd? */
@@ -185,8 +234,22 @@ static void release_lock_handle(struct crypt_device *cd, struct crypt_lock_handl
log_dbg(cd, "Failed to unlink resource file: %s", res);
}
if ((h->mode == DEV_LOCK_BDEV) && /* was it block device */
!flock(h->flock_fd, LOCK_EX | LOCK_NB) && /* lock to drop the file */
!resource_by_devno(res, sizeof(res), h->u.bdev.devno, 1) && /* acquire lock resource name */
!fstat(h->flock_fd, &buf_a) && /* read inode id referred by fd */
!stat(res, &buf_b) && /* does path file still exist? */
same_inode(buf_a, buf_b)) { /* is it same id as the one referenced by fd? */
/* coverity[toctou] */
if (unlink(res)) /* yes? unlink the file */
log_dbg(cd, "Failed to unlink resource file: %s", res);
}
if (h->mode == DEV_LOCK_NAME)
free(h->u.name.name);
if (close(h->flock_fd))
log_dbg(cd, "Failed to close resource fd (%d).", h->flock_fd);
log_dbg(cd, "Failed to close lock resource fd (%d).", h->flock_fd);
}
int device_locked(struct crypt_lock_handle *h)
@@ -205,10 +268,16 @@ static int verify_lock_handle(const char *device_path, struct crypt_lock_handle
struct stat lck_st, res_st;
/* we locked a regular file, check during device_open() instead. No reason to check now */
if (S_ISREG(h->mode))
if (h->mode == DEV_LOCK_FILE)
return 0;
if (resource_by_devno(res, sizeof(res), h->devno, 1))
if (h->mode == DEV_LOCK_NAME) {
if (resource_by_name(res, sizeof(res), h->u.name.name, true))
return -EINVAL;
} else if (h->mode == DEV_LOCK_BDEV) {
if (resource_by_devno(res, sizeof(res), h->u.bdev.devno, true))
return -EINVAL;
} else
return -EINVAL;
if (fstat(h->flock_fd, &lck_st))
@@ -217,108 +286,216 @@ static int verify_lock_handle(const char *device_path, struct crypt_lock_handle
return (stat(res, &res_st) || !same_inode(lck_st, res_st)) ? -EAGAIN : 0;
}
struct crypt_lock_handle *device_read_lock_handle(struct crypt_device *cd, const char *device_path)
static unsigned device_lock_inc(struct crypt_lock_handle *h)
{
return ++h->refcnt;
}
static unsigned device_lock_dec(struct crypt_lock_handle *h)
{
assert(h->refcnt);
return --h->refcnt;
}
static int acquire_and_verify(struct crypt_device *cd, struct device *device, const char *resource, int flock_op, struct crypt_lock_handle **lock)
{
int r;
struct crypt_lock_handle *h = malloc(sizeof(*h));
struct crypt_lock_handle *h;
if (!h)
return NULL;
if (device && resource)
return -EINVAL;
if (!(h = malloc(sizeof(*h))))
return -ENOMEM;
do {
r = acquire_lock_handle(cd, device_path, h);
if (r)
r = device ? acquire_lock_handle(cd, device, h) : acquire_lock_handle_by_name(cd, resource, h);
if (r < 0)
break;
log_dbg(cd, "Acquiring read lock for device %s.", device_path);
if (flock(h->flock_fd, LOCK_SH)) {
log_dbg(cd, "Shared flock failed with errno %d.", errno);
r = -EINVAL;
if (flock(h->flock_fd, flock_op)) {
log_dbg(cd, "Flock on fd %d failed with errno %d.", h->flock_fd, errno);
r = (errno == EWOULDBLOCK) ? -EBUSY : -EINVAL;
release_lock_handle(cd, h);
break;
}
log_dbg(cd, "Verifying read lock handle for device %s.", device_path);
log_dbg(cd, "Verifying lock handle for %s.", device ? device_path(device) : resource);
/*
* check whether another libcryptsetup process removed resource file before this
* one managed to flock() it. See release_lock_handle() for details
*/
r = verify_lock_handle(device_path, h);
if (r) {
flock(h->flock_fd, LOCK_UN);
r = verify_lock_handle(device_path(device), h);
if (r < 0) {
if (flock(h->flock_fd, LOCK_UN))
log_dbg(cd, "flock on fd %d failed.", h->flock_fd);
release_lock_handle(cd, h);
log_dbg(cd, "Read lock handle verification failed.");
log_dbg(cd, "Lock handle verification failed.");
}
} while (r == -EAGAIN);
if (r) {
if (r < 0) {
free(h);
return NULL;
return r;
}
*lock = h;
return 0;
}
int device_read_lock_internal(struct crypt_device *cd, struct device *device)
{
int r;
struct crypt_lock_handle *h;
if (!device)
return -EINVAL;
h = device_get_lock_handle(device);
if (device_locked(h)) {
device_lock_inc(h);
log_dbg(cd, "Device %s READ lock (or higher) already held.", device_path(device));
return 0;
}
log_dbg(cd, "Acquiring read lock for device %s.", device_path(device));
r = acquire_and_verify(cd, device, NULL, LOCK_SH, &h);
if (r < 0)
return r;
h->type = DEV_LOCK_READ;
h->refcnt = 1;
device_set_lock_handle(device, h);
return h;
log_dbg(cd, "Device %s READ lock taken.", device_path(device));
return 0;
}
struct crypt_lock_handle *device_write_lock_handle(struct crypt_device *cd, const char *device_path)
int device_write_lock_internal(struct crypt_device *cd, struct device *device)
{
int r;
struct crypt_lock_handle *h = malloc(sizeof(*h));
struct crypt_lock_handle *h;
if (!h)
return NULL;
if (!device)
return -EINVAL;
do {
r = acquire_lock_handle(cd, device_path, h);
if (r)
break;
h = device_get_lock_handle(device);
log_dbg(cd, "Acquiring write lock for device %s.", device_path);
if (flock(h->flock_fd, LOCK_EX)) {
log_dbg(cd, "Exclusive flock failed with errno %d.", errno);
r = -EINVAL;
release_lock_handle(cd, h);
break;
}
log_dbg(cd, "Verifying write lock handle for device %s.", device_path);
/*
* check whether another libcryptsetup process removed resource file before this
* one managed to flock() it. See release_lock_handle() for details
*/
r = verify_lock_handle(device_path, h);
if (r) {
flock(h->flock_fd, LOCK_UN);
release_lock_handle(cd, h);
log_dbg(cd, "Write lock handle verification failed.");
}
} while (r == -EAGAIN);
if (r) {
free(h);
return NULL;
if (device_locked(h)) {
log_dbg(cd, "Device %s WRITE lock already held.", device_path(device));
return device_lock_inc(h);
}
h->type = DEV_LOCK_WRITE;
log_dbg(cd, "Acquiring write lock for device %s.", device_path(device));
return h;
r = acquire_and_verify(cd, device, NULL, LOCK_EX, &h);
if (r < 0)
return r;
h->type = DEV_LOCK_WRITE;
h->refcnt = 1;
device_set_lock_handle(device, h);
log_dbg(cd, "Device %s WRITE lock taken.", device_path(device));
return 1;
}
void device_unlock_handle(struct crypt_device *cd, struct crypt_lock_handle *h)
int crypt_read_lock(struct crypt_device *cd, const char *resource, bool blocking, struct crypt_lock_handle **lock)
{
int r;
struct crypt_lock_handle *h;
if (!resource)
return -EINVAL;
log_dbg(cd, "Acquiring %sblocking read lock for resource %s.", blocking ? "" : "non", resource);
r = acquire_and_verify(cd, NULL, resource, LOCK_SH | (blocking ? 0 : LOCK_NB), &h);
if (r < 0)
return r;
h->type = DEV_LOCK_READ;
h->refcnt = 1;
log_dbg(cd, "READ lock for resource %s taken.", resource);
*lock = h;
return 0;
}
int crypt_write_lock(struct crypt_device *cd, const char *resource, bool blocking, struct crypt_lock_handle **lock)
{
int r;
struct crypt_lock_handle *h;
if (!resource)
return -EINVAL;
log_dbg(cd, "Acquiring %sblocking write lock for resource %s.", blocking ? "" : "non", resource);
r = acquire_and_verify(cd, NULL, resource, LOCK_EX | (blocking ? 0 : LOCK_NB), &h);
if (r < 0)
return r;
h->type = DEV_LOCK_WRITE;
h->refcnt = 1;
log_dbg(cd, "WRITE lock for resource %s taken.", resource);
*lock = h;
return 0;
}
static void unlock_internal(struct crypt_device *cd, struct crypt_lock_handle *h)
{
if (flock(h->flock_fd, LOCK_UN))
log_dbg(cd, "flock on fd %d failed.", h->flock_fd);
release_lock_handle(cd, h);
free(h);
}
void crypt_unlock_internal(struct crypt_device *cd, struct crypt_lock_handle *h)
{
if (!h)
return;
/* nested locks are illegal */
assert(!device_lock_dec(h));
log_dbg(cd, "Unlocking %s lock for resource %s.",
device_locked_readonly(h) ? "READ" : "WRITE", h->u.name.name);
unlock_internal(cd, h);
}
void device_unlock_internal(struct crypt_device *cd, struct device *device)
{
bool readonly;
struct crypt_lock_handle *h = device_get_lock_handle(device);
unsigned u = device_lock_dec(h);
if (u)
return;
readonly = device_locked_readonly(h);
unlock_internal(cd, h);
log_dbg(cd, "Device %s %s lock released.", device_path(device),
readonly ? "READ" : "WRITE");
device_set_lock_handle(device, NULL);
}
int device_locked_verify(struct crypt_device *cd, int dev_fd, struct crypt_lock_handle *h)
{
char res[PATH_MAX];

View File

@@ -1,8 +1,8 @@
/*
* Metadata on-disk locking for processes serialization
*
* Copyright (C) 2016-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2019 Ondrej Kozina
* Copyright (C) 2016-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2020 Ondrej Kozina
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -24,14 +24,24 @@
struct crypt_device;
struct crypt_lock_handle;
struct device;
int device_locked_readonly(struct crypt_lock_handle *h);
int device_locked(struct crypt_lock_handle *h);
struct crypt_lock_handle *device_read_lock_handle(struct crypt_device *cd, const char *device_path);
struct crypt_lock_handle *device_write_lock_handle(struct crypt_device *cd, const char *device_path);
void device_unlock_handle(struct crypt_device *cd, struct crypt_lock_handle *h);
int device_read_lock_internal(struct crypt_device *cd, struct device *device);
int device_write_lock_internal(struct crypt_device *cd, struct device *device);
void device_unlock_internal(struct crypt_device *cd, struct device *device);
int device_locked_verify(struct crypt_device *cd, int fd, struct crypt_lock_handle *h);
int crypt_read_lock(struct crypt_device *cd, const char *name, bool blocking, struct crypt_lock_handle **lock);
int crypt_write_lock(struct crypt_device *cd, const char *name, bool blocking, struct crypt_lock_handle **lock);
void crypt_unlock_internal(struct crypt_device *cd, struct crypt_lock_handle *h);
/* Used only in device internal allocation */
void device_set_lock_handle(struct device *device, struct crypt_lock_handle *h);
struct crypt_lock_handle *device_get_lock_handle(struct device *device);
#endif

View File

@@ -3,8 +3,8 @@
*
* Copyright (C) 2004 Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2019 Milan Broz
* Copyright (C) 2009-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2020 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -111,7 +111,7 @@ static char *lookup_dev_old(int major, int minor)
return result;
/* If it is dm, try DM dir */
if (dm_is_dm_device(major, minor)) {
if (dm_is_dm_device(major)) {
strncpy(buf, dm_get_dir(), PATH_MAX);
if ((result = __lookup_dev(buf, dev, 0, 0)))
return result;

View File

@@ -3,8 +3,8 @@
*
* Copyright (C) 2004 Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2019 Milan Broz
* Copyright (C) 2009-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2020 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -33,6 +33,17 @@ struct crypt_params_verity;
struct device;
struct crypt_params_integrity;
/* Device mapper internal flags */
#define DM_RESUME_PRIVATE (1 << 4) /* CRYPT_ACTIVATE_PRIVATE */
#define DM_SUSPEND_SKIP_LOCKFS (1 << 5)
#define DM_SUSPEND_WIPE_KEY (1 << 6)
#define DM_SUSPEND_NOFLUSH (1 << 7)
static inline uint32_t act2dmflags(uint32_t act_flags)
{
return (act_flags & DM_RESUME_PRIVATE);
}
/* Device mapper backend - kernel support flags */
#define DM_KEY_WIPE_SUPPORTED (1 << 0) /* key wipe message */
#define DM_LMK_SUPPORTED (1 << 1) /* lmk mode */
@@ -51,8 +62,14 @@ struct crypt_params_integrity;
#define DM_CAPI_STRING_SUPPORTED (1 << 14) /* support for cryptoapi format cipher definition */
#define DM_DEFERRED_SUPPORTED (1 << 15) /* deferred removal of device */
#define DM_INTEGRITY_RECALC_SUPPORTED (1 << 16) /* dm-integrity automatic recalculation supported */
#define DM_INTEGRITY_BITMAP_SUPPORTED (1 << 17) /* dm-integrity bitmap mode supported */
#define DM_GET_TARGET_VERSION_SUPPORTED (1 << 18) /* dm DM_GET_TARGET version ioctl supported */
#define DM_INTEGRITY_FIX_PADDING_SUPPORTED (1 << 19) /* supports the parameter fix_padding that fixes a bug that caused excessive padding */
#define DM_BITLK_EBOIV_SUPPORTED (1 << 20) /* EBOIV for BITLK supported */
#define DM_BITLK_ELEPHANT_SUPPORTED (1 << 21) /* Elephant diffuser for BITLK supported */
#define DM_VERITY_SIGNATURE_SUPPORTED (1 << 22) /* Verity option root_hash_sig_key_desc supported */
typedef enum { DM_CRYPT = 0, DM_VERITY, DM_INTEGRITY, DM_LINEAR, DM_UNKNOWN } dm_target_type;
typedef enum { DM_CRYPT = 0, DM_VERITY, DM_INTEGRITY, DM_LINEAR, DM_ERROR, DM_ZERO, DM_UNKNOWN } dm_target_type;
enum tdirection { TARGET_SET = 1, TARGET_QUERY };
int dm_flags(struct crypt_device *cd, dm_target_type target, uint32_t *flags);
@@ -97,6 +114,7 @@ struct dm_target {
const char *root_hash;
uint32_t root_hash_size;
const char *root_hash_sig_key_desc;
uint64_t hash_offset; /* hash offset in blocks (not header) */
uint64_t hash_blocks; /* size of hash device (in hash blocks) */
@@ -125,10 +143,14 @@ struct dm_target {
struct volume_key *journal_crypt_key;
struct device *meta_device;
bool fix_padding;
} integrity;
struct {
uint64_t offset;
} linear;
struct {
} zero;
} u;
char *params;
@@ -156,22 +178,24 @@ void dm_backend_exit(struct crypt_device *cd);
int dm_targets_allocate(struct dm_target *first, unsigned count);
void dm_targets_free(struct crypt_device *cd, struct crypt_dm_active_device *dmd);
int dm_crypt_target_set(struct dm_target *tgt, size_t seg_offset, size_t seg_size,
int dm_crypt_target_set(struct dm_target *tgt, uint64_t seg_offset, uint64_t seg_size,
struct device *data_device, struct volume_key *vk, const char *cipher,
size_t iv_offset, size_t data_offset, const char *integrity,
uint64_t iv_offset, uint64_t data_offset, const char *integrity,
uint32_t tag_size, uint32_t sector_size);
int dm_verity_target_set(struct dm_target *tgt, size_t seg_offset, size_t seg_size,
int dm_verity_target_set(struct dm_target *tgt, uint64_t seg_offset, uint64_t seg_size,
struct device *data_device, struct device *hash_device, struct device *fec_device,
const char *root_hash, uint32_t root_hash_size, uint64_t hash_offset_block,
uint64_t hash_blocks, struct crypt_params_verity *vp);
int dm_integrity_target_set(struct dm_target *tgt, size_t seg_offset, size_t seg_size,
const char *root_hash, uint32_t root_hash_size, const char *root_hash_sig_key_desc,
uint64_t hash_offset_block, uint64_t hash_blocks, struct crypt_params_verity *vp);
int dm_integrity_target_set(struct crypt_device *cd,
struct dm_target *tgt, uint64_t seg_offset, uint64_t seg_size,
struct device *meta_device,
struct device *data_device, uint64_t tag_size, uint64_t offset, uint32_t sector_size,
struct volume_key *vk,
struct volume_key *journal_crypt_key, struct volume_key *journal_mac_key,
const struct crypt_params_integrity *ip);
int dm_linear_target_set(struct dm_target *tgt, size_t seg_offset, size_t seg_size,
struct device *data_device, size_t data_offset);
int dm_linear_target_set(struct dm_target *tgt, uint64_t seg_offset, uint64_t seg_size,
struct device *data_device, uint64_t data_offset);
int dm_zero_target_set(struct dm_target *tgt, uint64_t seg_offset, uint64_t seg_size);
int dm_remove_device(struct crypt_device *cd, const char *name, uint32_t flags);
int dm_status_device(struct crypt_device *cd, const char *name);
@@ -180,13 +204,14 @@ int dm_status_verity_ok(struct crypt_device *cd, const char *name);
int dm_status_integrity_failures(struct crypt_device *cd, const char *name, uint64_t *count);
int dm_query_device(struct crypt_device *cd, const char *name,
uint32_t get_flags, struct crypt_dm_active_device *dmd);
int dm_device_deps(struct crypt_device *cd, const char *name, const char *prefix,
char **names, size_t names_length);
int dm_create_device(struct crypt_device *cd, const char *name,
const char *type, struct crypt_dm_active_device *dmd);
int dm_reload_device(struct crypt_device *cd, const char *name,
struct crypt_dm_active_device *dmd, unsigned resume);
int dm_suspend_device(struct crypt_device *cd, const char *name);
int dm_suspend_and_wipe_key(struct crypt_device *cd, const char *name);
int dm_resume_device(struct crypt_device *cd, const char *name, uint32_t flags);
struct crypt_dm_active_device *dmd, uint32_t dmflags, unsigned resume);
int dm_suspend_device(struct crypt_device *cd, const char *name, uint32_t dmflags);
int dm_resume_device(struct crypt_device *cd, const char *name, uint32_t dmflags);
int dm_resume_and_reinstate_key(struct crypt_device *cd, const char *name,
const struct volume_key *vk);
int dm_error_device(struct crypt_device *cd, const char *name);
@@ -197,8 +222,9 @@ const char *dm_get_dir(void);
int lookup_dm_dev_by_uuid(struct crypt_device *cd, const char *uuid, const char *type);
/* These are DM helpers used only by utils_devpath file */
int dm_is_dm_device(int major, int minor);
int dm_is_dm_device(int major);
int dm_is_dm_kernel_name(const char *name);
char *dm_device_path(const char *prefix, int major, int minor);
char *dm_device_name(const char *path);
#endif /* _UTILS_DM_H */

View File

@@ -1,7 +1,7 @@
/*
* FIPS mode utilities
*
* Copyright (C) 2011-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2020 Red Hat, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

View File

@@ -1,7 +1,7 @@
/*
* FIPS mode utilities
*
* Copyright (C) 2011-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2020 Red Hat, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

View File

@@ -3,8 +3,8 @@
*
* Copyright (C) 2004 Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2019 Milan Broz
* Copyright (C) 2009-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2020 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

View File

@@ -3,8 +3,8 @@
*
* Copyright (C) 2004 Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2019 Milan Broz
* Copyright (C) 2009-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2020 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

View File

@@ -1,8 +1,8 @@
/*
* kernel keyring utilities
*
* Copyright (C) 2016-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2019 Ondrej Kozina
* Copyright (C) 2016-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2020 Ondrej Kozina
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -25,17 +25,28 @@
#include <unistd.h>
#include <sys/syscall.h>
#include "libcryptsetup.h"
#include "utils_keyring.h"
#ifndef HAVE_KEY_SERIAL_T
#define HAVE_KEY_SERIAL_T
#include <stdint.h>
typedef int32_t key_serial_t;
#endif
#include "utils_crypt.h"
#include "utils_keyring.h"
#ifndef ARRAY_SIZE
# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#endif
#ifdef KERNEL_KEYRING
static const struct {
key_type_t type;
const char *type_name;
} key_types[] = {
{ LOGON_KEY, "logon" },
{ USER_KEY, "user" },
};
#include <linux/keyctl.h>
/* request_key */
@@ -86,12 +97,16 @@ int keyring_check(void)
#endif
}
int keyring_add_key_in_thread_keyring(const char *key_desc, const void *key, size_t key_size)
int keyring_add_key_in_thread_keyring(key_type_t ktype, const char *key_desc, const void *key, size_t key_size)
{
#ifdef KERNEL_KEYRING
key_serial_t kid;
const char *type_name = key_type_name(ktype);
kid = add_key("logon", key_desc, key, key_size, KEY_SPEC_THREAD_KEYRING);
if (!type_name || !key_desc)
return -EINVAL;
kid = add_key(type_name, key_desc, key, key_size, KEY_SPEC_THREAD_KEYRING);
if (kid < 0)
return -errno;
@@ -101,6 +116,34 @@ int keyring_add_key_in_thread_keyring(const char *key_desc, const void *key, siz
#endif
}
/* currently used in client utilities only */
int keyring_add_key_in_user_keyring(key_type_t ktype, const char *key_desc, const void *key, size_t key_size)
{
#ifdef KERNEL_KEYRING
const char *type_name = key_type_name(ktype);
key_serial_t kid;
if (!type_name || !key_desc)
return -EINVAL;
kid = add_key(type_name, key_desc, key, key_size, KEY_SPEC_USER_KEYRING);
if (kid < 0)
return -errno;
return 0;
#else
return -ENOTSUP;
#endif
}
/* alias for the same code */
int keyring_get_key(const char *key_desc,
char **key,
size_t *key_size)
{
return keyring_get_passphrase(key_desc, key, key_size);
}
int keyring_get_passphrase(const char *key_desc,
char **passphrase,
size_t *passphrase_len)
@@ -113,7 +156,7 @@ int keyring_get_passphrase(const char *key_desc,
size_t len = 0;
do
kid = request_key("user", key_desc, NULL, 0);
kid = request_key(key_type_name(USER_KEY), key_desc, NULL, 0);
while (kid < 0 && errno == EINTR);
if (kid < 0)
@@ -134,7 +177,7 @@ int keyring_get_passphrase(const char *key_desc,
if (ret < 0) {
err = errno;
if (buf)
crypt_memzero(buf, len);
crypt_safe_memzero(buf, len);
free(buf);
return -err;
}
@@ -148,13 +191,16 @@ int keyring_get_passphrase(const char *key_desc,
#endif
}
int keyring_revoke_and_unlink_key(const char *key_desc)
static int keyring_revoke_and_unlink_key_type(const char *type_name, const char *key_desc)
{
#ifdef KERNEL_KEYRING
key_serial_t kid;
if (!type_name || !key_desc)
return -EINVAL;
do
kid = request_key("logon", key_desc, NULL, 0);
kid = request_key(type_name, key_desc, NULL, 0);
while (kid < 0 && errno == EINTR);
if (kid < 0)
@@ -177,3 +223,20 @@ int keyring_revoke_and_unlink_key(const char *key_desc)
return -ENOTSUP;
#endif
}
const char *key_type_name(key_type_t type)
{
#ifdef KERNEL_KEYRING
unsigned int i;
for (i = 0; i < ARRAY_SIZE(key_types); i++)
if (type == key_types[i].type)
return key_types[i].type_name;
#endif
return NULL;
}
int keyring_revoke_and_unlink_key(key_type_t ktype, const char *key_desc)
{
return keyring_revoke_and_unlink_key_type(key_type_name(ktype), key_desc);
}

View File

@@ -1,8 +1,8 @@
/*
* kernel keyring syscall wrappers
*
* Copyright (C) 2016-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2019 Ondrej Kozina
* Copyright (C) 2016-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2020 Ondrej Kozina
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -24,17 +24,32 @@
#include <stddef.h>
typedef enum { LOGON_KEY = 0, USER_KEY } key_type_t;
const char *key_type_name(key_type_t ktype);
int keyring_check(void);
int keyring_get_key(const char *key_desc,
char **key,
size_t *key_size);
int keyring_get_passphrase(const char *key_desc,
char **passphrase,
size_t *passphrase_len);
int keyring_add_key_in_thread_keyring(
key_type_t ktype,
const char *key_desc,
const void *key,
size_t key_size);
int keyring_revoke_and_unlink_key(const char *key_desc);
int keyring_add_key_in_user_keyring(
key_type_t ktype,
const char *key_desc,
const void *key,
size_t key_size);
int keyring_revoke_and_unlink_key(key_type_t ktype, const char *key_desc);
#endif

View File

@@ -1,8 +1,8 @@
/*
* loopback block device utilities
*
* Copyright (C) 2009-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2019 Milan Broz
* Copyright (C) 2009-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2020 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -252,7 +252,12 @@ static char *_sysfs_backing_file(const char *loop)
char *crypt_loop_backing_file(const char *loop)
{
char *bf = _sysfs_backing_file(loop);
char *bf;
if (!crypt_loop_device(loop))
return NULL;
bf = _sysfs_backing_file(loop);
return bf ?: _ioctl_backing_file(loop);
}

View File

@@ -1,8 +1,8 @@
/*
* loopback block device utilities
*
* Copyright (C) 2009-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2019 Milan Broz
* Copyright (C) 2009-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2020 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

View File

@@ -1,8 +1,8 @@
/*
* utils_pbkdf - PBKDF settings for libcryptsetup
*
* Copyright (C) 2009-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2019 Milan Broz
* Copyright (C) 2009-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2020 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -181,7 +181,7 @@ int init_pbkdf_type(struct crypt_device *cd,
if (crypt_fips_mode()) {
if (pbkdf && strcmp(pbkdf->type, CRYPT_KDF_PBKDF2)) {
log_err(cd, "Only PBKDF2 is supported in FIPS mode.");
log_err(cd, _("Only PBKDF2 is supported in FIPS mode."));
return -EINVAL;
}
if (!pbkdf)
@@ -258,9 +258,13 @@ int init_pbkdf_type(struct crypt_device *cd,
}
}
log_dbg(cd, "PBKDF %s, hash %s, time_ms %u (iterations %u), max_memory_kb %u, parallel_threads %u.",
cd_pbkdf->type ?: "(none)", cd_pbkdf->hash ?: "(none)", cd_pbkdf->time_ms,
cd_pbkdf->iterations, cd_pbkdf->max_memory_kb, cd_pbkdf->parallel_threads);
if (!strcmp(pbkdf->type, CRYPT_KDF_PBKDF2))
log_dbg(cd, "PBKDF %s-%s, time_ms %u (iterations %u).",
cd_pbkdf->type, cd_pbkdf->hash, cd_pbkdf->time_ms, cd_pbkdf->iterations);
else
log_dbg(cd, "PBKDF %s, time_ms %u (iterations %u), max_memory_kb %u, parallel_threads %u.",
cd_pbkdf->type, cd_pbkdf->time_ms, cd_pbkdf->iterations,
cd_pbkdf->max_memory_kb, cd_pbkdf->parallel_threads);
return 0;
}

102
lib/utils_safe_memory.c Normal file
View File

@@ -0,0 +1,102 @@
/*
* utils_safe_memory - safe memory helpers
*
* Copyright (C) 2009-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2020 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 <stdlib.h>
#include <string.h>
#include "libcryptsetup.h"
struct safe_allocation {
size_t size;
char data[0];
};
/*
* Replacement for memset(s, 0, n) on stack that can be optimized out
* Also used in safe allocations for explicit memory wipe.
*/
void crypt_safe_memzero(void *data, size_t size)
{
#ifdef HAVE_EXPLICIT_BZERO
explicit_bzero(data, size);
#else
volatile uint8_t *p = (volatile uint8_t *)data;
while(size--)
*p++ = 0;
#endif
}
/* safe allocations */
void *crypt_safe_alloc(size_t size)
{
struct safe_allocation *alloc;
if (!size || size > (SIZE_MAX - offsetof(struct safe_allocation, data)))
return NULL;
alloc = malloc(size + offsetof(struct safe_allocation, data));
if (!alloc)
return NULL;
alloc->size = size;
crypt_safe_memzero(&alloc->data, size);
/* coverity[leaked_storage] */
return &alloc->data;
}
void crypt_safe_free(void *data)
{
struct safe_allocation *alloc;
if (!data)
return;
alloc = (struct safe_allocation *)
((char *)data - offsetof(struct safe_allocation, data));
crypt_safe_memzero(data, alloc->size);
alloc->size = 0x55aa55aa;
free(alloc);
}
void *crypt_safe_realloc(void *data, size_t size)
{
struct safe_allocation *alloc;
void *new_data;
new_data = crypt_safe_alloc(size);
if (new_data && data) {
alloc = (struct safe_allocation *)
((char *)data - offsetof(struct safe_allocation, data));
if (size > alloc->size)
size = alloc->size;
memcpy(new_data, data, size);
}
crypt_safe_free(data);
return new_data;
}

View File

@@ -0,0 +1,395 @@
/*
* Generic wrapper for storage functions
* (experimental only)
*
* Copyright (C) 2018-2020, Ondrej Kozina
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <limits.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "utils_storage_wrappers.h"
#include "internal.h"
struct crypt_storage_wrapper {
crypt_storage_wrapper_type type;
int dev_fd;
int block_size;
size_t mem_alignment;
uint64_t data_offset;
union {
struct {
struct crypt_storage *s;
uint64_t iv_start;
} cb;
struct {
int dmcrypt_fd;
char name[PATH_MAX];
} dm;
} u;
};
static int crypt_storage_backend_init(struct crypt_device *cd,
struct crypt_storage_wrapper *w,
uint64_t iv_start,
int sector_size,
const char *cipher,
const char *cipher_mode,
const struct volume_key *vk,
uint32_t flags)
{
int r;
struct crypt_storage *s;
/* iv_start, sector_size */
r = crypt_storage_init(&s, sector_size, cipher, cipher_mode, vk->key, vk->keylength);
if (r)
return r;
if ((flags & DISABLE_KCAPI) && crypt_storage_kernel_only(s)) {
log_dbg(cd, "Could not initialize userspace block cipher and kernel fallback is disabled.");
crypt_storage_destroy(s);
return -ENOTSUP;
}
w->type = USPACE;
w->u.cb.s = s;
w->u.cb.iv_start = iv_start;
return 0;
}
static int crypt_storage_dmcrypt_init(
struct crypt_device *cd,
struct crypt_storage_wrapper *cw,
struct device *device,
uint64_t device_offset,
uint64_t iv_start,
int sector_size,
const char *cipher_spec,
struct volume_key *vk,
int open_flags)
{
static int counter = 0;
char path[PATH_MAX];
struct crypt_dm_active_device dmd = {
.flags = CRYPT_ACTIVATE_PRIVATE,
};
int mode, r, fd = -1;
log_dbg(cd, "Using temporary dmcrypt to access data.");
if (snprintf(cw->u.dm.name, sizeof(cw->u.dm.name), "temporary-cryptsetup-%d-%d", getpid(), counter++) < 0)
return -ENOMEM;
if (snprintf(path, sizeof(path), "%s/%s", dm_get_dir(), cw->u.dm.name) < 0)
return -ENOMEM;
r = device_block_adjust(cd, device, DEV_OK,
device_offset, &dmd.size, &dmd.flags);
if (r < 0) {
log_err(cd, _("Device %s does not exist or access denied."),
device_path(device));
return -EIO;
}
mode = open_flags | O_DIRECT;
if (dmd.flags & CRYPT_ACTIVATE_READONLY)
mode = (open_flags & ~O_ACCMODE) | O_RDONLY;
if (vk->key_description)
dmd.flags |= CRYPT_ACTIVATE_KEYRING_KEY;
r = dm_crypt_target_set(&dmd.segment, 0, dmd.size,
device,
vk,
cipher_spec,
iv_start,
device_offset,
NULL,
0,
sector_size);
if (r)
return r;
r = dm_create_device(cd, cw->u.dm.name, "TEMP", &dmd);
if (r < 0) {
if (r != -EACCES && r != -ENOTSUP)
log_dbg(cd, "error hint would be nice");
r = -EIO;
}
dm_targets_free(cd, &dmd);
if (r)
return r;
fd = open(path, mode);
if (fd < 0) {
log_dbg(cd, "Failed to open %s", path);
dm_remove_device(cd, cw->u.dm.name, CRYPT_DEACTIVATE_FORCE);
return -EINVAL;
}
cw->type = DMCRYPT;
cw->u.dm.dmcrypt_fd = fd;
return 0;
}
int crypt_storage_wrapper_init(struct crypt_device *cd,
struct crypt_storage_wrapper **cw,
struct device *device,
uint64_t data_offset,
uint64_t iv_start,
int sector_size,
const char *cipher,
struct volume_key *vk,
uint32_t flags)
{
int open_flags, r;
char _cipher[MAX_CIPHER_LEN], mode[MAX_CIPHER_LEN];
struct crypt_storage_wrapper *w;
/* device-mapper restrictions */
if (data_offset & ((1 << SECTOR_SHIFT) - 1))
return -EINVAL;
if (crypt_parse_name_and_mode(cipher, _cipher, NULL, mode))
return -EINVAL;
open_flags = O_CLOEXEC | ((flags & OPEN_READONLY) ? O_RDONLY : O_RDWR);
w = malloc(sizeof(*w));
if (!w)
return -ENOMEM;
memset(w, 0, sizeof(*w));
w->data_offset = data_offset;
w->mem_alignment = device_alignment(device);
w->block_size = device_block_size(cd, device);
if (!w->block_size || !w->mem_alignment) {
log_dbg(cd, "block size or alignment error.");
r = -EINVAL;
goto err;
}
w->dev_fd = device_open(cd, device, open_flags);
if (w->dev_fd < 0) {
r = -EINVAL;
goto err;
}
if (!strcmp(_cipher, "cipher_null")) {
log_dbg(cd, "Requested cipher_null, switching to noop wrapper.");
w->type = NONE;
*cw = w;
return 0;
}
if (!vk) {
log_dbg(cd, "no key passed.");
r = -EINVAL;
goto err;
}
r = crypt_storage_backend_init(cd, w, iv_start, sector_size, _cipher, mode, vk, flags);
if (!r) {
*cw = w;
return 0;
}
log_dbg(cd, "Failed to initialize userspace block cipher.");
if ((r != -ENOTSUP && r != -ENOENT) || (flags & DISABLE_DMCRYPT))
goto err;
r = crypt_storage_dmcrypt_init(cd, w, device, data_offset >> SECTOR_SHIFT, iv_start,
sector_size, cipher, vk, open_flags);
if (r) {
log_dbg(cd, "Dm-crypt backend failed to initialize.");
goto err;
}
*cw = w;
return 0;
err:
crypt_storage_wrapper_destroy(w);
/* wrapper destroy */
return r;
}
/* offset is relative to sector_start */
ssize_t crypt_storage_wrapper_read(struct crypt_storage_wrapper *cw,
off_t offset, void *buffer, size_t buffer_length)
{
return read_lseek_blockwise(cw->dev_fd,
cw->block_size,
cw->mem_alignment,
buffer,
buffer_length,
cw->data_offset + offset);
}
ssize_t crypt_storage_wrapper_read_decrypt(struct crypt_storage_wrapper *cw,
off_t offset, void *buffer, size_t buffer_length)
{
int r;
ssize_t read;
if (cw->type == DMCRYPT)
return read_lseek_blockwise(cw->u.dm.dmcrypt_fd,
cw->block_size,
cw->mem_alignment,
buffer,
buffer_length,
offset);
read = read_lseek_blockwise(cw->dev_fd,
cw->block_size,
cw->mem_alignment,
buffer,
buffer_length,
cw->data_offset + offset);
if (cw->type == NONE || read < 0)
return read;
r = crypt_storage_decrypt(cw->u.cb.s,
cw->u.cb.iv_start + (offset >> SECTOR_SHIFT),
read,
buffer);
if (r)
return -EINVAL;
return read;
}
ssize_t crypt_storage_wrapper_decrypt(struct crypt_storage_wrapper *cw,
off_t offset, void *buffer, size_t buffer_length)
{
int r;
ssize_t read;
if (cw->type == NONE)
return 0;
if (cw->type == DMCRYPT) {
/* there's nothing we can do, just read/decrypt via dm-crypt */
read = crypt_storage_wrapper_read_decrypt(cw, offset, buffer, buffer_length);
if (read < 0 || (size_t)read != buffer_length)
return -EINVAL;
return 0;
}
r = crypt_storage_decrypt(cw->u.cb.s,
cw->u.cb.iv_start + (offset >> SECTOR_SHIFT),
buffer_length,
buffer);
if (r)
return r;
return 0;
}
ssize_t crypt_storage_wrapper_write(struct crypt_storage_wrapper *cw,
off_t offset, void *buffer, size_t buffer_length)
{
return write_lseek_blockwise(cw->dev_fd,
cw->block_size,
cw->mem_alignment,
buffer,
buffer_length,
cw->data_offset + offset);
}
ssize_t crypt_storage_wrapper_encrypt_write(struct crypt_storage_wrapper *cw,
off_t offset, void *buffer, size_t buffer_length)
{
if (cw->type == DMCRYPT)
return write_lseek_blockwise(cw->u.dm.dmcrypt_fd,
cw->block_size,
cw->mem_alignment,
buffer,
buffer_length,
offset);
if (cw->type == USPACE &&
crypt_storage_encrypt(cw->u.cb.s,
cw->u.cb.iv_start + (offset >> SECTOR_SHIFT),
buffer_length, buffer))
return -EINVAL;
return write_lseek_blockwise(cw->dev_fd,
cw->block_size,
cw->mem_alignment,
buffer,
buffer_length,
cw->data_offset + offset);
}
ssize_t crypt_storage_wrapper_encrypt(struct crypt_storage_wrapper *cw,
off_t offset, void *buffer, size_t buffer_length)
{
if (cw->type == NONE)
return 0;
if (cw->type == DMCRYPT)
return -ENOTSUP;
if (crypt_storage_encrypt(cw->u.cb.s,
cw->u.cb.iv_start + (offset >> SECTOR_SHIFT),
buffer_length,
buffer))
return -EINVAL;
return 0;
}
void crypt_storage_wrapper_destroy(struct crypt_storage_wrapper *cw)
{
if (!cw)
return;
if (cw->type == USPACE)
crypt_storage_destroy(cw->u.cb.s);
if (cw->type == DMCRYPT) {
close(cw->u.dm.dmcrypt_fd);
dm_remove_device(NULL, cw->u.dm.name, CRYPT_DEACTIVATE_FORCE);
}
free(cw);
}
int crypt_storage_wrapper_datasync(const struct crypt_storage_wrapper *cw)
{
if (!cw)
return -EINVAL;
if (cw->type == DMCRYPT)
return fdatasync(cw->u.dm.dmcrypt_fd);
else
return fdatasync(cw->dev_fd);
}
crypt_storage_wrapper_type crypt_storage_wrapper_get_type(const struct crypt_storage_wrapper *cw)
{
return cw ? cw->type : NONE;
}

View File

@@ -0,0 +1,71 @@
/*
* Generic wrapper for storage functions
* (experimental only)
*
* Copyright (C) 2018-2020, Ondrej Kozina
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef _UTILS_STORAGE_WRAPPERS_H
#define _UTILS_STORAGE_WRAPPERS_H
struct crypt_storage_wrapper;
struct device;
struct volume_key;
struct crypt_device;
#define DISABLE_USPACE (1 << 0)
#define DISABLE_KCAPI (1 << 1)
#define DISABLE_DMCRYPT (1 << 2)
#define OPEN_READONLY (1 << 3)
typedef enum {
NONE = 0,
USPACE,
DMCRYPT
} crypt_storage_wrapper_type;
int crypt_storage_wrapper_init(struct crypt_device *cd,
struct crypt_storage_wrapper **cw,
struct device *device,
uint64_t data_offset,
uint64_t iv_start,
int sector_size,
const char *cipher,
struct volume_key *vk,
uint32_t flags);
void crypt_storage_wrapper_destroy(struct crypt_storage_wrapper *cw);
/* !!! when doing 'read' or 'write' all offset values are RELATIVE to data_offset !!! */
ssize_t crypt_storage_wrapper_read(struct crypt_storage_wrapper *cw,
off_t offset, void *buffer, size_t buffer_length);
ssize_t crypt_storage_wrapper_read_decrypt(struct crypt_storage_wrapper *cw,
off_t offset, void *buffer, size_t buffer_length);
ssize_t crypt_storage_wrapper_decrypt(struct crypt_storage_wrapper *cw,
off_t offset, void *buffer, size_t buffer_length);
ssize_t crypt_storage_wrapper_write(struct crypt_storage_wrapper *cw,
off_t offset, void *buffer, size_t buffer_length);
ssize_t crypt_storage_wrapper_encrypt_write(struct crypt_storage_wrapper *cw,
off_t offset, void *buffer, size_t buffer_length);
ssize_t crypt_storage_wrapper_encrypt(struct crypt_storage_wrapper *cw,
off_t offset, void *buffer, size_t buffer_length);
int crypt_storage_wrapper_datasync(const struct crypt_storage_wrapper *cw);
crypt_storage_wrapper_type crypt_storage_wrapper_get_type(const struct crypt_storage_wrapper *cw);
#endif

View File

@@ -2,8 +2,8 @@
* utils_wipe - wipe a device
*
* Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2019 Milan Broz
* Copyright (C) 2009-2020 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2020 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -139,7 +139,7 @@ int crypt_wipe_device(struct crypt_device *cd,
int (*progress)(uint64_t size, uint64_t offset, void *usrptr),
void *usrptr)
{
int r, devfd = -1;
int r, devfd;
size_t bsize, alignment;
char *sf = NULL;
uint64_t dev_size;
@@ -157,7 +157,10 @@ int crypt_wipe_device(struct crypt_device *cd,
if (MISALIGNED_512(offset) || MISALIGNED_512(length) || MISALIGNED_512(wipe_block_size))
return -EINVAL;
devfd = device_open(cd, device, O_RDWR);
if (device_is_locked(device))
devfd = device_open_locked(cd, device, O_RDWR);
else
devfd = device_open(cd, device, O_RDWR);
if (devfd < 0)
return errno ? -errno : -EINVAL;
@@ -179,7 +182,7 @@ int crypt_wipe_device(struct crypt_device *cd,
goto out;
if (lseek64(devfd, offset, SEEK_SET) < 0) {
log_err(cd, "Cannot seek to device offset.");
log_err(cd, _("Cannot seek to device offset."));
r = -EINVAL;
goto out;
}
@@ -203,7 +206,7 @@ int crypt_wipe_device(struct crypt_device *cd,
r = wipe_block(cd, devfd, pattern, sf, bsize, alignment,
wipe_block_size, offset, &need_block_init);
if (r) {
log_err(cd, "Device wipe error, offset %" PRIu64 ".", offset);
log_err(cd,_("Device wipe error, offset %" PRIu64 "."), offset);
break;
}
@@ -215,9 +218,8 @@ int crypt_wipe_device(struct crypt_device *cd,
}
}
device_sync(cd, device, devfd);
device_sync(cd, device);
out:
close(devfd);
free(sf);
return r;
}

View File

@@ -3,7 +3,7 @@
*
* Copyright (C) 2004 Phil Karn, KA9Q
* libcryptsetup modifications
* Copyright (C) 2017-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2017-2020 Red Hat, Inc. All rights reserved.
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

View File

@@ -3,7 +3,7 @@
*
* Copyright (C) 2002, Phil Karn, KA9Q
* libcryptsetup modifications
* Copyright (C) 2017-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2017-2020 Red Hat, Inc. All rights reserved.
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

View File

@@ -3,7 +3,7 @@
*
* Copyright (C) 2002, Phil Karn, KA9Q
* libcryptsetup modifications
* Copyright (C) 2017-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2017-2020 Red Hat, Inc. All rights reserved.
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

View File

@@ -1,7 +1,7 @@
/*
* dm-verity volume handling
*
* Copyright (C) 2012-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2020 Red Hat, Inc. All rights reserved.
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -60,13 +60,13 @@ int VERITY_read_sb(struct crypt_device *cd,
struct device *device = crypt_metadata_device(cd);
struct verity_sb sb = {};
ssize_t hdr_size = sizeof(struct verity_sb);
int devfd = 0, sb_version;
int devfd, sb_version;
log_dbg(cd, "Reading VERITY header of size %zu on device %s, offset %" PRIu64 ".",
sizeof(struct verity_sb), device_path(device), sb_offset);
if (params->flags & CRYPT_VERITY_NO_HEADER) {
log_err(cd, _("Verity device %s doesn't use on-disk header."),
log_err(cd, _("Verity device %s does not use on-disk header."),
device_path(device));
return -EINVAL;
}
@@ -84,11 +84,8 @@ int VERITY_read_sb(struct crypt_device *cd,
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
device_alignment(device), &sb, hdr_size,
sb_offset) < hdr_size) {
close(devfd);
sb_offset) < hdr_size)
return -EIO;
}
close(devfd);
if (memcmp(sb.signature, VERITY_SIGNATURE, sizeof(sb.signature))) {
log_err(cd, _("Device %s is not a valid VERITY device."),
@@ -160,7 +157,7 @@ int VERITY_write_sb(struct crypt_device *cd,
ssize_t hdr_size = sizeof(struct verity_sb);
char *algorithm;
uuid_t uuid;
int r, devfd = 0;
int r, devfd;
log_dbg(cd, "Updating VERITY header of size %zu on device %s, offset %" PRIu64 ".",
sizeof(struct verity_sb), device_path(device), sb_offset);
@@ -172,7 +169,7 @@ int VERITY_write_sb(struct crypt_device *cd,
}
if (params->flags & CRYPT_VERITY_NO_HEADER) {
log_err(cd, _("Verity device %s doesn't use on-disk header."),
log_err(cd, _("Verity device %s does not use on-disk header."),
device_path(device));
return -EINVAL;
}
@@ -202,8 +199,7 @@ int VERITY_write_sb(struct crypt_device *cd,
log_err(cd, _("Error during update of verity header on device %s."),
device_path(device));
device_sync(cd, device, devfd);
close(devfd);
device_sync(cd, device);
return r;
}
@@ -239,6 +235,7 @@ int VERITY_activate(struct crypt_device *cd,
const char *name,
const char *root_hash,
size_t root_hash_size,
const char *signature_description,
struct device *fec_device,
struct crypt_params_verity *verity_hdr,
uint32_t activation_flags)
@@ -256,6 +253,11 @@ int VERITY_activate(struct crypt_device *cd,
name ?: "[none]", verity_hdr->hash_name);
if (verity_hdr->flags & CRYPT_VERITY_CHECK_HASH) {
if (signature_description) {
log_err(cd, _("Root hash signature verification is not supported."));
return -EINVAL;
}
log_dbg(cd, "Verification of data in userspace required.");
r = VERITY_verify(cd, verity_hdr, root_hash, root_hash_size);
@@ -295,7 +297,8 @@ int VERITY_activate(struct crypt_device *cd,
r = dm_verity_target_set(&dmd.segment, 0, dmd.size, crypt_data_device(cd),
crypt_metadata_device(cd), fec_device, root_hash,
root_hash_size, VERITY_hash_offset_block(verity_hdr),
root_hash_size, signature_description,
VERITY_hash_offset_block(verity_hdr),
VERITY_hash_blocks(cd, verity_hdr), verity_hdr);
if (r)
@@ -303,7 +306,11 @@ int VERITY_activate(struct crypt_device *cd,
r = dm_create_device(cd, name, CRYPT_VERITY, &dmd);
if (r < 0 && (dm_flags(cd, DM_VERITY, &dmv_flags) || !(dmv_flags & DM_VERITY_SUPPORTED))) {
log_err(cd, _("Kernel doesn't support dm-verity mapping."));
log_err(cd, _("Kernel does not support dm-verity mapping."));
r = -ENOTSUP;
}
if (r < 0 && signature_description && !(dmv_flags & DM_VERITY_SIGNATURE_SUPPORTED)) {
log_err(cd, _("Kernel does not support dm-verity signature option."));
r = -ENOTSUP;
}
if (r < 0)

View File

@@ -1,7 +1,7 @@
/*
* dm-verity volume handling
*
* Copyright (C) 2012-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2020 Red Hat, Inc. All rights reserved.
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -46,6 +46,7 @@ int VERITY_activate(struct crypt_device *cd,
const char *name,
const char *root_hash,
size_t root_hash_size,
const char *signature_description,
struct device *fec_device,
struct crypt_params_verity *verity_hdr,
uint32_t activation_flags);
@@ -57,7 +58,7 @@ int VERITY_verify(struct crypt_device *cd,
int VERITY_create(struct crypt_device *cd,
struct crypt_params_verity *verity_hdr,
char *root_hash,
const char *root_hash,
size_t root_hash_size);
int VERITY_FEC_process(struct crypt_device *cd,

View File

@@ -2,7 +2,7 @@
* dm-verity Forward Error Correction (FEC) support
*
* Copyright (C) 2015 Google, Inc. All rights reserved.
* Copyright (C) 2017-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2017-2020 Red Hat, Inc. All rights reserved.
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -166,7 +166,7 @@ static int FEC_process_inputs(struct crypt_device *cd,
/* decoding from parity device */
if (decode) {
if (read_buffer(fd, &rs_block[ctx.rsn], ctx.roots) != ctx.roots) {
if (read_buffer(fd, &rs_block[ctx.rsn], ctx.roots) < 0) {
log_err(cd, _("Failed to read parity for RS block %" PRIu64 "."), n);
r = -EIO;
goto out;
@@ -185,7 +185,7 @@ static int FEC_process_inputs(struct crypt_device *cd,
} else {
/* encoding and writing parity data to fec device */
encode_rs_char(rs, rs_block, &rs_block[ctx.rsn]);
if (write_buffer(fd, &rs_block[ctx.rsn], ctx.roots) != ctx.roots) {
if (write_buffer(fd, &rs_block[ctx.rsn], ctx.roots) < 0) {
log_err(cd, _("Failed to write parity for RS block %" PRIu64 "."), n);
r = -EIO;
goto out;

View File

@@ -1,7 +1,7 @@
/*
* dm-verity volume handling
*
* Copyright (C) 2012-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2020 Red Hat, Inc. All rights reserved.
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -102,7 +102,7 @@ static int hash_levels(size_t hash_block_size, size_t digest_size,
off_t *hash_level_block, off_t *hash_level_size)
{
size_t hash_per_block_bits;
off_t s;
off_t s, s_shift;
int i;
if (!digest_size)
@@ -124,7 +124,10 @@ static int hash_levels(size_t hash_block_size, size_t digest_size,
if (hash_level_block)
hash_level_block[i] = *hash_position;
// verity position of block data_file_blocks at level i
s = (data_file_blocks + ((off_t)1 << ((i + 1) * hash_per_block_bits)) - 1) >> ((i + 1) * hash_per_block_bits);
s_shift = (i + 1) * hash_per_block_bits;
if (s_shift > 63)
return -EINVAL;
s = (data_file_blocks + ((off_t)1 << s_shift) - 1) >> ((i + 1) * hash_per_block_bits);
if (hash_level_size)
hash_level_size[i] = s;
if ((*hash_position + s) < *hash_position ||
@@ -418,7 +421,7 @@ int VERITY_verify(struct crypt_device *cd,
/* Create verity hash */
int VERITY_create(struct crypt_device *cd,
struct crypt_params_verity *verity_hdr,
char *root_hash,
const char *root_hash,
size_t root_hash_size)
{
unsigned pgsize = (unsigned)crypt_getpagesize();
@@ -439,7 +442,7 @@ int VERITY_create(struct crypt_device *cd,
verity_hdr->data_block_size,
verity_hdr->data_size,
VERITY_hash_offset_block(verity_hdr),
root_hash,
CONST_CAST(char*)root_hash,
root_hash_size,
verity_hdr->salt,
verity_hdr->salt_size);

View File

@@ -2,7 +2,7 @@
* cryptsetup volume key implementation
*
* Copyright (C) 2004-2006 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2010-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2020 Red Hat, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -39,13 +39,15 @@ struct volume_key *crypt_alloc_volume_key(size_t keylength, const char *key)
vk->key_description = NULL;
vk->keylength = keylength;
vk->id = -1;
vk->next = NULL;
/* keylength 0 is valid => no key */
if (vk->keylength) {
if (key)
memcpy(&vk->key, key, keylength);
else
crypt_memzero(&vk->key, keylength);
crypt_safe_memzero(&vk->key, keylength);
}
return vk;
@@ -64,13 +66,66 @@ int crypt_volume_key_set_description(struct volume_key *vk, const char *key_desc
return 0;
}
void crypt_volume_key_set_id(struct volume_key *vk, int id)
{
if (vk && id >= 0)
vk->id = id;
}
int crypt_volume_key_get_id(const struct volume_key *vk)
{
return vk ? vk->id : -1;
}
struct volume_key *crypt_volume_key_by_id(struct volume_key *vks, int id)
{
struct volume_key *vk = vks;
if (id < 0)
return NULL;
while (vk && vk->id != id)
vk = vk->next;
return vk;
}
void crypt_volume_key_add_next(struct volume_key **vks, struct volume_key *vk)
{
struct volume_key *tmp;
if (!vks)
return;
if (!*vks) {
*vks = vk;
return;
}
tmp = *vks;
while (tmp->next)
tmp = tmp->next;
tmp->next = vk;
}
struct volume_key *crypt_volume_key_next(struct volume_key *vk)
{
return vk ? vk->next : NULL;
}
void crypt_free_volume_key(struct volume_key *vk)
{
if (vk) {
crypt_memzero(vk->key, vk->keylength);
struct volume_key *vk_next;
while (vk) {
crypt_safe_memzero(vk->key, vk->keylength);
vk->keylength = 0;
free(CONST_CAST(void*)vk->key_description);
vk_next = vk->next;
free(vk);
vk = vk_next;
}
}

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