1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 Mikkel Krautz <mikkel@krautz.dk>
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtNetwork module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 
41 /*!
42     \class QSslDiffieHellmanParameters
43     \brief The QSslDiffieHellmanParameters class provides an interface for Diffie-Hellman parameters for servers.
44     \since 5.8
45 
46     \reentrant
47     \ingroup network
48     \ingroup ssl
49     \ingroup shared
50     \inmodule QtNetwork
51 
52     QSslDiffieHellmanParameters provides an interface for setting Diffie-Hellman parameters to servers based on QSslSocket.
53 
54     \sa QSslSocket, QSslCipher, QSslConfiguration
55 */
56 
57 #include "qssldiffiehellmanparameters.h"
58 #include "qssldiffiehellmanparameters_p.h"
59 #include "qsslsocket.h"
60 #include "qsslsocket_p.h"
61 
62 #include <QtCore/qcoreapplication.h>
63 #include <QtCore/qatomic.h>
64 #include <QtCore/qbytearray.h>
65 #include <QtCore/qbytearraymatcher.h>
66 #include <QtCore/qiodevice.h>
67 #include <QtCore/qdebug.h>
68 
69 QT_BEGIN_NAMESPACE
70 
71 // The 1024-bit MODP group from RFC 2459 (Second Oakley Group)
72 Q_AUTOTEST_EXPORT const char *qssl_dhparams_default_base64 =
73     "MIGHAoGBAP//////////yQ/aoiFowjTExmKLgNwc0SkCTgiKZ8x0Agu+pjsTmyJR"
74     "Sgh5jjQE3e+VGbPNOkMbMCsKbfJfFDdP4TVtbVHCReSFtXZiXn7G9ExC6aY37WsL"
75     "/1y29Aa37e44a/taiZ+lrp8kEXxLH+ZJKGZR7OZTgf//////////AgEC";
76 
77 /*!
78     Returns the default QSslDiffieHellmanParameters used by QSslSocket.
79 
80     This is currently the 1024-bit MODP group from RFC 2459, also
81     known as the Second Oakley Group.
82 */
defaultParameters()83 QSslDiffieHellmanParameters QSslDiffieHellmanParameters::defaultParameters()
84 {
85     QSslDiffieHellmanParameters def;
86     def.d->derData = QByteArray::fromBase64(QByteArray(qssl_dhparams_default_base64));
87     return def;
88 }
89 
90 /*!
91     Constructs an empty QSslDiffieHellmanParameters instance.
92 
93     If an empty QSslDiffieHellmanParameters instance is set on a
94     QSslConfiguration object, Diffie-Hellman negotiation will
95     be disabled.
96 
97     \sa isValid()
98     \sa QSslConfiguration
99 */
QSslDiffieHellmanParameters()100 QSslDiffieHellmanParameters::QSslDiffieHellmanParameters()
101     : d(new QSslDiffieHellmanParametersPrivate)
102 {
103     d->ref.ref();
104 }
105 
106 /*!
107     Constructs a QSslDiffieHellmanParameters object using
108     the byte array \a encoded in either PEM or DER form as specified by \a encoding.
109 
110     Use the isValid() method on the returned object to
111     check whether the Diffie-Hellman parameters were valid and
112     loaded correctly.
113 
114     \sa isValid()
115     \sa QSslConfiguration
116 */
fromEncoded(const QByteArray & encoded,QSsl::EncodingFormat encoding)117 QSslDiffieHellmanParameters QSslDiffieHellmanParameters::fromEncoded(const QByteArray &encoded, QSsl::EncodingFormat encoding)
118 {
119     QSslDiffieHellmanParameters result;
120     switch (encoding) {
121     case QSsl::Der:
122         result.d->decodeDer(encoded);
123         break;
124     case QSsl::Pem:
125         result.d->decodePem(encoded);
126         break;
127     }
128     return result;
129 }
130 
131 /*!
132     Constructs a QSslDiffieHellmanParameters object by
133     reading from \a device in either PEM or DER form as specified by \a encoding.
134 
135     Use the isValid() method on the returned object
136     to check whether the Diffie-Hellman parameters were valid
137     and loaded correctly.
138 
139     In particular, if \a device is \nullptr or not open for reading, an invalid
140     object will be returned.
141 
142     \sa isValid()
143     \sa QSslConfiguration
144 */
fromEncoded(QIODevice * device,QSsl::EncodingFormat encoding)145 QSslDiffieHellmanParameters QSslDiffieHellmanParameters::fromEncoded(QIODevice *device, QSsl::EncodingFormat encoding)
146 {
147     if (device)
148         return fromEncoded(device->readAll(), encoding);
149     else
150         return QSslDiffieHellmanParameters();
151 }
152 
153 /*!
154     Constructs an identical copy of \a other.
155 */
QSslDiffieHellmanParameters(const QSslDiffieHellmanParameters & other)156 QSslDiffieHellmanParameters::QSslDiffieHellmanParameters(const QSslDiffieHellmanParameters &other)
157     : d(other.d)
158 {
159     if (d)
160         d->ref.ref();
161 }
162 
163 /*!
164     \fn QSslDiffieHellmanParameters::QSslDiffieHellmanParameters(QSslDiffieHellmanParameters &&other)
165 
166     Move-constructs from \a other.
167 
168     \note The moved-from object \a other is placed in a partially-formed state, in which
169     the only valid operations are destruction and assignment of a new value.
170 */
171 
172 /*!
173     Destroys the QSslDiffieHellmanParameters object.
174 */
~QSslDiffieHellmanParameters()175 QSslDiffieHellmanParameters::~QSslDiffieHellmanParameters()
176 {
177     if (d && !d->ref.deref())
178         delete d;
179 }
180 
181 /*!
182     Copies the contents of \a other into this QSslDiffieHellmanParameters, making the two QSslDiffieHellmanParameters
183     identical.
184 
185     Returns a reference to this QSslDiffieHellmanParameters.
186 */
operator =(const QSslDiffieHellmanParameters & other)187 QSslDiffieHellmanParameters &QSslDiffieHellmanParameters::operator=(const QSslDiffieHellmanParameters &other)
188 {
189     QSslDiffieHellmanParameters copy(other);
190     swap(copy);
191     return *this;
192 }
193 
194 /*!
195     \fn QSslDiffieHellmanParameters &QSslDiffieHellmanParameters::operator=(QSslDiffieHellmanParameters &&other)
196 
197     Move-assigns \a other to this QSslDiffieHellmanParameters instance.
198 
199     \note The moved-from object \a other is placed in a partially-formed state, in which
200     the only valid operations are destruction and assignment of a new value.
201 */
202 
203 /*!
204     \fn void QSslDiffieHellmanParameters::swap(QSslDiffieHellmanParameters &other)
205 
206     Swaps this QSslDiffieHellmanParameters with \a other. This function is very fast and
207     never fails.
208 */
209 
210 /*!
211     Returns \c true if this is a an empty QSslDiffieHellmanParameters instance.
212 
213     Setting an empty QSslDiffieHellmanParameters instance on a QSslSocket-based
214     server will disable Diffie-Hellman key exchange.
215 */
isEmpty() const216 bool QSslDiffieHellmanParameters::isEmpty() const noexcept
217 {
218     return d->derData.isNull() && d->error == QSslDiffieHellmanParameters::NoError;
219 }
220 
221 /*!
222     Returns \c true if this is a valid QSslDiffieHellmanParameters; otherwise false.
223 
224     This method should be used after constructing a QSslDiffieHellmanParameters
225     object to determine its validity.
226 
227     If a QSslDiffieHellmanParameters object is not valid, you can use the error()
228     method to determine what error prevented the object from being constructed.
229 
230     \sa error()
231 */
isValid() const232 bool QSslDiffieHellmanParameters::isValid() const noexcept
233 {
234     return d->error == QSslDiffieHellmanParameters::NoError;
235 }
236 
237 /*!
238     \enum QSslDiffieHellmanParameters::Error
239 
240     Describes a QSslDiffieHellmanParameters error.
241 
242     \value NoError               No error occurred.
243 
244     \value InvalidInputDataError The given input data could not be used to
245                                  construct a QSslDiffieHellmanParameters
246                                  object.
247 
248     \value UnsafeParametersError The Diffie-Hellman parameters are unsafe
249                                  and should not be used.
250 */
251 
252 /*!
253     Returns the error that caused the QSslDiffieHellmanParameters object
254     to be invalid.
255 */
error() const256 QSslDiffieHellmanParameters::Error QSslDiffieHellmanParameters::error() const noexcept
257 {
258     return d->error;
259 }
260 
261 /*!
262     Returns a human-readable description of the error that caused the
263     QSslDiffieHellmanParameters object to be invalid.
264 */
errorString() const265 QString QSslDiffieHellmanParameters::errorString() const noexcept
266 {
267     switch (d->error) {
268     case QSslDiffieHellmanParameters::NoError:
269         return QCoreApplication::translate("QSslDiffieHellmanParameter", "No error");
270     case QSslDiffieHellmanParameters::InvalidInputDataError:
271         return QCoreApplication::translate("QSslDiffieHellmanParameter", "Invalid input data");
272     case QSslDiffieHellmanParameters::UnsafeParametersError:
273         return QCoreApplication::translate("QSslDiffieHellmanParameter", "The given Diffie-Hellman parameters are deemed unsafe");
274     }
275 
276     Q_UNREACHABLE();
277     return QString();
278 }
279 
280 /*!
281     \since 5.8
282     \relates QSslDiffieHellmanParameters
283 
284     Returns \c true if \a lhs is equal to \a rhs; otherwise returns \c false.
285 */
operator ==(const QSslDiffieHellmanParameters & lhs,const QSslDiffieHellmanParameters & rhs)286 bool operator==(const QSslDiffieHellmanParameters &lhs, const QSslDiffieHellmanParameters &rhs) noexcept
287 {
288     return lhs.d->derData == rhs.d->derData;
289 }
290 
291 #ifndef QT_NO_DEBUG_STREAM
292 /*!
293     \since 5.8
294     \relates QSslDiffieHellmanParameters
295 
296     Writes the set of Diffie-Hellman parameters in \a dhparam into the debug object \a debug for
297     debugging purposes.
298 
299     The Diffie-Hellman parameters will be represented in Base64-encoded DER form.
300 
301     \sa {Debugging Techniques}
302 */
operator <<(QDebug debug,const QSslDiffieHellmanParameters & dhparam)303 QDebug operator<<(QDebug debug, const QSslDiffieHellmanParameters &dhparam)
304 {
305     QDebugStateSaver saver(debug);
306     debug.resetFormat().nospace();
307     debug << "QSslDiffieHellmanParameters(" << dhparam.d->derData.toBase64() << ')';
308     return debug;
309 }
310 #endif
311 
312 /*!
313     \since 5.8
314     \relates QSslDiffieHellmanParameters
315 
316     Returns an hash value for \a dhparam, using \a seed to seed
317     the calculation.
318 */
qHash(const QSslDiffieHellmanParameters & dhparam,uint seed)319 uint qHash(const QSslDiffieHellmanParameters &dhparam, uint seed) noexcept
320 {
321     return qHash(dhparam.d->derData, seed);
322 }
323 
324 QT_END_NAMESPACE
325