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