diff options
Diffstat (limited to 'src/knx/netip/qknxnetipsecurewrapper.cpp')
-rw-r--r-- | src/knx/netip/qknxnetipsecurewrapper.cpp | 209 |
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 |