Skip to content

Commit

Permalink
Merge pull request #348 from IsraelShushan/networkTab
Browse files Browse the repository at this point in the history
Adding DTLS protocol
  • Loading branch information
dannagle authored Dec 31, 2023
2 parents 87dd08e + 0af8997 commit af22ac7
Show file tree
Hide file tree
Showing 27 changed files with 2,125 additions and 64 deletions.
6 changes: 6 additions & 0 deletions src/PacketSender.pro
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ TRANSLATIONS += languages/packetsender_en.ts \
languages/packetsender_it.ts

SOURCES += mainwindow.cpp \
association.cpp \
dtlsserver.cpp \
dtlsthread.cpp \
languagechooser.cpp \
panel.cpp \
sendpacketbutton.cpp \
Expand All @@ -35,6 +38,9 @@ SOURCES += mainwindow.cpp \
persistenthttp.cpp

HEADERS += mainwindow.h \
association.h \
dtlsserver.h \
dtlsthread.h \
languagechooser.h \
panel.h \
sendpacketbutton.h \
Expand Down
248 changes: 248 additions & 0 deletions src/association.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
// Copyright (C) 2018 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

#include "association.h"
#include "packet.h"

DtlsAssociation::DtlsAssociation(QHostAddress &address, quint16 port,
const QString &connectionName, std::vector<QString> cmdComponents)
: name(connectionName),
crypto(QSslSocket::SslClientMode)
{


QFile certFile(cmdComponents[4]);//4
if(!certFile.open(QIODevice::ReadOnly)){
return;
}
QSsl::EncodingFormat format = getCertFormat(certFile);
QSslCertificate certificate(&certFile, format);
if (certificate.isNull()) {
packetToSend.errorString += "Your local certificate content isn't structured as any certificate format";
}

//key
QFile keyFile(cmdComponents[3]);//3
if(!keyFile.open(QIODevice::ReadOnly)){
return;
}
QSslKey privateKey = getPrivateKey(keyFile);

//ca-cert
QFile caCertFile(cmdComponents[5]);//5
if(!caCertFile.open(QIODevice::ReadOnly)){
return;
}
//getCertFormat
QSsl::EncodingFormat formatCa = getCertFormat(caCertFile);
QSslCertificate caCertificate(&caCertFile, formatCa);
if (caCertificate.isNull()) {
packetToSend.errorString += "Your ca-certificate content isn't structured as any certificate format";
}
QSettings settings(SETTINGSFILE, QSettings::IniFormat);
QString hostName = settings.value("hostNameEdit").toString();

//check if the address field contains a valid host name instead of implicite address
if (hostName.isEmpty()){
QHostInfo host = QHostInfo::fromName(cmdComponents[1]);
// Check if the lookup was successful
if (host.error() != QHostInfo::NoError) {
packetToSend.errorString += "Lookup failed:" + host.errorString();
qDebug() << "Lookup failed:" << host.errorString();
} else {
// Output the host name
foreach (const QHostAddress &resolvedAddress, host.addresses()) {
//if it is an ipv4 save it as addres and fill the hostName with the current hostName
if (resolvedAddress.protocol() == QAbstractSocket::IPv4Protocol){
address = resolvedAddress;
hostName = cmdComponents[1];
}

}
}
}

configuration.setLocalCertificate(certificate);
configuration.setPrivateKey(privateKey);
configuration.setCaCertificates(QList<QSslCertificate>() << caCertificate);

configuration.setPeerVerifyMode(QSslSocket::VerifyPeer);
crypto.setPeer(address, port);
crypto.setPeerVerificationName(hostName);
crypto.setDtlsConfiguration(configuration);

hostName = "";
connect(&crypto, &QDtls::pskRequired, this, &DtlsAssociation::pskRequired);
//! [3]
socket.connectToHost(address.toString(), port);
socket.waitForConnected();
//! [3]
//! [13]
connect(&socket, &QUdpSocket::readyRead, this, &DtlsAssociation::readyRead);
//! [13]

}

