shared secret alternative to DSA

Paul Crowley paul at ciphergoth.org
Sat Jun 4 00:43:32 PDT 2005


Brad Fitzpatrick wrote:
> As requested, I'm appointing you security dictator over the OpenID spec.

Wow, thanks!  I promise to be a benevolent dictator; see the ubiquitous 
posters showing me gazing into the future with benificent vision.

I'm pushing quite hard for the shared secret based protocol here, but 
I'm not wedded to it - I'm actually more concerned about the lifespan 
stuff and other concerns raised in parts two and three, all of which is 
necessary no matter which way this goes.  However everyone seems to be 
happy to agree on those changes, so I think this is the only one that 
remains to be decided.

> DEFINITIONS:

I want to modify these somewhat.  All the modifications make life easier 
for server implementors and make no difference to consumers

The only rule in the specification is that (1) you must get a fresh (ie 
never-before-issued by this server) secret ID every time you ask for 
one, and (2) the map between the set of secret IDs ever issued and the 
secrets they map to must be indistinguishable from random.  The rest is 
just an implementation recommendation.

I'd recommend something more like this:

     secret_handle ::= latest-secret-time(<time>) "-" <public-nonce>

     secret_value(handle) ::= 
HMAC_SHA1_Hex(server-secret(<time(handle)>),  <public-nonce(handle)>)

     secret_expiry(handle) ::= server-secret-expiry(<time(handle)>)

In other words, the "time" field in the handle is more of a "server 
secret reference".  OK, so this means you're effectively telling the 
world how often you regenerate your server secret, but that's no harm 
really.

I've replaced <public-random> with <public-nonce>, because there's no 
requirement that this field be random either.  It can be an incrementing 
counter if you like; this gives away how many IDs you've been asked for 
that day, but again there's little harm in that.  You can put a prefix 
on it indicating which server from your server farm generated it, so 
each server has its own pool of IDs and they can't step on each other's 
toes.

Finally, HMAC-SHA1 takes two values, a key and a string, so I've 
modified it to show that.

>    consumer -> idserver:
>           openid.mode=generate_secret
>           (perhaps also the consumer site's trust_root, so the returned secret handle/value
>            are tied to one trust_root in case the value is intercepted)

No need.  You can't use this secret to try and spoof other consumers, 
because those other consumers don't know this secret.

>    idserver -> consumer:
> 
>           secret_handle = 1117855428-random_string_19283746
>           secret_expiry = 86400
>           secret_value = 2e47994eec0b1fa16ac62180005fa5651f5e0e14

I'd rather handle the expiry stuff slightly differently, but that's 
nothing to do with the shared secret so I'll save it for another post.

>       openid.mode = id_res
>       openid.assert_identity = http://bradfitz.com/
>       secret_handle = 1117855428-random_string_19283746
>       hmac_sha1 = HMACSHA1( secret_value(secret_handle) + plain )
>                 = HMACSHA1( "2e47994eec0b1fa16ac62180005fa5651f5e0e14" +
>                             "yyyy-mm-ddThh:mm:ssZ assert_identity http://bradfitz.com/ http://return.to.com");

> Is that about right?

Yup, except that again, HMAC-SHA1 is two-valued, so replace + with , there.

Again this is nothing to do with shared secret, but I wonder what the 
pros and cons are of making the server explicitly include information 
like secret_handle and openid.assert_identity in the reply, over making 
the client encode it in the return_to URL however they like?

>        -- DSA isn't /that/ hard.  We already have Perl, Java, and PHP
>          implementations.

Sure.  But the dependencies are quite a bind, and you really can't 
escape them - rolling your own DSA implementation is really out of the 
question, because even if you're prepared to put up with the very poor 
performance that a naive bignum-based implementation would give you, 
rolling an ASN.1 parser and parsing out the public key is quite painful 
enough by itself.  I've been looking through the list archives and 
there's been quite a bit of discussion of how to meet them - and one 
person reacted quite positively to this proposal when I first put it 
forward because of them.

>  CON:  consumers /must/ cache the secret_handle -> secret_value, at least
>        for 30 seconds or so.  at least with DSA mode, a completely stateless
>        design was possible and caching just helped:  it wasn't required.

A completely stateless design is still possible, but you need to be 
cunning about it.  You have to have a consumer secret, then encrypt/MAC 
the HMAC-SHA1 secret with the consumer secret, and include that in the 
return_to URL.

However, if this turns out to be a big pain, it would be possible for 
identity servers to do more to support consumers that really can't store 
any state at all; a simple variant on this protocol would allow for 
something more like your original idea of a callback from consumer to 
server on each identification, which is what the stateless consumers 
have to do anyway.

 > What pros/cons and counter arguments am I missing?

The big PRO argument that doesn't get a mention here is performance. 
People who take a lot of SSL connections spend real money on SSL 
accelerators to do the public key math in reasonable time.  HMAC-SHA1 is 
a thousand times faster.  It makes it possible to host the world's most 
popular OpenID server on an old Pentium under the stairs.  A three 
millisecond calculation is a noticeable burden; a two microsecond 
HMAC-SHA1 one really isn't.

One other PRO is that we only really need to send the first 64 bits or 
so of the HMAC-SHA1 output, so the resulting signature is about a fifth 
of the length of a DSA signature.  But that's probably not a big 
consideration for most applications.

>  CON:  secret value goes from idserver to consumer in the clear.

This seems to be everyone's main stopping point.

In one post you mentioned that sending secrets in the clear "looks bad". 
    But to my eyes, sending public keys unauthenticated looks worse. 
Either can make it look as if the security of the protocol isn't very 
well considered, if we don't justify them explicitly.  Both are 
justified only by our assumption that actually, doing bad things to core 
internet connections is quite difficult.  Both are solved if SSL is used.

>        -- Diffie-Hellman /could/ be used for secret exchange, maybe.

If I really can't convince people here that it's no worse to send the 
MAC secret in the clear, then let's move to an HMAC-SHA1 + DH protocol. 
  That will address people's concerns, while still preserving the 
performance advantages, and avoiding the implementation complexity of 
DSA.   But to be honest I'm still far from convinced.  If you think 
there's a real risk your consumer connection to the ID server will be 
snooped, you should be just as worried about the risk it'll be tampered 
with, and in that case the only thing that will save you is SSL.
-- 
   __
\/ o\ Paul Crowley, paul at ciphergoth.org
/\__/ http://www.ciphergoth.org/


More information about the yadis mailing list