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
qsslsocket_qt.cpp
Go to the documentation of this file.
1// Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
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:critical reason:cryptography
4
6
7#include <QtCore/qbytearray.h>
8#include <QtCore/qdatastream.h>
9#include <QtCore/qmessageauthenticationcode.h>
10#include <QtCore/qrandom.h>
11
12#include <QtNetwork/private/qsslsocket_p.h>
13#include <QtNetwork/private/qsslkey_p.h>
14
16
17/*
18 PKCS12 helpers.
19*/
20
21static QAsn1Element wrap(quint8 type, const QAsn1Element &child)
22{
23 QByteArray value;
24 QDataStream stream(&value, QIODevice::WriteOnly);
25 child.write(stream);
26 return QAsn1Element(type, value);
27}
28
29static QAsn1Element _q_PKCS7_data(const QByteArray &data)
30{
31 QList<QAsn1Element> items;
32 items << QAsn1Element::fromObjectId("1.2.840.113549.1.7.1");
33 items << wrap(QAsn1Element::Context0Type,
34 QAsn1Element(QAsn1Element::OctetStringType, data));
35 return QAsn1Element::fromVector(items);
36}
37
38/*!
39 PKCS #12 key derivation.
40
41 Some test vectors:
42 http://www.drh-consultancy.demon.co.uk/test.txt
43 \internal
44*/
45static QByteArray _q_PKCS12_keygen(char id, const QByteArray &salt, const QString &passPhrase, int n, int r)
46{
47 const int u = 20;
48 const int v = 64;
49
50 // password formatting
51 QByteArray passUnicode(passPhrase.size() * 2 + 2, '\0');
52 char *p = passUnicode.data();
53 for (int i = 0; i < passPhrase.size(); ++i) {
54 quint16 ch = passPhrase[i].unicode();
55 *(p++) = (ch & 0xff00) >> 8;
56 *(p++) = (ch & 0xff);
57 }
58
59 // prepare I
60 QByteArray D(64, id);
61 QByteArray S, P;
62 const int sSize = v * ((salt.size() + v - 1) / v);
63 S.resize(sSize);
64 for (int i = 0; i < sSize; ++i)
65 S[i] = salt[i % salt.size()];
66 const int pSize = v * ((passUnicode.size() + v - 1) / v);
67 P.resize(pSize);
68 for (int i = 0; i < pSize; ++i)
69 P[i] = passUnicode[i % passUnicode.size()];
70 QByteArray I = S + P;
71
72 // apply hashing
73 const int c = (n + u - 1) / u;
74 QByteArray A;
75 QByteArray B;
76 B.resize(v);
77 for (int i = 0; i < c; ++i) {
78 // hash r iterations
79 QByteArray Ai = D + I;
80 for (int j = 0; j < r; ++j)
81 Ai = QCryptographicHash::hash(Ai, QCryptographicHash::Sha1);
82
83 for (int j = 0; j < v; ++j)
84 B[j] = Ai[j % u];
85
86 // modify I as Ij = (Ij + B + 1) modulo 2^v
87 for (int p = 0; p < I.size(); p += v) {
88 quint8 carry = 1;
89 for (int j = v - 1; j >= 0; --j) {
90 quint16 v = quint8(I[p + j]) + quint8(B[j]) + carry;
91 I[p + j] = v & 0xff;
92 carry = (v & 0xff00) >> 8;
93 }
94 }
95 A += Ai;
96 }
97 return A.left(n);
98}
99
101{
102 QByteArray salt;
103 salt.resize(8);
104 for (int i = 0; i < salt.size(); ++i)
105 salt[i] = (QRandomGenerator::global()->generate() & 0xff);
106 return salt;
107}
108
109static QByteArray _q_PKCS12_certBag(const QSslCertificate &cert)
110{
111 QList<QAsn1Element> items;
112 items << QAsn1Element::fromObjectId("1.2.840.113549.1.12.10.1.3");
113
114 // certificate
115 QList<QAsn1Element> certItems;
116 certItems << QAsn1Element::fromObjectId("1.2.840.113549.1.9.22.1");
117 certItems << wrap(QAsn1Element::Context0Type,
118 QAsn1Element(QAsn1Element::OctetStringType, cert.toDer()));
119 items << wrap(QAsn1Element::Context0Type,
120 QAsn1Element::fromVector(certItems));
121
122 // local key id
123 const QByteArray localKeyId = cert.digest(QCryptographicHash::Sha1);
124 QList<QAsn1Element> idItems;
125 idItems << QAsn1Element::fromObjectId("1.2.840.113549.1.9.21");
126 idItems << wrap(QAsn1Element::SetType,
127 QAsn1Element(QAsn1Element::OctetStringType, localKeyId));
128 items << wrap(QAsn1Element::SetType, QAsn1Element::fromVector(idItems));
129
130 // dump
131 QAsn1Element root = wrap(QAsn1Element::SequenceType, QAsn1Element::fromVector(items));
132 QByteArray ba;
133 QDataStream stream(&ba, QIODevice::WriteOnly);
134 root.write(stream);
135 return ba;
136}
137
138QAsn1Element _q_PKCS12_key(const QSslKey &key)
139{
140 Q_ASSERT(key.algorithm() == QSsl::Rsa || key.algorithm() == QSsl::Dsa);
141
142 QList<QAsn1Element> keyItems;
143 keyItems << QAsn1Element::fromInteger(0);
144 QList<QAsn1Element> algoItems;
145 if (key.algorithm() == QSsl::Rsa)
146 algoItems << QAsn1Element::fromObjectId(RSA_ENCRYPTION_OID);
147 else if (key.algorithm() == QSsl::Dsa)
148 algoItems << QAsn1Element::fromObjectId(DSA_ENCRYPTION_OID);
149 algoItems << QAsn1Element(QAsn1Element::NullType);
150 keyItems << QAsn1Element::fromVector(algoItems);
151 keyItems << QAsn1Element(QAsn1Element::OctetStringType, key.toDer());
152 return QAsn1Element::fromVector(keyItems);
153}
154
155static QByteArray _q_PKCS12_shroudedKeyBag(const QSslKey &key, const QString &passPhrase, const QByteArray &localKeyId)
156{
157 const int iterations = 2048;
158 QByteArray salt = _q_PKCS12_salt();
159 QByteArray cKey = _q_PKCS12_keygen(1, salt, passPhrase, 24, iterations);
160 QByteArray cIv = _q_PKCS12_keygen(2, salt, passPhrase, 8, iterations);
161
162 // prepare and encrypt data
163 QByteArray plain;
164 QDataStream plainStream(&plain, QIODevice::WriteOnly);
165 _q_PKCS12_key(key).write(plainStream);
166 QByteArray crypted = QSslKeyPrivate::encrypt(QTlsPrivate::Cipher::DesEde3Cbc,
167 plain, cKey, cIv);
168
169 QList<QAsn1Element> items;
170 items << QAsn1Element::fromObjectId("1.2.840.113549.1.12.10.1.2");
171
172 // key
173 QList<QAsn1Element> keyItems;
174 QList<QAsn1Element> algoItems;
175 algoItems << QAsn1Element::fromObjectId("1.2.840.113549.1.12.1.3");
176 QList<QAsn1Element> paramItems;
177 paramItems << QAsn1Element(QAsn1Element::OctetStringType, salt);
178 paramItems << QAsn1Element::fromInteger(iterations);
179 algoItems << QAsn1Element::fromVector(paramItems);
180 keyItems << QAsn1Element::fromVector(algoItems);
181 keyItems << QAsn1Element(QAsn1Element::OctetStringType, crypted);
182 items << wrap(QAsn1Element::Context0Type,
183 QAsn1Element::fromVector(keyItems));
184
185 // local key id
186 QList<QAsn1Element> idItems;
187 idItems << QAsn1Element::fromObjectId("1.2.840.113549.1.9.21");
188 idItems << wrap(QAsn1Element::SetType,
189 QAsn1Element(QAsn1Element::OctetStringType, localKeyId));
190 items << wrap(QAsn1Element::SetType,
191 QAsn1Element::fromVector(idItems));
192
193 // dump
194 QAsn1Element root = wrap(QAsn1Element::SequenceType, QAsn1Element::fromVector(items));
195 QByteArray ba;
196 QDataStream stream(&ba, QIODevice::WriteOnly);
197 root.write(stream);
198 return ba;
199}
200
201static QByteArray _q_PKCS12_bag(const QList<QSslCertificate> &certs, const QSslKey &key, const QString &passPhrase)
202{
203 QList<QAsn1Element> items;
204
205 // certs
206 for (int i = 0; i < certs.size(); ++i)
207 items << _q_PKCS7_data(_q_PKCS12_certBag(certs[i]));
208
209 // key
210 if (!key.isNull()) {
211 const QByteArray localKeyId = certs.first().digest(QCryptographicHash::Sha1);
212 items << _q_PKCS7_data(_q_PKCS12_shroudedKeyBag(key, passPhrase, localKeyId));
213 }
214
215 // dump
216 QAsn1Element root = QAsn1Element::fromVector(items);
217 QByteArray ba;
218 QDataStream stream(&ba, QIODevice::WriteOnly);
219 root.write(stream);
220 return ba;
221}
222
223static QAsn1Element _q_PKCS12_mac(const QByteArray &data, const QString &passPhrase)
224{
225 const int iterations = 2048;
226
227 // salt generation
228 QByteArray macSalt = _q_PKCS12_salt();
229 QByteArray key = _q_PKCS12_keygen(3, macSalt, passPhrase, 20, iterations);
230
231 // HMAC calculation
232 QMessageAuthenticationCode hmac(QCryptographicHash::Sha1, key);
233 hmac.addData(data);
234
235 QList<QAsn1Element> algoItems;
236 algoItems << QAsn1Element::fromObjectId("1.3.14.3.2.26");
237 algoItems << QAsn1Element(QAsn1Element::NullType);
238
239 QList<QAsn1Element> digestItems;
240 digestItems << QAsn1Element::fromVector(algoItems);
241 digestItems << QAsn1Element(QAsn1Element::OctetStringType, hmac.result());
242
243 QList<QAsn1Element> macItems;
244 macItems << QAsn1Element::fromVector(digestItems);
245 macItems << QAsn1Element(QAsn1Element::OctetStringType, macSalt);
246 macItems << QAsn1Element::fromInteger(iterations);
247 return QAsn1Element::fromVector(macItems);
248}
249
250QByteArray _q_makePkcs12(const QList<QSslCertificate> &certs, const QSslKey &key, const QString &passPhrase)
251{
252 QList<QAsn1Element> items;
253
254 // version
256
257 // auth safe
258 const QByteArray data = _q_PKCS12_bag(certs, key, passPhrase);
259 items << _q_PKCS7_data(data);
260
261 // HMAC
262 items << _q_PKCS12_mac(data, passPhrase);
263
264 // dump
265 QAsn1Element root = QAsn1Element::fromVector(items);
266 QByteArray ba;
267 QDataStream stream(&ba, QIODevice::WriteOnly);
268 root.write(stream);
269 return ba;
270}
271
272QT_END_NAMESPACE
static QAsn1Element fromInteger(unsigned int val)
#define DSA_ENCRYPTION_OID
#define RSA_ENCRYPTION_OID
static QByteArray _q_PKCS12_salt()
static QAsn1Element _q_PKCS7_data(const QByteArray &data)
static QByteArray _q_PKCS12_bag(const QList< QSslCertificate > &certs, const QSslKey &key, const QString &passPhrase)
static QByteArray _q_PKCS12_certBag(const QSslCertificate &cert)
static QByteArray _q_PKCS12_shroudedKeyBag(const QSslKey &key, const QString &passPhrase, const QByteArray &localKeyId)
static QAsn1Element _q_PKCS12_mac(const QByteArray &data, const QString &passPhrase)
static QByteArray _q_PKCS12_keygen(char id, const QByteArray &salt, const QString &passPhrase, int n, int r)
PKCS #12 key derivation.
static QT_BEGIN_NAMESPACE QAsn1Element wrap(quint8 type, const QAsn1Element &child)
QByteArray _q_makePkcs12(const QList< QSslCertificate > &certs, const QSslKey &key, const QString &passPhrase)
QAsn1Element _q_PKCS12_key(const QSslKey &key)