mail archive of the rauc mailing list
 help / color / mirror / Atom feed
* [RAUC] RAUC bundle encryption, design question
@ 2018-08-20 18:39 Evan Edstrom
  2018-08-21  8:03 ` Jan Lübbe
  0 siblings, 1 reply; 5+ messages in thread
From: Evan Edstrom @ 2018-08-20 18:39 UTC (permalink / raw)
  To: rauc

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.

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.

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.

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


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.

Perhaps there is a much better way to do this than I've thought of.
I'd love to hear your thoughts on this.

Best,
Evan Edstrom

_______________________________________________
RAUC mailing list

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

* Re: [RAUC] RAUC bundle encryption, design question
  2018-08-20 18:39 [RAUC] RAUC bundle encryption, design question Evan Edstrom
@ 2018-08-21  8:03 ` Jan Lübbe
  2018-08-22 20:27   ` Evan Edstrom
  0 siblings, 1 reply; 5+ messages in thread
From: Jan Lübbe @ 2018-08-21  8:03 UTC (permalink / raw)
  To: rauc

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-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
RAUC mailing list

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

* Re: [RAUC] RAUC bundle encryption, design question
  2018-08-21  8:03 ` Jan Lübbe
@ 2018-08-22 20:27   ` Evan Edstrom
  2018-08-23  9:03     ` Jan Lübbe
  0 siblings, 1 reply; 5+ messages in thread
From: Evan Edstrom @ 2018-08-22 20:27 UTC (permalink / raw)
  To: Jan Lübbe; +Cc: rauc

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 mount the mapper device.
Am I understanding correctly?

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

I agree building in encryption support is nice, though successful
implementation of encryption and security for embedded devices
requires some level of custom hardware. 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.
Even without storing the payload key in a CMS message, it should be
possible for a user to securely implement a TPM to generate the
decryption key.

Let me do a little more reading on OpenSSL encryption and CMS messages.

Thanks again,
Evan

_______________________________________________
RAUC mailing list

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

* Re: [RAUC] RAUC bundle encryption, design question
  2018-08-22 20:27   ` Evan Edstrom
@ 2018-08-23  9:03     ` Jan Lübbe
  2018-08-23 19:13       ` Evan Edstrom
  0 siblings, 1 reply; 5+ messages in thread
From: Jan Lübbe @ 2018-08-23  9:03 UTC (permalink / raw)
  To: rauc

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 RAUC will need to store the
> decryption key, but this could still leverage a TPM or secure storage
> on whichever architecture they used.

Yes.

> > 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)]

Actually more like:
[ squashfs hashed with dm-verity and encrypted in dm-crypt compatible
format ][ CMS encrypted and signed (algorithm settings, dm-verity root
hash, 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 mount the mapper device.
> Am I understanding correctly?

Yes. CMS can also use simple passwords (instead or as an additional
recipient), not only public keys.

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

> 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.
> Even without storing the payload key in a CMS message, it should be
> possible for a user to securely implement a TPM to generate the
> decryption key.

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.

> Let me do a little more reading on OpenSSL encryption and CMS messages.

Sure, thanks for providing a concrete use-case so we can make progress
on the design.

Regards,
Jan
-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
RAUC mailing list

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

* Re: [RAUC] RAUC bundle encryption, design question
  2018-08-23  9:03     ` Jan Lübbe
@ 2018-08-23 19:13       ` Evan Edstrom
  0 siblings, 0 replies; 5+ messages in thread
From: Evan Edstrom @ 2018-08-23 19:13 UTC (permalink / raw)
  To: Jan Lübbe; +Cc: rauc

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

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

end of thread, other threads:[~2018-08-23 19:13 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-08-20 18:39 [RAUC] RAUC bundle encryption, design question Evan Edstrom
2018-08-21  8:03 ` Jan Lübbe
2018-08-22 20:27   ` Evan Edstrom
2018-08-23  9:03     ` Jan Lübbe
2018-08-23 19:13       ` Evan Edstrom

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox