pax_global_header 0000666 0000000 0000000 00000000064 15201107217 0014506 g ustar 00root root 0000000 0000000 52 comment=6df9b6969da3fa438604cc711cb231ba2fa52a4d
latchset-clevis-6df9b69/ 0000775 0000000 0000000 00000000000 15201107217 0015233 5 ustar 00root root 0000000 0000000 latchset-clevis-6df9b69/.fmf/ 0000775 0000000 0000000 00000000000 15201107217 0016061 5 ustar 00root root 0000000 0000000 latchset-clevis-6df9b69/.fmf/version 0000664 0000000 0000000 00000000001 15201107217 0017460 0 ustar 00root root 0000000 0000000 1 latchset-clevis-6df9b69/.github/ 0000775 0000000 0000000 00000000000 15201107217 0016573 5 ustar 00root root 0000000 0000000 latchset-clevis-6df9b69/.github/workflows/ 0000775 0000000 0000000 00000000000 15201107217 0020630 5 ustar 00root root 0000000 0000000 latchset-clevis-6df9b69/.github/workflows/build.yml 0000664 0000000 0000000 00000003121 15201107217 0022447 0 ustar 00root root 0000000 0000000 ---
name: build
on:
push:
ignore-paths:
- '**.md'
pull_request:
ignore-paths:
- '**.md'
jobs:
build:
runs-on: ubuntu-latest
continue-on-error: ${{ ! matrix.stable }}
strategy:
matrix:
os:
- fedora:latest
- quay.io/centos/centos:stream10
- quay.io/centos/centos:stream9
- debian:testing
- debian:latest
- ubuntu:rolling
- ubuntu:latest
stable: [true]
include:
- os: quay.io/fedora/fedora:rawhide
stable: false
- os: ubuntu:devel
stable: false
steps:
- uses: actions/checkout@v4
- name: Show OS information
run: cat /etc/os-release 2>/dev/null || echo /etc/os-release not available
- name: Install build dependencies
run: bash .github/workflows/install-dependencies
- name: Build clevis
run: |
mkdir -p build && cd build
export ninja=$(command -v ninja)
[ -z "${ninja}" ] && export ninja=$(command -v ninja-build)
export CFLAGS="-g -coverage"
meson .. || cat meson-logs/meson-log.txt >&2
${ninja}
- name: Run tests
run: |
cd build
if ! meson test ; then
cat meson-logs/testlog.txt >&2
exit -1
fi
- name: Show full test logs
run: cat build/meson-logs/testlog.txt >&2
container:
image: ${{matrix.os}}
env:
DISTRO: ${{matrix.os}}
options: --privileged --device /dev/loop-control
# vim:set ts=2 sw=2 et:
latchset-clevis-6df9b69/.github/workflows/differential-shellcheck.yml 0000664 0000000 0000000 00000001215 15201107217 0026111 0 ustar 00root root 0000000 0000000 # Doc: https://github.com/redhat-plumbers-in-action/differential-shellcheck#usage
---
name: Differential ShellCheck
on:
pull_request:
branches: [master]
ignore-paths:
- '**.md'
permissions:
contents: read
jobs:
lint:
runs-on: ubuntu-latest
permissions:
security-events: write
pull-requests: write
steps:
- name: Repository checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Differential ShellCheck
uses: redhat-plumbers-in-action/differential-shellcheck@v3
with:
severity: warning
token: ${{ secrets.GITHUB_TOKEN }}
latchset-clevis-6df9b69/.github/workflows/install-dependencies 0000775 0000000 0000000 00000004132 15201107217 0024650 0 ustar 00root root 0000000 0000000 #!/bin/bash -ex
COMMON="meson curl git make file bzip2 jose tang cryptsetup keyutils jq socat lsof procps ${CC}"
case "${DISTRO}" in
debian:*|ubuntu:*)
apt-get clean
while ! apt-get update; do
sleep 5
done
while ! apt-get -y \
-o Dpkg::Options::="--force-confdef" \
-o Dpkg::Options::="--force-confnew" \
dist-upgrade; do
sleep 5
done
export DEBIAN_FRONTEND=noninteractive
apt-get install -y keyboard-configuration console-setup
while ! apt-get -y install ${COMMON} \
build-essential pkg-config libssl-dev libjansson-dev libjose-dev \
luksmeta libluksmeta-dev libpwquality-tools libglib2.0-dev \
libudisks2-dev libaudit-dev systemd opensc pcscd libsofthsm2-dev \
swtpm-tools tpm-tools tpm2-tools; do
sleep 5
done
;;
*fedora:*)
printf 'max_parallel_downloads=10\nfastestmirror=1\n' >> /etc/dnf/dnf.conf
dnf -y clean all
# Fix Fedora 43 (rawhide) build - install systemd and awk
dnf -y install --allowerasing systemd awk
dnf -y --setopt=deltarpm=0 update
dnf -y install dnf-utils jq socat cryptsetup keyutils cracklib-dicts lsof \
opensc pcsc-lite softhsm swtpm-tools tpm-tools trousers
command -v dnf5 && dnf5 -y install dnf5-command\(builddep\) \
|| dnf -y install dnf-command\(builddep\)
dnf -y builddep clevis
;;
*centos:*)
yum -y clean all
yum -y --setopt=deltarpm=0 update
yum install -y yum-utils
yum config-manager -y --set-enabled crb || yum config-manager \
-y --set-enabled powertools || :
yum -y install epel-release
yum -y install epel-next-release || :
yum -y --allowerasing install ${COMMON}
yum -y install pkgconfig openssl-devel openssl zlib-devel \
jansson-devel findutils gcc libjose-devel luksmeta libluksmeta-devel \
audit-libs-devel tpm2-tools desktop-file-utils cracklib-dicts opensc \
pcsc-lite softhsm swtpm-tools tpm-tools trousers
sed -i 's|>=1\.0\.2|>=1\.0\.1|' meson.build
;;
esac
# vim: set ts=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
latchset-clevis-6df9b69/.github/workflows/spellcheck.yml 0000664 0000000 0000000 00000003063 15201107217 0023472 0 ustar 00root root 0000000 0000000 name: Spellcheck
on:
push:
# branches: [main]
pull_request:
jobs:
spell-check:
name: Language tool & Misspell check
runs-on: ubuntu-latest
steps:
- name: check out code
uses: actions/checkout@v4
- name: running language tool
uses: reviewdog/action-languagetool@v1
with:
github_token: ${{ secrets.github_token }}
# Change reviewdog reporter if you need [github-pr-check,github-check,github-pr-review].
reporter: github-check
# Change reporter level if you need.
level: warning
language: en-US
disabled_categories: 'TYPOS,TYPOGRAPHY,CASING'
disabled_rules: 'WHITESPACE_RULE,EN_QUOTES,DASH_RULE,WORD_CONTAINS_UNDERSCORE,UPPERCASE_SENTENCE_START,ARROWS,COMMA_PARENTHESIS_WHITESPACE,UNLIKELY_OPENING_PUNCTUATION,SENTENCE_WHITESPACE,CURRENCY,EN_UNPAIRED_BRACKETS,PHRASE_REPETITION,PUNCTUATION_PARAGRAPH_END,METRIC_UNITS_EN_US,ENGLISH_WORD_REPEAT_BEGINNING_RULE,DOUBLE_PUNCTUATION,'
enabled_only: 'false'
enabled_rules: ''
enabled_categories: ''
patterns: "**.md"
- name: running misspell
# To perform misspell check even after the language tool test fails
if: success() || failure()
uses: reviewdog/action-misspell@v1
with:
github_token: ${{ secrets.github_token }}
locale: "US"
reporter: github-check
level: info
pattern: "**.md"
exclude: |
./.git/*
./.cache/*
latchset-clevis-6df9b69/.gitignore 0000664 0000000 0000000 00000000703 15201107217 0017223 0 ustar 00root root 0000000 0000000 *~
*.a
*.o
*.la
*.lo
*.log
*.m4
*.so
*.swp
*.swo
*.trs
.autotools
.cproject
.deps
.dirstamp
.libs/
.project
.settings
aclocal.m4
ar-lib
autom4te.cache
build
compile
config.guess
config.log
config.status
config.sub
configure
configure-stamp
depcomp
install-sh
libtool
ltmain.sh
Makecache
Makefile.in
Makefile
missing
tags
test-driver
src/clevis-encrypt-sss
src/clevis-decrypt-sss
src/udisks2/clevis-luks-udisks2
src/udisks2/clevis-luks-udisks2.desktop
latchset-clevis-6df9b69/.packit.yaml 0000664 0000000 0000000 00000001163 15201107217 0017451 0 ustar 00root root 0000000 0000000 jobs:
- &tests-ci-base
job: tests
trigger: pull_request
branch: master
skip_build: true
fmf_url: "https://github.com/RedHat-SP-Security/clevis-tests"
fmf_ref: "master"
targets:
- fedora-stable
- centos-stream-10-x86_64
- centos-stream-9-x86_64
identifier: "sanity"
tmt_plan: "/Plans/upstream/sanity"
tf_extra_params:
environment:
tmt:
context:
target_PR_branch: master
- <<: *tests-ci-base
targets:
- centos-stream-10-x86_64
identifier: "pkcs11"
tmt_plan: "/Plans/upstream/pkcs11-.*"
use_internal_tf: True
latchset-clevis-6df9b69/COPYING 0000664 0000000 0000000 00000104513 15201107217 0016272 0 ustar 00root root 0000000 0000000 GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Copyright (C)
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 3 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, see .
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
Copyright (C)
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
.
latchset-clevis-6df9b69/COPYING.openssl 0000664 0000000 0000000 00000001277 15201107217 0017757 0 ustar 00root root 0000000 0000000 In addition, as a special exception, the copyright holders give
permission to link the code of portions of this program with the
OpenSSL library under certain conditions as described in each
individual source file, and distribute linked combinations
including the two.
You must obey the GNU General Public License in all respects
for all of the code used other than OpenSSL. If you modify
file(s) with this exception, you may extend this exception to your
version of the file(s), but you are not obligated to do so. If you
do not wish to do so, delete this exception statement from your
version. If you delete this exception statement from all source
files in the program, then also delete it here.
latchset-clevis-6df9b69/INSTALL.md 0000664 0000000 0000000 00000003673 15201107217 0016674 0 ustar 00root root 0000000 0000000 This file contains instructions to build and install Clevis from source
# Dependencies
To build and install the Clevis software the following software packages
are required. In many cases dependencies are platform specific and so the
following sections describe them for the supported platforms.
## Linux:
* Meson
* Ninja
* C compiler
* C Library Development Libraries and Header Files
* [jose](https://github.com/latchset/jose)
* [luksmeta](https://github.com/latchset/luksmeta)
* [audit-libs](https://github.com/linux-audit/audit-userspace)
* [udisks2](https://github.com/storaged-project/udisks)
* [OpenSSL](https://github.com/openssl/openssl)
* [desktop-file-utils](https://cgit.freedesktop.org/xdg/desktop-file-utils)
* [pkg-config](https://cgit.freedesktop.org/pkg-config)
* [systemd](https://github.com/systemd)
* [dracut](https://github.com/dracutdevs/dracut)
* [tang](https://github.com/latchset/tang)
* [curl](https://github.com/curl/curl)
* [tpm2-tools](https://github.com/tpm2-software/tpm2-tools)
### Fedora
There is a package already, so the package build dependencies information can be
used to make sure that the needed packages to compile from source are installed:
```
$ sudo dnf builddep clevis
```
# Building From Source
## Configuring the Build
To configure Clevis, run `meson` which generates the build files:
```
$ meson build
```
## Compiling
Then compile the code using `ninja`:
```
$ ninja -C build -j$(nproc)
```
## Installing
Once you've built the Clevis software it can be installed with:
```
$ sudo ninja -C build install
```
This will install Clevis to a location determined at configure time.
See the output of `meson --help` for the available options. Typically,
much won't be needed besides providing an alternative --prefix option at
configure time, and maybe DESTDIR at install time if you're packaging for
a distro.
After is installed, the dracut and systemd hooks can be added to the
initramfs with:
```
$ sudo dracut -f
```
latchset-clevis-6df9b69/README.md 0000664 0000000 0000000 00000073307 15201107217 0016524 0 ustar 00root root 0000000 0000000 [](https://github.com/latchset/clevis/actions)
# Clevis
## Welcome to Clevis!
Clevis is a pluggable framework for automated decryption. It can be used to
provide automated decryption of data or even automated unlocking of LUKS
volumes.
### Encrypting Data
What does this look like? Well, the first step is encrypting some data. We do
this with a simple command:
```bash
$ clevis encrypt PIN CONFIG < PLAINTEXT > CIPHERTEXT.jwe
```
This command takes plaintext on standard input and produces an encrypted JWE
object on standard output. Besides the plaintext, we need to specify two
additional input parameters.
First, is the pin. In clevis terminology, a pin is a plugin which implements
automated decryption. We simply pass the name of a pin here.
Second, is the config. The config is a JSON object which will be passed
directly to the pin. It contains all the necessary configuration to perform
encryption and setup automated decryption.
To decrypt our JWE, we simply perform the following:
```bash
$ clevis decrypt < CIPHERTEXT.jwe > PLAINTEXT
```
Notice that no additional input or interaction is required for the decrypt
command. Let's look at some more concrete examples.
#### PIN: Tang
[Tang](http://github.com/latchset/tang) is a server implementation which
provides cryptographic binding services without the need for an escrow.
Clevis has full support for Tang. Here is an example of how to use Clevis with
Tang:
```bash
$ echo hi | clevis encrypt tang '{"url": "http://tang.local"}' > hi.jwe
The advertisement is signed with the following keys:
kWwirxc5PhkFIH0yE28nc-EvjDY
Do you wish to trust the advertisement? [yN] y
```
In this example, we encrypt the message "hi" using the Tang pin. The only
parameter needed in this case is the URL of the Tang server. During the
encryption process, the Tang pin requests the key advertisement from the
server and asks you to trust the keys. This works similarly to SSH.
Alternatively, you can manually load the advertisement using the `adv`
parameter. This parameter takes either a string referencing the file where the
advertisement is stored, or the JSON contents of the advertisement itself. When
the advertisement is specified manually like this, Clevis presumes that the
advertisement is trusted.
#### PIN: TPM1 and TPM2
Clevis provides support to encrypt a key in a Trusted Platform Module 1.2 (TPM1)
and 2.0 (TPM2) chips. The cryptographically-strong, random key used for
encryption is encrypted using the TPM chip, and is decrypted using TPM at the
time of decryption to allow clevis to decrypt the secret stored in the JWE.
For example for TPM1 pin:
```bash
$ echo hi | clevis encrypt tpm1 '{}' > hi.jwe
```
or TPM2 pin:
```bash
$ echo hi | clevis encrypt tpm2 '{}' > hi.jwe
```
Clevis store the public and private keys of the encrypted key in the JWE object,
so those can be fetched on decryption to unseal the key encrypted using the TPM
chip.
Check manual pages for `clevis-encrypt-tpm1` and `clevis-encrypt-tpm2` tools for
more options, like binding to a particular PCR registry states and/or values.
##### TPM1 PIN Limitations
To avoid prompting for a password during unlocking, the encryption and
decryption processes require that the well-known Storage Root Key (SRK) be
configured when taking ownership of the TPM 1.2 chip. This means you must have
either run the `tpm_takeownership` command
```bash
$ tpm_takeownership --srk-well-known
```
during setup or executed `tpm_changeownerauth` command
```bash
$ tpm_changeownerauth --srk --set-well-known
```
to configure it. Note that a _well-known_ key is not the same as an empty key.
> [!IMPORTANT]
> If you have changed the SRK to a _well-known_ key, remember to run
> `update-initramfs` command (on Debian-like systems)
>
> ```bash
> $ update-initramfs -u
> ```
>
> or `dracut` command (on Fedora-like systems)
>
> ```bash
> $ dracut -f
> ```
>
> afterward to recreate initramfs image, because `/var/lib/tpm` is
> included in the image. This applies to `initramfs-tools` and Dracut in
> _host-only_ mode. In Dracut's _default_ mode, `/var/lib/tpm` is already
> configured to allow access to the TPM 1.2 chip using a _well-known_ SRK.
##### Unlocking with a Separately-Encrypted `/var` Volume with TPM1 PIN
Because TPM1 PIN relies on the `tcsd` daemon from the Trousers project to
access the TPM 1.2 chip, the daemon must start early in the boot process to
unlock the root filesystem automatically. The `/var/lib/tpm` directory
contains runtime data for `tcsd` and must be available before the daemon
starts.
A minimal copy of the required `/var` files is included in the initramfs
image prepared by Clevis, so the daemon _should_ be able to start during the
_initrd bootup_ phase if everything is configured correctly. After switching
to the real root (`/`) filesystem, the _System Manager bootup_ phase starts
and `/var` is mounted from the actual target. At this point, Clevis cannot
unlock it (`tcsd` would need `/var` to unlock `/var`), so it must already be
unlocked. Refer to the instructions below for `initramfs-tools` and Dracut.
If the `/var` volume is part of the main LVM volume group (the same as the
root `/` filesystem) and is protected by the same LUKS volume, no special
configuration is needed. However, if the `/var` volume is encrypted separately
(i.e., it uses a different LUKS volume, regardless of whether it has the same
password), follow the instructions below to enable automatic unlocking with
Clevis.
###### `initramfs-tools` Initrd Bootup
`initramfs-tools` unlocks the root and swap filesystems by copying the
corresponding option lines from `/etc/crypttab` into the initramfs. To ensure
that `/var` volume options are also included, add the `initramfs` option on
Debian-like system to the relevant line in `/etc/crypttab` as shown in the
following example:
> `/etc/crypttab`
> ```bash
> …
> luks-aa0ce19c-cde9-44a2-adbd-4afb1845a959 UUID=aa0ce19c-cde9-44a2-adbd-4afb1845a959 none discard,initramfs
> …
> ```
This line corresponds to the `crypto_LUKS` volume used by the `/var` volume,
as shown by the `lsblk -fp` command:
> LVM on LUKS
> ```bash
> …
> └─/dev/vda3 crypto_LUKS 2 aa0ce19c-cde9-44a2-adbd-4afb1845a959
> └─/dev/mapper/luks-aa0ce19c-cde9-44a2-adbd-4afb1845a959 LVM2_member LVM2 001 lgk4ap-Fo39-PemI-eqKn-fxW2-e3Zt-CPGIv2
> └─/dev/mapper/separate-var xfs 767b750e-bba7-4ea7-b2b8-b1e6a2e22e43 753,3M 22% /var
> ```
The above example uses an LVM-on-LUKS encryption scheme, but the same applies to
LUKS-on-LVM — just check the `crypto_LUKS` volume UUID.
> LUKS on LVM
> ```bash
> …
> └─/dev/vda3 LVM2_member LVM2 001 lgk4ap-Fo39-PemI-eqKn-fxW2-e3Zt-CPGIv2
> └─/dev/mapper/separate-var crypto_LUKS 2 aa0ce19c-cde9-44a2-adbd-4afb1845a959
> └─/dev/mapper/luks-aa0ce19c-cde9-44a2-adbd-4afb1845a959 xfs 767b750e-bba7-4ea7-b2b8-b1e6a2e22e43 781,5M 19% /var
> ````
> [!IMPORTANT]
> After modifying `/etc/crypttab`, you must run `update-initramfs -u` (on
> Debian-like systems).
###### Dracut Initrd Bootup
Dracut automatically unlocks the root and swap filesystems. The operating
system installer ensures that the kernel command line (in `/etc/default/grub`)
contains the necessary parameters for Dracut and Systemd. Dracut considers
both the kernel command line and the lines copied from `/etc/crypttab` for
unlocking.
By default, the root and swap lines from `/etc/crypttab` are copied into the
initramfs. To ensure the `/var` volume is also unlocked, you must ensure that
its options are included and referenced by the kernel command line (as
described below).
> [!CAUTION]
> Changing the following options can render the system unbootable, potentially
> requiring a rescue DVD and expert knowledge to recover. Make a full backup
> before proceeding!
>
> For recovery, you may find these commands helpful:
>
> * `cryptsetup open /dev/ `
> * `mount /dev/mapper/ /`
> * `lvm vgscan`
> * `lvm lvdisplay -o lv_full_name,lv_dm_path`
To ensure that the `/var` options are included, add either the `x-initrd.attach`
option to the corresponding line in /etc/crypttab (to unlock the `/var` volume)
or the `x-initrd.mount` option to the corresponding line in `/etc/fstab` (to
unlock _and_ mount the `/var` volume). Using both is equivalent to
`x-initrd.mount`.
> `/etc/crypttab`
> ```bash
> …
> luks-aa0ce19c-cde9-44a2-adbd-4afb1845a959 UUID=aa0ce19c-cde9-44a2-adbd-4afb1845a959 none discard,x-initrd.attach
> …
> ```
> `/etc/fstab`
> ```bash
> …
> UUID=767b750e-bba7-4ea7-b2b8-b1e6a2e22e43 /var xfs defaults,x-systemd.device-timeout=0,x-initrd.mount 0 0
> …
> ```
Refer to the `initramfs-tools` section for instructions on finding the correct
`/etc/crypttab` line with `lsblk -fp`. The `/etc/fstab` entry is matched by the
UUID of the filesystem (see the line with `/var` in the `lsblk -fp` output).
> [!IMPORTANT]
> After changing `/etc/crypttab` and/or `/etc/fstab`, run `dracut -f`.
> [!NOTE]
> If you use `x-initrd.mount`, the volume is mounted during the _initrd bootup_
> phase. However, this is not strictly necessary. Systemd's startup order
> ensures that `/var` is mounted before `tcsd` starts in the _System Manager
> bootup_ phase, so using `x-initrd.attach` alone is sufficient.
Next, ensure that the volumes are found and unlocked. Two kernel command line
parameters in `/etc/default/grub` affect this:
* `rd.luks.uuid` – Either remove all values or add the UUID of the
`crypto_LUKS` volume (optionally prefixed by `luks-`). If this option is
present (it can appear multiple times), only the specified volumes are
initialized from `/etc/crypttab`. If it is missing, all lines from
`/etc/crypttab` are considered.
* `rd.lvm.lv` – Either remove all values or add the full LVM volume name for
`/var`. If this option is present (it can appear multiple times), only the
listed logical volumes are initialized. If it is missing, Dracut
automatically detects LVM volumes during boot.
> [!NOTE]
> The `rd.lvm.lv` option matters only in the LUKS-on-LVM case, because the
> `crypto_LUKS` volume is accessible only after the LVM logical volume is
> activated. If `rd.lvm.lv` is missing, Dracut will detect LVM volumes
> automatically. If it is present, make sure to include the `/var` full volume
> name.
For more information, see `man dracut.cmdline` and
`man systemd-cryptsetup-generator`.
> [!NOTE]
> Dracut internally uses the same Systemd options, so the same logic applies
> even if Systemd is not present in the Dracut initrd environment.
To find the correct `rd.lvm.lv` value, run:
```bash
lvs -o lv_full_name,lv_dm_path
```
This shows the logical volume's full name and Device Mapper path, which also
appears in the `lsblk -fp` output. For example, if it shows `separate/var`
(see example below), the `rd.lvm.lv` value would be `rd.lvm.lv=separate/var`:
> ```bash
> LV DMPath
> …
> separate/var /dev/mapper/separate-var
> …
> ```
Example of a kernel command line in `/etc/default/grub` with all options
present:
> `/etc/default/grub`
> ```bash
> GRUB_CMDLINE_LINUX="rd.lvm.lv=fedora/root rd.luks.uuid=luks-21a9c1b8-c202-4985-809a-aba2d6fdab01 rd.lvm.lv=separate/var rd.luks.uuid=luks-aa0ce19c-cde9-44a2-adbd-4afb1845a959 quiet"
> ```
Example of a kernel command line in `/etc/default/grub` when relying on the
configuration copied from `/etc/crypttab` and Dracut’s automatic LVM
detection:
> `/etc/default/grub`
> ```bash
> GRUB_CMDLINE_LINUX="quiet"
> ```
> [!IMPORTANT]
> After changing the kernel command line, update the Grub configuration with
> `update-grub2` (on Debian-like systems) or
> `grub2-mkconfig -o /etc/grub2.cfg` (on Fedora-like systems).
#### PIN: PKCS#11
Clevis can perform the role of a PKCS#11 application, as described in the [RFC 7512: The PKCS#11 URI Scheme](https://www.rfc-editor.org/rfc/rfc7512.html).
PKCS#11 protocol determines that a PIN (Personal Identity Number) must be configured into the hardware device so that the unlocking process is successful. Clevis will allow users to unlock a particular encrypted disk, and will provide a way to get the PIN. There will be two possibilities:
1 - Provide the PIN at boot time: In this first case, Clevis will detect PKCS#11 device and will prompt for its PIN.
In case PIN is wrong, Clevis will prompt for the PIN again. It is the user's responsibility to be aware of the possible lock / brick of the device in case PIN is unknown.
2 - Provide the PIN at Clevis configuration time: In this second case, Clevis will be configured with the PIN value.
Initially, RFC7512 defines a mechanism to specify a special kind of URI (the `pkcs11` URI), that allows identifying both a device and also the information required for it to be unlocked. Special attention deserves the parameters `pin-value`, which allow specifying the value of the PIN or the location of the PIN respectively. Clevis will understand, initially, the 'pin-value' parameter. Below you can find and example of PKCS#11 URIs using previous parameter:
* PKCS#11 URI with `pin-value` defined:
```
pkcs11:token=Software%20PKCS%2311%20softtoken;manufacturer=Snake%20Oil,%20Inc.?pin-value=the-pin
```
In the next section, Clevis configuration examples are provided, so that it is clarified what are the different options for a PKCS#11 device to be bound to an encrypted disk.
##### Clevis configuration
Clevis will provide a mechanism for the user to bind a particular PKCS#11 device to an encrypted device. The name of the new pin for Clevis will be `pkcs11`, and the way to configure it will be the same that is currently used:
```
$ clevis luks bind -h
```
```
Usage: clevis luks bind [-y] [-f] [-s SLT] [-k KEY] [-t TOKEN_ID] [-e EXISTING_TOKEN_ID] -d DEV PIN CFG
```
##### Configuration to provide a PKCS#11 URI to Clevis
As first example, a user can provide the information of the device by specifying its URI to Clevis:
```
$ clevis luks bind -d /dev/sda1 pkcs11 '{"uri": "pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;
serial=0a35ba26b062b9c5;token=clevis;id=%02;object=Encryption%20Key"}'
```
##### Configuration to bind Clevis to the first PKCS#11 device found
An additional option is to provide Clevis a configuration so that the first PKCS#11 device found by Clevis is bound. To do so, an empty URI can be provided as shown below:
```
$ clevis luks bind -d /dev/sda1 pkcs11 '{"uri": "pkcs11:"}'
```
An even shorter configuration command, equivalent to the previous one, is shown below:
```
$ clevis luks bind -d /dev/sda1 pkcs11 '{}'
```
In this case, Clevis will be responsible for the detection of the device and, if no device is found, responsible for dumping the corresponding error.
It must be clarified that providing an empty URI will make Clevis to prompt also to select one of the available keys matched on the token to avoid accidentally encryption with unwanted keys.
##### Configuration to provide a module path to Clevis PKCS#11 pin:
A module path can be provided to Clevis, so that it uses that module to access a device. This is only required in case the card is not supported by underlying Clevis software (OpenSC). For this reason, the module path field is completely optional. To provide the module location the user can provide the "module-path" to the "uri" Clevis configuration:
```
$ clevis-luks-bind -d /dev/sda1 pkcs11 '{"uri": "pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;
serial=0a35ba26b062b9c5;token=clevis;id=%02;object=Encryption%20Key?
module-path=/usr/local/lib64/libmypkcs11.so"}'
```
As it happens with the rest of devices, encrypted disks that have been bound to a PKCS#11 device can be checked with `clevis luks list` command:
```
$ clevis luks list -d /dev/sda1
```
```
1: pkcs11 '{"uri": "pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;
serial=0a35ba26b062b9c5;token=clevis;id=%02;object=Encryption%20Key?
module-path=/usr/local/lib64/libmypkcs11.so"}'
```
##### Configuration to provide PKCS#11 tool a different mechanism
In the first phase of development, Clevis will be used in top of OpenSC to provide PKCS#11 functionality.
OpenSC, and, in particular, `pkcs11-tool`, provides an option to indicate the mechanism to use for decryption.
For testing purposes, some libraries, such as [SoftHSM](https://www.opendnssec.org/softhsm)), don't work with default `pkcs11-tool` mechanism,
so it is required to provide a particular mechanism to use. For this reason, Clevis can be provided with
the mechanism to use, in case the default one, `RSA-PKCS-OAEP`, is not valid:
```
$ clevis luks bind -d /dev/sda1 pkcs11 '{"uri": "pkcs11:", "mechanism":"RSA-PKCS"}'
```
In order to check available mechanisms for a specific token, command `pkcs11-tool -M` can be used:
```
$ pkcs11-tool -M
Using slot 0 with a present token (0x0)
Supported mechanisms:
SHA-1, digest
...
SHA512, digest
MD5, digest
...
RSA-PKCS-KEY-PAIR-GEN, keySize={2048,4096}, generate_key_pair
```
At this time, only RSA mechanisms are supported by Clevis. Due to a limitation of the rest of the algorithms, no other asymmetric cryptographic algorithm can do encryption easily. The ECC supports only signatures and key derivation, but not encryption. The encryption operation can be somehow constructed from the key derivation, but it is not a straightforward operation.
It must be highlighted that the RSA-PKCS mechanism (PKCS#1.5 padding for encryption) is [considered to be not secure](https://people.redhat.com/~hkario/marvin/) and it is mostly provided for compatibility, but it is not recommended using it in production.
##### Multi-device configuration
Clevis will allow specifying the slot where a PKCS#11 device is located through the parameters provided to the URI:
```
$ clevis luks bind -d /dev/sda1 pkcs11 '{"uri": "pkcs11:slot-id=0"}'
```
It must be clarified that providing just the slot information will make Clevis to guess one of the available keys matched on the token in the selected slot, which could cause accidentally encryption with unwanted keys. **It is not recommended to use slot as device selector, as slot id is a number that is not guaranteed to be stable across PKCS#11 module initializations**. However, there are certain libraries and modules that provide stable slot identifiers, so it can be used for these particular cases.
There are two better options to distinguish between different PKCS#11 devices:
1 - Multi-device configuration with public key object (**recommended**):
With recent versions of `OpenSC` (from OpenSC 0.26.0 release) onwards, `pkcs11-tool`, which is used by Clevis to handle most of the PKCS#11 commands, the PKCS#11 URI is dumped for both the tokens and the objects of a particular token:
```
$ pkcs11-tool -L | grep uri
uri : pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;serial=42facd1f749ece7f;token=clevis
uri : pkcs11:model=PKCS%2315%20emulated;manufacturer=OpenPGP%20project;serial=000f06080f4f;token=OpenPGP%20card%20%28User%20PIN%29
$ pkcs11-tool -O --slot-index 1 --type pubkey | grep uri
ising slot 0 with a present token (0x0)
uri: pkcs11:model=PKCS%2315%20emulated;manufacturer=OpenPGP%20project;serial=000f06080f4f;token=OpenPGP%20card%20%28User%20PIN%29;id=%03;object=Authentication%20key;type=public
```
In this particular cases, when multiple PKCS#11 devices exist, select the public key of the particular device and bind it to Clevis:
```
$ clevis luks bind -d /dev/sda pkcs11 '{"uri":"pkcs11:model=PKCS%2315%20emulated;manufacturer=OpenPGP%20project;serial=000f06080f4f;token=OpenPGP%20card%20%28User%20PIN%29;id=%03;object=Authentication%20key;type=public"}'
```
**In case you are using module-path, you will have to use the one returned when providing --module option:**
```
$ pkcs11-tool --module /usr/lib64/libykcs11.so -O --type pubkey | grep uri
/usr/local/bin/pkcs11-tool.manual --module /usr/lib64/libykcs11.so -O --type pubkey | grep uri
Using slot 0 with a present token (0x0)
uri: pkcs11:model=YubiKey%20YK5;manufacturer=Yubico%20%28www.yubico.com%29;serial=28083311;token=YubiKey%20PIV%20%2328083311;id=%03;object=Public%20key%20for%20Key%20Management;type=public
uri: pkcs11:model=YubiKey%20YK5;manufacturer=Yubico%20%28www.yubico.com%29;serial=28083311;token=YubiKey%20PIV%20%2328083311;id=%19;object=Public%20key%20for%20PIV%20Attestation;type=public
$ clevis luks bind -d /dev/sda pkcs11 '{"uri":"pkcs11:model=YubiKey%20YK5;manufacturer=Yubico%20%28www.yubico.com%29;serial=28083311;token=YubiKey%20PIV%20%2328083311;id=%03;object=Public%20key%20for%20Key%20Management;type=public;module-path=/usr/lib64/libykcs11.so"}'
```
2 - Multi-device configuration with serial + token specification:
**For versions where `pkcs11-tool` does not dump the URI for the tokens/objects**, specific identification will be "tried" by Clevis by using the device `serial` + `token label` pair.
In this type of scenarios, identification can be performed with these two parameters, although `model` should be provided also to ease Clevis informing about the device when asking for the PIN:
```
# pkcs11-tool -L | grep "token label\|serial"
token label : OpenPGP card (User PIN)
serial num : 42facd1f749ece7f
$ clevis luks bind -d /dev/sda pkcs11 '{"uri":"pkcs11:model=PKCS%2315%20emulated;serial=000f06080f4f;token=OpenPGP%20card%20%28User%20PIN%29"}'
```
Remember that special characters must be defined in percent mode, as defined in [RFC 7512: The PKCS#11 URI Scheme](https://www.rfc-editor.org/rfc/rfc7512.html).
##### Clevis PKCS#11 installation and configuration
For installation and configuration of the clevis PKCS#11 feature, next steps must be followed:
1 - Install Clevis required dependencies, including PKCS#11 dependencies:
```
$ sudo dnf install clevis-pin-pkcs11
```
2 - The PKCS11 device must be accessible by “pkcs11-tool”:
```
$ pkcs11-tool -L
pkcs11-tool -L
Available slots:
Slot 0 (0x0): Yubico YubiKey OTP+CCID 00 00
token label : clevis
...
uri : pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;serial=42facd1f749ece7f;token=clevis
```
3 - Configure device to bind with clevis:
```
$ sudo clevis luks bind -d /dev/sda5 pkcs11 '{"uri":"pkcs11:"}'
```
In case it is required to provide the module to use, it can be done through `module-path` URI parameter:
```
$ sudo clevis luks bind -d /dev/sda5 pkcs11 '{"uri":"pkcs11:module-path=/usr/lib64/libykcs11.so.2"}'
```
4 - Enable clevis-luks-pkcs11-askpass.socket unit:
```
$ sudo systemctl enable --now clevis-luks-pkcs11-askpass.socket
```
5 - /etc/crypttab configuration:
For PKCS#11 feature to work appropriately, `/etc/crypttab` file must be configured so that systemd uses an AF\_UNIX socket to wait for the keyphrase that will unlock the disk and not to prompt it through the console.
Clevis PKCS#11 unit file will configure a socket in path `/run/systemd/clevis-pkcs11.sock` to send and receive information about disk unlocking. For disks that will be unlocked through PKCS#11 Clevis pin, that socket file must be configured as key file. So, next change must be introduced in `/etc/crypttab` for unlocking to take place:
```
$ sudo diff -Nuar /etc/crypttab.ori /etc/crypttab
--- /etc/crypttab.ori 2024-07-04 10:46:16.295073739 +0200
+++ /etc/crypttab 2024-07-03 17:14:27.764743860 +0200
@@ -1 +1,2 @@
-luks-6e38d5e1-7f83-43cc-819a-7416bcbf9f84 UUID=6e38d5e1-7f83-43cc-819a-7416bcbf9f84 - -
+luks-6e38d5e1-7f83-43cc-819a-7416bcbf9f84 UUID=6e38d5e1-7f83-43cc-819a-7416bcbf9f84 /run/systemd/clevis-pkcs11.sock keyfile-timeout=30s
```
It is highly recommended setting a `keyfile-timeout` option to configure a fall-through mechanism in case some unlocking error occurs and passphrase is required to be entered manually through console.
6 - Reboot and test:
System should boot and ask for the PKCS#11 device PIN, and decrypt the corresponding configured encrypted disk only in case PIN is correct.
7 - In case no boot process needs to be tested, encrypt and decrypt with next command (note it is necessary to provide the PIN value for it to work appropriately) and check encryption/decryption of a string can be performed with this one-liner, and no error takes place:
```
$ echo "top secret" | clevis encrypt pkcs11 '{"uri":"pkcs11:module-path=/usr/lib64/libykcs11.so.2?pin-value=123456"}' | clevis decrypt
```
The `top secret` string should be returned
#### PIN: Shamir Secret Sharing
Clevis provides a way to mix pins together to provide sophisticated unlocking
policies. This is accomplished by using an algorithm called Shamir Secret
Sharing (SSS).
SSS is a thresholding scheme. It creates a key and divides it into a number of
pieces. Each piece is encrypted using another pin (possibly even SSS
recursively). Additionally, you define the threshold `t`. If at least `t`
pieces can be decrypted, then the encryption key can be recovered and
decryption can succeed.
Here is an example where we use the SSS pin with both the Tang and TPM2 pins:
```bash
$ echo hi | clevis encrypt sss \
'{"t": 2, "pins": {"tpm2": {"pcr_ids": "0"}, "tang": {"url": "http://tang.local"}}}' \
> hi.jwe
```
In the above example, we define two child pins and have a threshold of 2.
This means that during decryption **both** child pins must succeed in order for
SSS itself to succeed.
Here is another example where we use just the Tang pin:
```bash
$ echo hi | clevis encrypt sss \
'{"t": 1, "pins": {"tang": [{"url": "http://server1.local/key"}, {"url": "http://server2.local/key"}]}}' \
> hi.jwe
```
In this example, we define two child instances of the Tang pin - each with its
own configuration. Since we have a threshold of 1, if **either** of the Tang
pin instances succeed during decryption, SSS will succeed.
### Binding LUKS Volumes
Clevis can be used to bind a LUKS volume using a pin so that it can be
automatically unlocked.
How this works is rather simple. We generate a new, cryptographically strong
key. This key is added to LUKS as an additional passphrase. We then encrypt
this key using Clevis, and store the output JWE inside the LUKS header using
[LUKSMeta](http://github.com/latchset/luksmeta).
Here is an example where we bind `/dev/sda1` using the Tang pin:
```bash
$ sudo clevis luks bind -d /dev/sda1 tang '{"url": "http://tang.local"}'
The advertisement is signed with the following keys:
kWwirxc5PhkFIH0yE28nc-EvjDY
Do you wish to trust the advertisement? [yN] y
Enter existing LUKS password:
```
Upon successful completion of this binding process, the disk can be unlocked
using one of the provided unlockers.
#### Network based unlocking
If you want to use network based unlocking you will need to specify `rd.neednet=1` as kernel argument or use `--hostonly-cmdline` when creating with dracut.
If you're using **Tang** with TLS (Example: `'{"url": "https://tang.remote"}'`), the folder `/etc/ssl` should be included in the initramfs image, `--include /etc/ssl /etc/ssl --force` when creating with dracut.
#### Unlocker: Dracut
The Dracut unlocker attempts to automatically unlock volumes during early
boot. This permits automated root volume encryption. Enabling the Dracut
unlocker is easy. Just rebuild your initramfs after installing Clevis:
```bash
$ sudo dracut -f
```
Upon reboot, you will be prompted to unlock the volume using a password. In
the background, Clevis will attempt to unlock the volume automatically. If it
succeeds, the password prompt will be cancelled and boot will continue.
#### Unlocker: Initramfs-tools
When using Clevis with initramfs-tools, in order to rebuild your
initramfs you will need to run:
```bash
sudo update-initramfs -u -k 'all'
```
Upon reboot, it will behave exactly as if using Dracut.
#### Unlocker: UDisks2
Our UDisks2 unlocker runs in your desktop session. You should not need to
manually enable it; just install the Clevis UDisks2 unlocker and restart your
desktop session. The unlocker should be started automatically.
This unlocker works almost exactly the same as the Dracut unlocker. If you
insert a removable storage device that has been bound with Clevis, we will
attempt to unlock it automatically in parallel with a desktop password prompt.
If automatic unlocking succeeds, the password prompt will be dismissed without
user intervention.
#### Unlocker: Clevis command
A LUKS device bound to a Clevis policy can also be unlocked by using the clevis
luks unlock command.
```bash
$ sudo clevis luks unlock -d /dev/sda1
```
#### Unbinding LUKS volumes
LUKS volumes can be unbound using the clevis luks unbind command. For example:
```bash
$ sudo clevis luks unbind -d /dev/sda1 -s 1
```
#### Listing pins bound to LUKS volumes
The pins that are bound to a given LUKS volume can be listed using the clevis
luks list command. For example:
```bash
$ sudo clevis luks list -d /dev/sda1
```
## Installing Clevis
Please don't install Clevis directly. Instead, use your preferred
distribution's packages.
### Fedora 24+
This command installs the core Clevis commands, the Dracut, Systemd and LUKs unlockers,
and the UDisks2 unlocker, respectively.
```bash
$ sudo dnf install clevis clevis-dracut clevis-udisks2 clevis-systemd clevis-luks
```
## Manual compilation
As remarked in the previous section, **it is suggested not to install Clevis directly**.
However, in case no Clevis packages exist for your Linux distribution, the steps to
manually compile and install Clevis are next ones:
* Download latest version of the binaries (note that the latest version could change):
```bash
$ wget https://github.com/latchset/clevis/releases/download/v21/clevis-21.tar.xz
```
* Untar the binaries file:
```bash
$ tar Jxvf clevis-21.tar.xz
```
* Create build directory and change path to it:
```bash
$ cd clevis-21
$ mkdir build
$ cd build
```
* Execute `meson` to setup compilation:
```bash
$ meson setup ..
```
* Compile with `ninja` command:
```bash
$ ninja
```
* Install with `ninja install` command (you will need root permissions for it):
```bash
$ sudo ninja install
```
latchset-clevis-6df9b69/meson.build 0000664 0000000 0000000 00000003444 15201107217 0017402 0 ustar 00root root 0000000 0000000 project('clevis', 'c', license: 'GPL3+',
version: '23',
default_options: 'c_std=c99'
)
libexecdir = join_paths(get_option('prefix'), get_option('libexecdir'))
sysconfdir = join_paths(get_option('prefix'), get_option('sysconfdir'))
bindir = join_paths(get_option('prefix'), get_option('bindir'))
libdir = join_paths(get_option('prefix'), get_option('libdir'))
data = configuration_data()
data.set('libexecdir', libexecdir)
data.set('sysconfdir', sysconfdir)
data.set('bindir', bindir)
data.set('libdir', libdir)
add_project_arguments(
'-Wall',
'-Wextra',
'-Werror',
'-Wstrict-aliasing',
'-Wchar-subscripts',
'-Wformat-security',
'-Wmissing-declarations',
'-Wmissing-prototypes',
'-Wnested-externs',
'-Wpointer-arith',
'-Wshadow',
'-Wsign-compare',
'-Wstrict-prototypes',
'-Wtype-limits',
'-Wunused-function',
'-Wno-missing-field-initializers',
'-Wno-unused-parameter',
'-Wno-unknown-pragmas',
'-D_DEFAULT_SOURCE',
'-D_POSIX_C_SOURCE=200112L',
'-DBINDIR="' + bindir + '"',
'-DCLEVIS_USER="' + get_option('user') + '"',
'-DCLEVIS_GROUP="' + get_option('group') + '"',
language: 'c'
)
jansson = dependency('jansson', version: '>=2.10', required: false)
jose = dependency('jose', version: '>=8')
a2x = find_program('a2x', required: false)
bins = []
mans = []
subdir('src')
install_data(bins, install_dir: bindir)
if a2x.found()
foreach m : mans
custom_target(m.split('/')[-1], input: m + '.adoc', output: m.split('/')[-1],
command: [a2x, '-f', 'manpage', '-D', meson.current_build_dir(), '@INPUT@'],
install_dir: join_paths(get_option('mandir'), 'man' + m.split('.')[-1]),
install: true
)
endforeach
else
warning('Will not build man pages due to missing dependencies!')
endif
summary('TPM 1.2 pin', get_option('tpm1'), section: 'Features')
latchset-clevis-6df9b69/meson_options.txt 0000664 0000000 0000000 00000000472 15201107217 0020673 0 ustar 00root root 0000000 0000000 option('user', type: 'string', value: 'clevis', description: 'Unprivileged user for secure clevis operations')
option('group', type: 'string', value: 'clevis', description: 'Unprivileged group for secure clevis operations')
option('tpm1', type: 'feature', value: 'auto', description: 'Enable TPM 1.2 pin support')
latchset-clevis-6df9b69/src/ 0000775 0000000 0000000 00000000000 15201107217 0016022 5 ustar 00root root 0000000 0000000 latchset-clevis-6df9b69/src/bash/ 0000775 0000000 0000000 00000000000 15201107217 0016737 5 ustar 00root root 0000000 0000000 latchset-clevis-6df9b69/src/bash/clevis 0000664 0000000 0000000 00000002223 15201107217 0020146 0 ustar 00root root 0000000 0000000 # bash completion support for clevis.
_clevis()
{
local dir prev cur field
dir=$(dirname "$(command -v clevis)")
prev=${COMP_WORDS[COMP_CWORD-1]}
cur=${COMP_WORDS[COMP_CWORD]}
field=$((COMP_CWORD + 1))
case "${prev}" in
-d)
cur=${cur:=/dev/}
_filedir
return
;;
-k)
_filedir
return
;;
esac
local name suggestions
if [[ "${COMP_WORDS[COMP_CWORD-1]}" == "clevis" ]]; then
name="clevis-*"
fi
if [[ "${COMP_WORDS[COMP_CWORD-2]}" == "clevis" ]]; then
name="clevis-${COMP_WORDS[COMP_CWORD-1]}-*"
fi
suggestions=
if [[ -n "${name}" ]]; then
suggestions=$(find "${dir}" -name "${name}" -executable \
| cut -d '-' -f"${field}" | sort -u)
local word
if [[ -n "${cur}" ]]; then
suggestions=$(for word in "${suggestions[@]}"; do \
echo "${word}" | grep -- "${cur}"; done)
fi
fi
COMPREPLY=($(compgen -W "${suggestions}" -- "${cur}"))
}
complete -F _clevis clevis
# vim: set ts=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
latchset-clevis-6df9b69/src/bash/meson.build 0000664 0000000 0000000 00000000432 15201107217 0021100 0 ustar 00root root 0000000 0000000 bashcomp = dependency('bash-completion', required: false)
if bashcomp.found()
bashcompdir = bashcomp.get_pkgconfig_variable('completionsdir')
install_data('clevis', install_dir: bashcompdir)
else
warning('Will not install bash completion due to missing dependencies!')
endif
latchset-clevis-6df9b69/src/clevis 0000775 0000000 0000000 00000003220 15201107217 0017232 0 ustar 00root root 0000000 0000000 #!/bin/bash -e
# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
#
# Copyright (c) 2017 Red Hat, Inc.
# Author: Nathaniel McCallum
#
# 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 3 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, see .
#
function findexe() {
[ $# -eq 1 ] || return 1
while read -r -d: path; do
[ -f "$path/$1" ] && [ -x "$path/$1" ] && echo "$path/$1" && return 0
done <<< "$PATH:"
return 1
}
cmd=clevis
input_commands="$cmd $@"
while [ $# -gt 0 ]; do
[[ "$1" =~ ^- ]] && break
cmd="$cmd-$1"
shift
exe="$(findexe "$cmd")" && exec "$exe" "$@"
done
exec >&2
if [ "$cmd" != "clevis" ];
then
echo
echo "Command '$input_commands' is invalid"
fi
echo
echo "Usage: clevis COMMAND [OPTIONS]"
echo
max=0
for f in "$0"-*; do
[ -f "$f" ] && [ -x "$f" ] || continue
f="${f##*/}"
[ ${#f} -gt $max ] && max=${#f}
done
for f in "$0"-*; do
[ -f "$f" ] && [ -x "$f" ] || continue
summ="$("$f" --summary 2>/dev/null)" || continue
f="${f##*/}"
printf " %-*s %s\n" "$max" "${f//-/ }" "$summ"
done
echo
exit 2
latchset-clevis-6df9b69/src/clevis-decrypt 0000775 0000000 0000000 00000003174 15201107217 0020712 0 ustar 00root root 0000000 0000000 #!/bin/bash -e
# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
#
# Copyright (c) 2017 Red Hat, Inc.
# Author: Nathaniel McCallum
#
# 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 3 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, see .
#
SUMMARY="Decrypts using the policy defined at encryption time"
function findexe() {
[ $# -eq 1 ] || return 1
while read -r -d: path; do
[ -f "$path/$1" ] && [ -x "$path/$1" ] && echo "$path/$1" && return 0
done <<< "$PATH:"
return 1
}
if [ $# -eq 1 ] && [ "$1" == "--summary" ]; then
echo "$SUMMARY"
exit 0
fi
if ! [ -t 0 ]; then
read -r -d . hdr
if ! pin="$(jose fmt -q "$hdr" -SyOg clevis -Og pin -Su-)"; then
echo "JWE is missing the required 'clevis.pin' header property!" >&2
exit 1
fi
if ! cmd="$(findexe clevis-decrypt-"$pin")"; then
echo "Unable to locate pin '$pin'!" >&2
exit 1
fi
(echo -n "$hdr."; /bin/cat) | "$cmd"
exit $?
fi
exec >&2
echo
echo "Usage: clevis decrypt < JWE > PLAINTEXT"
echo
echo "$SUMMARY"
echo
exit 2
latchset-clevis-6df9b69/src/clevis-decrypt.1.adoc 0000664 0000000 0000000 00000000657 15201107217 0021756 0 ustar 00root root 0000000 0000000 CLEVIS-DECRYPT(1)
=================
:doctype: manpage
== NAME
clevis-decrypt - Decrypts using the policy defined at encryption time
== SYNOPSIS
*clevis decrypt* CONFIG < JWE > PT
== OVERVIEW
The *clevis decrypt* command decrypts data using the policy defined at
encryption time. The specific decryption pin is inferred during decryption.
There are no parameters.
== SEE ALSO
link:clevis-decrypt.1.adoc[*clevis-decrypt*(1)]
latchset-clevis-6df9b69/src/clevis.1.adoc 0000664 0000000 0000000 00000011077 15201107217 0020304 0 ustar 00root root 0000000 0000000 CLEVIS(1)
=========
:doctype: manpage
== NAME
clevis - Automated decryption policy framework
== SYNOPSIS
*clevis* COMMAND [OPTIONS]
== OVERVIEW
Clevis is a framework for automated decryption policy. It allows you to define
a policy at encryption time that must be satisfied for the data to decrypt.
Once this policy is met, the data is decrypted.
Clevis is pluggable. Our plugins are called pins. The job of a pin is to
take a policy as its first argument and plaintext on standard input and to
encrypt the data so that it can be automatically decrypted if the policy is
met. Lets walk through an example.
== TANG BINDING
Clevis provides support for the Tang network binding server. Tang provides
a stateless, lightweight alternative to escrows. Encrypting data using the Tang
pin works much like our HTTP pin above:
$ clevis encrypt tang '{"url":"http://tang.srv"}' < PT > JWE
The advertisement contains the following signing keys:
_OsIk0T-E2l6qjfdDiwVmidoZjA
Do you wish to trust these keys? [ynYN] y
As you can see above, Tang utilizes a trust-on-first-use workflow.
Alternatively, Tang can perform entirely offline encryption if you pre-share
the server advertisement. Decryption, too works like our first example:
$ clevis decrypt < JWE > PT
For more information, see link:clevis-encrypt-tang.1.adoc[*clevis-encrypt-tang*(1)].
== TPM2 BINDING
Clevis provides support to encrypt a key in a Trusted Platform Module 2.0 (TPM2)
chip. The cryptographically-strong, random key used for encryption is encrypted
using the TPM2 chip, and then at decryption time is decrypted using the TPM2 to
allow clevis to decrypt the secret stored in the JWE.
Encrypting data using the tpm2 pin works the same than the pins mentioned above:
$ clevis encrypt tpm2 '{}' < PT > JWE
The pin has reasonable defaults for its configuration, but a different hierarchy,
hash, and key algorithms can be chosen if the defaults used are not suitable.
Decryption also works similar to other pins, only the JWE needs to be provided:
$ clevis decrypt < JWE > PT
Note that like other pins no configuration is used for decryption, this is due
clevis storing the public and private keys to unseal the TPM2 encrypted object
in the JWE so clevis can fetch that information from there.
For more information see link:clevis-encrypt-tpm2.1.adoc[*clevis-encrypt-tpm2*(1)].
== SHAMIR'S SECRET SHARING
Clevis provides a way to mix pins together to create sophisticated unlocking
and high availability policies. This is accomplished by using an algorithm
called Shamir's Secret Sharing (SSS).
SSS is a thresholding scheme. It creates a key and divides it into a number of
pieces. Each piece is encrypted using another pin (possibly even SSS
recursively). Additionally, you define the threshold *t*. If at least *t*
pieces can be decrypted, then the encryption key can be recovered and
decryption can succeed.
For example, let's create a high-availability setup using Tang:
$ cfg='{"t":1,"pins":{"tang":[{"url":...},{"url":...}]}}'
$ clevis encrypt sss "$cfg" < PT > JWE
In this policy, we are declaring that we have a threshold of 1, but that there
are multiple key fragments encrypted using different Tang servers. Since our
threshold is 1, so long as any of the Tang servers are available, decryption
will succeed. As always, decryption is simply:
$ clevis decrypt < JWE > PT
For more information, see link:clevis-encrypt-tang.1.adoc[*clevis-encrypt-tang*(1)].
== LUKS BINDING
Clevis can be used to bind an existing LUKS volume to its automation policy.
This is accomplished with a simple command:
$ clevis luks bind -d /dev/sda tang '{"url":...}'
This command performs four steps:
1. Creates a new key with the same entropy as the LUKS master key -- maximum entropy bits is 256.
2. Encrypts the new key with Clevis.
3. Stores the Clevis JWE in the LUKS header.
4. Enables the new key for use with LUKS.
This disk can now be unlocked with your existing password as well as with
the Clevis policy. Clevis provides two unlockers for LUKS volumes. First,
we provide integration with Dracut to automatically unlock your root volume
during early boot. Second, we provide integration with UDisks2 to
automatically unlock your removable media in your desktop session.
For more information, see link:clevis-luks-bind.1.adoc[*clevis-luks-bind*(1)].
== SEE ALSO
link:clevis-encrypt-tang.1.adoc[*clevis-encrypt-tang*(1)],
link:clevis-encrypt-tpm2.1.adoc[*clevis-encrypt-tpm2*(1)],
link:clevis-encrypt-sss.1.adoc[*clevis-encrypt-sss*(1)],
link:clevis-luks-bind.1.adoc[*clevis-luks-bind*(1)],
link:clevis-decrypt.1.adoc[*clevis-decrypt*(1)]
latchset-clevis-6df9b69/src/initramfs-tools/ 0000775 0000000 0000000 00000000000 15201107217 0021154 5 ustar 00root root 0000000 0000000 latchset-clevis-6df9b69/src/initramfs-tools/hooks/ 0000775 0000000 0000000 00000000000 15201107217 0022277 5 ustar 00root root 0000000 0000000 latchset-clevis-6df9b69/src/initramfs-tools/hooks/clevis.in 0000775 0000000 0000000 00000016050 15201107217 0024121 0 ustar 00root root 0000000 0000000 #!/bin/bash
#
# Copyright (c) 2017 Shawn Rose
# Author: Shawn Rose
#
# 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 3 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, see .
#
PREREQ="cryptroot"
prereqs()
{
echo "$PREREQ"
}
case $1 in
prereqs)
prereqs
exit 0
;;
esac
. @initramfstoolsdir@/hook-functions
die() {
code="$1"
msg="$2"
echo " (ERROR): $msg" >&2
exit $1
}
find_binary() {
bin_name="$1"
resolved=$(command -v ${bin_name})
[ -z "$resolved" ] && die 1 "Unable to find ${bin_name}"
echo "$resolved"
}
find_library() {
lib_name="$1"
for lib_path in \
{/usr,}/libexec/${lib_name} \
{/usr,}/lib64/${lib_name} \
{/usr,}/lib/${lib_name} \
/usr/lib/`uname -m`-linux-gnu*/${lib_name} \
; do
if [ -e "$lib_path" ]; then
echo "$lib_path"
return
fi
done
die 1 "Unable to find library ${lib_name}"
}
if [ -n "${FORCE_CLEVIS}" ] && [ "${FORCE_CLEVIS}" != "n" ]; then
for f in /sbin/cryptsetup /sbin/dmsetup /lib/cryptsetup/askpass; do
if [ ! -e "${DESTDIR}${f}" ]; then
die 2 "cryptsetup utility '$f' wasn't found in the generated ramdisk image. "
fi
done
fi
copy_exec @bindir@/clevis-decrypt-tang || die 1 "@bindir@/clevis-decrypt-tang not found"
copy_exec @bindir@/clevis-decrypt-sss || die 1 "@bindir@/clevis-decrypt-sss not found"
copy_exec @bindir@/clevis-decrypt-null || die 1 "@bindir@/clevis-decrypt-null not found"
copy_exec @bindir@/clevis-decrypt || die 1 "@bindir@/clevis-decrypt not found"
copy_exec @bindir@/clevis-luks-common-functions || die 1 "@bindir@/clevis-luks-common-functions not found"
copy_exec @bindir@/clevis-luks-list || die 1 "@bindir@/clevis-luks-list not found"
if [ -x @bindir@/clevis-decrypt-tpm2 ]; then
copy_exec @bindir@/clevis-decrypt-tpm2 || die 1 "@bindir@/clevis-decrypt-tpm2 not found"
tpm2_creatprimary_bin=$(find_binary "tpm2_createprimary")
tpm2_unseal_bin=$(find_binary "tpm2_unseal")
tpm2_load_bin=$(find_binary "tpm2_load")
tpm2_flushcontext=$(find_binary "tpm2_flushcontext")
copy_exec "${tpm2_creatprimary_bin}" || die 1 "Unable to copy ${tpm2_creatprimary_bin}"
copy_exec "${tpm2_unseal_bin}" || die 1 "Unable to copy ${tpm2_unseal_bin}"
copy_exec "${tpm2_load_bin}" || die 1 "Unable to copy ${tpm2_load_bin}"
copy_exec "${tpm2_flushcontext}" || die 1 "Unable to copy ${tpm2_flushcontext}"
for _LIBRARY in @libdir@/libtss2-tcti-device.so*; do
if [ -e "${_LIBRARY}" ]; then
copy_exec "${_LIBRARY}" || die 2 "Unable to copy ${_LIBRARY}"
fi
done
manual_add_modules tpm_crb
manual_add_modules tpm_tis
fi
if [ -x @bindir@/clevis-decrypt-tpm1 ]; then
copy_exec @bindir@/clevis-decrypt-tpm1 || die 1 "@bindir@/clevis-decrypt-tpm1 not found"
copy_exec @libexecdir@/clevis-luks-tpm1-functions || die 1 "@libexecdir@/clevis-luks-tpm1-functions not found"
copy_exec @libdir@/libclevis-tpm1-tcsd-preload.so || die 1 "@libdir@/libclevis-tpm1-tcsd-preload.so not found"
tcsd_bin=$(find_binary "tcsd")
# libgcc_s.so.* is no longer installed for gcc 2.34+ (no link to libpthread)
libgcc_s=$(find_library "libgcc_s.so.[1-9]")
tpm_version_bin=$(find_binary "tpm_version")
tpm_unsealdata_bin=$(find_binary "tpm_unsealdata")
copy_exec "${tpm_version_bin}" || die 1 "Unable to copy ${tpm_version_bin}"
copy_exec "${tpm_unsealdata_bin}" || die 1 "Unable to copy ${tpm_unsealdata_bin}"
copy_exec "${tcsd_bin}" || die 1 "Unable to copy ${tcsd_bin}"
copy_exec "${libgcc_s}" || die 1 "Unable to copy ${libgcc_s}"
copy_file config /etc/tcsd.conf || die 2 "Unable to copy /etc/tcsd.conf"
mkdir -p "${DESTDIR}/var/lib/tpm" || die 2 "Unable to create /var/lib/tpm"
cp /var/lib/tpm/* "${DESTDIR}/var/lib/tpm/" || die 2 "Unable to copy /var/lib/tpm"
chown -R tss:tss "${DESTDIR}/var/lib/tpm" || die 2 "Unable to change owner of /var/lib/tpm"
chmod -R u=rwX,go= "${DESTDIR}/var/lib/tpm" || die 2 "Unable to change permissions of /var/lib/tpm"
if (( $(umask) & 0004 )); then
# Root-only readable initrd filesystem, we need to run as root
# shellcheck disable=SC2154 # $verbose is a dracut variable
[ "${verbose}" = "y" ] && echo "Forcing tcsd to run as root"
sed -i 's/^\([ ]*remote_ops\)/#\1/' "${DESTDIR}/etc/tcsd.conf"
echo "TCSD_NO_PRIVILEGE_DROP=1" >> "${DESTDIR}/conf/conf.d/clevis"
fi
mkdir -p "${DESTDIR}/lib/udev/rules.d" || die 2 "Unable to create /lib/udev/rules.d"
# shellcheck disable=SC2043
for rule in 60-tpm-udev.rules; do
if [ -e /etc/udev/rules.d/$rule ]; then
copy_file udev_rule /etc/udev/rules.d/$rule "/lib/udev/rules.d" || die 2 "Unable to copy $rule"
elif [ -e /lib/udev/rules.d/$rule ]; then
copy_file udev_rule /lib/udev/rules.d/$rule "/lib/udev/rules.d" || die 2 "Unable to copy $rule"
fi
done
echo "root:x:0:0:root:/root:/bin/bash" >> "${DESTDIR}/etc/passwd"
echo "root:x:0:" >> "${DESTDIR}/etc/group"
group_id=`id -g tss` || die 2 "Unable to get tss group ID"
user_id=`id -u tss` || die 2 "Unable to get tss user ID"
echo "tss:x:$user_id:$group_id::/var/lib/tpm:/bin/false" >> "${DESTDIR}/etc/passwd"
echo "tss:x:$group_id:" >> "${DESTDIR}/etc/group"
echo "127.0.0.1 localhost" >> "${DESTDIR}/etc/hosts"
echo "::1 localhost ip6-localhost ip6-loopback" >> "${DESTDIR}/etc/hosts"
echo "ff02::1 ip6-allnodes" >> "${DESTDIR}/etc/hosts"
echo "ff02::2 ip6-allrouters" >> "${DESTDIR}/etc/hosts"
manual_add_modules tpm_tis
fi
luksmeta_bin=$(find_binary "luksmeta")
jose_bin=$(find_binary "jose")
copy_exec "${luksmeta_bin}" || die 2 "Unable to copy ${luksmeta_bin}"
copy_exec "${jose_bin}" || die 2 "Unable to copy ${jose_bin}"
copy_exec @bindir@/clevis || die 1 "@bindir@/clevis not found"
curl_bin=$(find_binary "curl")
awk_bin=$(find_binary "awk")
bash_bin=$(find_binary "bash")
copy_exec "${curl_bin}" || die 2 "Unable to copy ${curl_bin} to initrd image"
copy_exec "${awk_bin}" || die 2 "Unable to copy ${awk_bin} to initrd image"
copy_exec "${bash_bin}" || die 2 "Unable to copy ${bash_bin} to initrd image"
# Copy latest versions of shared objects needed for DNS resolution
for so in $(ldconfig -p | sed -nr 's/^\s*libnss_files\.so\.[0-9]+\s.*=>\s*//p'); do
copy_exec "${so}"
done
for so in $(ldconfig -p | sed -nr 's/^\s*libnss_dns\.so\.[0-9]+\s.*=>\s*//p'); do
copy_exec "${so}"
done
copy_file data @sysconfdir@/ssl/certs/ca-certificates.crt || die 2 "Unable to copy certificate bundle to initrd image"
latchset-clevis-6df9b69/src/initramfs-tools/hooks/meson.build 0000664 0000000 0000000 00000000201 15201107217 0024432 0 ustar 00root root 0000000 0000000 configure_file(
input: 'clevis.in',
output: 'clevis',
install_dir: initramfs_hooks_dir,
configuration: initramfs_data,
)
latchset-clevis-6df9b69/src/initramfs-tools/meson.build 0000664 0000000 0000000 00000001203 15201107217 0023312 0 ustar 00root root 0000000 0000000 initramfs_tools = find_program('update-initramfs', required: false)
if initramfs_tools.found()
initramfstools_dir = '/usr/share/initramfs-tools'
initramfs_hooks_dir = '/usr/share/initramfs-tools/hooks'
initramfs_scripts_dir = '/usr/share/initramfs-tools/scripts'
initramfs_data = configuration_data()
initramfs_data.merge_from(data)
initramfs_data.set('initramfstoolsdir', initramfstools_dir)
libdir = join_paths(get_option('prefix'), get_option('libdir'))
initramfs_data.set('libdir', libdir)
subdir('hooks')
subdir('scripts')
else
warning('Will not install initramfs-tools module due to missing dependencies!')
endif
latchset-clevis-6df9b69/src/initramfs-tools/scripts/ 0000775 0000000 0000000 00000000000 15201107217 0022643 5 ustar 00root root 0000000 0000000 latchset-clevis-6df9b69/src/initramfs-tools/scripts/local-bottom/ 0000775 0000000 0000000 00000000000 15201107217 0025237 5 ustar 00root root 0000000 0000000 latchset-clevis-6df9b69/src/initramfs-tools/scripts/local-bottom/clevis.in 0000775 0000000 0000000 00000002736 15201107217 0027067 0 ustar 00root root 0000000 0000000 #!/bin/bash
#
# Copyright (c) 2017 Shawn Rose
#
# Author: Shawn Rose
#
# 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 3 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, see .
#
PREREQ=""
prereqs() {
echo "$PREREQ"
}
case "$1" in
prereqs)
prereqs
exit 0
;;
esac
[ -s /run/clevis.pid ] || exit 0
. @bindir@/clevis-luks-common-functions
if [ -f @libexecdir@/clevis-luks-tpm1-functions ]; then
. @libexecdir@/clevis-luks-tpm1-functions
stop_tcsd
fi
pid=$(cat /run/clevis.pid)
clevis_kill_pid $pid
rm -f /run/clevis.pid
# Not really worried about downing extra interfaces: they will come up
# during the actual boot. Might make this configurable later if needed.
for iface in /sys/class/net/*; do
if [ -e "$iface" ]; then
iface=$(basename "$iface")
ip link set dev "$iface" down
ip addr flush dev "$iface"
ip route flush dev "$iface" > /dev/null 2>&1
fi
done
latchset-clevis-6df9b69/src/initramfs-tools/scripts/local-bottom/meson.build 0000664 0000000 0000000 00000000237 15201107217 0027403 0 ustar 00root root 0000000 0000000 configure_file(
input: 'clevis.in',
output: 'clevis',
install_dir: join_paths(initramfs_scripts_dir, 'local-bottom'),
configuration: initramfs_data,
)
latchset-clevis-6df9b69/src/initramfs-tools/scripts/local-top/ 0000775 0000000 0000000 00000000000 15201107217 0024535 5 ustar 00root root 0000000 0000000 latchset-clevis-6df9b69/src/initramfs-tools/scripts/local-top/clevis.in 0000775 0000000 0000000 00000022523 15201107217 0026361 0 ustar 00root root 0000000 0000000 #!/bin/bash
#
# Copyright (c) 2017 Red Hat, Inc.
# Copyright (c) 2017 Shawn Rose
# Copyright (c) 2017 Guilhem Moulin
#
# Author: Harald Hoyer
# Author: Nathaniel McCallum
# Author: Shawn Rose
# Author: Guilhem Moulin
#
# 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 3 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, see .
#
case $1 in
prereqs) exit 0 ;;
esac
# Return fifo path or nothing if not found
get_pid_fifo_path() {
local pid="$1"
for fd in /proc/$pid/fd/*; do
if [ -e "$fd" ]; then
if [[ $(readlink -f "${fd}") == *"/cryptsetup/passfifo" ]]; then
readlink -f "${fd}"
return 0
fi
fi
done
return 1
}
# Gets the luks device to be unlocked and used pins
get_pid_device_pins() {
local pid="$1"
local CRYPTTAB_SOURCE
CRYPTTAB_SOURCE=$(tr '\0' '\n' 2>/dev/null "$cache"
fi
cat "$cache"
return 0
}
# Print colon-separated password-asking info like device, pins and fifo
# path for unlocking with password
get_askpass_info() {
local cryptkeyscript=$1
local psinfo pf dev_pins
psinfo=$(ps) # Doing this so I don't end up matching myself
echo "$psinfo" | awk "/$cryptkeyscript/ { print \$1 }" | {
while read -r pid; do
if pf=$(get_pid_fifo_path "${pid}") && dev_pins=$(get_pid_device_pins "${pid}"); then
if [[ $pf != "" && $dev_pins != "" ]]; then
# Output only in case of clevis device
echo "${dev_pins}:${pf}"
fi
# Return that we found valid process
return 0
fi
done
return 1
}
}
# Try to decrypt the password to fifo file
luks_decrypt() {
local CRYPTTAB_SOURCE=$1
local PASSFIFO=$2
local pt
if pt=$(clevis_luks_unlock_device "${CRYPTTAB_SOURCE}"); then
echo -n "${pt}" >"${PASSFIFO}"
return 0
else
return 1
fi
}
# Wait for askpass, and then try and decrypt immediately. Just in case
# there are multiple devices that need decrypting, this will loop
# infinitely (The local-bottom script will kill this after decryption)
clevisloop() {
# Set the path how we want it (Probably not all needed)
PATH="/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin"
local cryptkeyscript
local askpass_info
local sleep_time
local CRYPTTAB_SOURCE
local OLD_CRYPTTAB_SOURCE=""
local netcfg_attempted=0
local tpm1cfg_attempted=0
local pins
local PASSFIFO
if [ -x /bin/plymouth ] && plymouth --ping; then
cryptkeyscript='plymouth ask-for-password'
else
# This has to be escaped for awk
cryptkeyscript='\/lib\/cryptsetup\/askpass'
fi
while true; do
# Re-get the askpass PID in case there are multiple encrypted devices
CRYPTTAB_SOURCE=""
sleep_time=.1
until [ -n "$CRYPTTAB_SOURCE" ] && [ -p "$PASSFIFO" ]; do
sleep $sleep_time
if askpass_info=$(get_askpass_info "$cryptkeyscript"); then
# Workaround for initramfs-tools checking the script as sh-compatible
IFS=':' read -r CRYPTTAB_SOURCE pins PASSFIFO <> /etc/resolv.conf
fi
if [ ! -z "${IPV4DNS1}" ] && [ "${IPV4DNS1}" != "0.0.0.0" ]; then
echo nameserver "${IPV4DNS1}" >> /etc/resolv.conf
fi
if [ ! -z "${IPV6DNS0}" ]; then
echo nameserver "${IPV6DNS0}" >> /etc/resolv.conf
fi
done
fi
fi
}
do_configure_tpm1() {
local tcsd_output=
[ -x @bindir@/clevis-decrypt-tpm1 ] && [ -f @libexecdir@/clevis-luks-tpm1-functions ] || return
. @libexecdir@/clevis-luks-tpm1-functions
log_begin_msg "clevis: Starting TCSD daemon"
wait_for_udev 10
# shellcheck disable=SC2034 # setting default value
TCSD_NO_PRIVILEGE_DROP=0
[ -f /conf/conf.d/clevis ] && . /conf/conf.d/clevis
if ! tcsd_output=$(start_tcsd 2>&1); then
if [ -n "$tcsd_output" ]; then
log_failure_msg "failed to start TCSD: $tcsd_output"
else
log_failure_msg "failed to start TCSD"
fi
fi
log_end_msg
}
mkdir -p /var/cache/clevis-disks
chmod 0700 /var/cache/clevis-disks
clevisloop &
echo $! >/run/clevis.pid
latchset-clevis-6df9b69/src/initramfs-tools/scripts/local-top/meson.build 0000664 0000000 0000000 00000000234 15201107217 0026676 0 ustar 00root root 0000000 0000000 configure_file(
input: 'clevis.in',
output: 'clevis',
install_dir: join_paths(initramfs_scripts_dir, 'local-top'),
configuration: initramfs_data,
)
latchset-clevis-6df9b69/src/initramfs-tools/scripts/meson.build 0000664 0000000 0000000 00000000053 15201107217 0025003 0 ustar 00root root 0000000 0000000 subdir('local-top')
subdir('local-bottom')
latchset-clevis-6df9b69/src/luks/ 0000775 0000000 0000000 00000000000 15201107217 0017000 5 ustar 00root root 0000000 0000000 latchset-clevis-6df9b69/src/luks/clevis-luks-bind 0000775 0000000 0000000 00000010743 15201107217 0022106 0 ustar 00root root 0000000 0000000 #!/bin/bash -e
# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
#
# Copyright (c) 2016 Red Hat, Inc.
# Author: Harald Hoyer
# Author: Nathaniel McCallum
#
# 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 3 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, see .
#
. clevis-luks-common-functions
SUMMARY="Binds a LUKS device using the specified policy"
usage() {
exec >&2
echo
echo "Usage: clevis luks bind [-y] [-f] [-s SLT] [-k KEY] [-t TOKEN_ID] [-e EXISTING_TOKEN_ID] -d DEV PIN CFG"
echo
echo "$SUMMARY":
echo
echo " -f Do not prompt for LUKSMeta initialization"
echo
echo " -d DEV The LUKS device on which to perform binding"
echo
echo " -y Automatically answer yes for all questions"
echo
echo " -s SLT The LUKS slot to use"
echo
echo " -t TKN_ID The LUKS token ID to use; only available for LUKS2"
echo
echo " -k KEY Non-interactively read LUKS password from KEY file"
echo " -k - Non-interactively read LUKS password from standard input"
echo
echo " -e E_TKN_ID Existing LUKS token ID for existing passphrase; only available for LUKS2"
echo
exit 2
}
if [ $# -eq 1 ] && [ "$1" = "--summary" ]; then
echo "$SUMMARY"
exit 0
fi
FRC=
YES=
while getopts ":hfyd:s:k:t:e:" o; do
case "$o" in
f) FRC='-f';;
d) DEV="$OPTARG";;
s) SLT="$OPTARG";;
k) KEY="$OPTARG";;
t) TOKEN_ID="$OPTARG";;
e) EXISTING_TOKEN_ID="$OPTARG";;
y) FRC='-f'
YES='-y';;
*) usage;;
esac
done
if [ -z "$DEV" ]; then
echo "Did not specify a device!" >&2
usage
fi
if ! luks_type="$(clevis_luks_type "${DEV}")"; then
echo "${DEV} is not a supported LUKS device" >&2
exit 1
fi
if ! PIN="${@:$((OPTIND++)):1}" || [ -z "$PIN" ]; then
echo "Did not specify a pin!" >&2
usage
elif ! EXE=$(command -v clevis-encrypt-"${PIN}") || [ -z "${EXE}" ]; then
echo "'${PIN}' is not a valid pin!" >&2
usage
fi
if ! CFG="${@:$((OPTIND++)):1}" || [ -z "$CFG" ]; then
echo "Did not specify a pin config!" >&2
usage
fi
# Check whether the config is valid JSON.
if ! jose fmt --json="${CFG}" --object 2>/dev/null; then
echo "Configuration is malformed; it should be valid JSON" >&2
exit 1
fi
if [ "${luks_type}" = "luks1" ] && [ -n "${TOKEN_ID}" ]; then
echo "${DEV} is a LUKS1 device; -t is only supported in LUKS2" >&2
exit 1
fi
if [ -n "${EXISTING_TOKEN_ID}" ] && ! clevis_luks_luks2_existing_token_id_supported; then
echo "Existing token ID not supported in this cryptsetup version" >&2
exit 1
fi
# Get the existing passphrase/keyfile.
existing_key=
keyfile=
case "${KEY}" in
"")
if [ -z "${EXISTING_TOKEN_ID}" ] ; then
IFS= read -r -s -p "Enter existing LUKS password: " existing_key; echo >&2
fi
;;
-) IFS= read -r -s -p "" existing_key ||:
if [ "${luks_type}" = "luks1" ] && ! luksmeta test -d "${DEV}" \
&& [ -z "${FRC}" ]; then
echo "Cannot use '-k-' without '-f' or '-y' unless already initialized!" >&2
usage
fi
;;
*) keyfile="${KEY}"
if [ ! -r "${keyfile}" ]; then
echo "Cannot read key file '${keyfile}'" >&2
exit 1
fi
;;
esac
# Check if existing token id for keyring read is provided
# If so, keyfile is not allowed
if [ -n "${EXISTING_TOKEN_ID}" ] && [ -n "${keyfile}" ] ; then
echo "Cannot specify kernel keyring description together with key file" >&2
exit 1
fi
# If necessary, initialize the LUKS volume.
if [ "${luks_type}" = "luks1" ] && ! luksmeta test -d "${DEV}"; then
luksmeta init -d "${DEV}" ${FRC}
fi
if ! clevis_luks_do_bind "${DEV}" "${SLT}" "${TOKEN_ID}" \
"${PIN}" "${CFG}" \
"${YES}" "" \
"${existing_key}" "${keyfile}" "${EXISTING_TOKEN_ID}"; then
echo "Error adding new binding to ${DEV}" >&2
exit 1
fi
latchset-clevis-6df9b69/src/luks/clevis-luks-bind.1.adoc 0000664 0000000 0000000 00000005063 15201107217 0023146 0 ustar 00root root 0000000 0000000 CLEVIS-LUKS-BIND(1)
===================
:doctype: manpage
== NAME
clevis-luks-bind - Bind a LUKS device using the specified policy
== SYNOPSIS
*clevis luks bind* [-f] [-y] -d DEV [-t TKN_ID] [-s SLT] [-k KEY] [-e EXISTING_TOKEN_ID] PIN CFG
== OVERVIEW
The *clevis luks bind* command binds a LUKS device using the specified
policy. This is accomplished with a simple command:
$ clevis luks bind -d /dev/sda tang '{"url":...}'
This command performs four steps:
1. Creates a new key with the same entropy as the LUKS master key -- maximum entropy bits is 256.
2. Encrypts the new key with Clevis.
3. Stores the Clevis JWE in the LUKS header.
4. Enables the new key for use with LUKS.
This disk can now be unlocked with your existing password as well as with
the Clevis policy. You will additionally need to enable one or more of the
Clevis LUKS unlockers. See link:clevis-luks-unlockers.7.adoc[*clevis-luks-unlockers*(7)].
== OPTIONS
* *-f* :
Do not prompt for LUKSMeta initialization
* *-y* :
Automatically answer yes for all questions. When using _tang_, it
causes the advertisement trust check to be skipped, which can be
useful in automated deployments
* *-d* _DEV_ :
The LUKS device on which to perform binding
* *-s* _SLT_ :
The LUKSMeta slot to use for metadata storage
* *-t* _TKN_ID_ :
The LUKS token ID to use; only available for LUKS2
* *-k* _KEY_ :
Non-interactively read LUKS password from KEY file
* *-k* - :
Non-interactively read LUKS password from standard input
* *-e* _E_TKN_ID_ :
LUKS token ID for existing passphrase; only available for LUKS2.
This parameter allows providing a configured token ID in LUKS2
containing the existing passphrase for this device, so that
existing passphrase is not prompted by clevis
== CAVEATS
This command does not change the LUKS master key. This implies that if you
create a LUKS-encrypted image for use in a Virtual Machine or Cloud
environment, all the instances that run this image will share a master key.
This is extremely dangerous and should be avoided at all cost.
This is not a limitation of Clevis but a design principle of LUKS. If you wish
to have encrypted root volumes in the cloud, you will need to make sure that
you perform the OS install method for each instance in the cloud as well.
The images cannot be shared without also sharing a master key.
== SEE ALSO
link:clevis-luks-unlockers.7.adoc[*clevis-luks-unlockers*(7)],
link:clevis-encrypt-tang.1.adoc[*clevis-encrypt-tang*(1)],
link:clevis-encrypt-sss.1.adoc[*clevis-encrypt-sss*(1)],
link:clevis-decrypt.1.adoc[*clevis-decrypt*(1)]
latchset-clevis-6df9b69/src/luks/clevis-luks-common-functions.in 0000664 0000000 0000000 00000117453 15201107217 0025100 0 ustar 00root root 0000000 0000000 #!/bin/bash -e
# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
#
# Copyright (c) 2019 Red Hat, Inc.
# Author: Sergio Correia
#
# 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 3 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, see .
#
CLEVIS_UUID="cb6e8904-81ff-40da-a84a-07ab9ab5715e"
# Length, in bytes, used for password generated for LUKS key
# This value corresponds to an entropy of 256 bits if the password
# was generated by pwmake or similar tool
JOSE_PASSWORD_LENGTH=40
enable_debugging() {
# Automatically enable debugging if in initramfs phase and rd.debug
if [ -e /usr/lib/dracut-lib.sh ]; then
local bashopts=$-
# Because dracut is loosely written, disable hardening options temporarily
[[ $bashopts != *u* ]] || set +u
[[ $bashopts != *e* ]] || set +e
. /usr/lib/dracut-lib.sh
[[ $bashopts != *u* ]] || set -u
[[ $bashopts != *e* ]] || set -e
fi
}
enable_debugging
# valid_slot() will check whether a given slot is possibly valid, i.e., if it
# is a numeric value within the specified range.
valid_slot() {
local SLT="${1}"
local MAX_SLOTS="${2}"
case "${SLT}" in
''|*[!0-9]*)
return 1
;;
*)
# We got an integer, now let's make sure it is within the
# supported range.
if [ "${SLT}" -ge "${MAX_SLOTS}" ]; then
return 1
fi
;;
esac
}
# clevis_luks_read_slot() will read a particular slot of a given device, which
# should be either LUKS1 or LUKS2. Returns 1 in case of failure; 0 in case of
# success.
clevis_luks_read_slot() {
local DEV="${1}"
local SLT="${2}"
if [ -z "${DEV}" ] || [ -z "${SLT}" ]; then
echo "Need both a device and a slot as arguments." >&2
return 1
fi
local DATA_CODED=''
local MAX_LUKS1_SLOTS=8
local MAX_LUKS2_SLOTS=32
if cryptsetup isLuks --type luks1 "${DEV}"; then
if ! valid_slot "${SLT}" "${MAX_LUKS1_SLOTS}"; then
echo "Please, provide a valid key slot number; 0-7 for LUKS1" >&2
return 1
fi
if ! luksmeta test -d "${DEV}"; then
echo "The ${DEV} device is not valid!" >&2
return 1
fi
local uuid
# Pattern from luksmeta: active slot uuid.
read -r _ _ uuid <<< "$(luksmeta show -d "${DEV}" | grep "^${SLT} *")"
if [ "${uuid}" != ${CLEVIS_UUID}"" ]; then
echo "Not a clevis slot!" >&2
return 1
fi
if ! DATA_CODED="$(luksmeta load -d "${DEV}" -s "${SLT}")"; then
echo "Cannot load data from ${DEV} slot:${SLT}!" >&2
return 1
fi
elif cryptsetup isLuks --type luks2 "${DEV}"; then
if ! valid_slot "${SLT}" "${MAX_LUKS2_SLOTS}"; then
echo "Please, provide a valid key slot number; 0-31 for LUKS2" >&2
return 1
fi
local token_id
token_id=$(cryptsetup luksDump "${DEV}" \
| grep -E -B1 "^\s+Keyslot:\s+${SLT}$" \
| sed -n 1p | sed -rn 's|^\s+([0-9]+): clevis|\1|p')
if [ -z "${token_id}" ]; then
echo "Cannot load data from ${DEV} slot:${SLT}. No token found!" >&2
return 1
fi
local token
token=$(cryptsetup token export --token-id "${token_id}" "${DEV}")
DATA_CODED=$(jose fmt -j- -Og jwe -o- <<< "${token}" \
| jose jwe fmt -i- -c)
if [ -z "${DATA_CODED}" ]; then
echo "Cannot load data from ${DEV} slot:${SLT}!" >&2
return 1
fi
else
echo "${DEV} is not a supported LUKS device!" >&2
return 1
fi
echo "${DATA_CODED}"
}
# clevis_luks_used_slots() will return the list of used slots for a given LUKS
# device.
clevis_luks_used_slots() {
local DEV="${1:-}"
[ -z "${DEV}" ] && return 1
local used_slots
if cryptsetup isLuks --type luks1 "${DEV}"; then
if ! used_slots=$(cryptsetup luksDump "${DEV}" 2>/dev/null \
| sed -rn 's|^Key Slot ([0-7]): ENABLED$|\1|p'); then
return 1
fi
elif cryptsetup isLuks --type luks2 "${DEV}"; then
if ! used_slots=$(cryptsetup luksDump "${DEV}" 2>/dev/null \
| sed -rn 's|^\s+([0-9]+): luks2$|\1|p'); then
return 1
fi
else
echo "${DEV} is not a supported LUKS device!" >&2
return 1
fi
echo "${used_slots}"
}
# clevis_luks_decode_jwe() will decode a given JWE.
clevis_luks_decode_jwe() {
local jwe="${1}"
local coded
read -r -d . coded <<< "${jwe}"
jose b64 dec -i- <<< "${coded}"
}
# clevis_luks_print_pin_config() will print the config of a given pin; i.e.
# for tang it will display the associated url address, and for tpm2, the
# properties in place, like the hash, for instance.
clevis_luks_print_pin_config() {
local P="${1}"
local decoded="${2}"
local content
if ! content="$(jose fmt -j- -g clevis -g "${P}" -o- <<< "${decoded}")" \
|| [ -z "${content}" ]; then
return 1
fi
local pin=
case "${P}" in
null)
printf "null '{}'"
;;
pkcs11)
local uri
uri="$(jose fmt -j- -g uri -u- <<< "${content}")"
mechanism="$(jose fmt -j- -g mechanism -u- <<< "${content}")"
if [ -z "${mechanism}" ]; then
pin=$(printf '{"uri":"%s"}' "${uri}")
else
pin=$(printf '{"uri":"%s", "mechanism":"%s"}' "${uri}" "${mechanism}")
fi
printf "pkcs11 '%s'" "${pin}"
;;
sss)
local threshold
threshold=$(jose fmt -j- -Og t -o- <<< "${content}")
clevis_luks_process_sss_pin "${content}" "${threshold}"
;;
tang)
local url
url="$(jose fmt -j- -g url -u- <<< "${content}")"
pin=$(printf '{"url":"%s"}' "${url}")
printf "tang '%s'" "${pin}"
;;
tpm1)
pcr_ids="$(jose fmt -j- -g pcr_ids -u- <<< "${content}")"
pin=$(printf '"pcr_ids":"%s"' "${pcr_ids}")
printf "tpm1 '{%s}'" "${pin}"
;;
tpm2)
# Valid properties for tpm2 pin are the following:
# hash, key, pcr_bank, pcr_ids, pcr_digest.
local key
local value
for key in 'hash' 'key' 'pcr_bank' 'pcr_ids' 'pcr_digest'; do
if value=$(jose fmt -j- -g "${key}" -u- <<< "${content}"); then
pin=$(printf '%s,"%s":"%s"' "${pin}" "${key}" "${value}")
fi
done
# Remove possible leading comma.
pin=${pin/#,/}
printf "tpm2 '{%s}'" "${pin}"
;;
*)
printf "unknown pin '%s'" "${P}"
;;
esac
}
# clevis_luks_decode_pin_config() will receive a JWE and extract a pin config
# from it.
clevis_luks_decode_pin_config() {
local jwe="${1}"
local decoded
if ! decoded=$(clevis_luks_decode_jwe "${jwe}"); then
return 1
fi
local P
if ! P=$(jose fmt -j- -Og clevis -g pin -u- <<< "${decoded}"); then
return 1
fi
clevis_luks_print_pin_config "${P}" "${decoded}"
}
# clevis_luks_join_sss_cfg() will receive a list of configurations for a given
# pin and returns it as list, in the format PIN [cfg1, cfg2, ..., cfgN].
clevis_luks_join_sss_cfg() {
local pin="${1}"
local cfg="${2}"
cfg=$(echo "${cfg}" | tr -d "'" | sed -e 's/^,//')
printf '"%s":[%s]' "${pin}" "${cfg}"
}
# clevis_luks_process_sss_pin() will receive a JWE with information on the sss
# pin config, and also its associated threshold, and will extract the info.
clevis_luks_process_sss_pin() {
local jwe="${1}"
local threshold="${2}"
local sss_null
local sss_pkcs11
local sss_tang
local sss_tpm1
local sss_tpm2
local sss
local pin_cfg
local pin
local cfg
local coded
for coded in $(jose fmt -j- -Og jwe -Af- <<< "${jwe}"| tr -d '"'); do
if ! pin_cfg="$(clevis_luks_decode_pin_config "${coded}")"; then
continue
fi
read -r pin cfg <<< "${pin_cfg}"
case "${pin}" in
null)
sss_null="${sss_null},${cfg}"
;;
pkcs11)
sss_pkcs11="${sss_pkcs11},${cfg}"
;;
tang)
sss_tang="${sss_tang},${cfg}"
;;
tpm1)
sss_tpm1="${sss_tpm1},${cfg}"
;;
tpm2)
sss_tpm2="${sss_tpm2},${cfg}"
;;
sss)
sss=$(echo "${cfg}" | tr -d "'")
;;
esac
done
cfg=
if [ -n "${sss_null}" ]; then
cfg=$(clevis_luks_join_sss_cfg "null" "${sss_null}")
fi
if [ -n "${sss_tang}" ]; then
cfg=$(clevis_luks_join_sss_cfg "tang" "${sss_tang}")
fi
if [ -n "${sss_tpm1}" ]; then
cfg="${cfg},"$(clevis_luks_join_sss_cfg "tpm1" "${sss_tpm1}")
fi
if [ -n "${sss_tpm2}" ]; then
cfg="${cfg},"$(clevis_luks_join_sss_cfg "tpm2" "${sss_tpm2}")
fi
if [ -n "${sss_pkcs11}" ]; then
cfg="${cfg},"$(clevis_luks_join_sss_cfg "pkcs11" "${sss_pkcs11}")
fi
if [ -n "${sss}" ]; then
cfg=$(printf '%s,"sss":%s' "${cfg}" "${sss}")
fi
# Remove possible leading comma.
cfg=${cfg/#,/}
pin=$(printf '{"t":%d,"pins":{%s}}' "${threshold}" "${cfg}")
printf "sss '%s'" "${pin}"
}
# clevis_luks_read_pins_from_slot() will receive a given device and slot and
# will then output its associated policy configuration.
clevis_luks_read_pins_from_slot() {
local DEV="${1}"
local SLOT="${2}"
local jwe
if ! jwe=$(clevis_luks_read_slot "${DEV}" "${SLOT}" 2>/dev/null); then
return 1
fi
local cfg
if ! cfg="$(clevis_luks_decode_pin_config "${jwe}")"; then
return 1
fi
printf "%s: %s\n" "${SLOT}" "${cfg}"
}
# clevis_luks_decode_used_pins() will receive a JWE and extract used pins
# (line-separated, unsorted, not deduped) from it.
clevis_luks_decode_used_pins() {
local jwe="${1}"
local pins=
local decoded
if ! decoded=$(clevis_luks_decode_jwe "${jwe}"); then
return 1
fi
local P
if ! P=$(jose fmt -j- -Og clevis -g pin -u- <<< "${decoded}"); then
return 1
fi
pins=$(printf "%s\n%s" "${pins}" "${P}")
if [ "${P}" = "sss" ]; then
local sss_jwe
if ! sss_jwe="$(jose fmt -j- -g clevis -g "${P}" -o- <<< "${decoded}")" \
|| [ -z "${sss_jwe}" ]; then
return 1
fi
local coded sss_pins
for coded in $(jose fmt -j- -Og jwe -Af- <<< "${sss_jwe}"| tr -d '"'); do
if ! sss_pins="$(clevis_luks_decode_used_pins "${coded}")"; then
continue
fi
pins=$(printf "%s\n%s" "${pins}" "${sss_pins}")
done
fi
echo "${pins}"
}
# clevis_luks_read_used_pins_from_slot() will receive a given device and slot
# and will then output space-separated sorted slot-prefixed list of used pins.
clevis_luks_read_used_pins_from_slot() {
local DEV="${1}"
local SLOT="${2}"
local jwe
if ! jwe=$(clevis_luks_read_slot "${DEV}" "${SLOT}" 2>/dev/null); then
return 1
fi
local pins
if ! pins=$(clevis_luks_decode_used_pins "${jwe}"); then
return 1
fi
pins=$(echo -n "${pins}" | sed -e '/^$/d' | sort -u | tr '\n' ' ' | sed -e 's/ $//')
printf "%s: %s\n" "${SLOT}" "${pins}"
}
# clevis_luks_read_used_pins() will receive a given device and will then output
# space-separated sorted list of all used pins in all slots.
clevis_luks_read_used_pins() {
local DEV="${1}"
[ -z "${DEV}" ] && return 1
local used_slots
if ! used_slots=$(clevis_luks_used_slots "${DEV}") \
|| [ -z "${used_slots}" ]; then
return 1
fi
local pins=
local slot slot_pins used_pins
for slot in ${used_slots}; do
if ! slot_pins=$(clevis_luks_read_used_pins_from_slot "${DEV}" "${slot}"); then
continue
fi
read -r _ used_pins <<< "${slot_pins}"
pins=$(printf "%s\n%s" "${pins}" "${used_pins}")
done
pins=$(echo -n "${pins}" | tr ' ' '\n' | sed -e '/^$/d' | sort -u | tr '\n' ' ' | sed -e 's/ $//')
[ -z "${pins}" ] && return 1
echo "${pins}"
}
# clevis_luks_check_valid_key_or_keyfile() receives a devices and either a
# passphrase or keyfile and then checks whether it is able to unlock the
# device wih the received passphrase/keyfile.
clevis_luks_check_valid_key_or_keyfile() {
local DEV="${1}"
local KEY="${2:-}"
local KEYFILE="${3:-}"
local SLT="${4:-}"
local EXISTING_TOKEN_ID="${5:-}"
[ -z "${DEV}" ] && return 1
local extra_args
extra_args="$([ -n "${SLT}" ] && printf -- '--key-slot %s' "${SLT}")"
# We have an empty key here.
if [ -z "${EXISTING_TOKEN_ID}" ] && [ -z "${KEYFILE}" ] \
&& [ -z "${KEY}" ]; then
echo | cryptsetup open --force-password --test-passphrase "${DEV}" \
${extra_args}
return
fi
if [ -n "${KEYFILE}" ]; then
cryptsetup open --test-passphrase "${DEV}" --key-file "${KEYFILE}" \
${extra_args}
return
fi
if [ -n "${EXISTING_TOKEN_ID}" ]; then
cryptsetup open --test-passphrase "${DEV}" --token-id "${EXISTING_TOKEN_ID}" \
${extra_args}
return
fi
printf '%s' "${KEY}" | cryptsetup open --test-passphrase "${DEV}" \
${extra_args}
}
# clevis_luks_unlock_device_by_slot() does the unlock of the device and slot
# passed as parameters and returns the decoded passphrase.
clevis_luks_unlock_device_by_slot() {
local DEV="${1}"
local SLT="${2}"
local SKIP_CHECK="${3}"
[ -z "${DEV}" ] && return 1
[ -z "${SLT}" ] && return 1
local jwe passphrase
if ! jwe="$(clevis_luks_read_slot "${DEV}" "${SLT}" 2>/dev/null)" \
|| [ -z "${jwe}" ]; then
return 1
fi
if ! passphrase="$(printf '%s' "${jwe}" | clevis decrypt)" \
|| [ -z "${passphrase}" ]; then
return 1
fi
if [ -z "${SKIP_CHECK}" ]; then
clevis_luks_check_valid_key_or_keyfile "${DEV}" "${passphrase}" || return 1
fi
printf '%s' "${passphrase}"
}
# clevis_luks_unlock_device() does the unlock of the device passed as
# parameter and returns the decoded passphrase.
clevis_luks_unlock_device() {
local DEV="${1}"
local SKIP_CHECK="YES"
[ -z "${DEV}" ] && return 1
local used_slots
if ! used_slots=$(clevis_luks_used_slots "${DEV}") \
|| [ -z "${used_slots}" ]; then
return 1
fi
local slt pt
for slt in ${used_slots}; do
if ! pt=$(clevis_luks_unlock_device_by_slot "${DEV}" "${slt}" "${SKIP_CHECK}") \
|| [ -z "${pt}" ]; then
continue
fi
printf '%s' "${pt}"
return 0
done
return 1
}
# clevis_map_device() tries to map the device received as a parameter to a
# block device. As per crypttab(5), we support /path/to/encrypted/blockdev
# or UUID=.
clevis_map_device() {
local CDEV="${1}"
if [[ "${CDEV}" == UUID=* ]]; then
CDEV=/dev/disk/by-uuid/${CDEV#UUID=}
fi
if [[ "${CDEV}" == /* ]] && [ -b "${CDEV}" ]; then
echo "${CDEV}"
else
# Invalid crypttab entry.
return 1
fi
}
# clevis_is_luks_device_by_uuid_open() checks whether the LUKS device whose
# UUID was passed as a parameter is already open.
clevis_is_luks_device_by_uuid_open() {
local dev_luks_uuid="${1}"
[ -z "${dev_luks_uuid}" ] && return 1
dev_luks_uuid="$(echo "${dev_luks_uuid}" | sed -e 's/-//g')"
test -b /dev/disk/by-id/dm-uuid-*"${dev_luks_uuid}"*
}
# clevis_devices_to_unlock() returns a list of devices to be unlocked, as per
# the info from crypttab.
clevis_devices_to_unlock() {
local list_open_devices="${1:-}"
[ ! -r /etc/crypttab ] && return 1
local dev clevis_devices crypt_device dev_uuid bindings
clevis_devices=
# Build list of devices to unlock.
while read -r _volname_ crypt_device _; do
# skip empty lines and lines which begin with the '#' char, per
# crypttab(5)
case $_volname_ in
''|\#*) continue ;;
esac
if ! dev=$(clevis_map_device "${crypt_device}") \
|| [ -z "${dev}" ]; then
# Unable to get the device - maybe it's not available, e.g. a
# device on a volume group that has not been activated yet.
# Add it to the list anyway, since it's a pending device.
clevis_devices="${clevis_devices} ${crypt_device}"
continue
fi
# Check if this device has clevis bindings.
if ! bindings="$(clevis luks list -d "${dev}" 2>/dev/null)" \
|| [ -z "${bindings}" ]; then
continue
fi
if [ -z "${list_open_devices}" ]; then
# Check if this device is already open.
dev_uuid="$(cryptsetup luksUUID "${dev}")"
if clevis_is_luks_device_by_uuid_open "${dev_uuid}"; then
continue
fi
fi
clevis_devices="${clevis_devices} ${dev}"
done < /etc/crypttab
echo "${clevis_devices}" | sed -e 's/^ //'
}
# clevis_luks1_save_slot() works with LUKS1 devices and it saves a given JWE
# to a specific device and slot. The last parameter indicates whether we
# should overwrite existing metadata.
clevis_luks1_save_slot() {
local DEV="${1}"
local SLOT="${2}"
local JWE="${3}"
local SHOULD_OVERWRITE="${4:-}"
luksmeta test -d "${DEV}" || return 1
if luksmeta load -d "${DEV}" -s "${SLOT}" -u "${CLEVIS_UUID}" \
>/dev/null 2>/dev/null; then
[ -z "${SHOULD_OVERWRITE}" ] && return 1
if ! luksmeta wipe -f -d "${DEV}" -s "${SLOT}" \
-u "${CLEVIS_UUID}"; then
echo "Error wiping slot ${SLOT} from ${DEV}" >&2
return 1
fi
fi
if ! echo -n "${JWE}" | luksmeta save -d "${DEV}" -s "${SLOT}" \
-u "${CLEVIS_UUID}"; then
echo "Error saving metadata to LUKSMeta slot ${SLOT} from ${DEV}" >&2
return 1
fi
if ! luksmeta test -d "${DEV}" 2>/dev/null >/dev/null ; then
echo "Error detected after saving metadata to LUKSMeta slot ${SLOT}, device ${DEV}" >&2
return 1
fi
return 0
}
# clevis_luks2_save_slot() works with LUKS2 devices and it saves a given JWE
# to a specific device and slot. The last parameter indicates whether we
# should overwrite existing metadata.
clevis_luks2_save_slot() {
local DEV="${1}"
local SLOT="${2}"
local TKN_ID="${3}"
local JWE="${4}"
local SHOULD_OVERWRITE="${5:-}"
# Sanitize clevis LUKS2 tokens. Remove "orphan" clevis tokens, i.e.,
# tokens that are not linked to any key slots.
local token array_len
for token in $(cryptsetup luksDump "${DEV}" \
| sed -rn 's|^\s+([0-9]+): clevis|\1|p'); do
# Let's check the length of the "keyslots" array. If zero, it means
# no key slots are linked, which is a problem.
if ! array_len=$(cryptsetup token export --token-id \
"${token}" "${DEV}" \
| jose fmt --json=- --get keyslots --array --length \
--output=-) || [ "${array_len}" -eq 0 ]; then
# Remove bad token.
cryptsetup token remove --token-id "${token}" "${DEV}"
fi
done
if ! token="$(cryptsetup luksDump "${DEV}" \
| grep -E -B1 "^\s+Keyslot:\s+${SLOT}$" \
| sed -rn 's|^\s+([0-9]+): clevis|\1|p')"; then
echo "Error trying to read token from LUKS2 device ${DEV}, slot ${SLOT}" >&2
return 1
fi
if [ -n "${token}" ]; then
[ -z "${SHOULD_OVERWRITE}" ] && return 1
if ! cryptsetup token remove --token-id "${token}" "${DEV}"; then
echo "Error while removing token ${token} from LUKS2 device ${DEV}" >&2
return 1
fi
fi
if [ -n "${SHOULD_OVERWRITE}" ] && [ -n "${TKN_ID}" ]; then
cryptsetup token remove --token-id "${TKN_ID}" "${DEV}" 2>/dev/null || :
fi
local metadata
metadata=$(printf '{"type":"clevis","keyslots":["%s"],"jwe":%s}' \
"${SLOT}" "$(jose jwe fmt --input="${JWE}")")
if ! printf '%s' "${metadata}" | cryptsetup token import \
$([ -n "${TKN_ID}" ] && printf -- '--token-id %s' "${TKN_ID}") \
"${DEV}"; then
echo "Error saving metadata to LUKS2 header in device ${DEV}" >&2
return 1
fi
return 0
}
# clevis_luks_save_slot() saves a given JWE to a LUKS device+slot. It can also
# overwrite existing metadata.
clevis_luks_save_slot() {
local DEV="${1}"
local SLOT="${2}"
local TKN_ID="${3}"
local JWE="${4}"
local SHOULD_OVERWRITE="${5:-}"
if cryptsetup isLuks --type luks1 "${DEV}"; then
clevis_luks1_save_slot "${DEV}" "${SLOT}" "${JWE}" \
"${SHOULD_OVERWRITE}" || return 1
elif cryptsetup isLuks --type luks2 "${DEV}"; then
clevis_luks2_save_slot "${DEV}" "${SLOT}" "${TKN_ID}" "${JWE}" \
"${SHOULD_OVERWRITE}" || return 1
else
return 1
fi
return 0
}
# clevis_luks1_backup_dev() backups the LUKSMeta slots from a LUKS device,
# which can be restored with clevis_luks1_restore_dev().
clevis_luks1_backup_dev() {
local DEV="${1}"
local TMP="${2}"
[ -z "${DEV}" ] && return 1
[ -z "${TMP}" ] && return 1
luksmeta test -d "${DEV}" || return 0
touch "${TMP}/initialized"
local used_slots slt uuid jwe fname
if ! used_slots=$(clevis_luks_used_slots "${DEV}") \
|| [ -z "${used_slots}" ]; then
return 1
fi
for slt in ${used_slots}; do
if ! uuid=$(luksmeta show -d "${DEV}" -s "${slt}") \
|| [ -z "${uuid}" ]; then
continue
fi
if ! jwe=$(luksmeta load -d "${DEV}" -s "${slt}") \
|| [ -z "${jwe}" ]; then
continue
fi
fname=$(printf "slot_%s_%s" "${slt}" "${uuid}")
printf "%s" "${jwe}" > "${TMP}/${fname}"
done
return 0
}
# clevis_luks1_restore_dev() takes care of restoring the LUKSMeta slots from
# a LUKS device that was backup'ed by clevis_luks1_backup_dev().
clevis_luks1_restore_dev() {
local DEV="${1}"
local TMP="${2}"
[ -z "${DEV}" ] && return 1
[ -z "${TMP}" ] && return 1
[ -e "${TMP}/initialized" ] || return 0
luksmeta test -d "${DEV}" || luksmeta init -f -d "${DEV}"
local slt uuid jwe fname
for fname in "${TMP}"/slot_*; do
[ -f "${fname}" ] || break
if ! slt=$(echo "${fname}" | cut -d '_' -f 2) \
|| [ -z "${slt}" ]; then
continue
fi
if ! uuid=$(echo "${fname}" | cut -d '_' -f 3) \
|| [ -z "${uuid}" ]; then
continue
fi
if ! jwe=$(cat "${fname}") || [ -z "${jwe}" ]; then
continue
fi
if ! clevis_luks1_save_slot "${DEV}" "${slt}" \
"${jwe}" "overwrite"; then
echo "Error restoring LUKSmeta slot ${slt} from ${DEV}" >&2
return 1
fi
done
return 0
}
# clevis_luks_backup_dev() backups a particular LUKS device, which can then
# be restored with clevis_luks_restore_dev().
clevis_luks_backup_dev() {
local DEV="${1}"
local TMP="${2}"
[ -z "${DEV}" ] && return 1
[ -z "${TMP}" ] && return 1
printf '%s' "${DEV}" > "${TMP}/device"
printf '%s' "${DEV}" > "${TMP}/device"
local HDR
HDR="${TMP}/$(basename "${DEV}").header"
if ! cryptsetup luksHeaderBackup "${DEV}" --batch-mode \
--header-backup-file "${HDR}"; then
echo "Error backing up LUKS header from ${DEV}" >&2
return 1
fi
# If LUKS1, we need to manually back up (and later restore) the
# LUKSmeta slots. For LUKS2, simply saving the header also saves
# the associated tokens.
if cryptsetup isLuks --type luks1 "${DEV}"; then
if ! clevis_luks1_backup_dev "${DEV}" "${TMP}"; then
return 1
fi
fi
return 0
}
# clevis_luks_restore_dev() restores a given device that was backup'ed by
# clevis_luks_backup_dev().
clevis_luks_restore_dev() {
local TMP="${1}"
[ -z "${TMP}" ] && return 1
[ -r "${TMP}"/device ] || return 1
local DEV
DEV="$(cat "${TMP}"/device)"
local HDR
HDR="${TMP}/$(basename "${DEV}").header"
if [ ! -e "${HDR}" ]; then
echo "LUKS header backup does not exist" >&2
return 1
fi
if ! cryptsetup luksHeaderRestore "${DEV}" --batch-mode \
--header-backup-file "${HDR}"; then
echo "Error restoring LUKS header from ${DEV}" >&2
return 1
fi
# If LUKS1, we need to manually back up (and later restore) the
# LUKSmeta slots. For LUKS2, simply saving the header also saves
# the associated tokens.
if cryptsetup isLuks --type luks1 "${DEV}"; then
if ! clevis_luks1_restore_dev "${DEV}" "${TMP}"; then
return 1
fi
fi
return 0
}
# clevis_luks_get_existing_key() may try to recover a valid password from
# existing bindings and additionally prompt the user for the passphrase.
clevis_luks_get_existing_key() {
local DEV="${1}"
local PROMPT="${2}"
local RECOVER="${3:-}"
[ -z "${DEV}" ] && return 1
local pt
if [ -n "${RECOVER}" ] && pt="$(clevis_luks_unlock_device "${DEV}")" \
&& [ -n "${pt}" ]; then
printf '%s' "${pt}"
return 0
fi
# Let's prompt the user for the password.
IFS= read -r -s -p "${PROMPT}" pt; echo >&2
# Check if key is valid.
clevis_luks_check_valid_key_or_keyfile "${DEV}" "${pt}" || return 1
printf '%s' "${pt}"
}
# clevis_luks_luksmeta_sync_fix() makes sure LUKSmeta slots are sync'ed with
# cryptsetup, in order to prevent issues when saving clevis metadata.
clevis_luks_luksmeta_sync_fix() {
local DEV="${DEV}"
[ -z "${DEV}" ] && return 1
# This applies only to LUKS1 devices.
cryptsetup isLuks --type luks1 "${DEV}" || return 0
# No issues if the LUKSmeta metadata is not initialized.
luksmeta test -d "${DEV}" || return 0
local first_free_slot
if ! first_free_slot=$(clevis_luks_first_free_slot "${DEV}") \
|| [ -z "${first_free_slot}" ]; then
echo "There are possibly no free slots in ${DEV}" >&2
return 1
fi
# In certain circumstances, we may have LUKSMeta slots "not in sync" with
# cryptsetup, which means we will try to save LUKSMeta metadata over an
# already used or partially used slot -- github issue #70.
# If that is the case, let's wipe the LUKSMeta slot here prior to using
# the LUKSMeta slot.
local lmeta_slot lmeta_status lmeta_uuid
lmeta_slot="$(luksmeta show -d "${DEV}" | grep "^${first_free_slot}")"
# 1 active cb6e8904-81ff-40da-a84a-07ab9ab5715e
# 2 inactive cb6e8904-81ff-40da-a84a-07ab9ab5715e
lmeta_status="$(echo "${lmeta_slot}" | awk '{print $2}')"
[ "${lmeta_status}" != 'inactive' ] && return 0
lmeta_uuid="$(echo "${lmeta_slot}" | awk '{print $3}')"
[ "${lmeta_uuid}" != "${CLEVIS_UUID}" ] && return 0
luksmeta wipe -f -d "${DEV}" -s "${first_free_slot}"
}
# clevis_luks_get_hash() returns the hash algorithm used by a LUKS device.
clevis_luks_get_hash() {
local DEV="${1}"
[ -z "${DEV}" ] && return 1
local luks_type hash
luks_type=$(clevis_luks_type "${DEV}") || return 1
case "${luks_type}" in
luks1) hash=$(cryptsetup luksDump "${DEV}" 2>/dev/null \
| awk '/^Hash spec:[ \t]+/{print $3; exit}');;
luks2) hash=$(cryptsetup luksDump "${DEV}" 2>/dev/null \
| awk '/^[[:space:]]+[0-9]+: luks/{in_slot=1}
in_slot && /Hash:/{print $2; exit}');;
*) return 1;;
esac
# Validate: only allow alphanumeric characters, hyphens and underscores.
case "${hash}" in
*[!a-zA-Z0-9_-]*|"") return 1;;
esac
printf '%s\n' "${hash}"
}
# clevis_luks_add_key() adds a new key to a key slot.
clevis_luks_add_key() {
local DEV="${1}"
local SLT="${2}"
local NEWKEY="${3}"
local KEY="${4}"
local KEYFILE="${5:-}"
local EXISTING_TOKEN_ID="${6:-}"
[ -z "${DEV}" ] && return 1
[ -z "${NEWKEY}" ] && return 1
local extra_args='' input
input="$(printf '%s\n%s' "${KEY}" "${NEWKEY}")"
if [ -n "${KEYFILE}" ]; then
extra_args="$(printf -- '--key-file %s' "${KEYFILE}")"
input="$(printf '%s' "${NEWKEY}")"
fi
if [ -n "${EXISTING_TOKEN_ID}" ]; then
extra_args="$(printf -- '--token-id %s' "${EXISTING_TOKEN_ID}")"
input="$(printf '%s' "${NEWKEY}")"
fi
local pbkdf_args="--pbkdf pbkdf2 --pbkdf-force-iterations 1000"
local hash
hash=$(clevis_luks_get_hash "${DEV}")
if [ -n "${hash}" ]; then
pbkdf_args="${pbkdf_args} --hash ${hash}"
fi
printf '%s' "${input}" | cryptsetup luksAddKey --force-password --batch-mode \
--key-slot "${SLT}" \
"${DEV}" \
${pbkdf_args} \
${extra_args}
}
# clevis_luks_update_key() will update a key slot with a new key.
clevis_luks_update_key() {
local DEV="${1}"
local SLT="${2}"
local NEWKEY="${3}"
local KEY="${4}"
local KEYFILE="${5:-}"
local EXISTING_TOKEN_ID="${6:-}"
[ -z "${DEV}" ] && return 1
[ -z "${NEWKEY}" ] && return 1
# Update the key slot with the new key. If we have the key for this slot,
# the change happens in-place. Otherwise, we kill the slot and re-add it.
local in_place
clevis_luks_check_valid_key_or_keyfile "${DEV}" \
"${KEY}" "${KEYFILE}" \
"${SLT}" "${EXISTING_TOKEN_ID}" 2>/dev/null \
&& in_place=true
local input extra_args=
input="$(printf '%s\n%s' "${KEY}" "${NEWKEY}")"
if [ -n "${KEYFILE}" ]; then
extra_args="$(printf -- '--key-file %s --force-password' "${KEYFILE}")"
input="$(printf '%s' "${NEWKEY}")"
fi
if [ -n "${EXISTING_TOKEN_ID}" ]; then
extra_args="$(printf -- '--token-id %s --force-password' "${EXISTING_TOKEN_ID}")"
input="$(printf '%s' "${NEWKEY}")"
fi
local pbkdf_args="--pbkdf pbkdf2 --pbkdf-force-iterations 1000"
local hash
hash=$(clevis_luks_get_hash "${DEV}")
if [ -n "${hash}" ]; then
pbkdf_args="${pbkdf_args} --hash ${hash}"
fi
if [ -n "${in_place}" ]; then
printf '%s' "${input}" | cryptsetup luksChangeKey "${DEV}" \
--key-slot "${SLT}" \
--batch-mode \
${pbkdf_args} \
${extra_args}
return
fi
if ! printf '%s' "${input}" | cryptsetup luksKillSlot "${DEV}" \
"${SLT}" \
${extra_args}; then
echo "Error wiping slot ${SLT} from ${DEV}" >&2
return 1
fi
clevis_luks_add_key "${DEV}" "${SLT}" "${NEWKEY}" "${KEY}" "${KEYFILE}"
}
# clevis_luks_save_key_to_slot() will save a new key to a slot. It can either
# add a new key to a slot or updating an already used slot.
clevis_luks_save_key_to_slot() {
local DEV="${1}"
local SLT="${2}"
local NEWKEY="${3}"
local KEY="${4}"
local KEYFILE="${5:-}"
local OVERWRITE="${6:-}"
local EXISTING_TOKEN_ID="${7:-}"
[ -z "${DEV}" ] && return 1
[ -z "${SLT}" ] && return 1
[ -z "${NEWKEY}" ] && return 1
# Make sure LUKSmeta slots are in sync with cryptsetup, to avoid the
# problem reported in github issue #70. Applies to LUKS1 only.
clevis_luks_luksmeta_sync_fix "${DEV}"
# Let's check if we are adding a new key or updating an existing one.
local update
update="$(clevis_luks_used_slots "${DEV}" | grep "^${SLT}$")"
if [ -n "${update}" ]; then
# Replace an existing key.
[ -n "${OVERWRITE}" ] || return 1
clevis_luks_update_key "${DEV}" "${SLT}" \
"${NEWKEY}" "${KEY}" "${KEYFILE}" "${EXISTING_TOKEN_ID}"
return
fi
# Add a new key.
clevis_luks_add_key "${DEV}" "${SLT}" \
"${NEWKEY}" "${KEY}" "${KEYFILE}" "${EXISTING_TOKEN_ID}"
}
# clevis_luks_generate_key() generates a new key for use with clevis.
clevis_luks_generate_key() {
local input
input=$(printf '{"kty":"oct","bytes":%s}' "${JOSE_PASSWORD_LENGTH}")
jose jwk gen --input="${input}" --output=- | \
jose fmt --json=- --object --get k --unquote=-
}
# clevis_luks_token_id_by_slot() returns the token ID linked to a
# particular LUKS2 key slot.
clevis_luks_token_id_by_slot() {
local DEV="${1}"
local SLT="${2}"
[ -z "${DEV}" ] && return 1
[ -z "${SLT}" ] && return 1
cryptsetup isLuks --type luks1 "${DEV}" && echo && return
local tkn_id
tkn_id="$(cryptsetup luksDump "${DEV}" \
| grep -E -B1 "^\s+Keyslot:\s+${SLT}$" \
| sed -rn 's|^\s+([0-9]+): clevis|\1|p')"
printf '%s' "${tkn_id}"
}
# clevis_luks_cleanup() removes the temporary directory used to store the data
# relevant to device backup and restore.
clevis_luks_cleanup() {
[ -z "${CLEVIS_TMP_DIR}" ] && return 0
[ -d "${CLEVIS_TMP_DIR}" ] || return 0
if ! rm -rf "${CLEVIS_TMP_DIR}"; then
echo "Deleting temporary files failed!" >&2
echo "You may need to clean up '${CLEVIS_TMP_DIR}'" >&2
exit 1
fi
unset CLEVIS_TMP_DIR
}
# clevis_luks_first_free_slot() returns the first key slot that is available
# in a LUKS device.
clevis_luks_first_free_slot() {
local DEV="${1}"
[ -z "${DEV}" ] && return 1
local first_free_slot
if cryptsetup isLuks --type luks1 "${DEV}"; then
first_free_slot=$(cryptsetup luksDump "${DEV}" \
| sed -rn 's|^Key Slot ([0-7]): DISABLED$|\1|p' \
| sed -n 1p)
elif cryptsetup isLuks --type luks2 "${DEV}"; then
local used_slots slt
used_slots="$(clevis_luks_used_slots "${DEV}")"
for slt in {0..31}; do
if ! echo "${used_slots}" | grep -q "^${slt}$"; then
first_free_slot="${slt}"
break
fi
done
else
echo "Unsupported device ${DEV}" >&2
return 1
fi
echo "${first_free_slot}"
}
# clevis_luks_do_bind() creates or updates a particular binding.
clevis_luks_do_bind() {
local DEV="${1}"
local SLT="${2}"
local TKN_ID="${3}"
local PIN="${4}"
local CFG="${5}"
local YES="${6:-}"
local OVERWRITE="${7:-}"
local KEY="${8:-}"
local KEYFILE="${9:-}"
local EXISTING_TOKEN_ID="${10:-}"
[ -z "${DEV}" ] && return 1
[ -z "${PIN}" ] && return 1
[ -z "${CFG}" ] && return 1
if ! clevis_luks_check_valid_key_or_keyfile "${DEV}" \
"${KEY}" \
"${KEYFILE}" \
"" \
"${EXISTING_TOKEN_ID}" \
&& ! KEY="$(clevis_luks_get_existing_key "${DEV}" \
"Enter existing LUKS password: " \
"recover")"; then
return 1
fi
local newkey jwe
if ! newkey="$(clevis_luks_generate_key)" || [ -z "${newkey}" ]; then
echo "Unable to generate a new key" >&2
return 1
fi
# Encrypt the new key.
if ! jwe="$(printf '%s' "${newkey}" | clevis encrypt "${PIN}" "${CFG}" \
${YES})" || [ -z "${jwe}" ]; then
echo "Unable to perform encryption with PIN '${PIN}' and config '${CFG}'" >&2
return 1
fi
# We can proceed to binding, after backing up the LUKS header and
# metadata.
local CLEVIS_TMP_DIR
mkdir -p "${TMPDIR:-/tmp}"
if ! CLEVIS_TMP_DIR="$(mktemp -d)" || [ -z "${CLEVIS_TMP_DIR}" ]; then
echo "Unable to create a a temporary dir for device backup/restore" >&2
return 1
fi
export CLEVIS_TMP_DIR
trap 'clevis_luks_cleanup' EXIT
# Backup LUKS header.
if ! clevis_luks_backup_dev "${DEV}" "${CLEVIS_TMP_DIR}"; then
echo "Unable to back up LUKS header from ${DEV}" >&2
return 1
fi
if [ -z "${SLT}" ] && ! SLT=$(clevis_luks_first_free_slot "${DEV}") \
|| [ -z "${SLT}" ]; then
echo "Unable to find a free slot in ${DEV}" >&2
return 1
fi
[ -z "${TKN_ID}" ] && ! TKN_ID="$(clevis_luks_token_id_by_slot "${DEV}" \
"${SLT}")" && return 1
if ! clevis_luks_save_key_to_slot "${DEV}" "${SLT}" \
"${newkey}" "${KEY}" "${KEYFILE}" \
"${OVERWRITE}" "${EXISTING_TOKEN_ID}"; then
echo "Unable to save/update key slot; operation cancelled" >&2
clevis_luks_restore_dev "${CLEVIS_TMP_DIR}" || :
rm -rf "${CLEVIS_TMP_DIR}"
return 1
fi
if ! clevis_luks_save_slot "${DEV}" "${SLT}" "${TKN_ID}" \
"${jwe}" "${OVERWRITE}"; then
echo "Unable to update metadata; operation cancelled" >&2
clevis_luks_restore_dev "${CLEVIS_TMP_DIR}" || :
rm -rf "${CLEVIS_TMP_DIR}"
return 1
fi
clevis_luks_cleanup
trap - EXIT
return 0
}
# clevis_luks_luks2_supported() indicates whether we support LUKS2 devices.
# Support is determined at build time.
function clevis_luks_luks2_supported() {
# We require cryptsetup >= 2.0.4 to fully support LUKSv2.
return @OLD_CRYPTSETUP@
}
# clevis_luks_luks2_existing_token_id_supported() indicates whether
# cryptsetup allows token id for passphrase providing
function clevis_luks_luks2_existing_token_id_supported() {
# We require cryptsetup >= 2.6.0 to fully support LUKSv2 addkey/open by token ID
return @OLD_CRYPTSETUP_EXISTING_TOKEN_ID@
}
# clevis_luks_type() returns the LUKS type of a device, e.g. "luks1".
clevis_luks_type() {
local DEV="${1}"
[ -z "${DEV}" ] && return 1
local luks_type
if cryptsetup isLuks --type luks1 "${DEV}"; then
luks_type="luks1"
elif cryptsetup isLuks --type luks2 "${DEV}"; then
clevis_luks_luks2_supported "${DEV}" || return 1
luks_type="luks2"
else
return 1
fi
echo "${luks_type}"
}
# clevis_kill_pid() kills process and its children in a portable way
# Works with both procps ps and Busybox ps.
clevis_kill_pid() {
local pid="$1"
local child_pids
[ -z "${pid}" ] && return 1
child_pids="$({ ps -Ao pid,ppid 2>/dev/null || ps -o pid,ppid 2>/dev/null || ps -Al 2>/dev/null || ps -l ||
{ echo 'clevis: unable to get list of processes' >&2; exit 1; }; } |
awk -v pid="$pid" '
NR==1 {
for (i=1; i<=NF; i++) if ($i == "PID") pid_col = i; else if ($i == "PPID") ppid_col = i
if (!pid_col || !ppid_col) { print "clevis: unable to find PID and/or PPID columns in ps output" | "cat >&2"; exit 1 }
next
}
{ if ($ppid_col == pid) print $pid_col }')"
for kill_pid in $pid $child_pids; do
kill "$kill_pid" 2>/dev/null
done
}
latchset-clevis-6df9b69/src/luks/clevis-luks-edit 0000775 0000000 0000000 00000012111 15201107217 0022106 0 ustar 00root root 0000000 0000000 #!/bin/bash -e
# vim: set ts=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
#
# Copyright (c) 2020 Red Hat, Inc.
# Author: Sergio Correia
#
# 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 3 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, see .
#
. clevis-luks-common-functions
SUMMARY="Edit a binding from a clevis-bound slot in a LUKS device"
usage() {
exec >&2
echo "Usage: clevis luks edit [-f] -d DEV -s SLT [-c CONFIG]"
echo
echo "${SUMMARY}"
echo
echo "'clevis luks edit' uses the text editor defined in the EDITOR environment variable."
echo " If EDITOR is not defined, it will attempt to use 'vi' as default editor."
echo
echo " -d DEV The LUKS device to edit clevis-bound pins"
echo
echo " -s SLOT The slot to use when editing the clevis binding"
echo
echo " -f Proceed with the edit operation even if the configuration is unchanged"
echo
echo " -c CONFIG The updated config to use"
echo
exit 1
}
on_exit() {
[ -d "${CLEVIS_EDIT_TMP}" ] && rm -rf "${CLEVIS_EDIT_TMP}"
}
validate_cfg() {
local json="${1}"
[ -z "${json}" ] && return 1
jose fmt --json="${json}" --object 2>/dev/null
}
edit_cfg() {
local cfg_file="${1}"
local editor="${EDITOR:-vi}"
if ! command -v "${editor}" >/dev/null; then
echo "Editor '${editor}' not found. " >&2
echo "Please define a valid text editor with the EDITOR environment variable." >&2
exit 1
fi
"${editor}" "${cfg_file}" || true
if ! validate_cfg "${cfg_file}"; then
local ans=
while true; do
read -r -p \
"Malformed configuration. Would you like to edit again? [ynYN] " \
ans
[ "${ans}" != "y" ] && [ "${ans}" != "Y" ] && return 1
break
done
edit_cfg "${cfg_file}"
fi
return 0
}
if [ "${#}" -eq 1 ] && [ "${1}" = "--summary" ]; then
echo "${SUMMARY}"
exit 0
fi
CFG=
FRC=
while getopts ":fd:s:c:" o; do
case "$o" in
d) DEV=${OPTARG};;
s) SLT=${OPTARG};;
c) CFG=${OPTARG};;
f) FRC=-f;;
*) usage;;
esac
done
if [ -z "${DEV}" ]; then
echo "Did not specify a device!" >&2
usage
fi
if [ -z "${SLT}" ]; then
echo "Did not specify a slot!" >&2
usage
fi
if ! binding="$(clevis luks list -d "${DEV}" -s "${SLT}" 2>/dev/null)" \
|| [ -z "${binding}" ]; then
echo "Error retrieving current configuration from ${DEV}:${SLT}" >&2
exit 1
fi
pin="$(echo "${binding}" | cut -d' ' -f2)"
cfg="$(echo "${binding}" | cut -d' ' -f3 | sed -e "s/'//g")"
if ! pretty_cfg="$(printf '%s' "${cfg}" | jq --monochrome-output .)" \
|| [ -z "${pretty_cfg}" ]; then
echo "Error reading the configuration from ${DEV}:${SLT}" >&2
exit 1
fi
mkdir -p "${TMPDIR:-/tmp}"
if ! CLEVIS_EDIT_TMP="$(mktemp -d)" || [ -z "${CLEVIS_EDIT_TMP}" ]; then
echo "Creating a temporary dir for editing binding failed" >&2
exit 1
fi
trap 'on_exit' EXIT
if [ -z "${CFG}" ]; then
CFG_FILE="${CLEVIS_EDIT_TMP}/cfg"
echo "${pretty_cfg}" > "${CFG_FILE}"
edit_cfg "${CFG_FILE}" || exit 1
if ! new_cfg="$(jq . -S < "${CFG_FILE}")" || [ -z "${new_cfg}" ]; then
echo "Error reading the updated config for ${DEV}:${SLT}" >&2
exit 1
fi
else
if ! validate_cfg "${CFG}"; then
echo "Invalid configuration given as parameter with -c" >&2
exit 1
fi
new_cfg="$(printf '%s' "${CFG}" | jq --sort-keys --monochrome-output .)"
fi
if [ "${new_cfg}" = "$(printf '%s' "${pretty_cfg}" \
| jq --sort-keys --monochrome-output .)" ] \
&& [ -z "${FRC}" ]; then
echo "No changes detected; exiting" >&2
exit 1
fi
if ! jcfg="$(jose fmt --json="${new_cfg}" --object --output=- 2>/dev/null)" \
|| [ -z "${jcfg}" ]; then
echo "Error preparing the configuration for the binding update" >&2
exit 1
fi
if [ -z "${CFG}" ]; then
printf "Pin: %s\nNew config:\n%s\n" "${pin}" "${new_cfg}"
while true; do
read -r -p \
"Would you like to proceed with the updated configuration? [ynYN] " \
ans
[ "${ans}" != "y" ] && [ "${ans}" != "Y" ] && exit 0
break
done
fi
# Remove temporary directory.
rm -rf "${CLEVIS_EDIT_TMP}"
echo "Updating binding..."
if ! clevis_luks_do_bind "${DEV}" "${SLT}" "" "${pin}" "${new_cfg}" \
"-y" "overwrite"; then
echo "Unable to update binding in ${DEV}:${SLT}. Operation cancelled." >&2
exit 1
fi
echo "Binding edited successfully" >&2
latchset-clevis-6df9b69/src/luks/clevis-luks-edit.1.adoc 0000664 0000000 0000000 00000003702 15201107217 0023155 0 ustar 00root root 0000000 0000000 CLEVIS-LUKS-EDIT(1)
===================
:doctype: manpage
== NAME
clevis-luks-edit - Edit a binding from a clevis-bound slot in a LUKS device
== SYNOPSIS
*clevis luks edit* [-f] -d DEV -s SLT [-c CONFIG]
== OVERVIEW
The *clevis luks edit* command edits clevis bindings from a LUKS device.
For example:
clevis luks edit -d /dev/sda1 -s 1
== OPTIONS
* *-d* _DEV_ :
The LUKS device to edit clevis-bound pins
* *-s* _SLT_ :
The slot to use when editing the clevis binding
* *-f* :
Proceed with the edit operation even if the config is unchanged
* *-c* _CONFIG_ :
The updated config to use
== EXAMPLES
clevis luks list -d /dev/sda1
1: tang '{"url":"addr"}'
As we can see in the example above, */dev/sda1* has one slots bound, in this case, to a _tang_ pin.
We can edit this binding by issuing the following command:
clevis luks edit -d /dev/sda1 -s 1
This will open a text editor -- the one set in the $EDITOR environment variable, or _vi_, as a fallback -- with the current
configuration of this binding to be edited. In this case, we should have the following:
{
"url": "addr"
}
Once at the editor, we can edit the pin configuration. For _tang_, we could edit the _url_, for instance. After completing the change,
save the file and exit. The updated configuration will be validated for JSON, and if there are no errors, you will be shown the
updated configuration and prompted whether to proceed.
By proceeding, the binding will be updated. There may be required to provide a valid LUKS passphrase for the device.
In the second example, we will update the same device and slot, but we will be providing the updated configuration as well:
clevis luks edit -d /dev/sda1 -s 1 -c '{"url":"new-addr-here"}'
In this case, the binding update will be done in non-interactive mode. Note that it may also be required to provide a LUKS
passphrase for the device.
== SEE ALSO
link:clevis-luks-list.1.adoc[*clevis-luks-list*(1)],
latchset-clevis-6df9b69/src/luks/clevis-luks-list 0000775 0000000 0000000 00000004413 15201107217 0022142 0 ustar 00root root 0000000 0000000 #!/bin/bash -e
# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
#
# Copyright (c) 2017-2019 Red Hat, Inc.
# Author: Javier Martinez Canillas
# Author: Sergio Correia - LUKS2 support.
#
# 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 3 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, see .
#
. clevis-luks-common-functions
SUMMARY="Lists pins bound to a LUKSv1 or LUKSv2 device"
function usage() {
echo >&2
echo "Usage: clevis luks list -d DEV [-s SLT] [-p]" >&2
echo >&2
echo "$SUMMARY": >&2
echo >&2
echo " -d DEV The LUKS device to list bound pins" >&2
echo >&2
echo " -s SLOT The slot number to list" >&2
echo >&2
echo " -p Print only a sorted space-separated list of used pins bound to the specified device" >&2
echo >&2
exit 1
}
if [ ${#} -eq 1 ] && [ "${1}" = "--summary" ]; then
echo "${SUMMARY}"
exit 0
fi
luks_function=clevis_luks_read_pins_from_slot
while getopts ":d:s:p" o; do
case "$o" in
d) DEV=${OPTARG};;
s) SLT=${OPTARG};;
p) luks_function=clevis_luks_read_used_pins_from_slot;;
*) usage;;
esac
done
if [ -z "${DEV}" ]; then
echo "Did not specify a device!" >&2
usage
fi
if cryptsetup isLuks --type luks1 "${DEV}"; then
if ! luksmeta test -d "${DEV}" 2>/dev/null; then
echo "The ${DEV} device is not valid!" >&2
exit 1
fi
fi
if [ -n "${SLT}" ]; then
$luks_function "${DEV}" "${SLT}"
else
if ! used_slots=$(clevis_luks_used_slots "${DEV}"); then
echo "No used slots detected for device ${DEV}!" >&2
exit 1
fi
for s in ${used_slots}; do
if ! $luks_function "${DEV}" "${s}"; then
continue
fi
done
fi
latchset-clevis-6df9b69/src/luks/clevis-luks-list.1.adoc 0000664 0000000 0000000 00000003621 15201107217 0023203 0 ustar 00root root 0000000 0000000 CLEVIS-LUKS-LIST(1)
===================
:doctype: manpage
== NAME
clevis-luks-list - Lists pins bound to a LUKS device
== SYNOPSIS
*clevis luks list* -d DEV [-s SLT]
== OVERVIEW
The *clevis luks list* command list the pins bound to LUKS device.
For example:
clevis luks list -d /dev/sda1
== OPTIONS
* *-d* _DEV_ :
The LUKS device on which to list bound pins
* *-s* _SLT_ :
The slot to use for listing the pin from
* *-p* :
Print only a sorted space-separated list of bound pins
== EXAMPLES
clevis luks list -d /dev/sda1
1: sss '{"t":1,"pins":{"tang":[{"url":"addr1"},{"url":"addr2"}],"tpm2":[{"hash":"sha256","key":"ecc"}],"sss":{"t":1,"pins":{"tang":[{"url":"addr3"}]}}}}'
2: tang '{"url":"addr"}'
3: tpm2 '{"hash":"sha256","key":"ecc","pcr_bank":"sha1","pcr_ids":"7"}'
clevis luks list -d /dev/sda1 -p
1: sss tang tpm2
2: tang
3: tpm2
As we can see in the example above, */dev/sda1* has three slots bound each with a different pin.
- Slot #1 is bound with the _sss_ pin, and uses also tang and tpm2 pins in its policy.
- Slot #2 is bound using the _tang_ pin
- Slot #3 is bound with the _tpm2_ pin
Note that the output of *clevis luks list* can be used with the *clevis luks bind* command, such as:
clevis luks bind -d /dev/sda1 tpm2 '{"hash":"sha256","key":"ecc","pcr_bank":"sha1","pcr_ids":"7"}'
And we will bind another slot with a policy similar to the one we have in slot #3.
Also note that if you are interested in a particular slot, you can pass the _-s SLT_ argument to *clevis luks list*:
clevis luks list -d /dev/sda1 -s 2
2: tang '{"url":"addr"}'
In the above example, we listed only the pin bound to slot #2.
== SEE ALSO
link:clevis-luks-bind.1.adoc[*clevis-luks-bind*(1)],
link:clevis-encrypt-tang.1.adoc[*clevis-encrypt-tang*(1)],
link:clevis-encrypt-tpm2.1.adoc[*clevis-encrypt-tpm2*(1)],
link:clevis-encrypt-sss.1.adoc[*clevis-encrypt-sss*(1)],
latchset-clevis-6df9b69/src/luks/clevis-luks-pass 0000775 0000000 0000000 00000003341 15201107217 0022134 0 ustar 00root root 0000000 0000000 #!/bin/bash -e
# vim: set ts=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
#
# Copyright (c) 2019 Red Hat, Inc.
# Author: Sergio Correia
#
# 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 3 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, see .
#
. clevis-luks-common-functions
SUMMARY="Returns the LUKS passphrase used for binding a particular slot."
usage() {
exec >&2
echo "Usage: clevis luks pass -d DEV -s SLT"
echo
echo "$SUMMARY"
echo
echo " -d DEV The LUKS device to extract the LUKS passphrase used for binding"
echo
echo " -s SLOT The slot number to extract the LUKS passphrase"
echo
exit 1
}
if [ ${#} -eq 1 ] && [ "${1}" = "--summary" ]; then
echo "${SUMMARY}"
exit 0
fi
while getopts ":d:s:" o; do
case "$o" in
d) DEV=${OPTARG};;
s) SLT=${OPTARG};;
*) usage;;
esac
done
if [ -z "${DEV}" ]; then
echo "Did not specify a device!" >&2
usage
fi
if [ -z "${SLT}" ]; then
echo "Did not specify a slot!" >&2
usage
fi
if ! clevis_luks_unlock_device_by_slot "${DEV}" "${SLT}"; then
echo "It was not possible to decrypt the passphrase associated to slot ${SLT} in ${DEV}!" >&2
exit 1
fi
latchset-clevis-6df9b69/src/luks/clevis-luks-pass.1.adoc 0000664 0000000 0000000 00000002012 15201107217 0023167 0 ustar 00root root 0000000 0000000 CLEVIS-LUKS-PASS(1)
===================
:doctype: manpage
== NAME
clevis-luks-pass - Extracts the passphrase used for binding a particular slot in a LUKS device
== SYNOPSIS
*clevis luks pass* -d DEV -s SLT
== OVERVIEW
The *clevis luks pass* command extracts the passphrase used for binding a particular slot in a LUKS device.
For example:
clevis luks pass -d /dev/sda1 -s 1
== OPTIONS
* *-d* _DEV_ :
The LUKS device on which to extract a passphrase from
* *-s* _SLT_ :
The slot to use for extracting the passphrase
== EXAMPLE
clevis luks pass -d /dev/sda1 -s 1
Note that the output of *clevis luks pass* might be non-printable, in which case it would be better to redirect its output to a file and use it as a key file together with cryptsetup. For instance:
clevis luks pass -d /dev/sda1 -s 1 > slot1-passphrase
And the file slot1-passphrase will contain the passphrase associated with slot #1 in /dev/sda1.
== SEE ALSO
link:clevis-luks-unlock.1.adoc[*clevis-luks-unlock*(1)],
latchset-clevis-6df9b69/src/luks/clevis-luks-regen 0000775 0000000 0000000 00000004721 15201107217 0022271 0 ustar 00root root 0000000 0000000 #!/bin/bash -e
# vim: set ts=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
#
# Copyright (c) 2020 Red Hat, Inc.
# Author: Radovan Sroka
# Author: Sergio Correia
#
# 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 3 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, see .
#
. clevis-luks-common-functions
SUMMARY="Regenerate clevis binding"
if [ "${1}" = "--summary" ]; then
echo "${SUMMARY}"
exit 0
fi
usage_and_exit () {
exec >&2
echo "Usage: clevis luks regen [-q] -d DEV -s SLOT"
echo
echo "${SUMMARY}"
echo
echo " -d DEV The LUKS device on which to perform rebinding"
echo
echo " -s SLT The LUKS slot to use"
echo
echo " -q Do not prompt for confirmation"
echo
exit "${1}"
}
QOPT=
while getopts ":hqd:s:" o; do
case "${o}" in
d) DEV="${OPTARG}";;
h) usage_and_exit 0;;
s) SLT="${OPTARG}";;
q) QOPT="-q";;
*) usage_and_exit 1;;
esac
done
if [ -z "${DEV}" ]; then
echo "Did not specify a device!" >&2
exit 1
fi
if [ -z "${SLT}" ]; then
echo "Did not specify a slot!" >&2
exit 1
fi
# Get pin and configuration.
if ! pin_cfg="$(clevis luks list -d "${DEV}" -s "${SLT}")" \
|| [ -z "${pin_cfg}" ]; then
exit 1
fi
pin="$(echo "${pin_cfg}" | cut -d' ' -f2)"
cfg="$(echo "${pin_cfg}" | cut -d' ' -f3 | sed -e "s/'//g")"
if [ -z "${pin}" ] || [ -z "${cfg}" ]; then
echo "Invalid pin or configuration" >&2
exit 1
fi
echo "Regenerating binding (device ${DEV}, slot ${SLT}):"
echo "Pin: ${pin}, Config: '${cfg}'"
if [ -z "${QOPT}" ]; then
read -r -p "Do you want to proceed? [ynYN] " ans
[ "${ans}" != "y" ] && [ "${ans}" != "Y" ] && exit 0
fi
if ! clevis_luks_do_bind "${DEV}" "${SLT}" "" "${pin}" "${cfg}" \
"-y" "overwrite"; then
echo "Unable to regenerate binding in ${DEV}:${SLT}" >&2
exit 1
fi
echo "Binding regenerated successfully" >&2
latchset-clevis-6df9b69/src/luks/clevis-luks-regen.1.adoc 0000664 0000000 0000000 00000002671 15201107217 0023334 0 ustar 00root root 0000000 0000000 CLEVIS-LUKS-REGEN(1)
=====================
:doctype: manpage
== NAME
clevis-luks-regen - Regenerates a clevis binding
== SYNOPSIS
*clevis luks regen* [-q] -d DEV -s SLT
== OVERVIEW
The *clevis luks regen* command regenerates the clevis binding for a given slot in a LUKS device, using the same configuration of the
existing binding. Its operation can be compared to performing *clevis luks unbind* and *clevis luks bind* for rebinding said slot and device.
This is useful when rotating tang keys.
== OPTIONS
* *-d* _DEV_ :
The bound LUKS device
* *-s* _SLT_ :
The slot or key slot number for rebinding. Note that it requires that such slot is currently bound by clevis.
* *-q*:
Do not prompt for confirmation.
== EXAMPLE
Let's start by using clevis luks list to see the current binding configuration in /dev/sda1:
# clevis luks list -d /dev/sda1
1: tang '{"url":"http://tang.server"}'
2: tpm2 '{"hash":"sha256","key":"ecc"}'
We see that slot 1 in /dev/sda1 has a tang binding with the following configuration:
'{"url":"http://tang.server"}'
Now let's do the rebinding of slot 1:
# clevis luks regen -d /dev/sda1 -s 1
After a successful operation, we will have the new binding using the same configuration that was already in place.
== SEE ALSO
link:clevis-luks-list.1.adoc[*clevis-luks-list*(1)]
link:clevis-luks-bind.1.adoc[*clevis-luks-bind*(1)]
link:clevis-luks-unbind.1.adoc[*clevis-luks-unbind*(1)]
latchset-clevis-6df9b69/src/luks/clevis-luks-report 0000775 0000000 0000000 00000013600 15201107217 0022500 0 ustar 00root root 0000000 0000000 #!/bin/bash -e
# vim: set ts=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
#
# Copyright (c) 2018, 2020 Red Hat, Inc.
# Author: Radovan Sroka
# Author: Sergio Correia
#
# 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 3 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, see .
#
. clevis-luks-common-functions
SUMMARY="Report tang keys' rotations"
if [ "${1}" = "--summary" ]; then
echo "${SUMMARY}"
exit 0
fi
report_compare() {
local adv_keys="${1}"
local mdata_keys="${2}"
[ -z "${adv_keys}" ] && return 1
[ -z "${mdata_keys}" ] && return 1
local thp keys
for thp in $(printf '%s' "${mdata_keys}" | jose jwk thp --input=-); do
if ! printf '%s' "${adv_keys}" | jose jwk thp --input=- \
--find "${thp}" >/dev/null; then
keys="$(printf '%s %s' "${keys}" "${thp}")"
fi
done
printf '%s' "${keys}"
}
report_tang() {
local content="${1}"
[ -z "${content}" ] && return 1
local url
if ! url="$(jose fmt --json="${content}" --get url --unquote=-)" \
|| [ -z "${url}" ]; then
echo "Invalid tang metadata; URL not found" >&2
return 1
fi
local jws
if ! jws="$(curl -sfg "${url}/adv")"; then
echo "Unable to fetch advertisement (${url}/adv)" >&2
return 1
fi
local adv_keys
if ! adv_keys="$(jose fmt --json="${jws}" --object --get payload \
--string --b64load --object --get keys \
--array --unwind --output=-)"; then
echo "Advertisement is malformed" >&2
return 1
fi
# Check advertisement validity.
local ver
if ! ver="$(printf '%s' "${adv_keys}" | jose jwk use --input=- \
--required \
--use=verify \
--output=-)"; then
echo "Unable to validate advertisement" >&2
return 1
fi
if ! printf '%s' "${ver}" | jose jws ver --input="${jws}" --key=- \
--all; then
echo "Advertisement is missing signatures" >&2
return 1
fi
local mdata_keys
if ! mdata_keys="$(jose fmt --json="${content}" --get adv --output=-)" \
|| [ -z "${mdata_keys}" ]; then
echo "Keys from clevis metadata not found" >&2
return 1
fi
report_compare "${adv_keys}" "${mdata_keys}"
}
report_sss() {
local content="${1}"
[ -z "${content}" ] && return 1
local jwe
for jwe in $(jose fmt --json="${content}" --get jwe --foreach=-); do
jwe="$(printf '%s' "${jwe}" | sed -e 's/"//g')"
report_decode "${jwe}"
done
}
report_decode() {
local data64="${1}"
[ -z "${data64}" ] && return 1
local data
if ! data="$(clevis_luks_decode_jwe "${data64}")" || [ -z "${data}" ]; then
echo "Unable to decode metadata" >&2
exit 1
fi
local pin
if ! pin="$(jose fmt --json="${data}" --get clevis --get pin --unquote=-)" \
|| [ -z "${pin}" ]; then
echo "Pin not found in clevis metadata" >&2
exit 1
fi
local content
if ! content="$(jose fmt --json="${data}" --get clevis --get "${pin}" \
--output=-)" || [ -z "${content}" ]; then
echo "Invalid pin metadata; no content found" >&2
return 1
fi
case "${pin}" in
tang)
report_tang "${content}"
;;
sss)
report_sss "${content}"
;;
esac
}
usage_and_exit () {
exec >&2
echo "Usage: clevis luks report [-q] [-r] -d DEV -s SLOT"
echo
echo "${SUMMARY}"
echo
echo " -d DEV The LUKS device to check for key rotations"
echo
echo " -s SLT The LUKS slot to use"
echo
echo " -q Quiet mode; do not prompt for using 'clevis luks regen'"
echo
echo " -r Regenerate binding with 'clevis luks regen -q -d DEV -s SLOT'"
echo
exit "${1}"
}
while getopts "hd:s:rq" o; do
case "${o}" in
d) DEV="${OPTARG}";;
h) usage_and_exit 0;;
r) ROPT="regen";;
s) SLT="${OPTARG}";;
q) QOPT="quiet";;
*) usage_and_exit 1;;
esac
done
if [ -z "${DEV}" ]; then
echo "Did not specify a device!" >&2
exit 1
fi
if [ -z "${SLT}" ]; then
echo "Did not specify a slot!" >&2
exit 1
fi
if ! data64="$(clevis_luks_read_slot "${DEV}" "${SLT}")" \
|| [ -z "${data64}" ]; then
# Error message was already displayed by clevis_luks_read_slot(),
# at this point.
exit 1
fi
if ! keys="$(report_decode "${data64}")"; then
echo "Unable to verify whether there are rotated keys" >&2
exit 1
fi
# No rotated keys.
[ -z "${keys}" ] && exit 0
echo "The following keys are not in the current advertisement and were probably rotated:"
for k in ${keys}; do
printf ' %s\n' "${k}"
done
if [ -z "${QOPT}" ] && [ -z "${ROPT}" ]; then
read -r -p "Do you want to regenerate the binding with \"clevis luks regen -q -d ${DEV} -s ${SLT}\"? [ynYN] " ans
if [ "${ans}" = "y" ] || [ "${ans}" = "Y" ]; then
ROPT="regen"
fi
fi
if [ "${ROPT}" = "regen" ]; then
if ! EXE="$(command -v clevis-luks-regen)" || [ -z "${EXE}" ]; then
echo "Unable to find clevis luks regen" >&2
exit 1
fi
exec "${EXE}" -q -d "${DEV}" -s "${SLT}"
fi
exit 1
latchset-clevis-6df9b69/src/luks/clevis-luks-report.1.adoc 0000664 0000000 0000000 00000001564 15201107217 0023547 0 ustar 00root root 0000000 0000000 CLEVIS-LUKS-REPORT(1)
=====================
:doctype: manpage
== NAME
clevis-luks-report - Reports whether a pin bound to a LUKS1 or LUKS2 volume has been rotated
== SYNOPSIS
*clevis luks report* -d DEV -s SLT
== OVERVIEW
The *clevis luks report* command checks a given slot of a LUKS device and reports whether the pin bound to it
-- if any -- has been rotated.
== OPTIONS
* *-d* _DEV_ :
The bound LUKS device
* *-s* _SLT_ :
The slot or key slot number for the pin to be verified
* *-q* :
Quiet mode. If used, we will not prompt whether to regenerate the binding with *clevis luks regen*
* *-r* :
Regenerates LUKS metadata with *clevis luks regen -q -d DEV -s SLT*
== EXAMPLE
Check whether the pin bound to slot 1 in /dev/sda1 has been rotated:
# clevis luks report -d /dev/sda1 -s 1
== SEE ALSO
link:clevis-luks-regen.1.adoc[*clevis-luks-regen*(1)]
latchset-clevis-6df9b69/src/luks/clevis-luks-tpm1-functions.in 0000775 0000000 0000000 00000005654 15201107217 0024473 0 ustar 00root root 0000000 0000000 #!/bin/sh
#
# Copyright (c) 2024 Oldřich Jedlička
#
# Author: Oldřich Jedlička
#
# 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 3 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, see .
#
start_tcsd() {
[ -s /run/tcsd.pid ] && return 0
if ! ip link show up dev lo | grep -qw UP; then
ip link set dev lo up && echo "lo" > /tmp/tcsd.if || :
if ! ip link show up dev lo | grep -qw UP; then
echo "Unable to set-up loopback network device"
return 1
fi
fi
if ! temp_dir="$(mktemp -d)"; then
echo "Unable to create temporary directory"
return 1
fi
fifo_file="$temp_dir/fifo"
output_file="$temp_dir/output"
# If we have udev, let the initialization on udev
if ! [ -f /lib/udev/rules.d/60-tpm-udev.rules ]; then
chown tss: /dev/tpm0
chmod 660 /dev/tpm0
fi
mkfifo "$fifo_file"
# Start timeout to finish TCSD startup
sleep 10 &
sleep_pid=$!
# The following loop ends when output side of FIFO closes (i.e. TCSD ends)
{ while IFS= read -r LINE; do
echo "$LINE"
case "$LINE" in
*"TCSD up and running"*)
kill $sleep_pid 2>/dev/null
;;
esac
done < $fifo_file && kill $sleep_pid; } >> "$output_file" 2>&1 &
# TCSD in background mode logs into syslogd, so we would not have any logs
# available for debugging, so start TCSD in foreground mode, but as a
# background job. Unfortunatelly the redirected output to pipe is
# block-buffered (see `man 3 setbuf`), so in order to see any output we
# need to set it to line-buffered with LD_PRELOAD library
TCSD_NO_PRIVILEGE_DROP=${TCSD_NO_PRIVILEGE_DROP:-0} LD_PRELOAD="@libdir@/libclevis-tpm1-tcsd-preload.so" tcsd -f >$fifo_file 2>&1 &
tcsd_pid=$!
wait $sleep_pid 2>/dev/null
if { ps -A 2>/dev/null || ps; } | awk -v pid="$tcsd_pid" '$1==pid {found=1} END {exit !found}'; then
ret=0
echo $tcsd_pid > /run/tcsd.pid
else
ret=1
[ -s "$output_file" ] && cat "$output_file"
fi
rm -rf "$temp_dir"
return $ret
}
stop_tcsd() {
[ -s /run/tcsd.pid ] && {
pid=$(cat /run/tcsd.pid)
kill $pid >/dev/null 2>&1 || :
rm -f /run/tcsd.pid
}
[ -s /tmp/tcsd.if ] && {
ip link set dev lo down || :
ip addr flush dev lo || :
rm -f /tmp/tcsd.if
}
}
latchset-clevis-6df9b69/src/luks/clevis-luks-unbind.1.adoc 0000664 0000000 0000000 00000001147 15201107217 0023510 0 ustar 00root root 0000000 0000000 CLEVIS-LUKS-UNBIND(1)
=====================
:doctype: manpage
== NAME
clevis-luks-unbind - Unbinds a pin bound to a LUKS volume
== SYNOPSIS
*clevis luks unbind* -d DEV -s SLT
== OVERVIEW
The *clevis luks unbind* command unbinds a pin bound to a LUKS volume.
For example:
$ clevis luks unbind -d /dev/sda -s 1
== OPTIONS
* *-d* _DEV_ :
The bound LUKS device
* *-s* _SLT_ :
The slot number for the pin to unbind. When using LUKSv1, this is the
the LUKSmeta slot
* *-f* :
Do not ask for confirmation and wipe slot in batch-mode
== SEE ALSO
link:clevis-luks-bind.1.adoc[*clevis-luks-bind*(1)]
latchset-clevis-6df9b69/src/luks/clevis-luks-unbind.in 0000775 0000000 0000000 00000007402 15201107217 0023054 0 ustar 00root root 0000000 0000000 #!/bin/bash -e
# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
#
# Copyright (c) 2017 Red Hat, Inc.
# Author: Javier Martinez Canillas
#
# 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 3 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, see .
#
SUMMARY="Unbinds a pin bound to a LUKS volume"
UUID=cb6e8904-81ff-40da-a84a-07ab9ab5715e
# We require cryptsetup >= 2.0.4 to fully support LUKSv2.
# Support is determined at build time.
function luks2_supported() {
return @OLD_CRYPTSETUP@
}
function usage() {
exec >&2
echo
echo "Usage: clevis luks unbind -d DEV -s SLT"
echo
echo "$SUMMARY":
echo
echo " -d DEV The bound LUKS device"
echo
echo " -s SLOT The LUKS slot number for the pin unbind"
echo
echo " -f Do not ask for confirmation and wipe slot in batch-mode"
echo
exit 2
}
if [ $# -eq 1 ] && [ "$1" == "--summary" ]; then
echo "$SUMMARY"
exit 0
fi
FRC=()
while getopts ":d:s:f" o; do
case "$o" in
f) FRC+=(-q);;
d) DEV="$OPTARG";;
s) SLT="$OPTARG";;
*) usage;;
esac
done
if [ -z "$DEV" ]; then
echo "Did not specify a device!" >&2
usage
fi
if [ -z "$SLT" ]; then
echo "Did not specify a slot!" >&2
usage
fi
if ! cryptsetup isLuks "$DEV"; then
echo "$DEV is not a LUKS device!" >&2
exit 1
fi
if luks2_supported; then
if cryptsetup isLuks --type luks1 "$DEV"; then
luks_type="luks1"
elif cryptsetup isLuks --type luks2 "$DEV";then
luks_type="luks2"
else
echo "$DEV is not a supported LUKS device!" >&2
exit 1
fi
else
luks_type="luks1"
fi
if [ "$luks_type" == "luks1" ]; then
if ! luksmeta test -d "$DEV" 2>/dev/null; then
echo "The $DEV device does not contain a LUKSMeta header!" >&2
exit 1
fi
read -r slot state uuid < <(luksmeta show -d "$DEV" | grep "^$SLT *")
if [ "$uuid" == "empty" ]; then
echo "The LUKSMeta slot $SLT on device $DEV is already empty." >&2
exit 1
fi
[ "$state" == "active" ] && KILL=true
elif [ "$luks_type" == "luks2" ]; then
dump="$(cryptsetup luksDump "$DEV")"
grep -q "^\s*$SLT: luks2" <<< "$dump" && KILL=true
TOK="$(grep -E -B1 "^\s+Keyslot:\s+$SLT$" <<< "$dump" \
| sed -rn 's|^\s+([0-9]+): clevis|\1|p')"
if [ -z "${TOK}" ]; then
echo "No clevis slot detected on device ${DEV}:${SLT}!" >&2
exit 1
fi
fi
if [ -z "${FRC[*]}" ]; then
echo "The unbind operation will wipe a slot. This operation is unrecoverable." >&2
read -r -p "Do you wish to erase LUKS slot $SLT on $DEV? [ynYN] " ans < /dev/tty
[[ "$ans" =~ ^[yY]$ ]] || exit 0
fi
if [ -n "$KILL" ]; then
if ! cryptsetup luksKillSlot "$DEV" "$SLT" "${FRC[@]}"; then
echo "LUKS slot $SLT for device $DEV couldn't be deleted"
exit 1
fi
fi
if [ "$luks_type" == "luks1" ]; then
if ! luksmeta wipe -f -d "$DEV" -u "$UUID" -s "$SLT"; then
echo "LUKSMeta slot $SLT for device $DEV couldn't be deleted"
exit 1
fi
elif [ "$luks_type" == "luks2" ] && [ -n "$TOK" ]; then
if ! cryptsetup token remove --token-id "$TOK" "$DEV"; then
echo "Error while removing token $TOK from LUKS device $DEV!" >&2
exit 1
fi
fi
latchset-clevis-6df9b69/src/luks/clevis-luks-unlock 0000775 0000000 0000000 00000004513 15201107217 0022463 0 ustar 00root root 0000000 0000000 #!/bin/bash -e
# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
#
# Copyright (c) 2016 Red Hat, Inc.
# Author: Nathaniel McCallum
#
# 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 3 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, see .
#
. clevis-luks-common-functions
SUMMARY="Unlocks a LUKS volume"
function usage() {
exec >&2
echo
echo "Usage: clevis luks unlock -d DEV [-n NAME] [-t SLT]"
echo
echo "$SUMMARY":
echo
echo " -d DEV The LUKS device on which to perform unlocking"
echo
echo " -n NAME The name of the unlocked device node"
echo
echo " -t SLT Test the passphrase for the given slot without unlocking"
echo " the device"
echo
echo " -o OPTS Pass options to underlying 'cryptsetup open'; be sure"
echo " to quote the OPTS you pass, if they contain a space,"
echo " etc."
echo
exit 2
}
if [ $# -eq 1 ] && [ "$1" == "--summary" ]; then
echo "$SUMMARY"
exit 0
fi
while getopts ":d:n:t:o:" o; do
case "$o" in
d) DEV="$OPTARG";;
n) NAME="$OPTARG";;
t) SLT="$OPTARG";;
o) OPENARGS="$OPTARG";;
*) usage;;
esac
done
if [ -z "$DEV" ]; then
echo "Did not specify a device!" >&2
usage
fi
if ! cryptsetup isLuks "$DEV"; then
echo "$DEV is not a LUKS device!" >&2
exit 1
fi
NAME="${NAME:-luks-"$(cryptsetup luksUUID "$DEV")"}"
if [ -n "$SLT" ]; then
if ! clevis_luks_unlock_device_by_slot "${DEV}" "${SLT}" >/dev/null; then
echo "Test for token slot ${SLT} on device ${DEV} failed." >&2
exit 1
fi
else
if ! pt=$(clevis_luks_unlock_device "${DEV}"); then
echo "${DEV} could not be opened." >&2
exit 1
fi
echo -n "${pt}" | cryptsetup ${OPENARGS} open -d- "${DEV}" "${NAME}"
fi
latchset-clevis-6df9b69/src/luks/clevis-luks-unlock.1.adoc 0000664 0000000 0000000 00000001332 15201107217 0023520 0 ustar 00root root 0000000 0000000 CLEVIS-LUKS-UNLOCK(1)
=====================
:doctype: manpage
== NAME
clevis-luks-unlock - Unlocks a LUKS device bound with a Clevis policy
== SYNOPSIS
*clevis luks unlock* -d DEV [-n NAME] [-t SLT]
== OVERVIEW
The *clevis luks unlock* command unlocks a LUKS device using its already
provisioned Clevis policy. For example:
$ clevis luks unlock -d /dev/sda
== OPTIONS
* *-d* _DEV_ :
The LUKS device to unlock
* *-n* _NAME_ :
The name to give the unlocked device node
* *-t* _SLT_ :
Test the passphrase for the given slot without unlocking the device
* *-o* _PARAMS_ :
Pass arbitrary parameters to cryptsetup; quote parameters as necessary
== SEE ALSO
link:clevis-luks-bind.1.adoc[*clevis-luks-bind*(1)]
latchset-clevis-6df9b69/src/luks/clevis-luks-unlockers.7.adoc 0000664 0000000 0000000 00000004465 15201107217 0024252 0 ustar 00root root 0000000 0000000 CLEVIS-LUKS-UNLOCKERS(7)
========================
:doctype: manpage
== NAME
clevis-luks-unlockers - Overview of clevis luks unlockers
== OVERVIEW
Clevis provides unlockers for LUKS volumes which can use LUKS policy:
* clevis-luks-unlock - Unlocks manually using the command line.
* dracut - Unlocks automatically during early boot.
* systemd - Unlocks automatically during late boot.
* udisks2 - Unlocks automatically in a GNOME desktop session.
Once a LUKS volume is bound using *clevis luks bind*, it can be unlocked using
any of the above unlockers without using a password.
== MANUAL UNLOCKING
You can unlock a LUKS volume manually using the following command:
$ sudo clevis luks unlock -d /dev/sda
For more information, see link:clevis-luks-unlock.1.adoc[*clevis-luks-unlock*(1)].
== EARLY BOOT UNLOCKING
If Clevis integration does not already ship in your initramfs, you may need to
rebuild your initramfs with this command:
$ sudo dracut -f
Once Clevis is integrated into your initramfs, a simple reboot should unlock
your root volume. Note, however, that early boot integration only works for the
root volume. Non-root volumes should use the late boot unlocker.
Dracut will not bring up your network by default. You can either have it come
up via DHCP by using rd.neednet=1 in kernel cmdline or you can specify custom
network parameters, such as static IP configuration, please consult the dracut
documentation.
DHCP can be easily added to early boot by setting it in a configuration file
and rebuilding initramfs afterwards
$ echo 'kernel_cmdline="rd.neednet=1"' | sudo tee /etc/dracut.conf.d/clevis.conf
$ sudo dracut -f
== LATE BOOT UNLOCKING
You can enable late boot unlocking by executing the following command:
$ sudo systemctl enable clevis-luks-askpass.path
After a reboot, Clevis will attempt to unlock all devices listed in
*/etc/crypttab* that have clevis bindings when systemd prompts for their passwords.
== DESKTOP UNLOCKING
When the udisks2 unlocker is installed, your GNOME desktop session should
unlock LUKS removable devices configured with Clevis automatically. You may
need to restart your desktop session after installation for the unlocker to be
loaded.
== SEE ALSO
link:clevis-luks-unlock.1.adoc[*clevis-luks-unlock*(1)]
link:clevis-luks-bind.1.adoc[*clevis-luks-bind*(1)]
latchset-clevis-6df9b69/src/luks/dracut/ 0000775 0000000 0000000 00000000000 15201107217 0020262 5 ustar 00root root 0000000 0000000 latchset-clevis-6df9b69/src/luks/dracut/clevis-pin-null/ 0000775 0000000 0000000 00000000000 15201107217 0023303 5 ustar 00root root 0000000 0000000 latchset-clevis-6df9b69/src/luks/dracut/clevis-pin-null/meson.build 0000664 0000000 0000000 00000000637 15201107217 0025453 0 ustar 00root root 0000000 0000000 dracut = dependency('dracut', required: false)
if dracut.found()
dracutdir = dracut.get_pkgconfig_variable('dracutmodulesdir') + '/50' + meson.project_name() + '-pin-null'
configure_file(
input: 'module-setup.sh.in',
output: 'module-setup.sh',
install_dir: dracutdir,
configuration: data,
)
else
warning('Will not install dracut module clevis-pin-null due to missing dependencies!')
endif
latchset-clevis-6df9b69/src/luks/dracut/clevis-pin-null/module-setup.sh.in 0000775 0000000 0000000 00000001617 15201107217 0026677 0 ustar 00root root 0000000 0000000 #!/bin/bash
# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
#
# Copyright (c) 2016 Red Hat, Inc.
# Author: Nathaniel McCallum
#
# 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 3 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, see .
#
depends() {
echo clevis
return 0
}
install() {
inst clevis-decrypt-null
}
latchset-clevis-6df9b69/src/luks/dracut/clevis-pin-pkcs11/ 0000775 0000000 0000000 00000000000 15201107217 0023433 5 ustar 00root root 0000000 0000000 latchset-clevis-6df9b69/src/luks/dracut/clevis-pin-pkcs11/clevis-pkcs11-hook.sh.in 0000775 0000000 0000000 00000001704 15201107217 0027724 0 ustar 00root root 0000000 0000000 #!/bin/sh
#
# Copyright (c) 2024 Red Hat, Inc.
# Author: Sergio Arroutbi
#
# 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 3 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, see .
#
. /usr/bin/clevis-pkcs11-common
if [ ! -f /run/systemd/clevis-pkcs11.run ] && [ -d /run/systemd ];
then
clevis_start_pcscd_server
echo "" >/run/systemd/clevis-pkcs11.run
@libexecdir@/clevis-luks-pkcs11-askpin -d -r
fi
latchset-clevis-6df9b69/src/luks/dracut/clevis-pin-pkcs11/clevis-pkcs11-prehook.sh 0000775 0000000 0000000 00000001724 15201107217 0030030 0 ustar 00root root 0000000 0000000 #!/bin/sh
#
# Copyright (c) 2024 Red Hat, Inc.
# Author: Sergio Arroutbi
#
# 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 3 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, see .
#
if [ ! -f /run/systemd/clevis-pkcs11.pre.run ] && [ -d /run/systemd ];
then
clevis-pkcs11-afunix-socket-unlock -l /run/systemd/clevis-pkcs11-dracut.log -f /run/systemd/clevis-pkcs11.sock -s 60 &
echo "" > /run/systemd/clevis-pkcs11.pre.run
fi
latchset-clevis-6df9b69/src/luks/dracut/clevis-pin-pkcs11/meson.build 0000664 0000000 0000000 00000001201 15201107217 0025567 0 ustar 00root root 0000000 0000000 dracut = dependency('dracut', required: false)
if dracut.found()
dracutdir = dracut.get_pkgconfig_variable('dracutmodulesdir') + '/50' + meson.project_name() + '-pin-pkcs11'
configure_file(
input: 'module-setup.sh.in',
output: 'module-setup.sh',
install_dir: dracutdir,
configuration: data,
)
configure_file(
input: 'clevis-pkcs11-hook.sh.in',
output: 'clevis-pkcs11-hook.sh',
install_dir: dracutdir,
configuration: data,
)
install_data('clevis-pkcs11-prehook.sh', install_dir: dracutdir)
else
warning('Will not install dracut module clevis-pin-pkcs11 due to missing dependencies!')
endif
latchset-clevis-6df9b69/src/luks/dracut/clevis-pin-pkcs11/module-setup.sh.in 0000775 0000000 0000000 00000004137 15201107217 0027027 0 ustar 00root root 0000000 0000000 #!/bin/bash
#
# Copyright (c) 2024 Red Hat, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 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, see .
#
# shellcheck disable=SC2154
#
check() {
require_binaries pcscd pkcs11-tool clevis-decrypt-pkcs11 || return 1
require_binaries awk head sed socat tail tr || return 1
return 0
}
depends() {
echo clevis
return 255
}
install() {
inst_hook pre-trigger 60 "${moddir}/clevis-pkcs11-prehook.sh"
inst_hook initqueue/settled 60 "${moddir}/clevis-pkcs11-hook.sh"
inst_hook initqueue/online 60 "${moddir}/clevis-pkcs11-hook.sh"
inst_multiple \
awk \
pcscd \
pkcs11-tool \
head \
sed \
socat \
tail \
tr \
/usr/lib64/pcsc/drivers/ifd-ccid.bundle/Contents/Linux/libccid.so \
/usr/lib64/pcsc/drivers/ifd-ccid.bundle/Contents/Info.plist \
/usr/lib64/opensc-pkcs11.so \
/usr/lib64/pkcs11/opensc-pkcs11.so \
/usr/lib64/libopensc.so* \
/etc/opensc.conf \
/usr/lib64/ossl-modules/legacy.so \
/lib64/libpcsclite.so.1 \
@libexecdir@/clevis-luks-pkcs11-askpass \
@libexecdir@/clevis-luks-pkcs11-askpin \
clevis-luks-common-functions \
clevis-pkcs11-afunix-socket-unlock \
clevis-pkcs11-common \
clevis-decrypt-pkcs11
# Include libraries from configuration automatically
. /usr/bin/clevis-pkcs11-common
for file in $(clevis_get_module_path_from_pkcs11_config | sed -e 's@;@\n@g'); do
inst_multiple ${file}
done
dracut_need_initqueue
}
latchset-clevis-6df9b69/src/luks/dracut/clevis-pin-sss/ 0000775 0000000 0000000 00000000000 15201107217 0023141 5 ustar 00root root 0000000 0000000 latchset-clevis-6df9b69/src/luks/dracut/clevis-pin-sss/meson.build 0000664 0000000 0000000 00000000635 15201107217 0025307 0 ustar 00root root 0000000 0000000 dracut = dependency('dracut', required: false)
if dracut.found()
dracutdir = dracut.get_pkgconfig_variable('dracutmodulesdir') + '/50' + meson.project_name() + '-pin-sss'
configure_file(
input: 'module-setup.sh.in',
output: 'module-setup.sh',
install_dir: dracutdir,
configuration: data,
)
else
warning('Will not install dracut module clevis-pin-sss due to missing dependencies!')
endif
latchset-clevis-6df9b69/src/luks/dracut/clevis-pin-sss/module-setup.sh.in 0000775 0000000 0000000 00000001616 15201107217 0026534 0 ustar 00root root 0000000 0000000 #!/bin/bash
# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
#
# Copyright (c) 2016 Red Hat, Inc.
# Author: Nathaniel McCallum
#
# 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 3 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, see .
#
depends() {
echo clevis
return 0
}
install() {
inst clevis-decrypt-sss
}
latchset-clevis-6df9b69/src/luks/dracut/clevis-pin-tang/ 0000775 0000000 0000000 00000000000 15201107217 0023262 5 ustar 00root root 0000000 0000000 latchset-clevis-6df9b69/src/luks/dracut/clevis-pin-tang/meson.build 0000664 0000000 0000000 00000000637 15201107217 0025432 0 ustar 00root root 0000000 0000000 dracut = dependency('dracut', required: false)
if dracut.found()
dracutdir = dracut.get_pkgconfig_variable('dracutmodulesdir') + '/50' + meson.project_name() + '-pin-tang'
configure_file(
input: 'module-setup.sh.in',
output: 'module-setup.sh',
install_dir: dracutdir,
configuration: data,
)
else
warning('Will not install dracut module clevis-pin-tang due to missing dependencies!')
endif
latchset-clevis-6df9b69/src/luks/dracut/clevis-pin-tang/module-setup.sh.in 0000775 0000000 0000000 00000002514 15201107217 0026653 0 ustar 00root root 0000000 0000000 #!/bin/bash
# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
#
# Copyright (c) 2016 Red Hat, Inc.
# Author: Nathaniel McCallum
#
# 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 3 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, see .
#
depends() {
echo clevis network
return 0
}
have_tang_bindings() {
. clevis-luks-common-functions
local dev
for dev in $(clevis_devices_to_unlock "list-open-devices"); do
if clevis luks list -d "${dev}" -p | grep -q tang; then
return 0
fi
done
return 1
}
install() {
if [ "${hostonly_cmdline}" = "yes" ] && have_tang_bindings; then
echo "rd.neednet=1" > "${initdir}/etc/cmdline.d/99clevis-pin-tang.conf"
fi
inst_multiple \
clevis-decrypt-tang \
curl
}
latchset-clevis-6df9b69/src/luks/dracut/clevis-pin-tpm1/ 0000775 0000000 0000000 00000000000 15201107217 0023212 5 ustar 00root root 0000000 0000000 latchset-clevis-6df9b69/src/luks/dracut/clevis-pin-tpm1/meson.build 0000664 0000000 0000000 00000000637 15201107217 0025362 0 ustar 00root root 0000000 0000000 dracut = dependency('dracut', required: false)
if dracut.found()
dracutdir = dracut.get_pkgconfig_variable('dracutmodulesdir') + '/50' + meson.project_name() + '-pin-tpm1'
configure_file(
input: 'module-setup.sh.in',
output: 'module-setup.sh',
install_dir: dracutdir,
configuration: data,
)
else
warning('Will not install dracut module clevis-pin-tpm1 due to missing dependencies!')
endif
latchset-clevis-6df9b69/src/luks/dracut/clevis-pin-tpm1/module-setup.sh.in 0000775 0000000 0000000 00000013715 15201107217 0026610 0 ustar 00root root 0000000 0000000 #!/bin/bash
# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
#
# Copyright (c) 2024 Oldřich Jedlička
#
# Author: Oldřich Jedlička
#
# 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 3 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, see .
#
require_file() {
local path="$1"
if ! [ -f "$path" ]; then
# shellcheck disable=SC2154 # $moddir is a dracut variable
local _module_name="${moddir##*/[0-9][0-9]}"
dinfo "dracut module '${_module_name}' will not be installed, because file '$path' could not be found!"
return 1
fi
return 0
}
require_files() {
local _ret=0
for path in "$@"; do
require_file "$path" || ((_ret++))
done
return "$_ret"
}
require_dir() {
local path="$1"
if ! [ -d "$path" ]; then
local _module_name="${moddir##*/[0-9][0-9]}"
dinfo "dracut module '${_module_name}' will not be installed, because directory '$path' could not be found!"
return 1
fi
return 0
}
require_nonempty_dir() {
local path="$1"
require_dir "$path" || return 1
# See https://superuser.com/a/667095 how to test empty dir
files=$(shopt -s nullglob; shopt -u dotglob; echo "$path/"*)
if ! [[ "$files" ]]; then
local _module_name="${moddir##*/[0-9][0-9]}"
dinfo "dracut module '${_module_name}' will not be installed, because directory '$path' is empty!"
return 1
fi
return 0
}
check() {
local _module_name="${moddir##*/[0-9][0-9]}"
require_binaries clevis-decrypt-tpm1 tpm_version tpm_unsealdata tcsd || return 1
if [[ $hostonly ]]; then
require_nonempty_dir /var/lib/tpm || return 1
else
[ -f /usr/share/trousers/system.data.auth ] || \
[ -f /var/lib/tpm/system.data.auth ] || \
ddebug " ${_module_name}: no usable system.data.auth in /usr/share/trousers nor /var/lib/tpm found, using built-in one"
fi
if dracut_module_included "systemd"; then
# shellcheck disable=SC2154 # $systemdsystemunitdir is a dracut variable
require_files \
"$systemdsystemunitdir"/tcsd.service \
"$systemdsystemunitdir"/tcsd.service.d/clevis-tcsd.conf \
|| return 1
fi
return 0
}
depends() {
echo clevis network
return 0
}
install() {
if dracut_module_included "systemd"; then
inst_multiple \
"$systemdsystemunitdir/tcsd.service" \
"$systemdsystemunitdir/tcsd.service.d/clevis-tcsd.conf"
# shellcheck disable=SC2154 # $initdir is a dracut variable
systemctl -q --root "$initdir" add-wants cryptsetup.target tcsd.service
else
inst_multiple \
awk chmod chown mkfifo mktemp ip ps \
@libdir@/libclevis-tpm1-tcsd-preload.so \
@libexecdir@/clevis-luks-tpm1-functions
fi
inst_multiple \
clevis-decrypt-tpm1 \
tcsd \
tpm_version \
tpm_unsealdata
inst_rules 60-tpm-udev.rules
if ! [[ $hostonly ]] || ! dracut_module_included "systemd"; then
# /etc/hosts is installed only in host-only mode with systemd, so
# we need to create our own in order to get tpm tools working.
# The localhost entry is required by tpm tools.
if [ ! -f "$initdir/etc/hosts" ]; then
echo "127.0.0.1 localhost" >> "$initdir/etc/hosts"
echo "::1 localhost ip6-localhost ip6-loopback" >> "$initdir/etc/hosts"
echo "ff02::1 ip6-allnodes" >> "$initdir/etc/hosts"
echo "ff02::2 ip6-allrouters" >> "$initdir/etc/hosts"
fi
fi
if [[ $hostonly ]]; then
inst /etc/tcsd.conf
inst_multiple /var/lib/tpm/*
else
inst_dir /etc
touch "$initdir/etc/tcsd.conf"
if [ -f "/etc/tcsd.conf" ] && [[ $(stat -c "0%a" "/etc/tcsd.conf") = "0600" ]]; then
# Compatibility with tcsd version 0.3.14
chmod 0600 "$initdir/etc/tcsd.conf"
chown tss:tss "$initdir/etc/tcsd.conf"
else
chmod 0640 "$initdir/etc/tcsd.conf"
chown root:tss "$initdir/etc/tcsd.conf"
fi
inst_dir /var/lib/tpm
if [ -f /usr/share/trousers/system.data.auth ]; then
inst /usr/share/trousers/system.data.auth /var/lib/tpm/system.data
elif [ -f /var/lib/tpm/system.data.auth ]; then
inst /var/lib/tpm/system.data.auth /var/lib/tpm/system.data
else
jose b64 dec -i- >"$initdir/var/lib/tpm/system.data" <