//! [12]
DtlsAssociation::~DtlsAssociation()
{
if (crypto.isConnectionEncrypted())
crypto.shutdown(&socket);
}
//! [12]

//! [5]
void DtlsAssociation::startHandshake()
{
if (socket.state() != QAbstractSocket::ConnectedState) {
emit infoMessage(tr("%1: connecting UDP socket first ...").arg(name));
connect(&socket, &QAbstractSocket::connected, this, &DtlsAssociation::udpSocketConnected);
return;
}

if (!crypto.doHandshake(&socket)){
packetToSend.errorString += " Failed to start a handshake ";
emit errorMessage(tr("%1: failed to start a handshake - %2").arg(name, crypto.dtlsErrorString()));
}
else{
while(true){
socket.waitForReadyRead();
if(crypto.isConnectionEncrypted() || closeRequest){

break;

}
}
emit infoMessage(tr("%1: starting a handshake").arg(name));
}

}
//! [5]

void DtlsAssociation::udpSocketConnected()
{
emit infoMessage(tr("%1: UDP socket is now in ConnectedState, continue with handshake ...").arg(name));
startHandshake();
}


void DtlsAssociation::readyRead()
{

if (socket.pendingDatagramSize() <= 0) {
emit warningMessage(tr("%1: spurious read notification?").arg(name));
return;
}

//! [6]
QByteArray dgram(socket.pendingDatagramSize(), Qt::Uninitialized);
const qint64 bytesRead = socket.readDatagram(dgram.data(), dgram.size());
if (bytesRead <= 0) {
emit warningMessage(tr("%1: spurious read notification?").arg(name));
return;
}

dgram.resize(bytesRead);
//! [6]
//! [7]
if (crypto.isConnectionEncrypted()) {
const QByteArray plainText = crypto.decryptDatagram(&socket, dgram);
if (plainText.size()) {
emit receivedDatagram(plainText);
return;
}

if (crypto.dtlsError() == QDtlsError::RemoteClosedConnectionError) {
packetToSend.errorString += " Shutdown alert received";
emit errorMessage(tr("%1: shutdown alert received").arg(name));
socket.close();
pingTimer.stop();
return;
}

emit warningMessage(tr("%1: zero-length datagram received?").arg(name));
} else {
//! [7]
//! [8]
if (!crypto.doHandshake(&socket, dgram)) {
packetToSend.errorString += " handshake error ";
emit errorMessage(tr("%1: handshake error - %2").arg(name, crypto.dtlsErrorString()));
return;
}
//! [8]
crypto.doHandshake(&socket, dgram);
//! [9]
if (crypto.isConnectionEncrypted()) {
emit infoMessage(tr("%1: encrypted connection established!").arg(name));
emit handShakeComplited();
} else {
//! [9]
emit infoMessage(tr("%1: continuing with handshake ...").arg(name));
}

}


}


//! [11]
void DtlsAssociation::handshakeTimeout()
{
emit warningMessage(tr("%1: handshake timeout, trying to re-transmit").arg(name));
if (!crypto.handleTimeout(&socket))
packetToSend.errorString += " Failed to re-transmit ";

emit errorMessage(tr("%1: failed to re-transmit - %2").arg(name, crypto.dtlsErrorString()));
}
//! [11]

//! [14]
void DtlsAssociation::pskRequired(QSslPreSharedKeyAuthenticator *auth)
{
Q_ASSERT(auth);

emit infoMessage(tr("%1: providing pre-shared key ...").arg(name));
auth->setIdentity(name.toLatin1());
auth->setPreSharedKey(QByteArrayLiteral("\x1a\x2b\x3c\x4d\x5e\x6f"));
}


void DtlsAssociation::setCipher(QString chosenCipher) {
configuration.setCiphers(chosenCipher);
crypto.setDtlsConfiguration(configuration);
}

