mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-09 18:00:01 +01:00
Compare commits
475 Commits
v2.5.0-rc1
...
v2.7.0-rc0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f725123e4a | ||
|
|
e1ef5214e7 | ||
|
|
b44c2ce071 | ||
|
|
5d50617594 | ||
|
|
cea9c2972e | ||
|
|
1e9d31e0e4 | ||
|
|
d3a8393476 | ||
|
|
70a151242f | ||
|
|
ec4e2faf14 | ||
|
|
e4a845c51e | ||
|
|
d64203a018 | ||
|
|
c0dfd1178d | ||
|
|
b3f1f611cd | ||
|
|
86498858fc | ||
|
|
403d12d52c | ||
|
|
fcf6f8febf | ||
|
|
06d02f4766 | ||
|
|
6262da3a11 | ||
|
|
dfbb7752b5 | ||
|
|
6b2cf68713 | ||
|
|
0f51b5bacb | ||
|
|
d3cc5e846a | ||
|
|
722c77c883 | ||
|
|
20c8096cc8 | ||
|
|
8c0a943e5c | ||
|
|
5ef1878b34 | ||
|
|
836e5e4539 | ||
|
|
0328d61f29 | ||
|
|
31f82fd37c | ||
|
|
9ca46971f2 | ||
|
|
7aeb1c3aea | ||
|
|
cf7874de4b | ||
|
|
d82a1843ba | ||
|
|
9a5a3855a0 | ||
|
|
83bb3648e3 | ||
|
|
564379618a | ||
|
|
04a20e9b7d | ||
|
|
11ab2f0d9e | ||
|
|
7d4628e379 | ||
|
|
a176f29dc4 | ||
|
|
a8168eb854 | ||
|
|
98f2b9c136 | ||
|
|
0e44494aba | ||
|
|
371cfc4394 | ||
|
|
860550b3c6 | ||
|
|
2a9752b6c8 | ||
|
|
4543a445a0 | ||
|
|
ee31159c68 | ||
|
|
029d4bdd57 | ||
|
|
89e0ef96c2 | ||
|
|
f623eb2e99 | ||
|
|
d09b27a170 | ||
|
|
abf7e3e359 | ||
|
|
79444bc615 | ||
|
|
0154893ad5 | ||
|
|
b23e9f32f2 | ||
|
|
1b7211f013 | ||
|
|
b9ba5ec14d | ||
|
|
af8c53a823 | ||
|
|
45ddc623bc | ||
|
|
52b2dc5148 | ||
|
|
e6590e808a | ||
|
|
7d17b09d41 | ||
|
|
fea8b82e8d | ||
|
|
32fbac17b1 | ||
|
|
4081037bdb | ||
|
|
f15b2ffdec | ||
|
|
800ec5d1ed | ||
|
|
7b6feb20b4 | ||
|
|
0c9258484a | ||
|
|
385c0afebe | ||
|
|
1f007061d6 | ||
|
|
20bfec91d8 | ||
|
|
15c3a2a2a9 | ||
|
|
717bd0665d | ||
|
|
8f442bc97a | ||
|
|
84682f6271 | ||
|
|
a18fe71d8d | ||
|
|
593f22a9a8 | ||
|
|
edc2505923 | ||
|
|
1f5b229a0e | ||
|
|
742bb0693d | ||
|
|
a5e2a97b53 | ||
|
|
0236b82802 | ||
|
|
cfe257e10e | ||
|
|
05d3cb9196 | ||
|
|
df9976e2a7 | ||
|
|
f0b556b2d4 | ||
|
|
ca0c9c765e | ||
|
|
57bd4e0e66 | ||
|
|
fde3e881fc | ||
|
|
d011ba710c | ||
|
|
6296e8d4f8 | ||
|
|
cdce1d96f0 | ||
|
|
305688d678 | ||
|
|
f6c464844d | ||
|
|
0404e65da8 | ||
|
|
2d54e0bc58 | ||
|
|
05634f272c | ||
|
|
51a1e218cf | ||
|
|
7ae109dccd | ||
|
|
c16f644c9f | ||
|
|
748cff228d | ||
|
|
f147c823ea | ||
|
|
c497d8baa9 | ||
|
|
4872a14830 | ||
|
|
b0610e1f73 | ||
|
|
1c7dd08c63 | ||
|
|
6df6ac49bf | ||
|
|
1c31b93e5c | ||
|
|
1969b6be2f | ||
|
|
464fe987f9 | ||
|
|
ab71eff3b9 | ||
|
|
9b768cd401 | ||
|
|
c417c70a78 | ||
|
|
8c87958b3b | ||
|
|
81574d0f14 | ||
|
|
eb4a3f2904 | ||
|
|
f18d370b4a | ||
|
|
f70bf71dff | ||
|
|
5628de1f65 | ||
|
|
ffd630973b | ||
|
|
95425d45dd | ||
|
|
b31863c052 | ||
|
|
e14316f132 | ||
|
|
54ada7b8e3 | ||
|
|
e43de57fac | ||
|
|
e5bd99665e | ||
|
|
1aab3afcba | ||
|
|
d0ef2d84be | ||
|
|
6bcd9ed52c | ||
|
|
1f2dac34d0 | ||
|
|
a674fb968c | ||
|
|
138da3e73a | ||
|
|
1b25cc5ed7 | ||
|
|
cb184bcbb8 | ||
|
|
aea21309ed | ||
|
|
e2c413e5a9 | ||
|
|
cfbba1819b | ||
|
|
58385d68d8 | ||
|
|
28e1c95c22 | ||
|
|
6751b43424 | ||
|
|
50207333f1 | ||
|
|
b65fb6072e | ||
|
|
a7821c3d9e | ||
|
|
01f1512730 | ||
|
|
ef46ded7b4 | ||
|
|
28da4ed72d | ||
|
|
e1d494c4e1 | ||
|
|
5cf9e28530 | ||
|
|
570d3ad4e4 | ||
|
|
b60ffe9e06 | ||
|
|
fc04761cdc | ||
|
|
0a805d325c | ||
|
|
ad3013dfe4 | ||
|
|
7754660409 | ||
|
|
928061f1f0 | ||
|
|
4d487d5dcf | ||
|
|
33bf0c6ae9 | ||
|
|
b7c361df94 | ||
|
|
ace8b8578c | ||
|
|
decbe09fb3 | ||
|
|
5716f959a7 | ||
|
|
446ad76011 | ||
|
|
b9cc0129c9 | ||
|
|
fc4151f77e | ||
|
|
b8711faf92 | ||
|
|
1f01eea60e | ||
|
|
10847d7100 | ||
|
|
e13840c5cb | ||
|
|
9c5f555930 | ||
|
|
33a3d1ba7b | ||
|
|
53aa5f6c4f | ||
|
|
2712882aa3 | ||
|
|
5042ec2cd0 | ||
|
|
d6107bf241 | ||
|
|
47ac021c03 | ||
|
|
969e67e743 | ||
|
|
6a8fa14007 | ||
|
|
fd91de82ad | ||
|
|
926679f7f1 | ||
|
|
11d8c58c72 | ||
|
|
716cf78da6 | ||
|
|
dff9ee8c8c | ||
|
|
80a001232f | ||
|
|
841c681825 | ||
|
|
438cf1d1b3 | ||
|
|
91d8ab7f20 | ||
|
|
d173514b81 | ||
|
|
9a92c6a677 | ||
|
|
6721d3a8b2 | ||
|
|
7893c33d71 | ||
|
|
23dd988545 | ||
|
|
c81c3d1fc0 | ||
|
|
7859673bd2 | ||
|
|
34953cb10f | ||
|
|
bc426bba67 | ||
|
|
234ca010e2 | ||
|
|
32febb4483 | ||
|
|
b6eaa236bc | ||
|
|
a617c23ccc | ||
|
|
e4c2aa64b5 | ||
|
|
2a2027ee3e | ||
|
|
192ff16cd8 | ||
|
|
17a0b1e2d3 | ||
|
|
c2045b9585 | ||
|
|
9d5e45be54 | ||
|
|
d4840d46e1 | ||
|
|
cca490a0b8 | ||
|
|
a752e571ab | ||
|
|
d209bb27b4 | ||
|
|
ccf48bb28e | ||
|
|
76c0a81318 | ||
|
|
b297b59ba2 | ||
|
|
f686fc7108 | ||
|
|
9a96e260aa | ||
|
|
cb177c5076 | ||
|
|
4ebc6a1616 | ||
|
|
1c65c1c3d1 | ||
|
|
b12e9534c3 | ||
|
|
8b3162069e | ||
|
|
27f8e5c08f | ||
|
|
899bad8c06 | ||
|
|
62aa392205 | ||
|
|
428c2f323b | ||
|
|
045ed9d485 | ||
|
|
114a13af84 | ||
|
|
9d5327c37b | ||
|
|
1d109a114c | ||
|
|
e455110c8e | ||
|
|
e244c8c543 | ||
|
|
384b7f2e94 | ||
|
|
1f805cb35a | ||
|
|
ec0efe7068 | ||
|
|
4fc619853d | ||
|
|
72f799b393 | ||
|
|
5d622102c6 | ||
|
|
93c5013577 | ||
|
|
83d3c04347 | ||
|
|
53668a0203 | ||
|
|
fcf2ce9073 | ||
|
|
9364fd5931 | ||
|
|
f5253e6826 | ||
|
|
f697444d14 | ||
|
|
06b52c83b3 | ||
|
|
18a7427bad | ||
|
|
23dfb78823 | ||
|
|
5da3fd8622 | ||
|
|
8b90d16762 | ||
|
|
31fe5ccd19 | ||
|
|
4339dd0bff | ||
|
|
7e6b8fc0d7 | ||
|
|
ace015a3e5 | ||
|
|
5ed0358f12 | ||
|
|
5a33f1dc9a | ||
|
|
ae80dc0e8e | ||
|
|
3f6d5470e3 | ||
|
|
4cd8d1efdb | ||
|
|
48d6f85cc3 | ||
|
|
5216002773 | ||
|
|
482c819ea2 | ||
|
|
0622b51634 | ||
|
|
7bbfccbbfa | ||
|
|
7c25db5bf3 | ||
|
|
034041a922 | ||
|
|
776baf4ccc | ||
|
|
d1a607e0b2 | ||
|
|
1682e72bf5 | ||
|
|
8e7f07841e | ||
|
|
50e8879528 | ||
|
|
c18dcfaa0b | ||
|
|
be088b8de8 | ||
|
|
de221b4ea7 | ||
|
|
170161b9b6 | ||
|
|
a649d734b6 | ||
|
|
15c998d523 | ||
|
|
14eff9480d | ||
|
|
4621580802 | ||
|
|
4bede447c8 | ||
|
|
b08212ea45 | ||
|
|
5a976ad1d9 | ||
|
|
0e4182874b | ||
|
|
487e85fdec | ||
|
|
32344d5a84 | ||
|
|
ebb16a511c | ||
|
|
51200eb6da | ||
|
|
119c57e00e | ||
|
|
700b0f6e36 | ||
|
|
8fff498062 | ||
|
|
2ef2f6017d | ||
|
|
cdfa213ad0 | ||
|
|
dab00bfd4f | ||
|
|
c018558f2d | ||
|
|
3633b81909 | ||
|
|
b23a02b05c | ||
|
|
347c39ca97 | ||
|
|
2d1f1833e8 | ||
|
|
7f09ab67e2 | ||
|
|
f5fb1f1b94 | ||
|
|
005141554f | ||
|
|
cd8f80b7ee | ||
|
|
c7bbae01a6 | ||
|
|
257bc80ae9 | ||
|
|
6c2e64bf75 | ||
|
|
942cea1803 | ||
|
|
e7eab5fec2 | ||
|
|
b0779c6529 | ||
|
|
37d045df00 | ||
|
|
4b95f36804 | ||
|
|
faf3b27f51 | ||
|
|
c85d1351ea | ||
|
|
3b18fe2b23 | ||
|
|
e96588b8b5 | ||
|
|
c31494abc6 | ||
|
|
819902a33a | ||
|
|
395beb635c | ||
|
|
81c56a8395 | ||
|
|
3333f3e9bb | ||
|
|
b086430877 | ||
|
|
01f3f3e66c | ||
|
|
e37d8bdf91 | ||
|
|
8b4a5e5931 | ||
|
|
33d8d19408 | ||
|
|
9bb98d49c0 | ||
|
|
1c5fd5ae10 | ||
|
|
3d1b965c46 | ||
|
|
2770273582 | ||
|
|
f6b6e41951 | ||
|
|
03059fae75 | ||
|
|
ba9757b14b | ||
|
|
cd5bd1c773 | ||
|
|
a5c7bba6ee | ||
|
|
4bce6d5962 | ||
|
|
cb9deaf354 | ||
|
|
0ce5de9c1c | ||
|
|
35071c6d50 | ||
|
|
af6ea01997 | ||
|
|
1d5d6d73a5 | ||
|
|
1ffc9d967c | ||
|
|
1f4c7a83f9 | ||
|
|
f312ba6256 | ||
|
|
5186f49613 | ||
|
|
616d3cd493 | ||
|
|
cd2e22cb87 | ||
|
|
54073ef65f | ||
|
|
3e7c1e46fd | ||
|
|
ea05e4307e | ||
|
|
f35b9cc99b | ||
|
|
d4888fba86 | ||
|
|
f9e778a2cd | ||
|
|
69025faa24 | ||
|
|
871000fa05 | ||
|
|
cb53c643c2 | ||
|
|
f771f9a694 | ||
|
|
9009a2de26 | ||
|
|
6a279e21c9 | ||
|
|
124367f365 | ||
|
|
55c39d7d16 | ||
|
|
f7e2ed956b | ||
|
|
0e6264c53c | ||
|
|
01c16111d7 | ||
|
|
49ab658c9c | ||
|
|
888c6321df | ||
|
|
20f8c09195 | ||
|
|
57d4c677bd | ||
|
|
cde7b90735 | ||
|
|
3e4c69a017 | ||
|
|
19c15a652f | ||
|
|
2390395150 | ||
|
|
9a9ddc7d22 | ||
|
|
3616da631f | ||
|
|
b380fa7494 | ||
|
|
23f49eca43 | ||
|
|
00baa92756 | ||
|
|
8bbb018a01 | ||
|
|
c464d61995 | ||
|
|
d260ca6680 | ||
|
|
d05a2a6c99 | ||
|
|
758a2974f5 | ||
|
|
4b5e814094 | ||
|
|
98f5e0538a | ||
|
|
f03180d06a | ||
|
|
39b94ae530 | ||
|
|
3690d5f532 | ||
|
|
e595940637 | ||
|
|
dab939c3c9 | ||
|
|
cc276527c7 | ||
|
|
27429daf5d | ||
|
|
b20821a520 | ||
|
|
46b465ff2e | ||
|
|
d8fd9caa6a | ||
|
|
dad11f97ce | ||
|
|
c06e853938 | ||
|
|
c35e4479d5 | ||
|
|
8585fb29eb | ||
|
|
97b3926655 | ||
|
|
a3f248df9b | ||
|
|
e1a84607cc | ||
|
|
2f4267ba81 | ||
|
|
99e8ee6b7e | ||
|
|
f58aff21a9 | ||
|
|
de8a27ae02 | ||
|
|
b9b08eba7c | ||
|
|
82b56300cd | ||
|
|
9f8fe3da16 | ||
|
|
50803ebacb | ||
|
|
5fce0c2ad1 | ||
|
|
2e29eb7906 | ||
|
|
b867f0b578 | ||
|
|
1745fd5aea | ||
|
|
90ad841a45 | ||
|
|
0397cac878 | ||
|
|
033ff34109 | ||
|
|
0d61e4c20f | ||
|
|
b4863897fe | ||
|
|
eac02f5605 | ||
|
|
94e8a7ca96 | ||
|
|
b183bb25e2 | ||
|
|
09ac5321f4 | ||
|
|
c1302555b7 | ||
|
|
01c032df04 | ||
|
|
88d9524e6c | ||
|
|
4b47091b85 | ||
|
|
b9bf657449 | ||
|
|
21d87a246e | ||
|
|
db65a5ceac | ||
|
|
132027bafa | ||
|
|
f6fd73aea5 | ||
|
|
5b001b7962 | ||
|
|
429afe8fc3 | ||
|
|
abfb5e374f | ||
|
|
f8c79f9a95 | ||
|
|
190e4fc033 | ||
|
|
093adfc5f9 | ||
|
|
a009614191 | ||
|
|
75111d382b | ||
|
|
1cc6c82f21 | ||
|
|
2c555bd4a0 | ||
|
|
3f3f5a6aab | ||
|
|
c6ed1becd7 | ||
|
|
766ac108ec | ||
|
|
94e5d227ce | ||
|
|
f96e19147c | ||
|
|
05dbf04d82 | ||
|
|
b9b7c3a9bd | ||
|
|
17e6d2053a | ||
|
|
912109ae66 | ||
|
|
25b877a403 | ||
|
|
8270b72bfc | ||
|
|
9c0cdcc2f9 | ||
|
|
1e2cb2d419 | ||
|
|
3e178caeaf | ||
|
|
803957cd3e | ||
|
|
bf4bfeac8a | ||
|
|
090dca635a | ||
|
|
0369ffdcc1 | ||
|
|
648a85ed3a | ||
|
|
8f3884e0d7 | ||
|
|
289d5e5891 | ||
|
|
b37d04975d | ||
|
|
6578dac2f9 | ||
|
|
dc5f284e42 | ||
|
|
32149e4ee7 | ||
|
|
0e4857ee81 | ||
|
|
06dd06ea27 | ||
|
|
03eb8f860a | ||
|
|
fbcef71c41 | ||
|
|
8315ada3b0 | ||
|
|
782dae9292 | ||
|
|
96c0544527 | ||
|
|
cb7e2c6433 | ||
|
|
f0da65cc63 | ||
|
|
a76c96d361 | ||
|
|
3106b4e2c1 | ||
|
|
5d711c000f |
31
.codeql-config.yml
Normal file
31
.codeql-config.yml
Normal file
@@ -0,0 +1,31 @@
|
||||
name: "Cryptsetup CodeQL config"
|
||||
|
||||
query-filters:
|
||||
- exclude:
|
||||
id: cpp/fixme-comment
|
||||
- exclude:
|
||||
id: cpp/empty-block
|
||||
- exclude:
|
||||
id: cpp/poorly-documented-function
|
||||
- exclude:
|
||||
id: cpp/loop-variable-changed
|
||||
- exclude:
|
||||
id: cpp/empty-if
|
||||
- exclude:
|
||||
id: cpp/long-switch
|
||||
- exclude:
|
||||
id: cpp/complex-condition
|
||||
- exclude:
|
||||
id: cpp/commented-out-code
|
||||
|
||||
# These produce many false positives
|
||||
- exclude:
|
||||
id: cpp/uninitialized-local
|
||||
- exclude:
|
||||
id: cpp/path-injection
|
||||
- exclude:
|
||||
id: cpp/missing-check-scanf
|
||||
|
||||
# CodeQL should understand coverity [toctou] comments
|
||||
- exclude:
|
||||
id: cpp/toctou-race-condition
|
||||
4
.github/workflows/cibuild-setup-ubuntu.sh
vendored
4
.github/workflows/cibuild-setup-ubuntu.sh
vendored
@@ -4,10 +4,10 @@ set -ex
|
||||
|
||||
PACKAGES=(
|
||||
git make autoconf automake autopoint pkg-config libtool libtool-bin
|
||||
gettext libssl-dev libdevmapper-dev libpopt-dev uuid-dev libsepol1-dev
|
||||
gettext libssl-dev libdevmapper-dev libpopt-dev uuid-dev libsepol-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
|
||||
asciidoctor meson ninja-build
|
||||
)
|
||||
|
||||
COMPILER="${COMPILER:?}"
|
||||
|
||||
50
.github/workflows/codeql.yml
vendored
Normal file
50
.github/workflows/codeql.yml
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
- 'wip-luks2'
|
||||
- 'v2.3.x'
|
||||
- 'v2.4.x'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'mbroz/cryptsetup'
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ matrix.language }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
permissions:
|
||||
actions: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'cpp' ]
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
queries: +security-extended,security-and-quality
|
||||
config-file: .codeql-config.yml
|
||||
|
||||
- name: Install dependencies
|
||||
run: sudo -E .github/workflows/cibuild-setup-ubuntu.sh
|
||||
env: { COMPILER: "gcc", COMPILER_VERSION: "11", RUN_SSH_PLUGIN_TEST: "1" }
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -58,3 +58,4 @@ tests/unit-utils-io
|
||||
tests/vectors-test
|
||||
tests/test-symbols-list.h
|
||||
tests/all-symbols-test
|
||||
tests/fuzz/LUKS2.pb*
|
||||
|
||||
@@ -15,6 +15,9 @@ include:
|
||||
- local: .gitlab/ci/annocheck.yml
|
||||
- local: .gitlab/ci/csmock.yml
|
||||
- local: .gitlab/ci/gitlab-shared-docker.yml
|
||||
- local: .gitlab/ci/compilation-various-disables.yml
|
||||
- local: .gitlab/ci/compilation-gcc.gitlab-ci.yml
|
||||
- local: .gitlab/ci/compilation-clang.gitlab-ci.yml
|
||||
- local: .gitlab/ci/alpinelinux.yml
|
||||
- local: .gitlab/ci/ubuntu-32bit.yml
|
||||
- local: .gitlab/ci/cifuzz.yml
|
||||
|
||||
@@ -23,11 +23,11 @@ test-main-commit-job-alpinelinux:
|
||||
variables:
|
||||
RUN_SSH_PLUGIN_TEST: "0"
|
||||
rules:
|
||||
- if: $RUN_SYSTEMD_PLUGIN_TEST != null
|
||||
when: never
|
||||
- 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
|
||||
@@ -44,6 +44,8 @@ test-mergerq-job-alpinelinux:
|
||||
variables:
|
||||
RUN_SSH_PLUGIN_TEST: "0"
|
||||
rules:
|
||||
- if: $RUN_SYSTEMD_PLUGIN_TEST != null
|
||||
when: never
|
||||
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
|
||||
when: never
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
|
||||
@@ -14,6 +14,4 @@ test-main-commit-job-annocheck:
|
||||
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
|
||||
- sudo /opt/run-annocheck.sh
|
||||
|
||||
@@ -27,6 +27,8 @@ test-main-commit-centos-stream9:
|
||||
variables:
|
||||
RUN_SSH_PLUGIN_TEST: "1"
|
||||
rules:
|
||||
- if: $RUN_SYSTEMD_PLUGIN_TEST != null
|
||||
when: never
|
||||
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
|
||||
when: never
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
|
||||
@@ -46,6 +48,8 @@ test-mergerq-centos-stream9:
|
||||
variables:
|
||||
RUN_SSH_PLUGIN_TEST: "1"
|
||||
rules:
|
||||
- if: $RUN_SYSTEMD_PLUGIN_TEST != null
|
||||
when: never
|
||||
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
|
||||
when: never
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
|
||||
@@ -4,10 +4,10 @@ set -ex
|
||||
|
||||
PACKAGES=(
|
||||
git make autoconf automake autopoint pkg-config libtool libtool-bin
|
||||
gettext libssl-dev libdevmapper-dev libpopt-dev uuid-dev libsepol1-dev
|
||||
gettext libssl-dev libdevmapper-dev libpopt-dev uuid-dev libsepol-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
|
||||
sharutils dmsetup jq xxd expect keyutils netcat-openbsd passwd openssh-client
|
||||
sshpass asciidoctor
|
||||
)
|
||||
|
||||
COMPILER="${COMPILER:?}"
|
||||
|
||||
46
.gitlab/ci/cifuzz.yml
Normal file
46
.gitlab/ci/cifuzz.yml
Normal file
@@ -0,0 +1,46 @@
|
||||
cifuzz:
|
||||
variables:
|
||||
OSS_FUZZ_PROJECT_NAME: cryptsetup
|
||||
CFL_PLATFORM: gitlab
|
||||
CIFUZZ_DEBUG: "True"
|
||||
FUZZ_SECONDS: 300 # 5 minutes per fuzzer
|
||||
ARCHITECTURE: "x86_64"
|
||||
DRY_RUN: "False"
|
||||
LOW_DISK_SPACE: "True"
|
||||
BAD_BUILD_CHECK: "True"
|
||||
LANGUAGE: "c"
|
||||
DOCKER_HOST: "tcp://docker:2375"
|
||||
DOCKER_IN_DOCKER: "true"
|
||||
DOCKER_DRIVER: overlay2
|
||||
DOCKER_TLS_CERTDIR: ""
|
||||
image:
|
||||
name: gcr.io/oss-fuzz-base/cifuzz-base
|
||||
entrypoint: [""]
|
||||
services:
|
||||
- docker:dind
|
||||
|
||||
stage: test
|
||||
parallel:
|
||||
matrix:
|
||||
- SANITIZER: [address, undefined, memory]
|
||||
rules:
|
||||
# Default code change.
|
||||
# - if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
# variables:
|
||||
# MODE: "code-change"
|
||||
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
|
||||
when: never
|
||||
- if: $BUILD_AND_RUN_FUZZERS != null
|
||||
before_script:
|
||||
# Get gitlab's container id.
|
||||
- export CFL_CONTAINER_ID=`cut -c9- < /proc/1/cpuset`
|
||||
script:
|
||||
# Will build and run the fuzzers.
|
||||
# We use a hack to override CI_JOB_ID, because otherwise a bad path is used
|
||||
# in GitLab CI environment
|
||||
- CI_JOB_ID="$CI_PROJECT_NAMESPACE/$CI_PROJECT_TITLE" python3 "/opt/oss-fuzz/infra/cifuzz/cifuzz_combined_entrypoint.py"
|
||||
artifacts:
|
||||
# Upload artifacts when a crash makes the job fail.
|
||||
when: always
|
||||
paths:
|
||||
- artifacts/
|
||||
@@ -25,10 +25,9 @@ EXTRA="\
|
||||
-Wswitch \
|
||||
-Wmissing-format-attribute \
|
||||
-Winit-self \
|
||||
-Wdeclaration-after-statement \
|
||||
-Wold-style-definition \
|
||||
-Wno-missing-field-initializers \
|
||||
-Wno-unused-parameter \
|
||||
-Wunused-parameter \
|
||||
-Wno-long-long"
|
||||
|
||||
exec $CLANG $PEDANTIC $CONVERSION \
|
||||
|
||||
@@ -3,6 +3,7 @@ test-clang-compilation:
|
||||
- .gitlab-shared-clang
|
||||
script:
|
||||
- export CFLAGS="-Wall -Werror"
|
||||
- ./autogen.sh
|
||||
- ./configure
|
||||
- make -j
|
||||
- make -j check-programs
|
||||
@@ -13,6 +14,7 @@ test-clang-Wall-script:
|
||||
script:
|
||||
- export CFLAGS="-g -O0"
|
||||
- export CC="$CI_PROJECT_DIR/.gitlab/ci/clang-Wall"
|
||||
- ./autogen.sh
|
||||
- ./configure
|
||||
- make -j CFLAGS="-g -O0 -Werror"
|
||||
- make -j CFLAGS="-g -O0 -Werror" check-programs
|
||||
@@ -21,6 +23,7 @@ test-scan-build:
|
||||
extends:
|
||||
- .gitlab-shared-clang
|
||||
script:
|
||||
- ./autogen.sh
|
||||
- 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
|
||||
|
||||
@@ -3,6 +3,7 @@ test-gcc-compilation:
|
||||
- .gitlab-shared-gcc
|
||||
script:
|
||||
- export CFLAGS="-Wall -Werror"
|
||||
- ./autogen.sh
|
||||
- ./configure
|
||||
- make -j
|
||||
- make -j check-programs
|
||||
@@ -13,6 +14,7 @@ test-gcc-Wall-script:
|
||||
script:
|
||||
- export CFLAGS="-g -O0"
|
||||
- export CC="$CI_PROJECT_DIR/.gitlab/ci/gcc-Wall"
|
||||
- ./autogen.sh
|
||||
- ./configure
|
||||
- make -j CFLAGS="-g -O0 -Werror"
|
||||
- make -j CFLAGS="-g -O0 -Werror" check-programs
|
||||
@@ -22,6 +24,7 @@ test-gcc-fanalyzer:
|
||||
- .gitlab-shared-gcc
|
||||
script:
|
||||
- export CFLAGS="-Wall -Werror -g -O0 -fanalyzer -fdiagnostics-path-format=separate-events"
|
||||
- ./autogen.sh
|
||||
- ./configure
|
||||
- make -j
|
||||
- make -j check-programs
|
||||
|
||||
32
.gitlab/ci/compilation-various-disables.yml
Normal file
32
.gitlab/ci/compilation-various-disables.yml
Normal file
@@ -0,0 +1,32 @@
|
||||
test-gcc-disable-compiles:
|
||||
extends:
|
||||
- .gitlab-shared-gcc
|
||||
parallel:
|
||||
matrix:
|
||||
- DISABLE_FLAGS: [
|
||||
"keyring",
|
||||
"external-tokens ssh-token",
|
||||
"luks2-reencryption",
|
||||
"cryptsetup veritysetup integritysetup",
|
||||
"kernel_crypto",
|
||||
"udev",
|
||||
"internal-argon2",
|
||||
"blkid"
|
||||
]
|
||||
artifacts:
|
||||
name: "meson-build-logs-$CI_COMMIT_REF_NAME"
|
||||
paths:
|
||||
- meson_builddir/meson-logs
|
||||
script:
|
||||
- DEBIAN_FRONTEND=noninteractive apt-get -yq install meson ninja-build
|
||||
- export CFLAGS="-Wall -Werror"
|
||||
- ./autogen.sh
|
||||
- echo "Configuring with --disable-$DISABLE_FLAGS"
|
||||
- ./configure $(for i in $DISABLE_FLAGS; do echo "--disable-$i"; done)
|
||||
- make -j
|
||||
- make -j check-programs
|
||||
- git checkout -f && git clean -xdf
|
||||
- meson -v
|
||||
- echo "Configuring with -D$DISABLE_FLAGS=false"
|
||||
- meson setup meson_builddir $(for i in $DISABLE_FLAGS; do [ "$i" == "internal-argon2" ] && echo "-Dargon-implementation=internal" || echo "-D$i=false"; done)
|
||||
- ninja -C meson_builddir
|
||||
@@ -3,7 +3,7 @@ test-commit-job-csmock:
|
||||
- .dump_kernel_log
|
||||
tags:
|
||||
- libvirt
|
||||
- rhel7-csmock
|
||||
- rhel9-csmock
|
||||
stage: test
|
||||
interruptible: true
|
||||
allow_failure: true
|
||||
@@ -14,4 +14,10 @@ test-commit-job-csmock:
|
||||
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
|
||||
- sudo /opt/run-csmock.sh
|
||||
artifacts:
|
||||
# Upload artifacts when a crash makes the job fail.
|
||||
when: always
|
||||
paths:
|
||||
- cryptsetup-csmock-results.tar.xz
|
||||
- cryptsetup-csmock-results
|
||||
|
||||
@@ -2,13 +2,17 @@
|
||||
extends:
|
||||
- .dump_kernel_log
|
||||
before_script:
|
||||
- sudo apt-get -y update
|
||||
- >
|
||||
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
|
||||
[ -z "$RUN_SYSTEMD_PLUGIN_TEST" ] ||
|
||||
sudo apt-get -y install -y -qq swtpm meson ninja-build python3-jinja2
|
||||
gperf libcap-dev libtss2-dev libmount-dev swtpm-tools
|
||||
- >
|
||||
sudo apt-get -y install -y -qq git gcc make autoconf automake autopoint
|
||||
pkgconf libtool libtool-bin gettext libssl-dev libdevmapper-dev
|
||||
libpopt-dev uuid-dev libsepol-dev libjson-c-dev libssh-dev libblkid-dev
|
||||
tar libargon2-0-dev libpwquality-dev sharutils dmsetup jq xxd expect
|
||||
keyutils netcat-openbsd passwd openssh-client sshpass asciidoctor
|
||||
- sudo apt-get -y build-dep cryptsetup
|
||||
- sudo -E git clean -xdf
|
||||
- ./autogen.sh
|
||||
@@ -19,7 +23,7 @@ test-mergerq-job-debian:
|
||||
- .debian-prep
|
||||
tags:
|
||||
- libvirt
|
||||
- debian10
|
||||
- debian12
|
||||
stage: test
|
||||
interruptible: true
|
||||
variables:
|
||||
@@ -38,7 +42,7 @@ test-main-commit-job-debian:
|
||||
- .debian-prep
|
||||
tags:
|
||||
- libvirt
|
||||
- debian10
|
||||
- debian12
|
||||
stage: test
|
||||
interruptible: true
|
||||
variables:
|
||||
@@ -51,3 +55,44 @@ test-main-commit-job-debian:
|
||||
- make -j
|
||||
- make -j -C tests check-programs
|
||||
- sudo -E make check
|
||||
|
||||
# meson tests
|
||||
test-mergerq-job-debian-meson:
|
||||
extends:
|
||||
- .debian-prep
|
||||
tags:
|
||||
- libvirt
|
||||
- debian12
|
||||
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:
|
||||
- sudo apt-get -y install -y -qq meson ninja-build
|
||||
- meson setup build
|
||||
- ninja -C build
|
||||
- cd build && sudo -E meson test --verbose --print-errorlogs
|
||||
|
||||
test-main-commit-job-debian-meson:
|
||||
extends:
|
||||
- .debian-prep
|
||||
tags:
|
||||
- libvirt
|
||||
- debian12
|
||||
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:
|
||||
- sudo apt-get -y install -y -qq meson ninja-build
|
||||
- meson setup build
|
||||
- ninja -C build
|
||||
- cd build && sudo -E meson test --verbose --print-errorlogs
|
||||
|
||||
@@ -3,7 +3,12 @@
|
||||
- .dump_kernel_log
|
||||
before_script:
|
||||
- >
|
||||
sudo dnf -y -q install
|
||||
[ -z "$RUN_SYSTEMD_PLUGIN_TEST" ] ||
|
||||
sudo dnf -y -q install
|
||||
swtpm meson ninja-build python3-jinja2 gperf libcap-devel tpm2-tss-devel
|
||||
libmount-devel swtpm-tools
|
||||
- >
|
||||
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
|
||||
|
||||
@@ -31,7 +31,7 @@ EXTRA="-Wextra \
|
||||
-Wunsafe-loop-optimizations \
|
||||
-Wold-style-definition \
|
||||
-Wno-missing-field-initializers \
|
||||
-Wno-unused-parameter \
|
||||
-Wunused-parameter \
|
||||
-Wno-long-long \
|
||||
-Wmaybe-uninitialized \
|
||||
-Wvla \
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.gitlab-shared-docker:
|
||||
image: ubuntu:focal
|
||||
image: ubuntu:lunar
|
||||
tags:
|
||||
- gitlab-org-docker
|
||||
stage: test
|
||||
@@ -12,7 +12,6 @@
|
||||
- .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:
|
||||
@@ -27,5 +26,5 @@
|
||||
- .gitlab-shared-docker
|
||||
variables:
|
||||
COMPILER: "clang"
|
||||
COMPILER_VERSION: "13"
|
||||
COMPILER_VERSION: "17"
|
||||
RUN_SSH_PLUGIN_TEST: "1"
|
||||
|
||||
@@ -27,6 +27,8 @@ test-main-commit-rhel8:
|
||||
variables:
|
||||
RUN_SSH_PLUGIN_TEST: "1"
|
||||
rules:
|
||||
- if: $RUN_SYSTEMD_PLUGIN_TEST != null
|
||||
when: never
|
||||
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
|
||||
when: never
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
|
||||
@@ -46,6 +48,8 @@ test-main-commit-rhel9:
|
||||
variables:
|
||||
RUN_SSH_PLUGIN_TEST: "1"
|
||||
rules:
|
||||
- if: $RUN_SYSTEMD_PLUGIN_TEST != null
|
||||
when: never
|
||||
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
|
||||
when: never
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
|
||||
@@ -67,10 +71,13 @@ test-main-commit-rhel8-fips:
|
||||
variables:
|
||||
RUN_SSH_PLUGIN_TEST: "1"
|
||||
rules:
|
||||
- if: $RUN_SYSTEMD_PLUGIN_TEST != null
|
||||
when: never
|
||||
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
|
||||
when: never
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
|
||||
script:
|
||||
- fips-mode-setup --check || exit 1
|
||||
- make -j
|
||||
- make -j -C tests check-programs
|
||||
- sudo -E make check
|
||||
@@ -87,10 +94,13 @@ test-main-commit-rhel9-fips:
|
||||
variables:
|
||||
RUN_SSH_PLUGIN_TEST: "1"
|
||||
rules:
|
||||
- if: $RUN_SYSTEMD_PLUGIN_TEST != null
|
||||
when: never
|
||||
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
|
||||
when: never
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
|
||||
script:
|
||||
- fips-mode-setup --check || exit 1
|
||||
- make -j
|
||||
- make -j -C tests check-programs
|
||||
- sudo -E make check
|
||||
|
||||
41
.gitlab/ci/ubuntu-32bit.yml
Normal file
41
.gitlab/ci/ubuntu-32bit.yml
Normal file
@@ -0,0 +1,41 @@
|
||||
test-mergerq-job-ubuntu-32bit:
|
||||
extends:
|
||||
- .debian-prep
|
||||
tags:
|
||||
- libvirt
|
||||
- ubuntu-bionic-32bit
|
||||
stage: test
|
||||
interruptible: true
|
||||
variables:
|
||||
RUN_SSH_PLUGIN_TEST: "1"
|
||||
rules:
|
||||
- if: $RUN_SYSTEMD_PLUGIN_TEST != null
|
||||
when: never
|
||||
- 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-ubuntu-32bit:
|
||||
extends:
|
||||
- .debian-prep
|
||||
tags:
|
||||
- libvirt
|
||||
- ubuntu-bionic-32bit
|
||||
stage: test
|
||||
interruptible: true
|
||||
variables:
|
||||
RUN_SSH_PLUGIN_TEST: "1"
|
||||
rules:
|
||||
- if: $RUN_SYSTEMD_PLUGIN_TEST != null
|
||||
when: never
|
||||
- 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
11
.lgtm.yml
@@ -1,11 +0,0 @@
|
||||
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"
|
||||
43
FAQ.md
43
FAQ.md
@@ -1192,7 +1192,7 @@
|
||||
|
||||
More references can be found at the end of this document. Note that
|
||||
these are estimates from the defender side, so assuming something is
|
||||
easier than it actually is is fine. An attacker may still have
|
||||
easier than it actually is fine. An attacker may still have
|
||||
significantly higher cost than estimated here.
|
||||
|
||||
LUKS1 used SHA1 (since version 1.7.0 it uses SHA256) for hashing per
|
||||
@@ -1864,11 +1864,11 @@
|
||||
|
||||
This basically means that if you already have a slot-key, and you have
|
||||
set the PBKDF2 iteration count to 1 (it is > 10'000 normally), you could
|
||||
(maybe) derive a different passphrase that gives you the the same
|
||||
slot-key. But if you have the slot-key, you can already unlock the
|
||||
key-slot and get the volume key, breaking everything. So basically,
|
||||
this SHA-1 vulnerability allows you to open a LUKS1 container with high
|
||||
effort when you already have it open.
|
||||
(maybe) derive a different passphrase that gives you the same slot-key.
|
||||
But if you have the slot-key, you can already unlock the key-slot and
|
||||
get the volume key, breaking everything. So basically, this SHA-1
|
||||
vulnerability allows you to open a LUKS1 container with high effort when
|
||||
you already have it open.
|
||||
|
||||
The real problem here is people that do not understand crypto and claim
|
||||
things are broken just because some mechanism is used that has been
|
||||
@@ -2506,6 +2506,31 @@ offset length name data type description
|
||||
individually created (and hence has its own volume key). In this case,
|
||||
changing the default passphrase will make it secure again.
|
||||
|
||||
* **6.16 How to convert the printed volume key to a raw one?**
|
||||
A volume key printed via something like:
|
||||
```
|
||||
cryptsetup --dump-volume-key luksDump /dev/<device> >volume-key
|
||||
```
|
||||
(i.e. without using `--volume-key-file`), which gives something like:
|
||||
```
|
||||
LUKS header information for /dev/<device>
|
||||
Cipher name: aes
|
||||
Cipher mode: xts-plain64
|
||||
Payload offset: 32768
|
||||
UUID: 6e914442-e8b5-4eb5-98c4-5bf0cf17ecad
|
||||
MK bits: 512
|
||||
MK dump: e0 3f 15 c2 0f e5 80 ab 35 b4 10 03 ae 30 b9 5d
|
||||
4c 0d 28 9e 1b 0f e3 b0 50 57 ef d4 4d 53 a0 12
|
||||
b7 4e 43 a1 20 7e c5 02 1f f1 f5 08 04 3c f5 20
|
||||
a6 0b 23 f6 7b 53 55 aa 22 d8 aa 02 e0 2f d5 04
|
||||
```
|
||||
can be converted to the raw volume key for example via:
|
||||
```
|
||||
sed -E -n '/^MK dump:\t/,/^[^\t]/{0,/^MK dump:\t/s/^MK dump://; /^([^\t].*)?$/q; s/\t+//p;};' volume-key | xxd -r -p
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
# 7. Interoperability with other Disk Encryption Tools
|
||||
|
||||
@@ -3014,9 +3039,9 @@ offset length name data type description
|
||||
currently associated with any data/crypt segment (encrypted area) in the
|
||||
LUKS2 'Segments' section (displayed by luksDump).
|
||||
|
||||
This is a bit of a more general idea. It basically allows to use a keyslot
|
||||
as a container for a key to be used in other things than decrypting a
|
||||
data segment.
|
||||
This is a bit of a more general idea. It basically allows one to use a
|
||||
keyslot as a container for a key to be used in other things than decrypting
|
||||
a data segment.
|
||||
|
||||
As of April 2020, the following uses are defined:
|
||||
|
||||
|
||||
28
Makefile.am
28
Makefile.am
@@ -1,5 +1,18 @@
|
||||
EXTRA_DIST = README.md COPYING.LGPL FAQ.md docs misc autogen.sh
|
||||
SUBDIRS = po tests
|
||||
EXTRA_DIST = README.md SECURITY.md COPYING.LGPL FAQ.md docs misc autogen.sh
|
||||
EXTRA_DIST += meson_options.txt \
|
||||
meson.build \
|
||||
lib/crypto_backend/argon2/meson.build \
|
||||
lib/crypto_backend/meson.build \
|
||||
lib/meson.build \
|
||||
man/meson.build \
|
||||
po/meson.build \
|
||||
scripts/meson.build \
|
||||
src/meson.build \
|
||||
tests/meson.build \
|
||||
tokens/meson.build \
|
||||
tokens/ssh/meson.build
|
||||
|
||||
SUBDIRS = po tests tests/fuzz
|
||||
CLEANFILES =
|
||||
DISTCLEAN_TARGETS =
|
||||
|
||||
@@ -14,8 +27,14 @@ AM_CPPFLAGS = \
|
||||
-DVERSION=\""$(VERSION)"\" \
|
||||
-DEXTERNAL_LUKS2_TOKENS_PATH=\"${EXTERNAL_LUKS2_TOKENS_PATH}\"
|
||||
AM_CFLAGS = -Wall
|
||||
AM_CXXFLAGS = -Wall
|
||||
AM_LDFLAGS =
|
||||
|
||||
if ENABLE_FUZZ_TARGETS
|
||||
AM_CFLAGS += -fsanitize=fuzzer-no-link
|
||||
AM_CXXFLAGS += -fsanitize=fuzzer-no-link
|
||||
endif
|
||||
|
||||
LDADD = $(LTLIBINTL)
|
||||
|
||||
tmpfilesddir = @DEFAULT_TMPFILESDIR@
|
||||
@@ -64,3 +83,8 @@ uninstall-local:
|
||||
|
||||
check-programs: libcryptsetup.la
|
||||
$(MAKE) -C tests $@
|
||||
|
||||
if ENABLE_FUZZ_TARGETS
|
||||
fuzz-targets: libcryptsetup.la libcrypto_backend.la
|
||||
$(MAKE) -C tests/fuzz $@
|
||||
endif
|
||||
|
||||
175
README.md
175
README.md
@@ -2,121 +2,150 @@
|
||||
|
||||
What the ...?
|
||||
=============
|
||||
**Cryptsetup** is a utility used to conveniently set up disk encryption based
|
||||
on the [DMCrypt](https://gitlab.com/cryptsetup/cryptsetup/wikis/DMCrypt) kernel module.
|
||||
**Cryptsetup** is an open-source utility used to conveniently set up disk encryption based
|
||||
on the [dm-crypt](https://gitlab.com/cryptsetup/cryptsetup/wikis/DMCrypt) kernel module.
|
||||
|
||||
These include **plain** **dm-crypt** volumes, **LUKS** volumes, **loop-AES**,
|
||||
**TrueCrypt** (including **VeraCrypt** extension) and **BitLocker** formats.
|
||||
These formats are supported:
|
||||
* **plain** volumes,
|
||||
* **LUKS** volumes,
|
||||
* **loop-AES**,
|
||||
* **TrueCrypt** (including **VeraCrypt** extension),
|
||||
* **BitLocker**, and
|
||||
* **FileVault2**.
|
||||
|
||||
The project also includes a **veritysetup** utility used to conveniently setup
|
||||
[DMVerity](https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity) block integrity checking kernel module
|
||||
and **integritysetup** to setup
|
||||
[DMIntegrity](https://gitlab.com/cryptsetup/cryptsetup/wikis/DMIntegrity) block integrity kernel module.
|
||||
[dm-verity](https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity)
|
||||
block integrity checking kernel module and **integritysetup** to setup
|
||||
[dm-integrity](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.
|
||||
**LUKS** is the standard for Linux disk encryption. By providing a standardized on-disk format,
|
||||
it not only facilitate compatibility among distributions, but also enables secure management
|
||||
of multiple user passwords. LUKS stores all necessary setup information in the partition header,
|
||||
which enables users to transport or migrate data seamlessly.
|
||||
|
||||
### Specifications
|
||||
|
||||
Last version of the LUKS2 format specification is
|
||||
[available here](https://gitlab.com/cryptsetup/LUKS2-docs).
|
||||
|
||||
Last version of the LUKS1 format specification is
|
||||
[available here](https://www.kernel.org/pub/linux/utils/cryptsetup/LUKS_docs/on-disk-format.pdf).
|
||||
|
||||
Why LUKS?
|
||||
---------
|
||||
* compatibility via standardization,
|
||||
* secure against low entropy attacks,
|
||||
* support for multiple keys,
|
||||
* effective passphrase revocation,
|
||||
* free.
|
||||
|
||||
[Project home page](https://gitlab.com/cryptsetup/cryptsetup/).
|
||||
-----------------
|
||||
|
||||
[Frequently asked questions (FAQ)](https://gitlab.com/cryptsetup/cryptsetup/wikis/FrequentlyAskedQuestions)
|
||||
--------------------------------
|
||||
### Specification and documentation
|
||||
* The latest version of the
|
||||
[LUKS2 format specification](https://gitlab.com/cryptsetup/LUKS2-docs).
|
||||
* The latest version of the
|
||||
[LUKS1 format specification](https://www.kernel.org/pub/linux/utils/cryptsetup/LUKS_docs/on-disk-format.pdf).
|
||||
* [Project home page](https://gitlab.com/cryptsetup/cryptsetup/).
|
||||
* [Frequently asked questions (FAQ)](https://gitlab.com/cryptsetup/cryptsetup/wikis/FrequentlyAskedQuestions)
|
||||
|
||||
Download
|
||||
--------
|
||||
All release tarballs and release notes are hosted on [kernel.org](https://www.kernel.org/pub/linux/utils/cryptsetup/).
|
||||
Release notes and tarballs are available at
|
||||
[kernel.org](https://www.kernel.org/pub/linux/utils/cryptsetup/).
|
||||
|
||||
**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)
|
||||
**The latest stable cryptsetup release candidate version is 2.7.0-rc0**
|
||||
* [cryptsetup-2.7.0-rc0.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.7/cryptsetup-2.7.0-rc0.tar.xz)
|
||||
* Signature [cryptsetup-2.7.0-rc0.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.7/cryptsetup-2.7.0-rc0.tar.sign)
|
||||
_(You need to decompress file first to check signature.)_
|
||||
* [Cryptsetup 2.5.0-rc1 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.5/v2.5.0-rc1-ReleaseNotes).
|
||||
* [Cryptsetup 2.7.0-rc0 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.7/v2.7.0-rc0-ReleaseNotes).
|
||||
|
||||
**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)
|
||||
**The latest stable cryptsetup release version is 2.6.1**
|
||||
* [cryptsetup-2.6.1.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.6/cryptsetup-2.6.1.tar.xz)
|
||||
* Signature [cryptsetup-2.6.1.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.6/cryptsetup-2.6.1.tar.sign)
|
||||
_(You need to decompress file first to check signature.)_
|
||||
* [Cryptsetup 2.4.3 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.4/v2.4.3-ReleaseNotes).
|
||||
* [Cryptsetup 2.6.1 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.6/v2.6.1-ReleaseNotes).
|
||||
|
||||
Previous versions
|
||||
* [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 2.5.0](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.5/cryptsetup-2.5.0.tar.xz) -
|
||||
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.5/cryptsetup-2.5.0.tar.sign) -
|
||||
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.5/v2.5.0-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).
|
||||
|
||||
Source and API docs
|
||||
-------------------
|
||||
For development version code, please refer to [source](https://gitlab.com/cryptsetup/cryptsetup/tree/master) page,
|
||||
mirror on [kernel.org](https://git.kernel.org/cgit/utils/cryptsetup/cryptsetup.git/) or [GitHub](https://github.com/mbroz/cryptsetup).
|
||||
Source and API documentation
|
||||
----------------------------
|
||||
For development version code, please refer to the
|
||||
[source](https://gitlab.com/cryptsetup/cryptsetup/tree/master) page, with mirrors
|
||||
at [kernel.org](https://git.kernel.org/cgit/utils/cryptsetup/cryptsetup.git/) and
|
||||
[GitHub](https://github.com/mbroz/cryptsetup).
|
||||
|
||||
For libcryptsetup documentation see [libcryptsetup API](https://mbroz.fedorapeople.org/libcryptsetup_API/) page.
|
||||
For libcryptsetup documentation see
|
||||
[libcryptsetup API](https://mbroz.fedorapeople.org/libcryptsetup_API/) page.
|
||||
|
||||
The libcryptsetup API/ABI changes are tracked in [compatibility report](https://abi-laboratory.pro/tracker/timeline/cryptsetup/).
|
||||
|
||||
NLS PO files are maintained by [TranslationProject](https://translationproject.org/domain/cryptsetup.html).
|
||||
NLS PO files are maintained by
|
||||
[TranslationProject](https://translationproject.org/domain/cryptsetup.html).
|
||||
|
||||
Required packages
|
||||
-----------------
|
||||
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.
|
||||
All major Linux distributions provide cryptsetup as a bundled package. If you need
|
||||
to compile cryptsetup yourself, various additional packages are required.
|
||||
Any distribution-specific build tools are preferred when 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 the internal testsuite you also need to install `sharutils device-mapper jq vim-common expect keyutils netcat shadow-utils openssh-clients openssh sshpass`.
|
||||
Below are the packages needed to build for certain Linux distributions:
|
||||
|
||||
* 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`
|
||||
**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
|
||||
|
||||
Note that the list could change as the distributions evolve.
|
||||
Optionally: libargon2-devel libpwquality-devel
|
||||
```
|
||||
To run the internal testsuite (make check) 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 the internal testsuite (make check) you also need to install
|
||||
```
|
||||
sharutils dmsetup jq xxd expect keyutils netcat passwd openssh-client sshpass
|
||||
```
|
||||
|
||||
Note that the list may change as Linux 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.
|
||||
The cryptsetup project uses **automake** and **autoconf** system to generate all files needed to build.
|
||||
When building from a git snapshot,, use **./autogen.sh && ./configure && make**
|
||||
to compile the project. When building from a release **tar.xz** tarball, the configure script
|
||||
is pre-generated (no need to run **autoconf.sh**).
|
||||
See **./configure --help** and use the **--disable-[feature]** and **--enable-[feature]** 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.
|
||||
To run the test suite that come with the project, type **make check**.
|
||||
Note that most tests will need root user privileges and will run dangerous storage failure simulations.
|
||||
Do **not** run tests with root privilege on production systems! Some tests will need the **scsi_debug**
|
||||
kernel module to be installed.
|
||||
|
||||
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.
|
||||
For more details, please refer to the
|
||||
[automake](https://www.gnu.org/software/automake/manual/automake.html) and
|
||||
[autoconf](https://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf.html) documentation.
|
||||
|
||||
Help!
|
||||
-----
|
||||
|
||||
### Documentation
|
||||
Please read the following before posting questions to the mailing list so that
|
||||
you can ask better questions and better understand answers.
|
||||
|
||||
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
|
||||
* [Frequently asked questions (FAQ)](https://gitlab.com/cryptsetup/cryptsetup/wikis/FrequentlyAskedQuestions),
|
||||
* [LUKS Specifications](#specification-and-documentation), and
|
||||
* 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
|
||||
The FAQ is available online and in the source code for the project. The specifications are
|
||||
referenced above in this document. The man pages live within the source tree 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).
|
||||
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 email message 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.
|
||||
USEnet News (NNTP), Atom feed and git access to the 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.
|
||||
The former **dm-crypt** [list archive](https://lore.kernel.org/dm-crypt/) is also available.
|
||||
|
||||
@@ -74,7 +74,7 @@ autopoint --force $AP_OPTS
|
||||
libtoolize --force --copy
|
||||
aclocal -I m4 $AL_OPTS
|
||||
autoheader $AH_OPTS
|
||||
automake --add-missing --copy --gnu $AM_OPTS
|
||||
automake --force-missing --add-missing --copy --gnu $AM_OPTS
|
||||
autoconf $AC_OPTS
|
||||
|
||||
echo
|
||||
|
||||
114
configure.ac
114
configure.ac
@@ -1,9 +1,9 @@
|
||||
AC_PREREQ([2.67])
|
||||
AC_INIT([cryptsetup],[2.5.0-rc1])
|
||||
AC_INIT([cryptsetup],[2.7.0-rc0])
|
||||
|
||||
dnl library version from <major>.<minor>.<release>[-<suffix>]
|
||||
LIBCRYPTSETUP_VERSION=$(echo $PACKAGE_VERSION | cut -f1 -d-)
|
||||
LIBCRYPTSETUP_VERSION_INFO=20:0:8
|
||||
LIBCRYPTSETUP_VERSION_INFO=22:0:10
|
||||
|
||||
AM_SILENT_RULES([yes])
|
||||
AC_CONFIG_SRCDIR(src/cryptsetup.c)
|
||||
@@ -28,6 +28,7 @@ AC_USE_SYSTEM_EXTENSIONS
|
||||
AC_PROG_CC
|
||||
AM_PROG_CC_C_O
|
||||
AC_PROG_CPP
|
||||
AC_PROG_CXX
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_MAKE_SET
|
||||
AC_PROG_MKDIR_P
|
||||
@@ -127,7 +128,6 @@ if test "x$enable_largefile" = "xno"; then
|
||||
AC_MSG_ERROR([Building with --disable-largefile is not supported, it can cause data corruption.])
|
||||
fi
|
||||
|
||||
AC_C_CONST
|
||||
AC_C_BIGENDIAN
|
||||
AC_TYPE_OFF_T
|
||||
AC_SYS_LARGEFILE
|
||||
@@ -150,6 +150,7 @@ if test "x$enable_external_tokens" = "xyes"; then
|
||||
AC_SUBST(DL_LIBS, $LIBS)
|
||||
LIBS=$saved_LIBS
|
||||
fi
|
||||
AM_CONDITIONAL(EXTERNAL_TOKENS, test "x$enable_external_tokens" = "xyes")
|
||||
|
||||
AC_ARG_ENABLE([ssh-token],
|
||||
AS_HELP_STRING([--disable-ssh-token], [disable LUKS2 ssh-token]),
|
||||
@@ -213,6 +214,17 @@ if test "x$enable_pwquality" = "xyes"; then
|
||||
PWQUALITY_STATIC_LIBS="$PWQUALITY_LIBS -lcrack -lz"
|
||||
fi
|
||||
|
||||
dnl ==========================================================================
|
||||
dnl fuzzers, it requires own static library compilation later
|
||||
AC_ARG_ENABLE([fuzz-targets],
|
||||
AS_HELP_STRING([--enable-fuzz-targets], [enable building fuzz targets]))
|
||||
AM_CONDITIONAL(ENABLE_FUZZ_TARGETS, test "x$enable_fuzz_targets" = "xyes")
|
||||
|
||||
if test "x$enable_fuzz_targets" = "xyes"; then
|
||||
AX_CHECK_COMPILE_FLAG([-fsanitize=fuzzer-no-link],,
|
||||
AC_MSG_ERROR([Required compiler options not supported; use clang.]), [-Werror])
|
||||
fi
|
||||
|
||||
dnl ==========================================================================
|
||||
dnl passwdqc library (cryptsetup CLI only)
|
||||
AC_ARG_ENABLE([passwdqc],
|
||||
@@ -254,6 +266,9 @@ AC_DEFUN([CONFIGURE_GCRYPT], [
|
||||
GCRYPT_REQ_VERSION=1.1.42
|
||||
fi
|
||||
|
||||
use_internal_pbkdf2=0
|
||||
use_internal_argon2=1
|
||||
|
||||
dnl libgcrypt rejects to use pkgconfig, use AM_PATH_LIBGCRYPT from gcrypt-devel here.
|
||||
dnl Do not require gcrypt-devel if other crypto backend is used.
|
||||
m4_ifdef([AM_PATH_LIBGCRYPT],[
|
||||
@@ -277,7 +292,24 @@ AC_DEFUN([CONFIGURE_GCRYPT], [
|
||||
NO_FIPS([])
|
||||
fi
|
||||
|
||||
m4_ifdef([AM_PATH_LIBGCRYPT],[
|
||||
AC_ARG_ENABLE([gcrypt-argon2],
|
||||
dnl Check if we can use gcrypt Argon2 (1.11.0 supports empty password)
|
||||
AS_HELP_STRING([--disable-gcrypt-argon2], [force disable internal gcrypt Argon2]),
|
||||
[],
|
||||
[AM_PATH_LIBGCRYPT([1.11.0], [use_internal_argon2=0], [use_internal_argon2=1])])
|
||||
AM_PATH_LIBGCRYPT($GCRYPT_REQ_VERSION,,[AC_MSG_ERROR([You need the gcrypt library.])])],
|
||||
AC_MSG_ERROR([Missing support for gcrypt: install gcrypt and regenerate configure.]))
|
||||
|
||||
AC_MSG_CHECKING([if internal cryptsetup Argon2 is compiled-in])
|
||||
if test $use_internal_argon2 = 0; then
|
||||
AC_MSG_RESULT([no])
|
||||
else
|
||||
AC_MSG_RESULT([yes])
|
||||
fi
|
||||
|
||||
AC_CHECK_DECLS([GCRY_CIPHER_MODE_XTS], [], [], [#include <gcrypt.h>])
|
||||
AC_CHECK_DECLS([GCRY_KDF_ARGON2], [], [], [#include <gcrypt.h>])
|
||||
|
||||
if test "x$enable_static_cryptsetup" = "xyes"; then
|
||||
saved_LIBS=$LIBS
|
||||
@@ -297,19 +329,25 @@ AC_DEFUN([CONFIGURE_GCRYPT], [
|
||||
])
|
||||
|
||||
AC_DEFUN([CONFIGURE_OPENSSL], [
|
||||
PKG_CHECK_MODULES([OPENSSL], [openssl >= 0.9.8],,
|
||||
PKG_CHECK_MODULES([LIBCRYPTO], [libcrypto >= 0.9.8],,
|
||||
AC_MSG_ERROR([You need openssl library.]))
|
||||
CRYPTO_CFLAGS=$OPENSSL_CFLAGS
|
||||
CRYPTO_LIBS=$OPENSSL_LIBS
|
||||
CRYPTO_CFLAGS=$LIBCRYPTO_CFLAGS
|
||||
CRYPTO_LIBS=$LIBCRYPTO_LIBS
|
||||
use_internal_pbkdf2=0
|
||||
use_internal_argon2=1
|
||||
|
||||
if test "x$enable_static_cryptsetup" = "xyes"; then
|
||||
saved_PKG_CONFIG=$PKG_CONFIG
|
||||
PKG_CONFIG="$PKG_CONFIG --static"
|
||||
PKG_CHECK_MODULES([OPENSSL_STATIC], [openssl])
|
||||
CRYPTO_STATIC_LIBS=$OPENSSL_STATIC_LIBS
|
||||
PKG_CHECK_MODULES([LIBCRYPTO_STATIC], [libcrypto])
|
||||
CRYPTO_STATIC_LIBS=$LIBCRYPTO_STATIC_LIBS
|
||||
PKG_CONFIG=$saved_PKG_CONFIG
|
||||
fi
|
||||
|
||||
saved_LIBS=$LIBS
|
||||
AC_CHECK_DECLS([OSSL_get_max_threads], [], [], [#include <openssl/thread.h>])
|
||||
AC_CHECK_DECLS([OSSL_KDF_PARAM_ARGON2_VERSION], [], [], [#include <openssl/core_names.h>])
|
||||
LIBS=$saved_LIBS
|
||||
])
|
||||
|
||||
AC_DEFUN([CONFIGURE_NSS], [
|
||||
@@ -330,6 +368,7 @@ AC_DEFUN([CONFIGURE_NSS], [
|
||||
CRYPTO_CFLAGS=$NSS_CFLAGS
|
||||
CRYPTO_LIBS=$NSS_LIBS
|
||||
use_internal_pbkdf2=1
|
||||
use_internal_argon2=1
|
||||
NO_FIPS([])
|
||||
])
|
||||
|
||||
@@ -340,6 +379,7 @@ AC_DEFUN([CONFIGURE_KERNEL], [
|
||||
# [AC_MSG_ERROR([You need Linux kernel with userspace crypto interface.])],
|
||||
# [#include <sys/socket.h>])
|
||||
use_internal_pbkdf2=1
|
||||
use_internal_argon2=1
|
||||
NO_FIPS([])
|
||||
])
|
||||
|
||||
@@ -356,6 +396,7 @@ AC_DEFUN([CONFIGURE_NETTLE], [
|
||||
|
||||
CRYPTO_STATIC_LIBS=$CRYPTO_LIBS
|
||||
use_internal_pbkdf2=0
|
||||
use_internal_argon2=1
|
||||
NO_FIPS([])
|
||||
])
|
||||
|
||||
@@ -480,7 +521,15 @@ AC_ARG_ENABLE([internal-argon2],
|
||||
AC_ARG_ENABLE([libargon2],
|
||||
AS_HELP_STRING([--enable-libargon2], [enable external libargon2 (PHC) library (disables internal bundled version)]))
|
||||
|
||||
if test "x$enable_libargon2" = "xyes" ; then
|
||||
if test $use_internal_argon2 = 0 -o "x$enable_internal_argon2" = "xno" ; then
|
||||
if test "x$enable_internal_argon2" = "xyes" -o "x$enable_libargon" = "xyes"; then
|
||||
AC_MSG_WARN([Argon2 in $with_crypto_backend lib is used; internal Argon2 options are ignored.])
|
||||
fi
|
||||
enable_internal_argon2=no
|
||||
enable_internal_sse_argon2=no
|
||||
enable_libargon2=no
|
||||
use_internal_argon2=0
|
||||
elif test "x$enable_libargon2" = "xyes" ; then
|
||||
AC_CHECK_HEADERS(argon2.h,,
|
||||
[AC_MSG_ERROR([You need libargon2 development library installed.])])
|
||||
AC_CHECK_DECL(Argon2_id,,[AC_MSG_ERROR([You need more recent Argon2 library with support for Argon2id.])], [#include <argon2.h>])
|
||||
@@ -504,11 +553,10 @@ else
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "x$enable_internal_argon2" = "xyes"; then
|
||||
AC_DEFINE(USE_INTERNAL_ARGON2, 1, [Use internal Argon2])
|
||||
fi
|
||||
AM_CONDITIONAL(CRYPTO_INTERNAL_ARGON2, test "x$enable_internal_argon2" = "xyes")
|
||||
AM_CONDITIONAL(CRYPTO_INTERNAL_SSE_ARGON2, test "x$enable_internal_sse_argon2" = "xyes")
|
||||
dnl If libargon is in use, we have defined HAVE_ARGON2_H
|
||||
AC_DEFINE_UNQUOTED(USE_INTERNAL_ARGON2, [$use_internal_argon2], [Use internal Argon2])
|
||||
|
||||
dnl Link with blkid to check for other device types
|
||||
AC_ARG_ENABLE([blkid],
|
||||
@@ -543,6 +591,27 @@ AM_CONDITIONAL(HAVE_BLKID, test "x$enable_blkid" = "xyes")
|
||||
AM_CONDITIONAL(HAVE_BLKID_WIPE, test "x$enable_blkid_wipe" = "xyes")
|
||||
AM_CONDITIONAL(HAVE_BLKID_STEP_BACK, test "x$enable_blkid_step_back" = "xyes")
|
||||
|
||||
AC_ARG_ENABLE([hw-opal],
|
||||
AS_HELP_STRING([--disable-hw-opal], [disable use of hardware-backed OPAL for device encryption]),
|
||||
[],
|
||||
[enable_hw_opal=yes])
|
||||
|
||||
if test "x$enable_hw_opal" = "xyes"; then
|
||||
have_opal=yes
|
||||
AC_CHECK_DECLS([ OPAL_FL_SUM_SUPPORTED,
|
||||
IOC_OPAL_GET_LR_STATUS,
|
||||
IOC_OPAL_GET_GEOMETRY
|
||||
],
|
||||
[],
|
||||
[have_opal=no],
|
||||
[#include <linux/sed-opal.h>])
|
||||
if test "x$have_opal" = "xyes"; then
|
||||
AC_DEFINE([HAVE_HW_OPAL], 1, [Define to 1 to enable OPAL support.])
|
||||
else
|
||||
AC_MSG_WARN([Can not compile with OPAL support, kernel headers are too old, requires v6.4.])
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl Magic for cryptsetup.static build.
|
||||
if test "x$enable_static_cryptsetup" = "xyes"; then
|
||||
saved_PKG_CONFIG=$PKG_CONFIG
|
||||
@@ -617,6 +686,22 @@ AC_SUBST([LIBSSH_LIBS])
|
||||
AC_SUBST([LIBCRYPTSETUP_VERSION])
|
||||
AC_SUBST([LIBCRYPTSETUP_VERSION_INFO])
|
||||
|
||||
dnl Set Requires.private for libcryptsetup.pc
|
||||
dnl pwquality is used only by tools
|
||||
PKGMODULES="uuid devmapper json-c"
|
||||
case $with_crypto_backend in
|
||||
gcrypt) PKGMODULES="$PKGMODULES libgcrypt" ;;
|
||||
openssl) PKGMODULES="$PKGMODULES openssl" ;;
|
||||
nss) PKGMODULES="$PKGMODULES nss" ;;
|
||||
nettle) PKGMODULES="$PKGMODULES nettle" ;;
|
||||
esac
|
||||
if test "x$enable_libargon2" = "xyes"; then
|
||||
PKGMODULES="$PKGMODULES libargon2"
|
||||
fi
|
||||
if test "x$enable_blkid" = "xyes"; then
|
||||
PKGMODULES="$PKGMODULES blkid"
|
||||
fi
|
||||
AC_SUBST([PKGMODULES])
|
||||
dnl ==========================================================================
|
||||
AC_ARG_ENABLE([dev-random],
|
||||
AS_HELP_STRING([--enable-dev-random], [use /dev/random by default for key generation (otherwise use /dev/urandom)]))
|
||||
@@ -652,9 +737,9 @@ AC_DEFUN([CS_ABSPATH], [
|
||||
])
|
||||
|
||||
dnl ==========================================================================
|
||||
CS_STR_WITH([plain-hash], [password hashing function for plain mode], [ripemd160])
|
||||
CS_STR_WITH([plain-hash], [password hashing function for plain mode], [sha256])
|
||||
CS_STR_WITH([plain-cipher], [cipher for plain mode], [aes])
|
||||
CS_STR_WITH([plain-mode], [cipher mode for plain mode], [cbc-essiv:sha256])
|
||||
CS_STR_WITH([plain-mode], [cipher mode for plain mode], [xts-plain64])
|
||||
CS_NUM_WITH([plain-keybits],[key length in bits for plain mode], [256])
|
||||
|
||||
CS_STR_WITH([luks1-hash], [hash function for LUKS1 header], [sha256])
|
||||
@@ -739,5 +824,6 @@ lib/libcryptsetup.pc
|
||||
po/Makefile.in
|
||||
scripts/cryptsetup.conf
|
||||
tests/Makefile
|
||||
tests/fuzz/Makefile
|
||||
])
|
||||
AC_OUTPUT
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
2012-03-16 Milan Broz <gmazyland@gmail.com>
|
||||
* Add --keyfile-offset and --new-keyfile-offset parameters to API and CLI.
|
||||
* Add repair command and crypt_repair() for known LUKS metadata problems repair.
|
||||
* Allow to specify --align-payload only for luksFormat.
|
||||
* Allow one to specify --align-payload only for luksFormat.
|
||||
|
||||
2012-03-16 Milan Broz <mbroz@redhat.com>
|
||||
* Unify password verification option.
|
||||
@@ -228,7 +228,7 @@
|
||||
* Fix password callback call.
|
||||
* Fix default plain password entry from terminal in activate_by_passphrase.
|
||||
* Add --dump-master-key option for luksDump to allow volume key dump.
|
||||
* Allow to activate by internally cached volume key
|
||||
* Allow one to activate by internally cached volume key
|
||||
(format/activate without keyslots active - used for temporary devices).
|
||||
* Initialize volume key from active device in crypt_init_by_name()
|
||||
* Fix cryptsetup binary exitcodes.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* libcryptsetup API log example
|
||||
*
|
||||
* Copyright (C) 2011-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2011-2023 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* libcryptsetup API - using LUKS device example
|
||||
*
|
||||
* Copyright (C) 2011-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2011-2023 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
|
||||
|
||||
@@ -85,7 +85,7 @@ Libcryptsetup API additions:
|
||||
|
||||
* Fix optional password callback handling.
|
||||
|
||||
* Allow to activate by internally cached volume key immediately after
|
||||
* Allow one to activate by internally cached volume key immediately after
|
||||
crypt_format() without active slot (for temporary devices with
|
||||
on-disk metadata)
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ Changes since version 1.4.1
|
||||
* Fix header check to support old (cryptsetup 1.0.0) header alignment.
|
||||
(Regression in 1.4.0)
|
||||
|
||||
* Allow to specify --align-payload only for luksFormat.
|
||||
* Allow one to specify --align-payload only for luksFormat.
|
||||
|
||||
* Add --master-key-file option to luksOpen (open using volume key).
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ Changes since version 1.4.2
|
||||
Device-mapper now retry removal if device is busy.
|
||||
|
||||
* Allow "private" activation (skip some udev global rules) flag.
|
||||
Cryptsetup library API now allows to specify CRYPT_ACTIVATE_PRIVATE,
|
||||
Cryptsetup library API now allows one to specify CRYPT_ACTIVATE_PRIVATE,
|
||||
which means that some udev rules are not processed.
|
||||
(Used for temporary devices, like internal keyslot mappings where
|
||||
it is not desirable to run any device scans.)
|
||||
|
||||
@@ -4,7 +4,7 @@ Cryptsetup 1.6.0 Release Notes
|
||||
Changes since version 1.6.0-rc1
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Change LUKS default cipher to to use XTS encryption mode,
|
||||
* Change LUKS default cipher to use XTS encryption mode,
|
||||
aes-xts-plain64 (i.e. using AES128-XTS).
|
||||
|
||||
XTS mode becomes standard in hard disk encryption.
|
||||
@@ -209,7 +209,7 @@ Important changes
|
||||
|
||||
WARNING: these tests do not use dmcrypt, only crypto API.
|
||||
You have to benchmark the whole device stack and you can get completely
|
||||
different results. But is is usable for basic comparison.
|
||||
different results. But it is usable for basic comparison.
|
||||
(Note for example AES-NI decryption optimization effect in example above.)
|
||||
|
||||
Features
|
||||
|
||||
@@ -8,7 +8,7 @@ Changes since version 1.6.1
|
||||
* Fix cipher specification string parsing (found by gcc -fsanitize=address option).
|
||||
|
||||
* Try to map TCRYPT system encryption through partition
|
||||
(allows to activate mapping when other partition on the same device is mounted).
|
||||
(allows one to activate mapping when other partition on the same device is mounted).
|
||||
|
||||
* Print a warning if system encryption is used and device is a partition.
|
||||
(TCRYPT system encryption uses whole device argument.)
|
||||
|
||||
@@ -25,7 +25,7 @@ Changes since version 1.6.3
|
||||
|
||||
Please refer to cryptsetup FAQ for detail how to fix this situation.
|
||||
|
||||
* Allow to use --disable-gcrypt-pbkdf2 during configuration
|
||||
* Allow one to use --disable-gcrypt-pbkdf2 during configuration
|
||||
to force use internal PBKDF2 code.
|
||||
|
||||
* Require gcrypt 1.6.1 for imported implementation of PBKDF2
|
||||
|
||||
@@ -38,7 +38,7 @@ Changes since version 1.6.4
|
||||
The command "cryptsetup status" will print basic info, even if you
|
||||
do not provide detached header argument.
|
||||
|
||||
* Allow to specify ECB mode in cryptsetup benchmark.
|
||||
* Allow one to specify ECB mode in cryptsetup benchmark.
|
||||
|
||||
* Add some LUKS images for regression testing.
|
||||
Note that if image with Whirlpool fails, the most probable cause is that
|
||||
|
||||
@@ -35,14 +35,14 @@ Changes since version 1.6.6
|
||||
* Support permanent device decryption for cryptsetup-reencrypt.
|
||||
To remove LUKS encryption from a device, you can now use --decrypt option.
|
||||
|
||||
* Allow to use --header option in all LUKS commands.
|
||||
* Allow one to use --header option in all LUKS commands.
|
||||
The --header always takes precedence over positional device argument.
|
||||
|
||||
* Allow luksSuspend without need to specify a detached header.
|
||||
|
||||
* Detect if O_DIRECT is usable on a device allocation.
|
||||
There are some strange storage stack configurations which wrongly allows
|
||||
to open devices with direct-io but fails on all IO operations later.
|
||||
one to open devices with direct-io but fails on all IO operations later.
|
||||
|
||||
Cryptsetup now tries to read the device first sector to ensure it can use
|
||||
direct-io.
|
||||
|
||||
@@ -30,7 +30,7 @@ Changes since version 1.6.7
|
||||
cryptsetup resize will try to resize underlying loop device as well.
|
||||
(It can be used to grow up file-backed device in one step.)
|
||||
|
||||
* Cryptsetup now allows to use empty password through stdin pipe.
|
||||
* Cryptsetup now allows one to use empty password through stdin pipe.
|
||||
(Intended only for testing in scripts.)
|
||||
|
||||
Cryptsetup API NOTE:
|
||||
|
||||
@@ -3,7 +3,7 @@ Cryptsetup 1.7.4 Release Notes
|
||||
|
||||
Changes since version 1.7.3
|
||||
|
||||
* Allow to specify LUKS1 hash algorithm in Python luksFormat wrapper.
|
||||
* Allow one to specify LUKS1 hash algorithm in Python luksFormat wrapper.
|
||||
|
||||
* Use LUKS1 compiled-in defaults also in Python wrapper.
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ Changes since version 2.0.1
|
||||
|
||||
* Add LUKS2 specific options for cryptsetup-reencrypt.
|
||||
Tokens and persistent flags are now transferred during reencryption;
|
||||
change of PBKDF keyslot parameters is now supported and allows
|
||||
change of PBKDF keyslot parameters is now supported and allows one
|
||||
to set precalculated values (no benchmarks).
|
||||
|
||||
* Do not allow LUKS2 --persistent and --test-passphrase cryptsetup flags
|
||||
|
||||
@@ -28,7 +28,7 @@ Changes since version 2.0.2
|
||||
|
||||
* New API extensions for unbound keyslots (LUKS2 only)
|
||||
crypt_keyslot_get_key_size() and crypt_volume_key_get()
|
||||
These functions allow to get key and key size for unbound keyslots.
|
||||
These functions allow one to get key and key size for unbound keyslots.
|
||||
|
||||
* New enum value CRYPT_SLOT_UNBOUND for keyslot status (LUKS2 only).
|
||||
|
||||
|
||||
@@ -170,21 +170,21 @@ These new calls are now exported, for details see libcryptsetup.h:
|
||||
|
||||
* crypt_get_metadata_size
|
||||
* crypt_set_metadata_size
|
||||
allows to set/get area sizes in LUKS header
|
||||
allows one to set/get area sizes in LUKS header
|
||||
(according to specification).
|
||||
|
||||
* crypt_get_default_type
|
||||
get default compiled-in LUKS type (version).
|
||||
|
||||
* crypt_get_pbkdf_type_params
|
||||
allows to get compiled-in PBKDF parameters.
|
||||
allows one to get compiled-in PBKDF parameters.
|
||||
|
||||
* crypt_keyslot_set_encryption
|
||||
* crypt_keyslot_get_encryption
|
||||
allows to set/get per-keyslot encryption algorithm for LUKS2.
|
||||
allows one to set/get per-keyslot encryption algorithm for LUKS2.
|
||||
|
||||
* crypt_keyslot_get_pbkdf
|
||||
allows to get PBKDF parameters per-keyslot.
|
||||
allows one to get PBKDF parameters per-keyslot.
|
||||
|
||||
and these new defines:
|
||||
* CRYPT_LOG_DEBUG_JSON (message type for JSON debug)
|
||||
|
||||
@@ -9,7 +9,7 @@ native read-write access to BitLocker Full Disk Encryption devices.
|
||||
|
||||
The BITLK implementation is based on publicly available information
|
||||
and it is an independent and opensource implementation that allows
|
||||
to access this proprietary disk encryption.
|
||||
one to access this proprietary disk encryption.
|
||||
|
||||
Changes since version 2.2.2
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -18,7 +18,7 @@ Changes since version 2.3.1
|
||||
The slot number --key-slot (-S) option is mandatory here.
|
||||
|
||||
An unbound keyslot store a key is that is not assigned to data
|
||||
area on disk (LUKS2 allows to store arbitrary keys).
|
||||
area on disk (LUKS2 allows one to store arbitrary keys).
|
||||
|
||||
* Rephrase some error messages and remove redundant end-of-lines.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Cryptsetup 2.5.0-rc1 Release Notes
|
||||
==================================
|
||||
Stable release candidate with new features and bug fixes.
|
||||
Cryptsetup 2.5.0 Release Notes
|
||||
==============================
|
||||
Stable release with new features and bug fixes.
|
||||
|
||||
Changes since version 2.4.3
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -125,6 +125,11 @@ LUKS volume reencryption changes
|
||||
|
||||
* Support all options allowed with luksFormat with encrypt action.
|
||||
|
||||
* Add prompt if LUKS2 decryption is run with a detached header.
|
||||
|
||||
* Add warning for reencryption of file image and mention
|
||||
the possible use of --force-offline-reencrypt option.
|
||||
|
||||
Other changes
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
@@ -258,6 +263,11 @@ Other changes
|
||||
|
||||
* Reimplement BASE64 with simplified code instead of coreutils version.
|
||||
|
||||
* Fix regression when warning messages were not displayed
|
||||
if some kernel feature is not supported (2.4.2).
|
||||
|
||||
* Add support for --key-slot option in luksResume action.
|
||||
|
||||
Libcryptsetup API extensions and changes
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
236
docs/v2.6.0-ReleaseNotes
Normal file
236
docs/v2.6.0-ReleaseNotes
Normal file
@@ -0,0 +1,236 @@
|
||||
Cryptsetup 2.6.0 Release Notes
|
||||
==============================
|
||||
Stable release with new features and bug fixes.
|
||||
|
||||
Changes since version 2.5.0
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Introduce support for handling macOS FileVault2 devices (FVAULT2).
|
||||
|
||||
Cryptsetup now supports the mapping of FileVault2 full-disk encryption
|
||||
by Apple for the macOS operating system using a native Linux kernel.
|
||||
You can open an existing USB FileVault portable device and (with
|
||||
the hfsplus filesystem driver) access the native data read/write.
|
||||
|
||||
Cryptsetup supports only (legacy) FileVault2 based on Core Storage
|
||||
and HFS+ filesystem (introduced in MacOS X 10.7 Lion).
|
||||
It does NOT support the new version of FileVault based on the APFS
|
||||
filesystem used in recent macOS versions.
|
||||
|
||||
Header formatting and changes are not supported; cryptsetup never
|
||||
changes the metadata on the device.
|
||||
|
||||
FVAULT2 extension requires kernel userspace crypto API and kernel
|
||||
driver for HFS+ (hfsplus) filesystem (available on most systems today).
|
||||
|
||||
Example of using FileVault2 formatted USB device:
|
||||
|
||||
A typical encrypted device contains three partitions; the FileVault
|
||||
encrypted partition is here sda2:
|
||||
|
||||
$ lsblk -o NAME,FSTYPE,LABEL /dev/sda
|
||||
NAME FSTYPE LABEL
|
||||
sda
|
||||
|-sda1 vfat EFI
|
||||
|-sda2
|
||||
`-sda3 hfsplus Boot OS X
|
||||
|
||||
Note: blkid does not recognize FileVault2 format yet.
|
||||
|
||||
To dump metadata information about the device, you can use
|
||||
the fvault2Dump command:
|
||||
|
||||
$ cryptsetup fvault2Dump /dev/sda2
|
||||
Header information for FVAULT2 device /dev/sda2.
|
||||
Physical volume UUID: 6f353c05-daae-4e76-a0ee-6a9569a22d81
|
||||
Family UUID: f82cceb0-a788-4815-945a-53d57fcd55a8
|
||||
Logical volume offset: 67108864 [bytes]
|
||||
Logical volume size: 3288334336 [bytes]
|
||||
Cipher: aes
|
||||
Cipher mode: xts-plain64
|
||||
PBKDF2 iterations: 97962
|
||||
PBKDF2 salt: 173a4ec7447662ec79ca7a47df6c2a01
|
||||
|
||||
To activate the device, use open --type fvault2 option:
|
||||
|
||||
$ cryptsetup open --type fvault2 /dev/sda2 test
|
||||
Enter passphrase for /dev/sda2: ...
|
||||
|
||||
And check the status of the active device:
|
||||
|
||||
$ cryptsetup status test
|
||||
/dev/mapper/test is active.
|
||||
type: FVAULT2
|
||||
cipher: aes-xts-plain64
|
||||
keysize: 256 bits
|
||||
key location: dm-crypt
|
||||
device: /dev/sda2
|
||||
sector size: 512
|
||||
offset: 131072 sectors
|
||||
size: 6422528 sectors
|
||||
mode: read/write
|
||||
|
||||
Now, if the kernel contains hfsplus filesystem driver, you can mount
|
||||
decrypted content:
|
||||
|
||||
$ mount /dev/mapper/test /mnt/test
|
||||
|
||||
For more info about implementation, please refer to the master thesis
|
||||
by Pavel Tobias, which was the source for this extension.
|
||||
https://is.muni.cz/th/p0aok/?lang=en
|
||||
|
||||
* libcryptsetup: no longer use global memory locking through mlockall()
|
||||
|
||||
For many years, libcryptsetup locked all memory (including dependent
|
||||
library address space) to prevent swapping sensitive content outside
|
||||
of RAM.
|
||||
|
||||
This strategy no longer works as the locking of basic libraries exceeds
|
||||
the memory locking limit if running as a non-root user.
|
||||
|
||||
Libcryptsetup now locks only memory ranges containing sensitive
|
||||
material (keys) through crypt_safe_alloc() calls.
|
||||
|
||||
This change solves many reported mysterious problems of unexpected
|
||||
failures. If the initial lock was still under the limit and succeeded,
|
||||
some following memory allocation could fail later as it exceeded
|
||||
the locking limit. If the initial locking fails, memory locking
|
||||
was quietly ignored completely.
|
||||
|
||||
The whole crypt_memory_lock() API call is deprecated; it no longer
|
||||
calls memlockall().
|
||||
|
||||
* libcryptsetup: process priority is increased only for key derivation
|
||||
(PBKDF) calls.
|
||||
|
||||
Increasing priority was tight to memory locking and works only if
|
||||
running under superuser.
|
||||
Only PBKDF calls and benchmarking now increase the process priority.
|
||||
|
||||
* Add new LUKS keyslot context handling functions and API.
|
||||
|
||||
In practice, the luksAddKey action does two operations.
|
||||
It unlocks the existing device volume key and stores the unlocked
|
||||
volume key in a new keyslot.
|
||||
Previously the options were limited to key files and passphrases.
|
||||
|
||||
Newly available methods (keyslot contexts) are passphrase, keyfile,
|
||||
key (binary representation), and LUKS2 token.
|
||||
|
||||
To unlock a keyslot user may:
|
||||
- provide existing passphrase via interactive prompt (default method)
|
||||
- use --key-file option to provide a file with a valid passphrase
|
||||
- provide volume key directly via --volume-key-file
|
||||
- unlock keyslot via all available LUKS2 tokens by --token-only
|
||||
- unlock keyslot via specific token with --token-id
|
||||
- unlock keyslot via specific token type by --token-type
|
||||
|
||||
To provide the passphrase for a new keyslot, a user may:
|
||||
- provide existing passphrase via interactive prompt (default method)
|
||||
- use --new-keyfile to read the passphrase from the file
|
||||
- use --new-token-id to select LUKS2 token to get passphrase
|
||||
for new keyslot. The new keyslot is assigned to the selected token
|
||||
id if the operation is successful.
|
||||
|
||||
* The volume key may now be extracted using a passphrase, keyfile, or
|
||||
token. For LUKS devices, it also returns the volume key after
|
||||
a successful crypt_format call.
|
||||
|
||||
* Fix --disable-luks2-reencryption configuration option.
|
||||
|
||||
* cryptsetup: Print a better error message and warning if the format
|
||||
produces an image without space available for data.
|
||||
|
||||
Activation now fails early with a more descriptive message.
|
||||
|
||||
* Print error if anti-forensic LUKS2 hash setting is not available.
|
||||
If the specified hash was not available, activation quietly failed.
|
||||
|
||||
* Fix internal crypt segment compare routine if the user
|
||||
specified cipher in kernel format (capi: prefix).
|
||||
|
||||
* cryptsetup: Add token unassign action.
|
||||
|
||||
This action allows removing token binding on specific keyslot.
|
||||
|
||||
* veritysetup: add support for --use-tasklets option.
|
||||
|
||||
This option sets try_verify_in_tasklet kernel dm-verity option
|
||||
(available since Linux kernel 6.0) to allow some performance
|
||||
improvement on specific systems.
|
||||
|
||||
* Provide pkgconfig Require.private settings.
|
||||
|
||||
While we do not completely provide static build on udev systems,
|
||||
it helps produce statically linked binaries in certain situations.
|
||||
|
||||
* Always update automake library files if autogen.sh is run.
|
||||
|
||||
For several releases, we distributed older automake scripts by mistake.
|
||||
|
||||
* reencryption: Fix user defined moved segment size in LUKS2 decryption.
|
||||
|
||||
The --hotzone-size argument was ignored in cases where the actual data
|
||||
size was less than the original LUKS2 data offset.
|
||||
|
||||
* Delegate FIPS mode detection to configured crypto backend.
|
||||
System FIPS mode check no longer depends on /etc/system-fips file.
|
||||
|
||||
* tests: externally provided systemd plugin is now optionally compiled
|
||||
from systemd git and tested with cryptsetup
|
||||
|
||||
* tests: initial integration to OSS-fuzz project with basic crypt_load()
|
||||
test for LUKS2 and JSON mutated fuzzing.
|
||||
|
||||
For more info, see README in tests/fuzz directory.
|
||||
|
||||
* Update documentation, including FAQ and man pages.
|
||||
|
||||
Libcryptsetup API extensions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
The libcryptsetup API is backward compatible with existing symbols.
|
||||
|
||||
New symbols:
|
||||
crypt_keyslot_context_init_by_passphrase
|
||||
crypt_keyslot_context_init_by_keyfile
|
||||
crypt_keyslot_context_init_by_token
|
||||
crypt_keyslot_context_init_by_volume_key
|
||||
crypt_keyslot_context_get_error
|
||||
crypt_keyslot_context_set_pin
|
||||
crypt_keyslot_context_get_type
|
||||
crypt_keyslot_context_free
|
||||
crypt_keyslot_add_by_keyslot_context
|
||||
crypt_volume_key_get_by_keyslot_context
|
||||
|
||||
New defines:
|
||||
CRYPT_FVAULT2 "FVAULT2" (FileVault2 compatible mode)
|
||||
|
||||
Keyslot context types:
|
||||
CRYPT_KC_TYPE_PASSPHRASE
|
||||
CRYPT_KC_TYPE_KEYFILE
|
||||
CRYPT_KC_TYPE_TOKEN
|
||||
CRYPT_KC_TYPE_KEY
|
||||
|
||||
CRYPT_ACTIVATE_TASKLETS (dm-verity: use tasklets activation flag)
|
||||
|
||||
WARNING!
|
||||
~~~~~~~~
|
||||
The next version of cryptsetup will change the encryption mode and key
|
||||
derivation option for the PLAIN format.
|
||||
|
||||
This change will cause backward incompatibility.
|
||||
For this reason, the user will have to specify the exact parameters
|
||||
for cipher, key size, and key derivation parameters for plain format.
|
||||
|
||||
The default encryption mode will be AES-XTS with 512bit key (AES-256).
|
||||
The CBC mode is no longer considered the best default, as it allows easy
|
||||
bit-flipped ciphertext modification attacks and performance problems.
|
||||
|
||||
For the passphrase hashing in plain mode, the encryption key is directly
|
||||
derived through iterative hashing from a user-provided passphrase
|
||||
(except a keyfile that is not hashed).
|
||||
|
||||
The default hash is RIPEMD160, which is no longer the best default
|
||||
option. The exact change will be yet discussed but should include
|
||||
the possibility of using a password-based key derivation function
|
||||
instead of iterative hashing.
|
||||
50
docs/v2.6.1-ReleaseNotes
Normal file
50
docs/v2.6.1-ReleaseNotes
Normal file
@@ -0,0 +1,50 @@
|
||||
Cryptsetup 2.6.1 Release Notes
|
||||
==============================
|
||||
Stable bug-fix release with minor extensions.
|
||||
|
||||
All users of cryptsetup 2.6.0 should upgrade to this version.
|
||||
|
||||
Changes since version 2.6.0
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* bitlk: Fixes for BitLocker-compatible on-disk metadata parser
|
||||
(found by new cryptsetup OSS-Fuzz fuzzers).
|
||||
- Fix a possible memory leak if the metadata contains more than
|
||||
one description field.
|
||||
- Harden parsing of metadata entries for key and description entries.
|
||||
- Fix broken metadata parsing that can cause a crash or out of memory.
|
||||
|
||||
* Fix possible iteration overflow in OpenSSL2 PBKDF2 crypto backend.
|
||||
OpenSSL2 uses a signed integer for PBKDF2 iteration count.
|
||||
As cryptsetup uses an unsigned value, this can lead to overflow and
|
||||
a decrease in the actual iteration count.
|
||||
This situation can happen only if the user specifies
|
||||
--pbkdf-force-iterations option.
|
||||
OpenSSL3 (and other supported crypto backends) are not affected.
|
||||
|
||||
* Fix compilation for new ISO C standards (gcc with -std=c11 and higher).
|
||||
|
||||
* fvault2: Fix compilation with very old uuid.h.
|
||||
|
||||
* verity: Fix possible hash offset setting overflow.
|
||||
|
||||
* bitlk: Fix use of startup BEK key on big-endian platforms.
|
||||
|
||||
* Fix compilation with latest musl library.
|
||||
Recent musl no longer implements lseek64() in some configurations.
|
||||
Use lseek() as 64-bit offset is mandatory for cryptsetup.
|
||||
|
||||
* Do not initiate encryption (reencryption command) when the header and
|
||||
data devices are the same.
|
||||
If data device reduction is not requsted, this leads to data corruption
|
||||
since LUKS metadata was written over the data device.
|
||||
|
||||
* Fix possible memory leak if crypt_load() fails.
|
||||
|
||||
* Always use passphrases with a minimal 8 chars length for benchmarking.
|
||||
Some enterprise distributions decided to set an unconditional check
|
||||
for PBKDF2 password length when running in FIPS mode.
|
||||
This questionable change led to unexpected failures during LUKS format
|
||||
and keyslot operations, where short passwords were used for
|
||||
benchmarking PBKDF2 speed.
|
||||
PBKDF2 benchmark calculations should not be affected by this change.
|
||||
435
docs/v2.7.0-rc0-ReleaseNotes
Normal file
435
docs/v2.7.0-rc0-ReleaseNotes
Normal file
@@ -0,0 +1,435 @@
|
||||
Cryptsetup 2.7.0-rc0 Release Notes
|
||||
==================================
|
||||
Stable release candidate with new features and bug fixes.
|
||||
|
||||
Changes since version 2.6.1
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Introduce support for hardware OPAL disk encryption.
|
||||
|
||||
Some SATA and NVMe devices support hardware encryption through OPAL2
|
||||
TCG interface (SEDs - self-encrypting drives). Using hardware disk
|
||||
encryption is controversial as you must trust proprietary hardware.
|
||||
|
||||
On the other side, using both software and hardware encryption
|
||||
layers increases the security margin by adding an additional layer
|
||||
of protection. There is usually no performance drop if OPAL encryption
|
||||
is used (the drive always operates with full throughput), and it does
|
||||
not add any utilization to the main CPU.
|
||||
|
||||
LUKS2 now supports hardware encryption through the Linux kernel
|
||||
SED OPAL interface (CONFIG_BLK_SED_OPAL Linux kernel option must be
|
||||
enabled). Cryptsetup OPAL is never enabled by default; you have to use
|
||||
luksFormat parameters to use it. OPAL support can be disabled during
|
||||
the build phase with --disable-hw-opal configure option.
|
||||
|
||||
LUKS2 OPAL encryption is configured the same way as software encryption
|
||||
- it stores metadata in the LUKS2 header and activates encryption for
|
||||
the data area on the disk (configured OPAL locking range).
|
||||
LUKS2 header metadata must always be visible (thus not encrypted).
|
||||
The key stored in LUKS2 keyslots contains two parts - volume key
|
||||
for software (dm-crypt) encryption and unlocking key for OPAL.
|
||||
OPAL unlocking key is independent of the dm-crypt volume key and is
|
||||
always 256 bits long. Cryptsetup does not support full drive OPAL
|
||||
encryption; only a specific locking range is always used.
|
||||
|
||||
If the OPAL device is in its initial factory state (after factory
|
||||
reset), cryptsetup needs to configure the OPAL admin user and password.
|
||||
If the OPAL admin user is already set, the OPAL password must be
|
||||
provided during luksFormat.
|
||||
The provided password is needed only to configure or reset the OPAL
|
||||
locking range; LUKS device activation requires LUKS passphrase only.
|
||||
LUKS passphrase should be different from OPAL password (OPAL admin user
|
||||
is configured inside OPAL hardware while LUKS unlocking passphrase
|
||||
unlocks LUKS keyslot).
|
||||
|
||||
OPAL encryption can be used in combination with software (dm-crypt)
|
||||
encryption (--hw-opal option) or without the software layer
|
||||
(--hw-opal-only option).
|
||||
You can see the configured segment parameters in the luksDump command.
|
||||
Note: formal specification of OPAL LUKS2 segment metadata will be added
|
||||
in the next release candidate. LUKS2 devices with OPAL segments set
|
||||
a new requirement flag in the LUKS2 header to prevent older cryptsetup
|
||||
metadata manipulation. Do not use hardware-only encryption if you do
|
||||
not fully trust your hardware vendor.
|
||||
|
||||
Compatibility notes:
|
||||
- Linux kernel SED interface does NOT work through USB external
|
||||
adapters due to the mising compatibility layer in Linux USB storage
|
||||
drivers (even if USB hardware itself can support OPAL commands).
|
||||
- other TCG security subsystems like Ruby or Pyrite are not
|
||||
supported. Note that many drives support only Pyrite subsystem that
|
||||
does NOT encrypt data (it provides only authentication).
|
||||
- compatibility among OPAL-enabled drives is often very problematic,
|
||||
specifically for older drives. Many drives have bugs in the firmware
|
||||
that make the Linux kernel interface unusable.
|
||||
- unlocking key for OPAL remains in memory even after luksSuspend
|
||||
- if you forget the OPAL admin password, the only way to recover is
|
||||
the full drive factory reset through the PSID key (usually printed
|
||||
on the drive itself) that wipes all data on the drive (not only the
|
||||
LUKS area).
|
||||
- cryptsetup reencryption is not supported for LUKS2 OPAL-enabled
|
||||
devices
|
||||
- most OPAL drives use AES-XTS cipher mode (older drives can use
|
||||
AES-CBC). This information is not available through kernel SED API.
|
||||
- locked OPAL locking ranges return IO errors while reading; this
|
||||
can produce a lot of scary messages in the log if some tools (like
|
||||
blkid) try to read the locked area.
|
||||
|
||||
Examples:
|
||||
|
||||
* Formatting the drive
|
||||
Use --hw-opal with luksFormat (or --hw-opal-only for hardware only
|
||||
encryption):
|
||||
|
||||
# cryptsetup luksFormat --hw-opal <device>
|
||||
Enter passphrase for <device>: ***
|
||||
Enter OPAL Admin password: ***
|
||||
|
||||
* Check configuration with luksDump.
|
||||
Note "hw-opal-crypt" segment that uses both dm-crypt and OPAL
|
||||
encryption - keyslot stores 768 bits key (512 sw + 256 bits OPAL key).
|
||||
|
||||
# cryptsetup luksDump <device>
|
||||
LUKS header information
|
||||
Version: 2
|
||||
...
|
||||
Data segments:
|
||||
0: hw-opal-crypt
|
||||
offset: 16777216 [bytes]
|
||||
length: ... [bytes]
|
||||
cipher: aes-xts-plain64
|
||||
sector: 512 [bytes]
|
||||
HW OPAL encryption:
|
||||
OPAL segment number: 1
|
||||
OPAL key: 256 bits
|
||||
OPAL segment length: ... [bytes]
|
||||
Keyslots:
|
||||
0: luks2
|
||||
Key: 768 bits
|
||||
...
|
||||
|
||||
For devices with OPAL encryption ONLY (only 256 bits OPAL unlocking
|
||||
key is stored):
|
||||
LUKS header information
|
||||
Version: 2
|
||||
...
|
||||
|
||||
Data segments:
|
||||
0: hw-opal
|
||||
offset: 16777216 [bytes]
|
||||
length: ... [bytes]
|
||||
cipher: (no SW encryption)
|
||||
HW OPAL encryption:
|
||||
OPAL segment number: 1
|
||||
OPAL key: 256 bits
|
||||
OPAL segment length: ... [bytes]
|
||||
Keyslots:
|
||||
0: luks2
|
||||
Key: 256 bits
|
||||
...
|
||||
|
||||
* Activation and deactivation (open, close, luksSuspend, luksResume)
|
||||
with OPAL works the same as for the LUKS2 device.
|
||||
|
||||
* Erase LUKS metadata (keyslots) and remove OPAL locking range:
|
||||
# cryptsetup luksErase <device>
|
||||
Enter OPAL Admin password: ***
|
||||
|
||||
The LUKS header is destroyed (unlike in normal LUKS luksErase) as
|
||||
data are no longer accessible even with previous volume key knowledge.
|
||||
|
||||
* Factory reset OPAL drive (if you do not know the Admin password).
|
||||
You need the PSID (physical presence security ID), which is usually
|
||||
printed on the device label. Note this will reset the device to
|
||||
factory state, erasing all data on it (not only LUKS).
|
||||
|
||||
# cryptsetup luksErase --hw-opal-factory-reset <device>
|
||||
Enter OPAL PSID: ***
|
||||
|
||||
* plain mode: Set default cipher to aes-xts-plain64 and password hashing
|
||||
to sha256.
|
||||
|
||||
NOTE: this is a backward incompatible change for plain mode (if you
|
||||
rely on defaults). It is not relevant for LUKS devices.
|
||||
|
||||
The default plain encryption mode was CBC for a long time, with many
|
||||
performance problems. Using XTS mode aligns it with LUKS defaults.
|
||||
|
||||
The hash algorithm for plain mode was ripemd160, which is considered
|
||||
deprecated, so the new default is sha256.
|
||||
|
||||
The default key size remains 256 bits (it means using AES-128 as XTS
|
||||
requires two keys).
|
||||
|
||||
Always specify cipher, hash, and key size for plain mode (or even
|
||||
better, use LUKS as it stores all options in its metadata on disk).
|
||||
As we need to upgrade algorithms from time to time because of security
|
||||
reasons, cryptsetup now warns users to specify these options explicitly
|
||||
in the open cryptsetup command if plain mode is used.
|
||||
Cryptsetup does not block using any legacy encryption type; just it
|
||||
must be specified explicitly on the cryptsetup command line.
|
||||
|
||||
You can configure these defaults during build time if you need to
|
||||
enforce backward compatibility.
|
||||
To get the backward-compatible setting, use:
|
||||
--with-plain-hash=ripemd160 --with-plain-cipher=aes
|
||||
--with-plain-mode=cbc-essiv:sha256
|
||||
|
||||
Compiled-in defaults are visible in cryptsetup --help output.
|
||||
|
||||
* Allow activation (open), luksResume, and luksAddKey to use the volume
|
||||
key stored in a keyring.
|
||||
* Allow to store volume key to a user-specified keyring in open and
|
||||
luksResume commands.
|
||||
|
||||
These options are intended to be used for integration with other
|
||||
systems for automation.
|
||||
|
||||
Note: the API will slightly change in the next release candidate
|
||||
(active reencryption will need to setup old and new keys together).
|
||||
|
||||
Users can now use the volume key (not passphrase) stored in arbitrary
|
||||
kernel keyring and directly use it in particular cryptsetup commands
|
||||
with --volume-key-keyring option. The keyring can use various policies
|
||||
(set outside of the cryptsetup scope, for example, by keyctl).
|
||||
|
||||
The --volume-key-keyring option takes a key description in
|
||||
keyctl-compatible syntax and can either be a numeric key ID or
|
||||
a string name in the format [%<key type>:]<key name>.
|
||||
The default key type is "user".
|
||||
|
||||
To store the volume key in a keyring, you can use cryptsetup with
|
||||
--link-vk-to-keyring option that is available for open and luksResume
|
||||
cryptsetup command. The option argument has a more complex format:
|
||||
<keyring_description>::<key_description>.
|
||||
The <keyring_description> contains the existing kernel keyring
|
||||
description (numeric id or keyctl format). The <keyring_description>
|
||||
may be optionaly prefixed with "%:" or "%keyring:". The string "::" is
|
||||
a delimiter that separates keyring and key descriptions.
|
||||
The <key_description> has the same syntax as used in the
|
||||
--volume-key-keyring option.
|
||||
|
||||
Example:
|
||||
|
||||
Open the device and store the volume key to the keyring:
|
||||
# cryptsetup open <device> --link-vk-to-keyring "@s::%user:testkey" tst
|
||||
|
||||
Add keyslot using the stored key in a keyring:
|
||||
# cryptsetup luksAddKey <device> --volume-key-keyring "%user:testkey"
|
||||
|
||||
* Do not flush IO operations if resize grows the device.
|
||||
This can help performance in specific cases where the encrypted device
|
||||
is extended automatically while running many IO operations.
|
||||
|
||||
* Use only half of detected free memory for Argon2 PBKDF on systems
|
||||
without swap (for LUKS2 new keyslot or format operations).
|
||||
|
||||
This should avoid out-of-memory crashes on low-memory systems without
|
||||
swap. The benchmark for memory-hard KDF during format is tricky, and
|
||||
it seems that relying on the maximum half of physical memory is not
|
||||
enough; relying on free memory should bring the needed security margin
|
||||
while still using Argon2.
|
||||
There is no change for systems with active swap.
|
||||
Note, for very-low memory-constrained systems, a user should avoid
|
||||
memory-hard PBKDF completely (manually select legacy PBKDF2 instead
|
||||
of Argon2); cryptsetup does not change PBKDF automatically.
|
||||
|
||||
* Add the possibility to specify a directory for external LUKS2 token
|
||||
handlers (plugins).
|
||||
|
||||
Use --external-tokens-path parameter in cryptsetup or
|
||||
crypt_token_set_external_path API call. The parameter is required to be
|
||||
an absolute path, and it is set per process context. This parameter is
|
||||
intended mainly for testing and developing new tokens.
|
||||
|
||||
* Do not allow reencryption/decryption on LUKS2 devices with
|
||||
authenticated encryption or hardware (OPAL) encryption.
|
||||
|
||||
The operation fails later anyway; cryptsetup now detects incompatible
|
||||
parameters early.
|
||||
|
||||
* Do not fail LUKS format if the operation was interrupted on subsequent
|
||||
device wipe.
|
||||
|
||||
Device wipe (used with authenticated encryption) is an optional
|
||||
operation and can be interrupted; not yet wiped part of the device will
|
||||
only report integrity errors (until overwritten with new data).
|
||||
|
||||
* Fix the LUKS2 keyslot option to be used while activating the device
|
||||
by a token.
|
||||
|
||||
It can also be used to check if a specific token (--token-id) can
|
||||
unlock a specific keyslot (--key-slot option) when --test-passphrase
|
||||
option is specified.
|
||||
|
||||
* Properly report if the dm-verity device cannot be activated due to
|
||||
the inability to verify the signed root hash.
|
||||
|
||||
If the kernel returns ENOKEY, it is properly propagated.
|
||||
|
||||
* Fix to check passphrase for selected keyslot only when adding
|
||||
new keyslot.
|
||||
|
||||
If the user specifies the exact keyslot to unlock, cryptsetup no longer
|
||||
checks other keyslots.
|
||||
|
||||
* Fix to not wipe the keyslot area before in-place overwrite.
|
||||
|
||||
If the LUKS2 keyslot area has to be overwritten (due to lack of free
|
||||
space for keyslot swap), cryptsetup does not wipe the affected area as
|
||||
the first step (it will be overwritten later anyway).
|
||||
Previously, there was an unnecessary risk of losing the keyslot data
|
||||
if the code crashed before adding the new keyslot.
|
||||
|
||||
If there is enough space in the keyslot area, cryptsetup never
|
||||
overwrites the older keyslot before the new one is written correctly
|
||||
(even if the keyslot number remains the same).
|
||||
|
||||
* bitlk: Fix segfaults when attempting to verify the volume key.
|
||||
|
||||
Also, clarify that verifying the volume key is impossible without
|
||||
providing a passphrase or recovery key.
|
||||
|
||||
* Add --disable-blkid command line option to avoid blkid device check.
|
||||
|
||||
* Add support for the meson build system.
|
||||
|
||||
All basic operations are supported (compile, test, and dist) with some
|
||||
minor exceptions; please see the meson manual for more info.
|
||||
|
||||
The Meson build system will completely replace autotools in some future
|
||||
major release. Both autotools and meson build systems are supported,
|
||||
and the release archive is built with autotools.
|
||||
|
||||
* Fix wipe operation that overwrites the whole device if used for LUKS2
|
||||
header with no keyslot area.
|
||||
|
||||
Formatting a LUKS2 device with no defined keyslots area is a very
|
||||
specific operation, and the code now properly recognizes such
|
||||
configuration.
|
||||
|
||||
* Fix luksErase to work with detached LUKS header.
|
||||
|
||||
* Disallow the use of internal kernel crypto driver names in "capi"
|
||||
specification.
|
||||
|
||||
The common way to specify cipher mode in cryptsetup is to use
|
||||
cipher-mode-iv notation (like aes-xts-plain64).
|
||||
With the introduction of authenticated ciphers, we also allow
|
||||
"capi:<spec>" notation that is directly used by dm-crypt
|
||||
(e.g., capi:xts(aes)-plain64).
|
||||
|
||||
CAPI specification was never intended to be used directly in the LUKS
|
||||
header; unfortunately, the code allowed it until now.
|
||||
Devices with CAPI specification in metadata can no longer be activated;
|
||||
header repair is required.
|
||||
|
||||
CAPI specification could allow attackers to change the cipher
|
||||
specification to enforce loading some specific kernel crypto driver
|
||||
(for example, load driver with known side-channel issues).
|
||||
This can be problematic, specifically in a cloud environment
|
||||
(modifying LUKS2 metadata in container image).
|
||||
|
||||
Thanks to Jan Wichelmann, Luca Wilke, and Thomas Eisenbarth from
|
||||
University of Luebeck for noticing the problems with this code.
|
||||
|
||||
* Fix reencryption to fail early for unknown cipher.
|
||||
|
||||
* tcrypt: Support new Blake2 hash for VeraCrypt.
|
||||
|
||||
VeraCrypt introduces support for Blake2 PRF for PBKDF2; also support it
|
||||
in cryptsetup compatible tcrypt format.
|
||||
|
||||
* tcrypt: use hash values as substring for limiting KDF check.
|
||||
|
||||
This allows the user to specify --hash sha or --hash blake2 to limit
|
||||
the KDF scan without the need to specify the full algorithm name
|
||||
(similar to cipher where we already use substring match).
|
||||
|
||||
* Add Aria cipher support and block size info.
|
||||
|
||||
Aria cipher is similar to AES and is supported in Linux kernel crypto
|
||||
API in recent releases.
|
||||
It can be now used also for LUKS keyslot encryption.
|
||||
|
||||
* Do not decrease PBKDF parameters if the user forces them.
|
||||
|
||||
If a user explicitly specifies PBKDF parameters (like iterations,
|
||||
used memory, or threads), do not limit them, even if it can cause
|
||||
resource exhaustion.
|
||||
The force options were mostly used for decreasing parameters, but it
|
||||
should work even opposite - despite the fact it can mean an
|
||||
out-of-memory crash.
|
||||
|
||||
The only limits are hard limits per the PBKDF algorithm.
|
||||
|
||||
* Support OpenSSL 3.2 Argon2 implementation.
|
||||
|
||||
Argon2 is now available directly in OpenSSL, so the code no longer
|
||||
needs to use libargon implementation.
|
||||
Configure script should detect this automatically.
|
||||
|
||||
* Add support for Argon2 from libgcrypt
|
||||
(requires yet unreleased gcrypt 1.11).
|
||||
|
||||
Argon2 has been available since version 1.10, but we need version 1.11,
|
||||
which will allow empty passwords.
|
||||
|
||||
* Link only libcrypto from OpenSSL.
|
||||
|
||||
This reduces dependencies as other OpenSSL libraries are not needed.
|
||||
|
||||
* Disable reencryption for Direct-Access (DAX) devices.
|
||||
|
||||
Linux kernel device-mapper cannot stack DAX/non-DAX devices in
|
||||
the mapping table, so online reencryption cannot work. Detect DAX
|
||||
devices and warn users during LUKS format. Also, DAX or persistent
|
||||
memory devices do not provide atomic sector updates; any single
|
||||
modification can corrupt the whole encryption block.
|
||||
|
||||
* Print a warning message if the device is not aligned to sector size.
|
||||
|
||||
If a partition is resized after format, activation could fail when
|
||||
the device is not multiple of a sector size. Print at least a warning
|
||||
here, as the activation error message is visible only in kernel syslog.
|
||||
|
||||
* Fix sector size and integrity fields display for non-LUKS2 crypt
|
||||
devices for the status command.
|
||||
|
||||
* Fix suspend for LUKS2 with authenticated encryption (also suspend
|
||||
dm-integrity device underneath).
|
||||
|
||||
This should stop the dm-integrity device from issuing journal updates
|
||||
and possibly corrupt data if the user also tries to modify the
|
||||
underlying device.
|
||||
|
||||
Libcryptsetup API extensions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
The libcryptsetup API is backward compatible for all existing symbols.
|
||||
|
||||
New symbols:
|
||||
crypt_activate_by_keyslot_context
|
||||
crypt_format_luks2_opal
|
||||
crypt_get_hw_encryption_type
|
||||
crypt_get_hw_encryption_key_size
|
||||
crypt_keyslot_context_init_by_keyring
|
||||
crypt_keyslot_context_init_by_vk_in_keyring
|
||||
crypt_keyslot_context_init_by_signed_key
|
||||
crypt_resume_by_keyslot_context
|
||||
crypt_token_set_external_path
|
||||
crypt_set_keyring_to_link
|
||||
crypt_wipe_hw_opal
|
||||
|
||||
New defines (hw encryption status):
|
||||
CRYPT_SW_ONLY
|
||||
CRYPT_OPAL_HW_ONLY
|
||||
CRYPT_SW_AND_OPAL_HW
|
||||
|
||||
New keyslot context types:
|
||||
CRYPT_KC_TYPE_KEYRING
|
||||
CRYPT_KC_TYPE_VK_KEYRING
|
||||
CRYPT_KC_TYPE_SIGNED_KEY
|
||||
|
||||
New requirement flag:
|
||||
CRYPT_REQUIREMENT_OPAL
|
||||
@@ -53,8 +53,6 @@ libcryptsetup_la_SOURCES = \
|
||||
lib/utils_loop.h \
|
||||
lib/utils_devpath.c \
|
||||
lib/utils_wipe.c \
|
||||
lib/utils_fips.c \
|
||||
lib/utils_fips.h \
|
||||
lib/utils_device.c \
|
||||
lib/utils_keyring.c \
|
||||
lib/utils_keyring.h \
|
||||
@@ -75,6 +73,8 @@ libcryptsetup_la_SOURCES = \
|
||||
lib/loopaes/loopaes.c \
|
||||
lib/tcrypt/tcrypt.h \
|
||||
lib/tcrypt/tcrypt.c \
|
||||
lib/keyslot_context.h \
|
||||
lib/keyslot_context.c \
|
||||
lib/luks1/af.h \
|
||||
lib/luks1/af.c \
|
||||
lib/luks1/keyencryption.c \
|
||||
@@ -103,7 +103,11 @@ libcryptsetup_la_SOURCES = \
|
||||
lib/luks2/luks2_token.c \
|
||||
lib/luks2/luks2_internal.h \
|
||||
lib/luks2/luks2.h \
|
||||
lib/luks2/hw_opal/hw_opal.c \
|
||||
lib/luks2/hw_opal/hw_opal.h \
|
||||
lib/utils_blkid.c \
|
||||
lib/utils_blkid.h \
|
||||
lib/bitlk/bitlk.h \
|
||||
lib/bitlk/bitlk.c
|
||||
lib/bitlk/bitlk.c \
|
||||
lib/fvault2/fvault2.h \
|
||||
lib/fvault2/fvault2.c
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/*
|
||||
* BITLK (BitLocker-compatible) volume handling
|
||||
*
|
||||
* Copyright (C) 2019-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2019-2022 Milan Broz
|
||||
* Copyright (C) 2019-2022 Vojtech Trefny
|
||||
* Copyright (C) 2019-2023 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2019-2023 Milan Broz
|
||||
* Copyright (C) 2019-2023 Vojtech Trefny
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -255,13 +255,16 @@ static int parse_vmk_entry(struct crypt_device *cd, uint8_t *data, int start, in
|
||||
(*vmk)->protection == BITLK_PROTECTION_RECOVERY_PASSPHRASE ||
|
||||
(*vmk)->protection == BITLK_PROTECTION_STARTUP_KEY;
|
||||
|
||||
while (end - start > 2) {
|
||||
while ((end - start) >= (ssize_t)(sizeof(key_entry_size) + sizeof(key_entry_type) + sizeof(key_entry_value))) {
|
||||
/* size of this entry */
|
||||
memcpy(&key_entry_size, data + start, sizeof(key_entry_size));
|
||||
key_entry_size = le16_to_cpu(key_entry_size);
|
||||
if (key_entry_size == 0)
|
||||
break;
|
||||
|
||||
if (key_entry_size > (end - start))
|
||||
return -EINVAL;
|
||||
|
||||
/* type and value of this entry */
|
||||
memcpy(&key_entry_type, data + start + sizeof(key_entry_size), sizeof(key_entry_type));
|
||||
memcpy(&key_entry_value,
|
||||
@@ -280,20 +283,24 @@ static int parse_vmk_entry(struct crypt_device *cd, uint8_t *data, int start, in
|
||||
}
|
||||
|
||||
/* stretch key with salt, skip 4 B (encryption method of the stretch key) */
|
||||
if (key_entry_value == BITLK_ENTRY_VALUE_STRETCH_KEY)
|
||||
if (key_entry_value == BITLK_ENTRY_VALUE_STRETCH_KEY) {
|
||||
if ((end - start) < (BITLK_ENTRY_HEADER_LEN + BITLK_SALT_SIZE + 4))
|
||||
return -EINVAL;
|
||||
memcpy((*vmk)->salt,
|
||||
data + start + BITLK_ENTRY_HEADER_LEN + 4,
|
||||
sizeof((*vmk)->salt));
|
||||
BITLK_SALT_SIZE);
|
||||
/* AES-CCM encrypted key */
|
||||
else if (key_entry_value == BITLK_ENTRY_VALUE_ENCRYPTED_KEY) {
|
||||
} else if (key_entry_value == BITLK_ENTRY_VALUE_ENCRYPTED_KEY) {
|
||||
if (key_entry_size < (BITLK_ENTRY_HEADER_LEN + BITLK_NONCE_SIZE + BITLK_VMK_MAC_TAG_SIZE))
|
||||
return -EINVAL;
|
||||
/* nonce */
|
||||
memcpy((*vmk)->nonce,
|
||||
data + start + BITLK_ENTRY_HEADER_LEN,
|
||||
sizeof((*vmk)->nonce));
|
||||
BITLK_NONCE_SIZE);
|
||||
/* MAC tag */
|
||||
memcpy((*vmk)->mac_tag,
|
||||
data + start + BITLK_ENTRY_HEADER_LEN + BITLK_NONCE_SIZE,
|
||||
sizeof((*vmk)->mac_tag));
|
||||
BITLK_VMK_MAC_TAG_SIZE);
|
||||
/* AES-CCM encrypted key */
|
||||
key_size = key_entry_size - (BITLK_ENTRY_HEADER_LEN + BITLK_NONCE_SIZE + BITLK_VMK_MAC_TAG_SIZE);
|
||||
key = (const char *) data + start + BITLK_ENTRY_HEADER_LEN + BITLK_NONCE_SIZE + BITLK_VMK_MAC_TAG_SIZE;
|
||||
@@ -318,6 +325,8 @@ 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 (key_entry_size < BITLK_ENTRY_HEADER_LEN)
|
||||
return -EINVAL;
|
||||
string = malloc((key_entry_size - BITLK_ENTRY_HEADER_LEN) * 2 + 1);
|
||||
if (!string)
|
||||
return -ENOMEM;
|
||||
@@ -405,6 +414,7 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
|
||||
struct bitlk_fve_metadata fve = {};
|
||||
struct bitlk_entry_vmk entry_vmk = {};
|
||||
uint8_t *fve_entries = NULL;
|
||||
size_t fve_entries_size = 0;
|
||||
uint32_t fve_metadata_size = 0;
|
||||
int fve_offset = 0;
|
||||
char guid_buf[UUID_STR_LEN] = {0};
|
||||
@@ -413,7 +423,6 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
|
||||
int i = 0;
|
||||
int r = 0;
|
||||
int start = 0;
|
||||
int end = 0;
|
||||
size_t key_size = 0;
|
||||
const char *key = NULL;
|
||||
char *description = NULL;
|
||||
@@ -514,7 +523,6 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
|
||||
|
||||
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);
|
||||
|
||||
switch (le16_to_cpu(fve.encryption)) {
|
||||
/* AES-CBC with Elephant difuser */
|
||||
@@ -569,40 +577,56 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
|
||||
|
||||
params->creation_time = filetime_to_unixtime(le64_to_cpu(fve.creation_time));
|
||||
|
||||
fve_metadata_size = le32_to_cpu(fve.metadata_size);
|
||||
if (fve_metadata_size < (BITLK_FVE_METADATA_HEADER_LEN + sizeof(entry_size) + sizeof(entry_type)) ||
|
||||
fve_metadata_size > BITLK_FVE_METADATA_SIZE) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
fve_entries_size = fve_metadata_size - BITLK_FVE_METADATA_HEADER_LEN;
|
||||
|
||||
/* read and parse all FVE metadata entries */
|
||||
fve_entries = malloc(fve_metadata_size - BITLK_FVE_METADATA_HEADER_LEN);
|
||||
fve_entries = malloc(fve_entries_size);
|
||||
if (!fve_entries) {
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
memset(fve_entries, 0, (fve_metadata_size - BITLK_FVE_METADATA_HEADER_LEN));
|
||||
memset(fve_entries, 0, fve_entries_size);
|
||||
|
||||
log_dbg(cd, "Reading BITLK FVE metadata entries of size %" PRIu32 " on device %s, offset %" PRIu64 ".",
|
||||
fve_metadata_size - BITLK_FVE_METADATA_HEADER_LEN, device_path(device),
|
||||
params->metadata_offset[0] + BITLK_FVE_METADATA_HEADERS_LEN);
|
||||
log_dbg(cd, "Reading BITLK FVE metadata entries of size %zu on device %s, offset %" PRIu64 ".",
|
||||
fve_entries_size, device_path(device), params->metadata_offset[0] + BITLK_FVE_METADATA_HEADERS_LEN);
|
||||
|
||||
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
|
||||
device_alignment(device), fve_entries, fve_metadata_size - BITLK_FVE_METADATA_HEADER_LEN,
|
||||
params->metadata_offset[0] + BITLK_FVE_METADATA_HEADERS_LEN) != (ssize_t)(fve_metadata_size - BITLK_FVE_METADATA_HEADER_LEN)) {
|
||||
device_alignment(device), fve_entries, fve_entries_size,
|
||||
params->metadata_offset[0] + BITLK_FVE_METADATA_HEADERS_LEN) != (ssize_t)fve_entries_size) {
|
||||
log_err(cd, _("Failed to read BITLK metadata entries from %s."), device_path(device));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
end = fve_metadata_size - BITLK_FVE_METADATA_HEADER_LEN;
|
||||
while (end - start > 2) {
|
||||
while ((fve_entries_size - start) >= (sizeof(entry_size) + sizeof(entry_type))) {
|
||||
|
||||
/* size of this entry */
|
||||
memcpy(&entry_size, fve_entries + start, sizeof(entry_size));
|
||||
entry_size = le16_to_cpu(entry_size);
|
||||
if (entry_size == 0)
|
||||
break;
|
||||
|
||||
if (entry_size > (fve_entries_size - start)) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* type of this entry */
|
||||
memcpy(&entry_type, fve_entries + start + sizeof(entry_size), sizeof(entry_type));
|
||||
entry_type = le16_to_cpu(entry_type);
|
||||
|
||||
/* VMK */
|
||||
if (entry_type == BITLK_ENTRY_TYPE_VMK) {
|
||||
if (entry_size < (BITLK_ENTRY_HEADER_LEN + sizeof(entry_vmk))) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
/* skip first four variables in the entry (entry size, type, value and version) */
|
||||
memcpy(&entry_vmk,
|
||||
fve_entries + start + BITLK_ENTRY_HEADER_LEN,
|
||||
@@ -639,7 +663,11 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
|
||||
vmk_p = vmk;
|
||||
vmk = vmk->next;
|
||||
/* FVEK */
|
||||
} else if (entry_type == BITLK_ENTRY_TYPE_FVEK) {
|
||||
} else if (entry_type == BITLK_ENTRY_TYPE_FVEK && !params->fvek) {
|
||||
if (entry_size < (BITLK_ENTRY_HEADER_LEN + BITLK_NONCE_SIZE + BITLK_VMK_MAC_TAG_SIZE)) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
params->fvek = malloc(sizeof(struct bitlk_fvek));
|
||||
if (!params->fvek) {
|
||||
r = -ENOMEM;
|
||||
@@ -647,11 +675,11 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
|
||||
}
|
||||
memcpy(params->fvek->nonce,
|
||||
fve_entries + start + BITLK_ENTRY_HEADER_LEN,
|
||||
sizeof(params->fvek->nonce));
|
||||
BITLK_NONCE_SIZE);
|
||||
/* MAC tag */
|
||||
memcpy(params->fvek->mac_tag,
|
||||
fve_entries + start + BITLK_ENTRY_HEADER_LEN + BITLK_NONCE_SIZE,
|
||||
sizeof(params->fvek->mac_tag));
|
||||
BITLK_VMK_MAC_TAG_SIZE);
|
||||
/* AES-CCM encrypted key */
|
||||
key_size = entry_size - (BITLK_ENTRY_HEADER_LEN + BITLK_NONCE_SIZE + BITLK_VMK_MAC_TAG_SIZE);
|
||||
key = (const char *) fve_entries + start + BITLK_ENTRY_HEADER_LEN + BITLK_NONCE_SIZE + BITLK_VMK_MAC_TAG_SIZE;
|
||||
@@ -663,19 +691,29 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
|
||||
/* volume header info (location and size) */
|
||||
} else if (entry_type == BITLK_ENTRY_TYPE_VOLUME_HEADER) {
|
||||
struct bitlk_entry_header_block entry_header;
|
||||
if ((fve_entries_size - start) < (BITLK_ENTRY_HEADER_LEN + sizeof(entry_header))) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
memcpy(&entry_header,
|
||||
fve_entries + start + BITLK_ENTRY_HEADER_LEN,
|
||||
sizeof(entry_header));
|
||||
params->volume_header_offset = le64_to_cpu(entry_header.offset);
|
||||
params->volume_header_size = le64_to_cpu(entry_header.size);
|
||||
/* volume description (utf-16 string) */
|
||||
} else if (entry_type == BITLK_ENTRY_TYPE_DESCRIPTION) {
|
||||
description = malloc((entry_size - BITLK_ENTRY_HEADER_LEN - BITLK_ENTRY_HEADER_LEN) * 2 + 1);
|
||||
if (!description)
|
||||
return -ENOMEM;
|
||||
} else if (entry_type == BITLK_ENTRY_TYPE_DESCRIPTION && !params->description) {
|
||||
if (entry_size < BITLK_ENTRY_HEADER_LEN) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
description = malloc((entry_size - BITLK_ENTRY_HEADER_LEN) * 2 + 1);
|
||||
if (!description) {
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
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) {
|
||||
if (r < 0) {
|
||||
free(description);
|
||||
BITLK_bitlk_vmk_free(vmk);
|
||||
log_err(cd, _("Failed to convert BITLK volume description"));
|
||||
@@ -697,6 +735,7 @@ int BITLK_dump(struct crypt_device *cd, struct device *device, struct bitlk_meta
|
||||
{
|
||||
struct volume_key *vk_p;
|
||||
struct bitlk_vmk *vmk_p;
|
||||
char time[32];
|
||||
int next_id = 0;
|
||||
int i = 0;
|
||||
|
||||
@@ -705,7 +744,8 @@ int BITLK_dump(struct crypt_device *cd, struct device *device, struct bitlk_meta
|
||||
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)));
|
||||
if (ctime_r((time_t *)¶ms->creation_time, time))
|
||||
log_std(cd, "Created: \t%s", time);
|
||||
log_std(cd, "Description: \t%s\n", params->description);
|
||||
log_std(cd, "Cipher name: \t%s\n", params->cipher);
|
||||
log_std(cd, "Cipher mode: \t%s\n", params->cipher_mode);
|
||||
@@ -773,13 +813,13 @@ static int get_recovery_key(struct crypt_device *cd,
|
||||
- each part is a number dividable by 11
|
||||
*/
|
||||
if (passwordLen != BITLK_RECOVERY_KEY_LEN) {
|
||||
if (passwordLen == BITLK_RECOVERY_KEY_LEN + 1 && password[passwordLen - 1] == '\n') {
|
||||
/* looks like a recovery key with an extra newline, possibly from a key file */
|
||||
passwordLen--;
|
||||
log_dbg(cd, "Possible extra EOL stripped from the recovery key.");
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
if (passwordLen == BITLK_RECOVERY_KEY_LEN + 1 && password[passwordLen - 1] == '\n') {
|
||||
/* looks like a recovery key with an extra newline, possibly from a key file */
|
||||
passwordLen--;
|
||||
log_dbg(cd, "Possible extra EOL stripped from the recovery key.");
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = BITLK_RECOVERY_PART_LEN; i < passwordLen; i += BITLK_RECOVERY_PART_LEN + 1) {
|
||||
if (password[i] != '-')
|
||||
@@ -822,13 +862,16 @@ static int parse_external_key_entry(struct crypt_device *cd,
|
||||
struct bitlk_guid guid;
|
||||
char guid_buf[UUID_STR_LEN] = {0};
|
||||
|
||||
while (end - start > 2) {
|
||||
while ((end - start) >= (ssize_t)(sizeof(key_entry_size) + sizeof(key_entry_type) + sizeof(key_entry_value))) {
|
||||
/* size of this entry */
|
||||
memcpy(&key_entry_size, data + start, sizeof(key_entry_size));
|
||||
key_entry_size = le16_to_cpu(key_entry_size);
|
||||
if (key_entry_size == 0)
|
||||
break;
|
||||
|
||||
if (key_entry_size > (end - start))
|
||||
return -EINVAL;
|
||||
|
||||
/* type and value of this entry */
|
||||
memcpy(&key_entry_type, data + start + sizeof(key_entry_size), sizeof(key_entry_type));
|
||||
memcpy(&key_entry_value,
|
||||
@@ -843,6 +886,8 @@ static int parse_external_key_entry(struct crypt_device *cd,
|
||||
}
|
||||
|
||||
if (key_entry_value == BITLK_ENTRY_VALUE_KEY) {
|
||||
if (key_entry_size < (BITLK_ENTRY_HEADER_LEN + 4))
|
||||
return -EINVAL;
|
||||
key_size = key_entry_size - (BITLK_ENTRY_HEADER_LEN + 4);
|
||||
key = (const char *) data + start + BITLK_ENTRY_HEADER_LEN + 4;
|
||||
*vk = crypt_alloc_volume_key(key_size, key);
|
||||
@@ -854,6 +899,8 @@ static int parse_external_key_entry(struct crypt_device *cd,
|
||||
;
|
||||
/* GUID of the BitLocker device we are trying to open with this key */
|
||||
else if (key_entry_value == BITLK_ENTRY_VALUE_GUID) {
|
||||
if ((end - start) < (ssize_t)(BITLK_ENTRY_HEADER_LEN + sizeof(struct bitlk_guid)))
|
||||
return -EINVAL;
|
||||
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) {
|
||||
@@ -887,7 +934,7 @@ static int get_startup_key(struct crypt_device *cd,
|
||||
uint16_t key_entry_type = 0;
|
||||
uint16_t key_entry_value = 0;
|
||||
|
||||
if (passwordLen < BITLK_BEK_FILE_HEADER_LEN)
|
||||
if (passwordLen < (BITLK_BEK_FILE_HEADER_LEN + sizeof(key_entry_size) + sizeof(key_entry_type) + sizeof(key_entry_value)))
|
||||
return -EPERM;
|
||||
|
||||
memcpy(&bek_header, password, BITLK_BEK_FILE_HEADER_LEN);
|
||||
@@ -899,13 +946,14 @@ static int get_startup_key(struct crypt_device *cd,
|
||||
else
|
||||
return -EPERM;
|
||||
|
||||
if (bek_header.metadata_version != 1) {
|
||||
log_err(cd, _("Unsupported BEK metadata version %" PRIu32), bek_header.metadata_version);
|
||||
if (le32_to_cpu(bek_header.metadata_version) != 1) {
|
||||
log_err(cd, _("Unsupported BEK metadata version %" PRIu32), le32_to_cpu(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);
|
||||
if (le32_to_cpu(bek_header.metadata_size) != passwordLen) {
|
||||
log_err(cd, _("Unexpected BEK metadata size %" PRIu32 " does not match BEK file length"),
|
||||
le32_to_cpu(bek_header.metadata_size));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -936,8 +984,7 @@ static int get_startup_key(struct crypt_device *cd,
|
||||
}
|
||||
}
|
||||
|
||||
static int bitlk_kdf(struct crypt_device *cd,
|
||||
const char *password,
|
||||
static int bitlk_kdf(const char *password,
|
||||
size_t passwordLen,
|
||||
bool recovery,
|
||||
const uint8_t *salt,
|
||||
@@ -1074,7 +1121,7 @@ int BITLK_get_volume_key(struct crypt_device *cd,
|
||||
next_vmk = params->vmks;
|
||||
while (next_vmk) {
|
||||
if (next_vmk->protection == BITLK_PROTECTION_PASSPHRASE) {
|
||||
r = bitlk_kdf(cd, password, passwordLen, false, next_vmk->salt, &vmk_dec_key);
|
||||
r = bitlk_kdf(password, passwordLen, false, next_vmk->salt, &vmk_dec_key);
|
||||
if (r) {
|
||||
/* something wrong happened, but we still want to check other key slots */
|
||||
next_vmk = next_vmk->next;
|
||||
@@ -1094,7 +1141,7 @@ int BITLK_get_volume_key(struct crypt_device *cd,
|
||||
continue;
|
||||
}
|
||||
log_dbg(cd, "Trying to use given password as a recovery key.");
|
||||
r = bitlk_kdf(cd, recovery_key->key, recovery_key->keylength,
|
||||
r = bitlk_kdf(recovery_key->key, recovery_key->keylength,
|
||||
true, next_vmk->salt, &vmk_dec_key);
|
||||
crypt_free_volume_key(recovery_key);
|
||||
if (r)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/*
|
||||
* BITLK (BitLocker-compatible) header definition
|
||||
*
|
||||
* Copyright (C) 2019-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2019-2022 Milan Broz
|
||||
* Copyright (C) 2019-2022 Vojtech Trefny
|
||||
* Copyright (C) 2019-2023 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2019-2023 Milan Broz
|
||||
* Copyright (C) 2019-2023 Vojtech Trefny
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
* cryptsetup plain device helper functions
|
||||
*
|
||||
* Copyright (C) 2004 Jana Saout <jana@saout.de>
|
||||
* Copyright (C) 2010-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2022 Milan Broz
|
||||
* Copyright (C) 2010-2023 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2023 Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
||||
28
lib/crypto_backend/argon2/meson.build
Normal file
28
lib/crypto_backend/argon2/meson.build
Normal file
@@ -0,0 +1,28 @@
|
||||
libargon2_sources = files(
|
||||
'blake2/blake2b.c',
|
||||
'argon2.c',
|
||||
'core.c',
|
||||
'encoding.c',
|
||||
'thread.c',
|
||||
)
|
||||
|
||||
if use_internal_sse_argon2
|
||||
libargon2_sources += files(
|
||||
'opt.c',
|
||||
)
|
||||
else
|
||||
libargon2_sources += files(
|
||||
'ref.c',
|
||||
)
|
||||
endif
|
||||
|
||||
libargon2 = static_library('argon2',
|
||||
libargon2_sources,
|
||||
override_options : ['c_std=c89', 'optimization=3'],
|
||||
build_by_default : false,
|
||||
include_directories: include_directories(
|
||||
'blake2',
|
||||
),
|
||||
dependencies : [
|
||||
threads,
|
||||
])
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Argon2 PBKDF2 library wrapper
|
||||
*
|
||||
* Copyright (C) 2016-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2016-2022 Milan Broz
|
||||
* Copyright (C) 2016-2023 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2016-2023 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -29,14 +29,12 @@
|
||||
|
||||
#define CONST_CAST(x) (x)(uintptr_t)
|
||||
|
||||
#if USE_INTERNAL_ARGON2 || HAVE_ARGON2_H
|
||||
int argon2(const char *type, const char *password, size_t password_length,
|
||||
const char *salt, size_t salt_length,
|
||||
char *key, size_t key_length,
|
||||
uint32_t iterations, uint32_t memory, uint32_t parallel)
|
||||
{
|
||||
#if !USE_INTERNAL_ARGON2 && !HAVE_ARGON2_H
|
||||
return -EINVAL;
|
||||
#else
|
||||
argon2_type atype;
|
||||
argon2_context context = {
|
||||
.flags = ARGON2_DEFAULT_FLAGS,
|
||||
@@ -75,5 +73,17 @@ int argon2(const char *type, const char *password, size_t password_length,
|
||||
}
|
||||
|
||||
return r;
|
||||
#endif
|
||||
}
|
||||
|
||||
#else /* USE_INTERNAL_ARGON2 || HAVE_ARGON2_H */
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
|
||||
int argon2(const char *type, const char *password, size_t password_length,
|
||||
const char *salt, size_t salt_length,
|
||||
char *key, size_t key_length,
|
||||
uint32_t iterations, uint32_t memory, uint32_t parallel)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Copyright (C) 2010 Lennart Poettering
|
||||
*
|
||||
* cryptsetup related changes
|
||||
* Copyright (C) 2021-2022 Milan Broz
|
||||
* Copyright (C) 2021-2023 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -24,7 +24,6 @@
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "crypto_backend.h"
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Cipher performance check
|
||||
*
|
||||
* Copyright (C) 2018-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2018-2022 Milan Broz
|
||||
* Copyright (C) 2018-2023 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2018-2023 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Linux kernel cipher generic utilities
|
||||
*
|
||||
* Copyright (C) 2018-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2018-2022 Milan Broz
|
||||
* Copyright (C) 2018-2023 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2018-2023 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -51,6 +51,7 @@ static const struct cipher_alg cipher_algs[] = {
|
||||
{ "xchacha12,aes", "adiantum", 32, false },
|
||||
{ "xchacha20,aes", "adiantum", 32, false },
|
||||
{ "sm4", NULL, 16, false },
|
||||
{ "aria", NULL, 16, false },
|
||||
{ NULL, NULL, 0, false }
|
||||
};
|
||||
|
||||
|
||||
@@ -97,18 +97,87 @@ static const uint32_t crc32_tab[] = {
|
||||
0x2d02ef8dL
|
||||
};
|
||||
|
||||
static const uint32_t crc32c_tab[] = {
|
||||
0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L, 0xC79A971FL,
|
||||
0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL, 0x8AD958CFL, 0x78B2DBCCL,
|
||||
0x6BE22838L, 0x9989AB3BL, 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L,
|
||||
0x5E133C24L, 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
|
||||
0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L, 0x9A879FA0L,
|
||||
0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L, 0x5D1D08BFL, 0xAF768BBCL,
|
||||
0xBC267848L, 0x4E4DFB4BL, 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L,
|
||||
0x33ED7D2AL, 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
|
||||
0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L, 0x6DFE410EL,
|
||||
0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL, 0x30E349B1L, 0xC288CAB2L,
|
||||
0xD1D83946L, 0x23B3BA45L, 0xF779DEAEL, 0x05125DADL, 0x1642AE59L,
|
||||
0xE4292D5AL, 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
|
||||
0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L, 0x417B1DBCL,
|
||||
0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L, 0x86E18AA3L, 0x748A09A0L,
|
||||
0x67DAFA54L, 0x95B17957L, 0xCBA24573L, 0x39C9C670L, 0x2A993584L,
|
||||
0xD8F2B687L, 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
|
||||
0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L, 0x96BF4DCCL,
|
||||
0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L, 0xDBFC821CL, 0x2997011FL,
|
||||
0x3AC7F2EBL, 0xC8AC71E8L, 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L,
|
||||
0x0F36E6F7L, 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
|
||||
0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L, 0xEB1FCBADL,
|
||||
0x197448AEL, 0x0A24BB5AL, 0xF84F3859L, 0x2C855CB2L, 0xDEEEDFB1L,
|
||||
0xCDBE2C45L, 0x3FD5AF46L, 0x7198540DL, 0x83F3D70EL, 0x90A324FAL,
|
||||
0x62C8A7F9L, 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
|
||||
0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L, 0x3CDB9BDDL,
|
||||
0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L, 0x82F63B78L, 0x709DB87BL,
|
||||
0x63CD4B8FL, 0x91A6C88CL, 0x456CAC67L, 0xB7072F64L, 0xA457DC90L,
|
||||
0x563C5F93L, 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
|
||||
0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL, 0x92A8FC17L,
|
||||
0x60C37F14L, 0x73938CE0L, 0x81F80FE3L, 0x55326B08L, 0xA759E80BL,
|
||||
0xB4091BFFL, 0x466298FCL, 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL,
|
||||
0x0B21572CL, 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
|
||||
0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L, 0x65D122B9L,
|
||||
0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL, 0x2892ED69L, 0xDAF96E6AL,
|
||||
0xC9A99D9EL, 0x3BC21E9DL, 0xEF087A76L, 0x1D63F975L, 0x0E330A81L,
|
||||
0xFC588982L, 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
|
||||
0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L, 0x38CC2A06L,
|
||||
0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L, 0xFF56BD19L, 0x0D3D3E1AL,
|
||||
0x1E6DCDEEL, 0xEC064EEDL, 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L,
|
||||
0xD0DDD530L, 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
|
||||
0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL, 0x8ECEE914L,
|
||||
0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L, 0xD3D3E1ABL, 0x21B862A8L,
|
||||
0x32E8915CL, 0xC083125FL, 0x144976B4L, 0xE622F5B7L, 0xF5720643L,
|
||||
0x07198540L, 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
|
||||
0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL, 0xE330A81AL,
|
||||
0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL, 0x24AA3F05L, 0xD6C1BC06L,
|
||||
0xC5914FF2L, 0x37FACCF1L, 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L,
|
||||
0x7AB90321L, 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
|
||||
0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L, 0x34F4F86AL,
|
||||
0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL, 0x79B737BAL, 0x8BDCB4B9L,
|
||||
0x988C474DL, 0x6AE7C44EL, 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L,
|
||||
0xAD7D5351L
|
||||
};
|
||||
|
||||
/*
|
||||
* This a generic crc32() function, it takes seed as an argument,
|
||||
* and does __not__ xor at the end. Then individual users can do
|
||||
* whatever they need.
|
||||
*/
|
||||
uint32_t crypt_crc32(uint32_t seed, const unsigned char *buf, size_t len)
|
||||
static uint32_t compute_crc32(
|
||||
const uint32_t *crc32_table,
|
||||
uint32_t seed,
|
||||
const unsigned char *buf,
|
||||
size_t len)
|
||||
{
|
||||
uint32_t crc = seed;
|
||||
const unsigned char *p = buf;
|
||||
|
||||
while(len-- > 0)
|
||||
crc = crc32_tab[(crc ^ *p++) & 0xff] ^ (crc >> 8);
|
||||
crc = crc32_table[(crc ^ *p++) & 0xff] ^ (crc >> 8);
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
uint32_t crypt_crc32(uint32_t seed, const unsigned char *buf, size_t len)
|
||||
{
|
||||
return compute_crc32(crc32_tab, seed, buf, len);
|
||||
}
|
||||
|
||||
uint32_t crypt_crc32c(uint32_t seed, const unsigned char *buf, size_t len)
|
||||
{
|
||||
return compute_crc32(crc32c_tab, seed, buf, len);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* crypto backend implementation
|
||||
*
|
||||
* Copyright (C) 2010-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2022 Milan Broz
|
||||
* Copyright (C) 2010-2023 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2023 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -21,6 +21,7 @@
|
||||
#ifndef _CRYPTO_BACKEND_H
|
||||
#define _CRYPTO_BACKEND_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
@@ -40,7 +41,8 @@ struct crypt_storage;
|
||||
int crypt_backend_init(bool fips);
|
||||
void crypt_backend_destroy(void);
|
||||
|
||||
#define CRYPT_BACKEND_KERNEL (1 << 0) /* Crypto uses kernel part, for benchmark */
|
||||
#define CRYPT_BACKEND_KERNEL (1 << 0) /* Crypto uses kernel part, for benchmark */
|
||||
#define CRYPT_BACKEND_PBKDF2_INT (1 << 1) /* Iteration in PBKDF2 is signed int and can overflow */
|
||||
|
||||
uint32_t crypt_backend_flags(void);
|
||||
const char *crypt_backend_version(void);
|
||||
@@ -88,6 +90,7 @@ 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);
|
||||
uint32_t crypt_crc32c(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);
|
||||
@@ -152,4 +155,7 @@ static inline void crypt_backend_memzero(void *s, size_t n)
|
||||
/* Memcmp helper (memcmp in constant time) */
|
||||
int crypt_backend_memeq(const void *m1, const void *m2, size_t n);
|
||||
|
||||
/* crypto backend running in FIPS mode */
|
||||
bool crypt_fips_mode(void);
|
||||
|
||||
#endif /* _CRYPTO_BACKEND_H */
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* crypto backend implementation
|
||||
*
|
||||
* Copyright (C) 2010-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2022 Milan Broz
|
||||
* Copyright (C) 2010-2023 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2023 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Linux kernel userspace API crypto backend implementation (skcipher)
|
||||
*
|
||||
* Copyright (C) 2012-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2012-2022 Milan Broz
|
||||
* Copyright (C) 2012-2023 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2012-2023 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -109,6 +109,7 @@ int crypt_cipher_init_kernel(struct crypt_cipher_kernel *ctx, const char *name,
|
||||
}
|
||||
|
||||
/* The in/out should be aligned to page boundary */
|
||||
/* coverity[ -taint_source : arg-3 ] */
|
||||
static int _crypt_cipher_crypt(struct crypt_cipher_kernel *ctx,
|
||||
const char *in, size_t in_length,
|
||||
char *out, size_t out_length,
|
||||
@@ -312,6 +313,8 @@ int crypt_bitlk_decrypt_key_kernel(const void *key, size_t key_length,
|
||||
}
|
||||
|
||||
#else /* ENABLE_AF_ALG */
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
|
||||
int crypt_cipher_init_kernel(struct crypt_cipher_kernel *ctx, const char *name,
|
||||
const char *mode, const void *key, size_t key_length)
|
||||
{
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* GCRYPT crypto backend implementation
|
||||
*
|
||||
* Copyright (C) 2010-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2022 Milan Broz
|
||||
* Copyright (C) 2010-2023 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2023 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -22,8 +22,8 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <gcrypt.h>
|
||||
#include <pthread.h>
|
||||
#include "crypto_backend_internal.h"
|
||||
|
||||
static int crypto_backend_initialised = 0;
|
||||
@@ -267,7 +267,6 @@ int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
|
||||
void crypt_hash_destroy(struct crypt_hash *ctx)
|
||||
{
|
||||
gcry_md_close(ctx->hd);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
@@ -342,7 +341,6 @@ int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
|
||||
void crypt_hmac_destroy(struct crypt_hmac *ctx)
|
||||
{
|
||||
gcry_md_close(ctx->hd);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
@@ -387,6 +385,130 @@ static int pbkdf2(const char *hash,
|
||||
#endif /* USE_INTERNAL_PBKDF2 */
|
||||
}
|
||||
|
||||
#if HAVE_DECL_GCRY_KDF_ARGON2 && !USE_INTERNAL_ARGON2
|
||||
struct gcrypt_thread_job
|
||||
{
|
||||
pthread_t thread;
|
||||
struct job_thread_param {
|
||||
gcry_kdf_job_fn_t job;
|
||||
void *p;
|
||||
} work;
|
||||
};
|
||||
|
||||
struct gcrypt_threads
|
||||
{
|
||||
pthread_attr_t attr;
|
||||
unsigned int num_threads;
|
||||
unsigned int max_threads;
|
||||
struct gcrypt_thread_job *jobs_ctx;
|
||||
};
|
||||
|
||||
static void *gcrypt_job_thread(void *p)
|
||||
{
|
||||
struct job_thread_param *param = p;
|
||||
param->job(param->p);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
static int gcrypt_wait_all_jobs(void *ctx)
|
||||
{
|
||||
unsigned int i;
|
||||
struct gcrypt_threads *threads = ctx;
|
||||
|
||||
for (i = 0; i < threads->num_threads; i++) {
|
||||
pthread_join(threads->jobs_ctx[i].thread, NULL);
|
||||
threads->jobs_ctx[i].thread = 0;
|
||||
}
|
||||
|
||||
threads->num_threads = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gcrypt_dispatch_job(void *ctx, gcry_kdf_job_fn_t job, void *p)
|
||||
{
|
||||
struct gcrypt_threads *threads = ctx;
|
||||
|
||||
if (threads->num_threads >= threads->max_threads)
|
||||
return -1;
|
||||
|
||||
threads->jobs_ctx[threads->num_threads].work.job = job;
|
||||
threads->jobs_ctx[threads->num_threads].work.p = p;
|
||||
|
||||
if (pthread_create(&threads->jobs_ctx[threads->num_threads].thread, &threads->attr,
|
||||
gcrypt_job_thread, &threads->jobs_ctx[threads->num_threads].work))
|
||||
return -1;
|
||||
|
||||
threads->num_threads++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gcrypt_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)
|
||||
{
|
||||
gcry_kdf_hd_t hd;
|
||||
int atype, r = -EINVAL;
|
||||
unsigned long param[4];
|
||||
struct gcrypt_threads threads = {
|
||||
.max_threads = parallel,
|
||||
.num_threads = 0
|
||||
};
|
||||
const gcry_kdf_thread_ops_t ops = {
|
||||
.jobs_context = &threads,
|
||||
.dispatch_job = gcrypt_dispatch_job,
|
||||
.wait_all_jobs = gcrypt_wait_all_jobs
|
||||
};
|
||||
|
||||
if (!strcmp(type, "argon2i"))
|
||||
atype = GCRY_KDF_ARGON2I;
|
||||
else if (!strcmp(type, "argon2id"))
|
||||
atype = GCRY_KDF_ARGON2ID;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
param[0] = key_length;
|
||||
param[1] = iterations;
|
||||
param[2] = memory;
|
||||
param[3] = parallel;
|
||||
|
||||
if (gcry_kdf_open(&hd, GCRY_KDF_ARGON2, atype, param, 4,
|
||||
password, password_length, salt, salt_length,
|
||||
NULL, 0, NULL, 0)) {
|
||||
free(threads.jobs_ctx);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (parallel == 1) {
|
||||
/* Do not use threads here */
|
||||
if (gcry_kdf_compute(hd, NULL))
|
||||
goto out;
|
||||
} else {
|
||||
threads.jobs_ctx = calloc(threads.max_threads,
|
||||
sizeof(struct gcrypt_thread_job));
|
||||
if (!threads.jobs_ctx)
|
||||
goto out;
|
||||
|
||||
if (pthread_attr_init(&threads.attr))
|
||||
goto out;
|
||||
|
||||
if (gcry_kdf_compute(hd, &ops))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (gcry_kdf_final(hd, key_length, key))
|
||||
goto out;
|
||||
r = 0;
|
||||
out:
|
||||
gcry_kdf_close(hd);
|
||||
pthread_attr_destroy(&threads.attr);
|
||||
free(threads.jobs_ctx);
|
||||
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* PBKDF */
|
||||
int crypt_pbkdf(const char *kdf, const char *hash,
|
||||
const char *password, size_t password_length,
|
||||
@@ -401,8 +523,13 @@ int crypt_pbkdf(const char *kdf, const char *hash,
|
||||
return pbkdf2(hash, password, password_length, salt, salt_length,
|
||||
key, key_length, iterations);
|
||||
else if (!strncmp(kdf, "argon2", 6))
|
||||
#if HAVE_DECL_GCRY_KDF_ARGON2 && !USE_INTERNAL_ARGON2
|
||||
return gcrypt_argon2(kdf, password, password_length, salt, salt_length,
|
||||
key, key_length, iterations, memory, parallel);
|
||||
#else
|
||||
return argon2(kdf, password, password_length, salt, salt_length,
|
||||
key, key_length, iterations, memory, parallel);
|
||||
#endif
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -555,3 +682,23 @@ int crypt_backend_memeq(const void *m1, const void *m2, size_t n)
|
||||
{
|
||||
return crypt_internal_memeq(m1, m2, n);
|
||||
}
|
||||
|
||||
#if !ENABLE_FIPS
|
||||
bool crypt_fips_mode(void) { return false; }
|
||||
#else
|
||||
bool crypt_fips_mode(void)
|
||||
{
|
||||
static bool fips_mode = false, fips_checked = false;
|
||||
|
||||
if (fips_checked)
|
||||
return fips_mode;
|
||||
|
||||
if (crypt_backend_init(false /* ignored */))
|
||||
return false;
|
||||
|
||||
fips_mode = gcry_fips_mode_active();
|
||||
fips_checked = true;
|
||||
|
||||
return fips_mode;
|
||||
}
|
||||
#endif /* ENABLE FIPS */
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Linux kernel userspace API crypto backend implementation
|
||||
*
|
||||
* Copyright (C) 2010-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2022 Milan Broz
|
||||
* Copyright (C) 2010-2023 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2023 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -245,7 +245,6 @@ void crypt_hash_destroy(struct crypt_hash *ctx)
|
||||
close(ctx->tfmfd);
|
||||
if (ctx->opfd >= 0)
|
||||
close(ctx->opfd);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
@@ -324,7 +323,6 @@ void crypt_hmac_destroy(struct crypt_hmac *ctx)
|
||||
close(ctx->tfmfd);
|
||||
if (ctx->opfd >= 0)
|
||||
close(ctx->opfd);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
@@ -421,3 +419,8 @@ int crypt_backend_memeq(const void *m1, const void *m2, size_t n)
|
||||
{
|
||||
return crypt_internal_memeq(m1, m2, n);
|
||||
}
|
||||
|
||||
bool crypt_fips_mode(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Nettle crypto backend implementation
|
||||
*
|
||||
* Copyright (C) 2011-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2011-2022 Milan Broz
|
||||
* Copyright (C) 2011-2023 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2011-2023 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -453,3 +453,8 @@ 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);
|
||||
}
|
||||
|
||||
bool crypt_fips_mode(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* NSS crypto backend implementation
|
||||
*
|
||||
* Copyright (C) 2010-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2022 Milan Broz
|
||||
* Copyright (C) 2010-2023 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2023 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -400,3 +400,8 @@ int crypt_backend_memeq(const void *m1, const void *m2, size_t n)
|
||||
{
|
||||
return NSS_SecureMemcmp(m1, m2, n);
|
||||
}
|
||||
|
||||
bool crypt_fips_mode(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* OPENSSL crypto backend implementation
|
||||
*
|
||||
* Copyright (C) 2010-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2022 Milan Broz
|
||||
* Copyright (C) 2010-2023 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2023 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/hmac.h>
|
||||
@@ -43,9 +44,20 @@ 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";
|
||||
|
||||
#define MAX_THREADS 8
|
||||
#if !HAVE_DECL_OSSL_GET_MAX_THREADS
|
||||
static int OSSL_set_max_threads(OSSL_LIB_CTX *ctx __attribute__((unused)),
|
||||
uint64_t max_threads __attribute__((unused))) { return 0; }
|
||||
static uint64_t OSSL_get_max_threads(OSSL_LIB_CTX *ctx __attribute__((unused))) { return 0; }
|
||||
#else
|
||||
#include <openssl/thread.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#define CONST_CAST(x) (x)(uintptr_t)
|
||||
#define UNUSED(x) (void)(x)
|
||||
|
||||
static int crypto_backend_initialised = 0;
|
||||
|
||||
@@ -161,6 +173,7 @@ static int openssl_backend_init(bool fips)
|
||||
*/
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
int r;
|
||||
bool ossl_threads = false;
|
||||
|
||||
/*
|
||||
* In FIPS mode we keep default OpenSSL context & global config
|
||||
@@ -180,16 +193,23 @@ static int openssl_backend_init(bool fips)
|
||||
ossl_legacy = OSSL_PROVIDER_try_load(ossl_ctx, "legacy", 0);
|
||||
}
|
||||
|
||||
r = snprintf(backend_version, sizeof(backend_version), "%s %s%s%s",
|
||||
if (OSSL_set_max_threads(ossl_ctx, MAX_THREADS) == 1 &&
|
||||
OSSL_get_max_threads(ossl_ctx) == MAX_THREADS)
|
||||
ossl_threads = true;
|
||||
|
||||
r = snprintf(backend_version, sizeof(backend_version), "%s%s%s%s%s",
|
||||
OpenSSL_version(OPENSSL_VERSION),
|
||||
ossl_default ? "[default]" : "",
|
||||
ossl_legacy ? "[legacy]" : "",
|
||||
fips ? "[fips]" : "");
|
||||
fips ? "[fips]" : "",
|
||||
ossl_threads ? "[threads]" : "");
|
||||
|
||||
if (r < 0 || (size_t)r >= sizeof(backend_version)) {
|
||||
openssl_backend_exit();
|
||||
return -EINVAL;
|
||||
}
|
||||
#else
|
||||
UNUSED(fips);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
@@ -231,7 +251,11 @@ void crypt_backend_destroy(void)
|
||||
|
||||
uint32_t crypt_backend_flags(void)
|
||||
{
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
return 0;
|
||||
#else
|
||||
return CRYPT_BACKEND_PBKDF2_INT;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *crypt_backend_version(void)
|
||||
@@ -276,6 +300,8 @@ static void hash_id_free(const EVP_MD *hash_id)
|
||||
{
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
EVP_MD_free(CONST_CAST(EVP_MD*)hash_id);
|
||||
#else
|
||||
UNUSED(hash_id);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -292,6 +318,8 @@ static void cipher_type_free(const EVP_CIPHER *cipher_type)
|
||||
{
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
EVP_CIPHER_free(CONST_CAST(EVP_CIPHER*)cipher_type);
|
||||
#else
|
||||
UNUSED(cipher_type);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -386,7 +414,6 @@ 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);
|
||||
}
|
||||
|
||||
@@ -522,7 +549,6 @@ void crypt_hmac_destroy(struct crypt_hmac *ctx)
|
||||
hash_id_free(ctx->hash_id);
|
||||
HMAC_CTX_free(ctx->md);
|
||||
#endif
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
@@ -574,6 +600,10 @@ static int openssl_pbkdf2(const char *password, size_t password_length,
|
||||
if (!hash_id)
|
||||
return -EINVAL;
|
||||
|
||||
/* OpenSSL2 has iteration as signed int, avoid overflow */
|
||||
if (iterations > INT_MAX)
|
||||
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
|
||||
@@ -584,8 +614,53 @@ static int openssl_argon2(const char *type, const char *password, size_t passwor
|
||||
const char *salt, size_t salt_length, char *key, size_t key_length,
|
||||
uint32_t iterations, uint32_t memory, uint32_t parallel)
|
||||
{
|
||||
#if HAVE_DECL_OSSL_KDF_PARAM_ARGON2_VERSION
|
||||
EVP_KDF_CTX *ctx;
|
||||
EVP_KDF *argon2;
|
||||
unsigned int threads = parallel;
|
||||
int r;
|
||||
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_uint(OSSL_KDF_PARAM_THREADS, &threads),
|
||||
OSSL_PARAM_uint32(OSSL_KDF_PARAM_ARGON2_LANES, ¶llel),
|
||||
OSSL_PARAM_uint32(OSSL_KDF_PARAM_ARGON2_MEMCOST, &memory),
|
||||
OSSL_PARAM_END
|
||||
};
|
||||
|
||||
if (OSSL_get_max_threads(ossl_ctx) == 0)
|
||||
threads = 1;
|
||||
|
||||
argon2 = EVP_KDF_fetch(ossl_ctx, type, NULL);
|
||||
if (!argon2)
|
||||
return -EINVAL;
|
||||
|
||||
ctx = EVP_KDF_CTX_new(argon2);
|
||||
if (!ctx) {
|
||||
EVP_KDF_free(argon2);
|
||||
return -EINVAL;;
|
||||
}
|
||||
|
||||
if (EVP_KDF_CTX_set_params(ctx, params) != 1) {
|
||||
EVP_KDF_CTX_free(ctx);
|
||||
EVP_KDF_free(argon2);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = EVP_KDF_derive(ctx, (unsigned char*)key, key_length, NULL /*params*/);
|
||||
|
||||
EVP_KDF_CTX_free(ctx);
|
||||
EVP_KDF_free(argon2);
|
||||
|
||||
/* _derive() returns 0 or negative value on error, 1 on success */
|
||||
return r == 1 ? 0 : -EINVAL;
|
||||
#else
|
||||
return argon2(type, password, password_length, salt, salt_length,
|
||||
key, key_length, iterations, memory, parallel);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* PBKDF */
|
||||
@@ -812,3 +887,29 @@ int crypt_backend_memeq(const void *m1, const void *m2, size_t n)
|
||||
{
|
||||
return CRYPTO_memcmp(m1, m2, n);
|
||||
}
|
||||
|
||||
#if !ENABLE_FIPS
|
||||
bool crypt_fips_mode(void) { return false; }
|
||||
#else
|
||||
static bool openssl_fips_mode(void)
|
||||
{
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
return EVP_default_properties_is_fips_enabled(NULL);
|
||||
#else
|
||||
return FIPS_mode();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool crypt_fips_mode(void)
|
||||
{
|
||||
static bool fips_mode = false, fips_checked = false;
|
||||
|
||||
if (fips_checked)
|
||||
return fips_mode;
|
||||
|
||||
fips_mode = openssl_fips_mode();
|
||||
fips_checked = true;
|
||||
|
||||
return fips_mode;
|
||||
}
|
||||
#endif /* ENABLE FIPS */
|
||||
|
||||
@@ -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-2022 Milan Broz
|
||||
* Copyright (C) 2014-2023 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
||||
40
lib/crypto_backend/meson.build
Normal file
40
lib/crypto_backend/meson.build
Normal file
@@ -0,0 +1,40 @@
|
||||
if use_internal_argon2
|
||||
subdir('argon2')
|
||||
endif
|
||||
|
||||
libcrypto_backend_dependencies = [
|
||||
crypto_backend_library,
|
||||
clock_gettime,
|
||||
]
|
||||
libcrypto_backend_link_with = []
|
||||
|
||||
libcrypto_backend_sources = files(
|
||||
'argon2_generic.c',
|
||||
'base64.c',
|
||||
'cipher_check.c',
|
||||
'cipher_generic.c',
|
||||
'crc32.c',
|
||||
'crypto_cipher_kernel.c',
|
||||
'crypto_storage.c',
|
||||
'pbkdf_check.c',
|
||||
'utf8.c',
|
||||
)
|
||||
|
||||
crypto_backend = get_option('crypto-backend')
|
||||
libcrypto_backend_sources += files('crypto_@0@.c'.format(crypto_backend))
|
||||
|
||||
if use_internal_pbkdf2
|
||||
libcrypto_backend_sources += files('pbkdf2_generic.c')
|
||||
endif
|
||||
|
||||
if use_internal_argon2 and get_option('argon-implementation') == 'internal'
|
||||
libcrypto_backend_link_with += libargon2
|
||||
elif get_option('argon-implementation') == 'libargon2'
|
||||
libcrypto_backend_dependencies += libargon2_external
|
||||
endif
|
||||
|
||||
libcrypto_backend = static_library('crypto_backend',
|
||||
libcrypto_backend_sources,
|
||||
include_directories: includes_lib,
|
||||
dependencies: libcrypto_backend_dependencies,
|
||||
link_with: libcrypto_backend_link_with)
|
||||
@@ -4,8 +4,8 @@
|
||||
* Copyright (C) 2004 Free Software Foundation
|
||||
*
|
||||
* cryptsetup related changes
|
||||
* Copyright (C) 2012-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2012-2022 Milan Broz
|
||||
* Copyright (C) 2012-2023 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2012-2023 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* PBKDF performance check
|
||||
* Copyright (C) 2012-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2012-2022 Milan Broz
|
||||
* Copyright (C) 2012-2023 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2012-2023 Milan Broz
|
||||
* Copyright (C) 2016-2020 Ondrej Mosnacek
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Copyright (C) 2010 Lennart Poettering
|
||||
*
|
||||
* cryptsetup related changes
|
||||
* Copyright (C) 2021-2022 Vojtech Trefny
|
||||
* Copyright (C) 2021-2023 Vojtech Trefny
|
||||
|
||||
* Parts of the original systemd implementation are based on the GLIB utf8
|
||||
* validation functions.
|
||||
@@ -28,7 +28,6 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <endian.h>
|
||||
|
||||
|
||||
1057
lib/fvault2/fvault2.c
Normal file
1057
lib/fvault2/fvault2.c
Normal file
File diff suppressed because it is too large
Load Diff
80
lib/fvault2/fvault2.h
Normal file
80
lib/fvault2/fvault2.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* FVAULT2 (FileVault2-compatible) volume handling
|
||||
*
|
||||
* Copyright (C) 2021-2022 Pavel Tobias
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this file; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef _CRYPTSETUP_FVAULT2_H
|
||||
#define _CRYPTSETUP_FVAULT2_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define FVAULT2_WRAPPED_KEY_SIZE 24
|
||||
#define FVAULT2_PBKDF2_SALT_SIZE 16
|
||||
#define FVAULT2_UUID_LEN 37
|
||||
|
||||
struct crypt_device;
|
||||
struct volume_key;
|
||||
|
||||
struct fvault2_params {
|
||||
const char *cipher;
|
||||
const char *cipher_mode;
|
||||
uint16_t key_size;
|
||||
uint32_t pbkdf2_iters;
|
||||
char pbkdf2_salt[FVAULT2_PBKDF2_SALT_SIZE];
|
||||
char wrapped_kek[FVAULT2_WRAPPED_KEY_SIZE];
|
||||
char wrapped_vk[FVAULT2_WRAPPED_KEY_SIZE];
|
||||
char family_uuid[FVAULT2_UUID_LEN];
|
||||
char ph_vol_uuid[FVAULT2_UUID_LEN];
|
||||
uint64_t log_vol_off;
|
||||
uint64_t log_vol_size;
|
||||
};
|
||||
|
||||
int FVAULT2_read_metadata(
|
||||
struct crypt_device *cd,
|
||||
struct fvault2_params *params);
|
||||
|
||||
int FVAULT2_get_volume_key(
|
||||
struct crypt_device *cd,
|
||||
const char *passphrase,
|
||||
size_t passphrase_len,
|
||||
const struct fvault2_params *params,
|
||||
struct volume_key **vol_key);
|
||||
|
||||
int FVAULT2_dump(
|
||||
struct crypt_device *cd,
|
||||
struct device *device,
|
||||
const struct fvault2_params *params);
|
||||
|
||||
int FVAULT2_activate_by_passphrase(
|
||||
struct crypt_device *cd,
|
||||
const char *name,
|
||||
const char *passphrase,
|
||||
size_t passphrase_len,
|
||||
const struct fvault2_params *params,
|
||||
uint32_t flags);
|
||||
|
||||
int FVAULT2_activate_by_volume_key(
|
||||
struct crypt_device *cd,
|
||||
const char *name,
|
||||
const char *key,
|
||||
size_t key_size,
|
||||
const struct fvault2_params *params,
|
||||
uint32_t flags);
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Integrity volume handling
|
||||
*
|
||||
* Copyright (C) 2016-2022 Milan Broz
|
||||
* Copyright (C) 2016-2023 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -335,13 +335,62 @@ int INTEGRITY_activate(struct crypt_device *cd,
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _create_reduced_device(struct crypt_device *cd,
|
||||
const char *name,
|
||||
uint64_t device_size_sectors,
|
||||
struct device **ret_device)
|
||||
{
|
||||
int r;
|
||||
char path[PATH_MAX];
|
||||
struct device *dev;
|
||||
|
||||
struct crypt_dm_active_device dmd = {
|
||||
.size = device_size_sectors,
|
||||
.flags = CRYPT_ACTIVATE_PRIVATE,
|
||||
};
|
||||
|
||||
assert(cd);
|
||||
assert(name);
|
||||
assert(device_size_sectors);
|
||||
assert(ret_device);
|
||||
|
||||
r = snprintf(path, sizeof(path), "%s/%s", dm_get_dir(), name);
|
||||
if (r < 0 || (size_t)r >= sizeof(path))
|
||||
return -EINVAL;
|
||||
|
||||
r = device_block_adjust(cd, crypt_data_device(cd), DEV_OK,
|
||||
crypt_get_data_offset(cd), &device_size_sectors, &dmd.flags);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
log_dbg(cd, "Activating reduced helper device %s.", name);
|
||||
|
||||
r = dm_linear_target_set(&dmd.segment, 0, dmd.size, crypt_data_device(cd), crypt_get_data_offset(cd));
|
||||
if (!r)
|
||||
r = dm_create_device(cd, name, CRYPT_SUBDEV, &dmd);
|
||||
dm_targets_free(cd, &dmd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = device_alloc(cd, &dev, path);
|
||||
if (!r) {
|
||||
*ret_device = dev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
dm_remove_device(cd, name, CRYPT_DEACTIVATE_FORCE);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int INTEGRITY_format(struct crypt_device *cd,
|
||||
const struct crypt_params_integrity *params,
|
||||
struct volume_key *journal_crypt_key,
|
||||
struct volume_key *journal_mac_key)
|
||||
struct volume_key *journal_mac_key,
|
||||
uint64_t backing_device_sectors)
|
||||
{
|
||||
uint32_t dmi_flags;
|
||||
char tmp_name[64], tmp_uuid[40];
|
||||
char reduced_device_name[70], tmp_name[64], tmp_uuid[40];
|
||||
struct crypt_dm_active_device dmdi = {
|
||||
.size = 8,
|
||||
.flags = CRYPT_ACTIVATE_PRIVATE, /* We always create journal but it can be unused later */
|
||||
@@ -349,6 +398,8 @@ int INTEGRITY_format(struct crypt_device *cd,
|
||||
struct dm_target *tgt = &dmdi.segment;
|
||||
int r;
|
||||
uuid_t tmp_uuid_bin;
|
||||
uint64_t data_offset_sectors;
|
||||
struct device *p_metadata_device, *p_data_device, *reduced_device = NULL;
|
||||
struct volume_key *vk = NULL;
|
||||
|
||||
uuid_generate(tmp_uuid_bin);
|
||||
@@ -358,18 +409,42 @@ int INTEGRITY_format(struct crypt_device *cd,
|
||||
if (r < 0 || (size_t)r >= sizeof(tmp_name))
|
||||
return -EINVAL;
|
||||
|
||||
p_metadata_device = INTEGRITY_metadata_device(cd);
|
||||
|
||||
if (backing_device_sectors) {
|
||||
r = snprintf(reduced_device_name, sizeof(reduced_device_name),
|
||||
"temporary-cryptsetup-reduced-%s", tmp_uuid);
|
||||
if (r < 0 || (size_t)r >= sizeof(reduced_device_name))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Creates reduced dm-linear mapping over data device starting at
|
||||
* crypt_data_offset(cd) and backing_device_sectors in size.
|
||||
*/
|
||||
r = _create_reduced_device(cd, reduced_device_name,
|
||||
backing_device_sectors, &reduced_device);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
data_offset_sectors = 0;
|
||||
p_data_device = reduced_device;
|
||||
if (p_metadata_device == crypt_data_device(cd))
|
||||
p_metadata_device = reduced_device;
|
||||
} else {
|
||||
data_offset_sectors = crypt_get_data_offset(cd);
|
||||
p_data_device = crypt_data_device(cd);
|
||||
}
|
||||
|
||||
/* There is no data area, we can actually use fake zeroed key */
|
||||
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, 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,
|
||||
r = dm_integrity_target_set(cd, tgt, 0, dmdi.size, p_metadata_device,
|
||||
p_data_device, crypt_get_integrity_tag_size(cd),
|
||||
data_offset_sectors, crypt_get_sector_size(cd), vk,
|
||||
journal_crypt_key, journal_mac_key, params);
|
||||
if (r < 0) {
|
||||
crypt_free_volume_key(vk);
|
||||
return r;
|
||||
}
|
||||
if (r < 0)
|
||||
goto err;
|
||||
|
||||
log_dbg(cd, "Trying to format INTEGRITY device on top of %s, tmp name %s, tag size %d.",
|
||||
device_path(tgt->data_device), tmp_name, tgt->u.integrity.tag_size);
|
||||
@@ -379,24 +454,26 @@ int INTEGRITY_format(struct crypt_device *cd,
|
||||
log_err(cd, _("Kernel does not support dm-integrity mapping."));
|
||||
r = -ENOTSUP;
|
||||
}
|
||||
if (r) {
|
||||
dm_targets_free(cd, &dmdi);
|
||||
return r;
|
||||
}
|
||||
if (r)
|
||||
goto err;
|
||||
|
||||
if (tgt->u.integrity.meta_device) {
|
||||
r = device_block_adjust(cd, tgt->u.integrity.meta_device, DEV_EXCL, 0, NULL, NULL);
|
||||
if (r) {
|
||||
dm_targets_free(cd, &dmdi);
|
||||
return r;
|
||||
}
|
||||
if (r)
|
||||
goto err;
|
||||
}
|
||||
|
||||
r = dm_create_device(cd, tmp_name, CRYPT_INTEGRITY, &dmdi);
|
||||
crypt_free_volume_key(vk);
|
||||
dm_targets_free(cd, &dmdi);
|
||||
if (r)
|
||||
return r;
|
||||
goto err;
|
||||
|
||||
return dm_remove_device(cd, tmp_name, CRYPT_DEACTIVATE_FORCE);
|
||||
r = dm_remove_device(cd, tmp_name, CRYPT_DEACTIVATE_FORCE);
|
||||
err:
|
||||
dm_targets_free(cd, &dmdi);
|
||||
crypt_free_volume_key(vk);
|
||||
if (reduced_device) {
|
||||
dm_remove_device(cd, reduced_device_name, CRYPT_DEACTIVATE_FORCE);
|
||||
device_free(cd, reduced_device);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Integrity header definition
|
||||
*
|
||||
* Copyright (C) 2016-2022 Milan Broz
|
||||
* Copyright (C) 2016-2023 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,8 @@ int INTEGRITY_hash_tag_size(const char *integrity);
|
||||
int INTEGRITY_format(struct crypt_device *cd,
|
||||
const struct crypt_params_integrity *params,
|
||||
struct volume_key *journal_crypt_key,
|
||||
struct volume_key *journal_mac_key);
|
||||
struct volume_key *journal_mac_key,
|
||||
uint64_t backing_device_sectors);
|
||||
|
||||
int INTEGRITY_activate(struct crypt_device *cd,
|
||||
const char *name,
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
*
|
||||
* Copyright (C) 2004 Jana Saout <jana@saout.de>
|
||||
* Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2022 Milan Broz
|
||||
* Copyright (C) 2009-2023 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2023 Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "nls.h"
|
||||
#include "bitops.h"
|
||||
@@ -38,7 +39,6 @@
|
||||
#include "utils_crypt.h"
|
||||
#include "utils_loop.h"
|
||||
#include "utils_dm.h"
|
||||
#include "utils_fips.h"
|
||||
#include "utils_keyring.h"
|
||||
#include "utils_io.h"
|
||||
#include "crypto_backend/crypto_backend.h"
|
||||
@@ -53,6 +53,7 @@
|
||||
#define MAX_DM_DEPS 32
|
||||
|
||||
#define CRYPT_SUBDEV "SUBDEV" /* prefix for sublayered devices underneath public crypt types */
|
||||
#define CRYPT_LUKS2_HW_OPAL "LUKS2-OPAL" /* dm uuid prefix used for any HW OPAL enabled LUKS2 device */
|
||||
|
||||
#ifndef O_CLOEXEC
|
||||
#define O_CLOEXEC 0
|
||||
@@ -89,6 +90,7 @@ int crypt_benchmark_pbkdf_internal(struct crypt_device *cd,
|
||||
struct crypt_pbkdf_type *pbkdf,
|
||||
size_t volume_key_size);
|
||||
const char *crypt_get_cipher_spec(struct crypt_device *cd);
|
||||
uint32_t pbkdf_adjusted_phys_memory_kb(void);
|
||||
|
||||
/* Device backend */
|
||||
struct device;
|
||||
@@ -113,6 +115,7 @@ void device_release_excl(struct crypt_device *cd, struct device *device);
|
||||
void device_disable_direct_io(struct device *device);
|
||||
int device_is_identical(struct device *device1, struct device *device2);
|
||||
int device_is_rotational(struct device *device);
|
||||
int device_is_dax(struct device *device);
|
||||
size_t device_alignment(struct device *device);
|
||||
int device_direct_io(const struct device *device);
|
||||
int device_fallocate(struct device *device, uint64_t size);
|
||||
@@ -153,21 +156,31 @@ int create_or_reload_device_with_integrity(struct crypt_device *cd, const char *
|
||||
struct device *crypt_metadata_device(struct crypt_device *cd);
|
||||
struct device *crypt_data_device(struct crypt_device *cd);
|
||||
|
||||
uint64_t crypt_get_metadata_size_bytes(struct crypt_device *cd);
|
||||
uint64_t crypt_get_keyslots_size_bytes(struct crypt_device *cd);
|
||||
uint64_t crypt_get_data_offset_sectors(struct crypt_device *cd);
|
||||
int crypt_opal_supported(struct crypt_device *cd, struct device *opal_device);
|
||||
|
||||
int crypt_confirm(struct crypt_device *cd, const char *msg);
|
||||
|
||||
char *crypt_lookup_dev(const char *dev_id);
|
||||
int crypt_dev_is_rotational(int major, int minor);
|
||||
int crypt_dev_is_dax(int major, int minor);
|
||||
int crypt_dev_is_partition(const char *dev_path);
|
||||
char *crypt_get_partition_device(const char *dev_path, uint64_t offset, uint64_t size);
|
||||
int crypt_dev_get_partition_number(const char *dev_path);
|
||||
char *crypt_get_base_device(const char *dev_path);
|
||||
uint64_t crypt_dev_partition_offset(const char *dev_path);
|
||||
int lookup_by_disk_id(const char *dm_uuid);
|
||||
int lookup_by_sysfs_uuid_field(const char *dm_uuid);
|
||||
int crypt_uuid_cmp(const char *dm_uuid, const char *hdr_uuid);
|
||||
int crypt_uuid_type_cmp(const char *dm_uuid, const char *type);
|
||||
|
||||
size_t crypt_getpagesize(void);
|
||||
unsigned crypt_cpusonline(void);
|
||||
uint64_t crypt_getphysmemory_kb(void);
|
||||
uint64_t crypt_getphysmemoryfree_kb(void);
|
||||
bool crypt_swapavailable(void);
|
||||
|
||||
int init_crypto(struct crypt_device *ctx);
|
||||
|
||||
@@ -178,8 +191,7 @@ int init_crypto(struct crypt_device *ctx);
|
||||
|
||||
int crypt_get_debug_level(void);
|
||||
|
||||
int crypt_memlock_inc(struct crypt_device *ctx);
|
||||
int crypt_memlock_dec(struct crypt_device *ctx);
|
||||
void crypt_process_priority(struct crypt_device *cd, int *priority, bool raise);
|
||||
|
||||
int crypt_metadata_locking_enabled(void);
|
||||
|
||||
@@ -203,7 +215,7 @@ void crypt_set_luks2_reencrypt(struct crypt_device *cd, struct luks2_reencrypt *
|
||||
struct luks2_reencrypt *crypt_get_luks2_reencrypt(struct crypt_device *cd);
|
||||
|
||||
int onlyLUKS2(struct crypt_device *cd);
|
||||
int onlyLUKS2mask(struct crypt_device *cd, uint32_t mask);
|
||||
int onlyLUKS2reencrypt(struct crypt_device *cd);
|
||||
|
||||
int crypt_wipe_device(struct crypt_device *cd,
|
||||
struct device *device,
|
||||
@@ -222,6 +234,14 @@ int crypt_get_integrity_tag_size(struct crypt_device *cd);
|
||||
int crypt_key_in_keyring(struct crypt_device *cd);
|
||||
void crypt_set_key_in_keyring(struct crypt_device *cd, unsigned key_in_keyring);
|
||||
int crypt_volume_key_load_in_keyring(struct crypt_device *cd, struct volume_key *vk);
|
||||
int crypt_keyring_get_user_key(struct crypt_device *cd,
|
||||
const char *key_description,
|
||||
char **key,
|
||||
size_t *key_size);
|
||||
int crypt_keyring_get_key_by_name(struct crypt_device *cd,
|
||||
const char *key_description,
|
||||
char **key,
|
||||
size_t *key_size);
|
||||
int crypt_use_keyring_for_vk(struct crypt_device *cd);
|
||||
void crypt_drop_keyring_key_by_description(struct crypt_device *cd, const char *key_description, key_type_t ktype);
|
||||
void crypt_drop_keyring_key(struct crypt_device *cd, struct volume_key *vks);
|
||||
@@ -251,4 +271,8 @@ static inline bool uint64_mult_overflow(uint64_t *u, uint64_t b, size_t size)
|
||||
return false;
|
||||
}
|
||||
|
||||
#define KEY_NOT_VERIFIED -2
|
||||
#define KEY_EXTERNAL_VERIFICATION -1
|
||||
#define KEY_VERIFIED 0
|
||||
|
||||
#endif /* INTERNAL_H */
|
||||
|
||||
828
lib/keyslot_context.c
Normal file
828
lib/keyslot_context.c
Normal file
@@ -0,0 +1,828 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup, keyslot unlock helpers
|
||||
*
|
||||
* Copyright (C) 2022-2023 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2022-2023 Ondrej Kozina
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "luks1/luks.h"
|
||||
#include "luks2/luks2.h"
|
||||
#include "keyslot_context.h"
|
||||
|
||||
static int get_luks2_key_by_passphrase(struct crypt_device *cd,
|
||||
struct crypt_keyslot_context *kc,
|
||||
int keyslot,
|
||||
int segment,
|
||||
struct volume_key **r_vk)
|
||||
{
|
||||
int r;
|
||||
|
||||
assert(cd);
|
||||
assert(kc && kc->type == CRYPT_KC_TYPE_PASSPHRASE);
|
||||
assert(r_vk);
|
||||
|
||||
r = LUKS2_keyslot_open(cd, keyslot, segment, kc->u.p.passphrase, kc->u.p.passphrase_size, r_vk);
|
||||
if (r < 0)
|
||||
kc->error = r;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int get_luks1_volume_key_by_passphrase(struct crypt_device *cd,
|
||||
struct crypt_keyslot_context *kc,
|
||||
int keyslot,
|
||||
struct volume_key **r_vk)
|
||||
{
|
||||
int r;
|
||||
|
||||
assert(cd);
|
||||
assert(kc && kc->type == CRYPT_KC_TYPE_PASSPHRASE);
|
||||
assert(r_vk);
|
||||
|
||||
r = LUKS_open_key_with_hdr(keyslot, kc->u.p.passphrase, kc->u.p.passphrase_size,
|
||||
crypt_get_hdr(cd, CRYPT_LUKS1), r_vk, cd);
|
||||
if (r < 0)
|
||||
kc->error = r;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int get_luks2_volume_key_by_passphrase(struct crypt_device *cd,
|
||||
struct crypt_keyslot_context *kc,
|
||||
int keyslot,
|
||||
struct volume_key **r_vk)
|
||||
{
|
||||
return get_luks2_key_by_passphrase(cd, kc, keyslot, CRYPT_DEFAULT_SEGMENT, r_vk);
|
||||
}
|
||||
|
||||
static int get_passphrase_by_passphrase(struct crypt_device *cd,
|
||||
struct crypt_keyslot_context *kc,
|
||||
const char **r_passphrase,
|
||||
size_t *r_passphrase_size)
|
||||
{
|
||||
assert(cd);
|
||||
assert(kc && kc->type == CRYPT_KC_TYPE_PASSPHRASE);
|
||||
assert(r_passphrase);
|
||||
assert(r_passphrase_size);
|
||||
|
||||
*r_passphrase = kc->u.p.passphrase;
|
||||
*r_passphrase_size = kc->u.p.passphrase_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_passphrase_by_keyfile(struct crypt_device *cd,
|
||||
struct crypt_keyslot_context *kc,
|
||||
const char **r_passphrase,
|
||||
size_t *r_passphrase_size)
|
||||
{
|
||||
int r;
|
||||
|
||||
assert(cd);
|
||||
assert(kc && kc->type == CRYPT_KC_TYPE_KEYFILE);
|
||||
assert(r_passphrase);
|
||||
assert(r_passphrase_size);
|
||||
|
||||
if (!kc->i_passphrase) {
|
||||
r = crypt_keyfile_device_read(cd, kc->u.kf.keyfile,
|
||||
&kc->i_passphrase, &kc->i_passphrase_size,
|
||||
kc->u.kf.keyfile_offset, kc->u.kf.keyfile_size, 0);
|
||||
if (r < 0) {
|
||||
kc->error = r;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
*r_passphrase = kc->i_passphrase;
|
||||
*r_passphrase_size = kc->i_passphrase_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_luks2_key_by_keyfile(struct crypt_device *cd,
|
||||
struct crypt_keyslot_context *kc,
|
||||
int keyslot,
|
||||
int segment,
|
||||
struct volume_key **r_vk)
|
||||
{
|
||||
int r;
|
||||
const char *passphrase;
|
||||
size_t passphrase_size;
|
||||
|
||||
assert(cd);
|
||||
assert(kc && kc->type == CRYPT_KC_TYPE_KEYFILE);
|
||||
assert(r_vk);
|
||||
|
||||
r = get_passphrase_by_keyfile(cd, kc, &passphrase, &passphrase_size);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = LUKS2_keyslot_open(cd, keyslot, segment, passphrase, passphrase_size, r_vk);
|
||||
if (r < 0)
|
||||
kc->error = r;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int get_luks2_volume_key_by_keyfile(struct crypt_device *cd,
|
||||
struct crypt_keyslot_context *kc,
|
||||
int keyslot,
|
||||
struct volume_key **r_vk)
|
||||
{
|
||||
return get_luks2_key_by_keyfile(cd, kc, keyslot, CRYPT_DEFAULT_SEGMENT, r_vk);
|
||||
}
|
||||
|
||||
static int get_luks1_volume_key_by_keyfile(struct crypt_device *cd,
|
||||
struct crypt_keyslot_context *kc,
|
||||
int keyslot,
|
||||
struct volume_key **r_vk)
|
||||
{
|
||||
int r;
|
||||
const char *passphrase;
|
||||
size_t passphrase_size;
|
||||
|
||||
assert(cd);
|
||||
assert(kc && kc->type == CRYPT_KC_TYPE_KEYFILE);
|
||||
assert(r_vk);
|
||||
|
||||
r = get_passphrase_by_keyfile(cd, kc, &passphrase, &passphrase_size);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = LUKS_open_key_with_hdr(keyslot, passphrase, passphrase_size,
|
||||
crypt_get_hdr(cd, CRYPT_LUKS1), r_vk, cd);
|
||||
if (r < 0)
|
||||
kc->error = r;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int get_key_by_key(struct crypt_device *cd __attribute__((unused)),
|
||||
struct crypt_keyslot_context *kc,
|
||||
int keyslot __attribute__((unused)),
|
||||
int segment __attribute__((unused)),
|
||||
struct volume_key **r_vk)
|
||||
{
|
||||
assert(kc && kc->type == CRYPT_KC_TYPE_KEY);
|
||||
assert(r_vk);
|
||||
|
||||
if (!kc->u.k.volume_key) {
|
||||
kc->error = -ENOENT;
|
||||
return kc->error;
|
||||
}
|
||||
|
||||
*r_vk = crypt_alloc_volume_key(kc->u.k.volume_key_size, kc->u.k.volume_key);
|
||||
if (!*r_vk) {
|
||||
kc->error = -ENOMEM;
|
||||
return kc->error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_volume_key_by_key(struct crypt_device *cd,
|
||||
struct crypt_keyslot_context *kc,
|
||||
int keyslot __attribute__((unused)),
|
||||
struct volume_key **r_vk)
|
||||
{
|
||||
return get_key_by_key(cd, kc, -2 /* unused */, -2 /* unused */, r_vk);
|
||||
}
|
||||
|
||||
static int get_generic_volume_key_by_key(struct crypt_device *cd,
|
||||
struct crypt_keyslot_context *kc,
|
||||
struct volume_key **r_vk)
|
||||
{
|
||||
return get_key_by_key(cd, kc, -2 /* unused */, -2 /* unused */, r_vk);
|
||||
}
|
||||
|
||||
static int get_generic_signed_key_by_key(struct crypt_device *cd,
|
||||
struct crypt_keyslot_context *kc,
|
||||
struct volume_key **r_vk,
|
||||
struct volume_key **r_signature)
|
||||
{
|
||||
struct volume_key *vk, *vk_sig;
|
||||
|
||||
assert(kc && ((kc->type == CRYPT_KC_TYPE_KEY) ||
|
||||
(kc->type == CRYPT_KC_TYPE_SIGNED_KEY)));
|
||||
assert(r_vk);
|
||||
assert(r_signature);
|
||||
|
||||
/* return key with no signature */
|
||||
if (kc->type == CRYPT_KC_TYPE_KEY) {
|
||||
*r_signature = NULL;
|
||||
return get_key_by_key(cd, kc, -2 /* unused */, -2 /* unused */, r_vk);
|
||||
}
|
||||
|
||||
if (!kc->u.ks.volume_key || !kc->u.ks.signature) {
|
||||
kc->error = -EINVAL;
|
||||
return kc->error;
|
||||
}
|
||||
|
||||
vk = crypt_alloc_volume_key(kc->u.ks.volume_key_size, kc->u.ks.volume_key);
|
||||
if (!vk) {
|
||||
kc->error = -ENOMEM;
|
||||
return kc->error;
|
||||
}
|
||||
|
||||
vk_sig = crypt_alloc_volume_key(kc->u.ks.signature_size, kc->u.ks.signature);
|
||||
if (!vk_sig) {
|
||||
crypt_free_volume_key(vk);
|
||||
kc->error = -ENOMEM;
|
||||
return kc->error;
|
||||
}
|
||||
|
||||
*r_vk = vk;
|
||||
*r_signature = vk_sig;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_luks2_key_by_token(struct crypt_device *cd,
|
||||
struct crypt_keyslot_context *kc,
|
||||
int keyslot,
|
||||
int segment,
|
||||
struct volume_key **r_vk)
|
||||
{
|
||||
int r;
|
||||
struct luks2_hdr *hdr;
|
||||
|
||||
assert(cd);
|
||||
assert(kc && kc->type == CRYPT_KC_TYPE_TOKEN);
|
||||
assert(r_vk);
|
||||
|
||||
hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
|
||||
if (!hdr)
|
||||
return -EINVAL;
|
||||
|
||||
r = LUKS2_token_unlock_key(cd, hdr, keyslot, kc->u.t.id, kc->u.t.type,
|
||||
kc->u.t.pin, kc->u.t.pin_size, segment, kc->u.t.usrptr, r_vk);
|
||||
if (r < 0)
|
||||
kc->error = r;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int get_luks2_volume_key_by_token(struct crypt_device *cd,
|
||||
struct crypt_keyslot_context *kc,
|
||||
int keyslot,
|
||||
struct volume_key **r_vk)
|
||||
{
|
||||
return get_luks2_key_by_token(cd, kc, keyslot, CRYPT_DEFAULT_SEGMENT, r_vk);
|
||||
}
|
||||
|
||||
static int get_passphrase_by_token(struct crypt_device *cd,
|
||||
struct crypt_keyslot_context *kc,
|
||||
const char **r_passphrase,
|
||||
size_t *r_passphrase_size)
|
||||
{
|
||||
int r;
|
||||
|
||||
assert(cd);
|
||||
assert(kc && kc->type == CRYPT_KC_TYPE_TOKEN);
|
||||
assert(r_passphrase);
|
||||
assert(r_passphrase_size);
|
||||
|
||||
if (!kc->i_passphrase) {
|
||||
r = LUKS2_token_unlock_passphrase(cd, crypt_get_hdr(cd, CRYPT_LUKS2), kc->u.t.id,
|
||||
kc->u.t.type, kc->u.t.pin, kc->u.t.pin_size,
|
||||
kc->u.t.usrptr, &kc->i_passphrase, &kc->i_passphrase_size);
|
||||
if (r < 0) {
|
||||
kc->error = r;
|
||||
return r;
|
||||
}
|
||||
kc->u.t.id = r;
|
||||
}
|
||||
|
||||
*r_passphrase = kc->i_passphrase;
|
||||
*r_passphrase_size = kc->i_passphrase_size;
|
||||
|
||||
return kc->u.t.id;
|
||||
}
|
||||
|
||||
static int get_passphrase_by_keyring(struct crypt_device *cd,
|
||||
struct crypt_keyslot_context *kc,
|
||||
const char **r_passphrase,
|
||||
size_t *r_passphrase_size)
|
||||
{
|
||||
int r;
|
||||
|
||||
assert(cd);
|
||||
assert(kc && kc->type == CRYPT_KC_TYPE_KEYRING);
|
||||
assert(r_passphrase);
|
||||
assert(r_passphrase_size);
|
||||
|
||||
if (!kc->i_passphrase) {
|
||||
r = crypt_keyring_get_user_key(cd, kc->u.kr.key_description,
|
||||
&kc->i_passphrase, &kc->i_passphrase_size);
|
||||
if (r < 0) {
|
||||
log_err(cd, _("Failed to read passphrase from keyring."));
|
||||
kc->error = -EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
*r_passphrase = kc->i_passphrase;
|
||||
*r_passphrase_size = kc->i_passphrase_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_luks2_key_by_keyring(struct crypt_device *cd,
|
||||
struct crypt_keyslot_context *kc,
|
||||
int keyslot,
|
||||
int segment,
|
||||
struct volume_key **r_vk)
|
||||
{
|
||||
int r;
|
||||
|
||||
assert(cd);
|
||||
assert(kc && kc->type == CRYPT_KC_TYPE_KEYRING);
|
||||
assert(r_vk);
|
||||
|
||||
r = get_passphrase_by_keyring(cd, kc, CONST_CAST(const char **) &kc->i_passphrase,
|
||||
&kc->i_passphrase_size);
|
||||
if (r < 0) {
|
||||
log_err(cd, _("Failed to read passphrase from keyring."));
|
||||
kc->error = -EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = LUKS2_keyslot_open(cd, keyslot, segment, kc->i_passphrase, kc->i_passphrase_size, r_vk);
|
||||
if (r < 0)
|
||||
kc->error = r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_luks2_volume_key_by_keyring(struct crypt_device *cd,
|
||||
struct crypt_keyslot_context *kc,
|
||||
int keyslot,
|
||||
struct volume_key **r_vk)
|
||||
{
|
||||
return get_luks2_key_by_keyring(cd, kc, keyslot, CRYPT_DEFAULT_SEGMENT, r_vk);
|
||||
}
|
||||
|
||||
static int get_luks1_volume_key_by_keyring(struct crypt_device *cd,
|
||||
struct crypt_keyslot_context *kc,
|
||||
int keyslot,
|
||||
struct volume_key **r_vk)
|
||||
{
|
||||
int r;
|
||||
|
||||
assert(cd);
|
||||
assert(kc && kc->type == CRYPT_KC_TYPE_PASSPHRASE);
|
||||
assert(r_vk);
|
||||
|
||||
r = get_passphrase_by_keyring(cd, kc, CONST_CAST(const char **) &kc->i_passphrase,
|
||||
&kc->i_passphrase_size);
|
||||
if (r < 0) {
|
||||
log_err(cd, _("Failed to read passphrase from keyring."));
|
||||
kc->error = -EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = LUKS_open_key_with_hdr(keyslot, kc->i_passphrase, kc->i_passphrase_size,
|
||||
crypt_get_hdr(cd, CRYPT_LUKS1), r_vk, cd);
|
||||
if (r < 0)
|
||||
kc->error = r;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int get_key_by_vk_in_keyring(struct crypt_device *cd,
|
||||
struct crypt_keyslot_context *kc,
|
||||
int keyslot __attribute__((unused)),
|
||||
int segment __attribute__((unused)),
|
||||
struct volume_key **r_vk)
|
||||
{
|
||||
char *key;
|
||||
size_t key_size;
|
||||
int r;
|
||||
|
||||
assert(cd);
|
||||
assert(kc && kc->type == CRYPT_KC_TYPE_VK_KEYRING);
|
||||
assert(r_vk);
|
||||
|
||||
r = crypt_keyring_get_key_by_name(cd, kc->u.vk_kr.key_description,
|
||||
&key, &key_size);
|
||||
if (r < 0) {
|
||||
log_err(cd, _("Failed to read volume key candidate from keyring."));
|
||||
kc->error = -EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*r_vk = crypt_alloc_volume_key(key_size, key);
|
||||
crypt_safe_free(key);
|
||||
if (!*r_vk) {
|
||||
kc->error = -ENOMEM;
|
||||
return kc->error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_volume_key_by_vk_in_keyring(struct crypt_device *cd,
|
||||
struct crypt_keyslot_context *kc,
|
||||
int keyslot __attribute__((unused)),
|
||||
struct volume_key **r_vk)
|
||||
{
|
||||
return get_key_by_vk_in_keyring(cd, kc, -2 /* unused */, -2 /* unused */, r_vk);
|
||||
}
|
||||
|
||||
static void unlock_method_init_internal(struct crypt_keyslot_context *kc)
|
||||
{
|
||||
assert(kc);
|
||||
|
||||
kc->error = 0;
|
||||
kc->i_passphrase = NULL;
|
||||
kc->i_passphrase_size = 0;
|
||||
}
|
||||
|
||||
void crypt_keyslot_unlock_by_keyring_internal(struct crypt_keyslot_context *kc,
|
||||
const char *key_description)
|
||||
{
|
||||
assert(kc);
|
||||
|
||||
kc->type = CRYPT_KC_TYPE_KEYRING;
|
||||
kc->u.kr.key_description = key_description;
|
||||
|
||||
kc->get_luks2_key = get_luks2_key_by_keyring;
|
||||
kc->get_luks2_volume_key = get_luks2_volume_key_by_keyring;
|
||||
kc->get_luks1_volume_key = get_luks1_volume_key_by_keyring;
|
||||
kc->get_passphrase = get_passphrase_by_keyring;
|
||||
kc->get_plain_volume_key = NULL;
|
||||
kc->get_bitlk_volume_key = NULL;
|
||||
kc->get_fvault2_volume_key = NULL;
|
||||
kc->get_verity_volume_key = NULL;
|
||||
kc->get_integrity_volume_key = NULL;
|
||||
unlock_method_init_internal(kc);
|
||||
}
|
||||
|
||||
void crypt_keyslot_unlock_by_key_init_internal(struct crypt_keyslot_context *kc,
|
||||
const char *volume_key,
|
||||
size_t volume_key_size)
|
||||
{
|
||||
assert(kc);
|
||||
|
||||
kc->type = CRYPT_KC_TYPE_KEY;
|
||||
kc->u.k.volume_key = volume_key;
|
||||
kc->u.k.volume_key_size = volume_key_size;
|
||||
kc->get_luks2_key = get_key_by_key;
|
||||
kc->get_luks2_volume_key = get_volume_key_by_key;
|
||||
kc->get_luks1_volume_key = get_volume_key_by_key;
|
||||
kc->get_passphrase = NULL; /* keyslot key context does not provide passphrase */
|
||||
kc->get_plain_volume_key = get_generic_volume_key_by_key;
|
||||
kc->get_bitlk_volume_key = get_generic_volume_key_by_key;
|
||||
kc->get_fvault2_volume_key = get_generic_volume_key_by_key;
|
||||
kc->get_verity_volume_key = get_generic_signed_key_by_key;
|
||||
kc->get_integrity_volume_key = get_generic_volume_key_by_key;
|
||||
unlock_method_init_internal(kc);
|
||||
}
|
||||
|
||||
void crypt_keyslot_unlock_by_signed_key_init_internal(struct crypt_keyslot_context *kc,
|
||||
const char *volume_key,
|
||||
size_t volume_key_size,
|
||||
const char *signature,
|
||||
size_t signature_size)
|
||||
{
|
||||
assert(kc);
|
||||
|
||||
kc->type = CRYPT_KC_TYPE_SIGNED_KEY;
|
||||
kc->u.ks.volume_key = volume_key;
|
||||
kc->u.ks.volume_key_size = volume_key_size;
|
||||
kc->u.ks.signature = signature;
|
||||
kc->u.ks.signature_size = signature_size;
|
||||
kc->get_luks2_key = NULL;
|
||||
kc->get_luks2_volume_key = NULL;
|
||||
kc->get_luks1_volume_key = NULL;
|
||||
kc->get_passphrase = NULL;
|
||||
kc->get_plain_volume_key = NULL;
|
||||
kc->get_bitlk_volume_key = NULL;
|
||||
kc->get_fvault2_volume_key = NULL;
|
||||
kc->get_verity_volume_key = get_generic_signed_key_by_key;
|
||||
kc->get_integrity_volume_key = NULL;
|
||||
unlock_method_init_internal(kc);
|
||||
}
|
||||
|
||||
void crypt_keyslot_unlock_by_passphrase_init_internal(struct crypt_keyslot_context *kc,
|
||||
const char *passphrase,
|
||||
size_t passphrase_size)
|
||||
{
|
||||
assert(kc);
|
||||
|
||||
kc->type = CRYPT_KC_TYPE_PASSPHRASE;
|
||||
kc->u.p.passphrase = passphrase;
|
||||
kc->u.p.passphrase_size = passphrase_size;
|
||||
kc->get_luks2_key = get_luks2_key_by_passphrase;
|
||||
kc->get_luks2_volume_key = get_luks2_volume_key_by_passphrase;
|
||||
kc->get_luks1_volume_key = get_luks1_volume_key_by_passphrase;
|
||||
kc->get_passphrase = get_passphrase_by_passphrase;
|
||||
kc->get_plain_volume_key = NULL;
|
||||
kc->get_bitlk_volume_key = NULL;
|
||||
kc->get_fvault2_volume_key = NULL;
|
||||
kc->get_verity_volume_key = NULL;
|
||||
kc->get_integrity_volume_key = NULL;
|
||||
unlock_method_init_internal(kc);
|
||||
}
|
||||
|
||||
void crypt_keyslot_unlock_by_keyfile_init_internal(struct crypt_keyslot_context *kc,
|
||||
const char *keyfile,
|
||||
size_t keyfile_size,
|
||||
uint64_t keyfile_offset)
|
||||
{
|
||||
assert(kc);
|
||||
|
||||
kc->type = CRYPT_KC_TYPE_KEYFILE;
|
||||
kc->u.kf.keyfile = keyfile;
|
||||
kc->u.kf.keyfile_size = keyfile_size;
|
||||
kc->u.kf.keyfile_offset = keyfile_offset;
|
||||
kc->get_luks2_key = get_luks2_key_by_keyfile;
|
||||
kc->get_luks2_volume_key = get_luks2_volume_key_by_keyfile;
|
||||
kc->get_luks1_volume_key = get_luks1_volume_key_by_keyfile;
|
||||
kc->get_passphrase = get_passphrase_by_keyfile;
|
||||
kc->get_plain_volume_key = NULL;
|
||||
kc->get_bitlk_volume_key = NULL;
|
||||
kc->get_fvault2_volume_key = NULL;
|
||||
kc->get_verity_volume_key = NULL;
|
||||
kc->get_integrity_volume_key = NULL;
|
||||
unlock_method_init_internal(kc);
|
||||
}
|
||||
|
||||
void crypt_keyslot_unlock_by_token_init_internal(struct crypt_keyslot_context *kc,
|
||||
int token,
|
||||
const char *type,
|
||||
const char *pin,
|
||||
size_t pin_size,
|
||||
void *usrptr)
|
||||
{
|
||||
assert(kc);
|
||||
|
||||
kc->type = CRYPT_KC_TYPE_TOKEN;
|
||||
kc->u.t.id = token;
|
||||
kc->u.t.type = type;
|
||||
kc->u.t.pin = pin;
|
||||
kc->u.t.pin_size = pin_size;
|
||||
kc->u.t.usrptr = usrptr;
|
||||
kc->get_luks2_key = get_luks2_key_by_token;
|
||||
kc->get_luks2_volume_key = get_luks2_volume_key_by_token;
|
||||
kc->get_luks1_volume_key = NULL; /* LUKS1 is not supported */
|
||||
kc->get_passphrase = get_passphrase_by_token;
|
||||
kc->get_plain_volume_key = NULL;
|
||||
kc->get_bitlk_volume_key = NULL;
|
||||
kc->get_fvault2_volume_key = NULL;
|
||||
kc->get_verity_volume_key = NULL;
|
||||
kc->get_integrity_volume_key = NULL;
|
||||
unlock_method_init_internal(kc);
|
||||
}
|
||||
|
||||
void crypt_keyslot_unlock_by_vk_in_keyring_internal(struct crypt_keyslot_context *kc,
|
||||
const char *key_description)
|
||||
{
|
||||
assert(kc);
|
||||
|
||||
kc->type = CRYPT_KC_TYPE_VK_KEYRING;
|
||||
kc->u.vk_kr.key_description = key_description;
|
||||
|
||||
kc->get_luks2_key = get_key_by_vk_in_keyring;
|
||||
kc->get_luks2_volume_key = get_volume_key_by_vk_in_keyring;
|
||||
kc->get_luks1_volume_key = NULL;
|
||||
kc->get_passphrase = NULL; /* keyslot key context does not provide passphrase */
|
||||
kc->get_plain_volume_key = NULL;
|
||||
kc->get_bitlk_volume_key = NULL;
|
||||
kc->get_fvault2_volume_key = NULL;
|
||||
kc->get_verity_volume_key = NULL;
|
||||
kc->get_integrity_volume_key = NULL;
|
||||
unlock_method_init_internal(kc);
|
||||
}
|
||||
|
||||
|
||||
void crypt_keyslot_context_destroy_internal(struct crypt_keyslot_context *kc)
|
||||
{
|
||||
if (!kc)
|
||||
return;
|
||||
|
||||
crypt_safe_free(kc->i_passphrase);
|
||||
kc->i_passphrase = NULL;
|
||||
kc->i_passphrase_size = 0;
|
||||
}
|
||||
|
||||
void crypt_keyslot_context_free(struct crypt_keyslot_context *kc)
|
||||
{
|
||||
crypt_keyslot_context_destroy_internal(kc);
|
||||
free(kc);
|
||||
}
|
||||
|
||||
int crypt_keyslot_context_init_by_passphrase(struct crypt_device *cd __attribute__((unused)),
|
||||
const char *passphrase,
|
||||
size_t passphrase_size,
|
||||
struct crypt_keyslot_context **kc)
|
||||
{
|
||||
struct crypt_keyslot_context *tmp;
|
||||
|
||||
if (!kc || !passphrase)
|
||||
return -EINVAL;
|
||||
|
||||
tmp = malloc(sizeof(*tmp));
|
||||
if (!tmp)
|
||||
return -ENOMEM;
|
||||
|
||||
crypt_keyslot_unlock_by_passphrase_init_internal(tmp, passphrase, passphrase_size);
|
||||
|
||||
*kc = tmp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_keyslot_context_init_by_keyfile(struct crypt_device *cd __attribute__((unused)),
|
||||
const char *keyfile,
|
||||
size_t keyfile_size,
|
||||
uint64_t keyfile_offset,
|
||||
struct crypt_keyslot_context **kc)
|
||||
{
|
||||
struct crypt_keyslot_context *tmp;
|
||||
|
||||
if (!kc || !keyfile)
|
||||
return -EINVAL;
|
||||
|
||||
tmp = malloc(sizeof(*tmp));
|
||||
if (!tmp)
|
||||
return -ENOMEM;
|
||||
|
||||
crypt_keyslot_unlock_by_keyfile_init_internal(tmp, keyfile, keyfile_size, keyfile_offset);
|
||||
|
||||
*kc = tmp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_keyslot_context_init_by_token(struct crypt_device *cd __attribute__((unused)),
|
||||
int token,
|
||||
const char *type,
|
||||
const char *pin, size_t pin_size,
|
||||
void *usrptr,
|
||||
struct crypt_keyslot_context **kc)
|
||||
{
|
||||
struct crypt_keyslot_context *tmp;
|
||||
|
||||
if (!kc || (token < 0 && token != CRYPT_ANY_TOKEN))
|
||||
return -EINVAL;
|
||||
|
||||
tmp = malloc(sizeof(*tmp));
|
||||
if (!tmp)
|
||||
return -ENOMEM;
|
||||
|
||||
crypt_keyslot_unlock_by_token_init_internal(tmp, token, type, pin, pin_size, usrptr);
|
||||
|
||||
*kc = tmp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_keyslot_context_init_by_volume_key(struct crypt_device *cd __attribute__((unused)),
|
||||
const char *volume_key,
|
||||
size_t volume_key_size,
|
||||
struct crypt_keyslot_context **kc)
|
||||
{
|
||||
struct crypt_keyslot_context *tmp;
|
||||
|
||||
if (!kc)
|
||||
return -EINVAL;
|
||||
|
||||
tmp = malloc(sizeof(*tmp));
|
||||
if (!tmp)
|
||||
return -ENOMEM;
|
||||
|
||||
crypt_keyslot_unlock_by_key_init_internal(tmp, volume_key, volume_key_size);
|
||||
|
||||
*kc = tmp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_keyslot_context_init_by_signed_key(struct crypt_device *cd __attribute__((unused)),
|
||||
const char *volume_key,
|
||||
size_t volume_key_size,
|
||||
const char *signature,
|
||||
size_t signature_size,
|
||||
struct crypt_keyslot_context **kc)
|
||||
{
|
||||
struct crypt_keyslot_context *tmp;
|
||||
|
||||
if (!kc)
|
||||
return -EINVAL;
|
||||
|
||||
tmp = malloc(sizeof(*tmp));
|
||||
if (!tmp)
|
||||
return -ENOMEM;
|
||||
|
||||
crypt_keyslot_unlock_by_signed_key_init_internal(tmp, volume_key, volume_key_size,
|
||||
signature, signature_size);
|
||||
|
||||
*kc = tmp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_keyslot_context_init_by_keyring(struct crypt_device *cd __attribute__((unused)),
|
||||
const char *key_description,
|
||||
struct crypt_keyslot_context **kc)
|
||||
{
|
||||
struct crypt_keyslot_context *tmp;
|
||||
|
||||
if (!kc)
|
||||
return -EINVAL;
|
||||
|
||||
tmp = malloc(sizeof(*tmp));
|
||||
if (!tmp)
|
||||
return -ENOMEM;
|
||||
|
||||
crypt_keyslot_unlock_by_keyring_internal(tmp, key_description);
|
||||
|
||||
*kc = tmp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_keyslot_context_init_by_vk_in_keyring(struct crypt_device *cd __attribute__((unused)),
|
||||
const char *key_description,
|
||||
struct crypt_keyslot_context **kc)
|
||||
{
|
||||
struct crypt_keyslot_context *tmp;
|
||||
|
||||
if (!kc)
|
||||
return -EINVAL;
|
||||
|
||||
tmp = malloc(sizeof(*tmp));
|
||||
if (!tmp)
|
||||
return -ENOMEM;
|
||||
|
||||
crypt_keyslot_unlock_by_vk_in_keyring_internal(tmp, key_description);
|
||||
|
||||
*kc = tmp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_keyslot_context_get_error(struct crypt_keyslot_context *kc)
|
||||
{
|
||||
return kc ? kc->error : -EINVAL;
|
||||
}
|
||||
|
||||
int crypt_keyslot_context_set_pin(struct crypt_device *cd __attribute__((unused)),
|
||||
const char *pin, size_t pin_size,
|
||||
struct crypt_keyslot_context *kc)
|
||||
{
|
||||
if (!kc || kc->type != CRYPT_KC_TYPE_TOKEN)
|
||||
return -EINVAL;
|
||||
|
||||
kc->u.t.pin = pin;
|
||||
kc->u.t.pin_size = pin_size;
|
||||
kc->error = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_keyslot_context_get_type(const struct crypt_keyslot_context *kc)
|
||||
{
|
||||
return kc ? kc->type : -EINVAL;
|
||||
}
|
||||
|
||||
const char *keyslot_context_type_string(const struct crypt_keyslot_context *kc)
|
||||
{
|
||||
assert(kc);
|
||||
|
||||
switch (kc->type) {
|
||||
case CRYPT_KC_TYPE_PASSPHRASE:
|
||||
return "passphrase";
|
||||
case CRYPT_KC_TYPE_KEYFILE:
|
||||
return "keyfile";
|
||||
case CRYPT_KC_TYPE_TOKEN:
|
||||
return "token";
|
||||
case CRYPT_KC_TYPE_KEY:
|
||||
return "key";
|
||||
case CRYPT_KC_TYPE_KEYRING:
|
||||
return "keyring";
|
||||
case CRYPT_KC_TYPE_VK_KEYRING:
|
||||
return "volume key in keyring";
|
||||
case CRYPT_KC_TYPE_SIGNED_KEY:
|
||||
return "signed key";
|
||||
default:
|
||||
return "<unknown>";
|
||||
}
|
||||
}
|
||||
151
lib/keyslot_context.h
Normal file
151
lib/keyslot_context.h
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup, keyslot unlock helpers
|
||||
*
|
||||
* Copyright (C) 2022-2023 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2022-2023 Ondrej Kozina
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef KEYSLOT_CONTEXT_H
|
||||
#define KEYSLOT_CONTEXT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
typedef int (*keyslot_context_get_key) (
|
||||
struct crypt_device *cd,
|
||||
struct crypt_keyslot_context *kc,
|
||||
int keyslot,
|
||||
int segment,
|
||||
struct volume_key **r_vk);
|
||||
|
||||
typedef int (*keyslot_context_get_volume_key) (
|
||||
struct crypt_device *cd,
|
||||
struct crypt_keyslot_context *kc,
|
||||
int keyslot,
|
||||
struct volume_key **r_vk);
|
||||
|
||||
typedef int (*keyslot_context_get_generic_volume_key) (
|
||||
struct crypt_device *cd,
|
||||
struct crypt_keyslot_context *kc,
|
||||
struct volume_key **r_vk);
|
||||
|
||||
typedef int (*keyslot_context_get_generic_signed_key) (
|
||||
struct crypt_device *cd,
|
||||
struct crypt_keyslot_context *kc,
|
||||
struct volume_key **r_vk,
|
||||
struct volume_key **r_signature);
|
||||
|
||||
typedef int (*keyslot_context_get_passphrase) (
|
||||
struct crypt_device *cd,
|
||||
struct crypt_keyslot_context *kc,
|
||||
const char **r_passphrase,
|
||||
size_t *r_passphrase_size);
|
||||
|
||||
/* crypt_keyslot_context */
|
||||
struct crypt_keyslot_context {
|
||||
int type;
|
||||
|
||||
union {
|
||||
struct {
|
||||
const char *passphrase;
|
||||
size_t passphrase_size;
|
||||
} p;
|
||||
struct {
|
||||
const char *keyfile;
|
||||
uint64_t keyfile_offset;
|
||||
size_t keyfile_size;
|
||||
} kf;
|
||||
struct {
|
||||
int id;
|
||||
const char *type;
|
||||
const char *pin;
|
||||
size_t pin_size;
|
||||
void *usrptr;
|
||||
} t;
|
||||
struct {
|
||||
const char *volume_key;
|
||||
size_t volume_key_size;
|
||||
} k;
|
||||
struct {
|
||||
const char *volume_key;
|
||||
size_t volume_key_size;
|
||||
const char *signature;
|
||||
size_t signature_size;
|
||||
} ks;
|
||||
struct {
|
||||
const char *key_description;
|
||||
} kr;
|
||||
struct {
|
||||
const char *key_description;
|
||||
} vk_kr;
|
||||
} u;
|
||||
|
||||
int error;
|
||||
|
||||
char *i_passphrase;
|
||||
size_t i_passphrase_size;
|
||||
|
||||
keyslot_context_get_key get_luks2_key;
|
||||
keyslot_context_get_volume_key get_luks1_volume_key;
|
||||
keyslot_context_get_volume_key get_luks2_volume_key;
|
||||
keyslot_context_get_generic_volume_key get_plain_volume_key;
|
||||
keyslot_context_get_generic_volume_key get_bitlk_volume_key;
|
||||
keyslot_context_get_generic_volume_key get_fvault2_volume_key;
|
||||
keyslot_context_get_generic_signed_key get_verity_volume_key;
|
||||
keyslot_context_get_generic_volume_key get_integrity_volume_key;
|
||||
keyslot_context_get_passphrase get_passphrase;
|
||||
};
|
||||
|
||||
void crypt_keyslot_context_destroy_internal(struct crypt_keyslot_context *method);
|
||||
|
||||
void crypt_keyslot_unlock_by_key_init_internal(struct crypt_keyslot_context *kc,
|
||||
const char *volume_key,
|
||||
size_t volume_key_size);
|
||||
|
||||
void crypt_keyslot_unlock_by_signed_key_init_internal(struct crypt_keyslot_context *kc,
|
||||
const char *volume_key,
|
||||
size_t volume_key_size,
|
||||
const char *signature,
|
||||
size_t signature_size);
|
||||
|
||||
void crypt_keyslot_unlock_by_passphrase_init_internal(struct crypt_keyslot_context *kc,
|
||||
const char *passphrase,
|
||||
size_t passphrase_size);
|
||||
|
||||
void crypt_keyslot_unlock_by_keyfile_init_internal(struct crypt_keyslot_context *kc,
|
||||
const char *keyfile,
|
||||
size_t keyfile_size,
|
||||
uint64_t keyfile_offset);
|
||||
|
||||
void crypt_keyslot_unlock_by_token_init_internal(struct crypt_keyslot_context *kc,
|
||||
int token,
|
||||
const char *type,
|
||||
const char *pin,
|
||||
size_t pin_size,
|
||||
void *usrptr);
|
||||
|
||||
void crypt_keyslot_unlock_by_keyring_internal(struct crypt_keyslot_context *kc,
|
||||
const char *key_description);
|
||||
|
||||
void crypt_keyslot_unlock_by_vk_in_keyring_internal(struct crypt_keyslot_context *kc,
|
||||
const char *key_description);
|
||||
|
||||
const char *keyslot_context_type_string(const struct crypt_keyslot_context *kc);
|
||||
|
||||
#endif /* KEYSLOT_CONTEXT_H */
|
||||
@@ -3,8 +3,8 @@
|
||||
*
|
||||
* Copyright (C) 2004 Jana Saout <jana@saout.de>
|
||||
* Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2022 Milan Broz
|
||||
* Copyright (C) 2009-2023 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2023 Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -46,6 +46,7 @@ extern "C" {
|
||||
*/
|
||||
|
||||
struct crypt_device; /* crypt device handle */
|
||||
struct crypt_keyslot_context;
|
||||
|
||||
/**
|
||||
* Initialize crypt device handle and check if the provided device exists.
|
||||
@@ -272,7 +273,7 @@ struct crypt_pbkdf_type {
|
||||
|
||||
/** Iteration time set by crypt_set_iteration_time(), for compatibility only. */
|
||||
#define CRYPT_PBKDF_ITER_TIME_SET (UINT32_C(1) << 0)
|
||||
/** Never run benchmarks, use pre-set value or defaults. */
|
||||
/** Never run benchmarks or limit by system resources, use pre-set values or defaults. */
|
||||
#define CRYPT_PBKDF_NO_BENCHMARK (UINT32_C(1) << 1)
|
||||
|
||||
/** PBKDF2 according to RFC2898, LUKS1 legacy */
|
||||
@@ -344,6 +345,7 @@ void crypt_set_iteration_time(struct crypt_device *cd, uint64_t iteration_time_m
|
||||
|
||||
/**
|
||||
* Helper to lock/unlock memory to avoid swap sensitive data to disk.
|
||||
* \b Deprecated, only for backward compatibility. Memory with keys are locked automatically.
|
||||
*
|
||||
* @param cd crypt device handle, can be @e NULL
|
||||
* @param lock 0 to unlock otherwise lock memory
|
||||
@@ -353,7 +355,7 @@ void crypt_set_iteration_time(struct crypt_device *cd, uint64_t iteration_time_m
|
||||
* @note Only root can do this.
|
||||
* @note It locks/unlocks all process memory, not only crypt context.
|
||||
*/
|
||||
int crypt_memory_lock(struct crypt_device *cd, int lock);
|
||||
int crypt_memory_lock(struct crypt_device *cd, int lock) __attribute__((deprecated));
|
||||
|
||||
/**
|
||||
* Set global lock protection for on-disk metadata (file-based locking).
|
||||
@@ -427,6 +429,8 @@ int crypt_get_metadata_size(struct crypt_device *cd,
|
||||
#define CRYPT_INTEGRITY "INTEGRITY"
|
||||
/** BITLK (BitLocker-compatible mode) */
|
||||
#define CRYPT_BITLK "BITLK"
|
||||
/** FVAULT2 (FileVault2-compatible mode) */
|
||||
#define CRYPT_FVAULT2 "FVAULT2"
|
||||
|
||||
/** LUKS any version */
|
||||
#define CRYPT_LUKS NULL
|
||||
@@ -446,6 +450,34 @@ const char *crypt_get_type(struct crypt_device *cd);
|
||||
*/
|
||||
const char *crypt_get_default_type(void);
|
||||
|
||||
/**
|
||||
* @defgroup crypt-hw-encryption-types HW encryption type
|
||||
* @addtogroup crypt-hw-encryption-types
|
||||
* @{
|
||||
*/
|
||||
/** SW encryption, no OPAL encryption in place (default) */
|
||||
#define CRYPT_SW_ONLY INT16_C(0)
|
||||
/** OPAL HW encryption only (no SW encryption!) */
|
||||
#define CRYPT_OPAL_HW_ONLY INT16_C(1)
|
||||
/** SW encryption stacked over OPAL HW encryption */
|
||||
#define CRYPT_SW_AND_OPAL_HW INT16_C(2)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* Get HW encryption type
|
||||
*
|
||||
* @return HW encryption type (see @link crypt-hw-encryption-types @endlink)
|
||||
* or negative errno otherwise.
|
||||
*/
|
||||
int crypt_get_hw_encryption_type(struct crypt_device *cd);
|
||||
|
||||
/**
|
||||
* Get HW encryption (like OPAL) key size (in bytes)
|
||||
*
|
||||
* @return key size or 0 if no HW encryption is used.
|
||||
*/
|
||||
int crypt_get_hw_encryption_key_size(struct crypt_device *cd);
|
||||
|
||||
/**
|
||||
*
|
||||
* Structure used as parameter for PLAIN device type.
|
||||
@@ -605,6 +637,18 @@ struct crypt_params_luks2 {
|
||||
const char *label; /**< header label or @e NULL*/
|
||||
const char *subsystem; /**< header subsystem label or @e NULL*/
|
||||
};
|
||||
|
||||
/**
|
||||
* Structure used as parameter for OPAL (HW encrypted) device type.
|
||||
*
|
||||
* @see crypt_format_luks2_opal
|
||||
*
|
||||
*/
|
||||
struct crypt_params_hw_opal {
|
||||
const char *admin_key; /**< admin key */
|
||||
size_t admin_key_size; /**< admin key size in bytes */
|
||||
size_t user_key_size; /**< user authority key size part in bytes */
|
||||
};
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
@@ -644,6 +688,34 @@ int crypt_format(struct crypt_device *cd,
|
||||
size_t volume_key_size,
|
||||
void *params);
|
||||
|
||||
/**
|
||||
* Create (format) new LUKS2 crypt device over HW OPAL device but do not activate it.
|
||||
*
|
||||
* @pre @e cd contains initialized and not formatted device context (device type must @b not be set)
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param cipher for SW encryption (e.g. "aes") or NULL for HW encryption only
|
||||
* @param cipher_mode including IV specification (e.g. "xts-plain") or NULL for HW encryption only
|
||||
* @param uuid requested UUID or @e NULL if it should be generated
|
||||
* @param volume_key pre-generated volume key or @e NULL if it should be generated (only for LUKS2 SW encryption)
|
||||
* @param volume_key_size size of volume key in bytes (only for SW encryption).
|
||||
* @param params LUKS2 crypt type specific parameters (see @link crypt-type @endlink)
|
||||
* @param opal_params OPAL specific parameters
|
||||
*
|
||||
* @returns @e 0 on success or negative errno value otherwise.
|
||||
*
|
||||
* @note Note that crypt_format_luks2_opal does not create LUKS keyslot.
|
||||
* To create keyslot call any crypt_keyslot_add_* function.
|
||||
*/
|
||||
int crypt_format_luks2_opal(struct crypt_device *cd,
|
||||
const char *cipher,
|
||||
const char *cipher_mode,
|
||||
const char *uuid,
|
||||
const char *volume_keys,
|
||||
size_t volume_keys_size,
|
||||
struct crypt_params_luks2 *params,
|
||||
struct crypt_params_hw_opal *opal_params);
|
||||
|
||||
/**
|
||||
* Set format compatibility flags.
|
||||
*
|
||||
@@ -937,6 +1009,23 @@ int crypt_resume_by_token_pin(struct crypt_device *cd,
|
||||
const char *pin,
|
||||
size_t pin_size,
|
||||
void *usrptr);
|
||||
|
||||
/**
|
||||
* Resume crypt device using keyslot context.
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param name name of device to resume
|
||||
* @param keyslot requested keyslot to check or @e CRYPT_ANY_SLOT, keyslot is
|
||||
* ignored for unlock methods not based on passphrase
|
||||
* @param kc keyslot context providing volume key or passphrase.
|
||||
*
|
||||
* @return unlocked key slot number for passphrase-based unlock, zero for other
|
||||
* unlock methods (e.g. volume key context) or negative errno on error.
|
||||
*/
|
||||
int crypt_resume_by_keyslot_context(struct crypt_device *cd,
|
||||
const char *name,
|
||||
int keyslot,
|
||||
struct crypt_keyslot_context *kc);
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
@@ -1095,7 +1184,7 @@ int crypt_keyslot_add_by_volume_key(struct crypt_device *cd,
|
||||
* @warning CRYPT_VOLUME_KEY_SET flag force updates volume key. It is @b not @b reencryption!
|
||||
* By doing so you will most probably destroy your ciphertext data device. It's supposed
|
||||
* to be used only in wrapped keys scheme for key refresh process where real (inner) volume
|
||||
* key stays untouched. It may be involed on active @e keyslot which makes the (previously
|
||||
* key stays untouched. It may be involved on active @e keyslot which makes the (previously
|
||||
* unbound) keyslot new regular keyslot.
|
||||
*/
|
||||
int crypt_keyslot_add_by_key(struct crypt_device *cd,
|
||||
@@ -1106,6 +1195,250 @@ int crypt_keyslot_add_by_key(struct crypt_device *cd,
|
||||
size_t passphrase_size,
|
||||
uint32_t flags);
|
||||
|
||||
/**
|
||||
* @defgroup crypt-keyslot-context Crypt keyslot context
|
||||
* @addtogroup crypt-keyslot-context
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Release crypt keyslot context and used memory.
|
||||
*
|
||||
* @param kc crypt keyslot context
|
||||
*/
|
||||
void crypt_keyslot_context_free(struct crypt_keyslot_context *kc);
|
||||
|
||||
/**
|
||||
* Initialize keyslot context via passphrase.
|
||||
*
|
||||
* @param cd crypt device handle initialized to LUKS device context
|
||||
* @param passphrase passphrase for a keyslot
|
||||
* @param passphrase_size size of passphrase
|
||||
* @param kc returns crypt keyslot context handle type CRYPT_KC_TYPE_PASSPHRASE
|
||||
*
|
||||
* @return zero on success or negative errno otherwise.
|
||||
*/
|
||||
int crypt_keyslot_context_init_by_passphrase(struct crypt_device *cd,
|
||||
const char *passphrase,
|
||||
size_t passphrase_size,
|
||||
struct crypt_keyslot_context **kc);
|
||||
|
||||
/**
|
||||
* Initialize keyslot context via key file path.
|
||||
*
|
||||
* @param cd crypt device handle initialized to LUKS device context
|
||||
*
|
||||
* @param keyfile key file with passphrase for a keyslot
|
||||
* @param keyfile_size number of bytes to read from keyfile, @e 0 is unlimited
|
||||
* @param keyfile_offset number of bytes to skip at start of keyfile
|
||||
* @param kc returns crypt keyslot context handle type CRYPT_KC_TYPE_KEYFILE
|
||||
*
|
||||
* @return zero on success or negative errno otherwise.
|
||||
*/
|
||||
int crypt_keyslot_context_init_by_keyfile(struct crypt_device *cd,
|
||||
const char *keyfile,
|
||||
size_t keyfile_size,
|
||||
uint64_t keyfile_offset,
|
||||
struct crypt_keyslot_context **kc);
|
||||
|
||||
/**
|
||||
* Initialize keyslot context via LUKS2 token.
|
||||
*
|
||||
* @param cd crypt device handle initialized to LUKS2 device context
|
||||
*
|
||||
* @param token token providing passphrase for a keyslot or CRYPT_ANY_TOKEN
|
||||
* @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
|
||||
* @param kc returns crypt keyslot context handle type CRYPT_KC_TYPE_TOKEN
|
||||
*
|
||||
* @return zero on success or negative errno otherwise.
|
||||
*/
|
||||
int crypt_keyslot_context_init_by_token(struct crypt_device *cd,
|
||||
int token,
|
||||
const char *type,
|
||||
const char *pin, size_t pin_size,
|
||||
void *usrptr,
|
||||
struct crypt_keyslot_context **kc);
|
||||
|
||||
/**
|
||||
* Initialize keyslot context via key.
|
||||
*
|
||||
* @param cd crypt device handle initialized to LUKS device context
|
||||
*
|
||||
* @param volume_key provided volume key or @e NULL if used after crypt_format
|
||||
* or with CRYPT_VOLUME_KEY_NO_SEGMENT flag
|
||||
* @param volume_key_size size of volume_key
|
||||
* @param kc returns crypt keyslot context handle type CRYPT_KC_TYPE_KEY
|
||||
*
|
||||
* @return zero on success or negative errno otherwise.
|
||||
*/
|
||||
int crypt_keyslot_context_init_by_volume_key(struct crypt_device *cd,
|
||||
const char *volume_key,
|
||||
size_t volume_key_size,
|
||||
struct crypt_keyslot_context **kc);
|
||||
|
||||
/**
|
||||
* Initialize keyslot context via signed key.
|
||||
*
|
||||
* @param cd crypt device handle initialized to device context
|
||||
*
|
||||
* @param volume_key provided volume key
|
||||
* @param volume_key_size size of volume_key
|
||||
* @param signature buffer with signature for the key
|
||||
* @param signature_size bsize of signature buffer
|
||||
* @param kc returns crypt keyslot context handle type CRYPT_KC_TYPE_SIGNED_KEY
|
||||
*
|
||||
* @return zero on success or negative errno otherwise.
|
||||
*
|
||||
* @note currently supported only with VERITY devices.
|
||||
*/
|
||||
int crypt_keyslot_context_init_by_signed_key(struct crypt_device *cd,
|
||||
const char *volume_key,
|
||||
size_t volume_key_size,
|
||||
const char *signature,
|
||||
size_t signature_size,
|
||||
struct crypt_keyslot_context **kc);
|
||||
|
||||
/**
|
||||
* Initialize keyslot context via passphrase stored in a keyring.
|
||||
*
|
||||
* @param cd crypt device handle initialized to LUKS device context
|
||||
*
|
||||
* @param key_description kernel keyring key description library should look
|
||||
* for passphrase in
|
||||
* @param kc returns crypt keyslot context handle type CRYPT_KC_TYPE_KEYRING
|
||||
*
|
||||
* @return zero on success or negative errno otherwise.
|
||||
*/
|
||||
int crypt_keyslot_context_init_by_keyring(struct crypt_device *cd,
|
||||
const char *key_description,
|
||||
struct crypt_keyslot_context **kc);
|
||||
|
||||
/**
|
||||
* Initialize keyslot context via volume key stored in a keyring.
|
||||
*
|
||||
* @param cd crypt device handle initialized to LUKS device context
|
||||
*
|
||||
* @param key_description kernel keyring key description library should look
|
||||
* for passphrase in. The key can be passed either as number in ASCII,
|
||||
* or a text representation in the form "%<key_type>:<key_name>"
|
||||
* @param kc returns crypt keyslot context handle type CRYPT_KC_TYPE_KEYRING
|
||||
*
|
||||
* @return zero on success or negative errno otherwise.
|
||||
*/
|
||||
int crypt_keyslot_context_init_by_vk_in_keyring(struct crypt_device *cd,
|
||||
const char *key_description,
|
||||
struct crypt_keyslot_context **kc);
|
||||
|
||||
/**
|
||||
* Get error code per keyslot context from last failed call.
|
||||
*
|
||||
* @note If @link crypt_keyslot_add_by_keyslot_context @endlink passed with
|
||||
* no negative return code. The return value of this function is undefined.
|
||||
*
|
||||
* @param kc keyslot context involved in failed @link crypt_keyslot_add_by_keyslot_context @endlink
|
||||
*
|
||||
* @return Negative errno if keyslot context caused a failure, zero otherwise.
|
||||
*/
|
||||
int crypt_keyslot_context_get_error(struct crypt_keyslot_context *kc);
|
||||
|
||||
/**
|
||||
* Set new pin to token based keyslot context.
|
||||
*
|
||||
* @note Use when @link crypt_keyslot_add_by_keyslot_context @endlink failed
|
||||
* and token keyslot context returned -ENOANO error code via
|
||||
* @link crypt_keyslot_context_get_error @endlink.
|
||||
*
|
||||
* @param cd crypt device handle initialized to LUKS2 device context
|
||||
* @param pin passphrase (or PIN) to unlock token (may be binary data)
|
||||
* @param pin_size size of @e pin
|
||||
* @param kc LUKS2 keyslot context (only @link CRYPT_KC_TYPE_TOKEN @endlink is allowed)
|
||||
*
|
||||
* @return zero on success or negative errno otherwise
|
||||
*/
|
||||
int crypt_keyslot_context_set_pin(struct crypt_device *cd,
|
||||
const char *pin, size_t pin_size,
|
||||
struct crypt_keyslot_context *kc);
|
||||
|
||||
/**
|
||||
* @defgroup crypt-keyslot-context-types Crypt keyslot context
|
||||
* @addtogroup crypt-keyslot-context-types
|
||||
* @{
|
||||
*/
|
||||
/** keyslot context initialized by passphrase (@link crypt_keyslot_context_init_by_passphrase @endlink) */
|
||||
#define CRYPT_KC_TYPE_PASSPHRASE INT16_C(1)
|
||||
/** keyslot context initialized by keyfile (@link crypt_keyslot_context_init_by_keyfile @endlink) */
|
||||
#define CRYPT_KC_TYPE_KEYFILE INT16_C(2)
|
||||
/** keyslot context initialized by token (@link crypt_keyslot_context_init_by_token @endlink) */
|
||||
#define CRYPT_KC_TYPE_TOKEN INT16_C(3)
|
||||
/** keyslot context initialized by volume key or unbound key (@link crypt_keyslot_context_init_by_volume_key @endlink) */
|
||||
#define CRYPT_KC_TYPE_KEY INT16_C(4)
|
||||
/** keyslot context initialized by description of a keyring key
|
||||
* (@link crypt_keyslot_context_init_by_keyring @endlink)
|
||||
*/
|
||||
#define CRYPT_KC_TYPE_KEYRING INT16_C(5)
|
||||
/** keyslot context initialized by description of a keyring key containing the volume key
|
||||
* (@link crypt_keyslot_context_init_by_vk_in_keyring @endlink)
|
||||
*/
|
||||
#define CRYPT_KC_TYPE_VK_KEYRING INT16_C(6)
|
||||
/** keyslot context initialized by signed key (@link crypt_keyslot_context_init_by_signed_key @endlink) */
|
||||
#define CRYPT_KC_TYPE_SIGNED_KEY INT16_C(7)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* Get type identifier for crypt keyslot context.
|
||||
*
|
||||
* @param kc keyslot context
|
||||
*
|
||||
* @return crypt keyslot context type id (see @link crypt-keyslot-context-types @endlink) or negative errno otherwise.
|
||||
*/
|
||||
int crypt_keyslot_context_get_type(const struct crypt_keyslot_context *kc);
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* Add key slot by volume key provided by keyslot context (kc). New
|
||||
* keyslot will be protected by passphrase provided by new keyslot context (new_kc).
|
||||
* See @link crypt-keyslot-context @endlink for context initialization routines.
|
||||
*
|
||||
* @pre @e cd contains initialized and formatted LUKS device context.
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param keyslot_existing existing keyslot or CRYPT_ANY_SLOT to get volume key from.
|
||||
* @param kc keyslot context providing volume key.
|
||||
* @param keyslot_new new keyslot or CRYPT_ANY_SLOT (first free number is used).
|
||||
* @param new_kc keyslot context providing passphrase for new keyslot.
|
||||
* @param flags key flags to set
|
||||
*
|
||||
* @return allocated key slot number or negative errno otherwise.
|
||||
*
|
||||
* @note new_kc can not be @e CRYPT_KC_TYPE_KEY type keyslot context.
|
||||
*
|
||||
* @note For kc parameter with type @e CRYPT_KC_TYPE_KEY the keyslot_existing
|
||||
* parameter is ignored.
|
||||
*
|
||||
* @note in case there is no active LUKS keyslot to get existing volume key from, one of following must apply:
|
||||
* @li @e cd must be device handle used in crypt_format() by current process (it holds reference to generated volume key)
|
||||
* @li kc must be of @e CRYPT_KC_TYPE_KEY type with valid volume key.
|
||||
*
|
||||
* @note With CRYPT_VOLUME_KEY_NO_SEGMENT flag raised and kc of type @e CRYPT_KC_TYPE_KEY with @e volume_key set to @e NULL
|
||||
* the new volume_key will be generated and stored in new keyslot. The keyslot will become unbound (unusable to
|
||||
* dm-crypt device activation).
|
||||
*
|
||||
* @warning CRYPT_VOLUME_KEY_SET flag force updates volume key. It is @b not @b reencryption!
|
||||
* By doing so you will most probably destroy your ciphertext data device. It's supposed
|
||||
* to be used only in wrapped keys scheme for key refresh process where real (inner) volume
|
||||
* key stays untouched. It may be involved on active @e keyslot which makes the (previously
|
||||
* unbound) keyslot new regular keyslot.
|
||||
*/
|
||||
int crypt_keyslot_add_by_keyslot_context(struct crypt_device *cd,
|
||||
int keyslot_existing,
|
||||
struct crypt_keyslot_context *kc,
|
||||
int keyslot_new,
|
||||
struct crypt_keyslot_context *new_kc,
|
||||
uint32_t flags);
|
||||
|
||||
/**
|
||||
* Destroy (and disable) key slot.
|
||||
*
|
||||
@@ -1182,6 +1515,8 @@ int crypt_keyslot_destroy(struct crypt_device *cd, int keyslot);
|
||||
#define CRYPT_ACTIVATE_NO_WRITE_WORKQUEUE (UINT32_C(1) << 25)
|
||||
/** dm-integrity: reset automatic recalculation */
|
||||
#define CRYPT_ACTIVATE_RECALCULATE_RESET (UINT32_C(1) << 26)
|
||||
/** dm-verity: try to use tasklets */
|
||||
#define CRYPT_ACTIVATE_TASKLETS (UINT32_C(1) << 27)
|
||||
|
||||
/**
|
||||
* Active device runtime attributes
|
||||
@@ -1233,6 +1568,8 @@ uint64_t crypt_get_active_integrity_failures(struct crypt_device *cd,
|
||||
#define CRYPT_REQUIREMENT_OFFLINE_REENCRYPT (UINT32_C(1) << 0)
|
||||
/** Online reencryption in-progress */
|
||||
#define CRYPT_REQUIREMENT_ONLINE_REENCRYPT (UINT32_C(1) << 1)
|
||||
/** Device configured with OPAL support */
|
||||
#define CRYPT_REQUIREMENT_OPAL (UINT32_C(1) << 2)
|
||||
/** unknown requirement in header (output only) */
|
||||
#define CRYPT_REQUIREMENT_UNKNOWN (UINT32_C(1) << 31)
|
||||
|
||||
@@ -1286,6 +1623,25 @@ int crypt_persistent_flags_get(struct crypt_device *cd,
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Activate device or check using keyslot context.
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param name name of device to create, if @e NULL only check passphrase
|
||||
* @param keyslot requested keyslot to check or @e CRYPT_ANY_SLOT, keyslot is
|
||||
* ignored for unlock methods not based on passphrase
|
||||
* @param kc keyslot context providing volume key or passphrase.
|
||||
* @param flags activation flags
|
||||
*
|
||||
* @return unlocked key slot number for passphrase-based unlock, zero for other
|
||||
* unlock methods (e.g. volume key context) or negative errno on error.
|
||||
*/
|
||||
int crypt_activate_by_keyslot_context(struct crypt_device *cd,
|
||||
const char *name,
|
||||
int keyslot,
|
||||
struct crypt_keyslot_context *kc,
|
||||
uint32_t flags);
|
||||
|
||||
/**
|
||||
* Activate device or check passphrase.
|
||||
*
|
||||
@@ -1366,6 +1722,9 @@ int crypt_activate_by_keyfile(struct crypt_device *cd,
|
||||
* CRYPT_ACTIVATE_READONLY flag always.
|
||||
* @note For TCRYPT the volume key should be always NULL
|
||||
* the key from decrypted header is used instead.
|
||||
* @note For BITLK @name cannot be @e NULL checking volume key is not
|
||||
* supported for BITLK, the device will be activated even if the
|
||||
* provided key is not correct.
|
||||
*/
|
||||
int crypt_activate_by_volume_key(struct crypt_device *cd,
|
||||
const char *name,
|
||||
@@ -1471,6 +1830,9 @@ int crypt_deactivate(struct crypt_device *cd, const char *name);
|
||||
* @note For TCRYPT cipher chain is the volume key concatenated
|
||||
* for all ciphers in chain.
|
||||
* @note For VERITY the volume key means root hash used for activation.
|
||||
* @note For LUKS devices, if passphrase is @e NULL and volume key is cached in
|
||||
* device context it returns the volume key generated in preceding
|
||||
* @link crypt_format @endlink call.
|
||||
*/
|
||||
int crypt_volume_key_get(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
@@ -1479,6 +1841,41 @@ int crypt_volume_key_get(struct crypt_device *cd,
|
||||
const char *passphrase,
|
||||
size_t passphrase_size);
|
||||
|
||||
/**
|
||||
* Get volume key from crypt device by keyslot context.
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param keyslot use this keyslot or @e CRYPT_ANY_SLOT
|
||||
* @param volume_key buffer for volume key
|
||||
* @param volume_key_size on input, size of buffer @e volume_key,
|
||||
* on output size of @e volume_key
|
||||
* @param kc keyslot context used to unlock volume key
|
||||
*
|
||||
* @return unlocked key slot number or negative errno otherwise.
|
||||
*
|
||||
* @note See @link crypt-keyslot-context-types @endlink for info on keyslot
|
||||
* context initialization.
|
||||
* @note For TCRYPT cipher chain is the volume key concatenated
|
||||
* for all ciphers in chain (kc may be NULL).
|
||||
* @note For VERITY the volume key means root hash used for activation
|
||||
* (kc may be NULL).
|
||||
* @note For LUKS devices, if kc is @e NULL and volume key is cached in
|
||||
* device context it returns the volume key generated in preceding
|
||||
* @link crypt_format @endlink call.
|
||||
* @note @link CRYPT_KC_TYPE_TOKEN @endlink keyslot context is usable only with LUKS2 devices.
|
||||
* @note @link CRYPT_KC_TYPE_KEY @endlink keyslot context can not be used.
|
||||
* @note To get LUKS2 unbound key, keyslot parameter must not be @e CRYPT_ANY_SLOT.
|
||||
* @note EPERM errno means provided keyslot context could not unlock any (or selected)
|
||||
* keyslot.
|
||||
* @note ENOENT errno means no LUKS keyslot is available to retrieve volume key from
|
||||
* and there's no cached volume key in device handle.
|
||||
*/
|
||||
int crypt_volume_key_get_by_keyslot_context(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
char *volume_key,
|
||||
size_t *volume_key_size,
|
||||
struct crypt_keyslot_context *kc);
|
||||
|
||||
/**
|
||||
* Verify that provided volume key is valid for crypt device.
|
||||
*
|
||||
@@ -2036,6 +2433,35 @@ int crypt_wipe(struct crypt_device *cd,
|
||||
#define CRYPT_WIPE_NO_DIRECT_IO (UINT32_C(1) << 0)
|
||||
/** @} */
|
||||
|
||||
enum {
|
||||
CRYPT_LUKS2_SEGMENT = -2,
|
||||
CRYPT_NO_SEGMENT = -1,
|
||||
};
|
||||
|
||||
/**
|
||||
* Safe erase of a partition or an entire OPAL device. WARNING: ALL DATA ON
|
||||
* PARTITION/DISK WILL BE LOST. If the CRYPT_NO_SEGMENT is passed as the segment
|
||||
* parameter, the entire device will be wiped, not just what is included in the
|
||||
* LUKS2 device/partition.
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param segment the segment number to wipe (0..8), or CRYPT_LUKS2_SEGMENT
|
||||
* to wipe the segment configured in the LUKS2 header, or CRYPT_NO_SEGMENT
|
||||
* to wipe the entire device via a factory reset.
|
||||
* @param password admin password/PSID (for factory reset) to wipe the
|
||||
* partition/device
|
||||
* @param password_size length of password/PSID
|
||||
* @param flags (currently unused)
|
||||
*
|
||||
* @return @e 0 on success or negative errno value otherwise.
|
||||
*/
|
||||
int crypt_wipe_hw_opal(struct crypt_device *cd,
|
||||
int segment, /* 0..8, CRYPT_LUKS2_SEGMENT -2, CRYPT_NO_SEGMENT -1 */
|
||||
const char *password, /* Admin1 PIN or PSID */
|
||||
size_t password_size,
|
||||
uint32_t flags /* currently unused */
|
||||
);
|
||||
|
||||
/**
|
||||
* @defgroup crypt-tokens LUKS2 token wrapper access
|
||||
*
|
||||
@@ -2341,6 +2767,17 @@ int crypt_token_register(const crypt_token_handler *handler);
|
||||
*/
|
||||
const char *crypt_token_external_path(void);
|
||||
|
||||
/**
|
||||
* Override configured external token handlers path for the library.
|
||||
*
|
||||
* @param path Absolute path (starts with '/') to new external token handlers directory or @e NULL.
|
||||
*
|
||||
* @note if @e path is @e NULL the external token path is reset to default path.
|
||||
*
|
||||
* @return @e 0 on success or negative errno value otherwise.
|
||||
*/
|
||||
int crypt_token_set_external_path(const char *path);
|
||||
|
||||
/**
|
||||
* Disable external token handlers (plugins) support
|
||||
* If disabled, it cannot be enabled again.
|
||||
@@ -2648,6 +3085,29 @@ void *crypt_safe_realloc(void *data, size_t size);
|
||||
*/
|
||||
void crypt_safe_memzero(void *data, size_t size);
|
||||
|
||||
/**
|
||||
* Link the volume key to the specified kernel keyring.
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param key_description the key description of volume key linked in desired keyring.
|
||||
* @param key_type the key type used for the volume key. Currently only "user" and "logon" types are
|
||||
* supported. if @e NULL is specified the default "user" type is applied.
|
||||
* @param keyring_to_link_vk the keyring description of the keyring in which volume key should
|
||||
* be linked, if @e NULL is specified, linking will be disabled.
|
||||
*
|
||||
* @note keyring_to_link_vk may be passed in various string formats:
|
||||
* It can be kernel key numeric id of existing keyring written as a string,
|
||||
* keyring name prefixed optionally be either "%:" or "%keyring:" substrings or keyctl
|
||||
* special values for keyrings "@t", "@p", "@s" and so on. See keyctl(1) man page,
|
||||
* section KEY IDENTIFIERS for more information. All other prefixes starting "%<type>:"
|
||||
* are ignored.
|
||||
*
|
||||
* @note key_description "%<type>:" prefixes are ignored. Type is applied based on key_type parameter
|
||||
* value.
|
||||
*/
|
||||
int crypt_set_keyring_to_link(struct crypt_device *cd, const char *key_description,
|
||||
const char *key_type_desc, const char *keyring_to_link_vk);
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -8,3 +8,4 @@ Description: cryptsetup library
|
||||
Version: @LIBCRYPTSETUP_VERSION@
|
||||
Cflags: -I${includedir}
|
||||
Libs: -L${libdir} -lcryptsetup
|
||||
Requires.private: @PKGMODULES@
|
||||
|
||||
@@ -151,3 +151,32 @@ CRYPTSETUP_2.5 {
|
||||
crypt_get_subsystem;
|
||||
crypt_resume_by_token_pin;
|
||||
} CRYPTSETUP_2.4;
|
||||
|
||||
CRYPTSETUP_2.6 {
|
||||
global:
|
||||
crypt_keyslot_context_free;
|
||||
crypt_keyslot_context_init_by_passphrase;
|
||||
crypt_keyslot_context_init_by_keyfile;
|
||||
crypt_keyslot_context_init_by_token;
|
||||
crypt_keyslot_context_init_by_volume_key;
|
||||
crypt_keyslot_context_get_error;
|
||||
crypt_keyslot_context_set_pin;
|
||||
crypt_keyslot_context_get_type;
|
||||
crypt_keyslot_add_by_keyslot_context;
|
||||
crypt_volume_key_get_by_keyslot_context;
|
||||
} CRYPTSETUP_2.5;
|
||||
|
||||
CRYPTSETUP_2.7 {
|
||||
global:
|
||||
crypt_activate_by_keyslot_context;
|
||||
crypt_format_luks2_opal;
|
||||
crypt_get_hw_encryption_type;
|
||||
crypt_get_hw_encryption_key_size;
|
||||
crypt_keyslot_context_init_by_keyring;
|
||||
crypt_keyslot_context_init_by_vk_in_keyring;
|
||||
crypt_keyslot_context_init_by_signed_key;
|
||||
crypt_resume_by_keyslot_context;
|
||||
crypt_token_set_external_path;
|
||||
crypt_set_keyring_to_link;
|
||||
crypt_wipe_hw_opal;
|
||||
} CRYPTSETUP_2.6;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Definitions of common constant and generic macros of libcryptsetup
|
||||
*
|
||||
* Copyright (C) 2009-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2022 Milan Broz
|
||||
* Copyright (C) 2009-2023 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2023 Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Helpers for defining versioned symbols
|
||||
*
|
||||
* Copyright (C) 2021-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2021-2023 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
|
||||
@@ -72,9 +72,9 @@
|
||||
__attribute__((__symver__(#_public_sym _ver_str #_maj "." #_min)))
|
||||
#endif
|
||||
|
||||
#if !defined(_CRYPT_SYMVER) && defined(__GNUC__)
|
||||
#if !defined(_CRYPT_SYMVER) && (defined(__GNUC__) || defined(__clang__))
|
||||
# define _CRYPT_SYMVER(_local_sym, _public_sym, _ver_str, _maj, _min) \
|
||||
asm(".symver " #_local_sym "," #_public_sym _ver_str #_maj "." #_min);
|
||||
__asm__(".symver " #_local_sym "," #_public_sym _ver_str #_maj "." #_min);
|
||||
#endif
|
||||
|
||||
#define _CRYPT_FUNC(_public_sym, _prefix_str, _maj, _min, _ret, ...) \
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
*
|
||||
* Copyright (C) 2004 Jana Saout <jana@saout.de>
|
||||
* Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2022 Milan Broz
|
||||
* Copyright (C) 2009-2023 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2023 Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -31,7 +31,6 @@
|
||||
#ifdef HAVE_SYS_SYSMACROS_H
|
||||
# include <sys/sysmacros.h> /* for major, minor */
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include "internal.h"
|
||||
|
||||
#define DM_CRYPT_TARGET "crypt"
|
||||
@@ -205,6 +204,9 @@ static void _dm_set_verity_compat(struct crypt_device *cd,
|
||||
if (_dm_satisfies_version(1, 7, 0, verity_maj, verity_min, verity_patch))
|
||||
_dm_flags |= DM_VERITY_PANIC_CORRUPTION_SUPPORTED;
|
||||
|
||||
if (_dm_satisfies_version(1, 9, 0, verity_maj, verity_min, verity_patch))
|
||||
_dm_flags |= DM_VERITY_TASKLETS_SUPPORTED;
|
||||
|
||||
_dm_verity_checked = true;
|
||||
}
|
||||
|
||||
@@ -473,27 +475,22 @@ static size_t int_log10(uint64_t x)
|
||||
return r;
|
||||
}
|
||||
|
||||
#define CLEN 64 /* 2*MAX_CIPHER_LEN */
|
||||
#define CLENS "63" /* for sscanf length + '\0' */
|
||||
#define CAPIL 144 /* should be enough to fit whole capi string */
|
||||
#define CAPIS "143" /* for sscanf of crypto API string + 16 + \0 */
|
||||
|
||||
static int cipher_c2dm(const char *org_c, const char *org_i, unsigned tag_size,
|
||||
static int cipher_dm2c(const char *org_c, const char *org_i, unsigned tag_size,
|
||||
char *c_dm, int c_dm_size,
|
||||
char *i_dm, int i_dm_size)
|
||||
{
|
||||
int c_size = 0, i_size = 0, i;
|
||||
char cipher[CLEN], mode[CLEN], iv[CLEN+1], tmp[CLEN];
|
||||
char capi[CAPIL];
|
||||
char cipher[MAX_CAPI_ONE_LEN], mode[MAX_CAPI_ONE_LEN], iv[MAX_CAPI_ONE_LEN+1],
|
||||
tmp[MAX_CAPI_ONE_LEN], capi[MAX_CAPI_LEN];
|
||||
|
||||
if (!c_dm || !c_dm_size || !i_dm || !i_dm_size)
|
||||
return -EINVAL;
|
||||
|
||||
i = sscanf(org_c, "%" CLENS "[^-]-%" CLENS "s", cipher, tmp);
|
||||
i = sscanf(org_c, "%" MAX_CAPI_ONE_LEN_STR "[^-]-%" MAX_CAPI_ONE_LEN_STR "s", cipher, tmp);
|
||||
if (i != 2)
|
||||
return -EINVAL;
|
||||
|
||||
i = sscanf(tmp, "%" CLENS "[^-]-%" CLENS "s", mode, iv);
|
||||
i = sscanf(tmp, "%" MAX_CAPI_ONE_LEN_STR "[^-]-%" MAX_CAPI_ONE_LEN_STR "s", mode, iv);
|
||||
if (i == 1) {
|
||||
memset(iv, 0, sizeof(iv));
|
||||
strncpy(iv, mode, sizeof(iv)-1);
|
||||
@@ -540,75 +537,6 @@ static int cipher_c2dm(const char *org_c, const char *org_i, unsigned tag_size,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cipher_dm2c(char **org_c, char **org_i, const char *c_dm, const char *i_dm)
|
||||
{
|
||||
char cipher[CLEN], mode[CLEN], iv[CLEN], auth[CLEN];
|
||||
char tmp[CAPIL], dmcrypt_tmp[CAPIL*2], capi[CAPIL+1];
|
||||
size_t len;
|
||||
int i;
|
||||
|
||||
if (!c_dm)
|
||||
return -EINVAL;
|
||||
|
||||
/* legacy mode */
|
||||
if (strncmp(c_dm, "capi:", 4)) {
|
||||
if (!(*org_c = strdup(c_dm)))
|
||||
return -ENOMEM;
|
||||
*org_i = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* modes with capi: prefix */
|
||||
i = sscanf(c_dm, "capi:%" CAPIS "[^-]-%" CLENS "s", tmp, iv);
|
||||
if (i != 2)
|
||||
return -EINVAL;
|
||||
|
||||
len = strlen(tmp);
|
||||
if (len < 2)
|
||||
return -EINVAL;
|
||||
|
||||
if (tmp[len-1] == ')')
|
||||
tmp[len-1] = '\0';
|
||||
|
||||
if (sscanf(tmp, "rfc4309(%" CAPIS "s", capi) == 1) {
|
||||
if (!(*org_i = strdup("aead")))
|
||||
return -ENOMEM;
|
||||
} else if (sscanf(tmp, "rfc7539(%" CAPIS "[^,],%" CLENS "s", capi, auth) == 2) {
|
||||
if (!(*org_i = strdup(auth)))
|
||||
return -ENOMEM;
|
||||
} else if (sscanf(tmp, "authenc(%" CLENS "[^,],%" CAPIS "s", auth, capi) == 2) {
|
||||
if (!(*org_i = strdup(auth)))
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
if (i_dm) {
|
||||
if (!(*org_i = strdup(i_dm)))
|
||||
return -ENOMEM;
|
||||
} else
|
||||
*org_i = NULL;
|
||||
memset(capi, 0, sizeof(capi));
|
||||
strncpy(capi, tmp, sizeof(capi)-1);
|
||||
}
|
||||
|
||||
i = sscanf(capi, "%" CLENS "[^(](%" CLENS "[^)])", mode, cipher);
|
||||
if (i == 2)
|
||||
i = snprintf(dmcrypt_tmp, sizeof(dmcrypt_tmp), "%s-%s-%s", cipher, mode, iv);
|
||||
else
|
||||
i = snprintf(dmcrypt_tmp, sizeof(dmcrypt_tmp), "%s-%s", capi, iv);
|
||||
if (i < 0 || (size_t)i >= sizeof(dmcrypt_tmp)) {
|
||||
free(*org_i);
|
||||
*org_i = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!(*org_c = strdup(dmcrypt_tmp))) {
|
||||
free(*org_i);
|
||||
*org_i = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *_uf(char *buf, size_t buf_size, const char *s, unsigned u)
|
||||
{
|
||||
size_t r = snprintf(buf, buf_size, " %s:%u", s, u);
|
||||
@@ -626,7 +554,7 @@ static char *get_dm_crypt_params(const struct dm_target *tgt, uint32_t flags)
|
||||
if (!tgt)
|
||||
return NULL;
|
||||
|
||||
r = cipher_c2dm(tgt->u.crypt.cipher, tgt->u.crypt.integrity, tgt->u.crypt.tag_size,
|
||||
r = cipher_dm2c(tgt->u.crypt.cipher, tgt->u.crypt.integrity, tgt->u.crypt.tag_size,
|
||||
cipher_dm, sizeof(cipher_dm), integrity_dm, sizeof(integrity_dm));
|
||||
if (r < 0)
|
||||
return NULL;
|
||||
@@ -674,7 +602,8 @@ static char *get_dm_crypt_params(const struct dm_target *tgt, uint32_t flags)
|
||||
hexkey = crypt_safe_alloc(keystr_len);
|
||||
if (!hexkey)
|
||||
goto out;
|
||||
r = snprintf(hexkey, keystr_len, ":%zu:logon:%s", tgt->u.crypt.vk->keylength, tgt->u.crypt.vk->key_description);
|
||||
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
|
||||
@@ -734,6 +663,8 @@ static char *get_dm_verity_params(const struct dm_target *tgt, uint32_t flags)
|
||||
num_options++;
|
||||
if (flags & CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE)
|
||||
num_options++;
|
||||
if (flags & CRYPT_ACTIVATE_TASKLETS)
|
||||
num_options++;
|
||||
|
||||
max_fec_size = (tgt->u.verity.fec_device ? strlen(device_block_path(tgt->u.verity.fec_device)) : 0) + 256;
|
||||
fec_features = crypt_safe_alloc(max_fec_size);
|
||||
@@ -764,13 +695,14 @@ static char *get_dm_verity_params(const struct dm_target *tgt, uint32_t flags)
|
||||
} else
|
||||
*verity_verify_args = '\0';
|
||||
|
||||
if (num_options) { /* MAX length int32 + 18 + 22 + 20 + 19 + 19 */
|
||||
r = snprintf(features, sizeof(features), " %d%s%s%s%s%s", num_options,
|
||||
if (num_options) { /* MAX length int32 + 18 + 22 + 20 + 19 + 19 + 22 */
|
||||
r = snprintf(features, sizeof(features), " %d%s%s%s%s%s%s", num_options,
|
||||
(flags & CRYPT_ACTIVATE_IGNORE_CORRUPTION) ? " ignore_corruption" : "",
|
||||
(flags & CRYPT_ACTIVATE_RESTART_ON_CORRUPTION) ? " restart_on_corruption" : "",
|
||||
(flags & CRYPT_ACTIVATE_PANIC_ON_CORRUPTION) ? " panic_on_corruption" : "",
|
||||
(flags & CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS) ? " ignore_zero_blocks" : "",
|
||||
(flags & CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE) ? " check_at_most_once" : "");
|
||||
(flags & CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE) ? " check_at_most_once" : "",
|
||||
(flags & CRYPT_ACTIVATE_TASKLETS) ? " try_verify_in_tasklet" : "");
|
||||
if (r < 0 || (size_t)r >= sizeof(features))
|
||||
goto out;
|
||||
} else
|
||||
@@ -1399,7 +1331,15 @@ static int _dm_create_device(struct crypt_device *cd, const char *name, const ch
|
||||
goto out;
|
||||
|
||||
if (!dm_task_run(dmt)) {
|
||||
r = dm_status_device(cd, name);;
|
||||
|
||||
r = -dm_task_get_errno(dmt);
|
||||
if (r == -ENOKEY || r == -EKEYREVOKED || r == -EKEYEXPIRED) {
|
||||
/* propagate DM errors around key management as such */
|
||||
r = -ENOKEY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = dm_status_device(cd, name);
|
||||
if (r >= 0)
|
||||
r = -EEXIST;
|
||||
if (r != -EEXIST && r != -ENODEV)
|
||||
@@ -1670,16 +1610,99 @@ int dm_create_device(struct crypt_device *cd, const char *name,
|
||||
return -ENOTSUP;
|
||||
|
||||
r = _dm_create_device(cd, name, type, dmd);
|
||||
|
||||
if (r < 0 && dm_flags(cd, dmd->segment.type, &dmt_flags))
|
||||
if (!r || r == -EEXIST)
|
||||
goto out;
|
||||
|
||||
if (r && (dmd->segment.type == DM_CRYPT || dmd->segment.type == DM_LINEAR || dmd->segment.type == DM_ZERO) &&
|
||||
if (dm_flags(cd, dmd->segment.type, &dmt_flags))
|
||||
goto out;
|
||||
|
||||
if ((dmd->segment.type == DM_CRYPT || dmd->segment.type == DM_LINEAR || dmd->segment.type == DM_ZERO) &&
|
||||
check_retry(cd, &dmd->flags, dmt_flags)) {
|
||||
log_dbg(cd, "Retrying open without incompatible options.");
|
||||
r = _dm_create_device(cd, name, type, dmd);
|
||||
if (!r || r == -EEXIST)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (dmd->flags & (CRYPT_ACTIVATE_SAME_CPU_CRYPT|CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS) &&
|
||||
!(dmt_flags & (DM_SAME_CPU_CRYPT_SUPPORTED|DM_SUBMIT_FROM_CRYPT_CPUS_SUPPORTED))) {
|
||||
log_err(cd, _("Requested dm-crypt performance options are not supported."));
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
||||
if (dmd->flags & (CRYPT_ACTIVATE_NO_READ_WORKQUEUE | CRYPT_ACTIVATE_NO_WRITE_WORKQUEUE) &&
|
||||
!(dmt_flags & DM_CRYPT_NO_WORKQUEUE_SUPPORTED)) {
|
||||
log_err(cd, _("Requested dm-crypt performance options are not supported."));
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
||||
if (dmd->flags & (CRYPT_ACTIVATE_IGNORE_CORRUPTION|
|
||||
CRYPT_ACTIVATE_RESTART_ON_CORRUPTION|
|
||||
CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS|
|
||||
CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE) &&
|
||||
!(dmt_flags & DM_VERITY_ON_CORRUPTION_SUPPORTED)) {
|
||||
log_err(cd, _("Requested dm-verity data corruption handling options are not supported."));
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
||||
if (dmd->flags & CRYPT_ACTIVATE_TASKLETS &&
|
||||
!(dmt_flags & DM_VERITY_TASKLETS_SUPPORTED)) {
|
||||
log_err(cd, _("Requested dm-verity tasklets option is not supported."));
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
||||
if (dmd->flags & CRYPT_ACTIVATE_PANIC_ON_CORRUPTION &&
|
||||
!(dmt_flags & DM_VERITY_PANIC_CORRUPTION_SUPPORTED)) {
|
||||
log_err(cd, _("Requested dm-verity data corruption handling options are not supported."));
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
||||
if (dmd->segment.type == DM_VERITY &&
|
||||
dmd->segment.u.verity.fec_device && !(dmt_flags & DM_VERITY_FEC_SUPPORTED)) {
|
||||
log_err(cd, _("Requested dm-verity FEC options are not supported."));
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
||||
if (dmd->segment.type == DM_CRYPT) {
|
||||
if (dmd->segment.u.crypt.integrity && !(dmt_flags & DM_INTEGRITY_SUPPORTED)) {
|
||||
log_err(cd, _("Requested data integrity options are not supported."));
|
||||
r = -EINVAL;
|
||||
}
|
||||
if (dmd->segment.u.crypt.sector_size != SECTOR_SIZE && !(dmt_flags & DM_SECTOR_SIZE_SUPPORTED)) {
|
||||
log_err(cd, _("Requested sector_size option is not supported."));
|
||||
r = -EINVAL;
|
||||
}
|
||||
if (dmd->segment.u.crypt.sector_size > SECTOR_SIZE &&
|
||||
dmd->size % dmd->segment.u.crypt.sector_size) {
|
||||
log_err(cd, _("The device size is not multiple of the requested sector size."));
|
||||
r = -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (dmd->segment.type == DM_INTEGRITY && (dmd->flags & CRYPT_ACTIVATE_RECALCULATE) &&
|
||||
!(dmt_flags & DM_INTEGRITY_RECALC_SUPPORTED)) {
|
||||
log_err(cd, _("Requested automatic recalculation of integrity tags is not supported."));
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
||||
if (dmd->segment.type == DM_INTEGRITY && (dmd->flags & CRYPT_ACTIVATE_RECALCULATE_RESET) &&
|
||||
!(dmt_flags & DM_INTEGRITY_RESET_RECALC_SUPPORTED)) {
|
||||
log_err(cd, _("Requested automatic recalculation of integrity tags is not supported."));
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
||||
if (dmd->segment.type == DM_INTEGRITY && (dmd->flags & CRYPT_ACTIVATE_ALLOW_DISCARDS) &&
|
||||
!(dmt_flags & DM_INTEGRITY_DISCARDS_SUPPORTED)) {
|
||||
log_err(cd, _("Discard/TRIM is not supported."));
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
||||
if (dmd->segment.type == DM_INTEGRITY && (dmd->flags & CRYPT_ACTIVATE_NO_JOURNAL_BITMAP) &&
|
||||
!(dmt_flags & DM_INTEGRITY_BITMAP_SUPPORTED)) {
|
||||
log_err(cd, _("Requested dm-integrity bitmap mode is not supported."));
|
||||
r = -EINVAL;
|
||||
}
|
||||
out:
|
||||
/*
|
||||
* Print warning if activating dm-crypt cipher_null device unless it's reencryption helper or
|
||||
* keyslot encryption helper device (LUKS1 cipher_null devices).
|
||||
@@ -1688,54 +1711,6 @@ int dm_create_device(struct crypt_device *cd, const char *name,
|
||||
crypt_is_cipher_null(dmd->segment.u.crypt.cipher))
|
||||
log_dbg(cd, "Activated dm-crypt device with cipher_null. Device is not encrypted.");
|
||||
|
||||
if (r == -EINVAL &&
|
||||
dmd->flags & (CRYPT_ACTIVATE_SAME_CPU_CRYPT|CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS) &&
|
||||
!(dmt_flags & (DM_SAME_CPU_CRYPT_SUPPORTED|DM_SUBMIT_FROM_CRYPT_CPUS_SUPPORTED)))
|
||||
log_err(cd, _("Requested dm-crypt performance options are not supported."));
|
||||
|
||||
if (r == -EINVAL &&
|
||||
dmd->flags & (CRYPT_ACTIVATE_NO_READ_WORKQUEUE | CRYPT_ACTIVATE_NO_WRITE_WORKQUEUE) &&
|
||||
!(dmt_flags & DM_CRYPT_NO_WORKQUEUE_SUPPORTED))
|
||||
log_err(cd, _("Requested dm-crypt performance options are not supported."));
|
||||
|
||||
if (r == -EINVAL && dmd->flags & (CRYPT_ACTIVATE_IGNORE_CORRUPTION|
|
||||
CRYPT_ACTIVATE_RESTART_ON_CORRUPTION|
|
||||
CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS|
|
||||
CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE) &&
|
||||
!(dmt_flags & DM_VERITY_ON_CORRUPTION_SUPPORTED))
|
||||
log_err(cd, _("Requested dm-verity data corruption handling options are not supported."));
|
||||
|
||||
if (r == -EINVAL && dmd->flags & CRYPT_ACTIVATE_PANIC_ON_CORRUPTION &&
|
||||
!(dmt_flags & DM_VERITY_PANIC_CORRUPTION_SUPPORTED))
|
||||
log_err(cd, _("Requested dm-verity data corruption handling options are not supported."));
|
||||
|
||||
if (r == -EINVAL && dmd->segment.type == DM_VERITY &&
|
||||
dmd->segment.u.verity.fec_device && !(dmt_flags & DM_VERITY_FEC_SUPPORTED))
|
||||
log_err(cd, _("Requested dm-verity FEC options are not supported."));
|
||||
|
||||
if (r == -EINVAL && dmd->segment.type == DM_CRYPT) {
|
||||
if (dmd->segment.u.crypt.integrity && !(dmt_flags & DM_INTEGRITY_SUPPORTED))
|
||||
log_err(cd, _("Requested data integrity options are not supported."));
|
||||
if (dmd->segment.u.crypt.sector_size != SECTOR_SIZE && !(dmt_flags & DM_SECTOR_SIZE_SUPPORTED))
|
||||
log_err(cd, _("Requested sector_size option is not supported."));
|
||||
}
|
||||
|
||||
if (r == -EINVAL && dmd->segment.type == DM_INTEGRITY && (dmd->flags & CRYPT_ACTIVATE_RECALCULATE) &&
|
||||
!(dmt_flags & DM_INTEGRITY_RECALC_SUPPORTED))
|
||||
log_err(cd, _("Requested automatic recalculation of integrity tags is not supported."));
|
||||
|
||||
if (r == -EINVAL && dmd->segment.type == DM_INTEGRITY && (dmd->flags & CRYPT_ACTIVATE_RECALCULATE_RESET) &&
|
||||
!(dmt_flags & DM_INTEGRITY_RESET_RECALC_SUPPORTED))
|
||||
log_err(cd, _("Requested automatic recalculation of integrity tags is not supported."));
|
||||
|
||||
if (r == -EINVAL && dmd->segment.type == DM_INTEGRITY && (dmd->flags & CRYPT_ACTIVATE_ALLOW_DISCARDS) &&
|
||||
!(dmt_flags & DM_INTEGRITY_DISCARDS_SUPPORTED))
|
||||
log_err(cd, _("Discard/TRIM is not supported."));
|
||||
|
||||
if (r == -EINVAL && dmd->segment.type == DM_INTEGRITY && (dmd->flags & CRYPT_ACTIVATE_NO_JOURNAL_BITMAP) &&
|
||||
!(dmt_flags & DM_INTEGRITY_BITMAP_SUPPORTED))
|
||||
log_err(cd, _("Requested dm-integrity bitmap mode is not supported."));
|
||||
out:
|
||||
dm_exit_context();
|
||||
return r;
|
||||
}
|
||||
@@ -2030,9 +2005,7 @@ static int _dm_target_query_crypt(struct crypt_device *cd, uint32_t get_flags,
|
||||
|
||||
/* cipher */
|
||||
if (get_flags & DM_ACTIVE_CRYPT_CIPHER) {
|
||||
r = cipher_dm2c(CONST_CAST(char**)&cipher,
|
||||
CONST_CAST(char**)&integrity,
|
||||
rcipher, rintegrity);
|
||||
r = crypt_capi_to_cipher(&cipher, &integrity, rcipher, rintegrity);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
}
|
||||
@@ -2265,6 +2238,8 @@ static int _dm_target_query_verity(struct crypt_device *cd,
|
||||
*act_flags |= CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS;
|
||||
else if (!strcasecmp(arg, "check_at_most_once"))
|
||||
*act_flags |= CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE;
|
||||
else if (!strcasecmp(arg, "try_verify_in_tasklet"))
|
||||
*act_flags |= CRYPT_ACTIVATE_TASKLETS;
|
||||
else if (!strcasecmp(arg, "use_fec_from_device")) {
|
||||
str = strsep(¶ms, " ");
|
||||
str2 = crypt_lookup_dev(str);
|
||||
@@ -2736,7 +2711,7 @@ static int _dm_query_device(struct crypt_device *cd, const char *name,
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Never allow to return empty key */
|
||||
/* Never allow one to return empty key */
|
||||
if ((get_flags & DM_ACTIVE_CRYPT_KEY) && dmi.suspended) {
|
||||
log_dbg(cd, "Cannot read volume key while suspended.");
|
||||
r = -EINVAL;
|
||||
@@ -2818,7 +2793,8 @@ int dm_query_device(struct crypt_device *cd, const char *name,
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _process_deps(struct crypt_device *cd, const char *prefix, struct dm_deps *deps, char **names, size_t names_offset, size_t names_length)
|
||||
static int _process_deps(struct crypt_device *cd, const char *prefix, struct dm_deps *deps,
|
||||
char **names, size_t names_offset, size_t names_length)
|
||||
{
|
||||
#if HAVE_DECL_DM_DEVICE_GET_NAME
|
||||
struct crypt_dm_active_device dmd;
|
||||
@@ -2864,7 +2840,8 @@ static int _process_deps(struct crypt_device *cd, const char *prefix, struct dm_
|
||||
#endif
|
||||
}
|
||||
|
||||
int dm_device_deps(struct crypt_device *cd, const char *name, const char *prefix, char **names, size_t names_length)
|
||||
int dm_device_deps(struct crypt_device *cd, const char *name, const char *prefix,
|
||||
char **names, size_t names_length)
|
||||
{
|
||||
struct dm_task *dmt;
|
||||
struct dm_info dmi;
|
||||
@@ -3026,7 +3003,8 @@ int dm_resume_and_reinstate_key(struct crypt_device *cd, const char *name,
|
||||
}
|
||||
|
||||
if (vk->key_description) {
|
||||
r = snprintf(msg, msg_size, "key set :%zu:logon:%s", vk->keylength, 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) {
|
||||
@@ -3063,6 +3041,18 @@ const char *dm_get_dir(void)
|
||||
return dm_dir();
|
||||
}
|
||||
|
||||
int dm_get_iname(const char *name, char **iname, bool with_path)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (with_path)
|
||||
r = asprintf(iname, "%s/%s_dif", dm_get_dir(), name);
|
||||
else
|
||||
r = asprintf(iname, "%s_dif", name);
|
||||
|
||||
return r < 0 ? -ENOMEM : 0;
|
||||
}
|
||||
|
||||
int dm_is_dm_device(int major)
|
||||
{
|
||||
return dm_is_dm_major((uint32_t)major);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* loop-AES compatible volume handling
|
||||
*
|
||||
* Copyright (C) 2011-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2011-2022 Milan Broz
|
||||
* Copyright (C) 2011-2023 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2011-2023 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* loop-AES compatible volume handling
|
||||
*
|
||||
* Copyright (C) 2011-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2011-2022 Milan Broz
|
||||
* Copyright (C) 2011-2023 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2011-2023 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* AFsplitter - Anti forensic information splitter
|
||||
*
|
||||
* Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2023 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* AFsplitter diffuses information over a large stripe of data,
|
||||
* therefore supporting secure data destruction.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* AFsplitter - Anti forensic information splitter
|
||||
*
|
||||
* Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2023 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* AFsplitter diffuses information over a large stripe of data,
|
||||
* therefore supporting secure data destruction.
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
* LUKS - Linux Unified Key Setup
|
||||
*
|
||||
* Copyright (C) 2004-2006 Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2012-2022 Milan Broz
|
||||
* Copyright (C) 2009-2023 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2012-2023 Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
* LUKS - Linux Unified Key Setup
|
||||
*
|
||||
* Copyright (C) 2004-2006 Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2013-2022 Milan Broz
|
||||
* Copyright (C) 2009-2023 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2013-2023 Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -28,8 +28,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include <uuid/uuid.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "luks.h"
|
||||
#include "af.h"
|
||||
@@ -232,11 +232,12 @@ int LUKS_hdr_backup(const char *backup_file, struct crypt_device *ctx)
|
||||
hdr_size = LUKS_device_sectors(&hdr) << SECTOR_SHIFT;
|
||||
buffer_size = size_round_up(hdr_size, crypt_getpagesize());
|
||||
|
||||
buffer = crypt_safe_alloc(buffer_size);
|
||||
buffer = malloc(buffer_size);
|
||||
if (!buffer || hdr_size < LUKS_ALIGN_KEYSLOTS || hdr_size > buffer_size) {
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
memset(buffer, 0, buffer_size);
|
||||
|
||||
log_dbg(ctx, "Storing backup of header (%zu bytes) and keyslot area (%zu bytes).",
|
||||
sizeof(hdr), hdr_size - LUKS_ALIGN_KEYSLOTS);
|
||||
@@ -280,7 +281,8 @@ int LUKS_hdr_backup(const char *backup_file, struct crypt_device *ctx)
|
||||
r = 0;
|
||||
out:
|
||||
crypt_safe_memzero(&hdr, sizeof(hdr));
|
||||
crypt_safe_free(buffer);
|
||||
crypt_safe_memzero(buffer, buffer_size);
|
||||
free(buffer);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -308,7 +310,7 @@ int LUKS_hdr_restore(
|
||||
goto out;
|
||||
}
|
||||
|
||||
buffer = crypt_safe_alloc(buffer_size);
|
||||
buffer = malloc(buffer_size);
|
||||
if (!buffer) {
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
@@ -379,7 +381,8 @@ int LUKS_hdr_restore(
|
||||
r = LUKS_read_phdr(hdr, 1, 0, ctx);
|
||||
out:
|
||||
device_sync(ctx, device);
|
||||
crypt_safe_free(buffer);
|
||||
crypt_safe_memzero(buffer, buffer_size);
|
||||
free(buffer);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -922,8 +925,12 @@ int LUKS_set_key(unsigned int keyIndex,
|
||||
hdr->keyblock[keyIndex].passwordSalt, LUKS_SALTSIZE,
|
||||
derived_key->key, hdr->keyBytes,
|
||||
hdr->keyblock[keyIndex].passwordIterations, 0, 0);
|
||||
if (r < 0)
|
||||
if (r < 0) {
|
||||
if ((crypt_backend_flags() & CRYPT_BACKEND_PBKDF2_INT) &&
|
||||
hdr->keyblock[keyIndex].passwordIterations > INT_MAX)
|
||||
log_err(ctx, _("PBKDF2 iteration value overflow."));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* AF splitting, the volume key stored in vk->key is split to AfKey
|
||||
@@ -1227,6 +1234,10 @@ int LUKS_wipe_header_areas(struct luks_phdr *hdr,
|
||||
uint64_t offset, length;
|
||||
size_t wipe_block;
|
||||
|
||||
r = LUKS_check_device_size(ctx, hdr, 1);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
/* Wipe complete header, keyslots and padding areas with zeroes. */
|
||||
offset = 0;
|
||||
length = (uint64_t)hdr->payloadOffset * SECTOR_SIZE;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* LUKS - Linux Unified Key Setup
|
||||
*
|
||||
* Copyright (C) 2004-2006 Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2023 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
|
||||
|
||||
997
lib/luks2/hw_opal/hw_opal.c
Normal file
997
lib/luks2/hw_opal/hw_opal.c
Normal file
@@ -0,0 +1,997 @@
|
||||
/*
|
||||
* OPAL utilities
|
||||
*
|
||||
* Copyright (C) 2022-2023 Luca Boccassi <bluca@debian.org>
|
||||
* 2023 Ondrej Kozina <okozina@redhat.com>
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "libcryptsetup.h"
|
||||
#include "luks2/hw_opal/hw_opal.h"
|
||||
|
||||
#if HAVE_HW_OPAL
|
||||
|
||||
#include <linux/sed-opal.h>
|
||||
|
||||
/* Error codes are defined in the specification:
|
||||
* TCG_Storage_Architecture_Core_Spec_v2.01_r1.00
|
||||
* Section 5.1.5: Method Status Codes
|
||||
* Names and values from table 166 */
|
||||
typedef enum OpalStatus {
|
||||
OPAL_STATUS_SUCCESS,
|
||||
OPAL_STATUS_NOT_AUTHORIZED,
|
||||
OPAL_STATUS_OBSOLETE0, /* Undefined but possible return values are called 'obsolete' */
|
||||
OPAL_STATUS_SP_BUSY,
|
||||
OPAL_STATUS_SP_FAILED,
|
||||
OPAL_STATUS_SP_DISABLED,
|
||||
OPAL_STATUS_SP_FROZEN,
|
||||
OPAL_STATUS_NO_SESSIONS_AVAILABLE,
|
||||
OPAL_STATUS_UNIQUENESS_CONFLICT,
|
||||
OPAL_STATUS_INSUFFICIENT_SPACE,
|
||||
OPAL_STATUS_INSUFFICIENT_ROWS,
|
||||
OPAL_STATUS_INVALID_PARAMETER,
|
||||
OPAL_STATUS_OBSOLETE1,
|
||||
OPAL_STATUS_OBSOLETE2,
|
||||
OPAL_STATUS_TPER_MALFUNCTION,
|
||||
OPAL_STATUS_TRANSACTION_FAILURE,
|
||||
OPAL_STATUS_RESPONSE_OVERFLOW,
|
||||
OPAL_STATUS_AUTHORITY_LOCKED_OUT,
|
||||
OPAL_STATUS_FAIL = 0x3F, /* As defined by specification */
|
||||
_OPAL_STATUS_MAX,
|
||||
_OPAL_STATUS_INVALID = -EINVAL,
|
||||
} OpalStatus;
|
||||
|
||||
static const char* const opal_status_table[_OPAL_STATUS_MAX] = {
|
||||
[OPAL_STATUS_SUCCESS] = "success",
|
||||
[OPAL_STATUS_NOT_AUTHORIZED] = "not authorized",
|
||||
[OPAL_STATUS_OBSOLETE0] = "obsolete",
|
||||
[OPAL_STATUS_SP_BUSY] = "SP busy",
|
||||
[OPAL_STATUS_SP_FAILED] = "SP failed",
|
||||
[OPAL_STATUS_SP_DISABLED] = "SP disabled",
|
||||
[OPAL_STATUS_SP_FROZEN] = "SP frozen",
|
||||
[OPAL_STATUS_NO_SESSIONS_AVAILABLE] = "no sessions available",
|
||||
[OPAL_STATUS_UNIQUENESS_CONFLICT] = "uniqueness conflict",
|
||||
[OPAL_STATUS_INSUFFICIENT_SPACE] = "insufficient space",
|
||||
[OPAL_STATUS_INSUFFICIENT_ROWS] = "insufficient rows",
|
||||
[OPAL_STATUS_INVALID_PARAMETER] = "invalid parameter",
|
||||
[OPAL_STATUS_OBSOLETE1] = "obsolete",
|
||||
[OPAL_STATUS_OBSOLETE2] = "obsolete",
|
||||
[OPAL_STATUS_TPER_MALFUNCTION] = "TPer malfunction",
|
||||
[OPAL_STATUS_TRANSACTION_FAILURE] = "transaction failure",
|
||||
[OPAL_STATUS_RESPONSE_OVERFLOW] = "response overflow",
|
||||
[OPAL_STATUS_AUTHORITY_LOCKED_OUT] = "authority locked out",
|
||||
[OPAL_STATUS_FAIL] = "unknown failure",
|
||||
};
|
||||
|
||||
static const char *opal_status_to_string(int t)
|
||||
{
|
||||
if (t < 0)
|
||||
return strerror(-t);
|
||||
|
||||
if (t >= _OPAL_STATUS_MAX)
|
||||
return "unknown error";
|
||||
|
||||
return opal_status_table[t];
|
||||
}
|
||||
|
||||
static const char *opal_ioctl_to_string(unsigned long rq)
|
||||
{
|
||||
switch(rq) {
|
||||
case IOC_OPAL_GET_STATUS: return "GET_STATUS";
|
||||
case IOC_OPAL_GET_GEOMETRY: return "GET_GEOMETRY";
|
||||
case IOC_OPAL_GET_LR_STATUS: return "GET_LR_STATUS";
|
||||
case IOC_OPAL_TAKE_OWNERSHIP: return "TAKE_OWNERSHIP";
|
||||
case IOC_OPAL_ACTIVATE_USR: return "ACTIVATE_USR";
|
||||
case IOC_OPAL_ACTIVATE_LSP: return "ACTIVATE_LSP";
|
||||
case IOC_OPAL_ERASE_LR: return "ERASE_LR";
|
||||
case IOC_OPAL_SECURE_ERASE_LR: return "SECURE_ERASE_LR";
|
||||
case IOC_OPAL_ADD_USR_TO_LR: return "ADD_USR_TO_LR";
|
||||
case IOC_OPAL_SET_PW: return "SET_PW";
|
||||
case IOC_OPAL_LR_SETUP: return "LR_SETUP";
|
||||
case IOC_OPAL_LOCK_UNLOCK: return "LOCK_UNLOCK";
|
||||
case IOC_OPAL_SAVE: return "SAVE";
|
||||
case IOC_OPAL_PSID_REVERT_TPR: return "PSID_REVERT_TPR";
|
||||
}
|
||||
|
||||
assert(false && "unknown OPAL ioctl");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void opal_ioctl_debug(struct crypt_device *cd,
|
||||
unsigned long rq,
|
||||
void *args,
|
||||
bool post,
|
||||
int ret)
|
||||
{
|
||||
const char *cmd = opal_ioctl_to_string(rq);
|
||||
|
||||
if (ret) {
|
||||
log_dbg(cd, "OPAL %s failed: %s", cmd, opal_status_to_string(ret));
|
||||
return;
|
||||
}
|
||||
|
||||
if (post) switch(rq) {
|
||||
case IOC_OPAL_GET_STATUS: { /* OUT */
|
||||
struct opal_status *st = args;
|
||||
log_dbg(cd, "OPAL %s: flags:%" PRIu32, cmd, st->flags);
|
||||
};
|
||||
break;
|
||||
case IOC_OPAL_GET_GEOMETRY: { /* OUT */
|
||||
struct opal_geometry *geo = args;
|
||||
log_dbg(cd, "OPAL %s: align:%" PRIu8 ", lb_size:%" PRIu32 ", gran:%" PRIu64 ", lowest_lba:%" PRIu64,
|
||||
cmd, geo->align, geo->logical_block_size, geo->alignment_granularity, geo->lowest_aligned_lba);
|
||||
};
|
||||
break;
|
||||
case IOC_OPAL_GET_LR_STATUS: { /* OUT */
|
||||
struct opal_lr_status *lrs = args;
|
||||
log_dbg(cd, "OPAL %s: sum:%" PRIu32 ", who:%" PRIu32 ", lr:%" PRIu8
|
||||
", start:%" PRIu64 ", length:%" PRIu64 ", rle:%" PRIu32 ", rwe:%" PRIu32 ", state:%" PRIu32,
|
||||
cmd, lrs->session.sum, lrs->session.who, lrs->session.opal_key.lr,
|
||||
lrs->range_start, lrs->range_length, lrs->RLE, lrs->WLE, lrs->l_state);
|
||||
};
|
||||
break;
|
||||
} else switch (rq) {
|
||||
case IOC_OPAL_TAKE_OWNERSHIP: { /* IN */
|
||||
log_dbg(cd, "OPAL %s", cmd);
|
||||
};
|
||||
break;
|
||||
case IOC_OPAL_ACTIVATE_USR: { /* IN */
|
||||
struct opal_session_info *ui = args;
|
||||
log_dbg(cd, "OPAL %s: sum:%" PRIu32 ", who:%" PRIu32 ", lr:%" PRIu8,
|
||||
cmd, ui->sum, ui->who, ui->opal_key.lr);
|
||||
};
|
||||
break;
|
||||
case IOC_OPAL_ACTIVATE_LSP: { /* IN */
|
||||
struct opal_lr_act *act = args;
|
||||
log_dbg(cd, "OPAL %s: k.lr:%" PRIu8 ", sum:%" PRIu32 ", num_lrs:%" PRIu8 ", lr:"
|
||||
"%"PRIu8"|%"PRIu8"|%"PRIu8"|%"PRIu8"|%"PRIu8"|%"PRIu8"|%"PRIu8"|%"PRIu8"|%"PRIu8,
|
||||
cmd, act->key.lr, act->sum, act->num_lrs,
|
||||
act->lr[0], act->lr[1], act->lr[2], act->lr[3], act->lr[4],
|
||||
act->lr[5], act->lr[6], act->lr[7], act->lr[8]);
|
||||
};
|
||||
break;
|
||||
case IOC_OPAL_ERASE_LR: { /* IN */
|
||||
struct opal_session_info *ui = args;
|
||||
log_dbg(cd, "OPAL %s: sum:%" PRIu32 ", who:%" PRIu32 ", lr:%" PRIu8,
|
||||
cmd, ui->sum, ui->who, ui->opal_key.lr);
|
||||
};
|
||||
break;
|
||||
case IOC_OPAL_SECURE_ERASE_LR: { /* IN */
|
||||
struct opal_session_info *ui = args;
|
||||
log_dbg(cd, "OPAL %s: sum:%" PRIu32 ", who:%" PRIu32 ", lr:%" PRIu8,
|
||||
cmd, ui->sum, ui->who, ui->opal_key.lr);
|
||||
};
|
||||
break;
|
||||
case IOC_OPAL_ADD_USR_TO_LR: { /* IN */
|
||||
struct opal_lock_unlock *lu = args;
|
||||
log_dbg(cd, "OPAL %s: sum:%" PRIu32 ", who:%" PRIu32 ", lr:%" PRIu8
|
||||
", l_state:%" PRIu32 ", flags:%" PRIu16,
|
||||
cmd, lu->session.sum, lu->session.who, lu->session.opal_key.lr,
|
||||
lu->l_state, lu->flags);
|
||||
};
|
||||
break;
|
||||
case IOC_OPAL_SET_PW: { /* IN */
|
||||
struct opal_new_pw *pw = args;
|
||||
log_dbg(cd, "OPAL %s: sum:%" PRIu32 ", who:%" PRIu32 ", lr:%" PRIu8,
|
||||
cmd, pw->session.sum, pw->session.who, pw->session.opal_key.lr);
|
||||
};
|
||||
break;
|
||||
case IOC_OPAL_LR_SETUP: { /* IN */
|
||||
struct opal_user_lr_setup *lrs = args;
|
||||
log_dbg(cd, "OPAL %s: sum:%" PRIu32 ", who:%" PRIu32 ", lr:%" PRIu8
|
||||
", start:%" PRIu64 ", length:%" PRIu64 ", rle:%" PRIu32 ", rwe:%" PRIu32,
|
||||
cmd, lrs->session.sum, lrs->session.who, lrs->session.opal_key.lr,
|
||||
lrs->range_start, lrs->range_length, lrs->RLE, lrs->WLE);
|
||||
};
|
||||
break;
|
||||
case IOC_OPAL_LOCK_UNLOCK: { /* IN */
|
||||
struct opal_lock_unlock *lu = args;
|
||||
log_dbg(cd, "OPAL %s: sum:%" PRIu32 ", who:%" PRIu32 ", lr:%" PRIu8
|
||||
", l_state:%" PRIu32 ", flags:%" PRIu16,
|
||||
cmd, lu->session.sum, lu->session.who, lu->session.opal_key.lr,
|
||||
lu->l_state, lu->flags);
|
||||
};
|
||||
break;
|
||||
case IOC_OPAL_SAVE: { /* IN */
|
||||
struct opal_lock_unlock *lu = args;
|
||||
log_dbg(cd, "OPAL %s: sum:%" PRIu32 ", who:%" PRIu32 ", lr:%" PRIu8
|
||||
", l_state:%" PRIu32 ", flags:%" PRIu16,
|
||||
cmd, lu->session.sum, lu->session.who, lu->session.opal_key.lr,
|
||||
lu->l_state, lu->flags);
|
||||
};
|
||||
break;
|
||||
case IOC_OPAL_PSID_REVERT_TPR: { /* IN */
|
||||
struct opal_key *key = args;
|
||||
log_dbg(cd, "OPAL %s: lr:%" PRIu8,
|
||||
cmd, key->lr);
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int opal_ioctl(struct crypt_device *cd, int fd, unsigned long rq, void *args)
|
||||
{
|
||||
int r;
|
||||
|
||||
opal_ioctl_debug(cd, rq, args, false, 0);
|
||||
r = ioctl(fd, rq, args);
|
||||
opal_ioctl_debug(cd, rq, args, true, r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int opal_geometry_fd(struct crypt_device *cd,
|
||||
int fd,
|
||||
bool *ret_align,
|
||||
uint32_t *ret_block_size,
|
||||
uint64_t *ret_alignment_granularity_blocks,
|
||||
uint64_t *ret_lowest_lba_blocks)
|
||||
{
|
||||
int r;
|
||||
struct opal_geometry geo;
|
||||
|
||||
assert(fd >= 0);
|
||||
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_GET_GEOMETRY, &geo);
|
||||
if (r != OPAL_STATUS_SUCCESS)
|
||||
return r;
|
||||
|
||||
if (ret_align)
|
||||
*ret_align = (geo.align == 1);
|
||||
if (ret_block_size)
|
||||
*ret_block_size = geo.logical_block_size;
|
||||
if (ret_alignment_granularity_blocks)
|
||||
*ret_alignment_granularity_blocks = geo.alignment_granularity;
|
||||
if (ret_lowest_lba_blocks)
|
||||
*ret_lowest_lba_blocks = geo.lowest_aligned_lba;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int opal_range_check_attributes_fd(struct crypt_device *cd,
|
||||
int fd,
|
||||
uint32_t segment_number,
|
||||
const struct volume_key *vk,
|
||||
const uint64_t *check_offset_sectors,
|
||||
const uint64_t *check_length_sectors,
|
||||
bool *check_read_locked,
|
||||
bool *check_write_locked)
|
||||
{
|
||||
int r;
|
||||
struct opal_lr_status *lrs;
|
||||
uint32_t opal_block_bytes;
|
||||
uint64_t offset, length;
|
||||
bool read_locked, write_locked;
|
||||
|
||||
assert(fd >= 0);
|
||||
assert(cd);
|
||||
assert(vk);
|
||||
|
||||
r = opal_geometry_fd(cd, fd, NULL, &opal_block_bytes, NULL, NULL);
|
||||
if (r != OPAL_STATUS_SUCCESS)
|
||||
return -EINVAL;
|
||||
|
||||
lrs = crypt_safe_alloc(sizeof(*lrs));
|
||||
if (!lrs) {
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*lrs = (struct opal_lr_status) {
|
||||
.session = {
|
||||
.who = segment_number + 1,
|
||||
.opal_key = {
|
||||
.key_len = vk->keylength,
|
||||
.lr = segment_number
|
||||
}
|
||||
}
|
||||
};
|
||||
memcpy(lrs->session.opal_key.key, vk->key, vk->keylength);
|
||||
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_GET_LR_STATUS, lrs);
|
||||
if (r != OPAL_STATUS_SUCCESS) {
|
||||
log_dbg(cd, "Failed to get locking range status on device '%s'.",
|
||||
crypt_get_device_name(cd));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = 0;
|
||||
|
||||
offset = lrs->range_start * opal_block_bytes / SECTOR_SIZE;
|
||||
if (check_offset_sectors && (offset != *check_offset_sectors)) {
|
||||
log_err(cd, _("OPAL range %d offset %" PRIu64 " does not match expected values %" PRIu64 "."),
|
||||
segment_number, offset, *check_offset_sectors);
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
||||
length = lrs->range_length * opal_block_bytes / SECTOR_SIZE;
|
||||
if (check_length_sectors && (length != *check_length_sectors)) {
|
||||
log_err(cd, _("OPAL range %d length %" PRIu64" does not match device length %" PRIu64 "."),
|
||||
segment_number, length, *check_length_sectors);
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
||||
if (!lrs->RLE || !lrs->WLE) {
|
||||
log_err(cd, _("OPAL range %d locking is disabled."), segment_number);
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
||||
read_locked = (lrs->l_state == OPAL_LK);
|
||||
write_locked = !!(lrs->l_state & (OPAL_RO | OPAL_LK));
|
||||
|
||||
if (check_read_locked && (read_locked != *check_read_locked)) {
|
||||
log_dbg(cd, "OPAL range %d read lock is %slocked.",
|
||||
segment_number, *check_read_locked ? "" : "not ");
|
||||
log_err(cd, _("Unexpected OPAL range %d lock state."), segment_number);
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
||||
if (check_write_locked && (write_locked != *check_write_locked)) {
|
||||
log_dbg(cd, "OPAL range %d write lock is %slocked.",
|
||||
segment_number, *check_write_locked ? "" : "not ");
|
||||
log_err(cd, _("Unexpected OPAL range %d lock state."), segment_number);
|
||||
r = -EINVAL;
|
||||
}
|
||||
out:
|
||||
crypt_safe_free(lrs);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int opal_setup_ranges(struct crypt_device *cd,
|
||||
struct device *dev,
|
||||
const struct volume_key *vk,
|
||||
uint64_t range_start,
|
||||
uint64_t range_length,
|
||||
uint32_t segment_number,
|
||||
const void *admin_key,
|
||||
size_t admin_key_len)
|
||||
{
|
||||
struct opal_lr_act *activate = NULL;
|
||||
struct opal_session_info *user_session = NULL;
|
||||
struct opal_lock_unlock *user_add_to_lr = NULL, *lock = NULL;
|
||||
struct opal_new_pw *new_pw = NULL;
|
||||
struct opal_user_lr_setup *setup = NULL;
|
||||
int r, fd;
|
||||
|
||||
assert(cd);
|
||||
assert(dev);
|
||||
assert(vk);
|
||||
assert(admin_key);
|
||||
assert(vk->keylength <= OPAL_KEY_MAX);
|
||||
|
||||
if (admin_key_len > OPAL_KEY_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
fd = device_open(cd, dev, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return -EIO;
|
||||
|
||||
r = opal_enabled(cd, dev);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* If OPAL has never been enabled, we need to take ownership and do basic setup first */
|
||||
if (r == 0) {
|
||||
activate = crypt_safe_alloc(sizeof(struct opal_lr_act));
|
||||
if (!activate) {
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
*activate = (struct opal_lr_act) {
|
||||
.key = {
|
||||
.key_len = admin_key_len,
|
||||
},
|
||||
.num_lrs = 8,
|
||||
/* A max of 9 segments are supported, enable them all as there's no reason not to
|
||||
* (0 is whole-volume)
|
||||
*/
|
||||
.lr = { 1, 2, 3, 4, 5, 6, 7, 8 },
|
||||
};
|
||||
memcpy(activate->key.key, admin_key, admin_key_len);
|
||||
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_TAKE_OWNERSHIP, &activate->key);
|
||||
if (r < 0) {
|
||||
r = -ENOTSUP;
|
||||
log_dbg(cd, "OPAL not supported on this kernel version, refusing.");
|
||||
goto out;
|
||||
}
|
||||
if (r == OPAL_STATUS_NOT_AUTHORIZED) /* We'll try again with a different key. */ {
|
||||
r = -EPERM;
|
||||
log_dbg(cd, "Failed to take ownership of OPAL device '%s': permission denied",
|
||||
crypt_get_device_name(cd));
|
||||
goto out;
|
||||
}
|
||||
if (r != OPAL_STATUS_SUCCESS) {
|
||||
log_dbg(cd, "Failed to take ownership of OPAL device '%s': %s",
|
||||
crypt_get_device_name(cd), opal_status_to_string(r));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_ACTIVATE_LSP, activate);
|
||||
if (r != OPAL_STATUS_SUCCESS) {
|
||||
log_dbg(cd, "Failed to activate OPAL device '%s': %s",
|
||||
crypt_get_device_name(cd), opal_status_to_string(r));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
/* If it is already enabled, wipe the locking range first */
|
||||
user_session = crypt_safe_alloc(sizeof(struct opal_session_info));
|
||||
if (!user_session) {
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
*user_session = (struct opal_session_info) {
|
||||
.who = OPAL_ADMIN1,
|
||||
.opal_key = {
|
||||
.lr = segment_number,
|
||||
.key_len = admin_key_len,
|
||||
},
|
||||
};
|
||||
memcpy(user_session->opal_key.key, admin_key, admin_key_len);
|
||||
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_ERASE_LR, user_session);
|
||||
if (r != OPAL_STATUS_SUCCESS) {
|
||||
log_dbg(cd, "Failed to reset (erase) OPAL locking range %u on device '%s': %s",
|
||||
segment_number, crypt_get_device_name(cd), opal_status_to_string(r));
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_SECURE_ERASE_LR, user_session);
|
||||
if (r != OPAL_STATUS_SUCCESS) {
|
||||
log_dbg(cd, "Failed to reset (secure erase) OPAL locking range %u on device '%s': %s",
|
||||
segment_number, crypt_get_device_name(cd), opal_status_to_string(r));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
crypt_safe_free(user_session);
|
||||
|
||||
user_session = crypt_safe_alloc(sizeof(struct opal_session_info));
|
||||
if (!user_session) {
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
*user_session = (struct opal_session_info) {
|
||||
.who = segment_number + 1,
|
||||
.opal_key = {
|
||||
.key_len = admin_key_len,
|
||||
},
|
||||
};
|
||||
memcpy(user_session->opal_key.key, admin_key, admin_key_len);
|
||||
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_ACTIVATE_USR, user_session);
|
||||
if (r != OPAL_STATUS_SUCCESS) {
|
||||
log_dbg(cd, "Failed to activate OPAL user on device '%s': %s",
|
||||
crypt_get_device_name(cd), opal_status_to_string(r));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
user_add_to_lr = crypt_safe_alloc(sizeof(struct opal_lock_unlock));
|
||||
if (!user_add_to_lr) {
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
*user_add_to_lr = (struct opal_lock_unlock) {
|
||||
.session = {
|
||||
.who = segment_number + 1,
|
||||
.opal_key = {
|
||||
.lr = segment_number,
|
||||
.key_len = admin_key_len,
|
||||
},
|
||||
},
|
||||
.l_state = OPAL_RO,
|
||||
};
|
||||
memcpy(user_add_to_lr->session.opal_key.key, admin_key, admin_key_len);
|
||||
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_ADD_USR_TO_LR, user_add_to_lr);
|
||||
if (r != OPAL_STATUS_SUCCESS) {
|
||||
log_dbg(cd, "Failed to add OPAL user to locking range %u (RO) on device '%s': %s",
|
||||
segment_number, crypt_get_device_name(cd), opal_status_to_string(r));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
user_add_to_lr->l_state = OPAL_RW;
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_ADD_USR_TO_LR, user_add_to_lr);
|
||||
if (r != OPAL_STATUS_SUCCESS) {
|
||||
log_dbg(cd, "Failed to add OPAL user to locking range %u (RW) on device '%s': %s",
|
||||
segment_number, crypt_get_device_name(cd), opal_status_to_string(r));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
new_pw = crypt_safe_alloc(sizeof(struct opal_new_pw));
|
||||
if (!new_pw) {
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
*new_pw = (struct opal_new_pw) {
|
||||
.session = {
|
||||
.who = OPAL_ADMIN1,
|
||||
.opal_key = {
|
||||
.lr = segment_number,
|
||||
.key_len = admin_key_len,
|
||||
},
|
||||
},
|
||||
.new_user_pw = {
|
||||
.who = segment_number + 1,
|
||||
.opal_key = {
|
||||
.key_len = vk->keylength,
|
||||
.lr = segment_number,
|
||||
},
|
||||
},
|
||||
};
|
||||
memcpy(new_pw->new_user_pw.opal_key.key, vk->key, vk->keylength);
|
||||
memcpy(new_pw->session.opal_key.key, admin_key, admin_key_len);
|
||||
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_SET_PW, new_pw);
|
||||
if (r != OPAL_STATUS_SUCCESS) {
|
||||
log_dbg(cd, "Failed to set OPAL user password on device '%s': (%d) %s",
|
||||
crypt_get_device_name(cd), r, opal_status_to_string(r));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
setup = crypt_safe_alloc(sizeof(struct opal_user_lr_setup));
|
||||
if (!setup) {
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
*setup = (struct opal_user_lr_setup) {
|
||||
.range_start = range_start,
|
||||
.range_length = range_length,
|
||||
/* Some drives do not enable Locking Ranges on setup. This have some
|
||||
* interesting consequences: Lock command called later below will pass,
|
||||
* but locking range will _not_ be locked at all.
|
||||
*/
|
||||
.RLE = 1,
|
||||
.WLE = 1,
|
||||
.session = {
|
||||
.who = OPAL_ADMIN1,
|
||||
.opal_key = {
|
||||
.key_len = admin_key_len,
|
||||
.lr = segment_number,
|
||||
},
|
||||
},
|
||||
};
|
||||
memcpy(setup->session.opal_key.key, admin_key, admin_key_len);
|
||||
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_LR_SETUP, setup);
|
||||
if (r != OPAL_STATUS_SUCCESS) {
|
||||
log_dbg(cd, "Failed to setup locking range of length %llu at offset %llu on OPAL device '%s': %s",
|
||||
setup->range_length, setup->range_start, crypt_get_device_name(cd), opal_status_to_string(r));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* After setup an OPAL device is unlocked, but the expectation with cryptsetup is that it needs
|
||||
* to be activated separately, so lock it immediately. */
|
||||
lock = crypt_safe_alloc(sizeof(struct opal_lock_unlock));
|
||||
if (!lock) {
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
*lock = (struct opal_lock_unlock) {
|
||||
.l_state = OPAL_LK,
|
||||
.session = {
|
||||
.who = segment_number + 1,
|
||||
.opal_key = {
|
||||
.key_len = vk->keylength,
|
||||
.lr = segment_number,
|
||||
},
|
||||
}
|
||||
};
|
||||
memcpy(lock->session.opal_key.key, vk->key, vk->keylength);
|
||||
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_LOCK_UNLOCK, lock);
|
||||
if (r != OPAL_STATUS_SUCCESS) {
|
||||
log_dbg(cd, "Failed to lock OPAL device '%s': %s",
|
||||
crypt_get_device_name(cd), opal_status_to_string(r));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Double check the locking range is locked and the ranges are set up as configured */
|
||||
r = opal_range_check_attributes_fd(cd, fd, segment_number, vk, &range_start,
|
||||
&range_length, &(bool) {true}, &(bool){true});
|
||||
out:
|
||||
crypt_safe_free(activate);
|
||||
crypt_safe_free(user_session);
|
||||
crypt_safe_free(user_add_to_lr);
|
||||
crypt_safe_free(new_pw);
|
||||
crypt_safe_free(setup);
|
||||
crypt_safe_free(lock);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int opal_lock_unlock(struct crypt_device *cd,
|
||||
struct device *dev,
|
||||
uint32_t segment_number,
|
||||
const struct volume_key *vk,
|
||||
bool lock)
|
||||
{
|
||||
struct opal_lock_unlock unlock = {
|
||||
.l_state = lock ? OPAL_LK : OPAL_RW,
|
||||
.session = {
|
||||
.who = segment_number + 1,
|
||||
.opal_key = {
|
||||
.lr = segment_number,
|
||||
},
|
||||
},
|
||||
};
|
||||
int r, fd;
|
||||
|
||||
if (opal_supported(cd, dev) <= 0)
|
||||
return -ENOTSUP;
|
||||
if (!lock && !vk)
|
||||
return -EINVAL;
|
||||
|
||||
fd = device_open(cd, dev, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return -EIO;
|
||||
|
||||
if (!lock) {
|
||||
assert(vk->keylength <= OPAL_KEY_MAX);
|
||||
|
||||
unlock.session.opal_key.key_len = vk->keylength;
|
||||
memcpy(unlock.session.opal_key.key, vk->key, vk->keylength);
|
||||
}
|
||||
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_LOCK_UNLOCK, &unlock);
|
||||
if (r < 0) {
|
||||
r = -ENOTSUP;
|
||||
log_dbg(cd, "OPAL not supported on this kernel version, refusing.");
|
||||
goto out;
|
||||
}
|
||||
if (r == OPAL_STATUS_NOT_AUTHORIZED) /* We'll try again with a different key. */ {
|
||||
r = -EPERM;
|
||||
log_dbg(cd, "Failed to %slock OPAL device '%s': permission denied",
|
||||
lock ? "" : "un", crypt_get_device_name(cd));
|
||||
goto out;
|
||||
}
|
||||
if (r != OPAL_STATUS_SUCCESS) {
|
||||
log_dbg(cd, "Failed to %slock OPAL device '%s': %s",
|
||||
lock ? "" : "un", crypt_get_device_name(cd), opal_status_to_string(r));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* If we are unlocking, also tell the kernel to automatically unlock when resuming
|
||||
* from suspend, otherwise the drive will be locked and everything will go up in flames.
|
||||
* Also set the flag to allow locking without having to pass the key again.
|
||||
* But do not error out if this fails, as the device will already be unlocked. */
|
||||
if (!lock) {
|
||||
unlock.flags = OPAL_SAVE_FOR_LOCK;
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_SAVE, &unlock);
|
||||
if (r != OPAL_STATUS_SUCCESS) {
|
||||
log_std(cd, "Failed to prepare OPAL device '%s' for sleep resume, be aware before suspending: %s",
|
||||
crypt_get_device_name(cd), opal_status_to_string(r));
|
||||
r = 0;
|
||||
}
|
||||
}
|
||||
out:
|
||||
if (!lock)
|
||||
crypt_safe_memzero(unlock.session.opal_key.key, unlock.session.opal_key.key_len);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int opal_lock(struct crypt_device *cd, struct device *dev, uint32_t segment_number)
|
||||
{
|
||||
return opal_lock_unlock(cd, dev, segment_number, NULL, /* lock= */ true);
|
||||
}
|
||||
|
||||
int opal_unlock(struct crypt_device *cd,
|
||||
struct device *dev,
|
||||
uint32_t segment_number,
|
||||
const struct volume_key *vk)
|
||||
{
|
||||
return opal_lock_unlock(cd, dev, segment_number, vk, /* lock= */ false);
|
||||
}
|
||||
|
||||
int opal_factory_reset(struct crypt_device *cd,
|
||||
struct device *dev,
|
||||
const char *password,
|
||||
size_t password_len)
|
||||
{
|
||||
struct opal_key reset = {
|
||||
.key_len = password_len,
|
||||
};
|
||||
int r, fd;
|
||||
|
||||
assert(cd);
|
||||
assert(dev);
|
||||
assert(password);
|
||||
|
||||
if (password_len > OPAL_KEY_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
fd = device_open(cd, dev, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return -EIO;
|
||||
|
||||
memcpy(reset.key, password, password_len);
|
||||
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_PSID_REVERT_TPR, &reset);
|
||||
if (r < 0) {
|
||||
r = -ENOTSUP;
|
||||
log_dbg(cd, "OPAL not supported on this kernel version, refusing.");
|
||||
goto out;
|
||||
}
|
||||
if (r == OPAL_STATUS_NOT_AUTHORIZED) /* We'll try again with a different key. */ {
|
||||
r = -EPERM;
|
||||
log_dbg(cd, "Failed to reset OPAL device '%s', incorrect PSID?",
|
||||
crypt_get_device_name(cd));
|
||||
goto out;
|
||||
}
|
||||
if (r != OPAL_STATUS_SUCCESS) {
|
||||
r = -EINVAL;
|
||||
log_dbg(cd, "Failed to reset OPAL device '%s' with PSID: %s",
|
||||
crypt_get_device_name(cd), opal_status_to_string(r));
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
crypt_safe_memzero(reset.key, reset.key_len);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int opal_reset_segment(struct crypt_device *cd,
|
||||
struct device *dev,
|
||||
uint32_t segment_number,
|
||||
const char *password,
|
||||
size_t password_len)
|
||||
{
|
||||
struct opal_session_info *user_session = NULL;
|
||||
struct opal_user_lr_setup *setup = NULL;
|
||||
int r, fd;
|
||||
|
||||
assert(cd);
|
||||
assert(dev);
|
||||
assert(password);
|
||||
|
||||
if (password_len > OPAL_KEY_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (opal_enabled(cd, dev) <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
user_session = crypt_safe_alloc(sizeof(struct opal_session_info));
|
||||
if (!user_session)
|
||||
return -ENOMEM;
|
||||
*user_session = (struct opal_session_info) {
|
||||
.who = OPAL_ADMIN1,
|
||||
.opal_key = {
|
||||
.lr = segment_number,
|
||||
.key_len = password_len,
|
||||
},
|
||||
};
|
||||
memcpy(user_session->opal_key.key, password, password_len);
|
||||
|
||||
fd = device_open(cd, dev, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
r = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_ERASE_LR, user_session);
|
||||
if (r != OPAL_STATUS_SUCCESS) {
|
||||
log_dbg(cd, "Failed to reset (erase) OPAL locking range %u on device '%s': %s",
|
||||
segment_number, crypt_get_device_name(cd), opal_status_to_string(r));
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_SECURE_ERASE_LR, user_session);
|
||||
if (r != OPAL_STATUS_SUCCESS) {
|
||||
log_dbg(cd, "Failed to reset (secure erase) OPAL locking range %u on device '%s': %s",
|
||||
segment_number, crypt_get_device_name(cd), opal_status_to_string(r));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Unlike IOC_OPAL_ERASE_LR, IOC_OPAL_SECURE_ERASE_LR does not disable the locking range,
|
||||
* we have to do that by hand.
|
||||
*/
|
||||
setup = crypt_safe_alloc(sizeof(struct opal_user_lr_setup));
|
||||
if (!setup) {
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
*setup = (struct opal_user_lr_setup) {
|
||||
.range_start = 0,
|
||||
.range_length = 0,
|
||||
.session = {
|
||||
.who = OPAL_ADMIN1,
|
||||
.opal_key = user_session->opal_key,
|
||||
},
|
||||
};
|
||||
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_LR_SETUP, setup);
|
||||
if (r != OPAL_STATUS_SUCCESS) {
|
||||
log_dbg(cd, "Failed to disable locking range on OPAL device '%s': %s",
|
||||
crypt_get_device_name(cd), opal_status_to_string(r));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
out:
|
||||
crypt_safe_free(user_session);
|
||||
crypt_safe_free(setup);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int opal_query_status(struct crypt_device *cd, struct device *dev, unsigned expected)
|
||||
{
|
||||
struct opal_status st = { };
|
||||
int fd, r;
|
||||
|
||||
assert(cd);
|
||||
assert(dev);
|
||||
|
||||
fd = device_open(cd, dev, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return -EIO;
|
||||
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_GET_STATUS, &st);
|
||||
|
||||
return r < 0 ? -EINVAL : (st.flags & expected) ? 1 : 0;
|
||||
}
|
||||
|
||||
int opal_supported(struct crypt_device *cd, struct device *dev)
|
||||
{
|
||||
return opal_query_status(cd, dev, OPAL_FL_SUPPORTED|OPAL_FL_LOCKING_SUPPORTED);
|
||||
}
|
||||
|
||||
int opal_enabled(struct crypt_device *cd, struct device *dev)
|
||||
{
|
||||
return opal_query_status(cd, dev, OPAL_FL_LOCKING_ENABLED);
|
||||
}
|
||||
|
||||
int opal_geometry(struct crypt_device *cd,
|
||||
struct device *dev,
|
||||
bool *ret_align,
|
||||
uint32_t *ret_block_size,
|
||||
uint64_t *ret_alignment_granularity_blocks,
|
||||
uint64_t *ret_lowest_lba_blocks)
|
||||
{
|
||||
int fd;
|
||||
|
||||
assert(cd);
|
||||
assert(dev);
|
||||
|
||||
fd = device_open(cd, dev, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return -EIO;
|
||||
|
||||
return opal_geometry_fd(cd, fd, ret_align, ret_block_size,
|
||||
ret_alignment_granularity_blocks, ret_lowest_lba_blocks);
|
||||
}
|
||||
|
||||
int opal_range_check_attributes(struct crypt_device *cd,
|
||||
struct device *dev,
|
||||
uint32_t segment_number,
|
||||
const struct volume_key *vk,
|
||||
const uint64_t *check_offset_sectors,
|
||||
const uint64_t *check_length_sectors,
|
||||
bool *check_read_locked,
|
||||
bool *check_write_locked)
|
||||
{
|
||||
int fd;
|
||||
|
||||
assert(cd);
|
||||
assert(dev);
|
||||
assert(vk);
|
||||
|
||||
fd = device_open(cd, dev, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return -EIO;
|
||||
|
||||
return opal_range_check_attributes_fd(cd, fd, segment_number, vk,
|
||||
check_offset_sectors, check_length_sectors, check_read_locked,
|
||||
check_write_locked);
|
||||
}
|
||||
|
||||
#else
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
|
||||
int opal_setup_ranges(struct crypt_device *cd,
|
||||
struct device *dev,
|
||||
const struct volume_key *vk,
|
||||
uint64_t range_start,
|
||||
uint64_t range_length,
|
||||
uint32_t segment_number,
|
||||
const void *admin_key,
|
||||
size_t admin_key_len)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
int opal_lock(struct crypt_device *cd, struct device *dev, uint32_t segment_number)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
int opal_unlock(struct crypt_device *cd,
|
||||
struct device *dev,
|
||||
uint32_t segment_number,
|
||||
const struct volume_key *vk)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
int opal_supported(struct crypt_device *cd, struct device *dev)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
int opal_enabled(struct crypt_device *cd, struct device *dev)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
int opal_factory_reset(struct crypt_device *cd,
|
||||
struct device *dev,
|
||||
const char *password,
|
||||
size_t password_len)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
int opal_reset_segment(struct crypt_device *cd,
|
||||
struct device *dev,
|
||||
uint32_t segment_number,
|
||||
const char *password,
|
||||
size_t password_len)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
int opal_geometry(struct crypt_device *cd,
|
||||
struct device *dev,
|
||||
bool *ret_align,
|
||||
uint32_t *ret_block_size,
|
||||
uint64_t *ret_alignment_granularity_blocks,
|
||||
uint64_t *ret_lowest_lba_blocks)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
int opal_range_check_attributes(struct crypt_device *cd,
|
||||
struct device *dev,
|
||||
uint32_t segment_number,
|
||||
const struct volume_key *vk,
|
||||
const uint64_t *check_offset_sectors,
|
||||
const uint64_t *check_length_sectors,
|
||||
bool *check_read_locked,
|
||||
bool *check_write_locked)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
#endif
|
||||
66
lib/luks2/hw_opal/hw_opal.h
Normal file
66
lib/luks2/hw_opal/hw_opal.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* OPAL utilities
|
||||
*
|
||||
* Copyright (C) 2022-2023 Luca Boccassi <bluca@debian.org>
|
||||
* 2023 Ondrej Kozina <okozina@redhat.com>
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this file; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef _UTILS_OPAL
|
||||
#define _UTILS_OPAL
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
int opal_setup_ranges(struct crypt_device *cd,
|
||||
struct device *dev,
|
||||
const struct volume_key *vk,
|
||||
uint64_t range_start,
|
||||
uint64_t range_length,
|
||||
uint32_t segment_number,
|
||||
const void *admin_key,
|
||||
size_t admin_key_len);
|
||||
int opal_lock(struct crypt_device *cd, struct device *dev, uint32_t segment_number);
|
||||
int opal_unlock(struct crypt_device *cd,
|
||||
struct device *dev,
|
||||
uint32_t segment_number,
|
||||
const struct volume_key *vk);
|
||||
int opal_supported(struct crypt_device *cd, struct device *dev);
|
||||
int opal_enabled(struct crypt_device *cd, struct device *dev);
|
||||
int opal_factory_reset(struct crypt_device *cd,
|
||||
struct device *dev,
|
||||
const char *password,
|
||||
size_t password_len);
|
||||
int opal_reset_segment(struct crypt_device *cd,
|
||||
struct device *dev,
|
||||
uint32_t segment_number,
|
||||
const char *password,
|
||||
size_t password_len);
|
||||
int opal_geometry(struct crypt_device *cd,
|
||||
struct device *dev,
|
||||
bool *ret_align,
|
||||
uint32_t *ret_block_size,
|
||||
uint64_t *ret_alignment_granularity_blocks,
|
||||
uint64_t *ret_lowest_lba_blocks);
|
||||
int opal_range_check_attributes(struct crypt_device *cd,
|
||||
struct device *dev,
|
||||
uint32_t segment_number,
|
||||
const struct volume_key *vk,
|
||||
const uint64_t *check_offset_sectors,
|
||||
const uint64_t *check_length_sectors,
|
||||
bool *check_read_locked,
|
||||
bool *check_write_locked);
|
||||
|
||||
#endif
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2
|
||||
*
|
||||
* Copyright (C) 2015-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2022 Milan Broz
|
||||
* Copyright (C) 2015-2023 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2023 Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -121,6 +121,7 @@ struct luks2_hdr {
|
||||
uint8_t salt2[LUKS2_SALT_L];
|
||||
char uuid[LUKS2_UUID_L];
|
||||
void *jobj;
|
||||
void *jobj_rollback;
|
||||
};
|
||||
|
||||
struct luks2_keyslot_params {
|
||||
@@ -167,6 +168,7 @@ int LUKS2_hdr_version_unlocked(struct crypt_device *cd,
|
||||
int LUKS2_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr, int repair);
|
||||
int LUKS2_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr);
|
||||
int LUKS2_hdr_write_force(struct crypt_device *cd, struct luks2_hdr *hdr);
|
||||
int LUKS2_hdr_rollback(struct crypt_device *cd, struct luks2_hdr *hdr);
|
||||
int LUKS2_hdr_dump(struct crypt_device *cd, struct luks2_hdr *hdr);
|
||||
int LUKS2_hdr_dump_json(struct crypt_device *cd, struct luks2_hdr *hdr, const char **json);
|
||||
|
||||
@@ -222,8 +224,7 @@ int LUKS2_keyslot_store(struct crypt_device *cd,
|
||||
|
||||
int LUKS2_keyslot_wipe(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
int wipe_area_only);
|
||||
int keyslot);
|
||||
|
||||
crypt_keyslot_priority LUKS2_keyslot_priority_get(struct luks2_hdr *hdr, int keyslot);
|
||||
|
||||
@@ -275,6 +276,7 @@ crypt_token_info LUKS2_token_status(struct crypt_device *cd,
|
||||
|
||||
int LUKS2_token_open_and_activate(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
int token,
|
||||
const char *name,
|
||||
const char *type,
|
||||
@@ -283,13 +285,14 @@ int LUKS2_token_open_and_activate(struct crypt_device *cd,
|
||||
uint32_t flags,
|
||||
void *usrptr);
|
||||
|
||||
int LUKS2_token_unlock_volume_key(struct crypt_device *cd,
|
||||
int LUKS2_token_unlock_key(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
int token,
|
||||
const char *type,
|
||||
const char *pin,
|
||||
size_t pin_size,
|
||||
uint32_t flags,
|
||||
int segment,
|
||||
void *usrptr,
|
||||
struct volume_key **vk);
|
||||
|
||||
@@ -300,6 +303,16 @@ int LUKS2_token_keyring_get(struct luks2_hdr *hdr,
|
||||
int LUKS2_token_keyring_json(char *buffer, size_t buffer_size,
|
||||
const struct crypt_token_params_luks2_keyring *keyring_params);
|
||||
|
||||
int LUKS2_token_unlock_passphrase(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int token,
|
||||
const char *type,
|
||||
const char *pin,
|
||||
size_t pin_size,
|
||||
void *usrptr,
|
||||
char **passphrase,
|
||||
size_t *passphrase_size);
|
||||
|
||||
void crypt_token_unload_external_all(struct crypt_device *cd);
|
||||
|
||||
/*
|
||||
@@ -347,7 +360,8 @@ int LUKS2_digest_create(struct crypt_device *cd,
|
||||
*/
|
||||
int LUKS2_activate(struct crypt_device *cd,
|
||||
const char *name,
|
||||
struct volume_key *vk,
|
||||
struct volume_key *crypt_key,
|
||||
struct volume_key *opal_key,
|
||||
uint32_t flags);
|
||||
|
||||
int LUKS2_activate_multi(struct crypt_device *cd,
|
||||
@@ -366,16 +380,23 @@ int LUKS2_generate_hdr(
|
||||
struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
const struct volume_key *vk,
|
||||
const char *cipherName,
|
||||
const char *cipherMode,
|
||||
const char *cipher_spec,
|
||||
const char *integrity,
|
||||
const char *uuid,
|
||||
unsigned int sector_size,
|
||||
uint64_t data_offset,
|
||||
uint64_t align_offset,
|
||||
uint64_t required_alignment,
|
||||
uint64_t metadata_size,
|
||||
uint64_t keyslots_size);
|
||||
uint64_t metadata_size_bytes,
|
||||
uint64_t keyslots_size_bytes,
|
||||
uint64_t device_size_bytes,
|
||||
uint32_t opal_segment_number,
|
||||
uint32_t opal_key_size);
|
||||
|
||||
int LUKS2_hdr_get_storage_params(struct crypt_device *cd,
|
||||
uint64_t alignment_offset_bytes,
|
||||
uint64_t alignment_bytes,
|
||||
uint64_t *ret_metadata_size_bytes,
|
||||
uint64_t *ret_keyslots_size_bytes,
|
||||
uint64_t *ret_data_offset_bytes);
|
||||
|
||||
int LUKS2_check_metadata_area_size(uint64_t metadata_size);
|
||||
int LUKS2_check_keyslots_area_size(uint64_t keyslots_size);
|
||||
@@ -402,6 +423,12 @@ int LUKS2_keyslot_area(struct luks2_hdr *hdr,
|
||||
uint64_t *length);
|
||||
int LUKS2_keyslot_pbkdf(struct luks2_hdr *hdr, int keyslot, struct crypt_pbkdf_type *pbkdf);
|
||||
|
||||
int LUKS2_split_crypt_and_opal_keys(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
const struct volume_key *vk,
|
||||
struct volume_key **ret_crypt_key,
|
||||
struct volume_key **ret_opal_key);
|
||||
|
||||
/*
|
||||
* Permanent activation flags stored in header
|
||||
*/
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2, digest handling
|
||||
*
|
||||
* Copyright (C) 2015-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2022 Milan Broz
|
||||
* Copyright (C) 2015-2023 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2023 Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -157,7 +157,7 @@ int LUKS2_digest_dump(struct crypt_device *cd, int digest)
|
||||
}
|
||||
|
||||
int LUKS2_digest_any_matching(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
struct luks2_hdr *hdr __attribute__((unused)),
|
||||
const struct volume_key *vk)
|
||||
{
|
||||
int digest;
|
||||
@@ -174,6 +174,18 @@ int LUKS2_digest_verify_by_segment(struct crypt_device *cd,
|
||||
int segment,
|
||||
const struct volume_key *vk)
|
||||
{
|
||||
int r = -EINVAL;
|
||||
unsigned s;
|
||||
|
||||
if (segment == CRYPT_ANY_SEGMENT) {
|
||||
for (s = 0; s < json_segments_count(LUKS2_get_segments_jobj(hdr)); s++) {
|
||||
if ((r = LUKS2_digest_verify_by_digest(cd, LUKS2_digest_by_segment(hdr, s), vk)) >= 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
return LUKS2_digest_verify_by_digest(cd, LUKS2_digest_by_segment(hdr, segment), vk);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2, PBKDF2 digest handler (LUKS1 compatible)
|
||||
*
|
||||
* Copyright (C) 2015-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2022 Milan Broz
|
||||
* Copyright (C) 2015-2023 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2023 Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -147,6 +147,9 @@ static int PBKDF2_digest_store(struct crypt_device *cd,
|
||||
json_object_object_get_ex(hdr->jobj, "digests", &jobj_digests);
|
||||
}
|
||||
|
||||
if (!jobj_digest)
|
||||
return -ENOMEM;
|
||||
|
||||
json_object_object_add(jobj_digest, "type", json_object_new_string("pbkdf2"));
|
||||
json_object_object_add(jobj_digest, "keyslots", json_object_new_array());
|
||||
json_object_object_add(jobj_digest, "segments", json_object_new_array());
|
||||
@@ -169,8 +172,13 @@ static int PBKDF2_digest_store(struct crypt_device *cd,
|
||||
json_object_object_add(jobj_digest, "digest", json_object_new_string(base64_str));
|
||||
free(base64_str);
|
||||
|
||||
if (jobj_digests)
|
||||
json_object_object_add_by_uint(jobj_digests, digest, jobj_digest);
|
||||
if (jobj_digests) {
|
||||
r = json_object_object_add_by_uint(jobj_digests, digest, jobj_digest);
|
||||
if (r < 0) {
|
||||
json_object_put(jobj_digest);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
JSON_DBG(cd, jobj_digest, "Digest JSON:");
|
||||
return 0;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2
|
||||
*
|
||||
* Copyright (C) 2015-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2022 Milan Broz
|
||||
* Copyright (C) 2015-2023 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2023 Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -19,8 +19,6 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "luks2_internal.h"
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2
|
||||
*
|
||||
* Copyright (C) 2015-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2022 Milan Broz
|
||||
* Copyright (C) 2015-2023 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2023 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,6 +62,7 @@ uint32_t crypt_jobj_get_uint32(json_object *jobj);
|
||||
json_object *crypt_jobj_new_uint64(uint64_t value);
|
||||
|
||||
int json_object_object_add_by_uint(json_object *jobj, unsigned key, json_object *jobj_val);
|
||||
int json_object_object_add_by_uint_by_ref(json_object *jobj, unsigned key, json_object **jobj_val_ref);
|
||||
void json_object_object_del_by_uint(json_object *jobj, unsigned key);
|
||||
int json_object_copy(json_object *jobj_src, json_object **jobj_dst);
|
||||
|
||||
@@ -189,6 +190,8 @@ void keyring_dump(struct crypt_device *cd, const char *json);
|
||||
|
||||
int keyring_validate(struct crypt_device *cd, const char *json);
|
||||
|
||||
void keyring_buffer_free(void *buffer, size_t buffer_size);
|
||||
|
||||
struct crypt_token_handler_v2 {
|
||||
const char *name;
|
||||
crypt_token_open_func open;
|
||||
@@ -293,13 +296,24 @@ 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);
|
||||
uint32_t json_segment_get_sector_size(json_object *jobj_segment);
|
||||
int json_segment_get_opal_segment_id(json_object *jobj_segment, uint32_t *ret_opal_segment_id);
|
||||
int json_segment_get_opal_key_size(json_object *jobj_segment, size_t *ret_key_size);
|
||||
bool json_segment_is_backup(json_object *jobj_segment);
|
||||
json_object *json_segments_get_segment(json_object *jobj_segments, int segment);
|
||||
unsigned json_segments_count(json_object *jobj_segments);
|
||||
void json_segment_remove_flag(json_object *jobj_segment, const char *flag);
|
||||
uint64_t json_segments_get_minimal_offset(json_object *jobj_segments, unsigned blockwise);
|
||||
json_object *json_segment_create_linear(uint64_t offset, const uint64_t *length, unsigned reencryption);
|
||||
json_object *json_segment_create_crypt(uint64_t offset, uint64_t iv_offset, const uint64_t *length, const char *cipher, uint32_t sector_size, unsigned reencryption);
|
||||
json_object *json_segment_create_crypt(uint64_t offset, uint64_t iv_offset, const uint64_t *length,
|
||||
const char *cipher, const char *integrity,
|
||||
uint32_t sector_size, unsigned reencryption);
|
||||
json_object *json_segment_create_opal(uint64_t offset, const uint64_t *length,
|
||||
uint32_t segment_number, uint32_t key_size);
|
||||
json_object *json_segment_create_opal_crypt(uint64_t offset, const uint64_t *length,
|
||||
uint32_t segment_number, uint32_t key_size,
|
||||
uint64_t iv_offset, const char *cipher,
|
||||
const char *integrity, 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);
|
||||
@@ -336,10 +350,26 @@ uint64_t LUKS2_segment_size(struct luks2_hdr *hdr,
|
||||
int segment,
|
||||
unsigned blockwise);
|
||||
|
||||
bool LUKS2_segment_set_size(struct luks2_hdr *hdr,
|
||||
int segment,
|
||||
const uint64_t *segment_size_bytes);
|
||||
|
||||
uint64_t LUKS2_opal_segment_size(struct luks2_hdr *hdr,
|
||||
int segment,
|
||||
unsigned blockwise);
|
||||
|
||||
int LUKS2_segment_is_type(struct luks2_hdr *hdr,
|
||||
int segment,
|
||||
const char *type);
|
||||
|
||||
bool LUKS2_segment_is_hw_opal(struct luks2_hdr *hdr, int segment);
|
||||
bool LUKS2_segment_is_hw_opal_crypt(struct luks2_hdr *hdr, int segment);
|
||||
bool LUKS2_segment_is_hw_opal_only(struct luks2_hdr *hdr, int segment);
|
||||
|
||||
int LUKS2_get_opal_segment_number(struct luks2_hdr *hdr, int segment,
|
||||
uint32_t *ret_opal_segment_number);
|
||||
int LUKS2_get_opal_key_size(struct luks2_hdr *hdr, int segment);
|
||||
|
||||
int LUKS2_segment_by_type(struct luks2_hdr *hdr,
|
||||
const char *type);
|
||||
|
||||
@@ -348,6 +378,8 @@ int LUKS2_last_segment_by_type(struct luks2_hdr *hdr,
|
||||
|
||||
int LUKS2_get_default_segment(struct luks2_hdr *hdr);
|
||||
|
||||
bool LUKS2_segments_dynamic_size(struct luks2_hdr *hdr);
|
||||
|
||||
int LUKS2_reencrypt_digest_new(struct luks2_hdr *hdr);
|
||||
int LUKS2_reencrypt_digest_old(struct luks2_hdr *hdr);
|
||||
int LUKS2_reencrypt_data_offset(struct luks2_hdr *hdr, bool blockwise);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2, LUKS2 header format code
|
||||
*
|
||||
* Copyright (C) 2015-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2022 Milan Broz
|
||||
* Copyright (C) 2015-2023 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2015-2023 Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -21,7 +21,6 @@
|
||||
|
||||
#include "luks2_internal.h"
|
||||
#include <uuid/uuid.h>
|
||||
#include <assert.h>
|
||||
|
||||
struct area {
|
||||
uint64_t offset;
|
||||
@@ -205,76 +204,33 @@ int LUKS2_generate_hdr(
|
||||
struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
const struct volume_key *vk,
|
||||
const char *cipherName,
|
||||
const char *cipherMode,
|
||||
const char *cipher_spec,
|
||||
const char *integrity,
|
||||
const char *uuid,
|
||||
unsigned int sector_size, /* in bytes */
|
||||
uint64_t data_offset, /* in bytes */
|
||||
uint64_t align_offset, /* in bytes */
|
||||
uint64_t required_alignment,
|
||||
uint64_t metadata_size,
|
||||
uint64_t keyslots_size)
|
||||
uint64_t metadata_size_bytes,
|
||||
uint64_t keyslots_size_bytes,
|
||||
uint64_t device_size_bytes,
|
||||
uint32_t opal_segment_number,
|
||||
uint32_t opal_key_size)
|
||||
{
|
||||
struct json_object *jobj_segment, *jobj_integrity, *jobj_keyslots, *jobj_segments, *jobj_config;
|
||||
char cipher[128];
|
||||
struct json_object *jobj_segment, *jobj_keyslots, *jobj_segments, *jobj_config;
|
||||
uuid_t partitionUuid;
|
||||
int r, digest;
|
||||
uint64_t mdev_size;
|
||||
|
||||
if (!metadata_size)
|
||||
metadata_size = LUKS2_HDR_16K_LEN;
|
||||
hdr->hdr_size = metadata_size;
|
||||
assert(cipher_spec || (opal_key_size > 0 && device_size_bytes));
|
||||
|
||||
if (data_offset && data_offset < get_min_offset(hdr)) {
|
||||
log_err(cd, _("Requested data offset is too small."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Increase keyslot size according to data offset */
|
||||
if (!keyslots_size && data_offset)
|
||||
keyslots_size = data_offset - get_min_offset(hdr);
|
||||
|
||||
/* keyslots size has to be 4 KiB aligned */
|
||||
keyslots_size -= (keyslots_size % 4096);
|
||||
|
||||
if (keyslots_size > LUKS2_MAX_KEYSLOTS_SIZE)
|
||||
keyslots_size = LUKS2_MAX_KEYSLOTS_SIZE;
|
||||
|
||||
if (!keyslots_size) {
|
||||
assert(LUKS2_DEFAULT_HDR_SIZE > 2 * LUKS2_HDR_OFFSET_MAX);
|
||||
keyslots_size = LUKS2_DEFAULT_HDR_SIZE - get_min_offset(hdr);
|
||||
/* Decrease keyslots_size due to metadata device being too small */
|
||||
if (!device_size(crypt_metadata_device(cd), &mdev_size) &&
|
||||
((keyslots_size + get_min_offset(hdr)) > mdev_size) &&
|
||||
device_fallocate(crypt_metadata_device(cd), keyslots_size + get_min_offset(hdr)) &&
|
||||
(get_min_offset(hdr) <= mdev_size))
|
||||
keyslots_size = mdev_size - get_min_offset(hdr);
|
||||
}
|
||||
|
||||
/* Decrease keyslots_size if we have smaller data_offset */
|
||||
if (data_offset && (keyslots_size + get_min_offset(hdr)) > data_offset) {
|
||||
keyslots_size = data_offset - get_min_offset(hdr);
|
||||
log_dbg(cd, "Decreasing keyslot area size to %" PRIu64
|
||||
" bytes due to the requested data offset %"
|
||||
PRIu64 " bytes.", keyslots_size, data_offset);
|
||||
}
|
||||
|
||||
/* Data offset has priority */
|
||||
if (!data_offset && required_alignment) {
|
||||
data_offset = size_round_up(get_min_offset(hdr) + keyslots_size,
|
||||
(size_t)required_alignment);
|
||||
data_offset += align_offset;
|
||||
}
|
||||
hdr->hdr_size = metadata_size_bytes;
|
||||
|
||||
log_dbg(cd, "Formatting LUKS2 with JSON metadata area %" PRIu64
|
||||
" bytes and keyslots area %" PRIu64 " bytes.",
|
||||
metadata_size - LUKS2_HDR_BIN_LEN, keyslots_size);
|
||||
metadata_size_bytes - LUKS2_HDR_BIN_LEN, keyslots_size_bytes);
|
||||
|
||||
if (keyslots_size < (LUKS2_HDR_OFFSET_MAX - 2*LUKS2_HDR_16K_LEN))
|
||||
if (keyslots_size_bytes < (LUKS2_HDR_OFFSET_MAX - 2*LUKS2_HDR_16K_LEN))
|
||||
log_std(cd, _("WARNING: keyslots area (%" PRIu64 " bytes) is very small,"
|
||||
" available LUKS2 keyslot count is very limited.\n"),
|
||||
keyslots_size);
|
||||
keyslots_size_bytes);
|
||||
|
||||
hdr->seqid = 1;
|
||||
hdr->version = 2;
|
||||
@@ -292,54 +248,81 @@ int LUKS2_generate_hdr(
|
||||
|
||||
uuid_unparse(partitionUuid, hdr->uuid);
|
||||
|
||||
if (*cipherMode != '\0')
|
||||
r = snprintf(cipher, sizeof(cipher), "%s-%s", cipherName, cipherMode);
|
||||
else
|
||||
r = snprintf(cipher, sizeof(cipher), "%s", cipherName);
|
||||
if (r < 0 || (size_t)r >= sizeof(cipher))
|
||||
return -EINVAL;
|
||||
|
||||
hdr->jobj = json_object_new_object();
|
||||
if (!hdr->jobj) {
|
||||
r = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
jobj_keyslots = json_object_new_object();
|
||||
if (!jobj_keyslots) {
|
||||
r = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
json_object_object_add(hdr->jobj, "keyslots", jobj_keyslots);
|
||||
json_object_object_add(hdr->jobj, "tokens", json_object_new_object());
|
||||
jobj_segments = json_object_new_object();
|
||||
if (!jobj_segments) {
|
||||
r = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
json_object_object_add(hdr->jobj, "segments", jobj_segments);
|
||||
json_object_object_add(hdr->jobj, "digests", json_object_new_object());
|
||||
jobj_config = json_object_new_object();
|
||||
if (!jobj_config) {
|
||||
r = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
json_object_object_add(hdr->jobj, "config", jobj_config);
|
||||
|
||||
digest = LUKS2_digest_create(cd, "pbkdf2", hdr, vk);
|
||||
if (digest < 0)
|
||||
if (digest < 0) {
|
||||
r = -EINVAL;
|
||||
goto err;
|
||||
|
||||
if (LUKS2_digest_segment_assign(cd, hdr, 0, digest, 1, 0) < 0)
|
||||
goto err;
|
||||
|
||||
jobj_segment = json_segment_create_crypt(data_offset, 0, NULL, cipher, sector_size, 0);
|
||||
if (!jobj_segment)
|
||||
goto err;
|
||||
|
||||
if (integrity) {
|
||||
jobj_integrity = json_object_new_object();
|
||||
json_object_object_add(jobj_integrity, "type", json_object_new_string(integrity));
|
||||
json_object_object_add(jobj_integrity, "journal_encryption", json_object_new_string("none"));
|
||||
json_object_object_add(jobj_integrity, "journal_integrity", json_object_new_string("none"));
|
||||
json_object_object_add(jobj_segment, "integrity", jobj_integrity);
|
||||
}
|
||||
|
||||
json_object_object_add_by_uint(jobj_segments, 0, jobj_segment);
|
||||
if (LUKS2_digest_segment_assign(cd, hdr, 0, digest, 1, 0) < 0) {
|
||||
r = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
json_object_object_add(jobj_config, "json_size", crypt_jobj_new_uint64(metadata_size - LUKS2_HDR_BIN_LEN));
|
||||
json_object_object_add(jobj_config, "keyslots_size", crypt_jobj_new_uint64(keyslots_size));
|
||||
if (!opal_key_size)
|
||||
jobj_segment = json_segment_create_crypt(data_offset, 0,
|
||||
NULL, cipher_spec,
|
||||
integrity, sector_size,
|
||||
0);
|
||||
else if (opal_key_size && cipher_spec)
|
||||
jobj_segment = json_segment_create_opal_crypt(data_offset, &device_size_bytes,
|
||||
opal_segment_number, opal_key_size, 0,
|
||||
cipher_spec, integrity,
|
||||
sector_size, 0);
|
||||
else
|
||||
jobj_segment = json_segment_create_opal(data_offset, &device_size_bytes,
|
||||
opal_segment_number, opal_key_size);
|
||||
|
||||
if (!jobj_segment) {
|
||||
r = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (json_object_object_add_by_uint(jobj_segments, 0, jobj_segment)) {
|
||||
json_object_put(jobj_segment);
|
||||
r = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
json_object_object_add(jobj_config, "json_size", crypt_jobj_new_uint64(metadata_size_bytes - LUKS2_HDR_BIN_LEN));
|
||||
json_object_object_add(jobj_config, "keyslots_size", crypt_jobj_new_uint64(keyslots_size_bytes));
|
||||
|
||||
JSON_DBG(cd, hdr->jobj, "Header JSON:");
|
||||
return 0;
|
||||
err:
|
||||
json_object_put(hdr->jobj);
|
||||
hdr->jobj = NULL;
|
||||
return -EINVAL;
|
||||
return r;
|
||||
}
|
||||
|
||||
int LUKS2_wipe_header_areas(struct crypt_device *cd,
|
||||
@@ -363,6 +346,10 @@ int LUKS2_wipe_header_areas(struct crypt_device *cd,
|
||||
wipe_block = 4096;
|
||||
}
|
||||
|
||||
r = device_check_size(cd, crypt_metadata_device(cd), length, 1);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
log_dbg(cd, "Wiping LUKS areas (0x%06" PRIx64 " - 0x%06" PRIx64") with zeroes.",
|
||||
offset, length + offset);
|
||||
|
||||
@@ -376,6 +363,14 @@ int LUKS2_wipe_header_areas(struct crypt_device *cd,
|
||||
offset = get_min_offset(hdr);
|
||||
length = LUKS2_keyslots_size(hdr);
|
||||
|
||||
/*
|
||||
* Skip keyslots area wipe in case it is not defined.
|
||||
* Otherwise we would wipe whole data device (length == 0)
|
||||
* starting at offset get_min_offset(hdr).
|
||||
*/
|
||||
if (!length)
|
||||
return 0;
|
||||
|
||||
log_dbg(cd, "Wiping keyslots area (0x%06" PRIx64 " - 0x%06" PRIx64") with random data.",
|
||||
offset, length + offset);
|
||||
|
||||
@@ -406,3 +401,80 @@ int LUKS2_set_keyslots_size(struct luks2_hdr *hdr, uint64_t data_offset)
|
||||
json_object_object_add(jobj_config, "keyslots_size", crypt_jobj_new_uint64(keyslots_size));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LUKS2_hdr_get_storage_params(struct crypt_device *cd,
|
||||
uint64_t alignment_offset_bytes,
|
||||
uint64_t alignment_bytes,
|
||||
uint64_t *ret_metadata_size_bytes,
|
||||
uint64_t *ret_keyslots_size_bytes,
|
||||
uint64_t *ret_data_offset_bytes)
|
||||
{
|
||||
uint64_t data_offset_bytes, keyslots_size_bytes, metadata_size_bytes, mdev_size_bytes;
|
||||
|
||||
assert(cd);
|
||||
assert(ret_metadata_size_bytes);
|
||||
assert(ret_keyslots_size_bytes);
|
||||
assert(ret_data_offset_bytes);
|
||||
|
||||
metadata_size_bytes = crypt_get_metadata_size_bytes(cd);
|
||||
keyslots_size_bytes = crypt_get_keyslots_size_bytes(cd);
|
||||
data_offset_bytes = crypt_get_data_offset_sectors(cd) * SECTOR_SIZE;
|
||||
|
||||
if (!metadata_size_bytes)
|
||||
metadata_size_bytes = LUKS2_HDR_16K_LEN;
|
||||
|
||||
if (data_offset_bytes && data_offset_bytes < 2 * metadata_size_bytes) {
|
||||
log_err(cd, _("Requested data offset is too small."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Increase keyslot size according to data offset */
|
||||
if (!keyslots_size_bytes && data_offset_bytes)
|
||||
keyslots_size_bytes = data_offset_bytes - 2 * metadata_size_bytes;
|
||||
|
||||
/* keyslots size has to be 4 KiB aligned */
|
||||
keyslots_size_bytes -= (keyslots_size_bytes % 4096);
|
||||
|
||||
if (keyslots_size_bytes > LUKS2_MAX_KEYSLOTS_SIZE)
|
||||
keyslots_size_bytes = LUKS2_MAX_KEYSLOTS_SIZE;
|
||||
|
||||
if (!keyslots_size_bytes) {
|
||||
assert(LUKS2_DEFAULT_HDR_SIZE > 2 * LUKS2_HDR_OFFSET_MAX);
|
||||
keyslots_size_bytes = LUKS2_DEFAULT_HDR_SIZE - 2 * metadata_size_bytes;
|
||||
/* Decrease keyslots_size due to metadata device being too small */
|
||||
if (!device_size(crypt_metadata_device(cd), &mdev_size_bytes) &&
|
||||
((keyslots_size_bytes + 2 * metadata_size_bytes) > mdev_size_bytes) &&
|
||||
device_fallocate(crypt_metadata_device(cd), keyslots_size_bytes + 2 * metadata_size_bytes) &&
|
||||
((2 * metadata_size_bytes) <= mdev_size_bytes))
|
||||
keyslots_size_bytes = mdev_size_bytes - 2 * metadata_size_bytes;
|
||||
}
|
||||
|
||||
/* Decrease keyslots_size if we have smaller data_offset */
|
||||
if (data_offset_bytes && (keyslots_size_bytes + 2 * metadata_size_bytes) > data_offset_bytes) {
|
||||
keyslots_size_bytes = data_offset_bytes - 2 * metadata_size_bytes;
|
||||
log_dbg(cd, "Decreasing keyslot area size to %" PRIu64
|
||||
" bytes due to the requested data offset %"
|
||||
PRIu64 " bytes.", keyslots_size_bytes, data_offset_bytes);
|
||||
}
|
||||
|
||||
/* Data offset has priority */
|
||||
if (!data_offset_bytes && alignment_bytes) {
|
||||
data_offset_bytes = size_round_up(2 * metadata_size_bytes + keyslots_size_bytes,
|
||||
(size_t)alignment_bytes);
|
||||
data_offset_bytes += alignment_offset_bytes;
|
||||
}
|
||||
|
||||
if (crypt_get_metadata_size_bytes(cd) && (crypt_get_metadata_size_bytes(cd) != metadata_size_bytes))
|
||||
log_std(cd, _("WARNING: LUKS2 metadata size changed to %" PRIu64 " bytes.\n"),
|
||||
metadata_size_bytes);
|
||||
|
||||
if (crypt_get_keyslots_size_bytes(cd) && (crypt_get_keyslots_size_bytes(cd) != keyslots_size_bytes))
|
||||
log_std(cd, _("WARNING: LUKS2 keyslots area size changed to %" PRIu64 " bytes.\n"),
|
||||
keyslots_size_bytes);
|
||||
|
||||
*ret_metadata_size_bytes = metadata_size_bytes;
|
||||
*ret_keyslots_size_bytes = keyslots_size_bytes;
|
||||
*ret_data_offset_bytes = data_offset_bytes;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user