

Is it ASCII or Protobuf? The importance of types in cryptographic signatures - qiqing
https://blog.sandstorm.io/news/2015-05-01-is-that-ascii-or-protobuf.html

======
BoppreH
That's a fairly big problem I hadn't read about before, with great writing.
But I don't think the proposed solutions are realistic.

    
    
      [...] all those web sites must use exactly the same format for 
      authentication challenges.
    
      [...] the key cannot be used for any automated purpose [...]
    
      [...]  all applications which use the key for signing must include
      such a context string, and context strings must be chosen to avoid conflicts.
    
      [...] better than either of the above is to use a different key for each purpose.
    

That's shifting protocol problems to standardization and human caution. It may
work, but I'm skeptic.

Maybe a change in the cryptographic protocol can fix the problem? For example,
instead of

    
    
        Server: server_value // domain + action + nonce + ...
        Client: sign(server_value)
    

we use

    
    
        Server: server_value
        Client: sign(client_random) + sign(server_value XOR client_random)
    

and the server verifies that the two signed components, when XOR'd, result in
the same value sent. This way the client only signs random data but can still
authenticate.

This is not supposed to be a final solution, and is likely to have flaws, but
I think it's a better direction to pursue.

~~~
sdevlin
Here's another attack scenario to think about.

Consider the original protocol: server sends a t-bit nonce N, client signs it.

Suppose that Eve can passively observe Alice's authentications to Bob's
server, but she can't actively MitM the connection. Her best generic attack is
a birthday attack:

1\. Eve observes 2^b authentications and remembers each (N, S(N)) pair.

2\. Eve attempts to authenticate as Alice. If Bob sends an N she has seen
before, she's in. If he sends a fresh N, she aborts and tries again.

Eve will succeed in step 2 after roughly 2^(t-b) attempts.

Now consider the amended protocol. In each authentication, Eve observes two
signatures: S(R) and S(R^N). Each is a signature over what is essentially a
random t-bit number. This allows Eve to improve her attack:

1\. Eve observes 2^b authentications. She stores two (X, S(X)) pairs per
authentication: one for X = R and one for X = R^N. The size of the set is
2^(b+1).

2\. Eve attempts to authenticate as Alice. Bob sends N. For each X in her set
of observations, Eve calculates X' = X^N. If X' is also in the set, Eve wins.
If not, she aborts and tries again.

Notice that Eve is now colliding N with the set of (X, X') pairs. Since this
set grows with the square of Alice's authentication attempts, Eve will succeed
after roughly 2^(t-2(b+1)) attempts.

This attack is plausible for sufficiently small t (say, 64) and sufficiently
large b (say, 16-20). While b will be very small in web login scenarios, large
b may be plausible in automated authentication scenarios.

This can obviously be defeated by choosing a sufficiently large t.

EDIT: (I'm not 100% certain about all the math. Corrections are welcome.)

~~~
BoppreH
That's a very cool attack. However, the client can sign R and R^N together,
which I think defeats it. I didn't describe it as such because I was afraid
"S(R+R^N)" may cause some confusion, and I ran some numbers and found the
security level acceptable for 128-bit nonces and a few billion logins.

------
binarnosp
This was the reason that made me reject both protobuf and thrift for my own
project. I ended up developing my own protocol which has to guarantee a
normalized stream: there is only one way of encoding a set of data, any other
way causes a error in the parser.

Here it is (still under development):
[https://bitbucket.org/binarno/goingthere](https://bitbucket.org/binarno/goingthere)

Can be embedded into streams, but it has a "strict" flag that forces the
parser to throw an error if unexpected data is found in the stream. Optional
tags not specified in the schema simply cannot be there, and all the tags must
be encoded following a specific order.

Still looking for a simple protocol that allows to have a normalized
representation that is always the same for the same set of data; I hate to
develop my own things and prefer to steal ready made things :-)

~~~
heavenlyhash
You may also want to consider cbor:
[http://tools.ietf.org/html/rfc7049](http://tools.ietf.org/html/rfc7049) It
doesn't require canonicalization, but it has a suggested format for
canonicalization, and libraries I've been using have made it reasonably
possible to force field ordering.

Though this may be something of a tangent, since as kentonv says,
canonicalization is only part of the dance; it all depends on what _other_
actors do as well. :)

------
dfox
One problem with this article (that does not invalidate the main point that
you should not reuse keys for different protocols) is using SSH authentication
as an example.

In SSH what gets signed in publickey (and hostkey) authentication is not
controlled by server (client). Instead of some random value provided by other
side, signed data include session id that is derived from result of first DH
key exchange and thus unpredictable to either side of connection.

~~~
sdevlin
> signed data include session id that is derived from result of first DH key
> exchange and thus unpredictable to either side of connection

The unpredictability of DH output depends on the group parameters and public
key validation performed by the peer. If the group contains small subgroups,
Eve can send an element of small order and predict the DH output with high
probability.

For example, this is one of the attack vectors for the triple handshake attack
on TLS: [https://www.secure-resumption.com/tlsauth.pdf](https://www.secure-
resumption.com/tlsauth.pdf).

~~~
dfox
Which is mitigated in SSH by two things:

1) The DH group is negotiated by both peers from fixed list. 2) output of key
exchange is hashed with various values that are not all controlled by same
side of connection

Also after reading the relevant part of RFC4253 I've found out that the
session id is conceptually an output of key exchange, but in the DH case it's
derived from contents of key exchange messages and not from the result itself
(not that it makes much of an difference).

------
zaroth
Why does the server present any data to be signed at all? The client generates
a string, I am Sam logging into Google and Time is Now, Signed Sam.

The server has the public key and verifies.

~~~
kentonv
A timestamp doesn't prevent replay attacks, it just time-limits them. Also,
requiring time sync tends to be problematic -- many people have incorrect
clocks. Finally, just because your protocol uses a timestamp at some position
doesn't mean some other protocol won't interpret those bits in some other way.
Removing server-controlled bits makes an attack harder but not necessarily
impossible.

~~~
zaroth
But anyone who can get this signed message can also get the session token?

Or are the rules of the game this has to work over an unencrypted channel? In
which case you need two keys and you do DH.

~~~
kentonv
I assumed the "time is now" was meant to prevent replays. But yes, it's great
if you can establish a secure channel first with a session key generated based
on randomness provided by both client and server and then, once the session is
up, send a signature of the session key, signed by your long-term key. No
timestamp needed, then (I think). (Insert obligatory reminder not to roll your
own crypto.)

But this is beside the point. You still have the problem that you are signing
a thing, and if the signing key isn't restricted to signing _only_ this type
of thing, there is a risk that the thing you are signing could have a
different meaning when interpreted as a different type. _Even if_ the client
fully-controls the content of the thing to be signed, this is still possible.
Perhaps you can dismiss it as "unlikely", but I'm not sure I'm comfortable
doing so.