QSsl::EncodingFormat DtlsAssociation::getCertFormat(QFile& certFile){
QFileInfo fileInfo(certFile.fileName());
QString fileExtension = fileInfo.suffix().toLower();
QSsl::EncodingFormat format;

if (fileExtension == "pem") {
format = QSsl::Pem;
} else if (fileExtension == "der") {
format = QSsl::Der;
}
return format;
}

QSslKey DtlsAssociation::getPrivateKey(QFile& keyFile){
QList<QSsl::KeyAlgorithm> keyTypes = { QSsl::Dh, QSsl::Dsa, QSsl::Ec, QSsl::Rsa };
QSslKey privateKey;
foreach (QSsl::KeyAlgorithm type, keyTypes) {
QSslKey key(&keyFile, type);
if (!key.isNull()) {
privateKey = key;
break;
}
keyFile.reset();
}
if(privateKey.isNull()){
packetToSend.errorString += "Your key isn't one of the known key's types: Dh, Dsa, Ec, Rsa";
}
return privateKey;
}




56 changes: 56 additions & 0 deletions src/association.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright (C) 2018 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef ASSOCIATION_H
#define ASSOCIATION_H

#include <QtNetwork>
#include <QtCore>
#include "packet.h"

//! [0]
class DtlsAssociation : public QObject
{
Q_OBJECT

public:
DtlsAssociation(QHostAddress &address, quint16 port,
const QString &connectionName, std::vector<QString> cmdComponents);
~DtlsAssociation();
void startHandshake();
void setCipher(QString chosenCipher);
QSsl::EncodingFormat getCertFormat(QFile& certFile);
QSslKey getPrivateKey(QFile& keyFile);


QSslConfiguration configuration = QSslConfiguration::defaultDtlsConfiguration();
QDtls crypto;
QUdpSocket socket;
QString name;
Packet packetToSend;

bool closeRequest;

signals:
void errorMessage(const QString &message);
void warningMessage(const QString &message);
void infoMessage(const QString &message);
void handShakeComplited();
void receivedDatagram(QByteArray plainText);

private slots:
void udpSocketConnected();
void readyRead();
void pskRequired(QSslPreSharedKeyAuthenticator *auth);
void handshakeTimeout();

private:


QTimer pingTimer;
unsigned ping = 0;

Q_DISABLE_COPY(DtlsAssociation)
};


#endif // ASSOCIATION_H
15 changes: 15 additions & 0 deletions src/cmd_dtls_client.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
@echo off

rem Set environment variables for dataStr, toIP, port, sslPrivateKeyPath, sslLocalCertificatePath, and sslCaPath
@echo dataStr=%1
@echo toIP=%2
@echo port=%3
@echo sslPrivateKeyPath=%4
@echo sslLocalCertificatePath=%5
@echo sslCaPath=%6

rem Create an empty "session.pem" file
type nul > session.pem

rem Run your long OpenSSL command
echo %dataStr% | openssl s_client -dtls1_2 -connect %toIP%:%port% -sess_out session.pem -key %sslPrivateKeyPath% -cert %sslLocalCertificatePath% -CAfile %sslCaPath% -verify 2 -cipher AES256-GCM-SHA384
15 changes: 15 additions & 0 deletions src/cmd_dtls_client.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
@echo off

rem Set environment variables for dataStr, toIP, port, sslPrivateKeyPath, sslLocalCertificatePath, and sslCaPath
set dataStr=%1
set toIP=%2
set port=%3
set sslPrivateKeyPath=%4
set sslLocalCertificatePath=%5
set sslCaPath=%6

rem Create an empty "session.pem" file
type nul > session.pem

rem Run your long OpenSSL command
echo %dataStr% | openssl s_client -dtls1_2 -connect %toIP%:%port% -sess_out session.pem -key %sslPrivateKeyPath% -cert %sslLocalCertificatePath% -CAfile %sslCaPath% -verify 2 -cipher AES256-GCM-SHA384
Loading

0 comments on commit af22ac7

Please sign in to comment.