From: Stephen Feyrer <stephen.feyrer@btinternet.com>
To: dm-crypt@saout.de
Subject: [dm-crypt] cryptsetup - 2FA feature request
Date: Fri, 27 Aug 2021 12:29:11 +0100 [thread overview]
Message-ID: <c3cb2dfa-14c7-f6c7-c3b9-a8664b9168db@btinternet.com> (raw)
[-- Attachment #1.1: Type: text/plain, Size: 7018 bytes --]
Hi Everyone,
Before I start, I'd like to offer some caveats as I've had a week to
think about this. This is a topic which I imagine has already been
covered ad nauseam (so I may be re-opening a can of worms - sorry). You
may also consider what I have to say as being out of scope for
cryptsetup or just overly complicated. There may be details which I'm
not aware of or haven't given proper consideration. So, take a deep
breath and lets dive in.
The rationale behind what I'm suggesting, is that I am working on using
a Yubikey as a second factor when decrypting my filesystem. To do this I
have an unencrypted partition where my kernel and initrd etc. are kept.
A script (that I am writing) will run and this will present a password
to cryptsetup. It is the function of this script which creates the
password for which I suggest that cryptsetup take ownership.
My script picks up a JSON file with a structure like:
[
{"timeout": <TIME IN MILLISECONDS> }
{<SERIAL#.id1>:
{"slot 1": {
"password challenge timeout": <TIME IN MILLISECONDS>,
"password required": TRUE,
"Enabled": TRUE,
"password hint": "My Password is..."
"seed": <ENCRYPTED CHALLENGE VALUE>
}
},
{"slot 2": {
"password challenge timeout": <TIME IN MILLISECONDS>,
"password required": FALSE,
"Enabled": FALSE,
"password hint": "lazy but quick"
"seed": <UNIQUE CHALLENGE VALUE>
}
}
},
{<SERIAL#.id2>:
{"slot 1": {
"password challenge timeout": <TIME IN MILLISECONDS>,
"password required": FALSE,
"Enabled": TRUE,
"password hint": "Backup Key Forgotten Password"
"seed": <UNIQUE CHALLENGE VALUE>
}
},
{"slot 2": {
"password challenge timeout": <TIME IN MILLISECONDS>,
"password required": FALSE,
"Enabled": FALSE,
"password hint": "Not Set Up"
"seed": <UNUSED VALUE>
}
}
}
]
That should give you an idea of what the script does but I'll give a
brief explanation for clarity:
1. First it reads this file and gets the time out.
2. The script enters a loop waiting for a USB Yubikey to be detected.
3. Then when it detects a key, the serial number is checked and the
data for that key is read.
4. The script chooses the enabled slot on the Yubikey. If both slots
are enabled then it would choose the first slot, which if it fails
then disable that slot and fail to boot.
5. The password hint is printed as a re-assurance to the user that
their key has been recognised.
6. If a password is required (recommended), ask the user to enter their
password and store in a variable (not the most secure but this is my
first pass at the script).
7. Call GPG to decrypt the seed value using the stored password.
8. Pipe the decrypted value to ykchalresp using the selected slot
9. Pipe the returned value into cryptsetup to open the desired device.
10. Generate a new raw seed value with uuid-gen.
11. Replace the cryptsetup password.
12. Call GPG with the stored password and encrypt the new seed.
13. Write the encrypted seed value over the original.
14. Pass control back to the system.
This doesn't take account for error handling or malefactors or setup,
its just an overview.
At this point I can already imagine 'Out of Scope' and 'What does this
have to do with cryptsetup?' oozing out of angry indignant emails. It
seems I'm using my imagination a lot here because I'm also imagining
there are a lot of users wondering why cryptsetup doesn't support
Yubikey or another second factor natively and save them all a lot of
bother? I'm one of them...
My first thought was to clone cryptsetup, make a branch and have a go.
Then I looked at the cryptsetup code and realised that my C skills are
woefully inadequate, sorry. I don't mind having a go but I don't want
to cause more problems than I'd solve.
Therefore I ask that you please consider this. Create a Yubikey option
in cryptsetup which roughly follows the workflow outlined above.
Albeit, hypothetically storing the json in an fs-block and using
cryptsetups password authentication mechanism in place of GPG. Storing
the setup data of 8 keys could be recorded in one or more 4Kb block(s)
give or take (given that we have some free form text fields). There is
a Yubikey SDK at: https://developers.yubico.com
In fact, such an architecture might be able to be generalised to allow
2FA plug-ins. In that case, the plug-in would only need two special
function calls into cryptsetup. One to get the data "object" stored on
the fs and the other to decrypt a token with a given password.
Otherwise the plug-in would call functions similar to lukFormat,
luksChangeKey and luksOpen, as means to perform the setup and house
keeping actions.
The *advantages *of such a scheme include; It would enable a second
factor for unlocking the filesystem natively. Assuming other external
second factor devices operate similarly it would allow for
generalisation. There isn't a direct change to the way cryptsetup works
in terms of taking a password and decrypting a filesystem key.
Cryptsetup effectively retains control of the authentication process.
Initramfs tools have an established relationship with cryptsetup, while
Yubikey doesn't seem to me to really fit in the great initramfs scheme
of things as it's a second factor not a device to be initialised. This
would be more secure than relying on some random shell script.
The *detractors *which I can imagine include; Efficient systems don't
leave 4Kb blocks just lying around idly doing nothing. In the end more
than one block might be needed. There's no guarantee that even if this
approach were taken that it would work as a generalised form. No-body
likes strangers off the internet waltzing up and asking them to do
work. The Yubikey SDK maybe more complicated than I thought. This may
be just out of the scope of cryptsetup. The Yubikey's been around for a
while and if the cryptsetup developers were going to do something about
it, they'd probably have done it by now.
I've tried to give a balanced view and hope I haven't made it too
complicated. Or perhaps, I've over simplified it, you guys work on
cryptography after all...
Please let me know your thoughts?
Thanks,
Stephen.
[-- Attachment #1.2: Type: text/html, Size: 8288 bytes --]
[-- Attachment #2: Type: text/plain, Size: 147 bytes --]
_______________________________________________
dm-crypt mailing list -- dm-crypt@saout.de
To unsubscribe send an email to dm-crypt-leave@saout.de
next reply other threads:[~2021-08-27 11:35 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-08-27 11:29 Stephen Feyrer [this message]
2021-09-20 13:43 ` [dm-crypt] Re: cryptsetup - 2FA feature request Ondrej Kozina
2021-09-21 12:53 ` Jeremiah Moree
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=c3cb2dfa-14c7-f6c7-c3b9-a8664b9168db@btinternet.com \
--to=stephen.feyrer@btinternet.com \
--cc=dm-crypt@saout.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.