aboutsummaryrefslogtreecommitdiffstats
path: root/src/coap/qcoapclient.cpp
diff options
context:
space:
mode:
authorSona Kurazyan <sona.kurazyan@qt.io>2019-01-09 14:30:01 +0100
committerSona Kurazyan <sona.kurazyan@qt.io>2019-01-30 15:28:38 +0000
commit14b68fb394b0d02f672c2c8340c32580d007d2ba (patch)
treee3e53dcde5071d8048f06e68adc5441dba244025 /src/coap/qcoapclient.cpp
parent214e0eeece8f0155ce16499a2097577e2d92bdaa (diff)
Add DTLS support to CoAP implementationv5.13.0-alpha1
Added transport layer security based on QDtls. This implementation supports authentication using pre-shared keys and X.509 certificates. Split the QCoapConnection class into a base class to be shared with other transports and a specialized class that relies on QUdpSocket using QDtls for security. Note, that raw public key mode (which is mandatory to implement according to RFC) is not implemented yet, since the underlying OpenSSL library does not support it yet. However, if we later decide to integrate another DTLS implementation, it can be done with minimal changes, by having the new implementations's connection type inherit the QCoapConnection class, which hides the implementation of the transport layer. Tests and examples will be added in a later commit. Change-Id: I14b34a9fd978e1993e86d47becbeed74397d1d6e Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> Reviewed-by: Karsten Heimrich <karsten.heimrich@qt.io>
Diffstat (limited to 'src/coap/qcoapclient.cpp')
-rw-r--r--src/coap/qcoapclient.cpp79
1 files changed, 70 insertions, 9 deletions
diff --git a/src/coap/qcoapclient.cpp b/src/coap/qcoapclient.cpp
index 36b6888..834a7d3 100644
--- a/src/coap/qcoapclient.cpp
+++ b/src/coap/qcoapclient.cpp
@@ -32,6 +32,8 @@
#include "qcoapreply.h"
#include "qcoapdiscoveryreply.h"
#include "qcoapnamespace.h"
+#include "qcoapsecurityconfiguration.h"
+#include "qcoapqudpconnection.h"
#include <QtCore/qiodevice.h>
#include <QtCore/qurl.h>
#include <QtNetwork/qudpsocket.h>
@@ -40,10 +42,10 @@ QT_BEGIN_NAMESPACE
QRandomGenerator QtCoap::randomGenerator = QRandomGenerator::securelySeeded();
-QCoapClientPrivate::QCoapClientPrivate(QCoapProtocol *protocol, QCoapConnection *connection) :
- protocol(protocol),
- connection(connection),
- workerThread(new QThread)
+QCoapClientPrivate::QCoapClientPrivate(QCoapProtocol *protocol, QCoapConnection *connection)
+ : protocol(protocol)
+ , connection(connection)
+ , workerThread(new QThread)
{
protocol->moveToThread(workerThread);
connection->moveToThread(workerThread);
@@ -60,6 +62,23 @@ QCoapClientPrivate::~QCoapClientPrivate()
}
/*!
+ \enum QtCoap::SecurityMode
+
+ Specifies the security mode used for securing a CoAP connection, as defined in
+ \l{https://tools.ietf.org/html/rfc7252#section-9}{RFC 7252}.
+
+ \value NoSec There is no protocol-level security (DTLS is disabled).
+
+ \value PreSharedKey DTLS is enabled, PSK authentication will be used for security.
+
+ \value RawPublicKey DTLS is enabled, an asymmetric key pair without a certificate
+ (a raw public key) will be used for security. This mode is not
+ supported yet.
+
+ \value Certificate DTLS is enabled, an asymmetric key pair with an X.509 certificate
+ will be used for security.
+*/
+/*!
\enum QtCoap::Error
Indicates and error condition found during the processing of the request.
@@ -258,10 +277,27 @@ QtCoap::Error QtCoap::responseCodeError(QtCoap::ResponseCode code)
*/
/*!
- Constructs a QCoapClient object and sets \a parent as the parent object.
+ Constructs a QCoapClient object for the given \a securityMode and
+ sets \a parent as the parent object.
+
+ The default for \a securityMode is SecurityMode::NoSec, which
+ disables security.
+
+ This connects using a QCoapQUdpConnection; to use a custom transport,
+ sub-class QCoapConnection and pass an instance to one of the other
+ constructors.
*/
-QCoapClient::QCoapClient(QObject *parent) :
- QCoapClient(new QCoapProtocol, new QCoapConnection, parent)
+QCoapClient::QCoapClient(QtCoap::SecurityMode securityMode, QObject *parent) :
+ QCoapClient(new QCoapProtocol, new QCoapQUdpConnection(securityMode), parent)
+{
+}
+
+/*!
+ Constructs a QCoapClient object with the given \a connection and
+ sets \a parent as the parent object.
+*/
+QCoapClient::QCoapClient(QCoapConnection *connection, QObject *parent) :
+ QCoapClient(new QCoapProtocol, connection, parent)
{
}
@@ -286,8 +322,8 @@ QCoapClient::QCoapClient(QCoapProtocol *protocol, QCoapConnection *connection, Q
qRegisterMetaType<QCoapMessageId>("QCoapMessageId");
qRegisterMetaType<QAbstractSocket::SocketOption>();
- connect(d->connection, SIGNAL(readyRead(const QNetworkDatagram &)),
- d->protocol, SLOT(onFrameReceived(const QNetworkDatagram &)));
+ connect(d->connection, SIGNAL(readyRead(const QByteArray &, const QHostAddress &)),
+ d->protocol, SLOT(onFrameReceived(const QByteArray &, const QHostAddress &)));
connect(d->connection, SIGNAL(error(QAbstractSocket::SocketError)),
d->protocol, SLOT(onConnectionError(QAbstractSocket::SocketError)));
@@ -324,6 +360,7 @@ QCoapReply *QCoapClient::get(const QCoapRequest &request)
}
QCoapRequest copyRequest(request, QtCoap::Get);
+ copyRequest.adjustUrl(d->connection->isSecure());
return d->sendRequest(copyRequest);
}
@@ -359,6 +396,7 @@ QCoapReply *QCoapClient::put(const QCoapRequest &request, const QByteArray &data
QCoapRequest copyRequest(request, QtCoap::Put);
copyRequest.setPayload(data);
+ copyRequest.adjustUrl(d->connection->isSecure());
return d->sendRequest(copyRequest);
}
@@ -410,6 +448,7 @@ QCoapReply *QCoapClient::post(const QCoapRequest &request, const QByteArray &dat
QCoapRequest copyRequest(request, QtCoap::Post);
copyRequest.setPayload(data);
+ copyRequest.adjustUrl(d->connection->isSecure());
return d->sendRequest(copyRequest);
}
@@ -463,6 +502,7 @@ QCoapReply *QCoapClient::deleteResource(const QCoapRequest &request)
}
QCoapRequest copyRequest(request, QtCoap::Delete);
+ copyRequest.adjustUrl(d->connection->isSecure());
return d->sendRequest(copyRequest);
}
@@ -500,6 +540,7 @@ QCoapDiscoveryReply *QCoapClient::discover(const QUrl &url, const QString &disco
QCoapRequest request(discoveryUrl);
request.setMethod(QtCoap::Get);
+ request.adjustUrl(d->connection->isSecure());
return d->sendDiscovery(request);
}
@@ -608,6 +649,12 @@ bool QCoapClientPrivate::send(QCoapReply *reply)
{
Q_Q(QCoapClient);
+ const auto scheme = connection->isSecure() ? QLatin1String("coaps") : QLatin1String("coap");
+ if (reply->request().url().scheme() != scheme) {
+ qWarning("QCoapClient: Failed to send request, URL has an incorrect scheme.");
+ return false;
+ }
+
if (!QCoapRequest::isUrlValid(reply->request().url())) {
qWarning("QCoapClient: Failed to send request for an invalid URL.");
return false;
@@ -624,6 +671,20 @@ bool QCoapClientPrivate::send(QCoapReply *reply)
}
/*!
+ Sets the security configuration parameters from \a configuration.
+ Configuration will be ignored if the QtCoap::NoSec mode is used.
+
+ \note This method must be called before the handshake starts.
+*/
+void QCoapClient::setSecurityConfiguration(const QCoapSecurityConfiguration &configuration)
+{
+ Q_D(QCoapClient);
+
+ QMetaObject::invokeMethod(d->connection, "setSecurityConfiguration", Qt::QueuedConnection,
+ Q_ARG(QCoapSecurityConfiguration, configuration));
+}
+
+/*!
Sets the maximum block size used by the protocol when sending requests
and receiving replies. The block size must be a power of two.