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