Phase 1 needs to provide the ability to change the per pool wrapping key (Here in after referred to as the Data Set Key Encryption Key: DSKEK). I think there is a potential problem though. Each pool knows only a "reference" to the DSKEK, ie: passphrase, filename, pkcs11 token object description (by knows I mean stored in a per pool property). In order to do a change of the DSKEK value we need to decrypt/unwrap each dataset key with the current DSKEK and reencrypt/wrap with the new DSKEK (in a single transaction). How do we know if the supplied DSKEK was the correct one ? I don''t believe we want to encrypt a known (even unique to the pool) bit of data to be able to verify this since that provides known plain text. We also can''t provide a hash of the DSKEK value because we may not be able to extract if from the keystore (PKCS#11 token) only use it. As far as the UI (CLI and GUI) is concerned I believe we should make changing the DSKEK an explicit action that is distinct from setting the key reference and distinct from the normal operation of providing the passphrase or PIN (in the case of a sensitive PKCS#11 token object). This should mean that providing the wrong key value (ie bad passphrase, wrong file content at the correct path, or wrong PKCS#11 token but with a correctly named object) the result is just garbage being returned rather than a failure condition (resulting in EIO for example). I''d like some suggestions on who we can overcome the issues of key change and also some suggestions for how the the CLI case would look. -- Darren J Moffat
Darren J Moffat wrote:> Phase 1 needs to provide the ability to change the per pool wrapping key > (Here in after referred to as the Data Set Key Encryption Key: DSKEK). > > I think there is a potential problem though. Each pool knows only a > "reference" to the DSKEK, ie: passphrase, filename, pkcs11 token object > description (by knows I mean stored in a per pool property). > > In order to do a change of the DSKEK value we need to decrypt/unwrap > each dataset key with the current DSKEK and reencrypt/wrap with the new > DSKEK (in a single transaction). > > How do we know if the supplied DSKEK was the correct one ? > > I don''t believe we want to encrypt a known (even unique to the pool) bit > of data to be able to verify this since that provides known plain text. > We also can''t provide a hash of the DSKEK value because we may not be > able to extract if from the keystore (PKCS#11 token) only use it. > > As far as the UI (CLI and GUI) is concerned I believe we should make > changing the DSKEK an explicit action that is distinct from setting the > key reference and distinct from the normal operation of providing the > passphrase or PIN (in the case of a sensitive PKCS#11 token object). > > This should mean that providing the wrong key value (ie bad passphrase, > wrong file content at the correct path, or wrong PKCS#11 token but > with a correctly named object) the result is just garbage being returned > rather than a failure condition (resulting in EIO for example). > > I''d like some suggestions on who we can overcome the issues of key > change and also some suggestions for how the the CLI case would look. >How does this differ from the import of the pool?.. Say for example an incorrectly entered passphrase..
Anthony Scarpino wrote:> How does this differ from the import of the pool?.. Say for example an > incorrectly entered passphrase..In the case where you don''t present the correct key you just get garbage file data because it doesn''t decrypt correctly. In the key change case if you decrypt the dataset key with the wrong "current" DSKEK you get something that looks like a key for the dataset but it is the wrong one. You then reencrypt the dataset key with the new DSKEK you have lost all access to your data on read because it now gets decrypted with the wrong per dataset key and is garbage (at least until you change it back to the correct DSKEK assuming it still exists). -- Darren J Moffat
Darren J Moffat wrote:> Anthony Scarpino wrote: >> How does this differ from the import of the pool?.. Say for example an >> incorrectly entered passphrase.. > > In the case where you don''t present the correct key you just get garbage > file data because it doesn''t decrypt correctly.So is the intent that when you import a pool and give the wrong passphrase the the pool is still important, just the encrypted datasets are garbage and unaccessable.. or that the import will fail?..> > In the key change case if you decrypt the dataset key with the wrong > "current" DSKEK you get something that looks like a key for the dataset > but it is the wrong one. You then reencrypt the dataset key with the > new DSKEK you have lost all access to your data on read because it now > gets decrypted with the wrong per dataset key and is garbage (at least > until you change it back to the correct DSKEK assuming it still exists). >somehow comparing to a successful import would be good, but it hinging on your thought on the above question...
Anthony Scarpino wrote:> Darren J Moffat wrote: >> Anthony Scarpino wrote: >>> How does this differ from the import of the pool?.. Say for example >>> an incorrectly entered passphrase.. >> >> In the case where you don''t present the correct key you just get >> garbage file data because it doesn''t decrypt correctly. > > So is the intent that when you import a pool and give the wrong > passphrase the the pool is still important, just the encrypted datasets > are garbage and unaccessable.. or that the import will fail?..The import will succeed but encrypted datasets will not be usable (ie data will be garabage). We can NOT make the import fail because this would preclude using any encrypted data sets on a ZFS root filesystem. I see no reason to make the import fail and lots of reasons why failing it would be quite annoying. -- Darren J Moffat
On Fri, Aug 03, 2007 at 05:57:58PM +0100, Darren J Moffat wrote:> Anthony Scarpino wrote: > > Darren J Moffat wrote: > >> Anthony Scarpino wrote: > >>> How does this differ from the import of the pool?.. Say for example > >>> an incorrectly entered passphrase.. > >> > >> In the case where you don''t present the correct key you just get > >> garbage file data because it doesn''t decrypt correctly. > > > > So is the intent that when you import a pool and give the wrong > > passphrase the the pool is still important, just the encrypted datasets > > are garbage and unaccessable.. or that the import will fail?.. > > The import will succeed but encrypted datasets will not be usable (ie > data will be garabage).That''s really not user-friendly... What if user simply misspell the passphrase? He won''t be asked again, but will find garbage instead? -- Pawel Jakub Dawidek http://www.wheel.pl pjd at FreeBSD.org http://www.FreeBSD.org FreeBSD committer Am I Evil? Yes, I Am! -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 187 bytes Desc: not available URL: <http://mail.opensolaris.org/pipermail/zfs-crypto-discuss/attachments/20070803/90e1569c/attachment.bin>
Darren J Moffat wrote:> Anthony Scarpino wrote: >> Darren J Moffat wrote: >>> Anthony Scarpino wrote: >>>> How does this differ from the import of the pool?.. Say for example >>>> an incorrectly entered passphrase.. >>> >>> In the case where you don''t present the correct key you just get >>> garbage file data because it doesn''t decrypt correctly. >> >> So is the intent that when you import a pool and give the wrong >> passphrase the the pool is still important, just the encrypted >> datasets are garbage and unaccessable.. or that the import will fail?.. > > The import will succeed but encrypted datasets will not be usable (ie > data will be garabage). > > We can NOT make the import fail because this would preclude using any > encrypted data sets on a ZFS root filesystem.Well taking the TPM/Secure Boot scenario off the table, we''ll have a chicken & egg problem. A key in a file/usb stick will require a root file system and a pkcs11 provider won''t be accessible because of signing.. so I don''t see how you can mount the encrypted datasets. This would mean a zfs root fs dataset in cleartext on a pool with a wrapped key defined would fail to mount encrypted datasets everytime on boot.. That maybe the right answer for the scenario.. it just ain''t pretty :) So the next questions.. if the wrong key is obtained during import how does one reenter the key? At this point the current cli is assuming import handles the keys and we can''t export the pool with a root fs dataset to reenter the key.. would we have to modify import to implement a reload process for? otherwise we may be looking at another zpool command..> > I see no reason to make the import fail and lots of reasons why failing > it would be quite annoying.I think it would be annoying as well for the non-encrypted datasets, but I figured that was the cost of using an encrypted pool.. one had to make sacrifices.. We are deviating from your original questions here, but I think it''s important we get on the same page with this.. it might open up some ideas to answer your question..
Pawel Jakub Dawidek wrote:> On Fri, Aug 03, 2007 at 05:57:58PM +0100, Darren J Moffat wrote: >> Anthony Scarpino wrote: >>> Darren J Moffat wrote: >>>> Anthony Scarpino wrote: >>>>> How does this differ from the import of the pool?.. Say for example >>>>> an incorrectly entered passphrase.. >>>> In the case where you don''t present the correct key you just get >>>> garbage file data because it doesn''t decrypt correctly. >>> So is the intent that when you import a pool and give the wrong >>> passphrase the the pool is still important, just the encrypted datasets >>> are garbage and unaccessable.. or that the import will fail?.. >> The import will succeed but encrypted datasets will not be usable (ie >> data will be garabage). > > That''s really not user-friendly... What if user simply misspell the > passphrase? He won''t be asked again, but will find garbage instead?Agreed but to verify it was the correct one you need to store something known to do so and that leads to known plaintext problems. The tools will allow you to specify the key at any time it isn''t limited to just doing it at pool import. -- Darren J Moffat
Anthony Scarpino wrote:>> We can NOT make the import fail because this would preclude using any >> encrypted data sets on a ZFS root filesystem. > > Well taking the TPM/Secure Boot scenario off the table, we''ll have a > chicken & egg problem. A key in a file/usb stick will require a root > file system and a pkcs11 provider won''t be accessible because of > signing.. so I don''t see how you can mount the encrypted datasets.I don''t believe we do have that problem. You seem to be assuming, despite me saying that not having the key didn''t block import, that the key has to be available at the time the pool is brought online/imported. > This> would mean a zfs root fs dataset in cleartext on a pool with a wrapped > key defined would fail to mount encrypted datasets everytime on boot.. > That maybe the right answer for the scenario.. it just ain''t pretty :)Maybe, but you are assuming that we won''t make any changes to the current SMF startup - I''m assuming that we will (I just haven''t discussed them yet because I don''t know what they will be). I think I wasn''t quite clear on the intended supported configuration, so let me be explit: pool of one disk: rootpool data set for Solaris root filesystem: rootpool/snv_75 data set for user home dirs: rootpool/home/bob data set for documents in home dir rootpool/home/bob/Documents We boot from rootpool/snv_75 and this cleartext. The only encrypted dataset is rootpool/home/bob/Documents In this case we MUST be able to bring the pool online and have the cleartext datasets available without the encrypted ones being available. There is not problem with doing this since the key isn''t needed until something in the encrypted dataset is accessed. There is a possible issue with scrub and with resilver in mirrors, and that impacts AES_CBC+HMAC_SHA256 and AES_CCM differently.> So the next questions.. if the wrong key is obtained during import how > does one reenter the key? At this point the current cli is assuming > import handles the keys and we can''t export the pool with a root fs > dataset to reenter the key.. would we have to modify import to implement > a reload process for? otherwise we may be looking at another zpool > command..I''m not assuming that at all and I''ve never said I was assuming that. The current prototype I have of this gets the token PIN or passphrase EVERY time you run, and you can run it at any time. eg: # zpool set dskek=passphrase tank Enter passphase for tank: # # zpool set dskek=pkcs11:Sun Metaslot:::mykey Enter PIN for token "Sun Metaslot": # # zpool set dskek=file:/rmdisk/stick/keys/mykey # I don''t think we have to do anything to pool import.>> I see no reason to make the import fail and lots of reasons why failing >> it would be quite annoying. > > I think it would be annoying as well for the non-encrypted datasets, but > I figured that was the cost of using an encrypted pool.. one had to make > sacrifices..I don''t see how it impacts cleartext datasets at all. -- Darren J Moffat
On Mon, Aug 06, 2007 at 11:55:58AM +0100, Darren J Moffat wrote:> Pawel Jakub Dawidek wrote: > > That''s really not user-friendly... What if user simply misspell the > > passphrase? He won''t be asked again, but will find garbage instead? > > Agreed but to verify it was the correct one you need to store something > known to do so and that leads to known plaintext problems.Can''t you simply store HMAC result, where password is the passphrase given by the user, read from a file, etc. and data is the wrapping key? You can always strengthen passphrase using PKCS#5. I don''t really see why you don''t want to do that. Do you want to protect against brute-force attacks? -- Pawel Jakub Dawidek http://www.wheel.pl pjd at FreeBSD.org http://www.FreeBSD.org FreeBSD committer Am I Evil? Yes, I Am! -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 187 bytes Desc: not available URL: <http://mail.opensolaris.org/pipermail/zfs-crypto-discuss/attachments/20070806/b2535f82/attachment.bin>
Pawel Jakub Dawidek wrote:> On Mon, Aug 06, 2007 at 11:55:58AM +0100, Darren J Moffat wrote: >> Pawel Jakub Dawidek wrote: >>> That''s really not user-friendly... What if user simply misspell the >>> passphrase? He won''t be asked again, but will find garbage instead? >> Agreed but to verify it was the correct one you need to store something >> known to do so and that leads to known plaintext problems. > > Can''t you simply store HMAC result, where password is the passphrase > given by the user, read from a file, etc.You mean the HMAC secret ? > and data is the wrapping key? So an HMAC of the wrapping key itself ? In the case of the wrapping key being in a PKCS#11 token you might not be able to get the value of it (the token won''t give it too you because it is sensitive) only use it. In that case I don''t see how you can run an HMAC over it. What if we used the pool GUID as the data and stored an HMAC of that ? However that still leaves us with a possible minor issue in that we need to ensure that the actual wrapping key is usable as both an HMAC and encryption key. That is usually okay but for the case where it is in a PKCS#11 token there could be so edge cases in theory (I don''t think we have a problem with that in OpenSolaris libpkcs11/kcf though).> You can always strengthen passphrase using PKCS#5.That was in the plan anyway for when the passphrase is used as the wrapping key.> I don''t really see why you don''t want to do that. Do you want to protect > against brute-force attacks?I hadn''t considered storing an HMAC - not sure why because that is basically how we solved the implementation of C_Login in pkcs11_softtoken and that was in the back of my mind. -- Darren J Moffat
Darren J Moffat wrote:> You seem to be assuming, despite me saying that not having the key > didn''t block import, that the key has to be available at the time the > pool is brought online/imported.Ok, so back to the original question.. if importing has no requirements to get a key or even the right key, the only way I see to solve this right now is to have and encrypted value somewhere in the dataset structure that you already know and can compare with.. Something like the GUID encrypted by the dataset key for example..
On Mon, Aug 06, 2007 at 03:20:13PM +0100, Darren J Moffat wrote:> Pawel Jakub Dawidek wrote: > > Can''t you simply store HMAC result, where password is the passphrase > > given by the user, read from a file, etc. > > You mean the HMAC secret ? > > > and data is the wrapping key? > > So an HMAC of the wrapping key itself ?Please, forget what I wrote before, I was a bit confused. I''ll explain what I do in geli (disk encryption in FreeBSD) after consulting sci.crypt. MasterKey - key used to encrypt actual data on disk (equivalent of DSKEK - pool/master key, if I understand correctly [1]). UserKey - user supplied key (passphrase, random bytes from a file, etc.; let''s leave PKCS#11 tokens for now) (equivalent of wrapping key). Now, what I do is to encrypt MasterKey and store it on disk, but also HMAC MasterKey and store HMAC on disk. It is not recommended to use the same key for encryption and HMAC, but we can easly generate two keys from UserKey: EncryptionUserKey = HMAC(UserKey, 0x00) HMACUserKey = HMAC(UserKey, 0x01) First argument to HMAC() is secret and second argument is one byte of data. This was recommended as safe method of key cloning. Now I can store MasterKey encrypted with EncryptionUserKey and its HMAC calculated using HMACUserKey and later I''m able to verify correctness of UserKey. Of course PKCS#11 tokens make all this a bit more complex. We could still HMAC, as you suggested, pool''s GUID. Do you think about using DSKEK (or key derived from it) as HMAC secret? Another option is to use some kind of verification string. For example we randomly generate a string, which we encrypt using DSKEK and store on disk as well as we calculate SHA256 from this string and also store on disk. When we want to verify if DSKEK was decrypted correctly, we decrypt verification string, calculate SHA256 and compare with hash from disk. We could also think about simply storing hash of DSKEK, but I''d be carefull with that. [1] DSKEK is probably not used for data encryption, but is a wrapping key for per-dataset keys, but anyway. -- Pawel Jakub Dawidek http://www.wheel.pl pjd at FreeBSD.org http://www.FreeBSD.org FreeBSD committer Am I Evil? Yes, I Am! -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 187 bytes Desc: not available URL: <http://mail.opensolaris.org/pipermail/zfs-crypto-discuss/attachments/20070806/29a005db/attachment.bin>
Darren J Moffat wrote:> Anthony Scarpino wrote:[...]>> So the next questions.. if the wrong key is obtained during import how >> does one reenter the key? At this point the current cli is assuming >> import handles the keys and we can''t export the pool with a root fs >> dataset to reenter the key.. would we have to modify import to >> implement a reload process for? otherwise we may be looking at >> another zpool command.. > > I''m not assuming that at all and I''ve never said I was assuming that. > > The current prototype I have of this gets the token PIN or passphrase > EVERY time you run, and you can run it at any time. eg: > > > # zpool set dskek=passphrase tank > Enter passphase for tank: > # > > # zpool set dskek=pkcs11:Sun Metaslot:::mykey > Enter PIN for token "Sun Metaslot": > # > > # zpool set dskek=file:/rmdisk/stick/keys/mykey > # > > I don''t think we have to do anything to pool import. >I was only talking about ''zpool import'' only.. During import of the pool, import command would have to run through all the datasets again, check for encrypted ones, and reset the dataset keys in memory.. I have not looked to see if zpool can handle typing ''zpool import'' twice.. zfskeymgr maybe solves this problem by going straight to the key.. But I think we still have a usability problem if one types ''ls'' on a encrypted pool with the wrong key and sees junk.. the first thought is going to be the encryption failed or the dataset is corrupted..
Anthony Scarpino wrote:> Darren J Moffat wrote: >> Anthony Scarpino wrote: > [...] >>> So the next questions.. if the wrong key is obtained during import how >>> does one reenter the key? At this point the current cli is assuming >>> import handles the keys and we can''t export the pool with a root fs >>> dataset to reenter the key.. would we have to modify import to >>> implement a reload process for? otherwise we may be looking at >>> another zpool command.. >> I''m not assuming that at all and I''ve never said I was assuming that. >> >> The current prototype I have of this gets the token PIN or passphrase >> EVERY time you run, and you can run it at any time. eg: >> >> >> # zpool set dskek=passphrase tank >> Enter passphase for tank: >> # >> >> # zpool set dskek=pkcs11:Sun Metaslot:::mykey >> Enter PIN for token "Sun Metaslot": >> # >> >> # zpool set dskek=file:/rmdisk/stick/keys/mykey >> # >> >> I don''t think we have to do anything to pool import. >> > > I was only talking about ''zpool import'' only.. During import of the > pool, import command would have to run through all the datasets again, > check for encrypted ones, and reset the dataset keys in memory.. I have > not looked to see if zpool can handle typing ''zpool import'' twice.. > > zfskeymgr maybe solves this problem by going straight to the key.. But I > think we still have a usability problem if one types ''ls'' on a encrypted > pool with the wrong key and sees junk.. the first thought is going to be > the encryption failed or the dataset is corrupted..What alternative would you expect ? Remember the whole point of doing the encryption is that things aren''t readable if the key isn''t available. Possibilities are: * Return EIO for all access to an encrypted dataset if they key isn''t there - this might not be as easy as it sounds due to how the zio pipeline works. I did try this at one point and had problems (panic''s that may or may not have been related to zio_t->io_error != 0, but I''ll try it again. * Fail the mount of the encrypted data set - this might be the best way to do it. Currently I haven''t worked out how to do this. * Return the ciphertext - I don''t actually like that idea because it ends up being equivalent to giving raw disk access. While the ciphertext should be safe it feels wrong to give it up if we don''t have to. This is what my current code does. * Return some other random garbage - this probably does need to be just randomness. -- Darren J Moffat
Darren J Moffat wrote:> Anthony Scarpino wrote: >> Darren J Moffat wrote: >>> Anthony Scarpino wrote: >> [...] >>>> So the next questions.. if the wrong key is obtained during import >>>> how does one reenter the key? At this point the current cli is >>>> assuming import handles the keys and we can''t export the pool with a >>>> root fs dataset to reenter the key.. would we have to modify import >>>> to implement a reload process for? otherwise we may be looking at >>>> another zpool command.. >>> I''m not assuming that at all and I''ve never said I was assuming that. >>> >>> The current prototype I have of this gets the token PIN or passphrase >>> EVERY time you run, and you can run it at any time. eg: >>> >>> >>> # zpool set dskek=passphrase tank >>> Enter passphase for tank: >>> # >>> >>> # zpool set dskek=pkcs11:Sun Metaslot:::mykey >>> Enter PIN for token "Sun Metaslot": >>> # >>> >>> # zpool set dskek=file:/rmdisk/stick/keys/mykey >>> # >>> >>> I don''t think we have to do anything to pool import. >>> >> >> I was only talking about ''zpool import'' only.. During import of the >> pool, import command would have to run through all the datasets again, >> check for encrypted ones, and reset the dataset keys in memory.. I >> have not looked to see if zpool can handle typing ''zpool import'' twice.. >> >> zfskeymgr maybe solves this problem by going straight to the key.. But >> I think we still have a usability problem if one types ''ls'' on a >> encrypted pool with the wrong key and sees junk.. the first thought is >> going to be the encryption failed or the dataset is corrupted.. > > What alternative would you expect ? Remember the whole point of doing > the encryption is that things aren''t readable if the key isn''t available. > > Possibilities are: > > * Return EIO for all access to an encrypted dataset if they key isn''t > there - this might not be as easy as it sounds due to how the zio > pipeline works. I did try this at one point and had problems (panic''s > that may or may not have been related to zio_t->io_error != 0, but I''ll > try it again. > > * Fail the mount of the encrypted data set - this might be the best > way to do it. Currently I haven''t worked out how to do this. > > * Return the ciphertext - I don''t actually like that idea because it > ends up being equivalent to giving raw disk access. While the > ciphertext should be safe it feels wrong to give it up if we don''t have > to. This is what my current code does. > > * Return some other random garbage - this probably does need to be just > randomness. >Failing to mount would be my choice.. and knowing it''s because of encryption rather than some other problem would be good too.. So that the command can return back that there is a key problem. I''m not sure how much this latter half crosses over into your EIO comments..