dm-crypt.saout.de archive mirror
 help / color / mirror / Atom feed
* [dm-crypt] cryptsetup - 2FA feature request
@ 2021-08-27 11:29 Stephen Feyrer
  2021-09-20 13:43 ` [dm-crypt] " Ondrej Kozina
  0 siblings, 1 reply; 3+ messages in thread
From: Stephen Feyrer @ 2021-08-27 11:29 UTC (permalink / raw)
  To: dm-crypt


[-- 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

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [dm-crypt] Re: cryptsetup - 2FA feature request
  2021-08-27 11:29 [dm-crypt] cryptsetup - 2FA feature request Stephen Feyrer
@ 2021-09-20 13:43 ` Ondrej Kozina
  2021-09-21 12:53   ` Jeremiah Moree
  0 siblings, 1 reply; 3+ messages in thread
From: Ondrej Kozina @ 2021-09-20 13:43 UTC (permalink / raw)
  To: dm-crypt; +Cc: Stephen Feyrer

Hi Stephen,

I'm sorry for late reply but I was busy with bug fixing lately...

On 8/27/21 1:29 PM, Stephen Feyrer wrote:
> Hi Everyone,


> 
> 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.

See what LUKS2 external token handlers (plugins) allow since cryptsetup 
2.4.0 upstream release.

There's simple example in cryptsetup sources, see "tokens/ssh" subdirectory.

Also, there are already 3 implementations of LUKS2 external handlers 
available in systemd project, for example. For anyone interested, feel 
free to look in src/cryptsetup/cryptsetup-tokens sources of systemd for 
inspiration/guidance on how to write native cryptsetup LUKS2 plugins. 
For example systemd-fido2 token is pretty close to 2fa you have 
described above. Provided the hw token is configured to require 
PIN/user_presence to release secret. It basically create new LUKS2 
keyslot that can be unlocked with key provided only by fido2 token when 
user provides right PIN (or touches hw token).

Any extension to LUKS2 token based device activation is expected to 
implement utility for binding LUKS2 device to alternative activation 
method (LUKS2 token metadata extension). In case of ssh plugin it's 
cryptsetup-ssh utility in case of systemd extensions, it's 
systemd-cryptenroll utility. Those utilities bind LUKS2 device (write 
LUKS2 token json metadata) to some other method how to obtain LUKS2 
passphrase (KEK) securely (even remotely).

The second part of each extension is plugin used to unlock such bound 
keyslot. libcryptsetup-token-ssh.so for example. cryptsetup library 
loads such plugin when it discovers appropriate LUKS2 token assigned to 
usable LUKS2 keyslot. The plugin then extracts key from remote 
host/yubikey/tpm2 or whatever and libcryptsetup unlocks device with MEK 
decrypted from bound keyslot.

Basically anyone can now write LUKS2 extension that plugs-in "cryptsetup 
open" command provided the device is LUKS2 format version.

 From cryptsetup cli perspective it works as follows:

In before activation by passphrase (interactive query) we try to 
activate device using any available token handler in the system 
(crypt_activate_by_token & crypt_activate_by_token_pin library API). 
Only when no appropriate LUKS2 token can be used to unlock the device we 
fall back to passphrase based activation.

So if anyone is willing to implement another 2FA method they're most 
welcome to. We'll provide them with help in case anything in 
libcryptsetup is missing (or buggy), but we do not plan to implement any 
LUKS2 external token implementation in nearterm. We're (upstream) very 
limited in workforce.

Regards
O.

_______________________________________________
dm-crypt mailing list -- dm-crypt@saout.de
To unsubscribe send an email to dm-crypt-leave@saout.de

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [dm-crypt] Re: cryptsetup - 2FA feature request
  2021-09-20 13:43 ` [dm-crypt] " Ondrej Kozina
@ 2021-09-21 12:53   ` Jeremiah Moree
  0 siblings, 0 replies; 3+ messages in thread
From: Jeremiah Moree @ 2021-09-21 12:53 UTC (permalink / raw)
  To: Ondrej Kozina; +Cc: dmcrypt, Stephen Feyrer


[-- Attachment #1.1: Type: text/plain, Size: 731 bytes --]

>
> In before activation by passphrase (interactive query) we try to
> activate device using any available token handler in the system
> (crypt_activate_by_token & crypt_activate_by_token_pin library API).
> Only when no appropriate LUKS2 token can be used to unlock the device we
> fall back to passphrase based activation.
>

I was looking for detailed documentation on token handling plugins but not
finding it.  Am I missing it?   Is it in the man page or the luks2 pdf or
the wiki or the readme? or somewhere else?

In lieu of the docs I plan to start some code and communicate with the
mailing list but given the problems with the mailing list lately I am
waiting.  (I keep getting kicked off--both email addresses).

-- 
JT

[-- Attachment #1.2: Type: text/html, Size: 1055 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

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2021-09-21 12:56 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-27 11:29 [dm-crypt] cryptsetup - 2FA feature request Stephen Feyrer
2021-09-20 13:43 ` [dm-crypt] " Ondrej Kozina
2021-09-21 12:53   ` Jeremiah Moree

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).