1

I have a php ssl client, and a C++ Qt ssl server, and I need the client to be authenticated rather than the server.

The reason is that the C++ Qt ssl server actually runs on a desktop application, and i don't want to provide the desktop application with a private key for security reasons and also because the server does not need to authenticated it self.

So I had the client provided with certificate and private key, while the server has only the certificate that authenticates the client.

however in the above scenario I get and ssl error from the server side, the handshake fails for lack of shared ciphers.

If i provide the server with its own local private key and certificate the handshake is done successfully.

below some php code to set up ssl:

/* $local_cert_path is a file containing a complete certificate
 * verification chain and the private key
 */
if (! is_file($local_cert_path))
{
    throw new Exception(sprintf('cannot find certificate path: %s', $local_cert_path));
}
$this->ctx = stream_context_create();
stream_context_set_option($this->ctx, 'ssl', 'verify_peer', FALSE);
stream_context_set_option($this->ctx, 'ssl', 'allow_self_signed', TRUE);
stream_context_set_option($this->ctx, 'ssl', 'local_cert', $local_cert_path);

and C++ (Qt):

QList<QSslCertificate> certs = cacerts(); 
socket->setCaCertificates(certs); // loading the CA
// socket->setLocalCertificate(":/res/cert.pem", QSsl::Pem);
// socket->setPrivateKey(":/res/key.pem");
socket->setPeerVerifyMode(QSslSocket::VerifyPeer);
socket->setProtocol(QSsl::TlsV1);

If I provide the server with its own local private key and certificate (uncommenting the two lines above) then the handshake works.

andrea
  • 452
  • 5
  • 14
  • http://serverfault.com/questions/233650/public-key-authentication-or-similar-over-http-https might shed some insight? Also check out WebId, a W3C proposal which uses key based authentication. There will likely be a lot of articles it references to perform the task. – Kevin Peno Nov 22 '11 at 21:36
  • 1
    Thanks Kevin, believe it or not I have WebID rolling in my head for over 10 years now, but did not know about the actual W3c proposal. In fact i ma working on another project besides the current one, that uses x509 certificates to authenticate people the CommonName is the person verified email address. – andrea Nov 22 '11 at 23:00
  • Unfortunately at the moment the problem i have is different, i don't want the server to hold a private key, but it seems that using the ssl implementation i am using is not possible to have a successful handshake (and subsequent encrypted channel) without the server holding a valid key. – andrea Nov 22 '11 at 23:09
  • @KevinPeno, WebID (ex. FOAF+SSL) doesn't reverse role of the client and the server as far as SSL is concerned. It's just a different way to check whether the client certificate is trusting (replacing traditional PKI), where the SSL server becomes a client to check the key in the FOAF document, but that's a separate connection (if there is a connection at all, since the FOAF document could be cached or local in principle). – Bruno Nov 23 '11 at 00:00
  • @Bruno I wasn't suggesting that it does, per say. I was suggesting it as reading for the OP since the scenario give is similar in approach and that it might lead them to an answer :) – Kevin Peno Nov 23 '11 at 00:15

2 Answers2

1

In general, yes, SSL allows this - the client validates any certificate presented by the server, and the server mandates use of client authentication, so the client must authenticate using its certificate. On the other hand your SSL library can be not flexible enough to do this.

Eugene Mayevski 'Callback
  • 45,135
  • 8
  • 71
  • 121
  • Thanks Eugene, in normal situations i have no problem authenticating the client. But in this case i don't need the server to be authenticated. Qt QSslSocket implementation seems to require a key and certificate when acting as server, as you said it seems a library limitation. – andrea Nov 22 '11 at 23:17
  • @andrea why not create a self-signed certificate for the server? In most implementations the server must present the certificate (unless other authentication mechanisms are used), so just put anything there. – Eugene Mayevski 'Callback Nov 23 '11 at 04:41
  • Thank you @Eugene, is a good suggestion, unfortunately the server is destined to be in an application that should run on desktop computers and laptops. Qt the library i am using to develop the application does not allow the use of a certificate for authentication purposes without a private key. There is no point in packaging a self signed certificate with a private key inside a desktop application because it can be extracted (by crackers) very easily, making the authentication useless. Anyway all working well now, i manage to reverse the roles, the handshake is successful and channel encrypted – andrea Nov 23 '11 at 12:52
  • @andrea you are not going to authenticate a server. Your self-signed certificate would be used only because it's required by the library and you don't care if one forged it, right? – Eugene Mayevski 'Callback Nov 23 '11 at 15:31
  • as I managed to reverse the roles, the desktop server acts as client when i comes to ssl handshake, while the client behaves as server during the handshake, the library does not require the certificate/key pair anymore. The library needed the certificate/key pair only during the normal handshake process. – andrea Nov 23 '11 at 21:12
