The client certificate is public, just like the server certificate. The only reason to keep the client certificate would be privacy, if you don't want to reveal that you are this particular client. Publishing the client certificate does not allow anyone to impersonate you.
Client authentication does not only require the client to show that it knows the certificate. The client shows the certificate to identify itself, i.e. to claim “this is who I am”. Showing the certificate is not authentication: for authentication, the client needs to prove “this is who I am”.
The client can prove who it is because it knows the private key associated with the public key contained in the certificate. It proves that it knows the private key by making a signature of data that includes a unique challenge sent by the server. (The challenge is some random bytes sent at the very beginning of the TLS handshake.) Including a unique challenge prevents against replay attacks: if an eavesdropper records the client's responses, they won't be able to replay them to make a valid connection to the server, because next time the server's challenge will be different.
In order to decide whether the client is acceptable, the server does two things:
- The server checks that the certificate is acceptable. It may have a list of acceptable certificates (this works for self-signed certificates), or it may only accept certificates that have been signed by a particular entity. This shows that if the client is who it claims to be, it's acceptable.
- The server checks that the signature from the client is correct, using the public key contained in the certificate. This shows that the client is who it claims to be.
All of these mechanisms are similar in principle to how a client authenticates a server, although the protocol is not perfectly symmetric.
Having the sever encrypt a challenge with the client's public key, and the client prove that it knows the private key by decrypting this challenge, would also work, from a security point of view. It is not done for several reasons:
- It would require the client's private key to be capable of doing encryption. The types of private keys commonly used for TLS are RSA keys, which can do both signature and encryption, and ECDSA keys, which can only do signature.
- It would involve asymmetric decryption. Assymetric decryption is considerably harder to implement securely than signature, because it involves both the private key and externally-supplied data (the thing to decrypt) in the same operation. There is a very long history of vulnerabilities in RSA decryption. The history of RSA signature is a lot less depressing.
- It would make the protocol less efficient: it would need an extra round trip. The server can send a challenge to sign at the beginning of the connection. If it had to send a challenge to decrypt, it would first need to know the client's public key. Before the client could send its public key, it needs to know what cryptographic algorithms the server support and whether the server wants client authentication. The client sends both its certificate and its signature in the second flight of messages that it sends to the server, when it knows what algorithms the server supports. If the protocol used decryption instead of signature, the client would have to send its certificate in the second flight and there would have to be a third flight for the decrypted challenge.