Re: [RAUC] RAUC bundle encryption, design question
Thank you for the helpful feedback. I like the direction of this design quite a bit. Agree with implementing the encryption using OpenSSL in user-space. I will expand a little on our specific use case, I'd like to dig a bit deeper on the CMS message contents. We have a crypto key storage chip on our embedded device, an ATSHA204A. We want to feed it a salt, and it will generate a key from the given salt and its internal secret key. In our case all of the devices, given the same salt, will produce the same key. I'd like to use this key to decrypt the CMS message. Other users of RAUC may want to handle this differently. I wasn't quite clear how you were picturing RAUC being delivered a key for the CMS message in a generic way. Regardless, to use this approach we would need a portion of the bundle metadata which is not encrypted to store the salt. Since this may differ from user to user, I would propose allowing a user to pass a file to the bundle generator which would be stored in the bundle signed but not encrypted. On the device, we would need a handler to deliver the data so we could send it to the crypto device, then provide the resulting key to RAUC to open the bundle. RAUC would then have everything it needed to decrypt the message and in turn mount the encrypted squashfs partition. A RAUC user wouldn't have to leverage this, but a custom data section coupled with a handler between the start and decrypt steps would be widely accommodating. My other proposal is to either move or include a copy of the manifest in the unencrypted but signed portion of the bundle metadata. Since decrypting and mounting a bundle could take a little time, having it easily accessible would allow getting a quick response from "rauc info", it would be nice to do compatibility checks at this time too. You could also inspect a bundle off-device to see what it was. For example on a artifact storage server or web interface. I drew a crude diagram. Wasn't sure if all mail clients rendering in fixed width was a good assumption, so I put it here: http://file.evanedstrom.com/osrc/rauc/misc/bundle_logic1.txt Evan On Thu, Aug 23, 2018 at 2:04 AM Jan Lübbe wrote: > On Wed, 2018-08-22 at 13:27 -0700, Evan Edstrom wrote: > > On Tue, Aug 21, 2018 at 1:03 AM, Jan Lübbe wrote: > > > On Mon, 2018-08-20 at 11:39 -0700, Evan Edstrom wrote: > > I agree building in encryption support is nice, though successful > > implementation of encryption and security for embedded devices > > requires some level of custom hardware. > What kind of custom hardware are you thinking about? I'd prefer to > reuse and integrate with existing HW/SW as much as possible. Just mean that two embedded devices from different companies are likely to look extremely different in terms of how they handle security. Specifically key storage or generation (see use case above). > > This is going to be very > > device specific and I'm worried forcing the use of a specific > > procedure may be too limiting. I wonder if we would still need to > > provide some user customizability in the form of a handler somewhere. > You want to use a random payload key for every bundle to avoid problems > with key/IV reuse. So I think the (encrypted) payload key needs to be > contained in the bundle metadata. If you have a fixed (shared secret) > key on the devices, this could still be handle by passing it as a > password to the CMS decryption. I do like this idea of having a random payload key stored in an encrypted CMS message. But somehow OpenSSL needs to get a key to decrypt the CMS message. I am worried about the potential variety in this area across devices. ___ RAUC mailing list
Re: [RAUC] RAUC bundle encryption, design question
On Wed, 2018-08-22 at 13:27 -0700, Evan Edstrom wrote: > On Tue, Aug 21, 2018 at 1:03 AM, Jan Lübbe wrote: > > On Mon, 2018-08-20 at 11:39 -0700, Evan Edstrom wrote: > > > I am using RAUC for a commercial product, and one of the things we > > > need to accomplish is to encrypt our update bundles. I've manually > > > created an encrypted rauc bundle using a LUKS container. Once the > > > container is opened it can be mounted like normal as a squashfs > > > partition and used by RAUC. > > > > A normal RAUC bundle looks (mostly) like this: > > [ squashfs ][ CMS signature over hash of squashfs ] > > > > I expect that your LUKS container wraps both: > > [ LUKS header ][ LUKS encrpytion ( RAUC bundle ) ] > > > > So you get symmetric encryption of whole bundle with a password (i.e. a > > shared secret), right? > > Yes, I was using a keyfile with 1024 bytes of /dev/random to test with. OK. > > While this setup is pretty straight forward, I see some downsides: > > - RAUC cannot read any information about the bundle before decryption > > - With a single shared secret, there is no way to revoke a compromised > > key (for example extracted from a single device in the field) > > > * Option 1: > > > Provide an optional "decryption handler"... If the config file defines > > > this handler, the update process would essentially run the handler > > > instead of r_mount_loop() in bundle.c. > > > > r_mount_loop() only runs after reading and verifying the bundle > > signature, so it would need a different layout than the one above. > > Something like: > > [ LUKS header ][ LUKS encrpytion ( squashfs ) ] CMS signature over hash > > of LUKS header+encrypted data ] > > Exactly what I was picturing. Filling the container, closing it, then > signing using the existing method so RAUC could verify the signature > before attempting to decrypt in the same way it currently would. > > > > This gives a user the most flexibility as they're not locked into any > > > particular encryption method or even bundle format. Bundle creation gets > > > a little more tricky as there isn't a concept of handlers built in. Could > > > have > > > an optional argument which provides a mounted and empty bundle. > > > > A squashfs is generated by using mksquashfs. The result would then be > > copied into a fresh LUKS container. So creating encrypted bundles would > > required root. > > Correct, this is a limitation of device-mapper which is used by > cryptsetup. This wasn't a show stopper for our particular case, but I > see how this could be an issue for other cases. It would be a show-stopper for most of our projects, because it would be hard to use securely on a CI server and not all developer have root access on the build machines. A lot of work went into build systems and image generation tools to avoid the root requirement. > > > * Option 2: > > > Implement encryption support directly into RAUC as a compile option. > > > This could create an encrypted bundle and decrypt and mount during > > > install time. > > > > I'd definitely prefer built-in encryption support. Mainly because: > > - It can be integrated with the existing CMS-based signatures, so we > > get support for multiple recipient devices with individual private > > keys. > > - It's easier to use (you don't need to write a handler). > > - By using dm-crypt without LUKS, we can generate the encrypted bundle > > without requiring root privileges (via OpenSSL). > > Would we be able to encrypt the squashfs partition using OpenSSL > without mounting it with dm-crypt? Or I suppose another way, can > dm-crypt mount a squashfs partition which was encrypted with OpenSSL? We'd need to implement aes-xts-plain64 or aes-cbc-essiv in user-space, but these modes are pretty straight forward. > > - When using per device private keys, we can also store them in a TPM > > or a PKCS#11 token/smartcard, so they can't be easily extracted. > > > > As we use CMS [1] for signing, we can potentially support everything > > the OpenSSL cms tool (see 'man cms') supports (N-of-M signatures, > > encryption with shared secrets and/or public/private keys). > > These are all good points. I am not too familiar with the abilities of > CMS. I will need to do some reading before I can give as thoughtful of > a response.test/openssl-ca.sh Maybe take a look at the OpenSSL CMS tool source and the end of test/openssl-ca.sh in RAUC. > > So my current concept would be to use a differemt payload in the CMS > > message (instead of a hash over the squashfs), consisting of > > information about the encryption (algorithm, parameters and payload > > key) and the payload hash (or dm-verity root hash). The CMS message > > would then be encrypted in addition to being signed. > > We don't have to use LUKS, but its header does include information > about the encryption method which is inspection without decrypting > first. It builds in a similar mechanism, though the header is only > signed, not encrypted. Of course a user of
Re: [RAUC] RAUC bundle encryption, design question
Thanks for the feedback! On Tue, Aug 21, 2018 at 1:03 AM, Jan Lübbe wrote: > On Mon, 2018-08-20 at 11:39 -0700, Evan Edstrom wrote: >> I am using RAUC for a commercial product, and one of the things we >> need to accomplish is to encrypt our update bundles. I've manually >> created an encrypted rauc bundle using a LUKS container. Once the >> container is opened it can be mounted like normal as a squashfs >> partition and used by RAUC. > > A normal RAUC bundle looks (mostly) like this: > [ squashfs ][ CMS signature over hash of squashfs ] > > I expect that your LUKS container wraps both: > [ LUKS header ][ LUKS encrpytion ( RAUC bundle ) ] > > So you get symmetric encryption of whole bundle with a password (i.e. a > shared secret), right? Yes, I was using a keyfile with 1024 bytes of /dev/random to test with. > While this setup is pretty straight forward, I see some downsides: > - RAUC cannot read any information about the bundle before decryption > - With a single shared secret, there is no way to revoke a compromised > key (for example extracted from a single device in the field) >> * Option 1: >> Provide an optional "decryption handler"... If the config file defines >> this handler, the update process would essentially run the handler >> instead of r_mount_loop() in bundle.c. > r_mount_loop() only runs after reading and verifying the bundle > signature, so it would need a different layout than the one above. > Something like: > [ LUKS header ][ LUKS encrpytion ( squashfs ) ] CMS signature over hash > of LUKS header+encrypted data ] Exactly what I was picturing. Filling the container, closing it, then signing using the existing method so RAUC could verify the signature before attempting to decrypt in the same way it currently would. >> This gives a user the most flexibility as they're not locked into any >> particular encryption method or even bundle format. Bundle creation gets >> a little more tricky as there isn't a concept of handlers built in. Could >> have >> an optional argument which provides a mounted and empty bundle. > > A squashfs is generated by using mksquashfs. The result would then be > copied into a fresh LUKS container. So creating encrypted bundles would > required root. Correct, this is a limitation of device-mapper which is used by cryptsetup. This wasn't a show stopper for our particular case, but I see how this could be an issue for other cases. >> * Option 2: >> Implement encryption support directly into RAUC as a compile option. >> This could create an encrypted bundle and decrypt and mount during >> install time. > > I'd definitely prefer built-in encryption support. Mainly because: > - It can be integrated with the existing CMS-based signatures, so we > get support for multiple recipient devices with individual private > keys. > - It's easier to use (you don't need to write a handler). > - By using dm-crypt without LUKS, we can generate the encrypted bundle > without requiring root privileges (via OpenSSL). Would we be able to encrypt the squashfs partition using OpenSSL without mounting it with dm-crypt? Or I suppose another way, can dm-crypt mount a squashfs partition which was encrypted with OpenSSL? > - When using per device private keys, we can also store them in a TPM > or a PKCS#11 token/smartcard, so they can't be easily extracted. > > As we use CMS [1] for signing, we can potentially support everything > the OpenSSL cms tool (see 'man cms') supports (N-of-M signatures, > encryption with shared secrets and/or public/private keys). These are all good points. I am not too familiar with the abilities of CMS. I will need to do some reading before I can give as thoughtful of a response. > So my current concept would be to use a differemt payload in the CMS > message (instead of a hash over the squashfs), consisting of > information about the encryption (algorithm, parameters and payload > key) and the payload hash (or dm-verity root hash). The CMS message > would then be encrypted in addition to being signed. We don't have to use LUKS, but its header does include information about the encryption method which is inspection without decrypting first. It builds in a similar mechanism, though the header is only signed, not encrypted. Of course a user of RAUC will need to store the decryption key, but this could still leverage a TPM or secure storage on whichever architecture they used. > When opening the bundle, OpenSSL would detect that the CMS message is > encrypted, look for the matching private key and decrypt. Then we have > the information to configure dm-crypt and/or dm-verity on top of the > loop device. The rest of the installation would proceed as usual. Are you suggesting: [Arbitrary encryption method (squashfs)][CMS encrypted+signed (squashfs encryption format + payload key)] So you would first decrypt the CMS message using OpenSSL with a private key (optionally stored on a TPM or smartcard), use the newly acquired information to setup dm-crypt, and moun
Re: [RAUC] RAUC bundle encryption, design question
Hi Evan, thanks for starting this discussion! On Mon, 2018-08-20 at 11:39 -0700, Evan Edstrom wrote: > I am using RAUC for a commercial product, and one of the things we > need to accomplish is to encrypt our update bundles. I've manually > created an encrypted rauc bundle using a LUKS container. Once the > container is opened it can be mounted like normal as a squashfs > partition and used by RAUC. A normal RAUC bundle looks (mostly) like this: [ squashfs ][ CMS signature over hash of squashfs ] I expect that your LUKS container wraps both: [ LUKS header ][ LUKS encrpytion ( RAUC bundle ) ] So you get symmetric encryption of whole bundle with a password (i.e. a shared secret), right? While this setup is pretty straight forward, I see some downsides: - RAUC cannot read any information about the bundle before decryption - With a single shared secret, there is no way to revoke a compromised key (for example extracted from a single device in the field) > This seems generally useful; if this is something you'd like to see in > the project I'd be happy to contribute and submit a pull request. I > wanted to seek your input before I begin about the proper scope for > this, as it could be achieved in many different ways. Here are the two > methods I've narrowed in on. > > * Option 1: > Provide an optional "decryption handler" for the user to implement > which provides the bundle path and mount point. A user would implement > their decrypt and mount steps as needed. If the config file defines > this handler, the update process would essentially run the handler > instead of r_mount_loop() in bundle.c. r_mount_loop() only runs after reading and verifying the bundle signature, so it would need a different layout than the one above. Something like: [ LUKS header ][ LUKS encrpytion ( squashfs ) ] CMS signature over hash of LUKS header+encrypted data ] > This gives a user the most flexibility as they're not locked into any > particular encryption method or even bundle format. Bundle creation gets > a little more tricky as there isn't a concept of handlers built in. Could have > an optional argument which provides a mounted and empty bundle. A squashfs is generated by using mksquashfs. The result would then be copied into a fresh LUKS container. So creating encrypted bundles would required root. > * Option 2: > Implement encryption support directly into RAUC as a compile option. > This could create an encrypted bundle and decrypt and mount during > install time. > > This is much easier to use and allows easy encrypted bundle creation, > but is quite a bit less flexible. It also adds a dependency, like > cryptsetup, to the project. I'd definitely prefer built-in encryption support. Mainly because: - It can be integrated with the existing CMS-based signatures, so we get support for multiple recipient devices with individual private keys. - It's easier to use (you don't need to write a handler). - By using dm-crypt without LUKS, we can generate the encrypted bundle without requiring root privileges (via OpenSSL). - When using per device private keys, we can also store them in a TPM or a PKCS#11 token/smartcard, so they can't be easily extracted. > For either option, there is the possibility of inspecting a bundle > file's header and knowing whether to run the default mount function or > the handler. This would be useful if you thought clients should be > able to accept either encrypted or unencrypted bundles. Yes. We'd also need an option in the system.conf to configure which key to use for decryption. > Perhaps there is a much better way to do this than I've thought of. > I'd love to hear your thoughts on this. As we use CMS [1] for signing, we can potentially support everything the OpenSSL cms tool (see 'man cms') supports (N-of-M signatures, encryption with shared secrets and/or public/private keys). So my current concept would be to use a differemt payload in the CMS message (instead of a hash over the squashfs), consisting of information about the encryption (algorithm, parameters and payload key) and the payload hash (or dm-verity root hash). The CMS message would then be encrypted in addition to being signed. When opening the bundle, OpenSSL would detect that the CMS message is encrypted, look for the matching private key and decrypt. Then we have the information to configure dm-crypt and/or dm-verity on top of the loop device. The rest of the installation would proceed as usual. So the only places that would need to change are bundle opening (setup OpenSSL for decryption and configure device mapper targets) and bundle creation (optionally encrypt, optionally use veritysetup and use OpenSSL for CMS encyption). What do you think about this apporach? [1] https://tools.ietf.org/html/rfc5652 -- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-51