Skip to content

Commit 22cb93d

Browse files
author
Christoph Biedl
committed
Provide a template for new pins
This should ease writing new pins a lot, for newcomers and for experienced authors as well.
1 parent 0bea5c4 commit 22cb93d

File tree

8 files changed

+530
-0
lines changed

8 files changed

+530
-0
lines changed

src/pins/template/README.md

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
2+
# Writing your own pin
3+
4+
The files here should give you an introduction into writing your own pin.
5+
6+
## Overall workflow
7+
8+
The `encrypt` script reads a plain text from stdin, encrypts it using
9+
`jose jwe enc` which writes the result to stdout, together with some
10+
information how to re-create the plain text later. The encryption key
11+
itself *must* *not* be included here.
12+
13+
The encryption key is provided or created by the pin and stashed away
14+
in some way. That is the core logic of a pin.
15+
16+
A configuration in the JSON format is provided as the first parameter,
17+
it controls the pin's operation.
18+
19+
The `decrypt` script reads the encrypted information from stdin,
20+
decrypts it using `ose jwe dec` which again writes the result to
21+
stdout. The information provided by `encrypt` above is available, this
22+
must be sufficient to restore the encryption key.
23+
24+
## How to use this template
25+
26+
Copy all the files here (except for this one) into a new subdirectory
27+
of `src/pins/`, named as your pin.
28+
29+
Replace @pin@ with the name of your pin everywhere, including file names.
30+
31+
The `clevis-{en,de}crypt-@pin@` scripts require the most attention.
32+
33+
Have a man page in `clevis-encrypt-@pin@.1.adoc`.
34+
35+
Adjust `meson.build`.
36+
37+
Provide a test in `pin-@pin@`.
38+
39+
Adjust dracut configuration in `dracut.module-setup.sh.in`.
40+
41+
Adjust initramfs configuration in `initramfs.in`.
42+
43+
Optionally add something to `clevis-luks-list`.
44+
45+
Finally, add your pin in `../meson.build`.
46+
47+
## Comments
48+
49+
An extra form of comments is used to explain concepts. They all should
50+
be removed before sending out patches/merge requests.
51+
52+
#%# some generic information
53+
#!# things worth to know, gotchas
54+
#?# some bits that require more understanding
55+
56+
## Nameing your pin and configuration variables
57+
58+
The pin name should be short and reflect the purpose. To avoid trouble
59+
or extra work, the name should start with a letter, followed by letters,
60+
digits, or underscore.
61+
62+
Parameter names for the pin configuration should follow the same
63+
syntax. These templates assume they can be used as a shell variable.
64+
65+
## Templates variables
66+
67+
The templates use `@...@` to mark places that can semi-automatically
68+
be adjusted to your needs. Variables are
69+
70+
* `@pin@`: The name of this pin, see above
71+
* `@PIN@`: The name of this pin, uppercase
72+
* `@year@`: Current year
73+
* `@name@`: Your name
74+
* `@email@`: Your e-mail address
75+
* `@mand1@`: The name of a mandatory parameter
76+
* `@mand2@`: The name of another mandatory parameter
77+
* `@opt1@`: The name of an optional parameter
78+
* `@param1@`: The name of a parameter needed for decryption
79+
* `@param2@`: Another name
80+
81+
If you have more parameters, extend accordingly
82+
83+
Any `@@` requires attention in wording.
84+
85+
Make sure you've replaced *all* occurances of template variables.
86+
Else the build will probably fail.
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#%# Creating an decrypting pin
2+
#%#
3+
#%# Read README.md and clevis-encrypt-@pin@ first, this file aims to
4+
#%# to avoid information duplication.
5+
#%# Unfortunately, this one uses a bashism (read -d) that is not at
6+
#%# all easy to eliminate.
7+
#!/bin/bash
8+
9+
set -eu
10+
11+
# Copyright (c) @year@ @name@
12+
# Author: @name@ <@email@>
13+
#
14+
# This program is free software: you can redistribute it and/or modify
15+
# it under the terms of the GNU General Public License as published by
16+
# the Free Software Foundation, either version 3 of the License, or
17+
# (at your option) any later version.
18+
#
19+
# This program is distributed in the hope that it will be useful,
20+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
21+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22+
# GNU General Public License for more details.
23+
#
24+
# You should have received a copy of the GNU General Public License
25+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
26+
#
27+
28+
#%# This program takes no options - everything needed to know will be
29+
#%# read from stdin.
30+
[ $# -eq 1 ] && [ "${1:-}" = "--summary" ] && exit 2
31+
32+
if [ -t 0 ] ; then
33+
echo >&2
34+
echo 'Usage: clevis decrypt @pin@ < JWE > PLAINTEXT' >&2
35+
echo >&2
36+
exit 1
37+
fi
38+
39+
#%# The input is concatenated using the dot. Read the first element
40+
#%# but leave everything else in the buffer. Only read -d can to that.
41+
read -d . hdr64
42+
#%# The header is base64-encoded. Decode now and also verify this is valid JSON
43+
if ! hdr="$(jose fmt --quote="$hdr64" --string --b64load --object --output=-)" ; then
44+
echo 'JWE header corrupt' >&2
45+
exit 1
46+
fi
47+
48+
#%# Input validation: The pin must exist by name.
49+
if [ "$(jose fmt --json="$hdr" --get clevis --get pin --unquote=-)" != '@pin@' ] ; then
50+
echo 'JWE pin mismatch!' >&2
51+
exit 1
52+
fi
53+
54+
#%# Load the parameters into shell variables.
55+
if ! @param1@="$(jose fmt --json="$hdr" --get clevis --get @pin@ --get @param1@ --unquote=-)" ; then
56+
echo 'JWE missing 'clevis.@pin@.@param1@' header parameter!' >&2
57+
exit 1
58+
fi
59+
if ! @param2@="$(jose fmt --json="$hdr" --get clevis --get @pin@ --get @param2@ --unquote=-)" ; then
60+
echo 'JWE missing 'clevis.@pin@.@param2@' header parameter!' >&2
61+
exit 1
62+
fi
63+
64+
#%# Possibly some pre-checks on your parameters are needed.
65+
66+
#%# Now everything is set up for your pin's business logic
67+
#%#
68+
#%# Your job: Somehow bring the key into `jwk`.
69+
jwk="$(load_jwk)"
70+
71+
#%# Finally, forward everything to `jose jwe dec` which does the
72+
#%# decryption job.
73+
( printf '%s' "$jwk$hdr64." ; cat ) | exec jose jwe dec --key=- --input=-
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
#%# Creating an encrypting pin
2+
#%#
3+
#%# Read README.md first.
4+
#%#
5+
#%# The shell interpreter. For portability, it should have as little
6+
#%# requirements as possibly. Especially the decrypt should be executable
7+
#%# in busybox' ash as well
8+
#!/bin/sh
9+
10+
#%# Some hardening. Safeguard against coding errors.
11+
set -eu
12+
13+
#%# Legal stuff. Put your name etc. here.
14+
#%# Of course you're not bound to GPL-3+ but it will certainly ease
15+
#%# inclusion in upstream clevis if you use that.
16+
# Copyright (c) @year@ @name@
17+
# Author: @name@ <@email@>
18+
#
19+
# This program is free software: you can redistribute it and/or modify
20+
# it under the terms of the GNU General Public License as published by
21+
# the Free Software Foundation, either version 3 of the License, or
22+
# (at your option) any later version.
23+
#
24+
# This program is distributed in the hope that it will be useful,
25+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
26+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27+
# GNU General Public License for more details.
28+
#
29+
# You should have received a copy of the GNU General Public License
30+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
31+
#
32+
33+
#%# A one-line summary. Will be used in the help messages below.
34+
SUMMARY='Encrypts using a @pin@ @@ policy'
35+
36+
#%# Some option parsing, very simple.
37+
#%# Don't touch, it's hardcoded in the `clevis` program.
38+
if [ "${1:-}" = '--summary' ] ; then
39+
echo "$SUMMARY"
40+
exit 0
41+
fi
42+
43+
#%# Regular operation assumes output goes to a file. If not, print
44+
#%# some usage information and bail out.
45+
if [ -t 0 ] ; then
46+
#!# Since this script runs in a pipe, *all* operational messages
47+
#!# must go to stderr.
48+
exec >&2
49+
echo
50+
#%# Don't be confused: This script is called from `clevis`, so
51+
#%# the usage text has spaces, not dashes.
52+
#%# Also, the configuration is in $1, see below.
53+
echo 'Usage: clevis encrypt @pin@ CONFIG < PLAINTEXT > JWE'
54+
echo
55+
echo "$SUMMARY"
56+
echo
57+
echo 'This command uses the following configuration properties:'
58+
echo
59+
#%# For the sake of users: Give a good explanation of your pin's
60+
#%# parameters.
61+
#%# Mandatory parameters should contain the string "REQUIRED"
62+
echo ' @mand1@: <string> One parameter @@ (REQUIRED)'
63+
echo
64+
echo ' @mand2@: <string> Another parameter @@ (REQUIRED)'
65+
echo
66+
#%# Optional parameters should mention the default value.
67+
echo ' @opt1@: <string> An optional parameter @@ (default: @@)'
68+
echo
69+
#%# Pure visual: Make sure the short descriptions are aligned to the
70+
#%# same column.
71+
exit 2
72+
fi
73+
74+
#%# The CONFIG parameter in $1 has to be valid JSON
75+
if ! cfg="$(jose fmt --json="${1:-}" --object --output=- 2>/dev/null)" ; then
76+
echo 'Configuration is malformed!' >&2
77+
exit 1
78+
fi
79+
80+
#%# Load the values from the configuration into shell variables.
81+
#%# Re-using the name is certainly a good idea
82+
#%#
83+
#%# For mandatory parameters it's like that:
84+
if ! @mand1@="$(jose fmt --json="$cfg" --object --get @mand1@ --unquote=-)" ; then
85+
echo 'Missing the required @mand1@ property!' >&2
86+
exit 1
87+
fi
88+
if ! @mand2@="$(jose fmt --json="$cfg" --object --get @mand2@ --unquote=-)" ; then
89+
echo 'Missing the required @mand2@ property!' >&2
90+
exit 1
91+
fi
92+
93+
#%# For optional parameters, use:
94+
@opt1@="$(jose fmt --json="$cfg" --object --get @opt1@ --unquote=-)" || @opt1@='@@'
95+
96+
#%# Possibly validate parameters. If a check can be done at *en*crypt
97+
#%# time, it should be done now.
98+
99+
#%# Now everything is set up for your pin's business logic.
100+
#%#
101+
#%# Your jobs, in no particular order:
102+
#%#
103+
#%# 1. Have the key in `jwk`:
104+
#%# If you want to create a new key:
105+
jwk="$(jose jwk gen --input='{"alg":"A256GCM"}')"
106+
#%# Feel free to use different algorithms for `"alg"`,
107+
#%# jose-jwk-gen(1) and jose-alg(1) have more on all this.
108+
#%#
109+
#%# Or, if you want to use an existing key, just load it into `jwk`
110+
#%# from wherever you got it from:
111+
jwk="$(somehow_get_the_key)"
112+
#%# Remember the result must be a valid jwk object.
113+
114+
#%# 2. Store the key somewhere. That's your logic.
115+
store_the_jwk "$jwk"
116+
#%# It is a good idea to store the entire `$jwk`. If you want to
117+
#%# extract the actual key, use
118+
#%# jose fmt --json="$jwk" --object --get k --unquote=-
119+
#%# ... but you're probably wrong if you want to do that.
120+
121+
#%# 3. Assemble all the information you will need to re-create
122+
#%# the key later in `jwe`:
123+
#%#
124+
#%# First create a skeleton that declares the pin, and creates a store.
125+
jwe='{"protected":{"clevis":{"pin":"@pin@","@pin@":{}}}}'
126+
#%# Then populate that store. Possibly you'll just have to pass
127+
#%# the parameters. Leave out those you will not need for decryption.
128+
#%# NB: The long form of the `-U` parameter of `jose fmt` is "--unwind"
129+
jwe="$(jose fmt --json="$jwe" --get protected --get clevis --get @pin@ --quote "$@mand1@" --set @mand1@ -UUUU --output=-)"
130+
jwe="$(jose fmt --json="$jwe" --get protected --get clevis --get @pin@ --quote "$@opt1@" --set @opt1@ -UUUU --output=-)"
131+
132+
#%# Almost there!
133+
#%# Forward everything to `jose jwe enc` which does the encryption job -
134+
#%# including reading the plaintext from stdin which gets replicated
135+
#%# using `cat`.
136+
( printf '%s' "$jwe$jwk" ; cat ) | exec jose jwe enc --input=- --key=- --detached=- --compact
137+
#%# Anything that follows is executed only if jose failed.
138+
#%#
139+
#!# When using mktemp or the like, cleaning up has to be done
140+
#!# manually. See clevis-{en,de}crypt-tpm2 for an example.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#%# Align the equal signs after substitution
2+
CLEVIS-ENCRYPT-@PIN@(1)
3+
=======================
4+
:doctype: manpage
5+
6+
7+
== NAME
8+
9+
clevis-encrypt-@pin@ - Encrypts using a @@ policy
10+
11+
== SYNOPSIS
12+
13+
*clevis encrypt @pin@* CONFIG < PT > JWE
14+
15+
== OVERVIEW
16+
17+
The *clevis encrypt @pin@* command encrypts using a @@ policy.
18+
Its only argument is the JSON configuration object.
19+
20+
#%# And so on ...
21+
22+
Encrypting data using the @pin@ pin works like this:
23+
24+
$ clevis encrypt @pin@ '{"@mand1@":"@@","@mand2":"@@"}' < PT > JWE
25+
26+
To decrypt the data, just pass it to the *clevis decrypt* command:
27+
28+
$ clevis decrypt < JWE > PT
29+
30+
== CONFIG
31+
32+
This command uses the following configuration properties:
33+
34+
#%# Keep this in sync with the short help in clevis-encrypt-@pin@
35+
36+
* *@mand1@* (string) :
37+
@@ (REQUIRED)
38+
39+
* *@mand2@* (string) :
40+
@@ (REQUIRED)
41+
42+
* *@opt1@* (string) :
43+
@@ (default: @@)
44+
45+
== BUGS
46+
47+
#%# List any flaws and gotchas here.
48+
49+
== SEE ALSO
50+
51+
link:clevis-decrypt.1.adoc[*clevis-decrypt*(1)]
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#!/bin/sh
2+
#
3+
# Copyright (c) @year@ @name@
4+
# Author: @name@ <@email@>
5+
#
6+
# This program is free software: you can redistribute it and/or modify
7+
# it under the terms of the GNU General Public License as published by
8+
# the Free Software Foundation, either version 3 of the License, or
9+
# (at your option) any later version.
10+
#
11+
# This program is distributed in the hope that it will be useful,
12+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
# GNU General Public License for more details.
15+
#
16+
# You should have received a copy of the GNU General Public License
17+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+
#
19+
20+
depends() {
21+
echo clevis
22+
return 0
23+
}
24+
25+
install() {
26+
inst clevis-decrypt-@pin@
27+
}

0 commit comments

Comments
 (0)