[openstack-dev] [nova][keystone] Message Queue Security

Simo Sorce simo at redhat.com
Fri Apr 26 19:59:07 UTC 2013


On Fri, 2013-04-26 at 11:23 -0700, JIANGANG Zhang wrote:
> (The previous reply used the wrong subject line - my appologies)
> 
> 
> Hi Simo,
> 
> Nice writeup. A couple of comments I have just in case:

Hi,
thank you for your comments!


> 1) Regardless public key or shared key based solution, there's always
> a need to store the secret key. The difference is with public key
> based, only the owner has the private key.

Yup.
> 
> 2) You mentioned that PKI is slow and complex, which is true
> comparatively but should be ok in this use case. For example, I can do
> 1034 sign/s and 22829 verify/s on my shabby macbook pro of 2010 and
> the CPU usage does not seem to be an issue. Compared to the 2 lookups
> per message in your proposal as you mentioned, it's much much more
> efficient.

And how many HMACs can you do ?

> 
> 3) It looks like your key server is like Kerberos.  There's probably
> no point to reinvent the wheel. It should easily adapt to this 1:1 use
> case as you proposal supported.

I already replied about this, there is however a difference, where it
comes to trusts between different realms and most importantly group
recipients. They are all solvable so I always keep an option open to
just move everything over to use Kerberos for most of what is done here.
The changes would be minimal so far and would be able to drop in place
easily. I am just trying to do a simpler implementation now so we can
have something decent in Havana that works.
> 
> 4) Arguably, your proposal supports confidentiality, authorization
> control (via the shared secret)  and integrity and anti-replay (via
> timestamp), but it falls short on non-repudiation due to the nature of
> shared secret. 

True, but I do not think we need non-repudiation at this stage.
> 
> 5) The 2 lookups to Key Server per message is way too much with regard
> to efficiency.

Keep in mind that the 2 lookups are not *per-message* but per-peer-pair.
Ie if you send many messages between A and B in a short timeframe you do
only 2 lookups in total, not 2 lookups per message.

Also read the email I sent today, the number of lookups is down to 1
now, just like in the public key case.
> 
> 6) As mentioned, failure to support 1:m, m:n messaging imposes too
> much restriction to the overall system.

Indeed this has been mostly addressed though.
> 
> That said, the following is what I would suggest, which supports 1:1,
> 1:m and m:n messaging with confidentiality, integrity, authorization,
> non-repudiation and anti-reply:
> 
> 
> a) In keystone, for each user add an entry for its public key - only
> the user itself knows its own private key.
> 
> 
> b) To support 1:m and m:n, each "group/role" of users is provisioned
> with its group public key - all users of this "group/role" is
> provisioned with the "group/role" private key. 

How do you provision these keys ? How do you revoke and replace them ?

In my recent design I have a very simple method that avoids very
expensive provisioning. (still setting up the share key need to be done,
but that's inevitable)
> 
> c) All public keys (via x.509 or bare key) are cacheable. Cautious
> senders and recipients should check regularly but it's an overkill to
> check once per message.
> 
Indeed, nobody is suggesting to check once per message.

> d) On sending the message, the sender does the following:
> 
> 
>         d.a) looks up (if not cached or to be cautious - assuming
>         there's no revocation in place) for the recipient's or
>         recipients' public key. 
>         
>         
>         d.b) generate a encryption key (EK) and a signing key (SK)
>         (not necessary if public key signing is used) and decide its
>         lifetime (expiration and) 
>         
>         
>         d.c) generate a random # of at least 128 bit long,
>         start/current time (e.g. via gettimeofday), EK and SK
>         signature, expiration and and sender-id, concatenate and sign
>         them using its private key
>         
>         
>         d.d) Encrypt the message (together necessary meta data, e.g.
>         recipient list and lifetime left, sequence counter) using EK,
>         as BodyE and sign the encrypted BodyE using the sign key as
>         SIGN.
>         
>         
>         d.e) For each recipient, use its public key to encrypt EK, the
>         encryption algo,  signing key SK (if needed), signing algo,
>          and EK/SK expiration), then prepend it with the recipient's
>         public key identifier - e.g. uid.
>         
>         
>         d.f) Send the the outcome of d.c), BodyE and SIGN from d.d)
>         and d.e) over the all recipients.
>         
>         
>         Note: d.b), d.c) and d.e) are only done once for the duration
>         of the EK/SK lifetime, so the # of public key calculations
>         (RSA/EC etc) are minimized. The algos are there for
>         extensibility and the recipient can reject if it's weak.

Yes this is very similar to what I described in the document and the
recent amendment to the list except you use a public key scheme to
protect EK and SK.
However there is a problem here, you assume that either the sender knows
the identity of all recipients one by one or use of a shared private key
for groups of services.

If you send to multiple recipients, you need one lookup for each
recipient, which becomes very expansive rapidly. and the message size
also increases quite rapidly as you have to encrypt the same body
multiple times, plus you need to use something like a dict so the
recipient can find the correct key, which further increases message
size.

If you send to a shared identity you still have a shared private key
system but your shared key for a group is long term and not short term.
Also you need a way to communicate this key to all peers, how do you do
that ?

> e) On receiving the message, the recipient doe the following:
> 
> 
>         e.a) looks up )if not cached or to be cautious - assuming
>         there's no revocation in place)  for the sender's public key.
>         
>         
>         e.b) verify sender signature and time window etc if not
>         previously verified for this "session" (a while ago - time
>         window == expiration).
>         
>         
>         e.c) decrypt the block prepared by d.e), gets the EK, SK,
>         expiration and verify the expiration. 
>         
>         
>         e.d) Using SK to verify signature
>         
>         
>         e.e) Decrypt the message using EK, check against replay via
>         verifying the expiration and counter/sequence etc.
>         
>         
> If more detailes are needed, please let me know. Note that there may
> be loose ends given the limited time I have spent on this. 

Well I see 2 problems with this scheme.

1. Now you are doing 2 lookups because you have to look up keys on both
sender and receiver. While my revised scheme needs only one :-)

2. Because you do not have a key server in the mix you also do not have
access control there, which means the receiver will have to additionally
perform access control to decide whether the sending party is allowed to
send messages at all, and this is an additional policy lookup from some
central server. It can be cached, but you still need to regularly
refresh it in case policies change.

In my design if the A -> B message is not permitted the sender doesn't
even get a key so no resources are spent at all either on the sender or
on the receiver. So it seem to me my proposal is more efficient on
various levels.

Simo.


-- 
Simo Sorce * Red Hat, Inc * New York




More information about the OpenStack-dev mailing list