#include #include #include "SslClient.h" SslClient::SslClient(): port(13666) { SslClient(QString("127.0.0.1")); } SslClient::SslClient(QString addr): port(13666) { server = addr; /* read certificates */ QFile ca_cert_file(":/ca.crt"); ca_cert_file.open(QIODevice::ReadOnly); QByteArray ca_cert_arr = ca_cert_file.readAll(); QSslCertificate ca_cert(ca_cert_arr); QList ca_certs; ca_certs.push_back(ca_cert); ca_cert_file.close(); QFile key_file(":/client.key"); key_file.open(QIODevice::ReadOnly); QByteArray key_arr = key_file.readAll(); QSslKey key(key_arr, QSsl::Rsa); key_file.close(); QFile cert_file(":/client.crt"); cert_file.open(QIODevice::ReadOnly); QByteArray cert_arr = cert_file.readAll(); QSslCertificate cert(cert_arr); cert_file.close(); /* create ssl socket */ //sslSocket = new QSslSocket; sslSocket.setLocalCertificate(cert); sslSocket.setPrivateKey(key); sslSocket.setCaCertificates(ca_certs); #ifdef DEBUG sslSocket.setPeerVerifyMode(QSslSocket::VerifyNone); #else sslSocket.setPeerVerifyMode(QSslSocket::VerifyPeer); #endif sslSocket.setProtocol(QSsl::SslV3); /* setup signal handlers */ connect(&sslSocket, SIGNAL(encrypted()), this, SLOT(Connected())); connect(&sslSocket, SIGNAL(disconnected()), this, SLOT(Disconnected())); connect(&sslSocket, SIGNAL(readyRead()), this, SLOT(DataRecieved())); connect(&sslSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(Error(QAbstractSocket::SocketError))); connect(&sslSocket, SIGNAL(peerVerifyError(const QSslError &)), this, SLOT(PeerVerifyError(const QSslError))); connect(&sslSocket, SIGNAL(sslErrors(const QList &)), this, SLOT(SslErrors(const QList &))); } void SslClient::SetServerAddr(QString addr) { server = addr; } void SslClient::SendRequest(RequestType type) { Logger::Trace("Sending request w code %x\n", type); if (sslSocket.state() != QAbstractSocket::ConnectedState) { Logger::Trace("Connecting to server %s:%u\n", server.toLocal8Bit().data(), port); sslSocket.connectToHostEncrypted(server, port); } else { Logger::Trace("Already connected to %s:%u\n", server.toLocal8Bit().data(), port); } unsigned char rcode = 0x00; switch (type) { case Config: case GenericProxyList: case StaticProxyList: case FirewallList: case UploadList: case DeleteList: rcode = type; break; default: Logger::Error("Invalid server request type\n"); break; } char data[5] = {0x13, 0x13, rcode, 0x14, 0x14}; QByteArray pkt(data); sslSocket.write(pkt); } /* * Signal handlers */ void SslClient::Connected() { Logger::Info("Connected to server %s\n", server.toStdString().c_str()); } void SslClient::Disconnected() { Logger::Info("Disconnected from server %s\n", server.toStdString().c_str()); } void SslClient::DataRecieved() { Logger::Trace("Recieved reply from %s\n", server.toStdString().c_str()); QByteArray data = sslSocket.readAll(); int length = data.size(); if (length < 6) { Logger::Error("Server packet too short. Aborting.\n"); return; } char h1 = data[0]; char h2 = data[1]; char t1 = data[length-3]; char t2 = data[length-2]; char t3 = data[length-1]; if ((h1 != 0x13) || (h2 != 0x13) || (t1 != 0x14) || (t2 != 0x14) || (t3 != 0x00)) { Logger::Error("Invalid data packet recieved!\n"); return; } RequestType type; char rcode = data[2]; switch (rcode) { case Config: case GenericProxyList: case StaticProxyList: case FirewallList: case UploadList: case DeleteList: type = (RequestType)rcode; break; default: Logger::Error("Invalid reply code: %x\n", rcode); return; } /* remove header and tail */ data.remove(0, 3); data.remove(length-1, 3); emit ReplyRecieved(type, data); } void SslClient::Disconnect() { sslSocket.close(); } void SslClient::Error(QAbstractSocket::SocketError e) { QString desc; switch(e) { case QAbstractSocket::ConnectionRefusedError: desc = "ConnectionRefusedError"; break; case QAbstractSocket::RemoteHostClosedError: desc = "RemoteHostClosedError"; break; case QAbstractSocket::HostNotFoundError: desc = "HostNotFoundError"; break; case QAbstractSocket::SocketAccessError: desc = "SocketAccessError"; break; case QAbstractSocket::SocketResourceError: desc = "SocketResourceError"; break; case QAbstractSocket::SocketTimeoutError: desc = "SocketTimeoutError"; break; case QAbstractSocket::DatagramTooLargeError: desc = "DatagramTooLargeError"; break; case QAbstractSocket::NetworkError: desc = "NetworkError"; break; case QAbstractSocket::AddressInUseError: desc = "AddressInUseError"; break; case QAbstractSocket::SocketAddressNotAvailableError: desc = "SocketAddressNotAvailableError"; break; case QAbstractSocket::UnsupportedSocketOperationError: desc = "UnsupportedSocketOperationError"; break; case QAbstractSocket::ProxyAuthenticationRequiredError: desc = "ProxyAuthenticationRequiredError"; break; case QAbstractSocket::SslHandshakeFailedError: desc = "SslHandshakeFailedError"; break; case QAbstractSocket::UnfinishedSocketOperationError: desc = "UnfinishedSocketOperationError"; break; case QAbstractSocket::ProxyConnectionRefusedError: desc = "ProxyConnectionRefusedError"; break; case QAbstractSocket::ProxyConnectionClosedError: desc = "ProxyConnectionClosedError"; break; case QAbstractSocket::ProxyConnectionTimeoutError: desc = "ProxyConnectionTimeoutError"; break; case QAbstractSocket::ProxyNotFoundError: desc = "ProxyNotFoundError"; break; case QAbstractSocket::ProxyProtocolError: desc = "ProxyProtocolError"; break; default: desc = "Unknown error"; } Logger::Fatal("Socket error! ( %s)\n", desc.toLocal8Bit().data()); emit ConnectionError(); } void SslClient::PeerVerifyError(const QSslError &error) { switch(error.error()) { case QSslError::InvalidCaCertificate: case QSslError::NoPeerCertificate: case QSslError::UnspecifiedError: case QSslError::AuthorityIssuerSerialNumberMismatch: Logger::Fatal("Critical peer verify error!, Aborting connection\n" "Error description: %s\n", error.errorString().toStdString().c_str()); sslSocket.abort(); break; default: Logger::Fatal("Can't verify peer: %s\n", error.errorString().toStdString().c_str()); break; } } void SslClient::SslErrors(const QList &errors) { if (!errors.empty()) { for (int i = 0; i < errors.size(); i++) { Logger::Fatal("%s\n", errors[i].errorString().toStdString().c_str()); } } }