diff options
author | Sona Kurazyan <sona.kurazyan@qt.io> | 2019-01-09 14:30:01 +0100 |
---|---|---|
committer | Sona Kurazyan <sona.kurazyan@qt.io> | 2019-01-30 15:28:38 +0000 |
commit | 14b68fb394b0d02f672c2c8340c32580d007d2ba (patch) | |
tree | e3e53dcde5071d8048f06e68adc5441dba244025 /src/coap/qcoapclient.cpp | |
parent | 214e0eeece8f0155ce16499a2097577e2d92bdaa (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.cpp | 79 |
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. |