Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qsslkeyingmaterial.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 Governikus GmbH & Co. KG.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6
7#ifndef QT_NO_DEBUG_STREAM
8#include <QtCore/qdebug.h>
9#endif
10#include <QtCore/qhashfunctions.h>
11
12QT_BEGIN_NAMESPACE
13
14/*!
15 \class QSslKeyingMaterial
16 \since 6.12
17 \preliminary
18
19 \brief Describes exported keying material derived from a TLS session.
20
21 \reentrant
22 \ingroup network
23 \ingroup ssl
24 \inmodule QtNetwork
25 \compares equality
26
27 QSslKeyingMaterial represents a request for keying material derived
28 from an established TLS connection using the TLS exporter mechanism.
29
30 The exporter mechanism is defined in RFC 5705 for TLS 1.2 and earlier
31 and in RFC 8446 for TLS 1.3. It allows applications to derive
32 cryptographically separate keying material from the TLS session
33 without exposing the session's traffic keys.
34
35 Each QSslKeyingMaterial object specifies:
36 \list
37 \li an exporter label identifying the purpose of the derived
38 keying material
39 \li an optional context value binding the keying material to
40 application-specific data
41 \li the desired size of the exported keying material
42 \endlist
43
44 The actual keying material is derived by the TLS backend after a
45 successful handshake and can be read with value().
46
47 QSslKeyingMaterial objects are typically configured via
48 QSslConfiguration::setKeyingMaterial() before initiating a TLS
49 connection.
50
51 Example: Deterministic export on client and server
52 \code
53 // Both client and server configure the same label and optional context
54 QSslKeyingMaterial keying("session-label", 32, "app-specific-context");
55
56 // After the TLS handshake completes get data from QSslConfiguration.
57 QByteArray derived = sslConfiguration().takeKeyingMaterial(keying)->value();
58
59 // Both client and server will obtain the same 'derived' bytes
60 // even though they each performed the derivation independently.
61 use(derived);
62 \endcode
63
64 \section1 Security Considerations
65
66 Exported keying material is a secret. QByteArray is a copy-on-write
67 container, so every QSslKeyingMaterial object holding a value shares one
68 buffer, and the secret remains in memory for as long as any of those
69 objects lives. An application that needs to guarantee it holds the only
70 remaining reference must release the Qt-internal ones explicitly.
71
72 After a successful handshake the value lives in exactly one place inside
73 Qt: the QSslKeyingMaterial entry in the socket's internal
74 QSslConfiguration. Each QSslConfiguration returned by
75 QSslSocket::sslConfiguration() is an independent copy of that
76 configuration, sharing the value's buffer with it.
77
78 Both QSslConfiguration::takeKeyingMaterial() overloads hand the values over
79 instead of sharing them: what they return holds the only reference to the
80 value, and the entries they leave behind in the configuration they were
81 called on are valueless \l{clone()}{clones}. Copy the value out of the
82 returned object with \l value() and let the object itself go out of scope,
83 then write the configuration back to the socket: that overwrites the
84 socket's entry with the valueless one, dropping the last reference Qt
85 holds.
86
87 \code
88 QSslConfiguration config = socket->sslConfiguration();
89
90 // Copy the value out of the temporary that owns it, and let it die:
91 QByteArray secret = config.takeKeyingMaterial(request)->value();
92
93 // Overwrite the socket's copy with the entry left behind, which has no value:
94 socket->setSslConfiguration(config);
95 \endcode
96
97 The following copies are outside the socket's control and must be dealt
98 with separately:
99 \list
100 \li Any other QSslConfiguration copy the application still holds,
101 including one stored in a QNetworkRequest or installed with
102 QSslConfiguration::setDefaultConfiguration(). Taking the value
103 from one copy does not affect the others.
104 \li A configuration that was never written back to the socket. Taking
105 the values out of a QSslConfiguration only strips that copy of the
106 configuration; the socket keeps its own until it is given the
107 valueless entries.
108 \li Any QSslKeyingMaterial copy the application made itself. Use
109 \l clone() when a copy of a request is needed without its value.
110 \endlist
111
112 The socket also drops the values when it starts a new handshake, because
113 its entries are reset to valueless clones then, and when it is destroyed.
114 Neither replaces the explicit step above for a socket that stays alive.
115*/
116
117/*!
118 Default-constructs an instance of QSslKeyingMaterial.
119
120 A default instance is never valid.
121
122 \sa isValid()
123*/
124
125QSslKeyingMaterial::QSslKeyingMaterial()
126 = default;
127
128/*!
129 \fn explicit QSslKeyingMaterial::QSslKeyingMaterial(const QByteArray &label, qsizetype size)
130 \fn explicit QSslKeyingMaterial::QSslKeyingMaterial(const QByteArray &label, qsizetype size, const QByteArray &context)
131
132 Constructs a QSslKeyingMaterial object with the given exporter
133 \a label, output \a size, and optional \a context.
134
135 The \a label identifies the purpose of the exported keying material
136 and must be non-empty. The \a size specifies the number of bytes
137 to be derived from the TLS exporter.
138
139 The optional \a context is application-defined data that is mixed
140 into the key derivation process to provide domain separation.
141
142 The keying material itself is not generated until a TLS handshake
143 has completed successfully.
144
145 \note Under TLS 1.2 (RFC 5705), a null context and an empty (non-null)
146 context produce different keying material: the context length field is
147 omitted entirely when no context is present, yielding a different PRF
148 input. Under TLS 1.3 (RFC 8446), an absent context and an empty context
149 are defined to be equivalent and produce the same keying material.
150 Use \l{QByteArray::isNull()} to distinguish them.
151
152 \sa isValid(), label(), context(), value()
153*/
154
155QSslKeyingMaterial::QSslKeyingMaterial(const QByteArray &label, qsizetype size)
156 : m_label(label),
157 m_requestedSize(size)
158{
159}
160
161QSslKeyingMaterial::QSslKeyingMaterial(const QByteArray &label, qsizetype size, const QByteArray &context)
162 : m_label(label),
163 m_context(context),
164 m_requestedSize(size)
165{
166}
167
168QSslKeyingMaterial::QSslKeyingMaterial(const QSslKeyingMaterial &other)
169 = default;
170
171QSslKeyingMaterial &QSslKeyingMaterial::operator=(const QSslKeyingMaterial &other)
172 = default;
173
174QSslKeyingMaterial::~QSslKeyingMaterial()
175 = default;
176
177/*!
178 Returns true if this QSslKeyingMaterial object describes a valid
179 exporter request.
180
181 A QSslKeyingMaterial object is considered valid if it has a
182 non-empty exporter label and a positive output size.
183
184 \sa label(), value()
185*/
186
187bool QSslKeyingMaterial::isValid() const noexcept
188{
189 return !m_label.isEmpty() && requestedSize() > 0;
190}
191
192/*!
193 \fn QByteArray QSslKeyingMaterial::label() const
194
195 Returns the exporter label used for deriving the keying material.
196
197 The label identifies the purpose of the exported keying material
198 and is included verbatim in the TLS exporter derivation.
199
200 \sa context(), value()
201*/
202
203/*!
204 \fn QByteArray QSslKeyingMaterial::context() const
205
206 Returns the optional context value used for deriving the keying material.
207
208 The context value binds the exported keying material to
209 application-specific data and helps prevent accidental reuse of
210 identical keys across different purposes.
211
212 If no context was specified, a null/empty QByteArray is returned (see
213 \l{QSslKeyingMaterial::QSslKeyingMaterial()}).
214
215 \sa label(), value()
216*/
217
218/*!
219 Returns a copy of this keying material request, without its value().
220
221 The returned object carries the exporter label(), context() and
222 requestedSize(), so it can be used to request the same keying material
223 again, but its value() is empty. Use it to initialize a copy, or to
224 reset an entry, without carrying the value along.
225
226 \sa value()
227*/
228QSslKeyingMaterial QSslKeyingMaterial::clone() const
229{
230 return QSslKeyingMaterial(m_label, m_requestedSize, m_context);
231}
232
233/*!
234 \fn QByteArray QSslKeyingMaterial::value() const
235
236 Returns the exported keying material.
237
238 The returned QByteArray contains the keying material derived from
239 the TLS session using the configured exporter label and context.
240
241 If the TLS handshake has not completed successfully or if the TLS
242 backend does not support key exporters, this function returns an
243 empty value.
244
245 \note The contents of the returned keying material are
246 security-sensitive and must be handled with care. See
247 \l{QSslKeyingMaterial#Security Considerations}{Security
248 Considerations} for how to keep the returned QByteArray the
249 only copy of it.
250
251 \sa label(), context(), requestedSize()
252*/
253
254/*!
255 \fn qsizetype QSslKeyingMaterial::requestedSize() const noexcept
256
257 The desired size of the keying material.
258
259 The desired size is the number of bytes the handshake protocol
260 is asked to generate for the purpose described by the \l label()
261 and \l context() of the requested keying material.
262
263 \sa value()
264*/
265
266/*!
267 \fn void QSslKeyingMaterial::swap(QSslKeyingMaterial &other) noexcept
268 \memberswap{keying material}
269*/
270
271/*!
272 \fn size_t qHash(const QSslKeyingMaterial &key) noexcept
273 \fn size_t qHash(const QSslKeyingMaterial &key, size_t seed) noexcept
274 \qhashold{QHash}
275*/
276size_t qHash(const QSslKeyingMaterial &material, size_t seed) noexcept
277{
278 return qHashMulti(seed, material.m_label, material.m_context, material.m_value,
279 material.m_requestedSize);
280}
281
282// friend
283bool comparesEqual(const QSslKeyingMaterial &lhs, const QSslKeyingMaterial &rhs) noexcept
284{
285 return lhs.m_requestedSize == rhs.m_requestedSize
286 && lhs.m_label == rhs.m_label
287 && lhs.m_context.isNull() == rhs.m_context.isNull()
288 && lhs.m_context == rhs.m_context
289 && lhs.m_value == rhs.m_value;
290}
291
292#ifndef QT_NO_DEBUG_STREAM
293/*!
294 \relates QSslKeyingMaterial
295
296 Writes a textual representation of the keying material \a keying
297 to the debug object \a debug.
298
299 \sa {Debugging Techniques}
300*/
301QDebug operator<<(QDebug debug, const QSslKeyingMaterial &keying)
302{
303 QDebugStateSaver saver(debug);
304 debug.resetFormat().nospace();
305 debug << "QSslKeyingMaterial("
306 << keying.label() << ',' << keying.context()
307 << ", requested size: " << keying.requestedSize()
308 << ", actual size: " << keying.value().size() << ')';
309 return debug;
310}
311#endif
312
313QT_END_NAMESPACE
bool comparesEqual(const QFileInfo &lhs, const QFileInfo &rhs)
constexpr size_t qHash(const QSize &s, size_t seed=0) noexcept
Definition qsize.h:192