PDA

View Full Version : SSLServer + certificates



eleanor
17th April 2009, 09:17
Hello to all. I'm programming client-server where both need to identify to the other with certificate (they both also check if the certificate is really from who it says to be - with CA).

So here's the code of server and client program. The problem is it never starts a SSL handshake, it keeps saying: the socket is not encrypted:

Server.cpp

Server::Server(QObject *parent) : QTcpServer(parent) {
/* listen for incoming connections on localhost:PORT */
if(!this->listen(QHostAddress::LocalHost, PORT)) {
qFatal("Unable to start the server on localhost:%d",PORT);
}

//connect(tcpServer, SIGNAL(incomingConnection(int)), this, SLOT(check_ssl_connection()));
/* newConnection() signal is emitted every time a client connects to server */
//connect(tcpServer, SIGNAL(newConnection(int &)), this, SLOT(incomingConnection2(int &)));
}

/**
* This function is called by QTcpServer whenever a new connection is available
**/
void Server::incomingConnection(int socket_descriptor) {
(void)new SSLServer(socket_descriptor, this);
}



SSLServer.cpp


SSLServer::SSLServer(int socket_descriptor, QObject *parent) : QObject(parent) {
/* create server socket */
server = new QSslSocket(this);

/* set socket descriptor */
if(!server->setSocketDescriptor(socket_descriptor)) {
qWarning("Failed to set socket descriptor in SSLServer");
close(socket_descriptor);
delete this;
return;
}

//TODO: dynamic filename
/* add CA certificate: it is used by the handshake process to validate the peer's certificate*/
QSslCertificate ca_cert = handle_certificate("/cert/ca.crt");
server->addCaCertificate(ca_cert);

/* set the server's (LOCAL) digital certificate */
QSslCertificate server_cert = handle_certificate("/cert/server.crt");
server->setLocalCertificate(server_cert);

/* set the server's (LOCAL) private key -> [key+certificate == prove identity to SSL peer] */
server->setPrivateKey("/cert/server.key", QSsl::Rsa, QSsl::Pem, "");

/* set cipher protocol */
server->setProtocol(QSsl::SslV3);

/* wait for socket to complete SSL handshake -> when encrypted it emits encrypted signal */
if(server->waitForEncrypted(5000))
qDebug() << "Socket is encrypted." << endl;

QFile file("/home/eleanor/client.p12");
file.open(QIODevice::ReadOnly);
QByteArray data = file.readAll();
server->write(data);

print_socket_info();

/* handshake is successful and encrypted socket is ready to use */
connect(server, SIGNAL(encrypted()), this, SLOT(connection_established()));
/* if error occurs the sslErrors() signal is emitted */
connect(server, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(error_occured(const QList<QSslError> &)));
/* socket has changed the mode from unencrypted to client/server mode */
connect(server, SIGNAL(modeChanged(QSslSocket::SslMode)), this, SLOT(mode_has_changed(QSslSocket::SslMode)));
}

void SSLServer::mode_has_changed(QSslSocket::SslMode mode) {
qDebug() << "SSL Handshake Mode is: " << mode << endl;

}

/**
* This function prints useful information about a SSL socket
**/
void SSLServer::print_socket_info() {
/* if the socket is encrypted */
if(server->isEncrypted()) {
qDebug() << "Server socket is encrypted" << endl;
}
else {
qDebug() << "Server socket is not encryted" << endl;
}

}


/**
* This function reads the certificate from:
* - disk - if available
* - network - if not avalable it downloads the certificate from the server and store it on disk
* Then return the certificate
**/
QSslCertificate SSLServer::handle_certificate(QString filename) {
/* read the CA certificate */
QFile file(filename);

/* if file exists */
if(!file.exists()) {
qWarning("Filename %s doesn't exists.", qPrintable(filename));
//TODO: download the file from server and store it on disk (predefined location)
}

/* open file */
if(!file.open(QIODevice::ReadOnly)) {
qWarning("Cannot open filename %s.", qPrintable(filename));
}

/* read the whole file into array */
QByteArray data = file.readAll();

/* construct new certificate */
QSslCertificate cert(data, QSsl::Pem);

/* check if the certificate is null */
if(cert.isNull()) {
qWarning("The CA certificate has no content.");
}

/* check if the certificate is valid */
if(!cert.isValid()) {
qWarning("The CA certificate expired.");
}

return cert;
}


