Open szszszsz opened 3 years ago
Hey @szszszsz, I could look into this one as indeed the request makes sense.
I however don't have a HW token (and don't use VC with one), would you be able to recommend any SW-based setup with e.g. some emulator, so that I could test this out properly? I guess you may have used something like that when working on Nitrokeys ;)
@alt3r-3go We are glad to provide you the necessary Nitrokeys for free. Please send us your shipping address to info@ (contact).
Thanks @jans23, that would be quite useful, thank you. I also wanted to take a deeper look and maybe contribute to Nitrokeys from the dev standpoint for a while now, this could be a great excuse to finally find the time to do that :) I'll contact you over the email soon to discuss what can be arranged here - however please also see below, as it may not be strictly necessary for fulfilling this particular request.
On this particular one, I've conducted some initial research (so the below is preliminary and I'll investigate more) and looks like it may not be possible to change this at the VC level.
This particular limitation of using the OpenPGP PDO 0101 when going via OpenSC's PKCS#11 (which is I guess what @szszszsz is using as the default recommendation for Nitrokeys) is hardcoded into OpenSC due to specific technical limitation of exposing PIN-protected DOs: https://github.com/OpenSC/OpenSC/blob/master/src/pkcs15init/pkcs15-openpgp.c#L451-L457 (this functionality in general was added at some point to provide TC/VC support in OpenSC).
From its end, VC just uses PKCS#11's C_CreateObject()
(https://github.com/veracrypt/VeraCrypt/blob/master/src/Common/SecurityToken.cpp#L145) and there doesn't seem to be any PKCS#11 API for specifying the OpenPGP's PDO directly (which generally makes sense as these are different APIs/abstractions of course).
So at this level of elaboration, it looks like it would rather be an OpenSC change to somehow overcome that hardcoding and expose other DOs, or a noticeable change of the usage model at the VC end, to actually start using smartcard as such, and not as a glorified USB flash drive. There were arguments about that - which I generally share - during the review of that OpenSC PR, indicating that this way of storing the keyfile may be relatively meaningless, especially on a PIN-less DO.
@idrassi, FWIW, please feel free to assign this one to me as I'm willing to drive it to conclusion (whatever it is - we'll see).
I'm looking further into this, to see how this could be implemented with minimal changes, given the limitations: VeraCrypt's established keyfile feature expectations (VC needs to have access to keyfile contents to produce the key and there's even a "threshold" functionality where keyfile may be split into pieces!) and OpenSC's current - "hardcoded" to a noticeable degree - implementation.
I'm currently thinking of maybe leaving the PDO 0101/OpenSC alone, but adding a token-based encryption/decryption operation on top - i.e. VC would ask the token to encrypt/decrypt the keyfile when storing/reading it to/from the PDO. Assuming the operation requires authentication (haven't checked the details yet, but that's key usage, so should be authenticated somehow), that would leave OpenSC as-is, preserve the keyfile functionality and increase the security of keyfile storage (encrypted and access is authenticated) at the cost of creating a dependency on a token-internal key, which makes sense for this use case. Stay tuned (and feel free to comment if you have any better ideas or don't like this one) :)
Fun fact I've noticed during further code analysis: OpenSC actually does require PW1 when reading the PDO, but as it's implemented in the PKCS#11/15 emulation layer on top of the underlying OpenPGP functionality, when one uses OpenPGP interface directly, that is of course not happening and PDO 0101 requires no PIN for reading. This difference can be observed via OpenSC's own pkcs11-tool
and openpgp-tool
. The former requires login: pkcs11-tool.exe --read-object --type data --label PrivDO1 --login
to display the contents, the latter - doesn't: openpgp-tool.exe --do 1
.
And just for reference, here are the relevant OpenSC PRs where TC/VC-related PDO functionality was added (thank you @hongquan!):
Just to note - I've not forgotten about this one, it's just that the solution given the limitations is not as elegant as I'd like it to be + I have only part of the weekend(s) to work on this right now, slowing it down. I'm still determined to drive it to the conclusion though.
I'm currently thinking of maybe leaving the PDO 0101/OpenSC alone, but adding a token-based encryption/decryption operation on top - i.e. VC would ask the token to encrypt/decrypt the keyfile when storing/reading it to/from the PDO.
This is how tokens and smart cards are usually used. It gives the best security and least dependency on available PDOs for example.
If the keyfile is encrypted with the key stored in the token, I suggest to not store the encrypted keyfile in the PDO but in VC's volume header instead.
Assuming the operation requires authentication
Yes, decryption operations require authentication through PIN.
If the keyfile is encrypted with the key stored in the token, I suggest to not store the encrypted keyfile in the PDO but in VC's volume header instead.
Currently VC volume header size is limited to 512 bytes and it is already mostly full with needed parameters so we can't use it to store an encrypted key file.
Also keyfiles can have a large size. Of course, we can limit their size for smart card integration to 128 bytes (same as maximum password length) but depending on the size of key used, their encrypted form can be large (for example 512 bytes for 4096-bits RSA key if it is encrypted directly using CKM_RSA_PKCS
or CKM_RSA_PKCS_OAEP
).
In my opinion, it makes more sens from the security point of view to put the encrypted key file on the smart card than in the volume itself: an attacker that somehow can break the RSA or EC key used for encryption (for example by compromising a backup of the key) will not be able to access the volume since the encrypted keyfile resides on the smart card and it is protected by a PIN.
From the security point of view I don't see a practical benefit of storing the encrypted key file in the smart card. Smart cards and HSMs are used for all sorts of encryption and signing applications and their approach to only store private keys has proven to be working well and secure. However, if volume header doesn't have sufficient space, that's a strong argument for doing so nevertheless.
Looking further into this, I found out that no one (tokens and OpenSC as an interface) implements public key encryption. AFAIU that's based on the assumption that those who need to do that just export the public key from the token and do encryption "outside". Only private-key operations are supported on the device and that means for PKE we'd need to implement this in VeraCrypt itself.
That IMO makes no sense in the current approach with no crypto library being used and only necessary pieces being added to the source tree when necessary. Addint PKE to VC would require a lot of that and if that's a desirable direction at all, I'd say a prerequisite would be to switch to using some crypto library first (I think a BSI report published recently suggested that as well).
An additional, smaller and more arguable thing (depending on specific attack scenarios I haven't thought through) is that OpenPGP (at least 3.3 I'm looking at) doesn't seem to support OAEP, only the PKCS#1_v1.5, which is a big no-no these days due to padding oracle attacks.
Now, while Nitrokey Pro (unlike Start) does support storing an AES key and encryption/decryption using it, it's (1) not supported in OpenSC AFAICS and (2) seems to support only the CBC mode (AFAIU it implements what the OpenPGP spec says) - and that's again not the best choice for key/key material encryption due to no integrity protection and potential padding oracle attacks. And of course that limits the choice of users toonly those tokens that support symmetric keys/ops.
So unless someone has any other ideas, it looks like we're back to square one and the only approach left is to try to see if we can add PDO3/4 support into OpenSC.
Just as an update, I'm moving on with the DO-based approach, did some testing with OpenSC today and it looks promising - looks like there's at least some possibility to pick the actual DO even via the OpenSC's PKCS#11 interface (by hijacking the Label values and with respective changes at the OpenSC side - so that's a bit sketchy at the moment), but there also seems to be some bug in there, as some of the pkcs11-tool
commands don't work properly with DOs 0102-0104 when populated and I'm investigating.
Just so stale-bot doesn't intervene :) This is still in progress, just not having enough time to work on this more actively.
It's been a long while, but I still haven't got to that, all my free time is essentially filled up now with something else. This is still on the list though, so there's hope.
As you can imagine this hasn't moved much since the last update, but I now have a more firm plan to work on this - around the end of September I should have time for this. I plan to move forward with the idea described above, which is, while a bit hacky, hopefully won't be rejected outright by the OpenSC folks, as it still IMO fits their current approach to managing private DOs. We'll see.
As a user I would like to have an option to select the PDO slot on my OpenPGP smart card, while saving the keyfile. Instead of the PDO1 I would like to use PDO3 or PDO4, which require User/Admin PIN (respectively) for the read operation. Changing defaults to PDO3 (instead of PDO1) for OpenPGP smart card would also work.
Right now Veracrypt saves keyfiles on the OpenPGP smart card in PDO1, where it is available to read without providing the PIN.