Cryptsetup pkcs11 - #2776
Conversation
|
This does not compile, please run |
|
Hmm, what's the strategy here regarding the smartcard being required at early boot, but the smartcard reader not having been probed that early yet? This sounds racy, what's you strategy to handle that? |
|
zongue,poettering: Thank you for your quick responses! zonque: I've updated the PR with a new commit that adds the missing header file to Makefile.am. I will take a look at the coding guidelines tomorrow. poettering: |
|
Isn't pcscd a late boot service? cryptsetup is an early-boot and initrd service, i.e. it runs in a very limited, very early environment, and are you sure pcscd is available that early? Also, note that Wants=pcscd.service pulls in that service, but defines no ordering against it. if you want to order your service after it you have to add After=pcscd.service too. But of course, that's going to break if pcscd is a late-boot service (which I think it is)... Moreover just ordering pcscd before the cryptsetup is unlikely to be enough... The thing is that hardware (in particular USB hardware) can take any time it wants to be probed. As we boot up, and as the cryptsetup logic is run, hardware is still popping up, and the smartcard reader device might not have shown up yet. Thus the hdd/cryptsetup logic will race against the smartcard probing: if the smartcard reader is quicker and is probed first, and the hdd shows up later, and thus cryptsetup is started later than all is good. However, if the reverse happens, and the hdd is probed first and the smartcard reader only shows up later, then we might end up using the smartcard API before the device is actually available, and the operation will fail. Given that hardware initialization times are effectively random the smartcard stuff hence might work sometimes, but other times it will fail, depending on probing times. To make this reliable I figure it's necessary to actively wait for smartcard devices to show up by watching udev, if the smartcard setting is set in crypttab... That all said, I have no experience with smartcards, and I don't know pcscd... Maybe pcscd is actually ready to be run in early boot, and maybe it already has provisions for waiting for devices, but my guess it is and does neither, hence my question regarding the strategy with this. Note that the patch doesn't follow the coding style we adopted for systemd, already superficially when it comes to indenting and placing brackets. Please have a look at the CODING_STYLE file and realign the patch accordingly. |
|
I will look into waiting for a smartcard reader to be probed and a smartcard to be inserted. Ideally I would like the user to be able to cancel this if they have a keyboard-input LUKS key as fallback, but I'm not sure how askpassword would handle that. Otherwise I'm thinking a configurable timeout, what would be the appropriate way to do that? As for the notes on the coding_style, I still have to read through the entire file but I want to ask, are you referring to the changes in cryptsetup.c and cryptsetup-generator.c or are you referring to pkcs11.h? The header file is borrowed from scute (www.scute.org) and I have not made any changes to it except for expanding tabs to spaces. What is the systemd way of handling these kinds of headers? Would you rather I rewrite it in the systemd code style? (benefit being that it conforms to the coding style, with the obvious disadvantage that there won't be an easy way to update if the source (scute) makes fixes and/or improvements) |
There was a problem hiding this comment.
Regarding coding style, I was referring to things like this: please put the { on the same line as the if ...
|
Instead, do something like this:
and then add one line at the bottom of
|
|
Another issue is that the code must be OOM-safe. I.e. every operation which allocate memory, e.g. I don't understand why |
I think this should be done in |
|
I have just pushed a few commits with mostly cleanup of the code but also making sure that there's an option (waitforpkcs11) that makes systemd-cryptsetup wait for smartcard readers and smartcards for DEFAULT_TIMEOUT_MSEC. Looking forward to your comments :) |
|
Please always rebase/squash your patches. |
There was a problem hiding this comment.
Compare with the lines above, "\0" is missing.
9e9c70e to
4cfc769
Compare
|
Thank you for your feedbak keszybs, I have squashed and rebased now, as well as fixed the error that you pointed out. |
|
Let's not talk about style or implementation details until we have the high level details worked out. In what circumstances would you want to set Unfortunately I don't think we can accept the implementation of Also, I don't think there's any reason to use dynamic loading. Why not link to This functionality seems very useful, but the amount of code to add it is rather small, but if it lands in systemd the implementation must be reasonable. So no busy waits, sorry. |
|
Thank you for your comments keszybz :) And it'd be great if this removed the need for a timeout, but I don't think it does. I think that in the case of a device that's allowed to fail, there needs to be either a one-shot try at getting the key or a sensible timeout, no? Ideally the user would be presented with the choice to either insert a pkcs11 device or skip unlocking this volume, I'm not sure if this kind of support should/could be included in the password agents? I'm not really a fan of the busy-wait loop myself. It came from the need of a timeout and the fact that pkcs11 provides only a nonblocking WaitForSlotEvent and an infinite blocking one. Using the infinitely blocking one would require a fork() in order to provide a timeout, but perhaps that's preferable? If so, please do point me to an example of how it's done the 'systemd-way'. I will look into static linking instead of dynamic loading, the loading is an artifact from early development of this when I thought I'd potentially need to probe several cryptoki implementations. However, now I'm thinking we'll stick to only opensc right now as that seems to be what is used. Please correct me if I'm wrong in this :) |
|
It seems that since this commit (OpenSC/OpenSC@5a23069) only GetFunctionList is exported in opensc-pkcs11.so, and that static linking is not generally how pkcs11/cryptoki is done. EDIT: It also seems that all functions are exported again in OpenSC since this commit (OpenSC/OpenSC@52b6505) following the discussion of issue #183 (OpenSC/OpenSC#183). However, the version included in my distribution (debian testing) does not export all symbols. Would static linking be prefered even if the function references are loaded through C_GetFunctionList? |
I still don't see how that would obviate the need to wait. If you have pkcs11key configured, even if in the end you decide not to use it and type in the password instead, the machine has no way of knowing your intent, and has to present you with a valid pkcs11 prompt, so it has to wait for the hardware. Otherwise the case where you do want to use pkcs11 would not work reliably.
Yes, a sensible timeout. (Probably there should be an option to specify the timeout, but that's something that can easily be added later). There should always be a timeout, even if the device is not allowed to fail. In that case we want to fall back to
It seems that this commit must have been reverted at a later point. https://github.com/OpenSC/OpenSC/blob/master/src/pkcs11/pkcs11.exports has a long list of functions.
Static linking is even worse than dlopen ;) Normal "shared" linking only please.
There's always the option of simply entering an empty password a few times. I don't know if our password agents currently have an option to cancel. It might be useful, but either way, it's not strictly related to this pull request.
Then it should be done as a separate process. Basically cryptsetup would "announce" the need for a pkcs11 password (similarly how it "announces" the need for a normal password), maybe start an external service, and wait for a reply until some timeout. This circles back to the topic of "binary passwords" that was discussed before (https://lists.freedesktop.org/archives/systemd-devel/2014-July/020880.html) without reaching a clear resolution. We are now using the keyring, but I don't know if this changes much, and if the kernel keyring would be useful here. |
|
Actually, wouldn't the normal password agent logic be appropriate here? If binary passwords were supported, then cryptsetup could emit a question that contains all the information for the pkcs11 agent, and the agent could query for the PIN and send back the answer. This has two issues:
|
|
Right now I'm feeling kind of discouraged about getting to a good solution here. sigh There's two major setbacks right now:
I'm going to research if there's a better pkcs11 implementation to link against than opensc but if not, I don't see how this is going to be good enough to be a part of systemd, which is kind of sad because it works pretty well for me locally by now and I do think the feature would be appreciated. |
|
The pkg-config file is just a nicety that makes it easy to detect if the library is installed. Linking with pkcs11-helper is not much more than adding With a bit of udev magic, the "busy loop" could be made quite smart. If you add a filter that corresponds to some superset of the devices that could be used, and react to new devices showing up, restarting would only have to happen when new devices are detected. After the initial phase of hardware discovery, there would be no more looping. |
Yes, the thing is however that I'm not interested in linking against pkcs11-helper (the dependency on pkcs11-helper was added following a comment that the pkcs11.h was packaged in pkcs11-helper. The only file used from that package is the header file, which btw. is also packaged with icedove, iceweasel, libgnutls and others). The library I need to link against in order to not do dynamic loading is opensc-pkcs11.so (and probably other libraries on other platforms), this would be done by adding -l:opensc.pkcs11.so. This begs the question of what platforms/distributions are the target of systemd?
No. I'm sorry, but udev magic won't help us here. I earlier stated that PKCS11/cryptoki has a blocking WaitForSlotEvent function. While that is true, the standard specifies such a function, the opensc implementation of pkcs11/cryptoki will always return an error on calling the blocking version of that function. So in reality, when using opensc, there's no blocking version of WaitForSlotEvent and thus a busy loop is required. I will look further into providing pkcs11 as a password agent, if this is deemed a more reasonable place to have a busy-wait loop. |
At least that's easy. Linux only.
Yes, this seems to be the best direction. |
4cfc769 to
63b5434
Compare
|
A note on the last commit: I will update when I get home and can test this properly. |
e19d2fa to
f587698
Compare
f587698 to
72e0f86
Compare
|
I've ironed out a few kinks. This works as expected under a running system. |
|
I've now tested this on Fedora 23 with dracut initrd. If you include pcscd and the relevant reader drivers in the initrd, as well as make sure pcscd is compiled without polkit support (since polkit isn't available at initrd-time) it works well. I can do a writeup of the procedure I followed if that helps. As for the discussion on wether to include pkcs11 support here or in cryptsetup (dmcrypt) please see the following discussion with their developers: http://article.gmane.org/gmane.linux.kernel.device-mapper.dm-crypt/8548 ("in new version of LUKS we plan to add some kind of token Sidenote: I think the autopkgtest-systems were broken during my last commit, at least |
|
Thanks for the update. We're getting ready for a release, so review might be a bit delayed. |
|
I get the "a bit delayed" part but now it's been three months? Any update on this keszybz? |
|
This PR is 6 months old, stale, and got rejected in its present form. If this is still relevant, can you please fix and rebase to current master, and otherwise close this? Thanks! |
|
@martinpitt This is stale since @keszybz said that review might be "a bit delayed" since you were getting ready for a release? This was in May, and there seems to have been releases of systemd since? |
| if (password) { | ||
| if (STR_IN_SET(password, "/dev/urandom", "/dev/random", "/dev/hw_random")) | ||
| if (startswith(password, "pkcs11:")) | ||
| fputs("After=pcscd.service\nRequires=pcscd.service\n", f); |
There was a problem hiding this comment.
fputs("After=pcscd.service\n" \
"Requires=pcscd.service\n", f);
``
There was a problem hiding this comment.
i'm not an authority on style or anything...
| if (!path_is_absolute(argv[4]) && !startswith(argv[4], "pkcs11:")) | ||
| log_error("Password file path '%s' is not absolute. Ignoring.", argv[4]); | ||
| else | ||
| key_file = argv[4]; |
There was a problem hiding this comment.
is there any circumstance where key_file might be changed and no longer start with pkcs11: when you go to look for it later? Seems ok though but maybe do the checks once and then call out ?
It might be cool to set the stage for further expansion/extensions, switch statement? Break out isome functionality? Idk... really excited about this pr though, need good support for hsms etc
|
Since v245 of systemd we actually support a different method of hooking up PKCS#11 with cryptsetup. Instead of storing anything on the pkcs#11 key we decrypt an encrypted version of the LUKS unlocking key with a RSA key from the PKCS#11 device. Thus we can re-use keys that exist on the device anyway, and can unlock as many volumes with the same key as we want. I think this is a good alternative to what is proposed in this PR, hence let's close this one. Sorry this took so long. And sorry for not reviewing this PR properly early on! |
This adds pkcs11/cryptoki support to systemd-cryptsetup. I use it in dracut initramfs to enable me to retreive a luks key from a smartcard for unlocking the system root. All other usecases are so far untested.
I realise there are multiple ways this code could be improved, and I intend to do so. I'm making this PR to check whether there is an interest for this functionality in systemd or not and to get some first comments on what I need to improve to get the code accepted.
As this is my first PR to systemd, please have some patience for me making newbie mistakes :)