Hi,
I have been trying to make SSL/TLS connection using client
authentication.
I have found several issues in the class SSLSocket.
As the code for this class is pretty much the same between Jessie
v1.0.1 and Classpath v0.92,
I am cross posting to Jessie and Classpath.
1. Digest cloning
In the following piece of code, the clone of digest was badly placed
after receiving the CertificateVerify instead of being done BEFORE.
This is a problem as this digest is computed on the fly from data
read from the stream
Since the digest is computed on the client side before creating the
verify message, this was causing a mismatch.
2. In the same code, the read was call without specifying the cipher
suite. As this info is used to determine how to read the signature,
a NPE was thrown with the original code. Providing the cipher suite
fixes the bug.
==========
(Around line 2890)
if (clientCanSign && (wantClientAuth || needClientAuth))
{
// FIX the digest need to be cloned before the verify
message is read since their have been computed by the client
// BEFORE sending the CertificateVerify Message
IMessageDigest cvMD5 = (IMessageDigest) md5.clone();
IMessageDigest cvSHA = (IMessageDigest) sha.clone();
//FIX CH If suite is null, the signature cannot be read since
the key type/cipher signature type is used.
// msg = Handshake.read(din);
msg = Handshake.read(din, suite, null);
if (msg.getType() != Handshake.Type.CERTIFICATE_VERIFY)
{
throwUnexpectedMessage();
}
CertificateVerify verify = (CertificateVerify)
msg.getBody();
if (clientChain != null && clientChain.length > 0)
{
// IMessageDigest cvMD5 = (IMessageDigest) md5.clone();
// IMessageDigest cvSHA = (IMessageDigest) sha.clone();
==========
3. When reading the client certificate, the call to Handshake.read()
missed the certificate type. The fix as shown in the code below is to
add the CertificateType.X509 argument.
========
(around line 2690)
if (suite.getKeyExchange() == "RSA")
{
msg = Handshake.read(din, suite, kexPair.getPublic(),
CertificateType.X509);
}
else
{
msg = Handshake.read(din, suite, null,
CertificateType.X509);
}
boolean clientCertOk = false;
boolean clientCanSign = false;
X509Certificate[] clientChain = null;
PublicKey clientKey = null;
// Read the client's certificate, if sent.
if (msg.getType() == Handshake.Type.CERTIFICATE)
========
4. This is one more general: It's not clear what certificate the code
expect to find in the trust store (self-issued ok?, external root
certificate ?, certificate stored in the key store with or without
its private key?), on the client side, and on the server side.
This is maybe a system-level issue but for some configuration, the
code just crash with a NPE. After analysis of the error, the
'correct' usage can be understood, but some explanation would be
needed, especially when client authentication is on.
Anyway, after few hours of debugging, I am happy to have TLS working
with server AND client authentication.
Thanks for the nice piece of code.
Cheers,
Cedric