aboutsummaryrefslogtreecommitdiff
path: root/src/base
diff options
context:
space:
mode:
authorMelvin Keskin <melvo@olomono.de>2022-10-03 13:14:32 +0200
committerGitHub <noreply@github.com>2022-10-03 13:14:32 +0200
commitb020af2439342e3f748ecdcad6d4db4d5a8a2880 (patch)
tree7d478009ac9d76cce201d9d6ec6b11ec0f351aa8 /src/base
parentcdf9984a6543f29b7a307a5a45e3e10d0fb28db4 (diff)
Implement XEP-0167: Jingle RTP Sessions SRTP negotiation (#487)
Diffstat (limited to 'src/base')
-rw-r--r--src/base/QXmppJingleIq.cpp302
-rw-r--r--src/base/QXmppJingleIq.h59
2 files changed, 361 insertions, 0 deletions
diff --git a/src/base/QXmppJingleIq.cpp b/src/base/QXmppJingleIq.cpp
index fc198278..a89f87a6 100644
--- a/src/base/QXmppJingleIq.cpp
+++ b/src/base/QXmppJingleIq.cpp
@@ -240,6 +240,9 @@ public:
QList<QXmppJinglePayloadType> payloadTypes;
QList<QXmppJingleCandidate> transportCandidates;
+ // XEP-0167: Jingle RTP Sessions
+ std::optional<QXmppJingleRtpEncryption> rtpEncryption;
+
// XEP-0293: Jingle RTP Feedback Negotiation
QVector<QXmppJingleRtpFeedbackProperty> rtpFeedbackProperties;
QVector<QXmppJingleRtpFeedbackInterval> rtpFeedbackIntervals;
@@ -418,6 +421,31 @@ void QXmppJingleIq::Content::setRtpMultiplexingSupported(bool isRtpMultiplexingS
d->isRtpMultiplexingSupported = isRtpMultiplexingSupported;
}
+///
+/// Returns the encryption used for SRTP negotiation as specified by
+/// \xep{0167, Jingle RTP Sessions}.
+///
+/// \return the RTP encryption via SRTP
+///
+/// \since QXmpp 1.5
+///
+std::optional<QXmppJingleRtpEncryption> QXmppJingleIq::Content::rtpEncryption() const
+{
+ return d->rtpEncryption;
+}
+
+///
+/// Sets the encryption used for SRTP negotiation as specified by \xep{0167, Jingle RTP Sessions}.
+///
+/// \param rtpEncryption RTP encryption via SRTP
+///
+/// \since QXmpp 1.5
+///
+void QXmppJingleIq::Content::setRtpEncryption(const std::optional<QXmppJingleRtpEncryption> &rtpEncryption)
+{
+ d->rtpEncryption = rtpEncryption;
+}
+
void QXmppJingleIq::Content::addPayloadType(const QXmppJinglePayloadType &payload)
{
d->descriptionType = ns_jingle_rtp;
@@ -664,6 +692,17 @@ void QXmppJingleIq::Content::parse(const QDomElement &element)
d->descriptionSsrc = descriptionElement.attribute(QStringLiteral("ssrc")).toULong();
d->isRtpMultiplexingSupported = !descriptionElement.firstChildElement(QStringLiteral("rtcp-mux")).isNull();
+ for (auto childElement = descriptionElement.firstChildElement();
+ !childElement.isNull();
+ childElement = childElement.nextSiblingElement()) {
+ if (QXmppJingleRtpEncryption::isJingleRtpEncryption(childElement)) {
+ QXmppJingleRtpEncryption encryption;
+ encryption.parse(childElement);
+ d->rtpEncryption = encryption;
+ break;
+ }
+ }
+
parseJingleRtpFeedbackNegotiationElements(descriptionElement, d->rtpFeedbackProperties, d->rtpFeedbackIntervals);
parseJingleRtpHeaderExtensionsNegotiationElements(descriptionElement, d->rtpHeaderExtensionProperties, d->isRtpHeaderExtensionMixingAllowed);
@@ -723,6 +762,10 @@ void QXmppJingleIq::Content::toXml(QXmlStreamWriter *writer) const
writer->writeEmptyElement(QStringLiteral("rtcp-mux"));
}
+ if (d->rtpEncryption) {
+ d->rtpEncryption->toXml(writer);
+ }
+
jingleRtpFeedbackNegotiationElementsToXml(writer, d->rtpFeedbackProperties, d->rtpFeedbackIntervals);
jingleRtpHeaderExtensionsNegotiationElementsToXml(writer, d->rtpHeaderExtensionProperties, d->isRtpHeaderExtensionMixingAllowed);
@@ -2115,6 +2158,265 @@ bool QXmppSdpParameter::isSdpParameter(const QDomElement &element)
return element.tagName() == QStringLiteral("parameter");
}
+class QXmppJingleRtpCryptoElementPrivate : public QSharedData
+{
+public:
+ uint32_t tag = 0;
+ QString cryptoSuite;
+ QString keyParams;
+ QString sessionParams;
+};
+
+///
+/// \class QXmppJingleRtpCryptoElement
+///
+/// \brief The QXmppJingleRtpCryptoElement class represents the \xep{0167: Jingle RTP Sessions}
+/// "crypto" element used for SRTP negotiation.
+///
+/// \since QXmpp 1.5
+///
+
+///
+/// Constructs a Jingle RTP crypto element.
+///
+QXmppJingleRtpCryptoElement::QXmppJingleRtpCryptoElement()
+ : d(new QXmppJingleRtpCryptoElementPrivate())
+{
+}
+
+QXMPP_PRIVATE_DEFINE_RULE_OF_SIX(QXmppJingleRtpCryptoElement)
+
+///
+/// Returns the tag used as an identifier for the crypto element.
+///
+/// \return the identifying tag
+///
+uint32_t QXmppJingleRtpCryptoElement::tag() const
+{
+ return d->tag;
+}
+
+///
+/// Sets the tag used as an identifier for the crypto element.
+///
+/// \param tag identifying tag
+///
+void QXmppJingleRtpCryptoElement::setTag(uint32_t tag)
+{
+ d->tag = tag;
+}
+
+///
+/// Returns the crypto suite used as an identifier for describing the encryption and authentication
+/// algorithms.
+///
+/// \return the identifying crypto suite
+///
+QString QXmppJingleRtpCryptoElement::cryptoSuite() const
+{
+ return d->cryptoSuite;
+}
+
+///
+/// Sets the crypto suite used as an identifier for describing the encryption and authentication
+/// algorithms.
+///
+/// \param cryptoSuite identifying crypto suite
+///
+void QXmppJingleRtpCryptoElement::setCryptoSuite(const QString &cryptoSuite)
+{
+ d->cryptoSuite = cryptoSuite;
+}
+
+///
+/// Returns the key parameters providing one or more sets of keying material for the crypto suite.
+///
+/// \return the key parameters providing one or more sets of keying material
+///
+QString QXmppJingleRtpCryptoElement::keyParams() const
+{
+ return d->keyParams;
+}
+
+///
+/// Sets the key parameters providing one or more sets of keying material for the crypto suite.
+///
+/// \param keyParams key parameters providing one or more sets of keying material
+///
+void QXmppJingleRtpCryptoElement::setKeyParams(const QString &keyParams)
+{
+ d->keyParams = keyParams;
+}
+
+///
+/// Returns the session parameters providing transport-specific data.
+///
+/// \return the session parameters providing transport-specific data
+///
+QString QXmppJingleRtpCryptoElement::sessionParams() const
+{
+ return d->sessionParams;
+}
+
+///
+/// Sets the session parameters providing transport-specific data.
+///
+/// \param sessionParams session parameters providing transport-specific data
+///
+void QXmppJingleRtpCryptoElement::setSessionParams(const QString &sessionParams)
+{
+ d->sessionParams = sessionParams;
+}
+
+/// \cond
+void QXmppJingleRtpCryptoElement::parse(const QDomElement &element)
+{
+ d->tag = element.attribute(QStringLiteral("tag")).toUInt();
+ d->cryptoSuite = element.attribute(QStringLiteral("crypto-suite"));
+ d->keyParams = element.attribute(QStringLiteral("key-params"));
+ d->sessionParams = element.attribute(QStringLiteral("session-params"));
+}
+
+void QXmppJingleRtpCryptoElement::toXml(QXmlStreamWriter *writer) const
+{
+ if (!d->cryptoSuite.isEmpty() && !d->keyParams.isEmpty()) {
+ writer->writeStartElement(QStringLiteral("crypto"));
+ writer->writeAttribute(QStringLiteral("tag"), QString::number(d->tag));
+ writer->writeAttribute(QStringLiteral("crypto-suite"), d->cryptoSuite);
+ writer->writeAttribute(QStringLiteral("key-params"), d->keyParams);
+ helperToXmlAddAttribute(writer, QStringLiteral("session-params"), d->sessionParams);
+ writer->writeEndElement();
+ }
+}
+/// \endcond
+
+///
+/// Determines whether the given DOM element is an RTP crypto element.
+///
+/// \param element DOM element being checked
+///
+/// \return whether element is an RTP crypto element
+///
+bool QXmppJingleRtpCryptoElement::isJingleRtpCryptoElement(const QDomElement &element)
+{
+ return element.tagName() == QStringLiteral("crypto");
+}
+
+class QXmppJingleRtpEncryptionPrivate : public QSharedData
+{
+public:
+ bool isRequired = false;
+ QVector<QXmppJingleRtpCryptoElement> cryptoElements;
+};
+
+///
+/// \class QXmppJingleRtpEncryption
+///
+/// \brief The QXmppJingleRtpEncryption class represents the \xep{0167: Jingle RTP Sessions}
+/// "encryption" element used for SRTP negotiation.
+///
+/// \since QXmpp 1.5
+///
+
+///
+/// Constructs a Jingle RTP encryption.
+///
+QXmppJingleRtpEncryption::QXmppJingleRtpEncryption()
+ : d(new QXmppJingleRtpEncryptionPrivate())
+{
+}
+
+QXMPP_PRIVATE_DEFINE_RULE_OF_SIX(QXmppJingleRtpEncryption)
+
+///
+/// Returns whether encryption via SRTP is required.
+///
+/// \return whether encryption is required
+///
+bool QXmppJingleRtpEncryption::isRequired() const
+{
+ return d->isRequired;
+}
+
+///
+/// Sets whether encryption via SRTP is required.
+///
+/// \param isRequired whether encryption is required
+///
+void QXmppJingleRtpEncryption::setRequired(bool isRequired)
+{
+ d->isRequired = isRequired;
+}
+
+///
+/// Returns the crypto elements used for encryption via SRTP.
+///
+/// \return the crypto elements
+///
+QVector<QXmppJingleRtpCryptoElement> QXmppJingleRtpEncryption::cryptoElements() const
+{
+ return d->cryptoElements;
+}
+
+///
+/// Sets the crypto elements used for encryption via SRTP.
+///
+/// \param cryptoElements the crypto elements
+///
+void QXmppJingleRtpEncryption::setCryptoElements(const QVector<QXmppJingleRtpCryptoElement> &cryptoElements)
+{
+ d->cryptoElements = cryptoElements;
+}
+
+/// \cond
+void QXmppJingleRtpEncryption::parse(const QDomElement &element)
+{
+ d->isRequired = element.attribute(QStringLiteral("required")) == QStringLiteral("true") ||
+ element.attribute(QStringLiteral("required")) == QStringLiteral("1");
+
+ for (auto childElement = element.firstChildElement();
+ !childElement.isNull();
+ childElement = childElement.nextSiblingElement()) {
+ if (QXmppJingleRtpCryptoElement::isJingleRtpCryptoElement(childElement)) {
+ QXmppJingleRtpCryptoElement cryptoElement;
+ cryptoElement.parse(childElement);
+ d->cryptoElements.append(std::move(cryptoElement));
+ }
+ }
+}
+
+void QXmppJingleRtpEncryption::toXml(QXmlStreamWriter *writer) const
+{
+ if (!d->cryptoElements.isEmpty()) {
+ writer->writeStartElement(QStringLiteral("encryption"));
+ writer->writeDefaultNamespace(ns_jingle_rtp);
+
+ if (d->isRequired) {
+ writer->writeAttribute(QStringLiteral("required"), QStringLiteral("1"));
+ }
+
+ for (const auto &cryptoElement : std::as_const(d->cryptoElements)) {
+ cryptoElement.toXml(writer);
+ }
+
+ writer->writeEndElement();
+ }
+}
+/// \endcond
+
+///
+/// Determines whether the given DOM element is an RTP encryption element.
+///
+/// \param element DOM element being checked
+///
+/// \return whether element is an RTP encryption element
+///
+bool QXmppJingleRtpEncryption::isJingleRtpEncryption(const QDomElement &element)
+{
+ return element.tagName() == QStringLiteral("encryption") &&
+ element.namespaceURI() == ns_jingle_rtp;
+}
+
class QXmppJingleRtpFeedbackPropertyPrivate : public QSharedData
{
public:
diff --git a/src/base/QXmppJingleIq.h b/src/base/QXmppJingleIq.h
index 5d8de1f8..f5da136c 100644
--- a/src/base/QXmppJingleIq.h
+++ b/src/base/QXmppJingleIq.h
@@ -16,6 +16,8 @@ class QXmppJingleCandidatePrivate;
class QXmppJingleIqContentPrivate;
class QXmppJingleIqPrivate;
class QXmppJinglePayloadTypePrivate;
+class QXmppJingleRtpCryptoElementPrivate;
+class QXmppJingleRtpEncryptionPrivate;
class QXmppJingleRtpFeedbackPropertyPrivate;
class QXmppJingleRtpHeaderExtensionPropertyPrivate;
class QXmppSdpParameterPrivate;
@@ -44,6 +46,60 @@ private:
QSharedDataPointer<QXmppSdpParameterPrivate> d;
};
+class QXMPP_EXPORT QXmppJingleRtpCryptoElement
+{
+public:
+ QXmppJingleRtpCryptoElement();
+
+ QXMPP_PRIVATE_DECLARE_RULE_OF_SIX(QXmppJingleRtpCryptoElement)
+
+ uint32_t tag() const;
+ void setTag(uint32_t tag);
+
+ QString cryptoSuite() const;
+ void setCryptoSuite(const QString &cryptoSuite);
+
+ QString keyParams() const;
+ void setKeyParams(const QString &keyParams);
+
+ QString sessionParams() const;
+ void setSessionParams(const QString &sessionParams);
+
+ /// \cond
+ void parse(const QDomElement &element);
+ void toXml(QXmlStreamWriter *writer) const;
+ /// \endcond
+
+ static bool isJingleRtpCryptoElement(const QDomElement &element);
+
+private:
+ QSharedDataPointer<QXmppJingleRtpCryptoElementPrivate> d;
+};
+
+class QXMPP_EXPORT QXmppJingleRtpEncryption
+{
+public:
+ QXmppJingleRtpEncryption();
+
+ QXMPP_PRIVATE_DECLARE_RULE_OF_SIX(QXmppJingleRtpEncryption)
+
+ bool isRequired() const;
+ void setRequired(bool isRequired);
+
+ QVector<QXmppJingleRtpCryptoElement> cryptoElements() const;
+ void setCryptoElements(const QVector<QXmppJingleRtpCryptoElement> &cryptoElements);
+
+ /// \cond
+ void parse(const QDomElement &element);
+ void toXml(QXmlStreamWriter *writer) const;
+ /// \endcond
+
+ static bool isJingleRtpEncryption(const QDomElement &element);
+
+private:
+ QSharedDataPointer<QXmppJingleRtpEncryptionPrivate> d;
+};
+
class QXMPP_EXPORT QXmppJingleRtpFeedbackProperty
{
public:
@@ -350,6 +406,9 @@ public:
bool isRtpMultiplexingSupported() const;
void setRtpMultiplexingSupported(bool isRtpMultiplexingSupported);
+ std::optional<QXmppJingleRtpEncryption> rtpEncryption() const;
+ void setRtpEncryption(const std::optional<QXmppJingleRtpEncryption> &rtpEncryption);
+
void addPayloadType(const QXmppJinglePayloadType &payload);
QList<QXmppJinglePayloadType> payloadTypes() const;
void setPayloadTypes(const QList<QXmppJinglePayloadType> &payloadTypes);