Compare commits

...

569 Commits

Author SHA1 Message Date
Milan Broz
bf2e48e404 Version 2.5.0-rc1. 2022-07-14 16:00:01 +02:00
Ondrej Kozina
d943b2efb9 Clarify cryptsetup-open options in man page. 2022-07-14 13:51:37 +00:00
Milan Broz
02d5c5ce38 Add 2.5.0-rc1 Release Notes. 2022-07-14 14:10:33 +02:00
Milan Broz
bdc97ef389 Update cryptsetup.pot. 2022-07-14 14:09:45 +02:00
Milan Broz
6540ffd1a6 Fix spacing with man footer by adding space.
So it is always separate section.
2022-07-14 09:42:04 +02:00
Milan Broz
c7a8c9a620 Always regenerate man pages if source file changes. 2022-07-14 09:42:01 +02:00
Milan Broz
d96dcff883 Set 2.5.0-rc1 version. 2022-07-13 21:13:07 +02:00
Milan Broz
4034c548c2 Update LUKS2 on-disk description. 2022-07-13 21:13:07 +02:00
daniel.zatovic
8eff391a66 Regenerate manual pages using AsciiDoctor in spec file. 2022-07-13 21:08:17 +02:00
daniel.zatovic
dae6aa0384 Obsolete cryptsetup-reencrypt and add manual pages to spec file.
The cryptsetup-reencrypt utility is now replaced by reencrypt action.
New per-action manual pages have been added.
2022-07-13 21:08:15 +02:00
daniel.zatovic
a2afe0396f Split manual pages into per-action page and use AsciiDoc format
Use pre-generated man pages in make dist.

[Added fixes and updates from Ondrej Kozina and Milan Broz]
2022-07-13 21:08:02 +02:00
daniel.zatovic
fec2517386 CI: enable Asciidoctor 2022-07-13 16:03:35 +02:00
Ondrej Kozina
c413434715 Add error message for failed in-use auto-detect.
When reencrypting image files cryptsetup is unable to
detect reliably if image file is in use or not.

User must decide it explictly. Add error message that
references --force-offline-reencrypt to solve the issue
in non interactive mode.

(It will be replaced with early detection in before 2.5.0 final
release).
2022-07-13 10:56:17 +00:00
Milan Broz
aa126ac10a Remove dracut plugin that is obsolete and will not work with current reencrypt code. 2022-07-12 17:58:48 +00:00
Ondrej Kozina
56d4e9924e Add LUKS2 reencryption mangle tests. 2022-07-12 14:05:03 +02:00
Ondrej Kozina
a60fd0a81b Do not fail LUKS2 validation by newer online-reencrypt requirement.
Do not invalidate LUKS2 format when future online-reencrypt
requirement flag is encountered (by older releases).
But it must stop device from being activated, reencrypted
or modified.
2022-07-12 14:05:03 +02:00
Ondrej Kozina
af68e8a1da Check for multiple online reencrypt requirement flags.
Having multiple online-reencrypt requirements flags
candidate in config section should invalidate LUKS2
metadata.
2022-07-12 14:05:03 +02:00
Ondrej Kozina
13f6dfa61f Add proper version data to reencryption verification digest.
LUKS2 decryption requires new online-reencrypt version
flag (v3).

The verification digest performs coding
for version suffix in "online-reencrypt-v" flag string
as follows:

'v1' :  unused (no digest)
'v2' :  0x30 + 2   = 0x32 = '2'
'v3' :  0x30 + 3   = 0x33 = '3'
(...)
'v10':  0x30 + 10  = 0x3A = ':'
'v11':  0x30 + 11  = 0x3B = ';'
(...)
'v207': 0x30 + 207 = 0xFF
2022-07-12 14:03:25 +02:00
Ondrej Kozina
8493f6afd5 Change size of requirement version to 1 byte.
Mostly due to reencryption verification routine
currently expects only single byte of version
data to create digest from.
2022-07-12 13:54:24 +02:00
Milan Broz
1a55b69a0f Fix leak of dm target structure.
The dmd_source need to be cleared with dm_targets_free().
2022-07-07 09:17:13 +00:00
Milan Broz
914f621251 Do not use uninitialized memory for cipher check.
We do not care about the bufer content, but valgrind do, just wipe
the buffer before test.
2022-07-07 09:17:13 +00:00
Milan Broz
5904516122 Skip reencryption test if required ciphers are not available in userspace.
This happens for some very old systems like CentOS6 or own compiled
crypto libraries.
2022-07-05 15:08:43 +02:00
Milan Broz
4507ced868 Report failure if userspace cannot use specified cipher.
Reencryption require support both for kernel and userspace library.

If only kernel supports the copher, the error was quiet.
2022-07-05 15:07:33 +02:00
Milan Broz
b4603f1e28 Fix valgrind test in compat-test. 2022-07-04 14:34:04 +02:00
Petr Pisar
1c21c24f7b po: update cs.po (from translationproject.org) 2022-07-04 09:36:22 +02:00
Ondrej Kozina
0009d9532e Extend LUKS2 decryption with datashift API tests. 2022-06-30 11:21:38 +02:00
Ondrej Kozina
47cb9b0ee2 Fix copy&paste mistake in exclusive open comment. 2022-06-27 16:01:50 +02:00
Ondrej Kozina
0ffd105cb8 Harden LUKS2 decryption with datashift parameters.
Abort early if detached header is passed in API
by any chance.
2022-06-27 16:01:50 +02:00
Ondrej Kozina
24d498e393 Add debug message in LUKS2 reencryption initialization. 2022-06-27 16:01:50 +02:00
Ondrej Kozina
3c8b3201d7 Improve crypt_reencrypt_status return values.
Empty context or any non-LUKS types now returns
CRYPT_REENCRYPT_INVALID value.

For LUKS1 devices return CRYPT_REENCRYPT_NONE
(since any LUKS1 device in legacy reencryption
does not have valid LUKS1 header/metadata).
2022-06-27 16:01:50 +02:00
Ondrej Kozina
f531b567e0 Test reencryption initalization error path.
Test cli behaves properly when there's not enough
space in keyslots area for new unbound keyslot or
reencryption keyslot.

Fixes: #688.
2022-06-27 16:01:43 +02:00
Jakub Bogusz
7c76881921 po: update pl.po (from translationproject.org) 2022-06-24 15:19:10 +02:00
Milan Broz
f642417ed7 Add check to LUKS1 convert for segments count. 2022-06-23 07:24:27 +02:00
Milan Broz
1c1df24258 Clean up convert code style.
Remove FIXMEs and comment style.
2022-06-23 07:10:22 +02:00
Milan Broz
b3e8e1a9d4 Log visible error if convert fails due to validation check 2022-06-23 07:08:42 +02:00
Milan Broz
d22b003640 Fix possible keyslot area size overflow during convert to LUKS2
If keyslots are not sorted according to binary area offset,
the calculation of area size is wrong and can overflow
(LUKS1 does not store area size, only offset).

Let's just use function that calculates size from volume key size.
Images where keyslot areas are not aligned to 4k offset
are not supported anyway.

Fixes: #753
2022-06-23 07:06:38 +02:00
Ondrej Kozina
a485f44b57 Fix decryption with datashift initialization.
It did not work with --active-name option for
active LUKS2 devices.
2022-06-21 15:27:43 +02:00
Ondrej Kozina
f182d73001 Speed up reencryption tests.
By not testing repeatedly that 'wipe' test utility actually
wipes the device. This test is supposed to test reencryption
code.

I have left untouched already existing first time checks
for each data digest.
2022-06-21 10:47:42 +02:00
Yuri Chornoivan
05fc7b172d po: update uk.po (from translationproject.org) 2022-06-20 17:30:20 +02:00
Hiroshi Takekawa
66c5b52b42 po: update ja.po (from translationproject.org) 2022-06-20 17:30:20 +02:00
Frédéric Marchal
af3559a0f6 po: update fr.po (from translationproject.org) 2022-06-20 17:30:20 +02:00
Roland Illig
bcde337a42 po: update de.po (from translationproject.org) 2022-06-20 17:30:20 +02:00
Yuri Chornoivan
83103627b2 Fix minor typo.
Fixes: #752
2022-06-20 11:37:44 +00:00
Milan Broz
8f8703f1c3 Update cryptsetup.pot. 2022-06-17 19:58:31 +02:00
Milan Broz
857d17d210 Fix makefile to include wipe-test in dist tarball. 2022-06-17 19:57:31 +02:00
Milan Broz
62a3954c9d Add a debug message after crypt_load in error path. 2022-06-17 19:30:35 +02:00
Milan Broz
c72aecf86d Add comment to validation code. 2022-06-17 16:08:52 +02:00
Milan Broz
d9b66afe5e Replace json_bool with stdbool.
This is some relict from old code, just use bool, we already
require it elsewhere.
2022-06-17 16:04:31 +02:00
Milan Broz
18ada2b7de Check for interval overflow in LUKS2 validation code.
Invalid values that overflows in interval check were silently ignored.

Fix this by explictily adding check for interval overflow in keyslots
and segment validation.

Fixes: #748
2022-06-17 16:03:32 +02:00
Milan Broz
279490b622 Add test for keyslot area overflow during validation. 2022-06-17 16:03:32 +02:00
Milan Broz
dfd96d8a39 Report uint64 overflows and conversion errors in log debug during LUKS2 validate. 2022-06-17 16:03:30 +02:00
Milan Broz
ba9e36ceae Add empty string check to LUKS2 JSON validation.
Most of the LUKS2 fields cannot be empty,
add check for JSON validation for it to fail early.

Fixes: #746
2022-06-17 14:46:50 +02:00
Ondrej Kozina
f97af5dcfe Add LUKS2 decryption with datashift tests. 2022-06-17 13:48:15 +02:00
Ondrej Kozina
b4e9bca354 Enable LUKS2 decryption datashift support in cli.
Fixes: #669.
2022-06-17 13:48:12 +02:00
Ondrej Kozina
c36f9899cf Add support for LUKS2 decryption with datashift.
Adds support for LUKS2 decryption of devices with a
header put in the head of data device. During the initialization
header is exported to a file and first data segment
is moved to head of data device in place of original header.

The feature introduces several new resilience modes (combination
of existing modes datashift and "checksum" or "journal").
Where datashift resilience mode is applied for data moved towards
the first segment and first segment is decrypted in-place.

The mode is not backward compatible with prior LUKS2 reencryption
and therefor interrupted operation in progress can not be resumed
using older cryptsetup releases.

Fixes: #669.
2022-06-17 13:48:12 +02:00
Ondrej Kozina
f3a46b8e93 Check user provided correct passphrase before initializing decryption.
It would fail later anyway (due to wrong passphrase provided) but
it's better to stop sooner.
2022-06-17 13:48:12 +02:00
Ondrej Kozina
b84132c140 Wrap some long lines. 2022-06-17 13:48:12 +02:00
Ondrej Kozina
90ff707bff Move load_luks2_by_name helper. 2022-06-17 13:48:12 +02:00
Ondrej Kozina
f00d897240 Wipe unused area after reencryption with datashift in forward direction. 2022-06-17 13:48:12 +02:00
Ondrej Kozina
daa2b60d62 Sync signature wipes in tools_wipe_all_signutares. 2022-06-17 13:48:12 +02:00
Ondrej Kozina
4892b24d6a Add options parameters to tools_wipe_all_signatures routine. 2022-06-17 13:47:48 +02:00
Ondrej Kozina
369a18cd3b Rename sector size related variables. 2022-06-14 17:11:25 +02:00
Ondrej Kozina
2240e75bb9 Add proper error message for invalid device_size reencryption argument. 2022-06-14 15:31:52 +02:00
Ondrej Kozina
3a4e38736c Rename variable used to store total reencryption data size. 2022-06-14 15:31:52 +02:00
Ondrej Kozina
dff34a1251 Check datashift value against larger sector size.
For example it could cause an issue if misaligned to 4K sector
size during decryption.
2022-06-14 15:31:52 +02:00
Ondrej Kozina
c08aa21a93 Move datashift alignment verification to reencrypt_verify_resilience_params. 2022-06-14 15:31:52 +02:00
Ondrej Kozina
cbf82733ae Clarify error message about invalid datashift value. 2022-06-14 15:31:52 +02:00
Ondrej Kozina
75e429b8d1 Simplify LUKS2 sector_size helpers. 2022-06-14 15:31:52 +02:00
Ondrej Kozina
e23992d531 Fix bug in json_segment_get_sector_size.
Upper layers always expected 0 on error.
Due to this bug this function could cause
sector_size overflow when segment definition
did not contain 'sector_size' field ('linear').
2022-06-14 15:31:52 +02:00
Milan Broz
f881092bbc tcrypt: fix EPERM return code
If some kdf are not available, we incuidentally returned EINVAL
error code instead od EPERM.

This caused that error message is not correctly printed and also
retry count is not applied.

Fixes: #745.
2022-06-13 12:45:22 +02:00
Ondrej Kozina
ba37298e4f Add debug message in validation code for missing key digest. 2022-06-09 12:03:14 +02:00
Ondrej Kozina
98ca9c61d6 Add new internal state marking resilience type as not set. 2022-06-09 12:03:14 +02:00
Ondrej Kozina
ee5a7d19c9 Simplify reencrypt_update_flag usage due to version support. 2022-06-09 12:03:14 +02:00
Ondrej Kozina
7b4d5fe067 Provide routine for setting LUKS2 requirement with version. 2022-06-09 12:03:14 +02:00
Ondrej Kozina
07f8dfc46d Write updated LUKS2 reencrypt keyslot immediately. 2022-06-09 12:03:14 +02:00
Ondrej Kozina
99a3d328f0 Harden checksum resilience parameters verification. 2022-06-09 12:03:14 +02:00
Ondrej Kozina
e8ec3e1005 Allocate buffer for checksum resilience on-demand. 2022-06-09 12:03:14 +02:00
Ondrej Kozina
007e56727c Refactor reencrypt_recover_segment. 2022-06-09 12:03:14 +02:00
Ondrej Kozina
4de09ace8f Minor code refactoring in reencryption loop. 2022-06-09 12:03:14 +02:00
Ondrej Kozina
97b88d878e Refactor internal reencrypt_hotzone_protect_final.
Avoid passing whole reencryption context when not
needed.
2022-06-09 12:03:14 +02:00
Ondrej Kozina
b43ca18c64 Postpone reencryption dm segments refresh.
Refresh (and therefore suspend hotzone) reencryption dm
segments in-before actual hotzone reencryption takes place.

This commit shortens time window during which hotzone is
suspended. Also it avoids eventual deadlock if reencryption process
triggers page miss during storage wrapper reinitialization and required
data is stored in (previously) suspended hotzone (corner case).
2022-06-09 12:03:14 +02:00
Ondrej Kozina
0768d3be84 Cleanup existing assert usage in LUKS2 json code. 2022-06-09 12:03:14 +02:00
Ondrej Kozina
828cfdb6a2 Reduce code duplication in LUKS2 requirements handling. 2022-06-09 12:03:14 +02:00
Ondrej Kozina
582f2c3449 Replace memset with crypt_safe_memzero where reasonable.
Better safe than sorry.
2022-06-09 12:03:14 +02:00
Ondrej Kozina
bf0d0203e8 Add routine for erasing resilience structure. 2022-06-09 12:03:14 +02:00
Ondrej Kozina
b75a6d2b64 Properly update hash parameter for checksum resilience.
Checksum hash parameter obtained via API call can not be used directly.
It gets lost during subsequent call to crypt_reencrypt_init_by_* API
when library reloads crypt context.
2022-06-09 12:03:14 +02:00
Ondrej Kozina
450265c153 Separate reencryption params verification for update. 2022-06-09 12:03:14 +02:00
Ondrej Kozina
cfb54be9a3 Refactor reencrypt_length() function. 2022-06-09 12:03:14 +02:00
daniel.zatovic
828ddad7c2 CI: add Alpine Linux runner 2022-06-09 09:46:51 +00:00
Milan Broz
dd3fe9f5fd Check cipher before LUKS conversion to LUKS2.
There are some historic incompatibilities that are ignored
for LUKS1 but do not work for LUKS2.

Check the cipher before conversion through crypto backend.

Also it switches LUKS2_check_cipher to use userspace backend only
(this should be ok for the reencryption code that uses it too).

Fixes: #641
2022-06-09 08:50:15 +00:00
Ondrej Kozina
692bb8a455 Properly define uint32_t constants in API.
We do not change any value but it was not declared properly
and limit values had to be type cast to avoid compiler warnings
with strict options.
2022-06-07 11:30:34 +02:00
Milan Broz
6ac27f50ad Print output of symver attribute check in autoconf. 2022-06-06 07:29:38 +00:00
Milan Broz
93f90bf0f7 Do not report FIXME and empty blocks in LGTM. 2022-06-05 20:42:08 +02:00
Milan Broz
e921991ba5 Annotate LGTM TOCTOU condition.
The race here is not avoidable.
2022-06-05 20:38:22 +02:00
Milan Broz
4913de11fc Remove condition that is always true. 2022-06-05 20:29:52 +02:00
Milan Broz
82a6ae3c25 Remove condition that is always true. 2022-06-05 20:27:52 +02:00
Milan Broz
ddc8c9c441 Use %s for JSON progress print. 2022-06-05 20:26:20 +02:00
Milan Broz
fc49a258bd Add configuration file for lgtm analyser. 2022-06-04 22:30:22 +02:00
Ondrej Kozina
a1734e2d52 Revalidate LUKS2 reencrypt keyslot after update. 2022-05-26 12:13:06 +00:00
Ondrej Kozina
8f97d9b6e6 Do not refresh reencryption digest when not needed.
Due to commit 0113ac2d88
we recalculate reencryption digest whenever LUKS2 reencryption
keyslot gets updated. Until now we perform reencryption digest
refresh every time we call LUKS2_keyslot_reencrypt_update even
when no metadata was updated.

This improves on it and should speed up reencryption resume
process.
2022-05-26 12:13:06 +00:00
Ondrej Kozina
fa12a0a490 Add missing translation tag. 2022-05-26 12:13:06 +00:00
Ondrej Kozina
d9dad29149 Move LUKS2 reencrypt keyslot update procedure.
The LUKS2 reencrypt keyslot update process should
not be performed in crypt_reencrypt_run() loop where
data reencryption takes place.

The proper location is reencryption process initialization
when we validate reencryption metadata and decide if
new user provided resilience metadata are valid.
2022-05-26 12:13:06 +00:00
Ondrej Kozina
fc4b2cab25 Store proper resilience data in LUKS2 reencrypt initialization.
Prior to commit 0113ac2d88 it did
not matter what resilince metadata we stored during initialization.
So we stored 'none' type unless 'datashift' operation was initialized.

After the commit, it triggered reencryption metadata digest refresh
almost each time (except 'datashift') which was suboptimal.

By storing proper resilience type during reencryption initialization
we will avoid the needless reencryption digest refresh later (after
update optimization).
2022-05-26 12:13:06 +00:00
Ondrej Kozina
d9eff7ffd7 Test passed resilience parameter is not NULL. 2022-05-26 12:13:06 +00:00
Ondrej Kozina
2820626f5e Move LUKS2_keyslot_reencrypt_allocate function.
It does not fit internal LUKS2 keyslot API so
there's no need to hook it in it.
2022-05-26 12:13:06 +00:00
Ondrej Kozina
1cdb7da2ad Fix mem leaks on error path in reenc_keyslot_alloc. 2022-05-26 12:13:06 +00:00
Ondrej Kozina
e00eecf9ca Remove unused union member. 2022-05-26 12:13:06 +00:00
Ondrej Kozina
346f104f26 Move internal structure definition to internal header file. 2022-05-26 12:13:06 +00:00
Ondrej Kozina
082d23af92 Store data_shift value in rp structure.
data_shift value is part of recovery data
and should be stored in rp structure instead.
2022-05-26 12:13:06 +00:00
Ondrej Kozina
392b0136dc Store checksum protection data block size in rp structure.
The structure is supposed to store all data necessary to perform
reencryption crash recovery. The data block size stored
in LUKS2 metadata was missing and stored in reencryption top level handle
instead.
2022-05-26 12:13:06 +00:00
Ondrej Kozina
3a4ced84a6 Release lock on reencryption initialization error path. 2022-05-26 12:13:06 +00:00
Milan Broz
16c35d155a Fix error message for LUKS2 only cryptsetup commands.
Some cryptsetup commands requires LUKS2 device, but message
"not a LUKS device" is printed. Just change it to LUKS2.

Fixes: #741
2022-05-26 10:17:34 +02:00
Milan Broz
97a22c27dd Make crypt_load quiet if metadata is not detected.
Ths will allow automatic scan of known formats.

Errors are printed only if something is wrong with already detected metadata.

This change means that it is responsibility of the caller to print an error
message if needed.

Also fix some places without a message.

Fixes: #642
2022-05-26 10:17:32 +02:00
Milan Broz
bce9bd3a3b Use better error message for incompatible dm-integrity metadata.
If cryptsetup/integritysetup tool is too old, it can happen that
kernel dm-integrity uses more recent version of dm-integrity metadata.

Print (and also traslate) better error in this case.

Fixes: #667
2022-05-26 06:44:53 +00:00
Milan Broz
59692e3ca2 Add a test for LUKS2 integrity with detached header. 2022-05-26 06:44:53 +00:00
Milan Broz
39fda3bed1 Properly deactivate integrity device even if LUKS2 header is not available.
If LUKS2 is used with integrity protection, there is always a dm-integrity
device underneath.

We should deactivate the device if DM status return tag size (it means,
that dm-crypt uses dm-integrity DIF).

This allows "cryptsetup close <name>" peroperly remove both stacked devices
even if LUKS2 header is no longer available (like in detached header activation).
2022-05-26 06:44:53 +00:00
Milan Broz
2d2f230c9d Allow use of --header option for cryptsetup close.
This can have perhpas only one use - checking that
activated device has the same UUID.
2022-05-26 06:44:53 +00:00
Milan Broz
4dd514a12f Fix activation of LUKS2 device with integrity and detached header.
While the metadata device is detached header here, integrity
superblock is located on the data device.
For standalone integrity device it is diffferent
- data device contains only data and possible metadata device
contains integrity superblock and tag areas.

Fix it by checking metadata format.

Fixes: #609,#730
2022-05-26 06:44:53 +00:00
Milan Broz
7e6c48f67c integritysetup: mention and test xxhash64 non-crypto hash
Fast xxhash64 algoritm can be used for integrity protection.
Add implicit tag size (so user do not need to use --tag-size),
mention it in man page and add a test.

Fixes: #632
2022-05-24 14:36:25 +00:00
Milan Broz
360bd7f68d integritysetup: clarify format question message and man page if data device is used
If existing data device is used, user must specify --no-wipe option
otherwise data device is wiped.
(Tags then can be recalculated on activation with --integrity-recalculate option).

Fixes: #679
2022-05-24 14:36:25 +00:00
Vojtech Trefny
f1fd38c726 bitlk: Add warning when activating device with wrong size 2022-05-24 06:48:26 +00:00
Vojtech Trefny
795b37d128 bitlk: Add BitLocker volume size to dump 2022-05-24 06:48:26 +00:00
Milan Broz
5aa01da2b5 Fix two more lowercase ARG macro undefs. 2022-05-24 08:46:54 +02:00
Daniel Parks
3341bfd6c5 The ARG macro should be uppercased when undefining it
This isn't a bug right now, but it could be in the future if ARG is
used in a different context.
2022-05-23 17:26:48 +00:00
Vojtech Trefny
6c73057156 integrity: Fix integrity_key_size for algorithms without keys
INTEGRITY_key_size returns -EINVAL for algorithms without a key
and because crypt_params_integrity.integrity_key_size is an
unsigned integer we get key size 4294967274 instead of more
appropriate 0 for these algorithms.
2022-05-22 19:58:00 +02:00
Milan Broz
5d9e362553 Make CRYPT_WIPE_ENCRYPTED_ZERO obsolete.
It was never implemented (the idea was to speed up wipe), but
with the recent RNG performance changes it makes no longer sense.
2022-05-18 16:39:53 +02:00
Milan Broz
4d6e9e7c32 Add crypt_wipe unit test.
It uses simple C wrapper aroung crypt_wipe() libcryptsetup
and then bash test scripts wipung simple file and block device.
2022-05-18 16:39:48 +02:00
Milan Broz
227fdb7393 Fix init for util_wipe call.
It should init crypt, as it uses RNG.

Also it should fail early if no device is initialized.
2022-05-18 16:39:43 +02:00
Milan Broz
251eb37c4a Do not try to print NULL string in destructor. 2022-05-18 16:39:38 +02:00
Milan Broz
0009089855 Add ZEROOUT ioctl support for crypt_wipe.
For block devices we can use in-kernel BLKZEROOUT ioctl,
that should be faster in most cases.

This cannot be used for images in files.
2022-05-18 16:39:30 +02:00
Milan Broz
41d61df667 Set loopback sector size according to verity block sizes.
Verity block size has the same limits, so we can optimize
loop device this way.
2022-05-18 09:57:48 +00:00
Milan Broz
8945f3e9e2 Add per-keyslot options to man page.
Some options were missing for LUKS2 luksAddKey and luksChangeKey.

Fixes: #720
2022-05-17 14:37:24 +02:00
Milan Broz
8606865e15 Avoid using top_srcdir in SOURCES. 2022-05-11 09:36:26 +00:00
Milan Broz
9e7894081f Verity: dump device sizes.
Calculating device sizes for verity devices is a little bit tricky,
Data, hash and FEC can share devices or it can be a separate devices.

This patch prints used device sizes in veritysetup dump command,
but it requires that user specifies all values that are not stored
in superblock (like a FEC device and FEC roots).
2022-05-09 22:48:59 +02:00
Milan Broz
0c80ee6c28 Move verity dump to per-format directory. 2022-05-09 13:47:16 +02:00
Milan Broz
853abf53f5 Fix debug message for crypt_activate_by_signed_key.
If name is not uses, there are two spaces.
Also it is more readable now.
2022-05-09 13:46:58 +02:00
Milan Broz
3173595fc9 Avoid using bash arrays in verity test.
This will break on every small change (as in following patch).
Just grep the key word as used elsewhere.
2022-05-09 13:46:24 +02:00
Milan Broz
ede2a8a45f Add some basic UTF conversion function test.
Used only in bitlk format.
2022-05-03 15:48:09 +00:00
Milan Broz
6631033d8a Fix cryptsetup manpage to use PBKDF consitently.
Fixes: #738
2022-05-02 08:01:06 +02:00
Fabrice Fontaine
fe3878199c configure.ac: replace argp_usage check
Replace check for argp_usage by argp_parse as argp_usage is not used by
cryptsetup. Moreover, this will fix the following build failure raised
with argp-standalone in version 1.4.0 and
e7ff8d9787:

/home/autobuild/autobuild/instance-10/output-1/host/lib/gcc/i686-buildroot-linux-musl/10.3.0/../../../../i686-buildroot-linux-musl/bin/ld: tokens/ssh/cryptsetup_ssh-cryptsetup-ssh.o: in function `parse_opt':
cryptsetup-ssh.c:(.text+0x14c): undefined reference to `argp_state_help'
/home/autobuild/autobuild/instance-10/output-1/host/lib/gcc/i686-buildroot-linux-musl/10.3.0/../../../../i686-buildroot-linux-musl/bin/ld: tokens/ssh/cryptsetup_ssh-cryptsetup-ssh.o: in function `main':
cryptsetup-ssh.c:(.text+0x7db): undefined reference to `argp_parse'

Fixes:
 - http://autobuild.buildroot.org/results/cb3fdae4e0da603f304501f65127800346cb3915

Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
2022-04-28 17:24:35 +00:00
Milan Broz
2bf0f537f6 Add constant time memcmp and use it for comparing keys.
There is perhaps no problem now, but it is a good practise to use
constant time for key comaprison to avoid possible side channel
issues.
2022-04-28 15:19:23 +00:00
Milan Broz
4f44bb40b7 Do not print full help in CI clang scan_build. 2022-04-28 12:56:59 +00:00
Milan Broz
3ee0b37303 Use absolute path for compilers scripts.
Then make check-programs in tests directory works.
2022-04-28 12:56:59 +00:00
Milan Broz
a25d10407d Fix some scan build warnings for api-test-2. 2022-04-28 12:56:59 +00:00
Milan Broz
ae3ce2a207 Compile test also programs tests dir. 2022-04-28 12:56:59 +00:00
Milan Broz
2d8cdb2e35 Add unit test fo some functions in utils_crypt.c. 2022-04-28 08:11:58 +00:00
Milan Broz
ceed3c0c3b Introduce crypt_log_hex helper and use it for log_std output. 2022-04-28 08:11:58 +00:00
Milan Broz
e161cd1859 Add constant time crypt_bytes_to_hex helper and use it in libdevmapper.
Fixes: #736
2022-04-28 08:11:58 +00:00
Milan Broz
ff14c17de7 Use constant time conversion for crypt_hex_to_bytes.
We use hexa conversions for keys, avoid possible
leaks with cover channels by making these functions
constant time.
2022-04-28 08:11:58 +00:00
Ondrej Kozina
1ac6a58475 Simplify LUKS2_segment_first_unused_id(). 2022-04-27 11:50:48 +02:00
Ondrej Kozina
2dbd96ebbf Fix LUKS2_get_data_size function.
The function wrongly expected segment objects being
ordered (ascending order) in segments container.

The LUKS2 format never guaranteed that and it could
lead to wrong LUKS2 device size calculation in case
last segment (by key) was stored before any other segment
with fixed size.
2022-04-27 11:44:51 +02:00
Ondrej Kozina
a29f74b5ad Silent reencryption by volume key passed in file.
It emitted confusing error message. It's expected
new volume key would not match the existing one.
2022-04-26 05:46:01 +00:00
Ondrej Kozina
cc107ee20e Silent crypt_volume_key_verify call.
And moves the error message in tools instead.
2022-04-25 19:47:09 +00:00
Ondrej Kozina
c67db10c22 Do not allow sector size increase reencryption in offline mode.
The eventual logical block size increase on dm-crypt device above
filesystem block size may lead making fs unusable. Do not allow
offline reencryption when sector size increase is requested.

If users really want to perform it make them use existing
--force-offline-reencrypt option.
2022-04-25 12:18:33 +02:00
Ondrej Kozina
65a5943ee5 Check sb block size only if actual sector size gets increased. 2022-04-25 09:55:55 +02:00
Ondrej Kozina
5a8b95aa45 Clarify clean up path of empty dm_target structure. 2022-04-22 15:02:41 +00:00
Milan Broz
f391f4baf1 Fix memory leaks in integrity resize with keyed parameters.
The whole game with reallocating keys is not needed.

(Perhaps not even for crypt type, but that is not part of this patch).
2022-04-22 11:34:13 +02:00
Milan Broz
4cdcd908f4 Fix memory leak in integrity resize api-test. 2022-04-21 08:21:01 +00:00
Milan Broz
1d6a445e43 Fix integrity api-test.
The journal crypt is in wrong format (this never worked! :),
here it takes kernel syntax.
Also use CBC a CTR mode could be missing here.

Fox typo in key length caclulation.

Clear temporary dm devices after test, loop devices are reused.

If the first device format is ok, all subsequent cals should
be treated as an error.
2022-04-21 08:21:01 +00:00
Milan Broz
ed13852899 Fix reload integrity device.
The offset cannot be referenced from the crypt union for integrity type.

Keyring setting key works only for crypt devices.

Also reformat long lines.
2022-04-21 08:21:01 +00:00
Milan Broz
efc1590405 Fix formatting warning for a 32bit arch. 2022-04-21 08:21:01 +00:00
Milan Broz
4b1ba47ca1 Avoid compilation warning if configured with --disable-blkid. 2022-04-20 16:08:58 +00:00
Milan Broz
e4a0d25315 Fix missing batch option in test. 2022-04-20 16:08:58 +00:00
Milan Broz
81a63aca22 Fix tests if compiled with --disable-blkid.
Note that htere are some systems with blkid but without
blkid support for secondary LUKS2 header (CentOS6 for example).
2022-04-20 16:08:58 +00:00
Milan Broz
ebabf3ffee Add compile-in flag to program version output.
Then we can check if tools are compiled with a support for specific
extension/library.
2022-04-20 16:08:58 +00:00
Milan Broz
3363bad8c2 Speed-up tcrypt test.
We can limit hash and cipher to not scan all variants here.
2022-04-20 14:37:13 +00:00
Milan Broz
773fc0195f Fix typos found by codespell.
Thanks Dimitri Papadopoulos Orfanos for the patch.

Fixes: #734.
2022-04-20 14:37:13 +00:00
Milan Broz
d3ad18ad81 Add compile info to README.
This information was lost when we removed default automake INSTALL file.
2022-04-20 14:37:13 +00:00
Milan Broz
5c7858883c Remove cryptsetup-reencrypt version dump from tests. 2022-04-20 14:37:13 +00:00
Ondrej Kozina
c9da460b6c Do not allow dangerous sector size change during reencryption.
By changing encryption sector size during reencryption we may
increase effective logical block size for dm-crypt active device.

For example if hosted filesystem on encrypted data device
has block size set to 512 bytes and we increase dm-crypt logical
size durign reencryption to 4096 bytes it breaks the filesystem.

Do not allow encryption sector size to be increased over value
provided by fs superblock in BLOCK_SIZE property.

The check is applied while initialising LUKS2 device encryption
(reencrypt --encrypt/--new) or when initialising LUKS2 reencryption
on active dm-crypt device.

Note that this check cannot be applied on offline device (data device
is encrypted).
2022-04-19 13:27:37 +00:00
Ondrej Kozina
38d1f01b12 Add tools helper reporting blkid support. 2022-04-19 13:27:37 +00:00
Ondrej Kozina
624026a98f Refactor reencrypt_get_active_name helper. 2022-04-19 13:27:37 +00:00
Ondrej Kozina
f6452e1656 Add superblock BLOCK_SIZE detection in tools. 2022-04-19 13:27:37 +00:00
Ondrej Kozina
2388777763 Add option to probe only superblocks in blkid. 2022-04-19 13:27:37 +00:00
Ondrej Kozina
be5c5788d4 Add support for superblock BLOCK_SIZE property. 2022-04-19 13:27:37 +00:00
Milan Broz
f1eea3a4b3 Clean reencrypt status struct for API call.
This function should not return unitialized struct as there
is no indication that it failed and caller can access it.

Also fixes a Coverity warning.
2022-04-19 08:53:44 +00:00
Milan Broz
2857e10083 Fix UTF16 buffer overflow in bitlk volume key dump.
It is UTF16, so even the terminating character is char16_t.

(Found by gcc sanitizer.)
2022-04-17 13:59:03 +02:00
Milan Broz
99c4c3adbf Skip question if batch mode is set for volume key bitlk dump.
Other formats use the same logic.
2022-04-17 13:58:08 +02:00
Milan Broz
f34b3b27ec Do not use definitions in for cycle. 2022-04-15 21:44:52 +02:00
Milan Broz
ab6762b849 Fix possible missing uchar.h. 2022-04-15 21:43:45 +02:00
Milan Broz
3fbc480e32 Clean headers for utf8 wrapper. 2022-04-15 21:22:07 +02:00
Milan Broz
ce1c39dc54 Properly report if sectior size cannot be used for bitlk activation. 2022-04-15 21:02:52 +02:00
Milan Broz
9b60e2d959 Add some tests for invalid keyslot JSON objects. 2022-04-14 10:28:20 +00:00
Milan Broz
e89071e73f Fix keyslot JSON validation.
If keyslot JSON is corrupted (kdf,af,area objects),
validate function can crash.

Fix it by always using JSON type check.

Fixes: #731
2022-04-14 10:28:20 +00:00
Ondrej Kozina
dbd4dc1dc0 Speedup reencryption tests. 2022-04-13 16:23:01 +02:00
Ondrej Kozina
acd2601bd7 Drop unused code in lib/utils_blkid.c 2022-04-13 16:16:57 +02:00
Ondrej Kozina
d56ccc97b8 Detect broken LUKS metadata in-before encryption.
We should abort LUKS device in-place encryption
when target data device or metadata device
contain broken LUKS metadata (any version).
Filed crypt_load() call was not good enough check
because the call fails also when a device contains
LUKS metadata overlapping with other superblock
(e.g. LVM2 PV signature).

Let blkid decide if device contains broken LUKS
metadata or not.

Fixes: #723.
2022-04-11 11:38:56 +00:00
Ondrej Kozina
412de7dc25 Add suport for filtering only LUKS signatures. 2022-04-11 11:38:56 +00:00
Ondrej Kozina
8c350b65a3 Prepare tools_detect_signatures for new filter type. 2022-04-11 11:38:56 +00:00
Milan Broz
83ef36bd59 Add tests for LUKS2 JSON mangled top-level objects. 2022-04-09 21:27:09 +02:00
Milan Broz
c07cfa20de test generators: unify checksum check functions 2022-04-09 21:25:55 +02:00
Milan Broz
6d8587c137 test generators: unify kill header check functions 2022-04-09 21:25:55 +02:00
Milan Broz
d43b495f21 test generators: unify mangle & kill header functions 2022-04-09 21:25:55 +02:00
Milan Broz
e97238fb6d test generators: use one common cleanup function 2022-04-09 21:25:55 +02:00
Milan Broz
c9ead0482d test generators: use one common prepare function 2022-04-09 21:25:55 +02:00
daniel.zatovic
9c26a73d96 Validate JSON area root objects' types. 2022-04-07 15:29:05 +00:00
Ondrej Kozina
ea35573c82 Ask user for confirmation before resuming reencryption.
The prompt is not showed in batch mode or when user
explicitly asks for reencryption resume via --resume-only.
2022-04-07 13:50:09 +02:00
Ondrej Kozina
d3079c2fb3 Do not resume reencryption with conflicting parameters.
Do not resume reencryption operation with conflicting parameters.
For example if operation was initialized as --encrypt do not
allow resume with oposing parameter --decrypt and vice versa.

Also checks for conflicting --resilience parameters (datashift cannot
be changed after initialization).

Previously, conflicting reencryption parameters were silently ignored.
So, for example operation initialized with mode --encrypt and resumed
with mode --decrypt simply finished --encrypt operation and did not
report any error. This could lead to impresion different type of
operation was perfomed instead.

Fixes: #570.
2022-04-07 13:49:40 +02:00
Ondrej Kozina
b661452e3a Asks offline reencryption confirmation only with image files.
If auto-detection fails for other reason just return the
error. Users may now bypass active device auto-detection
with --force-offline-reencrypt option.
2022-04-07 11:51:41 +02:00
Ondrej Kozina
31c4afbc17 Add --force-offline-reencrypt option.
It can be used to enforce offline reencryption
in batch mode when data_device is regular file
and therefore cryptsetup cannot detect properly
active device dm name.

Also it may be useful when active device
auto-detection fails for some reason and user
has no other choice but inspect device holders
manually.
2022-04-06 22:59:37 +02:00
Ondrej Kozina
496a0e37c4 Active device auto-detection code cleanup. 2022-04-06 22:59:35 +02:00
Ondrej Kozina
8c04264fb3 Reduce code duplication in active device auto-detection. 2022-04-06 22:57:13 +02:00
Milan Broz
db1ff4cf88 Silence false positive Coverity warning.
The init_keyslot_passwords() allocates properly sized arrray here.
2022-03-30 17:53:14 +02:00
Milan Broz
3e4368feeb Use link to main branch. 2022-03-30 13:08:57 +02:00
Milan Broz
faee0e694f Use main branch in GitHub CI. 2022-03-30 13:07:55 +02:00
Milan Broz
7a38f16cef Use volume key in FAQ. 2022-03-29 19:06:38 +00:00
Milan Broz
08aa2ca242 Replace master on a few more places. 2022-03-29 19:06:38 +00:00
Milan Broz
3a56cf05bf Replace mk_ with vk_ name prefix. 2022-03-29 19:06:38 +00:00
Milan Broz
b6c36f50ba Replace name master with volume key.
And keep two tests for compatibility.
2022-03-29 19:06:38 +00:00
Milan Broz
b050448db9 Add aliases for --volume-key-file and --dump-volume-key-file. 2022-03-29 19:06:38 +00:00
Milan Broz
68796e12dd Replace OPT_MASTER_KEY_FILE_ID with OPT_VOLUME_KEY_FILE_ID. 2022-03-29 19:06:38 +00:00
Milan Broz
650c7e8b67 Enable csmock for merge requests. 2022-03-29 15:40:48 +00:00
Milan Broz
0dc18fba22 Fix a leak in error path.
Also fix a warning, all detected by Coverity scan.
2022-03-29 15:40:48 +00:00
Milan Broz
1116289de4 Try to load dm-integrity in api-test. 2022-03-29 14:17:53 +00:00
Milan Broz
1595fcf479 Do not run keyed integrity resize tests for older kernel. 2022-03-29 14:17:53 +00:00
Milan Broz
c4c1ca2224 Use batch mode for integrity resize test. 2022-03-29 14:17:53 +00:00
Ondrej Kozina
2b42968e92 Port cryptsetup --new option to CRYPT_ARG_ALIAS type. 2022-03-29 12:54:58 +02:00
Ondrej Kozina
e2a5af9e64 Add new argument type CRYPT_ARG_ALIAS.
It can be used to easily define option
aliases for command line utilities.
2022-03-29 12:54:15 +02:00
Milan Broz
e4ed545cbf Remove debug line from api-test. 2022-03-28 22:27:54 +02:00
Ondrej Kozina
65be641f20 Refactor LUKS reencryption. 2022-03-24 15:14:32 +00:00
Ondrej Kozina
ce55fa4d1c Refactor LUKS decryption. 2022-03-24 15:14:32 +00:00
Ondrej Kozina
92baacadad Refactor LUKS encryption.
It also adds hardened checks for accidental
nested device encryption.
2022-03-24 15:14:32 +00:00
Ondrej Kozina
2e59229e5a Add checks for some conflicting requests.
It also moves device load for reencryption purposes
further up in code path to better optimize the code
later.
2022-03-24 15:14:32 +00:00
Ondrej Kozina
3f42b69fc8 Add reencrypt_luks2_resume helper.
To be used later.
2022-03-24 15:14:32 +00:00
Ondrej Kozina
b10c0b6a02 Simplify load_luks2_by_name.
Also adds specific error messsage when device
is not actualy LUKS2.
2022-03-24 15:14:32 +00:00
Ondrej Kozina
f388662418 Remove 'type' argument from load_luks helper.
The code removal will help simplify further code
changes.
2022-03-24 15:14:32 +00:00
Ondrej Kozina
8bc10ee853 Rename luks2 reencryption initialization routines. 2022-03-24 15:14:32 +00:00
Ondrej Kozina
b663b9305c Add helper for checking data device type during encryption.
In case operation is invoked with --header parameter
check if data device does not already contain LUKS device
2022-03-24 15:14:32 +00:00
Ondrej Kozina
828555db97 Remove unused code in helper routine. 2022-03-24 15:14:32 +00:00
Ondrej Kozina
ba08f02a40 Move helper for LUKS2 auth. encryption detection. 2022-03-24 15:14:32 +00:00
Ondrej Kozina
a55b0530a4 Restrict --active-name to LUKS2 type only. 2022-03-24 15:14:32 +00:00
daniel.zatovic
a2f30ebd4c Display progress when wiping the end of resized device. 2022-03-24 11:38:16 +01:00
daniel.zatovic
d20d41c7a5 Add log messages, when kernel doesn't support resize. 2022-03-24 11:38:16 +01:00
daniel.zatovic
4eba55c73e Add tests for integritysetup resize action. 2022-03-24 11:38:16 +01:00
daniel.zatovic
29ddd68a0f Add API tests for resize of integrity volume. 2022-03-24 11:38:16 +01:00
daniel.zatovic
9707b71f98 Describe resize action in manual page. 2022-03-24 11:38:16 +01:00
daniel.zatovic
36cdda870b Add resize action to integritysetup.
Fixes: #594.
2022-03-24 11:38:16 +01:00
daniel.zatovic
9b8a872006 Add support for resizing raw integrity devices. 2022-03-24 11:38:16 +01:00
daniel.zatovic
45b808c186 Move checking for detached integrity metadata device.
To allow resizing integrity devices with detached metadata device, the
check has to be moved from _compare_integrity_devices to
_reload_device_with_integrity.
2022-03-24 11:38:16 +01:00
daniel.zatovic
87afb9d783 Remove size parameter comparison for integrity devices.
To support device resize, we can not compare the device size (it is
already not compared for crypt devices).
2022-03-24 11:38:16 +01:00
daniel.zatovic
86402a1102 Add API tests for refreshing integrity devices. 2022-03-24 11:38:16 +01:00
daniel.zatovic
64e7c3d3b1 Add support for refreshing integrity devices.
If the provided key is NULL, we load it from the active device. This is
always available, since keyring keys are not supported in kernel for
integrity devices.
2022-03-24 11:38:16 +01:00
daniel.zatovic
f6c1445c6b Add support for querying journal active devices for integrity and encryption keys. 2022-03-18 09:56:59 +00:00
Ondrej Kozina
f5724a30f9 Test nested encryption is not possible. 2022-03-17 19:07:10 +00:00
Ondrej Kozina
47f31205cf Do not allow nested encryption in LUKS reencrypt.
Try to avoid accidental nested encryption via
cryptsetup reencrypt --new/--encrypt command.

If detached header or data device is already reported
as LUKS1 or LUKS2 device operation gets aborted.

Fixes: #713.
2022-03-17 19:07:10 +00:00
Ondrej Kozina
5bd5462a9e Improve helpers for reencryption utilities.
Also clarifies some code path.
2022-03-17 19:07:10 +00:00
Ondrej Kozina
d1f0376c77 Decouple auth. encryption check from in-reencrypt detection. 2022-03-17 19:07:10 +00:00
Ondrej Kozina
dae91fd9ec Code reshuffle in-before some changes. 2022-03-17 19:07:10 +00:00
daniel.zatovic
df4ed89141 CI: disable updates. 2022-03-17 19:04:41 +00:00
Milan Broz
559012b6a7 Check dm-zero availability for bitlk type.
Bitlocker compatible mode uses dm-zero to mask metadata area,
device cannot be activated if dm-zero is not available.

Just add zero target check to device-mapper backend and
if activation fails, print a better error message here.

Fixes: #722
2022-03-16 12:21:30 +01:00
Milan Broz
6534e86c22 Update gitignore. 2022-03-15 13:12:27 +01:00
Milan Broz
70c1eb7352 Support make check-programs target from top level makefile.
Also fix genereated header dependence.
2022-03-15 13:07:10 +01:00
Ondrej Kozina
dee2fa7159 Prefer token PIN query before passphrase in some case.
When user provides --token-type or specific --token-id
prefer token PIN query over passphrase query (if token
handler responds with 'PIN needed').

Fixes: #670.
2022-03-14 17:34:41 +01:00
Ondrej Kozina
3af754b5eb Use proper function parameter in token pin helper. 2022-03-14 17:33:41 +01:00
Ondrej Kozina
3b85ab2dc1 Do not continue operation when interrupted in PIN prompt. 2022-03-14 14:04:36 +00:00
Ondrej Kozina
2a5483d8c3 Add progress function init before reencryption loop.
Otherwise elapsed time tracking is off and also breaks
speed estimation.
2022-03-07 12:35:38 +01:00
Ondrej Kozina
8340d0cb1a Remove useless condition in reencryption loop.
(always true)
2022-03-07 12:35:38 +01:00
Ondrej Kozina
3cd5d83ee9 Add --progress-json parameter to utilities.
Progress data can now be printed out in json format
suitable for machine processing.
2022-03-07 12:35:38 +01:00
Ondrej Kozina
6852c49d0c Merge progress functions into single routine. 2022-03-07 12:35:38 +01:00
Ondrej Kozina
63c79256e4 Refactor time diff calculation helper. 2022-03-07 12:35:38 +01:00
Ondrej Kozina
75622b332b Improve progress routine for cryptsetup utilities.
The progress routine is now fully translated and
prints out progress in following manner (examples):

Progress: 25,5%, ETA 00m31s, 7 GiB written, speed 838,6 MiB/s
Progress: 25,5%, ETA 20h11m31s, 7 GiB written, speed 24 KiB/s
Progress: 25,5%, ETA 06 days, 12 MiB written, speed 4 KiB/s

Also got rid of -lm dependency due to floor().

Fixes: #671.
2022-03-07 12:35:38 +01:00
Ondrej Kozina
c1e94abbab Move progress utilities in separate file. 2022-03-07 12:35:38 +01:00
Ondrej Kozina
1af7eefbc0 Minor time progress print out improvements.
Mostly moves float arithmetics in slow path and
also cleans up code a bit.
2022-03-07 12:35:37 +01:00
Milan Broz
bf4a039d50 Add a debug info if maximum interactive passphrase was read (possible trimmed).
If passphrase is read from a real terminal, there is maximum
interactive input length applied. This means that passphrase
can be trimmed in this case.

This patch adds debug log warning, if read does not detect
end of input (EOL or EOF) and the maximal input read is achieved.

We cannot say for sure if the next character is EOL without
actually reading it, debug warning should be enough in this case.

Fixes: #699
2022-02-25 14:14:03 +01:00
Milan Broz
0085985419 Fix gcc warnings in tests. 2022-02-24 20:28:29 +01:00
Milan Broz
12c35da768 Check all snprintf calls for returning values for tests. 2022-02-24 20:28:25 +01:00
Milan Broz
677e06c48a Check all snprintf calls for returning values. 2022-02-24 20:28:18 +01:00
Milan Broz
c27d6a89bb Add hint for false positive coverity warning. 2022-02-24 14:04:24 +01:00
Milan Broz
e5ce189db8 Add info about broken Intel QAT crypt drivers to FAQ. 2022-02-24 11:05:25 +01:00
Milan Broz
3407cbbad1 Add info about bug report to FAQ and add SECURITY.md file. 2022-02-23 22:20:09 +01:00
Milan Broz
2c91590d52 Add info about CVE-2021-4122 to FAQ. 2022-02-23 21:35:20 +01:00
Milan Broz
c5e500ea0f Add note about fake RAID and data corruption.
Fixes: #714
2022-02-23 21:27:05 +01:00
Milan Broz
5efe03ddd7 Update mailing list info in FAQ. 2022-02-23 21:08:34 +01:00
Ondrej Kozina
8ab41e0776 Improve debug messages while verifying reencryption metadata. 2022-02-23 15:00:11 +01:00
Ondrej Kozina
f671febe64 Add more tests for --test-passphrase parameter. 2022-02-23 15:00:11 +01:00
Ondrej Kozina
0a9f14c658 Fix --test-passphrase when device in reencryption.
Commit 0113ac2d broke test passphrase mode when
device was in LUKS2 reencryption.

Previously --test-passphrase parameter automatically raised
CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY flag. It did not make sense
when users mostly want to test whether device can be activated by
provided passphrase or not. Raise the aforementioned flag only
if user requested it either by --unbound parameter or when
specific keyslot was selected.

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

Fixes: #716.
2022-02-23 15:00:08 +01:00
Ondrej Kozina
6b774e617b Remove unused funtion prototype and few useless comments. 2022-02-23 12:28:20 +01:00
Milan Broz
0d6b63a6a2 FAQ: Use relative links in chapter references. 2022-02-22 12:17:25 +01:00
Milan Broz
6018d2bcd8 Use markdown version of FAQ. 2022-02-22 12:03:37 +01:00
Ondrej Kozina
d5dbde5dd1 Clarify graceful reencryption interruption.
Currently it can be interrupted by both SIGINT and SIGTERM
signals.

Fixes: #715.
2022-02-21 11:38:57 +01:00
Milan Broz
ef7559bad9 Print output of verity test if concurrent check fails.
This tests randomly fails in CI, at least print output if this happens.
2022-02-21 10:13:38 +00:00
Milan Broz
e9e994fb0d Run some io to actually test dm-crypt flags. 2022-02-21 10:13:38 +00:00
Arno Wagner
c5d9f3f380 Typos, additional info on dd use. 2022-02-20 20:19:16 +00:00
Milan Broz
d23943f989 Fix old list archive link. 2022-02-17 19:58:55 +01:00
Milan Broz
b47b89adac Add new list info. 2022-02-17 19:56:00 +01:00
daniel.zatovic
452467661e Support --device-size option for plain devices. 2022-02-13 08:52:39 +00:00
Ondrej Kozina
bef46c950d Properly detect optimal encryption sector size.
Move code setting data device during format so that
we can properly detect optimal encryption sector size
for data device instead of metadata device (header).

Fixes: #708.
2022-02-09 15:43:25 +01:00
Milan Broz
5c323e9146 Remove ssh backgroud option causing spurious test failures.
The keyfile creation must be synchronous, otherwise following command
can fail ("SFTP server: No such file").
2022-02-08 22:12:35 +01:00
Milan Broz
33d8605924 Fix duplicate ssh plugin error message. 2022-02-08 22:12:31 +01:00
Vojtech Trefny
76086dbe95 ssh-plugin-test: Make the test fail if SSH setup fails
We should avoid silently skipping the test if there is something
wrong with the test itself. If we have all dependencies, the test
should be able to run.
2022-02-08 16:10:31 +01:00
Vojtech Trefny
7eb44f32a3 ssh-plugin-test: Copy SSH key manually instead of with ssh-copy-id
ssh-copy-id requires password authentication that might be disabled
on some cloud images. We can simply copy the key manually, because
everything runs on localhost anyway.

Fixes: #701
2022-02-08 16:10:08 +01:00
Milan Broz
cef0dc059a Add missing variable to run ssh plugin test. 2022-02-08 10:45:12 +01:00
Milan Broz
e4091fe8a5 Fix some benign warnings with gcc-12.
The string buffer is large enough, but gcc do not understant it.
Easy to avoid these warnings with a larger buffer here.
2022-02-06 18:03:49 +01:00
Milan Broz
685148af00 Enable new warnings (introduced in gcc-12). 2022-02-06 18:02:41 +01:00
Ondrej Kozina
8798aa0a75 Do not upload keys in keyring during offline reencryption.
Fixes: #696.
2022-02-05 10:29:55 +00:00
Ondrej Kozina
7ca1a233f1 Split reencrypt_verify_and_upload_keys function. 2022-02-05 10:29:55 +00:00
Ondrej Kozina
ab295b1159 Do not resume device when not suspended.
Abort action luksResume early if device is not suspended.
We would needlesly ask for passphrase or load cryptsetup
plugins only to fail later in crypt_resume_by_* API.
2022-02-04 13:41:24 +01:00
Ondrej Kozina
fea648cb1d Add support for crypt_resume_by_token_pin in cryptsetup. 2022-02-04 13:40:22 +01:00
Ondrej Kozina
ce6f6a48e8 Add crypt_resume_by_token_pin API. 2022-02-04 13:40:20 +01:00
Ondrej Kozina
416f1343fe Split LUKS2_activate_by_token. 2022-02-04 13:32:45 +01:00
Ondrej Kozina
388ba9f00d Add explicit tests for command failure in LUKS1 reencryption test. 2022-02-04 11:28:05 +01:00
Ondrej Kozina
e38a184907 Avoid partial read in luks1 reencryption loop.
Starting with kernel 5.17-rc there are some changes
in block layer aiming to block partial I/O in
O_DIRECT mode.
2022-02-04 11:28:05 +01:00
Milan Broz
f2dbab7043 Add more label/susbystem API tests. 2022-02-03 11:43:04 +01:00
Luca Boccassi
2938c1f077 Add crypt_get_label/subsystem
There's an API to set the label and subsystem, and they are
dumped with luksDump, but there's no programmatic interface
to query them.
2022-02-03 10:23:57 +00:00
Milan Broz
95d35ecf4b Allow CI rawhide runner to fail.
As there is often something broken (currently kernel), let's just
set it to allow_failure in CI.
2022-02-03 11:21:48 +01:00
Milan Broz
a1baa01ddd Set higher timeout for interactive tests.
Under heavy load 10 seconds is not enough, just use the same
values as when running under valgrind.
2022-02-03 08:05:11 +01:00
Ondrej Kozina
7ab7365020 Add check program for symver attribute.
Fixes: #709.
2022-02-02 21:30:48 +00:00
daniel.zatovic
43a636d809 CI: Detect core dumps generated during testing 2022-02-02 20:32:53 +00:00
Milan Broz
8531a8a753 Skip more tests if --disable-cryptsetup is used.
If there is no cryptsetup, some tests returns ok while noting was
tested in reality. Just mark them skipped.
2022-02-02 21:29:54 +01:00
Alyssa Ross
c0cef43a4e Skip cryptsetup tests when cryptsetup is disabled
If configured with --disable-cryptsetup (e.g. if only veritysetup is
required), these tests won't be able to run cryptsetup, so they need
to be skipped.
2022-02-02 16:51:49 +00:00
Ondrej Kozina
06b6542b28 Remove -Wno-attributes from -Wall tests.
It breaks compile time check for __attribute__((__symver__))
and it does not make sense either. Quoting gcc man page:

-Wno-attributes

Do not warn if an unexpected "__attribute__" is used, such as
unrecognized attributes, function attributes applied to variables,
etc. This does not stop errors for incorrect use of supported attributes.

Well, we do want to check for unsupported __attributes__ un our code,
right?
2022-02-02 15:05:09 +01:00
Milan Broz
03adc091ce Use tabs in SSH plugin test. 2022-01-29 12:07:38 +01:00
Milan Broz
f85921497c Remove loop device use from SSH plugin test. 2022-01-29 12:07:35 +01:00
Milan Broz
ab975bc1c4 Update copyright year.
And unify format in several places.
2022-01-29 10:43:02 +01:00
Milan Broz
0cb4f59006 Rename encrypt helper function to avoid clash with unistd prototype. 2022-01-29 10:21:06 +01:00
Ondrej Kozina
230b80404d Remove parameters annotated by __attribute__((unused)).
Attribute unused is useless and makes code imcomprehensible
when decorates internal functions not exposed via API.

Let's cleanup internal funtion prototypes whenever possible.
2022-01-28 17:27:00 +00:00
Alex Xu (Hello71)
46efbc0a36 argon2: Don't call _endthreadex/pthread_exit
Returning from the thread creation function is documented to be a valid
way of exiting a thread on both Windows and pthread systems. Removing
the explicit call avoids the need to install libgcc_s.so in initramfs
for glibc systems, and slightly reduces code size.

Upstream: https://github.com/P-H-C/phc-winner-argon2/pull/331
2022-01-28 15:06:08 +00:00
Milan Broz
903dae1b6c Enable clang and gcc cast-align[=strict] warning in CI. 2022-01-26 10:28:57 +00:00
Milan Broz
0b2c4187b0 Workaround clang alignment warnings (Wcast-align) when working with byt arrays.
This should silence similar warnings like
  warning: cast from 'char *' to 'struct xyz *' increases required alignment from 1 to X
when we try to calclulate byte pointer offsets in a buffer.
2022-01-26 10:28:57 +00:00
Milan Broz
c11a83bf0f Enable clang -Wextra and -Wsign-compare build in CI. 2022-01-26 10:28:57 +00:00
Milan Broz
a68eb60be9 Fix clang warnings for integer comparison. 2022-01-26 10:28:57 +00:00
daniel.zatovic
48872e9f2e CI: Save journalctl in artifacts. 2022-01-25 22:24:39 +01:00
daniel.zatovic
bb35a284e8 CI: Save dmesg in artifacts. 2022-01-25 22:24:33 +01:00
Vojtech Trefny
793b7cddaf bitlk: Fix coverity warnings introduced in 6e47fb6d 2022-01-24 17:54:54 +01:00
Ondrej Kozina
161eeb7473 Fix resource leaks in utils_reencrypt.c
Fixes: #703.
2022-01-24 16:29:35 +00:00
daniel.zatovic
71f33418d2 Add FIPS update again. 2022-01-24 12:04:23 +01:00
daniel.zatovic
f4e2daec94 Fix annocheck job. 2022-01-22 22:24:10 +01:00
Milan Broz
34f033b254 Do not use too small key in tests.
Apparently FIPS mode enforces somewhere minimal key size.
As 64bit key is no longer useful anyway, just remove it.

Apparently cipher_null is now more safer with the longer key,
isn't? :-)
2022-01-21 12:30:10 +01:00
Milan Broz
91db91352f Get rid of SHA1 in tests.
OpenSSL with FIPS provider now doesn't not support SHA1.
Kernel still does, but some operations fail anyway (we get
hash size from crypto backend).

Let's remove most of the SHA1 use in tests, SHA1 removal
will happen anyway.

The LUKS1 compatimage is regenerated with the same parameters,
just hash is switched to sha256 so we do not need to fix tests.
2022-01-21 12:29:36 +01:00
Milan Broz
05a237be2a Fix PBKDF benchmark in OpenSSL3 FIPS mode.
OpenSSL now enforces minimal parameters for PBKDF2 according to SP 800-132
key length (112 bits), minimal salt length (128 bits) and minimal number
of iterations (1000).

Our benchmark violates this, causeing cryptsetup misbehave for luksFormat.

Just inrease tet salt to 16 bytes here, it will little bit influence benchmark,
but there is no way back.
2022-01-21 09:47:13 +01:00
daniel.zatovic
cb9a204a98 Remove merge jobs and RHEL 9 FIPS package updates. 2022-01-20 15:10:17 +00:00
daniel.zatovic
bec18489c7 Add new RHEL and CentOS runners. 2022-01-20 15:10:17 +00:00
Milan Broz
f596e48cc4 Increase timeout for interactive input test. 2022-01-20 14:37:31 +01:00
Vojtech Trefny
ae213537ba utf8: Fix clang null pointer dereference warning 2022-01-20 13:01:05 +01:00
Milan Broz
c4e60a7037 Use only default flags for test CI compilation. 2022-01-20 11:27:04 +01:00
Milan Broz
12a07dcdbd Fix scan-build to fail for reported warnings. 2022-01-20 11:16:55 +01:00
Vojtech Trefny
6e47fb6d85 Use custom utf8/16 conversion instead of iconv
We can avoid the additional dependency by using few functions from
systemd.
2022-01-19 17:09:32 +00:00
Ondrej Kozina
e12ce642a1 Fix typo in repair prompt. 2022-01-19 14:31:11 +01:00
Milan Broz
9a1b3a8aff Remove old base64 implementation and switch to crypto_backend.
This completely removes old base64 implementation.
Code was originally taken from coreutils but recent changes
added many new funtions we do not need.
2022-01-18 12:15:20 +01:00
Milan Broz
f1c7a9896d Add base64 wrappers to crypto_backend.
We need LGPL 2.1+ implementation in crypto backend and also this code
is much easier to read and maintain.
2022-01-18 12:15:20 +01:00
Vojtech Trefny
c210c3a665 man: Fix default locking directory in cryptsetup man page
The default location has been changed from /run/lock/cryptsetup to
/run/cryptsetup in 6f4c15b2b2.
2022-01-17 07:31:54 +01:00
Milan Broz
8e27541a3b Relax a little bit warnings in CI and run it in merge requests.
It is almost impossible for contributors to replicate our warnings
if filtered. Let's make it simpler.

Also run clang with extended warnings (some fixes needed).
2022-01-15 16:11:49 +01:00
Guilhem Moulin
1592511fdb Local tests: Add option to avoid treating skipped tests as success.
`make -f Makefile.localtest tests CRYPTSETUP_PATH=/sbin TESTSUITE_NOSKIP=y`
exits with status 77 upon the first skipped test.  This can be useful
when a full test coverage is desired.

As before the test suite exits (with status 1) as soon as a failed (or
skipped when the TESTSUITE_NOSKIP environment variable is defined to
non-empty string) test is encountered.
2022-01-15 11:55:18 +00:00
Guilhem Moulin
cbc143bf95 tests: Replace which calls with command -v.
AFAIK older versions of the POSIX Standard didn't specify a way to
locate commands.  Many operating systems and distributions added a
which(1) utility for that purpose, unfortunately without consistent
behavior across the board.

OTOH POSIX.1-2008 (or was it older?  POSIX.1-2001 mentions it too, but
with a restriction: “On systems supporting the User Portability Utilities
option”) specifies that `command -v` can be used for that purpose:

    https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/utilities/command.html

Moreover the standard adds that if the argument is neither a valid
utility, builtin, shell function nor alias then “no output shall be
written and the exit status shall reflect that the name was not found”.
It's therefore no longer needed to void the error output (spewing error
messages was one of the inconsistent behavior of the different which(1)
utilities).

The upcoming Debian 12 (codename Bookworm) appears to have deprecated
its which(1) utility (as a first step for its removal from the base
system):

    $ which foo
    /usr/bin/which: this version of `which' is deprecated; use `command -v' in scripts instead.

In most places the deprecation notice isn't visible when running the
test suite because most `which` calls run with the error output
redirected to /dev/null, however this is not the case everywhere:

    https://gitlab.com/cryptsetup/cryptsetup/-/blob/v2.4.3/tests/integrity-compat-test#L333
    https://gitlab.com/cryptsetup/cryptsetup/-/blob/v2.4.3/tests/reencryption-compat-test2#L232

This commit replaces all `which` calls from tests/* with `command -v`,
and removes the error output redirection.
2022-01-15 08:50:15 +00:00
Guilhem Moulin
3e160447eb Fix minor spelling error.
(Found by Lintian.)
2022-01-14 15:48:25 +01:00
Milan Broz
5ab106465c Update README. 2022-01-13 10:23:27 +01:00
Milan Broz
79720dabb9 Fix reencrypt mangle test for older jq. 2022-01-13 10:07:38 +01:00
Milan Broz
0bff50a31a Remove reference to missing test. 2022-01-12 18:38:37 +01:00
Milan Broz
c2291a1b9b Add Release Notes. 2022-01-12 18:38:30 +01:00
Milan Broz
f1d7d30dbb Update LUKS2 on-disk description. 2022-01-12 18:38:26 +01:00
Ondrej Kozina
00feca3ce0 Allow reencryption metadata repair from cryptsetup. 2022-01-12 18:38:22 +01:00
Ondrej Kozina
ea47937187 Add CRYPT_REENCRYPT_REPAIR_NEEDED flag.
crypt_reencrypt_status() returns this flag if old
online-reencrypt requirement is detected and reencryption
keyslot digest is missing.

crypt_reencrypt_init_by_passphrase() with same flag applied
repairs (upgrade) reencryption metadata so that
automatic reencryption recovery during activation
is again possible and reencryption operation can be resumed
post CVE-2021-4122 fix.
2022-01-12 18:38:17 +01:00
Milan Broz
f77b26b42b Add reencryption mangle test 2022-01-12 18:38:14 +01:00
Ondrej Kozina
6c8314b297 Make reencryption flag and keyslot inseparable.
LUKS2 validation code now requires reencrypt keyslot together with
online-reencryption flag or none of those.
2022-01-12 18:38:10 +01:00
Ondrej Kozina
59e39e484a Rename LUKS2_keyslot_reencrypt_create function.
The function never writes on-disk. Also removed validation
function call-in since it will be called later before
writing on-disk and metadata does not have to be complete
at the moment of LUKS2_keyslot_reencrypt_allocate call.
2022-01-12 18:38:06 +01:00
Ondrej Kozina
b61ec23e48 Add segments validation for reencryption.
Effective segments during LUKS2 reencryption must
match key characteristics of backup segment
(cipher, sector_size, segment type).
2022-01-12 18:37:52 +01:00
Ondrej Kozina
7420f879e0 Split requirements validation from config section validation. 2022-01-12 14:01:44 +01:00
Ondrej Kozina
7de8ff5ccf Expose json_segment_contains_flag to internal library. 2022-01-12 14:01:04 +01:00
Ondrej Kozina
b4ba1d8758 Move requirement helpers for later changes. 2022-01-12 14:00:57 +01:00
Milan Broz
139d663541 Add disable-luks2 reencryption configure option.
The option --disable-luks2-reencryption completely disable
LUKS2 reencryption code.

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

Devices with online reencryption in progress cannot be activated.

This option can cause some incompatibilities. Please use with care.
2022-01-12 13:58:35 +01:00
Milan Broz
665816ae4d Print better error if resilience hash is not available. 2022-01-12 13:56:46 +01:00
Milan Broz
c522996edc Do not run reencryption recovery when not needed. 2022-01-12 13:56:22 +01:00
Milan Broz
750afe309f Reenc keyslot must have key_size == 1. 2022-01-12 13:55:49 +01:00
Milan Broz
eb220d834d Fix debug message. 2022-01-12 13:55:39 +01:00
Ondrej Kozina
0113ac2d88 Fix CVE-2021-4122 - LUKS2 reencryption crash recovery attack
Fix possible attacks against data confidentiality through LUKS2 online
reencryption extension crash recovery.

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

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

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

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

The fix introduces additional digest protection of reencryption
metadata. The digest is calculated from known keys and critical
reencryption metadata. Now an attacker cannot create correct metadata
digest without knowledge of a passphrase for used keyslots.
For more details, see LUKS2 On-Disk Format Specification version 1.1.0.
2022-01-12 13:50:37 +01:00
Josef Andersson
5a17d677c4 po: update sv.po (from translationproject.org) 2021-12-25 16:19:16 +01:00
Мирослав Николић
629fb68aa8 po: update sr.po (from translationproject.org) 2021-12-25 16:19:16 +01:00
Antonio Ceballos
31b36a410b po: update es.po (from translationproject.org) 2021-12-25 16:19:16 +01:00
Tianjia Zhang
80b2cb213c Fix manual typo. 2021-12-24 16:43:57 +08:00
Sean
f996b9b9e8 Update README.md 2021-12-08 16:44:01 +00:00
Milan Broz
c4b66283fe Run CI on stable branches.
The stable branch is named "v2.<minor>.x".
2021-12-01 22:43:33 +01:00
Milan Broz
feb4d24327 Do not mix tabs and spaces in GitHub CI script. 2021-11-28 21:04:12 +01:00
Milan Broz
8a3716d18c Do not mix tabs and spaces in Gitlab CI script. 2021-11-28 21:02:09 +01:00
Milan Broz
e5534c47e9 Fix tabs in GitLab CI scripts and remove gcc comment.
The -Wall changes according to gcc versions.
2021-11-28 21:00:25 +01:00
Milan Broz
03e4cc6f6d Fix missing backslash in CI. 2021-11-28 20:52:31 +01:00
Milan Broz
7940563131 Add limitation to cryptsetup group again in CI. 2021-11-28 20:50:20 +01:00
Vojtech Trefny
6eae9f6e91 bitlk: Fix support for startup key with new metadata entry
Windows 11 now includes the BitLocker volume GUID in the BEK file
metadata entries. This was previously not included so cryptsetup
refused to open the file because there was an unknown metadata
entry in the startup key.

Fixes: #690
2021-11-28 17:10:25 +01:00
Ondrej Kozina
1c36ddfe73 Unify few reencryption error messages. 2021-11-24 19:58:57 +01:00
Ondrej Kozina
db9991d471 Clarify some variable names in reencryption utils. 2021-11-24 19:58:57 +01:00
Ondrej Kozina
6bc1378ddb Remove LUKS2 encryption data size restriction.
LUKS2 encryption with data shift required remaining
data size (size remaining after substracting --reduce-data-size value)
to be at least --reduce-data-size. This was wrong. Remaining
data size restriction should be correctly at least single sector
(whatever sector size is selected or auto-detected).
2021-11-24 19:58:57 +01:00
Ondrej Kozina
d4e49f9988 Enable legacy reencryption compat test. 2021-11-24 19:58:57 +01:00
Ondrej Kozina
2e23913e3b Fix compat-test-args to reflect on luks1 reencryption params.
--decrypt parameter works with LUKS1 format even without --header
parameter.
2021-11-24 19:58:57 +01:00
Ondrej Kozina
8d7bce164c Fix compat-test-args test.
Option --device-size was never used in open action.
2021-11-24 19:58:57 +01:00
Ondrej Kozina
2cf11a2fa4 All options allowed with luksFormat also pass with reencrypt action.
During encryption (both formats) we need full luksFormat action
parameters set
2021-11-24 19:58:57 +01:00
Ondrej Kozina
bd4405ada6 Add --keyslot-cipher and --keyslot-key-size action restrictions. 2021-11-24 19:58:57 +01:00
Ondrej Kozina
c46fd35e56 Add per action parameters verification routines.
It cleans up bloated main function and improves code clarity on
when some parameters need to be verified and when not.
2021-11-24 19:58:57 +01:00
Ondrej Kozina
957c58db41 Remove cryptsetup-reencrypt from the project. 2021-11-24 19:58:57 +01:00
Ondrej Kozina
06fd461bd8 Add --new alias for --encrypt parameter.
To be compatible with cryptsetup-reencrypt utility.
2021-11-24 19:58:57 +01:00
Ondrej Kozina
686acf82a2 Add option to turn off O_EXCL flag in device_check() 2021-11-24 19:58:57 +01:00
Ondrej Kozina
cade8201d2 Enable legacy LUKS1 reencryption in cryptsetup utility. 2021-11-24 19:58:57 +01:00
Ondrej Kozina
390f3f5b73 Remove (legacy) LUKS2 code from former cryptsetup-reencrypt utility.
The old LUKS2 reencryption from cryptsetup-reencrypt will not be
supported anymore.
2021-11-24 19:58:57 +01:00
Ondrej Kozina
d5fdf47b19 Copy effective cryptsetup-reencrypt code in new file.
With only minor editing and drop of code path entry and
command line parameters parsing.
2021-11-24 19:58:57 +01:00
Ondrej Kozina
7d77e0dcbd Refactor new LUKS2 reencryption code.
It will ease the merge with legacy LUKS1 reencryption
code later.
2021-11-24 19:58:54 +01:00
Ondrej Kozina
eb0f9b4f29 Move LUKS2 reencrytption code in separate file. 2021-11-24 19:57:37 +01:00
Ondrej Kozina
7b10f71373 Preparation to merge cryptsetup-reencrypt in cryptsetup. 2021-11-24 19:57:37 +01:00
Ondrej Kozina
c82c3509cf Do not build cryptsetup-reencrypt.
Source code will be removed later completely.
2021-11-24 19:57:37 +01:00
Ondrej Kozina
74ad0d71b9 Add --keep-key parameter for LUKS2 reencryption.
One of missing features when comparing to legacy
reencryption code.
2021-11-24 19:57:30 +01:00
Chris Coulson
98cd52c8d7 allow tokens to be replaced
Currently, token import and token add actions will fail if you use the
--token-id option to specify a token ID that is already in use, but there
are scenarios where you might genuinely want to replace an existing token
in a single atomic operation.

A use case for this might be for a keyslot that is protected by a
TPM, where you store the TPM sealed key and associated metadata as a
token and you want to update the PCR policy associated with the sealed
object or make other changes to it. Currently this requires importing a
new token and then removing the old token.

Instead, add a --token-replace option to allow token import and token
add to replace an existing token if you try to add or import one with an
ID that is already in use.
2021-11-23 15:45:33 +00:00
daniel.zatovic
a9bf78adc3 Remove LLVM repo script 2021-11-23 14:57:51 +01:00
Daniel Zaťovič
83efc03426 Add compilation tests and static analysis on the Gitlab shared runner. 2021-11-23 14:53:10 +01:00
Milan Broz
bfc39f68d8 Set devel version. 2021-11-19 14:36:47 +01:00
Milan Broz
ff51d5a8fa Version 2.4.2. 2021-11-18 11:35:45 +01:00
Jakub Bogusz
949ed8c9e2 po: update pl.po (from translationproject.org) 2021-11-18 10:57:02 +01:00
Milan Broz
31698f8388 LUKS convert: also check sysfs for device activity.
On some "broken" systems, udev directory (where we try to check
if device is active) is present, but the symlink is missing.

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

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

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

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

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

Just rely on snprintf here.

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

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

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

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

Return -ENODEV here instead of -EINVAL.

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

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

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

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

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

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

And do not use ECB :)

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

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

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

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

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

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

(Moreover, the query path is currently used only for flag, not for the value.)
2021-08-04 13:06:14 +02:00
Yuri Chornoivan
b00946d449 Fix minor typo: assing -> assign 2021-07-30 16:19:36 +00:00
Guilhem Moulin
6a14f52e5d Fix minor spelling errors.
(Found by Lintian.)
2021-07-30 02:56:38 +02:00
Milan Broz
3c68e3f5b1 Version 2.4.0-rc1 update. 2021-07-29 23:28:08 +02:00
Milan Broz
ec1ef8f19d Update cryptsetup.pot. 2021-07-29 23:22:33 +02:00
Milan Broz
6a64c2e932 Prepare 2.4.0-rc1 version. 2021-07-29 23:18:59 +02:00
Milan Broz
835c603b13 Use cannot in all messages. 2021-07-29 22:00:04 +02:00
Milan Broz
a718b90ac6 Fix some gcc warnings in compiled tests. 2021-07-29 20:40:48 +02:00
Milan Broz
089edb74b4 Fix return code for skipped align tests. 2021-07-29 20:19:45 +02:00
Milan Broz
8c60cf8645 Silence also scsi_debug module load in tests. 2021-07-29 17:41:25 +02:00
Ondrej Kozina
f364990b9b Do not fallback to pasphrase based activation when device exists.
If token based device activation activation fails with -EEXIST
report proper error and do not fallback to passphrase based
activation in cli.
2021-07-29 14:47:16 +00:00
Ondrej Kozina
3b826d0fa3 Add verbose messages explaining token errors. 2021-07-29 14:47:16 +00:00
Milan Broz
cab332c367 Silence all modprobe/rmmod calls in tests.
On systems where are modules compiled-in or missing this produces nois,
test will be skipped later anyway.
2021-07-29 16:20:00 +02:00
Ondrej Kozina
9ee74f59d7 Add cryptsetup --token-type parameter.
It restricts token type to parameter value in
case no specific token-id is selected.
2021-07-29 08:46:20 +00:00
Ondrej Kozina
46afee6299 Remove duplicate macro definition. 2021-07-29 08:46:20 +00:00
Milan Broz
90bba399ab Fix LOOP_CONFIGURE incompatibility is some kernels.
Kernels with 32bit userspace can return ENOTTY,
we should use fallback to old code in this case.

For more info see
  583990d25b
2021-07-29 10:32:13 +02:00
Milan Broz
c403f73ad0 Skip tests id scsi_debug is compiled-in or in use.
We need standalone scsi_debug module for some tests.
2021-07-28 23:20:45 +02:00
Milan Broz
470b99a647 Use long otpion for salt in tests.
Some old distros fail with -s=XX syntax (libpopt issue).
2021-07-28 19:36:56 +02:00
Milan Broz
a68968af8f Fix possible dereference of pbkdf params.
This can only happen during misconfiguration of default parameters,
but eliminates one gcc warning.
2021-07-27 12:44:13 +02:00
Ondrej Kozina
ee9c7855ca Use max token id in api test at least once.
so that we also test bitfield limits.
2021-07-26 14:10:08 +02:00
Ondrej Kozina
1a156458f2 Add PIN try loop for actions supporting tokens. 2021-07-26 14:10:08 +02:00
Ondrej Kozina
796b901912 Do not retry tokens that already returned -ENOANO.
In token based activation loop (token_id == CRYPT_ANY_TOKEN)
we do not want retry tokens that already returned -ENOANO (wrong pin)
once.
2021-07-26 14:10:08 +02:00
Milan Broz
508284cd28 Support build with older libssh.
The function ssh_session_is_known_server() was introduced later,
fallback to older version if libssh is available.
2021-07-25 21:57:09 +02:00
Milan Broz
5d1972bb97 Use depreacated attribute compatible with old gcc. 2021-07-25 18:27:55 +02:00
Vojtech Trefny
7c76d17a9c ssh token: Make strings in the plugin translatable 2021-07-25 18:08:22 +02:00
Мирослав Николић
8ff663a761 po: update sr.po (from translationproject.org) 2021-07-25 13:40:57 +02:00
Antonio Ceballos
d3ad9fe25f po: update es.po (from translationproject.org) 2021-07-25 13:40:57 +02:00
Luca Boccassi
cc374ee10d veritysetup: add --root-hash-file option
Allow to pass the root hash via a file, rather than verbatim on
the command line, for the open/verify/format actions.
It is much more convenient when using veritysetup in scripts.

[some modifications by mbroz:]
- Add additional syntax and option description to man page.
- Fix a segfault with non-existing path.
- Do not read full file.
- Small refactor for argc handling and option processing.
2021-07-25 13:40:17 +02:00
Ondrej Kozina
06f132066b Add crypt_reencrypt_run superseding now deprecated crypt_reencrypt.
This reverts commit 367cb7a761
and retains original crypt_reencrypt() symbol marked as deprecated
in favour of new crypt_reencrypt_run(). This makes cryptsetup 2.4.0
release fully backward compatible.
2021-07-22 15:59:01 +02:00
Ondrej Kozina
82816cb52f Suppress error message when keyslot is unusable for segment.
It's too verbose when run in loop for token based activation.
2021-07-22 13:55:22 +02:00
Ondrej Kozina
426cab3aeb Add more LUKS2 token based activation tests. 2021-07-22 13:55:22 +02:00
Ondrej Kozina
152ed1fb44 Speed up LUKS2 api test. 2021-07-22 13:55:22 +02:00
Ondrej Kozina
c6ff9f8bd7 Respect keyslot priority with token based activation.
crypt_activate_by_token functions did not respect LUKS2 keyslot
priorities. These calls were able to activate device via keyslot with
CRYPT_SLOT_PRIORITY_IGNORE even when token was set to
CRYPT_ANY_TOKEN. This commit changes the token based activation
so that keyslot with priority ignore is eligible for unlock only
when specific token is selected. Also when activating with token
set to CRYPT_ANY_TOKEN keyslots with higher priority take precedence
over keyslots with normal priority. Keyslot with priority ignore are
correctly ignored when token is CRYPT_ANY_TOKEN.
2021-07-22 13:55:22 +02:00
Ondrej Kozina
c104bccc3f Print some compile-time defaults in 00module-test. 2021-07-22 13:55:22 +02:00
Ondrej Kozina
4654e6f578 Add best effort try-loop for token based activation.
The loop is run only when token id in any of crypt_activate_by_token*
calls is set to CRYPT_ANY_TOKEN.
2021-07-22 13:55:19 +02:00
Ondrej Kozina
2cf38465c4 Change default error returned by token open.
It has to be -ENOENT since -EPERM would wrongly
implied the token provided wrong keyslot passphrase.
2021-07-22 13:47:40 +02:00
Ondrej Kozina
3428296186 Improve debug logs for external token handling. 2021-07-22 13:47:40 +02:00
Ondrej Kozina
877afd2281 Replace original token activation retcode -EAGAIN with -ENOANO.
crypt_activate_by_token (and _pin variant) now returns -ENOANO
instead -EAGAIN in case token handler identifies specific token
requires PIN to sucessfully complete token based activation.

-EAGAIN is now used for special case when additional system
resources are missing (HW token, other device, system daemon,
etc).
2021-07-22 13:47:14 +02:00
Ondrej Kozina
2f320f3148 Avoid possible lock deadlock after error.
The deadlock is hypothetical since libcryptsetup applications
usualy terminates after error. The deadlock could only emerge
in case where single process handles multiple crypt contexts.
2021-07-22 10:31:02 +02:00
Yuri Chornoivan
a0277d3ff6 po: update uk.po (from translationproject.org) 2021-07-14 16:59:03 +02:00
Josef Andersson
531ebba50b po: update sv.po (from translationproject.org) 2021-07-14 16:59:03 +02:00
Мирослав Николић
d8bac63e5c po: update sr.po (from translationproject.org) 2021-07-14 16:59:03 +02:00
Yuri Kozlov
b408b8238c po: update ru.po (from translationproject.org) 2021-07-14 16:59:03 +02:00
Jakub Bogusz
2e80962501 po: update pl.po (from translationproject.org) 2021-07-14 16:59:03 +02:00
Hiroshi Takekawa
43827ba380 po: update ja.po (from translationproject.org) 2021-07-14 16:59:03 +02:00
Frédéric Marchal
cd374664d4 po: update fr.po (from translationproject.org) 2021-07-14 16:59:03 +02:00
Roland Illig
3694f9c099 po: update de.po (from translationproject.org) 2021-07-14 16:59:03 +02:00
Petr Pisar
06249b8e99 po: update cs.po (from translationproject.org) 2021-07-14 16:59:03 +02:00
Vojtech Trefny
bf915e82f4 man: Add information about maximum number of key slots to --key-slot 2021-07-13 09:37:46 +02:00
Vojtech Trefny
bfe0c7fc5f Fix error message for invalid key slot with LUKS2
Fixes: #651
2021-07-13 07:22:16 +02:00
Ondrej Kozina
0eb8493156 Fix ssh-plugin test. 2021-07-02 22:56:45 +02:00
Ondrej Kozina
9736f533bb tests: Do not guess default pbkdf anymore.
Instead of guessing get pbkdf defaults via libcryptsetup
API.
2021-07-02 21:55:42 +02:00
Milan Broz
cc6df5fa39 Fix some random typos. 2021-07-02 14:05:41 +02:00
349 changed files with 42488 additions and 32697 deletions

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

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

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

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

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

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

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

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

4
.gitignore vendored
View File

@@ -6,6 +6,8 @@ Makefile.in.in
*.lo
*.la
*.o
*.so
*.8
**/*.dirstamp
.deps/
.libs/
@@ -54,3 +56,5 @@ tests/luks1-images
tests/tcrypt-images
tests/unit-utils-io
tests/vectors-test
tests/test-symbols-list.h
tests/all-symbols-test

20
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,20 @@
stages:
- test
.dump_kernel_log:
after_script:
- sudo dmesg > /mnt/artifacts/dmesg.log
- sudo journalctl > /mnt/artifacts/journalctl.log
- '[ "$(ls -A /var/coredumps)" ] && exit 1 || true'
include:
- local: .gitlab/ci/debian.yml
- local: .gitlab/ci/fedora.yml
- local: .gitlab/ci/rhel.yml
- local: .gitlab/ci/centos.yml
- local: .gitlab/ci/annocheck.yml
- local: .gitlab/ci/csmock.yml
- local: .gitlab/ci/gitlab-shared-docker.yml
- local: .gitlab/ci/compilation-gcc.gitlab-ci.yml
- local: .gitlab/ci/compilation-clang.gitlab-ci.yml
- local: .gitlab/ci/alpinelinux.yml

View File

@@ -0,0 +1,53 @@
.alpinelinux-dependencies:
after_script:
- sudo dmesg > /mnt/artifacts/dmesg.log
- sudo cp /var/log/messages /mnt/artifacts/
- '[ "$(ls -A /var/coredumps)" ] && exit 1 || true'
before_script:
- >
sudo apk add
lvm2-dev openssl1.1-compat-dev popt-dev util-linux-dev json-c-dev
argon2-dev device-mapper which sharutils gettext gettext-dev automake
autoconf libtool build-base keyutils tar jq expect git asciidoctor
- ./autogen.sh
- ./configure --prefix=/usr --libdir=/lib --sbindir=/sbin --disable-static --enable-libargon2 --with-crypto_backend=openssl --disable-external-tokens --disable-ssh-token --enable-asciidoc
test-main-commit-job-alpinelinux:
extends:
- .alpinelinux-dependencies
tags:
- libvirt
- alpinelinux
stage: test
interruptible: true
variables:
RUN_SSH_PLUGIN_TEST: "0"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
script:
- make -j
- make -j -C tests check-programs
- sudo -E make check
test-mergerq-job-alpinelinux:
extends:
- .alpinelinux-dependencies
tags:
- libvirt
- alpinelinux
stage: test
interruptible: true
variables:
RUN_SSH_PLUGIN_TEST: "0"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
script:
- make -j
- make -j -C tests check-programs
- sudo -E make check

19
.gitlab/ci/annocheck.yml Normal file
View File

@@ -0,0 +1,19 @@
test-main-commit-job-annocheck:
extends:
- .dump_kernel_log
tags:
- libvirt
- rhel9-annocheck
stage: test
interruptible: true
allow_failure: true
variables:
RUN_SSH_PLUGIN_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
script:
- /opt/build-rpm-script.sh > /dev/null 2>&1
- annocheck /var/lib/mock/rhel-9.0.0-candidate-x86_64/result/*.rpm --profile=el9
- annocheck /var/lib/mock/rhel-9.0.0-candidate-x86_64/result/*.rpm --profile=el8

55
.gitlab/ci/centos.yml Normal file
View File

@@ -0,0 +1,55 @@
.centos-openssl-backend:
extends:
- .dump_kernel_log
before_script:
- >
sudo dnf -y -q install
autoconf automake device-mapper-devel gcc gettext-devel json-c-devel
libblkid-devel libpwquality-devel libselinux-devel libssh-devel libtool
libuuid-devel make popt-devel libsepol-devel nc openssh-clients passwd
pkgconfig sharutils sshpass tar uuid-devel vim-common device-mapper
expect gettext git jq keyutils openssl-devel openssl gem
- sudo gem install asciidoctor
- sudo -E git clean -xdf
- ./autogen.sh
- ./configure --enable-fips --enable-pwquality --with-crypto_backend=openssl --enable-asciidoc
# non-FIPS jobs
test-main-commit-centos-stream9:
extends:
- .centos-openssl-backend
tags:
- libvirt
- centos-stream9
stage: test
interruptible: true
variables:
RUN_SSH_PLUGIN_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
script:
- make -j
- make -j -C tests check-programs
- sudo -E make check
test-mergerq-centos-stream9:
extends:
- .centos-openssl-backend
tags:
- libvirt
- centos-stream9
stage: test
interruptible: true
variables:
RUN_SSH_PLUGIN_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
script:
- make -j
- make -j -C tests check-programs
- sudo -E make check

View File

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

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

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

View File

@@ -0,0 +1,27 @@
test-clang-compilation:
extends:
- .gitlab-shared-clang
script:
- export CFLAGS="-Wall -Werror"
- ./configure
- make -j
- make -j check-programs
test-clang-Wall-script:
extends:
- .gitlab-shared-clang
script:
- export CFLAGS="-g -O0"
- export CC="$CI_PROJECT_DIR/.gitlab/ci/clang-Wall"
- ./configure
- make -j CFLAGS="-g -O0 -Werror"
- make -j CFLAGS="-g -O0 -Werror" check-programs
test-scan-build:
extends:
- .gitlab-shared-clang
script:
- scan-build${COMPILER_VERSION:+-$COMPILER_VERSION} -V ./configure CFLAGS="-g -O0"
- make clean
- scan-build${COMPILER_VERSION:+-$COMPILER_VERSION} --status-bugs -maxloop 10 make -j
- scan-build${COMPILER_VERSION:+-$COMPILER_VERSION} --status-bugs -maxloop 10 make -j check-programs

View File

@@ -0,0 +1,27 @@
test-gcc-compilation:
extends:
- .gitlab-shared-gcc
script:
- export CFLAGS="-Wall -Werror"
- ./configure
- make -j
- make -j check-programs
test-gcc-Wall-script:
extends:
- .gitlab-shared-gcc
script:
- export CFLAGS="-g -O0"
- export CC="$CI_PROJECT_DIR/.gitlab/ci/gcc-Wall"
- ./configure
- make -j CFLAGS="-g -O0 -Werror"
- make -j CFLAGS="-g -O0 -Werror" check-programs
test-gcc-fanalyzer:
extends:
- .gitlab-shared-gcc
script:
- export CFLAGS="-Wall -Werror -g -O0 -fanalyzer -fdiagnostics-path-format=separate-events"
- ./configure
- make -j
- make -j check-programs

17
.gitlab/ci/csmock.yml Normal file
View File

@@ -0,0 +1,17 @@
test-commit-job-csmock:
extends:
- .dump_kernel_log
tags:
- libvirt
- rhel7-csmock
stage: test
interruptible: true
allow_failure: true
variables:
RUN_SSH_PLUGIN_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/ || $CI_PIPELINE_SOURCE == "merge_request_event"
script:
- /opt/csmock-run-script.sh

53
.gitlab/ci/debian.yml Normal file
View File

@@ -0,0 +1,53 @@
.debian-prep:
extends:
- .dump_kernel_log
before_script:
- >
sudo apt-get -y install -y -qq git gcc make
autoconf automake autopoint pkg-config libtool libtool-bin gettext
libssl-dev libdevmapper-dev libpopt-dev uuid-dev libsepol1-dev
libjson-c-dev libssh-dev libblkid-dev tar libargon2-0-dev
libpwquality-dev sharutils dmsetup jq xxd expect keyutils
netcat passwd openssh-client sshpass asciidoctor
- sudo apt-get -y build-dep cryptsetup
- sudo -E git clean -xdf
- ./autogen.sh
- ./configure --enable-libargon2 --enable-asciidoc
test-mergerq-job-debian:
extends:
- .debian-prep
tags:
- libvirt
- debian10
stage: test
interruptible: true
variables:
RUN_SSH_PLUGIN_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
script:
- make -j
- make -j -C tests check-programs
- sudo -E make check
test-main-commit-job-debian:
extends:
- .debian-prep
tags:
- libvirt
- debian10
stage: test
interruptible: true
variables:
RUN_SSH_PLUGIN_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
script:
- make -j
- make -j -C tests check-programs
- sudo -E make check

55
.gitlab/ci/fedora.yml Normal file
View File

@@ -0,0 +1,55 @@
.dnf-openssl-backend:
extends:
- .dump_kernel_log
before_script:
- >
sudo dnf -y -q install
autoconf automake device-mapper-devel gcc gettext-devel json-c-devel
libargon2-devel libblkid-devel libpwquality-devel libselinux-devel
libssh-devel libtool libuuid-devel make popt-devel
libsepol-devel.x86_64 netcat openssh-clients passwd pkgconfig sharutils
sshpass tar uuid-devel vim-common device-mapper expect gettext git jq
keyutils openssl-devel openssl asciidoctor
- sudo -E git clean -xdf
- ./autogen.sh
- ./configure --enable-fips --enable-pwquality --enable-libargon2 --with-crypto_backend=openssl --enable-asciidoc
test-main-commit-job-rawhide:
extends:
- .dnf-openssl-backend
tags:
- libvirt
- fedora-rawhide
stage: test
interruptible: true
allow_failure: true
variables:
RUN_SSH_PLUGIN_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
script:
- make -j
- make -j -C tests check-programs
- sudo -E make check
test-mergerq-job-rawhide:
extends:
- .dnf-openssl-backend
tags:
- libvirt
- fedora-rawhide
stage: test
interruptible: true
allow_failure: true
variables:
RUN_SSH_PLUGIN_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
script:
- make -j
- make -j -C tests check-programs
- sudo -E make check

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

@@ -0,0 +1,57 @@
#!/bin/bash
# gcc -Wall plus other important warnings not included in -Wall
for arg in "$@"
do
case $arg in
-O*) Wuninitialized=-Wuninitialized;; # only makes sense with `-O'
esac
done
GCC="gcc${COMPILER_VERSION:+-$COMPILER_VERSION}"
#PEDANTIC="-std=gnu99"
#PEDANTIC="-pedantic -std=gnu99"
#PEDANTIC="-pedantic -std=gnu99 -Wno-variadic-macros"
#CONVERSION="-Wconversion"
# -Wpacked \
# This does more than expected for gcc (mixed code with declarations)
# -Wdeclaration-after-statement \
EXTRA="-Wextra \
-Wsign-compare \
-Werror-implicit-function-declaration \
-Wpointer-arith \
-Wwrite-strings \
-Wswitch \
-Wmissing-format-attribute \
-Wstrict-aliasing=3 \
-Winit-self \
-Wunsafe-loop-optimizations \
-Wold-style-definition \
-Wno-missing-field-initializers \
-Wno-unused-parameter \
-Wno-long-long \
-Wmaybe-uninitialized \
-Wvla \
-Wformat-overflow \
-Wformat-truncation"
exec $GCC $PEDANTIC $CONVERSION \
-Wall $Wuninitialized \
-Wno-switch \
-Wdisabled-optimization \
-Wwrite-strings \
-Wpointer-arith \
-Wbad-function-cast \
-Wmissing-prototypes \
-Wmissing-declarations \
-Wstrict-prototypes \
-Wnested-externs \
-Wcomment \
-Winline \
-Wcast-align=strict \
-Wcast-qual \
-Wredundant-decls $EXTRA \
"$@"

View File

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

96
.gitlab/ci/rhel.yml Normal file
View File

@@ -0,0 +1,96 @@
.rhel-openssl-backend:
extends:
- .dump_kernel_log
before_script:
- >
sudo yum -y -q install
autoconf automake device-mapper-devel gcc gettext-devel json-c-devel
libblkid-devel libpwquality-devel libselinux-devel libssh-devel libtool
libuuid-devel make popt-devel libsepol-devel nc openssh-clients passwd
pkgconfig sharutils sshpass tar uuid-devel vim-common device-mapper
expect gettext git jq keyutils openssl-devel openssl gem > /dev/null 2>&1
- sudo gem install asciidoctor
- sudo -E git clean -xdf
- ./autogen.sh
- ./configure --enable-fips --enable-pwquality --with-crypto_backend=openssl --enable-asciidoc
# non-FIPS jobs
test-main-commit-rhel8:
extends:
- .rhel-openssl-backend
tags:
- libvirt
- rhel8
stage: test
interruptible: true
variables:
RUN_SSH_PLUGIN_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
script:
- make -j
- make -j -C tests check-programs
- sudo -E make check
test-main-commit-rhel9:
extends:
- .rhel-openssl-backend
tags:
- libvirt
- rhel9
stage: test
interruptible: true
variables:
RUN_SSH_PLUGIN_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
script:
- make -j
- make -j -C tests check-programs
- sudo -E make check
# FIPS jobs
test-main-commit-rhel8-fips:
extends:
- .rhel-openssl-backend
tags:
- libvirt
- rhel8-fips
stage: test
interruptible: true
variables:
RUN_SSH_PLUGIN_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
script:
- make -j
- make -j -C tests check-programs
- sudo -E make check
test-main-commit-rhel9-fips:
extends:
- .rhel-openssl-backend
tags:
- libvirt
- rhel9-fips
stage: test
interruptible: true
allow_failure: true
variables:
RUN_SSH_PLUGIN_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
script:
- make -j
- make -j -C tests check-programs
- sudo -E make check

11
.lgtm.yml Normal file
View File

@@ -0,0 +1,11 @@
queries:
- exclude: cpp/fixme-comment
- exclude: cpp/empty-block
# symver attribute detection cannot be used, disable it for lgtm
extraction:
cpp:
configure:
command:
- "./autogen.sh"
- "./configure --enable-external-tokens --enable-ssh-token"
- "echo \"#undef HAVE_ATTRIBUTE_SYMVER\" >> config.h"

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
EXTRA_DIST = README.md COPYING.LGPL FAQ docs misc
EXTRA_DIST = README.md COPYING.LGPL FAQ.md docs misc autogen.sh
SUBDIRS = po tests
CLEANFILES =
DISTCLEAN_TARGETS =
@@ -16,7 +16,7 @@ AM_CPPFLAGS = \
AM_CFLAGS = -Wall
AM_LDFLAGS =
LDADD = $(LTLIBINTL) -lm
LDADD = $(LTLIBINTL)
tmpfilesddir = @DEFAULT_TMPFILESDIR@
@@ -27,6 +27,7 @@ sbin_PROGRAMS =
man8_MANS =
tmpfilesd_DATA =
pkgconfig_DATA =
dist_noinst_DATA =
include man/Makemodule.am
@@ -46,7 +47,7 @@ ACLOCAL_AMFLAGS = -I m4
DISTCHECK_CONFIGURE_FLAGS = \
--with-tmpfilesdir=$$dc_install_base/usr/lib/tmpfiles.d \
--enable-internal-argon2 --enable-internal-sse-argon2 \
--enable-external-tokens --enable-ssh-token
--enable-external-tokens --enable-ssh-token --enable-asciidoc
distclean-local:
-find . -name \*~ -o -name \*.orig -o -name \*.rej | xargs rm -f
@@ -54,3 +55,12 @@ distclean-local:
clean-local:
-rm -rf docs/doxygen_api_docs libargon2.la
install-data-local:
$(MKDIR_P) -m 0755 $(DESTDIR)/${EXTERNAL_LUKS2_TOKENS_PATH}
uninstall-local:
rmdir $(DESTDIR)/${EXTERNAL_LUKS2_TOKENS_PATH} 2>/dev/null || :
check-programs: libcryptsetup.la
$(MAKE) -C tests $@

View File

@@ -13,13 +13,14 @@ The project also includes a **veritysetup** utility used to conveniently setup
and **integritysetup** to setup
[DMIntegrity](https://gitlab.com/cryptsetup/cryptsetup/wikis/DMIntegrity) block integrity kernel module.
LUKS Design
-----------
**LUKS** is the standard for Linux hard disk encryption. By providing a standard on-disk-format, it does not
only facilitate compatibility among distributions, but also provides secure management of multiple user passwords.
LUKS stores all necessary setup information in the partition header, enabling to transport or migrate data seamlessly.
### Specifications
Last version of the LUKS2 format specification is
[available here](https://gitlab.com/cryptsetup/LUKS2-docs).
@@ -44,22 +45,22 @@ Download
--------
All release tarballs and release notes are hosted on [kernel.org](https://www.kernel.org/pub/linux/utils/cryptsetup/).
**The latest release candidate cryptsetup version is 2.4.0-rc0**
* [cryptsetup-2.4.0-rc0.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.4/cryptsetup-2.4.0-rc0.tar.xz)
* Signature [cryptsetup-2.4.0-rc0.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.4/cryptsetup-2.4.0-rc0.tar.sign)
**The latest stable release candidate cryptsetup version is 2.5.0-rc1**
* [cryptsetup-2.5.0-rc1.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.5/cryptsetup-2.5.0-rc1.tar.xz)
* Signature [cryptsetup-2.5.0-rc1.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.5/cryptsetup-2.5.0-rc1.tar.sign)
_(You need to decompress file first to check signature.)_
* [Cryptsetup 2.4.0-rc0 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.4/v2.4.0-rc0-ReleaseNotes).
* [Cryptsetup 2.5.0-rc1 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.5/v2.5.0-rc1-ReleaseNotes).
**The latest stable cryptsetup version is 2.3.6**
* [cryptsetup-2.3.6.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/cryptsetup-2.3.6.tar.xz)
* Signature [cryptsetup-2.3.6.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/cryptsetup-2.3.6.tar.sign)
**The latest stable cryptsetup version is 2.4.3**
* [cryptsetup-2.4.3.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.4/cryptsetup-2.4.3.tar.xz)
* Signature [cryptsetup-2.4.3.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.4/cryptsetup-2.4.3.tar.sign)
_(You need to decompress file first to check signature.)_
* [Cryptsetup 2.3.6 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/v2.3.6-ReleaseNotes).
* [Cryptsetup 2.4.3 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.4/v2.4.3-ReleaseNotes).
Previous versions
* [Version 2.0.6](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.6.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.6.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.6-ReleaseNotes).
* [Version 2.3.7](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/cryptsetup-2.3.7.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/cryptsetup-2.3.7.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/v2.3.7-ReleaseNotes).
* [Version 1.7.5](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.5.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.5.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/v1.7.5-ReleaseNotes).
@@ -77,22 +78,45 @@ NLS PO files are maintained by [TranslationProject](https://translationproject.o
Required packages
-----------------
All distributions provide cryptsetup as distro package. If you need to compile cryptsetup youfself, some packages are required for compilation. Please always prefer distro specific build tools to manually configuring cryptsetup.
Fo available compile options, check ``configure --help`` for more info. If you are using a git snapshot, you need to generate configure script with ``autogen.sh`` script.
All distributions provide cryptsetup as distro package. If you need to compile cryptsetup yourself, some packages are required for compilation. Please always prefer distro specific build tools to manually configuring cryptsetup.
Here is the list of packages needed for the compilation of project for particular distributions:
* For Fedora: `git gcc make autoconf automake gettext-devel pkgconfig openssl-devel popt-devel device-mapper-devel libuuid-devel json-c-devel libblkid-devel findutils libtool libssh-devel tar`. Optionally `libargon2-devel libpwquality-devel`. To run internal testsuite you also need `sharutils device-mapper jq vim-common expect keyutils netcat shadow-utils openssh-clients openssh sshpass`.
* For Fedora: `git gcc make autoconf automake gettext-devel pkgconfig openssl-devel popt-devel device-mapper-devel libuuid-devel json-c-devel libblkid-devel findutils libtool libssh-devel tar`. Optionally `libargon2-devel libpwquality-devel`. To run the internal testsuite you also need to install `sharutils device-mapper jq vim-common expect keyutils netcat shadow-utils openssh-clients openssh sshpass`.
* For Debian and Ubuntu: `git gcc make autoconf automake autopoint pkg-config libtool gettext libssl-dev libdevmapper-dev libpopt-dev uuid-dev libsepol1-dev libjson-c-dev libssh-dev libblkid-dev tar`. Optionally `libargon2-0-dev libpwquality-dev`. To run internal testsuite you also need `sharutils dmsetup jq xxd expect keyutils netcat passwd openssh-client sshpass`
* For Debian and Ubuntu: `git gcc make autoconf automake autopoint pkg-config libtool gettext libssl-dev libdevmapper-dev libpopt-dev uuid-dev libsepol1-dev libjson-c-dev libssh-dev libblkid-dev tar`. Optionally `libargon2-0-dev libpwquality-dev`. To run the internal testsuite you also need to install `sharutils dmsetup jq xxd expect keyutils netcat passwd openssh-client sshpass`
Note that the list could change as distributions evolve.
Note that the list could change as the distributions evolve.
Compilation
-----------
The cryptsetup project uses **automake** and **autoconf** system to generate all needed files for compilation. If you check it from the git snapshot, use ``./autogen.sh && ./configure && make`` to compile the project. If you use downloaded released ``*.tar.xz`` archive, the configure script is already pre-generated (no need to run ``autoconf.sh``).
See ``./configure --help`` and use ``--disable-*`` and ``--enable-*`` options.
For running the test suite that come with the project, type ``make check``.
Note that most tests will need root user privileges and run many dangerous storage fail simulations.
Do **not** run tests with root privilege on production systems! Some tests will need scsi_debug kernel module to be available.
For more details, please refer to [automake](https://www.gnu.org/software/automake/manual/automake.html) and [autoconf](https://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf.html) manuals.
Help!
-----
Please always read [FAQ](https://gitlab.com/cryptsetup/cryptsetup/wikis/FrequentlyAskedQuestions) first.
For cryptsetup and LUKS related questions, please use the dm-crypt mailing list, [dm-crypt@saout.de](mailto:dm-crypt@saout.de).
If you want to subscribe just send an empty mail to [dm-crypt-subscribe@saout.de](mailto:dm-crypt-subscribe@saout.de).
### Documentation
You can also browse [list archive](https://www.saout.de/pipermail/dm-crypt/) or read and search it through
[web interface on lore.kernel.org](https://lore.kernel.org/dm-crypt/) or alternatively on [marc.info](https://marc.info/?l=dm-crypt).
Please read the following documentation before posting questions in the mailing list. You will be able to ask better questions and better understand the answers.
* [FAQ](https://gitlab.com/cryptsetup/cryptsetup/wikis/FrequentlyAskedQuestions)
* LUKS Specifications
* manuals (aka man page, man pages, man-page)
The FAQ is online and in the source code for the project. The Specifications are referenced above in this document. The man pages are in source and should be available after installation using standard man commands. e.g. man cryptsetup
### Mailing List
For cryptsetup and LUKS related questions, please use the cryptsetup mailing list [cryptsetup@lists.linux.dev](mailto:cryptsetup@lists.linux.dev), hosted at [kernel.org subspace](https://subspace.kernel.org/lists.linux.dev.html).
To subscribe send an empty mail to [cryptsetup+subscribe@lists.linux.dev](mailto:cryptsetup+subscribe@lists.linux.dev).
You can also browse and/or search the mailing [list archive](https://lore.kernel.org/cryptsetup/).
News (NNTP), Atom feed and git access to public inbox is available through [lore.kernel.org](https://lore.kernel.org) service.
The former dm-crypt [list archive](https://lore.kernel.org/dm-crypt/) is also available.

10
SECURITY.md Normal file
View File

@@ -0,0 +1,10 @@
# Reporting a Security Bug in cryptsetup project
If you think you have discovered a security issue, please report it through
the project issue tracker [New issue](https://gitlab.com/cryptsetup/cryptsetup/issues)
as a confidential issue (select confidential checkbox).
An alternative is to send PGP encrypted mail to the cryptsetup maintainer.
Current maintainer is [Milan Broz](mailto:gmazyland@gmail.com), use PGP key
with fingerprint 2A29 1824 3FDE 4664 8D06 86F9 D9B0 577B D93E 98FC.

View File

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

View File

@@ -1,9 +1,9 @@
AC_PREREQ([2.67])
AC_INIT([cryptsetup],[2.4.0-rc0])
AC_INIT([cryptsetup],[2.5.0-rc1])
dnl library version from <major>.<minor>.<release>[-<suffix>]
LIBCRYPTSETUP_VERSION=$(echo $PACKAGE_VERSION | cut -f1 -d-)
LIBCRYPTSETUP_VERSION_INFO=19:0:7
LIBCRYPTSETUP_VERSION_INFO=20:0:8
AM_SILENT_RULES([yes])
AC_CONFIG_SRCDIR(src/cryptsetup.c)
@@ -30,10 +30,10 @@ AM_PROG_CC_C_O
AC_PROG_CPP
AC_PROG_INSTALL
AC_PROG_MAKE_SET
AC_PROG_MKDIR_P
AC_ENABLE_STATIC(no)
LT_INIT
PKG_PROG_PKG_CONFIG
AM_ICONV
dnl ==========================================================================
dnl define PKG_CHECK_VAR for old pkg-config <= 0.28
@@ -52,13 +52,33 @@ AS_VAR_COPY([$1], [pkg_cv_][$1])
AS_VAR_IF([$1], [""], [$5], [$4])
])
])
dnl ==========================================================================
dnl AsciiDoc manual pages
AC_ARG_ENABLE([asciidoc],
AS_HELP_STRING([--disable-asciidoc], [do not generate man pages from asciidoc]),
[], [enable_asciidoc=yes]
)
AC_PATH_PROG([ASCIIDOCTOR], [asciidoctor])
if test "x$enable_asciidoc" = xyes -a "x$ASCIIDOCTOR" = x; then
AC_MSG_ERROR([Building man pages requires asciidoctor installed.])
fi
AM_CONDITIONAL([ENABLE_ASCIIDOC], [test "x$enable_asciidoc" = xyes])
have_manpages=no
AS_IF([test -f "$srcdir/man/cryptsetup-open.8"], [
AC_MSG_NOTICE([re-use already generated man-pages.])
have_manpages=yes]
)
AM_CONDITIONAL([HAVE_MANPAGES], [test "x$have_manpages" = xyes])
dnl ==========================================================================
AC_C_RESTRICT
AC_HEADER_DIRENT
AC_HEADER_STDC
AC_CHECK_HEADERS(fcntl.h malloc.h inttypes.h sys/ioctl.h sys/mman.h \
AC_CHECK_HEADERS(fcntl.h malloc.h inttypes.h uchar.h sys/ioctl.h sys/mman.h \
sys/sysmacros.h sys/statvfs.h ctype.h unistd.h locale.h byteswap.h endian.h stdint.h)
AC_CHECK_DECLS([O_CLOEXEC],,[AC_DEFINE([O_CLOEXEC],[0], [Defined to 0 if not provided])],
[[
@@ -123,6 +143,12 @@ AC_ARG_ENABLE([external-tokens],
[], [enable_external_tokens=yes])
if test "x$enable_external_tokens" = "xyes"; then
AC_DEFINE(USE_EXTERNAL_TOKENS, 1, [Use external tokens])
dnl we need dynamic library loading here
saved_LIBS=$LIBS
AC_SEARCH_LIBS([dlsym],[dl])
AC_CHECK_FUNCS([dlvsym])
AC_SUBST(DL_LIBS, $LIBS)
LIBS=$saved_LIBS
fi
AC_ARG_ENABLE([ssh-token],
@@ -134,6 +160,14 @@ if test "x$enable_ssh_token" = "xyes" -a "x$enable_external_tokens" = "xno"; the
AC_MSG_ERROR([Requested LUKS2 ssh-token build, but external tokens are disabled.])
fi
dnl LUKS2 online reencryption
AC_ARG_ENABLE([luks2-reencryption],
AS_HELP_STRING([--disable-luks2-reencryption], [disable LUKS2 online reencryption extension]),
[], [enable_luks2_reencryption=yes])
if test "x$enable_luks2_reencryption" = "xyes"; then
AC_DEFINE(USE_LUKS2_REENCRYPTION, 1, [Use LUKS2 online reencryption extension])
fi
dnl ==========================================================================
AM_GNU_GETTEXT([external],[need-ngettext])
@@ -348,11 +382,6 @@ AC_ARG_ENABLE([veritysetup],
[], [enable_veritysetup=yes])
AM_CONDITIONAL(VERITYSETUP, test "x$enable_veritysetup" = "xyes")
AC_ARG_ENABLE([cryptsetup-reencrypt],
AS_HELP_STRING([--disable-cryptsetup-reencrypt], [disable cryptsetup-reencrypt tool]),
[], [enable_cryptsetup_reencrypt=yes])
AM_CONDITIONAL(REENCRYPT, test "x$enable_cryptsetup_reencrypt" = "xyes")
AC_ARG_ENABLE([integritysetup],
AS_HELP_STRING([--disable-integritysetup], [disable integritysetup support]),
[], [enable_integritysetup=yes])
@@ -399,9 +428,15 @@ PKG_CHECK_MODULES([JSON_C], [json-c])
AC_CHECK_DECLS([json_object_object_add_ex], [], [], [#include <json-c/json.h>])
AC_CHECK_DECLS([json_object_deep_copy], [], [], [#include <json-c/json.h>])
dnl Check for libssh for SSH plugin
dnl Check for libssh and argp for SSH plugin
if test "x$enable_ssh_token" = "xyes"; then
PKG_CHECK_MODULES([LIBSSH], [libssh])
AC_CHECK_DECLS([ssh_session_is_known_server], [], [], [#include <libssh/libssh.h>])
AC_CHECK_HEADER([argp.h], [], AC_MSG_ERROR([You need argp library.]))
saved_LIBS=$LIBS
AC_SEARCH_LIBS([argp_parse],[argp])
AC_SUBST(ARGP_LIBS, $LIBS)
LIBS=$saved_LIBS
fi
dnl Crypto backend configuration.
@@ -540,6 +575,23 @@ if test "x$enable_static_cryptsetup" = "xyes"; then
PKG_CONFIG=$saved_PKG_CONFIG
fi
dnl Check compiler support for symver function attribute
AC_MSG_CHECKING([for symver attribute support])
saved_CFLAGS=$CFLAGS
CFLAGS="-O0 -Werror"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
void _test_sym(void);
__attribute__((__symver__("sym@VERSION_4.2"))) void _test_sym(void) {}
]],
[[ _test_sym() ]]
)],[
AC_DEFINE([HAVE_ATTRIBUTE_SYMVER], 1, [Define to 1 to use __attribute__((symver))])
AC_MSG_RESULT([yes])
], [
AC_MSG_RESULT([no])
])
CFLAGS=$saved_CFLAGS
AC_MSG_CHECKING([for systemd tmpfiles config directory])
PKG_CHECK_VAR([systemd_tmpfilesdir], [systemd], [tmpfilesdir], [], [systemd_tmpfilesdir=no])
AC_MSG_RESULT([$systemd_tmpfilesdir])

View File

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

View File

@@ -1,7 +1,7 @@
/*
* libcryptsetup API log example
*
* Copyright (C) 2011-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2022 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 @@
/*
* libcryptsetup API - using LUKS device example
*
* Copyright (C) 2011-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2022 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

Binary file not shown.

View File

@@ -89,7 +89,7 @@ Important features
Integritysetup is intended to be used for settings that require
non-cryptographic data integrity protection with no data encryption.
Fo setting integrity protected encrypted devices, see disk authenticated
For setting integrity protected encrypted devices, see disk authenticated
encryption below.
Note that after formatting the checksums need to be initialized;
@@ -583,7 +583,7 @@ Unfinished things & TODO for next releases
in kernel (more on this later).
NOTE: Currently available authenticated modes (GCM, Chacha20-poly1305)
in kernel have too small 96-bit nonces that are problematic with
randomly generated IVs (the collison probability is not negligible).
randomly generated IVs (the collision probability is not negligible).
For the GCM, nonce collision is a fatal problem.
* Authenticated encryption do not set encryption for dm-integrity journal.

View File

@@ -75,7 +75,7 @@ Changes since version 2.3.3
If users want to use blake2b/blake2s, the kernel algorithm name includes
a dash (like "blake2s-256").
Theses algorithms can now be used for integritysetup devices.
These algorithms can now be used for integritysetup devices.
* Fix crypto backend to properly handle ECB mode.

View File

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

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

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

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

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

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

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

View File

@@ -0,0 +1,281 @@
Cryptsetup 2.5.0-rc1 Release Notes
==================================
Stable release candidate with new features and bug fixes.
Changes since version 2.4.3
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Split manual pages into per-action pages and use AsciiDoc format.
Manual pages are now generated from AsciiDoc format, allowing easy
conditional modifications for per-action options.
Generation of man pages requires the asciidoctor tool installed.
Pre-generated man pages are also included in the distribution tarball.
You can use --disable-asciidoc configure option to skip man page
generation completely. In this case, pre-generated man pages will be
used for installation.
For cryptsetup, there is main man page (cryptsetup.8) that references
separate man pages for each command (for example, cryptsetup-open.8).
You can open such a man page by simply running "man cryptsetup open".
Also, man pages for action aliases are available (cryptsetup-luksOpen.8
is an alias for cryptsetup-open.8, etc.)
LUKS volume reencryption changes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Remove cryptsetup-reencrypt tool from the project and move reencryption
to already existing "cryptsetup reencrypt" command.
Cryptsetup reencrypt now handles both LUKS1 and LUKS2 reencryption,
encryption, and decryption.
If you need to emulate the old cryptsetup-reencrypt binary, use simple
wrappers script running "exec cryptsetup reencrypt $@".
All command line options should be compatible. An exception is the
reencryption of LUKS2 volumes with old LUKS1 reencryption code that was
replaced by native and more resilient LUKS2 reencryption.
* LUKS2: implement --decryption option that allows LUKS removal. The
operation can run online or offline and supports the data shift option.
During the initialization, the LUKS2 header is exported to a file.
The first data segment is moved to the head of the data device in place
of the original header.
The feature internally introduces several new resilience modes
(combination of existing modes datashift and "checksum" or "journal").
Datashift resilience mode is applied for data moved towards the first
segment, and the first segment is then decrypted in place.
This decryption mode is not backward compatible with prior LUKS2
reencryption. Interrupted operations in progress cannot be resumed
using older cryptsetup releases.
* Reencryption metadata options that are not compatible with recent code
(features implemented in more recent releases) are now only read, but
code will not activate or modify such metadata.
Reencryption metadata contains a version that is validated when
reencryption is resumed.
For more info, see the updated LUKS2 on-disk format specification.
Safe operation of reencryption is to always finish the operation with
only one version of the tools.
* Fix decryption operation with --active-name option and restrict
it to be used only with LUKS2.
* Do not refresh reencryption digest when not needed.
This should speed up the reencryption resume process.
* Store proper resilience data in LUKS2 reencrypt initialization.
Resuming reencryption now does not require specification of resilience
type parameters if these are the same as during initialization.
* Properly wipe the unused area after reencryption with datashift in
the forward direction.
* Check datashift value against larger sector size.
For example, it could cause an issue if misaligned 4K sector appears
during decryption.
* Do not allow sector size increase reencryption in offline mode.
The eventual logical block size increase on the dm-crypt device above
may lead to an unusable filesystem. Do not allow offline reencryption
when sector size increase is requested.
You can use --force-offline-reencrypt option to override this check
(and potentially destroy the data).
* Do not allow dangerous sector size change during reencryption.
By changing the encryption sector size during reencryption, a user
may increase the effective logical block size for the dm-crypt active
device.
Do not allow encryption sector size to be increased over the value
provided by fs superblock in BLOCK_SIZE property.
* Ask the user for confirmation before resuming reencryption.
The prompt is not shown in batch mode or when the user explicitly asks
for a reencryption resume via --resume-only.
* Do not resume reencryption with conflicting parameters.
For example, if the operation was initialized as --encrypt, do not
allow resume with opposing parameter --decrypt and vice versa.
Also, the code now checks for conflicting resilience parameters
(datashift cannot be changed after initialization).
* Add --force-offline-reencrypt option.
It can be used to enforce offline reencryption in batch mode when
the device is a regular file; therefore, cryptsetup cannot detect
properly active devices using it.
Also, it may be useful to override the active device auto-detection
for specific storage configurations (dangerous!).
* Do not allow nested encryption in LUKS reencrypt.
Avoid accidental nested encryption via cryptsetup reencrypt --encrypt.
* Fix --test-passphrase when the device is in reencryption.
* Do not upload keys in keyring during offline reencryption.
Reencryption runs in userspace, so the kernel does not need the key.
* Support all options allowed with luksFormat with encrypt action.
Other changes
~~~~~~~~~~~~~
* Add resize action to integritysetup.
This allows resizing of standalone integrity devices.
* Support --device-size option (that allows unit specification) for plain
devices (existing --size option requires 512-byte sectors units).
* Fix detection of encryption sector size if a detached header is used.
* Remove obsolete dracut plugin reencryption example.
* Fix possible keyslot area size overflow during conversion to LUKS2.
If keyslots are not sorted according to binary area offset, the area
size calculation was wrong and could overflow.
* Hardening and fixes to LUKS2 validation functions:
* Log a visible error if convert fails due to validation check.
* Check for interval (keyslot and segment area) overflow.
* Check cipher availability before LUKS conversion to LUKS2.
Some historic incompatibilities are ignored for LUKS1 but do not
work for LUKS2.
* Add empty string check to LUKS2 metadata JSON validation.
Most of the LUKS2 fields cannot be empty.
* Fix JSON objects validation to check JSON object type properly.
* TCRYPT: Properly apply retry count and continue if some PBKDF variant
is unavailable.
* BITLK: Add a warning when activating a device with the wrong size
stored in metadata.
* BITLK: Add BitLocker volume size to dump command.
* BITLK: Fix possible UTF16 buffer overflow in volume key dump.
* BITLK: Skip question if the batch mode is set for volume key dump.
* BITLK: Check dm-zero availability in the kernel.
Bitlocker compatible mode uses dm-zero to mask metadata area.
The device cannot be activated if dm-zero is not available.
* Fix error message for LUKS2-only cryptsetup commands to explicitly
state LUKS2 version is required.
* Fix error message for incompatible dm-integrity metadata.
If the integritysetup tool is too old, kernel dm-integrity may use
a more recent version of dm-integrity metadata.
* Properly deactivate the integrity device even if the LUKS2 header
is no longer available.
If LUKS2 is used with integrity protection, there is always
a dm-integrity device underneath that must be deactivated.
* Allow use of --header option for cryptsetup close.
This can be used to check that the activated device has the same UUID.
* Fix activation of LUKS2 device with integrity and detached header.
The kernel-parsed dm-integrity superblock is always located on the
data device, the incorrectly used detached header device here.
* Add ZEROOUT IOCTL support for crypt_wipe API call.
For block devices, we can use optimized in-kernel BLKZEROOUT ioctl.
* VERITY: set loopback sector size according to dm-verity block sizes.
Verity block size has the same limits, so we can optimize the loop
device to increase performance.
* Other Documentation and man page improvements:
* Update LUKS2 on-disk format description.
* Add per-keyslot LUKS2 options to the man page.
Some options were missing for LUKS2 luksAddKey and luksChangeKey.
* Fix cryptsetup manpage to use PBKDF consistently.
* Add compile info to README. This information was lost when we removed
the default automake INSTALL file.
* Use volume key consistently in FAQ and man pages.
* Use markdown version of FAQ directly for installation.
* Clarify graceful reencryption interruption.
Currently, it can be interrupted by both SIGINT and SIGTERM signals.
* Add new mailing list info.
* Mention non-cryptographic xxhash64 hash for integrity protection.
* veritysetup: dump device sizes.
Calculating device sizes for verity devices is a little bit tricky.
Data, hash, and FEC can share devices or be separate devices.
Now dump command prints used device sizes, but it requires that
the user specifies all values that are not stored in superblock
(like FEC device and FEC roots).
* Fix check for argp_usage in configure if argp-standalone lib is used.
* Add constant time memcmp and hexa print implementation and use it for
cryptographic keys handling.
* Display progress when wiping the end of the resized device.
* LUKS2 token: prefer token PIN query before passphrase in some cases.
When a user provides --token-type or specific --token-id, a token PIN
query is preferred to a passphrase query.
* LUKS2 token: allow tokens to be replaced with --token-replace option
for cryptsetup token command.
* LUKS2 token: do not continue operation when interrupted in PIN prompt.
* Add --progress-json parameter to utilities.
Progress data can now be printed out in JSON format suitable for
machine processing.
* Embedded Argon2 PBKDF: optimize and simplify thread exit.
* Avoid using SHA1 in tests and fix new enforcements introduced in FIPS
provider for OpenSSL3 (like minimal parameters for PBKDF2).
* Use custom UTF conversion and avoid linking to iconv as a dependency.
* Reimplement BASE64 with simplified code instead of coreutils version.
Libcryptsetup API extensions and changes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Properly define uint32_t constants in API.
This is not a real change, but it avoids strict compiler warnings.
* crypt_resume_by_token_pin() - Resume crypt device using LUKS2 token.
* crypt_get_label() - Get the label of the LUKS2 device.
* crypt_get_subsystem() - Get the subsystem label of the LUKS2 device.
* Make CRYPT_WIPE_ENCRYPTED_ZERO crypt_wipe() option obsolete.
It was never implemented (the idea was to speed up wipe), but with
the recent RNG performance changes, it makes no longer sense.
* Add struct crypt_params_reencrypt changes related to decryption.
* Improve crypt_reencrypt_status() return values.
Empty or any non-LUKS types now returns CRYPT_REENCRYPT_INVALID status.
For LUKS1 devices, it returns CRYPT_REENCRYPT_NONE.

View File

@@ -32,7 +32,8 @@ libcryptsetup_la_LIBADD = \
@LIBARGON2_LIBS@ \
@JSON_C_LIBS@ \
@BLKID_LIBS@ \
$(LTLIBICONV) \
@DL_LIBS@ \
$(LTLIBINTL) \
libcrypto_backend.la \
libutils_io.la
@@ -68,8 +69,6 @@ libcryptsetup_la_SOURCES = \
lib/volumekey.c \
lib/random.c \
lib/crypt_plain.c \
lib/base64.h \
lib/base64.c \
lib/integrity/integrity.h \
lib/integrity/integrity.c \
lib/loopaes/loopaes.h \
@@ -98,6 +97,7 @@ libcryptsetup_la_SOURCES = \
lib/luks2/luks2_keyslot_luks2.c \
lib/luks2/luks2_keyslot_reenc.c \
lib/luks2/luks2_reencrypt.c \
lib/luks2/luks2_reencrypt_digest.c \
lib/luks2/luks2_segment.c \
lib/luks2/luks2_token_keyring.c \
lib/luks2/luks2_token.c \

View File

@@ -1,605 +0,0 @@
/* base64.c -- Encode binary data using printable characters.
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
the Free Software Foundation; either version 2, 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, see <https://www.gnu.org/licenses/>. */
/* Written by Simon Josefsson. Partially adapted from GNU MailUtils
* (mailbox/filter_trans.c, as of 2004-11-28). Improved by review
* from Paul Eggert, Bruno Haible, and Stepan Kasal.
*
* See also RFC 4648 <https://www.ietf.org/rfc/rfc4648.txt>.
*
* Be careful with error checking. Here is how you would typically
* use these functions:
*
* bool ok = base64_decode_alloc (in, inlen, &out, &outlen);
* if (!ok)
* FAIL: input was not valid base64
* if (out == NULL)
* FAIL: memory allocation error
* OK: data in OUT/OUTLEN
*
* size_t outlen = base64_encode_alloc (in, inlen, &out);
* if (out == NULL && outlen == 0 && inlen != 0)
* FAIL: input too long
* if (out == NULL)
* FAIL: memory allocation error
* OK: data in OUT/OUTLEN.
*
*/
#include <config.h>
/* Get prototype. */
#include "base64.h"
/* Get malloc. */
#include <stdlib.h>
/* Get UCHAR_MAX. */
#include <limits.h>
#include <string.h>
/* C89 compliant way to cast 'char' to 'unsigned char'. */
static unsigned char
to_uchar (char ch)
{
return ch;
}
static const char b64c[64] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/* Base64 encode IN array of size INLEN into OUT array. OUT needs
to be of length >= BASE64_LENGTH(INLEN), and INLEN needs to be
a multiple of 3. */
static void
base64_encode_fast (const char *restrict in, size_t inlen, char *restrict out)
{
while (inlen)
{
*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];
inlen -= 3;
in += 3;
}
}
/* Base64 encode IN array of size INLEN into OUT array of size OUTLEN.
If OUTLEN is less than BASE64_LENGTH(INLEN), write as many bytes as
possible. If OUTLEN is larger than BASE64_LENGTH(INLEN), also zero
terminate the output buffer. */
void
base64_encode (const char *restrict in, size_t inlen,
char *restrict out, size_t outlen)
{
/* Note this outlen constraint can be enforced at compile time.
I.E. that the output buffer is exactly large enough to hold
the encoded inlen bytes. The inlen constraints (of corresponding
to outlen, and being a multiple of 3) can change at runtime
at the end of input. However the common case when reading
large inputs is to have both constraints satisfied, so we depend
on both in base_encode_fast(). */
if (outlen % 4 == 0 && inlen == outlen / 4 * 3)
{
base64_encode_fast (in, inlen, out);
return;
}
while (inlen && outlen)
{
*out++ = b64c[(to_uchar (in[0]) >> 2) & 0x3f];
if (!--outlen)
break;
*out++ = b64c[((to_uchar (in[0]) << 4)
+ (--inlen ? to_uchar (in[1]) >> 4 : 0))
& 0x3f];
if (!--outlen)
break;
*out++ =
(inlen
? b64c[((to_uchar (in[1]) << 2)
+ (--inlen ? to_uchar (in[2]) >> 6 : 0))
& 0x3f]
: '=');
if (!--outlen)
break;
*out++ = inlen ? b64c[to_uchar (in[2]) & 0x3f] : '=';
if (!--outlen)
break;
if (inlen)
inlen--;
if (inlen)
in += 3;
}
if (outlen)
*out = '\0';
}
/* Allocate a buffer and store zero terminated base64 encoded data
from array IN of size INLEN, returning BASE64_LENGTH(INLEN), i.e.,
the length of the encoded data, excluding the terminating zero. On
return, the OUT variable will hold a pointer to newly allocated
memory that must be deallocated by the caller. If output string
length would overflow, 0 is returned and OUT is set to NULL. If
memory allocation failed, OUT is set to NULL, and the return value
indicates length of the requested memory block, i.e.,
BASE64_LENGTH(inlen) + 1. */
size_t
base64_encode_alloc (const char *in, size_t inlen, char **out)
{
size_t outlen = 1 + BASE64_LENGTH (inlen);
/* Check for overflow in outlen computation.
*
* If there is no overflow, outlen >= inlen.
*
* If the operation (inlen + 2) overflows then it yields at most +1, so
* outlen is 0.
*
* If the multiplication overflows, we lose at least half of the
* correct value, so the result is < ((inlen + 2) / 3) * 2, which is
* less than (inlen + 2) * 0.66667, which is less than inlen as soon as
* (inlen > 4).
*/
if (inlen > outlen)
{
*out = NULL;
return 0;
}
*out = malloc (outlen);
if (!*out)
return outlen;
base64_encode (in, inlen, *out, outlen);
return outlen - 1;
}
/* With this approach this file works independent of the charset used
(think EBCDIC). However, it does assume that the characters in the
Base64 alphabet (A-Za-z0-9+/) are encoded in 0..255. POSIX
1003.1-2001 require that char and unsigned char are 8-bit
quantities, though, taking care of that problem. But this may be a
potential problem on non-POSIX C99 platforms.
IBM C V6 for AIX mishandles "#define B64(x) ...'x'...", so use "_"
as the formal parameter rather than "x". */
#define B64(_) \
((_) == 'A' ? 0 \
: (_) == 'B' ? 1 \
: (_) == 'C' ? 2 \
: (_) == 'D' ? 3 \
: (_) == 'E' ? 4 \
: (_) == 'F' ? 5 \
: (_) == 'G' ? 6 \
: (_) == 'H' ? 7 \
: (_) == 'I' ? 8 \
: (_) == 'J' ? 9 \
: (_) == 'K' ? 10 \
: (_) == 'L' ? 11 \
: (_) == 'M' ? 12 \
: (_) == 'N' ? 13 \
: (_) == 'O' ? 14 \
: (_) == 'P' ? 15 \
: (_) == 'Q' ? 16 \
: (_) == 'R' ? 17 \
: (_) == 'S' ? 18 \
: (_) == 'T' ? 19 \
: (_) == 'U' ? 20 \
: (_) == 'V' ? 21 \
: (_) == 'W' ? 22 \
: (_) == 'X' ? 23 \
: (_) == 'Y' ? 24 \
: (_) == 'Z' ? 25 \
: (_) == 'a' ? 26 \
: (_) == 'b' ? 27 \
: (_) == 'c' ? 28 \
: (_) == 'd' ? 29 \
: (_) == 'e' ? 30 \
: (_) == 'f' ? 31 \
: (_) == 'g' ? 32 \
: (_) == 'h' ? 33 \
: (_) == 'i' ? 34 \
: (_) == 'j' ? 35 \
: (_) == 'k' ? 36 \
: (_) == 'l' ? 37 \
: (_) == 'm' ? 38 \
: (_) == 'n' ? 39 \
: (_) == 'o' ? 40 \
: (_) == 'p' ? 41 \
: (_) == 'q' ? 42 \
: (_) == 'r' ? 43 \
: (_) == 's' ? 44 \
: (_) == 't' ? 45 \
: (_) == 'u' ? 46 \
: (_) == 'v' ? 47 \
: (_) == 'w' ? 48 \
: (_) == 'x' ? 49 \
: (_) == 'y' ? 50 \
: (_) == 'z' ? 51 \
: (_) == '0' ? 52 \
: (_) == '1' ? 53 \
: (_) == '2' ? 54 \
: (_) == '3' ? 55 \
: (_) == '4' ? 56 \
: (_) == '5' ? 57 \
: (_) == '6' ? 58 \
: (_) == '7' ? 59 \
: (_) == '8' ? 60 \
: (_) == '9' ? 61 \
: (_) == '+' ? 62 \
: (_) == '/' ? 63 \
: -1)
static const signed char b64[0x100] = {
B64 (0), B64 (1), B64 (2), B64 (3),
B64 (4), B64 (5), B64 (6), B64 (7),
B64 (8), B64 (9), B64 (10), B64 (11),
B64 (12), B64 (13), B64 (14), B64 (15),
B64 (16), B64 (17), B64 (18), B64 (19),
B64 (20), B64 (21), B64 (22), B64 (23),
B64 (24), B64 (25), B64 (26), B64 (27),
B64 (28), B64 (29), B64 (30), B64 (31),
B64 (32), B64 (33), B64 (34), B64 (35),
B64 (36), B64 (37), B64 (38), B64 (39),
B64 (40), B64 (41), B64 (42), B64 (43),
B64 (44), B64 (45), B64 (46), B64 (47),
B64 (48), B64 (49), B64 (50), B64 (51),
B64 (52), B64 (53), B64 (54), B64 (55),
B64 (56), B64 (57), B64 (58), B64 (59),
B64 (60), B64 (61), B64 (62), B64 (63),
B64 (64), B64 (65), B64 (66), B64 (67),
B64 (68), B64 (69), B64 (70), B64 (71),
B64 (72), B64 (73), B64 (74), B64 (75),
B64 (76), B64 (77), B64 (78), B64 (79),
B64 (80), B64 (81), B64 (82), B64 (83),
B64 (84), B64 (85), B64 (86), B64 (87),
B64 (88), B64 (89), B64 (90), B64 (91),
B64 (92), B64 (93), B64 (94), B64 (95),
B64 (96), B64 (97), B64 (98), B64 (99),
B64 (100), B64 (101), B64 (102), B64 (103),
B64 (104), B64 (105), B64 (106), B64 (107),
B64 (108), B64 (109), B64 (110), B64 (111),
B64 (112), B64 (113), B64 (114), B64 (115),
B64 (116), B64 (117), B64 (118), B64 (119),
B64 (120), B64 (121), B64 (122), B64 (123),
B64 (124), B64 (125), B64 (126), B64 (127),
B64 (128), B64 (129), B64 (130), B64 (131),
B64 (132), B64 (133), B64 (134), B64 (135),
B64 (136), B64 (137), B64 (138), B64 (139),
B64 (140), B64 (141), B64 (142), B64 (143),
B64 (144), B64 (145), B64 (146), B64 (147),
B64 (148), B64 (149), B64 (150), B64 (151),
B64 (152), B64 (153), B64 (154), B64 (155),
B64 (156), B64 (157), B64 (158), B64 (159),
B64 (160), B64 (161), B64 (162), B64 (163),
B64 (164), B64 (165), B64 (166), B64 (167),
B64 (168), B64 (169), B64 (170), B64 (171),
B64 (172), B64 (173), B64 (174), B64 (175),
B64 (176), B64 (177), B64 (178), B64 (179),
B64 (180), B64 (181), B64 (182), B64 (183),
B64 (184), B64 (185), B64 (186), B64 (187),
B64 (188), B64 (189), B64 (190), B64 (191),
B64 (192), B64 (193), B64 (194), B64 (195),
B64 (196), B64 (197), B64 (198), B64 (199),
B64 (200), B64 (201), B64 (202), B64 (203),
B64 (204), B64 (205), B64 (206), B64 (207),
B64 (208), B64 (209), B64 (210), B64 (211),
B64 (212), B64 (213), B64 (214), B64 (215),
B64 (216), B64 (217), B64 (218), B64 (219),
B64 (220), B64 (221), B64 (222), B64 (223),
B64 (224), B64 (225), B64 (226), B64 (227),
B64 (228), B64 (229), B64 (230), B64 (231),
B64 (232), B64 (233), B64 (234), B64 (235),
B64 (236), B64 (237), B64 (238), B64 (239),
B64 (240), B64 (241), B64 (242), B64 (243),
B64 (244), B64 (245), B64 (246), B64 (247),
B64 (248), B64 (249), B64 (250), B64 (251),
B64 (252), B64 (253), B64 (254), B64 (255)
};
#if UCHAR_MAX == 255
# define uchar_in_range(c) true
#else
# define uchar_in_range(c) ((c) <= 255)
#endif
/* Return true if CH is a character from the Base64 alphabet, and
false otherwise. Note that '=' is padding and not considered to be
part of the alphabet. */
bool
isbase64 (char ch)
{
return uchar_in_range (to_uchar (ch)) && 0 <= b64[to_uchar (ch)];
}
/* Initialize decode-context buffer, CTX. */
void
base64_decode_ctx_init (struct base64_decode_context *ctx)
{
ctx->i = 0;
}
/* If CTX->i is 0 or 4, there are four or more bytes in [*IN..IN_END), and
none of those four is a newline, then return *IN. Otherwise, copy up to
4 - CTX->i non-newline bytes from that range into CTX->buf, starting at
index CTX->i and setting CTX->i to reflect the number of bytes copied,
and return CTX->buf. In either case, advance *IN to point to the byte
after the last one processed, and set *N_NON_NEWLINE to the number of
verified non-newline bytes accessible through the returned pointer. */
static const char *
get_4 (struct base64_decode_context *ctx,
char const *restrict *in, char const *restrict in_end,
size_t *n_non_newline)
{
if (ctx->i == 4)
ctx->i = 0;
if (ctx->i == 0)
{
char const *t = *in;
if (4 <= in_end - *in && memchr (t, '\n', 4) == NULL)
{
/* This is the common case: no newline. */
*in += 4;
*n_non_newline = 4;
return (const char *) t;
}
}
{
/* Copy non-newline bytes into BUF. */
char const *p = *in;
while (p < in_end)
{
char c = *p++;
if (c != '\n')
{
ctx->buf[ctx->i++] = c;
if (ctx->i == 4)
break;
}
}
*in = p;
*n_non_newline = ctx->i;
return ctx->buf;
}
}
#define return_false \
do \
{ \
*outp = out; \
return false; \
} \
while (false)
/* Decode up to four bytes of base64-encoded data, IN, of length INLEN
into the output buffer, *OUT, of size *OUTLEN bytes. Return true if
decoding is successful, false otherwise. If *OUTLEN is too small,
as many bytes as possible are written to *OUT. On return, advance
*OUT to point to the byte after the last one written, and decrement
*OUTLEN to reflect the number of bytes remaining in *OUT. */
static bool
decode_4 (char const *restrict in, size_t inlen,
char *restrict *outp, size_t *outleft)
{
char *out = *outp;
if (inlen < 2)
return false;
if (!isbase64 (in[0]) || !isbase64 (in[1]))
return false;
if (*outleft)
{
*out++ = ((b64[to_uchar (in[0])] << 2)
| (b64[to_uchar (in[1])] >> 4));
--*outleft;
}
if (inlen == 2)
return_false;
if (in[2] == '=')
{
if (inlen != 4)
return_false;
if (in[3] != '=')
return_false;
}
else
{
if (!isbase64 (in[2]))
return_false;
if (*outleft)
{
*out++ = (((b64[to_uchar (in[1])] << 4) & 0xf0)
| (b64[to_uchar (in[2])] >> 2));
--*outleft;
}
if (inlen == 3)
return_false;
if (in[3] == '=')
{
if (inlen != 4)
return_false;
}
else
{
if (!isbase64 (in[3]))
return_false;
if (*outleft)
{
*out++ = (((b64[to_uchar (in[2])] << 6) & 0xc0)
| b64[to_uchar (in[3])]);
--*outleft;
}
}
}
*outp = out;
return true;
}
/* Decode base64-encoded input array IN of length INLEN to output array
OUT that can hold *OUTLEN bytes. The input data may be interspersed
with newlines. Return true if decoding was successful, i.e. if the
input was valid base64 data, false otherwise. If *OUTLEN is too
small, as many bytes as possible will be written to OUT. On return,
*OUTLEN holds the length of decoded bytes in OUT. Note that as soon
as any non-alphabet, non-newline character is encountered, decoding
is stopped and false is returned. If INLEN is zero, then process
only whatever data is stored in CTX.
Initially, CTX must have been initialized via base64_decode_ctx_init.
Subsequent calls to this function must reuse whatever state is recorded
in that buffer. It is necessary for when a quadruple of base64 input
bytes spans two input buffers.
If CTX is NULL then newlines are treated as garbage and the input
buffer is processed as a unit. */
bool
base64_decode_ctx (struct base64_decode_context *ctx,
const char *restrict in, size_t inlen,
char *restrict out, size_t *outlen)
{
size_t outleft = *outlen;
bool ignore_newlines = ctx != NULL;
bool flush_ctx = false;
unsigned int ctx_i = 0;
if (ignore_newlines)
{
ctx_i = ctx->i;
flush_ctx = inlen == 0;
}
while (true)
{
size_t outleft_save = outleft;
if (ctx_i == 0 && !flush_ctx)
{
while (true)
{
/* Save a copy of outleft, in case we need to re-parse this
block of four bytes. */
outleft_save = outleft;
if (!decode_4 (in, inlen, &out, &outleft))
break;
in += 4;
inlen -= 4;
}
}
if (inlen == 0 && !flush_ctx)
break;
/* Handle the common case of 72-byte wrapped lines.
This also handles any other multiple-of-4-byte wrapping. */
if (inlen && *in == '\n' && ignore_newlines)
{
++in;
--inlen;
continue;
}
/* Restore OUT and OUTLEFT. */
out -= outleft_save - outleft;
outleft = outleft_save;
{
char const *in_end = in + inlen;
char const *non_nl;
if (ignore_newlines)
non_nl = get_4 (ctx, &in, in_end, &inlen);
else
non_nl = in; /* Might have nl in this case. */
/* If the input is empty or consists solely of newlines (0 non-newlines),
then we're done. Likewise if there are fewer than 4 bytes when not
flushing context and not treating newlines as garbage. */
if (inlen == 0 || (inlen < 4 && !flush_ctx && ignore_newlines))
{
inlen = 0;
break;
}
if (!decode_4 (non_nl, inlen, &out, &outleft))
break;
inlen = in_end - in;
}
}
*outlen -= outleft;
return inlen == 0;
}
/* Allocate an output buffer in *OUT, and decode the base64 encoded
data stored in IN of size INLEN to the *OUT buffer. On return, the
size of the decoded data is stored in *OUTLEN. OUTLEN may be NULL,
if the caller is not interested in the decoded length. *OUT may be
NULL to indicate an out of memory error, in which case *OUTLEN
contains the size of the memory block needed. The function returns
true on successful decoding and memory allocation errors. (Use the
*OUT and *OUTLEN parameters to differentiate between successful
decoding and memory error.) The function returns false if the
input was invalid, in which case *OUT is NULL and *OUTLEN is
undefined. */
bool
base64_decode_alloc_ctx (struct base64_decode_context *ctx,
const char *in, size_t inlen, char **out,
size_t *outlen)
{
/* This may allocate a few bytes too many, depending on input,
but it's not worth the extra CPU time to compute the exact size.
The exact size is 3 * (inlen + (ctx ? ctx->i : 0)) / 4, minus 1 if the
input ends with "=" and minus another 1 if the input ends with "==".
Dividing before multiplying avoids the possibility of overflow. */
size_t needlen = 3 * (inlen / 4) + 3;
*out = malloc (needlen);
if (!*out)
return true;
if (!base64_decode_ctx (ctx, in, inlen, *out, &needlen))
{
free (*out);
*out = NULL;
return false;
}
if (outlen)
*outlen = needlen;
return true;
}

View File

@@ -1,68 +0,0 @@
/* base64.h -- Encode binary data using printable characters.
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
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, 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, see <https://www.gnu.org/licenses/>. */
#ifndef BASE64_H
# define BASE64_H
/* Get size_t. */
# include <stddef.h>
/* Get bool. */
# include <stdbool.h>
# ifdef __cplusplus
extern "C" {
# endif
/* This uses that the expression (n+(k-1))/k means the smallest
integer >= n/k, i.e., the ceiling of n/k. */
# define BASE64_LENGTH(inlen) ((((inlen) + 2) / 3) * 4)
struct base64_decode_context
{
unsigned int i;
char buf[4];
};
extern bool isbase64 (char ch) __attribute__ ((__const__));
extern void base64_encode (const char *restrict in, size_t inlen,
char *restrict out, size_t outlen);
extern size_t base64_encode_alloc (const char *in, size_t inlen, char **out);
extern void base64_decode_ctx_init (struct base64_decode_context *ctx);
extern bool base64_decode_ctx (struct base64_decode_context *ctx,
const char *restrict in, size_t inlen,
char *restrict out, size_t *outlen);
extern bool base64_decode_alloc_ctx (struct base64_decode_context *ctx,
const char *in, size_t inlen,
char **out, size_t *outlen);
#define base64_decode(in, inlen, out, outlen) \
base64_decode_ctx (NULL, in, inlen, out, outlen)
#define base64_decode_alloc(in, inlen, out, outlen) \
base64_decode_alloc_ctx (NULL, in, inlen, out, outlen)
# ifdef __cplusplus
}
# endif
#endif /* BASE64_H */

View File

@@ -1,9 +1,9 @@
/*
* BITLK (BitLocker-compatible) volume handling
*
* Copyright (C) 2019-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2019-2021 Milan Broz
* Copyright (C) 2019-2021 Vojtech Trefny
* Copyright (C) 2019-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2019-2022 Milan Broz
* Copyright (C) 2019-2022 Vojtech Trefny
*
* 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,6 @@
#include <string.h>
#include <uuid/uuid.h>
#include <time.h>
#include <iconv.h>
#include <limits.h>
#include "bitlk.h"
@@ -234,86 +233,11 @@ static const char* get_bitlk_type_string(BITLKEncryptionType type)
}
}
/* TODO -- move to some utils file */
static void hexprint(struct crypt_device *cd, const char *d, int n, const char *sep)
{
int i;
for(i = 0; i < n; i++)
log_std(cd, "%02hhx%s", (const char)d[i], sep);
}
static uint64_t filetime_to_unixtime(uint64_t time)
{
return (time - EPOCH_AS_FILETIME) / HUNDREDS_OF_NANOSECONDS;
}
static int convert_to_utf8(struct crypt_device *cd, uint8_t *input, size_t inlen, char **out)
{
char *outbuf = NULL;
iconv_t ic;
size_t ic_inlen = inlen;
size_t ic_outlen = inlen;
char *ic_outbuf = NULL;
size_t r = 0;
outbuf = malloc(inlen);
if (outbuf == NULL)
return -ENOMEM;
memset(outbuf, 0, inlen);
ic_outbuf = outbuf;
ic = iconv_open("UTF-8", "UTF-16LE");
r = iconv(ic, (char **) &input, &ic_inlen, &ic_outbuf, &ic_outlen);
iconv_close(ic);
if (r == 0)
*out = strdup(outbuf);
else {
*out = NULL;
log_dbg(cd, "Failed to convert volume description: %s", strerror(errno));
r = 0;
}
free(outbuf);
return r;
}
static int passphrase_to_utf16(struct crypt_device *cd, char *input, size_t inlen, char **out)
{
char *outbuf = NULL;
iconv_t ic;
size_t ic_inlen = inlen;
size_t ic_outlen = inlen * 2;
char *ic_outbuf = NULL;
size_t r = 0;
if (inlen == 0)
return r;
outbuf = crypt_safe_alloc(inlen * 2);
if (outbuf == NULL)
return -ENOMEM;
memset(outbuf, 0, inlen * 2);
ic_outbuf = outbuf;
ic = iconv_open("UTF-16LE", "UTF-8");
r = iconv(ic, &input, &ic_inlen, &ic_outbuf, &ic_outlen);
iconv_close(ic);
if (r == 0) {
*out = outbuf;
} else {
*out = NULL;
crypt_safe_free(outbuf);
log_dbg(cd, "Failed to convert passphrase: %s", strerror(errno));
r = -errno;
}
return r;
}
static int parse_vmk_entry(struct crypt_device *cd, uint8_t *data, int start, int end, struct bitlk_vmk **vmk)
{
uint16_t key_entry_size = 0;
@@ -324,6 +248,7 @@ static int parse_vmk_entry(struct crypt_device *cd, uint8_t *data, int start, in
const char *key = NULL;
struct volume_key *vk = NULL;
bool supported = false;
int r = 0;
/* only passphrase or recovery passphrase vmks are supported (can be used to activate) */
supported = (*vmk)->protection == BITLK_PROTECTION_PASSPHRASE ||
@@ -393,9 +318,14 @@ static int parse_vmk_entry(struct crypt_device *cd, uint8_t *data, int start, in
} else if (key_entry_value == BITLK_ENTRY_VALUE_RECOVERY_TIME) {
;
} else if (key_entry_value == BITLK_ENTRY_VALUE_STRING) {
if (convert_to_utf8(cd, data + start + BITLK_ENTRY_HEADER_LEN, key_entry_size - BITLK_ENTRY_HEADER_LEN, &string) < 0) {
log_err(cd, _("Invalid string found when parsing Volume Master Key."));
string = malloc((key_entry_size - BITLK_ENTRY_HEADER_LEN) * 2 + 1);
if (!string)
return -ENOMEM;
r = crypt_utf16_to_utf8(&string, CONST_CAST(char16_t *)(data + start + BITLK_ENTRY_HEADER_LEN),
key_entry_size - BITLK_ENTRY_HEADER_LEN);
if (r < 0 || !string) {
free(string);
log_err(cd, _("Invalid string found when parsing Volume Master Key."));
return -EINVAL;
} else if ((*vmk)->name != NULL) {
if (supported) {
@@ -486,6 +416,7 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
int end = 0;
size_t key_size = 0;
const char *key = NULL;
char *description = NULL;
struct bitlk_vmk *vmk = NULL;
struct bitlk_vmk *vmk_p = params->vmks;
@@ -499,8 +430,8 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
/* read and check the signature */
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
device_alignment(device), &sig, sizeof(sig), 0) != sizeof(sig)) {
log_err(cd, _("Failed to read BITLK signature from %s."), device_path(device));
r = -EINVAL;
log_dbg(cd, "Failed to read BITLK signature from %s.", device_path(device));
r = -EIO;
goto out;
}
@@ -511,7 +442,7 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
params->togo = true;
fve_offset = BITLK_HEADER_METADATA_OFFSET_TOGO;
} else {
log_err(cd, _("Invalid or unknown signature for BITLK device."));
log_dbg(cd, "Invalid or unknown signature for BITLK device.");
r = -EINVAL;
goto out;
}
@@ -581,6 +512,7 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
le16_to_cpu(fve.curr_state), le16_to_cpu(fve.next_state));
}
params->volume_size = le64_to_cpu(fve.volume_size);
params->metadata_version = le16_to_cpu(fve.fve_version);
fve_metadata_size = le32_to_cpu(fve.metadata_size);
@@ -738,13 +670,18 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
params->volume_header_size = le64_to_cpu(entry_header.size);
/* volume description (utf-16 string) */
} else if (entry_type == BITLK_ENTRY_TYPE_DESCRIPTION) {
r = convert_to_utf8(cd, fve_entries + start + BITLK_ENTRY_HEADER_LEN,
entry_size - BITLK_ENTRY_HEADER_LEN,
&(params->description));
if (r < 0) {
description = malloc((entry_size - BITLK_ENTRY_HEADER_LEN - BITLK_ENTRY_HEADER_LEN) * 2 + 1);
if (!description)
return -ENOMEM;
r = crypt_utf16_to_utf8(&description, CONST_CAST(char16_t *)(fve_entries + start + BITLK_ENTRY_HEADER_LEN),
entry_size - BITLK_ENTRY_HEADER_LEN);
if (r < 0 || !description) {
free(description);
BITLK_bitlk_vmk_free(vmk);
log_err(cd, _("Failed to convert BITLK volume description"));
goto out;
}
params->description = description;
}
start += entry_size;
@@ -767,6 +704,7 @@ int BITLK_dump(struct crypt_device *cd, struct device *device, struct bitlk_meta
log_std(cd, "Version: \t%u\n", params->metadata_version);
log_std(cd, "GUID: \t%s\n", params->guid);
log_std(cd, "Sector size: \t%u [bytes]\n", params->sector_size);
log_std(cd, "Volume size: \t%" PRIu64 " [bytes]\n", params->volume_size);
log_std(cd, "Created: \t%s", ctime((time_t *)&(params->creation_time)));
log_std(cd, "Description: \t%s\n", params->description);
log_std(cd, "Cipher name: \t%s\n", params->cipher);
@@ -785,7 +723,7 @@ int BITLK_dump(struct crypt_device *cd, struct device *device, struct bitlk_meta
log_std(cd, "\tGUID: \t%s\n", vmk_p->guid);
log_std(cd, "\tProtection: \t%s\n", get_vmk_protection_string (vmk_p->protection));
log_std(cd, "\tSalt: \t");
hexprint(cd, (const char *) vmk_p->salt, 16, "");
crypt_log_hex(cd, (const char *) vmk_p->salt, 16, "", 0, NULL);
log_std(cd, "\n");
vk_p = vmk_p->vk;
@@ -869,13 +807,20 @@ static int get_recovery_key(struct crypt_device *cd,
return 0;
}
static int parse_external_key_entry(struct crypt_device *cd, const char *data, int start, int end, struct volume_key **vk)
static int parse_external_key_entry(struct crypt_device *cd,
const char *data,
int start,
int end,
struct volume_key **vk,
const struct bitlk_metadata *params)
{
uint16_t key_entry_size = 0;
uint16_t key_entry_type = 0;
uint16_t key_entry_value = 0;
size_t key_size = 0;
const char *key = NULL;
struct bitlk_guid guid;
char guid_buf[UUID_STR_LEN] = {0};
while (end - start > 2) {
/* size of this entry */
@@ -892,8 +837,7 @@ static int parse_external_key_entry(struct crypt_device *cd, const char *data, i
key_entry_type = le16_to_cpu(key_entry_type);
key_entry_value = le16_to_cpu(key_entry_value);
/* only properties should be in this entry */
if (key_entry_type != BITLK_ENTRY_TYPE_PROPERTY) {
if (key_entry_type != BITLK_ENTRY_TYPE_PROPERTY && key_entry_type != BITLK_ENTRY_TYPE_VOLUME_GUID) {
log_err(cd, _("Unexpected metadata entry type '%u' found when parsing external key."), key_entry_type);
return -EINVAL;
}
@@ -908,7 +852,15 @@ static int parse_external_key_entry(struct crypt_device *cd, const char *data, i
/* optional "ExternalKey" string, we can safely ignore it */
} else if (key_entry_value == BITLK_ENTRY_VALUE_STRING)
;
else {
/* GUID of the BitLocker device we are trying to open with this key */
else if (key_entry_value == BITLK_ENTRY_VALUE_GUID) {
memcpy(&guid, data + start + BITLK_ENTRY_HEADER_LEN, sizeof(struct bitlk_guid));
guid_to_string(&guid, guid_buf);
if (strcmp(guid_buf, params->guid) != 0) {
log_err(cd, _("BEK file GUID '%s' does not match GUID of the volume."), guid_buf);
return -EINVAL;
}
} else {
log_err(cd, _("Unexpected metadata entry value '%u' found when parsing external key."), key_entry_value);
return -EINVAL;
}
@@ -925,7 +877,8 @@ static int get_startup_key(struct crypt_device *cd,
const char *password,
size_t passwordLen,
const struct bitlk_vmk *vmk,
struct volume_key **su_key)
struct volume_key **su_key,
const struct bitlk_metadata *params)
{
struct bitlk_bek_header bek_header = {0};
char guid_buf[UUID_STR_LEN] = {0};
@@ -947,12 +900,12 @@ static int get_startup_key(struct crypt_device *cd,
return -EPERM;
if (bek_header.metadata_version != 1) {
log_err(cd, "Unsupported BEK metadata version %" PRIu32 "", bek_header.metadata_version);
log_err(cd, _("Unsupported BEK metadata version %" PRIu32), bek_header.metadata_version);
return -ENOTSUP;
}
if (bek_header.metadata_size != passwordLen) {
log_err(cd, "Unexpected BEK metadata size %" PRIu32 " does not match BEK file length", bek_header.metadata_size);
log_err(cd, _("Unexpected BEK metadata size %" PRIu32 " does not match BEK file length"), bek_header.metadata_size);
return -EINVAL;
}
@@ -975,7 +928,7 @@ static int get_startup_key(struct crypt_device *cd,
if (key_entry_type == BITLK_ENTRY_TYPE_STARTUP_KEY && key_entry_value == BITLK_ENTRY_VALUE_EXTERNAL_KEY) {
return parse_external_key_entry(cd, password,
BITLK_BEK_FILE_HEADER_LEN + BITLK_ENTRY_HEADER_LEN + BITLK_STARTUP_KEY_HEADER_LEN,
passwordLen, su_key);
passwordLen, su_key, params);
} else {
log_err(cd, _("Unexpected metadata entry found when parsing startup key."));
log_dbg(cd, "Entry type: %u, entry value: %u", key_entry_type, key_entry_value);
@@ -993,7 +946,7 @@ static int bitlk_kdf(struct crypt_device *cd,
struct bitlk_kdf_data kdf = {};
struct crypt_hash *hd = NULL;
int len = 0;
char *utf16Password = NULL;
char16_t *utf16Password = NULL;
int i = 0;
int r = 0;
@@ -1010,11 +963,16 @@ static int bitlk_kdf(struct crypt_device *cd,
if (!recovery) {
/* passphrase: convert to UTF-16 first, then sha256(sha256(pw)) */
r = passphrase_to_utf16(cd, CONST_CAST(char*)password, passwordLen, &utf16Password);
utf16Password = crypt_safe_alloc(sizeof(char16_t) * (passwordLen + 1));
if (!utf16Password) {
r = -ENOMEM;
goto out;
}
r = crypt_utf8_to_utf16(&utf16Password, CONST_CAST(char*)password, passwordLen);
if (r < 0)
goto out;
crypt_hash_write(hd, utf16Password, passwordLen * 2);
crypt_hash_write(hd, (char*)utf16Password, passwordLen * 2);
r = crypt_hash_final(hd, kdf.initial_sha256, len);
if (r < 0)
goto out;
@@ -1142,7 +1100,7 @@ int BITLK_get_volume_key(struct crypt_device *cd,
if (r)
return r;
} else if (next_vmk->protection == BITLK_PROTECTION_STARTUP_KEY) {
r = get_startup_key(cd, password, passwordLen, next_vmk, &vmk_dec_key);
r = get_startup_key(cd, password, passwordLen, next_vmk, &vmk_dec_key, params);
if (r) {
next_vmk = next_vmk->next;
continue;
@@ -1243,7 +1201,7 @@ static int _activate(struct crypt_device *cd,
uint64_t next_start = 0;
uint64_t next_end = 0;
uint64_t last_segment = 0;
uint32_t dmt_flags;
uint32_t dmt_flags = 0;
r = _activate_check(cd, params);
if (r)
@@ -1254,6 +1212,11 @@ static int _activate(struct crypt_device *cd,
if (r)
return r;
if (dmd.size * SECTOR_SIZE != params->volume_size)
log_std(cd, _("WARNING: BitLocker volume size %" PRIu64 " does not match the underlying device size %" PRIu64 ""),
params->volume_size,
dmd.size * SECTOR_SIZE);
/* there will be always 4 dm-zero segments: 3x metadata, 1x FS header */
for (i = 0; i < 3; i++) {
segments[num_segments].offset = params->metadata_offset[i] / SECTOR_SIZE;
@@ -1384,6 +1347,14 @@ static int _activate(struct crypt_device *cd,
log_err(cd, _("Cannot activate device, kernel dm-crypt is missing support for BITLK Elephant diffuser."));
r = -ENOTSUP;
}
if ((dmd.flags & CRYPT_ACTIVATE_IV_LARGE_SECTORS) && !(dmt_flags & DM_SECTOR_SIZE_SUPPORTED)) {
log_err(cd, _("Cannot activate device, kernel dm-crypt is missing support for large sector size."));
r = -ENOTSUP;
}
if (dm_flags(cd, DM_ZERO, &dmt_flags) < 0) {
log_err(cd, _("Cannot activate device, kernel dm-zero module is missing."));
r = -ENOTSUP;
}
}
out:
dm_targets_free(cd, &dmd);

View File

@@ -1,9 +1,9 @@
/*
* BITLK (BitLocker-compatible) header definition
*
* Copyright (C) 2019-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2019-2021 Milan Broz
* Copyright (C) 2019-2021 Vojtech Trefny
* Copyright (C) 2019-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2019-2022 Milan Broz
* Copyright (C) 2019-2022 Vojtech Trefny
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -61,6 +61,7 @@ typedef enum {
BITLK_ENTRY_TYPE_STARTUP_KEY = 0x0006,
BITLK_ENTRY_TYPE_DESCRIPTION = 0x0007,
BITLK_ENTRY_TYPE_VOLUME_HEADER = 0x000f,
BITLK_ENTRY_TYPE_VOLUME_GUID = 0x0019,
} BITLKFVEEntryType;
typedef enum {
@@ -76,6 +77,7 @@ typedef enum {
BITLK_ENTRY_VALUE_EXTERNAL_KEY = 0x0009,
BITLK_ENTRY_VALUE_OFFSET_SIZE = 0x000f,
BITLK_ENTRY_VALUE_RECOVERY_TIME = 0x015,
BITLK_ENTRY_VALUE_GUID = 0x0017,
} BITLKFVEEntryValue;
struct bitlk_vmk {
@@ -97,6 +99,7 @@ struct bitlk_fvek {
struct bitlk_metadata {
uint16_t sector_size;
uint64_t volume_size;
bool togo;
bool state;
BITLKEncryptionType type;

View File

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

View File

@@ -9,6 +9,8 @@ libcrypto_backend_la_SOURCES = \
lib/crypto_backend/crypto_storage.c \
lib/crypto_backend/pbkdf_check.c \
lib/crypto_backend/crc32.c \
lib/crypto_backend/base64.c \
lib/crypto_backend/utf8.c \
lib/crypto_backend/argon2_generic.c \
lib/crypto_backend/cipher_generic.c \
lib/crypto_backend/cipher_check.c

View File

@@ -120,18 +120,24 @@ void free_memory(const argon2_context *context, uint8_t *memory,
}
}
void NOT_OPTIMIZED secure_wipe_memory(void *v, size_t n) {
#if defined(_MSC_VER) && VC_GE_2005(_MSC_VER)
void secure_wipe_memory(void *v, size_t n) {
SecureZeroMemory(v, n);
}
#elif defined memset_s
void secure_wipe_memory(void *v, size_t n) {
memset_s(v, n, 0, n);
}
#elif defined(HAVE_EXPLICIT_BZERO)
void secure_wipe_memory(void *v, size_t n) {
explicit_bzero(v, n);
}
#else
void NOT_OPTIMIZED secure_wipe_memory(void *v, size_t n) {
static void *(*const volatile memset_sec)(void *, int, size_t) = &memset;
memset_sec(v, 0, n);
#endif
}
#endif
/* Memory clear flag defaults to true. */
int FLAG_clear_internal_memory = 1;
@@ -273,7 +279,6 @@ static void *fill_segment_thr(void *thread_data)
{
argon2_thread_data *my_data = thread_data;
fill_segment(my_data->instance_ptr, my_data->pos);
argon2_thread_exit();
return 0;
}

View File

@@ -46,12 +46,4 @@ int argon2_thread_join(argon2_thread_handle_t handle) {
#endif
}
void argon2_thread_exit(void) {
#if defined(_WIN32)
_endthreadex(0);
#else
pthread_exit(NULL);
#endif
}
#endif /* ARGON2_NO_THREADS */

View File

@@ -58,10 +58,5 @@ int argon2_thread_create(argon2_thread_handle_t *handle,
*/
int argon2_thread_join(argon2_thread_handle_t handle);
/* Terminate the current thread. Must be run inside a thread created by
* argon2_thread_create.
*/
void argon2_thread_exit(void);
#endif /* ARGON2_NO_THREADS */
#endif

View File

@@ -1,8 +1,8 @@
/*
* Argon2 PBKDF2 library wrapper
*
* Copyright (C) 2016-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2021 Milan Broz
* Copyright (C) 2016-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2022 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

277
lib/crypto_backend/base64.c Normal file
View File

@@ -0,0 +1,277 @@
/*
* Base64 "Not encryption" helpers, copied and adapted from systemd project.
*
* Copyright (C) 2010 Lennart Poettering
*
* cryptsetup related changes
* Copyright (C) 2021-2022 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 <stdlib.h>
#include <limits.h>
#include <assert.h>
#include "crypto_backend.h"
#define WHITESPACE " \t\n\r"
/* https://tools.ietf.org/html/rfc4648#section-4 */
static char base64char(int x)
{
static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
return table[x & 63];
}
static int unbase64char(char c)
{
unsigned offset;
if (c >= 'A' && c <= 'Z')
return c - 'A';
offset = 'Z' - 'A' + 1;
if (c >= 'a' && c <= 'z')
return c - 'a' + offset;
offset += 'z' - 'a' + 1;
if (c >= '0' && c <= '9')
return c - '0' + offset;
offset += '9' - '0' + 1;
if (c == '+')
return offset;
offset++;
if (c == '/')
return offset;
return -EINVAL;
}
int crypt_base64_encode(char **out, size_t *out_length, const char *in, size_t in_length)
{
char *r, *z;
const uint8_t *x;
assert(in || in_length == 0);
assert(out);
/* three input bytes makes four output bytes, padding is added so we must round up */
z = r = malloc(4 * (in_length + 2) / 3 + 1);
if (!r)
return -ENOMEM;
for (x = (const uint8_t *)in; x < (const uint8_t*)in + (in_length / 3) * 3; x += 3) {
/* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
*(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
*(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
*(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */
*(z++) = base64char(x[2] & 63); /* 00ZZZZZZ */
}
switch (in_length % 3) {
case 2:
*(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
*(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
*(z++) = base64char((x[1] & 15) << 2); /* 00YYYY00 */
*(z++) = '=';
break;
case 1:
*(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
*(z++) = base64char((x[0] & 3) << 4); /* 00XX0000 */
*(z++) = '=';
*(z++) = '=';
break;
}
*z = 0;
*out = r;
if (out_length)
*out_length = z - r;
return 0;
}
static int unbase64_next(const char **p, size_t *l)
{
int ret;
assert(p);
assert(l);
/* Find the next non-whitespace character, and decode it. If we find padding, we return it as INT_MAX. We
* greedily skip all preceding and all following whitespace. */
for (;;) {
if (*l == 0)
return -EPIPE;
if (!strchr(WHITESPACE, **p))
break;
/* Skip leading whitespace */
(*p)++, (*l)--;
}
if (**p == '=')
ret = INT_MAX; /* return padding as INT_MAX */
else {
ret = unbase64char(**p);
if (ret < 0)
return ret;
}
for (;;) {
(*p)++, (*l)--;
if (*l == 0)
break;
if (!strchr(WHITESPACE, **p))
break;
/* Skip following whitespace */
}
return ret;
}
int crypt_base64_decode(char **out, size_t *out_length, const char *in, size_t in_length)
{
uint8_t *buf = NULL;
const char *x;
uint8_t *z;
size_t len;
int r;
assert(in || in_length == 0);
assert(out);
assert(out_length);
if (in_length == (size_t) -1)
in_length = strlen(in);
/* A group of four input bytes needs three output bytes, in case of padding we need to add two or three extra
* bytes. Note that this calculation is an upper boundary, as we ignore whitespace while decoding */
len = (in_length / 4) * 3 + (in_length % 4 != 0 ? (in_length % 4) - 1 : 0);
buf = malloc(len + 1);
if (!buf)
return -ENOMEM;
for (x = in, z = buf;;) {
int a, b, c, d; /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
a = unbase64_next(&x, &in_length);
if (a == -EPIPE) /* End of string */
break;
if (a < 0) {
r = a;
goto err;
}
if (a == INT_MAX) { /* Padding is not allowed at the beginning of a 4ch block */
r = -EINVAL;
goto err;
}
b = unbase64_next(&x, &in_length);
if (b < 0) {
r = b;
goto err;
}
if (b == INT_MAX) { /* Padding is not allowed at the second character of a 4ch block either */
r = -EINVAL;
goto err;
}
c = unbase64_next(&x, &in_length);
if (c < 0) {
r = c;
goto err;
}
d = unbase64_next(&x, &in_length);
if (d < 0) {
r = d;
goto err;
}
if (c == INT_MAX) { /* Padding at the third character */
if (d != INT_MAX) { /* If the third character is padding, the fourth must be too */
r = -EINVAL;
goto err;
}
/* b == 00YY0000 */
if (b & 15) {
r = -EINVAL;
goto err;
}
if (in_length > 0) { /* Trailing rubbish? */
r = -ENAMETOOLONG;
goto err;
}
*(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
break;
}
if (d == INT_MAX) {
/* c == 00ZZZZ00 */
if (c & 3) {
r = -EINVAL;
goto err;
}
if (in_length > 0) { /* Trailing rubbish? */
r = -ENAMETOOLONG;
goto err;
}
*(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
*(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
break;
}
*(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
*(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
*(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */
}
*z = 0;
*out_length = (size_t) (z - buf);
*out = (char *)buf;
return 0;
err:
free(buf);
/* Ignore other errors in crypt_backend */
if (r != -ENOMEM)
r = -EINVAL;
return r;
}

View File

@@ -1,8 +1,8 @@
/*
* Cipher performance check
*
* Copyright (C) 2018-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2018-2021 Milan Broz
* Copyright (C) 2018-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2018-2022 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

@@ -1,8 +1,8 @@
/*
* Linux kernel cipher generic utilities
*
* Copyright (C) 2018-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2018-2021 Milan Broz
* Copyright (C) 2018-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2018-2022 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

@@ -1,8 +1,8 @@
/*
* crypto backend implementation
*
* Copyright (C) 2010-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2021 Milan Broz
* Copyright (C) 2010-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2022 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,13 +25,19 @@
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#ifdef HAVE_UCHAR_H
#include <uchar.h>
#else
#define char32_t uint32_t
#define char16_t uint16_t
#endif
struct crypt_hash;
struct crypt_hmac;
struct crypt_cipher;
struct crypt_storage;
int crypt_backend_init(void);
int crypt_backend_init(bool fips);
void crypt_backend_destroy(void);
#define CRYPT_BACKEND_KERNEL (1 << 0) /* Crypto uses kernel part, for benchmark */
@@ -83,6 +89,14 @@ int crypt_pbkdf_perf(const char *kdf, const char *hash,
/* CRC32 */
uint32_t crypt_crc32(uint32_t seed, const unsigned char *buf, size_t len);
/* Base64 */
int crypt_base64_encode(char **out, size_t *out_length, const char *in, size_t in_length);
int crypt_base64_decode(char **out, size_t *out_length, const char *in, size_t in_length);
/* UTF8/16 */
int crypt_utf16_to_utf8(char **out, const char16_t *s, size_t length /* bytes! */);
int crypt_utf8_to_utf16(char16_t **out, const char *s, size_t length);
/* Block ciphers */
int crypt_cipher_ivsize(const char *name, const char *mode);
int crypt_cipher_wrapped_key(const char *name, const char *mode);
@@ -135,4 +149,7 @@ static inline void crypt_backend_memzero(void *s, size_t n)
#endif
}
/* Memcmp helper (memcmp in constant time) */
int crypt_backend_memeq(const void *m1, const void *m2, size_t n);
#endif /* _CRYPTO_BACKEND_H */

View File

@@ -1,8 +1,8 @@
/*
* crypto backend implementation
*
* Copyright (C) 2010-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2021 Milan Broz
* Copyright (C) 2010-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2022 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -58,4 +58,18 @@ int crypt_bitlk_decrypt_key_kernel(const void *key, size_t key_length,
const char *iv, size_t iv_length,
const char *tag, size_t tag_length);
/* Internal implementation for constant time memory comparison */
static inline int crypt_internal_memeq(const void *m1, const void *m2, size_t n)
{
const unsigned char *_m1 = (const unsigned char *) m1;
const unsigned char *_m2 = (const unsigned char *) m2;
unsigned char result = 0;
size_t i;
for (i = 0; i < n; i++)
result |= _m1[i] ^ _m2[i];
return result;
}
#endif /* _CRYPTO_BACKEND_INTERNAL_H */

View File

@@ -1,8 +1,8 @@
/*
* Linux kernel userspace API crypto backend implementation (skcipher)
*
* Copyright (C) 2012-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2021 Milan Broz
* Copyright (C) 2012-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2022 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

@@ -1,8 +1,8 @@
/*
* GCRYPT crypto backend implementation
*
* Copyright (C) 2010-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2021 Milan Broz
* Copyright (C) 2010-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2022 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -94,7 +94,7 @@ static void crypt_hash_test_whirlpool_bug(void)
crypto_backend_whirlpool_bug = 1;
}
int crypt_backend_init(void)
int crypt_backend_init(bool fips __attribute__((unused)))
{
int r;
@@ -550,3 +550,8 @@ out:
return -ENOTSUP;
#endif
}
int crypt_backend_memeq(const void *m1, const void *m2, size_t n)
{
return crypt_internal_memeq(m1, m2, n);
}

View File

@@ -1,8 +1,8 @@
/*
* Linux kernel userspace API crypto backend implementation
*
* Copyright (C) 2010-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2021 Milan Broz
* Copyright (C) 2010-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2022 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -117,7 +117,7 @@ static int crypt_kernel_socket_init(struct sockaddr_alg *sa, int *tfmfd, int *op
return 0;
}
int crypt_backend_init(void)
int crypt_backend_init(bool fips __attribute__((unused)))
{
struct utsname uts;
struct sockaddr_alg sa = {
@@ -416,3 +416,8 @@ int crypt_bitlk_decrypt_key(const void *key, size_t key_length,
return crypt_bitlk_decrypt_key_kernel(key, key_length, in, out, length,
iv, iv_length, tag, tag_length);
}
int crypt_backend_memeq(const void *m1, const void *m2, size_t n)
{
return crypt_internal_memeq(m1, m2, n);
}

View File

@@ -1,8 +1,8 @@
/*
* Nettle crypto backend implementation
*
* Copyright (C) 2011-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2021 Milan Broz
* Copyright (C) 2011-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2022 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,6 +26,7 @@
#include <nettle/sha3.h>
#include <nettle/hmac.h>
#include <nettle/pbkdf2.h>
#include <nettle/memops.h>
#include "crypto_backend_internal.h"
#if HAVE_NETTLE_VERSION_H
@@ -213,7 +214,7 @@ static struct hash_alg *_get_alg(const char *name)
return NULL;
}
int crypt_backend_init(void)
int crypt_backend_init(bool fips __attribute__((unused)))
{
return 0;
}
@@ -446,3 +447,9 @@ int crypt_bitlk_decrypt_key(const void *key, size_t key_length,
return crypt_bitlk_decrypt_key_kernel(key, key_length, in, out, length,
iv, iv_length, tag, tag_length);
}
int crypt_backend_memeq(const void *m1, const void *m2, size_t n)
{
/* The logic is inverse to memcmp... */
return !memeql_sec(m1, m2, n);
}

View File

@@ -1,8 +1,8 @@
/*
* NSS crypto backend implementation
*
* Copyright (C) 2010-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2021 Milan Broz
* Copyright (C) 2010-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2022 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -75,7 +75,7 @@ static struct hash_alg *_get_alg(const char *name)
return NULL;
}
int crypt_backend_init(void)
int crypt_backend_init(bool fips __attribute__((unused)))
{
int r;
@@ -395,3 +395,8 @@ int crypt_bitlk_decrypt_key(const void *key, size_t key_length,
return crypt_bitlk_decrypt_key_kernel(key, key_length, in, out, length,
iv, iv_length, tag, tag_length);
}
int crypt_backend_memeq(const void *m1, const void *m2, size_t n)
{
return NSS_SecureMemcmp(m1, m2, n);
}

View File

@@ -1,8 +1,8 @@
/*
* OPENSSL crypto backend implementation
*
* Copyright (C) 2010-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2021 Milan Broz
* Copyright (C) 2010-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2022 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -28,21 +28,21 @@
* for all of the code used other than OpenSSL.
*/
/*
* HMAC will be later rewritten to a new API from OpenSSL 3
*/
#define OPENSSL_SUPPRESS_DEPRECATED
#include <string.h>
#include <errno.h>
#include <openssl/crypto.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/rand.h>
#include "crypto_backend_internal.h"
#if OPENSSL_VERSION_MAJOR >= 3
#include <openssl/provider.h>
#include <openssl/kdf.h>
#include <openssl/core_names.h>
static OSSL_PROVIDER *ossl_legacy = NULL;
static OSSL_PROVIDER *ossl_default = NULL;
static OSSL_LIB_CTX *ossl_ctx = NULL;
static char backend_version[256] = "OpenSSL";
#endif
#define CONST_CAST(x) (x)(uintptr_t)
@@ -56,8 +56,14 @@ struct crypt_hash {
};
struct crypt_hmac {
#if OPENSSL_VERSION_MAJOR >= 3
EVP_MAC *mac;
EVP_MAC_CTX *md;
EVP_MAC_CTX *md_org;
#else
HMAC_CTX *md;
const EVP_MD *hash_id;
#endif
int hash_len;
};
@@ -68,6 +74,7 @@ struct crypt_cipher {
struct {
EVP_CIPHER_CTX *hd_enc;
EVP_CIPHER_CTX *hd_dec;
const EVP_CIPHER *cipher_type;
size_t iv_length;
} lib;
} u;
@@ -84,9 +91,10 @@ struct hash_alg {
#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
static void openssl_backend_init(void)
static int openssl_backend_init(bool fips __attribute__((unused)))
{
OpenSSL_add_all_algorithms();
return 0;
}
static void openssl_backend_exit(void)
@@ -130,46 +138,79 @@ static void HMAC_CTX_free(HMAC_CTX *md)
free(md);
}
#else
static void openssl_backend_init(void)
static void openssl_backend_exit(void)
{
#if OPENSSL_VERSION_MAJOR >= 3
if (ossl_legacy)
OSSL_PROVIDER_unload(ossl_legacy);
if (ossl_default)
OSSL_PROVIDER_unload(ossl_default);
if (ossl_ctx)
OSSL_LIB_CTX_free(ossl_ctx);
ossl_legacy = NULL;
ossl_default = NULL;
ossl_ctx = NULL;
#endif
}
static int openssl_backend_init(bool fips)
{
/*
* OpenSSL >= 3.0.0 provides some algorithms in legacy provider
*/
#if OPENSSL_VERSION_MAJOR >= 3
OPENSSL_init_crypto(OPENSSL_INIT_NO_ATEXIT, NULL);
ossl_legacy = OSSL_PROVIDER_try_load(NULL, "legacy", 0);
ossl_default = OSSL_PROVIDER_try_load(NULL, "default", 0);
#endif
}
int r;
static void openssl_backend_exit(void)
{
#if OPENSSL_VERSION_MAJOR >= 3
/*
* If Destructor was already called, we must not call it again
* In FIPS mode we keep default OpenSSL context & global config
*/
if (OPENSSL_init_crypto(0, NULL) != 0) {
OSSL_PROVIDER_unload(ossl_legacy);
OSSL_PROVIDER_unload(ossl_default);
OPENSSL_cleanup();
if (!fips) {
ossl_ctx = OSSL_LIB_CTX_new();
if (!ossl_ctx)
return -EINVAL;
ossl_default = OSSL_PROVIDER_try_load(ossl_ctx, "default", 0);
if (!ossl_default) {
OSSL_LIB_CTX_free(ossl_ctx);
return -EINVAL;
}
/* Optional */
ossl_legacy = OSSL_PROVIDER_try_load(ossl_ctx, "legacy", 0);
}
r = snprintf(backend_version, sizeof(backend_version), "%s %s%s%s",
OpenSSL_version(OPENSSL_VERSION),
ossl_default ? "[default]" : "",
ossl_legacy ? "[legacy]" : "",
fips ? "[fips]" : "");
if (r < 0 || (size_t)r >= sizeof(backend_version)) {
openssl_backend_exit();
return -EINVAL;
}
ossl_legacy = NULL;
ossl_default = NULL;
#endif
return 0;
}
static const char *openssl_backend_version(void)
{
return OpenSSL_version(OPENSSL_VERSION);
#if OPENSSL_VERSION_MAJOR >= 3
return backend_version;
#else
return OpenSSL_version(OPENSSL_VERSION);
#endif
}
#endif
int crypt_backend_init(void)
int crypt_backend_init(bool fips)
{
if (crypto_backend_initialised)
return 0;
openssl_backend_init();
if (openssl_backend_init(fips))
return -EINVAL;
crypto_backend_initialised = 1;
return 0;
@@ -177,7 +218,14 @@ int crypt_backend_init(void)
void crypt_backend_destroy(void)
{
/*
* If Destructor was already called, we must not call it again
*/
if (!crypto_backend_initialised)
return;
crypto_backend_initialised = 0;
openssl_backend_exit();
}
@@ -215,16 +263,51 @@ static const char *crypt_hash_compat_name(const char *name)
return hash_name;
}
static const EVP_MD *hash_id_get(const char *name)
{
#if OPENSSL_VERSION_MAJOR >= 3
return EVP_MD_fetch(ossl_ctx, crypt_hash_compat_name(name), NULL);
#else
return EVP_get_digestbyname(crypt_hash_compat_name(name));
#endif
}
static void hash_id_free(const EVP_MD *hash_id)
{
#if OPENSSL_VERSION_MAJOR >= 3
EVP_MD_free(CONST_CAST(EVP_MD*)hash_id);
#endif
}
static const EVP_CIPHER *cipher_type_get(const char *name)
{
#if OPENSSL_VERSION_MAJOR >= 3
return EVP_CIPHER_fetch(ossl_ctx, name, NULL);
#else
return EVP_get_cipherbyname(name);
#endif
}
static void cipher_type_free(const EVP_CIPHER *cipher_type)
{
#if OPENSSL_VERSION_MAJOR >= 3
EVP_CIPHER_free(CONST_CAST(EVP_CIPHER*)cipher_type);
#endif
}
/* HASH */
int crypt_hash_size(const char *name)
{
int size;
const EVP_MD *hash_id;
hash_id = EVP_get_digestbyname(crypt_hash_compat_name(name));
hash_id = hash_id_get(name);
if (!hash_id)
return -EINVAL;
return EVP_MD_size(hash_id);
size = EVP_MD_size(hash_id);
hash_id_free(hash_id);
return size;
}
int crypt_hash_init(struct crypt_hash **ctx, const char *name)
@@ -241,7 +324,7 @@ int crypt_hash_init(struct crypt_hash **ctx, const char *name)
return -ENOMEM;
}
h->hash_id = EVP_get_digestbyname(crypt_hash_compat_name(name));
h->hash_id = hash_id_get(name);
if (!h->hash_id) {
EVP_MD_CTX_free(h->md);
free(h);
@@ -249,6 +332,7 @@ int crypt_hash_init(struct crypt_hash **ctx, const char *name)
}
if (EVP_DigestInit_ex(h->md, h->hash_id, NULL) != 1) {
hash_id_free(h->hash_id);
EVP_MD_CTX_free(h->md);
free(h);
return -EINVAL;
@@ -300,6 +384,7 @@ int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
void crypt_hash_destroy(struct crypt_hash *ctx)
{
hash_id_free(ctx->hash_id);
EVP_MD_CTX_free(ctx->md);
memset(ctx, 0, sizeof(*ctx));
free(ctx);
@@ -315,7 +400,39 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
const void *key, size_t key_length)
{
struct crypt_hmac *h;
#if OPENSSL_VERSION_MAJOR >= 3
OSSL_PARAM params[] = {
OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, CONST_CAST(void*)name, 0),
OSSL_PARAM_END
};
h = malloc(sizeof(*h));
if (!h)
return -ENOMEM;
h->mac = EVP_MAC_fetch(ossl_ctx, OSSL_MAC_NAME_HMAC, NULL);
if (!h->mac) {
free(h);
return -EINVAL;
}
h->md = EVP_MAC_CTX_new(h->mac);
if (!h->md) {
EVP_MAC_free(h->mac);
free(h);
return -ENOMEM;
}
if (EVP_MAC_init(h->md, key, key_length, params) != 1) {
EVP_MAC_CTX_free(h->md);
EVP_MAC_free(h->mac);
free(h);
return -EINVAL;
}
h->hash_len = EVP_MAC_CTX_get_mac_size(h->md);
h->md_org = EVP_MAC_CTX_dup(h->md);
#else
h = malloc(sizeof(*h));
if (!h)
return -ENOMEM;
@@ -326,7 +443,7 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
return -ENOMEM;
}
h->hash_id = EVP_get_digestbyname(crypt_hash_compat_name(name));
h->hash_id = hash_id_get(name);
if (!h->hash_id) {
HMAC_CTX_free(h->md);
free(h);
@@ -336,45 +453,75 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
HMAC_Init_ex(h->md, key, key_length, h->hash_id, NULL);
h->hash_len = EVP_MD_size(h->hash_id);
#endif
*ctx = h;
return 0;
}
static void crypt_hmac_restart(struct crypt_hmac *ctx)
static int crypt_hmac_restart(struct crypt_hmac *ctx)
{
#if OPENSSL_VERSION_MAJOR >= 3
EVP_MAC_CTX_free(ctx->md);
ctx->md = EVP_MAC_CTX_dup(ctx->md_org);
if (!ctx->md)
return -EINVAL;
#else
HMAC_Init_ex(ctx->md, NULL, 0, ctx->hash_id, NULL);
#endif
return 0;
}
int crypt_hmac_write(struct crypt_hmac *ctx, const char *buffer, size_t length)
{
#if OPENSSL_VERSION_MAJOR >= 3
return EVP_MAC_update(ctx->md, (const unsigned char *)buffer, length) == 1 ? 0 : -EINVAL;
#else
HMAC_Update(ctx->md, (const unsigned char *)buffer, length);
return 0;
#endif
}
int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
{
unsigned char tmp[EVP_MAX_MD_SIZE];
#if OPENSSL_VERSION_MAJOR >= 3
size_t tmp_len = 0;
if (length > (size_t)ctx->hash_len)
return -EINVAL;
if (EVP_MAC_final(ctx->md, tmp, &tmp_len, sizeof(tmp)) != 1)
return -EINVAL;
#else
unsigned int tmp_len = 0;
if (length > (size_t)ctx->hash_len)
return -EINVAL;
HMAC_Final(ctx->md, tmp, &tmp_len);
#endif
memcpy(buffer, tmp, length);
crypt_backend_memzero(tmp, sizeof(tmp));
if (tmp_len < length)
return -EINVAL;
crypt_hmac_restart(ctx);
if (crypt_hmac_restart(ctx))
return -EINVAL;
return 0;
}
void crypt_hmac_destroy(struct crypt_hmac *ctx)
{
#if OPENSSL_VERSION_MAJOR >= 3
EVP_MAC_CTX_free(ctx->md);
EVP_MAC_CTX_free(ctx->md_org);
EVP_MAC_free(ctx->mac);
#else
hash_id_free(ctx->hash_id);
HMAC_CTX_free(ctx->md);
#endif
memset(ctx, 0, sizeof(*ctx));
free(ctx);
}
@@ -389,48 +536,91 @@ int crypt_backend_rng(char *buffer, size_t length,
return 0;
}
static int openssl_pbkdf2(const char *password, size_t password_length,
const char *salt, size_t salt_length, uint32_t iterations,
const char *hash, char *key, size_t key_length)
{
int r;
#if OPENSSL_VERSION_MAJOR >= 3
EVP_KDF_CTX *ctx;
EVP_KDF *pbkdf2;
OSSL_PARAM params[] = {
OSSL_PARAM_octet_string(OSSL_KDF_PARAM_PASSWORD,
CONST_CAST(void*)password, password_length),
OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SALT,
CONST_CAST(void*)salt, salt_length),
OSSL_PARAM_uint32(OSSL_KDF_PARAM_ITER, &iterations),
OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_DIGEST,
CONST_CAST(void*)hash, 0),
OSSL_PARAM_END
};
pbkdf2 = EVP_KDF_fetch(ossl_ctx, "pbkdf2", NULL);
if (!pbkdf2)
return -EINVAL;
ctx = EVP_KDF_CTX_new(pbkdf2);
if (!ctx) {
EVP_KDF_free(pbkdf2);
return -EINVAL;
}
r = EVP_KDF_derive(ctx, (unsigned char*)key, key_length, params);
EVP_KDF_CTX_free(ctx);
EVP_KDF_free(pbkdf2);
#else
const EVP_MD *hash_id = EVP_get_digestbyname(crypt_hash_compat_name(hash));
if (!hash_id)
return -EINVAL;
r = PKCS5_PBKDF2_HMAC(password, (int)password_length, (const unsigned char *)salt,
(int)salt_length, iterations, hash_id, (int)key_length, (unsigned char*) key);
#endif
return r == 1 ? 0 : -EINVAL;
}
static int openssl_argon2(const char *type, const char *password, size_t password_length,
const char *salt, size_t salt_length, char *key, size_t key_length,
uint32_t iterations, uint32_t memory, uint32_t parallel)
{
return argon2(type, password, password_length, salt, salt_length,
key, key_length, iterations, memory, parallel);
}
/* PBKDF */
int crypt_pbkdf(const char *kdf, const char *hash,
const char *password, size_t password_length,
const char *salt, size_t salt_length,
char *key, size_t key_length,
uint32_t iterations, uint32_t memory, uint32_t parallel)
{
const EVP_MD *hash_id;
if (!kdf)
return -EINVAL;
if (!strcmp(kdf, "pbkdf2")) {
hash_id = EVP_get_digestbyname(crypt_hash_compat_name(hash));
if (!hash_id)
return -EINVAL;
if (!PKCS5_PBKDF2_HMAC(password, (int)password_length,
(const unsigned char *)salt, (int)salt_length,
(int)iterations, hash_id, (int)key_length, (unsigned char *)key))
return -EINVAL;
return 0;
} else if (!strncmp(kdf, "argon2", 6)) {
return argon2(kdf, password, password_length, salt, salt_length,
key, key_length, iterations, memory, parallel);
}
if (!strcmp(kdf, "pbkdf2"))
return openssl_pbkdf2(password, password_length, salt, salt_length,
iterations, hash, key, key_length);
if (!strncmp(kdf, "argon2", 6))
return openssl_argon2(kdf, password, password_length, salt, salt_length,
key, key_length, iterations, memory, parallel);
return -EINVAL;
}
/* Block ciphers */
static void _cipher_destroy(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec)
static void _cipher_destroy(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec, const EVP_CIPHER **cipher_type)
{
EVP_CIPHER_CTX_free(*hd_enc);
*hd_enc = NULL;
EVP_CIPHER_CTX_free(*hd_dec);
*hd_dec = NULL;
cipher_type_free(*cipher_type);
*cipher_type = NULL;
}
static int _cipher_init(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec, const char *name,
static int _cipher_init(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec, const EVP_CIPHER **cipher_type, const char *name,
const char *mode, const void *key, size_t key_length, size_t *iv_length)
{
char cipher_name[256];
@@ -445,32 +635,38 @@ static int _cipher_init(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec, const
if (r < 0 || (size_t)r >= sizeof(cipher_name))
return -EINVAL;
type = EVP_get_cipherbyname(cipher_name);
type = cipher_type_get(cipher_name);
if (!type)
return -ENOENT;
if (EVP_CIPHER_key_length(type) != (int)key_length)
if (EVP_CIPHER_key_length(type) != (int)key_length) {
cipher_type_free(type);
return -EINVAL;
}
*hd_enc = EVP_CIPHER_CTX_new();
*hd_dec = EVP_CIPHER_CTX_new();
*iv_length = EVP_CIPHER_iv_length(type);
if (!*hd_enc || !*hd_dec)
if (!*hd_enc || !*hd_dec) {
cipher_type_free(type);
return -EINVAL;
}
if (EVP_EncryptInit_ex(*hd_enc, type, NULL, key, NULL) != 1 ||
EVP_DecryptInit_ex(*hd_dec, type, NULL, key, NULL) != 1) {
_cipher_destroy(hd_enc, hd_dec);
_cipher_destroy(hd_enc, hd_dec, &type);
return -EINVAL;
}
if (EVP_CIPHER_CTX_set_padding(*hd_enc, 0) != 1 ||
EVP_CIPHER_CTX_set_padding(*hd_dec, 0) != 1) {
_cipher_destroy(hd_enc, hd_dec);
_cipher_destroy(hd_enc, hd_dec, &type);
return -EINVAL;
}
*cipher_type = type;
return 0;
}
@@ -484,7 +680,7 @@ int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
if (!h)
return -ENOMEM;
if (!_cipher_init(&h->u.lib.hd_enc, &h->u.lib.hd_dec, name, mode, key,
if (!_cipher_init(&h->u.lib.hd_enc, &h->u.lib.hd_dec, &h->u.lib.cipher_type, name, mode, key,
key_length, &h->u.lib.iv_length)) {
h->use_kernel = false;
*ctx = h;
@@ -507,7 +703,7 @@ void crypt_cipher_destroy(struct crypt_cipher *ctx)
if (ctx->use_kernel)
crypt_cipher_destroy_kernel(&ctx->u.kernel);
else
_cipher_destroy(&ctx->u.lib.hd_enc, &ctx->u.lib.hd_dec);
_cipher_destroy(&ctx->u.lib.hd_enc, &ctx->u.lib.hd_dec, &ctx->u.lib.cipher_type);
free(ctx);
}
@@ -594,9 +790,6 @@ int crypt_bitlk_decrypt_key(const void *key, size_t key_length __attribute__((un
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)
@@ -614,3 +807,8 @@ out:
return -ENOTSUP;
#endif
}
int crypt_backend_memeq(const void *m1, const void *m2, size_t n)
{
return CRYPTO_memcmp(m1, m2, n);
}

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-2021 Milan Broz
* Copyright (C) 2014-2022 Milan Broz
*
* 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,8 @@ static int crypt_sector_iv_init(struct crypt_sector_iv *ctx,
static int crypt_sector_iv_generate(struct crypt_sector_iv *ctx, uint64_t sector)
{
uint64_t val;
uint64_t val, *u64_iv;
uint32_t *u32_iv;
switch (ctx->type) {
case IV_NONE:
@@ -161,19 +162,24 @@ static int crypt_sector_iv_generate(struct crypt_sector_iv *ctx, uint64_t sector
break;
case IV_PLAIN:
memset(ctx->iv, 0, ctx->iv_size);
*(uint32_t *)ctx->iv = cpu_to_le32(sector & 0xffffffff);
u32_iv = (void *)ctx->iv;
*u32_iv = cpu_to_le32(sector & 0xffffffff);
break;
case IV_PLAIN64:
memset(ctx->iv, 0, ctx->iv_size);
*(uint64_t *)ctx->iv = cpu_to_le64(sector);
u64_iv = (void *)ctx->iv;
*u64_iv = cpu_to_le64(sector);
break;
case IV_PLAIN64BE:
memset(ctx->iv, 0, ctx->iv_size);
*(uint64_t *)&ctx->iv[ctx->iv_size - sizeof(uint64_t)] = cpu_to_be64(sector);
/* iv_size is at least of size u64; usually it is 16 bytes */
u64_iv = (void *)&ctx->iv[ctx->iv_size - sizeof(uint64_t)];
*u64_iv = cpu_to_be64(sector);
break;
case IV_ESSIV:
memset(ctx->iv, 0, ctx->iv_size);
*(uint64_t *)ctx->iv = cpu_to_le64(sector);
u64_iv = (void *)ctx->iv;
*u64_iv = cpu_to_le64(sector);
return crypt_cipher_encrypt(ctx->cipher,
ctx->iv, ctx->iv, ctx->iv_size, NULL, 0);
break;
@@ -184,7 +190,8 @@ static int crypt_sector_iv_generate(struct crypt_sector_iv *ctx, uint64_t sector
break;
case IV_EBOIV:
memset(ctx->iv, 0, ctx->iv_size);
*(uint64_t *)ctx->iv = cpu_to_le64(sector << ctx->shift);
u64_iv = (void *)ctx->iv;
*u64_iv = cpu_to_le64(sector << ctx->shift);
return crypt_cipher_encrypt(ctx->cipher,
ctx->iv, ctx->iv, ctx->iv_size, NULL, 0);
break;

View File

@@ -4,8 +4,8 @@
* Copyright (C) 2004 Free Software Foundation
*
* cryptsetup related changes
* Copyright (C) 2012-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2021 Milan Broz
* Copyright (C) 2012-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2022 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

@@ -1,7 +1,7 @@
/*
* PBKDF performance check
* Copyright (C) 2012-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2021 Milan Broz
* Copyright (C) 2012-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2022 Milan Broz
* Copyright (C) 2016-2020 Ondrej Mosnacek
*
* This file is free software; you can redistribute it and/or

289
lib/crypto_backend/utf8.c Normal file
View File

@@ -0,0 +1,289 @@
/*
* UTF8/16 helpers, copied and adapted from systemd project.
*
* Copyright (C) 2010 Lennart Poettering
*
* cryptsetup related changes
* Copyright (C) 2021-2022 Vojtech Trefny
* Parts of the original systemd implementation are based on the GLIB utf8
* validation functions.
* gutf8.c - Operations on UTF-8 strings.
*
* Copyright (C) 1999 Tom Tromey
* Copyright (C) 2000 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <assert.h>
#include <errno.h>
#include <endian.h>
#include "crypto_backend.h"
static inline bool utf16_is_surrogate(char16_t c)
{
return c >= 0xd800U && c <= 0xdfffU;
}
static inline bool utf16_is_trailing_surrogate(char16_t c)
{
return c >= 0xdc00U && c <= 0xdfffU;
}
static inline char32_t utf16_surrogate_pair_to_unichar(char16_t lead, char16_t trail)
{
return ((((char32_t) lead - 0xd800U) << 10) + ((char32_t) trail - 0xdc00U) + 0x10000U);
}
/**
* utf8_encode_unichar() - Encode single UCS-4 character as UTF-8
* @out_utf8: output buffer of at least 4 bytes or NULL
* @g: UCS-4 character to encode
*
* This encodes a single UCS-4 character as UTF-8 and writes it into @out_utf8.
* The length of the character is returned. It is not zero-terminated! If the
* output buffer is NULL, only the length is returned.
*
* Returns: The length in bytes that the UTF-8 representation does or would
* occupy.
*/
static size_t utf8_encode_unichar(char *out_utf8, char32_t g)
{
if (g < (1 << 7)) {
if (out_utf8)
out_utf8[0] = g & 0x7f;
return 1;
} else if (g < (1 << 11)) {
if (out_utf8) {
out_utf8[0] = 0xc0 | ((g >> 6) & 0x1f);
out_utf8[1] = 0x80 | (g & 0x3f);
}
return 2;
} else if (g < (1 << 16)) {
if (out_utf8) {
out_utf8[0] = 0xe0 | ((g >> 12) & 0x0f);
out_utf8[1] = 0x80 | ((g >> 6) & 0x3f);
out_utf8[2] = 0x80 | (g & 0x3f);
}
return 3;
} else if (g < (1 << 21)) {
if (out_utf8) {
out_utf8[0] = 0xf0 | ((g >> 18) & 0x07);
out_utf8[1] = 0x80 | ((g >> 12) & 0x3f);
out_utf8[2] = 0x80 | ((g >> 6) & 0x3f);
out_utf8[3] = 0x80 | (g & 0x3f);
}
return 4;
}
return 0;
}
/**
* crypt_utf16_to_utf8()
* @out: output buffer, should be 2 * @length + 1 long
* @s: string to convert
* @length: length of @s in bytes
*
* Converts a UTF16LE encoded string to a UTF8 encoded string.
*
* Returns: 0 on success, negative errno otherwise
*/
int crypt_utf16_to_utf8(char **out, const char16_t *s, size_t length /* bytes! */)
{
const uint8_t *f;
char *t;
assert(s);
assert(out);
assert(*out);
/* Input length is in bytes, i.e. the shortest possible character takes 2 bytes. Each unicode character may
* take up to 4 bytes in UTF-8. Let's also account for a trailing NUL byte. */
if (length * 2 < length)
return -EOVERFLOW; /* overflow */
f = (const uint8_t*) s;
t = *out;
while (f + 1 < (const uint8_t*) s + length) {
char16_t w1, w2;
/* see RFC 2781 section 2.2 */
w1 = f[1] << 8 | f[0];
f += 2;
if (!utf16_is_surrogate(w1)) {
t += utf8_encode_unichar(t, w1);
continue;
}
if (utf16_is_trailing_surrogate(w1))
continue; /* spurious trailing surrogate, ignore */
if (f + 1 >= (const uint8_t*) s + length)
break;
w2 = f[1] << 8 | f[0];
f += 2;
if (!utf16_is_trailing_surrogate(w2)) {
f -= 2;
continue; /* surrogate missing its trailing surrogate, ignore */
}
t += utf8_encode_unichar(t, utf16_surrogate_pair_to_unichar(w1, w2));
}
*t = 0;
return 0;
}
/* count of characters used to encode one unicode char */
static size_t utf8_encoded_expected_len(uint8_t c)
{
if (c < 0x80)
return 1;
if ((c & 0xe0) == 0xc0)
return 2;
if ((c & 0xf0) == 0xe0)
return 3;
if ((c & 0xf8) == 0xf0)
return 4;
if ((c & 0xfc) == 0xf8)
return 5;
if ((c & 0xfe) == 0xfc)
return 6;
return 0;
}
/* decode one unicode char */
static int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar)
{
char32_t unichar;
size_t len, i;
assert(str);
len = utf8_encoded_expected_len(str[0]);
switch (len) {
case 1:
*ret_unichar = (char32_t)str[0];
return 0;
case 2:
unichar = str[0] & 0x1f;
break;
case 3:
unichar = (char32_t)str[0] & 0x0f;
break;
case 4:
unichar = (char32_t)str[0] & 0x07;
break;
case 5:
unichar = (char32_t)str[0] & 0x03;
break;
case 6:
unichar = (char32_t)str[0] & 0x01;
break;
default:
return -EINVAL;
}
for (i = 1; i < len; i++) {
if (((char32_t)str[i] & 0xc0) != 0x80)
return -EINVAL;
unichar <<= 6;
unichar |= (char32_t)str[i] & 0x3f;
}
*ret_unichar = unichar;
return 0;
}
static size_t utf16_encode_unichar(char16_t *out, char32_t c)
{
/* Note that this encodes as little-endian. */
switch (c) {
case 0 ... 0xd7ffU:
case 0xe000U ... 0xffffU:
out[0] = htole16(c);
return 1;
case 0x10000U ... 0x10ffffU:
c -= 0x10000U;
out[0] = htole16((c >> 10) + 0xd800U);
out[1] = htole16((c & 0x3ffU) + 0xdc00U);
return 2;
default: /* A surrogate (invalid) */
return 0;
}
}
/**
* crypt_utf8_to_utf16()
* @out: output buffer, should be @length + 1 long
* @s: string to convert
* @length: length of @s in bytes
*
* Converts a UTF8 encoded string to a UTF16LE encoded string.
*
* Returns: 0 on success, negative errno otherwise
*/
int crypt_utf8_to_utf16(char16_t **out, const char *s, size_t length)
{
char16_t *p;
size_t i;
int r;
assert(s);
p = *out;
for (i = 0; i < length;) {
char32_t unichar;
size_t e;
e = utf8_encoded_expected_len(s[i]);
if (e <= 1) /* Invalid and single byte characters are copied as they are */
goto copy;
if (i + e > length) /* sequence longer than input buffer, then copy as-is */
goto copy;
r = utf8_encoded_to_unichar(s + i, &unichar);
if (r < 0) /* sequence invalid, then copy as-is */
goto copy;
p += utf16_encode_unichar(p, unichar);
i += e;
continue;
copy:
*(p++) = htole16(s[i++]);
}
*p = 0;
return 0;
}

View File

@@ -1,7 +1,7 @@
/*
* Integrity volume handling
*
* Copyright (C) 2016-2021 Milan Broz
* Copyright (C) 2016-2022 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,6 +27,17 @@
#include "integrity.h"
#include "internal.h"
/* For LUKS2, integrity metadata are on DATA device even for detached header! */
static struct device *INTEGRITY_metadata_device(struct crypt_device *cd)
{
const char *type = crypt_get_type(cd);
if (type && !strcmp(type, CRYPT_LUKS2))
return crypt_data_device(cd);
return crypt_metadata_device(cd);
}
static int INTEGRITY_read_superblock(struct crypt_device *cd,
struct device *device,
uint64_t offset, struct superblock *sb)
@@ -38,11 +49,13 @@ static int INTEGRITY_read_superblock(struct crypt_device *cd,
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_5) {
log_std(cd, "No integrity superblock detected on %s.\n",
device_path(device));
device_alignment(device), sb, sizeof(*sb), offset) != sizeof(*sb) ||
memcmp(sb->magic, SB_MAGIC, sizeof(sb->magic))) {
log_dbg(cd, "No kernel dm-integrity metadata detected on %s.", device_path(device));
r = -EINVAL;
} else if (sb->version < SB_VERSION_1 || sb->version > SB_VERSION_5) {
log_err(cd, _("Incompatible kernel dm-integrity metadata (version %u) detected on %s."),
sb->version, device_path(device));
r = -EINVAL;
} else {
sb->integrity_tag_size = le16toh(sb->integrity_tag_size);
@@ -63,7 +76,7 @@ int INTEGRITY_read_sb(struct crypt_device *cd,
struct superblock sb;
int r;
r = INTEGRITY_read_superblock(cd, crypt_metadata_device(cd), 0, &sb);
r = INTEGRITY_read_superblock(cd, INTEGRITY_metadata_device(cd), 0, &sb);
if (r)
return r;
@@ -120,7 +133,7 @@ int INTEGRITY_data_sectors(struct crypt_device *cd,
return 0;
}
int INTEGRITY_key_size(struct crypt_device *cd __attribute__((unused)), const char *integrity)
int INTEGRITY_key_size(const char *integrity)
{
if (!integrity)
return 0;
@@ -154,6 +167,9 @@ int INTEGRITY_hash_tag_size(const char *integrity)
if (!strcmp(integrity, "crc32") || !strcmp(integrity, "crc32c"))
return 4;
if (!strcmp(integrity, "xxhash64"))
return 8;
r = sscanf(integrity, "hmac(%" MAX_CIPHER_LEN_STR "[^)]s", hash);
if (r == 1)
r = crypt_hash_size(hash);
@@ -163,8 +179,7 @@ int INTEGRITY_hash_tag_size(const char *integrity)
return r < 0 ? 0 : r;
}
int INTEGRITY_tag_size(struct crypt_device *cd __attribute__((unused)),
const char *integrity,
int INTEGRITY_tag_size(const char *integrity,
const char *cipher,
const char *cipher_mode)
{
@@ -228,13 +243,13 @@ int INTEGRITY_create_dmd_device(struct crypt_device *cd,
if (sb_flags & SB_FLAG_RECALCULATING)
dmd->flags |= CRYPT_ACTIVATE_RECALCULATE;
r = INTEGRITY_data_sectors(cd, crypt_metadata_device(cd),
r = INTEGRITY_data_sectors(cd, INTEGRITY_metadata_device(cd),
crypt_get_data_offset(cd) * SECTOR_SIZE, &dmd->size);
if (r < 0)
return r;
return dm_integrity_target_set(cd, &dmd->segment, 0, dmd->size,
crypt_metadata_device(cd), crypt_data_device(cd),
INTEGRITY_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);
@@ -256,18 +271,8 @@ int INTEGRITY_activate_dmd_device(struct crypt_device *cd,
log_dbg(cd, "Trying to activate INTEGRITY device on top of %s, using name %s, tag size %d, provided sectors %" PRIu64".",
device_path(tgt->data_device), name, tgt->u.integrity.tag_size, dmd->size);
r = device_block_adjust(cd, tgt->data_device, DEV_EXCL,
tgt->u.integrity.offset, NULL, &dmd->flags);
if (r)
return r;
r = create_or_reload_device(cd, name, type, dmd);
if (tgt->u.integrity.meta_device) {
r = device_block_adjust(cd, tgt->u.integrity.meta_device, DEV_EXCL, 0, NULL, NULL);
if (r)
return r;
}
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 does not support dm-integrity mapping."));
return -ENOTSUP;
@@ -299,14 +304,33 @@ int INTEGRITY_activate(struct crypt_device *cd,
struct volume_key *journal_mac_key,
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, sb_flags);
struct crypt_dm_active_device dmdq = {}, dmd = {};
int r;
if (r < 0)
return r;
if (flags & CRYPT_ACTIVATE_REFRESH) {
r = dm_query_device(cd, name, DM_ACTIVE_CRYPT_KEYSIZE |
DM_ACTIVE_CRYPT_KEY |
DM_ACTIVE_INTEGRITY_PARAMS |
DM_ACTIVE_JOURNAL_CRYPT_KEY |
DM_ACTIVE_JOURNAL_MAC_KEY, &dmdq);
if (r < 0)
return r;
r = INTEGRITY_activate_dmd_device(cd, name, CRYPT_INTEGRITY, &dmd, sb_flags);
r = INTEGRITY_create_dmd_device(cd, params, vk ?: dmdq.segment.u.integrity.vk,
journal_crypt_key ?: dmdq.segment.u.integrity.journal_crypt_key,
journal_mac_key ?: dmdq.segment.u.integrity.journal_integrity_key,
&dmd, flags, sb_flags);
if (!r)
dmd.size = dmdq.size;
} else
r = INTEGRITY_create_dmd_device(cd, params, vk, journal_crypt_key,
journal_mac_key, &dmd, flags, sb_flags);
if (!r)
r = INTEGRITY_activate_dmd_device(cd, name, CRYPT_INTEGRITY, &dmd, sb_flags);
dm_targets_free(cd, &dmdq);
dm_targets_free(cd, &dmd);
return r;
}
@@ -338,7 +362,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(cd, tgt, 0, dmdi.size, crypt_metadata_device(cd),
r = dm_integrity_target_set(cd, tgt, 0, dmdi.size, INTEGRITY_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);

View File

@@ -1,7 +1,7 @@
/*
* Integrity header definition
*
* Copyright (C) 2016-2021 Milan Broz
* Copyright (C) 2016-2022 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -66,9 +66,8 @@ int INTEGRITY_dump(struct crypt_device *cd, struct device *device, uint64_t offs
int INTEGRITY_data_sectors(struct crypt_device *cd,
struct device *device, uint64_t offset,
uint64_t *data_sectors);
int INTEGRITY_key_size(struct crypt_device *cd, const char *integrity);
int INTEGRITY_tag_size(struct crypt_device *cd,
const char *integrity,
int INTEGRITY_key_size(const char *integrity);
int INTEGRITY_tag_size(const char *integrity,
const char *cipher,
const char *cipher_mode);
int INTEGRITY_hash_tag_size(const char *integrity);

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-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2021 Milan Broz
* Copyright (C) 2009-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2022 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

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-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2021 Milan Broz
* Copyright (C) 2009-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2022 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -129,9 +129,10 @@ void crypt_free(struct crypt_device *cd);
* other values mean accepted.
*
* @param cd crypt device handle
* @param confirm user defined confirm callback reference
* @param confirm user defined confirm callback reference; use
* @p msg for message for user to confirm and
* @p usrptr for identification in callback
* @param usrptr provided identification in callback
* @param msg Message for user to confirm
*
* @note Current version of cryptsetup API requires confirmation for UUID change and
* LUKS header restore only.
@@ -196,10 +197,11 @@ int crypt_set_data_offset(struct crypt_device *cd, uint64_t data_offset);
* Set log function.
*
* @param cd crypt device handle (can be @e NULL to set default log function)
* @param log user defined log function reference
* @param log user defined log function reference; use
* @p level for log level,
* @p msg for message, and
* @p usrptr for identification in callback
* @param usrptr provided identification in callback
* @param level log level below (debug messages can uses other levels)
* @param msg log message
*/
void crypt_set_log_callback(struct crypt_device *cd,
void (*log)(int level, const char *msg, void *usrptr),
@@ -269,9 +271,9 @@ struct crypt_pbkdf_type {
};
/** Iteration time set by crypt_set_iteration_time(), for compatibility only. */
#define CRYPT_PBKDF_ITER_TIME_SET (1 << 0)
#define CRYPT_PBKDF_ITER_TIME_SET (UINT32_C(1) << 0)
/** Never run benchmarks, use pre-set value or defaults. */
#define CRYPT_PBKDF_NO_BENCHMARK (1 << 1)
#define CRYPT_PBKDF_NO_BENCHMARK (UINT32_C(1) << 1)
/** PBKDF2 according to RFC2898, LUKS1 legacy */
#define CRYPT_KDF_PBKDF2 "pbkdf2"
@@ -511,13 +513,13 @@ struct crypt_params_verity {
};
/** No on-disk header (only hashes) */
#define CRYPT_VERITY_NO_HEADER (1 << 0)
#define CRYPT_VERITY_NO_HEADER (UINT32_C(1) << 0)
/** Verity hash in userspace before activation */
#define CRYPT_VERITY_CHECK_HASH (1 << 1)
#define CRYPT_VERITY_CHECK_HASH (UINT32_C(1) << 1)
/** Create hash - format hash device */
#define CRYPT_VERITY_CREATE_HASH (1 << 2)
#define CRYPT_VERITY_CREATE_HASH (UINT32_C(1) << 2)
/** Root hash signature required for activation */
#define CRYPT_VERITY_ROOT_HASH_SIGNATURE (1 << 3)
#define CRYPT_VERITY_ROOT_HASH_SIGNATURE (UINT32_C(1) << 3)
/**
*
@@ -540,18 +542,18 @@ struct crypt_params_tcrypt {
};
/** Include legacy modes when scanning for header */
#define CRYPT_TCRYPT_LEGACY_MODES (1 << 0)
#define CRYPT_TCRYPT_LEGACY_MODES (UINT32_C(1) << 0)
/** Try to load hidden header (describing hidden device) */
#define CRYPT_TCRYPT_HIDDEN_HEADER (1 << 1)
#define CRYPT_TCRYPT_HIDDEN_HEADER (UINT32_C(1) << 1)
/** Try to load backup header */
#define CRYPT_TCRYPT_BACKUP_HEADER (1 << 2)
#define CRYPT_TCRYPT_BACKUP_HEADER (UINT32_C(1) << 2)
/** Device contains encrypted system (with boot loader) */
#define CRYPT_TCRYPT_SYSTEM_HEADER (1 << 3)
#define CRYPT_TCRYPT_SYSTEM_HEADER (UINT32_C(1) << 3)
/** Include VeraCrypt modes when scanning for header,
* all other TCRYPT flags applies as well.
* VeraCrypt device is reported as TCRYPT type.
*/
#define CRYPT_TCRYPT_VERA_MODES (1 << 4)
#define CRYPT_TCRYPT_VERA_MODES (UINT32_C(1) << 4)
/**
*
@@ -660,11 +662,11 @@ void crypt_set_compatibility(struct crypt_device *cd, uint32_t 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)
#define CRYPT_COMPAT_LEGACY_INTEGRITY_PADDING (UINT32_C(1) << 0)
/** dm-integrity device does not protect superblock with HMAC (old kernels) */
#define CRYPT_COMPAT_LEGACY_INTEGRITY_HMAC (1 << 1)
#define CRYPT_COMPAT_LEGACY_INTEGRITY_HMAC (UINT32_C(1) << 1)
/** dm-integrity allow recalculating of volumes with HMAC keys (old kernels) */
#define CRYPT_COMPAT_LEGACY_INTEGRITY_RECALC (1 << 2)
#define CRYPT_COMPAT_LEGACY_INTEGRITY_RECALC (UINT32_C(1) << 2)
/**
* Convert to new type for already existing device.
@@ -716,6 +718,24 @@ int crypt_set_label(struct crypt_device *cd,
const char *label,
const char *subsystem);
/**
* Get the label of an existing device.
*
* @param cd crypt device handle
*
* @return label, or @e NULL otherwise
*/
const char *crypt_get_label(struct crypt_device *cd);
/**
* Get the subsystem of an existing device.
*
* @param cd crypt device handle
*
* @return subsystem, or @e NULL otherwise
*/
const char *crypt_get_subsystem(struct crypt_device *cd);
/**
* Enable or disable loading of volume keys via kernel keyring. When set to
* 'enabled' library loads key in kernel keyring first and pass the key
@@ -747,7 +767,8 @@ int crypt_volume_key_keyring(struct crypt_device *cd, int enable);
* @post In case LUKS header is read successfully but payload device is too small
* error is returned and device type in context is set to @e NULL
*
* @note Note that in current version load works only for LUKS and VERITY device type.
* @note Note that load works only for device types with on-disk metadata.
* @note Function does not print visible error message if metadata is not present.
*
*/
int crypt_load(struct crypt_device *cd,
@@ -879,6 +900,43 @@ int crypt_resume_by_volume_key(struct crypt_device *cd,
const char *name,
const char *volume_key,
size_t volume_key_size);
/**
* Resume crypt device using LUKS2 token.
*
* @param cd LUKS2 crypt device handle
* @param name name of device to resume
* @param type restrict type of token, if @e NULL all types are allowed
* @param pin passphrase (or PIN) to unlock token (may be binary data)
* @param pin_size size of @e pin
* @param usrptr provided identification in callback
*
* @return unlocked key slot number or negative errno otherwise.
*
* @note EPERM errno means token provided passphrase successfully, but
* passphrase did not unlock any keyslot associated with the token.
*
* @note ENOENT errno means no token (or subsequently assigned keyslot) was
* eligible to resume LUKS2 device.
*
* @note ENOANO errno means that token is PIN protected and was either missing
* (NULL) or wrong.
*
* @note Negative EAGAIN errno means token handler requires additional hardware
* not present in the system to unlock keyslot.
*
* @note with @param token set to CRYPT_ANY_TOKEN libcryptsetup runs best effort loop
* to resume device using any available token. It may happen that various token handlers
* return different error codes. At the end loop returns error codes in the following
* order (from the most significant to the least) any negative errno except those
* listed below, non negative token id (success), -ENOANO, -EAGAIN, -EPERM, -ENOENT.
*/
int crypt_resume_by_token_pin(struct crypt_device *cd,
const char *name,
const char *type,
int token,
const char *pin,
size_t pin_size,
void *usrptr);
/** @} */
/**
@@ -1003,13 +1061,13 @@ int crypt_keyslot_add_by_volume_key(struct crypt_device *cd,
size_t passphrase_size);
/** create keyslot with volume key not associated with current dm-crypt segment */
#define CRYPT_VOLUME_KEY_NO_SEGMENT (1 << 0)
#define CRYPT_VOLUME_KEY_NO_SEGMENT (UINT32_C(1) << 0)
/** create keyslot with new volume key and assign it to current dm-crypt segment */
#define CRYPT_VOLUME_KEY_SET (1 << 1)
#define CRYPT_VOLUME_KEY_SET (UINT32_C(1) << 1)
/** Assign key to first matching digest before creating new digest */
#define CRYPT_VOLUME_KEY_DIGEST_REUSE (1 << 2)
#define CRYPT_VOLUME_KEY_DIGEST_REUSE (UINT32_C(1) << 2)
/**
* Add key slot using provided key.
@@ -1071,59 +1129,59 @@ int crypt_keyslot_destroy(struct crypt_device *cd, int keyslot);
*/
/** device is read only */
#define CRYPT_ACTIVATE_READONLY (1 << 0)
#define CRYPT_ACTIVATE_READONLY (UINT32_C(1) << 0)
/** only reported for device without uuid */
#define CRYPT_ACTIVATE_NO_UUID (1 << 1)
#define CRYPT_ACTIVATE_NO_UUID (UINT32_C(1) << 1)
/** activate even if cannot grant exclusive access (DANGEROUS) */
#define CRYPT_ACTIVATE_SHARED (1 << 2)
#define CRYPT_ACTIVATE_SHARED (UINT32_C(1) << 2)
/** enable discards aka TRIM */
#define CRYPT_ACTIVATE_ALLOW_DISCARDS (1 << 3)
#define CRYPT_ACTIVATE_ALLOW_DISCARDS (UINT32_C(1) << 3)
/** skip global udev rules in activation ("private device"), input only */
#define CRYPT_ACTIVATE_PRIVATE (1 << 4)
#define CRYPT_ACTIVATE_PRIVATE (UINT32_C(1) << 4)
/** corruption detected (verity), output only */
#define CRYPT_ACTIVATE_CORRUPTED (1 << 5)
#define CRYPT_ACTIVATE_CORRUPTED (UINT32_C(1) << 5)
/** use same_cpu_crypt option for dm-crypt */
#define CRYPT_ACTIVATE_SAME_CPU_CRYPT (1 << 6)
#define CRYPT_ACTIVATE_SAME_CPU_CRYPT (UINT32_C(1) << 6)
/** use submit_from_crypt_cpus for dm-crypt */
#define CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS (1 << 7)
#define CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS (UINT32_C(1) << 7)
/** dm-verity: ignore_corruption flag - ignore corruption, log it only */
#define CRYPT_ACTIVATE_IGNORE_CORRUPTION (1 << 8)
#define CRYPT_ACTIVATE_IGNORE_CORRUPTION (UINT32_C(1) << 8)
/** dm-verity: restart_on_corruption flag - restart kernel on corruption */
#define CRYPT_ACTIVATE_RESTART_ON_CORRUPTION (1 << 9)
#define CRYPT_ACTIVATE_RESTART_ON_CORRUPTION (UINT32_C(1) << 9)
/** dm-verity: ignore_zero_blocks - do not verify zero blocks */
#define CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS (1 << 10)
#define CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS (UINT32_C(1) << 10)
/** key loaded in kernel keyring instead directly in dm-crypt */
#define CRYPT_ACTIVATE_KEYRING_KEY (1 << 11)
#define CRYPT_ACTIVATE_KEYRING_KEY (UINT32_C(1) << 11)
/** dm-integrity: direct writes, do not use journal */
#define CRYPT_ACTIVATE_NO_JOURNAL (1 << 12)
#define CRYPT_ACTIVATE_NO_JOURNAL (UINT32_C(1) << 12)
/** dm-integrity: recovery mode - no journal, no integrity checks */
#define CRYPT_ACTIVATE_RECOVERY (1 << 13)
#define CRYPT_ACTIVATE_RECOVERY (UINT32_C(1) << 13)
/** ignore persistently stored flags */
#define CRYPT_ACTIVATE_IGNORE_PERSISTENT (1 << 14)
#define CRYPT_ACTIVATE_IGNORE_PERSISTENT (UINT32_C(1) << 14)
/** dm-verity: check_at_most_once - check data blocks only the first time */
#define CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE (1 << 15)
#define CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE (UINT32_C(1) << 15)
/** allow activation check including unbound keyslots (keyslots without segments) */
#define CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY (1 << 16)
#define CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY (UINT32_C(1) << 16)
/** dm-integrity: activate automatic recalculation */
#define CRYPT_ACTIVATE_RECALCULATE (1 << 17)
#define CRYPT_ACTIVATE_RECALCULATE (UINT32_C(1) << 17)
/** reactivate existing and update flags, input only */
#define CRYPT_ACTIVATE_REFRESH (1 << 18)
#define CRYPT_ACTIVATE_REFRESH (UINT32_C(1) << 18)
/** Use global lock to serialize memory hard KDF on activation (OOM workaround) */
#define CRYPT_ACTIVATE_SERIALIZE_MEMORY_HARD_PBKDF (1 << 19)
#define CRYPT_ACTIVATE_SERIALIZE_MEMORY_HARD_PBKDF (UINT32_C(1) << 19)
/** dm-integrity: direct writes, use bitmap to track dirty sectors */
#define CRYPT_ACTIVATE_NO_JOURNAL_BITMAP (1 << 20)
#define CRYPT_ACTIVATE_NO_JOURNAL_BITMAP (UINT32_C(1) << 20)
/** device is suspended (key should be wiped from memory), output only */
#define CRYPT_ACTIVATE_SUSPENDED (1 << 21)
#define CRYPT_ACTIVATE_SUSPENDED (UINT32_C(1) << 21)
/** use IV sector counted in sector_size instead of default 512 bytes sectors */
#define CRYPT_ACTIVATE_IV_LARGE_SECTORS (1 << 22)
#define CRYPT_ACTIVATE_IV_LARGE_SECTORS (UINT32_C(1) << 22)
/** dm-verity: panic_on_corruption flag - panic kernel on corruption */
#define CRYPT_ACTIVATE_PANIC_ON_CORRUPTION (1 << 23)
#define CRYPT_ACTIVATE_PANIC_ON_CORRUPTION (UINT32_C(1) << 23)
/** dm-crypt: bypass internal workqueue and process read requests synchronously. */
#define CRYPT_ACTIVATE_NO_READ_WORKQUEUE (1 << 24)
#define CRYPT_ACTIVATE_NO_READ_WORKQUEUE (UINT32_C(1) << 24)
/** dm-crypt: bypass internal workqueue and process write requests synchronously. */
#define CRYPT_ACTIVATE_NO_WRITE_WORKQUEUE (1 << 25)
#define CRYPT_ACTIVATE_NO_WRITE_WORKQUEUE (UINT32_C(1) << 25)
/** dm-integrity: reset automatic recalculation */
#define CRYPT_ACTIVATE_RECALCULATE_RESET (1 << 26)
#define CRYPT_ACTIVATE_RECALCULATE_RESET (UINT32_C(1) << 26)
/**
* Active device runtime attributes
@@ -1172,11 +1230,11 @@ uint64_t crypt_get_active_integrity_failures(struct crypt_device *cd,
* LUKS2 header requirements
*/
/** Unfinished offline reencryption */
#define CRYPT_REQUIREMENT_OFFLINE_REENCRYPT (1 << 0)
#define CRYPT_REQUIREMENT_OFFLINE_REENCRYPT (UINT32_C(1) << 0)
/** Online reencryption in-progress */
#define CRYPT_REQUIREMENT_ONLINE_REENCRYPT (1 << 1)
#define CRYPT_REQUIREMENT_ONLINE_REENCRYPT (UINT32_C(1) << 1)
/** unknown requirement in header (output only) */
#define CRYPT_REQUIREMENT_UNKNOWN (1 << 31)
#define CRYPT_REQUIREMENT_UNKNOWN (UINT32_C(1) << 31)
/**
* Persistent flags type
@@ -1306,8 +1364,8 @@ int crypt_activate_by_keyfile(struct crypt_device *cd,
* @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.
* @note For TCRYPT the volume key should be always NULL and because master
* key from decrypted header is used instead.
* @note For TCRYPT the volume key should be always NULL
* the key from decrypted header is used instead.
*/
int crypt_activate_by_volume_key(struct crypt_device *cd,
const char *name,
@@ -1363,11 +1421,11 @@ int crypt_activate_by_keyring(struct crypt_device *cd,
uint32_t flags);
/** lazy deactivation - remove once last user releases it */
#define CRYPT_DEACTIVATE_DEFERRED (1 << 0)
#define CRYPT_DEACTIVATE_DEFERRED (UINT32_C(1) << 0)
/** force deactivation - if the device is busy, it is replaced by error device */
#define CRYPT_DEACTIVATE_FORCE (1 << 1)
#define CRYPT_DEACTIVATE_FORCE (UINT32_C(1) << 1)
/** if set, remove lazy deactivation */
#define CRYPT_DEACTIVATE_DEFERRED_CANCEL (1 << 2)
#define CRYPT_DEACTIVATE_DEFERRED_CANCEL (UINT32_C(1) << 2)
/**
* Deactivate crypt device. This function tries to remove active device-mapper
@@ -1429,6 +1487,10 @@ int crypt_volume_key_get(struct crypt_device *cd,
* @param volume_key_size size of @e volume_key
*
* @return @e 0 on success or negative errno value otherwise.
*
* @note Negative EPERM return value means that passed volume_key
* did not pass digest verification routine (not a valid volume
* key).
*/
int crypt_volume_key_verify(struct crypt_device *cd,
const char *volume_key,
@@ -1921,7 +1983,7 @@ int crypt_keyfile_read(struct crypt_device *cd,
uint32_t flags);
/** Read key only to the first end of line (\\n). */
#define CRYPT_KEYFILE_STOP_EOL (1 << 0)
#define CRYPT_KEYFILE_STOP_EOL (UINT32_C(1) << 0)
/** @} */
/**
@@ -1935,7 +1997,7 @@ int crypt_keyfile_read(struct crypt_device *cd,
typedef enum {
CRYPT_WIPE_ZERO, /**< Fill with zeroes */
CRYPT_WIPE_RANDOM, /**< Use RNG to fill data */
CRYPT_WIPE_ENCRYPTED_ZERO, /**< Add encryption and fill with zeroes as plaintext */
CRYPT_WIPE_ENCRYPTED_ZERO, /**< Obsolete, same as CRYPT_WIPE_RANDOM */
CRYPT_WIPE_SPECIAL, /**< Compatibility only, do not use (Gutmann method) */
} crypt_wipe_pattern;
@@ -1971,7 +2033,7 @@ int crypt_wipe(struct crypt_device *cd,
);
/** Use direct-io */
#define CRYPT_WIPE_NO_DIRECT_IO (1 << 0)
#define CRYPT_WIPE_NO_DIRECT_IO (UINT32_C(1) << 0)
/** @} */
/**
@@ -2156,6 +2218,15 @@ int crypt_token_is_assigned(struct crypt_device *cd,
* @param buffer returned allocated buffer with password
* @param buffer_len length of the buffer
* @param usrptr user data in @link crypt_activate_by_token @endlink
*
* @return 0 on success (token passed LUKS2 keyslot passphrase in buffer) or
* negative errno otherwise.
*
* @note Negative ENOANO errno means that token is PIN protected and caller should
* use @link crypt_activate_by_token_pin @endlink with PIN provided.
*
* @note Negative EAGAIN errno means token handler requires additional hardware
* not present in the system.
*/
typedef int (*crypt_token_open_func) (
struct crypt_device *cd,
@@ -2177,6 +2248,15 @@ typedef int (*crypt_token_open_func) (
* @param buffer returned allocated buffer with password
* @param buffer_len length of the buffer
* @param usrptr user data in @link crypt_activate_by_token @endlink
*
* @return 0 on success (token passed LUKS2 keyslot passphrase in buffer) or
* negative errno otherwise.
*
* @note Negative ENOANO errno means that token is PIN protected and PIN was
* missing or wrong.
*
* @note Negative EAGAIN errno means token handler requires additional hardware
* not present in the system.
*/
typedef int (*crypt_token_open_pin_func) (
struct crypt_device *cd,
@@ -2267,15 +2347,20 @@ const char *crypt_token_external_path(void);
*/
void crypt_token_external_disable(void);
/** ABI version for external token in libcryptsetup-token-<name>.so */
/** ABI version for external token in libcryptsetup-token-[name].so */
#define CRYPT_TOKEN_ABI_VERSION1 "CRYPTSETUP_TOKEN_1.0"
/** ABI exported symbol for external token */
#define CRYPT_TOKEN_ABI_OPEN "cryptsetup_token_open" /* mandatory */
/** open by token - ABI exported symbol for external token (mandatory) */
#define CRYPT_TOKEN_ABI_OPEN "cryptsetup_token_open"
/** open by token with PIN - ABI exported symbol for external token */
#define CRYPT_TOKEN_ABI_OPEN_PIN "cryptsetup_token_open_pin"
/** deallocate callback - ABI exported symbol for external token */
#define CRYPT_TOKEN_ABI_BUFFER_FREE "cryptsetup_token_buffer_free"
/** validate token metadata - ABI exported symbol for external token */
#define CRYPT_TOKEN_ABI_VALIDATE "cryptsetup_token_validate"
/** dump token metadata - ABI exported symbol for external token */
#define CRYPT_TOKEN_ABI_DUMP "cryptsetup_token_dump"
/** token version - ABI exported symbol for external token */
#define CRYPT_TOKEN_ABI_VERSION "cryptsetup_token_version"
/**
@@ -2293,10 +2378,19 @@ void crypt_token_external_disable(void);
* passphrase did not unlock any keyslot associated with the token.
*
* @note ENOENT errno means no token (or subsequently assigned keyslot) was
* eligible to unlock device.
* eligible to unlock device.
*
* @note EAGAIN errno means that token is PIN protected and you should call
* @note ENOANO errno means that token is PIN protected and you should call
* @link crypt_activate_by_token_pin @endlink with PIN
*
* @note Negative EAGAIN errno means token handler requires additional hardware
* not present in the system.
*
* @note with @e token set to CRYPT_ANY_TOKEN libcryptsetup runs best effort loop
* to unlock device using any available token. It may happen that various token handlers
* return different error codes. At the end loop returns error codes in the following
* order (from the most significant to the least) any negative errno except those
* listed below, non negative token id (success), -ENOANO, -EAGAIN, -EPERM, -ENOENT.
*/
int crypt_activate_by_token(struct crypt_device *cd,
const char *name,
@@ -2318,12 +2412,23 @@ int crypt_activate_by_token(struct crypt_device *cd,
*
* @return unlocked key slot number or negative errno otherwise.
*
* @note EPERM errno means pin did not match or token provided passphrase
* successfully, but passphrase did not unlock any keyslot associated
* with the token.
* @note EPERM errno means token provided passphrase successfully, but
* passphrase did not unlock any keyslot associated with the token.
*
* @note ENOENT errno means no token (or subsequently assigned keyslot) was
* eligible to unlock device.
* eligible to unlock device.
*
* @note ENOANO errno means that token is PIN protected and was either missing
* (NULL) or wrong.
*
* @note Negative EAGAIN errno means token handler requires additional hardware
* not present in the system.
*
* @note with @e token set to CRYPT_ANY_TOKEN libcryptsetup runs best effort loop
* to unlock device using any available token. It may happen that various token handlers
* return different error codes. At the end loop returns error codes in the following
* order (from the most significant to the least) any negative errno except those
* listed below, non negative token id (success), -ENOANO, -EAGAIN, -EPERM, -ENOENT.
*/
int crypt_activate_by_token_pin(struct crypt_device *cd,
const char *name,
@@ -2345,13 +2450,16 @@ int crypt_activate_by_token_pin(struct crypt_device *cd,
*/
/** 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)
#define CRYPT_REENCRYPT_INITIALIZE_ONLY (UINT32_C(1) << 0)
/** Move the first segment, used only with datashift resilience mode
* and subvariants. (in/out) */
#define CRYPT_REENCRYPT_MOVE_FIRST_SEGMENT (UINT32_C(1) << 1)
/** Resume already initialized reencryption only. (in) */
#define CRYPT_REENCRYPT_RESUME_ONLY (1 << 2)
#define CRYPT_REENCRYPT_RESUME_ONLY (UINT32_C(1) << 2)
/** Run reencryption recovery only. (in) */
#define CRYPT_REENCRYPT_RECOVERY (1 << 3)
#define CRYPT_REENCRYPT_RECOVERY (UINT32_C(1) << 3)
/** Reencryption requires metadata protection. (in/out) */
#define CRYPT_REENCRYPT_REPAIR_NEEDED (UINT32_C(1) << 4)
/**
* Reencryption direction
@@ -2376,10 +2484,15 @@ typedef enum {
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 *resilience; /**< Resilience mode: "none", "checksum", "journal", "datashift",
"datashift-checksum" or "datashift-journal".
"datashift" mode is immutable, "datashift-" subvariant can be only
changed to other "datashift-" subvariant */
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 data_shift; /**< Used in "datashift" mode (and subvariants), must be non-zero,
immutable after first init. */
uint64_t max_hotzone_size; /**< Maximum hotzone size (may be lowered by library). For "datashift-" subvariants
it is used to set size of moved segment (decryption only). */
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. */
@@ -2443,6 +2556,21 @@ int crypt_reencrypt_init_by_keyring(struct crypt_device *cd,
const char *cipher_mode,
const struct crypt_params_reencrypt *params);
/**
* Legacy data reencryption function.
*
* @param cd crypt device handle
* @param progress is a callback function reporting device \b size,
* current \b offset of reencryption and provided \b usrptr identification
*
* @return @e 0 on success or negative errno value otherwise.
*
* @deprecated Use @link crypt_reencrypt_run @endlink instead.
*/
int crypt_reencrypt(struct crypt_device *cd,
int (*progress)(uint64_t size, uint64_t offset, void *usrptr))
__attribute__((deprecated));
/**
* Run data reencryption.
*
@@ -2453,7 +2581,7 @@ int crypt_reencrypt_init_by_keyring(struct crypt_device *cd,
*
* @return @e 0 on success or negative errno value otherwise.
*/
int crypt_reencrypt(struct crypt_device *cd,
int crypt_reencrypt_run(struct crypt_device *cd,
int (*progress)(uint64_t size, uint64_t offset, void *usrptr),
void *usrptr);

View File

@@ -134,7 +134,7 @@ CRYPTSETUP_2.0 {
CRYPTSETUP_2.4 {
global:
crypt_reencrypt;
crypt_reencrypt_run;
crypt_token_max;
crypt_header_is_detached;
crypt_logf;
@@ -144,3 +144,10 @@ CRYPTSETUP_2.4 {
crypt_token_external_disable;
crypt_token_external_path;
} CRYPTSETUP_2.0;
CRYPTSETUP_2.5 {
global:
crypt_get_label;
crypt_get_subsystem;
crypt_resume_by_token_pin;
} CRYPTSETUP_2.4;

View File

@@ -1,8 +1,8 @@
/*
* Definitions of common constant and generic macros fo libcryptsetup
* Definitions of common constant and generic macros of libcryptsetup
*
* Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2021 Milan Broz
* Copyright (C) 2009-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2022 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -25,12 +25,17 @@
/* to silent gcc -Wcast-qual for const cast */
#define CONST_CAST(x) (x)(uintptr_t)
/* to silent clang -Wcast-align when working with byte arrays */
#define VOIDP_CAST(x) (x)(void*)
#define UNUSED(x) (void)(x)
#ifndef ARRAY_SIZE
# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#endif
#define BITFIELD_SIZE(BF_PTR) (sizeof(*(BF_PTR)) * 8)
#define MOVE_REF(x, y) \
do { \
__typeof__(x) *_px = &(x), *_py = &(y); \

View File

@@ -1,7 +1,7 @@
/*
* Helpers for defining versioned symbols
*
* Copyright (C) 2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2021-2022 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
@@ -31,7 +31,7 @@
* It's supposed to be used only with symbols that are exported in at least
* two versions simultaneously as follows:
*
* - the latest version is marked with _NEW variant and oll other compatible
* - the latest version is marked with _NEW variant and all other compatible
* symbols should be marked with _OLD variant
*
* Examples:
@@ -67,11 +67,9 @@
* under CRYPT_SYMBOL_EXPORT_OLD(int, crypt_func_X, ...) macro
*/
#ifdef __has_attribute
# if __has_attribute(symver)
# define _CRYPT_SYMVER(_local_sym, _public_sym, _ver_str, _maj, _min) \
__attribute__((__symver__(#_public_sym _ver_str #_maj "." #_min)))
# endif
#if HAVE_ATTRIBUTE_SYMVER
# define _CRYPT_SYMVER(_local_sym, _public_sym, _ver_str, _maj, _min) \
__attribute__((__symver__(#_public_sym _ver_str #_maj "." #_min)))
#endif
#if !defined(_CRYPT_SYMVER) && defined(__GNUC__)

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-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2021 Milan Broz
* Copyright (C) 2009-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2022 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -47,6 +47,7 @@ static bool _dm_ioctl_checked = false;
static bool _dm_crypt_checked = false;
static bool _dm_verity_checked = false;
static bool _dm_integrity_checked = false;
static bool _dm_zero_checked = false;
static int _quiet_log = 0;
static uint32_t _dm_flags = 0;
@@ -241,6 +242,20 @@ static void _dm_set_integrity_compat(struct crypt_device *cd,
_dm_integrity_checked = true;
}
static void _dm_set_zero_compat(struct crypt_device *cd,
unsigned zero_maj,
unsigned zero_min,
unsigned zero_patch)
{
if (_dm_zero_checked || zero_maj == 0)
return;
log_dbg(cd, "Detected dm-zero version %i.%i.%i.",
zero_maj, zero_min, zero_patch);
_dm_zero_checked = true;
}
/* We use this for loading target module */
static void _dm_check_target(dm_target_type target_type)
{
@@ -278,11 +293,12 @@ 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 && _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))
(target_type == DM_ZERO && _dm_zero_checked) ||
(target_type == DM_LINEAR) ||
(_dm_crypt_checked && _dm_verity_checked && _dm_integrity_checked && _dm_zero_checked))
return 1;
/* Shut up DM while checking */
@@ -331,8 +347,12 @@ static int _dm_check_versions(struct crypt_device *cd, dm_target_type target_typ
_dm_set_integrity_compat(cd, (unsigned)target->version[0],
(unsigned)target->version[1],
(unsigned)target->version[2]);
} else if (!strcmp(DM_ZERO_TARGET, target->name)) {
_dm_set_zero_compat(cd, (unsigned)target->version[0],
(unsigned)target->version[1],
(unsigned)target->version[2]);
}
target = (struct dm_versions *)((char *) target + target->next);
target = VOIDP_CAST(struct dm_versions *)((char *) target + target->next);
} while (last_target != target);
r = 1;
@@ -355,13 +375,14 @@ int dm_flags(struct crypt_device *cd, dm_target_type target, uint32_t *flags)
*flags = _dm_flags;
if (target == DM_UNKNOWN &&
_dm_crypt_checked && _dm_verity_checked && _dm_integrity_checked)
_dm_crypt_checked && _dm_verity_checked && _dm_integrity_checked && _dm_zero_checked)
return 0;
if ((target == DM_CRYPT && _dm_crypt_checked) ||
if ((target == DM_CRYPT && _dm_crypt_checked) ||
(target == DM_VERITY && _dm_verity_checked) ||
(target == DM_INTEGRITY && _dm_integrity_checked) ||
(target == DM_LINEAR) || (target == DM_ZERO)) /* nothing to check */
(target == DM_ZERO && _dm_zero_checked) ||
(target == DM_LINEAR)) /* nothing to check */
return 0;
return -ENODEV;
@@ -444,14 +465,6 @@ char *dm_device_name(const char *path)
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;
for(i = 0; i < key_size; i++)
sprintf(&hexkey[i * 2], "%02x", (unsigned char)key[i]);
}
static size_t int_log10(uint64_t x)
{
uint64_t r = 0;
@@ -655,24 +668,20 @@ static char *get_dm_crypt_params(const struct dm_target *tgt, uint32_t flags)
null_cipher = 1;
if (null_cipher)
hexkey = crypt_safe_alloc(2);
hexkey = crypt_bytes_to_hex(0, NULL);
else if (flags & CRYPT_ACTIVATE_KEYRING_KEY) {
keystr_len = strlen(tgt->u.crypt.vk->key_description) + int_log10(tgt->u.crypt.vk->keylength) + 10;
hexkey = crypt_safe_alloc(keystr_len);
} else
hexkey = crypt_safe_alloc(tgt->u.crypt.vk->keylength * 2 + 1);
if (!hexkey)
goto out;
if (null_cipher)
strncpy(hexkey, "-", 2);
else if (flags & CRYPT_ACTIVATE_KEYRING_KEY) {
if (!hexkey)
goto out;
r = snprintf(hexkey, keystr_len, ":%zu:logon:%s", tgt->u.crypt.vk->keylength, tgt->u.crypt.vk->key_description);
if (r < 0 || r >= keystr_len)
goto out;
} else
hex_key(hexkey, tgt->u.crypt.vk->keylength, tgt->u.crypt.vk->key);
hexkey = crypt_bytes_to_hex(tgt->u.crypt.vk->keylength, tgt->u.crypt.vk->key);
if (!hexkey)
goto out;
max_size = strlen(hexkey) + strlen(cipher_dm) +
strlen(device_block_path(tgt->data_device)) +
@@ -767,18 +776,13 @@ static char *get_dm_verity_params(const struct dm_target *tgt, uint32_t flags)
} else
*features = '\0';
hexroot = crypt_safe_alloc(tgt->u.verity.root_hash_size * 2 + 1);
hexroot = crypt_bytes_to_hex(tgt->u.verity.root_hash_size, tgt->u.verity.root_hash);
if (!hexroot)
goto out;
hex_key(hexroot, tgt->u.verity.root_hash_size, tgt->u.verity.root_hash);
hexsalt = crypt_safe_alloc(vp->salt_size ? vp->salt_size * 2 + 1 : 2);
hexsalt = crypt_bytes_to_hex(vp->salt_size, vp->salt);
if (!hexsalt)
goto out;
if (vp->salt_size)
hex_key(hexsalt, vp->salt_size, vp->salt);
else
strncpy(hexsalt, "-", 2);
max_size = strlen(hexroot) + strlen(hexsalt) +
strlen(device_block_path(tgt->data_device)) +
@@ -843,10 +847,9 @@ static char *get_dm_integrity_params(const struct dm_target *tgt, uint32_t flags
num_options++;
if (tgt->u.integrity.vk) {
hexkey = crypt_safe_alloc(tgt->u.integrity.vk->keylength * 2 + 1);
hexkey = crypt_bytes_to_hex(tgt->u.integrity.vk->keylength, tgt->u.integrity.vk->key);
if (!hexkey)
goto out;
hex_key(hexkey, tgt->u.integrity.vk->keylength, tgt->u.integrity.vk->key);
} else
hexkey = NULL;
@@ -861,11 +864,10 @@ static char *get_dm_integrity_params(const struct dm_target *tgt, uint32_t flags
num_options++;
if (tgt->u.integrity.journal_integrity_key) {
hexkey = crypt_safe_alloc(tgt->u.integrity.journal_integrity_key->keylength * 2 + 1);
hexkey = crypt_bytes_to_hex( tgt->u.integrity.journal_integrity_key->keylength,
tgt->u.integrity.journal_integrity_key->key);
if (!hexkey)
goto out;
hex_key(hexkey, tgt->u.integrity.journal_integrity_key->keylength,
tgt->u.integrity.journal_integrity_key->key);
} else
hexkey = NULL;
@@ -880,11 +882,10 @@ static char *get_dm_integrity_params(const struct dm_target *tgt, uint32_t flags
num_options++;
if (tgt->u.integrity.journal_crypt_key) {
hexkey = crypt_safe_alloc(tgt->u.integrity.journal_crypt_key->keylength * 2 + 1);
hexkey = crypt_bytes_to_hex(tgt->u.integrity.journal_crypt_key->keylength,
tgt->u.integrity.journal_crypt_key->key);
if (!hexkey)
goto out;
hex_key(hexkey, tgt->u.integrity.journal_crypt_key->keylength,
tgt->u.integrity.journal_crypt_key->key);
} else
hexkey = NULL;
@@ -980,7 +981,7 @@ out:
return params_out;
}
static char *get_dm_linear_params(const struct dm_target *tgt, uint32_t flags __attribute__((unused)))
static char *get_dm_linear_params(const struct dm_target *tgt)
{
char *params;
int r;
@@ -1001,7 +1002,7 @@ 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 __attribute__((unused)), uint32_t flags __attribute__((unused)))
static char *get_dm_zero_params(void)
{
char *params = crypt_safe_alloc(1);
if (!params)
@@ -1243,7 +1244,7 @@ static int dm_prepare_uuid(struct crypt_device *cd, const char *name, const char
int lookup_dm_dev_by_uuid(struct crypt_device *cd, const char *uuid, const char *type)
{
int r;
int r_udev, r;
char *c;
char dev_uuid[DM_UUID_LEN + DM_BY_ID_PREFIX_LEN] = DM_BY_ID_PREFIX;
@@ -1257,13 +1258,15 @@ int lookup_dm_dev_by_uuid(struct crypt_device *cd, const char *uuid, const char
/* cut of dm name */
*c = '\0';
/* Either udev or sysfs can report that device is active. */
r = lookup_by_disk_id(dev_uuid);
if (r == -ENOENT) {
log_dbg(cd, "Search by disk id not available. Using sysfs instead.");
r = lookup_by_sysfs_uuid_field(dev_uuid + DM_BY_ID_PREFIX_LEN);
}
if (r > 0)
return r;
return r;
r_udev = r;
r = lookup_by_sysfs_uuid_field(dev_uuid + DM_BY_ID_PREFIX_LEN);
return r == -ENOENT ? r_udev : r;
}
static int _add_dm_targets(struct dm_task *dmt, struct crypt_dm_active_device *dmd)
@@ -1325,9 +1328,9 @@ static int _create_dm_targets_params(struct crypt_dm_active_device *dmd)
else if (tgt->type == DM_INTEGRITY)
tgt->params = get_dm_integrity_params(tgt, dmd->flags);
else if (tgt->type == DM_LINEAR)
tgt->params = get_dm_linear_params(tgt, dmd->flags);
tgt->params = get_dm_linear_params(tgt);
else if (tgt->type == DM_ZERO)
tgt->params = get_dm_zero_params(tgt, dmd->flags);
tgt->params = get_dm_zero_params();
else {
r = -ENOTSUP;
goto err;
@@ -1346,12 +1349,6 @@ err:
return r;
}
static bool dm_device_exists(struct crypt_device *cd, const char *name)
{
int r = dm_status_device(cd, name);
return (r >= 0 || r == -EEXIST);
}
static int _dm_create_device(struct crypt_device *cd, const char *name, const char *type,
struct crypt_dm_active_device *dmd)
{
@@ -1402,8 +1399,11 @@ static int _dm_create_device(struct crypt_device *cd, const char *name, const ch
goto out;
if (!dm_task_run(dmt)) {
if (dm_device_exists(cd, name))
r = dm_status_device(cd, name);;
if (r >= 0)
r = -EEXIST;
if (r != -EEXIST && r != -ENODEV)
r = -EINVAL;
goto out;
}
@@ -1576,6 +1576,9 @@ static void _dm_target_free_query_path(struct crypt_device *cd, struct dm_target
static void _dm_target_erase(struct crypt_device *cd, struct dm_target *tgt)
{
if (tgt->direction == TARGET_EMPTY)
return;
if (tgt->direction == TARGET_QUERY)
_dm_target_free_query_path(cd, tgt);
@@ -2303,16 +2306,16 @@ static int _dm_target_query_verity(struct crypt_device *cd,
str = strsep(&params, " ");
if (!str)
goto err;
if (!root_hash_sig_key_desc) {
if (vp && !root_hash_sig_key_desc) {
root_hash_sig_key_desc = strdup(str);
if (!root_hash_sig_key_desc) {
r = -ENOMEM;
goto err;
}
/* not stored in params, but cannot be used without vp */
vp->flags |= CRYPT_VERITY_ROOT_HASH_SIGNATURE;
}
i++;
if (vp)
vp->flags |= CRYPT_VERITY_ROOT_HASH_SIGNATURE;
} else /* unknown option */
goto err;
}
@@ -2370,6 +2373,8 @@ static int _dm_target_query_integrity(struct crypt_device *cd,
struct device *data_device = NULL, *meta_device = NULL;
char *integrity = NULL, *journal_crypt = NULL, *journal_integrity = NULL;
struct volume_key *vk = NULL;
struct volume_key *journal_integrity_key = NULL;
struct volume_key *journal_crypt_key = NULL;
tgt->type = DM_INTEGRITY;
tgt->direction = TARGET_QUERY;
@@ -2499,6 +2504,28 @@ static int _dm_target_query_integrity(struct crypt_device *cd,
goto err;
}
}
if (str) {
len = crypt_hex_to_bytes(str, &str2, 1);
if (len < 0) {
r = len;
goto err;
}
r = 0;
if (get_flags & DM_ACTIVE_JOURNAL_CRYPT_KEY) {
journal_crypt_key = crypt_alloc_volume_key(len, str2);
if (!journal_crypt_key)
r = -ENOMEM;
} else if (get_flags & DM_ACTIVE_JOURNAL_CRYPT_KEYSIZE) {
journal_crypt_key = crypt_alloc_volume_key(len, NULL);
if (!journal_crypt_key)
r = -ENOMEM;
}
crypt_safe_free(str2);
if (r < 0)
goto err;
}
} else if (!strncmp(arg, "journal_mac:", 12) && !journal_integrity) {
str = &arg[12];
arg = strsep(&str, ":");
@@ -2509,6 +2536,28 @@ static int _dm_target_query_integrity(struct crypt_device *cd,
goto err;
}
}
if (str) {
len = crypt_hex_to_bytes(str, &str2, 1);
if (len < 0) {
r = len;
goto err;
}
r = 0;
if (get_flags & DM_ACTIVE_JOURNAL_MAC_KEY) {
journal_integrity_key = crypt_alloc_volume_key(len, str2);
if (!journal_integrity_key)
r = -ENOMEM;
} else if (get_flags & DM_ACTIVE_JOURNAL_MAC_KEYSIZE) {
journal_integrity_key = crypt_alloc_volume_key(len, NULL);
if (!journal_integrity_key)
r = -ENOMEM;
}
crypt_safe_free(str2);
if (r < 0)
goto err;
}
} else if (!strcmp(arg, "recalculate")) {
*act_flags |= CRYPT_ACTIVATE_RECALCULATE;
} else if (!strcmp(arg, "reset_recalculate")) {
@@ -2544,6 +2593,10 @@ static int _dm_target_query_integrity(struct crypt_device *cd,
tgt->u.integrity.journal_integrity = journal_integrity;
if (vk)
tgt->u.integrity.vk = vk;
if (journal_integrity_key)
tgt->u.integrity.journal_integrity_key = journal_integrity_key;
if (journal_crypt_key)
tgt->u.integrity.journal_crypt_key = journal_crypt_key;
return 0;
err:
device_free(cd, data_device);
@@ -2552,6 +2605,8 @@ err:
free(journal_crypt);
free(journal_integrity);
crypt_free_volume_key(vk);
crypt_free_volume_key(journal_integrity_key);
crypt_free_volume_key(journal_crypt_key);
return r;
}
@@ -2595,7 +2650,7 @@ err:
return r;
}
static int _dm_target_query_error(struct crypt_device *cd __attribute__((unused)), struct dm_target *tgt)
static int _dm_target_query_error(struct dm_target *tgt)
{
tgt->type = DM_ERROR;
tgt->direction = TARGET_QUERY;
@@ -2603,7 +2658,7 @@ static int _dm_target_query_error(struct crypt_device *cd __attribute__((unused)
return 0;
}
static int _dm_target_query_zero(struct crypt_device *cd __attribute__((unused)), struct dm_target *tgt)
static int _dm_target_query_zero(struct dm_target *tgt)
{
tgt->type = DM_ZERO;
tgt->direction = TARGET_QUERY;
@@ -2631,9 +2686,9 @@ static int dm_target_query(struct crypt_device *cd, struct dm_target *tgt, const
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);
r = _dm_target_query_error(tgt);
else if (!strcmp(target_type, DM_ZERO_TARGET))
r = _dm_target_query_zero(cd, tgt);
r = _dm_target_query_zero(tgt);
if (!r) {
tgt->offset = *start;
@@ -2948,7 +3003,7 @@ int dm_resume_and_reinstate_key(struct crypt_device *cd, const char *name,
{
uint32_t dmt_flags;
int msg_size;
char *msg = NULL;
char *msg = NULL, *key = NULL;
int r = -ENOTSUP;
if (dm_init_context(cd, DM_CRYPT) || dm_flags(cd, DM_CRYPT, &dmt_flags))
@@ -2970,14 +3025,21 @@ int dm_resume_and_reinstate_key(struct crypt_device *cd, const char *name,
goto out;
}
strcpy(msg, "key set ");
if (!vk->keylength)
snprintf(msg + 8, msg_size - 8, "-");
else if (vk->key_description)
snprintf(msg + 8, msg_size - 8, ":%zu:logon:%s", vk->keylength, vk->key_description);
else
hex_key(&msg[8], vk->keylength, vk->key);
if (vk->key_description) {
r = snprintf(msg, msg_size, "key set :%zu:logon:%s", vk->keylength, vk->key_description);
} else {
key = crypt_bytes_to_hex(vk->keylength, vk->key);
if (!key) {
r = -ENOMEM;
goto out;
}
r = snprintf(msg, msg_size, "key set %s", key);
}
if (r < 0 || r >= msg_size) {
r = -EINVAL;
goto out;
}
if (!_dm_message(name, msg) ||
_dm_resume_device(name, 0)) {
r = -EINVAL;
@@ -2986,6 +3048,7 @@ int dm_resume_and_reinstate_key(struct crypt_device *cd, const char *name,
r = 0;
out:
crypt_safe_free(msg);
crypt_safe_free(key);
dm_exit_context();
return r;
}

View File

@@ -1,8 +1,8 @@
/*
* loop-AES compatible volume handling
*
* Copyright (C) 2011-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2021 Milan Broz
* Copyright (C) 2011-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2022 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

@@ -1,8 +1,8 @@
/*
* loop-AES compatible volume handling
*
* Copyright (C) 2011-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2021 Milan Broz
* Copyright (C) 2011-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2022 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-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2022 Red Hat, Inc. All rights reserved.
*
* AFsplitter diffuses information over a large stripe of data,
* therefore supporting secure data destruction.
@@ -131,7 +131,7 @@ out:
return r;
}
int AF_merge(struct crypt_device *ctx __attribute__((unused)), const char *src, char *dst,
int AF_merge(const char *src, char *dst,
size_t blocksize, unsigned int blocknumbers, const char *hash)
{
unsigned int i;
@@ -142,7 +142,7 @@ int AF_merge(struct crypt_device *ctx __attribute__((unused)), const char *src,
if (!bufblock)
return -ENOMEM;
for(i = 0; i < blocknumbers - 1; i++) {
for (i = 0; i < blocknumbers - 1; i++) {
XORblock(src + blocksize * i, bufblock, bufblock, blocksize);
r = diffuse(bufblock, bufblock, blocksize, hash);
if (r < 0)

View File

@@ -2,7 +2,7 @@
* AFsplitter - Anti forensic information splitter
*
* Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2022 Red Hat, Inc. All rights reserved.
*
* AFsplitter diffuses information over a large stripe of data,
* therefore supporting secure data destruction.
@@ -44,7 +44,7 @@ struct volume_key;
int AF_split(struct crypt_device *ctx, const char *src, char *dst,
size_t blocksize, unsigned int blocknumbers, const char *hash);
int AF_merge(struct crypt_device *ctx, const char *src, char *dst, size_t blocksize,
int AF_merge(const char *src, char *dst, size_t blocksize,
unsigned int blocknumbers, const char *hash);
size_t AF_split_sectors(size_t blocksize, unsigned int blocknumbers);

View File

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

View File

@@ -2,8 +2,8 @@
* LUKS - Linux Unified Key Setup
*
* Copyright (C) 2004-2006 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2013-2021 Milan Broz
* Copyright (C) 2009-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2013-2022 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -65,6 +65,27 @@ static void LUKS_sort_keyslots(const struct luks_phdr *hdr, int *array)
}
}
static int _is_not_lower(char *str, unsigned max_len)
{
for(; *str && max_len; str++, max_len--)
if (isupper(*str))
return 1;
return 0;
}
static int _to_lower(char *str, unsigned max_len)
{
int r = 0;
for(; *str && max_len; str++, max_len--)
if (isupper(*str)) {
*str = tolower(*str);
r = 1;
}
return r;
}
size_t LUKS_device_sectors(const struct luks_phdr *hdr)
{
int sorted_areas[LUKS_NUMKEYS] = { 0, 1, 2, 3, 4, 5, 6, 7 };
@@ -378,13 +399,37 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
/*
* cryptsetup 1.0 did not align keyslots to 4k, cannot repair this one
* Also we cannot trust possibly broken keyslots metadata here through LUKS_keyslots_offset().
* Expect first keyslot is aligned, if not, then manual repair is neccessary.
* Expect first keyslot is aligned, if not, then manual repair is necessary.
*/
if (phdr->keyblock[0].keyMaterialOffset < (LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE)) {
log_err(ctx, _("Non standard keyslots alignment, manual repair required."));
return -EINVAL;
}
/*
* ECB mode does not use IV but legacy dmcrypt silently allows it.
* Today device cannot be activated anyway, so we need to fix it here.
*/
if (!strncmp(phdr->cipherMode, "ecb-", 4)) {
log_err(ctx, _("Cipher mode repaired (%s -> %s)."), phdr->cipherMode, "ecb");
memset(phdr->cipherMode, 0, LUKS_CIPHERMODE_L);
strcpy(phdr->cipherMode, "ecb");
need_write = 1;
}
/*
* Old cryptsetup expects "sha1", gcrypt allows case insensitive names,
* so always convert hash to lower case in header
*/
if (_to_lower(phdr->hashSpec, LUKS_HASHSPEC_L)) {
log_err(ctx, _("Cipher hash repaired to lowercase (%s)."), phdr->hashSpec);
if (crypt_hmac_size(phdr->hashSpec) < LUKS_DIGESTSIZE) {
log_err(ctx, _("Requested LUKS hash %s is not supported."), phdr->hashSpec);
return -EINVAL;
}
need_write = 1;
}
r = LUKS_check_cipher(ctx, phdr->keyBytes, phdr->cipherName, phdr->cipherMode);
if (r < 0)
return -EINVAL;
@@ -486,7 +531,7 @@ static int _check_and_convert_hdr(const char *device,
hdr->hashSpec[LUKS_HASHSPEC_L - 1] = '\0';
if (crypt_hmac_size(hdr->hashSpec) < LUKS_DIGESTSIZE) {
log_err(ctx, _("Requested LUKS hash %s is not supported."), hdr->hashSpec);
return -EINVAL;
r = -EINVAL;
}
/* Header detected */
@@ -510,6 +555,16 @@ static int _check_and_convert_hdr(const char *device,
hdr->uuid[UUID_STRING_L - 1] = '\0';
if (repair) {
if (!strncmp(hdr->cipherMode, "ecb-", 4)) {
log_err(ctx, _("LUKS cipher mode %s is invalid."), hdr->cipherMode);
r = -EINVAL;
}
if (_is_not_lower(hdr->hashSpec, LUKS_HASHSPEC_L)) {
log_err(ctx, _("LUKS hash %s is invalid."), hdr->hashSpec);
r = -EINVAL;
}
if (r == -EINVAL)
r = _keyslot_repair(hdr, ctx);
else
@@ -519,27 +574,6 @@ static int _check_and_convert_hdr(const char *device,
return r;
}
static void _to_lower(char *str, unsigned max_len)
{
for(; *str && max_len; str++, max_len--)
if (isupper(*str))
*str = tolower(*str);
}
static void LUKS_fix_header_compatible(struct luks_phdr *header)
{
/* Old cryptsetup expects "sha1", gcrypt allows case insensitive names,
* so always convert hash to lower case in header */
_to_lower(header->hashSpec, LUKS_HASHSPEC_L);
/* ECB mode does not use IV but dmcrypt silently allows it.
* Drop any IV here if ECB is used (that is not secure anyway).*/
if (!strncmp(header->cipherMode, "ecb-", 4)) {
memset(header->cipherMode, 0, LUKS_CIPHERMODE_L);
strcpy(header->cipherMode, "ecb");
}
}
int LUKS_read_phdr_backup(const char *backup_file,
struct luks_phdr *hdr,
int require_luks_device,
@@ -559,11 +593,9 @@ int LUKS_read_phdr_backup(const char *backup_file,
if (read_buffer(devfd, hdr, hdr_size) < hdr_size)
r = -EIO;
else {
LUKS_fix_header_compatible(hdr);
else
r = _check_and_convert_hdr(backup_file, hdr,
require_luks_device, 0, ctx);
}
close(devfd);
return r;
@@ -771,11 +803,10 @@ int LUKS_generate_phdr(struct luks_phdr *header,
strncpy(header->cipherName,cipherName,LUKS_CIPHERNAME_L-1);
strncpy(header->cipherMode,cipherMode,LUKS_CIPHERMODE_L-1);
strncpy(header->hashSpec,hashSpec,LUKS_HASHSPEC_L-1);
_to_lower(header->hashSpec, LUKS_HASHSPEC_L);
header->keyBytes=vk->keylength;
LUKS_fix_header_compatible(header);
log_dbg(ctx, "Generating LUKS header version %d using hash %s, %s, %s, MK %d bytes",
header->version, header->hashSpec ,header->cipherName, header->cipherMode,
header->keyBytes);
@@ -786,7 +817,7 @@ int LUKS_generate_phdr(struct luks_phdr *header,
return r;
}
/* Compute master key digest */
/* Compute volume key digest */
pbkdf = crypt_get_pbkdf(ctx);
r = crypt_benchmark_pbkdf_internal(ctx, pbkdf, vk->keylength);
if (r < 0)
@@ -895,7 +926,7 @@ int LUKS_set_key(unsigned int keyIndex,
goto out;
/*
* AF splitting, the masterkey stored in vk->key is split to AfKey
* AF splitting, the volume key stored in vk->key is split to AfKey
*/
assert(vk->keylength == hdr->keyBytes);
AFEKSize = AF_split_sectors(vk->keylength, hdr->keyblock[keyIndex].stripes) * SECTOR_SIZE;
@@ -951,7 +982,7 @@ int LUKS_verify_volume_key(const struct luks_phdr *hdr,
hdr->mkDigestIterations, 0, 0) < 0)
return -EINVAL;
if (memcmp(checkHashBuf, hdr->mkDigest, LUKS_DIGESTSIZE))
if (crypt_backend_memeq(checkHashBuf, hdr->mkDigest, LUKS_DIGESTSIZE))
return -EPERM;
return 0;
@@ -1013,7 +1044,7 @@ static int LUKS_open_key(unsigned int keyIndex,
if (r < 0)
goto out;
r = AF_merge(ctx, AfKey, (*vk)->key, (*vk)->keylength, hdr->keyblock[keyIndex].stripes, hdr->hashSpec);
r = AF_merge(AfKey, (*vk)->key, (*vk)->keylength, hdr->keyblock[keyIndex].stripes, hdr->hashSpec);
if (r < 0)
goto out;

View File

@@ -2,7 +2,7 @@
* LUKS - Linux Unified Key Setup
*
* Copyright (C) 2004-2006 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2022 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-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2021 Milan Broz
* Copyright (C) 2015-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2022 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -62,8 +62,16 @@
/* 1 GiB */
#define LUKS2_REENCRYPT_MAX_HOTZONE_LENGTH 0x40000000
/* supported reencryption requirement versions */
#define LUKS2_REENCRYPT_REQ_VERSION UINT8_C(2)
#define LUKS2_DECRYPT_DATASHIFT_REQ_VERSION UINT8_C(3)
/* see reencrypt_assembly_verification_data() in luks2_reencrypt_digest.c */
/* LUKS2_REENCRYPT_MAX_VERSION UINT8_C(207) */
struct device;
struct luks2_reencrypt;
struct reenc_protection;
struct crypt_lock_handle;
struct crypt_dm_active_device;
struct luks_phdr; /* LUKS1 for conversion */
@@ -217,9 +225,7 @@ int LUKS2_keyslot_wipe(struct crypt_device *cd,
int keyslot,
int wipe_area_only);
crypt_keyslot_priority LUKS2_keyslot_priority_get(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot);
crypt_keyslot_priority LUKS2_keyslot_priority_get(struct luks2_hdr *hdr, int keyslot);
int LUKS2_keyslot_priority_set(struct crypt_device *cd,
struct luks2_hdr *hdr,
@@ -235,8 +241,7 @@ int LUKS2_keyslot_swap(struct crypt_device *cd,
/*
* Generic LUKS2 token
*/
int LUKS2_token_json_get(struct crypt_device *cd,
struct luks2_hdr *hdr,
int LUKS2_token_json_get(struct luks2_hdr *hdr,
int token,
const char **json);
@@ -247,8 +252,7 @@ int LUKS2_token_assign(struct crypt_device *cd,
int assign,
int commit);
int LUKS2_token_is_assigned(struct crypt_device *cd,
struct luks2_hdr *hdr,
int LUKS2_token_is_assigned(struct luks2_hdr *hdr,
int keyslot,
int token);
@@ -279,8 +283,17 @@ int LUKS2_token_open_and_activate(struct crypt_device *cd,
uint32_t flags,
void *usrptr);
int LUKS2_token_keyring_get(struct crypt_device *cd,
int LUKS2_token_unlock_volume_key(struct crypt_device *cd,
struct luks2_hdr *hdr,
int token,
const char *type,
const char *pin,
size_t pin_size,
uint32_t flags,
void *usrptr,
struct volume_key **vk);
int LUKS2_token_keyring_get(struct luks2_hdr *hdr,
int token,
struct crypt_token_params_luks2_keyring *keyring_params);
@@ -372,7 +385,7 @@ int LUKS2_wipe_header_areas(struct crypt_device *cd,
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);
uint32_t 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);
int LUKS2_keyslot_params_default(struct crypt_device *cd, struct luks2_hdr *hdr,
@@ -400,6 +413,11 @@ int LUKS2_config_set_flags(struct crypt_device *cd, struct luks2_hdr *hdr, uint3
*/
int LUKS2_config_get_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t *reqs);
int LUKS2_config_set_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs, bool commit);
int LUKS2_config_set_requirement_version(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t req_id, uint8_t req_version, bool commit);
int LUKS2_config_get_reencrypt_version(struct luks2_hdr *hdr, uint8_t *version);
bool LUKS2_reencrypt_requirement_candidate(struct luks2_hdr *hdr);
int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs_mask, int quiet);
@@ -408,7 +426,7 @@ int LUKS2_key_description_by_segment(struct crypt_device *cd,
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 volume_key *vk, int digest);
int LUKS2_luks1_to_luks2(struct crypt_device *cd,
struct luks_phdr *hdr1,
@@ -425,7 +443,6 @@ int LUKS2_reencrypt_locked_recovery_by_passphrase(struct crypt_device *cd,
int keyslot_new,
const char *passphrase,
size_t passphrase_size,
uint32_t flags,
struct volume_key **vks);
void LUKS2_reencrypt_free(struct crypt_device *cd,
@@ -453,4 +470,16 @@ int LUKS2_reencrypt_check_device_size(struct crypt_device *cd,
bool activation,
bool dynamic);
int LUKS2_reencrypt_digest_verify(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct volume_key *vks);
int LUKS2_reencrypt_max_hotzone_size(struct crypt_device *cd,
struct luks2_hdr *hdr,
const struct reenc_protection *rp,
int reencrypt_keyslot,
uint64_t *r_length);
void LUKS2_reencrypt_protection_erase(struct reenc_protection *rp);
#endif

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, digest handling
*
* Copyright (C) 2015-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2021 Milan Broz
* Copyright (C) 2015-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2022 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -111,7 +111,6 @@ int LUKS2_digest_by_keyslot(struct luks2_hdr *hdr, int keyslot)
}
int LUKS2_digest_verify_by_digest(struct crypt_device *cd,
struct luks2_hdr *hdr __attribute__((unused)),
int digest,
const struct volume_key *vk)
{
@@ -144,7 +143,7 @@ int LUKS2_digest_verify(struct crypt_device *cd,
log_dbg(cd, "Verifying key from keyslot %d, digest %d.", keyslot, digest);
return LUKS2_digest_verify_by_digest(cd, hdr, digest, vk);
return LUKS2_digest_verify_by_digest(cd, digest, vk);
}
int LUKS2_digest_dump(struct crypt_device *cd, int digest)
@@ -164,7 +163,7 @@ int LUKS2_digest_any_matching(struct crypt_device *cd,
int digest;
for (digest = 0; digest < LUKS2_DIGEST_MAX; digest++)
if (LUKS2_digest_verify_by_digest(cd, hdr, digest, vk) == digest)
if (LUKS2_digest_verify_by_digest(cd, digest, vk) == digest)
return digest;
return -ENOENT;
@@ -175,7 +174,7 @@ int LUKS2_digest_verify_by_segment(struct crypt_device *cd,
int segment,
const struct volume_key *vk)
{
return LUKS2_digest_verify_by_digest(cd, hdr, LUKS2_digest_by_segment(hdr, segment), vk);
return LUKS2_digest_verify_by_digest(cd, LUKS2_digest_by_segment(hdr, segment), vk);
}
/* FIXME: segment can have more digests */
@@ -259,8 +258,7 @@ 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 __attribute__((unused)),
struct luks2_hdr *hdr, int digest, int assign)
static int assign_all_segments(struct luks2_hdr *hdr, int digest, int assign)
{
json_object *jobj1, *jobj_digest, *jobj_digest_segments;
@@ -336,7 +334,7 @@ int LUKS2_digest_segment_assign(struct crypt_device *cd, struct luks2_hdr *hdr,
json_object_object_foreach(jobj_digests, key, val) {
UNUSED(val);
if (segment == CRYPT_ANY_SEGMENT)
r = assign_all_segments(cd, hdr, atoi(key), assign);
r = assign_all_segments(hdr, atoi(key), assign);
else
r = assign_one_segment(cd, hdr, segment, atoi(key), assign);
if (r < 0)
@@ -344,7 +342,7 @@ int LUKS2_digest_segment_assign(struct crypt_device *cd, struct luks2_hdr *hdr,
}
} else {
if (segment == CRYPT_ANY_SEGMENT)
r = assign_all_segments(cd, hdr, digest, assign);
r = assign_all_segments(hdr, digest, assign);
else
r = assign_one_segment(cd, hdr, segment, digest, assign);
}
@@ -443,7 +441,7 @@ int LUKS2_volume_key_load_in_keyring_by_keyslot(struct crypt_device *cd,
}
int LUKS2_volume_key_load_in_keyring_by_digest(struct crypt_device *cd,
struct luks2_hdr *hdr __attribute__((unused)), struct volume_key *vk, int digest)
struct volume_key *vk, int digest)
{
char *desc = get_key_description_by_digest(cd, digest);
int r;

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, PBKDF2 digest handler (LUKS1 compatible)
*
* Copyright (C) 2015-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2021 Milan Broz
* Copyright (C) 2015-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2022 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -33,10 +33,10 @@ static int PBKDF2_digest_verify(struct crypt_device *cd,
char checkHashBuf[64];
json_object *jobj_digest, *jobj1;
const char *hashSpec;
char *mkDigest = NULL, mkDigestSalt[LUKS_SALTSIZE];
char *mkDigest = NULL, *mkDigestSalt = NULL;
unsigned int mkDigestIterations;
size_t len;
int r;
int r = -EINVAL;
/* This can be done only for internally linked digests */
jobj_digest = LUKS2_get_digest_jobj(crypt_get_hdr(cd, CRYPT_LUKS2), digest);
@@ -53,25 +53,23 @@ static int PBKDF2_digest_verify(struct crypt_device *cd,
if (!json_object_object_get_ex(jobj_digest, "salt", &jobj1))
return -EINVAL;
len = sizeof(mkDigestSalt);
if (!base64_decode(json_object_get_string(jobj1),
json_object_get_string_len(jobj1), mkDigestSalt, &len))
return -EINVAL;
r = crypt_base64_decode(&mkDigestSalt, &len, json_object_get_string(jobj1),
json_object_get_string_len(jobj1));
if (r < 0)
goto out;
if (len != LUKS_SALTSIZE)
return -EINVAL;
goto out;
if (!json_object_object_get_ex(jobj_digest, "digest", &jobj1))
return -EINVAL;
len = 0;
if (!base64_decode_alloc(json_object_get_string(jobj1),
json_object_get_string_len(jobj1), &mkDigest, &len))
return -EINVAL;
goto out;
r = crypt_base64_decode(&mkDigest, &len, json_object_get_string(jobj1),
json_object_get_string_len(jobj1));
if (r < 0)
goto out;
if (len < LUKS_DIGESTSIZE ||
len > sizeof(checkHashBuf) ||
(len != LUKS_DIGESTSIZE && len != (size_t)crypt_hash_size(hashSpec))) {
free(mkDigest);
return -EINVAL;
}
(len != LUKS_DIGESTSIZE && len != (size_t)crypt_hash_size(hashSpec)))
goto out;
r = -EPERM;
if (crypt_pbkdf(CRYPT_KDF_PBKDF2, hashSpec, volume_key, volume_key_len,
@@ -80,11 +78,12 @@ static int PBKDF2_digest_verify(struct crypt_device *cd,
mkDigestIterations, 0, 0) < 0) {
r = -EINVAL;
} else {
if (memcmp(checkHashBuf, mkDigest, len) == 0)
if (crypt_backend_memeq(checkHashBuf, mkDigest, len) == 0)
r = 0;
}
out:
free(mkDigest);
free(mkDigestSalt);
return r;
}
@@ -154,18 +153,18 @@ static int PBKDF2_digest_store(struct crypt_device *cd,
json_object_object_add(jobj_digest, "hash", json_object_new_string(pbkdf.hash));
json_object_object_add(jobj_digest, "iterations", json_object_new_int(pbkdf.iterations));
base64_encode_alloc(salt, LUKS_SALTSIZE, &base64_str);
if (!base64_str) {
r = crypt_base64_encode(&base64_str, NULL, salt, LUKS_SALTSIZE);
if (r < 0) {
json_object_put(jobj_digest);
return -ENOMEM;
return r;
}
json_object_object_add(jobj_digest, "salt", json_object_new_string(base64_str));
free(base64_str);
base64_encode_alloc(digest_raw, hmac_size, &base64_str);
if (!base64_str) {
r = crypt_base64_encode(&base64_str, NULL, digest_raw, hmac_size);
if (r < 0) {
json_object_put(jobj_digest);
return -ENOMEM;
return r;
}
json_object_object_add(jobj_digest, "digest", json_object_new_string(base64_str));
free(base64_str);

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2
*
* Copyright (C) 2015-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2021 Milan Broz
* Copyright (C) 2015-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2022 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -62,8 +62,8 @@ static void log_dbg_checksum(struct crypt_device *cd,
int i;
for (i = 0; i < crypt_hash_size(csum_alg); i++)
snprintf(&csum_txt[i*2], 3, "%02hhx", (const char)csum[i]);
csum_txt[i*2+1] = '\0'; /* Just to be safe, sprintf should write \0 there. */
if (snprintf(&csum_txt[i*2], 3, "%02hhx", (const char)csum[i]) != 2)
return;
log_dbg(cd, "Checksum:%s (%s)", &csum_txt[0], info);
}
@@ -195,6 +195,8 @@ static int hdr_disk_sanity_check_pre(struct crypt_device *cd,
size_t *hdr_json_size, int secondary,
uint64_t offset)
{
uint64_t hdr_size;
if (memcmp(hdr->magic, secondary ? LUKS2_MAGIC_2ND : LUKS2_MAGIC_1ST, LUKS2_MAGIC_L))
return -EINVAL;
@@ -204,24 +206,31 @@ static int hdr_disk_sanity_check_pre(struct crypt_device *cd,
}
if (offset != be64_to_cpu(hdr->hdr_offset)) {
log_dbg(cd, "LUKS2 offset 0x%04x on device differs to expected offset 0x%04x.",
(unsigned)be64_to_cpu(hdr->hdr_offset), (unsigned)offset);
log_dbg(cd, "LUKS2 offset 0x%04" PRIx64 " on device differs to expected offset 0x%04" PRIx64 ".",
be64_to_cpu(hdr->hdr_offset), offset);
return -EINVAL;
}
if (secondary && (offset != be64_to_cpu(hdr->hdr_size))) {
log_dbg(cd, "LUKS2 offset 0x%04x in secondary header does not match size 0x%04x.",
(unsigned)offset, (unsigned)be64_to_cpu(hdr->hdr_size));
hdr_size = be64_to_cpu(hdr->hdr_size);
if (hdr_size < LUKS2_HDR_16K_LEN || hdr_size > LUKS2_HDR_OFFSET_MAX) {
log_dbg(cd, "LUKS2 header has bogus size 0x%04" PRIx64 ".", hdr_size);
return -EINVAL;
}
if (secondary && (offset != hdr_size)) {
log_dbg(cd, "LUKS2 offset 0x%04" PRIx64 " in secondary header does not match size 0x%04" PRIx64 ".",
offset, hdr_size);
return -EINVAL;
}
/* FIXME: sanity check checksum alg. */
log_dbg(cd, "LUKS2 header version %u of size %u bytes, checksum %s.",
(unsigned)be16_to_cpu(hdr->version), (unsigned)be64_to_cpu(hdr->hdr_size),
log_dbg(cd, "LUKS2 header version %u of size %" PRIu64 " bytes, checksum %s.",
be16_to_cpu(hdr->version), hdr_size,
hdr->checksum_alg);
*hdr_json_size = be64_to_cpu(hdr->hdr_size) - LUKS2_HDR_BIN_LEN;
*hdr_json_size = hdr_size - LUKS2_HDR_BIN_LEN;
return 0;
}
@@ -252,18 +261,19 @@ static int hdr_read_disk(struct crypt_device *cd,
return -EIO;
}
/*
* hdr_json_size is validated if this call succeeds
*/
r = hdr_disk_sanity_check_pre(cd, hdr_disk, &hdr_json_size, secondary, offset);
if (r < 0) {
if (r < 0)
return r;
}
/*
* Allocate and read JSON area. Always the whole area must be read.
*/
*json_area = malloc(hdr_json_size);
if (!*json_area) {
if (!*json_area)
return -ENOMEM;
}
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
device_alignment(device), *json_area, hdr_json_size,
@@ -279,6 +289,8 @@ static int hdr_read_disk(struct crypt_device *cd,
if (hdr_checksum_check(cd, hdr_disk->checksum_alg, hdr_disk,
*json_area, hdr_json_size)) {
log_dbg(cd, "LUKS2 header checksum error (offset %" PRIu64 ").", offset);
free(*json_area);
*json_area = NULL;
r = -EINVAL;
}
memset(hdr_disk->csum, 0, LUKS2_CHECKSUM_L);
@@ -695,7 +707,7 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
memcpy(&hdr_disk2, &hdr_disk1, LUKS2_HDR_BIN_LEN);
r = crypt_random_get(cd, (char*)hdr_disk2.salt, sizeof(hdr_disk2.salt), CRYPT_RND_SALT);
if (r)
log_dbg(cd, "Cannot generate master salt.");
log_dbg(cd, "Cannot generate header salt.");
else {
hdr_from_disk(&hdr_disk1, &hdr_disk2, hdr, 0);
r = hdr_write_disk(cd, device, hdr, json_area1, 1);
@@ -716,7 +728,7 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
memcpy(&hdr_disk1, &hdr_disk2, LUKS2_HDR_BIN_LEN);
r = crypt_random_get(cd, (char*)hdr_disk1.salt, sizeof(hdr_disk1.salt), CRYPT_RND_SALT);
if (r)
log_dbg(cd, "Cannot generate master salt.");
log_dbg(cd, "Cannot generate header salt.");
else {
hdr_from_disk(&hdr_disk2, &hdr_disk1, hdr, 1);
r = hdr_write_disk(cd, device, hdr, json_area2, 0);

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2
*
* Copyright (C) 2015-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2021 Milan Broz
* Copyright (C) 2015-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2022 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -27,7 +27,6 @@
#include <json-c/json.h>
#include "internal.h"
#include "base64.h"
#include "luks2.h"
/* override useless forward slash escape when supported by json-c */
@@ -73,9 +72,11 @@ void JSON_DBG(struct crypt_device *cd, json_object *jobj, const char *desc);
*/
/* validation helper */
json_bool validate_json_uint32(json_object *jobj);
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);
json_object *json_contains_string(struct crypt_device *cd, json_object *jobj,
const char *name, const char *section, const char *key);
int LUKS2_hdr_validate(struct crypt_device *cd, json_object *hdr_jobj, uint64_t json_size);
int LUKS2_check_json_size(struct crypt_device *cd, const struct luks2_hdr *hdr);
@@ -116,14 +117,13 @@ typedef int (*keyslot_store_func)(struct crypt_device *cd, int keyslot,
typedef int (*keyslot_wipe_func) (struct crypt_device *cd, int keyslot);
typedef int (*keyslot_dump_func) (struct crypt_device *cd, int keyslot);
typedef int (*keyslot_validate_func) (struct crypt_device *cd, json_object *jobj_keyslot);
typedef void(*keyslot_repair_func) (struct crypt_device *cd, json_object *jobj_keyslot);
typedef void(*keyslot_repair_func) (json_object *jobj_keyslot);
/* see LUKS2_luks2_to_luks1 */
int placeholder_keyslot_alloc(struct crypt_device *cd,
int keyslot,
uint64_t area_offset,
uint64_t area_length,
size_t volume_key_len);
uint64_t area_length);
/* validate all keyslot implementations in hdr json */
int LUKS2_keyslots_validate(struct crypt_device *cd, json_object *hdr_jobj);
@@ -140,11 +140,28 @@ 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);
struct reenc_protection {
enum { REENC_PROTECTION_NOT_SET = 0,
REENC_PROTECTION_NONE,
REENC_PROTECTION_CHECKSUM,
REENC_PROTECTION_JOURNAL,
REENC_PROTECTION_DATASHIFT } type;
union {
struct {
char hash[LUKS2_CHECKSUM_ALG_L];
struct crypt_hash *ch;
size_t hash_size;
/* buffer for checksums */
void *checksums;
size_t checksums_len;
size_t block_size;
} csum;
struct {
uint64_t data_shift;
} ds;
} p;
};
/**
* LUKS2 digest handlers (EXPERIMENTAL)
@@ -234,21 +251,48 @@ int LUKS2_keyslot_reencrypt_store(struct crypt_device *cd,
const void *buffer,
size_t buffer_length);
int LUKS2_keyslot_reencrypt_create(struct crypt_device *cd,
int LUKS2_keyslot_reencrypt_allocate(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const struct crypt_params_reencrypt *params);
const struct crypt_params_reencrypt *params,
size_t alignment);
int LUKS2_keyslot_reencrypt_update_needed(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const struct crypt_params_reencrypt *params,
size_t alignment);
int LUKS2_keyslot_reencrypt_update(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const struct crypt_params_reencrypt *params,
size_t alignment,
struct volume_key *vks);
int LUKS2_keyslot_reencrypt_load(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
struct reenc_protection *rp,
bool primary);
int LUKS2_keyslot_reencrypt_digest_create(struct crypt_device *cd,
struct luks2_hdr *hdr,
uint8_t version,
struct volume_key *vks);
int LUKS2_keyslot_dump(struct crypt_device *cd,
int keyslot);
int LUKS2_keyslot_jobj_area(json_object *jobj_keyslot, uint64_t *offset, uint64_t *length);
/* JSON helpers */
uint64_t json_segment_get_offset(json_object *jobj_segment, unsigned blockwise);
const char *json_segment_type(json_object *jobj_segment);
uint64_t json_segment_get_iv_offset(json_object *jobj_segment);
uint64_t json_segment_get_size(json_object *jobj_segment, unsigned blockwise);
const char *json_segment_get_cipher(json_object *jobj_segment);
int json_segment_get_sector_size(json_object *jobj_segment);
uint32_t 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);
@@ -257,6 +301,8 @@ uint64_t json_segments_get_minimal_offset(json_object *jobj_segments, unsigned b
json_object *json_segment_create_linear(uint64_t offset, const uint64_t *length, unsigned reencryption);
json_object *json_segment_create_crypt(uint64_t offset, uint64_t iv_offset, const uint64_t *length, const char *cipher, uint32_t sector_size, unsigned reencryption);
int json_segments_segment_in_reencrypt(json_object *jobj_segments);
bool json_segment_cmp(json_object *jobj_segment_1, json_object *jobj_segment_2);
bool json_segment_contains_flag(json_object *jobj_segment, const char *flag_str, size_t len);
int LUKS2_assembly_multisegment_dmd(struct crypt_device *cd,
struct luks2_hdr *hdr,
@@ -310,7 +356,6 @@ int LUKS2_reencrypt_data_offset(struct luks2_hdr *hdr, bool blockwise);
* Generic LUKS2 digest
*/
int LUKS2_digest_verify_by_digest(struct crypt_device *cd,
struct luks2_hdr *hdr,
int digest,
const struct volume_key *vk);
@@ -336,8 +381,6 @@ int LUKS2_reload(struct crypt_device *cd,
int LUKS2_keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment);
int LUKS2_find_keyslot(struct luks2_hdr *hdr, const char *type);
int LUKS2_set_keyslots_size(struct crypt_device *cd,
struct luks2_hdr *hdr,
uint64_t data_offset);
int LUKS2_set_keyslots_size(struct luks2_hdr *hdr, uint64_t data_offset);
#endif

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, LUKS2 header format code
*
* Copyright (C) 2015-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2021 Milan Broz
* Copyright (C) 2015-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2022 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -383,9 +383,7 @@ int LUKS2_wipe_header_areas(struct crypt_device *cd,
offset, length, wipe_block, NULL, NULL);
}
int LUKS2_set_keyslots_size(struct crypt_device *cd __attribute__((unused)),
struct luks2_hdr *hdr,
uint64_t data_offset)
int LUKS2_set_keyslots_size(struct luks2_hdr *hdr, uint64_t data_offset)
{
json_object *jobj_config;
uint64_t keyslots_size;

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-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2021 Milan Broz
* Copyright (C) 2015-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2022 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -27,12 +27,14 @@ extern const keyslot_handler reenc_keyslot;
static const keyslot_handler *keyslot_handlers[LUKS2_KEYSLOTS_MAX] = {
&luks2_keyslot,
#if USE_LUKS2_REENCRYPTION
&reenc_keyslot,
#endif
NULL
};
static const keyslot_handler
*LUKS2_keyslot_handler_type(struct crypt_device *cd __attribute__((unused)), const char *type)
*LUKS2_keyslot_handler_type(const char *type)
{
int i;
@@ -62,7 +64,7 @@ static const keyslot_handler
if (!json_object_object_get_ex(jobj1, "type", &jobj2))
return NULL;
return LUKS2_keyslot_handler_type(cd, json_object_get_string(jobj2));
return LUKS2_keyslot_handler_type(json_object_get_string(jobj2));
}
int LUKS2_keyslot_find_empty(struct crypt_device *cd, struct luks2_hdr *hdr, size_t keylength)
@@ -288,19 +290,9 @@ crypt_keyslot_info LUKS2_keyslot_info(struct luks2_hdr *hdr, int keyslot)
return CRYPT_SLOT_ACTIVE;
}
int LUKS2_keyslot_area(struct luks2_hdr *hdr,
int keyslot,
uint64_t *offset,
uint64_t *length)
int LUKS2_keyslot_jobj_area(json_object *jobj_keyslot, uint64_t *offset, uint64_t *length)
{
json_object *jobj_keyslot, *jobj_area, *jobj;
if(LUKS2_keyslot_info(hdr, keyslot) == CRYPT_SLOT_INVALID)
return -EINVAL;
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
if (!jobj_keyslot)
return -ENOENT;
json_object *jobj_area, *jobj;
if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
return -EINVAL;
@@ -316,6 +308,23 @@ int LUKS2_keyslot_area(struct luks2_hdr *hdr,
return 0;
}
int LUKS2_keyslot_area(struct luks2_hdr *hdr,
int keyslot,
uint64_t *offset,
uint64_t *length)
{
json_object *jobj_keyslot;
if (LUKS2_keyslot_info(hdr, keyslot) == CRYPT_SLOT_INVALID)
return -EINVAL;
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
if (!jobj_keyslot)
return -ENOENT;
return LUKS2_keyslot_jobj_area(jobj_keyslot, offset, length);
}
static int _open_and_verify(struct crypt_device *cd,
struct luks2_hdr *hdr,
const keyslot_handler *h,
@@ -552,7 +561,7 @@ out:
if (r == -ENOMEM)
log_err(cd, _("Not enough available memory to open a keyslot."));
else if (r != -EPERM)
else if (r != -EPERM && r != -ENOENT)
log_err(cd, _("Keyslot open failed."));
}
return r;
@@ -589,48 +598,13 @@ int LUKS2_keyslot_open(struct crypt_device *cd,
if (r < 0) {
if (r == -ENOMEM)
log_err(cd, _("Not enough available memory to open a keyslot."));
else if (r != -EPERM)
else if (r != -EPERM && r != -ENOENT)
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;
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,
@@ -669,7 +643,7 @@ int LUKS2_keyslot_store(struct crypt_device *cd,
if (!LUKS2_get_keyslot_jobj(hdr, keyslot)) {
/* Try to allocate default and empty keyslot type */
h = LUKS2_keyslot_handler_type(cd, "luks2");
h = LUKS2_keyslot_handler_type("luks2");
if (!h)
return -EINVAL;
@@ -775,8 +749,7 @@ int LUKS2_keyslot_dump(struct crypt_device *cd, int keyslot)
return h->dump(cd, keyslot);
}
crypt_keyslot_priority LUKS2_keyslot_priority_get(struct crypt_device *cd __attribute__((unused)),
struct luks2_hdr *hdr, int keyslot)
crypt_keyslot_priority LUKS2_keyslot_priority_get(struct luks2_hdr *hdr, int keyslot)
{
json_object *jobj_keyslot, *jobj_priority;
@@ -810,8 +783,7 @@ int LUKS2_keyslot_priority_set(struct crypt_device *cd, struct luks2_hdr *hdr,
int placeholder_keyslot_alloc(struct crypt_device *cd,
int keyslot,
uint64_t area_offset,
uint64_t area_length,
size_t volume_key_len __attribute__((unused)))
uint64_t area_length)
{
struct luks2_hdr *hdr;
json_object *jobj_keyslots, *jobj_keyslot, *jobj_area;
@@ -878,14 +850,21 @@ int LUKS2_keyslots_validate(struct crypt_device *cd, json_object *hdr_jobj)
const keyslot_handler *h;
int keyslot;
json_object *jobj_keyslots, *jobj_type;
uint32_t reqs, reencrypt_count = 0;
struct luks2_hdr dummy = {
.jobj = hdr_jobj
};
if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
return -EINVAL;
if (LUKS2_config_get_requirements(cd, &dummy, &reqs))
return -EINVAL;
json_object_object_foreach(jobj_keyslots, slot, val) {
keyslot = atoi(slot);
json_object_object_get_ex(val, "type", &jobj_type);
h = LUKS2_keyslot_handler_type(cd, json_object_get_string(jobj_type));
h = LUKS2_keyslot_handler_type(json_object_get_string(jobj_type));
if (!h)
continue;
if (h->validate && h->validate(cd, val)) {
@@ -897,6 +876,24 @@ int LUKS2_keyslots_validate(struct crypt_device *cd, json_object *hdr_jobj)
log_dbg(cd, "Keyslot %d is not assigned to exactly 1 digest.", keyslot);
return -EINVAL;
}
if (!strcmp(h->name, "reencrypt"))
reencrypt_count++;
}
if ((reqs & CRYPT_REQUIREMENT_ONLINE_REENCRYPT) && reencrypt_count == 0) {
log_dbg(cd, "Missing reencryption keyslot.");
return -EINVAL;
}
if (reencrypt_count && !LUKS2_reencrypt_requirement_candidate(&dummy)) {
log_dbg(cd, "Missing reencryption requirement flag.");
return -EINVAL;
}
if (reencrypt_count > 1) {
log_dbg(cd, "Too many reencryption keyslots.");
return -EINVAL;
}
return 0;
@@ -914,9 +911,9 @@ void LUKS2_keyslots_repair(struct crypt_device *cd, json_object *jobj_keyslots)
!json_object_is_type(jobj_type, json_type_string))
continue;
h = LUKS2_keyslot_handler_type(cd, json_object_get_string(jobj_type));
h = LUKS2_keyslot_handler_type(json_object_get_string(jobj_type));
if (h && h->repair)
h->repair(cd, val);
h->repair(val);
}
}

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, LUKS2 type keyslot handler
*
* Copyright (C) 2015-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2021 Milan Broz
* Copyright (C) 2015-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2022 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -142,10 +142,11 @@ static int luks2_decrypt_from_storage(char *dst, size_t dstLength,
}
static int luks2_keyslot_get_pbkdf_params(json_object *jobj_keyslot,
struct crypt_pbkdf_type *pbkdf, char *salt)
struct crypt_pbkdf_type *pbkdf, char **salt)
{
json_object *jobj_kdf, *jobj1, *jobj2;
size_t salt_len;
int r;
if (!jobj_keyslot || !pbkdf)
return -EINVAL;
@@ -181,13 +182,16 @@ static int luks2_keyslot_get_pbkdf_params(json_object *jobj_keyslot,
if (!json_object_object_get_ex(jobj_kdf, "salt", &jobj2))
return -EINVAL;
salt_len = LUKS_SALTSIZE;
if (!base64_decode(json_object_get_string(jobj2),
json_object_get_string_len(jobj2),
salt, &salt_len))
return -EINVAL;
if (salt_len != LUKS_SALTSIZE)
r = crypt_base64_decode(salt, &salt_len, json_object_get_string(jobj2),
json_object_get_string_len(jobj2));
if (r < 0)
return r;
if (salt_len != LUKS_SALTSIZE) {
free(*salt);
return -EINVAL;
}
return 0;
}
@@ -198,7 +202,7 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
const char *volume_key, size_t volume_key_len)
{
struct volume_key *derived_key;
char salt[LUKS_SALTSIZE], cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
char *salt = NULL, cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
char *AfKey = NULL;
const char *af_hash = NULL;
size_t AFEKSize, keyslot_key_len;
@@ -236,23 +240,28 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
return -EINVAL;
af_hash = json_object_get_string(jobj2);
if (luks2_keyslot_get_pbkdf_params(jobj_keyslot, &pbkdf, salt))
return -EINVAL;
r = luks2_keyslot_get_pbkdf_params(jobj_keyslot, &pbkdf, &salt);
if (r < 0)
return r;
/*
* Allocate derived key storage.
*/
derived_key = crypt_alloc_volume_key(keyslot_key_len, NULL);
if (!derived_key)
if (!derived_key) {
free(salt);
return -ENOMEM;
}
/*
* Calculate keyslot content, split and store it to keyslot area.
*/
log_dbg(cd, "Running keyslot key derivation.");
r = crypt_pbkdf(pbkdf.type, pbkdf.hash, password, passwordLen,
salt, LUKS_SALTSIZE,
derived_key->key, derived_key->keylength,
pbkdf.iterations, pbkdf.max_memory_kb,
pbkdf.parallel_threads);
free(salt);
if (r < 0) {
crypt_free_volume_key(derived_key);
return r;
@@ -269,7 +278,7 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
r = AF_split(cd, volume_key, AfKey, volume_key_len, LUKS_STRIPES, af_hash);
if (r == 0) {
log_dbg(cd, "Updating keyslot area [0x%04x].", (unsigned)area_offset);
log_dbg(cd, "Updating keyslot area [0x%04" PRIx64 "].", area_offset);
/* FIXME: sector_offset should be size_t, fix LUKS_encrypt... accordingly */
r = luks2_encrypt_to_storage(AfKey, AFEKSize, cipher, cipher_mode,
derived_key, (unsigned)(area_offset / SECTOR_SIZE), cd);
@@ -288,12 +297,12 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
const char *password, size_t passwordLen,
char *volume_key, size_t volume_key_len)
{
struct volume_key *derived_key;
struct volume_key *derived_key = NULL;
struct crypt_pbkdf_type pbkdf;
char *AfKey;
char *AfKey = NULL;
size_t AFEKSize;
const char *af_hash = NULL;
char salt[LUKS_SALTSIZE], cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
char *salt = NULL, cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
json_object *jobj2, *jobj_af, *jobj_area;
uint64_t area_offset;
size_t keyslot_key_len;
@@ -304,9 +313,6 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
return -EINVAL;
if (luks2_keyslot_get_pbkdf_params(jobj_keyslot, &pbkdf, salt))
return -EINVAL;
if (!json_object_object_get_ex(jobj_af, "hash", &jobj2))
return -EINVAL;
af_hash = json_object_get_string(jobj2);
@@ -325,29 +331,38 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
return -EINVAL;
keyslot_key_len = json_object_get_int(jobj2);
r = luks2_keyslot_get_pbkdf_params(jobj_keyslot, &pbkdf, &salt);
if (r < 0)
return r;
/*
* Allocate derived key storage space.
*/
derived_key = crypt_alloc_volume_key(keyslot_key_len, NULL);
if (!derived_key) {
r = -ENOMEM;
goto out;
}
AFEKSize = AF_split_sectors(volume_key_len, LUKS_STRIPES) * SECTOR_SIZE;
AfKey = crypt_safe_alloc(AFEKSize);
if (!AfKey) {
r = -ENOMEM;
goto out;
}
/*
* 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.
*/
derived_key = crypt_alloc_volume_key(keyslot_key_len, NULL);
if (!derived_key)
return -ENOMEM;
if (try_serialize_lock && (r = crypt_serialize_lock(cd)))
goto out;
AFEKSize = AF_split_sectors(volume_key_len, LUKS_STRIPES) * SECTOR_SIZE;
AfKey = crypt_safe_alloc(AFEKSize);
if (!AfKey) {
crypt_free_volume_key(derived_key);
return -ENOMEM;
}
/*
* Calculate derived key, decrypt keyslot content and merge it.
*/
log_dbg(cd, "Running keyslot key derivation.");
r = crypt_pbkdf(pbkdf.type, pbkdf.hash, password, passwordLen,
salt, LUKS_SALTSIZE,
derived_key->key, derived_key->keylength,
@@ -358,15 +373,16 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
crypt_serialize_unlock(cd);
if (r == 0) {
log_dbg(cd, "Reading keyslot area [0x%04x].", (unsigned)area_offset);
log_dbg(cd, "Reading keyslot area [0x%04" PRIx64 "].", area_offset);
/* FIXME: sector_offset should be size_t, fix LUKS_decrypt... accordingly */
r = luks2_decrypt_from_storage(AfKey, AFEKSize, cipher, cipher_mode,
derived_key, (unsigned)(area_offset / SECTOR_SIZE), cd);
}
if (r == 0)
r = AF_merge(cd, AfKey, volume_key, volume_key_len, LUKS_STRIPES, af_hash);
r = AF_merge(AfKey, volume_key, volume_key_len, LUKS_STRIPES, af_hash);
out:
free(salt);
crypt_free_volume_key(derived_key);
crypt_safe_free(AfKey);
@@ -427,9 +443,9 @@ static int luks2_keyslot_update_json(struct crypt_device *cd,
r = crypt_random_get(cd, salt, LUKS_SALTSIZE, CRYPT_RND_SALT);
if (r < 0)
return r;
base64_encode_alloc(salt, LUKS_SALTSIZE, &salt_base64);
if (!salt_base64)
return -ENOMEM;
r = crypt_base64_encode(&salt_base64, NULL, salt, LUKS_SALTSIZE);
if (r < 0)
return r;
json_object_object_add(jobj_kdf, "salt", json_object_new_string(salt_base64));
free(salt_base64);
@@ -657,50 +673,56 @@ static int luks2_keyslot_validate(struct crypt_device *cd, json_object *jobj_key
if (!jobj_keyslot)
return -EINVAL;
if (!json_object_object_get_ex(jobj_keyslot, "kdf", &jobj_kdf) ||
!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af) ||
!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
if (!(jobj_kdf = json_contains(cd, jobj_keyslot, "", "keyslot", "kdf", json_type_object)) ||
!(jobj_af = json_contains(cd, jobj_keyslot, "", "keyslot", "af", json_type_object)) ||
!(jobj_area = json_contains(cd, jobj_keyslot, "", "keyslot", "area", json_type_object)))
return -EINVAL;
count = json_object_object_length(jobj_kdf);
jobj1 = json_contains(cd, jobj_kdf, "", "kdf section", "type", json_type_string);
jobj1 = json_contains_string(cd, jobj_kdf, "", "kdf section", "type");
if (!jobj1)
return -EINVAL;
type = json_object_get_string(jobj1);
if (!strcmp(type, CRYPT_KDF_PBKDF2)) {
if (count != 4 || /* type, salt, hash, iterations only */
!json_contains(cd, jobj_kdf, "kdf type", type, "hash", json_type_string) ||
!json_contains_string(cd, jobj_kdf, "kdf type", type, "hash") ||
!json_contains(cd, jobj_kdf, "kdf type", type, "iterations", json_type_int) ||
!json_contains(cd, jobj_kdf, "kdf type", type, "salt", json_type_string))
!json_contains_string(cd, jobj_kdf, "kdf type", type, "salt"))
return -EINVAL;
} else if (!strcmp(type, CRYPT_KDF_ARGON2I) || !strcmp(type, CRYPT_KDF_ARGON2ID)) {
if (count != 5 || /* type, salt, time, memory, cpus only */
!json_contains(cd, jobj_kdf, "kdf type", type, "time", json_type_int) ||
!json_contains(cd, jobj_kdf, "kdf type", type, "memory", json_type_int) ||
!json_contains(cd, jobj_kdf, "kdf type", type, "cpus", json_type_int) ||
!json_contains(cd, jobj_kdf, "kdf type", type, "salt", json_type_string))
!json_contains_string(cd, jobj_kdf, "kdf type", type, "salt"))
return -EINVAL;
}
if (!json_object_object_get_ex(jobj_af, "type", &jobj1))
jobj1 = json_contains_string(cd, jobj_af, "", "af section", "type");
if (!jobj1)
return -EINVAL;
if (!strcmp(json_object_get_string(jobj1), "luks1")) {
if (!json_contains(cd, jobj_af, "", "luks1 af", "hash", json_type_string) ||
type = json_object_get_string(jobj1);
if (!strcmp(type, "luks1")) {
if (!json_contains_string(cd, jobj_af, "", "luks1 af", "hash") ||
!json_contains(cd, jobj_af, "", "luks1 af", "stripes", json_type_int))
return -EINVAL;
} else
return -EINVAL;
// FIXME check numbered
if (!json_object_object_get_ex(jobj_area, "type", &jobj1))
jobj1 = json_contains_string(cd, jobj_area, "", "area section", "type");
if (!jobj1)
return -EINVAL;
if (!strcmp(json_object_get_string(jobj1), "raw")) {
if (!json_contains(cd, jobj_area, "area", "raw type", "encryption", json_type_string) ||
type = json_object_get_string(jobj1);
if (!strcmp(type, "raw")) {
if (!json_contains_string(cd, jobj_area, "area", "raw type", "encryption") ||
!json_contains(cd, jobj_area, "area", "raw type", "key_size", json_type_int) ||
!json_contains(cd, jobj_area, "area", "raw type", "offset", json_type_string) ||
!json_contains(cd, jobj_area, "area", "raw type", "size", json_type_string))
!json_contains_string(cd, jobj_area, "area", "raw type", "offset") ||
!json_contains_string(cd, jobj_area, "area", "raw type", "size"))
return -EINVAL;
} else
return -EINVAL;
@@ -735,7 +757,7 @@ static int luks2_keyslot_update(struct crypt_device *cd,
return r;
}
static void luks2_keyslot_repair(struct crypt_device *cd __attribute__((unused)), json_object *jobj_keyslot)
static void luks2_keyslot_repair(json_object *jobj_keyslot)
{
const char *type;
json_object *jobj_kdf, *jobj_type;

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, reencryption keyslot handler
*
* Copyright (C) 2016-2021, Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2021, Ondrej Kozina
* Copyright (C) 2016-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2022 Ondrej Kozina
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -31,10 +31,77 @@ static int reenc_keyslot_open(struct crypt_device *cd __attribute__((unused)),
return -ENOENT;
}
int reenc_keyslot_alloc(struct crypt_device *cd,
static json_object *reencrypt_keyslot_area_jobj(struct crypt_device *cd,
const struct crypt_params_reencrypt *params,
size_t alignment,
uint64_t area_offset,
uint64_t area_length)
{
json_object *jobj_area = json_object_new_object();
if (!jobj_area || !params || !params->resilience)
return NULL;
json_object_object_add(jobj_area, "offset", crypt_jobj_new_uint64(area_offset));
json_object_object_add(jobj_area, "size", crypt_jobj_new_uint64(area_length));
json_object_object_add(jobj_area, "type", json_object_new_string(params->resilience));
if (!strcmp(params->resilience, "checksum")) {
log_dbg(cd, "Setting reencrypt keyslot for checksum protection.");
json_object_object_add(jobj_area, "hash", json_object_new_string(params->hash));
json_object_object_add(jobj_area, "sector_size", json_object_new_int64(alignment));
} else if (!strcmp(params->resilience, "journal")) {
log_dbg(cd, "Setting reencrypt keyslot for journal protection.");
} else if (!strcmp(params->resilience, "none")) {
log_dbg(cd, "Setting reencrypt keyslot for none protection.");
} else if (!strcmp(params->resilience, "datashift")) {
log_dbg(cd, "Setting reencrypt keyslot for datashift protection.");
json_object_object_add(jobj_area, "shift_size",
crypt_jobj_new_uint64(params->data_shift << SECTOR_SHIFT));
} else if (!strcmp(params->resilience, "datashift-checksum")) {
log_dbg(cd, "Setting reencrypt keyslot for datashift and checksum protection.");
json_object_object_add(jobj_area, "hash", json_object_new_string(params->hash));
json_object_object_add(jobj_area, "sector_size", json_object_new_int64(alignment));
json_object_object_add(jobj_area, "shift_size",
crypt_jobj_new_uint64(params->data_shift << SECTOR_SHIFT));
} else if (!strcmp(params->resilience, "datashift-journal")) {
log_dbg(cd, "Setting reencrypt keyslot for datashift and journal protection.");
json_object_object_add(jobj_area, "shift_size",
crypt_jobj_new_uint64(params->data_shift << SECTOR_SHIFT));
} else {
json_object_put(jobj_area);
return NULL;
}
return jobj_area;
}
static json_object *reencrypt_keyslot_area_jobj_update_block_size(struct crypt_device *cd,
json_object *jobj_area, size_t alignment)
{
json_object *jobj_type, *jobj_area_new = NULL;
if (!jobj_area ||
!json_object_object_get_ex(jobj_area, "type", &jobj_type) ||
(strcmp(json_object_get_string(jobj_type), "checksum") &&
strcmp(json_object_get_string(jobj_type), "datashift-checksum")))
return NULL;
if (json_object_copy(jobj_area, &jobj_area_new))
return NULL;
log_dbg(cd, "Updating reencrypt resilience checksum block size.");
json_object_object_add(jobj_area_new, "sector_size", json_object_new_int64(alignment));
return jobj_area_new;
}
static int reenc_keyslot_alloc(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const struct crypt_params_reencrypt *params)
const struct crypt_params_reencrypt *params,
size_t alignment)
{
int r;
json_object *jobj_keyslots, *jobj_keyslot, *jobj_area;
@@ -42,50 +109,41 @@ int reenc_keyslot_alloc(struct crypt_device *cd,
log_dbg(cd, "Allocating reencrypt keyslot %d.", keyslot);
if (!params || !params->resilience || params->direction > CRYPT_REENCRYPT_BACKWARD)
return -EINVAL;
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? */
/* only plain datashift resilience mode does not require additional storage */
if (!strcmp(params->resilience, "datashift"))
r = LUKS2_find_area_gap(cd, hdr, 1, &area_offset, &area_length);
if (r < 0)
return r;
}
else
r = LUKS2_find_area_max_gap(cd, hdr, &area_offset, &area_length);
if (r < 0)
return r;
jobj_area = reencrypt_keyslot_area_jobj(cd, params, alignment, area_offset, area_length);
if (!jobj_area)
return -EINVAL;
jobj_keyslot = json_object_new_object();
if (!jobj_keyslot)
if (!jobj_keyslot) {
json_object_put(jobj_area);
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", crypt_jobj_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", crypt_jobj_new_uint64(area_offset));
json_object_object_add(jobj_area, "size", crypt_jobj_new_uint64(area_length));
}
json_object_object_add(jobj_keyslot, "area", jobj_area);
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(jobj_keyslot, "direction", json_object_new_string("backward"));
json_object_object_add_by_uint(jobj_keyslots, keyslot, jobj_keyslot);
if (LUKS2_check_json_size(cd, hdr)) {
@@ -176,9 +234,17 @@ static int reenc_keyslot_store(struct crypt_device *cd,
return r < 0 ? r : keyslot;
}
static int reenc_keyslot_wipe(struct crypt_device *cd __attribute__((unused)),
int keyslot __attribute__((unused)))
static int reenc_keyslot_wipe(struct crypt_device *cd,
int keyslot)
{
struct luks2_hdr *hdr;
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
return -EINVAL;
/* remove reencryption verification data */
LUKS2_digest_assign(cd, hdr, keyslot, CRYPT_ANY_DIGEST, 0, 0);
return 0;
}
@@ -222,7 +288,8 @@ static int reenc_keyslot_dump(struct crypt_device *cd, int keyslot)
static int reenc_keyslot_validate(struct crypt_device *cd, json_object *jobj_keyslot)
{
json_object *jobj_mode, *jobj_area, *jobj_type, *jobj_shift_size, *jobj_hash, *jobj_sector_size, *jobj_direction;
json_object *jobj_mode, *jobj_area, *jobj_type, *jobj_shift_size, *jobj_hash,
*jobj_sector_size, *jobj_direction, *jobj_key_size;
const char *mode, *type, *direction;
uint32_t sector_size;
uint64_t shift_size;
@@ -230,10 +297,10 @@ static int reenc_keyslot_validate(struct crypt_device *cd, json_object *jobj_key
/* 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)
* type: (string: datashift, journal, checksum, none, datashift-journal, datashift-checksum)
* hash: (string: checksum and datashift-checksum types)
* sector_size (uint32: checksum and datashift-checksum types)
* shift_size (uint64: all datashift based types)
* }
*/
@@ -242,12 +309,18 @@ static int reenc_keyslot_validate(struct crypt_device *cd, json_object *jobj_key
!json_object_object_get_ex(jobj_area, "type", &jobj_type))
return -EINVAL;
jobj_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);
jobj_key_size = json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "key_size", json_type_int);
jobj_mode = json_contains_string(cd, jobj_keyslot, "", "reencrypt keyslot", "mode");
jobj_direction = json_contains_string(cd, jobj_keyslot, "", "reencrypt keyslot", "direction");
if (!jobj_mode || !jobj_direction)
if (!jobj_mode || !jobj_direction || !jobj_key_size)
return -EINVAL;
if (!validate_json_uint32(jobj_key_size) || crypt_jobj_get_uint32(jobj_key_size) != 1) {
log_dbg(cd, "Illegal reencrypt key size.");
return -EINVAL;
}
mode = json_object_get_string(jobj_mode);
type = json_object_get_string(jobj_type);
direction = json_object_get_string(jobj_direction);
@@ -263,20 +336,26 @@ static int reenc_keyslot_validate(struct crypt_device *cd, json_object *jobj_key
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 (!strcmp(type, "checksum") || !strcmp(type, "datashift-checksum")) {
jobj_hash = json_contains_string(cd, jobj_area, "type:checksum",
"Keyslot area", "hash");
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 = crypt_jobj_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);
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)))
} else if (!strcmp(type, "datashift") ||
!strcmp(type, "datashift-checksum") ||
!strcmp(type, "datashift-journal")) {
if (!(jobj_shift_size = json_contains_string(cd, jobj_area, "type:datashift",
"Keyslot area", "shift_size")))
return -EINVAL;
shift_size = crypt_jobj_get_uint64(jobj_shift_size);
@@ -284,7 +363,7 @@ static int reenc_keyslot_validate(struct crypt_device *cd, json_object *jobj_key
return -EINVAL;
if (MISALIGNED_512(shift_size)) {
log_dbg(cd, "Shift size field has to be aligned to sector size: %" PRIu32, SECTOR_SIZE);
log_dbg(cd, "Shift size field has to be aligned to 512 bytes.");
return -EINVAL;
}
}
@@ -292,6 +371,377 @@ static int reenc_keyslot_validate(struct crypt_device *cd, json_object *jobj_key
return 0;
}
static int reenc_keyslot_update_needed(struct crypt_device *cd,
json_object *jobj_keyslot,
const struct crypt_params_reencrypt *params,
size_t alignment)
{
const char *type;
json_object *jobj_area, *jobj_type, *jobj;
if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
!json_object_object_get_ex(jobj_area, "type", &jobj_type) ||
!(type = json_object_get_string(jobj_type)))
return -EINVAL;
/*
* If no resilience mode change is requested and effective
* resilience mode is 'checksum' then check alignment matches
* stored checksum block size.
*/
if (!params || !params->resilience) {
if (!strcmp(json_object_get_string(jobj_type), "checksum") ||
!strcmp(json_object_get_string(jobj_type), "datashift-checksum"))
return (json_object_object_get_ex(jobj_area, "sector_size", &jobj) ||
alignment != crypt_jobj_get_uint32(jobj));
return 0;
}
if (strcmp(params->resilience, type))
return 1;
if (!strcmp(type, "checksum") ||
!strcmp(type, "datashift-checksum")) {
if (!params->hash)
return -EINVAL;
if (!json_object_object_get_ex(jobj_area, "hash", &jobj) ||
strcmp(json_object_get_string(jobj), params->hash) ||
!json_object_object_get_ex(jobj_area, "sector_size", &jobj) ||
crypt_jobj_get_uint32(jobj) != alignment)
return 1;
}
if (!strncmp(type, "datashift", 9)) {
if (!json_object_object_get_ex(jobj_area, "shift_size", &jobj))
return -EINVAL;
if ((params->data_shift << SECTOR_SHIFT) != crypt_jobj_get_uint64(jobj))
return 1;
}
/* nothing to compare with 'none' and 'journal' */
return 0;
}
static int load_checksum_protection(struct crypt_device *cd,
json_object *jobj_area,
uint64_t area_length,
struct reenc_protection *rp)
{
int r;
json_object *jobj_hash, *jobj_block_size;
if (!jobj_area || !rp ||
!json_object_object_get_ex(jobj_area, "hash", &jobj_hash) ||
!json_object_object_get_ex(jobj_area, "sector_size", &jobj_block_size))
return -EINVAL;
r = snprintf(rp->p.csum.hash, sizeof(rp->p.csum.hash), "%s", json_object_get_string(jobj_hash));
if (r < 0 || (size_t)r >= sizeof(rp->p.csum.hash))
return -EINVAL;
if (crypt_hash_init(&rp->p.csum.ch, rp->p.csum.hash)) {
log_err(cd, _("Hash algorithm %s is not available."), rp->p.csum.hash);
return -EINVAL;
}
r = crypt_hash_size(rp->p.csum.hash);
if (r <= 0) {
crypt_hash_destroy(rp->p.csum.ch);
rp->p.csum.ch = NULL;
log_dbg(cd, "Invalid hash size");
return -EINVAL;
}
rp->p.csum.hash_size = r;
rp->p.csum.block_size = crypt_jobj_get_uint32(jobj_block_size);
rp->p.csum.checksums_len = area_length;
rp->type = REENC_PROTECTION_CHECKSUM;
return 0;
}
static int reenc_keyslot_load_resilience_primary(struct crypt_device *cd,
const char *type,
json_object *jobj_area,
uint64_t area_length,
struct reenc_protection *rp)
{
json_object *jobj;
if (!strcmp(type, "checksum")) {
log_dbg(cd, "Initializing checksum resilience mode.");
return load_checksum_protection(cd, jobj_area, area_length, rp);
} else if (!strcmp(type, "journal")) {
log_dbg(cd, "Initializing journal resilience mode.");
rp->type = REENC_PROTECTION_JOURNAL;
} else if (!strcmp(type, "none")) {
log_dbg(cd, "Initializing none resilience mode.");
rp->type = REENC_PROTECTION_NONE;
} else if (!strcmp(type, "datashift") ||
!strcmp(type, "datashift-checksum") ||
!strcmp(type, "datashift-journal")) {
log_dbg(cd, "Initializing datashift resilience mode.");
if (!json_object_object_get_ex(jobj_area, "shift_size", &jobj))
return -EINVAL;
rp->type = REENC_PROTECTION_DATASHIFT;
rp->p.ds.data_shift = crypt_jobj_get_uint64(jobj);
} else
return -EINVAL;
return 0;
}
static int reenc_keyslot_load_resilience_secondary(struct crypt_device *cd,
const char *type,
json_object *jobj_area,
uint64_t area_length,
struct reenc_protection *rp)
{
if (!strcmp(type, "datashift-checksum")) {
log_dbg(cd, "Initializing checksum resilience mode.");
return load_checksum_protection(cd, jobj_area, area_length, rp);
} else if (!strcmp(type, "datashift-journal")) {
log_dbg(cd, "Initializing journal resilience mode.");
rp->type = REENC_PROTECTION_JOURNAL;
} else
rp->type = REENC_PROTECTION_NOT_SET;
return 0;
}
static int reenc_keyslot_load_resilience(struct crypt_device *cd,
json_object *jobj_keyslot,
struct reenc_protection *rp,
bool primary)
{
const char *type;
int r;
json_object *jobj_area, *jobj_type;
uint64_t dummy, area_length;
if (!rp || !json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
!json_object_object_get_ex(jobj_area, "type", &jobj_type))
return -EINVAL;
r = LUKS2_keyslot_jobj_area(jobj_keyslot, &dummy, &area_length);
if (r < 0)
return r;
type = json_object_get_string(jobj_type);
if (!type)
return -EINVAL;
if (primary)
return reenc_keyslot_load_resilience_primary(cd, type, jobj_area, area_length, rp);
else
return reenc_keyslot_load_resilience_secondary(cd, type, jobj_area, area_length, rp);
}
static bool reenc_keyslot_update_is_valid(struct crypt_device *cd,
json_object *jobj_area,
const struct crypt_params_reencrypt *params)
{
const char *type;
json_object *jobj_type, *jobj;
if (!json_object_object_get_ex(jobj_area, "type", &jobj_type) ||
!(type = json_object_get_string(jobj_type)))
return false;
/* do not allow switch to/away from datashift resilience type */
if ((strcmp(params->resilience, "datashift") && !strcmp(type, "datashift")) ||
(!strcmp(params->resilience, "datashift") && strcmp(type, "datashift")))
return false;
/* do not allow switch to/away from datashift- resilience subvariants */
if ((strncmp(params->resilience, "datashift-", 10) &&
!strncmp(type, "datashift-", 10)) ||
(!strncmp(params->resilience, "datashift-", 10) &&
strncmp(type, "datashift-", 10)))
return false;
/* datashift value is also immutable */
if (!strncmp(type, "datashift", 9)) {
if (!json_object_object_get_ex(jobj_area, "shift_size", &jobj))
return false;
return (params->data_shift << SECTOR_SHIFT) == crypt_jobj_get_uint64(jobj);
}
return true;
}
static int reenc_keyslot_update(struct crypt_device *cd,
json_object *jobj_keyslot,
const struct crypt_params_reencrypt *params,
size_t alignment)
{
int r;
json_object *jobj_area, *jobj_area_new;
uint64_t area_offset, area_length;
if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
return -EINVAL;
r = LUKS2_keyslot_jobj_area(jobj_keyslot, &area_offset, &area_length);
if (r < 0)
return r;
if (!params || !params->resilience)
jobj_area_new = reencrypt_keyslot_area_jobj_update_block_size(cd, jobj_area, alignment);
else {
if (!reenc_keyslot_update_is_valid(cd, jobj_area, params)) {
log_err(cd, _("Invalid reencryption resilience mode change requested."));
return -EINVAL;
}
jobj_area_new = reencrypt_keyslot_area_jobj(cd, params, alignment,
area_offset, area_length);
}
if (!jobj_area_new)
return -EINVAL;
/* increase refcount for validation purposes */
json_object_get(jobj_area);
json_object_object_add(jobj_keyslot, "area", jobj_area_new);
r = reenc_keyslot_validate(cd, jobj_keyslot);
if (r) {
/* replace invalid object with previous valid one */
json_object_object_add(jobj_keyslot, "area", jobj_area);
return -EINVAL;
}
/* previous area object is no longer needed */
json_object_put(jobj_area);
return 0;
}
int LUKS2_keyslot_reencrypt_allocate(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const struct crypt_params_reencrypt *params,
size_t alignment)
{
int r;
if (keyslot == CRYPT_ANY_SLOT)
return -EINVAL;
r = reenc_keyslot_alloc(cd, hdr, keyslot, params, alignment);
if (r < 0)
return r;
r = LUKS2_keyslot_priority_set(cd, hdr, keyslot, CRYPT_SLOT_PRIORITY_IGNORE, 0);
if (r < 0)
return r;
r = reenc_keyslot_validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot));
if (r) {
log_dbg(cd, "Keyslot validation failed.");
return r;
}
return 0;
}
int LUKS2_keyslot_reencrypt_update_needed(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const struct crypt_params_reencrypt *params,
size_t alignment)
{
int r;
json_object *jobj_type, *jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
if (!jobj_keyslot ||
!json_object_object_get_ex(jobj_keyslot, "type", &jobj_type) ||
strcmp(json_object_get_string(jobj_type), "reencrypt"))
return -EINVAL;
r = reenc_keyslot_update_needed(cd, jobj_keyslot, params, alignment);
if (!r)
log_dbg(cd, "No update of reencrypt keyslot needed.");
return r;
}
int LUKS2_keyslot_reencrypt_update(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const struct crypt_params_reencrypt *params,
size_t alignment,
struct volume_key *vks)
{
int r;
uint8_t version;
uint64_t max_size, moved_segment_size;
json_object *jobj_type, *jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
struct reenc_protection check_rp = {};
if (!jobj_keyslot ||
!json_object_object_get_ex(jobj_keyslot, "type", &jobj_type) ||
strcmp(json_object_get_string(jobj_type), "reencrypt"))
return -EINVAL;
if (LUKS2_config_get_reencrypt_version(hdr, &version))
return -EINVAL;
/* verify existing reencryption metadata before updating */
r = LUKS2_reencrypt_digest_verify(cd, hdr, vks);
if (r < 0)
return r;
r = reenc_keyslot_update(cd, jobj_keyslot, params, alignment);
if (r < 0)
return r;
r = reenc_keyslot_load_resilience(cd, jobj_keyslot, &check_rp, false);
if (r < 0)
return r;
if (check_rp.type != REENC_PROTECTION_NOT_SET) {
r = LUKS2_reencrypt_max_hotzone_size(cd, hdr, &check_rp, keyslot, &max_size);
LUKS2_reencrypt_protection_erase(&check_rp);
if (r < 0)
return r;
moved_segment_size = json_segment_get_size(LUKS2_get_segment_by_flag(hdr, "backup-moved-segment"), 0);
if (!moved_segment_size)
return -EINVAL;
if (moved_segment_size > max_size) {
log_err(cd, _("Can not update resilience type. "
"New type only provides %" PRIu64 " bytes, "
"required space is: %" PRIu64 " bytes."),
max_size, moved_segment_size);
return -EINVAL;
}
}
r = LUKS2_keyslot_reencrypt_digest_create(cd, hdr, version, vks);
if (r < 0)
log_err(cd, _("Failed to refresh reencryption verification digest."));
return r ?: LUKS2_hdr_write(cd, hdr);
}
int LUKS2_keyslot_reencrypt_load(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
struct reenc_protection *rp,
bool primary)
{
json_object *jobj_type, *jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
if (!jobj_keyslot ||
!json_object_object_get_ex(jobj_keyslot, "type", &jobj_type) ||
strcmp(json_object_get_string(jobj_type), "reencrypt"))
return -EINVAL;
return reenc_keyslot_load_resilience(cd, jobj_keyslot, rp, primary);
}
const keyslot_handler reenc_keyslot = {
.name = "reencrypt",
.open = reenc_keyslot_open,

View File

@@ -1,9 +1,9 @@
/*
* LUKS - Linux Unified Key Setup v2, LUKS1 conversion code
*
* Copyright (C) 2015-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2021 Ondrej Kozina
* Copyright (C) 2015-2021 Milan Broz
* Copyright (C) 2015-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2022 Ondrej Kozina
* Copyright (C) 2015-2022 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -24,12 +24,38 @@
#include "../luks1/luks.h"
#include "../luks1/af.h"
/* This differs from LUKS_check_cipher() that it does not check dm-crypt fallback. */
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);
int r;
struct crypt_storage *s;
char buf[SECTOR_SIZE], *empty_key;
log_dbg(cd, "Checking if cipher %s-%s is usable (storage wrapper).", cipher, cipher_mode);
empty_key = crypt_safe_alloc(keylength);
if (!empty_key)
return -ENOMEM;
/* No need to get KEY quality random but it must avoid known weak keys. */
r = crypt_random_get(cd, empty_key, keylength, CRYPT_RND_NORMAL);
if (r < 0)
goto out;
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode, empty_key, keylength, false);
if (r < 0)
goto out;
memset(buf, 0, sizeof(buf));
r = crypt_storage_decrypt(s, 0, sizeof(buf), buf);
crypt_storage_destroy(s);
out:
crypt_safe_free(empty_key);
crypt_safe_memzero(buf, sizeof(buf));
return r;
}
static int json_luks1_keyslot(const struct luks_phdr *hdr_v1, int keyslot, struct json_object **keyslot_object)
@@ -37,7 +63,8 @@ static int json_luks1_keyslot(const struct luks_phdr *hdr_v1, int keyslot, struc
char *base64_str, cipher[LUKS_CIPHERNAME_L+LUKS_CIPHERMODE_L];
size_t base64_len;
struct json_object *keyslot_obj, *field, *jobj_kdf, *jobj_af, *jobj_area;
uint64_t offset, area_size, offs_a, offs_b, length;
uint64_t offset, area_size, length;
int r;
keyslot_obj = json_object_new_object();
json_object_object_add(keyslot_obj, "type", json_object_new_string("luks2"));
@@ -49,13 +76,11 @@ static int json_luks1_keyslot(const struct luks_phdr *hdr_v1, int keyslot, struc
json_object_object_add(jobj_kdf, "hash", json_object_new_string(hdr_v1->hashSpec));
json_object_object_add(jobj_kdf, "iterations", json_object_new_int64(hdr_v1->keyblock[keyslot].passwordIterations));
/* salt field */
base64_len = base64_encode_alloc(hdr_v1->keyblock[keyslot].passwordSalt, LUKS_SALTSIZE, &base64_str);
if (!base64_str) {
r = crypt_base64_encode(&base64_str, &base64_len, hdr_v1->keyblock[keyslot].passwordSalt, LUKS_SALTSIZE);
if (r < 0) {
json_object_put(keyslot_obj);
json_object_put(jobj_kdf);
if (!base64_len)
return -EINVAL;
return -ENOMEM;
return r;
}
field = json_object_new_string_len(base64_str, base64_len);
free(base64_str);
@@ -67,7 +92,7 @@ static int json_luks1_keyslot(const struct luks_phdr *hdr_v1, int keyslot, struc
json_object_object_add(jobj_af, "type", json_object_new_string("luks1"));
json_object_object_add(jobj_af, "hash", json_object_new_string(hdr_v1->hashSpec));
/* stripes field ignored, fixed to LUKS_STRIPES (4000) */
json_object_object_add(jobj_af, "stripes", json_object_new_int(4000));
json_object_object_add(jobj_af, "stripes", json_object_new_int(LUKS_STRIPES));
json_object_object_add(keyslot_obj, "af", jobj_af);
/* Area */
@@ -76,20 +101,22 @@ static int json_luks1_keyslot(const struct luks_phdr *hdr_v1, int keyslot, struc
/* encryption algorithm field */
if (*hdr_v1->cipherMode != '\0') {
(void) snprintf(cipher, sizeof(cipher), "%s-%s", hdr_v1->cipherName, hdr_v1->cipherMode);
if (snprintf(cipher, sizeof(cipher), "%s-%s", hdr_v1->cipherName, hdr_v1->cipherMode) < 0) {
json_object_put(keyslot_obj);
json_object_put(jobj_area);
return -EINVAL;
}
json_object_object_add(jobj_area, "encryption", json_object_new_string(cipher));
} else
json_object_object_add(jobj_area, "encryption", json_object_new_string(hdr_v1->cipherName));
/* area */
if (LUKS_keyslot_area(hdr_v1, 0, &offs_a, &length) ||
LUKS_keyslot_area(hdr_v1, 1, &offs_b, &length) ||
LUKS_keyslot_area(hdr_v1, keyslot, &offset, &length)) {
if (LUKS_keyslot_area(hdr_v1, keyslot, &offset, &length)) {
json_object_put(keyslot_obj);
json_object_put(jobj_area);
return -EINVAL;
}
area_size = offs_b - offs_a;
area_size = size_round_up(length, 4096);
json_object_object_add(jobj_area, "key_size", json_object_new_int(hdr_v1->keyBytes));
json_object_object_add(jobj_area, "offset", crypt_jobj_new_uint64(offset));
json_object_object_add(jobj_area, "size", crypt_jobj_new_uint64(area_size));
@@ -170,7 +197,10 @@ static int json_luks1_segment(const struct luks_phdr *hdr_v1, struct json_object
/* cipher field */
if (*hdr_v1->cipherMode != '\0') {
(void) snprintf(cipher, sizeof(cipher), "%s-%s", hdr_v1->cipherName, hdr_v1->cipherMode);
if (snprintf(cipher, sizeof(cipher), "%s-%s", hdr_v1->cipherName, hdr_v1->cipherMode) < 0) {
json_object_put(segment_obj);
return -EINVAL;
}
c = cipher;
} else
c = hdr_v1->cipherName;
@@ -216,8 +246,8 @@ static int json_luks1_segments(const struct luks_phdr *hdr_v1, struct json_objec
static int json_luks1_digest(const struct luks_phdr *hdr_v1, struct json_object **digest_object)
{
char keyslot_str[2], *base64_str;
int ks;
char keyslot_str[16], *base64_str;
int r, ks;
size_t base64_len;
struct json_object *digest_obj, *array, *field;
@@ -244,7 +274,12 @@ static int json_luks1_digest(const struct luks_phdr *hdr_v1, struct json_object
for (ks = 0; ks < LUKS_NUMKEYS; ks++) {
if (hdr_v1->keyblock[ks].active != LUKS_KEY_ENABLED)
continue;
(void) snprintf(keyslot_str, sizeof(keyslot_str), "%d", ks);
if (snprintf(keyslot_str, sizeof(keyslot_str), "%d", ks) < 0) {
json_object_put(field);
json_object_put(array);
json_object_put(digest_obj);
return -EINVAL;
}
field = json_object_new_string(keyslot_str);
if (!field || json_object_array_add(array, field) < 0) {
@@ -284,12 +319,10 @@ static int json_luks1_digest(const struct luks_phdr *hdr_v1, struct json_object
json_object_object_add(digest_obj, "hash", field);
/* salt field */
base64_len = base64_encode_alloc(hdr_v1->mkDigestSalt, LUKS_SALTSIZE, &base64_str);
if (!base64_str) {
r = crypt_base64_encode(&base64_str, &base64_len, hdr_v1->mkDigestSalt, LUKS_SALTSIZE);
if (r < 0) {
json_object_put(digest_obj);
if (!base64_len)
return -EINVAL;
return -ENOMEM;
return r;
}
field = json_object_new_string_len(base64_str, base64_len);
@@ -301,12 +334,10 @@ static int json_luks1_digest(const struct luks_phdr *hdr_v1, struct json_object
json_object_object_add(digest_obj, "salt", field);
/* digest field */
base64_len = base64_encode_alloc(hdr_v1->mkDigest, LUKS_DIGESTSIZE, &base64_str);
if (!base64_str) {
r = crypt_base64_encode(&base64_str, &base64_len, hdr_v1->mkDigest, LUKS_DIGESTSIZE);
if (r < 0) {
json_object_put(digest_obj);
if (!base64_len)
return -EINVAL;
return -ENOMEM;
return r;
}
field = json_object_new_string_len(base64_str, base64_len);
@@ -424,7 +455,6 @@ static void move_keyslot_offset(json_object *jobj, int offset_add)
}
}
/* FIXME: return specific error code for partial write error (aka keyslots are gone) */
static int move_keyslot_areas(struct crypt_device *cd, off_t offset_from,
off_t offset_to, size_t buf_size)
{
@@ -535,6 +565,12 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
return -EINVAL;
}
if (LUKS2_check_cipher(cd, hdr1->keyBytes, hdr1->cipherName, hdr1->cipherMode)) {
log_err(cd, _("Unable to use cipher specification %s-%s for LUKS2."),
hdr1->cipherName, hdr1->cipherMode);
return -EINVAL;
}
if (luksmeta_header_present(cd, luks1_size))
return -EINVAL;
@@ -558,7 +594,7 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
move_keyslot_offset(jobj, luks1_shift);
// fill hdr2
/* Create and fill LUKS2 hdr */
memset(hdr2, 0, sizeof(*hdr2));
hdr2->hdr_size = LUKS2_HDR_16K_LEN;
hdr2->seqid = 1;
@@ -580,6 +616,7 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
/* check future LUKS2 metadata before moving keyslots area */
if (LUKS2_hdr_validate(cd, hdr2->jobj, hdr2->hdr_size - LUKS2_HDR_BIN_LEN)) {
log_err(cd, _("Cannot convert to LUKS2 format - invalid metadata."));
r = -EINVAL;
goto out;
}
@@ -590,7 +627,7 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
goto out;
}
// move keyslots 4k -> 32k offset
/* move keyslots 4k -> 32k offset */
buf_offset = 2 * LUKS2_HDR_16K_LEN;
buf_size = luks1_size - LUKS_ALIGN_KEYSLOTS;
@@ -606,7 +643,7 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
goto out;
}
// Write JSON hdr2
/* Write new LUKS2 JSON */
r = LUKS2_hdr_write(cd, hdr2);
out:
LUKS2_hdr_free(cd, hdr2);
@@ -651,8 +688,6 @@ static int keyslot_LUKS1_compatible(struct crypt_device *cd, struct luks2_hdr *h
strcmp(json_object_get_string(jobj), hash))
return 0;
/* FIXME: should this go to validation code instead (aka invalid luks2 header if assigned to segment 0)? */
/* FIXME: check all keyslots are assigned to segment id 0, and segments count == 1 */
ks_cipher = LUKS2_get_keyslot_cipher(hdr, keyslot, &ks_key_size);
data_cipher = LUKS2_get_cipher(hdr, CRYPT_DEFAULT_SEGMENT);
if (!ks_cipher || !data_cipher || key_size != ks_key_size || strcmp(ks_cipher, data_cipher)) {
@@ -676,14 +711,14 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
{
size_t buf_size, buf_offset;
char cipher[LUKS_CIPHERNAME_L], cipher_mode[LUKS_CIPHERMODE_L];
char digest[LUKS_DIGESTSIZE], digest_salt[LUKS_SALTSIZE];
char *digest, *digest_salt;
const char *hash;
size_t len;
json_object *jobj_keyslot, *jobj_digest, *jobj_segment, *jobj_kdf, *jobj_area, *jobj1, *jobj2;
uint32_t key_size;
int i, r, last_active = 0;
uint64_t offset, area_length;
char buf[256], luksMagic[] = LUKS_MAGIC;
char *buf, luksMagic[] = LUKS_MAGIC;
jobj_digest = LUKS2_get_digest_jobj(hdr2, 0);
if (!jobj_digest)
@@ -718,6 +753,11 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
return -EINVAL;
}
if (json_segments_count(LUKS2_get_segments_jobj(hdr2)) != 1) {
log_err(cd, _("Cannot convert to LUKS1 format - device uses more segments."));
return -EINVAL;
}
r = LUKS2_tokens_count(hdr2);
if (r < 0)
return r;
@@ -773,7 +813,7 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
* inactive keyslots. Otherwise we would allocate all
* inactive luks1 keyslots over same binary keyslot area.
*/
if (placeholder_keyslot_alloc(cd, i, offset, area_length, key_size))
if (placeholder_keyslot_alloc(cd, i, offset, area_length))
return -EINVAL;
}
@@ -800,14 +840,16 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
if (!json_object_object_get_ex(jobj_kdf, "salt", &jobj1))
continue;
len = sizeof(buf);
memset(buf, 0, len);
if (!base64_decode(json_object_get_string(jobj1),
json_object_get_string_len(jobj1), buf, &len))
if (crypt_base64_decode(&buf, &len, json_object_get_string(jobj1),
json_object_get_string_len(jobj1)))
continue;
if (len > 0 && len != LUKS_SALTSIZE)
if (len > 0 && len != LUKS_SALTSIZE) {
free(buf);
continue;
}
memcpy(hdr1->keyblock[i].passwordSalt, buf, LUKS_SALTSIZE);
free(buf);
}
if (!jobj_keyslot) {
@@ -843,31 +885,36 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
if (!json_object_object_get_ex(jobj_digest, "digest", &jobj1))
return -EINVAL;
len = sizeof(digest);
if (!base64_decode(json_object_get_string(jobj1),
json_object_get_string_len(jobj1), digest, &len))
return -EINVAL;
r = crypt_base64_decode(&digest, &len, json_object_get_string(jobj1),
json_object_get_string_len(jobj1));
if (r < 0)
return r;
/* We can store full digest here, not only sha1 length */
if (len < LUKS_DIGESTSIZE)
if (len < LUKS_DIGESTSIZE) {
free(digest);
return -EINVAL;
}
memcpy(hdr1->mkDigest, digest, LUKS_DIGESTSIZE);
free(digest);
if (!json_object_object_get_ex(jobj_digest, "salt", &jobj1))
return -EINVAL;
len = sizeof(digest_salt);
if (!base64_decode(json_object_get_string(jobj1),
json_object_get_string_len(jobj1), digest_salt, &len))
return -EINVAL;
if (len != LUKS_SALTSIZE)
r = crypt_base64_decode(&digest_salt, &len, json_object_get_string(jobj1),
json_object_get_string_len(jobj1));
if (r < 0)
return r;
if (len != LUKS_SALTSIZE) {
free(digest_salt);
return -EINVAL;
}
memcpy(hdr1->mkDigestSalt, digest_salt, LUKS_SALTSIZE);
free(digest_salt);
if (!json_object_object_get_ex(jobj_segment, "offset", &jobj1))
return -EINVAL;
offset = crypt_jobj_get_uint64(jobj1) / SECTOR_SIZE;
if (offset > UINT32_MAX)
return -EINVAL;
/* FIXME: LUKS1 requires offset == 0 || offset >= luks1_hdr_size */
hdr1->payloadOffset = offset;
strncpy(hdr1->uuid, hdr2->uuid, UUID_STRING_L); /* max 36 chars */
@@ -881,7 +928,7 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
if (r)
return r > 0 ? -EBUSY : r;
// move keyslots 32k -> 4k offset
/* move keyslots 32k -> 4k offset */
buf_offset = 2 * LUKS2_HDR_16K_LEN;
buf_size = LUKS2_keyslots_size(hdr2);
r = move_keyslot_areas(cd, buf_offset, 8 * SECTOR_SIZE, buf_size);
@@ -893,6 +940,6 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
crypt_wipe_device(cd, crypt_metadata_device(cd), CRYPT_WIPE_ZERO, 0,
8 * SECTOR_SIZE, 8 * SECTOR_SIZE, NULL, NULL);
// Write LUKS1 hdr
/* Write new LUKS1 hdr */
return LUKS_write_phdr(hdr1, cd);
}

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, internal segment handling
*
* Copyright (C) 2018-2021, Red Hat, Inc. All rights reserved.
* Copyright (C) 2018-2021, Ondrej Kozina
* Copyright (C) 2018-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2018-2022 Ondrej Kozina
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -103,15 +103,17 @@ const char *json_segment_get_cipher(json_object *jobj_segment)
return json_object_get_string(jobj);
}
int json_segment_get_sector_size(json_object *jobj_segment)
uint32_t json_segment_get_sector_size(json_object *jobj_segment)
{
json_object *jobj;
int i;
if (!jobj_segment ||
!json_object_object_get_ex(jobj_segment, "sector_size", &jobj))
return -1;
return SECTOR_SIZE;
return json_object_get_int(jobj);
i = json_object_get_int(jobj);
return i < 0 ? SECTOR_SIZE : i;
}
static json_object *json_segment_get_flags(json_object *jobj_segment)
@@ -123,7 +125,7 @@ static json_object *json_segment_get_flags(json_object *jobj_segment)
return jobj;
}
static bool json_segment_contains_flag(json_object *jobj_segment, const char *flag_str, size_t len)
bool json_segment_contains_flag(json_object *jobj_segment, const char *flag_str, size_t len)
{
int r, i;
json_object *jobj, *jobj_flags = json_segment_get_flags(jobj_segment);
@@ -344,19 +346,11 @@ int LUKS2_segment_by_type(struct luks2_hdr *hdr, const char *type)
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;
return json_object_object_length(jobj_segments);
}
int LUKS2_segment_set_flag(json_object *jobj_segment, const char *flag)
@@ -410,3 +404,23 @@ json_object *LUKS2_get_segment_by_flag(struct luks2_hdr *hdr, const char *flag)
return jobj_segment;
}
/* compares key characteristics of both segments */
bool json_segment_cmp(json_object *jobj_segment_1, json_object *jobj_segment_2)
{
const char *type = json_segment_type(jobj_segment_1);
const char *type2 = json_segment_type(jobj_segment_2);
if (!type || !type2)
return false;
if (strcmp(type, type2))
return false;
if (!strcmp(type, "crypt"))
return (json_segment_get_sector_size(jobj_segment_1) == json_segment_get_sector_size(jobj_segment_2) &&
!strcmp(json_segment_get_cipher(jobj_segment_1),
json_segment_get_cipher(jobj_segment_2)));
return true;
}

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, token handling
*
* Copyright (C) 2016-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2021 Milan Broz
* Copyright (C) 2016-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2022 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -63,13 +63,17 @@ static void *token_dlvsym(struct crypt_device *cd,
char *error;
void *sym;
#ifdef HAVE_DLVSYM
log_dbg(cd, "Loading symbol %s@%s.", symbol, version);
sym = dlvsym(handle, symbol, version);
#else
log_dbg(cd, "Loading default version of symbol %s.", symbol);
sym = dlsym(handle, symbol);
#endif
error = dlerror();
if (error)
log_dbg(cd, "Error: %s.", error);
log_dbg(cd, "%s", error);
return sym;
}
@@ -81,12 +85,12 @@ static bool token_validate_v1(struct crypt_device *cd, const crypt_token_handler
return false;
if (!h->name) {
log_dbg(cd, "Token handler does not provide name attribute.");
log_dbg(cd, "Error: token handler does not provide name attribute.");
return false;
}
if (!h->open) {
log_dbg(cd, "Token handler does not provide open function.");
log_dbg(cd, "Error: token handler does not provide open function.");
return false;
}
@@ -103,7 +107,7 @@ static bool token_validate_v2(struct crypt_device *cd, const struct crypt_token_
return false;
if (!h->u.v2.version) {
log_dbg(cd, "Token handler does not provide " CRYPT_TOKEN_ABI_VERSION " function.");
log_dbg(cd, "Error: token handler does not provide " CRYPT_TOKEN_ABI_VERSION " function.");
return false;
}
@@ -157,7 +161,7 @@ crypt_token_load_external(struct crypt_device *cd, const char *name, struct cryp
h = dlopen(buf, RTLD_LAZY);
if (!h) {
log_dbg(NULL, "%s", dlerror());
log_dbg(cd, "%s", dlerror());
return -EINVAL;
}
dlerror();
@@ -182,7 +186,7 @@ crypt_token_load_external(struct crypt_device *cd, const char *name, struct cryp
if (r < 0 || (size_t)r >= sizeof(buf))
*buf = '\0';
log_dbg(cd, "Token handler %s-%s loaded sucessfuly.", token->name, buf);
log_dbg(cd, "Token handler %s-%s loaded successfully.", token->name, buf);
token->dlhandle = h;
ret->version = 2;
@@ -241,6 +245,7 @@ int crypt_token_register(const crypt_token_handler *handler)
void crypt_token_unload_external_all(struct crypt_device *cd)
{
#if USE_EXTERNAL_TOKENS
int i;
for (i = LUKS2_TOKENS_MAX - 1; i >= 0; i--) {
@@ -254,6 +259,7 @@ void crypt_token_unload_external_all(struct crypt_device *cd)
if (dlclose(CONST_CAST(void *)token_handlers[i].u.v2.dlhandle))
log_dbg(cd, "%s", dlerror());
}
#endif
}
static const void
@@ -417,10 +423,11 @@ static const char *token_json_to_string(json_object *jobj_token)
JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE);
}
static int token_for_segment(struct luks2_hdr *hdr, json_object *jobj_token, int segment)
static int token_is_usable(struct luks2_hdr *hdr, json_object *jobj_token, int segment, crypt_keyslot_priority minimal_priority)
{
crypt_keyslot_priority keyslot_priority;
json_object *jobj_array;
int i, len, r = -ENOENT;
int i, keyslot, len, r = -ENOENT;
if (!jobj_token)
return -EINVAL;
@@ -436,14 +443,17 @@ static int token_for_segment(struct luks2_hdr *hdr, json_object *jobj_token, int
if (len <= 0)
return -ENOENT;
/* no need to check anything */
if (segment == CRYPT_ANY_SEGMENT)
return 0;
for (i = 0; i < len; i++) {
r = LUKS2_keyslot_for_segment(hdr,
atoi(json_object_get_string(json_object_array_get_idx(jobj_array, i))),
segment);
keyslot = atoi(json_object_get_string(json_object_array_get_idx(jobj_array, i)));
keyslot_priority = LUKS2_keyslot_priority_get(hdr, keyslot);
if (keyslot_priority == CRYPT_SLOT_PRIORITY_INVALID)
return -EINVAL;
if (keyslot_priority < minimal_priority)
continue;
r = LUKS2_keyslot_for_segment(hdr, keyslot, segment);
if (r != -ENOENT)
return r;
}
@@ -453,9 +463,9 @@ static int token_for_segment(struct luks2_hdr *hdr, json_object *jobj_token, int
static int translate_errno(struct crypt_device *cd, int ret_val, const char *type)
{
if ((ret_val > 0 || ret_val == -EINVAL || ret_val == -ENOENT) && !is_builtin_candidate(type)) {
log_dbg(cd, "%s token handler returned %d. Changing to %d.", type, ret_val, -EPERM);
ret_val = -EPERM;
if ((ret_val > 0 || ret_val == -EINVAL || ret_val == -EPERM) && !is_builtin_candidate(type)) {
log_dbg(cd, "%s token handler returned %d. Changing to %d.", type, ret_val, -ENOENT);
ret_val = -ENOENT;
}
return ret_val;
@@ -467,6 +477,7 @@ static int LUKS2_token_open(struct crypt_device *cd,
json_object *jobj_token,
const char *type,
int segment,
crypt_keyslot_priority priority,
const char *pin,
size_t pin_size,
char **buffer,
@@ -479,6 +490,7 @@ static int LUKS2_token_open(struct crypt_device *cd,
assert(token >= 0);
assert(jobj_token);
assert(priority >= 0);
if (type) {
if (!json_object_object_get_ex(jobj_token, "type", &jobj_type))
@@ -487,10 +499,10 @@ static int LUKS2_token_open(struct crypt_device *cd,
return -ENOENT;
}
r = token_for_segment(hdr, jobj_token, segment);
r = token_is_usable(hdr, jobj_token, segment, priority);
if (r < 0) {
if (r == -ENOENT)
log_dbg(cd, "Token %d unusable for segment %d.", token, segment);
log_dbg(cd, "Token %d unusable for segment %d with desired keyslot priority %d.", token, segment, priority);
return r;
}
@@ -529,17 +541,38 @@ static void LUKS2_token_buffer_free(struct crypt_device *cd,
}
}
static bool break_loop_retval(int r)
{
if (r == -ENOENT || r == -EPERM || r == -EAGAIN || r == -ENOANO)
return false;
return true;
}
static void update_return_errno(int r, int *stored)
{
if (*stored == -ENOANO)
return;
else if (r == -ENOANO)
*stored = r;
else if (r == -EAGAIN && *stored != -ENOANO)
*stored = r;
else if (r == -EPERM && (*stored != -ENOANO && *stored != -EAGAIN))
*stored = r;
}
static int LUKS2_keyslot_open_by_token(struct crypt_device *cd,
struct luks2_hdr *hdr,
int token,
int segment,
crypt_keyslot_priority priority,
const char *buffer,
size_t buffer_len,
struct volume_key **vk)
{
crypt_keyslot_priority keyslot_priority;
json_object *jobj_token, *jobj_token_keyslots, *jobj_type, *jobj;
unsigned int num = 0;
int i, r;
int i, r = -ENOENT, stored_retval = -ENOENT;
jobj_token = LUKS2_get_token_jobj(hdr, token);
if (!jobj_token)
@@ -553,20 +586,160 @@ static int LUKS2_keyslot_open_by_token(struct crypt_device *cd,
return -EINVAL;
/* Try to open keyslot referenced in token */
r = -ENOENT;
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 = atoi(json_object_get_string(jobj));
keyslot_priority = LUKS2_keyslot_priority_get(hdr, num);
if (keyslot_priority == CRYPT_SLOT_PRIORITY_INVALID)
return -EINVAL;
if (keyslot_priority < priority)
continue;
log_dbg(cd, "Trying to open keyslot %u with token %d (type %s).", num, token, json_object_get_string(jobj_type));
r = LUKS2_keyslot_open(cd, num, segment, buffer, buffer_len, vk);
/* short circuit on fatal error */
if (r < 0 && r != -EPERM && r != -ENOENT)
return r;
/* save -EPERM in case no other keyslot is usable */
if (r == -EPERM)
stored_retval = r;
}
if (r < 0)
return r;
return stored_retval;
return num;
}
static bool token_is_blocked(int token, uint32_t *block_list)
{
/* it is safe now, but have assert in case LUKS2_TOKENS_MAX grows */
assert(token >= 0 && (size_t)token < BITFIELD_SIZE(block_list));
return (*block_list & (1 << token));
}
static void token_block(int token, uint32_t *block_list)
{
/* it is safe now, but have assert in case LUKS2_TOKENS_MAX grows */
assert(token >= 0 && (size_t)token < BITFIELD_SIZE(block_list));
*block_list |= (1 << token);
}
static int token_open_priority(struct crypt_device *cd,
struct luks2_hdr *hdr,
json_object *jobj_tokens,
const char *type,
int segment,
crypt_keyslot_priority priority,
const char *pin,
size_t pin_size,
void *usrptr,
int *stored_retval,
uint32_t *block_list,
struct volume_key **vk)
{
char *buffer;
size_t buffer_size;
int token, r;
assert(stored_retval);
assert(block_list);
json_object_object_foreach(jobj_tokens, slot, val) {
token = atoi(slot);
if (token_is_blocked(token, block_list))
continue;
r = LUKS2_token_open(cd, hdr, token, val, type, segment, priority, pin, pin_size, &buffer, &buffer_size, usrptr);
if (!r) {
r = LUKS2_keyslot_open_by_token(cd, hdr, token, segment, priority,
buffer, buffer_size, vk);
LUKS2_token_buffer_free(cd, token, buffer, buffer_size);
}
if (r == -ENOANO)
token_block(token, block_list);
if (break_loop_retval(r))
return r;
update_return_errno(r, stored_retval);
}
return *stored_retval;
}
static int token_open_any(struct crypt_device *cd, struct luks2_hdr *hdr, const char *type, int segment, const char *pin, size_t pin_size, void *usrptr, struct volume_key **vk)
{
json_object *jobj_tokens;
int r, retval = -ENOENT;
uint32_t blocked = 0; /* bitmap with tokens blocked from loop by returning -ENOANO (wrong/missing pin) */
json_object_object_get_ex(hdr->jobj, "tokens", &jobj_tokens);
/* passing usrptr for CRYPT_ANY_TOKEN does not make sense without specific type */
if (!type)
usrptr = NULL;
r = token_open_priority(cd, hdr, jobj_tokens, type, segment, CRYPT_SLOT_PRIORITY_PREFER, pin, pin_size, usrptr, &retval, &blocked, vk);
if (break_loop_retval(r))
return r;
return token_open_priority(cd, hdr, jobj_tokens, type, segment, CRYPT_SLOT_PRIORITY_NORMAL, pin, pin_size, usrptr, &retval, &blocked, vk);
}
int LUKS2_token_unlock_volume_key(struct crypt_device *cd,
struct luks2_hdr *hdr,
int token,
const char *type,
const char *pin,
size_t pin_size,
uint32_t flags,
void *usrptr,
struct volume_key **vk)
{
char *buffer;
size_t buffer_size;
json_object *jobj_token;
int segment, r = -ENOENT;
assert(vk);
if (flags & CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY)
segment = CRYPT_ANY_SEGMENT;
else {
segment = LUKS2_get_default_segment(hdr);
if (segment < 0)
return -EINVAL;
}
if (token >= 0 && token < LUKS2_TOKENS_MAX) {
if ((jobj_token = LUKS2_get_token_jobj(hdr, token))) {
r = LUKS2_token_open(cd, hdr, token, jobj_token, type, segment, CRYPT_SLOT_PRIORITY_IGNORE, pin, pin_size, &buffer, &buffer_size, usrptr);
if (!r) {
r = LUKS2_keyslot_open_by_token(cd, hdr, token, segment, CRYPT_SLOT_PRIORITY_IGNORE,
buffer, buffer_size, vk);
LUKS2_token_buffer_free(cd, token, buffer, buffer_size);
}
}
} else if (token == CRYPT_ANY_TOKEN)
/*
* return priorities (ordered form least to most significant):
* ENOENT - unusable for activation (no token handler, invalid token metadata, not assigned to volume segment, etc)
* EPERM - usable but token provided passphrase did not not unlock any assigned keyslot
* EAGAIN - usable but not ready (token HW is missing)
* ENOANO - ready, but token pin is wrong or missing
*
* success (>= 0) or any other negative errno short-circuits token activation loop
* immediately
*/
r = token_open_any(cd, hdr, type, segment, pin, pin_size, usrptr, vk);
else
r = -EINVAL;
return r;
}
int LUKS2_token_open_and_activate(struct crypt_device *cd,
struct luks2_hdr *hdr,
int token,
@@ -578,53 +751,15 @@ int LUKS2_token_open_and_activate(struct crypt_device *cd,
void *usrptr)
{
bool use_keyring;
char *buffer;
size_t buffer_size;
json_object *jobj_tokens, *jobj_token;
int keyslot, segment, r = -ENOENT;
int keyslot, r;
struct volume_key *vk = NULL;
if (flags & CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY)
segment = CRYPT_ANY_SEGMENT;
else {
segment = LUKS2_get_default_segment(hdr);
if (segment < 0)
return -EINVAL;
}
if (token >= 0 && token < LUKS2_TOKENS_MAX) {
if ((jobj_token = LUKS2_get_token_jobj(hdr, token))) {
r = LUKS2_token_open(cd, hdr, token, jobj_token, type, segment, pin, pin_size, &buffer, &buffer_size, usrptr);
if (!r) {
r = LUKS2_keyslot_open_by_token(cd, hdr, token, segment,
buffer, buffer_size, &vk);
LUKS2_token_buffer_free(cd, token, buffer, buffer_size);
}
}
} else if (token == CRYPT_ANY_TOKEN) {
json_object_object_get_ex(hdr->jobj, "tokens", &jobj_tokens);
/* passing usrptr for CRYPT_ANY_TOKEN does not make sense without specific type */
if (!type)
usrptr = NULL;
json_object_object_foreach(jobj_tokens, slot, val) {
token = atoi(slot);
r = LUKS2_token_open(cd, hdr, token, val, type, segment, pin, pin_size, &buffer, &buffer_size, usrptr);
if (!r) {
r = LUKS2_keyslot_open_by_token(cd, hdr, token, segment,
buffer, buffer_size, &vk);
LUKS2_token_buffer_free(cd, token, buffer, buffer_size);
}
if (r != -ENOENT && r != -EPERM)
break;
}
} else
return -EINVAL;
r = LUKS2_token_unlock_volume_key(cd, hdr, token, type, pin, pin_size, flags, usrptr, &vk);
if (r < 0)
return r;
assert(vk);
keyslot = r;
if (!crypt_use_keyring_for_vk(cd))
@@ -662,8 +797,7 @@ void LUKS2_token_dump(struct crypt_device *cd, int token)
}
}
int LUKS2_token_json_get(struct crypt_device *cd __attribute__((unused)), struct luks2_hdr *hdr,
int token, const char **json)
int LUKS2_token_json_get(struct luks2_hdr *hdr, int token, const char **json)
{
json_object *jobj_token;
@@ -778,8 +912,7 @@ static int token_is_assigned(struct luks2_hdr *hdr, int keyslot, int token)
return -ENOENT;
}
int LUKS2_token_is_assigned(struct crypt_device *cd __attribute__((unused)), struct luks2_hdr *hdr,
int keyslot, int token)
int LUKS2_token_is_assigned(struct luks2_hdr *hdr, int keyslot, int token)
{
if (keyslot < 0 || keyslot >= LUKS2_KEYSLOTS_MAX || token < 0 || token >= LUKS2_TOKENS_MAX)
return -EINVAL;

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, kernel keyring token
*
* Copyright (C) 2016-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2021 Ondrej Kozina
* Copyright (C) 2016-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2022 Ondrej Kozina
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -124,7 +124,7 @@ int LUKS2_token_keyring_json(char *buffer, size_t buffer_size,
return 0;
}
int LUKS2_token_keyring_get(struct crypt_device *cd __attribute__((unused)), struct luks2_hdr *hdr,
int LUKS2_token_keyring_get(struct luks2_hdr *hdr,
int token, struct crypt_token_params_luks2_keyring *keyring_params)
{
json_object *jobj_token, *jobj;

View File

@@ -1,7 +1,7 @@
/*
* cryptsetup kernel RNG access functions
*
* Copyright (C) 2010-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2022 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
@@ -42,8 +42,7 @@ static int random_fd = -1;
#define RANDOM_DEVICE_TIMEOUT 5
/* URANDOM_DEVICE access */
static int _get_urandom(struct crypt_device *ctx __attribute__((unused)),
char *buf, size_t len)
static int _get_urandom(char *buf, size_t len)
{
int r;
size_t old_len = len;
@@ -51,7 +50,7 @@ static int _get_urandom(struct crypt_device *ctx __attribute__((unused)),
assert(urandom_fd != -1);
while(len) {
while (len) {
r = read(urandom_fd, buf, len);
if (r == -1 && errno != EINTR)
return -EINVAL;
@@ -178,13 +177,13 @@ int crypt_random_get(struct crypt_device *ctx, char *buf, size_t len, int qualit
switch(quality) {
case CRYPT_RND_NORMAL:
status = _get_urandom(ctx, buf, len);
status = _get_urandom(buf, len);
break;
case CRYPT_RND_SALT:
if (crypt_fips_mode())
status = crypt_backend_rng(buf, len, quality, 1);
else
status = _get_urandom(ctx, buf, len);
status = _get_urandom(buf, len);
break;
case CRYPT_RND_KEY:
if (crypt_fips_mode()) {
@@ -195,7 +194,7 @@ int crypt_random_get(struct crypt_device *ctx, char *buf, size_t len, int qualit
crypt_random_default_key_rng();
switch (rng_type) {
case CRYPT_RNG_URANDOM:
status = _get_urandom(ctx, buf, len);
status = _get_urandom(buf, len);
break;
case CRYPT_RNG_RANDOM:
status = _get_random(ctx, buf, len);

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-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2021 Milan Broz
* Copyright (C) 2009-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2022 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -227,7 +227,7 @@ int init_crypto(struct crypt_device *ctx)
return r;
}
r = crypt_backend_init();
r = crypt_backend_init(crypt_fips_mode());
if (r < 0)
log_err(ctx, _("Cannot initialize crypto backend."));
@@ -429,7 +429,7 @@ static int keyslot_verify_or_find_empty(struct crypt_device *cd, int *keyslot)
switch (ki) {
case CRYPT_SLOT_INVALID:
log_err(cd, _("Key slot %d is invalid, please select between 0 and %d."),
*keyslot, LUKS_NUMKEYS - 1);
*keyslot, crypt_keyslot_max(cd->type) - 1);
return -EINVAL;
case CRYPT_SLOT_INACTIVE:
break;
@@ -752,7 +752,7 @@ static void _luks2_reload(struct crypt_device *cd)
}
static int _crypt_load_luks(struct crypt_device *cd, const char *requested_type,
int require_header, int repair)
bool quiet, bool repair)
{
char *cipher_spec;
struct luks_phdr hdr = {};
@@ -784,7 +784,7 @@ static int _crypt_load_luks(struct crypt_device *cd, const char *requested_type,
return r;
}
r = LUKS_read_phdr(&hdr, require_header, repair, cd);
r = LUKS_read_phdr(&hdr, !quiet, repair, cd);
if (r)
goto out;
@@ -829,6 +829,8 @@ static int _crypt_load_luks(struct crypt_device *cd, const char *requested_type,
r = _crypt_load_luks2(cd, cd->type != NULL, repair);
if (!r)
device_set_block_size(crypt_data_device(cd), LUKS2_get_sector_size(&cd->u.luks2.hdr));
else if (!quiet)
log_err(cd, _("Device %s is not a valid LUKS device."), mdata_device_path(cd));
} else {
if (version > 2)
log_err(cd, _("Unsupported LUKS version %d."), version);
@@ -972,8 +974,7 @@ static int _crypt_load_integrity(struct crypt_device *cd,
return 0;
}
static int _crypt_load_bitlk(struct crypt_device *cd,
struct bitlk_metadata *params __attribute__((unused)))
static int _crypt_load_bitlk(struct crypt_device *cd)
{
int r;
@@ -1025,7 +1026,7 @@ int crypt_load(struct crypt_device *cd,
return -EINVAL;
}
r = _crypt_load_luks(cd, requested_type, 1, 0);
r = _crypt_load_luks(cd, requested_type, true, false);
} else if (isVERITY(requested_type)) {
if (cd->type && !isVERITY(cd->type)) {
log_dbg(cd, "Context is already initialized to type %s", cd->type);
@@ -1049,7 +1050,7 @@ int crypt_load(struct crypt_device *cd,
log_dbg(cd, "Context is already initialized to type %s", cd->type);
return -EINVAL;
}
r = _crypt_load_bitlk(cd, params);
r = _crypt_load_bitlk(cd);
} else
return -EINVAL;
@@ -1269,7 +1270,7 @@ static int _init_by_name_crypt(struct crypt_device *cd, const char *name)
cd->u.loopaes.key_size = tgt->u.crypt.vk->keylength / key_nums;
} else if (isLUKS1(cd->type) || isLUKS2(cd->type)) {
if (crypt_metadata_device(cd)) {
r = _crypt_load_luks(cd, cd->type, 0, 0);
r = _crypt_load_luks(cd, cd->type, true, false);
if (r < 0) {
log_dbg(cd, "LUKS device header does not match active device.");
crypt_set_null_type(cd);
@@ -1296,7 +1297,7 @@ static int _init_by_name_crypt(struct crypt_device *cd, const char *name)
r = TCRYPT_init_by_name(cd, name, dmd.uuid, tgt, &cd->device,
&cd->u.tcrypt.params, &cd->u.tcrypt.hdr);
} else if (isBITLK(cd->type)) {
r = _crypt_load_bitlk(cd, NULL);
r = _crypt_load_bitlk(cd);
if (r < 0) {
log_dbg(cd, "BITLK device header not available.");
crypt_set_null_type(cd);
@@ -1742,6 +1743,16 @@ static int _crypt_format_luks2(struct crypt_device *cd,
if (params && params->sector_size)
sector_size_autodetect = false;
if (params && params->data_device) {
if (!cd->metadata_device)
cd->metadata_device = cd->device;
else
device_free(cd, cd->device);
cd->device = NULL;
if (device_alloc(cd, &cd->device, params->data_device) < 0)
return -ENOMEM;
}
if (sector_size_autodetect) {
sector_size = device_optimal_encryption_sector_size(cd, crypt_data_device(cd));
log_dbg(cd, "Auto-detected optimal encryption sector size for device %s is %d bytes.",
@@ -1775,13 +1786,13 @@ static int _crypt_format_luks2(struct crypt_device *cd,
params->integrity_params->journal_integrity)
return -ENOTSUP;
}
if (!INTEGRITY_tag_size(cd, integrity, cipher, cipher_mode)) {
if (!INTEGRITY_tag_size(integrity, cipher, cipher_mode)) {
if (!strcmp(integrity, "none"))
integrity = NULL;
else
return -EINVAL;
}
integrity_key_size = INTEGRITY_key_size(cd, integrity);
integrity_key_size = INTEGRITY_key_size(integrity);
if ((integrity_key_size < 0) || (integrity_key_size >= (int)volume_key_size)) {
log_err(cd, _("Volume key is too small for encryption with integrity extensions."));
return -EINVAL;
@@ -1812,16 +1823,6 @@ static int _crypt_format_luks2(struct crypt_device *cd,
if (r < 0)
return r;
if (params && params->data_device) {
if (!cd->metadata_device)
cd->metadata_device = cd->device;
else
device_free(cd, cd->device);
cd->device = NULL;
if (device_alloc(cd, &cd->device, params->data_device) < 0)
return -ENOMEM;
}
if (params && cd->metadata_device) {
/* For detached header the alignment is used directly as data offset */
if (!cd->data_offset)
@@ -1840,7 +1841,7 @@ static int _crypt_format_luks2(struct crypt_device *cd,
if (sector_size_autodetect) {
if (cd->data_offset && MISALIGNED(cd->data_offset, sector_size)) {
log_dbg(cd, "Data offset not alligned to sector size. Reverting to 512 bytes.");
log_dbg(cd, "Data offset not aligned to sector size. Reverting to 512 bytes.");
sector_size = SECTOR_SIZE;
} else if (MISALIGNED(dev_size - (uint64_t)required_alignment - (uint64_t)alignment_offset, sector_size)) {
/* underflow does not affect misalignment checks */
@@ -1860,7 +1861,7 @@ static int _crypt_format_luks2(struct crypt_device *cd,
}
if ((!integrity || integrity_key_size) && !crypt_cipher_wrapped_key(cipher, cipher_mode) &&
!INTEGRITY_tag_size(cd, NULL, cipher, cipher_mode)) {
!INTEGRITY_tag_size(NULL, cipher, cipher_mode)) {
r = LUKS_check_cipher(cd, volume_key_size - integrity_key_size,
cipher, cipher_mode);
if (r < 0)
@@ -2154,7 +2155,7 @@ static int _crypt_format_verity(struct crypt_device *cd,
if (!(cd->u.verity.uuid = strdup(uuid)))
r = -ENOMEM;
} else
r = VERITY_UUID_generate(cd, &cd->u.verity.uuid);
r = VERITY_UUID_generate(&cd->u.verity.uuid);
if (!r)
r = VERITY_write_sb(cd, cd->u.verity.hdr.hash_area_offset,
@@ -2378,7 +2379,7 @@ int crypt_repair(struct crypt_device *cd,
return -EINVAL;
/* Load with repair */
r = _crypt_load_luks(cd, requested_type, 1, 1);
r = _crypt_load_luks(cd, requested_type, false, true);
if (r < 0)
return r;
@@ -2402,7 +2403,7 @@ static int _compare_volume_keys(struct volume_key *svk, unsigned skeyring_only,
return 1;
if (!skeyring_only && !tkeyring_only)
return memcmp(svk->key, tvk->key, svk->keylength);
return crypt_backend_memeq(svk->key, tvk->key, svk->keylength);
if (svk->key_description && tvk->key_description)
return strcmp(svk->key_description, tvk->key_description);
@@ -2435,7 +2436,7 @@ static int _compare_device_types(struct crypt_device *cd,
log_dbg(cd, "Unexpected uuid prefix %s in target device.", tgt->uuid);
return -EINVAL;
}
} else {
} else if (!isINTEGRITY(cd->type)) {
log_dbg(cd, "Unsupported device type %s for reload.", cd->type ?: "<empty>");
return -ENOTSUP;
}
@@ -2524,15 +2525,6 @@ static int _compare_integrity_devices(struct crypt_device *cd,
return -EINVAL;
}
/* unsupported underneath dm-crypt with auth. encryption */
if (src->u.integrity.meta_device || tgt->u.integrity.meta_device)
return -ENOTSUP;
if (src->size != tgt->size) {
log_dbg(cd, "Device size parameters do not match.");
return -EINVAL;
}
if (device_is_identical(src->data_device, tgt->data_device) <= 0) {
log_dbg(cd, "Data devices do not match.");
return -EINVAL;
@@ -2605,13 +2597,13 @@ static int _reload_device(struct crypt_device *cd, const char *name,
r = dm_query_device(cd, name, DM_ACTIVE_DEVICE | DM_ACTIVE_CRYPT_CIPHER |
DM_ACTIVE_UUID | DM_ACTIVE_CRYPT_KEYSIZE |
DM_ACTIVE_CRYPT_KEY, &tdmd);
DM_ACTIVE_CRYPT_KEY | DM_ACTIVE_INTEGRITY_PARAMS | DM_ACTIVE_JOURNAL_CRYPT_KEY | DM_ACTIVE_JOURNAL_MAC_KEY, &tdmd);
if (r < 0) {
log_err(cd, _("Device %s is not active."), name);
return -EINVAL;
}
if (!single_segment(&tdmd) || tgt->type != DM_CRYPT || tgt->u.crypt.tag_size) {
if (!single_segment(&tdmd) || (tgt->type != DM_CRYPT && tgt->type != DM_INTEGRITY) || (tgt->type == DM_CRYPT && tgt->u.crypt.tag_size)) {
r = -ENOTSUP;
log_err(cd, _("Unsupported parameters on device %s."), name);
goto out;
@@ -2631,11 +2623,11 @@ static int _reload_device(struct crypt_device *cd, const char *name,
else
sdmd->flags &= ~CRYPT_ACTIVATE_READONLY;
if (sdmd->flags & CRYPT_ACTIVATE_KEYRING_KEY) {
if (tgt->type == DM_CRYPT && sdmd->flags & CRYPT_ACTIVATE_KEYRING_KEY) {
r = crypt_volume_key_set_description(tgt->u.crypt.vk, src->u.crypt.vk->key_description);
if (r)
goto out;
} else {
} else if (tgt->type == DM_CRYPT) {
crypt_free_volume_key(tgt->u.crypt.vk);
tgt->u.crypt.vk = crypt_alloc_volume_key(src->u.crypt.vk->keylength, src->u.crypt.vk->key);
if (!tgt->u.crypt.vk) {
@@ -2644,8 +2636,15 @@ static int _reload_device(struct crypt_device *cd, const char *name,
}
}
r = device_block_adjust(cd, src->data_device, DEV_OK,
src->u.crypt.offset, &sdmd->size, NULL);
if (tgt->type == DM_CRYPT)
r = device_block_adjust(cd, src->data_device, DEV_OK,
src->u.crypt.offset, &sdmd->size, NULL);
else if (tgt->type == DM_INTEGRITY)
r = device_block_adjust(cd, src->data_device, DEV_OK,
src->u.integrity.offset, &sdmd->size, NULL);
else
r = -EINVAL;
if (r)
goto out;
@@ -2709,6 +2708,10 @@ static int _reload_device_with_integrity(struct crypt_device *cd,
goto out;
}
/* unsupported underneath dm-crypt with auth. encryption */
if (sdmdi->segment.u.integrity.meta_device || tdmdi.segment.u.integrity.meta_device)
return -ENOTSUP;
src = &sdmd->segment;
srci = &sdmdi->segment;
@@ -2830,6 +2833,9 @@ int crypt_resize(struct crypt_device *cd, const char *name, uint64_t new_size)
{
struct crypt_dm_active_device dmdq, dmd = {};
struct dm_target *tgt = &dmdq.segment;
struct crypt_params_integrity params = {};
uint32_t supported_flags = 0;
uint64_t old_size;
int r;
/*
@@ -2848,12 +2854,12 @@ int crypt_resize(struct crypt_device *cd, const char *name, uint64_t new_size)
log_dbg(cd, "Resizing device %s to %" PRIu64 " sectors.", name, new_size);
r = dm_query_device(cd, name, DM_ACTIVE_CRYPT_KEYSIZE | DM_ACTIVE_CRYPT_KEY, &dmdq);
r = dm_query_device(cd, name, DM_ACTIVE_CRYPT_KEYSIZE | DM_ACTIVE_CRYPT_KEY | DM_ACTIVE_INTEGRITY_PARAMS | DM_ACTIVE_JOURNAL_CRYPT_KEY | DM_ACTIVE_JOURNAL_MAC_KEY, &dmdq);
if (r < 0) {
log_err(cd, _("Device %s is not active."), name);
return -EINVAL;
}
if (!single_segment(&dmdq) || tgt->type != DM_CRYPT) {
if (!single_segment(&dmdq) || (tgt->type != DM_CRYPT && tgt->type != DM_INTEGRITY)) {
log_dbg(cd, "Unsupported device table detected in %s.", name);
r = -EINVAL;
goto out;
@@ -2885,12 +2891,52 @@ int crypt_resize(struct crypt_device *cd, const char *name, uint64_t new_size)
log_err(cd, _("Cannot resize loop device."));
}
/*
* Integrity device metadata are maintained by the kernel. We need to
* reload the device (with the same parameters) and let the kernel
* calculate the maximum size of integrity device and store it in the
* superblock.
*/
if (!new_size && tgt->type == DM_INTEGRITY) {
r = INTEGRITY_data_sectors(cd, crypt_metadata_device(cd),
crypt_get_data_offset(cd) * SECTOR_SIZE, &old_size);
if (r < 0)
return r;
dmd.size = dmdq.size;
dmd.flags = dmdq.flags | CRYPT_ACTIVATE_REFRESH | CRYPT_ACTIVATE_PRIVATE;
r = crypt_get_integrity_info(cd, &params);
if (r)
goto out;
r = dm_integrity_target_set(cd, &dmd.segment, 0, dmdq.segment.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), tgt->u.integrity.vk, tgt->u.integrity.journal_crypt_key, tgt->u.integrity.journal_integrity_key, &params);
if (r)
goto out;
r = _reload_device(cd, name, &dmd);
if (r)
goto out;
r = INTEGRITY_data_sectors(cd, crypt_metadata_device(cd),
crypt_get_data_offset(cd) * SECTOR_SIZE, &new_size);
if (r < 0)
return r;
log_dbg(cd, "Maximum integrity device size from kernel %" PRIu64, new_size);
if (old_size == new_size && new_size == dmdq.size && !dm_flags(cd, tgt->type, &supported_flags) && !(supported_flags & DM_INTEGRITY_RESIZE_SUPPORTED))
log_std(cd, _("WARNING: Maximum size already set or kernel doesn't support resize.\n"));
}
r = device_block_adjust(cd, crypt_data_device(cd), DEV_OK,
crypt_get_data_offset(cd), &new_size, &dmdq.flags);
crypt_get_data_offset(cd), &new_size, &dmdq.flags);
if (r)
goto out;
if (MISALIGNED(new_size, tgt->u.crypt.sector_size >> SECTOR_SHIFT)) {
if (MISALIGNED(new_size, (tgt->type == DM_CRYPT ? tgt->u.crypt.sector_size : tgt->u.integrity.sector_size) >> SECTOR_SHIFT)) {
log_err(cd, _("Device size is not aligned to requested sector size."));
r = -EINVAL;
goto out;
@@ -2905,13 +2951,27 @@ int crypt_resize(struct crypt_device *cd, const char *name, uint64_t new_size)
dmd.uuid = crypt_get_uuid(cd);
dmd.size = new_size;
dmd.flags = dmdq.flags | CRYPT_ACTIVATE_REFRESH;
r = dm_crypt_target_set(&dmd.segment, 0, new_size, crypt_data_device(cd),
tgt->u.crypt.vk, crypt_get_cipher_spec(cd),
crypt_get_iv_offset(cd), crypt_get_data_offset(cd),
crypt_get_integrity(cd), crypt_get_integrity_tag_size(cd),
crypt_get_sector_size(cd));
if (r < 0)
goto out;
if (tgt->type == DM_CRYPT) {
r = dm_crypt_target_set(&dmd.segment, 0, new_size, crypt_data_device(cd),
tgt->u.crypt.vk, crypt_get_cipher_spec(cd),
crypt_get_iv_offset(cd), crypt_get_data_offset(cd),
crypt_get_integrity(cd), crypt_get_integrity_tag_size(cd),
crypt_get_sector_size(cd));
if (r < 0)
goto out;
} else if (tgt->type == DM_INTEGRITY) {
r = crypt_get_integrity_info(cd, &params);
if (r)
goto out;
r = dm_integrity_target_set(cd, &dmd.segment, 0, new_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), tgt->u.integrity.vk, tgt->u.integrity.journal_crypt_key, tgt->u.integrity.journal_integrity_key, &params);
if (r)
goto out;
}
if (new_size == dmdq.size) {
log_dbg(cd, "Device has already requested size %" PRIu64
@@ -2924,6 +2984,9 @@ int crypt_resize(struct crypt_device *cd, const char *name, uint64_t new_size)
r = LUKS2_unmet_requirements(cd, &cd->u.luks2.hdr, 0, 0);
if (!r)
r = _reload_device(cd, name, &dmd);
if (r && tgt->type == DM_INTEGRITY && !dm_flags(cd, tgt->type, &supported_flags) && !(supported_flags & DM_INTEGRITY_RESIZE_SUPPORTED))
log_err(cd, _("Resize failed, the kernel doesn't support it."));
}
out:
dm_targets_free(cd, &dmd);
@@ -2976,6 +3039,22 @@ int crypt_set_label(struct crypt_device *cd, const char *label, const char *subs
return LUKS2_hdr_labels(cd, &cd->u.luks2.hdr, label, subsystem, 1);
}
const char *crypt_get_label(struct crypt_device *cd)
{
if (_onlyLUKS2(cd, CRYPT_CD_QUIET | CRYPT_CD_UNRESTRICTED, 0))
return NULL;
return cd->u.luks2.hdr.label;
}
const char *crypt_get_subsystem(struct crypt_device *cd)
{
if (_onlyLUKS2(cd, CRYPT_CD_QUIET | CRYPT_CD_UNRESTRICTED, 0))
return NULL;
return cd->u.luks2.hdr.subsystem;
}
int crypt_header_backup(struct crypt_device *cd,
const char *requested_type,
const char *backup_file)
@@ -2989,7 +3068,7 @@ int crypt_header_backup(struct crypt_device *cd,
return -EINVAL;
/* Load with repair */
r = _crypt_load_luks(cd, requested_type, 1, 0);
r = _crypt_load_luks(cd, requested_type, false, false);
if (r < 0)
return r;
@@ -3055,7 +3134,7 @@ int crypt_header_restore(struct crypt_device *cd,
r = -EINVAL;
if (!r)
r = _crypt_load_luks(cd, version == 1 ? CRYPT_LUKS1 : CRYPT_LUKS2, 1, 1);
r = _crypt_load_luks(cd, version == 1 ? CRYPT_LUKS1 : CRYPT_LUKS2, false, true);
return r;
}
@@ -3081,7 +3160,7 @@ void crypt_free(struct crypt_device *cd)
if (!cd)
return;
log_dbg(cd, "Releasing crypt device %s context.", mdata_device_path(cd));
log_dbg(cd, "Releasing crypt device %s context.", mdata_device_path(cd) ?: "empty");
dm_backend_exit(cd);
crypt_free_volume_key(cd->volume_key);
@@ -3200,8 +3279,7 @@ static int resume_by_volume_key(struct crypt_device *cd,
digest = LUKS2_digest_by_segment(&cd->u.luks2.hdr, CRYPT_DEFAULT_SEGMENT);
if (digest < 0)
return -EINVAL;
r = LUKS2_volume_key_load_in_keyring_by_digest(cd,
&cd->u.luks2.hdr, vk, digest);
r = LUKS2_volume_key_load_in_keyring_by_digest(cd, vk, digest);
if (r < 0)
return r;
}
@@ -3387,6 +3465,40 @@ int crypt_resume_by_volume_key(struct crypt_device *cd,
return r;
}
int crypt_resume_by_token_pin(struct crypt_device *cd, const char *name,
const char *type, int token, const char *pin, size_t pin_size,
void *usrptr)
{
struct volume_key *vk = NULL;
int r, keyslot;
if (!name)
return -EINVAL;
log_dbg(cd, "Resuming volume %s by token (%s type) %d.",
name, type ?: "any", token);
if ((r = _onlyLUKS2(cd, CRYPT_CD_QUIET, 0)))
return r;
r = dm_status_suspended(cd, name);
if (r < 0)
return r;
if (!r) {
log_err(cd, _("Volume %s is not suspended."), name);
return -EINVAL;
}
r = LUKS2_token_unlock_volume_key(cd, &cd->u.luks2.hdr, token, type, pin, pin_size, 0, usrptr, &vk);
keyslot = r;
if (r >= 0)
r = resume_by_volume_key(cd, vk, name);
crypt_free_volume_key(vk);
return r < 0 ? r : keyslot;
}
/*
* Keyslot manipulation
*/
@@ -3901,7 +4013,7 @@ int create_or_reload_device(struct crypt_device *cd, const char *name,
return -EINVAL;
tgt = &dmd->segment;
if (tgt->type != DM_CRYPT)
if (tgt->type != DM_CRYPT && tgt->type != DM_INTEGRITY)
return -EINVAL;
/* drop CRYPT_ACTIVATE_REFRESH flag if any device is inactive */
@@ -3912,12 +4024,27 @@ int create_or_reload_device(struct crypt_device *cd, const char *name,
if (dmd->flags & CRYPT_ACTIVATE_REFRESH)
r = _reload_device(cd, name, dmd);
else {
device_check = dmd->flags & CRYPT_ACTIVATE_SHARED ? DEV_OK : DEV_EXCL;
if (tgt->type == DM_CRYPT) {
device_check = dmd->flags & CRYPT_ACTIVATE_SHARED ? DEV_OK : DEV_EXCL;
r = device_block_adjust(cd, tgt->data_device, device_check,
r = device_block_adjust(cd, tgt->data_device, device_check,
tgt->u.crypt.offset, &dmd->size, &dmd->flags);
if (!r) {
tgt->size = dmd->size;
if (!r) {
tgt->size = dmd->size;
r = dm_create_device(cd, name, type, dmd);
}
} else if (tgt->type == DM_INTEGRITY) {
r = device_block_adjust(cd, tgt->data_device, DEV_EXCL,
tgt->u.integrity.offset, NULL, &dmd->flags);
if (r)
return r;
if (tgt->u.integrity.meta_device) {
r = device_block_adjust(cd, tgt->u.integrity.meta_device, DEV_EXCL, 0, NULL, NULL);
if (r)
return r;
}
r = dm_create_device(cd, name, type, dmd);
}
}
@@ -3955,25 +4082,6 @@ out:
return r;
}
static int load_all_keys(struct crypt_device *cd, struct luks2_hdr *hdr, struct volume_key *vks)
{
int r;
struct volume_key *vk = vks;
while (vk) {
r = LUKS2_volume_key_load_in_keyring_by_digest(cd, hdr, vk, crypt_volume_key_get_id(vk));
if (r < 0)
return r;
vk = crypt_volume_key_next(vk);
}
return 0;
}
/* See fixmes in _open_and_activate_luks2 */
int update_reencryption_flag(struct crypt_device *cd, int enable, bool commit);
/* TODO: This function should 1:1 with pre-reencryption code */
static int _open_and_activate(struct crypt_device *cd,
int keyslot,
const char *name,
@@ -4017,6 +4125,22 @@ out:
return r < 0 ? r : keyslot;
}
#if USE_LUKS2_REENCRYPTION
static int load_all_keys(struct crypt_device *cd, struct luks2_hdr *hdr, struct volume_key *vks)
{
int r;
struct volume_key *vk = vks;
while (vk) {
r = LUKS2_volume_key_load_in_keyring_by_digest(cd, vk, crypt_volume_key_get_id(vk));
if (r < 0)
return r;
vk = crypt_volume_key_next(vk);
}
return 0;
}
static int _open_all_keys(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
@@ -4099,7 +4223,7 @@ static int _open_and_activate_reencrypt_device(struct crypt_device *cd,
if (ri == CRYPT_REENCRYPT_CRASH) {
r = LUKS2_reencrypt_locked_recovery_by_passphrase(cd, keyslot,
keyslot, passphrase, passphrase_size, flags, &vks);
keyslot, passphrase, passphrase_size, &vks);
if (r < 0) {
log_err(cd, _("LUKS2 reencryption recovery failed."));
goto out;
@@ -4131,6 +4255,12 @@ static int _open_and_activate_reencrypt_device(struct crypt_device *cd,
keyslot = r;
}
if (r >= 0) {
r = LUKS2_reencrypt_digest_verify(cd, hdr, vks);
if (r < 0)
goto out;
}
log_dbg(cd, "Entering clean reencryption state mode.");
if (r >= 0)
@@ -4158,8 +4288,9 @@ static int _open_and_activate_luks2(struct crypt_device *cd,
uint32_t flags)
{
crypt_reencrypt_info ri;
int r;
int r, rv;
struct luks2_hdr *hdr = &cd->u.luks2.hdr;
struct volume_key *vks = NULL;
ri = LUKS2_reencrypt_status(hdr);
if (ri == CRYPT_REENCRYPT_INVALID)
@@ -4169,15 +4300,45 @@ static int _open_and_activate_luks2(struct crypt_device *cd,
if (name)
r = _open_and_activate_reencrypt_device(cd, hdr, keyslot, name, passphrase,
passphrase_size, flags);
else
else {
r = _open_all_keys(cd, hdr, keyslot, passphrase,
passphrase_size, flags, NULL);
passphrase_size, flags, &vks);
if (r < 0)
return r;
rv = LUKS2_reencrypt_digest_verify(cd, hdr, vks);
crypt_free_volume_key(vks);
if (rv < 0)
return rv;
}
} else
r = _open_and_activate(cd, keyslot, name, passphrase,
passphrase_size, flags);
return r;
}
#else
static int _open_and_activate_luks2(struct crypt_device *cd,
int keyslot,
const char *name,
const char *passphrase,
size_t passphrase_size,
uint32_t flags)
{
crypt_reencrypt_info ri;
ri = LUKS2_reencrypt_status(&cd->u.luks2.hdr);
if (ri == CRYPT_REENCRYPT_INVALID)
return -EINVAL;
if (ri > CRYPT_REENCRYPT_NONE) {
log_err(cd, _("This operation is not supported for this device type."));
return -ENOTSUP;
}
return _open_and_activate(cd, keyslot, name, passphrase, passphrase_size, flags);
}
#endif
static int _activate_by_passphrase(struct crypt_device *cd,
const char *name,
@@ -4527,7 +4688,10 @@ int crypt_activate_by_signed_key(struct crypt_device *cd,
return -EINVAL;
}
log_dbg(cd, "%s volume %s by %skey.", name ? "Activating" : "Checking", name ?: "", signature ? "signed " : "");
if (name)
log_dbg(cd, "Activating volume %s by %skey.", name, signature ? "signed " : "");
else
log_dbg(cd, "Checking volume by key.");
if (cd->u.verity.hdr.flags & CRYPT_VERITY_ROOT_HASH_SIGNATURE && !signature) {
log_err(cd, _("Root hash signature required."));
@@ -4821,10 +4985,6 @@ int crypt_volume_key_verify(struct crypt_device *cd,
else
r = -EINVAL;
if (r == -EPERM)
log_err(cd, _("Volume key does not match the volume."));
crypt_free_volume_key(vk);
return r >= 0 ? 0 : r;
@@ -4903,13 +5063,6 @@ crypt_status_info crypt_status(struct crypt_device *cd, const char *name)
return CRYPT_INACTIVE;
}
static void hexprint(struct crypt_device *cd, const char *d, int n, const char *sep)
{
int i;
for(i = 0; i < n; i++)
log_std(cd, "%02hhx%s", (const char)d[i], sep);
}
static int _luks_dump(struct crypt_device *cd)
{
int i;
@@ -4922,12 +5075,12 @@ static int _luks_dump(struct crypt_device *cd)
log_std(cd, "Payload offset:\t%" PRIu32 "\n", cd->u.luks1.hdr.payloadOffset);
log_std(cd, "MK bits: \t%" PRIu32 "\n", cd->u.luks1.hdr.keyBytes * 8);
log_std(cd, "MK digest: \t");
hexprint(cd, cd->u.luks1.hdr.mkDigest, LUKS_DIGESTSIZE, " ");
crypt_log_hex(cd, cd->u.luks1.hdr.mkDigest, LUKS_DIGESTSIZE, " ", 0, NULL);
log_std(cd, "\n");
log_std(cd, "MK salt: \t");
hexprint(cd, cd->u.luks1.hdr.mkDigestSalt, LUKS_SALTSIZE/2, " ");
crypt_log_hex(cd, cd->u.luks1.hdr.mkDigestSalt, LUKS_SALTSIZE/2, " ", 0, NULL);
log_std(cd, "\n \t");
hexprint(cd, cd->u.luks1.hdr.mkDigestSalt+LUKS_SALTSIZE/2, LUKS_SALTSIZE/2, " ");
crypt_log_hex(cd, cd->u.luks1.hdr.mkDigestSalt+LUKS_SALTSIZE/2, LUKS_SALTSIZE/2, " ", 0, NULL);
log_std(cd, "\n");
log_std(cd, "MK iterations: \t%" PRIu32 "\n", cd->u.luks1.hdr.mkDigestIterations);
log_std(cd, "UUID: \t%s\n\n", cd->u.luks1.hdr.uuid);
@@ -4937,11 +5090,11 @@ static int _luks_dump(struct crypt_device *cd)
log_std(cd, "\tIterations: \t%" PRIu32 "\n",
cd->u.luks1.hdr.keyblock[i].passwordIterations);
log_std(cd, "\tSalt: \t");
hexprint(cd, cd->u.luks1.hdr.keyblock[i].passwordSalt,
LUKS_SALTSIZE/2, " ");
crypt_log_hex(cd, cd->u.luks1.hdr.keyblock[i].passwordSalt,
LUKS_SALTSIZE/2, " ", 0, NULL);
log_std(cd, "\n\t \t");
hexprint(cd, cd->u.luks1.hdr.keyblock[i].passwordSalt +
LUKS_SALTSIZE/2, LUKS_SALTSIZE/2, " ");
crypt_log_hex(cd, cd->u.luks1.hdr.keyblock[i].passwordSalt +
LUKS_SALTSIZE/2, LUKS_SALTSIZE/2, " ", 0, NULL);
log_std(cd, "\n");
log_std(cd, "\tKey material offset:\t%" PRIu32 "\n",
@@ -4955,29 +5108,6 @@ static int _luks_dump(struct crypt_device *cd)
return 0;
}
static int _verity_dump(struct crypt_device *cd)
{
log_std(cd, "VERITY header information for %s\n", mdata_device_path(cd));
log_std(cd, "UUID: \t%s\n", cd->u.verity.uuid ?: "");
log_std(cd, "Hash type: \t%u\n", cd->u.verity.hdr.hash_type);
log_std(cd, "Data blocks: \t%" PRIu64 "\n", cd->u.verity.hdr.data_size);
log_std(cd, "Data block size: \t%u\n", cd->u.verity.hdr.data_block_size);
log_std(cd, "Hash block size: \t%u\n", cd->u.verity.hdr.hash_block_size);
log_std(cd, "Hash algorithm: \t%s\n", cd->u.verity.hdr.hash_name);
log_std(cd, "Salt: \t");
if (cd->u.verity.hdr.salt_size)
hexprint(cd, cd->u.verity.hdr.salt, cd->u.verity.hdr.salt_size, "");
else
log_std(cd, "-");
log_std(cd, "\n");
if (cd->u.verity.root_hash) {
log_std(cd, "Root hash: \t");
hexprint(cd, cd->u.verity.root_hash, cd->u.verity.root_hash_size, "");
log_std(cd, "\n");
}
return 0;
}
int crypt_dump(struct crypt_device *cd)
{
if (!cd)
@@ -4987,7 +5117,9 @@ int crypt_dump(struct crypt_device *cd)
else if (isLUKS2(cd->type))
return LUKS2_hdr_dump(cd, &cd->u.luks2.hdr);
else if (isVERITY(cd->type))
return _verity_dump(cd);
return VERITY_dump(cd, &cd->u.verity.hdr,
cd->u.verity.root_hash, cd->u.verity.root_hash_size,
cd->u.verity.fec_device);
else if (isTCRYPT(cd->type))
return TCRYPT_dump(cd, &cd->u.tcrypt.hdr, &cd->u.tcrypt.params);
else if (isINTEGRITY(cd->type))
@@ -5115,13 +5247,15 @@ const char *crypt_get_integrity(struct crypt_device *cd)
/* INTERNAL only */
int crypt_get_integrity_key_size(struct crypt_device *cd)
{
int key_size = 0;
if (isINTEGRITY(cd->type))
return INTEGRITY_key_size(cd, crypt_get_integrity(cd));
key_size = INTEGRITY_key_size(crypt_get_integrity(cd));
if (isLUKS2(cd->type))
return INTEGRITY_key_size(cd, crypt_get_integrity(cd));
key_size = INTEGRITY_key_size(crypt_get_integrity(cd));
return 0;
return key_size > 0 ? key_size : 0;
}
/* INTERNAL only */
@@ -5131,7 +5265,7 @@ int crypt_get_integrity_tag_size(struct crypt_device *cd)
return cd->u.integrity.params.tag_size;
if (isLUKS2(cd->type))
return INTEGRITY_tag_size(cd, crypt_get_integrity(cd),
return INTEGRITY_tag_size(crypt_get_integrity(cd),
crypt_get_cipher(cd),
crypt_get_cipher_mode(cd));
return 0;
@@ -5485,7 +5619,7 @@ crypt_keyslot_priority crypt_keyslot_get_priority(struct crypt_device *cd, int k
return CRYPT_SLOT_PRIORITY_INVALID;
if (isLUKS2(cd->type))
return LUKS2_keyslot_priority_get(cd, &cd->u.luks2.hdr, keyslot);
return LUKS2_keyslot_priority_get(&cd->u.luks2.hdr, keyslot);
return CRYPT_SLOT_PRIORITY_NORMAL;
}
@@ -5577,7 +5711,7 @@ int crypt_get_integrity_info(struct crypt_device *cd,
ip->integrity = LUKS2_get_integrity(&cd->u.luks2.hdr, CRYPT_DEFAULT_SEGMENT);
ip->integrity_key_size = crypt_get_integrity_key_size(cd);
ip->tag_size = INTEGRITY_tag_size(cd, ip->integrity, crypt_get_cipher(cd), crypt_get_cipher_mode(cd));
ip->tag_size = INTEGRITY_tag_size(ip->integrity, crypt_get_cipher(cd), crypt_get_cipher_mode(cd));
ip->journal_integrity = NULL;
ip->journal_integrity_key_size = 0;
@@ -5690,6 +5824,10 @@ int crypt_activate_by_token_pin(struct crypt_device *cd, const char *name,
if ((flags & CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY) && name)
return -EINVAL;
r = _activate_check_status(cd, name, flags & CRYPT_ACTIVATE_REFRESH);
if (r < 0)
return r;
return LUKS2_token_open_and_activate(cd, &cd->u.luks2.hdr, token, name, type, pin, pin_size, flags, usrptr);
}
@@ -5711,7 +5849,7 @@ int crypt_token_json_get(struct crypt_device *cd, int token, const char **json)
if ((r = _onlyLUKS2(cd, CRYPT_CD_UNRESTRICTED, 0)))
return r;
return LUKS2_token_json_get(cd, &cd->u.luks2.hdr, token, json) ?: token;
return LUKS2_token_json_get(&cd->u.luks2.hdr, token, json) ?: token;
}
int crypt_token_json_set(struct crypt_device *cd, int token, const char *json)
@@ -5777,7 +5915,7 @@ int crypt_token_luks2_keyring_get(struct crypt_device *cd,
return -EINVAL;
}
return LUKS2_token_keyring_get(cd, &cd->u.luks2.hdr, token, params);
return LUKS2_token_keyring_get(&cd->u.luks2.hdr, token, params);
}
int crypt_token_luks2_keyring_set(struct crypt_device *cd,
@@ -5829,7 +5967,7 @@ int crypt_token_is_assigned(struct crypt_device *cd, int token, int keyslot)
if ((r = _onlyLUKS2(cd, CRYPT_CD_QUIET | CRYPT_CD_UNRESTRICTED, 0)))
return r;
return LUKS2_token_is_assigned(cd, &cd->u.luks2.hdr, keyslot, token);
return LUKS2_token_is_assigned(&cd->u.luks2.hdr, keyslot, token);
}
/* Internal only */
@@ -6198,7 +6336,13 @@ void crypt_serialize_unlock(struct crypt_device *cd)
crypt_reencrypt_info crypt_reencrypt_status(struct crypt_device *cd,
struct crypt_params_reencrypt *params)
{
if (!cd || !isLUKS2(cd->type))
if (params)
memset(params, 0, sizeof(*params));
if (!cd || !isLUKS(cd->type))
return CRYPT_REENCRYPT_INVALID;
if (isLUKS1(cd->type))
return CRYPT_REENCRYPT_NONE;
if (_onlyLUKS2(cd, CRYPT_CD_QUIET, CRYPT_REQUIREMENT_ONLINE_REENCRYPT))

View File

@@ -1,8 +1,8 @@
/*
* TCRYPT (TrueCrypt-compatible) and VeraCrypt volume handling
*
* Copyright (C) 2012-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2021 Milan Broz
* Copyright (C) 2012-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2022 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -264,8 +264,8 @@ static int TCRYPT_hdr_from_disk(struct crypt_device *cd,
*/
static void TCRYPT_swab_le(char *buf)
{
uint32_t *l = (uint32_t*)&buf[0];
uint32_t *r = (uint32_t*)&buf[4];
uint32_t *l = VOIDP_CAST(uint32_t*)&buf[0];
uint32_t *r = VOIDP_CAST(uint32_t*)&buf[4];
*l = swab32(*l);
*r = swab32(*r);
}
@@ -588,7 +588,6 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
(tcrypt_kdf[i].veracrypt_pim_mult * params->veracrypt_pim);
} else
iterations = tcrypt_kdf[i].iterations;
/* Derive header key */
log_dbg(cd, "TCRYPT: trying KDF: %s-%s-%d%s.",
tcrypt_kdf[i].name, tcrypt_kdf[i].hash, tcrypt_kdf[i].iterations,
@@ -601,6 +600,8 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
if (r < 0) {
log_verbose(cd, _("PBKDF2 hash algorithm %s not available, skipping."),
tcrypt_kdf[i].hash);
skipped++;
r = -EPERM;
continue;
}
@@ -609,16 +610,18 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
if (r == -ENOENT) {
skipped++;
r = -EPERM;
continue;
}
if (r != -EPERM)
break;
}
if ((r < 0 && r != -EPERM && skipped && skipped == i) || r == -ENOTSUP) {
if ((r < 0 && skipped && skipped == i) || r == -ENOTSUP) {
log_err(cd, _("Required kernel crypto interface not available."));
#ifdef ENABLE_AF_ALG
log_err(cd, _("Ensure you have algif_skcipher kernel module loaded."));
#endif
r = -ENOTSUP;
}
if (r < 0)
goto out;
@@ -827,7 +830,10 @@ int TCRYPT_activate(struct crypt_device *cd,
strncpy(dm_name, name, sizeof(dm_name)-1);
dmd.flags = flags;
} else {
snprintf(dm_name, sizeof(dm_name), "%s_%d", name, i-1);
if (snprintf(dm_name, sizeof(dm_name), "%s_%d", name, i-1) < 0) {
r = -EINVAL;
break;
}
dmd.flags = flags | CRYPT_ACTIVATE_PRIVATE;
}
@@ -835,8 +841,10 @@ int TCRYPT_activate(struct crypt_device *cd,
vk->key, hdr->d.keys);
if (algs->chain_count != i) {
snprintf(dm_dev_name, sizeof(dm_dev_name), "%s/%s_%d",
dm_get_dir(), name, i);
if (snprintf(dm_dev_name, sizeof(dm_dev_name), "%s/%s_%d", dm_get_dir(), name, i) < 0) {
r = -EINVAL;
break;
}
r = device_alloc(cd, &device, dm_dev_name);
if (r)
break;

View File

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

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