When you assume that C acts as an adversary, is eavesdropping and capable of constructing messages based on the acquired information, you have to design your protocol with care. This stems from the fact that C could potentially relay, replay, and construct messages. Therefore, you need to prevent replay and man-in-the-middle attacks, furthermore handling for multiple, (simultaneous) protocol sessions.
You already realized that a static signature might not be enough. Essentially, your problem is the motivation for authentication protocols and their design is not trivial: if you take a look at the Needham–Schroeder protocol 1 or the Woo-Lam protocol 2 you will see that unforeseen attack vectors could break your protocol as both examples are insecure in their original versions.
Basically, some best practices for secure protocol design are:
- Make maximally pessimistic assumption
- Put the sender and receiver in messages (i.e., their public keys)
- Use encryption to ensure that only the correct receiver can read the content
- Use nonces / timestamps to get freshness
- Generate nonces yourself to prevent replay attacks
- Always sign and encrypt components together
But still: there are protocols considered secure that do not follow all points and insecure protocols that do.
In any case, you would want to analyze your protocol (semi-)automatically using for example model checking or theorem proving.