I am designing a challenge-response protocol to enable a client to authenticate to a server. The client has a private key, and a certificate (issued by a trusted CA). At this point in the protocol, the server knows who the client claims to be, but wants to prove it. My first attempt was:
$C ← S : r_S$
$C → S : S_C (r_S)$
where:
- $r_S$ is a random challenge generated by $S$ (the server).
- $S_C(r_S)$ is a signature of the challenge, signed with $C$'s (the Client's) private key.
The problem with that, is that the private-key + certificate may be used for other purposes than identifying the client to the server. (For example, authorizing invoice payments.) A compromised server could send the client the hash of an invoice payment authorization, and get back the necessary signature to authorize it.
Next attempt:
$C ← S : r_S$
$C → S : r_C, S_C (H(r_S | r_C))$
where:
- $r_C$ is a random nonce generated by $C$.
- H is a suitable cryptographic hash function
- other terms are as above
Is this secure? Specifically, can a compromised server use such a scheme to calculate $S_C(V)$ for some predetermined value $V$?
In particular,
- would it be safer to put $r_C$ first in the concatenation?
- and is simple concatenation good enough, or do I need to do something like calculate $\text{HMAC}_K(r_S|r_C)$ using a hardcoded key $K$ or even $\text{HMAC}_{r_C}(r_S)$ (using $r_C$ as the key to the HMAC)?