1

Verifying the identity of the SSL/TLS server is necessary to prevent MITM attacks. Even if you use client-certificate authentication (a.k.a. mutual authentication), the client needs to check the identity of the server (typically by checking it trusts its X.509 certificate and that it matches the intended server identity in the certificate). For this, the TLS server needs to be configured with such a certificate (and its associated private key). Without this, the client could very well authenticate using a client-certificate indeed, except that it wouldn't know what it authenticates to (thus potentially leading to MITM attacks).

This being said, in your case, the TLS server needs not be the TCP server. Indeed, TLS tends to be used on top of TCP. In most cases, the TCP client is also the TLS client and, just once the client has established the TCP connection, it also sends a TLS ClientHello over it, starting its role as a TLS client.

You may be able to make the TCP server behave as a TLS server, by making the servre initiate the TLS handshake sending a ClientHello. Indeed, the TLS Glossary defines client as:

The application entity that initiates a TLS connection to a server. This may or may not imply that the client initiated the underlying transport connection. The primary operational difference between the server and client is that the server is generally authenticated, while the client is only optionally authenticated.

I've tried it in Java and it works fine. In Java, the role of which is the client and which is the server is only fixed once the handshake has taken place. Before that, you can still change the role of the SSLSocket using setUseClientMode, although an SSLServerSocket (obtained from an SSLServerSocketFactory will be in server mode, an SSLSocket converted from a plain Socket (resulting from an accept on the server side) can be used as a client TLS socket and vice versa.

TLS allows for this, but I don't know whether it's possible with the framework you're using.

Turning a plain TCP socket into a TLS socket is typically what's done for protocols that upgrade the socket via mechanisms such as STARTTLS (available in SMTP, IMAP and LDAP, for example).

You would need to make a plain TCP connection from your "real" client to your "real" server, turn the TCP client socket into a TLS socket and set it in server mode, turn your TCP server socket into a TLS socket, set it in client mode and initiate the handshake.

Community
  • 1
  • 1
Bruno
  • 119,590
  • 31
  • 270
  • 376
  • Thank you Bruno, extremely helpful answer, based on what you said i am working on both the client and the server, i think is possible to reverse the roles in such a way so that i don't need to have a private key on the server side. I will post the result + some code if i manage to make it working. – andrea Nov 23 '11 at 02:07
  • The reversed role seems to work: in php (the client) i changed the following: `// if (FALSE == ($ret = @stream_socket_enable_crypto($socket, TRUE, **STREAM_CRYPTO_METHOD_TLS_CLIENT**))) if (FALSE == ($ret = @stream_socket_enable_crypto($socket, TRUE, **STREAM_CRYPTO_METHOD_TLS_SERVER**)))` – andrea Nov 23 '11 at 03:16
  • in Qt: `// socket->startServerEncryption(); socket->startClientEncryption();` I now have some hostname mismatch issue, php is not sending the hostname in Qt: `socket->peerName();` returns empty string. And I am a little concern with MINM attacks, but the client is doing simple gets giving nothing away so maybe OK. – andrea Nov 23 '11 at 03:24
  • It's a scenario where it doesn't necessarily make sense to verify the hostname. The easiest might be to package your server cert (or your own CA cert) with the desktop application and make it trust only that certificate, in which case it will know it comes from the PHP application, which might be good enough in this particular case. – Bruno Nov 23 '11 at 15:24
  • this is exactly what i am doing now. Its true it was not vital to verify the hostname. But still i am doing it manually since the desktop clients can only receive connections from one server its easy to compare the certificate CommonName with the server hostname. Something interesting about Qt, the process of connecting to a host sets the hostname of that host this is then compared internally with the CommonName. And this is normal behavior during a Qt client doing normal ssl handshake, but when is a server doing the role of a client ssh handshake the connect method is never – andrea Nov 23 '11 at 21:25
  • called so the internal hostname is not set, so at the moment of comparing the hostname with the CommonName the ssl handshake fails because of mismatch, the hostname is empty. Fortunately i can intercept the failure and do the manual check. – andrea Nov 23 '11 at 21:28