void SSLServer::connection_established() {
qDebug() << "SSL Handshake succedded. The socket is now encrypted." << endl;
/* get client's (PEER) digital certificate - for diagnostic purposes */
QSslCertificate client_cert = server->peerCertificate();

}


void SSLServer::error_occured(const QList<QSslError> &error) {
/* ignore the errors */
//server->ignoreSslErrors();
qDebug() << "The following errors occured duing SSH Handshake: " << endl;
for(quint16 i=0;i<error.count(); i++) {
qDebug() << error[i] << endl;
}

}



Client.cpp


SSLClient::SSLClient(QObject *parent) : QObject(parent) {
/* create client socket */
client = new QSslSocket();

//TODO: dynamic filename
/* CA certificate: it is used by the handshake process to validate the peer's certificate */
QSslCertificate ca_cert = handle_certificate("/cert/ca.crt");
client->addCaCertificate(ca_cert);

/* set the client's (LOCAL) digital certificate */
QSslCertificate client_cert = handle_certificate("/cert/client.crt");
client->setLocalCertificate(client_cert);

/* set the client's (LOCAL) private key -> [key+certificate == prove identity to SSL peer] */
client->setPrivateKey("/cert/client.key", QSsl::Rsa, QSsl::Pem, "");

/* set cipher protocol */
client->setProtocol(QSsl::SslV3);

/* get server's (PEER) digital certificate */
//QSslCertificate server_cert = client->peerCertificate();

client->connectToHostEncrypted("127.0.0.1", 8088);

//client->startClientEncryption();

/* handshake is successful and encrypted socket is ready to use */
connect(client, SIGNAL(encrypted()), this, SLOT(connection_established()));
/* if error occurs the sslErrors() signal is emitted */
connect(client, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(error_occured(const QList<QSslError> &)));

}


/**
* This function reads the certificate from:
* - disk - if available
* - network - if not avalable it downloads the certificate from the server and store it on disk
* Then return the certificate
**/
QSslCertificate SSLClient::handle_certificate(QString filename) {
/* read the CA certificate */
QFile file(filename);

/* if file exists */
if(!file.exists()) {
qWarning("Filename %s doesn't exists.", qPrintable(filename));
//TODO: download the file from server and store it on disk (predefined location)
}

/* open file */
if(!file.open(QIODevice::ReadOnly)) {
qWarning("Cannot open filename %s.", qPrintable(filename));
}

/* read the whole file into array */
QByteArray data = file.readAll();

/* construct new certificate */
QSslCertificate cert(data, QSsl::Pem);

/* check if the certificate is null */
if(cert.isNull()) {
qWarning("The CA certificate has no content.");
}

/* check if the certificate is valid */
if(!cert.isValid()) {
qWarning("The CA certificate expired.");
}

/* add CA certificate - to validate the peer's certificate during handshake */
//client->addCaCertificate(cert);
return cert;
}


void SSLClient::connection_established() {
/* get the server's certificate */
QSslCertificate server_cert = client->peerCertificate();

/* write on the ssl connection */
client->write("Hello, world",13);


}


void SSLClient::error_occured(const QList<QSslError> &error) {
/* ignore the errors */
//client->ignoreSslErrors();

}


Thank you for all your help...

jeremiah
5th April 2016, 20:09
copied from this thread to give credit: http://www.qtcentre.org/threads/59820-Changing-QTcpServer-to-SSL-Server?p=265357#post265357

Use QSslsocket instead of QTcpSocket on both sides.

On the client side, call connecToHostEncrypted() ...
On the server side, call startServerEncryption().

See http://qt-project.org/doc/qt-5/QSslSocket.html#details