summaryrefslogtreecommitdiffstats
path: root/src/knx/netip/qknxnetipsecurewrapper.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/knx/netip/qknxnetipsecurewrapper.cpp')
-rw-r--r--src/knx/netip/qknxnetipsecurewrapper.cpp209
1 files changed, 207 insertions, 2 deletions
diff --git a/src/knx/netip/qknxnetipsecurewrapper.cpp b/src/knx/netip/qknxnetipsecurewrapper.cpp
index 0639eee..a100604 100644
--- a/src/knx/netip/qknxnetipsecurewrapper.cpp
+++ b/src/knx/netip/qknxnetipsecurewrapper.cpp
@@ -178,6 +178,14 @@ QKnxNetIpSecureWrapperProxy::Builder QKnxNetIpSecureWrapperProxy::builder()
return QKnxNetIpSecureWrapperProxy::Builder();
}
+/*!
+ Returns a builder object to create a KNXnet/IP secure wrapper frame.
+*/
+QKnxNetIpSecureWrapperProxy::SecureBuilder QKnxNetIpSecureWrapperProxy::secureBuilder()
+{
+ return QKnxNetIpSecureWrapperProxy::SecureBuilder();
+}
+
/*!
\class QKnxNetIpSecureWrapperProxy::Builder
@@ -280,7 +288,8 @@ QKnxNetIpSecureWrapperProxy::Builder &
This field contains an arbitrary value to differentiate two KNXnet/IP
secure wrapper multicast frames sent by one KNXnet/IP device within the
same millisecond (thus the same timer value).
- For unicast connections this field is ignored and must be set to \c 0x0000.
+
+ \note For unicast connections this field is ignored and must be set to \c 0x0000.
*/
QKnxNetIpSecureWrapperProxy::Builder &
QKnxNetIpSecureWrapperProxy::Builder::setMessageTag(quint16 tag)
@@ -330,7 +339,7 @@ QKnxNetIpFrame QKnxNetIpSecureWrapperProxy::Builder::create() const
return { QKnxNetIp::ServiceType::SecureWrapper };
}
- // TODO: introspect the frame and reject secure wrapper frames if possible at all
+ // TODO: introspect the frame and reject secure wrapper frames - if possible at all
return { QKnxNetIp::ServiceType::SecureWrapper, QKnxUtils::QUint16::bytes(d_ptr->m_sessionId)
+ QKnxUtils::QUint48::bytes(d_ptr->m_seqNumber) + d_ptr->m_serial
@@ -354,4 +363,200 @@ QKnxNetIpSecureWrapperProxy::Builder &
return *this;
}
+/*!
+ \class QKnxNetIpSecureWrapperProxy::SecureBuilder
+
+ \inmodule QtKnx
+ \inheaderfile QKnxNetIpSecureWrapperProxy
+
+ \brief The QKnxNetIpSecureWrapperProxy::SecureBuilder class provides the
+ means to create a KNXnet/IP secure wrapper frame.
+
+ This class is part of the Qt KNX module and currently available as a
+ Technology Preview, and therefore the API and functionality provided
+ by the class may be subject to change at any time without prior notice.
+
+ The advantage of using this builder over the default one is that it can
+ take away the burden to do the encryption of the encapsulated frame and
+ the calculation the message authentication code (MAC).
+
+ \note To use this class OpenSSL must be supported on your target system.
+
+ This frame will be sent during secure KNXnet/IP communication and includes
+ a fully encrypted KNXnet/IP frame as well as information needed to decrypt
+ the encapsulated frame and for ensuring data integrity and freshness.
+
+ The common way to create a secure wrapper frame is:
+
+ \code
+ QKnxNetIpFrame frame = QKnxNetIpFrame::fromBytes(...); // create frame
+
+ auto netIpFrame = QKnxNetIpSecureWrapperProxy::secureBuilder()
+ .setSequenceNumber(15021976)
+ .setSerialNumber(QKnxByteArray::fromHex("0123456789AB"))
+ .setEncapsulatedFrame(frame)
+ .create(sessionKey);
+ \endcode
+
+ \sa QKnxCryptographicEngine
+*/
+
+/*!
+ Creates a new empty secure wrapper frame builder object.
+*/
+QKnxNetIpSecureWrapperProxy::SecureBuilder::SecureBuilder()
+ : d_ptr(new QKnxNetIpSecureWrapperPrivate)
+{}
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+QKnxNetIpSecureWrapperProxy::SecureBuilder::~SecureBuilder() = default;
+
+/*!
+ Sets the secure session ID to \a sessionId and returns a reference to the
+ builder. By default value is set to \c 0x0000.
+
+ For multicast connections the fixed identifier \c 0x0000 must be used. For
+ unicast connections the ID was established during a previous successful
+ secure session setup procedure.
+*/
+QKnxNetIpSecureWrapperProxy::SecureBuilder &
+ QKnxNetIpSecureWrapperProxy::SecureBuilder::setSecureSessionId(quint16 sessionId)
+{
+ d_ptr->m_sessionId = sessionId;
+ return *this;
+}
+
+/*!
+ Sets the sequence number to \a seqNumber and returns a reference to the
+ builder.
+
+ For unicast connections it is a monotonically increasing sequence number
+ assigned by the sender; incremented by the sender after each frame sent.
+ For multicast connections this is the device's current multicast timer
+ value in millisecond resolution.
+
+ \note The size of a sequence number is limited to 48 bits, so the maximum
+ number can be \c 281474976710655. Passing a larger value will result in
+ creating an invalid frame.
+*/
+QKnxNetIpSecureWrapperProxy::SecureBuilder &
+ QKnxNetIpSecureWrapperProxy::SecureBuilder::setSequenceNumber(quint48 seqNumber)
+{
+ d_ptr->m_seqNumber = seqNumber;
+ return *this;
+}
+
+/*!
+ Sets the serial number to \a serialNumber of the device sending the frame
+ and returns a reference to the builder.
+
+ \note The serial number must contain exactly 6 bytes.
+*/
+QKnxNetIpSecureWrapperProxy::SecureBuilder &
+ QKnxNetIpSecureWrapperProxy::SecureBuilder::setSerialNumber(const QKnxByteArray &serialNumber)
+{
+ d_ptr->m_serial = serialNumber;
+ return *this;
+}
+
+/*!
+ Sets the message tag of the generic KNXnet/IP secure wrapper frame to \a tag
+ and returns a reference to the builder. By default value is set to \c 0x0000.
+
+ This field contains an arbitrary value to differentiate two KNXnet/IP
+ secure wrapper multicast frames sent by one KNXnet/IP device within the
+ same millisecond (thus the same timer value).
+
+ \note For unicast connections this field is ignored and must be set to \c 0x0000.
+*/
+QKnxNetIpSecureWrapperProxy::SecureBuilder &
+ QKnxNetIpSecureWrapperProxy::SecureBuilder::setMessageTag(quint16 tag)
+{
+ d_ptr->m_tag = tag;
+ return *this;
+}
+
+/*!
+ Sets the encapsulated KNXnet/IP frame to \a frame and returns a reference
+ to the builder.
+
+ \note A secure wrapper frame cannot be encapsulated in another secure
+ wrapper frame and will result in creating an invalid frame.
+*/
+QKnxNetIpSecureWrapperProxy::SecureBuilder &
+ QKnxNetIpSecureWrapperProxy::SecureBuilder::setEncapsulatedFrame(const QKnxNetIpFrame &frame)
+{
+ if (frame.serviceType() != QKnxNetIp::ServiceType::SecureWrapper)
+ d_ptr->m_unencryptedFrame = frame;
+ return *this;
+}
+
+/*!
+ Creates and returns a KNXnet/IP secure wrapper frame. During creation the
+ encapsulated frame gets encrypted and the corresponding MAC computed.
+ The given session key \a sessionKey takes part of the encryption process.
+ Both values, the encrypted frame and the MAC are appended to the KNXnet/IP
+ secure wrapper frame.
+
+ \note The returned frame may be invalid depending on the values used during
+ setup.
+
+ \sa isValid()
+*/
+QKnxNetIpFrame
+ QKnxNetIpSecureWrapperProxy::SecureBuilder::create(const QKnxByteArray &sessionKey) const
+{
+#if QT_CONFIG(opensslv11)
+ if (sessionKey.isEmpty() || d_ptr->m_seqNumber > Q_UINT48_MAX || d_ptr->m_serial.size() != 6
+ || !d_ptr->m_unencryptedFrame.isValid()) {
+ return { QKnxNetIp::ServiceType::SecureWrapper };
+ }
+
+ auto encryptedFrame = QKnxCryptographicEngine::encryptSecureWrapperPayload(sessionKey,
+ d_ptr->m_unencryptedFrame, d_ptr->m_seqNumber, d_ptr->m_serial, d_ptr->m_tag);
+ if (encryptedFrame.isEmpty())
+ return {};
+
+ auto builder = QKnxNetIpSecureWrapperProxy::builder();
+ auto frame = builder
+ .setSecureSessionId(d_ptr->m_sessionId)
+ .setSequenceNumber(d_ptr->m_seqNumber)
+ .setSerialNumber(d_ptr->m_serial)
+ .setMessageTag(d_ptr->m_tag)
+ .setEncapsulatedFrame(encryptedFrame)
+ .setMessageAuthenticationCode(QKnxByteArray(16, 0x00)) // dummy MAC to get a proper header
+ .create();
+
+ auto mac = QKnxCryptographicEngine::computeMessageAuthenticationCode(sessionKey,
+ frame.header(), d_ptr->m_sessionId, d_ptr->m_unencryptedFrame.bytes(), d_ptr->m_seqNumber,
+ d_ptr->m_serial, d_ptr->m_tag);
+ mac = QKnxCryptographicEngine::encryptMessageAuthenticationCode(sessionKey, mac,
+ d_ptr->m_seqNumber, d_ptr->m_serial, d_ptr->m_tag);
+
+ return builder.setMessageAuthenticationCode(mac).create();
+#else
+ Q_UNUSED(sessionKey)
+ return { QKnxNetIp::ServiceType::SecureWrapper };
+#endif
+}
+
+/*!
+ Constructs a copy of \a other.
+*/
+QKnxNetIpSecureWrapperProxy::SecureBuilder::SecureBuilder(const SecureBuilder &other)
+ : d_ptr(other.d_ptr)
+{}
+
+/*!
+ Assigns the specified \a other to this object.
+*/
+QKnxNetIpSecureWrapperProxy::SecureBuilder &
+ QKnxNetIpSecureWrapperProxy::SecureBuilder::operator=(const SecureBuilder &other)
+{
+ d_ptr = other.d_ptr;
+ return *this;
+}
+
QT_END_NAMESPACE